Compare commits

...
Author SHA1 Message Date
swung0x48 67069d4a12 [Fix]: compilation error after merge 2026-03-08 11:06:27 +08:00
swung0x48 4a38e7224e Merge branch 'dev' into Feat/Backend-Direct-Vulkan 2026-03-08 10:31:44 +08:00
swung0x48 645f2f748f [Fix] (MG_Backend/DirectVulkan): fix missing clear when (texture-FBO attach -> clear -> detach) occurs 2026-03-08 00:24:30 +08:00
swung0x48 5652f9ae5f [Chore] (MG_Backend/DirectVulkan): implements BlitFramebuffer using backend manager APIs 2026-03-07 19:29:33 +08:00
swung0x48 f3b0b242dd [Feat] (MG_Backend/DirectVulkan): implements BlitFramebuffer 2026-03-07 18:22:38 +08:00
swung0x48 876cb7bcd3 [Chore] (MG_Backend/DirectVulkan): asserts fbo existence 2026-03-07 09:33:05 +08:00
swung0x48 ee9a121c6f [Fix] (MG_Impl/Init): bind default fbo to draw/read slot at init 2026-03-07 09:31:42 +08:00
swung0x48 00439c5c4a [Fix] (MG_Backend/DirectVulkan): Fix sampled-texture/render-pass layout hazard 2026-03-06 21:53:50 +08:00
swung0x48 d7286a5832 [Fix] (MG_Backend/DirectVulkan): some transition fixes 2026-03-06 18:25:33 +08:00
swung0x48 972804fdc7 [Fix] (MG_Backend/DirectVulkan): fixing some layout mismatch 2026-03-06 17:16:55 +08:00
swung0x48 bca7328421 [Fix] (MG_Backend/DirectVulkan): use hash to save active render pass 2026-03-06 16:17:56 +08:00
swung0x48 8097c0d7b1 [Fix] (MG_Backend/DirectVulkan): add untreated aspect member in TextureResource move ctor 2026-03-06 15:45:19 +08:00
swung0x48 641f54e1b7 [Feat] (MG_Backend/DirectVulkan): Transition texture for sampling 2026-03-06 15:37:14 +08:00
swung0x48 c36bfe0843 [Fix] (MG_Backend/DirectVulkan): track image layout naively 2026-03-06 14:53:43 +08:00
swung0x48 8ae66521e3 [Fix] (MG_Backend/DirectVulkan/VkRenderPassManager): early return when there's an active render pass that is compatible 2026-03-06 14:46:51 +08:00
swung0x48 6e21fd9a35 [Chore] (MG_Backend/DirectVulkan): a lotta assertions & transition uploaded texture directly to VK_ACCESS_SHADER_READ_BIT 2026-03-05 23:17:27 +08:00
swung0x48 a2e8faafe5 [Fix] (MG_Backend/DirectVulkan): upload buffer using fence, without vkQueueWaitIdle 2026-03-05 18:02:28 +08:00
swung0x48 668fa3033e [Optimize] (MG_Backend/DirectVulkan): store textureResources in permanent scratch space rather than temp memory 2026-03-05 09:44:03 +08:00
swung0x48 139f3f978d [Chore] (MG_Backend/DirectVulkan): get rid of unnecessary checks 2026-03-04 16:19:35 +08:00
swung0x48 09f96e5ba5 [Fix] (MG_Backend/DirectVulkan): Properly handle front face state. save VkDevice as static member 2026-03-04 15:08:23 +08:00
swung0x48 592a69b1c4 [Feat] (MG_Backend/DirectVulkan): integrating cullmode and frontface render state into vk pipeline 2026-03-03 17:01:02 +08:00
swung0x48 9211341ae7 [Chore] (MG_Backend/DirectVulkan): remove unused functions 2026-03-03 15:16:27 +08:00
swung0x48 5f9d354adb [Fix] (CMakeLists): add absent source file 2026-03-03 15:05:33 +08:00
swung0x48 0ae36b71f5 [Chore] (MG_Backend/DirectVulkan): move ClearAttachmentsOnActiveRenderPass to VulkanRenderer 2026-03-03 14:59:03 +08:00
swung0x48 20e2768f27 [Chore] (MG_Backend/DirectVulkan): move enum conversion to MG_Utils 2026-03-03 14:17:28 +08:00
swung0x48 00c8b5ae3a [Chore] (MG_Backend/DirectVulkan): get rid of unused functions 2026-03-03 13:38:06 +08:00
swung0x48 7687c19b33 [Fix] (MG_Backend/DirectVulkan): hook up TextureManager to TextureEnumConverter 2026-03-03 13:30:33 +08:00
swung0x48 fc3a7cd5f1 [Chore] (Config): Bump version to 26.03 2026-03-03 10:50:24 +08:00
swung0x48 0b7f906533 [Fix] (MG_Backend/DirectVulkan): use proper scissor state to fix menu 2026-03-03 09:43:25 +08:00
swung0x48 c78a94ed09 [Chore] (MG_Backend/DirectVulkan): use vkCmdClearAttachments to implement clear semantics when there's one compatible render pass in flight (instead of interrupting it) 2026-03-02 17:16:18 +08:00
swung0x48 debcb171ce [Chore] (MG_Backend/DirectVulkan): relaxing byteSize checks for textures in VkTextureManager 2026-03-02 14:55:55 +08:00
swung0x48 282468c9d5 [Fix] (MG_Backend/DirectVulkan): query clear color/state inside of RenderPassManager 2026-03-02 10:13:59 +08:00
swung0x48 34b06da83b [Fix] (MG_Backend/DirectVulkan): get ImageView from swapchain when creating render pass for default FBO 2026-03-02 09:49:32 +08:00
swung0x48 3d55f38dab [Fix] (ConfigLoader): still defaults to DirectGLES backend 2026-03-02 08:58:15 +08:00
swung0x48 16426db244 [Chore] (MG_Backend/DirectVulkan): manage active renderpass inside RenderPassManager static functions 2026-03-01 23:02:54 +08:00
swung0x48 6f8c76f06c [Fix] (MG_Backend/DirectVulkan): fixing Vulkan backend initialization 2026-03-01 22:39:30 +08:00
swung0x48 43f2043478 [Fix] (MG_Backend/DirectVulkan): Vulkan backend default framebuffer initialization 2026-03-01 21:21:32 +08:00
swung0x48 f61f068e28 [Fix] (MG_Backend/DirectVulkan): refactor VkRenderPassManager and hook it up (this commit only compiles and does not work) 2026-03-01 18:17:34 +08:00
swung0x48 e234d471fe [Fix] (MG_Backend/DirectVulkan): uninitialized vars in VkRenderPassManager 2026-02-28 18:00:31 +08:00
swung0x48 6ff97a9bb1 [Feat] (MG_Backend/DirectVulkan): new VkRenderPassManager and a bunch of changes accordingly 2026-02-28 17:37:45 +08:00
swung0x48 8adf1d3b8a [Chore] (MG_Backend/DirectVulkan): get rid of junk 2026-02-27 17:36:57 +08:00
swung0x48 2935279603 [Chore] (MG_Backend/DirectVulkan): remove "transition" stuff in VkRenderTargetManager 2026-02-27 16:34:09 +08:00
swung0x48 918b39bb63 [Fix] (MG_Backend/DirectVulkan): remove weird texture binding fallback 2026-02-27 16:22:19 +08:00
swung0x48 963e88943c [Chore] (MG_Backend/DirectVulkan): manage default depth buffer in SwapchainObject 2026-02-27 15:33:01 +08:00
swung0x48 1a75bcba5e [Fix] (MG_Backend/DirectVulkan): prevent operation in assert getting compiled out in release 2026-02-27 15:05:10 +08:00
swung0x48 b64309edfc [Chore] (MG_Backend/DirectVulkan): get rid of junk 2026-02-27 14:14:11 +08:00
swung0x48 e3f1db0a9a [Chore] (MG_Backend/DirectVulkan): use VkTextureManager::TransitionImageLayout more 2026-02-27 13:59:39 +08:00
swung0x48 2c848ab44b [Chore] (MG_Backend/DirectVulkan): move TransitionImageLayout to VkTextureManager 2026-02-27 09:44:23 +08:00
swung0x48 9b23594415 [Fix] (MG_Backend/DirectVulkan): misc fixes 2026-02-25 16:49:58 +08:00
swung0x48 e2e52965df [Feat] (MG_Backend/DirectVulkan): VkClearManager 2026-02-25 16:12:33 +08:00
swung0x48 6e7907f183 [Chore] (MG_Backend/DirectVulkan): get rid of more junk 2026-02-25 12:46:47 +08:00
swung0x48 b4be1292b8 [Feat] (MG_Backend/DirectVulkan): TextureManager mipmap completeness check 2026-02-25 11:04:28 +08:00
swung0x48 db58f4c214 [Feat] (MG_Backend/DirectVulkan): TextureManager supports mipmap 2026-02-25 10:52:54 +08:00
swung0x48 59bad77176 [Chore] (MG_Backend/DirectVulkan): rename functions in VkTextureManager 2026-02-25 09:52:15 +08:00
BZLZHH 3504fca8da Merge branch 'dev' into Perf/Improvement1 2026-02-24 22:48:23 +08:00
BZLZHH e61817ff6a [Fix] (MG_Backend/DirectGLES): Improve iteration safety in CollectGarbage. 2026-02-24 22:47:18 +08:00
BZLZHH b9df28838c Merge pull request #5 from Perf/Improvement1
Merge Perf/improvement1 to dev
2026-02-24 22:09:38 +08:00
BZLZHH fff00e65c4 [Perf] (Texture|State): Replace dynamic_cast hot paths with static_cast. 2026-02-24 15:40:06 +08:00
BZLZHH 8320b4f456 [Feat|Fix] (MG_Backend/DirectGLES): Unify state-backend registries with weak-ref GC. 2026-02-24 15:27:28 +08:00
swung0x48 a757669df5 [Improvement] (MG_Backend/DirectVulkan): split TextureSamplerManager into TextureManager and SamplerManager 2026-02-24 15:19:34 +08:00
swung0x48 e16c0645c0 [Improvement] (MG_Backend/DirectVulkan): use VMA to allocate texture images 2026-02-24 14:21:24 +08:00
swung0x48 8d37763fd3 [Improvement] (MG_Backend/DirectVulkan): use VMA to allocate RT images 2026-02-24 13:09:26 +08:00
swung0x48 e0d0551e7b [Chore] (MG_Test/Backend/DirectVulkan/TestExec): FramebufferManager -> RenderTargetManager 2026-02-24 13:07:50 +08:00
swung0x48 caa814e8f9 [Chore] (MG_Test/Backend/DirectVulkan/TestExec): get rid of now useless default renderpass 2026-02-24 12:25:04 +08:00
swung0x48 2502d32a2e [Chore] (MG_Test/Backend/DirectVulkan/TestExec): get rid of necessary check 2026-02-24 12:10:44 +08:00
swung0x48 e57dd3529e [Chore] (MG_Test/Backend/DirectVulkan/TestExec): get rid of junk 2026-02-24 10:19:21 +08:00
swung0x48 4b8d809237 [Fix] (MG_Test/Backend/DirectVulkan/TestExec): initialize MobileGL first then EGL stuff 2026-02-24 09:26:46 +08:00
swung0x48 d42182befc [Fix] (MG_Backend/DirectVulkan): swap swapchain width/height on 90/270 rotation 2026-02-23 23:12:22 +08:00
swung0x48 5efdb1016e [Fix] (MG_Backend/DirectVulkan): make vk_enum_string_helper.h available on Android NDK 2026-02-23 22:11:30 +08:00
BZLZHH 15e24cda78 [Perf|Improvement] (All): Improve performance & optimize code. 2026-02-23 16:00:38 +08:00
swung0x48 5013108a7f [Chore] (MG_Backend/DirectVulkan): get rid of unnecessary checks 2026-02-22 13:17:22 +08:00
swung0x48 359ba1c572 [Fix] (MG_Backend/DirectVulkan): properly compute hash for samplers 2026-02-22 12:51:00 +08:00
swung0x48 733523011b [Chore] (MG_Backend/DirectVulkan): more hard assertions 2026-02-22 12:31:18 +08:00
swung0x48 14fc13c34d [Chore] (MG_Backend/DirectVulkan): get rid of fallback image/sampler/imageview 2026-02-22 12:18:49 +08:00
swung0x48 e9fee1358d [Chore] (MG_Backend/DirectVulkan): hard assert instead of silently fallback 2026-02-22 12:08:31 +08:00
swung0x48 dae3dd9996 [Chore] (MG_Backend/DirectVulkan): unifying framebuffer manager Transition* functiosn 2026-02-22 11:08:43 +08:00
swung0x48 556db8b02e [Chore] (MG_Backend/DirectVulkan): get rid of redundant guardrails (cont.) 2026-02-22 10:35:10 +08:00
swung0x48 96e993eecf [Chore] (MG_Backend/DirectVulkan): get rid of redundant guardrails 2026-02-22 10:19:44 +08:00
swung0x48 fb3e2123cc [Fix] (MG_Backend/DirectVulkan): dynamically retrieve Vulkan functions in loader, fixing compilation error on lower NDK versions 2026-02-22 10:11:14 +08:00
116 changed files with 11400 additions and 11890 deletions
-2
View File
@@ -14,7 +14,6 @@ bugprone-forwarding-reference-overload,
bugprone-inaccurate-erase, bugprone-inaccurate-erase,
bugprone-incorrect-roundings, bugprone-incorrect-roundings,
bugprone-integer-division, bugprone-integer-division,
bugprone-lambda-function-name,
bugprone-macro-parentheses, bugprone-macro-parentheses,
bugprone-macro-repeated-side-effects, bugprone-macro-repeated-side-effects,
bugprone-misplaced-operator-in-strlen-in-alloc, bugprone-misplaced-operator-in-strlen-in-alloc,
@@ -63,7 +62,6 @@ cert-str34-c,
cppcoreguidelines-interfaces-global-init, cppcoreguidelines-interfaces-global-init,
cppcoreguidelines-narrowing-conversions, cppcoreguidelines-narrowing-conversions,
cppcoreguidelines-pro-type-member-init, cppcoreguidelines-pro-type-member-init,
cppcoreguidelines-pro-type-static-cast-downcast,
cppcoreguidelines-slicing, cppcoreguidelines-slicing,
google-default-arguments, google-default-arguments,
google-runtime-operator, google-runtime-operator,
+6
View File
@@ -19,3 +19,9 @@
[submodule "3rdparty/VulkanMemoryAllocator"] [submodule "3rdparty/VulkanMemoryAllocator"]
path = 3rdparty/VulkanMemoryAllocator path = 3rdparty/VulkanMemoryAllocator
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
[submodule "3rdparty/Vulkan-Utility-Libraries"]
path = 3rdparty/Vulkan-Utility-Libraries
url = https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git
[submodule "3rdparty/Vulkan-Headers"]
path = 3rdparty/Vulkan-Headers
url = https://github.com/KhronosGroup/Vulkan-Headers.git
Vendored Submodule
+1
Submodule 3rdparty/Vulkan-Headers added at ad9ce1235e
+8 -2
View File
@@ -108,6 +108,8 @@ set(SPIRV_CROSS_STATIC ON CACHE BOOL "Prefer static libs" FORCE)
add_subdirectory(3rdparty/glslang) add_subdirectory(3rdparty/glslang)
add_subdirectory(3rdparty/SPIRV-Cross) add_subdirectory(3rdparty/SPIRV-Cross)
add_subdirectory(3rdparty/VulkanMemoryAllocator) add_subdirectory(3rdparty/VulkanMemoryAllocator)
add_subdirectory(3rdparty/Vulkan-Headers)
add_subdirectory(3rdparty/Vulkan-Utility-Libraries)
set(XXHASH_BUILD_XXHSUM OFF) set(XXHASH_BUILD_XXHSUM OFF)
option(BUILD_SHARED_LIBS OFF) option(BUILD_SHARED_LIBS OFF)
@@ -160,6 +162,8 @@ set(SOURCE_FILES
MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.cpp MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.cpp
MobileGL/MG_Util/Converters/GLToMG/ProgramEnumConverter.cpp MobileGL/MG_Util/Converters/GLToMG/ProgramEnumConverter.cpp
MobileGL/MG_Util/Converters/MGToMG/TextureEnumConverter.cpp MobileGL/MG_Util/Converters/MGToMG/TextureEnumConverter.cpp
MobileGL/MG_Util/Converters/MGToVk/RenderStateEnumConverter.cpp
MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp
MobileGL/MG_Util/Classifiers/TextureEnumClassifier.cpp MobileGL/MG_Util/Classifiers/TextureEnumClassifier.cpp
@@ -223,9 +227,10 @@ set(SOURCE_FILES
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateBuilder.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateBuilder.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/VkSamplerManager.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureSamplerManager.cpp
MobileGL/MG_State/GLState/Core.cpp MobileGL/MG_State/GLState/Core.cpp
MobileGL/MG_State/EGLState/Core.cpp MobileGL/MG_State/EGLState/Core.cpp
@@ -262,6 +267,7 @@ set(MOBILEGL_LINK_LIBRARIES
SPIRV-Tools SPIRV-Tools
xxHash::xxhash xxHash::xxhash
GPUOpen::VulkanMemoryAllocator GPUOpen::VulkanMemoryAllocator
Vulkan::UtilityHeaders
) )
set(MOBILEGL_COMPILE_DEF set(MOBILEGL_COMPILE_DEF
+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, 2, 0, "-dev", VersionType::Development}; inline const Version CoreVersion = {26, 3, 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;
+4 -4
View File
@@ -34,10 +34,10 @@ namespace MobileGL {
void Destroy() { void Destroy() {
MGLOG_I("MobileGL closing..."); MGLOG_I("MobileGL closing...");
glslang::FinalizeProcess(); glslang::FinalizeProcess();
delete MG_State::pGLContext; MG_State::pGLContext.reset();
delete MG_State::pEGLContext; MG_State::pEGLContext.reset();
delete MG_Impl::GLImpl::TextureImpl::pProxyTextureManager; MG_Impl::GLImpl::TextureImpl::pProxyTextureManager.reset();
delete MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo; MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo.reset();
MG_Util::Debug::Close(); MG_Util::Debug::Close();
// TODO: add and use Destroy functions for other subsystems // TODO: add and use Destroy functions for other subsystems
+146 -145
View File
@@ -8,6 +8,7 @@
#include "DirectGLES.h" #include "DirectGLES.h"
#include "EGL/egl.h" #include "EGL/egl.h"
#include "MG_Util/Types.h"
#include "Utils.h" #include "Utils.h"
#include "Managers.h" #include "Managers.h"
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h> #include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
@@ -45,7 +46,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
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(std::function<void(GLenum)> func) { void ErrorLopper::Loop(const std::function<void(GLenum)>& func) {
GLenum err = g_GLESFuncs.glGetError(); GLenum err = g_GLESFuncs.glGetError();
while (err != GL_NO_ERROR) { while (err != GL_NO_ERROR) {
func(err); func(err);
@@ -68,14 +69,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
Clear(); Clear();
} }
#else #else
void ErrorLopper::Loop(std::function<void(GLenum)> func) {} void ErrorLopper::Loop(const std::function<void(GLenum)>& func) {}
void ErrorLopper::Clear() {} void ErrorLopper::Clear() {}
ErrorLopper::ErrorLopper() {} ErrorLopper::ErrorLopper() = default;
ErrorLopper::~ErrorLopper() {} ErrorLopper::~ErrorLopper() = default;
#endif #endif
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG #if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
OpenGLScopeMarker::OpenGLScopeMarker(String scopeName) { OpenGLScopeMarker::OpenGLScopeMarker(const String& scopeName) {
g_GLESFuncs.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, scopeName.c_str()); g_GLESFuncs.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, scopeName.c_str());
} }
@@ -83,7 +84,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glPopDebugGroup(); g_GLESFuncs.glPopDebugGroup();
} }
#else #else
OpenGLScopeMarker::OpenGLScopeMarker(String scopeName) {} OpenGLScopeMarker::OpenGLScopeMarker(const String& scopeName) {}
OpenGLScopeMarker::~OpenGLScopeMarker() {} OpenGLScopeMarker::~OpenGLScopeMarker() {}
#endif #endif
@@ -92,31 +93,28 @@ namespace MobileGL::MG_Backend::DirectGLES {
// TODO: deletion for deleted objects // TODO: deletion for deleted objects
namespace BufferImpl { namespace BufferImpl {
void CreateAndSyncBufferObject(SharedPtr<MG_State::GLState::BufferObject>& bufferObject) { void CreateAndSyncBufferObject(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject) {
if (!(bufferObject->GetChangeBits() & BufferChangeBits::DirtyBit)) return; if (!(bufferObject->GetChangeBits() & BufferChangeBits::DirtyBit)) return;
const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject); const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject.get());
SharedPtr<BackendBufferObject> backendBufferObject; Bool exist = (backendBufferIt != g_backendBufferObjects.end());
if (backendBufferIt == g_backendBufferObjects.end()) { auto& backendObj = exist ? backendBufferIt->second : g_backendBufferObjects.GetOrCreate(bufferObject);
backendBufferObject = MakeShared<BackendBufferObject>(); if (!exist) {
g_backendBufferObjects[bufferObject] = backendBufferObject; backendObj = MakeShared<BackendBufferObject>();
} else {
backendBufferObject = backendBufferIt->second;
} }
backendBufferObject->SyncToBackend(bufferObject); backendObj->SyncToBackend(bufferObject);
} }
void SyncNeccessaryBuffers(Bool includeIBO = false, Bool includeIndirectBuffer = false) { void SyncNeccessaryBuffers(Bool includeIBO = false, Bool includeIndirectBuffer = false) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
g_backendBufferObjects.CollectGarbageIfNeeded();
// All buffers we need are: // All buffers we need are:
// 1.VBO 2.IBO (if needed) 3.UBO 4.IndirectBuffer (if needed) 5.SSBO (TODO) // 1.VBO 2.IBO (if needed) 3.UBO 4.IndirectBuffer (if needed) 5.SSBO (TODO)
// PBO is not needed since it should be handled in frontend // PBO is not needed since it should be handled in frontend
// static Vector<SharedPtr<MG_State::GLState::BufferObject>> buffersToSync;
// buffersToSync.clear();
const auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray(); const auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
if (!currentVAOObject) { if (!currentVAOObject) {
MGLOG_E("No VAO is currently bound, cannot sync necessary buffers."); MGLOG_E("No VAO is currently bound, cannot sync necessary buffers.");
@@ -126,7 +124,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
// VBO // VBO
for (const auto& attrib : currentVAOObject->GetAllAttributes()) { for (const auto& attrib : currentVAOObject->GetAllAttributes()) {
if (!attrib.Enabled) continue; if (!attrib.Enabled) continue;
auto bufferObject = attrib.Buffer; auto& bufferObject = attrib.Buffer;
if (bufferObject) { if (bufferObject) {
CreateAndSyncBufferObject(bufferObject); CreateAndSyncBufferObject(bufferObject);
} }
@@ -134,7 +132,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
// IBO // IBO
if (includeIBO) { if (includeIBO) {
auto possibleIBO = currentVAOObject->GetIndexBufferBindingSlot().GetBoundObject(); auto& possibleIBO = currentVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
if (possibleIBO) { if (possibleIBO) {
CreateAndSyncBufferObject(possibleIBO); CreateAndSyncBufferObject(possibleIBO);
} }
@@ -142,7 +140,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
// Indirect Buffer Object // Indirect Buffer Object
if (includeIndirectBuffer) { if (includeIndirectBuffer) {
auto possibleIndirectBuffer = auto& possibleIndirectBuffer =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject(); MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
if (possibleIndirectBuffer) { if (possibleIndirectBuffer) {
CreateAndSyncBufferObject(possibleIndirectBuffer); CreateAndSyncBufferObject(possibleIndirectBuffer);
@@ -153,7 +151,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
auto uboBindingPointCnt = MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform); auto uboBindingPointCnt = MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform);
for (SizeT i = 0; i < uboBindingPointCnt; ++i) { for (SizeT i = 0; i < uboBindingPointCnt; ++i) {
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, i); auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, i);
auto obj = point.GetBoundObject(); auto& obj = point.GetBoundObject();
if (obj) { if (obj) {
CreateAndSyncBufferObject(obj); CreateAndSyncBufferObject(obj);
} }
@@ -166,48 +164,49 @@ namespace MobileGL::MG_Backend::DirectGLES {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
auto currentVAOObject = MG_State::pGLContext->GetBoundVertexArray(); g_backendVertexArrayObjects.CollectGarbageIfNeeded();
auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
if (!currentVAOObject) { if (!currentVAOObject) {
MGLOG_E("No VAO is currently bound, cannot sync current VAO."); MGLOG_E("No VAO is currently bound, cannot sync current VAO.");
return; return;
} }
const auto& backendVAOIt = g_backendVertexArrayObjects.find(currentVAOObject); const auto& backendVAOIt = g_backendVertexArrayObjects.find(currentVAOObject.get());
SharedPtr<VertexArrayImpl::BackendVertexArrayObject> backendVAOObject; Bool exist = (backendVAOIt != g_backendVertexArrayObjects.end());
if (backendVAOIt == g_backendVertexArrayObjects.end()) { auto& backendObj = exist ? backendVAOIt->second : g_backendVertexArrayObjects.GetOrCreate(currentVAOObject);
backendVAOObject = MakeShared<VertexArrayImpl::BackendVertexArrayObject>(); if (!exist) {
g_backendVertexArrayObjects[currentVAOObject] = backendVAOObject; backendObj = MakeShared<VertexArrayImpl::BackendVertexArrayObject>();
} else {
backendVAOObject = backendVAOIt->second;
} }
backendVAOObject->SyncToBackend(currentVAOObject); backendObj->SyncToBackend(currentVAOObject);
} }
} // namespace VertexArrayImpl } // namespace VertexArrayImpl
namespace TextureImpl { namespace TextureImpl {
SharedPtr<BackendTextureObject> SyncTextureObjectToBackend( SharedPtr<BackendTextureObject>& SyncTextureObjectToBackend(
SharedPtr<MG_State::GLState::ITextureObject>& textureObject) { const SharedPtr<MG_State::GLState::ITextureObject>& textureObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
const auto& backendTextureIt = g_backendTextureObjects.find(textureObject); const auto& backendTextureIt = g_backendTextureObjects.find(textureObject.get());
SharedPtr<BackendTextureObject> backendTextureObject; Bool exist = (backendTextureIt != g_backendTextureObjects.end());
if (backendTextureIt == g_backendTextureObjects.end()) { auto& backendObj = exist ? backendTextureIt->second : g_backendTextureObjects.GetOrCreate(textureObject);
backendTextureObject = MakeShared<BackendTextureObject>(); if (!exist) {
g_backendTextureObjects[textureObject] = backendTextureObject; backendObj = MakeShared<BackendTextureObject>();
} else {
backendTextureObject = backendTextureIt->second;
} }
backendTextureObject->SyncTextureParamsToBackend(textureObject); backendObj->SyncTextureParamsToBackend(textureObject);
backendTextureObject->SyncBuiltinSamplerToBackend(textureObject); backendObj->SyncBuiltinSamplerToBackend(textureObject);
backendTextureObject->SyncMipmapsToBackend(textureObject); backendObj->SyncMipmapsToBackend(textureObject);
return backendTextureObject;
return backendObj;
} }
void SyncNeccessaryTextures() { void SyncNeccessaryTextures() {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
g_backendTextureObjects.CollectGarbageIfNeeded();
// All textures we need are: // All textures we need are:
// 1. textures bound to texture units (TODO: only sync ones that are used in current program) // 1. textures bound to texture units (TODO: only sync ones that are used in current program)
// 2. textures used in current FBO // 2. textures used in current FBO
@@ -216,7 +215,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
for (int index = 0; index < MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; ++index) { for (int index = 0; index < MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; ++index) {
auto& unit = MG_State::pGLContext->GetTextureUnitObject(index); auto& unit = MG_State::pGLContext->GetTextureUnitObject(index);
for (const auto& bindingSlot : unit.GetAllBindingSlots()) { for (const auto& bindingSlot : unit.GetAllBindingSlots()) {
auto textureObject = bindingSlot.GetBoundObject(); auto& textureObject = bindingSlot.GetBoundObject();
if (textureObject) { if (textureObject) {
SyncTextureObjectToBackend(textureObject); SyncTextureObjectToBackend(textureObject);
} }
@@ -228,7 +227,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
if (currentFBO) { if (currentFBO) {
for (const auto& attachment : currentFBO->GetAllAttachmentObjects()) { for (const auto& attachment : currentFBO->GetAllAttachmentObjects()) {
if (!attachment.IsTexture()) continue; if (!attachment.IsTexture()) continue;
auto textureObject = attachment.GetTexture(); auto& textureObject = attachment.GetTexture();
if (textureObject) { if (textureObject) {
SyncTextureObjectToBackend(textureObject); SyncTextureObjectToBackend(textureObject);
} }
@@ -242,16 +241,20 @@ namespace MobileGL::MG_Backend::DirectGLES {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
g_backendFramebufferObjects.CollectGarbageIfNeeded();
TextureImpl::g_backendTextureObjects.CollectGarbageIfNeeded();
RenderbufferImpl::g_backendRenderbufferObjects.CollectGarbageIfNeeded();
const FramebufferTarget fboTargets[] = {FramebufferTarget::Draw, FramebufferTarget::Read}; const FramebufferTarget fboTargets[] = {FramebufferTarget::Draw, FramebufferTarget::Read};
MG_State::GLState::FramebufferObject* lastUpdatedFBO = nullptr; MG_State::GLState::FramebufferObject* lastUpdatedFBO = nullptr;
for (auto target : fboTargets) { for (auto& target : fboTargets) {
auto slot = MG_State::pGLContext->GetFramebufferBindingSlot(target); auto& slot = MG_State::pGLContext->GetFramebufferBindingSlot(target);
auto version = slot.GetVersion(); auto version = slot.GetVersion();
if (version == g_fboBindVersions[SizeT(target)]) continue; if (version == g_fboBindVersions[SizeT(target)]) continue;
auto currentFBO = slot.GetBoundObject(); auto& currentFBO = slot.GetBoundObject();
if (!currentFBO) { if (!currentFBO) {
MGLOG_E("No FBO is currently bound, cannot sync current FBO."); MGLOG_E("No FBO is currently bound, cannot sync current FBO.");
@@ -263,21 +266,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
continue; continue;
} }
const auto& backendFBOIt = g_backendFramebufferObjects.find(currentFBO);
SharedPtr<BackendFramebufferObject> backendFBOObject;
if (backendFBOIt == g_backendFramebufferObjects.end()) {
backendFBOObject = MakeShared<BackendFramebufferObject>();
g_backendFramebufferObjects[currentFBO] = backendFBOObject;
} else {
backendFBOObject = backendFBOIt->second;
}
if (currentFBO.get() == lastUpdatedFBO) { if (currentFBO.get() == lastUpdatedFBO) {
MGLOG_D("Draw FBO and read FBO are the same, skipping sync."); MGLOG_D("Draw FBO and read FBO are the same, skipping sync.");
} else { continue;
backendFBOObject->SyncToBackend(currentFBO, target);
} }
const auto& backendFBOIt = g_backendFramebufferObjects.find(currentFBO.get());
Bool exist = (backendFBOIt != g_backendFramebufferObjects.end());
auto& backendObj = exist ? backendFBOIt->second : g_backendFramebufferObjects.GetOrCreate(currentFBO);
if (!exist) {
backendObj = MakeShared<BackendFramebufferObject>();
}
backendObj->SyncToBackend(currentFBO, target);
lastUpdatedFBO = currentFBO.get(); lastUpdatedFBO = currentFBO.get();
} }
} }
@@ -466,21 +467,23 @@ namespace MobileGL::MG_Backend::DirectGLES {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
auto currentProgram = MG_State::pGLContext->GetCurrentProgram(); g_backendProgramObjects.CollectGarbageIfNeeded();
SamplerImpl::g_backendSamplerObjects.CollectGarbageIfNeeded();
auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
if (!currentProgram || !currentProgram->GetLinkStatus()) { if (!currentProgram || !currentProgram->GetLinkStatus()) {
g_GLESFuncs.glUseProgram(0); g_GLESFuncs.glUseProgram(0);
return; return;
} }
const auto& backendProgramIt = g_backendProgramObjects.find(currentProgram); const auto& backendProgramIt = g_backendProgramObjects.find(currentProgram.get());
SharedPtr<BackendProgramObjectImpl> backendProgram; Bool exist = (backendProgramIt != g_backendProgramObjects.end());
if (backendProgramIt == g_backendProgramObjects.end()) { auto& backendObj = exist ? backendProgramIt->second : g_backendProgramObjects.GetOrCreate(currentProgram);
backendProgram = MakeShared<BackendProgramObjectImpl>(); if (!exist) {
g_backendProgramObjects[currentProgram] = backendProgram; backendObj = MakeShared<BackendProgramObjectImpl>();
backendProgram->SyncToBackend(currentProgram); backendObj->SyncToBackend(currentProgram);
} else { } else {
backendProgram = backendProgramIt->second; if (!backendObj->GetBackendProgramId()) {
if (!backendProgram->GetBackendProgramId()) { backendObj->SyncToBackend(currentProgram);
backendProgram->SyncToBackend(currentProgram);
} }
} }
} }
@@ -495,7 +498,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
const auto& currentFBO = slot.GetBoundObject(); const auto& currentFBO = slot.GetBoundObject();
if (currentFBO && currentFBO != MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO) { if (currentFBO && currentFBO != MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO) {
const auto& backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find(currentFBO); const auto& backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find(currentFBO.get());
if (backendFBOIt != FramebufferImpl::g_backendFramebufferObjects.end()) { if (backendFBOIt != FramebufferImpl::g_backendFramebufferObjects.end()) {
backendFBOIt->second->Bind(target); backendFBOIt->second->Bind(target);
} else { } else {
@@ -528,7 +531,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
#endif #endif
const auto& currentVAO = MG_State::pGLContext->GetBoundVertexArray(); const auto& currentVAO = MG_State::pGLContext->GetBoundVertexArray();
if (currentVAO) { if (currentVAO) {
const auto& backendVAOIt = VertexArrayImpl::g_backendVertexArrayObjects.find(currentVAO); const auto& backendVAOIt = VertexArrayImpl::g_backendVertexArrayObjects.find(currentVAO.get());
if (backendVAOIt != VertexArrayImpl::g_backendVertexArrayObjects.end()) { if (backendVAOIt != VertexArrayImpl::g_backendVertexArrayObjects.end()) {
backendVAOIt->second->Bind(); backendVAOIt->second->Bind();
} }
@@ -556,7 +559,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
MG_Util::ConvertTextureTargetToString(target).c_str()); MG_Util::ConvertTextureTargetToString(target).c_str());
continue; continue;
} }
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject); const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) continue; if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) continue;
GLenum targetGL = MG_Util::ConvertTextureTargetToGLEnum(target); GLenum targetGL = MG_Util::ConvertTextureTargetToGLEnum(target);
@@ -566,7 +569,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
// Bind sampler object if necessary // Bind sampler object if necessary
const auto& samplerObject = textureUnit.GetSamplerObject(); const auto& samplerObject = textureUnit.GetSamplerObject();
if (samplerObject) { if (samplerObject) {
const auto& backendSamplerIt = SamplerImpl::g_backendSamplerObjects.find(samplerObject); const auto& backendSamplerIt = SamplerImpl::g_backendSamplerObjects.find(samplerObject.get());
if (backendSamplerIt != SamplerImpl::g_backendSamplerObjects.end()) { if (backendSamplerIt != SamplerImpl::g_backendSamplerObjects.end()) {
backendSamplerIt->second->Bind(unit); backendSamplerIt->second->Bind(unit);
} }
@@ -581,7 +584,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedNC("BindCurrentProgram", TRACY_ZONECOLOR_BACKEND); ZoneScopedNC("BindCurrentProgram", TRACY_ZONECOLOR_BACKEND);
#endif #endif
const auto& backendProgramIt = PrgramImpl::g_backendProgramObjects.find(currentProgram); const auto& backendProgramIt = PrgramImpl::g_backendProgramObjects.find(currentProgram.get());
if (backendProgramIt != PrgramImpl::g_backendProgramObjects.end()) { if (backendProgramIt != PrgramImpl::g_backendProgramObjects.end()) {
backendProgramIt->second->Use(); backendProgramIt->second->Use();
auto backendProgramId = backendProgramIt->second->GetBackendProgramId(); auto backendProgramId = backendProgramIt->second->GetBackendProgramId();
@@ -623,11 +626,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
// Connect buffer to backend binding point // Connect buffer to backend binding point
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, binding); auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, binding);
auto bufferObj = point.GetBoundObject(); auto& bufferObj = point.GetBoundObject();
auto range = point.GetRange(); auto range = point.GetRange();
if (bufferObj) { if (bufferObj) {
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObj); const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObj.get());
if (backendBufferIt != BufferImpl::g_backendBufferObjects.end()) { if (backendBufferIt != BufferImpl::g_backendBufferObjects.end()) {
const auto& backendBufferObject = backendBufferIt->second; const auto& backendBufferObject = backendBufferIt->second;
backendBufferObject->Bind(GL_UNIFORM_BUFFER); backendBufferObject->Bind(GL_UNIFORM_BUFFER);
@@ -635,9 +638,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glBindBufferBase(GL_UNIFORM_BUFFER, lastUBOBinding, g_GLESFuncs.glBindBufferBase(GL_UNIFORM_BUFFER, lastUBOBinding,
backendBufferObject->GetBackendBufferId()); backendBufferObject->GetBackendBufferId());
} else { } else {
g_GLESFuncs.glBindBufferRange(GL_UNIFORM_BUFFER, lastUBOBinding, g_GLESFuncs.glBindBufferRange(
backendBufferObject->GetBackendBufferId(), GL_UNIFORM_BUFFER, lastUBOBinding, backendBufferObject->GetBackendBufferId(),
range.start, range.end - range.start); (GLintptr)range.start, (GLintptr)(range.end - range.start));
} }
} else { } else {
MGLOG_E("No backend buffer found for UBO binding, cannot bind UBO."); MGLOG_E("No backend buffer found for UBO binding, cannot bind UBO.");
@@ -660,18 +663,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
backendProgramIt->second->GetBackendProgramId(), name.c_str()); backendProgramIt->second->GetBackendProgramId(), name.c_str());
g_GLESFuncs.glUniform1i(locAtBackend, unit); g_GLESFuncs.glUniform1i(locAtBackend, unit);
auto samplerObject = MG_State::pGLContext->GetTextureUnitObject(unit).GetSamplerObject(); auto& samplerObject = MG_State::pGLContext->GetTextureUnitObject(unit).GetSamplerObject();
if (samplerObject) { if (samplerObject) {
const auto& backendSamplerIt = SamplerImpl::g_backendSamplerObjects.find(samplerObject); const auto& backendSamplerIt =
SharedPtr<SamplerImpl::BackendSamplerObject> backendSamplerObject; SamplerImpl::g_backendSamplerObjects.find(samplerObject.get());
if (backendSamplerIt == SamplerImpl::g_backendSamplerObjects.end()) { Bool exist = (backendSamplerIt != SamplerImpl::g_backendSamplerObjects.end());
backendSamplerObject = MakeShared<SamplerImpl::BackendSamplerObject>(); auto& backendObj = exist ? backendSamplerIt->second
SamplerImpl::g_backendSamplerObjects[samplerObject] = backendSamplerObject; : SamplerImpl::g_backendSamplerObjects.GetOrCreate(samplerObject);
} else { if (!exist) {
backendSamplerObject = backendSamplerIt->second; backendObj = MakeShared<SamplerImpl::BackendSamplerObject>();
} }
backendSamplerObject->SyncToBackend(samplerObject); backendObj->SyncToBackend(samplerObject);
} else { } else {
SamplerImpl::UnbindSampler(unit); SamplerImpl::UnbindSampler(unit);
} }
@@ -845,30 +848,29 @@ 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
DebugImpl::ErrorLopper errorLopper;
TextureImpl::SyncNeccessaryTextures(); TextureImpl::SyncNeccessaryTextures();
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
FramebufferImpl::SyncCurrentFBO(); FramebufferImpl::SyncCurrentFBO();
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
RenderStateImpl::SyncRenderState(); RenderStateImpl::SyncRenderState();
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
BindCurrentFBO(FramebufferTarget::Draw); BindCurrentFBO(FramebufferTarget::Draw);
BindCurrentFBO(FramebufferTarget::Read); BindCurrentFBO(FramebufferTarget::Read);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
MGLOG_D("ES %s(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)", __func__, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, MGLOG_D("ES %s(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)", __func__, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0,
dstX1, dstY1, mask, MG_Util::ConvertGLEnumToString(filter).c_str()); dstX1, dstY1, mask, MG_Util::ConvertGLEnumToString(filter).c_str());
g_GLESFuncs.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); g_GLESFuncs.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
} }
@@ -895,15 +897,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
MG_Util::ConvertTextureTargetToString(textureTarget).c_str()); MG_Util::ConvertTextureTargetToString(textureTarget).c_str());
} }
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject); const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
SharedPtr<TextureImpl::BackendTextureObject> backendTextureObject; Bool exist = (backendTextureIt != TextureImpl::g_backendTextureObjects.end());
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) { auto& backendObj =
backendTextureObject = MakeShared<TextureImpl::BackendTextureObject>(); exist ? backendTextureIt->second : TextureImpl::g_backendTextureObjects.GetOrCreate(textureObject);
TextureImpl::g_backendTextureObjects[textureObject] = backendTextureObject; if (!exist) {
} else { backendObj = MakeShared<TextureImpl::BackendTextureObject>();
backendTextureObject = backendTextureIt->second;
} }
backendTextureObject->Bind(target, unit); backendObj->Bind(target, unit);
} }
return true; return true;
} }
@@ -953,15 +954,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
DebugImpl::ErrorLopper errorLopper; DebugImpl::ErrorLopper errorLopper;
MGLOG_D("%s: Backend", __func__); MGLOG_D("%s: Backend", __func__);
TextureImpl::SyncNeccessaryTextures(); TextureImpl::SyncNeccessaryTextures();
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
FramebufferImpl::SyncCurrentFBO(); FramebufferImpl::SyncCurrentFBO();
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
RenderStateImpl::SyncRenderState(); RenderStateImpl::SyncRenderState();
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
if (!UpdateTextureBindingAtTarget(target)) return; if (!UpdateTextureBindingAtTarget(target)) return;
@@ -969,10 +970,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
// Bind necessary FBO and texture // Bind necessary FBO and texture
BindCurrentFBO(FramebufferTarget::Read); BindCurrentFBO(FramebufferTarget::Read);
Uint activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit(); Uint activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit) const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject((Int)activeTextureUnit)
.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target)) .GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target))
.GetBoundObject(); .GetBoundObject();
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject); const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) { if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
MGLOG_E("CopyTexSubImage2D: No backend texture found for texture %u.", MGLOG_E("CopyTexSubImage2D: No backend texture found for texture %u.",
textureObject ? textureObject->GetExternalIndex() : 0); textureObject ? textureObject->GetExternalIndex() : 0);
@@ -998,19 +999,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
if (!isDepthFormat) { if (!isDepthFormat) {
g_GLESFuncs.glCopyTexImage2D(target, level, internalformat, x, y, width, height, border); g_GLESFuncs.glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
} else { } else {
MGLOG_D("%s: Backend depth", __func__); MGLOG_D("%s: Backend depth", __func__);
g_GLESFuncs.glTexImage2D(target, level, (GLint)internalformat, width, height, border, format, type, g_GLESFuncs.glTexImage2D(target, level, (GLint)internalformat, width, height, border, format, type,
nullptr); nullptr);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
GLint currentTex = backendTextureIt->second->GetBackendTextureId(); auto currentTex = (GLint)backendTextureIt->second->GetBackendTextureId();
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
@@ -1026,7 +1027,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glBlitFramebuffer(x, y, x + width, y + height, 0, 0, width, height, g_GLESFuncs.glBlitFramebuffer(x, y, x + width, y + height, 0, 0, width, height,
GL_DEPTH_BUFFER_BIT | (isStencilFormat ? GL_STENCIL_BUFFER_BIT : 0), GL_DEPTH_BUFFER_BIT | (isStencilFormat ? GL_STENCIL_BUFFER_BIT : 0),
GL_NEAREST); GL_NEAREST);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
} }
@@ -1041,15 +1042,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("%s: Backend", __func__); MGLOG_D("%s: Backend", __func__);
TextureImpl::SyncNeccessaryTextures(); TextureImpl::SyncNeccessaryTextures();
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
FramebufferImpl::SyncCurrentFBO(); FramebufferImpl::SyncCurrentFBO();
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
RenderStateImpl::SyncRenderState(); RenderStateImpl::SyncRenderState();
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
@@ -1057,11 +1058,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
// Bind necessary FBO and texture // Bind necessary FBO and texture
BindCurrentFBO(FramebufferTarget::Read); BindCurrentFBO(FramebufferTarget::Read);
Uint activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit(); auto activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit) const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit)
.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target)) .GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target))
.GetBoundObject(); .GetBoundObject();
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject); const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) { if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
MGLOG_E("CopyTexSubImage2D: No backend texture found for texture %u.", MGLOG_E("CopyTexSubImage2D: No backend texture found for texture %u.",
textureObject ? textureObject->GetExternalIndex() : 0); textureObject ? textureObject->GetExternalIndex() : 0);
@@ -1069,12 +1070,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
backendTextureIt->second->Bind(target, activeTextureUnit); backendTextureIt->second->Bind(target, activeTextureUnit);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
GLenum internalFormat; GLenum internalFormat;
g_GLESFuncs.glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&internalFormat); g_GLESFuncs.glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&internalFormat);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
auto mgInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalFormat); auto mgInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalFormat);
@@ -1084,19 +1085,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
if (!isDepthFormat) { if (!isDepthFormat) {
g_GLESFuncs.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); g_GLESFuncs.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
} else { } else {
MGLOG_D("%s: Backend depth", __func__); MGLOG_D("%s: Backend depth", __func__);
GLint currentTex = backendTextureIt->second->GetBackendTextureId(); auto currentTex = backendTextureIt->second->GetBackendTextureId();
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
GLenum attachment = isStencilFormat ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT; GLenum attachment = isStencilFormat ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
TempFBOBinder tempFBOBinder(false); TempFBOBinder tempFBOBinder(false);
g_GLESFuncs.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target, currentTex, level); g_GLESFuncs.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target, currentTex, level);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
if (g_GLESFuncs.glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { if (g_GLESFuncs.glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
@@ -1107,7 +1108,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glBlitFramebuffer( g_GLESFuncs.glBlitFramebuffer(
x, y, x + width, y + height, xoffset, yoffset, xoffset + width, yoffset + height, x, y, x + width, y + height, xoffset, yoffset, xoffset + width, yoffset + height,
GL_DEPTH_BUFFER_BIT | (isStencilFormat ? GL_STENCIL_BUFFER_BIT : 0), GL_NEAREST); GL_DEPTH_BUFFER_BIT | (isStencilFormat ? GL_STENCIL_BUFFER_BIT : 0), GL_NEAREST);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
} }
@@ -1120,8 +1121,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
auto unitIndex = MG_State::pGLContext->GetActiveTextureUnit(); auto unitIndex = MG_State::pGLContext->GetActiveTextureUnit();
auto& unit = MG_State::pGLContext->GetTextureUnitObject(unitIndex); auto& unit = MG_State::pGLContext->GetTextureUnitObject(unitIndex);
auto& slot = unit.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target)); auto& slot = unit.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target));
auto texture = slot.GetBoundObject(); auto& texture = slot.GetBoundObject();
auto backendTexture = TextureImpl::SyncTextureObjectToBackend(texture); auto& backendTexture = TextureImpl::SyncTextureObjectToBackend(texture);
backendTexture->Bind(target, unitIndex); backendTexture->Bind(target, unitIndex);
g_GLESFuncs.glGenerateMipmap(target); g_GLESFuncs.glGenerateMipmap(target);
@@ -1184,7 +1185,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
PixelStoreParameters m_prevParams; PixelStoreParameters m_prevParams;
PixelStoreParameters QueryCurrentGLPixelStoreParams(Bool isUnpack) { static PixelStoreParameters QueryCurrentGLPixelStoreParams(Bool isUnpack) {
PixelStoreParameters p; PixelStoreParameters p;
if (!isUnpack) { if (!isUnpack) {
g_GLESFuncs.glGetIntegerv(GL_PACK_ALIGNMENT, (GLint*)&p.Alignment); g_GLESFuncs.glGetIntegerv(GL_PACK_ALIGNMENT, (GLint*)&p.Alignment);
@@ -1214,7 +1215,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
return p; return p;
} }
void Sync(Bool isUnpack, const PixelStoreParameters& params) { static void Sync(Bool isUnpack, const PixelStoreParameters& params) {
if (!isUnpack) { if (!isUnpack) {
g_GLESFuncs.glPixelStorei(GL_PACK_ALIGNMENT, params.Alignment); g_GLESFuncs.glPixelStorei(GL_PACK_ALIGNMENT, params.Alignment);
g_GLESFuncs.glPixelStorei(GL_PACK_ROW_LENGTH, params.RowLength); g_GLESFuncs.glPixelStorei(GL_PACK_ROW_LENGTH, params.RowLength);
@@ -1271,7 +1272,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
// Handle PBO // Handle PBO
auto pixelPackBufferObject = auto& pixelPackBufferObject =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject(); MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
Bool usePBO; Bool usePBO;
GLuint prevPixelPackBuffer = 0; GLuint prevPixelPackBuffer = 0;
@@ -1279,7 +1280,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
BufferImpl::CreateAndSyncBufferObject(pixelPackBufferObject); BufferImpl::CreateAndSyncBufferObject(pixelPackBufferObject);
MGLOG_D("ReadPixels: Using PBO %u", pixelPackBufferObject->GetExternalIndex()); MGLOG_D("ReadPixels: Using PBO %u", pixelPackBufferObject->GetExternalIndex());
usePBO = true; usePBO = true;
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(pixelPackBufferObject); const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(pixelPackBufferObject.get());
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) { if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
MGLOG_E("ReadPixels: No backend buffer found for PBO %u.", MGLOG_E("ReadPixels: No backend buffer found for PBO %u.",
@@ -1299,8 +1300,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
if (usePBO) { if (usePBO) {
// pull back to client memory if PBO is used // pull back to client memory if PBO is used
MGLOG_D("ReadPixels: PBO used, mapping buffer to client memory"); MGLOG_D("ReadPixels: PBO used, mapping buffer to client memory");
GLvoid* pboMappedPtr = g_GLESFuncs.glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, GLvoid* pboMappedPtr = g_GLESFuncs.glMapBufferRange(
pixelPackBufferObject->GetSize(), GL_MAP_READ_BIT); GL_PIXEL_PACK_BUFFER, 0, (GLsizeiptr)pixelPackBufferObject->GetSize(), GL_MAP_READ_BIT);
if (pboMappedPtr) { if (pboMappedPtr) {
MGLOG_D("ReadPixels: Copying data from PBO to client memory"); MGLOG_D("ReadPixels: Copying data from PBO to client memory");
SizeT size = pixelPackBufferObject->GetSize(); SizeT size = pixelPackBufferObject->GetSize();
@@ -1345,7 +1346,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("GetTexImage: SyncCurrentFBO()"); MGLOG_D("GetTexImage: SyncCurrentFBO()");
FramebufferImpl::SyncCurrentFBO(); FramebufferImpl::SyncCurrentFBO();
Uint activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit(); auto activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
MGLOG_D("GetTexImage: active texture unit = %u", activeTextureUnit); MGLOG_D("GetTexImage: active texture unit = %u", activeTextureUnit);
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit) const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit)
@@ -1355,7 +1356,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("GetTexImage: bound texture object = %p (name=%u)", textureObject.get(), MGLOG_D("GetTexImage: bound texture object = %p (name=%u)", textureObject.get(),
textureObject ? textureObject->GetExternalIndex() : 0); textureObject ? textureObject->GetExternalIndex() : 0);
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject); const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) { if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
MGLOG_E("GetTexImage: No backend texture found for texture %u.", MGLOG_E("GetTexImage: No backend texture found for texture %u.",
@@ -1383,14 +1384,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
return; return;
} }
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
MGLOG_D("GetTexImage: Applying TempPixelStoreParameterSync (PACK)"); MGLOG_D("GetTexImage: Applying TempPixelStoreParameterSync (PACK)");
TempPixelStoreParameterSync tempPackParamsSync(false); TempPixelStoreParameterSync tempPackParamsSync(false);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
@@ -1404,7 +1405,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get()); auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
auto levelRange = textureMipmapObject->GetLevelRange(); auto& levelRange = textureMipmapObject->GetLevelRange();
MGLOG_D("GetTexImage: mipmap level range = [%d, %d)", levelRange.x(), levelRange.y()); MGLOG_D("GetTexImage: mipmap level range = [%d, %d)", levelRange.x(), levelRange.y());
if (level < levelRange.x() || level >= levelRange.y()) { if (level < levelRange.x() || level >= levelRange.y()) {
@@ -1421,7 +1422,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("GetTexImage: mip level %d size = %dx%d", level, size.x(), size.y()); MGLOG_D("GetTexImage: mip level %d size = %dx%d", level, size.x(), size.y());
// Handle PBO // Handle PBO
auto pixelPackBufferObject = auto& pixelPackBufferObject =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject(); MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
Bool usePBO; Bool usePBO;
GLuint prevPixelPackBuffer = 0; GLuint prevPixelPackBuffer = 0;
@@ -1429,7 +1430,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
BufferImpl::CreateAndSyncBufferObject(pixelPackBufferObject); BufferImpl::CreateAndSyncBufferObject(pixelPackBufferObject);
MGLOG_D("GetTexImage: Using PBO %u", pixelPackBufferObject->GetExternalIndex()); MGLOG_D("GetTexImage: Using PBO %u", pixelPackBufferObject->GetExternalIndex());
usePBO = true; usePBO = true;
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(pixelPackBufferObject); const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(pixelPackBufferObject.get());
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) { if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
MGLOG_E("GetTexImage: No backend buffer found for PBO %u.", MGLOG_E("GetTexImage: No backend buffer found for PBO %u.",
pixelPackBufferObject ? pixelPackBufferObject->GetExternalIndex() : 0); pixelPackBufferObject ? pixelPackBufferObject->GetExternalIndex() : 0);
@@ -1443,7 +1444,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("GetTexImage: Not using PBO"); MGLOG_D("GetTexImage: Not using PBO");
} }
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
MGLOG_D("GetTexImage: glReadPixels(0, 0, %d, %d, %s, %s, %p)", size.x(), size.y(), MGLOG_D("GetTexImage: glReadPixels(0, 0, %d, %d, %s, %s, %p)", size.x(), size.y(),
@@ -1451,14 +1452,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
pixels); pixels);
g_GLESFuncs.glReadPixels(0, 0, size.x(), size.y(), esFormat, esType, pixels); g_GLESFuncs.glReadPixels(0, 0, size.x(), size.y(), esFormat, esType, pixels);
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
if (usePBO) { if (usePBO) {
// pull back to client memory if PBO is used // pull back to client memory if PBO is used
MGLOG_D("ReadPixels: PBO used, mapping buffer to client memory"); MGLOG_D("ReadPixels: PBO used, mapping buffer to client memory");
GLvoid* pboMappedPtr = g_GLESFuncs.glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, GLvoid* pboMappedPtr = g_GLESFuncs.glMapBufferRange(
pixelPackBufferObject->GetSize(), GL_MAP_READ_BIT); GL_PIXEL_PACK_BUFFER, 0, (GLsizeiptr)pixelPackBufferObject->GetSize(), GL_MAP_READ_BIT);
if (pboMappedPtr) { if (pboMappedPtr) {
MGLOG_D("ReadPixels: Copying data from PBO to client memory"); MGLOG_D("ReadPixels: Copying data from PBO to client memory");
SizeT size = pixelPackBufferObject->GetSize(); SizeT size = pixelPackBufferObject->GetSize();
@@ -1479,7 +1480,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
MGLOG_D("GetTexImage: finished"); MGLOG_D("GetTexImage: finished");
+101 -96
View File
@@ -7,10 +7,6 @@
// End of Source File Header // End of Source File Header
#include "Managers.h" #include "Managers.h"
#include "MG_State/GLState/TextureState/TextureEnum.h"
#include "MG_State/GLState/TextureState/TextureObject.h"
#include "MG_State/GLState/TextureState/TextureState.h"
#include "MG_Util/Converters/GLToMG/TextureEnumConverter.h"
#include "Utils.h" #include "Utils.h"
#include "DirectGLES.h" #include "DirectGLES.h"
@@ -18,6 +14,7 @@
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h> #include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/MGToGL/DataTypeConverter.h> #include <MG_Util/Converters/MGToGL/DataTypeConverter.h>
#include <MG_Util/Converters/MGToGL/BufferEnumConverter.h> #include <MG_Util/Converters/MGToGL/BufferEnumConverter.h>
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h> #include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h>
#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>
@@ -44,7 +41,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void BackendBufferObject::SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) { void BackendBufferObject::SyncToBackend(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -105,7 +102,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
void BackendBufferObject::SyncToBackend_glBufferData( void BackendBufferObject::SyncToBackend_glBufferData(
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) { const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -117,11 +114,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
GLenum usage = MG_Util::ConvertBufferUsageToGLEnum(stateBufferObject->GetUsage()); GLenum usage = MG_Util::ConvertBufferUsageToGLEnum(stateBufferObject->GetUsage());
Bind(); Bind();
g_GLESFuncs.glBufferData(TempBufferTarget, size, data, usage); g_GLESFuncs.glBufferData(TempBufferTarget, (GLsizeiptr)size, data, usage);
} }
void BackendBufferObject::SyncToBackend_glBufferSubData( void BackendBufferObject::SyncToBackend_glBufferSubData(
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) { const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -130,7 +127,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
const void* data = stateBufferObject->GetDataReadOnly()->data(); const void* data = stateBufferObject->GetDataReadOnly()->data();
// dirty range: [range.start, range.end) // dirty range: [range.start, range.end)
auto ranges = stateBufferObject->GetDirtyRanges(); auto& ranges = stateBufferObject->GetDirtyRanges();
if (ranges.empty()) { if (ranges.empty()) {
MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId); MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId);
return; return;
@@ -138,20 +135,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
for (const auto& range : ranges) { for (const auto& range : ranges) {
Bind(); Bind();
g_GLESFuncs.glBufferSubData(TempBufferTarget, range.start, range.end - range.start, g_GLESFuncs.glBufferSubData(TempBufferTarget, (GLintptr)range.start,
(GLintptr)(range.end - range.start),
reinterpret_cast<const char*>(data) + range.start); reinterpret_cast<const char*>(data) + range.start);
} }
} }
void BackendBufferObject::SyncToBackend_glMapBufferRange( void BackendBufferObject::SyncToBackend_glMapBufferRange(
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, Bool invalidate, Bool unsynchronized) { const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, Bool invalidate, Bool unsynchronized) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
MGLOG_D("Syncing buffer map (glMapBuffer) for object with ID : %u", m_backendBufferId); MGLOG_D("Syncing buffer map (glMapBuffer) for object with ID : %u", m_backendBufferId);
MGLOG_D("Mapping buffer with ID: %u", m_backendBufferId); MGLOG_D("Mapping buffer with ID: %u", m_backendBufferId);
auto ranges = stateBufferObject->GetDirtyRanges(); auto& ranges = stateBufferObject->GetDirtyRanges();
if (ranges.empty()) { if (ranges.empty()) {
MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId); MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId);
return; return;
@@ -159,9 +157,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
SizeT minStart = ranges.GetOverallMinStart(); SizeT minStart = ranges.GetOverallMinStart();
SizeT maxEnd = ranges.GetOverallMaxEnd(); SizeT maxEnd = ranges.GetOverallMaxEnd();
Bind(); Bind();
void* mappedData = g_GLESFuncs.glMapBufferRange(TempBufferTarget, minStart, maxEnd - minStart, void* mappedData = g_GLESFuncs.glMapBufferRange(
(invalidate ? GL_MAP_INVALIDATE_RANGE_BIT : 0) | TempBufferTarget, (GLintptr)minStart, (GLintptr)(maxEnd - minStart),
(unsynchronized ? GL_MAP_UNSYNCHRONIZED_BIT : 0) | (invalidate ? GL_MAP_INVALIDATE_RANGE_BIT : 0) | (unsynchronized ? GL_MAP_UNSYNCHRONIZED_BIT : 0) |
GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
const void* data = stateBufferObject->GetDataReadOnly()->data(); const void* data = stateBufferObject->GetDataReadOnly()->data();
if (mappedData) { if (mappedData) {
@@ -169,8 +167,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
Memcpy(mappedData, reinterpret_cast<const char*>(data) + minStart, maxEnd - minStart); Memcpy(mappedData, reinterpret_cast<const char*>(data) + minStart, maxEnd - minStart);
// Explicitly flush the dirty ranges // Explicitly flush the dirty ranges
for (const auto& range : ranges) { for (const auto& range : ranges) {
g_GLESFuncs.glFlushMappedBufferRange(TempBufferTarget, range.start - minStart, g_GLESFuncs.glFlushMappedBufferRange(TempBufferTarget, (GLintptr)(range.start - minStart),
range.end - range.start); (GLintptr)(range.end - range.start));
} }
g_GLESFuncs.glUnmapBuffer(TempBufferTarget); g_GLESFuncs.glUnmapBuffer(TempBufferTarget);
} else { } else {
@@ -191,7 +189,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glBindBuffer(target, m_backendBufferId); g_GLESFuncs.glBindBuffer(target, m_backendBufferId);
} }
UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>> g_backendBufferObjects; StateBackendObjectRegistry<MG_State::GLState::BufferObject, BackendBufferObject> g_backendBufferObjects;
BackendBufferObject* g_boundVertexBufferObject = nullptr; BackendBufferObject* g_boundVertexBufferObject = nullptr;
} // namespace BufferImpl } // namespace BufferImpl
@@ -209,22 +207,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void BackendVertexArrayObject::Bind() { void BackendVertexArrayObject::Bind() const {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
g_GLESFuncs.glBindVertexArray(m_backendVAOId); g_GLESFuncs.glBindVertexArray(m_backendVAOId);
} }
void BackendVertexArrayObject::BindAttributeBuffer(Uint index, inline void BindAttributeBuffer(const MG_State::GLState::VertexAttribute& attrib) {
const MG_State::GLState::VertexAttribute& attrib) {
const auto& bufferObject = attrib.Buffer; const auto& bufferObject = attrib.Buffer;
if (!bufferObject) { if (!bufferObject) {
MGLOG_W("Attribute has no bound buffer, skipping."); MGLOG_W("Attribute has no bound buffer, skipping.");
return; return;
} }
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObject); const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObject.get());
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) { if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
MGLOG_E("No backend buffer found for attribute's buffer, cannot bind attribute."); MGLOG_E("No backend buffer found for attribute's buffer, cannot bind attribute.");
return; return;
@@ -234,7 +231,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
backendBufferObject->Bind(GL_ARRAY_BUFFER); backendBufferObject->Bind(GL_ARRAY_BUFFER);
} }
void BackendVertexArrayObject::SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject) { void BackendVertexArrayObject::SyncToBackend(
const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -268,7 +266,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
m_syncedAttributeVersions[attribIndex].BufferVersion; m_syncedAttributeVersions[attribIndex].BufferVersion;
if (!needsSyncFormat && !needsSyncBuffer) continue; if (!needsSyncFormat && !needsSyncBuffer) continue;
BindAttributeBuffer(attribIndex, attrib); BindAttributeBuffer(attrib);
if (!attrib.IsInteger) { if (!attrib.IsInteger) {
g_GLESFuncs.glVertexAttribPointer( g_GLESFuncs.glVertexAttribPointer(
@@ -289,7 +287,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
if (currentIndexBufferVersion != m_syncedIndexBufferVersion) { if (currentIndexBufferVersion != m_syncedIndexBufferVersion) {
const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject(); const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
if (indexBufferBinding) { if (indexBufferBinding) {
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding); const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding.get());
if (backendBufferIt != BufferImpl::g_backendBufferObjects.end()) { if (backendBufferIt != BufferImpl::g_backendBufferObjects.end()) {
const auto& backendBufferObject = backendBufferIt->second; const auto& backendBufferObject = backendBufferIt->second;
backendBufferObject->Bind(GL_ELEMENT_ARRAY_BUFFER); backendBufferObject->Bind(GL_ELEMENT_ARRAY_BUFFER);
@@ -303,7 +301,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
m_syncedAttributeVersions = allAttributeVersions; m_syncedAttributeVersions = allAttributeVersions;
} }
UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>> StateBackendObjectRegistry<MG_State::GLState::VertexArrayObject, BackendVertexArrayObject>
g_backendVertexArrayObjects; g_backendVertexArrayObjects;
} // namespace VertexArrayImpl } // namespace VertexArrayImpl
@@ -336,7 +334,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_boundTexturesCache[unit][targetN] = this; g_boundTexturesCache[unit][targetN] = this;
} }
Uint BackendTextureObject::GetBackendTextureId() { Uint BackendTextureObject::GetBackendTextureId() const {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -344,7 +342,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
void BackendTextureObject::SyncMipmapsToBackend( void BackendTextureObject::SyncMipmapsToBackend(
SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) { const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
if (!stateTextureObject) { if (!stateTextureObject) {
MGLOG_E("State texture object is null, cannot sync to backend."); MGLOG_E("State texture object is null, cannot sync to backend.");
return; return;
@@ -353,7 +351,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
DebugImpl::ErrorLopper errorLopper;
MGLOG_D("Syncing texture mipmaps with backend ID %u to backend for state ID %u", m_backendTextureId, MGLOG_D("Syncing texture mipmaps with backend ID %u to backend for state ID %u", m_backendTextureId,
stateTextureObject->GetExternalIndex()); stateTextureObject->GetExternalIndex());
@@ -381,7 +378,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
Bind(target); Bind(target);
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
const auto baseSize = stateTextureObject->GetBaseSize(); const auto baseSize = stateTextureObject->GetBaseSize();
@@ -414,7 +411,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
&glFormat, &glType); &glFormat, &glType);
const auto& uploadTargets = textureMipmapObject->GetUploadTargets(); const auto& uploadTargets = textureMipmapObject->GetUploadTargets();
for (auto uploadTarget : uploadTargets) { for (auto& uploadTarget : uploadTargets) {
for (SizeT level = 0; level < mipmapCount; ++level) { for (SizeT level = 0; level < mipmapCount; ++level) {
auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level); auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
auto levelByteSize = textureMipmapObject->GetMipmapByteSize(uploadTarget, level); auto levelByteSize = textureMipmapObject->GetMipmapByteSize(uploadTarget, level);
@@ -429,22 +426,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData, levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData,
levelDirty ? "true" : "false"); levelDirty ? "true" : "false");
errorLopper.Clear(); DebugImpl::ErrorLopper::Clear();
g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
auto textureTarget = stateTextureObject->GetTarget(); auto textureTarget = stateTextureObject->GetTarget();
// TODO: handle more texture types // TODO: handle more texture types
switch (textureTarget) { switch (textureTarget) {
case TextureTarget::Texture2D: case TextureTarget::Texture2D:
case TextureTarget::TextureCubeMap: { case TextureTarget::TextureCubeMap: {
g_GLESFuncs.glTexImage2D(glUploadTarget, static_cast<GLint>(level), glInternalFormat, g_GLESFuncs.glTexImage2D(
static_cast<GLsizei>(levelTexelSize.x()), glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat,
static_cast<GLsizei>(levelTexelSize.y()), 0, glFormat, glType, static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
pData); 0, glFormat, glType, pData);
break; break;
} }
case TextureTarget::Texture3D: { case TextureTarget::Texture3D: {
g_GLESFuncs.glTexImage3D( g_GLESFuncs.glTexImage3D(
glUploadTarget, static_cast<GLint>(level), glInternalFormat, glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat,
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()), static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
static_cast<GLsizei>(levelTexelSize.z()), 0, glFormat, glType, pData); static_cast<GLsizei>(levelTexelSize.z()), 0, glFormat, glType, pData);
break; break;
@@ -454,8 +451,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
MG_Util::ConvertTextureTargetToString(textureTarget).c_str()); MG_Util::ConvertTextureTargetToString(textureTarget).c_str());
} }
} }
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, glUploadTarget, DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__,
glInternalFormat, glFormat, glType, pData](GLenum err) { glUploadTarget, glInternalFormat, glFormat, glType,
pData](GLenum err) {
MGLOG_D("%s(%s:%d) ES error: %s. glTexImage*: target=%s, internalformat=%s, format=%s, " MGLOG_D("%s(%s:%d) ES error: %s. glTexImage*: target=%s, internalformat=%s, format=%s, "
"type=%s, pixels=%p", "type=%s, pixels=%p",
func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(), func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(),
@@ -478,7 +476,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat, TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat,
&glFormat, &glType); &glFormat, &glType);
const auto& uploadTargets = textureMipmapObject->GetUploadTargets(); const auto& uploadTargets = textureMipmapObject->GetUploadTargets();
for (auto uploadTarget : uploadTargets) { for (auto& uploadTarget : uploadTargets) {
for (SizeT level = 0; level < mipmapCount; ++level) { for (SizeT level = 0; level < mipmapCount; ++level) {
if (!textureMipmapObject->IsStorageDirty(uploadTarget, level)) { if (!textureMipmapObject->IsStorageDirty(uploadTarget, level)) {
continue; continue;
@@ -499,7 +497,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
auto glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget); auto glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget);
g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { DebugImpl::ErrorLopper::Loop(
[file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MGLOG_D("%s(%s:%d) ES error: %s", func, file, line,
MG_Util::ConvertGLEnumToString(err).c_str()); MG_Util::ConvertGLEnumToString(err).c_str());
}); });
@@ -518,7 +517,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
auto* textureBufferObject = auto* textureBufferObject =
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();
auto bufferIndex = buffer->GetExternalIndex(); auto bufferIndex = buffer->GetExternalIndex();
currentTextureInfo.bufferExternalIndex = bufferIndex; currentTextureInfo.bufferExternalIndex = bufferIndex;
@@ -530,10 +529,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
// 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;
SharedPtr<BufferImpl::BackendBufferObject> backendBufferObject; SharedPtr<BufferImpl::BackendBufferObject> backendBufferObject;
const auto& backendBufferIt = backendBuffers.find(buffer); const auto& backendBufferIt = backendBuffers.find(buffer.get());
if (backendBufferIt == backendBuffers.end()) { if (backendBufferIt == backendBuffers.end()) {
backendBufferObject = MakeShared<BufferImpl::BackendBufferObject>(); auto& backendBufferSlot = backendBuffers.GetOrCreate(buffer);
backendBuffers[buffer] = backendBufferObject; if (!backendBufferSlot) {
backendBufferSlot = MakeShared<BufferImpl::BackendBufferObject>();
}
backendBufferObject = backendBufferSlot;
} else { } else {
backendBufferObject = backendBufferIt->second; backendBufferObject = backendBufferIt->second;
} }
@@ -553,7 +555,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
THROW_UNIMPL_EXCEPTION; THROW_UNIMPL_EXCEPTION;
} }
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
@@ -561,11 +563,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
void BackendTextureObject::SyncBuiltinSamplerToBackend( void BackendTextureObject::SyncBuiltinSamplerToBackend(
SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) { const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
DebugImpl::ErrorLopper errorLopper;
if (!stateTextureObject) { if (!stateTextureObject) {
MGLOG_E("State texture object is null, cannot sync to backend."); MGLOG_E("State texture object is null, cannot sync to backend.");
return; return;
@@ -594,7 +596,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
Bind(target); Bind(target);
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
@@ -607,7 +609,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glTexParameteri(target, glName, \ g_GLESFuncs.glTexParameteri(target, glName, \
MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)); \ MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)); \
m_cacheSamplerParameters.internalName = samplerParams.internalName; \ m_cacheSamplerParameters.internalName = samplerParams.internalName; \
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, \ DebugImpl::ErrorLopper::Loop( \
[file = __FILE__, line = __LINE__, func = __func__, \
t = MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)](GLenum err) { \ t = MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)](GLenum err) { \
MGLOG_D("%s(%s:%d) ES error %s, GL_TEXTURE_MIN_FILTER = %s", func, file, line, \ MGLOG_D("%s(%s:%d) ES error %s, GL_TEXTURE_MIN_FILTER = %s", func, file, line, \
MG_Util::ConvertGLEnumToString(err).c_str(), MG_Util::ConvertGLEnumToString(t).c_str()); \ MG_Util::ConvertGLEnumToString(err).c_str(), MG_Util::ConvertGLEnumToString(t).c_str()); \
@@ -616,19 +619,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
if (m_cacheSamplerParameters.minFilter != samplerParams.minFilter || if (m_cacheSamplerParameters.minFilter != samplerParams.minFilter ||
m_cacheSamplerParameters.mipmapMode != samplerParams.mipmapMode) { m_cacheSamplerParameters.mipmapMode != samplerParams.mipmapMode) {
g_GLESFuncs.glTexParameteri( g_GLESFuncs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER,
target, GL_TEXTURE_MIN_FILTER, (GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.minFilter,
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.minFilter, samplerParams.mipmapMode)); samplerParams.mipmapMode));
m_cacheSamplerParameters.minFilter = samplerParams.minFilter; m_cacheSamplerParameters.minFilter = samplerParams.minFilter;
m_cacheSamplerParameters.mipmapMode = samplerParams.mipmapMode; m_cacheSamplerParameters.mipmapMode = samplerParams.mipmapMode;
} }
if (m_cacheSamplerParameters.magFilter != samplerParams.magFilter) { if (m_cacheSamplerParameters.magFilter != samplerParams.magFilter) {
g_GLESFuncs.glTexParameteri( g_GLESFuncs.glTexParameteri(
target, GL_TEXTURE_MAG_FILTER, target, GL_TEXTURE_MAG_FILTER,
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None)); (GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None));
m_cacheSamplerParameters.magFilter = samplerParams.magFilter; m_cacheSamplerParameters.magFilter = samplerParams.magFilter;
} }
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
@@ -645,18 +648,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glTexParameterf(target, GL_TEXTURE_MAX_LOD, samplerParams.maxLod); g_GLESFuncs.glTexParameterf(target, GL_TEXTURE_MAX_LOD, samplerParams.maxLod);
m_cacheSamplerParameters.maxLod = samplerParams.maxLod; m_cacheSamplerParameters.maxLod = samplerParams.maxLod;
} }
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
#undef SYNC_TEX_SAMPLER_PARAM_IF_CHANGED #undef SYNC_TEX_SAMPLER_PARAM_IF_CHANGED
} }
void BackendTextureObject::SyncTextureParamsToBackend( void BackendTextureObject::SyncTextureParamsToBackend(
SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) { const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
DebugImpl::ErrorLopper errorLopper;
if (!stateTextureObject) { if (!stateTextureObject) {
MGLOG_E("State texture object is null, cannot sync to backend."); MGLOG_E("State texture object is null, cannot sync to backend.");
return; return;
@@ -683,7 +686,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
Bind(target); Bind(target);
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
@@ -696,14 +699,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, static_cast<GLint>(levelRange.x())); g_GLESFuncs.glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, static_cast<GLint>(levelRange.x()));
m_cacheLodRange.x() = levelRange.x(); m_cacheLodRange.x() = levelRange.x();
} }
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
if (m_cacheLodRange.y() != levelRange.y()) { if (m_cacheLodRange.y() != levelRange.y()) {
g_GLESFuncs.glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(levelRange.y())); g_GLESFuncs.glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(levelRange.y()));
m_cacheLodRange.y() = levelRange.y(); m_cacheLodRange.y() = levelRange.y();
} }
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
@@ -720,7 +723,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
SYNC_TEX_SWIZZLE_PARAM_IF_CHANGED(a(), GL_TEXTURE_SWIZZLE_A); SYNC_TEX_SWIZZLE_PARAM_IF_CHANGED(a(), GL_TEXTURE_SWIZZLE_A);
#undef SYNC_TEX_SWIZZLE_PARAM_IF_CHANGED #undef SYNC_TEX_SWIZZLE_PARAM_IF_CHANGED
m_cacheSwizzleParams = swizzleParams; m_cacheSwizzleParams = swizzleParams;
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
} }
@@ -730,7 +733,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
GLfloat borderColorArray[4] = {borderColor.x(), borderColor.y(), borderColor.z(), borderColor.w()}; GLfloat borderColorArray[4] = {borderColor.x(), borderColor.y(), borderColor.z(), borderColor.w()};
g_GLESFuncs.glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, borderColorArray); g_GLESFuncs.glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, borderColorArray);
m_cacheBorderColor = borderColor; m_cacheBorderColor = borderColor;
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
} }
@@ -760,8 +763,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>, Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS> MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
g_boundTexturesCache; g_boundTexturesCache;
UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>> StateBackendObjectRegistry<MG_State::GLState::ITextureObject, BackendTextureObject> g_backendTextureObjects;
g_backendTextureObjects;
} // namespace TextureImpl } // namespace TextureImpl
namespace FramebufferImpl { namespace FramebufferImpl {
@@ -778,7 +780,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void BackendFramebufferObject::Bind(FramebufferTarget target) { void BackendFramebufferObject::Bind(FramebufferTarget target) const {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -788,12 +790,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId); g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId);
} }
Bool BackendFramebufferObject::SyncAttachmentObject( static Bool SyncAttachmentObject(GLenum glFBOTarget,
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();
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject); const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) { if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
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;
@@ -807,11 +809,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
} else if (attachmentObject.IsRenderbuffer()) { } else if (attachmentObject.IsRenderbuffer()) {
const auto& renderbufferObject = attachmentObject.GetRenderbuffer(); const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
const auto& backendRenderbufferIt = const auto& backendRenderbufferIt =
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject); RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject.get());
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject; SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) { if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
backendRenderbufferObject = MakeShared<RenderbufferImpl::BackendRenderbufferObject>(); auto& backendRenderbufferSlot =
RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject; RenderbufferImpl::g_backendRenderbufferObjects.GetOrCreate(renderbufferObject);
if (!backendRenderbufferSlot) {
backendRenderbufferSlot = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
}
backendRenderbufferObject = backendRenderbufferSlot;
} else { } else {
backendRenderbufferObject = backendRenderbufferIt->second; backendRenderbufferObject = backendRenderbufferIt->second;
} }
@@ -824,8 +830,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
return true; return true;
} }
void BackendFramebufferObject::SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, void BackendFramebufferObject::SyncToBackend(
FramebufferTarget asTarget) { const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, FramebufferTarget asTarget) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -853,7 +859,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
std::fill(m_backendDrawBuffers, m_backendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE); std::fill(m_backendDrawBuffers, m_backendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE);
int nEffectiveBuffers = 0; int nEffectiveBuffers = 0;
for (GLint i = 0; i < FramebufferObject::MAX_DRAW_BUFFERS; ++i) { for (GLint i = 0; i < FramebufferObject::MAX_DRAW_BUFFERS; ++i) {
auto frontendBuf = stateDrawBuffers[i]; auto& frontendBuf = stateDrawBuffers[i];
if (frontendBuf == FramebufferAttachmentType::None) { if (frontendBuf == FramebufferAttachmentType::None) {
m_backendDrawBuffers[i] = GL_NONE; m_backendDrawBuffers[i] = GL_NONE;
continue; continue;
@@ -892,7 +898,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
const auto& attachmentVersions = stateFBOObject->GetAllFramebufferAttachmentVersions(); const auto& attachmentVersions = stateFBOObject->GetAllFramebufferAttachmentVersions();
for (SizeT i = 0; i < attachments.size(); ++i) { for (SizeT i = 0; i < attachments.size(); ++i) {
const auto& attachmentObject = attachments[i]; const auto& attachmentObject = attachments[i];
FramebufferAttachmentType frontendType = static_cast<FramebufferAttachmentType>(i); auto frontendType = static_cast<FramebufferAttachmentType>(i);
GLenum glBackendAttachment = GL_NONE; GLenum glBackendAttachment = GL_NONE;
if (frontendType >= FramebufferAttachmentType::Color0 && if (frontendType >= FramebufferAttachmentType::Color0 &&
frontendType <= FramebufferAttachmentType::Color31) frontendType <= FramebufferAttachmentType::Color31)
@@ -928,7 +934,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
// Verify that the backend object's name and parameters match the frontend attachment state // Verify that the backend object's name and parameters match the frontend attachment state
if (attachmentObject.IsTexture()) { if (attachmentObject.IsTexture()) {
const auto& textureObject = attachmentObject.GetTexture(); const auto& textureObject = attachmentObject.GetTexture();
auto backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject); auto backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
MOBILEGL_ASSERT(backendTextureIt != TextureImpl::g_backendTextureObjects.end(), MOBILEGL_ASSERT(backendTextureIt != TextureImpl::g_backendTextureObjects.end(),
"No backend texture found while framebuffer reports texture attachment."); "No backend texture found while framebuffer reports texture attachment.");
GLuint backendTexId = backendTextureIt->second->GetBackendTextureId(); GLuint backendTexId = backendTextureIt->second->GetBackendTextureId();
@@ -944,7 +950,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
"Attachment texture level mismatch between GLES and state object."); "Attachment texture level mismatch between GLES and state object.");
} else if (attachmentObject.IsRenderbuffer()) { } else if (attachmentObject.IsRenderbuffer()) {
const auto& renderbufferObject = attachmentObject.GetRenderbuffer(); const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
auto backendRboIt = RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject); auto backendRboIt =
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject.get());
MOBILEGL_ASSERT( MOBILEGL_ASSERT(
backendRboIt != RenderbufferImpl::g_backendRenderbufferObjects.end(), backendRboIt != RenderbufferImpl::g_backendRenderbufferObjects.end(),
"No backend renderbuffer found while framebuffer reports renderbuffer attachment."); "No backend renderbuffer found while framebuffer reports renderbuffer attachment.");
@@ -975,14 +982,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
return glBackendReadBuffer; return glBackendReadBuffer;
} }
UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>> StateBackendObjectRegistry<MG_State::GLState::FramebufferObject, BackendFramebufferObject>
g_backendFramebufferObjects; g_backendFramebufferObjects;
Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions = {0}; Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions = {0};
} // namespace FramebufferImpl } // namespace FramebufferImpl
namespace PrgramImpl { namespace PrgramImpl {
UnorderedMap<SharedPtr<MG_State::GLState::ProgramObject>, SharedPtr<BackendProgramObjectImpl>> StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl> g_backendProgramObjects;
g_backendProgramObjects;
BackendProgramObjectImpl::BackendProgramObjectImpl() { BackendProgramObjectImpl::BackendProgramObjectImpl() {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
@@ -1008,7 +1014,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void BackendProgramObjectImpl::SyncToBackend(SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject) { void BackendProgramObjectImpl::SyncToBackend(
const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -1161,7 +1168,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("Program sync completed. backend ID %u", m_backendProgramId); MGLOG_D("Program sync completed. backend ID %u", m_backendProgramId);
} }
void BackendProgramObjectImpl::Use() { void BackendProgramObjectImpl::Use() const {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -1184,7 +1191,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void BackendSamplerObject::SyncToBackend(SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject) { void BackendSamplerObject::SyncToBackend(
const SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -1210,22 +1218,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
#define SYNC_SAMPLER_PARAM_IF_CHANGED(internalName, glName, type) \ #define SYNC_SAMPLER_PARAM_IF_CHANGED(internalName, glName, type) \
if (m_cacheSamplerParameters.internalName != samplerParams.internalName) { \ if (m_cacheSamplerParameters.internalName != samplerParams.internalName) { \
g_GLESFuncs.glSamplerParameteri(m_backendSamplerId, glName, \ g_GLESFuncs.glSamplerParameteri(m_backendSamplerId, glName, \
MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)); \ (GLint)MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)); \
m_cacheSamplerParameters.internalName = samplerParams.internalName; \ m_cacheSamplerParameters.internalName = samplerParams.internalName; \
} }
if (m_cacheSamplerParameters.minFilter != samplerParams.minFilter || if (m_cacheSamplerParameters.minFilter != samplerParams.minFilter ||
m_cacheSamplerParameters.mipmapMode != samplerParams.mipmapMode) { m_cacheSamplerParameters.mipmapMode != samplerParams.mipmapMode) {
g_GLESFuncs.glSamplerParameteri( g_GLESFuncs.glSamplerParameteri(m_backendSamplerId, GL_TEXTURE_MIN_FILTER,
m_backendSamplerId, GL_TEXTURE_MIN_FILTER, (GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.minFilter, samplerParams.mipmapMode)); samplerParams.minFilter, samplerParams.mipmapMode));
m_cacheSamplerParameters.minFilter = samplerParams.minFilter; m_cacheSamplerParameters.minFilter = samplerParams.minFilter;
m_cacheSamplerParameters.mipmapMode = samplerParams.mipmapMode; m_cacheSamplerParameters.mipmapMode = samplerParams.mipmapMode;
} }
if (m_cacheSamplerParameters.magFilter != samplerParams.magFilter) { if (m_cacheSamplerParameters.magFilter != samplerParams.magFilter) {
g_GLESFuncs.glSamplerParameteri( g_GLESFuncs.glSamplerParameteri(
m_backendSamplerId, GL_TEXTURE_MAG_FILTER, m_backendSamplerId, GL_TEXTURE_MAG_FILTER,
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None)); (GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None));
m_cacheSamplerParameters.magFilter = samplerParams.magFilter; m_cacheSamplerParameters.magFilter = samplerParams.magFilter;
} }
@@ -1256,7 +1264,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_boundSamplersCache[unit] = this; g_boundSamplersCache[unit] = this;
} }
Uint BackendSamplerObject::GetBackendSamplerId() { Uint BackendSamplerObject::GetBackendSamplerId() const {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -1271,8 +1279,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS> g_boundSamplersCache; Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS> g_boundSamplersCache;
UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>> StateBackendObjectRegistry<MG_State::GLState::SamplerObject, BackendSamplerObject> g_backendSamplerObjects;
g_backendSamplerObjects;
} // namespace SamplerImpl } // namespace SamplerImpl
namespace RenderbufferImpl { namespace RenderbufferImpl {
@@ -1287,7 +1294,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void BackendRenderbufferObject::Bind() { void BackendRenderbufferObject::Bind() const {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -1334,9 +1341,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("RBO %u sync completed. backend ID %u", stateRBOObject->GetExternalIndex(), m_backendRBOId); MGLOG_D("RBO %u sync completed. backend ID %u", stateRBOObject->GetExternalIndex(), m_backendRBOId);
} }
UnorderedMap<SharedPtr<MG_State::GLState::RenderbufferObject>, SharedPtr<BackendRenderbufferObject>> StateBackendObjectRegistry<MG_State::GLState::RenderbufferObject, BackendRenderbufferObject>
g_backendRenderbufferObjects; g_backendRenderbufferObjects;
} // namespace RenderbufferImpl } // namespace RenderbufferImpl
namespace Utils {} // namespace Utils
} // namespace MobileGL::MG_Backend::DirectGLES } // namespace MobileGL::MG_Backend::DirectGLES
+122 -34
View File
@@ -15,19 +15,113 @@
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
namespace MobileGL::MG_Backend::DirectGLES { namespace MobileGL::MG_Backend::DirectGLES {
template <typename StateObject, typename BackendObject>
class StateBackendObjectRegistry {
public:
using StatePtr = SharedPtr<StateObject>;
using StateWeakPtr = std::weak_ptr<StateObject>;
using BackendPtr = SharedPtr<BackendObject>;
using BackendMap = UnorderedMap<StateObject*, BackendPtr>;
using StateRefMap = UnorderedMap<StateObject*, StateWeakPtr>;
using iterator = typename BackendMap::iterator;
using const_iterator = typename BackendMap::const_iterator;
BackendPtr& GetOrCreate(const StatePtr& stateObj) {
MOBILEGL_ASSERT(stateObj != nullptr, "State object must not be null");
auto* key = stateObj.get();
auto trackedStateIt = m_stateRefs.find(key);
if (trackedStateIt != m_stateRefs.end() && trackedStateIt->second.expired()) {
EraseByKey(key);
}
m_stateRefs[key] = stateObj;
return m_backendObjects[key];
}
iterator find(StateObject* stateObj) {
if (!IsAlive(stateObj)) {
EraseByKey(stateObj);
return m_backendObjects.end();
}
return m_backendObjects.find(stateObj);
}
const_iterator find(StateObject* stateObj) const {
return const_cast<StateBackendObjectRegistry*>(this)->find(stateObj);
}
iterator end() { return m_backendObjects.end(); }
const_iterator end() const { return m_backendObjects.end(); }
void CollectGarbageIfNeeded() {
++m_gcTick;
if (m_gcTick < kGCInterval) {
return;
}
CollectGarbage();
m_gcTick = 0;
}
void CollectGarbageNow() { CollectGarbage(); }
private:
bool IsAlive(StateObject* stateObj) const {
const auto trackedStateIt = m_stateRefs.find(stateObj);
if (trackedStateIt == m_stateRefs.end()) {
return false;
}
return !trackedStateIt->second.expired();
}
void EraseByKey(StateObject* stateObj) {
m_stateRefs.erase(stateObj);
m_backendObjects.erase(stateObj);
}
void CollectGarbage() {
if (m_isCollecting) {
return;
}
m_isCollecting = true;
Vector<StateObject*> staleKeys;
staleKeys.reserve(m_stateRefs.size());
for (const auto& [stateKey, stateWeakRef] : m_stateRefs) {
if (stateWeakRef.expired()) {
staleKeys.push_back(stateKey);
}
}
for (auto* stateKey : staleKeys) {
m_stateRefs.erase(stateKey);
m_backendObjects.erase(stateKey);
}
m_isCollecting = false;
}
private:
static constexpr Uint32 kGCInterval = 1024;
StateRefMap m_stateRefs;
BackendMap m_backendObjects;
Uint32 m_gcTick = 0;
Bool m_isCollecting = false;
};
namespace BufferImpl { namespace BufferImpl {
const GLenum TempBufferTarget = GL_ARRAY_BUFFER; const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
class BackendBufferObject { class BackendBufferObject {
public: public:
BackendBufferObject(); BackendBufferObject();
void SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject); void SyncToBackend(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
Uint GetBackendBufferId() { return m_backendBufferId; } Uint GetBackendBufferId() const { return m_backendBufferId; }
void Bind(GLenum target = TempBufferTarget); void Bind(GLenum target = TempBufferTarget);
private: private:
void SyncToBackend_glBufferData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject); void SyncToBackend_glBufferData(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
void SyncToBackend_glBufferSubData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject); void SyncToBackend_glBufferSubData(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
void SyncToBackend_glMapBufferRange(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, void SyncToBackend_glMapBufferRange(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject,
Bool invalidate = true, Bool unsynchronized = true); Bool invalidate = true, Bool unsynchronized = true);
Uint m_backendBufferId = 0; Uint m_backendBufferId = 0;
@@ -36,21 +130,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
}; };
extern BackendBufferObject* g_boundVertexBufferObject; extern BackendBufferObject* g_boundVertexBufferObject;
extern UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>> extern StateBackendObjectRegistry<MG_State::GLState::BufferObject, BackendBufferObject> g_backendBufferObjects;
g_backendBufferObjects;
} // namespace BufferImpl } // namespace BufferImpl
namespace VertexArrayImpl { namespace VertexArrayImpl {
class BackendVertexArrayObject { class BackendVertexArrayObject {
public: public:
BackendVertexArrayObject(); BackendVertexArrayObject();
void SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject); void SyncToBackend(const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
Uint GetBackendVertexArrayId() { return m_backendVAOId; } Uint GetBackendVertexArrayId() const { return m_backendVAOId; }
void Bind(); void Bind() const;
private: private:
void BindAttributeBuffer(Uint index, const MG_State::GLState::VertexAttribute& attrib);
Uint m_backendVAOId = 0; Uint m_backendVAOId = 0;
Bool m_isInitialized = false; Bool m_isInitialized = false;
Uint16 m_syncedIndexBufferVersion = 0; Uint16 m_syncedIndexBufferVersion = 0;
@@ -58,7 +149,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
m_syncedAttributeVersions; m_syncedAttributeVersions;
}; };
extern UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>> extern StateBackendObjectRegistry<MG_State::GLState::VertexArrayObject, BackendVertexArrayObject>
g_backendVertexArrayObjects; g_backendVertexArrayObjects;
} // namespace VertexArrayImpl } // namespace VertexArrayImpl
@@ -92,11 +183,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
class BackendTextureObject { class BackendTextureObject {
public: public:
BackendTextureObject(); BackendTextureObject();
void SyncMipmapsToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject); void SyncMipmapsToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
void SyncBuiltinSamplerToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject); void SyncBuiltinSamplerToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
void SyncTextureParamsToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject); void SyncTextureParamsToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
void Bind(GLenum target, Uint unit = TempTextureUnit); void Bind(GLenum target, Uint unit = TempTextureUnit);
Uint GetBackendTextureId(); Uint GetBackendTextureId() const;
private: private:
Uint m_backendTextureId = 0; Uint m_backendTextureId = 0;
@@ -113,7 +204,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
void ActivateTextureUnit(Uint unit); void ActivateTextureUnit(Uint unit);
void UnbindTexture(Uint unit, GLenum target); void UnbindTexture(Uint unit, GLenum target);
extern UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>> extern StateBackendObjectRegistry<MG_State::GLState::ITextureObject, BackendTextureObject>
g_backendTextureObjects; g_backendTextureObjects;
extern Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>, extern Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS> MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
@@ -125,13 +216,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
class BackendFramebufferObject { class BackendFramebufferObject {
public: public:
BackendFramebufferObject(); BackendFramebufferObject();
void SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, void SyncToBackend(const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
FramebufferTarget asTarget); FramebufferTarget asTarget);
Uint GetBackendFramebufferId() { return m_backendFBOId; } Uint GetBackendFramebufferId() const { return m_backendFBOId; }
void Bind(FramebufferTarget target); void Bind(FramebufferTarget target) const;
bool SyncAttachmentObject(GLenum glFBOTarget,
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
GLenum glBackendAttachment);
// FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index); // FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index);
GLenum GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const; GLenum GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const;
@@ -159,7 +247,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
FramebufferObject::FramebufferAttachmentVersionArray m_syncedFrontendAttachmentVersions = {0}; FramebufferObject::FramebufferAttachmentVersionArray m_syncedFrontendAttachmentVersions = {0};
}; };
extern UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>> extern StateBackendObjectRegistry<MG_State::GLState::FramebufferObject, BackendFramebufferObject>
g_backendFramebufferObjects; g_backendFramebufferObjects;
extern Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions; extern Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions;
} // namespace FramebufferImpl } // namespace FramebufferImpl
@@ -169,8 +257,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
public: public:
BackendProgramObjectImpl(); BackendProgramObjectImpl();
~BackendProgramObjectImpl(); ~BackendProgramObjectImpl();
void SyncToBackend(SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject); void SyncToBackend(const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject);
void Use(); void Use() 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; }
@@ -180,7 +268,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
Bool m_isInitialized = false; Bool m_isInitialized = false;
}; };
extern UnorderedMap<SharedPtr<MG_State::GLState::ProgramObject>, SharedPtr<BackendProgramObjectImpl>> extern StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl>
g_backendProgramObjects; g_backendProgramObjects;
} // namespace PrgramImpl } // namespace PrgramImpl
@@ -188,9 +276,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
class BackendSamplerObject { class BackendSamplerObject {
public: public:
BackendSamplerObject(); BackendSamplerObject();
void SyncToBackend(SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject); void SyncToBackend(const SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject);
void Bind(Uint unit); void Bind(Uint unit);
Uint GetBackendSamplerId(); Uint GetBackendSamplerId() const;
private: private:
Uint m_backendSamplerId = 0; Uint m_backendSamplerId = 0;
@@ -203,7 +291,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
extern Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS> extern Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
g_boundSamplersCache; g_boundSamplersCache;
extern UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>> extern StateBackendObjectRegistry<MG_State::GLState::SamplerObject, BackendSamplerObject>
g_backendSamplerObjects; g_backendSamplerObjects;
} // namespace SamplerImpl } // namespace SamplerImpl
@@ -212,8 +300,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
public: public:
BackendRenderbufferObject(); BackendRenderbufferObject();
void SyncToBackend(const SharedPtr<MG_State::GLState::RenderbufferObject>& stateRBOObject); void SyncToBackend(const SharedPtr<MG_State::GLState::RenderbufferObject>& stateRBOObject);
Uint GetBackendRenderbufferId() { return m_backendRBOId; } Uint GetBackendRenderbufferId() const { return m_backendRBOId; }
void Bind(); void Bind() const;
private: private:
Uint m_backendRBOId = 0; Uint m_backendRBOId = 0;
@@ -223,7 +311,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
Int m_cacheHeight = 0; Int m_cacheHeight = 0;
}; };
extern UnorderedMap<SharedPtr<MG_State::GLState::RenderbufferObject>, SharedPtr<BackendRenderbufferObject>> extern StateBackendObjectRegistry<MG_State::GLState::RenderbufferObject, BackendRenderbufferObject>
g_backendRenderbufferObjects; g_backendRenderbufferObjects;
} // namespace RenderbufferImpl } // namespace RenderbufferImpl
} // namespace MobileGL::MG_Backend::DirectGLES } // namespace MobileGL::MG_Backend::DirectGLES
-9
View File
@@ -19,10 +19,6 @@
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h> #include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
namespace MobileGL::MG_Backend::DirectGLES { namespace MobileGL::MG_Backend::DirectGLES {
namespace BufferImpl {} // namespace BufferImpl
namespace VertexArrayImpl {} // namespace VertexArrayImpl
namespace TextureImpl { namespace TextureImpl {
void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat, void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat,
GLenum* outFormat, GLenum* outType) { GLenum* outFormat, GLenum* outType) {
@@ -36,9 +32,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
outInternalFormat, outFormat, outType); outInternalFormat, outFormat, outType);
} }
} // namespace TextureImpl } // namespace TextureImpl
namespace FramebufferImpl {} // namespace FramebufferImpl
namespace PrgramImpl { namespace PrgramImpl {
String ProcessOutColorLocations(const String& glslCode) { String ProcessOutColorLocations(const String& glslCode) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
@@ -166,7 +159,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
return GL_UNIFORM_BUFFER_BINDING; return GL_UNIFORM_BUFFER_BINDING;
case GL_FRAMEBUFFER: case GL_FRAMEBUFFER:
return GL_FRAMEBUFFER_BINDING;
case GL_DRAW_FRAMEBUFFER: case GL_DRAW_FRAMEBUFFER:
return GL_DRAW_FRAMEBUFFER_BINDING; return GL_DRAW_FRAMEBUFFER_BINDING;
case GL_READ_FRAMEBUFFER: case GL_READ_FRAMEBUFFER:
@@ -176,7 +168,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
return GL_RENDERBUFFER_BINDING; return GL_RENDERBUFFER_BINDING;
case GL_VERTEX_ARRAY: case GL_VERTEX_ARRAY:
return GL_VERTEX_ARRAY_BINDING;
case GL_VERTEX_ARRAY_BINDING: case GL_VERTEX_ARRAY_BINDING:
return GL_VERTEX_ARRAY_BINDING; return GL_VERTEX_ARRAY_BINDING;
+3 -3
View File
@@ -14,15 +14,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
namespace DebugImpl { namespace DebugImpl {
class ErrorLopper { class ErrorLopper {
public: public:
void Loop(std::function<void(GLenum)>); static void Loop(const std::function<void(GLenum)>&);
void Clear(); static void Clear();
ErrorLopper(); ErrorLopper();
~ErrorLopper(); ~ErrorLopper();
}; };
class OpenGLScopeMarker { class OpenGLScopeMarker {
public: public:
explicit OpenGLScopeMarker(String scopeName); explicit OpenGLScopeMarker(const String& scopeName);
~OpenGLScopeMarker(); ~OpenGLScopeMarker();
}; };
} // namespace DebugImpl } // namespace DebugImpl
@@ -28,6 +28,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
auto nativeWindow = reinterpret_cast<NativeWindowType>(m_windowHandle.Handle); auto nativeWindow = reinterpret_cast<NativeWindowType>(m_windowHandle.Handle);
pVulkanRenderer = MakeUnique<MG_Backend::DirectVulkan::VulkanRenderer>(nativeWindow); pVulkanRenderer = MakeUnique<MG_Backend::DirectVulkan::VulkanRenderer>(nativeWindow);
MOBILEGL_ASSERT(pVulkanRenderer != nullptr, "InitWindowSurface: VulkanRenderer creation failed");
pVulkanRenderer->Initialize(); pVulkanRenderer->Initialize();
return true; return true;
} }
+20 -360
View File
@@ -17,165 +17,11 @@ 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 DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) { void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) {}
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsBaseVertex called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElementsBaseVertex called with null GL context");
if (count < 0) {
MGLOG_W("DrawElementsBaseVertex skipped: count (%d) must be non-negative", count);
return;
}
if (count == 0) {
return;
}
if (mode != GL_TRIANGLES) {
MGLOG_W("DrawElementsBaseVertex skipped: primitive mode %u is not supported yet", mode);
return;
}
SizeT indexSize = 0;
switch (type) {
case GL_UNSIGNED_SHORT:
indexSize = sizeof(Uint16);
break;
case GL_UNSIGNED_INT:
indexSize = sizeof(Uint32);
break;
default:
MGLOG_W("DrawElementsBaseVertex skipped: index type %u is not supported yet", type);
return;
}
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) {
MGLOG_W("DrawElementsBaseVertex skipped: no bound VAO");
return;
}
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
if (!indexBuffer) {
MGLOG_W("DrawElementsBaseVertex skipped: no bound ELEMENT_ARRAY_BUFFER");
return;
}
const auto indexData = indexBuffer->GetDataReadOnly();
if (!indexData || indexData->empty()) {
MGLOG_W("DrawElementsBaseVertex skipped: ELEMENT_ARRAY_BUFFER has no data");
return;
}
const SizeT byteOffset = reinterpret_cast<SizeT>(indices);
const SizeT requiredBytes = static_cast<SizeT>(count) * indexSize;
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
MGLOG_W("DrawElementsBaseVertex skipped: index range out of bounds (offset=%zu, size=%zu, buffer=%zu)",
byteOffset, requiredBytes, indexBuffer->GetSize());
return;
}
DrawElementPayload payload{};
payload.drawArray.mode = mode;
payload.drawArray.first = 0;
payload.drawArray.count = count;
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
payload.drawArray.vertexArray = vao.get();
payload.indexType = type;
payload.indexByteOffset = byteOffset;
payload.baseVertex = basevertex;
pVulkanRenderer->DrawElements(payload);
}
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices, void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount, const GLint* basevertex) { GLsizei drawcount, const GLint* basevertex) {}
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsBaseVertex called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElementsBaseVertex called with null GL context");
if (drawcount < 0) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: drawcount (%d) must be non-negative", drawcount);
return;
}
if (drawcount == 0) {
return;
}
if (!count || !indices || !basevertex) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: count/indices/basevertex pointer is null");
return;
}
if (mode != GL_TRIANGLES) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: primitive mode %u is not supported yet", mode);
return;
}
SizeT indexSize = 0;
switch (type) {
case GL_UNSIGNED_SHORT:
indexSize = sizeof(Uint16);
break;
case GL_UNSIGNED_INT:
indexSize = sizeof(Uint32);
break;
default:
MGLOG_W("MultiDrawElementsBaseVertex skipped: index type %u is not supported yet", type);
return;
}
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: no bound VAO");
return;
}
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
if (!indexBuffer) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: no bound ELEMENT_ARRAY_BUFFER");
return;
}
const auto indexData = indexBuffer->GetDataReadOnly();
if (!indexData || indexData->empty()) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: ELEMENT_ARRAY_BUFFER has no data");
return;
}
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
Vector<DrawElementPayload> payloads;
payloads.reserve(static_cast<SizeT>(drawcount));
for (GLsizei i = 0; i < drawcount; ++i) {
if (count[i] < 0) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: count[%d] (%d) must be non-negative", i, count[i]);
return;
}
if (count[i] == 0) {
continue;
}
const SizeT byteOffset = reinterpret_cast<SizeT>(indices[i]);
const SizeT requiredBytes = static_cast<SizeT>(count[i]) * indexSize;
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: draw[%d] index range out of bounds (offset=%zu, "
"size=%zu, buffer=%zu)",
i, byteOffset, requiredBytes, indexBuffer->GetSize());
return;
}
DrawElementPayload payload{};
payload.drawArray.mode = mode;
payload.drawArray.first = 0;
payload.drawArray.count = count[i];
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
payload.drawArray.vertexArray = vao.get();
payload.indexType = type;
payload.indexByteOffset = byteOffset;
payload.baseVertex = basevertex[i];
payloads.push_back(payload);
}
if (payloads.empty()) {
return;
}
pVulkanRenderer->MultiDrawElements(payloads);
}
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 DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
@@ -206,180 +52,44 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElements called with null GL context"); MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElements called with null GL context");
if (drawcount < 0) { Vector<DrawElementCmd> cmds;
MGLOG_W("MultiDrawElements skipped: drawcount (%d) must be non-negative", drawcount); cmds.reserve(static_cast<SizeT>(drawcount));
return;
}
if (drawcount == 0) {
return;
}
if (!count || !indices) {
MGLOG_W("MultiDrawElements skipped: count/indices pointer is null");
return;
}
if (mode != GL_TRIANGLES) {
MGLOG_W("MultiDrawElements skipped: primitive mode %u is not supported yet", mode);
return;
}
SizeT indexSize = 0;
switch (type) {
case GL_UNSIGNED_SHORT:
indexSize = sizeof(Uint16);
break;
case GL_UNSIGNED_INT:
indexSize = sizeof(Uint32);
break;
default:
MGLOG_W("MultiDrawElements skipped: index type %u is not supported yet", type);
return;
}
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) {
MGLOG_W("MultiDrawElements skipped: no bound VAO");
return;
}
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
if (!indexBuffer) {
MGLOG_W("MultiDrawElements skipped: no bound ELEMENT_ARRAY_BUFFER");
return;
}
const auto indexData = indexBuffer->GetDataReadOnly();
if (!indexData || indexData->empty()) {
MGLOG_W("MultiDrawElements skipped: ELEMENT_ARRAY_BUFFER has no data");
return;
}
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
Vector<DrawElementPayload> payloads;
payloads.reserve(static_cast<SizeT>(drawcount));
for (GLsizei i = 0; i < drawcount; ++i) { for (GLsizei i = 0; i < drawcount; ++i) {
if (count[i] < 0) {
MGLOG_W("MultiDrawElements skipped: count[%d] (%d) must be non-negative", i, count[i]);
return;
}
if (count[i] == 0) { if (count[i] == 0) {
continue; continue;
} }
const auto byteOffset = reinterpret_cast<SizeT>(indices[i]); DrawElementCmd payload{};
const SizeT requiredBytes = static_cast<SizeT>(count[i]) * indexSize; payload.mode = mode;
if (byteOffset + requiredBytes > indexBuffer->GetSize()) { payload.first = 0;
MGLOG_W("MultiDrawElements skipped: draw[%d] index range out of bounds (offset=%zu, size=%zu, " payload.count = count[i];
"buffer=%zu)",
i, byteOffset, requiredBytes, indexBuffer->GetSize());
return;
}
DrawElementPayload payload{};
payload.drawArray.mode = mode;
payload.drawArray.first = 0;
payload.drawArray.count = count[i];
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
payload.drawArray.vertexArray = vao.get();
payload.indexType = type; payload.indexType = type;
payload.indexByteOffset = byteOffset; payload.indexByteOffset = reinterpret_cast<SizeT>(indices[i]);
payloads.push_back(payload); cmds.push_back(payload);
} }
if (payloads.empty()) { if (cmds.empty()) {
return; return;
} }
pVulkanRenderer->MultiDrawElements(payloads); pVulkanRenderer->MultiDrawElements(cmds);
} }
void Clear(GLbitfield mask) { void Clear(GLbitfield mask) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Clear called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Clear called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::Clear called with null GL context"); MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::Clear called with null GL context");
pVulkanRenderer->Clear(mask);
const auto& drawFboSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
const auto drawFbo = drawFboSlot.GetBoundObject();
const auto defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
const auto defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO : nullptr;
const Bool isDefaultFboTarget = (drawFbo == defaultFbo) || (drawFbo == nullptr && defaultFbo != nullptr);
Uint drawFboExternalIndex = 0;
if (drawFbo) {
drawFboExternalIndex = drawFbo->GetExternalIndex();
} else if (defaultFbo) {
drawFboExternalIndex = defaultFbo->GetExternalIndex();
}
const auto& clearColor = MG_State::pGLContext->GetClearColor();
const auto clearDepth = MG_State::pGLContext->GetClearDepth();
const auto clearStencil = static_cast<Uint32>(MG_State::pGLContext->GetClearStencil());
pVulkanRenderer->RequestClear(mask, clearColor, clearDepth, clearStencil, drawFboExternalIndex,
isDefaultFboTarget);
} }
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) { void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElements called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElements called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElements called with null GL context"); MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElements called with null GL context");
if (count < 0) { DrawElementCmd payload{};
MGLOG_W("DrawElements skipped: count (%d) must be non-negative", count); payload.mode = mode;
return; payload.first = 0;
} payload.count = count;
if (count == 0) {
return;
}
if (mode != GL_TRIANGLES) {
MGLOG_W("DrawElements skipped: primitive mode %u is not supported yet", mode);
return;
}
SizeT indexSize = 0;
switch (type) {
case GL_UNSIGNED_SHORT:
indexSize = sizeof(Uint16);
break;
case GL_UNSIGNED_INT:
indexSize = sizeof(Uint32);
break;
default:
MGLOG_W("DrawElements skipped: index type %u is not supported yet", type);
return;
}
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) {
MGLOG_W("DrawElements skipped: no bound VAO");
return;
}
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
if (!indexBuffer) {
MGLOG_W("DrawElements skipped: no bound ELEMENT_ARRAY_BUFFER");
return;
}
const auto indexData = indexBuffer->GetDataReadOnly();
if (!indexData || indexData->empty()) {
MGLOG_W("DrawElements skipped: ELEMENT_ARRAY_BUFFER has no data");
return;
}
const auto byteOffset = reinterpret_cast<SizeT>(indices);
const SizeT requiredBytes = static_cast<SizeT>(count) * indexSize;
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
MGLOG_W("DrawElements skipped: index range out of bounds (offset=%zu, size=%zu, buffer=%zu)", byteOffset,
requiredBytes, indexBuffer->GetSize());
return;
}
DrawElementPayload payload{};
payload.drawArray.mode = mode;
payload.drawArray.first = 0;
payload.drawArray.count = count;
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
payload.drawArray.vertexArray = vao.get();
payload.indexType = type; payload.indexType = type;
payload.indexByteOffset = byteOffset; payload.indexByteOffset = reinterpret_cast<SizeT>(indices);
pVulkanRenderer->DrawElements(payload); pVulkanRenderer->DrawElements(payload);
} }
@@ -388,34 +98,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArrays called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArrays called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawArrays called with null GL context"); MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawArrays called with null GL context");
if (first < 0) { DrawArrayCmd payload{};
MGLOG_W("DrawArrays skipped: first (%d) must be non-negative", first);
return;
}
if (count < 0) {
MGLOG_W("DrawArrays skipped: count (%d) must be non-negative", count);
return;
}
if (count == 0) {
return;
}
if (mode != GL_TRIANGLES) {
MGLOG_W("DrawArrays skipped: primitive mode %u is not supported yet", mode);
return;
}
DrawArrayPayload payload{};
payload.mode = mode; payload.mode = mode;
payload.first = first; payload.first = first;
payload.count = count; payload.count = count;
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
payload.program = currentProgram ? currentProgram.get() : nullptr;
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
payload.vertexArray = vao ? vao.get() : nullptr;
pVulkanRenderer->DrawArrays(payload); pVulkanRenderer->DrawArrays(payload);
} }
@@ -424,33 +110,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
GLint dstY1, GLbitfield mask, GLenum filter) { GLint dstY1, GLbitfield mask, GLenum filter) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitFramebuffer called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitFramebuffer called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::BlitFramebuffer called with null GL context"); MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::BlitFramebuffer called with null GL context");
pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
const auto& readFboSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
const auto& drawFboSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
const auto readFbo = readFboSlot.GetBoundObject();
const auto drawFbo = drawFboSlot.GetBoundObject();
const auto defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
const auto defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO : nullptr;
const Bool readIsDefault = (readFbo == defaultFbo) || (readFbo == nullptr && defaultFbo != nullptr);
const Bool drawIsDefault = (drawFbo == defaultFbo) || (drawFbo == nullptr && defaultFbo != nullptr);
Uint readFboExternalIndex = 0;
if (readFbo) {
readFboExternalIndex = readFbo->GetExternalIndex();
} else if (defaultFbo) {
readFboExternalIndex = defaultFbo->GetExternalIndex();
}
Uint drawFboExternalIndex = 0;
if (drawFbo) {
drawFboExternalIndex = drawFbo->GetExternalIndex();
} else if (defaultFbo) {
drawFboExternalIndex = defaultFbo->GetExternalIndex();
}
pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter,
readFboExternalIndex, drawFboExternalIndex, readIsDefault, drawIsDefault);
} }
void Present() { void Present() {
@@ -21,6 +21,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.renderPass, sizeof(payload.renderPass))); XXHASH_VERIFY(XXH64_update(m_hashState, &payload.renderPass, sizeof(payload.renderPass)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.subpass, sizeof(payload.subpass))); XXHASH_VERIFY(XXH64_update(m_hashState, &payload.subpass, sizeof(payload.subpass)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.topology, sizeof(payload.topology))); XXHASH_VERIFY(XXH64_update(m_hashState, &payload.topology, sizeof(payload.topology)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.cullMode, sizeof(payload.cullMode)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.frontFace, sizeof(payload.frontFace)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthTestEnable, sizeof(payload.depthTestEnable))); XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthTestEnable, sizeof(payload.depthTestEnable)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthWriteEnable, sizeof(payload.depthWriteEnable))); XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthWriteEnable, sizeof(payload.depthWriteEnable)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthCompareOp, sizeof(payload.depthCompareOp))); XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthCompareOp, sizeof(payload.depthCompareOp)));
@@ -79,8 +81,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO}; VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO};
raster.polygonMode = VK_POLYGON_MODE_FILL; raster.polygonMode = VK_POLYGON_MODE_FILL;
raster.cullMode = VK_CULL_MODE_NONE; raster.cullMode = payload.cullMode;
raster.frontFace = VK_FRONT_FACE_CLOCKWISE; raster.frontFace = payload.frontFace;
raster.lineWidth = 1.0f; raster.lineWidth = 1.0f;
VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO}; VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO};
@@ -24,6 +24,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkRenderPass renderPass = VK_NULL_HANDLE; VkRenderPass renderPass = VK_NULL_HANDLE;
Uint32 subpass = 0; Uint32 subpass = 0;
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
Bool depthTestEnable = false; Bool depthTestEnable = false;
Bool depthWriteEnable = false; Bool depthWriteEnable = false;
VkCompareOp depthCompareOp = VK_COMPARE_OP_ALWAYS; VkCompareOp depthCompareOp = VK_COMPARE_OP_ALWAYS;
@@ -364,7 +364,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
auto& entry = m_cache[hash]; auto& entry = m_cache[hash];
entry.device = m_device;
entry.hash = hash; entry.hash = hash;
auto& shaders = program.GetAttachedShaders(); auto& shaders = program.GetAttachedShaders();
auto& spirv = program.GetGeneratedSpirv(); auto& spirv = program.GetGeneratedSpirv();
@@ -26,39 +26,35 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}; };
using CompileOptionFlags = Flags<CompileOptionBit>; using CompileOptionFlags = Flags<CompileOptionBit>;
using HashType = Uint64; using HashType = Uint64;
struct BackendProgramObject { struct VkProgramObject {
HashType hash = 0; HashType hash = 0;
VkDevice device = VK_NULL_HANDLE;
Vector<VkPipelineShaderStageCreateInfo> stages; Vector<VkPipelineShaderStageCreateInfo> stages;
Vector<VkShaderModule> modules; Vector<VkShaderModule> modules;
static inline VkDevice s_device = VK_NULL_HANDLE;
BackendProgramObject() = default; VkProgramObject() = default;
BackendProgramObject(const BackendProgramObject&) = delete; VkProgramObject(const VkProgramObject&) = delete;
BackendProgramObject& operator=(const BackendProgramObject&) = delete; VkProgramObject& operator=(const VkProgramObject&) = delete;
BackendProgramObject(BackendProgramObject&& other) noexcept { VkProgramObject(VkProgramObject&& other) noexcept {
hash = other.hash; hash = other.hash;
device = other.device;
stages = std::move(other.stages); stages = std::move(other.stages);
modules = std::move(other.modules); modules = std::move(other.modules);
other.hash = 0; other.hash = 0;
other.device = VK_NULL_HANDLE;
} }
BackendProgramObject& operator=(BackendProgramObject&& other) noexcept { VkProgramObject& operator=(VkProgramObject&& other) noexcept {
if (this == &other) { if (this == &other) {
return *this; return *this;
} }
DestroyModules(); DestroyModules();
stages.clear(); stages.clear();
hash = other.hash; hash = other.hash;
device = other.device;
stages = std::move(other.stages); stages = std::move(other.stages);
modules = std::move(other.modules); modules = std::move(other.modules);
other.hash = 0; other.hash = 0;
other.device = VK_NULL_HANDLE;
return *this; return *this;
} }
~BackendProgramObject() { ~VkProgramObject() {
DestroyModules(); DestroyModules();
stages.clear(); stages.clear();
} }
@@ -66,8 +62,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
private: private:
void DestroyModules() { void DestroyModules() {
for (auto module : modules) { for (auto module : modules) {
if (module != VK_NULL_HANDLE && device != VK_NULL_HANDLE) { if (module != VK_NULL_HANDLE && s_device != VK_NULL_HANDLE) {
vkDestroyShaderModule(device, module, nullptr); vkDestroyShaderModule(s_device, module, nullptr);
} }
} }
modules.clear(); modules.clear();
@@ -75,7 +71,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}; };
explicit ProgramFactory(VkDevice device, const VulkanRendererConfig& config) explicit ProgramFactory(VkDevice device, const VulkanRendererConfig& config)
: m_device(device), m_config(config) {} : m_device(device), m_config(config) {
VkProgramObject::s_device = device;
}
~ProgramFactory(); ~ProgramFactory();
ProgramFactory(const ProgramFactory&) = delete; ProgramFactory(const ProgramFactory&) = delete;
@@ -87,7 +85,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
private: private:
VkDevice m_device = VK_NULL_HANDLE; VkDevice m_device = VK_NULL_HANDLE;
UnorderedMap<HashType, BackendProgramObject> m_cache; UnorderedMap<HashType, VkProgramObject> m_cache;
const VulkanRendererConfig& m_config; const VulkanRendererConfig& m_config;
static inline XXH64_state_t* m_hashState = XXH64_createState(); static inline XXH64_state_t* m_hashState = XXH64_createState();
}; };
@@ -8,6 +8,9 @@
#include "SwapchainObject.h" #include "SwapchainObject.h"
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
#include "MG_State/GLState/TextureState/TextureObject2D.h"
#if defined(__has_include) #if defined(__has_include)
#if __has_include(<vulkan/vk_enum_string_helper.h>) #if __has_include(<vulkan/vk_enum_string_helper.h>)
#include <vulkan/vk_enum_string_helper.h> #include <vulkan/vk_enum_string_helper.h>
@@ -38,6 +41,40 @@ static const char* string_VkSurfaceTransformFlagBitsKHR(VkSurfaceTransformFlagBi
#endif #endif
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkan {
namespace {
Bool HasStencilComponent(VkFormat format) {
return format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT;
}
VkFormat FindSupportedDepthStencilFormat(VkPhysicalDevice physicalDevice) {
const VkFormat candidates[] = {VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT,
VK_FORMAT_D32_SFLOAT};
for (VkFormat format : candidates) {
VkFormatProperties props{};
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props);
if ((props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) {
return format;
}
}
return VK_FORMAT_UNDEFINED;
}
Uint32 FindMemoryType(VkPhysicalDevice physicalDevice, Uint32 typeFilter, VkMemoryPropertyFlags properties) {
VkPhysicalDeviceMemoryProperties memProperties{};
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
for (Uint32 i = 0; i < memProperties.memoryTypeCount; i++) {
if ((typeFilter & (1 << i)) &&
(memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
return i;
}
}
MOBILEGL_ASSERT(false, "Failed to find suitable memory type.");
return 0;
}
} // namespace
SwapchainObject::SwapchainCapabilities SwapchainObject::GetSwapchainCapabilities(VkPhysicalDevice physicalDevice, SwapchainObject::SwapchainCapabilities SwapchainObject::GetSwapchainCapabilities(VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface) { VkSurfaceKHR surface) {
SwapchainCapabilities swapchainCapabilities{}; SwapchainCapabilities swapchainCapabilities{};
@@ -127,6 +164,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
createInfo.imageFormat = pickedSurfaceFormat.format; createInfo.imageFormat = pickedSurfaceFormat.format;
createInfo.imageColorSpace = pickedSurfaceFormat.colorSpace; createInfo.imageColorSpace = pickedSurfaceFormat.colorSpace;
createInfo.imageExtent = swapchainCaps.currentExtent; createInfo.imageExtent = swapchainCaps.currentExtent;
if (swapchainCaps.currentTransform == VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR ||
swapchainCaps.currentTransform == VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
std::swap(createInfo.imageExtent.width, createInfo.imageExtent.height);
}
createInfo.imageArrayLayers = 1; createInfo.imageArrayLayers = 1;
const VkImageUsageFlags requiredImageUsage = const VkImageUsageFlags requiredImageUsage =
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
@@ -185,12 +227,133 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_imageLayouts.assign(imageCount, VK_IMAGE_LAYOUT_UNDEFINED); m_imageLayouts.assign(imageCount, VK_IMAGE_LAYOUT_UNDEFINED);
CreateImageViews(device); CreateImageViews(device);
CreateDepthStencilResources(device, physicalDevice);
MGLOG_I("Swapchain created, extent = %dx%d, swapchain imageCount = %d", m_extent.width, m_extent.height, MGLOG_I("Swapchain created, extent = %dx%d, swapchain imageCount = %d", m_extent.width, m_extent.height,
imageCount); imageCount);
// Properly initialize Default FBO here
auto& defaultFBOInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
auto* colorTex = static_cast<MG_State::GLState::TextureObject2D*>(defaultFBOInfo->colorAttachment.get());
colorTex->AllocateStorage(
TextureUploadTarget::Texture2D, 0, {
{(Int)createInfo.imageExtent.width, (Int)createInfo.imageExtent.height, 1},
createInfo.imageExtent.width * (Int)createInfo.imageExtent.height * 4}); // TODO: 4 is format size
TextureInternalFormat depthFormat = TextureInternalFormat::Depth24Stencil8;
switch (m_depthStencilFormat) {
case VK_FORMAT_D24_UNORM_S8_UINT:
depthFormat = TextureInternalFormat::Depth24Stencil8;
break;
case VK_FORMAT_D32_SFLOAT_S8_UINT:
depthFormat = TextureInternalFormat::Depth32FStencil8;
break;
case VK_FORMAT_D32_SFLOAT:
depthFormat = TextureInternalFormat::DepthComponent32F;
break;
default:
depthFormat = TextureInternalFormat::Depth24Stencil8;
break;
}
auto* depthTex = static_cast<MG_State::GLState::TextureObject2D*>(defaultFBOInfo->depthAttachment.get());
depthTex->SetInternalFormat(depthFormat);
depthTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, {
{(Int)createInfo.imageExtent.width, (Int)createInfo.imageExtent.height, 1},
createInfo.imageExtent.width * createInfo.imageExtent.width * 4}); // TODO: 4 is format size
}
void SwapchainObject::CreateDepthStencilResources(VkDevice device, VkPhysicalDevice physicalDevice) {
DestroyDepthStencilResources(device);
const auto imageCount = static_cast<Uint32>(m_images.size());
if (imageCount == 0) {
return;
}
m_depthStencilFormat = FindSupportedDepthStencilFormat(physicalDevice);
MOBILEGL_ASSERT(m_depthStencilFormat != VK_FORMAT_UNDEFINED, "No supported depth/stencil format found.");
m_depthStencilImages.assign(imageCount, VK_NULL_HANDLE);
m_depthStencilImageMemories.assign(imageCount, VK_NULL_HANDLE);
m_depthStencilImageViews.assign(imageCount, VK_NULL_HANDLE);
m_depthStencilImageLayouts.assign(imageCount, VK_IMAGE_LAYOUT_UNDEFINED);
for (Uint32 i = 0; i < imageCount; ++i) {
VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = m_extent.width;
imageInfo.extent.height = m_extent.height;
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.format = m_depthStencilFormat;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_VERIFY(vkCreateImage(device, &imageInfo, nullptr, &m_depthStencilImages[i]), "vkCreateImage(depth)");
VkMemoryRequirements memRequirements{};
vkGetImageMemoryRequirements(device, m_depthStencilImages[i], &memRequirements);
VkMemoryAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex =
FindMemoryType(physicalDevice, memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_VERIFY(vkAllocateMemory(device, &allocInfo, nullptr, &m_depthStencilImageMemories[i]),
"vkAllocateMemory(depth)");
VK_VERIFY(vkBindImageMemory(device, m_depthStencilImages[i], m_depthStencilImageMemories[i], 0),
"vkBindImageMemory(depth)");
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = m_depthStencilImages[i];
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = m_depthStencilFormat;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (HasStencilComponent(m_depthStencilFormat)) {
viewInfo.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
VK_VERIFY(vkCreateImageView(device, &viewInfo, nullptr, &m_depthStencilImageViews[i]),
"vkCreateImageView(depth)");
}
}
void SwapchainObject::DestroyDepthStencilResources(VkDevice device) {
for (auto view : m_depthStencilImageViews) {
if (view != VK_NULL_HANDLE) {
vkDestroyImageView(device, view, nullptr);
}
}
m_depthStencilImageViews.clear();
for (auto image : m_depthStencilImages) {
if (image != VK_NULL_HANDLE) {
vkDestroyImage(device, image, nullptr);
}
}
m_depthStencilImages.clear();
for (auto memory : m_depthStencilImageMemories) {
if (memory != VK_NULL_HANDLE) {
vkFreeMemory(device, memory, nullptr);
}
}
m_depthStencilImageMemories.clear();
m_depthStencilImageLayouts.clear();
m_depthStencilFormat = VK_FORMAT_UNDEFINED;
} }
void SwapchainObject::Shutdown(VkDevice device) { void SwapchainObject::Shutdown(VkDevice device) {
DestroyDepthStencilResources(device);
for (auto imageView : m_imageViews) { for (auto imageView : m_imageViews) {
vkDestroyImageView(device, imageView, nullptr); vkDestroyImageView(device, imageView, nullptr);
} }
@@ -221,6 +384,29 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_imageLayouts[index] = layout; m_imageLayouts[index] = layout;
} }
VkImage SwapchainObject::GetDepthStencilImage(Uint32 index) const {
MOBILEGL_ASSERT(index < m_depthStencilImages.size(), "Swapchain depth/stencil image index out of range");
return m_depthStencilImages[index];
}
VkImageView SwapchainObject::GetDepthStencilImageView(Uint32 index) const {
MOBILEGL_ASSERT(index < m_depthStencilImageViews.size(),
"Swapchain depth/stencil image view index out of range");
return m_depthStencilImageViews[index];
}
VkImageLayout SwapchainObject::GetDepthStencilImageLayout(Uint32 index) const {
MOBILEGL_ASSERT(index < m_depthStencilImageLayouts.size(),
"Swapchain depth/stencil image layout index out of range");
return m_depthStencilImageLayouts[index];
}
void SwapchainObject::SetDepthStencilImageLayout(Uint32 index, VkImageLayout layout) {
MOBILEGL_ASSERT(index < m_depthStencilImageLayouts.size(),
"Swapchain depth/stencil image layout index out of range");
m_depthStencilImageLayouts[index] = layout;
}
void SwapchainObject::CreateImageViews(VkDevice device) { void SwapchainObject::CreateImageViews(VkDevice device) {
m_imageViews.resize(m_images.size(), VK_NULL_HANDLE); m_imageViews.resize(m_images.size(), VK_NULL_HANDLE);
for (SizeT i = 0; i < m_imageViews.size(); i++) { for (SizeT i = 0; i < m_imageViews.size(); i++) {
@@ -38,6 +38,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkSurfaceTransformFlagBitsKHR GetPreTransform() const { return m_preTransform; } VkSurfaceTransformFlagBitsKHR GetPreTransform() const { return m_preTransform; }
const Vector<VkImage>& GetImages() const { return m_images; } const Vector<VkImage>& GetImages() const { return m_images; }
const Vector<VkImageView>& GetImageViews() const { return m_imageViews; } const Vector<VkImageView>& GetImageViews() const { return m_imageViews; }
VkFormat GetDepthStencilFormat() const { return m_depthStencilFormat; }
const Vector<VkImageView>& GetDepthStencilImageViews() const { return m_depthStencilImageViews; }
VkImage GetDepthStencilImage(Uint32 index) const;
VkImageView GetDepthStencilImageView(Uint32 index) const;
VkImageLayout GetDepthStencilImageLayout(Uint32 index) const;
void SetDepthStencilImageLayout(Uint32 index, VkImageLayout layout);
VkImage GetImage(Uint32 index) const; VkImage GetImage(Uint32 index) const;
VkImageLayout GetImageLayout(Uint32 index) const; VkImageLayout GetImageLayout(Uint32 index) const;
void SetImageLayout(Uint32 index, VkImageLayout layout); void SetImageLayout(Uint32 index, VkImageLayout layout);
@@ -45,6 +51,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
private: private:
void CreateImageViews(VkDevice device); void CreateImageViews(VkDevice device);
void CreateDepthStencilResources(VkDevice device, VkPhysicalDevice physicalDevice);
void DestroyDepthStencilResources(VkDevice device);
static constexpr VkPresentModeKHR s_desiredPresentModes[] { static constexpr VkPresentModeKHR s_desiredPresentModes[] {
VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_MAILBOX_KHR,
VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR,
@@ -59,5 +67,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Vector<VkImage> m_images; Vector<VkImage> m_images;
Vector<VkImageView> m_imageViews; Vector<VkImageView> m_imageViews;
Vector<VkImageLayout> m_imageLayouts; Vector<VkImageLayout> m_imageLayouts;
VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED;
Vector<VkImage> m_depthStencilImages;
Vector<VkDeviceMemory> m_depthStencilImageMemories;
Vector<VkImageView> m_depthStencilImageViews;
Vector<VkImageLayout> m_depthStencilImageLayouts;
}; };
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -8,13 +8,52 @@
#include "UniformDescriptorBinder.h" #include "UniformDescriptorBinder.h"
#include "VkFramebufferManager.h"
#include "MG_State/GLState/Core.h" #include "MG_State/GLState/Core.h"
#include "MG_State/GLState/ProgramState/ProgramObject.h" #include "MG_State/GLState/ProgramState/ProgramObject.h"
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
#include "MG_Util/ShaderTranspiler/Types.h" #include "MG_Util/ShaderTranspiler/Types.h"
#include <limits> #include <limits>
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkan {
static Bool FindFramebufferAttachmentForTexture(const MG_State::GLState::FramebufferObject& framebuffer,
const MG_State::GLState::ITextureObject& texture,
FramebufferAttachmentType& outAttachment, Int& outLevel) {
const auto& attachments = framebuffer.GetAllAttachmentObjects();
for (SizeT i = 0; i < attachments.size(); ++i) {
const auto attachmentType = static_cast<FramebufferAttachmentType>(i);
if (attachmentType == FramebufferAttachmentType::None) {
continue;
}
const auto& attachment = attachments[i];
if (!attachment.IsTexture()) {
continue;
}
auto attachedTexture = attachment.GetTexture();
if (attachedTexture && attachedTexture.get() == &texture) {
outAttachment = attachmentType;
outLevel = attachment.GetTextureLevel();
return true;
}
}
return false;
}
static Bool IsValidSampledImageLayout(VkImageLayout layout) {
switch (layout) {
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
case VK_IMAGE_LAYOUT_GENERAL:
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
return true;
default:
return false;
}
}
VkDeviceSize UniformDescriptorBinder::AlignUp(VkDeviceSize value, VkDeviceSize alignment) { VkDeviceSize UniformDescriptorBinder::AlignUp(VkDeviceSize value, VkDeviceSize alignment) {
if (alignment == 0) { if (alignment == 0) {
return value; return value;
@@ -138,8 +177,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Bool UniformDescriptorBinder::Initialize(VkDevice device, VmaAllocator allocator, Bool UniformDescriptorBinder::Initialize(VkDevice device, VmaAllocator allocator,
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount, VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
Uint32 maxBindings, Uint32 setsPerFrame, VkDeviceSize perFrameUploadBytes, Uint32 maxBindings, Uint32 setsPerFrame, VkDeviceSize perFrameUploadBytes,
VkTextureSamplerManager* textureSamplerManager, VkTextureManager* textureManager, VkSamplerManager* samplerManager) {
VkFramebufferManager* framebufferManager) {
Shutdown(); Shutdown();
MOBILEGL_ASSERT(device != VK_NULL_HANDLE, "UniformDescriptorBinder::Initialize requires valid VkDevice"); MOBILEGL_ASSERT(device != VK_NULL_HANDLE, "UniformDescriptorBinder::Initialize requires valid VkDevice");
@@ -147,6 +185,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MOBILEGL_ASSERT(frameCount > 0, "UniformDescriptorBinder::Initialize requires frameCount > 0"); MOBILEGL_ASSERT(frameCount > 0, "UniformDescriptorBinder::Initialize requires frameCount > 0");
MOBILEGL_ASSERT(maxBindings > 0, "UniformDescriptorBinder::Initialize requires maxBindings > 0"); MOBILEGL_ASSERT(maxBindings > 0, "UniformDescriptorBinder::Initialize requires maxBindings > 0");
MOBILEGL_ASSERT(setsPerFrame > 0, "UniformDescriptorBinder::Initialize requires setsPerFrame > 0"); MOBILEGL_ASSERT(setsPerFrame > 0, "UniformDescriptorBinder::Initialize requires setsPerFrame > 0");
MOBILEGL_ASSERT(textureManager != nullptr,
"UniformDescriptorBinder::Initialize requires valid texture manager");
MOBILEGL_ASSERT(samplerManager != nullptr,
"UniformDescriptorBinder::Initialize requires valid sampler manager");
m_device = device; m_device = device;
m_allocator = allocator; m_allocator = allocator;
@@ -156,8 +198,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_maxBindings = maxBindings; m_maxBindings = maxBindings;
m_setsPerFrame = setsPerFrame; m_setsPerFrame = setsPerFrame;
m_peakDescriptorSetsObserved = 0; m_peakDescriptorSetsObserved = 0;
m_textureSamplerManager = textureSamplerManager; m_textureManager = textureManager;
m_framebufferManager = framebufferManager; m_samplerManager = samplerManager;
m_frames.resize(m_frameCount); m_frames.resize(m_frameCount);
for (Uint32 frameIndex = 0; frameIndex < m_frameCount; ++frameIndex) { for (Uint32 frameIndex = 0; frameIndex < m_frameCount; ++frameIndex) {
@@ -219,8 +261,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_maxBindings = 0; m_maxBindings = 0;
m_setsPerFrame = 0; m_setsPerFrame = 0;
m_peakDescriptorSetsObserved = 0; m_peakDescriptorSetsObserved = 0;
m_textureSamplerManager = nullptr; m_textureManager = nullptr;
m_framebufferManager = nullptr; m_samplerManager = nullptr;
} }
void UniformDescriptorBinder::BeginFrame(Uint32 frameIndex) { void UniformDescriptorBinder::BeginFrame(Uint32 frameIndex) {
@@ -443,7 +485,86 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const MG_State::GLState::ProgramObject& program, const MG_State::GLState::ProgramObject& program,
const ProgramLayout& layout, Uint32 binding, const ProgramLayout& layout, Uint32 binding,
VkDescriptorImageInfo& outImageInfo) const { VkDescriptorImageInfo& outImageInfo) const {
if (!m_textureSamplerManager || !MG_State::pGLContext || binding >= layout.samplerUniformLocationByBinding.size()) { (void)commandBuffer;
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptor: texture manager is null");
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptor: sampler manager is null");
SharedPtr<MG_State::GLState::ITextureObject> texture;
if (!ResolveSamplerTexture(program, layout, binding, texture)) {
return false;
}
const Int location = layout.samplerUniformLocationByBinding[binding];
const Int unit = program.GetUniformSamplerOrImageUnitIndex(static_cast<Uint>(location));
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
const auto samplerOverride = textureUnit.GetSamplerObject();
if (!texture) {
return false;
}
const MG_State::GLState::SamplerObject* samplerToUse = samplerOverride ? samplerOverride.get() : texture->GetSamplerObject().get();
if (!samplerToUse) {
return false;
}
VkTextureManager::TextureResource* resource =
m_textureManager->SyncTextureAndGetDescriptor(*texture);
if (resource == nullptr) {
return false;
}
if (!IsValidSampledImageLayout(resource->layout)) {
auto drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
FramebufferAttachmentType attachmentType = FramebufferAttachmentType::None;
Int attachmentLevel = 0;
if (drawFbo &&
FindFramebufferAttachmentForTexture(*drawFbo, *texture, attachmentType, attachmentLevel)) {
MOBILEGL_ASSERT(false,
"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, "
"trackedLayout=%d)",
texture->GetExternalIndex(), binding, drawFbo->GetExternalIndex(),
MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(),
attachmentLevel, static_cast<Int>(resource->layout));
}
MOBILEGL_ASSERT(false,
"ResolveSamplerDescriptor: invalid sampled image layout=%d for textureId=%d, binding=%u",
static_cast<Int>(resource->layout), texture->GetExternalIndex(), binding);
return false;
}
outImageInfo = {
.sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse),
.imageView = resource->view,
.imageLayout = resource->layout,
};
return outImageInfo.sampler != VK_NULL_HANDLE;
}
Bool UniformDescriptorBinder::ResolveSamplerDescriptorOverride(
const SamplerBindingOverride& samplerBindingOverride,
VkDescriptorImageInfo& outImageInfo) const {
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptorOverride: texture manager is null");
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptorOverride: sampler manager is null");
if (samplerBindingOverride.texture == nullptr || samplerBindingOverride.sampler == nullptr) {
return false;
}
auto* resource = m_textureManager->SyncTextureAndGetDescriptor(*samplerBindingOverride.texture);
if (resource == nullptr || !IsValidSampledImageLayout(resource->layout)) {
return false;
}
outImageInfo = {
.sampler = m_samplerManager->GetOrCreateSampler(*samplerBindingOverride.sampler),
.imageView = resource->view,
.imageLayout = resource->layout,
};
return outImageInfo.sampler != VK_NULL_HANDLE;
}
Bool UniformDescriptorBinder::ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
const ProgramLayout& layout, Uint32 binding,
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const {
outTexture.reset();
if (!MG_State::pGLContext || binding >= layout.samplerUniformLocationByBinding.size()) {
return false; return false;
} }
@@ -458,41 +579,36 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit); auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
const auto samplerOverride = textureUnit.GetSamplerObject();
const TextureTarget preferredTarget = layout.samplerTextureTargetByBinding[binding]; const TextureTarget preferredTarget = layout.samplerTextureTargetByBinding[binding];
auto texture = textureUnit.GetBindingSlot(preferredTarget).GetBoundObject(); outTexture = textureUnit.GetBindingSlot(preferredTarget).GetBoundObject();
if (!texture) { return outTexture != nullptr;
auto& slots = textureUnit.GetAllBindingSlots();
for (auto& slot : slots) {
texture = slot.GetBoundObject();
if (texture) {
break;
} }
}
} Bool UniformDescriptorBinder::CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
if (!texture) { Vector<MG_State::GLState::ITextureObject*>& outTextures) {
outTextures.clear();
ProgramLayout* layout = GetOrCreateProgramLayout(program);
if (layout == nullptr) {
return false; return false;
} }
if (m_framebufferManager && for (Uint32 binding = 0; binding < m_maxBindings; ++binding) {
m_framebufferManager->TransitionOffscreenColorTextureToShaderRead(commandBuffer, texture->GetExternalIndex())) { if (layout->bindingKinds[binding] != BindingKind::CombinedImageSampler) {
VkImageView offscreenView = VK_NULL_HANDLE; continue;
if (m_framebufferManager->GetOffscreenColorViewByTexture(texture->GetExternalIndex(), offscreenView) && }
offscreenView != VK_NULL_HANDLE) {
VkDescriptorImageInfo sampledInfo{}; SharedPtr<MG_State::GLState::ITextureObject> texture;
if (!m_textureSamplerManager->SyncTextureAndGetDescriptor(*texture, samplerOverride.get(), sampledInfo)) { if (!ResolveSamplerTexture(program, *layout, binding, texture) || !texture) {
return false; continue;
}
auto found = std::find(outTextures.begin(), outTextures.end(), texture.get());
if (found == outTextures.end()) {
outTextures.push_back(texture.get());
}
} }
sampledInfo.imageView = offscreenView;
sampledInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
outImageInfo = sampledInfo;
return true; return true;
} }
}
return m_textureSamplerManager->SyncTextureAndGetDescriptor(*texture, samplerOverride.get(), outImageInfo);
}
UniformDescriptorBinder::ProgramLayout* UniformDescriptorBinder::GetOrCreateProgramLayout( UniformDescriptorBinder::ProgramLayout* UniformDescriptorBinder::GetOrCreateProgramLayout(
const MG_State::GLState::ProgramObject& program) { const MG_State::GLState::ProgramObject& program) {
@@ -578,10 +694,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
outData.assign(m_maxBindings, nullptr); outData.assign(m_maxBindings, nullptr);
outSizes.assign(m_maxBindings, 0); outSizes.assign(m_maxBindings, 0);
if (MG_State::pGLContext == nullptr) {
return false;
}
const Uint32 activeUniformBlockCount = static_cast<Uint32>(program.GetActiveUniformBlocksCount()); const Uint32 activeUniformBlockCount = static_cast<Uint32>(program.GetActiveUniformBlocksCount());
const Uint32 uniformBindingPointCount = const Uint32 uniformBindingPointCount =
static_cast<Uint32>(MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform)); static_cast<Uint32>(MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform));
@@ -693,27 +805,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return true; return true;
} }
Bool UniformDescriptorBinder::BindProgramUniformBuffers(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, Bool UniformDescriptorBinder::BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
const MG_State::GLState::ProgramObject& program, const MG_State::GLState::ProgramObject& program,
Uint32 frameIndex) { Uint32 frameIndex) {
if (m_frames.empty()) { return BindProgramUniformBuffers(commandBuffer, program, frameIndex, nullptr);
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: binder is not initialized");
return false;
}
if (frameIndex >= m_frames.size()) {
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: invalid frame index %u", frameIndex);
return false;
} }
Bool UniformDescriptorBinder::BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
const MG_State::GLState::ProgramObject& program,
Uint32 frameIndex,
const SamplerBindingOverride* samplerBindingOverride) {
ProgramLayout* layout = GetOrCreateProgramLayout(program); ProgramLayout* layout = GetOrCreateProgramLayout(program);
if (!layout || layout->pipelineLayout == VK_NULL_HANDLE || layout->descriptorSetLayout == VK_NULL_HANDLE) { MOBILEGL_ASSERT(layout != nullptr,
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: cannot get program layout"); "UniformDescriptorBinder::BindProgramUniformBuffers: program layout is null");
return false;
}
if (layout->pipelineLayout != pipelineLayout) {
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: pipelineLayout mismatch");
return false;
}
auto& frame = m_frames[frameIndex]; auto& frame = m_frames[frameIndex];
if (frame.descriptorPools.empty()) { if (frame.descriptorPools.empty()) {
@@ -764,8 +868,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
static const Uint8 kFallbackData[16] = {}; static const Uint8 kFallbackData[16] = {};
VkDescriptorImageInfo fallbackImageInfo{}; MOBILEGL_ASSERT(m_textureManager != nullptr, "BindProgramUniformBuffers: texture manager is null");
const Bool hasFallbackImage = m_textureSamplerManager && m_textureSamplerManager->GetFallbackDescriptor(fallbackImageInfo); MOBILEGL_ASSERT(m_samplerManager != nullptr, "BindProgramUniformBuffers: sampler manager is null");
Vector<VkWriteDescriptorSet> writes; Vector<VkWriteDescriptorSet> writes;
writes.reserve(m_maxBindings); writes.reserve(m_maxBindings);
@@ -830,16 +934,23 @@ namespace MobileGL::MG_Backend::DirectVulkan {
dynamicOffsets.push_back(static_cast<Uint32>(payloadOffset)); dynamicOffsets.push_back(static_cast<Uint32>(payloadOffset));
} else { } else {
VkDescriptorImageInfo imageInfo{}; VkDescriptorImageInfo imageInfo{};
Bool hasImage = ResolveSamplerDescriptor(commandBuffer, program, *layout, binding, imageInfo); Bool hasImage = false;
if (samplerBindingOverride != nullptr &&
samplerBindingOverride->binding == binding &&
samplerBindingOverride->texture != nullptr &&
samplerBindingOverride->sampler != nullptr) {
hasImage = ResolveSamplerDescriptorOverride(*samplerBindingOverride, imageInfo);
} else {
hasImage = ResolveSamplerDescriptor(commandBuffer, program, *layout, binding, imageInfo);
}
if (!hasImage) { if (!hasImage) {
if (!hasFallbackImage) { MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has no valid texture descriptor",
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: fallback sampler/texture is unavailable"); binding);
return false; return false;
} }
imageInfo = fallbackImageInfo;
}
if (imageInfo.sampler == VK_NULL_HANDLE || imageInfo.imageView == VK_NULL_HANDLE) { if (imageInfo.sampler == VK_NULL_HANDLE || imageInfo.imageView == VK_NULL_HANDLE) {
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: fallback sampler/texture is unavailable"); MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has null sampler or imageView",
binding);
return false; return false;
} }
imageInfos.push_back(imageInfo); imageInfos.push_back(imageInfo);
@@ -853,7 +964,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
vkUpdateDescriptorSets(m_device, static_cast<Uint32>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<Uint32>(writes.size()), writes.data(), 0, nullptr);
} }
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout->pipelineLayout, 0, 1, &descriptorSet,
static_cast<Uint32>(dynamicOffsets.size()), dynamicOffsets.data()); static_cast<Uint32>(dynamicOffsets.size()), dynamicOffsets.data());
return true; return true;
} }
@@ -872,4 +983,3 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_programLayouts.clear(); m_programLayouts.clear();
} }
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -9,18 +9,19 @@
#pragma once #pragma once
#include "VkBufferObject.h" #include "VkBufferObject.h"
#include "VkTextureSamplerManager.h" #include "VkSamplerManager.h"
#include "VkTextureManager.h"
#include "../VkIncludes.h" #include "../VkIncludes.h"
#include <Includes.h> #include <Includes.h>
#include <vk_mem_alloc.h> #include <vk_mem_alloc.h>
namespace MobileGL::MG_State::GLState { namespace MobileGL::MG_State::GLState {
class ITextureObject;
class ProgramObject; class ProgramObject;
class SamplerObject;
} }
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkan {
class VkFramebufferManager;
class UniformDescriptorBinder { class UniformDescriptorBinder {
public: public:
enum class BindingKind : Uint8 { enum class BindingKind : Uint8 {
@@ -29,17 +30,27 @@ namespace MobileGL::MG_Backend::DirectVulkan {
CombinedImageSampler CombinedImageSampler
}; };
struct SamplerBindingOverride {
Uint32 binding = 0;
MG_State::GLState::ITextureObject* texture = nullptr;
const MG_State::GLState::SamplerObject* sampler = nullptr;
};
Bool Initialize(VkDevice device, VmaAllocator allocator, VkDeviceSize minUniformBufferOffsetAlignment, Bool Initialize(VkDevice device, VmaAllocator allocator, VkDeviceSize minUniformBufferOffsetAlignment,
Uint32 frameCount, Uint32 maxBindings = 16, Uint32 setsPerFrame = 64, Uint32 frameCount, Uint32 maxBindings = 16, Uint32 setsPerFrame = 64,
VkDeviceSize perFrameUploadBytes = 4 * 1024 * 1024, VkDeviceSize perFrameUploadBytes = 4 * 1024 * 1024,
VkTextureSamplerManager* textureSamplerManager = nullptr, VkTextureManager* textureManager = nullptr, VkSamplerManager* samplerManager = nullptr);
VkFramebufferManager* framebufferManager = nullptr);
void Shutdown(); void Shutdown();
void BeginFrame(Uint32 frameIndex); void BeginFrame(Uint32 frameIndex);
VkPipelineLayout GetOrCreatePipelineLayout(const MG_State::GLState::ProgramObject& program); VkPipelineLayout GetOrCreatePipelineLayout(const MG_State::GLState::ProgramObject& program);
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, Bool CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
Vector<MG_State::GLState::ITextureObject*>& outTextures);
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
const MG_State::GLState::ProgramObject& program, Uint32 frameIndex); const MG_State::GLState::ProgramObject& program, Uint32 frameIndex);
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
const MG_State::GLState::ProgramObject& program, Uint32 frameIndex,
const SamplerBindingOverride* samplerBindingOverride);
private: private:
struct DescriptorPoolBucket { struct DescriptorPoolBucket {
@@ -74,9 +85,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
static TextureTarget UniformTypeToTextureTarget(GLenum glType); static TextureTarget UniformTypeToTextureTarget(GLenum glType);
Bool ReflectSamplerBindings(const MG_State::GLState::ProgramObject& program, ProgramLayout& layout) const; Bool ReflectSamplerBindings(const MG_State::GLState::ProgramObject& program, ProgramLayout& layout) const;
Bool ReflectGlobalUboBinding(const MG_State::GLState::ProgramObject& program, ProgramLayout& layout) const; Bool ReflectGlobalUboBinding(const MG_State::GLState::ProgramObject& program, ProgramLayout& layout) const;
Bool ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program, const ProgramLayout& layout,
Uint32 binding, SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const;
Bool ResolveSamplerDescriptor(VkCommandBuffer commandBuffer, const MG_State::GLState::ProgramObject& program, Bool ResolveSamplerDescriptor(VkCommandBuffer commandBuffer, const MG_State::GLState::ProgramObject& program,
const ProgramLayout& layout, Uint32 binding, const ProgramLayout& layout, Uint32 binding,
VkDescriptorImageInfo& outImageInfo) const; VkDescriptorImageInfo& outImageInfo) const;
Bool ResolveSamplerDescriptorOverride(const SamplerBindingOverride& samplerBindingOverride,
VkDescriptorImageInfo& outImageInfo) const;
Bool ReflectBindingKinds(const MG_State::GLState::ProgramObject& program, Vector<BindingKind>& outKinds) const; Bool ReflectBindingKinds(const MG_State::GLState::ProgramObject& program, Vector<BindingKind>& outKinds) const;
ProgramLayout* GetOrCreateProgramLayout(const MG_State::GLState::ProgramObject& program); ProgramLayout* GetOrCreateProgramLayout(const MG_State::GLState::ProgramObject& program);
Bool AllocateUploadRegion(FrameResources& frame, VkDeviceSize size, VkDeviceSize& outOffset); Bool AllocateUploadRegion(FrameResources& frame, VkDeviceSize size, VkDeviceSize& outOffset);
@@ -97,8 +112,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Uint32 m_maxBindings = 0; Uint32 m_maxBindings = 0;
Uint32 m_setsPerFrame = 0; Uint32 m_setsPerFrame = 0;
Uint32 m_peakDescriptorSetsObserved = 0; Uint32 m_peakDescriptorSetsObserved = 0;
VkTextureSamplerManager* m_textureSamplerManager = nullptr; VkTextureManager* m_textureManager = nullptr;
VkFramebufferManager* m_framebufferManager = nullptr; VkSamplerManager* m_samplerManager = nullptr;
}; };
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -0,0 +1,99 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.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 "VkClearManager.h"
namespace MobileGL::MG_Backend::DirectVulkan {
Bool VkClearManager::Initialize() {
return true;
}
void VkClearManager::Shutdown() {
}
void VkClearManager::QueueClear(GLbitfield mask, const ClearFramebufferPayload& clearPayload,
const MG_State::GLState::FramebufferObject& drawFbo) {
if (mask & GL_COLOR_BUFFER_BIT) {
auto& drawbufs = drawFbo.GetDrawBuffers();
// This should automatically work on default & offscreen FBO
for (auto drawbuf: drawbufs) {
if (drawbuf == FramebufferAttachmentType::None ||
drawFbo.GetAttachment(drawbuf).IsRenderbuffer())
continue;
QueueClear({
.color = clearPayload.color,
.attachmentType = drawbuf
}, drawFbo.GetAttachment(drawbuf).GetTexture());
}
}
if (mask & GL_DEPTH_BUFFER_BIT &&
!drawFbo.GetAttachment(FramebufferAttachmentType::Depth).IsRenderbuffer()) {
QueueClear({
.depth = clearPayload.depth,
.attachmentType = FramebufferAttachmentType::Depth,
}, drawFbo.GetAttachment(FramebufferAttachmentType::Depth).GetTexture());
}
if (mask & GL_STENCIL_BUFFER_BIT &&
!drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).IsRenderbuffer()) {
QueueClear({
.stencil = clearPayload.stencil,
.attachmentType = FramebufferAttachmentType::Stencil,
}, drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).GetTexture());
}
}
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
const SharedPtr<MG_State::GLState::ITextureObject>& texture) {
WeakPtr<MG_State::GLState::ITextureObject> weakTexturePtr = texture;
if (weakTexturePtr.expired())
return;
auto* pTexture = weakTexturePtr.lock().get();
m_aliveObjects[pTexture] = weakTexturePtr;
m_pendingClears[pTexture] = clearPayload;
}
Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) {
return m_pendingClears.find(texture) != m_pendingClears.end();
}
Bool VkClearManager::GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload) {
if (m_aliveObjects.find(texture) == m_aliveObjects.end() ||
m_pendingClears.find(texture) == m_pendingClears.end()) {
return false;
}
outPayload = m_pendingClears[texture];
return true;
}
void VkClearManager::PopPendingClear(MG_State::GLState::ITextureObject* texture) {
m_aliveObjects.erase(texture);
m_pendingClears.erase(texture);
}
SizeT VkClearManager::CollectGarbage() {
m_gcCounter++;
if (m_gcCounter != 0) {
return 0;
}
SizeT count = 0;
for (const auto& [raw, weak]: m_aliveObjects) {
if (weak.expired()) {
count++;
m_pendingClears.erase(raw);
m_aliveObjects.erase(raw);
}
}
return count;
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -0,0 +1,52 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.h
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
#pragma once
#include "../VkIncludes.h"
#include "../VulkanRendererConfig.h"
#include "MG_State/GLState/FramebufferState/FramebufferObject.h"
#include "MG_Util/Math/VectorTypes.h"
#include <Includes.h>
namespace MobileGL::MG_Backend::DirectVulkan {
struct ClearFramebufferPayload {
FloatVec4 color;
Float depth{};
Uint32 stencil{};
};
struct ClearAttachmentPayload {
union {
FloatVec4 color;
Float depth{};
Uint32 stencil;
};
FramebufferAttachmentType attachmentType = FramebufferAttachmentType::Color0;
};
class VkClearManager {
public:
Bool Initialize();
void Shutdown();
void QueueClear(GLbitfield mask, const ClearFramebufferPayload& clearPayload, const MG_State::GLState::FramebufferObject& drawFbo);
void QueueClear(
const ClearAttachmentPayload& clearPayload,
const SharedPtr<MG_State::GLState::ITextureObject>& texture);
Bool HasPendingClear(MG_State::GLState::ITextureObject* texture);
Bool GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload);
void PopPendingClear(MG_State::GLState::ITextureObject* texture);
SizeT CollectGarbage();
private:
Uint8 m_gcCounter = 0;
UnorderedMap<MG_State::GLState::ITextureObject*, ClearAttachmentPayload> m_pendingClears;
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,547 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.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 "VkFramebufferManager.h"
#include <MG_State/GLState/RenderbufferState/RenderbufferObject.h>
#include <MG_State/GLState/TextureState/TextureEnum.h>
namespace MobileGL::MG_Backend::DirectVulkan {
Bool VkFramebufferManager::Initialize(const InitInfo& initInfo) {
m_device = initInfo.device;
m_physicalDevice = initInfo.physicalDevice;
return m_device != VK_NULL_HANDLE && m_physicalDevice != VK_NULL_HANDLE;
}
void VkFramebufferManager::Shutdown() {
for (auto& [_, target] : m_offscreenColorTargets) {
DestroyOffscreenColorTarget(target);
}
m_offscreenColorTargets.clear();
m_device = VK_NULL_HANDLE;
m_physicalDevice = VK_NULL_HANDLE;
}
Bool VkFramebufferManager::EnsureOffscreenColorTarget(Uint glFboExternalIndex,
const MG_State::GLState::FramebufferObject& glFbo) {
const auto& colorAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Color0);
if (!colorAttachment.IsValid() || colorAttachment.IsEmpty()) {
MGLOG_W("VkFramebufferManager: FBO %u has no valid COLOR0 attachment", glFboExternalIndex);
return false;
}
const auto objectVersion = glFbo.GetObjectVersion();
auto& target = m_offscreenColorTargets[glFboExternalIndex];
if (target.image != VK_NULL_HANDLE && target.glObjectVersion == objectVersion) {
return true;
}
return RecreateOffscreenColorTarget(target, glFbo, colorAttachment, objectVersion);
}
Bool VkFramebufferManager::TransitionOffscreenColorToAttachment(VkCommandBuffer commandBuffer,
Uint glFboExternalIndex) {
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
if (it == m_offscreenColorTargets.end()) {
MGLOG_W("VkFramebufferManager::TransitionOffscreenColorToAttachment skipped: FBO %u not found",
glFboExternalIndex);
return false;
}
auto& target = it->second;
if (!TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_ASPECT_COLOR_BIT)) {
return false;
}
if (target.depthStencilImage == VK_NULL_HANDLE) {
return true;
}
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (target.depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
target.depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
return TransitionImageLayout(
commandBuffer, target.depthStencilImage, target.depthStencilLayout,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, aspectMask);
}
Bool VkFramebufferManager::TransitionOffscreenColorToTransferSrc(VkCommandBuffer commandBuffer,
Uint glFboExternalIndex) {
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
if (it == m_offscreenColorTargets.end()) {
MGLOG_W("VkFramebufferManager::TransitionOffscreenColorToTransferSrc skipped: FBO %u not found",
glFboExternalIndex);
return false;
}
auto& target = it->second;
return TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT);
}
Bool VkFramebufferManager::TransitionOffscreenColorToTransferDst(VkCommandBuffer commandBuffer,
Uint glFboExternalIndex) {
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
if (it == m_offscreenColorTargets.end()) {
MGLOG_W("VkFramebufferManager::TransitionOffscreenColorToTransferDst skipped: FBO %u not found",
glFboExternalIndex);
return false;
}
auto& target = it->second;
return TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT);
}
Bool VkFramebufferManager::TransitionOffscreenColorToGeneral(VkCommandBuffer commandBuffer,
Uint glFboExternalIndex) {
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
if (it == m_offscreenColorTargets.end()) {
MGLOG_W("VkFramebufferManager::TransitionOffscreenColorToGeneral skipped: FBO %u not found",
glFboExternalIndex);
return false;
}
auto& target = it->second;
return TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_GENERAL,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_ASPECT_COLOR_BIT);
}
Bool VkFramebufferManager::TransitionOffscreenDepthStencilToTransferSrc(VkCommandBuffer commandBuffer,
Uint glFboExternalIndex) {
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
if (it == m_offscreenColorTargets.end()) {
MGLOG_W("VkFramebufferManager::TransitionOffscreenDepthStencilToTransferSrc skipped: FBO %u not found",
glFboExternalIndex);
return false;
}
auto& target = it->second;
if (target.depthStencilImage == VK_NULL_HANDLE) {
return false;
}
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (target.depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
target.depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
return TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_READ_BIT, aspectMask);
}
Bool VkFramebufferManager::TransitionOffscreenDepthStencilToTransferDst(VkCommandBuffer commandBuffer,
Uint glFboExternalIndex) {
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
if (it == m_offscreenColorTargets.end()) {
MGLOG_W("VkFramebufferManager::TransitionOffscreenDepthStencilToTransferDst skipped: FBO %u not found",
glFboExternalIndex);
return false;
}
auto& target = it->second;
if (target.depthStencilImage == VK_NULL_HANDLE) {
return false;
}
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (target.depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
target.depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
return TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT, aspectMask);
}
Bool VkFramebufferManager::TransitionOffscreenDepthStencilToGeneral(VkCommandBuffer commandBuffer,
Uint glFboExternalIndex) {
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
if (it == m_offscreenColorTargets.end()) {
MGLOG_W("VkFramebufferManager::TransitionOffscreenDepthStencilToGeneral skipped: FBO %u not found",
glFboExternalIndex);
return false;
}
auto& target = it->second;
if (target.depthStencilImage == VK_NULL_HANDLE) {
return false;
}
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (target.depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
target.depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
return TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout,
VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, aspectMask);
}
Bool VkFramebufferManager::TransitionOffscreenColorTextureToShaderRead(VkCommandBuffer commandBuffer,
Uint textureExternalIndex) {
for (auto& [_, target] : m_offscreenColorTargets) {
if (target.colorTextureExternalIndex != textureExternalIndex || target.image == VK_NULL_HANDLE) {
continue;
}
const Bool fromUndefined = (target.layout == VK_IMAGE_LAYOUT_UNDEFINED);
return TransitionImageLayout(
commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
fromUndefined ? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
: (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT),
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
fromUndefined ? 0 : (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT),
VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT);
}
return false;
}
Bool VkFramebufferManager::GetOffscreenColorImage(Uint glFboExternalIndex, VkImage& outImage,
VkExtent2D& outExtent) const {
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
if (it == m_offscreenColorTargets.end() || it->second.image == VK_NULL_HANDLE) {
return false;
}
outImage = it->second.image;
outExtent = it->second.extent;
return true;
}
Bool VkFramebufferManager::GetOffscreenDepthStencilImage(Uint glFboExternalIndex, VkImage& outImage,
VkExtent2D& outExtent, VkFormat& outFormat) const {
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
if (it == m_offscreenColorTargets.end() || it->second.depthStencilImage == VK_NULL_HANDLE) {
return false;
}
outImage = it->second.depthStencilImage;
outExtent = it->second.extent;
outFormat = it->second.depthStencilFormat;
return true;
}
Bool VkFramebufferManager::GetOffscreenColorViewByTexture(Uint textureExternalIndex,
VkImageView& outImageView) const {
for (const auto& [_, target] : m_offscreenColorTargets) {
if (target.colorTextureExternalIndex != textureExternalIndex || target.imageView == VK_NULL_HANDLE) {
continue;
}
outImageView = target.imageView;
return true;
}
return false;
}
Bool VkFramebufferManager::GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView,
VkFormat& outColorFormat, VkImageView& outDepthStencilView,
VkFormat& outDepthStencilFormat, VkExtent2D& outExtent) const {
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
if (it == m_offscreenColorTargets.end() || it->second.imageView == VK_NULL_HANDLE) {
return false;
}
outColorView = it->second.imageView;
outColorFormat = it->second.format;
outDepthStencilView = it->second.depthStencilImageView;
outExtent = it->second.extent;
outDepthStencilFormat = it->second.depthStencilFormat;
return true;
}
Bool VkFramebufferManager::RecreateOffscreenColorTarget(
OffscreenColorTarget& target, const MG_State::GLState::FramebufferObject& glFbo,
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment, Uint16 glObjectVersion) {
DestroyOffscreenColorTarget(target);
const auto size = colorAttachment.GetSize();
if (size.x() <= 0 || size.y() <= 0) {
MGLOG_W("VkFramebufferManager: COLOR0 attachment size is invalid (%d, %d)", size.x(), size.y());
return false;
}
const VkFormat format = ResolveColorFormat(colorAttachment);
if (format == VK_FORMAT_UNDEFINED) {
MGLOG_W("VkFramebufferManager: COLOR0 attachment format is unsupported for Vulkan clear");
return false;
}
VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = static_cast<Uint32>(size.x());
imageInfo.extent.height = static_cast<Uint32>(size.y());
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.format = format;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_VERIFY(vkCreateImage(m_device, &imageInfo, nullptr, &target.image), "vkCreateImage(offscreen color)");
VkMemoryRequirements memoryRequirements{};
vkGetImageMemoryRequirements(m_device, target.image, &memoryRequirements);
VkMemoryAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memoryRequirements.size;
allocInfo.memoryTypeIndex =
FindMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_VERIFY(vkAllocateMemory(m_device, &allocInfo, nullptr, &target.memory), "vkAllocateMemory(offscreen color)");
VK_VERIFY(vkBindImageMemory(m_device, target.image, target.memory, 0), "vkBindImageMemory(offscreen color)");
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = target.image;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = format;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &target.imageView),
"vkCreateImageView(offscreen color)");
const auto& depthAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Depth);
const auto& stencilAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Stencil);
const Bool requestedDepthStencil = (depthAttachment.IsValid() && !depthAttachment.IsEmpty()) ||
(stencilAttachment.IsValid() && !stencilAttachment.IsEmpty());
VkFormat depthStencilFormat = ResolveDepthStencilFormat(depthAttachment, stencilAttachment);
if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT) {
depthStencilFormat =
FindSupportedDepthStencilFormat({VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT});
} else if (depthStencilFormat == VK_FORMAT_D32_SFLOAT) {
depthStencilFormat = FindSupportedDepthStencilFormat({VK_FORMAT_D32_SFLOAT, VK_FORMAT_D16_UNORM});
}
const Bool hasDepthStencil = (depthStencilFormat != VK_FORMAT_UNDEFINED);
if (requestedDepthStencil && !hasDepthStencil) {
MGLOG_W("VkFramebufferManager: FBO %u depth/stencil attachment exists but format is unsupported",
glFbo.GetExternalIndex());
}
if (hasDepthStencil) {
VkImageCreateInfo depthImageInfo{};
depthImageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
depthImageInfo.extent.width = static_cast<Uint32>(size.x());
depthImageInfo.extent.height = static_cast<Uint32>(size.y());
depthImageInfo.extent.depth = 1;
depthImageInfo.mipLevels = 1;
depthImageInfo.arrayLayers = 1;
depthImageInfo.format = depthStencilFormat;
depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_VERIFY(vkCreateImage(m_device, &depthImageInfo, nullptr, &target.depthStencilImage),
"vkCreateImage(offscreen depth/stencil)");
VkMemoryRequirements depthMemoryRequirements{};
vkGetImageMemoryRequirements(m_device, target.depthStencilImage, &depthMemoryRequirements);
VkMemoryAllocateInfo depthAllocInfo{};
depthAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
depthAllocInfo.allocationSize = depthMemoryRequirements.size;
depthAllocInfo.memoryTypeIndex =
FindMemoryType(depthMemoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_VERIFY(vkAllocateMemory(m_device, &depthAllocInfo, nullptr, &target.depthStencilMemory),
"vkAllocateMemory(offscreen depth/stencil)");
VK_VERIFY(vkBindImageMemory(m_device, target.depthStencilImage, target.depthStencilMemory, 0),
"vkBindImageMemory(offscreen depth/stencil)");
VkImageAspectFlags depthAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
depthAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
VkImageViewCreateInfo depthViewInfo{};
depthViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
depthViewInfo.image = target.depthStencilImage;
depthViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
depthViewInfo.format = depthStencilFormat;
depthViewInfo.subresourceRange.aspectMask = depthAspectMask;
depthViewInfo.subresourceRange.baseMipLevel = 0;
depthViewInfo.subresourceRange.levelCount = 1;
depthViewInfo.subresourceRange.baseArrayLayer = 0;
depthViewInfo.subresourceRange.layerCount = 1;
VK_VERIFY(vkCreateImageView(m_device, &depthViewInfo, nullptr, &target.depthStencilImageView),
"vkCreateImageView(offscreen depth/stencil)");
}
target.layout = VK_IMAGE_LAYOUT_UNDEFINED;
target.extent = {static_cast<Uint32>(size.x()), static_cast<Uint32>(size.y())};
target.format = format;
target.depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
target.depthStencilFormat = depthStencilFormat;
target.glObjectVersion = glObjectVersion;
target.colorTextureExternalIndex = (colorAttachment.IsTexture() && colorAttachment.GetTexture())
? colorAttachment.GetTexture()->GetExternalIndex()
: 0;
return true;
}
void VkFramebufferManager::DestroyOffscreenColorTarget(OffscreenColorTarget& target) {
if (target.imageView != VK_NULL_HANDLE) {
vkDestroyImageView(m_device, target.imageView, nullptr);
target.imageView = VK_NULL_HANDLE;
}
if (target.depthStencilImageView != VK_NULL_HANDLE) {
vkDestroyImageView(m_device, target.depthStencilImageView, nullptr);
target.depthStencilImageView = VK_NULL_HANDLE;
}
if (target.image != VK_NULL_HANDLE) {
vkDestroyImage(m_device, target.image, nullptr);
target.image = VK_NULL_HANDLE;
}
if (target.depthStencilImage != VK_NULL_HANDLE) {
vkDestroyImage(m_device, target.depthStencilImage, nullptr);
target.depthStencilImage = VK_NULL_HANDLE;
}
if (target.memory != VK_NULL_HANDLE) {
vkFreeMemory(m_device, target.memory, nullptr);
target.memory = VK_NULL_HANDLE;
}
if (target.depthStencilMemory != VK_NULL_HANDLE) {
vkFreeMemory(m_device, target.depthStencilMemory, nullptr);
target.depthStencilMemory = VK_NULL_HANDLE;
}
target.layout = VK_IMAGE_LAYOUT_UNDEFINED;
target.depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
target.extent = {0, 0};
target.format = VK_FORMAT_UNDEFINED;
target.depthStencilFormat = VK_FORMAT_UNDEFINED;
target.glObjectVersion = 0;
target.colorTextureExternalIndex = 0;
}
Bool VkFramebufferManager::TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image,
VkImageLayout& trackedLayout, VkImageLayout newLayout,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask) {
if (image == VK_NULL_HANDLE) {
return false;
}
if (trackedLayout == newLayout) {
return true;
}
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.srcAccessMask = srcAccessMask;
barrier.dstAccessMask = dstAccessMask;
barrier.oldLayout = trackedLayout;
barrier.newLayout = newLayout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange.aspectMask = aspectMask;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier);
trackedLayout = newLayout;
return true;
}
Uint32 VkFramebufferManager::FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const {
VkPhysicalDeviceMemoryProperties memoryProperties{};
vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &memoryProperties);
for (Uint32 i = 0; i < memoryProperties.memoryTypeCount; ++i) {
if ((typeFilter & (1U << i)) &&
(memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) {
return i;
}
}
MOBILEGL_ASSERT(false, "VkFramebufferManager::FindMemoryType failed");
return 0;
}
VkFormat VkFramebufferManager::ResolveColorFormat(
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment) {
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
if (colorAttachment.IsTexture()) {
const auto texture = colorAttachment.GetTexture();
internalFormat = texture ? texture->GetFormat() : TextureInternalFormat::Unknown;
} else if (colorAttachment.IsRenderbuffer()) {
const auto renderbuffer = colorAttachment.GetRenderbuffer();
internalFormat = renderbuffer ? renderbuffer->GetInternalFormat() : TextureInternalFormat::Unknown;
}
switch (internalFormat) {
case TextureInternalFormat::RGBA:
case TextureInternalFormat::RGBA8:
case TextureInternalFormat::SRGB8Alpha8:
return VK_FORMAT_R8G8B8A8_UNORM;
default:
return VK_FORMAT_UNDEFINED;
}
}
VkFormat VkFramebufferManager::ResolveDepthStencilFormat(
const MG_State::GLState::FramebufferAttachmentObject& depthAttachment,
const MG_State::GLState::FramebufferAttachmentObject& stencilAttachment) {
const auto resolveAttachmentFormat = [](const MG_State::GLState::FramebufferAttachmentObject& attachment) {
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
if (attachment.IsTexture()) {
const auto texture = attachment.GetTexture();
internalFormat = texture ? texture->GetFormat() : TextureInternalFormat::Unknown;
} else if (attachment.IsRenderbuffer()) {
const auto renderbuffer = attachment.GetRenderbuffer();
internalFormat = renderbuffer ? renderbuffer->GetInternalFormat() : TextureInternalFormat::Unknown;
}
return internalFormat;
};
const auto depthFormat = resolveAttachmentFormat(depthAttachment);
const auto stencilFormat = resolveAttachmentFormat(stencilAttachment);
switch (depthFormat) {
case TextureInternalFormat::Depth24Stencil8:
case TextureInternalFormat::Depth32FStencil8:
case TextureInternalFormat::DepthStencil:
return VK_FORMAT_D24_UNORM_S8_UINT;
case TextureInternalFormat::DepthComponent16:
return VK_FORMAT_D16_UNORM;
case TextureInternalFormat::DepthComponent24:
case TextureInternalFormat::DepthComponent32:
case TextureInternalFormat::DepthComponent32F:
case TextureInternalFormat::DepthComponent:
return VK_FORMAT_D32_SFLOAT;
default:
break;
}
switch (stencilFormat) {
case TextureInternalFormat::Depth24Stencil8:
case TextureInternalFormat::Depth32FStencil8:
case TextureInternalFormat::DepthStencil:
return VK_FORMAT_D24_UNORM_S8_UINT;
default:
return VK_FORMAT_UNDEFINED;
}
}
VkFormat VkFramebufferManager::FindSupportedDepthStencilFormat(const Vector<VkFormat>& candidates) const {
for (auto format : candidates) {
VkFormatProperties properties{};
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, format, &properties);
if ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) {
return format;
}
}
return VK_FORMAT_UNDEFINED;
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,83 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.h
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
#pragma once
#include "../VkIncludes.h"
#include <Includes.h>
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
namespace MobileGL::MG_Backend::DirectVulkan {
class VkFramebufferManager {
public:
struct InitInfo {
VkDevice device = VK_NULL_HANDLE;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
};
VkFramebufferManager() = default;
~VkFramebufferManager() = default;
Bool Initialize(const InitInfo& initInfo);
void Shutdown();
Bool EnsureOffscreenColorTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo);
Bool TransitionOffscreenColorToAttachment(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
Bool TransitionOffscreenColorToTransferSrc(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
Bool TransitionOffscreenColorToTransferDst(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
Bool TransitionOffscreenColorToGeneral(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
Bool TransitionOffscreenDepthStencilToTransferSrc(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
Bool TransitionOffscreenDepthStencilToTransferDst(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
Bool TransitionOffscreenDepthStencilToGeneral(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
Bool TransitionOffscreenColorTextureToShaderRead(VkCommandBuffer commandBuffer, Uint textureExternalIndex);
Bool GetOffscreenColorImage(Uint glFboExternalIndex, VkImage& outImage, VkExtent2D& outExtent) const;
Bool GetOffscreenDepthStencilImage(Uint glFboExternalIndex, VkImage& outImage, VkExtent2D& outExtent,
VkFormat& outFormat) const;
Bool GetOffscreenColorViewByTexture(Uint textureExternalIndex, VkImageView& outImageView) const;
Bool GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView, VkFormat& outColorFormat,
VkImageView& outDepthStencilView, VkFormat& outDepthStencilFormat,
VkExtent2D& outExtent) const;
private:
struct OffscreenColorTarget {
VkImage image = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
VkImageView imageView = VK_NULL_HANDLE;
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
VkExtent2D extent = {0, 0};
VkFormat format = VK_FORMAT_UNDEFINED;
VkImage depthStencilImage = VK_NULL_HANDLE;
VkDeviceMemory depthStencilMemory = VK_NULL_HANDLE;
VkImageView depthStencilImageView = VK_NULL_HANDLE;
VkImageLayout depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
Uint16 glObjectVersion = 0;
Uint colorTextureExternalIndex = 0;
};
Bool RecreateOffscreenColorTarget(OffscreenColorTarget& target,
const MG_State::GLState::FramebufferObject& glFbo,
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment,
Uint16 glObjectVersion);
void DestroyOffscreenColorTarget(OffscreenColorTarget& target);
Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout,
VkImageLayout newLayout, VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask);
Uint32 FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const;
static VkFormat ResolveColorFormat(const MG_State::GLState::FramebufferAttachmentObject& colorAttachment);
static VkFormat ResolveDepthStencilFormat(
const MG_State::GLState::FramebufferAttachmentObject& depthAttachment,
const MG_State::GLState::FramebufferAttachmentObject& stencilAttachment);
VkFormat FindSupportedDepthStencilFormat(const Vector<VkFormat>& candidates) const;
VkDevice m_device = VK_NULL_HANDLE;
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
UnorderedMap<Uint, OffscreenColorTarget> m_offscreenColorTargets;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -8,340 +8,463 @@
#include "VkRenderPassManager.h" #include "VkRenderPassManager.h"
namespace MobileGL::MG_Backend::DirectVulkan { #include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
Bool VkRenderPassManager::Initialize(const InitInfo& initInfo) { #include "MG_State/GLState/TextureState/TextureObject2D.h"
Shutdown(); #include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
if (initInfo.device == VK_NULL_HANDLE || initInfo.colorFormat == VK_FORMAT_UNDEFINED || namespace MobileGL::MG_Backend::DirectVulkan {
initInfo.depthStencilFormat == VK_FORMAT_UNDEFINED) { VkRenderPassManager::VkRenderPassManager(VkDevice device,
return false; const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager,
SwapchainObject& swapchainObject):
m_device(device), m_config(config), m_clearManager(clearManager), m_textureManager(textureManager),
m_swapchainObject(swapchainObject) {
RenderPassEntry::s_device = m_device;
s_clearManager = &m_clearManager;
s_textureManager = &m_textureManager;
s_swapchainObject = &m_swapchainObject;
} }
m_device = initInfo.device; VkRenderPassManager::~VkRenderPassManager() {}
m_colorFormat = initInfo.colorFormat;
m_depthStencilFormat = initInfo.depthStencilFormat; Bool VkRenderPassManager::Initialize() {
m_renderPassLoad = CreateDefaultRenderPass(VK_ATTACHMENT_LOAD_OP_LOAD); return true;
m_renderPassClear = CreateDefaultRenderPass(VK_ATTACHMENT_LOAD_OP_CLEAR);
MGLOG_D("VkRenderPassManager: RenderPasses created (LOAD/CLEAR).");
return m_renderPassLoad != VK_NULL_HANDLE && m_renderPassClear != VK_NULL_HANDLE;
} }
void VkRenderPassManager::Shutdown() { void VkRenderPassManager::Shutdown() {
DestroyDefaultFramebuffers();
for (auto& [_, target] : m_offscreenRenderTargets) {
DestroyOffscreenRenderTarget(target);
} }
m_offscreenRenderTargets.clear();
if (m_device != VK_NULL_HANDLE) { VkRenderPassManager::HashType VkRenderPassManager::ComputeHash(
if (m_renderPassClear != VK_NULL_HANDLE) { const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex, Bool includePendingClear) const {
vkDestroyRenderPass(m_device, m_renderPassClear, nullptr); XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion));
const Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
if (isDefaultFbo) {
XXHASH_VERIFY(XXH64_update(m_hashState, &swapchainImageIndex, sizeof(swapchainImageIndex)));
} }
if (m_renderPassLoad != VK_NULL_HANDLE) { auto& drawBuffers = fbo.GetDrawBuffers();
vkDestroyRenderPass(m_device, m_renderPassLoad, nullptr); XXHASH_VERIFY(XXH64_update(m_hashState, drawBuffers.data(), drawBuffers.size() * sizeof(drawBuffers[0])));
auto readBuffer = fbo.GetReadBuffer();
XXHASH_VERIFY(XXH64_update(m_hashState, &readBuffer, sizeof(FramebufferAttachmentType)));
Int validDrawBufCount = 0;
for (Int i = 0; i < drawBuffers.size(); ++i) {
auto drawbuf = drawBuffers[i];
if (drawbuf != FramebufferAttachmentType::None)
validDrawBufCount = std::max(validDrawBufCount, i + 1);
}
XXHASH_VERIFY(XXH64_update(m_hashState, &validDrawBufCount, sizeof(validDrawBufCount)));
auto combineFramebufferAttachmentObjHash = [&](FramebufferAttachmentType attachment) {
auto& att = fbo.GetAttachment(attachment);
Int type = 0;
if (att.IsEmpty()) type = 0;
else if (att.IsTexture()) type = 1;
else if (att.IsRenderbuffer()) type = 2;
XXHASH_VERIFY(XXH64_update(m_hashState, &type, sizeof(type)));
void* contentPtr = nullptr;
if (att.IsTexture())
contentPtr = att.GetTexture().get();
else if (att.IsRenderbuffer())
contentPtr = att.GetRenderbuffer().get();
XXHASH_VERIFY(XXH64_update(m_hashState, &contentPtr, sizeof(contentPtr)));
if (includePendingClear && att.IsTexture()) {
auto* texture = att.GetTexture().get();
auto hasClear = m_clearManager.HasPendingClear(texture);
XXHASH_VERIFY(XXH64_update(m_hashState, &hasClear, sizeof(hasClear)));
if (hasClear) {
ClearAttachmentPayload clearPayload{};
Bool hasPayload = m_clearManager.GetPendingClear(texture, clearPayload);
XXHASH_VERIFY(XXH64_update(m_hashState, &hasPayload, sizeof(hasPayload)));
if (hasPayload) {
XXHASH_VERIFY(XXH64_update(
m_hashState, &clearPayload.attachmentType, sizeof(clearPayload.attachmentType)));
} }
} }
m_renderPassClear = VK_NULL_HANDLE; VkImageLayout currentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
m_renderPassLoad = VK_NULL_HANDLE; if (isDefaultFbo) {
m_colorFormat = VK_FORMAT_UNDEFINED; if (attachment >= FramebufferAttachmentType::Color0 &&
m_depthStencilFormat = VK_FORMAT_UNDEFINED; attachment <= FramebufferAttachmentType::Color31) {
m_defaultExtent = {0, 0}; currentLayout = m_swapchainObject.GetImageLayout(swapchainImageIndex);
m_device = VK_NULL_HANDLE; } else if (attachment == FramebufferAttachmentType::Depth ||
attachment == FramebufferAttachmentType::Stencil) {
currentLayout = m_swapchainObject.GetDepthStencilImageLayout(swapchainImageIndex);
}
} else {
auto* resource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
if (resource != nullptr) {
currentLayout = resource->layout;
}
}
XXHASH_VERIFY(XXH64_update(m_hashState, &currentLayout, sizeof(currentLayout)));
}
};
for (Int i = 0; i < validDrawBufCount; ++i) {
auto drawbuf = drawBuffers[i];
combineFramebufferAttachmentObjHash(drawbuf);
} }
Bool VkRenderPassManager::RecreateDefaultFramebuffers(const Vector<VkImageView>& colorViews, combineFramebufferAttachmentObjHash(FramebufferAttachmentType::Depth);
const Vector<VkImageView>& depthStencilViews, combineFramebufferAttachmentObjHash(FramebufferAttachmentType::Stencil);
VkExtent2D extent) {
DestroyDefaultFramebuffers();
if (m_device == VK_NULL_HANDLE || m_renderPassLoad == VK_NULL_HANDLE || extent.width == 0 || return XXH64_digest(m_hashState);
extent.height == 0 || colorViews.empty() || colorViews.size() != depthStencilViews.size()) {
return false;
} }
m_defaultFramebuffers.reserve(colorViews.size()); RenderPassEntry& VkRenderPassManager::GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo,
for (SizeT i = 0; i < colorViews.size(); ++i) { Uint32 swapchainImageIndex) {
if (colorViews[i] == VK_NULL_HANDLE || depthStencilViews[i] == VK_NULL_HANDLE) { // retrieve from cache first
DestroyDefaultFramebuffers(); auto* activeRenderPass = GetActiveRenderPass();
return false; auto compatibilityHash = ComputeHash(fbo, swapchainImageIndex, false);
if (activeRenderPass != nullptr && activeRenderPass->CompatibleWith(compatibilityHash)) {
auto activeIt = m_renderPasses.find(activeRenderPass->hash);
MOBILEGL_ASSERT(activeIt != m_renderPasses.end(),
"GetOrCreateRenderPass: active render pass hash=0x%llx is missing from cache",
static_cast<unsigned long long>(activeRenderPass->hash));
return activeIt->second;
} }
VkImageView attachments[] = {colorViews[i], depthStencilViews[i]}; auto hash = ComputeHash(fbo, swapchainImageIndex, true);
VkFramebufferCreateInfo createInfo{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; auto it = m_renderPasses.find(hash);
createInfo.renderPass = m_renderPassLoad; if (it != m_renderPasses.end())
createInfo.attachmentCount = static_cast<Uint32>(std::size(attachments)); return it->second;
createInfo.pAttachments = attachments;
createInfo.width = extent.width; Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
createInfo.height = extent.height; // Color attachment
createInfo.layers = 1; auto& drawbufs = fbo.GetDrawBuffers();
VkFramebuffer framebuffer = VK_NULL_HANDLE; Int validDrawBufCount = 0;
if (vkCreateFramebuffer(m_device, &createInfo, nullptr, &framebuffer) != VK_SUCCESS) { for (Int i = 0; i < drawbufs.size(); ++i) {
DestroyDefaultFramebuffers(); auto drawbuf = drawbufs[i];
return false; if (drawbuf != FramebufferAttachmentType::None)
} validDrawBufCount = std::max(validDrawBufCount, i + 1);
m_defaultFramebuffers.push_back(framebuffer);
}
m_defaultExtent = extent;
return true;
} }
Bool VkRenderPassManager::GetDefaultRenderTarget(Uint32 imageIndex, VkRenderPass& outRenderPass, Int width = 0;
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent, Int height = 0;
VkFormat& outDepthStencilFormat) const { Vector<VkAttachmentDescription> attachmentDescriptions(validDrawBufCount);
if (imageIndex >= m_defaultFramebuffers.size() || m_renderPassLoad == VK_NULL_HANDLE) { Vector<VkAttachmentReference> colorAttachmentRefs(validDrawBufCount);
return false; Vector<PendingClearAttachmentInfo> pendingClearAttachments;
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
auto& textureResources = RenderPassEntry::s_textureResourcesScratch;
textureResources.clear();
textureResources.resize(validDrawBufCount, nullptr);
Vector<VkImageView> attachmentViews(validDrawBufCount, VK_NULL_HANDLE);
// This should automatically work on default & offscreen FBO
// assuming default FBO has the right param
for (Int i = 0; i < validDrawBufCount; ++i) {
auto drawbuf = drawbufs[i];
if (drawbuf == FramebufferAttachmentType::None ||
fbo.GetAttachment(drawbuf).IsRenderbuffer())
continue;
auto& att = fbo.GetAttachment(drawbuf);
auto* texture = att.GetTexture().get();
const auto textureTarget = texture->GetTarget();
// Color attachment description
VkAttachmentDescription& desc = attachmentDescriptions[i];
switch (textureTarget) {
case TextureTarget::Texture2D: {
auto* texture2d =
static_cast<MG_State::GLState::TextureObject2D*>(texture);
desc.flags = 0;
desc.format =
MG_Util::ConvertTextureInternalFormatToVkEnum(
texture2d->GetFormat());
desc.samples = VK_SAMPLE_COUNT_1_BIT;
ClearAttachmentPayload clearPayload{};
Bool hasClear = m_clearManager.GetPendingClear(texture, clearPayload);
VkImageLayout trackedColorLayout = VK_IMAGE_LAYOUT_UNDEFINED;
desc.loadOp = hasClear ?
VK_ATTACHMENT_LOAD_OP_CLEAR :
VK_ATTACHMENT_LOAD_OP_LOAD;
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
desc.finalLayout = isDefaultFbo ?
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR :
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
if (hasClear) {
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
.attachmentIndex = static_cast<Uint32>(i),
.texture = texture
});
} }
outRenderPass = m_renderPassLoad; if (width == 0)
outFramebuffer = m_defaultFramebuffers[imageIndex]; width = texture2d->GetBaseSize().x();
outExtent = m_defaultExtent; if (height == 0)
outDepthStencilFormat = m_depthStencilFormat; height = texture2d->GetBaseSize().y();
return outFramebuffer != VK_NULL_HANDLE;
if (isDefaultFbo) {
const auto& swapchainViews = m_swapchainObject.GetImageViews();
MOBILEGL_ASSERT(swapchainImageIndex < swapchainViews.size(),
"GetOrCreateRenderPass: swapchain image index out of range");
trackedColorLayout = m_swapchainObject.GetImageLayout(swapchainImageIndex);
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
.target = TrackedAttachmentTarget::SwapchainColor,
.swapchainImageIndex = swapchainImageIndex,
.finalLayout = desc.finalLayout,
});
attachmentViews[i] = swapchainViews[swapchainImageIndex];
} else {
textureResources[i] = m_textureManager.SyncTextureAndGetDescriptor(*texture);
MOBILEGL_ASSERT(textureResources[i],
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i);
trackedColorLayout = textureResources[i]->layout;
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
.target = TrackedAttachmentTarget::Texture,
.texture = texture,
.finalLayout = desc.finalLayout,
});
attachmentViews[i] = textureResources[i]->view;
} }
Bool VkRenderPassManager::EnsureOffscreenRenderTarget(const OffscreenRenderTargetInfo& targetInfo) { if (!hasClear && trackedColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
if (m_device == VK_NULL_HANDLE || targetInfo.colorView == VK_NULL_HANDLE || MGLOG_W("GetOrCreateRenderPass: color attachment textureId=%d starts with undefined layout and no clear; "
targetInfo.colorFormat == VK_FORMAT_UNDEFINED || targetInfo.extent.width == 0 || "using LOAD_OP_DONT_CARE",
targetInfo.extent.height == 0) { texture->GetExternalIndex());
return false; desc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
}
desc.initialLayout = (hasClear || trackedColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) ?
VK_IMAGE_LAYOUT_UNDEFINED :
trackedColorLayout;
break;
}
default:
MOBILEGL_ASSERT(false, "Unsupported texture target");
} }
const Bool hasDepthStencil = // Attachment reference
targetInfo.depthStencilView != VK_NULL_HANDLE && targetInfo.depthStencilFormat != VK_FORMAT_UNDEFINED; VkAttachmentReference& attachmentRef = colorAttachmentRefs[i];
attachmentRef.attachment = i;
auto& target = m_offscreenRenderTargets[targetInfo.targetExternalIndex]; attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
if (target.framebuffer != VK_NULL_HANDLE && target.renderPassLoad != VK_NULL_HANDLE &&
target.targetVersion == targetInfo.targetVersion && target.colorView == targetInfo.colorView &&
target.colorFormat == targetInfo.colorFormat && target.depthStencilView == targetInfo.depthStencilView &&
target.depthStencilFormat == targetInfo.depthStencilFormat &&
target.extent.width == targetInfo.extent.width && target.extent.height == targetInfo.extent.height) {
return true;
} }
DestroyOffscreenRenderTarget(target); // Depth attachment description
auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth);
const VkFormat depthStencilFormat = hasDepthStencil ? targetInfo.depthStencilFormat : VK_FORMAT_UNDEFINED; VkAttachmentDescription depthAttachmentDescription;
target.renderPassLoad = CreateRenderPass(targetInfo.colorFormat, depthStencilFormat, VK_ATTACHMENT_LOAD_OP_LOAD, VkAttachmentReference depthAttachmentRef;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); depthAttachmentRef.attachment = VK_ATTACHMENT_UNUSED;
if (target.renderPassLoad == VK_NULL_HANDLE) { depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
return false; VkTextureManager::TextureResource* depthTextureResource = nullptr;
if (depthAtt.IsComplete() && depthAtt.IsTexture()) {
auto& texture = *depthAtt.GetTexture();
const Uint32 depthAttachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
ClearAttachmentPayload clearPayload{};
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
Bool clearDepth = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Depth;
Bool clearStencil = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Stencil;
VkImageLayout trackedDepthLayout = isDefaultFbo ?
m_swapchainObject.GetDepthStencilImageLayout(swapchainImageIndex) :
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
if (!isDefaultFbo) {
depthTextureResource = m_textureManager.SyncTextureAndGetDescriptor(texture);
MOBILEGL_ASSERT(depthTextureResource,
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment");
trackedDepthLayout = depthTextureResource->layout;
}
depthAttachmentDescription.flags = 0;
depthAttachmentDescription.format =
MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachmentDescription.loadOp = clearDepth ?
VK_ATTACHMENT_LOAD_OP_CLEAR :
VK_ATTACHMENT_LOAD_OP_LOAD;
depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachmentDescription.stencilLoadOp = clearStencil ?
VK_ATTACHMENT_LOAD_OP_CLEAR :
VK_ATTACHMENT_LOAD_OP_LOAD;
depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
if (trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
if (!clearDepth) {
depthAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
}
if (!clearStencil) {
depthAttachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
}
}
depthAttachmentDescription.initialLayout =
(clearDepth && clearStencil) || trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED ?
VK_IMAGE_LAYOUT_UNDEFINED :
trackedDepthLayout;
if (hasClear) {
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
.attachmentIndex = depthAttachmentIndex,
.texture = &texture
});
}
if (isDefaultFbo) {
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
.target = TrackedAttachmentTarget::SwapchainDepthStencil,
.swapchainImageIndex = swapchainImageIndex,
.finalLayout = depthAttachmentDescription.finalLayout,
});
attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex));
} else {
MOBILEGL_ASSERT(clearDepth || clearStencil || depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED,
"GetOrCreateRenderPass: depth attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD",
texture.GetExternalIndex());
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
.target = TrackedAttachmentTarget::Texture,
.texture = &texture,
.finalLayout = depthAttachmentDescription.finalLayout,
});
textureResources.emplace_back(depthTextureResource);
attachmentViews.emplace_back(depthTextureResource->view);
if (width == 0 || height == 0) {
auto texture2d = static_cast<MG_State::GLState::TextureObject2D*>(&texture);
width = texture2d->GetBaseSize().x();
height = texture2d->GetBaseSize().y();
}
}
attachmentDescriptions.emplace_back(depthAttachmentDescription);
depthAttachmentRef.attachment = depthAttachmentIndex;
} }
Array<VkImageView, 2> attachments{}; // Subpass
attachments[0] = targetInfo.colorView; VkSubpassDescription subpassDesc;
Uint32 attachmentCount = 1; subpassDesc.flags = 0;
if (hasDepthStencil) { subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
attachments[1] = targetInfo.depthStencilView; subpassDesc.inputAttachmentCount = 0;
attachmentCount = 2; subpassDesc.pInputAttachments = nullptr;
} subpassDesc.colorAttachmentCount = colorAttachmentRefs.size();
subpassDesc.pColorAttachments = colorAttachmentRefs.data();
subpassDesc.pResolveAttachments = nullptr;
subpassDesc.pDepthStencilAttachment = depthAtt.IsComplete() ? &depthAttachmentRef : VK_NULL_HANDLE;
subpassDesc.preserveAttachmentCount = 0;
subpassDesc.pPreserveAttachments = nullptr;
VkFramebufferCreateInfo framebufferInfo{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; // Render Pass
framebufferInfo.renderPass = target.renderPassLoad; VkRenderPassCreateInfo renderPassCreateInfo;
framebufferInfo.attachmentCount = attachmentCount; renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
framebufferInfo.pAttachments = attachments.data(); renderPassCreateInfo.pNext = VK_NULL_HANDLE;
framebufferInfo.width = targetInfo.extent.width; renderPassCreateInfo.flags = 0;
framebufferInfo.height = targetInfo.extent.height; renderPassCreateInfo.attachmentCount = attachmentDescriptions.size();
framebufferInfo.layers = 1; renderPassCreateInfo.pAttachments = attachmentDescriptions.data();
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &target.framebuffer), renderPassCreateInfo.subpassCount = 1;
"vkCreateFramebuffer(offscreen)"); renderPassCreateInfo.pSubpasses = &subpassDesc;
renderPassCreateInfo.dependencyCount = 0;
target.targetVersion = targetInfo.targetVersion; renderPassCreateInfo.pDependencies = nullptr;
target.colorView = targetInfo.colorView;
target.colorFormat = targetInfo.colorFormat;
target.depthStencilView = targetInfo.depthStencilView;
target.depthStencilFormat = targetInfo.depthStencilFormat;
target.extent = targetInfo.extent;
return true;
}
Bool VkRenderPassManager::GetOffscreenRenderTarget(Uint targetExternalIndex, VkRenderPass& outRenderPass,
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
VkFormat& outDepthStencilFormat) const {
auto it = m_offscreenRenderTargets.find(targetExternalIndex);
if (it == m_offscreenRenderTargets.end() || it->second.renderPassLoad == VK_NULL_HANDLE ||
it->second.framebuffer == VK_NULL_HANDLE) {
return false;
}
outRenderPass = it->second.renderPassLoad;
outFramebuffer = it->second.framebuffer;
outExtent = it->second.extent;
outDepthStencilFormat = it->second.depthStencilFormat;
return true;
}
void VkRenderPassManager::RemoveOffscreenRenderTarget(Uint targetExternalIndex) {
auto it = m_offscreenRenderTargets.find(targetExternalIndex);
if (it == m_offscreenRenderTargets.end()) {
return;
}
DestroyOffscreenRenderTarget(it->second);
m_offscreenRenderTargets.erase(it);
}
void VkRenderPassManager::BeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass,
VkFramebuffer framebuffer, VkExtent2D extent) const {
VkRenderPassBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
beginInfo.renderPass = renderPass;
beginInfo.framebuffer = framebuffer;
beginInfo.renderArea.offset = {0, 0};
beginInfo.renderArea.extent = extent;
beginInfo.clearValueCount = 0;
beginInfo.pClearValues = nullptr;
vkCmdBeginRenderPass(commandBuffer, &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
void VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) const {
vkCmdEndRenderPass(commandBuffer);
}
void VkRenderPassManager::RecordColorClear(VkCommandBuffer commandBuffer, VkExtent2D extent,
const VkClearColorValue& clearColor) const {
VkClearAttachment clearAttachment{};
clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clearAttachment.colorAttachment = 0;
clearAttachment.clearValue.color = clearColor;
VkClearRect clearRect{};
clearRect.rect.offset = {0, 0};
clearRect.rect.extent = extent;
clearRect.baseArrayLayer = 0;
clearRect.layerCount = 1;
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
}
void VkRenderPassManager::RecordDepthStencilClear(VkCommandBuffer commandBuffer, VkExtent2D extent, GLbitfield mask,
Float depth, Uint32 stencil, VkFormat depthStencilFormat) const {
if (depthStencilFormat == VK_FORMAT_UNDEFINED) {
return;
}
VkImageAspectFlags aspectMask = 0;
if ((mask & GL_DEPTH_BUFFER_BIT) != 0) {
aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
}
if ((mask & GL_STENCIL_BUFFER_BIT) != 0 && HasStencilComponent(depthStencilFormat)) {
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
if (aspectMask == 0) {
return;
}
VkClearAttachment clearAttachment{};
clearAttachment.aspectMask = aspectMask;
clearAttachment.clearValue.depthStencil.depth = depth;
clearAttachment.clearValue.depthStencil.stencil = stencil;
VkClearRect clearRect{};
clearRect.rect.offset = {0, 0};
clearRect.rect.extent = extent;
clearRect.baseArrayLayer = 0;
clearRect.layerCount = 1;
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
}
VkRenderPass VkRenderPassManager::GetLoadRenderPass() const {
return m_renderPassLoad;
}
VkRenderPass VkRenderPassManager::GetClearRenderPass() const {
return m_renderPassClear;
}
VkRenderPass VkRenderPassManager::CreateDefaultRenderPass(VkAttachmentLoadOp colorLoadOp) const {
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "VkRenderPassManager: device is null");
MOBILEGL_ASSERT(m_colorFormat != VK_FORMAT_UNDEFINED, "VkRenderPassManager: color format is undefined");
MOBILEGL_ASSERT(m_depthStencilFormat != VK_FORMAT_UNDEFINED,
"VkRenderPassManager: depth/stencil format is undefined");
return CreateRenderPass(m_colorFormat, m_depthStencilFormat, colorLoadOp, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
}
VkRenderPass VkRenderPassManager::CreateRenderPass(VkFormat colorFormat, VkFormat depthStencilFormat,
VkAttachmentLoadOp colorLoadOp,
VkImageLayout colorFinalLayout) const {
VkAttachmentDescription color{};
color.format = colorFormat;
color.samples = VK_SAMPLE_COUNT_1_BIT;
color.loadOp = colorLoadOp;
color.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
color.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color.finalLayout = colorFinalLayout;
color.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
color.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
const Bool hasDepthStencil = depthStencilFormat != VK_FORMAT_UNDEFINED;
VkAttachmentDescription depthStencil{};
if (hasDepthStencil) {
depthStencil.format = depthStencilFormat;
depthStencil.samples = VK_SAMPLE_COUNT_1_BIT;
depthStencil.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depthStencil.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthStencil.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depthStencil.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthStencil.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthStencil.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
VkAttachmentReference colorRef{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
VkAttachmentReference depthStencilRef{1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorRef;
if (hasDepthStencil) {
subpass.pDepthStencilAttachment = &depthStencilRef;
}
Array<VkAttachmentDescription, 2> attachments{};
attachments[0] = color;
Uint32 attachmentCount = 1;
if (hasDepthStencil) {
attachments[1] = depthStencil;
attachmentCount = 2;
}
VkRenderPassCreateInfo createInfo{VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
createInfo.attachmentCount = attachmentCount;
createInfo.pAttachments = attachments.data();
createInfo.subpassCount = 1;
createInfo.pSubpasses = &subpass;
VkRenderPass renderPass = VK_NULL_HANDLE; VkRenderPass renderPass = VK_NULL_HANDLE;
VK_VERIFY(vkCreateRenderPass(m_device, &createInfo, nullptr, &renderPass), "vkCreateRenderPass"); VK_VERIFY(vkCreateRenderPass(m_device, &renderPassCreateInfo, nullptr, &renderPass));
return renderPass;
// Framebuffer
VkFramebufferCreateInfo framebufferCreateInfo;
framebufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferCreateInfo.pNext = nullptr;
framebufferCreateInfo.flags = 0;
framebufferCreateInfo.renderPass = renderPass;
framebufferCreateInfo.attachmentCount = attachmentViews.size();
framebufferCreateInfo.pAttachments = attachmentViews.data();
framebufferCreateInfo.width = width;
framebufferCreateInfo.height = height;
framebufferCreateInfo.layers = 1;
VkFramebuffer framebuffer = VK_NULL_HANDLE;
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer));
IntVec2 extent = {width, height};
RenderPassEntry renderPassEntry {
hash,
renderPass,
framebuffer,
compatibilityHash,
Move(pendingClearAttachments),
Move(trackedAttachmentLayouts),
static_cast<Uint32>(attachmentViews.size()),
extent,
1 };
auto [insertedIt, _] = m_renderPasses.emplace(hash, Move(renderPassEntry));
return insertedIt->second;
} }
void VkRenderPassManager::DestroyDefaultFramebuffers() { Bool VkRenderPassManager::BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry) {
for (auto framebuffer : m_defaultFramebuffers) { // TODO: Transition all the attachments into proper layout before starting the render pass
if (framebuffer != VK_NULL_HANDLE) { VkRenderPassBeginInfo renderPassBeginInfo;
vkDestroyFramebuffer(m_device, framebuffer, nullptr); renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = nullptr;
renderPassBeginInfo.renderPass = renderPassEntry.renderPass;
renderPassBeginInfo.framebuffer = renderPassEntry.framebuffer;
renderPassBeginInfo.renderArea.offset = { 0, 0 };
renderPassBeginInfo.renderArea.extent = {
(Uint32)renderPassEntry.extent.x(), (Uint32)renderPassEntry.extent.y() };
Vector<VkClearValue> clearValues(renderPassEntry.attachmentCount);
for (auto& clearValue: clearValues) {
clearValue.color = {0.0f, 0.0f, 0.0f, 1.0f};
clearValue.depthStencil = {1.0f, 0};
} }
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
if (!pending.texture || pending.attachmentIndex >= clearValues.size()) {
continue;
}
ClearAttachmentPayload clearPayload{};
if (!s_clearManager->GetPendingClear(pending.texture, clearPayload)) {
continue;
}
if (clearPayload.attachmentType >= FramebufferAttachmentType::Color0 &&
clearPayload.attachmentType <= FramebufferAttachmentType::Color31) {
clearValues[pending.attachmentIndex].color = {
clearPayload.color.x(),
clearPayload.color.y(),
clearPayload.color.z(),
clearPayload.color.w()
};
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Depth) {
clearValues[pending.attachmentIndex].depthStencil.depth = clearPayload.depth;
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Stencil) {
clearValues[pending.attachmentIndex].depthStencil.stencil = clearPayload.stencil;
} }
m_defaultFramebuffers.clear();
m_defaultExtent = {0, 0};
} }
void VkRenderPassManager::DestroyOffscreenRenderTarget(OffscreenRenderTarget& target) { renderPassBeginInfo.clearValueCount = static_cast<Uint32>(clearValues.size());
if (target.framebuffer != VK_NULL_HANDLE) { renderPassBeginInfo.pClearValues = clearValues.data();
vkDestroyFramebuffer(m_device, target.framebuffer, nullptr);
target.framebuffer = VK_NULL_HANDLE; vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
s_clearManager->PopPendingClear(pending.texture);
} }
if (target.renderPassLoad != VK_NULL_HANDLE) { s_activeRenderPass.hash = renderPassEntry.hash;
vkDestroyRenderPass(m_device, target.renderPassLoad, nullptr); s_activeRenderPass.compatibilityHash = renderPassEntry.compatibilityHash;
target.renderPassLoad = VK_NULL_HANDLE; s_activeRenderPass.trackedAttachmentLayouts = renderPassEntry.trackedAttachmentLayouts;
} s_activeRenderPass.extent = renderPassEntry.extent;
target.targetVersion = 0; s_hasActiveRenderPass = true;
target.colorView = VK_NULL_HANDLE;
target.colorFormat = VK_FORMAT_UNDEFINED; return true;
target.depthStencilView = VK_NULL_HANDLE;
target.depthStencilFormat = VK_FORMAT_UNDEFINED;
target.extent = {0, 0};
} }
Bool VkRenderPassManager::HasStencilComponent(VkFormat format) { Bool VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) {
return format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT; auto* activeRenderPass = GetActiveRenderPass();
vkCmdEndRenderPass(commandBuffer);
if (activeRenderPass != nullptr && !activeRenderPass->trackedAttachmentLayouts.empty()) {
for (const auto& trackedAttachment : activeRenderPass->trackedAttachmentLayouts) {
switch (trackedAttachment.target) {
case TrackedAttachmentTarget::Texture:
MOBILEGL_ASSERT(s_textureManager != nullptr, "EndRenderPass: texture manager is null");
s_textureManager->UpdateTrackedImageLayout(trackedAttachment.texture, trackedAttachment.finalLayout);
break;
case TrackedAttachmentTarget::SwapchainColor:
MOBILEGL_ASSERT(s_swapchainObject != nullptr, "EndRenderPass: swapchain object is null");
s_swapchainObject->SetImageLayout(trackedAttachment.swapchainImageIndex, trackedAttachment.finalLayout);
break;
case TrackedAttachmentTarget::SwapchainDepthStencil:
MOBILEGL_ASSERT(s_swapchainObject != nullptr, "EndRenderPass: swapchain object is null");
s_swapchainObject->SetDepthStencilImageLayout(trackedAttachment.swapchainImageIndex,
trackedAttachment.finalLayout);
break;
default:
MOBILEGL_ASSERT(false, "EndRenderPass: unsupported tracked attachment target=%d",
static_cast<Int>(trackedAttachment.target));
break;
}
}
}
s_activeRenderPass = {};
s_hasActiveRenderPass = false;
return true;
}
ActiveRenderPassInfo* VkRenderPassManager::GetActiveRenderPass() {
return s_hasActiveRenderPass ? &s_activeRenderPass : nullptr;
} }
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -8,79 +8,144 @@
#pragma once #pragma once
#include "SwapchainObject.h"
#include "VkClearManager.h"
#include "VkTextureManager.h"
#include "../VkIncludes.h" #include "../VkIncludes.h"
#include "../VulkanRendererConfig.h"
#include "MG_State/GLState/FramebufferState/FramebufferObject.h"
#include <Includes.h> #include <Includes.h>
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkan {
enum class TrackedAttachmentTarget : Uint8 {
Texture,
SwapchainColor,
SwapchainDepthStencil
};
struct PendingClearAttachmentInfo {
Uint32 attachmentIndex = 0;
MG_State::GLState::ITextureObject* texture = nullptr;
};
struct TrackedAttachmentLayoutInfo {
TrackedAttachmentTarget target = TrackedAttachmentTarget::Texture;
MG_State::GLState::ITextureObject* texture = nullptr;
Uint32 swapchainImageIndex = 0;
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
};
struct RenderPassEntry {
static inline VkDevice s_device;
static inline Vector<VkTextureManager::TextureResource*> s_textureResourcesScratch;
Uint64 hash = 0;
VkRenderPass renderPass = VK_NULL_HANDLE;
VkFramebuffer framebuffer = VK_NULL_HANDLE;
Uint64 compatibilityHash = 0;
Vector<PendingClearAttachmentInfo> pendingClearAttachments;
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
Uint32 attachmentCount = 0;
IntVec2 extent = {0, 0};
Uint32 subpass = 0;
RenderPassEntry() = default;
RenderPassEntry(const RenderPassEntry&) = delete;
RenderPassEntry(RenderPassEntry&& that) noexcept {
std::swap(hash, that.hash);
std::swap(renderPass, that.renderPass);
std::swap(framebuffer, that.framebuffer);
std::swap(compatibilityHash, that.compatibilityHash);
std::swap(pendingClearAttachments, that.pendingClearAttachments);
std::swap(trackedAttachmentLayouts, that.trackedAttachmentLayouts);
std::swap(attachmentCount, that.attachmentCount);
std::swap(extent, that.extent);
std::swap(subpass, that.subpass);
}
RenderPassEntry(
Uint64 hash,
VkRenderPass renderpass,
VkFramebuffer framebuffer,
Uint64 compatibilityHash,
const Vector<PendingClearAttachmentInfo>& pendingClearAttachments,
const Vector<TrackedAttachmentLayoutInfo>& trackedAttachmentLayouts,
Uint32 attachmentCount,
IntVec2 extent, int subpass):
hash(hash),
renderPass(renderpass),
framebuffer(framebuffer),
compatibilityHash(compatibilityHash),
pendingClearAttachments(Move(pendingClearAttachments)),
trackedAttachmentLayouts(Move(trackedAttachmentLayouts)),
attachmentCount(attachmentCount),
extent(extent),
subpass(subpass)
{}
~RenderPassEntry() {
if (renderPass != VK_NULL_HANDLE) {
vkDestroyRenderPass(s_device, renderPass, nullptr);
}
if (framebuffer != VK_NULL_HANDLE) {
vkDestroyFramebuffer(s_device, framebuffer, nullptr);
}
}
Bool CompatibleWith(const RenderPassEntry& that) const {
return this->compatibilityHash == that.compatibilityHash;
}
Bool CompatibleWith(Uint64 compatibilityHash) const {
return this->compatibilityHash == compatibilityHash;
}
};
struct ActiveRenderPassInfo {
Uint64 hash = 0;
Uint64 compatibilityHash = 0;
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
IntVec2 extent = {0, 0};
Bool CompatibleWith(const RenderPassEntry& that) const {
return compatibilityHash == that.compatibilityHash;
}
Bool CompatibleWith(Uint64 thatCompatibilityHash) const {
return compatibilityHash == thatCompatibilityHash;
}
};
class VkRenderPassManager { class VkRenderPassManager {
public: public:
struct InitInfo { using HashType = Uint64;
VkDevice device = VK_NULL_HANDLE; VkRenderPassManager(VkDevice device,
VkFormat colorFormat = VK_FORMAT_UNDEFINED; const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager,
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; SwapchainObject& swapchainObject);
}; ~VkRenderPassManager();
struct OffscreenRenderTargetInfo { Bool Initialize();
Uint targetExternalIndex = 0;
Uint16 targetVersion = 0;
VkImageView colorView = VK_NULL_HANDLE;
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
VkImageView depthStencilView = VK_NULL_HANDLE;
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
VkExtent2D extent = {0, 0};
};
Bool Initialize(const InitInfo& initInfo);
void Shutdown(); void Shutdown();
Bool RecreateDefaultFramebuffers(const Vector<VkImageView>& colorViews, HashType ComputeHash(
const Vector<VkImageView>& depthStencilViews, VkExtent2D extent); const MG_State::GLState::FramebufferObject& fbo,
Bool GetDefaultRenderTarget(Uint32 imageIndex, VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer, Uint32 swapchainImageIndex,
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const; Bool includePendingClear = true) const;
RenderPassEntry& GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex);
Bool EnsureOffscreenRenderTarget(const OffscreenRenderTargetInfo& targetInfo); static Bool BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry);
Bool GetOffscreenRenderTarget(Uint targetExternalIndex, VkRenderPass& outRenderPass, static Bool EndRenderPass(VkCommandBuffer commandBuffer);
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent, static ActiveRenderPassInfo* GetActiveRenderPass();
VkFormat& outDepthStencilFormat) const;
void RemoveOffscreenRenderTarget(Uint targetExternalIndex);
void BeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass, VkFramebuffer framebuffer,
VkExtent2D extent) const;
void EndRenderPass(VkCommandBuffer commandBuffer) const;
void RecordColorClear(VkCommandBuffer commandBuffer, VkExtent2D extent,
const VkClearColorValue& clearColor) const;
void RecordDepthStencilClear(VkCommandBuffer commandBuffer, VkExtent2D extent, GLbitfield mask, Float depth,
Uint32 stencil, VkFormat depthStencilFormat) const;
VkRenderPass GetLoadRenderPass() const;
VkRenderPass GetClearRenderPass() const;
private: private:
struct OffscreenRenderTarget {
Uint16 targetVersion = 0;
VkImageView colorView = VK_NULL_HANDLE;
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
VkImageView depthStencilView = VK_NULL_HANDLE;
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
VkExtent2D extent = {0, 0};
VkRenderPass renderPassLoad = VK_NULL_HANDLE;
VkFramebuffer framebuffer = VK_NULL_HANDLE;
};
VkRenderPass CreateDefaultRenderPass(VkAttachmentLoadOp colorLoadOp) const;
VkRenderPass CreateRenderPass(VkFormat colorFormat, VkFormat depthStencilFormat, VkAttachmentLoadOp colorLoadOp,
VkImageLayout colorFinalLayout) const;
void DestroyDefaultFramebuffers();
void DestroyOffscreenRenderTarget(OffscreenRenderTarget& target);
static Bool HasStencilComponent(VkFormat format);
VkDevice m_device = VK_NULL_HANDLE; VkDevice m_device = VK_NULL_HANDLE;
VkFormat m_colorFormat = VK_FORMAT_UNDEFINED; const VulkanRendererConfig& m_config;
VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED; VkClearManager& m_clearManager;
VkRenderPass m_renderPassLoad = VK_NULL_HANDLE; VkTextureManager& m_textureManager;
VkRenderPass m_renderPassClear = VK_NULL_HANDLE; SwapchainObject& m_swapchainObject;
Vector<VkFramebuffer> m_defaultFramebuffers; UnorderedMap<Uint64, RenderPassEntry> m_renderPasses;
VkExtent2D m_defaultExtent = {0, 0}; static inline XXH64_state_t* m_hashState = XXH64_createState();
UnorderedMap<Uint, OffscreenRenderTarget> m_offscreenRenderTargets; static inline ActiveRenderPassInfo s_activeRenderPass{};
static inline Bool s_hasActiveRenderPass = false;
static inline VkClearManager* s_clearManager = nullptr;
static inline VkTextureManager* s_textureManager = nullptr;
static inline SwapchainObject* s_swapchainObject = nullptr;
}; };
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -0,0 +1,156 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkSamplerManager.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 "VkSamplerManager.h"
#include "MG_State/GLState/Core.h"
namespace MobileGL::MG_Backend::DirectVulkan {
Bool VkSamplerManager::Initialize(const InitInfo& initInfo) {
Shutdown();
m_device = initInfo.device;
m_config = initInfo.config;
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE && m_config != nullptr,
"VkSamplerManager::Initialize failed: invalid initialization info");
return true;
}
void VkSamplerManager::Shutdown() {
for (auto& [_, sampler] : m_samplers) {
if (m_device != VK_NULL_HANDLE && sampler.handle != VK_NULL_HANDLE) {
vkDestroySampler(m_device, sampler.handle, nullptr);
}
sampler.handle = VK_NULL_HANDLE;
}
m_samplers.clear();
m_device = VK_NULL_HANDLE;
m_config = nullptr;
}
Uint64 VkSamplerManager::BuildSamplerKey(const MG_State::GLState::SamplerObject& sampler) const {
MOBILEGL_ASSERT(m_config != nullptr, "VkSamplerManager::BuildSamplerKey: m_config is null");
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config->CacheVersion));
const auto minFilter = sampler.GetMinFilter();
XXHASH_VERIFY(XXH64_update(m_hashState, &minFilter, sizeof(minFilter)));
const auto magFilter = sampler.GetMagFilter();
XXHASH_VERIFY(XXH64_update(m_hashState, &magFilter, sizeof(magFilter)));
const auto mipmapMode = sampler.GetMipmapMode();
XXHASH_VERIFY(XXH64_update(m_hashState, &mipmapMode, sizeof(mipmapMode)));
const auto wrapS = sampler.GetWrapS();
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapS, sizeof(wrapS)));
const auto wrapT = sampler.GetWrapT();
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapT, sizeof(wrapT)));
const auto wrapR = sampler.GetWrapR();
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapR, sizeof(wrapR)));
const auto minLod = sampler.GetMinLod();
XXHASH_VERIFY(XXH64_update(m_hashState, &minLod, sizeof(minLod)));
const auto maxLod = sampler.GetMaxLod();
XXHASH_VERIFY(XXH64_update(m_hashState, &maxLod, sizeof(maxLod)));
const auto lodBias = sampler.GetLodBias();
XXHASH_VERIFY(XXH64_update(m_hashState, &lodBias, sizeof(lodBias)));
const auto compareMode = sampler.GetCompareMode();
XXHASH_VERIFY(XXH64_update(m_hashState, &compareMode, sizeof(compareMode)));
const auto compareFunc = sampler.GetSamplerCompareFunc();
XXHASH_VERIFY(XXH64_update(m_hashState, &compareFunc, sizeof(compareFunc)));
return XXH64_digest(m_hashState);
}
VkSampler VkSamplerManager::GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler) {
const Uint64 key = BuildSamplerKey(sampler);
auto it = m_samplers.find(key);
if (it != m_samplers.end()) {
return it->second.handle;
}
VkSamplerCreateInfo samplerInfo{};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = ToVkFilter(sampler.GetMagFilter());
samplerInfo.minFilter = ToVkFilter(sampler.GetMinFilter());
samplerInfo.mipmapMode = ToVkMipmapMode(sampler.GetMipmapMode());
samplerInfo.addressModeU = ToVkAddressMode(sampler.GetWrapS());
samplerInfo.addressModeV = ToVkAddressMode(sampler.GetWrapT());
samplerInfo.addressModeW = ToVkAddressMode(sampler.GetWrapR());
samplerInfo.mipLodBias = sampler.GetLodBias();
samplerInfo.anisotropyEnable = VK_FALSE;
samplerInfo.maxAnisotropy = 1.0f;
samplerInfo.compareEnable = sampler.GetCompareMode() == SamplerCompareMode::CompareToTexture ? VK_TRUE : VK_FALSE;
samplerInfo.compareOp = ToVkCompareOp(sampler.GetSamplerCompareFunc());
samplerInfo.minLod = sampler.GetMinLod();
samplerInfo.maxLod = sampler.GetMaxLod();
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
samplerInfo.unnormalizedCoordinates = VK_FALSE;
VkSampler vkSampler = VK_NULL_HANDLE;
VK_VERIFY(vkCreateSampler(m_device, &samplerInfo, nullptr, &vkSampler), "vkCreateSampler(texture)");
SamplerCacheEntry entry{};
entry.handle = vkSampler;
entry.externalIndex = sampler.GetExternalIndex();
entry.version = sampler.GetVersion();
m_samplers[key] = entry;
return vkSampler;
}
VkFilter VkSamplerManager::ToVkFilter(SamplerFilterMode mode) {
return mode == SamplerFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
}
VkSamplerMipmapMode VkSamplerManager::ToVkMipmapMode(SamplerMipmapMode mode) {
switch (mode) {
case SamplerMipmapMode::Nearest:
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
case SamplerMipmapMode::Linear:
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
case SamplerMipmapMode::None:
default:
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
}
}
VkSamplerAddressMode VkSamplerManager::ToVkAddressMode(SamplerWrapMode mode) {
switch (mode) {
case SamplerWrapMode::ClampToEdge:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
case SamplerWrapMode::MirroredRepeat:
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
case SamplerWrapMode::Repeat:
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
case SamplerWrapMode::ClampToBorder:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
case SamplerWrapMode::MirrorClampToEdge:
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
default:
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
}
}
VkCompareOp VkSamplerManager::ToVkCompareOp(SamplerCompareFunc func) {
switch (func) {
case SamplerCompareFunc::Never:
return VK_COMPARE_OP_NEVER;
case SamplerCompareFunc::Less:
return VK_COMPARE_OP_LESS;
case SamplerCompareFunc::Equal:
return VK_COMPARE_OP_EQUAL;
case SamplerCompareFunc::LessEqual:
return VK_COMPARE_OP_LESS_OR_EQUAL;
case SamplerCompareFunc::Greater:
return VK_COMPARE_OP_GREATER;
case SamplerCompareFunc::NotEqual:
return VK_COMPARE_OP_NOT_EQUAL;
case SamplerCompareFunc::GreaterEqual:
return VK_COMPARE_OP_GREATER_OR_EQUAL;
case SamplerCompareFunc::Always:
default:
return VK_COMPARE_OP_ALWAYS;
}
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -0,0 +1,51 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkSamplerManager.h
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
#pragma once
#include "../VkIncludes.h"
#include "../VulkanRendererConfig.h"
#include <Includes.h>
#include <MG_State/GLState/SamplerState/SamplerObject.h>
namespace MobileGL::MG_State::GLState {
class SamplerObject;
}
namespace MobileGL::MG_Backend::DirectVulkan {
class VkSamplerManager {
public:
struct InitInfo {
VkDevice device = VK_NULL_HANDLE;
const VulkanRendererConfig* config = nullptr;
};
Bool Initialize(const InitInfo& initInfo);
void Shutdown();
VkSampler GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler);
private:
struct SamplerCacheEntry {
VkSampler handle = VK_NULL_HANDLE;
Uint externalIndex = 0;
Uint16 version = 0;
};
Uint64 BuildSamplerKey(const MG_State::GLState::SamplerObject& sampler) const;
static VkFilter ToVkFilter(SamplerFilterMode mode);
static VkSamplerMipmapMode ToVkMipmapMode(SamplerMipmapMode mode);
static VkSamplerAddressMode ToVkAddressMode(SamplerWrapMode mode);
static VkCompareOp ToVkCompareOp(SamplerCompareFunc func);
VkDevice m_device = VK_NULL_HANDLE;
const VulkanRendererConfig* m_config = nullptr;
UnorderedMap<Uint64, SamplerCacheEntry> m_samplers;
static inline XXH64_state_t* m_hashState = XXH64_createState();
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -0,0 +1,526 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.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 "VkTextureManager.h"
#include "MG_State/GLState/Core.h"
#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
namespace MobileGL::MG_Backend::DirectVulkan {
static constexpr VkPipelineStageFlags kGraphicsSampledReadStages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
static Bool IsValidSampledImageLayout(VkImageLayout layout) {
switch (layout) {
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
case VK_IMAGE_LAYOUT_GENERAL:
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
return true;
default:
return false;
}
}
Bool VkTextureManager::Initialize(const InitInfo& initInfo) {
Shutdown();
m_device = initInfo.device;
m_physicalDevice = initInfo.physicalDevice;
m_allocator = initInfo.allocator;
m_commandPool = initInfo.commandPool;
m_graphicsQueue = initInfo.graphicsQueue;
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE && m_physicalDevice != VK_NULL_HANDLE && m_allocator != nullptr &&
m_commandPool != VK_NULL_HANDLE && m_graphicsQueue != VK_NULL_HANDLE,
"VkTextureManager::Initialize failed: invalid initialization info");
TextureResource::s_device = m_device;
TextureResource::s_allocator = m_allocator;
return true;
}
void VkTextureManager::Shutdown() {
m_textureResources.clear();
m_device = VK_NULL_HANDLE;
m_physicalDevice = VK_NULL_HANDLE;
m_allocator = nullptr;
m_commandPool = VK_NULL_HANDLE;
m_graphicsQueue = VK_NULL_HANDLE;
}
VkTextureManager::TextureResource* VkTextureManager::SyncTextureAndGetDescriptor(MG_State::GLState::ITextureObject& texture) {
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "SyncTextureAndGetDescriptor: m_device == VK_NULL_HANDLE");
auto it = m_textureResources.find(&texture);
if (it == m_textureResources.end()) {
TextureResource initial{};
auto [insertIt, _] = m_textureResources.emplace(&texture, Move(initial));
it = insertIt;
}
if (!SyncTexture(texture, it->second)) {
MGLOG_D("%s: Syncing texture %d failed", __func__, texture.GetExternalIndex());
return nullptr;
}
return &(it->second);
}
void VkTextureManager::UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout) {
MOBILEGL_ASSERT(texture != nullptr, "UpdateTrackedImageLayout: texture is null");
auto it = m_textureResources.find(texture);
MOBILEGL_ASSERT(it != m_textureResources.end(),
"UpdateTrackedImageLayout: textureId=%d has no tracked resource", texture->GetExternalIndex());
MOBILEGL_ASSERT(it->second.image != VK_NULL_HANDLE,
"UpdateTrackedImageLayout: textureId=%d has null image", texture->GetExternalIndex());
it->second.layout = newLayout;
}
Bool VkTextureManager::TransitionTextureForSampling(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture) {
TextureResource* resource = SyncTextureAndGetDescriptor(texture);
if (resource == nullptr) {
return false;
}
if (IsValidSampledImageLayout(resource->layout)) {
return true;
}
if (resource->layout == VK_IMAGE_LAYOUT_UNDEFINED) {
MGLOG_W("TransitionTextureForSampling: textureId=%d is still in VK_IMAGE_LAYOUT_UNDEFINED before sampling",
texture.GetExternalIndex());
}
VkImageLayout targetLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkAccessFlags srcAccessMask = 0;
if ((resource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
MOBILEGL_ASSERT(resource->layout == VK_IMAGE_LAYOUT_UNDEFINED ||
resource->layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
"TransitionTextureForSampling: unsupported color layout=%d for textureId=%d",
static_cast<Int>(resource->layout), texture.GetExternalIndex());
if (resource->layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
}
targetLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
} else if ((resource->aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) {
MOBILEGL_ASSERT(resource->layout == VK_IMAGE_LAYOUT_UNDEFINED ||
resource->layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
"TransitionTextureForSampling: unsupported depth/stencil layout=%d for textureId=%d",
static_cast<Int>(resource->layout), texture.GetExternalIndex());
if (resource->layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
targetLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
} else {
MOBILEGL_ASSERT(false, "TransitionTextureForSampling: unsupported aspect mask=0x%x for textureId=%d",
static_cast<Uint32>(resource->aspect), texture.GetExternalIndex());
}
const Bool ok = TransitionImageLayout(commandBuffer, resource->image, resource->layout, targetLayout, srcStageMask,
kGraphicsSampledReadStages, srcAccessMask,
VK_ACCESS_SHADER_READ_BIT, resource->aspect);
MOBILEGL_ASSERT(ok, "TransitionTextureForSampling: transition failed for textureId=%d", texture.GetExternalIndex());
return ok;
}
Bool VkTextureManager::TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image,
VkImageLayout& trackedLayout, VkImageLayout newLayout,
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask,
VkImageAspectFlags aspectMask) {
MOBILEGL_ASSERT(image != VK_NULL_HANDLE, "TransitionImageLayout: m_image == VK_NULL_HANDLE");
MOBILEGL_ASSERT(!((dstAccessMask & VK_ACCESS_TRANSFER_READ_BIT) != 0 &&
(dstStageMask & VK_PIPELINE_STAGE_TRANSFER_BIT) == 0),
"TransitionImageLayout: invalid dstAccess/dstStage pair (dstAccess=0x%x, dstStage=0x%x, oldLayout=%d, newLayout=%d)",
static_cast<Uint32>(dstAccessMask), static_cast<Uint32>(dstStageMask), static_cast<Int>(trackedLayout),
static_cast<Int>(newLayout));
if (trackedLayout == newLayout) {
return true;
}
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.srcAccessMask = srcAccessMask;
barrier.dstAccessMask = dstAccessMask;
barrier.oldLayout = trackedLayout;
barrier.newLayout = newLayout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange.aspectMask = aspectMask;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier);
trackedLayout = newLayout;
return true;
}
SizeT VkTextureManager::CollectGarbage() {
m_gcCounter++;
if (m_gcCounter != 0) {
return 0;
}
SizeT count = 0;
for (const auto& [raw, weak]: m_aliveObjects) {
if (weak.expired()) {
count++;
m_textureResources.erase(raw);
m_aliveObjects.erase(raw);
}
}
return count;
}
Bool VkTextureManager::SyncTexture(MG_State::GLState::ITextureObject &texture,
TextureResource &outResource) {
TextureUploadTarget uploadTarget = TextureUploadTarget::Unknown;
IntVec3 texelSize{0, 0, 0};
SizeT byteSize = 0;
Uint32 mipLevelCount = 0;
if (!CheckMipmapCompleteness(texture, uploadTarget, texelSize, byteSize, mipLevelCount)) {
MGLOG_D("%s: mipmap not complete", __func__);
return false;
}
auto* mipTexture = dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(&texture);
if (!mipTexture) {
MGLOG_D("%s: not TextureObjectMipmap", __func__);
return false;
}
if (!SyncTextureResource(texture, uploadTarget, texelSize, byteSize, mipLevelCount, outResource)) {
MGLOG_D("%s: SyncTextureResource failed", __func__);
return false;
}
Bool hasDirtyMipLevel = false;
for (Uint32 level = 0; level < mipLevelCount; ++level) {
if (mipTexture->IsStorageDirty(uploadTarget, level)) {
hasDirtyMipLevel = true;
break;
}
}
if (!hasDirtyMipLevel) {
return true;
}
if (!UploadDirtyMipLevels(*mipTexture, uploadTarget, outResource)) {
MGLOG_D("%s: UploadDirtyMipLevels failed", __func__);
return false;
}
return true;
}
Bool VkTextureManager::SyncTextureResource(const MG_State::GLState::ITextureObject &texture,
TextureUploadTarget uploadTarget,
const IntVec3 &texelSize, SizeT byteSize, Uint32 mipLevels,
TextureResource &resource) {
const VkFormat format = MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
if (format == VK_FORMAT_UNDEFINED) {
MGLOG_D("%s: format == VK_FORMAT_UNDEFINED", __func__);
return false;
}
if (texelSize.x() <= 0 || texelSize.y() <= 0 /*|| byteSize == 0*/) {
MGLOG_D("%s: texelSize or byteSize is zero", __func__);
return false;
}
if (mipLevels == 0) {
MGLOG_D("%s: no mip levels", __func__);
return false;
}
if (uploadTarget != TextureUploadTarget::Texture2D) {
MGLOG_D("%s: not Texture2D, unsupported", __func__);
return false;
}
const Bool compatible = resource.image != VK_NULL_HANDLE && resource.format == format &&
resource.extent.width == static_cast<Uint32>(texelSize.x()) &&
resource.extent.height == static_cast<Uint32>(texelSize.y()) &&
resource.mipLevels == mipLevels;
if (compatible) {
return true;
}
resource.Reset();
auto aspect = GetAspectMaskForFormat(format);
VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = static_cast<Uint32>(texelSize.x());
imageInfo.extent.height = static_cast<Uint32>(texelSize.y());
imageInfo.extent.depth = 1;
imageInfo.mipLevels = mipLevels;
imageInfo.arrayLayers = 1;
imageInfo.format = format;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage =
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
((aspect & VK_IMAGE_ASPECT_COLOR_BIT) ?
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : 0) |
((aspect & VK_IMAGE_ASPECT_DEPTH_BIT || aspect & VK_IMAGE_ASPECT_STENCIL_BIT) ?
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : 0);
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo allocationInfo{};
allocationInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
allocationInfo.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
VK_VERIFY(vmaCreateImage(m_allocator, &imageInfo, &allocationInfo, &resource.image, &resource.allocation, nullptr),
"vmaCreateImage(texture)");
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = resource.image;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = format;
viewInfo.subresourceRange.aspectMask = aspect;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = mipLevels;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &resource.view), "vkCreateImageView(texture)");
resource.layout = VK_IMAGE_LAYOUT_UNDEFINED;
resource.extent = {static_cast<Uint32>(texelSize.x()), static_cast<Uint32>(texelSize.y())};
resource.mipLevels = mipLevels;
resource.format = format;
resource.aspect = viewInfo.subresourceRange.aspectMask;
return true;
}
Bool VkTextureManager::UploadDirtyMipLevels(MG_State::GLState::TextureObjectMipmap &mipmapTexture,
TextureUploadTarget uploadTarget,
TextureResource &outResource) {
struct UploadItem {
Uint32 level = 0;
SizeT byteSize = 0;
IntVec3 texelSize = {0, 0, 0};
const void* source = nullptr;
VkDeviceSize offset = 0;
};
Vector<UploadItem> uploadItems;
uploadItems.reserve(outResource.mipLevels);
VkDeviceSize stagingSize = 0;
for (Uint32 level = 0; level < outResource.mipLevels; ++level) {
if (!mipmapTexture.IsStorageDirty(uploadTarget, level)) {
continue;
}
const auto texelSize = mipmapTexture.GetMipmapTexelSize(uploadTarget, level);
const auto byteSize = mipmapTexture.GetMipmapByteSize(uploadTarget, level);
if (texelSize.x() <= 0 || texelSize.y() <= 0 || byteSize == 0) {
mipmapTexture.MarkStorageDirty(uploadTarget, level, false);
continue;
}
const void* source = mipmapTexture.MapMipmapData(uploadTarget, level);
if (source == nullptr) {
MGLOG_D("%s: MapmipmapData failed at level %d", __func__, level);
return false;
}
uploadItems.push_back({level, byteSize, texelSize, source, stagingSize});
stagingSize += static_cast<VkDeviceSize>(byteSize);
}
if (uploadItems.empty()) {
return true;
}
VkBuffer stagingBuffer = VK_NULL_HANDLE;
VmaAllocation stagingAllocation = nullptr;
VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = stagingSize;
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo stagingAllocationInfo{};
stagingAllocationInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
stagingAllocationInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
stagingAllocationInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
VK_VERIFY(vmaCreateBuffer(m_allocator, &bufferInfo, &stagingAllocationInfo, &stagingBuffer, &stagingAllocation, nullptr),
"vmaCreateBuffer(staging texture)");
void* mapped = nullptr;
VK_VERIFY(vmaMapMemory(m_allocator, stagingAllocation, &mapped), "vmaMapMemory(staging texture)");
for (const auto& item : uploadItems) {
std::memcpy(static_cast<Uint8*>(mapped) + item.offset, item.source, item.byteSize);
}
vmaUnmapMemory(m_allocator, stagingAllocation);
VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = m_commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
VK_VERIFY(vkAllocateCommandBuffers(m_device, &allocInfo, &commandBuffer), "vkAllocateCommandBuffers(texture)");
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
VK_VERIFY(vkBeginCommandBuffer(commandBuffer, &beginInfo), "vkBeginCommandBuffer(texture)");
const VkImageAspectFlags aspectMask = GetAspectMaskForFormat(outResource.format);
Bool ok = TransitionImageLayout(commandBuffer, outResource.image,
outResource.layout,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
outResource.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ?
kGraphicsSampledReadStages :
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
outResource.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ? VK_ACCESS_SHADER_READ_BIT : 0,
VK_ACCESS_TRANSFER_WRITE_BIT,
aspectMask);
MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL failed");
for (const auto& item : uploadItems) {
VkBufferImageCopy copy{};
copy.bufferOffset = item.offset;
copy.bufferRowLength = 0;
copy.bufferImageHeight = 0;
copy.imageSubresource.aspectMask = aspectMask;
copy.imageSubresource.mipLevel = item.level;
copy.imageSubresource.baseArrayLayer = 0;
copy.imageSubresource.layerCount = 1;
copy.imageOffset = {0, 0, 0};
copy.imageExtent = {static_cast<Uint32>(item.texelSize.x()), static_cast<Uint32>(item.texelSize.y()), 1};
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, outResource.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &copy);
}
ok = TransitionImageLayout(commandBuffer, outResource.image,
outResource.layout,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
kGraphicsSampledReadStages,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT,
aspectMask);
MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL failed");
outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VK_VERIFY(vkEndCommandBuffer(commandBuffer), "vkEndCommandBuffer(texture)");
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
VkFenceCreateInfo fenceInfo{};
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
VkFence uploadFence = VK_NULL_HANDLE;
VK_VERIFY(vkCreateFence(m_device, &fenceInfo, nullptr, &uploadFence), "vkCreateFence(texture upload)");
VK_VERIFY(vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, uploadFence), "vkQueueSubmit(texture)");
VK_VERIFY(vkWaitForFences(m_device, 1, &uploadFence, VK_TRUE, UINT64_MAX), "vkWaitForFences(texture upload)");
vkDestroyFence(m_device, uploadFence, nullptr);
vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer);
vmaDestroyBuffer(m_allocator, stagingBuffer, stagingAllocation);
if (!ok) {
MGLOG_D("%s: texture upload cmd failed", __func__);
return false;
}
for (const auto& item : uploadItems) {
mipmapTexture.MarkStorageDirty(uploadTarget, item.level, false);
}
outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
return true;
}
Bool VkTextureManager::CheckMipmapCompleteness(const MG_State::GLState::ITextureObject& texture,
TextureUploadTarget& outTarget,
IntVec3& outTexelSize,
SizeT& outByteSize,
Uint32& outMipLevelCount) {
const auto* mipTexture = dynamic_cast<const MG_State::GLState::TextureObjectMipmap*>(&texture);
if (!mipTexture) {
MGLOG_D("%s: not TextureObjectMipmap", __func__);
return false;
}
const auto& targets = texture.GetUploadTargets();
if (targets.empty()) {
MGLOG_D("%s: upload target empty", __func__);
return false;
}
for (const auto target : targets) {
const Uint32 mipLevelCount = GetUploadMipLevelCount(*mipTexture, target);
if (mipLevelCount == 0) {
MGLOG_D("%s: mipLevelCount == 0", __func__);
continue;
}
const auto level0TexelSize = mipTexture->GetMipmapTexelSize(target, 0);
const auto level0ByteSize = mipTexture->GetMipmapByteSize(target, 0);
if (level0TexelSize.x() <= 0 || level0TexelSize.y() <= 0 /*|| level0ByteSize == 0*/) {
continue;
}
outTarget = target;
outTexelSize = level0TexelSize;
outByteSize = level0ByteSize;
outMipLevelCount = mipLevelCount;
return true;
}
MGLOG_D("%s: no valid target or mipmap", __func__);
return false;
}
Uint32 VkTextureManager::GetUploadMipLevelCount(const MG_State::GLState::TextureObjectMipmap& texture,
TextureUploadTarget target) {
const Uint totalLevelCount = texture.GetMipmapLevelCount();
if (totalLevelCount == 0) {
return 0;
}
Uint32 validLevelCount = 0;
for (Uint level = 0; level < totalLevelCount; ++level) {
const auto size = texture.GetMipmapTexelSize(target, level);
const auto byteSize = texture.GetMipmapByteSize(target, level);
if (size.x() <= 0 || size.y() <= 0 /*|| byteSize == 0*/) {
break;
}
++validLevelCount;
}
return validLevelCount;
}
VkImageAspectFlags VkTextureManager::GetAspectMaskForFormat(VkFormat format) {
switch (format) {
case VK_FORMAT_D16_UNORM:
case VK_FORMAT_X8_D24_UNORM_PACK32:
case VK_FORMAT_D32_SFLOAT:
return VK_IMAGE_ASPECT_DEPTH_BIT;
case VK_FORMAT_S8_UINT:
return VK_IMAGE_ASPECT_STENCIL_BIT;
case VK_FORMAT_D16_UNORM_S8_UINT:
case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_D32_SFLOAT_S8_UINT:
return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
default:
return VK_IMAGE_ASPECT_COLOR_BIT;
}
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -0,0 +1,122 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
#pragma once
#include "../VkIncludes.h"
#include <Includes.h>
#include <MG_State/GLState/TextureState/TextureObject.h>
#include <vk_mem_alloc.h>
namespace MobileGL::MG_State::GLState {
class ITextureObject;
}
namespace MobileGL::MG_Backend::DirectVulkan {
class VkTextureManager {
public:
struct InitInfo {
VkDevice device = VK_NULL_HANDLE;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
VmaAllocator allocator = nullptr;
VkCommandPool commandPool = VK_NULL_HANDLE;
VkQueue graphicsQueue = VK_NULL_HANDLE;
};
struct TextureResource {
VkImage image = VK_NULL_HANDLE;
VmaAllocation allocation = nullptr;
VkImageView view = VK_NULL_HANDLE;
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
VkExtent2D extent = {0, 0};
Uint32 mipLevels = 1;
VkFormat format = VK_FORMAT_UNDEFINED;
VkImageAspectFlags aspect = VK_IMAGE_ASPECT_NONE;
TextureResource() = default;
TextureResource(const TextureResource&) = delete;
TextureResource(TextureResource&& that) noexcept {
std::swap(this->image, that.image);
std::swap(this->allocation, that.allocation);
std::swap(this->view, that.view);
std::swap(this->layout, that.layout);
std::swap(this->extent, that.extent);
std::swap(this->mipLevels, that.mipLevels);
std::swap(this->format, that.format);
std::swap(this->aspect, that.aspect);
}
void Reset() {
if (view != VK_NULL_HANDLE) {
vkDestroyImageView(s_device, view, nullptr);
}
if (image != VK_NULL_HANDLE && allocation != nullptr) {
vmaDestroyImage(s_allocator, image, allocation);
}
view = VK_NULL_HANDLE;
image = VK_NULL_HANDLE;
allocation = nullptr;
layout = VK_IMAGE_LAYOUT_UNDEFINED;
extent = {0, 0};
mipLevels = 1;
format = VK_FORMAT_UNDEFINED;
aspect = VK_IMAGE_ASPECT_NONE;
}
~TextureResource() {
Reset();
}
static inline VkDevice s_device = VK_NULL_HANDLE;
static inline VmaAllocator s_allocator = VK_NULL_HANDLE;
};
Bool Initialize(const InitInfo& initInfo);
void Shutdown();
TextureResource* SyncTextureAndGetDescriptor(
MG_State::GLState::ITextureObject& texture);
void UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout);
Bool TransitionTextureForSampling(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture);
static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout,
VkImageLayout newLayout, VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask);
SizeT CollectGarbage();
private:
Bool SyncTexture(MG_State::GLState::ITextureObject &texture,
TextureResource &outResource);
Bool SyncTextureResource(const MG_State::GLState::ITextureObject &texture,
TextureUploadTarget uploadTarget,
const IntVec3 &texelSize, SizeT byteSize, Uint32 mipLevels,
TextureResource &resource);
Bool UploadDirtyMipLevels(MG_State::GLState::TextureObjectMipmap &mipmapTexture,
TextureUploadTarget uploadTarget,
TextureResource &outResource);
static Bool CheckMipmapCompleteness(const MG_State::GLState::ITextureObject& texture,
TextureUploadTarget& outTarget,
IntVec3& outTexelSize,
SizeT& outByteSize,
Uint32& outMipLevelCount);
static Uint32 GetUploadMipLevelCount(const MG_State::GLState::TextureObjectMipmap& texture, TextureUploadTarget target);
static VkImageAspectFlags GetAspectMaskForFormat(VkFormat format);
VkDevice m_device = VK_NULL_HANDLE;
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
VmaAllocator m_allocator = nullptr;
VkCommandPool m_commandPool = VK_NULL_HANDLE;
VkQueue m_graphicsQueue = VK_NULL_HANDLE;
Uint8 m_gcCounter = 0;
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
UnorderedMap<MG_State::GLState::ITextureObject*, TextureResource> m_textureResources;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,644 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureSamplerManager.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 "VkTextureSamplerManager.h"
#include "MG_State/GLState/Core.h"
namespace MobileGL::MG_Backend::DirectVulkan {
namespace {
constexpr Uint64 BuildSamplerKey(Uint externalIndex, Uint16 version) {
return (static_cast<Uint64>(externalIndex) << 16) | static_cast<Uint64>(version);
}
} // namespace
Bool VkTextureSamplerManager::Initialize(const InitInfo& initInfo) {
Shutdown();
m_device = initInfo.device;
m_physicalDevice = initInfo.physicalDevice;
m_commandPool = initInfo.commandPool;
m_graphicsQueue = initInfo.graphicsQueue;
if (m_device == VK_NULL_HANDLE || m_physicalDevice == VK_NULL_HANDLE || m_commandPool == VK_NULL_HANDLE ||
m_graphicsQueue == VK_NULL_HANDLE) {
MGLOG_E("VkTextureSamplerManager::Initialize failed: invalid Vulkan handles");
Shutdown();
return false;
}
if (!UploadFallbackTexture()) {
MGLOG_E("VkTextureSamplerManager::Initialize failed: fallback texture creation failed");
Shutdown();
return false;
}
return true;
}
void VkTextureSamplerManager::Shutdown() {
for (auto& [_, resource] : m_textureResources) {
DestroyTextureResource(resource);
}
m_textureResources.clear();
for (auto& [_, sampler] : m_samplers) {
if (m_device != VK_NULL_HANDLE && sampler.handle != VK_NULL_HANDLE) {
vkDestroySampler(m_device, sampler.handle, nullptr);
}
sampler.handle = VK_NULL_HANDLE;
}
m_samplers.clear();
if (m_device != VK_NULL_HANDLE && m_fallbackSampler != VK_NULL_HANDLE) {
vkDestroySampler(m_device, m_fallbackSampler, nullptr);
}
if (m_device != VK_NULL_HANDLE && m_fallbackImageView != VK_NULL_HANDLE) {
vkDestroyImageView(m_device, m_fallbackImageView, nullptr);
}
if (m_device != VK_NULL_HANDLE && m_fallbackImage != VK_NULL_HANDLE) {
vkDestroyImage(m_device, m_fallbackImage, nullptr);
}
if (m_device != VK_NULL_HANDLE && m_fallbackImageMemory != VK_NULL_HANDLE) {
vkFreeMemory(m_device, m_fallbackImageMemory, nullptr);
}
m_fallbackSampler = VK_NULL_HANDLE;
m_fallbackImageView = VK_NULL_HANDLE;
m_fallbackImage = VK_NULL_HANDLE;
m_fallbackImageMemory = VK_NULL_HANDLE;
m_device = VK_NULL_HANDLE;
m_physicalDevice = VK_NULL_HANDLE;
m_commandPool = VK_NULL_HANDLE;
m_graphicsQueue = VK_NULL_HANDLE;
}
Bool VkTextureSamplerManager::GetFallbackDescriptor(VkDescriptorImageInfo& outImageInfo) const {
if (m_fallbackSampler == VK_NULL_HANDLE || m_fallbackImageView == VK_NULL_HANDLE) {
return false;
}
outImageInfo.sampler = m_fallbackSampler;
outImageInfo.imageView = m_fallbackImageView;
outImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
return true;
}
Bool VkTextureSamplerManager::SyncTextureAndGetDescriptor(const MG_State::GLState::ITextureObject& texture,
const MG_State::GLState::SamplerObject* samplerOverride,
VkDescriptorImageInfo& outImageInfo) {
if (m_device == VK_NULL_HANDLE) {
return GetFallbackDescriptor(outImageInfo);
}
auto it = m_textureResources.find(texture.GetExternalIndex());
if (it == m_textureResources.end()) {
TextureResource initial{};
initial.textureExternalIndex = texture.GetExternalIndex();
auto [insertIt, _] = m_textureResources.emplace(texture.GetExternalIndex(), initial);
it = insertIt;
}
if (!EnsureTextureSynced(it->second, texture)) {
return GetFallbackDescriptor(outImageInfo);
}
const MG_State::GLState::SamplerObject* samplerToUse = samplerOverride;
if (!samplerToUse) {
auto textureSampler = texture.GetSamplerObject();
if (textureSampler) {
samplerToUse = textureSampler.get();
}
}
VkSampler sampler = m_fallbackSampler;
if (samplerToUse) {
sampler = GetOrCreateSampler(*samplerToUse);
}
if (sampler == VK_NULL_HANDLE) {
sampler = m_fallbackSampler;
}
if (it->second.view == VK_NULL_HANDLE || sampler == VK_NULL_HANDLE) {
return GetFallbackDescriptor(outImageInfo);
}
outImageInfo.sampler = sampler;
outImageInfo.imageView = it->second.view;
outImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
return true;
}
Bool VkTextureSamplerManager::EnsureTextureSynced(TextureResource& resource,
const MG_State::GLState::ITextureObject& texture) {
TextureUploadTarget level0Target = TextureUploadTarget::Unknown;
IntVec3 texelSize{0, 0, 0};
SizeT byteSize = 0;
if (!ResolveLevel0(texture, level0Target, texelSize, byteSize)) {
return false;
}
if (!EnsureTextureResource(resource, texture, level0Target, texelSize, byteSize)) {
return false;
}
const auto* mipTexture = dynamic_cast<const MG_State::GLState::TextureObjectMipmap*>(&texture);
if (!mipTexture) {
return false;
}
if (!mipTexture->IsStorageDirty(level0Target, 0)) {
return true;
}
if (!UploadLevel0(resource, *mipTexture, level0Target, byteSize)) {
return false;
}
auto& mutableTexture = const_cast<MG_State::GLState::TextureObjectMipmap&>(*mipTexture);
mutableTexture.MarkStorageDirty(level0Target, 0, false);
return true;
}
Bool VkTextureSamplerManager::EnsureTextureResource(TextureResource& resource,
const MG_State::GLState::ITextureObject& texture,
TextureUploadTarget level0Target, const IntVec3& texelSize,
SizeT byteSize) {
const VkFormat format = ResolveTextureFormat(texture.GetFormat());
if (format == VK_FORMAT_UNDEFINED) {
return false;
}
if (texelSize.x() <= 0 || texelSize.y() <= 0 || byteSize == 0) {
return false;
}
if (level0Target != TextureUploadTarget::Texture2D) {
return false;
}
const Bool compatible = resource.image != VK_NULL_HANDLE && resource.format == format &&
resource.extent.width == static_cast<Uint32>(texelSize.x()) &&
resource.extent.height == static_cast<Uint32>(texelSize.y());
if (compatible) {
return true;
}
DestroyTextureResource(resource);
VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = static_cast<Uint32>(texelSize.x());
imageInfo.extent.height = static_cast<Uint32>(texelSize.y());
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.format = format;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_VERIFY(vkCreateImage(m_device, &imageInfo, nullptr, &resource.image), "vkCreateImage(texture)");
VkMemoryRequirements requirements{};
vkGetImageMemoryRequirements(m_device, resource.image, &requirements);
VkMemoryAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = requirements.size;
allocInfo.memoryTypeIndex = FindMemoryType(requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_VERIFY(vkAllocateMemory(m_device, &allocInfo, nullptr, &resource.memory), "vkAllocateMemory(texture)");
VK_VERIFY(vkBindImageMemory(m_device, resource.image, resource.memory, 0), "vkBindImageMemory(texture)");
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = resource.image;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = format;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &resource.view), "vkCreateImageView(texture)");
resource.layout = VK_IMAGE_LAYOUT_UNDEFINED;
resource.extent = {static_cast<Uint32>(texelSize.x()), static_cast<Uint32>(texelSize.y())};
resource.format = format;
resource.textureExternalIndex = texture.GetExternalIndex();
return true;
}
Bool VkTextureSamplerManager::UploadLevel0(TextureResource& resource,
const MG_State::GLState::TextureObjectMipmap& mipmapTexture,
TextureUploadTarget level0Target, SizeT byteSize) {
auto& mutableTexture = const_cast<MG_State::GLState::TextureObjectMipmap&>(mipmapTexture);
const void* source = mutableTexture.MapMipmapData(level0Target, 0);
if (source == nullptr || byteSize == 0) {
return false;
}
VkBuffer stagingBuffer = VK_NULL_HANDLE;
VkDeviceMemory stagingMemory = VK_NULL_HANDLE;
VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = byteSize;
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_VERIFY(vkCreateBuffer(m_device, &bufferInfo, nullptr, &stagingBuffer), "vkCreateBuffer(staging texture)");
VkMemoryRequirements requirements{};
vkGetBufferMemoryRequirements(m_device, stagingBuffer, &requirements);
VkMemoryAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = requirements.size;
allocInfo.memoryTypeIndex =
FindMemoryType(requirements.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
VK_VERIFY(vkAllocateMemory(m_device, &allocInfo, nullptr, &stagingMemory), "vkAllocateMemory(staging texture)");
VK_VERIFY(vkBindBufferMemory(m_device, stagingBuffer, stagingMemory, 0), "vkBindBufferMemory(staging texture)");
void* mapped = nullptr;
VK_VERIFY(vkMapMemory(m_device, stagingMemory, 0, byteSize, 0, &mapped), "vkMapMemory(staging texture)");
std::memcpy(mapped, source, byteSize);
vkUnmapMemory(m_device, stagingMemory);
const Bool ok = ExecuteImmediate([&](VkCommandBuffer commandBuffer) {
VkImageMemoryBarrier toTransferDst{};
toTransferDst.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
toTransferDst.srcAccessMask = 0;
toTransferDst.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
toTransferDst.oldLayout = resource.layout;
toTransferDst.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
toTransferDst.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
toTransferDst.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
toTransferDst.image = resource.image;
toTransferDst.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
toTransferDst.subresourceRange.baseMipLevel = 0;
toTransferDst.subresourceRange.levelCount = 1;
toTransferDst.subresourceRange.baseArrayLayer = 0;
toTransferDst.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0,
nullptr, 0, nullptr, 1, &toTransferDst);
VkBufferImageCopy copy{};
copy.bufferOffset = 0;
copy.bufferRowLength = 0;
copy.bufferImageHeight = 0;
copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy.imageSubresource.mipLevel = 0;
copy.imageSubresource.baseArrayLayer = 0;
copy.imageSubresource.layerCount = 1;
copy.imageOffset = {0, 0, 0};
copy.imageExtent = {resource.extent.width, resource.extent.height, 1};
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, resource.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
&copy);
VkImageMemoryBarrier toSampled{};
toSampled.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
toSampled.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
toSampled.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
toSampled.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
toSampled.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
toSampled.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
toSampled.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
toSampled.image = resource.image;
toSampled.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
toSampled.subresourceRange.baseMipLevel = 0;
toSampled.subresourceRange.levelCount = 1;
toSampled.subresourceRange.baseArrayLayer = 0;
toSampled.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
0, nullptr, 0, nullptr, 1, &toSampled);
});
vkDestroyBuffer(m_device, stagingBuffer, nullptr);
vkFreeMemory(m_device, stagingMemory, nullptr);
if (!ok) {
return false;
}
resource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
return true;
}
Bool VkTextureSamplerManager::ExecuteImmediate(const std::function<void(VkCommandBuffer)>& recorder) const {
VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = m_commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
VK_VERIFY(vkAllocateCommandBuffers(m_device, &allocInfo, &commandBuffer), "vkAllocateCommandBuffers(texture)");
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
VK_VERIFY(vkBeginCommandBuffer(commandBuffer, &beginInfo), "vkBeginCommandBuffer(texture)");
recorder(commandBuffer);
VK_VERIFY(vkEndCommandBuffer(commandBuffer), "vkEndCommandBuffer(texture)");
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
VK_VERIFY(vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE), "vkQueueSubmit(texture)");
VK_VERIFY(vkQueueWaitIdle(m_graphicsQueue), "vkQueueWaitIdle(texture)");
vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer);
return true;
}
void VkTextureSamplerManager::DestroyTextureResource(TextureResource& resource) const {
if (m_device != VK_NULL_HANDLE && resource.view != VK_NULL_HANDLE) {
vkDestroyImageView(m_device, resource.view, nullptr);
}
if (m_device != VK_NULL_HANDLE && resource.image != VK_NULL_HANDLE) {
vkDestroyImage(m_device, resource.image, nullptr);
}
if (m_device != VK_NULL_HANDLE && resource.memory != VK_NULL_HANDLE) {
vkFreeMemory(m_device, resource.memory, nullptr);
}
resource.view = VK_NULL_HANDLE;
resource.image = VK_NULL_HANDLE;
resource.memory = VK_NULL_HANDLE;
resource.layout = VK_IMAGE_LAYOUT_UNDEFINED;
resource.extent = {0, 0};
resource.format = VK_FORMAT_UNDEFINED;
}
Bool VkTextureSamplerManager::ResolveLevel0(const MG_State::GLState::ITextureObject& texture,
TextureUploadTarget& outTarget, IntVec3& outTexelSize,
SizeT& outByteSize) {
const auto* mipTexture = dynamic_cast<const MG_State::GLState::TextureObjectMipmap*>(&texture);
if (!mipTexture) {
return false;
}
const auto& targets = texture.GetUploadTargets();
if (targets.empty()) {
return false;
}
outTarget = targets.front();
outTexelSize = mipTexture->GetMipmapTexelSize(outTarget, 0);
outByteSize = mipTexture->GetMipmapByteSize(outTarget, 0);
return outTexelSize.x() > 0 && outTexelSize.y() > 0 && outByteSize > 0;
}
VkFormat VkTextureSamplerManager::ResolveTextureFormat(TextureInternalFormat format) {
switch (format) {
case TextureInternalFormat::RGBA:
case TextureInternalFormat::RGBA8:
return VK_FORMAT_R8G8B8A8_UNORM;
case TextureInternalFormat::SRGB8Alpha8:
return VK_FORMAT_R8G8B8A8_SRGB;
default:
return VK_FORMAT_UNDEFINED;
}
}
Uint32 VkTextureSamplerManager::FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const {
VkPhysicalDeviceMemoryProperties memProperties{};
vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &memProperties);
for (Uint32 i = 0; i < memProperties.memoryTypeCount; ++i) {
if ((typeFilter & (1u << i)) != 0 &&
(memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
return i;
}
}
MOBILEGL_ASSERT(false, "VkTextureSamplerManager::FindMemoryType failed");
return 0;
}
VkSampler VkTextureSamplerManager::GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler) {
const Uint64 key = BuildSamplerKey(sampler.GetExternalIndex(), sampler.GetVersion());
auto it = m_samplers.find(key);
if (it != m_samplers.end()) {
return it->second.handle;
}
VkSamplerCreateInfo samplerInfo{};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = ToVkFilter(sampler.GetMagFilter());
samplerInfo.minFilter = ToVkFilter(sampler.GetMinFilter());
samplerInfo.mipmapMode = ToVkMipmapMode(sampler.GetMipmapMode());
samplerInfo.addressModeU = ToVkAddressMode(sampler.GetWrapS());
samplerInfo.addressModeV = ToVkAddressMode(sampler.GetWrapT());
samplerInfo.addressModeW = ToVkAddressMode(sampler.GetWrapR());
samplerInfo.mipLodBias = sampler.GetLodBias();
samplerInfo.anisotropyEnable = VK_FALSE;
samplerInfo.maxAnisotropy = 1.0f;
samplerInfo.compareEnable = sampler.GetCompareMode() == SamplerCompareMode::CompareToTexture ? VK_TRUE : VK_FALSE;
samplerInfo.compareOp = ToVkCompareOp(sampler.GetSamplerCompareFunc());
samplerInfo.minLod = sampler.GetMinLod();
samplerInfo.maxLod = sampler.GetMaxLod();
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
samplerInfo.unnormalizedCoordinates = VK_FALSE;
VkSampler vkSampler = VK_NULL_HANDLE;
VK_VERIFY(vkCreateSampler(m_device, &samplerInfo, nullptr, &vkSampler), "vkCreateSampler(texture)");
SamplerCacheEntry entry{};
entry.handle = vkSampler;
entry.externalIndex = sampler.GetExternalIndex();
entry.version = sampler.GetVersion();
m_samplers[key] = entry;
return vkSampler;
}
VkFilter VkTextureSamplerManager::ToVkFilter(SamplerFilterMode mode) {
return mode == SamplerFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
}
VkSamplerMipmapMode VkTextureSamplerManager::ToVkMipmapMode(SamplerMipmapMode mode) {
switch (mode) {
case SamplerMipmapMode::Nearest:
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
case SamplerMipmapMode::Linear:
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
case SamplerMipmapMode::None:
default:
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
}
}
VkSamplerAddressMode VkTextureSamplerManager::ToVkAddressMode(SamplerWrapMode mode) {
switch (mode) {
case SamplerWrapMode::ClampToEdge:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
case SamplerWrapMode::MirroredRepeat:
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
case SamplerWrapMode::Repeat:
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
case SamplerWrapMode::ClampToBorder:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
case SamplerWrapMode::MirrorClampToEdge:
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
default:
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
}
}
VkCompareOp VkTextureSamplerManager::ToVkCompareOp(SamplerCompareFunc func) {
switch (func) {
case SamplerCompareFunc::Never:
return VK_COMPARE_OP_NEVER;
case SamplerCompareFunc::Less:
return VK_COMPARE_OP_LESS;
case SamplerCompareFunc::Equal:
return VK_COMPARE_OP_EQUAL;
case SamplerCompareFunc::LessEqual:
return VK_COMPARE_OP_LESS_OR_EQUAL;
case SamplerCompareFunc::Greater:
return VK_COMPARE_OP_GREATER;
case SamplerCompareFunc::NotEqual:
return VK_COMPARE_OP_NOT_EQUAL;
case SamplerCompareFunc::GreaterEqual:
return VK_COMPARE_OP_GREATER_OR_EQUAL;
case SamplerCompareFunc::Always:
default:
return VK_COMPARE_OP_ALWAYS;
}
}
Bool VkTextureSamplerManager::UploadFallbackTexture() {
const Uint32 rgba = 0xFFFFFFFFu;
VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent = {1, 1, 1};
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_VERIFY(vkCreateImage(m_device, &imageInfo, nullptr, &m_fallbackImage), "vkCreateImage(fallback)");
VkMemoryRequirements imageMemReq{};
vkGetImageMemoryRequirements(m_device, m_fallbackImage, &imageMemReq);
VkMemoryAllocateInfo imageAllocInfo{};
imageAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
imageAllocInfo.allocationSize = imageMemReq.size;
imageAllocInfo.memoryTypeIndex = FindMemoryType(imageMemReq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_VERIFY(vkAllocateMemory(m_device, &imageAllocInfo, nullptr, &m_fallbackImageMemory),
"vkAllocateMemory(fallback)");
VK_VERIFY(vkBindImageMemory(m_device, m_fallbackImage, m_fallbackImageMemory, 0), "vkBindImageMemory(fallback)");
VkBuffer stagingBuffer = VK_NULL_HANDLE;
VkDeviceMemory stagingMemory = VK_NULL_HANDLE;
VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = sizeof(rgba);
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_VERIFY(vkCreateBuffer(m_device, &bufferInfo, nullptr, &stagingBuffer), "vkCreateBuffer(fallback)");
VkMemoryRequirements stagingMemReq{};
vkGetBufferMemoryRequirements(m_device, stagingBuffer, &stagingMemReq);
VkMemoryAllocateInfo stagingAllocInfo{};
stagingAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
stagingAllocInfo.allocationSize = stagingMemReq.size;
stagingAllocInfo.memoryTypeIndex =
FindMemoryType(stagingMemReq.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
VK_VERIFY(vkAllocateMemory(m_device, &stagingAllocInfo, nullptr, &stagingMemory), "vkAllocateMemory(fallback)");
VK_VERIFY(vkBindBufferMemory(m_device, stagingBuffer, stagingMemory, 0), "vkBindBufferMemory(fallback)");
void* mapped = nullptr;
VK_VERIFY(vkMapMemory(m_device, stagingMemory, 0, sizeof(rgba), 0, &mapped), "vkMapMemory(fallback)");
std::memcpy(mapped, &rgba, sizeof(rgba));
vkUnmapMemory(m_device, stagingMemory);
const Bool uploadOk = ExecuteImmediate([&](VkCommandBuffer commandBuffer) {
VkImageMemoryBarrier toTransferDst{};
toTransferDst.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
toTransferDst.srcAccessMask = 0;
toTransferDst.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
toTransferDst.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
toTransferDst.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
toTransferDst.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
toTransferDst.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
toTransferDst.image = m_fallbackImage;
toTransferDst.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
toTransferDst.subresourceRange.baseMipLevel = 0;
toTransferDst.subresourceRange.levelCount = 1;
toTransferDst.subresourceRange.baseArrayLayer = 0;
toTransferDst.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0,
nullptr, 0, nullptr, 1, &toTransferDst);
VkBufferImageCopy copy{};
copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy.imageSubresource.mipLevel = 0;
copy.imageSubresource.baseArrayLayer = 0;
copy.imageSubresource.layerCount = 1;
copy.imageExtent = {1, 1, 1};
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, m_fallbackImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
&copy);
VkImageMemoryBarrier toSampled{};
toSampled.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
toSampled.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
toSampled.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
toSampled.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
toSampled.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
toSampled.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
toSampled.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
toSampled.image = m_fallbackImage;
toSampled.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
toSampled.subresourceRange.baseMipLevel = 0;
toSampled.subresourceRange.levelCount = 1;
toSampled.subresourceRange.baseArrayLayer = 0;
toSampled.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
0, nullptr, 0, nullptr, 1, &toSampled);
});
vkDestroyBuffer(m_device, stagingBuffer, nullptr);
vkFreeMemory(m_device, stagingMemory, nullptr);
if (!uploadOk) {
return false;
}
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = m_fallbackImage;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &m_fallbackImageView), "vkCreateImageView(fallback)");
VkSamplerCreateInfo samplerInfo{};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_NEAREST;
samplerInfo.minFilter = VK_FILTER_NEAREST;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.compareEnable = VK_FALSE;
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = 0.0f;
samplerInfo.maxAnisotropy = 1.0f;
VK_VERIFY(vkCreateSampler(m_device, &samplerInfo, nullptr, &m_fallbackSampler), "vkCreateSampler(fallback)");
return true;
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,88 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureSamplerManager.h
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
#pragma once
#include "../VkIncludes.h"
#include <Includes.h>
#include <MG_State/GLState/SamplerState/SamplerObject.h>
#include <MG_State/GLState/TextureState/TextureObject.h>
namespace MobileGL::MG_State::GLState {
class ITextureObject;
class SamplerObject;
}
namespace MobileGL::MG_Backend::DirectVulkan {
class VkTextureSamplerManager {
public:
struct InitInfo {
VkDevice device = VK_NULL_HANDLE;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
VkCommandPool commandPool = VK_NULL_HANDLE;
VkQueue graphicsQueue = VK_NULL_HANDLE;
};
Bool Initialize(const InitInfo& initInfo);
void Shutdown();
Bool GetFallbackDescriptor(VkDescriptorImageInfo& outImageInfo) const;
Bool SyncTextureAndGetDescriptor(const MG_State::GLState::ITextureObject& texture,
const MG_State::GLState::SamplerObject* samplerOverride,
VkDescriptorImageInfo& outImageInfo);
private:
struct TextureResource {
VkImage image = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
VkExtent2D extent = {0, 0};
VkFormat format = VK_FORMAT_UNDEFINED;
Uint textureExternalIndex = 0;
};
struct SamplerCacheEntry {
VkSampler handle = VK_NULL_HANDLE;
Uint externalIndex = 0;
Uint16 version = 0;
};
Bool EnsureTextureSynced(TextureResource& resource, const MG_State::GLState::ITextureObject& texture);
Bool EnsureTextureResource(TextureResource& resource, const MG_State::GLState::ITextureObject& texture,
TextureUploadTarget level0Target, const IntVec3& texelSize, SizeT byteSize);
Bool UploadLevel0(TextureResource& resource, const MG_State::GLState::TextureObjectMipmap& mipmapTexture,
TextureUploadTarget level0Target, SizeT byteSize);
Bool ExecuteImmediate(const std::function<void(VkCommandBuffer)>& recorder) const;
void DestroyTextureResource(TextureResource& resource) const;
static Bool ResolveLevel0(const MG_State::GLState::ITextureObject& texture, TextureUploadTarget& outTarget,
IntVec3& outTexelSize, SizeT& outByteSize);
static VkFormat ResolveTextureFormat(TextureInternalFormat format);
Uint32 FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const;
VkSampler GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler);
static VkFilter ToVkFilter(SamplerFilterMode mode);
static VkSamplerMipmapMode ToVkMipmapMode(SamplerMipmapMode mode);
static VkSamplerAddressMode ToVkAddressMode(SamplerWrapMode mode);
static VkCompareOp ToVkCompareOp(SamplerCompareFunc func);
Bool UploadFallbackTexture();
VkDevice m_device = VK_NULL_HANDLE;
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
VkCommandPool m_commandPool = VK_NULL_HANDLE;
VkQueue m_graphicsQueue = VK_NULL_HANDLE;
UnorderedMap<Uint, TextureResource> m_textureResources;
UnorderedMap<Uint64, SamplerCacheEntry> m_samplers;
VkImage m_fallbackImage = VK_NULL_HANDLE;
VkDeviceMemory m_fallbackImageMemory = VK_NULL_HANDLE;
VkImageView m_fallbackImageView = VK_NULL_HANDLE;
VkSampler m_fallbackSampler = VK_NULL_HANDLE;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
File diff suppressed because it is too large Load Diff
@@ -15,9 +15,10 @@
#include "UniformDescriptorBinder.h" #include "UniformDescriptorBinder.h"
#include "VertexInputStateFactory.h" #include "VertexInputStateFactory.h"
#include "VkBufferObject.h" #include "VkBufferObject.h"
#include "VkFramebufferManager.h" #include "VkClearManager.h"
#include "VkRenderPassManager.h" #include "VkRenderPassManager.h"
#include "VkTextureSamplerManager.h" #include "VkSamplerManager.h"
#include "VkTextureManager.h"
#include "MG_Util/Math/VectorTypes.h" #include "MG_Util/Math/VectorTypes.h"
#include <Includes.h> #include <Includes.h>
#include <vk_mem_alloc.h> #include <vk_mem_alloc.h>
@@ -27,20 +28,28 @@
namespace MobileGL::MG_State::GLState { namespace MobileGL::MG_State::GLState {
class FramebufferObject; class FramebufferObject;
class ProgramObject; class ProgramObject;
class SamplerObject;
class VertexArrayObject; class VertexArrayObject;
} // namespace MobileGL::MG_State::GLState } // namespace MobileGL::MG_State::GLState
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkan {
struct DrawArrayPayload { enum class DrawSetupAspect: Uint8 {
FramebufferObject = 1 << 0,
VertexArrayObject = 1 << 1,
UniformBuffer = 1 << 2,
VertexBuffer = 1 << 3,
IndexBuffer = 1 << 4,
Viewport = 1 << 5,
Scissor = 1 << 6,
};
struct DrawArrayCmd {
GLenum mode = GL_TRIANGLES; GLenum mode = GL_TRIANGLES;
GLint first = 0; GLint first = 0;
GLsizei count = 0; GLsizei count = 0;
const MG_State::GLState::ProgramObject* program = nullptr;
const MG_State::GLState::VertexArrayObject* vertexArray = nullptr;
}; };
struct DrawElementPayload { struct DrawElementCmd: public DrawArrayCmd {
DrawArrayPayload drawArray;
GLenum indexType = GL_UNSIGNED_SHORT; GLenum indexType = GL_UNSIGNED_SHORT;
SizeT indexByteOffset = 0; SizeT indexByteOffset = 0;
GLint baseVertex = 0; GLint baseVertex = 0;
@@ -69,17 +78,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void Initialize(); void Initialize();
void Shutdown(); void Shutdown();
void RequestClear(GLbitfield mask, const FloatVec4& color, Float depth, Uint32 stencil, void SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags<DrawSetupAspect> aspects);
Uint drawFboExternalIndex, Bool isDefaultFramebufferTarget); void ClearAttachmentsOnActiveRenderPass(VkCommandBuffer commandBuffer,
Bool ConsumePendingColorClear(VkClearColorValue& outClearColor); const RenderPassEntry& compatibleRenderPassEntry);
void EnsureFrameRecordingStarted();
void DrawArrays(const DrawArrayPayload& payload); void Clear(GLbitfield mask);
void DrawElements(const DrawElementPayload& payload); void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
void MultiDrawElements(const Vector<DrawElementPayload>& payloads); GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
Bool BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLbitfield mask, GLenum filter);
GLint dstY1, GLbitfield mask, GLenum filter, Uint readFboExternalIndex, void DrawArrays(const DrawArrayCmd& payload);
Uint drawFboExternalIndex, Bool readIsDefaultFramebuffer, Bool drawIsDefaultFramebuffer); void DrawElements(const DrawElementCmd& payload);
void Render(); void MultiDrawElements(const Vector<DrawElementCmd>& payloads);
void Present(); void Present();
const PhysicalDevice& GetPhysicalDevice() const; const PhysicalDevice& GetPhysicalDevice() const;
@@ -88,13 +97,21 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void RecreateSwapchain(); void RecreateSwapchain();
private: private:
struct PendingClearState { struct BlitUniformData {
GLbitfield mask = 0; float srcRect[4] = {0.f, 0.f, 1.f, 1.f};
VkClearColorValue color = {{0.0f, 0.0f, 0.0f, 1.0f}}; float dstRect[4] = {0.f, 0.f, 1.f, 1.f};
Float depth = 1.0f; Int surfaceTransform = 0;
Uint32 stencil = 0; Int padding[3] = {0, 0, 0};
Uint drawFboExternalIndex = 0; };
Bool targetsDefaultFramebuffer = true;
struct BlitResources {
SharedPtr<MG_State::GLState::ProgramObject> program;
SharedPtr<MG_State::GLState::SamplerObject> nearestSampler;
SharedPtr<MG_State::GLState::SamplerObject> linearSampler;
Int srcRectLocation = -1;
Int dstRectLocation = -1;
Int surfaceTransformLocation = -1;
Uint32 samplerBinding = 0;
}; };
NativeWindowType m_window = 0; NativeWindowType m_window = 0;
@@ -106,15 +123,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkInstance m_instance = VK_NULL_HANDLE; VkInstance m_instance = VK_NULL_HANDLE;
VkDebugUtilsMessengerEXT m_debugMessenger = VK_NULL_HANDLE; VkDebugUtilsMessengerEXT m_debugMessenger = VK_NULL_HANDLE;
PhysicalDevice m_physicalDevice; PhysicalDevice m_physicalDevice;
// VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
VkDevice m_device = VK_NULL_HANDLE; VkDevice m_device = VK_NULL_HANDLE;
VmaAllocator m_allocator = nullptr; VmaAllocator m_allocator = nullptr;
VkSurfaceKHR m_surface = VK_NULL_HANDLE; VkSurfaceKHR m_surface = VK_NULL_HANDLE;
SwapchainObject m_swapchainObject; SwapchainObject m_swapchainObject;
// Vector<VkQueueFamilyProperties> m_queueFamilies;
// QueueFamilyIndices m_queueFamilyIndices;
VkQueue m_graphicsQueue = VK_NULL_HANDLE; VkQueue m_graphicsQueue = VK_NULL_HANDLE;
VkQueue m_presentQueue = VK_NULL_HANDLE; VkQueue m_presentQueue = VK_NULL_HANDLE;
Bool m_drawIndirectCountExtensionEnabled = false; Bool m_drawIndirectCountExtensionEnabled = false;
@@ -126,13 +139,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkCommandPool m_commandPool = VK_NULL_HANDLE; VkCommandPool m_commandPool = VK_NULL_HANDLE;
VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED;
Vector<VkImage> m_depthStencilImages;
Vector<VkDeviceMemory> m_depthStencilImageMemories;
Vector<VkImageView> m_depthStencilImageViews;
Vector<VkImageLayout> m_depthStencilImageLayouts;
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
Vector<VkBufferObject> m_frameVertexUploadBuffers; Vector<VkBufferObject> m_frameVertexUploadBuffers;
Vector<VkDeviceSize> m_frameVertexUploadHeads; Vector<VkDeviceSize> m_frameVertexUploadHeads;
Vector<VkBufferObject> m_frameIndexUploadBuffers; Vector<VkBufferObject> m_frameIndexUploadBuffers;
@@ -141,21 +147,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Uint m_imageIndexAcquired = 0; Uint m_imageIndexAcquired = 0;
FrameContext m_frameContext; FrameContext m_frameContext;
UnorderedMap<Uint64, PendingClearState> m_pendingClears;
Bool m_isMainRenderPassActive = false;
VkRenderPass m_activeRenderPass = VK_NULL_HANDLE;
VkExtent2D m_activeRenderExtent = {0, 0};
VkFormat m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED;
Bool m_activeRenderTargetIsDefault = true;
Uint m_activeDrawFboExternalIndex = 0;
UniquePtr<PipelineFactory> m_pipelineFactory; UniquePtr<PipelineFactory> m_pipelineFactory;
UniquePtr<ProgramFactory> m_programFactory; UniquePtr<ProgramFactory> m_programFactory;
UniquePtr<UniformDescriptorBinder> m_uniformDescriptorBinder; UniquePtr<UniformDescriptorBinder> m_uniformDescriptorBinder;
UniquePtr<VertexInputStateFactory> m_vertexInputStateFactory; UniquePtr<VertexInputStateFactory> m_vertexInputStateFactory;
UniquePtr<VkFramebufferManager> m_framebufferManager; UniquePtr<VkClearManager> m_clearManager;
UniquePtr<VkRenderPassManager> m_renderPassManager; UniquePtr<VkRenderPassManager> m_renderPassManager;
UniquePtr<VkTextureSamplerManager> m_textureSamplerManager; UniquePtr<VkTextureManager> m_textureManager;
UniquePtr<VkSamplerManager> m_samplerManager;
BlitResources m_blitResources;
void CreateInstance(); void CreateInstance();
VkResult SetupDebugMessenger(); VkResult SetupDebugMessenger();
@@ -169,30 +170,33 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void CreateSwapchain(); void CreateSwapchain();
void CreateCommandPool(); void CreateCommandPool();
void CreateFrameContexts(); void CreateFrameContexts();
void CreateDepthStencilResources();
void DestroyDepthStencilResources(); VkPipeline GetOrCreatePipeline(
VkRenderPass GetDefaultLoadRenderPass() const; GLenum mode,
Bool GetDefaultRenderTargetForCurrentImage(VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer, const MG_State::GLState::ProgramObject& program,
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const; const MG_State::GLState::VertexArrayObject& vao,
Bool EnsureOffscreenRenderTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo, const RenderPassEntry& renderPassEntry);
VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat);
void PrepareDemoPipeline();
VkPipeline GetOrCreatePipeline(const MG_State::GLState::ProgramObject& program, VkPipelineLayout pipelineLayout,
Uint64 vertexInputHash,
const VkPipelineVertexInputStateCreateInfo& vertexInputState);
void TransitionSwapchainImageToColorAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
void TransitionDepthStencilImageToAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
void EndFrameRecordingIfNeeded();
void DeferDestroyBuffer(VkBufferObject& buffer); void DeferDestroyBuffer(VkBufferObject& buffer);
void CollectDeferredBufferReleases(Uint32 frameIndex); void CollectDeferredBufferReleases(Uint32 frameIndex);
Bool EnsureFrameUploadBufferCapacity(Uint32 frameIndex, Bool isIndexBuffer, VkDeviceSize requiredEndOffset, Bool EnsureFrameUploadBufferCapacity(Uint32 frameIndex, Bool isIndexBuffer, VkDeviceSize requiredEndOffset,
VkDeviceSize minCapacity, VkBufferUsageFlags usage); VkDeviceSize minCapacity, VkBufferUsageFlags usage);
Bool UploadAndBindVertexStreams(const VertexInputStateFactory::BackendVertexInputState& vertexInputState, Bool UploadAndBindVertexStreams(VkCommandBuffer commandBuffer, const MG_State::GLState::VertexArrayObject& vao);
const DrawArrayPayload& payload, VkCommandBuffer commandBuffer); Bool InitializeBlitResources();
void ShutdownBlitResources();
Bool TryBlitToDefaultFramebufferWithShader(FrameContext::FrameData& frame,
MG_State::GLState::FramebufferObject& readFbo,
MG_State::GLState::FramebufferObject& drawFbo,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLenum filter);
Bool MaterializePendingClearForTexture(VkCommandBuffer commandBuffer,
MG_State::GLState::ITextureObject& texture);
VkPipeline GetOrCreateBlitPipeline(const RenderPassEntry& renderPassEntry);
void ShutdownSwapchain(); void ShutdownSwapchain();
// Static functions
static Int GetPresentQueueFamilyIndex(const PhysicalDevice& physicalDevice, VkSurfaceKHR surface, static Int GetPresentQueueFamilyIndex(const PhysicalDevice& physicalDevice, VkSurfaceKHR surface,
const Vector<VkQueueFamilyProperties>& queueFamilies, const Vector<VkQueueFamilyProperties>& queueFamilies,
Int preferredFamilyIndex = -1); Int preferredFamilyIndex = -1);
@@ -212,10 +216,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
static Bool GetMoreCapablePhysicalDevice(VkPhysicalDevice newVkDevice, VkSurfaceKHR surface, static Bool GetMoreCapablePhysicalDevice(VkPhysicalDevice newVkDevice, VkSurfaceKHR surface,
const PhysicalDevice& compareWithDevice, const PhysicalDevice& compareWithDevice,
PhysicalDevice& outBetterDevice); PhysicalDevice& outBetterDevice);
Uint32 FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const;
static Uint64 BuildPendingClearKey(Uint drawFboExternalIndex, Bool targetsDefaultFramebuffer); static Uint64 BuildPendingClearKey(Uint drawFboExternalIndex, Bool targetsDefaultFramebuffer);
static Bool HasStencilComponent(VkFormat format);
static VkFormat FindSupportedDepthStencilFormat(VkPhysicalDevice physicalDevice);
static constexpr VkDynamicState s_dynamicStates[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; static constexpr VkDynamicState s_dynamicStates[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
static constexpr const char* s_validationLayerNames[] = {"VK_LAYER_KHRONOS_validation"}; static constexpr const char* s_validationLayerNames[] = {"VK_LAYER_KHRONOS_validation"};
static constexpr const char* s_deviceExtensionNames[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME}; static constexpr const char* s_deviceExtensionNames[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
+1 -1
View File
@@ -20,7 +20,7 @@ namespace MobileGL::MG_Impl::EGLImpl {
if (!MG_State::pEGLContext) { if (!MG_State::pEGLContext) {
MGLOG_E("pEGLContext is null. MG_State may not be initialized."); MGLOG_E("pEGLContext is null. MG_State may not be initialized.");
} }
return MG_State::pEGLContext; return MG_State::pEGLContext.get();
} }
MG_Backend::BackendObject* GetBackendObject(EGLStateContext* state) { MG_Backend::BackendObject* GetBackendObject(EGLStateContext* state) {
+77 -82
View File
@@ -8,19 +8,17 @@
#include "GL_Buffer.h" #include "GL_Buffer.h"
#include "Validators.h" #include "Validators.h"
#include "MG_Util/Converters/GLToStr/GLEnumConverter.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/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/GLToMG/BufferEnumConverter.h> #include <MG_Util/Converters/GLToMG/BufferEnumConverter.h>
#include <MG_Util/Converters/MGToGL/BufferEnumConverter.h> #include <MG_Util/Converters/MGToGL/BufferEnumConverter.h>
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
void GetBufferParameteriv_State(GLenum target, GLenum pname, GLint* params) { void GetBufferParameteriv_State(GLenum target, GLenum pname, GLint* params) {
if (!params) { if (!params) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, MG_State::pGLContext->RecordError(
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetBufferParameteriv_State",
"GetBufferParameteriv_State",
"Params pointer cannot be null.")); "Params pointer cannot be null."));
return; return;
} }
@@ -30,11 +28,11 @@ namespace MobileGL {
auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget);
auto bufferObject = bindingSlot.GetBoundObject(); auto& bufferObject = bindingSlot.GetBoundObject();
if (!bufferObject) { if (!bufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetBufferParameteriv_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetBufferParameteriv_State",
"Buffer target is bound to no buffer object.")); "Buffer target is bound to no buffer object."));
return; return;
} }
@@ -44,7 +42,7 @@ namespace MobileGL {
*params = static_cast<GLint>(bufferObject->GetSize()); *params = static_cast<GLint>(bufferObject->GetSize());
break; break;
case GL_BUFFER_USAGE: case GL_BUFFER_USAGE:
*params = MG_Util::ConvertBufferUsageToGLEnum(bufferObject->GetUsage()); *params = (GLint)MG_Util::ConvertBufferUsageToGLEnum(bufferObject->GetUsage());
break; break;
case GL_BUFFER_ACCESS: case GL_BUFFER_ACCESS:
if (bufferObject->IsMapped()) { if (bufferObject->IsMapped()) {
@@ -65,6 +63,11 @@ namespace MobileGL {
case GL_BUFFER_MAPPED: case GL_BUFFER_MAPPED:
*params = bufferObject->IsMapped() ? GL_TRUE : GL_FALSE; *params = bufferObject->IsMapped() ? GL_TRUE : GL_FALSE;
break; break;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetBufferParameteriv_State",
std::format("Invalid pname enum: 0x{:X}", pname)));
break;
} }
} }
@@ -72,13 +75,13 @@ namespace MobileGL {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteBuffers_State", "n must be non-negative.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteBuffers_State", "n must be non-negative."));
return; return;
} }
if (!buffers) { if (!buffers) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteBuffers_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteBuffers_State",
"Buffer names array cannot be null.")); "Buffer names array cannot be null."));
return; return;
} }
@@ -94,8 +97,7 @@ namespace MobileGL {
void FlushMappedBufferRange_State(GLenum target, GLintptr offset, GLsizeiptr length) { void FlushMappedBufferRange_State(GLenum target, GLintptr offset, GLsizeiptr length) {
if (length < 0 || offset < 0) { if (length < 0 || offset < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FlushMappedBufferRange_State",
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FlushMappedBufferRange_State",
"Offset and length must be non-negative.")); "Offset and length must be non-negative."));
return; return;
} }
@@ -105,11 +107,11 @@ namespace MobileGL {
auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget);
auto bufferObject = bindingSlot.GetBoundObject(); auto& bufferObject = bindingSlot.GetBoundObject();
if (!bufferObject) { if (!bufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FlushMappedBufferRange_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FlushMappedBufferRange_State",
"Buffer target is bound to no buffer object.")); "Buffer target is bound to no buffer object."));
return; return;
} }
@@ -117,15 +119,14 @@ namespace MobileGL {
if (!bufferObject->IsMapped()) { if (!bufferObject->IsMapped()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FlushMappedBufferRange_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FlushMappedBufferRange_State",
"Cannot flush a buffer object that is not mapped.")); "Cannot flush a buffer object that is not mapped."));
return; return;
} }
if (offset + length > bufferObject->GetSize()) { if (offset + length > bufferObject->GetSize()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FlushMappedBufferRange_State",
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FlushMappedBufferRange_State",
"Offset and length exceed buffer size.")); "Offset and length exceed buffer size."));
return; return;
} }
@@ -134,7 +135,7 @@ namespace MobileGL {
if (!(mappingAccess & BufferMappingAccessBit::FlushExplicit)) { if (!(mappingAccess & BufferMappingAccessBit::FlushExplicit)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", "FlushMappedBufferRange_State", "MG_Impl/GLImpl", "FlushMappedBufferRange_State",
"Cannot flush a buffer object that is not mapped with GL_MAP_FLUSH_EXPLICIT_BIT.")); "Cannot flush a buffer object that is not mapped with GL_MAP_FLUSH_EXPLICIT_BIT."));
return; return;
@@ -149,11 +150,11 @@ namespace MobileGL {
auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget);
auto bufferObject = bindingSlot.GetBoundObject(); auto& bufferObject = bindingSlot.GetBoundObject();
if (!bufferObject) { if (!bufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "UnmapBuffer_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "UnmapBuffer_State",
"Buffer target is bound to no buffer object.")); "Buffer target is bound to no buffer object."));
return GL_FALSE; return GL_FALSE;
} }
@@ -161,7 +162,7 @@ namespace MobileGL {
if (!bufferObject->IsMapped()) { if (!bufferObject->IsMapped()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "UnmapBuffer_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "UnmapBuffer_State",
"Cannot unmap a buffer object that is not mapped.")); "Cannot unmap a buffer object that is not mapped."));
return GL_FALSE; return GL_FALSE;
} }
@@ -172,15 +173,15 @@ namespace MobileGL {
void* MapBufferRange_State(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { void* MapBufferRange_State(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) {
if (length < 0 || offset < 0) { if (length < 0 || offset < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State",
"Offset and length must be non-negative.")); "Offset and length must be non-negative."));
return nullptr; return nullptr;
} }
if (length == 0) { if (length == 0) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State",
"Length must be greater than zero.")); "Length must be greater than zero."));
return nullptr; return nullptr;
} }
@@ -189,18 +190,18 @@ namespace MobileGL {
if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return nullptr; if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return nullptr;
auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget);
auto bufferObject = bindingSlot.GetBoundObject(); auto& bufferObject = bindingSlot.GetBoundObject();
if (!bufferObject) { if (!bufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State",
"Buffer target is bound to no buffer object.")); "Buffer target is bound to no buffer object."));
return nullptr; return nullptr;
} }
if (offset + length > bufferObject->GetSize()) { if (offset + length > bufferObject->GetSize()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State",
"Offset and length exceed buffer size.")); "Offset and length exceed buffer size."));
return nullptr; return nullptr;
} }
@@ -211,20 +212,19 @@ namespace MobileGL {
if (!(accessBits & (BufferMappingAccessBit::Read | BufferMappingAccessBit::Write))) { if (!(accessBits & (BufferMappingAccessBit::Read | BufferMappingAccessBit::Write))) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State",
"At least one of GL_MAP_READ_BIT or GL_MAP_WRITE_BIT must be set.")); "At least one of GL_MAP_READ_BIT or GL_MAP_WRITE_BIT must be set."));
return nullptr; return nullptr;
} }
if (accessBits & BufferMappingAccessBit::Read) { if (accessBits & BufferMappingAccessBit::Read) {
const auto invalidFlags = BufferMappingAccessBit::InvalidateRange | const auto invalidFlags = BufferMappingAccessBit::InvalidateRange |
BufferMappingAccessBit::InvalidateBuffer | BufferMappingAccessBit::InvalidateBuffer | BufferMappingAccessBit::Unsynchronized;
BufferMappingAccessBit::Unsynchronized;
if (accessBits & invalidFlags) { if (accessBits & invalidFlags) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", "MapBufferRange_State", "MG_Impl/GLImpl", "MapBufferRange_State",
"GL_MAP_READ_BIT cannot be combined with invalidation or unsynchronized flags.")); "GL_MAP_READ_BIT cannot be combined with invalidation or unsynchronized flags."));
return nullptr; return nullptr;
@@ -235,7 +235,7 @@ namespace MobileGL {
if (!(accessBits & BufferMappingAccessBit::Write)) { if (!(accessBits & BufferMappingAccessBit::Write)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State",
"GL_MAP_FLUSH_EXPLICIT_BIT requires GL_MAP_WRITE_BIT.")); "GL_MAP_FLUSH_EXPLICIT_BIT requires GL_MAP_WRITE_BIT."));
return nullptr; return nullptr;
} }
@@ -248,7 +248,7 @@ namespace MobileGL {
// implementation // implementation
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State",
"Access flags require matching storage flags in buffer.")); "Access flags require matching storage flags in buffer."));
return nullptr; return nullptr;
} }
@@ -260,7 +260,7 @@ namespace MobileGL {
if (!(accessBits & invalidateFlags)) { if (!(accessBits & invalidateFlags)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State",
"Cannot map a buffer object that is already mapped.")); "Cannot map a buffer object that is already mapped."));
return nullptr; return nullptr;
} }
@@ -271,7 +271,7 @@ namespace MobileGL {
if (!result) { if (!result) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::OutOfMemory, ErrorCode::OutOfMemory,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State",
"Failed to map buffer due to insufficient memory.")); "Failed to map buffer due to insufficient memory."));
return nullptr; return nullptr;
} }
@@ -284,8 +284,7 @@ namespace MobileGL {
if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE) { if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapBuffer_State",
"MG_Impl/GLImpl", "MapBuffer_State",
"Access must be one of GL_READ_ONLY, GL_WRITE_ONLY, or GL_READ_WRITE.")); "Access must be one of GL_READ_ONLY, GL_WRITE_ONLY, or GL_READ_WRITE."));
return nullptr; return nullptr;
} }
@@ -294,11 +293,11 @@ namespace MobileGL {
if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return nullptr; if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return nullptr;
auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget);
auto bufferObject = bindingSlot.GetBoundObject(); auto& bufferObject = bindingSlot.GetBoundObject();
if (!bufferObject) { if (!bufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "MapBuffer_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapBuffer_State",
"Buffer target is bound to no buffer object.")); "Buffer target is bound to no buffer object."));
return nullptr; return nullptr;
} }
@@ -306,7 +305,7 @@ namespace MobileGL {
if (bufferObject->IsMapped()) { if (bufferObject->IsMapped()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "MapBuffer_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapBuffer_State",
"Cannot map a buffer object that is already mapped.")); "Cannot map a buffer object that is already mapped."));
return nullptr; return nullptr;
} }
@@ -315,7 +314,7 @@ namespace MobileGL {
if (!result) { if (!result) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::OutOfMemory, ErrorCode::OutOfMemory,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "MapBuffer_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "MapBuffer_State",
"Failed to map buffer due to insufficient memory.")); "Failed to map buffer due to insufficient memory."));
return nullptr; return nullptr;
} }
@@ -325,27 +324,26 @@ namespace MobileGL {
void CopyBufferSubData_State(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, void CopyBufferSubData_State(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset,
GLsizeiptr size) { GLsizeiptr size) {
if (size < 0 || readOffset < 0 || writeOffset < 0) { if (size < 0 || readOffset < 0 || writeOffset < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "CopyBufferSubData_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CopyBufferSubData_State",
"Offset and size must be non-negative.")); "Offset and size must be non-negative."));
return; return;
} }
BufferTarget readBufferTarget = MG_Util::ConvertGLEnumToBufferTarget(readTarget); BufferTarget readBufferTarget = MG_Util::ConvertGLEnumToBufferTarget(readTarget);
BufferTarget writeBufferTarget = MG_Util::ConvertGLEnumToBufferTarget(writeTarget); BufferTarget writeBufferTarget = MG_Util::ConvertGLEnumToBufferTarget(writeTarget);
if (!BufferImpl::ValidateBufferTarget(readBufferTarget) || if (!BufferImpl::ValidateBufferTarget(readBufferTarget) || !BufferImpl::ValidateBufferTarget(writeBufferTarget))
!BufferImpl::ValidateBufferTarget(writeBufferTarget))
return; return;
auto& readBindingSlot = MG_State::pGLContext->GetBufferBindingSlot(readBufferTarget); auto& readBindingSlot = MG_State::pGLContext->GetBufferBindingSlot(readBufferTarget);
auto& writeBindingSlot = MG_State::pGLContext->GetBufferBindingSlot(writeBufferTarget); auto& writeBindingSlot = MG_State::pGLContext->GetBufferBindingSlot(writeBufferTarget);
auto readBufferObject = readBindingSlot.GetBoundObject(); auto& readBufferObject = readBindingSlot.GetBoundObject();
auto writeBufferObject = writeBindingSlot.GetBoundObject(); auto& writeBufferObject = writeBindingSlot.GetBoundObject();
if (!readBufferObject || !writeBufferObject) { if (!readBufferObject || !writeBufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "CopyBufferSubData_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CopyBufferSubData_State",
"One of the buffer targets is bound to no buffer object.")); "One of the buffer targets is bound to no buffer object."));
return; return;
} }
@@ -353,7 +351,7 @@ namespace MobileGL {
if (readOffset + size > readBufferObject->GetSize() || writeOffset + size > writeBufferObject->GetSize()) { if (readOffset + size > readBufferObject->GetSize() || writeOffset + size > writeBufferObject->GetSize()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "CopyBufferSubData_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CopyBufferSubData_State",
"Offset and size must be within the bounds of the buffer objects.")); "Offset and size must be within the bounds of the buffer objects."));
return; return;
} }
@@ -363,8 +361,7 @@ namespace MobileGL {
(writeOffset <= readOffset && writeOffset + size > readOffset)) { (writeOffset <= readOffset && writeOffset + size > readOffset)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CopyBufferSubData_State",
"MG_Impl/GLImpl", "CopyBufferSubData_State",
"Source and destination buffers overlap in the specified ranges.")); "Source and destination buffers overlap in the specified ranges."));
return; return;
} }
@@ -376,7 +373,7 @@ namespace MobileGL {
if (isIllegallyMapped(readBufferObject) || isIllegallyMapped(writeBufferObject)) { if (isIllegallyMapped(readBufferObject) || isIllegallyMapped(writeBufferObject)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "CopyBufferSubData_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CopyBufferSubData_State",
"Cannot copy data from/to a mapped buffer object unless it was mapped " "Cannot copy data from/to a mapped buffer object unless it was mapped "
"with GL_MAP_PERSISTENT_BIT.")); "with GL_MAP_PERSISTENT_BIT."));
return; return;
@@ -391,14 +388,13 @@ namespace MobileGL {
if (!data) { if (!data) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::NoError, // somehow OpenGL does not generate an error for this ErrorCode::NoError, // somehow OpenGL does not generate an error for this
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BufferSubData_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BufferSubData_State", "Data pointer cannot be null."));
"Data pointer cannot be null."));
return; return;
} }
if (size < 0 || offset < 0) { if (size < 0 || offset < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BufferSubData_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BufferSubData_State",
"Offset and size must be non-negative.")); "Offset and size must be non-negative."));
return; return;
} }
@@ -407,11 +403,11 @@ namespace MobileGL {
if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return; if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return;
auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget);
auto bufferObject = bindingSlot.GetBoundObject(); auto& bufferObject = bindingSlot.GetBoundObject();
if (!bufferObject) { if (!bufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BufferSubData_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BufferSubData_State",
"Buffer target is bound to no buffer object.")); "Buffer target is bound to no buffer object."));
return; return;
} }
@@ -421,7 +417,7 @@ namespace MobileGL {
if ((offset < mappedRange.end) && (offset + size > mappedRange.start)) { if ((offset < mappedRange.end) && (offset + size > mappedRange.start)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", "BufferSubData_State", "MG_Impl/GLImpl", "BufferSubData_State",
"Offset and size must not overlap with the mapped range of the buffer object.")); "Offset and size must not overlap with the mapped range of the buffer object."));
return; return;
@@ -433,7 +429,7 @@ namespace MobileGL {
if (offset + size >= mappedRange.start) { if (offset + size >= mappedRange.start) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BufferSubData_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BufferSubData_State",
"Cannot modify a mapped buffer object unless it was " "Cannot modify a mapped buffer object unless it was "
"mapped with GL_MAP_PERSISTENT_BIT.")); "mapped with GL_MAP_PERSISTENT_BIT."));
return; return;
@@ -444,13 +440,12 @@ namespace MobileGL {
} }
void BufferData_State(GLenum target, GLsizeiptr size, const void* data, GLenum usage) { void BufferData_State(GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
MGLOG_D("%s: %s, size = %d, data = %p, usage = %s", __func__, MGLOG_D("%s: %s, size = %d, data = %p, usage = %s", __func__, MG_Util::ConvertGLEnumToString(target).c_str(),
MG_Util::ConvertGLEnumToString(target).c_str(), size, data, size, data, MG_Util::ConvertGLEnumToString(usage).c_str());
MG_Util::ConvertGLEnumToString(usage).c_str());
if (size < 0) { if (size < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BufferData_State", "Size must be non-negative.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BufferData_State", "Size must be non-negative."));
return; return;
} }
@@ -461,11 +456,11 @@ namespace MobileGL {
if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return; if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return;
auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget);
auto bufferObject = bindingSlot.GetBoundObject(); auto& bufferObject = bindingSlot.GetBoundObject();
if (!bufferObject) { if (!bufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BufferData_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BufferData_State",
"Buffer target is bound to no buffer object.")); "Buffer target is bound to no buffer object."));
return; return;
} }
@@ -482,11 +477,11 @@ namespace MobileGL {
BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target);
if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return; if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return;
auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer); Bool doesBufferObjectCreated = MG_State::pGLContext->ValidateBufferObject(buffer);
if (!bufferObject) { if (!doesBufferObjectCreated) {
MG_State::pGLContext->CreateBufferObject(buffer); MG_State::pGLContext->CreateBufferObject(buffer);
bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
} }
auto& bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget);
bindingSlot.Bind(bufferObject); bindingSlot.Bind(bufferObject);
@@ -498,11 +493,12 @@ namespace MobileGL {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GenBuffers_State", "n must be non-negative")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenBuffers_State", "n must be non-negative"));
return; return;
} }
auto bufferNames = MG_State::pGLContext->GenBufferNames(n); static thread_local Vector<GLuint> bufferNames;
Copy(bufferNames.data(), buffers, bufferNames.size()); MG_State::pGLContext->GenBufferNames(n, bufferNames);
Memcpy(buffers, bufferNames.data(), n * sizeof(GLuint));
} }
GLboolean IsBuffer_State(GLuint buffer) { GLboolean IsBuffer_State(GLuint buffer) {
@@ -516,11 +512,11 @@ namespace MobileGL {
BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target);
if (!BufferImpl::ValidateBufferBindingPointTarget(bufferTarget)) return; if (!BufferImpl::ValidateBufferBindingPointTarget(bufferTarget)) return;
auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer); Bool doesBufferObjectCreated = MG_State::pGLContext->ValidateBufferObject(buffer);
if (!bufferObject) { if (!doesBufferObjectCreated) {
MG_State::pGLContext->CreateBufferObject(buffer); MG_State::pGLContext->CreateBufferObject(buffer);
bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
} }
auto& bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
auto& point = MG_State::pGLContext->GetBufferBindingPoint(bufferTarget, pointIndex); auto& point = MG_State::pGLContext->GetBufferBindingPoint(bufferTarget, pointIndex);
point.Bind(bufferObject); point.Bind(bufferObject);
@@ -534,11 +530,11 @@ namespace MobileGL {
BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target);
if (!BufferImpl::ValidateBufferBindingPointTarget(bufferTarget)) return; if (!BufferImpl::ValidateBufferBindingPointTarget(bufferTarget)) return;
auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer); Bool doesBufferObjectCreated = MG_State::pGLContext->ValidateBufferObject(buffer);
if (!bufferObject) { if (!doesBufferObjectCreated) {
MG_State::pGLContext->CreateBufferObject(buffer); MG_State::pGLContext->CreateBufferObject(buffer);
bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
} }
auto& bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
auto& point = MG_State::pGLContext->GetBufferBindingPoint(bufferTarget, index); auto& point = MG_State::pGLContext->GetBufferBindingPoint(bufferTarget, index);
point.Bind(bufferObject); point.Bind(bufferObject);
@@ -603,5 +599,4 @@ namespace MobileGL {
void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) { void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) {
BindBufferRange_State(target, index, buffer, offset, size); BindBufferRange_State(target, index, buffer, offset, size);
} }
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
+2 -4
View File
@@ -9,8 +9,7 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */ /* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params); void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
GLboolean IsBuffer(GLuint buffer); GLboolean IsBuffer(GLuint buffer);
@@ -28,5 +27,4 @@ namespace MobileGL {
void BindBufferBase(GLenum target, GLuint index, GLuint buffer); void BindBufferBase(GLenum target, GLuint index, GLuint buffer);
void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
+11 -16
View File
@@ -13,16 +13,14 @@
#include <MG_Util/Converters/MGToGL/BufferEnumConverter.h> #include <MG_Util/Converters/MGToGL/BufferEnumConverter.h>
#include <MG_Util/Converters/MGToStr/BufferEnumConverter.h> #include <MG_Util/Converters/MGToStr/BufferEnumConverter.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
namespace BufferImpl {
Bool ValidateBufferTarget(BufferTarget target) { Bool ValidateBufferTarget(BufferTarget target) {
if (target == BufferTarget::Unknown) { if (target == BufferTarget::Unknown) {
using namespace MG_Util; using namespace MG_Util;
String bufferTargetStr = ConvertBufferTargetToString(target); String bufferTargetStr = ConvertBufferTargetToString(target);
String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target)); String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target));
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>(
MakeShared<GenericErrorInfo>(
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget", "MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget",
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr))); std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
return false; return false;
@@ -30,7 +28,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (target == BufferTarget::Index && MG_State::pGLContext->GetBoundVertexArray() == nullptr) { if (target == BufferTarget::Index && MG_State::pGLContext->GetBoundVertexArray() == nullptr) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
"ValidateBufferTarget", "ValidateBufferTarget",
"No vertex array object is bound.")); "No vertex array object is bound."));
return false; return false;
@@ -46,8 +44,7 @@ namespace MobileGL::MG_Impl::GLImpl {
String bufferTargetStr = ConvertBufferTargetToString(target); String bufferTargetStr = ConvertBufferTargetToString(target);
String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target)); String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target));
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>(
MakeShared<GenericErrorInfo>(
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget", "MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget",
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr))); std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
return false; return false;
@@ -59,9 +56,8 @@ namespace MobileGL::MG_Impl::GLImpl {
if (index == 0) { if (index == 0) {
if (allowZero) return true; if (allowZero) return true;
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, MG_State::pGLContext->RecordError(
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName",
"ValidateBufferName",
"Buffer name 0 is not valid.")); "Buffer name 0 is not valid."));
return false; return false;
} }
@@ -69,7 +65,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (isValid) return true; if (isValid) return true;
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName",
std::format("Buffer name {} is not valid.", index))); std::format("Buffer name {} is not valid.", index)));
return false; return false;
} }
@@ -83,7 +79,7 @@ namespace MobileGL::MG_Impl::GLImpl {
String glUsageStr = ConvertGLEnumToString(ConvertBufferUsageToGLEnum(usage)); String glUsageStr = ConvertGLEnumToString(ConvertBufferUsageToGLEnum(usage));
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferUsage", "MG_Impl/GLImpl/BufferImpl", "ValidateBufferUsage",
std::format("Usage {} ({}) is not one of the allowable values.", bufferUsageStr, glUsageStr))); std::format("Usage {} ({}) is not one of the allowable values.", bufferUsageStr, glUsageStr)));
return false; return false;
@@ -92,7 +88,7 @@ namespace MobileGL::MG_Impl::GLImpl {
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits) { Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits) {
if (accessBits == BufferMappingAccessBit::Null) { if (accessBits == BufferMappingAccessBit::Null) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum, MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
"ValidateBufferMappingAccess", "ValidateBufferMappingAccess",
"Access bits cannot be null.")); "Access bits cannot be null."));
return false; return false;
@@ -106,12 +102,11 @@ namespace MobileGL::MG_Impl::GLImpl {
if ((accessBits & validBits) != accessBits) { if ((accessBits & validBits) != accessBits) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferMappingAccess", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferMappingAccess",
"Access bits cannot contain invalid flags.")); "Access bits cannot contain invalid flags."));
return false; return false;
} }
return true; return true;
} }
} // namespace BufferImpl } // namespace MobileGL::MG_Impl::GLImpl::BufferImpl
} // namespace MobileGL::MG_Impl::GLImpl
+2 -4
View File
@@ -10,12 +10,10 @@
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/BufferState/BufferObject.h> #include <MG_State/GLState/BufferState/BufferObject.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
namespace BufferImpl {
Bool ValidateBufferTarget(BufferTarget target); Bool ValidateBufferTarget(BufferTarget target);
Bool ValidateBufferName(Uint index, Bool allowZero = false); Bool ValidateBufferName(Uint index, Bool allowZero = false);
Bool ValidateBufferUsage(BufferUsage usage); Bool ValidateBufferUsage(BufferUsage usage);
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits); Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits);
Bool ValidateBufferBindingPointTarget(BufferTarget target); Bool ValidateBufferBindingPointTarget(BufferTarget target);
} // namespace BufferImpl } // namespace MobileGL::MG_Impl::GLImpl::BufferImpl
} // namespace MobileGL::MG_Impl::GLImpl
+3 -6
View File
@@ -9,11 +9,9 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */ /* @INSERTION_POINT:FUNCTION_DECLARATION@ */
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 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);
@@ -38,5 +36,4 @@ namespace MobileGL {
GLsizei drawcount, const GLint* basevertex); GLsizei drawcount, const GLint* basevertex);
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);
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
@@ -38,11 +38,11 @@ namespace MobileGL::MG_Impl::GLImpl {
RenderbufferTarget rbTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target); RenderbufferTarget rbTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
if (!FramebufferImpl::ValidateRenderbufferTarget(rbTarget)) return; if (!FramebufferImpl::ValidateRenderbufferTarget(rbTarget)) return;
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(rbTarget); auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(rbTarget);
auto renderbufferObject = bindingSlot.GetBoundObject(); auto& renderbufferObject = bindingSlot.GetBoundObject();
if (!renderbufferObject) { if (!renderbufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State",
"Renderbuffer target is bound to no renderbuffer object.")); "Renderbuffer target is bound to no renderbuffer object."));
return; return;
} }
@@ -50,7 +50,7 @@ namespace MobileGL::MG_Impl::GLImpl {
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, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State", ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State",
"Width and height must be non-negative.")); "Width and height must be non-negative."));
return; return;
} }
@@ -74,10 +74,11 @@ namespace MobileGL::MG_Impl::GLImpl {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<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;
} }
auto renderbufferNames = MG_State::pGLContext->GenRenderbufferNames(n); static thread_local Vector<GLuint> 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));
} }
@@ -85,10 +86,11 @@ namespace MobileGL::MG_Impl::GLImpl {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<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;
} }
auto framebuffersNames = MG_State::pGLContext->GenFramebufferNames(n); static thread_local Vector<GLuint> 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));
} }
@@ -119,11 +121,11 @@ namespace MobileGL::MG_Impl::GLImpl {
if (!TextureImpl::ValidateTextureName(texture, true)) return; if (!TextureImpl::ValidateTextureName(texture, true)) return;
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget); auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
auto framebufferObject = bindingSlot.GetBoundObject(); auto& framebufferObject = bindingSlot.GetBoundObject();
if (!framebufferObject) { if (!framebufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferTexture2D_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferTexture2D_State",
"Framebuffer target is bound to no framebuffer object.")); "Framebuffer target is bound to no framebuffer object."));
return; return;
} }
@@ -133,11 +135,11 @@ namespace MobileGL::MG_Impl::GLImpl {
return; return;
} }
auto textureObject = MG_State::pGLContext->GetTextureObject(texture); auto& textureObject = MG_State::pGLContext->GetTextureObject(texture);
if (!textureObject) { if (!textureObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferTexture2D_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferTexture2D_State",
std::format("Texture object {} is not valid.", texture))); std::format("Texture object {} is not valid.", texture)));
return; return;
} }
@@ -166,11 +168,11 @@ namespace MobileGL::MG_Impl::GLImpl {
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return; if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer)) return; if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer)) return;
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget); auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
auto framebufferObject = bindingSlot.GetBoundObject(); auto& framebufferObject = bindingSlot.GetBoundObject();
if (!framebufferObject) { if (!framebufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferRenderbuffer_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferRenderbuffer_State",
"Framebuffer target is bound to no framebuffer object.")); "Framebuffer target is bound to no framebuffer object."));
return; return;
} }
@@ -180,11 +182,11 @@ namespace MobileGL::MG_Impl::GLImpl {
return; return;
} }
auto renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer); auto& renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
if (!renderbufferObject) { if (!renderbufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferRenderbuffer_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferRenderbuffer_State",
std::format("Renderbuffer object {} is not valid.", renderbuffer))); std::format("Renderbuffer object {} is not valid.", renderbuffer)));
return; return;
} }
@@ -196,18 +198,18 @@ namespace MobileGL::MG_Impl::GLImpl {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`n` is less than 0.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`n` is less than 0."));
return; return;
} else if (n > MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) { } else if (n > MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<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 // Get bound framebuffer
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw); auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
auto fbo = bindingSlot.GetBoundObject(); auto& fbo = bindingSlot.GetBoundObject();
bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO); bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
static int existenceMap[(SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount] = {-1}; static int existenceMap[(SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount] = {-1};
@@ -220,7 +222,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (attType == FramebufferAttachmentType::Unknown) { if (attType == FramebufferAttachmentType::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::format("bufs[{}] = {} is not an accepted value.", i, std::format("bufs[{}] = {} is not an accepted value.", i,
MG_Util::ConvertGLEnumToString(bufs[i])))); MG_Util::ConvertGLEnumToString(bufs[i]))));
return; return;
@@ -230,7 +232,7 @@ namespace MobileGL::MG_Impl::GLImpl {
attType <= FramebufferAttachmentType::Color31) { attType <= FramebufferAttachmentType::Color31) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__, "MG_Impl/GLImpl", __func__,
std::format( std::format(
"FBO is default FBO, but bufs[{}] = {} is one of the `GL_COLOR_ATTACHMENTn` tokens.", i, "FBO is default FBO, but bufs[{}] = {} is one of the `GL_COLOR_ATTACHMENTn` tokens.", i,
@@ -242,7 +244,7 @@ namespace MobileGL::MG_Impl::GLImpl {
attType <= FramebufferAttachmentType::BackRight) { attType <= FramebufferAttachmentType::BackRight) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__, "MG_Impl/GLImpl", __func__,
std::format("FBO is not default FBO, but bufs[{}] = {} is anything other than `GL_NONE` or " std::format("FBO is not default FBO, but bufs[{}] = {} is anything other than `GL_NONE` or "
"one of the `GL_COLOR_ATTACHMENTn` tokens.", "one of the `GL_COLOR_ATTACHMENTn` tokens.",
@@ -253,7 +255,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (attType != FramebufferAttachmentType::None && existenceMap[(SizeT)attType] >= 0) { if (attType != FramebufferAttachmentType::None && existenceMap[(SizeT)attType] >= 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::format("a symbolic constant other than `GL_NONE` appears " std::format("a symbolic constant other than `GL_NONE` appears "
"more than once in bufs. bufs[{}] == bufs[{}] == {}.", "more than once in bufs. bufs[{}] == bufs[{}] == {}.",
i, existenceMap[(SizeT)attType], i, existenceMap[(SizeT)attType],
@@ -267,7 +269,7 @@ namespace MobileGL::MG_Impl::GLImpl {
(SizeT)FramebufferAttachmentType::Color0 + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) { (SizeT)FramebufferAttachmentType::Color0 + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::format("bufs[{}] == {} indicates a color buffer that does " std::format("bufs[{}] == {} indicates a color buffer that does "
"not exist in the current GL context.", "not exist in the current GL context.",
i, MG_Util::ConvertGLEnumToString(bufs[i])))); i, MG_Util::ConvertGLEnumToString(bufs[i]))));
@@ -297,7 +299,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (attType == FramebufferAttachmentType::Unknown) { if (attType == FramebufferAttachmentType::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__, "MG_Impl/GLImpl", __func__,
std::format("`mode` = {} is not an accepted value.", MG_Util::ConvertGLEnumToString(mode)))); std::format("`mode` = {} is not an accepted value.", MG_Util::ConvertGLEnumToString(mode))));
return; return;
@@ -305,7 +307,7 @@ namespace MobileGL::MG_Impl::GLImpl {
// Get bound framebuffer // Get bound framebuffer
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read); auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
auto fbo = bindingSlot.GetBoundObject(); auto& fbo = bindingSlot.GetBoundObject();
fbo->SetReadBuffer(attType); fbo->SetReadBuffer(attType);
} }
@@ -313,13 +315,13 @@ namespace MobileGL::MG_Impl::GLImpl {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteRenderbuffers_State", "n must be non-negative.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteRenderbuffers_State", "n must be non-negative."));
return; return;
} }
if (!renderbuffers) { if (!renderbuffers) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteRenderbuffers_State", ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteRenderbuffers_State",
"Renderbuffer names array cannot be null.")); "Renderbuffer names array cannot be null."));
return; return;
} }
@@ -336,13 +338,13 @@ namespace MobileGL::MG_Impl::GLImpl {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteFramebuffers_State", "n must be non-negative.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteFramebuffers_State", "n must be non-negative."));
return; return;
} }
if (!framebuffers) { if (!framebuffers) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteFramebuffers_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteFramebuffers_State",
"Framebuffer names array cannot be null.")); "Framebuffer names array cannot be null."));
return; return;
} }
@@ -360,11 +362,11 @@ namespace MobileGL::MG_Impl::GLImpl {
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return GL_FRAMEBUFFER_UNDEFINED; if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return GL_FRAMEBUFFER_UNDEFINED;
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget); auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
auto framebufferObject = bindingSlot.GetBoundObject(); auto& framebufferObject = bindingSlot.GetBoundObject();
if (!framebufferObject) { if (!framebufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "CheckFramebufferStatus_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CheckFramebufferStatus_State",
"Framebuffer target is bound to no framebuffer object.")); "Framebuffer target is bound to no framebuffer object."));
return GL_FRAMEBUFFER_UNDEFINED; return GL_FRAMEBUFFER_UNDEFINED;
} }
@@ -382,11 +384,11 @@ namespace MobileGL::MG_Impl::GLImpl {
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target); RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return; if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return;
auto renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer); Bool doesRenderbufferCreated = MG_State::pGLContext->ValidateRenderbufferObject(renderbuffer);
if (!renderbufferObject) { if (!doesRenderbufferCreated) {
MG_State::pGLContext->CreateRenderbufferObject(renderbuffer); MG_State::pGLContext->CreateRenderbufferObject(renderbuffer);
renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
} }
auto& renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget); auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
bindingSlot.Bind(renderbufferObject); bindingSlot.Bind(renderbufferObject);
@@ -403,11 +405,11 @@ namespace MobileGL::MG_Impl::GLImpl {
FramebufferTarget framebufferTarget = MG_Util::ConvertGLEnumToFramebufferTarget(target); FramebufferTarget framebufferTarget = MG_Util::ConvertGLEnumToFramebufferTarget(target);
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return; if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
auto framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer); Bool doesFramebufferCreated = MG_State::pGLContext->ValidateFramebufferObject(framebuffer);
if (!framebufferObject) { if (!doesFramebufferCreated) {
MG_State::pGLContext->CreateFramebufferObject(framebuffer); MG_State::pGLContext->CreateFramebufferObject(framebuffer);
framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
} }
auto& framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget); auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
bindingSlot.Bind(framebufferObject); bindingSlot.Bind(framebufferObject);
@@ -419,11 +421,11 @@ namespace MobileGL::MG_Impl::GLImpl {
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target); RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return; if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return;
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget); auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
auto renderbufferObject = bindingSlot.GetBoundObject(); auto& renderbufferObject = bindingSlot.GetBoundObject();
if (!renderbufferObject) { if (!renderbufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetRenderbufferParameteriv_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetRenderbufferParameteriv_State",
"Renderbuffer target is bound to no renderbuffer object.")); "Renderbuffer target is bound to no renderbuffer object."));
return; return;
} }
@@ -462,7 +464,7 @@ namespace MobileGL::MG_Impl::GLImpl {
default: default:
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", "GetRenderbufferParameteriv_State", "MG_Impl/GLImpl", "GetRenderbufferParameteriv_State",
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;
@@ -492,7 +494,7 @@ namespace MobileGL::MG_Impl::GLImpl {
// Check width/height // Check width/height
if (width < 0 || height < 0) { if (width < 0 || height < 0) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Width and height must be non-negative")); "Width and height must be non-negative"));
return; return;
} }
@@ -501,7 +503,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) { if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid format")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid format"));
return; return;
} }
@@ -509,17 +511,17 @@ namespace MobileGL::MG_Impl::GLImpl {
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) { if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid pixel data type")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid pixel data type"));
return; return;
} }
// Get bound framebuffer // Get bound framebuffer
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read); auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
auto framebufferObject = bindingSlot.GetBoundObject(); auto& framebufferObject = bindingSlot.GetBoundObject();
if (!framebufferObject) { if (!framebufferObject) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No framebuffer bound to read target")); "No framebuffer bound to read target"));
return; return;
} }
@@ -528,7 +530,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (!framebufferObject->CheckCompleteness()) { if (!framebufferObject->CheckCompleteness()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidFramebufferOperation, ErrorCode::InvalidFramebufferOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Framebuffer is incomplete")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Framebuffer is incomplete"));
return; return;
} }
@@ -537,7 +539,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) { if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No stencil buffer for stencil index format")); "No stencil buffer for stencil index format"));
return; return;
} }
@@ -545,7 +547,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Depth).IsValid()) { if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Depth).IsValid()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No depth buffer for depth component format")); "No depth buffer for depth component format"));
return; return;
} }
@@ -554,7 +556,7 @@ namespace MobileGL::MG_Impl::GLImpl {
!framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) { !framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No depth/stencil buffer for depth-stencil format")); "No depth/stencil buffer for depth-stencil format"));
return; return;
} }
@@ -563,7 +565,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (texturePixelDataType != TexturePixelDataType::UnsignedInt248 && if (texturePixelDataType != TexturePixelDataType::UnsignedInt248 &&
texturePixelDataType != TexturePixelDataType::Float32UnsignedInt248Rev) { texturePixelDataType != TexturePixelDataType::Float32UnsignedInt248Rev) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Invalid type for depth-stencil format")); "Invalid type for depth-stencil format"));
return; return;
} }
@@ -577,7 +579,7 @@ namespace MobileGL::MG_Impl::GLImpl {
// Check if PBO is mapped // Check if PBO is mapped
if (pixelPackBufferObject->IsMapped()) { if (pixelPackBufferObject->IsMapped()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, MakeShared<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"));
return; return;
} }
@@ -587,7 +589,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (reinterpret_cast<uintptr_t>(pixels) % typeSize != 0) { if (reinterpret_cast<uintptr_t>(pixels) % typeSize != 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Pixel data not aligned for pixel pack buffer")); "Pixel data not aligned for pixel pack buffer"));
return; return;
} }
@@ -595,11 +597,11 @@ namespace MobileGL::MG_Impl::GLImpl {
// Check multisampling // Check multisampling
if (framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).IsRenderbuffer()) { if (framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).IsRenderbuffer()) {
auto rbo = framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).GetRenderbuffer(); auto& rbo = framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).GetRenderbuffer();
if (rbo && rbo->GetSamples() > 1) { if (rbo && rbo->GetSamples() > 1) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"ReadPixels not supported for multisampled framebuffers")); "ReadPixels not supported for multisampled framebuffers"));
return; return;
} }
@@ -732,6 +734,6 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
namespace FramebufferImpl { namespace FramebufferImpl {
DefaultFramebufferInfo* pDefaultFramebufferInfo; UniquePtr<DefaultFramebufferInfo> pDefaultFramebufferInfo;
} // namespace FramebufferImpl } // namespace FramebufferImpl
} // namespace MobileGL::MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
@@ -11,8 +11,7 @@
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */ /* @INSERTION_POINT:FUNCTION_DECLARATION@ */
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 ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
@@ -55,7 +54,6 @@ namespace MobileGL {
SharedPtr<MG_State::GLState::ITextureObject> stencilAttachment; SharedPtr<MG_State::GLState::ITextureObject> stencilAttachment;
}; };
extern DefaultFramebufferInfo* pDefaultFramebufferInfo; extern UniquePtr<DefaultFramebufferInfo> pDefaultFramebufferInfo;
} // namespace FramebufferImpl } // namespace FramebufferImpl
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
@@ -13,16 +13,14 @@
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h> #include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
#include <MG_Util/Converters/MGToStr/FramebufferEnumConverter.h> #include <MG_Util/Converters/MGToStr/FramebufferEnumConverter.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
namespace FramebufferImpl {
Bool ValidateFramebufferTarget(FramebufferTarget target) { Bool ValidateFramebufferTarget(FramebufferTarget target) {
if (target == FramebufferTarget::Unknown) { if (target == FramebufferTarget::Unknown) {
using namespace MG_Util; using namespace MG_Util;
String bufferTargetStr = ConvertFramebufferTargetToString(target); String bufferTargetStr = ConvertFramebufferTargetToString(target);
String glTargetStr = ConvertGLEnumToString(ConvertFramebufferTargetToGLEnum(target)); String glTargetStr = ConvertGLEnumToString(ConvertFramebufferTargetToGLEnum(target));
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>(
MakeShared<GenericErrorInfo>(
"MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferTarget", "MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferTarget",
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr))); std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
return false; return false;
@@ -34,7 +32,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (index == 0 && !allowZero) { if (index == 0 && !allowZero) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName",
"Framebuffer name 0 is not valid in this situation.")); "Framebuffer name 0 is not valid in this situation."));
return false; return false;
} }
@@ -42,7 +40,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (isValid) return true; if (isValid) return true;
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName",
std::format("Framebuffer name {} is not valid.", index))); std::format("Framebuffer name {} is not valid.", index)));
return false; return false;
} }
@@ -54,7 +52,7 @@ namespace MobileGL::MG_Impl::GLImpl {
String glAttachmentStr = ConvertGLEnumToString(ConvertFramebufferAttachmentTypeToGLEnum(attachment)); String glAttachmentStr = ConvertGLEnumToString(ConvertFramebufferAttachmentTypeToGLEnum(attachment));
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferAttachmentType", "MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferAttachmentType",
std::format("Attachment type {} ({}) is not valid.", attachmentStr, glAttachmentStr))); std::format("Attachment type {} ({}) is not valid.", attachmentStr, glAttachmentStr)));
return false; return false;
@@ -69,7 +67,7 @@ namespace MobileGL::MG_Impl::GLImpl {
String glTargetStr = ConvertGLEnumToString(ConvertRenderbufferTargetToGLEnum(target)); String glTargetStr = ConvertGLEnumToString(ConvertRenderbufferTargetToGLEnum(target));
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferTarget", "MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferTarget",
std::format("Target {} ({}) is not valid.", renderbufferTargetStr, glTargetStr))); std::format("Target {} ({}) is not valid.", renderbufferTargetStr, glTargetStr)));
return false; return false;
@@ -81,7 +79,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (index == 0 && !allowZero) { if (index == 0 && !allowZero) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName",
"Renderbuffer name 0 is not valid in this situation.")); "Renderbuffer name 0 is not valid in this situation."));
return false; return false;
} }
@@ -89,9 +87,8 @@ namespace MobileGL::MG_Impl::GLImpl {
if (isValid) return true; if (isValid) return true;
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName",
std::format("Renderbuffer name {} is not valid.", index))); std::format("Renderbuffer name {} is not valid.", index)));
return false; return false;
} }
} // namespace FramebufferImpl } // namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl
} // namespace MobileGL::MG_Impl::GLImpl
@@ -10,12 +10,10 @@
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/FramebufferState/FramebufferObject.h> #include <MG_State/GLState/FramebufferState/FramebufferObject.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
namespace FramebufferImpl {
Bool ValidateFramebufferTarget(FramebufferTarget target); Bool ValidateFramebufferTarget(FramebufferTarget target);
Bool ValidateFramebufferName(Uint index, Bool allowZero = true); Bool ValidateFramebufferName(Uint index, Bool allowZero = true);
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment); Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment);
Bool ValidateRenderbufferTarget(RenderbufferTarget target); Bool ValidateRenderbufferTarget(RenderbufferTarget target);
Bool ValidateRenderbufferName(Uint index, Bool allowZero = true); Bool ValidateRenderbufferName(Uint index, Bool allowZero = true);
} // namespace FramebufferImpl } // namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl
} // namespace MobileGL::MG_Impl::GLImpl
+15 -14
View File
@@ -7,8 +7,6 @@
// End of Source File Header // End of Source File Header
#include "GL_Getter.h" #include "GL_Getter.h"
#include "GL/gl.h"
#include "MG_Util/Debug/Log.h"
#include <Config.h> #include <Config.h>
#include <MGGitHash.h> #include <MGGitHash.h>
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
@@ -127,7 +125,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (!params) { if (!params) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv", "params pointer cannot be null")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv", "params pointer cannot be null"));
return; return;
} }
@@ -146,9 +144,9 @@ namespace MobileGL::MG_Impl::GLImpl {
*params = 0; // TODO *params = 0; // TODO
break; break;
case GL_ARRAY_BUFFER_BINDING: { case GL_ARRAY_BUFFER_BINDING: {
auto obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex).GetBoundObject(); auto& obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex).GetBoundObject();
if (obj) if (obj)
*params = obj->GetExternalIndex(); *params = (GLint)obj->GetExternalIndex();
else else
*params = 0; *params = 0;
break; break;
@@ -256,14 +254,14 @@ namespace MobileGL::MG_Impl::GLImpl {
break; break;
case GL_CURRENT_PROGRAM: { case GL_CURRENT_PROGRAM: {
const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram(); const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
*params = currentProgram ? currentProgram->GetExternalIndex() : 0; *params = currentProgram ? (GLint)currentProgram->GetExternalIndex() : 0;
break; break;
} }
case GL_DEPTH_CLEAR_VALUE: case GL_DEPTH_CLEAR_VALUE:
*params = MG_State::pGLContext->GetClearDepth(); *params = (GLint)MG_State::pGLContext->GetClearDepth();
break; break;
case GL_DEPTH_FUNC: case GL_DEPTH_FUNC:
*params = MG_Util::ConvertDepthTestFuncToGLEnum(MG_State::pGLContext->GetDepthFunc()); *params = (GLint)MG_Util::ConvertDepthTestFuncToGLEnum(MG_State::pGLContext->GetDepthFunc());
break; break;
case GL_DEPTH_RANGE: case GL_DEPTH_RANGE:
*params = 0; // TODO *params = 0; // TODO
@@ -288,12 +286,12 @@ namespace MobileGL::MG_Impl::GLImpl {
break; break;
case GL_DRAW_FRAMEBUFFER_BINDING: { case GL_DRAW_FRAMEBUFFER_BINDING: {
const auto& FBO = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); const auto& FBO = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
*params = FBO ? FBO->GetExternalIndex() : 0; *params = FBO ? (GLint)FBO->GetExternalIndex() : 0;
break; break;
} }
case GL_READ_FRAMEBUFFER_BINDING: { case GL_READ_FRAMEBUFFER_BINDING: {
const auto& FBO = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(); const auto& FBO = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
*params = FBO ? FBO->GetExternalIndex() : 0; *params = FBO ? (GLint)FBO->GetExternalIndex() : 0;
break; break;
} }
case GL_ELEMENT_ARRAY_BUFFER_BINDING: { case GL_ELEMENT_ARRAY_BUFFER_BINDING: {
@@ -302,7 +300,7 @@ namespace MobileGL::MG_Impl::GLImpl {
break; break;
} }
const auto& bufferObject = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Index).GetBoundObject(); const auto& bufferObject = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Index).GetBoundObject();
*params = bufferObject ? bufferObject->GetExternalIndex() : 0; *params = bufferObject ? (GLint)bufferObject->GetExternalIndex() : 0;
break; break;
} }
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT: case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
@@ -886,7 +884,7 @@ namespace MobileGL::MG_Impl::GLImpl {
default: default:
MGLOG_E("glGetIntegerv: Invalid enum %s (0x%X)", MG_Util::ConvertGLEnumToString(pname).c_str(), pname); MGLOG_E("glGetIntegerv: Invalid enum %s (0x%X)", MG_Util::ConvertGLEnumToString(pname).c_str(), pname);
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum, MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv",
std::format("Invalid enum: 0x{:X}", pname))); std::format("Invalid enum: 0x{:X}", pname)));
break; break;
@@ -894,7 +892,10 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
GLenum GetError() { GLenum GetError() {
ErrorCode errorCode = MG_State::pGLContext->PopGLError().value_or(Error{ErrorCode::NoError, nullptr}).code; auto error = MG_State::pGLContext->PopGLError();
return MG_Util::ConvertErrorCodeToGLEnum(errorCode); if (!error || !error->get()) {
return GL_NO_ERROR;
}
return MG_Util::ConvertErrorCodeToGLEnum(error->get()->code);
} }
} // namespace MobileGL::MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
+112 -118
View File
@@ -8,35 +8,35 @@
#include "GL_Program.h" #include "GL_Program.h"
#include "Config.h" #include "Config.h"
#include "MG_Util/Converters/GLToStr/GLEnumConverter.h"
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/GLToMG/ProgramEnumConverter.h> #include <MG_Util/Converters/GLToMG/ProgramEnumConverter.h>
#include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h> #include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h>
#include <MG_Util/Converters/SPIRVCrossToGL/SpvcTypeConverter.h> #include <MG_Util/Converters/SPIRVCrossToGL/SpvcTypeConverter.h>
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
static bool CheckShaderNameValidity(Uint shader) { static bool CheckShaderNameValidity(Uint shader) {
if (shader == 0 || !MG_State::pGLContext->ValidateShaderName(shader)) { if (shader == 0 || !MG_State::pGLContext->ValidateShaderName(shader)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(shader) + " is not a valid name.")); std::to_string(shader) + " is not a valid name."));
return false; return false;
} }
return true; return true;
} }
static SharedPtr<MG_State::GLState::ShaderObject> TryToGetShaderObject(Uint shader) { static const SharedPtr<MG_State::GLState::ShaderObject>& TryToGetShaderObject(Uint shader) {
if (!CheckShaderNameValidity(shader)) return nullptr; static const SharedPtr<MG_State::GLState::ShaderObject> nullShaderObject = nullptr;
if (!CheckShaderNameValidity(shader)) return nullShaderObject;
auto shaderObject = MG_State::pGLContext->GetShaderObject(shader); auto& shaderObject = MG_State::pGLContext->GetShaderObject(shader);
if (!shaderObject) { if (!shaderObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(shader) + " is not a shader object.")); std::to_string(shader) + " is not a shader object."));
return nullptr; return nullShaderObject;
} }
return shaderObject; return shaderObject;
} }
@@ -45,23 +45,24 @@ namespace MobileGL {
if (!MG_State::pGLContext->ValidateProgramName(program)) { if (!MG_State::pGLContext->ValidateProgramName(program)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(program) + " is not a valid name.")); std::to_string(program) + " is not a valid name."));
return false; return false;
} }
return true; return true;
} }
static SharedPtr<MG_State::GLState::ProgramObject> TryToGetProgramObject(GLuint program) { static const SharedPtr<MG_State::GLState::ProgramObject>& TryToGetProgramObject(GLuint program) {
if (!CheckProgramNameValidity(program)) return nullptr; static const SharedPtr<MG_State::GLState::ProgramObject> nullProgramObject = nullptr;
if (!CheckProgramNameValidity(program)) return nullProgramObject;
auto programObject = MG_State::pGLContext->GetProgramObject(program); auto& programObject = MG_State::pGLContext->GetProgramObject(program);
if (!programObject) { if (!programObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(program) + " is not a program object.")); std::to_string(program) + " is not a program object."));
return nullptr; return nullProgramObject;
} }
return programObject; return programObject;
} }
@@ -77,13 +78,13 @@ namespace MobileGL {
} }
void AttachShader_State(GLuint program, GLuint shader) { void AttachShader_State(GLuint program, GLuint shader) {
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject) return; if (!programObject) return;
auto shaderObject = TryToGetShaderObject(shader); auto& shaderObject = TryToGetShaderObject(shader);
if (!shaderObject) return; if (!shaderObject) return;
if (!programObject->AttachShader(shaderObject)) { if (!programObject->AttachShader(shaderObject)) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(shader) + std::to_string(shader) +
" is already attached to " + " is already attached to " +
std::to_string(program) + ".")); std::to_string(program) + "."));
@@ -95,7 +96,7 @@ namespace MobileGL {
if (index >= MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS) { if (index >= MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"index " + std::to_string(index) + "index " + std::to_string(index) +
" is greater than or equal to `GL_MAX_VERTEX_ATTRIBS`.")); " is greater than or equal to `GL_MAX_VERTEX_ATTRIBS`."));
return; return;
@@ -104,13 +105,12 @@ namespace MobileGL {
if (strncmp(name, "gl_", 3) == 0) { if (strncmp(name, "gl_", 3) == 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"name " + std::string(name) + "name " + std::string(name) + " starts with the reserved prefix `gl_`."));
" starts with the reserved prefix `gl_`."));
return; return;
} }
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject) return; if (!programObject) return;
MGLOG_D("%s: loc %02d = \"%s\"", __func__, index, name); MGLOG_D("%s: loc %02d = \"%s\"", __func__, index, name);
@@ -118,12 +118,12 @@ namespace MobileGL {
} }
void CompileShader_State(GLuint shader) { void CompileShader_State(GLuint shader) {
auto shaderObject = TryToGetShaderObject(shader); auto& shaderObject = TryToGetShaderObject(shader);
if (!shaderObject) return; if (!shaderObject) return;
shaderObject->Compile(); shaderObject->Compile();
} }
GLuint CreateProgram_State(void) { GLuint CreateProgram_State() {
return MG_State::pGLContext->CreateProgram(); return MG_State::pGLContext->CreateProgram();
} }
@@ -132,7 +132,7 @@ namespace MobileGL {
if (shaderId == 0) { if (shaderId == 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`shaderType` is not an accepted value.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`shaderType` is not an accepted value."));
return 0; return 0;
} }
return shaderId; return shaderId;
@@ -149,16 +149,16 @@ namespace MobileGL {
} }
void DetachShader_State(GLuint program, GLuint shader) { void DetachShader_State(GLuint program, GLuint shader) {
auto shaderObject = TryToGetShaderObject(shader); auto& shaderObject = TryToGetShaderObject(shader);
if (!shaderObject) return; if (!shaderObject) return;
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject) return; if (!programObject) return;
auto count = programObject->DetachShader(shaderObject); auto count = programObject->DetachShader(shaderObject);
if (count <= 0) { if (count <= 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Shader is not attached to program.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Shader is not attached to program."));
return; return;
} }
} }
@@ -168,17 +168,17 @@ namespace MobileGL {
if (bufSize < 0) { if (bufSize < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"bufSize " + std::to_string(bufSize) + " is less than 0.")); "bufSize " + std::to_string(bufSize) + " is less than 0."));
return; return;
} }
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject || !programObject->GetLinkStatus()) return; if (!programObject || !programObject->GetLinkStatus()) return;
auto attribCount = programObject->GetActiveAttributesCount(); auto attribCount = programObject->GetActiveAttributesCount();
if (index >= attribCount) { if (index >= attribCount) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__, "MG_Impl/GLImpl", __func__,
"index " + std::to_string(index) + "index " + std::to_string(index) +
" is greater than or equal to the number of active attribute variables in " + " is greater than or equal to the number of active attribute variables in " +
@@ -188,7 +188,7 @@ namespace MobileGL {
if (type != nullptr) *type = programObject->GetAttribType(index); if (type != nullptr) *type = programObject->GetAttribType(index);
if (bufSize == 0) return; if (bufSize == 0) return;
auto& attribName = programObject->GetAttribName(index); auto& attribName = programObject->GetAttribName(index);
CopyStr(bufSize, length, name, attribName.c_str(), attribName.length()); CopyStr(bufSize, length, name, attribName.c_str(), (GLsizei)attribName.length());
} }
void GetActiveUniform_State(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, void GetActiveUniform_State(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size,
@@ -196,17 +196,17 @@ namespace MobileGL {
if (bufSize < 0) { if (bufSize < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"bufSize " + std::to_string(bufSize) + " is less than 0.")); "bufSize " + std::to_string(bufSize) + " is less than 0."));
return; return;
} }
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject || !programObject->GetLinkStatus()) return; if (!programObject || !programObject->GetLinkStatus()) return;
auto uniformCount = programObject->GetUniformCount(); auto uniformCount = programObject->GetUniformCount();
if (index >= uniformCount) { if (index >= uniformCount) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__, "MG_Impl/GLImpl", __func__,
"index " + std::to_string(index) + "index " + std::to_string(index) +
" is greater than or equal to the number of active uniform variables in " + " is greater than or equal to the number of active uniform variables in " +
@@ -217,18 +217,18 @@ namespace MobileGL {
if (type != nullptr) *type = programObject->GetUniformType(index); if (type != nullptr) *type = programObject->GetUniformType(index);
if (bufSize == 0) return; if (bufSize == 0) return;
auto& uniformName = programObject->GetUniformName(index); auto& uniformName = programObject->GetUniformName(index);
CopyStr(bufSize, length, name, uniformName.c_str(), uniformName.length()); CopyStr(bufSize, length, name, uniformName.c_str(), (GLsizei)uniformName.length());
} }
void GetAttachedShaders_State(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders) { void GetAttachedShaders_State(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders) {
if (maxCount < 0) { if (maxCount < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"maxCount " + std::to_string(maxCount) + " is less than 0.")); "maxCount " + std::to_string(maxCount) + " is less than 0."));
return; return;
} }
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject) return; if (!programObject) return;
const auto& s = programObject->GetAttachedShaders(); const auto& s = programObject->GetAttachedShaders();
GLsizei c = std::min((GLsizei)s.size(), maxCount); GLsizei c = std::min((GLsizei)s.size(), maxCount);
@@ -239,7 +239,7 @@ namespace MobileGL {
} }
GLint GetAttribLocation_State(GLuint program, const GLchar* name) { GLint GetAttribLocation_State(GLuint program, const GLchar* name) {
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject) return -1; if (!programObject) return -1;
if (strncmp(name, "gl_", 3) == 0) return -1; if (strncmp(name, "gl_", 3) == 0) return -1;
if (!programObject->GetLinkStatus()) return -1; if (!programObject->GetLinkStatus()) return -1;
@@ -247,7 +247,7 @@ namespace MobileGL {
} }
void GetProgramiv_State(GLuint program, GLenum pname, GLint* params) { void GetProgramiv_State(GLuint program, GLenum pname, GLint* params) {
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject) return; if (!programObject) return;
switch (pname) { switch (pname) {
@@ -265,13 +265,13 @@ namespace MobileGL {
break; break;
case GL_INFO_LOG_LENGTH: { case GL_INFO_LOG_LENGTH: {
const auto& log = programObject->GetInfoLog(); const auto& log = programObject->GetInfoLog();
*params = log.length(); *params = (GLint)log.length();
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params); MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
break; break;
} }
case GL_ATTACHED_SHADERS: { case GL_ATTACHED_SHADERS: {
const auto& attachedShaders = programObject->GetAttachedShaders(); const auto& attachedShaders = programObject->GetAttachedShaders();
*params = attachedShaders.size(); *params = (GLint)attachedShaders.size();
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params); MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
break; break;
} }
@@ -288,7 +288,7 @@ namespace MobileGL {
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params); MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
break; break;
case GL_ACTIVE_UNIFORMS: case GL_ACTIVE_UNIFORMS:
*params = programObject->GetUniformCount(); *params = (GLint)programObject->GetUniformCount();
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params); MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
break; break;
case GL_ACTIVE_UNIFORM_MAX_LENGTH: case GL_ACTIVE_UNIFORM_MAX_LENGTH:
@@ -317,27 +317,27 @@ namespace MobileGL {
MGLOG_D("%s: %s", __func__, MG_Util::ConvertGLEnumToString(pname).c_str()); MGLOG_D("%s: %s", __func__, MG_Util::ConvertGLEnumToString(pname).c_str());
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"pname " + std::to_string(pname) + " is not an accepted value.")); "pname " + std::to_string(pname) + " is not an accepted value."));
return; return;
} }
} }
void GetProgramInfoLog_State(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { void GetProgramInfoLog_State(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog) {
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject) return; if (!programObject) return;
const auto& log = programObject->GetInfoLog(); const auto& log = programObject->GetInfoLog();
CopyStr(bufSize, length, infoLog, log.c_str(), log.length()); CopyStr(bufSize, length, infoLog, log.c_str(), (GLsizei)log.length());
} }
void GetShaderiv_State(GLuint shader, GLenum pname, GLint* params) { void GetShaderiv_State(GLuint shader, GLenum pname, GLint* params) {
auto shaderObject = TryToGetShaderObject(shader); auto& shaderObject = TryToGetShaderObject(shader);
if (!shaderObject) return; if (!shaderObject) return;
switch (pname) { switch (pname) {
case GL_SHADER_TYPE: case GL_SHADER_TYPE:
*params = MG_Util::ConvertShaderStageToGLEnum(shaderObject->GetShaderStage()); *params = (GLint)MG_Util::ConvertShaderStageToGLEnum(shaderObject->GetShaderStage());
break; break;
case GL_DELETE_STATUS: case GL_DELETE_STATUS:
*params = shaderObject->GetDeleteStatus(); *params = shaderObject->GetDeleteStatus();
@@ -346,45 +346,45 @@ namespace MobileGL {
*params = shaderObject->GetCompileStatus(); *params = shaderObject->GetCompileStatus();
break; break;
case GL_INFO_LOG_LENGTH: case GL_INFO_LOG_LENGTH:
*params = shaderObject->GetInfoLog().length(); *params = (GLint)shaderObject->GetInfoLog().length();
break; break;
case GL_SHADER_SOURCE_LENGTH: case GL_SHADER_SOURCE_LENGTH:
*params = shaderObject->GetShaderSource().length(); *params = (GLint)shaderObject->GetShaderSource().length();
break; break;
default: default:
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"pname " + std::to_string(pname) + " is not an accepted value.")); "pname " + std::to_string(pname) + " is not an accepted value."));
return; return;
} }
} }
void GetShaderInfoLog_State(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { void GetShaderInfoLog_State(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog) {
auto shaderObject = TryToGetShaderObject(shader); auto& shaderObject = TryToGetShaderObject(shader);
if (!shaderObject) return; if (!shaderObject) return;
const auto& log = shaderObject->GetInfoLog(); const auto& log = shaderObject->GetInfoLog();
CopyStr(bufSize, length, infoLog, log.c_str(), log.length()); CopyStr(bufSize, length, infoLog, log.c_str(), (GLsizei)log.length());
} }
void GetShaderSource_State(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source) { void GetShaderSource_State(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source) {
if (bufSize < 0) { if (bufSize < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"bufSize " + std::to_string(bufSize) + " is less than 0.")); "bufSize " + std::to_string(bufSize) + " is less than 0."));
} }
auto shaderObject = TryToGetShaderObject(shader); auto& shaderObject = TryToGetShaderObject(shader);
if (!shaderObject) return; if (!shaderObject) return;
auto& src = shaderObject->GetShaderSource(); auto& src = shaderObject->GetShaderSource();
CopyStr(bufSize, length, source, src.c_str(), src.length()); CopyStr(bufSize, length, source, src.c_str(), (GLsizei)src.length());
} }
GLint GetUniformLocation_State(GLuint program, const GLchar* name) { GLint GetUniformLocation_State(GLuint program, const GLchar* name) {
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject) return -1; if (!programObject) return -1;
auto loc = programObject->GetUniformLocation(name); auto loc = programObject->GetUniformLocation(name);
MGLOG_D("%s: loc %02d = %s", __func__, loc, name); MGLOG_D("%s: loc %02d = %s", __func__, loc, name);
@@ -392,13 +392,13 @@ namespace MobileGL {
} }
void GetUniform_State(GLuint program, GLint location, void* params) { void GetUniform_State(GLuint program, GLint location, void* params) {
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject) return; if (!programObject) return;
if (!programObject->GetLinkStatus()) { if (!programObject->GetLinkStatus()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(program) + " has not been successfully linked.")); std::to_string(program) + " has not been successfully linked."));
return; return;
} }
@@ -407,7 +407,7 @@ namespace MobileGL {
if (location < 0 || location > programObject->GetMaxUniformLocation()) { if (location < 0 || location > programObject->GetMaxUniformLocation()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) + "location " + std::to_string(location) +
" does not correspond to a valid uniform variable location " " does not correspond to a valid uniform variable location "
"for the specified program object.")); "for the specified program object."));
@@ -419,7 +419,7 @@ namespace MobileGL {
if (uniformName.empty()) { if (uniformName.empty()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) + "location " + std::to_string(location) +
" does not correspond to a valid uniform variable location " " does not correspond to a valid uniform variable location "
"for the specified program object.")); "for the specified program object."));
@@ -441,8 +441,8 @@ namespace MobileGL {
// assuming float here, which may not be the case // assuming float here, which may not be the case
auto* pBase = pUBO + offset; auto* pBase = pUBO + offset;
for (int i = 0; i < ttype->getMatrixRows(); i++) { for (int i = 0; i < ttype->getMatrixRows(); i++) {
Memcpy((char*)params + ttype->getMatrixCols() * sizeof(float) * i, Memcpy((char*)params + ttype->getMatrixCols() * sizeof(float) * i, pBase + 4 * sizeof(float) * i,
pBase + 4 * sizeof(float) * i, ttype->getMatrixCols() * sizeof(float)); ttype->getMatrixCols() * sizeof(float));
} }
} }
} }
@@ -474,7 +474,7 @@ namespace MobileGL {
} }
void LinkProgram_State(GLuint program) { void LinkProgram_State(GLuint program) {
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject) return; if (!programObject) return;
MGLOG_D("%s: linking program %d", __func__, program); MGLOG_D("%s: linking program %d", __func__, program);
@@ -496,12 +496,12 @@ namespace MobileGL {
if (count < 0) { if (count < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"count " + std::to_string(count) + " is less than 0.")); "count " + std::to_string(count) + " is less than 0."));
return; return;
} }
auto shaderObject = TryToGetShaderObject(shader); auto& shaderObject = TryToGetShaderObject(shader);
if (!shaderObject) return; if (!shaderObject) return;
std::string src; std::string src;
@@ -511,7 +511,7 @@ namespace MobileGL {
shaderObject->SetShaderSource(Move(src)); shaderObject->SetShaderSource(Move(src));
} }
void UseProgram_State(GLint program) { void UseProgram_State(GLuint program) {
MGLOG_D("UseProgram_State: program=%u", program); MGLOG_D("UseProgram_State: program=%u", program);
if (program == 0) { if (program == 0) {
@@ -519,7 +519,7 @@ namespace MobileGL {
return; return;
} }
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject) return; if (!programObject) return;
MG_State::pGLContext->UseProgram(program); MG_State::pGLContext->UseProgram(program);
} }
@@ -533,8 +533,8 @@ namespace MobileGL {
auto size = programObject.GetUniformSizesInBytes(location); auto size = programObject.GetUniformSizesInBytes(location);
auto offset = programObject.GetUniformOffset(location); auto offset = programObject.GetUniformOffset(location);
MOBILEGL_ASSERT(size >= ItemCount * sizeof(T), MOBILEGL_ASSERT(size >= ItemCount * sizeof(T),
"Uniform size mismatch, expected at least %zu bytes, got %zu bytes.", "Uniform size mismatch, expected at least %zu bytes, got %zu bytes.", ItemCount * sizeof(T),
ItemCount * sizeof(T), size); size);
MGLOG_D("%s: program = %d, location = %d, byteOffset = %d", __func__, programObject.GetExternalIndex(), MGLOG_D("%s: program = %d, location = %d, byteOffset = %d", __func__, programObject.GetExternalIndex(),
location, offset + byteOffsetInsideUniform); location, offset + byteOffsetInsideUniform);
Memcpy((char*)programObject.MapUBO() + offset + byteOffsetInsideUniform, value, ItemCount * sizeof(T)); Memcpy((char*)programObject.MapUBO() + offset + byteOffsetInsideUniform, value, ItemCount * sizeof(T));
@@ -550,18 +550,18 @@ namespace MobileGL {
void Uniformv_State(GLint location, GLsizei count, T* value) { void Uniformv_State(GLint location, GLsizei count, T* value) {
if (location == -1) return; if (location == -1) return;
auto programObject = MG_State::pGLContext->GetCurrentProgram(); auto& programObject = MG_State::pGLContext->GetCurrentProgram();
if (programObject == nullptr) { if (programObject == nullptr) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "There is no current program object.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "There is no current program object."));
return; return;
} }
if (location > programObject->GetMaxUniformLocation() || location < -1) { if (location > programObject->GetMaxUniformLocation() || location < -1) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) + "location " + std::to_string(location) +
" is an invalid uniform location for the current program " " is an invalid uniform location for the current program "
"object and location " + "object and location " +
@@ -679,18 +679,18 @@ namespace MobileGL {
// If transpose is GL_TRUE, we need to transpose the matrix data // If transpose is GL_TRUE, we need to transpose the matrix data
if (location == -1) return; if (location == -1) return;
auto programObject = MG_State::pGLContext->GetCurrentProgram(); auto& programObject = MG_State::pGLContext->GetCurrentProgram();
if (programObject == nullptr) { if (programObject == nullptr) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "There is no current program object.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "There is no current program object."));
return; return;
} }
if (location > programObject->GetMaxUniformLocation() || location < -1) { if (location > programObject->GetMaxUniformLocation() || location < -1) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) + "location " + std::to_string(location) +
" is an invalid uniform location for the current program " " is an invalid uniform location for the current program "
"object and location " + "object and location " +
@@ -717,18 +717,18 @@ namespace MobileGL {
// If transpose is GL_TRUE, we need to transpose the matrix data // If transpose is GL_TRUE, we need to transpose the matrix data
if (location == -1) return; if (location == -1) return;
auto programObject = MG_State::pGLContext->GetCurrentProgram(); auto& programObject = MG_State::pGLContext->GetCurrentProgram();
if (programObject == nullptr) { if (programObject == nullptr) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "There is no current program object.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "There is no current program object."));
return; return;
} }
if (location > programObject->GetMaxUniformLocation() || location < -1) { if (location > programObject->GetMaxUniformLocation() || location < -1) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) + "location " + std::to_string(location) +
" is an invalid uniform location for the current program " " is an invalid uniform location for the current program "
"object and location " + "object and location " +
@@ -744,14 +744,12 @@ namespace MobileGL {
GLfloat transposedMatrix[9]; GLfloat transposedMatrix[9];
TransposeMatrix3x3(value + i * 9, transposedMatrix); TransposeMatrix3x3(value + i * 9, transposedMatrix);
for (int row = 0; row < 3; ++row) { for (int row = 0; row < 3; ++row) {
Uniform_State<3>(*programObject, location + i, transposedMatrix + row * 3, Uniform_State<3>(*programObject, location + i, transposedMatrix + row * 3, row * 4 * sizeof(float));
row * 4 * sizeof(float));
} }
} else { } else {
// No transpose needed, directly copy the matrix data // No transpose needed, directly copy the matrix data
for (int row = 0; row < 3; ++row) { for (int row = 0; row < 3; ++row) {
Uniform_State<3>(*programObject, location + i, value + i * 9 + row * 3, Uniform_State<3>(*programObject, location + i, value + i * 9 + row * 3, row * 4 * sizeof(float));
row * 4 * sizeof(float));
} }
} }
} }
@@ -762,18 +760,18 @@ namespace MobileGL {
// If transpose is GL_TRUE, we need to transpose the matrix data // If transpose is GL_TRUE, we need to transpose the matrix data
if (location == -1) return; if (location == -1) return;
auto programObject = MG_State::pGLContext->GetCurrentProgram(); auto& programObject = MG_State::pGLContext->GetCurrentProgram();
if (programObject == nullptr) { if (programObject == nullptr) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "There is no current program object.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "There is no current program object."));
return; return;
} }
if (location > programObject->GetMaxUniformLocation() || location < -1) { if (location > programObject->GetMaxUniformLocation() || location < -1) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) + "location " + std::to_string(location) +
" is an invalid uniform location for the current program " " is an invalid uniform location for the current program "
"object and location " + "object and location " +
@@ -801,7 +799,7 @@ namespace MobileGL {
if (!programObject->GetLinkStatus()) { if (!programObject->GetLinkStatus()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(program) + std::to_string(program) +
" is not a program object that has been linked.")); " is not a program object that has been linked."));
return GL_INVALID_INDEX; return GL_INVALID_INDEX;
@@ -814,17 +812,16 @@ namespace MobileGL {
void UniformBlockBinding_State(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) { void UniformBlockBinding_State(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) {
const auto& programObject = TryToGetProgramObject(program); const auto& programObject = TryToGetProgramObject(program);
if (!programObject->GetLinkStatus()) { if (!programObject->GetLinkStatus()) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, MG_State::pGLContext->RecordError(
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, ErrorCode::InvalidOperation,
"Program object" + MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(program) + "Program object" + std::to_string(program) + " that has been linked."));
" that has been linked."));
return; return;
} }
if (!programObject->IsActiveUniformBlock(uniformBlockIndex)) { if (!programObject->IsActiveUniformBlock(uniformBlockIndex)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__, "MG_Impl/GLImpl", __func__,
"uniformBlockIndex " + std::to_string(uniformBlockIndex) + "uniformBlockIndex " + std::to_string(uniformBlockIndex) +
" is greater than or equal to the value of `GL_ACTIVE_UNIFORM_BLOCKS` or is " " is greater than or equal to the value of `GL_ACTIVE_UNIFORM_BLOCKS` or is "
@@ -838,17 +835,16 @@ namespace MobileGL {
void GetActiveUniformBlockiv_State(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) { void GetActiveUniformBlockiv_State(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) {
const auto& programObject = TryToGetProgramObject(program); const auto& programObject = TryToGetProgramObject(program);
if (!programObject->GetLinkStatus()) { if (!programObject->GetLinkStatus()) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, MG_State::pGLContext->RecordError(
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, ErrorCode::InvalidOperation,
"Program object" + MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(program) + "Program object" + std::to_string(program) + " that has been linked."));
" that has been linked."));
return; return;
} }
if (!programObject->IsActiveUniformBlock(uniformBlockIndex)) { if (!programObject->IsActiveUniformBlock(uniformBlockIndex)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__, "MG_Impl/GLImpl", __func__,
"uniformBlockIndex " + std::to_string(uniformBlockIndex) + "uniformBlockIndex " + std::to_string(uniformBlockIndex) +
" is greater than or equal to the value of `GL_ACTIVE_UNIFORM_BLOCKS` or is " " is greater than or equal to the value of `GL_ACTIVE_UNIFORM_BLOCKS` or is "
@@ -858,12 +854,12 @@ namespace MobileGL {
} }
switch (pname) { switch (pname) {
case GL_UNIFORM_BLOCK_DATA_SIZE: { case GL_UNIFORM_BLOCK_DATA_SIZE: {
*params = programObject->GetUBOSizeAt(uniformBlockIndex); *params = (GLint)programObject->GetUBOSizeAt(uniformBlockIndex);
MGLOG_D("%s: GL_UNIFORM_BLOCK_DATA_SIZE = %d", __func__, *params); MGLOG_D("%s: GL_UNIFORM_BLOCK_DATA_SIZE = %d", __func__, *params);
break; break;
} }
case GL_UNIFORM_BLOCK_NAME_LENGTH: { case GL_UNIFORM_BLOCK_NAME_LENGTH: {
*params = programObject->GetUniformBlockName(uniformBlockIndex).length() + 1; *params = (GLint)programObject->GetUniformBlockName(uniformBlockIndex).length() + 1;
MGLOG_D("%s: GL_UNIFORM_BLOCK_NAME_LENGTH = %d", __func__, *params); MGLOG_D("%s: GL_UNIFORM_BLOCK_NAME_LENGTH = %d", __func__, *params);
break; break;
} }
@@ -887,21 +883,21 @@ namespace MobileGL {
default: default:
MGLOG_E("%s: unknown pname = %p %s", __func__, pname, MG_Util::ConvertGLEnumToString(pname).c_str()); MGLOG_E("%s: unknown pname = %p %s", __func__, pname, MG_Util::ConvertGLEnumToString(pname).c_str());
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, ErrorCode::InvalidEnum,
"pname " + std::to_string(pname) + MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
" is not one of the accepted tokens.")); "pname " + std::to_string(pname) + " is not one of the accepted tokens."));
break; break;
} }
} }
void GetActiveUniformBlockName_State(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, void GetActiveUniformBlockName_State(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length,
GLchar* uniformBlockName) { GLchar* uniformBlockName) {
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (!programObject) return; if (!programObject) return;
if (!programObject->GetLinkStatus()) { if (!programObject->GetLinkStatus()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(program) + std::to_string(program) +
" is not a program object that has been linked.")); " is not a program object that has been linked."));
return; return;
@@ -909,7 +905,7 @@ namespace MobileGL {
if (!programObject->IsActiveUniformBlock(uniformBlockIndex)) { if (!programObject->IsActiveUniformBlock(uniformBlockIndex)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__, "MG_Impl/GLImpl", __func__,
"uniformBlockIndex " + std::to_string(uniformBlockIndex) + "uniformBlockIndex " + std::to_string(uniformBlockIndex) +
" is greater than or equal to the value of `GL_ACTIVE_UNIFORM_BLOCKS` or is " " is greater than or equal to the value of `GL_ACTIVE_UNIFORM_BLOCKS` or is "
@@ -917,26 +913,25 @@ namespace MobileGL {
return; return;
} }
const auto& name = programObject->GetUniformBlockName(uniformBlockIndex); const auto& name = programObject->GetUniformBlockName(uniformBlockIndex);
CopyStr(bufSize, length, uniformBlockName, name.c_str(), name.length()); CopyStr(bufSize, length, uniformBlockName, name.c_str(), (GLsizei)name.length());
MGLOG_D("%s: \"%s\" at uniformBlockIndex %02d, length = %d", __func__, uniformBlockName, uniformBlockIndex, MGLOG_D("%s: \"%s\" at uniformBlockIndex %02d, length = %d", __func__, uniformBlockName, uniformBlockIndex,
*length); *length);
} }
void BindFragDataLocation_State(GLuint program, GLuint colorNumber, const char* name) { void BindFragDataLocation_State(GLuint program, GLuint colorNumber, const char* name) {
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (programObject == nullptr) { if (programObject == nullptr) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(program) + " is not the name of a program object.")); std::to_string(program) + " is not the name of a program object."));
return; return;
} }
if (strncmp(name, "gl_", 3) == 0) { if (strncmp(name, "gl_", 3) == 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"name " + std::string(name) + "name " + std::string(name) + " starts with the reserved prefix `gl_`."));
" starts with the reserved prefix `gl_`."));
return; return;
} }
// TODO: Emit error "if `colorNumber` is greater than or equal to `GL_MAX_DRAW_BUFFERS`" // TODO: Emit error "if `colorNumber` is greater than or equal to `GL_MAX_DRAW_BUFFERS`"
@@ -946,11 +941,11 @@ namespace MobileGL {
} }
GLint GetFragDataLocation_State(GLuint program, const char* name) { GLint GetFragDataLocation_State(GLuint program, const char* name) {
auto programObject = TryToGetProgramObject(program); auto& programObject = TryToGetProgramObject(program);
if (programObject == nullptr) { if (programObject == nullptr) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(program) + " is not the name of a program object.")); std::to_string(program) + " is not the name of a program object."));
return -1; return -1;
} }
@@ -1171,5 +1166,4 @@ namespace MobileGL {
void ValidateProgram(GLuint program) { void ValidateProgram(GLuint program) {
ValidateProgram_State(program); ValidateProgram_State(program);
} }
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
+2 -4
View File
@@ -9,8 +9,7 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
void AttachShader(GLuint program, GLuint shader); void AttachShader(GLuint program, GLuint shader);
void BindAttribLocation(GLuint program, GLuint index, const GLchar* name); void BindAttribLocation(GLuint program, GLuint index, const GLchar* name);
void CompileShader(GLuint shader); void CompileShader(GLuint shader);
@@ -65,5 +64,4 @@ namespace MobileGL {
void BindFragDataLocation(GLuint program, GLuint colorNumber, const char* name); void BindFragDataLocation(GLuint program, GLuint colorNumber, const char* name);
GLint GetFragDataLocation(GLuint program, const char* name); GLint GetFragDataLocation(GLuint program, const char* name);
void ValidateProgram(GLuint program); void ValidateProgram(GLuint program);
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
@@ -7,19 +7,17 @@
// End of Source File Header // End of Source File Header
#include "GL_RenderState.h" #include "GL_RenderState.h"
#include "MG_State/GLState/RenderState/RenderState.h"
#include "MG_Util/Converters/GLToStr/GLEnumConverter.h"
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/GLToMG/RenderStateEnumConverter.h> #include <MG_Util/Converters/GLToMG/RenderStateEnumConverter.h>
#include <MG_Util/Converters/MGToGL/RenderStateEnumConverter.h> #include <MG_Util/Converters/MGToGL/RenderStateEnumConverter.h>
#include <MG_Util/Converters/MGToStr/RenderStateEnumConverter.h> #include <MG_Util/Converters/MGToStr/RenderStateEnumConverter.h>
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
void Viewport_State(GLint x, GLint y, GLsizei width, GLsizei height) { void Viewport_State(GLint x, GLint y, GLsizei width, GLsizei height) {
if (width < 0 || height < 0) { if (width < 0 || height < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Viewport_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Viewport_State",
"Width abd height must be non-negative.")); "Width abd height must be non-negative."));
return; return;
} }
@@ -53,8 +51,8 @@ namespace MobileGL {
void Scissor_State(GLint x, GLint y, GLsizei width, GLsizei height) { void Scissor_State(GLint x, GLint y, GLsizei width, GLsizei height) {
if (width < 0 || height < 0) { if (width < 0 || height < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Scissor_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Scissor_State",
"Width abd height must be non-negative.")); "Width abd height must be non-negative."));
return; return;
} }
@@ -92,7 +90,7 @@ namespace MobileGL {
if (pixelStoreParam == PixelStoreParam::Unknown) { if (pixelStoreParam == PixelStoreParam::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "PixelStorei_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "PixelStorei_State",
"Pixel store param enum " + "Pixel store param enum " +
MG_Util::ConvertPixelStoreParamToString(pixelStoreParam) + "(" + MG_Util::ConvertPixelStoreParamToString(pixelStoreParam) + "(" +
MG_Util::ConvertGLEnumToString(pname) + ") is not supported.")); MG_Util::ConvertGLEnumToString(pname) + ") is not supported."));
@@ -115,10 +113,9 @@ namespace MobileGL {
if (capInput == CapabilityInput::Unknown) { if (capInput == CapabilityInput::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "IsEnabledi_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "IsEnabledi_State",
"Capability enum " + "Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
MG_Util::ConvertCapabilityInputToString(capInput) + "(" + "(" + MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
return GL_FALSE; return GL_FALSE;
} }
@@ -129,8 +126,8 @@ namespace MobileGL {
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap); CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
if (capInput == CapabilityInput::Unknown) { if (capInput == CapabilityInput::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>( ErrorCode::InvalidEnum,
"MG_Impl/GLImpl", "IsEnabled_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "IsEnabled_State",
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) + "Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported.")); "(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
return GL_FALSE; return GL_FALSE;
@@ -151,8 +148,8 @@ namespace MobileGL {
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap); CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
if (capInput == CapabilityInput::Unknown) { if (capInput == CapabilityInput::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>( ErrorCode::InvalidEnum,
"MG_Impl/GLImpl", "Enable_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Enable_State",
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) + "Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported.")); "(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
return; return;
@@ -165,8 +162,8 @@ namespace MobileGL {
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap); CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
if (capInput == CapabilityInput::Unknown) { if (capInput == CapabilityInput::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>( ErrorCode::InvalidEnum,
"MG_Impl/GLImpl", "Disable_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Disable_State",
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) + "Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported.")); "(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
return; return;
@@ -188,10 +185,9 @@ namespace MobileGL {
if (depthFunc == DepthTestFunc::Unknown) { if (depthFunc == DepthTestFunc::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DepthFunc_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DepthFunc_State",
"Depth function enum " + "Depth function enum " + MG_Util::ConvertDepthTestFuncToString(depthFunc) +
MG_Util::ConvertDepthTestFuncToString(depthFunc) + "(" + "(" + MG_Util::ConvertGLEnumToString(func) + ") is not supported."));
MG_Util::ConvertGLEnumToString(func) + ") is not supported."));
return; return;
} }
@@ -203,7 +199,7 @@ namespace MobileGL {
if (cullFaceMode == CullFaceMode::Unknown) { if (cullFaceMode == CullFaceMode::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "CullFace_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CullFace_State",
"Cull face mode enum " + "Cull face mode enum " +
MG_Util::ConvertCullFaceModeToString(cullFaceMode) + "(" + MG_Util::ConvertCullFaceModeToString(cullFaceMode) + "(" +
MG_Util::ConvertGLEnumToString(mode) + ") is not supported.")); MG_Util::ConvertGLEnumToString(mode) + ") is not supported."));
@@ -232,7 +228,7 @@ namespace MobileGL {
dstAlpha == BlendFactor::Unknown) { dstAlpha == BlendFactor::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BlendFuncSeparate_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BlendFuncSeparate_State",
"One of the blend factor enums is not supported: srcRGB " + "One of the blend factor enums is not supported: srcRGB " +
MG_Util::ConvertBlendFactorToString(srcRGB) + "(" + MG_Util::ConvertBlendFactorToString(srcRGB) + "(" +
MG_Util::ConvertGLEnumToString(sfactorRGB) + "), dstRGB " + MG_Util::ConvertGLEnumToString(sfactorRGB) + "), dstRGB " +
@@ -276,7 +272,7 @@ namespace MobileGL {
if (buf >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) { if (buf >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", "BlendFuncSeparatei_State", "MG_Impl/GLImpl", "BlendFuncSeparatei_State",
"Buffer index " + std::to_string(buf) + " is out of range. Max supported is " + "Buffer index " + std::to_string(buf) + " is out of range. Max supported is " +
std::to_string(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS - 1) + ".")); std::to_string(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS - 1) + "."));
@@ -295,10 +291,9 @@ namespace MobileGL {
if (capInput == CapabilityInput::Unknown) { if (capInput == CapabilityInput::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Disablei_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Disablei_State",
"Capability enum " + "Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
MG_Util::ConvertCapabilityInputToString(capInput) + "(" + "(" + MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
return; return;
} }
@@ -310,10 +305,9 @@ namespace MobileGL {
if (capInput == CapabilityInput::Unknown) { if (capInput == CapabilityInput::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Enablei_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Enablei_State",
"Capability enum " + "Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
MG_Util::ConvertCapabilityInputToString(capInput) + "(" + "(" + MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
return; return;
} }
@@ -476,5 +470,4 @@ namespace MobileGL {
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
ClearColor_State(red, green, blue, alpha); ClearColor_State(red, green, blue, alpha);
} }
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
@@ -9,8 +9,7 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */ /* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
void Disablei(GLenum target, GLuint index); void Disablei(GLenum target, GLuint index);
@@ -51,5 +50,4 @@ namespace MobileGL {
void ClearStencil(GLint s); void ClearStencil(GLint s);
void ClearDepth(GLclampd depth); void ClearDepth(GLclampd depth);
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
+39 -35
View File
@@ -12,15 +12,16 @@
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h> #include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h> #include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
void SetSamplerParam_State(GLuint sampler, GLenum pname, const void* param, bool isFloat, bool isInteger) { void SetSamplerParam_State(GLuint sampler, GLenum pname, const void* param, bool isFloat, bool isInteger) {
if (!SamplerImpl::ValidateSamplerName(sampler)) return; if (!SamplerImpl::ValidateSamplerName(sampler)) return;
auto samplerObj = MG_State::pGLContext->GetSamplerObject(sampler); Bool doesSamplerObjectCreated = MG_State::pGLContext->ValidateSamplerObject(sampler);
if (!samplerObj) { if (!doesSamplerObjectCreated) {
samplerObj = MG_State::pGLContext->CreateSamplerObject(sampler); // for compatibility // Create one for compatibility
MG_State::pGLContext->CreateSamplerObject(sampler);
} }
auto& samplerObj = MG_State::pGLContext->GetSamplerObject(sampler);
if (!SamplerImpl::ValidateSamplerObject(sampler)) return; if (!SamplerImpl::ValidateSamplerObject(sampler)) return;
using namespace MG_Util; using namespace MG_Util;
@@ -57,8 +58,8 @@ namespace MobileGL {
samplerObj->SetSamplerCompareFunc(MG_Util::ConvertGLEnumToSamplerCompareFunc(*(const GLint*)param)); samplerObj->SetSamplerCompareFunc(MG_Util::ConvertGLEnumToSamplerCompareFunc(*(const GLint*)param));
break; break;
default: default:
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "SetSamplerParam_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "SetSamplerParam_State",
"Invalid pname for sampler parameter")); "Invalid pname for sampler parameter"));
} }
} }
@@ -66,29 +67,31 @@ namespace MobileGL {
void GetSamplerParam_State(GLuint sampler, GLenum pname, void* params, bool isFloat, bool isInteger) { void GetSamplerParam_State(GLuint sampler, GLenum pname, void* params, bool isFloat, bool isInteger) {
if (!SamplerImpl::ValidateSamplerName(sampler)) return; if (!SamplerImpl::ValidateSamplerName(sampler)) return;
auto samplerObj = MG_State::pGLContext->GetSamplerObject(sampler); Bool doesSamplerObjectCreated = MG_State::pGLContext->ValidateSamplerObject(sampler);
if (!samplerObj) { if (!doesSamplerObjectCreated) {
samplerObj = MG_State::pGLContext->CreateSamplerObject(sampler); // for compatibility // Create one for compatibility
MG_State::pGLContext->CreateSamplerObject(sampler);
} }
auto& samplerObj = MG_State::pGLContext->GetSamplerObject(sampler);
if (!SamplerImpl::ValidateSamplerObject(sampler)) return; if (!SamplerImpl::ValidateSamplerObject(sampler)) return;
using namespace MG_Util; using namespace MG_Util;
switch (pname) { switch (pname) {
case GL_TEXTURE_WRAP_S: case GL_TEXTURE_WRAP_S:
*(GLint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapS()); *(GLuint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapS());
break; break;
case GL_TEXTURE_WRAP_T: case GL_TEXTURE_WRAP_T:
*(GLint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapT()); *(GLuint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapT());
break; break;
case GL_TEXTURE_WRAP_R: case GL_TEXTURE_WRAP_R:
*(GLint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapR()); *(GLuint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapR());
break; break;
case GL_TEXTURE_MIN_FILTER: case GL_TEXTURE_MIN_FILTER:
*(GLint*)params = *(GLuint*)params =
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObj->GetMinFilter(), samplerObj->GetMipmapMode()); MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObj->GetMinFilter(), samplerObj->GetMipmapMode());
break; break;
case GL_TEXTURE_MAG_FILTER: case GL_TEXTURE_MAG_FILTER:
*(GLint*)params = *(GLuint*)params =
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObj->GetMagFilter(), SamplerMipmapMode::None); MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObj->GetMagFilter(), SamplerMipmapMode::None);
break; break;
case GL_TEXTURE_MIN_LOD: case GL_TEXTURE_MIN_LOD:
@@ -101,14 +104,14 @@ namespace MobileGL {
*(GLfloat*)params = samplerObj->GetLodBias(); *(GLfloat*)params = samplerObj->GetLodBias();
break; break;
case GL_TEXTURE_COMPARE_MODE: case GL_TEXTURE_COMPARE_MODE:
*(GLint*)params = MG_Util::ConvertSamplerCompareModeToGLEnum(samplerObj->GetCompareMode()); *(GLuint*)params = MG_Util::ConvertSamplerCompareModeToGLEnum(samplerObj->GetCompareMode());
break; break;
case GL_TEXTURE_COMPARE_FUNC: case GL_TEXTURE_COMPARE_FUNC:
*(GLint*)params = MG_Util::ConvertSamplerCompareFuncToGLEnum(samplerObj->GetSamplerCompareFunc()); *(GLuint*)params = MG_Util::ConvertSamplerCompareFuncToGLEnum(samplerObj->GetSamplerCompareFunc());
break; break;
default: default:
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetSamplerParam_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetSamplerParam_State",
"Invalid pname for sampler parameter")); "Invalid pname for sampler parameter"));
} }
} }
@@ -122,21 +125,20 @@ namespace MobileGL {
if (count < 0) { if (count < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GenSamplers", "count must be non-negative")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenSamplers", "count must be non-negative"));
return; return;
} }
auto names = MG_State::pGLContext->GenSamplerNames(count); static thread_local Vector<GLuint> names;
for (GLsizei i = 0; i < count; ++i) { MG_State::pGLContext->GenSamplerNames(count, names);
samplers[i] = names[i]; Memcpy(samplers, names.data(), count * sizeof(GLuint));
}
} }
void DeleteSamplers_State(GLsizei count, const GLuint* samplers) { void DeleteSamplers_State(GLsizei count, const GLuint* samplers) {
if (count < 0) { if (count < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteSamplers", "count must be non-negative")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteSamplers", "count must be non-negative"));
return; return;
} }
@@ -151,11 +153,13 @@ namespace MobileGL {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GenSamplers", "count must be non-negative")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenSamplers", "count must be non-negative"));
return; return;
} }
auto names = MG_State::pGLContext->GenSamplerNames(n); static thread_local Vector<GLuint> names;
MG_State::pGLContext->GenSamplerNames(n, names);
Memcpy(samplers, names.data(), n * sizeof(GLuint));
for (GLsizei i = 0; i < n; ++i) { for (GLsizei i = 0; i < n; ++i) {
samplers[i] = names[i]; samplers[i] = names[i];
MG_State::pGLContext->CreateSamplerObject(names[i]); MG_State::pGLContext->CreateSamplerObject(names[i]);
@@ -166,19 +170,20 @@ namespace MobileGL {
if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) { if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BindSampler", "texture unit out of range")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BindSampler", "texture unit out of range"));
return; return;
} }
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit); auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject((Int)unit);
if (sampler == 0) { if (sampler == 0) {
textureUnit.SetSamplerObject(nullptr); textureUnit.SetSamplerObject(nullptr);
} else { } else {
if (!SamplerImpl::ValidateSamplerName(sampler)) return; if (!SamplerImpl::ValidateSamplerName(sampler)) return;
auto samplerObject = MG_State::pGLContext->GetSamplerObject(sampler); Bool doesSamplerObjectCreated = MG_State::pGLContext->ValidateSamplerObject(sampler);
if (!samplerObject) { if (!doesSamplerObjectCreated) {
samplerObject = MG_State::pGLContext->CreateSamplerObject(sampler); MG_State::pGLContext->CreateSamplerObject(sampler);
} }
auto& samplerObject = MG_State::pGLContext->GetSamplerObject(sampler);
textureUnit.SetSamplerObject(MG_State::pGLContext->GetSamplerObject(sampler)); textureUnit.SetSamplerObject(MG_State::pGLContext->GetSamplerObject(sampler));
} }
@@ -188,7 +193,7 @@ namespace MobileGL {
if (count < 0) { if (count < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BindSamplers", "count must be non-negative")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BindSamplers", "count must be non-negative"));
return; return;
} }
@@ -261,5 +266,4 @@ namespace MobileGL {
void BindSampler(GLuint unit, GLuint sampler) { void BindSampler(GLuint unit, GLuint sampler) {
BindSampler_State(unit, sampler); BindSampler_State(unit, sampler);
} }
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
+2 -4
View File
@@ -9,8 +9,7 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */ /* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params); void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params);
void SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint* param); void SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint* param);
@@ -28,5 +27,4 @@ namespace MobileGL {
void CreateSamplers(GLsizei n, GLuint* samplers); void CreateSamplers(GLsizei n, GLuint* samplers);
void BindSamplers(GLuint first, GLsizei count, const GLuint* samplers); void BindSamplers(GLuint first, GLsizei count, const GLuint* samplers);
void BindSampler(GLuint unit, GLuint sampler); void BindSampler(GLuint unit, GLuint sampler);
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
+17 -21
View File
@@ -11,13 +11,11 @@
#include <MG_State/GLState/ErrorState/Error.h> #include <MG_State/GLState/ErrorState/Error.h>
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h> #include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl::SamplerImpl {
namespace SamplerImpl {
Bool ValidateSamplerName(GLuint sampler) { Bool ValidateSamplerName(GLuint sampler) {
if (!MG_State::pGLContext->ValidateSamplerName(sampler)) { if (!MG_State::pGLContext->ValidateSamplerName(sampler)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerName",
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerName",
std::format("Invalid sampler name {}", sampler))); std::format("Invalid sampler name {}", sampler)));
return false; return false;
} }
@@ -28,7 +26,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (!MG_State::pGLContext->ValidateSamplerObject(sampler)) { if (!MG_State::pGLContext->ValidateSamplerObject(sampler)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerObject", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerObject",
std::format("Sampler object {} does not exist", sampler))); std::format("Sampler object {} does not exist", sampler)));
return false; return false;
} }
@@ -42,8 +40,8 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_TEXTURE_WRAP_T: case GL_TEXTURE_WRAP_T:
case GL_TEXTURE_WRAP_R: case GL_TEXTURE_WRAP_R:
if (MG_Util::ConvertGLEnumToSamplerWrapMode(param) == SamplerWrapMode::Unknown) { if (MG_Util::ConvertGLEnumToSamplerWrapMode(param) == SamplerWrapMode::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
"Invalid wrap mode parameter")); "Invalid wrap mode parameter"));
return false; return false;
} }
@@ -51,8 +49,8 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_TEXTURE_MIN_FILTER: case GL_TEXTURE_MIN_FILTER:
if (MG_Util::ConvertGLEnumToSamplerFilterMode(param) == SamplerFilterMode::Unknown) { if (MG_Util::ConvertGLEnumToSamplerFilterMode(param) == SamplerFilterMode::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
"Invalid min filter parameter")); "Invalid min filter parameter"));
return false; return false;
} }
@@ -60,8 +58,8 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_TEXTURE_MAG_FILTER: case GL_TEXTURE_MAG_FILTER:
if (param != GL_NEAREST && param != GL_LINEAR) { if (param != GL_NEAREST && param != GL_LINEAR) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
"Invalid mag filter parameter")); "Invalid mag filter parameter"));
return false; return false;
} }
@@ -69,8 +67,8 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_TEXTURE_COMPARE_MODE: case GL_TEXTURE_COMPARE_MODE:
if (param != GL_NONE && param != GL_COMPARE_REF_TO_TEXTURE) { if (param != GL_NONE && param != GL_COMPARE_REF_TO_TEXTURE) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
"Invalid compare mode parameter")); "Invalid compare mode parameter"));
return false; return false;
} }
@@ -78,8 +76,8 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_TEXTURE_COMPARE_FUNC: case GL_TEXTURE_COMPARE_FUNC:
if (param < GL_LEQUAL || param > GL_ALWAYS) { if (param < GL_LEQUAL || param > GL_ALWAYS) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
"Invalid compare function parameter")); "Invalid compare function parameter"));
return false; return false;
} }
@@ -87,7 +85,7 @@ namespace MobileGL::MG_Impl::GLImpl {
default: default:
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum, MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
"Invalid pname for sampler parameter")); "Invalid pname for sampler parameter"));
return false; return false;
} }
@@ -104,8 +102,7 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_TEXTURE_BORDER_COLOR: case GL_TEXTURE_BORDER_COLOR:
if (param < 0.0f || param > 1.0f) { if (param < 0.0f || param > 1.0f) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerFloatParam",
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerFloatParam",
"Border color component out of [0,1] range")); "Border color component out of [0,1] range"));
return false; return false;
} }
@@ -122,7 +119,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (param < 0 || param > 255) { if (param < 0 || param > 255) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerIntParam", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerIntParam",
"Border color component out of [0,255] range")); "Border color component out of [0,255] range"));
return false; return false;
} }
@@ -132,5 +129,4 @@ namespace MobileGL::MG_Impl::GLImpl {
return ValidateSamplerParam(pname, static_cast<GLenum>(param)); return ValidateSamplerParam(pname, static_cast<GLenum>(param));
} }
} }
} // namespace SamplerImpl } // namespace MobileGL::MG_Impl::GLImpl::SamplerImpl
} // namespace MobileGL::MG_Impl::GLImpl
+2 -4
View File
@@ -10,12 +10,10 @@
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/SamplerState/SamplerObject.h> #include <MG_State/GLState/SamplerState/SamplerObject.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl::SamplerImpl {
namespace SamplerImpl {
Bool ValidateSamplerName(GLuint sampler); Bool ValidateSamplerName(GLuint sampler);
Bool ValidateSamplerObject(GLuint sampler); Bool ValidateSamplerObject(GLuint sampler);
Bool ValidateSamplerParam(GLenum pname, GLenum param); Bool ValidateSamplerParam(GLenum pname, GLenum param);
Bool ValidateSamplerFloatParam(GLenum pname, GLfloat param); Bool ValidateSamplerFloatParam(GLenum pname, GLfloat param);
Bool ValidateSamplerIntParam(GLenum pname, GLint param); Bool ValidateSamplerIntParam(GLenum pname, GLint param);
} // namespace SamplerImpl } // namespace MobileGL::MG_Impl::GLImpl::SamplerImpl
} // namespace MobileGL::MG_Impl::GLImpl
+2 -4
View File
@@ -10,8 +10,7 @@
#include "MG_State/GLState/Core.h" #include "MG_State/GLState/Core.h"
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
GLsync FenceSync_Backend(GLenum condition, GLbitfield flags) { GLsync FenceSync_Backend(GLenum condition, GLbitfield flags) {
return 0; return 0;
} }
@@ -41,5 +40,4 @@ namespace MobileGL {
} }
void DeleteSync(GLsync sync) {} void DeleteSync(GLsync sync) {}
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
+2 -4
View File
@@ -9,10 +9,8 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
GLsync FenceSync(GLenum condition, GLbitfield flags); GLsync FenceSync(GLenum condition, GLbitfield flags);
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
void DeleteSync(GLsync sync); void DeleteSync(GLsync sync);
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
File diff suppressed because it is too large Load Diff
@@ -7,12 +7,10 @@
// End of Source File Header // End of Source File Header
#include "ProxyTexture.h" #include "ProxyTexture.h"
#include "MG_State/GLState/TextureState/TextureObject2D.h" #include <MG_State/GLState/TextureState/TextureObject2D.h>
#include "MG_Util/Types.h"
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
namespace TextureImpl { UniquePtr<ProxyTextureManager> pProxyTextureManager;
ProxyTextureManager* pProxyTextureManager;
Bool IsProxyTextureTarget(TextureUploadTarget target) { Bool IsProxyTextureTarget(TextureUploadTarget target) {
switch (target) { switch (target) {
@@ -32,23 +30,24 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
} }
SharedPtr<MG_State::GLState::ITextureObject> ProxyTextureManager::CreateOrReplaceProxyTextureObject( const SharedPtr<MG_State::GLState::ITextureObject>& ProxyTextureManager::CreateOrReplaceProxyTextureObject(
TextureUploadTarget target) { TextureUploadTarget target) {
auto it = m_proxyTexturesMap.find(target); auto it = m_proxyTexturesMap.find(target);
if (it != m_proxyTexturesMap.end()) { if (it != m_proxyTexturesMap.end()) {
m_proxyTexturesMap.erase(it); m_proxyTexturesMap.erase(it);
} }
m_proxyTexturesMap[target] = MakeShared<MG_State::GLState::TextureObject2D>(0); auto& obj = m_proxyTexturesMap[target];
return m_proxyTexturesMap[target]; obj = MakeShared<MG_State::GLState::TextureObject2D>(0);
return obj;
} }
SharedPtr<MG_State::GLState::ITextureObject> ProxyTextureManager::GetProxyTextureObject( const SharedPtr<MG_State::GLState::ITextureObject>& ProxyTextureManager::GetProxyTextureObject(
TextureUploadTarget target) { TextureUploadTarget target) {
auto it = m_proxyTexturesMap.find(target); auto it = m_proxyTexturesMap.find(target);
if (it != m_proxyTexturesMap.end()) { if (it != m_proxyTexturesMap.end()) {
return it->second; return it->second;
} }
return nullptr; static SharedPtr<MG_State::GLState::ITextureObject> nullTextureObject = nullptr;
return nullTextureObject;
} }
} // namespace TextureImpl } // namespace MobileGL::MG_Impl::GLImpl::TextureImpl
} // namespace MobileGL::MG_Impl::GLImpl
@@ -10,19 +10,18 @@
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
namespace TextureImpl {
Bool IsProxyTextureTarget(TextureUploadTarget target); Bool IsProxyTextureTarget(TextureUploadTarget target);
class ProxyTextureManager { class ProxyTextureManager {
public: public:
SharedPtr<MG_State::GLState::ITextureObject> CreateOrReplaceProxyTextureObject(TextureUploadTarget target); const SharedPtr<MG_State::GLState::ITextureObject>& CreateOrReplaceProxyTextureObject(
SharedPtr<MG_State::GLState::ITextureObject> GetProxyTextureObject(TextureUploadTarget target); TextureUploadTarget target);
const SharedPtr<MG_State::GLState::ITextureObject>& GetProxyTextureObject(TextureUploadTarget target);
private: private:
UnorderedMap<TextureUploadTarget, SharedPtr<MG_State::GLState::ITextureObject>> m_proxyTexturesMap; UnorderedMap<TextureUploadTarget, SharedPtr<MG_State::GLState::ITextureObject>> m_proxyTexturesMap;
}; };
extern ProxyTextureManager* pProxyTextureManager; extern UniquePtr<ProxyTextureManager> pProxyTextureManager;
} // namespace TextureImpl } // namespace MobileGL::MG_Impl::GLImpl::TextureImpl
} // namespace MobileGL::MG_Impl::GLImpl
+36 -50
View File
@@ -15,13 +15,12 @@
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h> #include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h> #include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
namespace TextureImpl {
Bool ValidateTextureTarget(TextureTarget target) { Bool ValidateTextureTarget(TextureTarget target) {
if (target == TextureTarget::Unknown) { if (target == TextureTarget::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureTarget", "Invalid texture target")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureTarget", "Invalid texture target"));
return false; return false;
} }
return true; return true;
@@ -29,9 +28,8 @@ namespace MobileGL::MG_Impl::GLImpl {
Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget) { Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget) {
if (textureUploadTarget == TextureUploadTarget::Unknown) { if (textureUploadTarget == TextureUploadTarget::Unknown) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum, MG_State::pGLContext->RecordError(
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureUploadTarget",
"ValidateTextureUploadTarget",
"Invalid texture upload target")); "Invalid texture upload target"));
return false; return false;
} }
@@ -42,16 +40,16 @@ namespace MobileGL::MG_Impl::GLImpl {
if (texture == 0) { if (texture == 0) {
if (allowZero) return true; if (allowZero) return true;
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, MG_State::pGLContext->RecordError(
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureName", ErrorCode::InvalidValue,
"Texture name cannot be zero")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureName", "Texture name cannot be zero"));
return false; return false;
} }
if (!MG_State::pGLContext->ValidateTextureName(texture)) { if (!MG_State::pGLContext->ValidateTextureName(texture)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureName", "Invalid texture name")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureName", "Invalid texture name"));
return false; return false;
} }
return true; return true;
@@ -60,7 +58,7 @@ namespace MobileGL::MG_Impl::GLImpl {
Bool ValidateTextureInputFormat(TextureInputFormat format) { Bool ValidateTextureInputFormat(TextureInputFormat format) {
if (format == TextureInputFormat::Unknown) { if (format == TextureInputFormat::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInputFormat", ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInputFormat",
"Invalid texture input format")); "Invalid texture input format"));
return false; return false;
} }
@@ -69,9 +67,8 @@ namespace MobileGL::MG_Impl::GLImpl {
Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType) { Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType) {
if (texturePixelDataType == TexturePixelDataType::Unknown) { if (texturePixelDataType == TexturePixelDataType::Unknown) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum, MG_State::pGLContext->RecordError(
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTexturePixelDataType",
"ValidateTexturePixelDataType",
"Invalid texture pixel data type")); "Invalid texture pixel data type"));
return false; return false;
} }
@@ -80,9 +77,8 @@ namespace MobileGL::MG_Impl::GLImpl {
Bool ValidateTextureLevelNumber(GLint level) { Bool ValidateTextureLevelNumber(GLint level) {
if (level < 0) { if (level < 0) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, MG_State::pGLContext->RecordError(
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureLevelNumber",
"ValidateTextureLevelNumber",
"Texture level must be non-negative")); "Texture level must be non-negative"));
return false; return false;
} }
@@ -100,18 +96,17 @@ namespace MobileGL::MG_Impl::GLImpl {
if (width != height) { if (width != height) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
"Width and height must be equal for cube map textures")); "Width and height must be equal for cube map textures"));
return false; return false;
} }
} }
if (!(target == TextureUploadTarget::Texture1DArray || if (!(target == TextureUploadTarget::Texture1DArray || target == TextureUploadTarget::ProxyTexture1DArray)) {
target == TextureUploadTarget::ProxyTexture1DArray)) {
if (height < 0) { if (height < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
"Height must be greater than or equal to zero")); "Height must be greater than or equal to zero"));
return false; return false;
} }
@@ -123,7 +118,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (height < 0) { if (height < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
"Height must be greater than or equal to zero")); "Height must be greater than or equal to zero"));
return false; return false;
} }
@@ -137,8 +132,7 @@ namespace MobileGL::MG_Impl::GLImpl {
Bool ValidateTextureSizeRange(SizeT width, SizeT height, SizeT depth) { Bool ValidateTextureSizeRange(SizeT width, SizeT height, SizeT depth) {
if (width < 0 || height < 0 || depth < 0) { if (width < 0 || height < 0 || depth < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeRange",
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeRange",
"Width and height must be greater than zero")); "Width and height must be greater than zero"));
return false; return false;
} }
@@ -151,8 +145,7 @@ namespace MobileGL::MG_Impl::GLImpl {
Bool ValidateTextureInternalFormat(TextureInternalFormat format) { Bool ValidateTextureInternalFormat(TextureInternalFormat format) {
if (format == TextureInternalFormat::Unknown) { if (format == TextureInternalFormat::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormat",
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormat",
"Invalid texture sized internal format")); "Invalid texture sized internal format"));
return false; return false;
} }
@@ -161,10 +154,9 @@ namespace MobileGL::MG_Impl::GLImpl {
Bool ValidateTextureBorderNumber(Int border) { Bool ValidateTextureBorderNumber(Int border) {
if (border != 0) { if (border != 0) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, MG_State::pGLContext->RecordError(
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", ErrorCode::InvalidValue,
"ValidateTextureBorderNumber", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureBorderNumber", "Border must be zero"));
"Border must be zero"));
return false; return false;
} }
return true; return true;
@@ -179,8 +171,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (format != TextureInputFormat::RGB) { if (format != TextureInputFormat::RGB) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
"ValidateTextureInternalFormatCompatibleWithInput",
"Invalid format for the given type")); "Invalid format for the given type"));
return false; return false;
} }
@@ -189,14 +180,12 @@ namespace MobileGL::MG_Impl::GLImpl {
if (type == TexturePixelDataType::UnsignedShort4444 || type == TexturePixelDataType::UnsignedShort4444Rev || if (type == TexturePixelDataType::UnsignedShort4444 || type == TexturePixelDataType::UnsignedShort4444Rev ||
type == TexturePixelDataType::UnsignedShort5551 || type == TexturePixelDataType::UnsignedShort1555Rev || type == TexturePixelDataType::UnsignedShort5551 || type == TexturePixelDataType::UnsignedShort1555Rev ||
type == TexturePixelDataType::UnsignedInt8888 || type == TexturePixelDataType::UnsignedInt8888Rev || type == TexturePixelDataType::UnsignedInt8888 || type == TexturePixelDataType::UnsignedInt8888Rev ||
type == TexturePixelDataType::UnsignedInt1010102 || type == TexturePixelDataType::UnsignedInt1010102 || type == TexturePixelDataType::UnsignedInt2101010Rev ||
type == TexturePixelDataType::UnsignedInt2101010Rev ||
type == TexturePixelDataType::UnsignedInt5999Rev) { type == TexturePixelDataType::UnsignedInt5999Rev) {
if (format != TextureInputFormat::RGBA && format != TextureInputFormat::BGRA) { if (format != TextureInputFormat::RGBA && format != TextureInputFormat::BGRA) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
"ValidateTextureInternalFormatCompatibleWithInput",
"Invalid format for the given type")); "Invalid format for the given type"));
return false; return false;
} }
@@ -209,8 +198,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (format != TextureInputFormat::DepthComponent) { if (format != TextureInputFormat::DepthComponent) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
"ValidateTextureInternalFormatCompatibleWithInput",
"Invalid format for depth component internal format")); "Invalid format for depth component internal format"));
return false; return false;
} }
@@ -225,7 +213,7 @@ namespace MobileGL::MG_Impl::GLImpl {
)) { )) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
"Invalid internal format for depth component format")); "Invalid internal format for depth component format"));
return false; return false;
} }
@@ -233,12 +221,11 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level) { Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level) {
if (target == TextureUploadTarget::TextureRectangle || if (target == TextureUploadTarget::TextureRectangle || target == TextureUploadTarget::ProxyTextureRectangle) {
target == TextureUploadTarget::ProxyTextureRectangle) {
if (level != 0) { if (level != 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureLevelWithUploadTarget", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureLevelWithUploadTarget",
"Level must be zero for rectangle textures")); "Level must be zero for rectangle textures"));
return false; return false;
} }
@@ -250,7 +237,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (!textureObject) { if (!textureObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureObject", "Texture object is null")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureObject", "Texture object is null"));
return false; return false;
} }
return true; return true;
@@ -263,7 +250,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (prevTarget != target) { if (prevTarget != target) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureTargetUniformity", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureTargetUniformity",
"Texture target does not match the previously created texture")); "Texture target does not match the previously created texture"));
return false; return false;
} }
@@ -276,7 +263,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (xoffset < 0 || (xoffset + width) > baseSize.x()) { if (xoffset < 0 || (xoffset + width) > baseSize.x()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
"xoffset must be non-negative and (xoffset + width) must not exceed " "xoffset must be non-negative and (xoffset + width) must not exceed "
"the texture width.")); "the texture width."));
return false; return false;
@@ -286,7 +273,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (yoffset < 0 || (yoffset + height) > baseSize.y()) { if (yoffset < 0 || (yoffset + height) > baseSize.y()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
"yoffset must be non-negative and (yoffset + height) must not exceed " "yoffset must be non-negative and (yoffset + height) must not exceed "
"the texture height.")); "the texture height."));
return false; return false;
@@ -296,7 +283,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (zoffset < 0 || (zoffset + depth) > baseSize.z()) { if (zoffset < 0 || (zoffset + depth) > baseSize.z()) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
"zoffset must be non-negative and (zoffset + depth) must not exceed " "zoffset must be non-negative and (zoffset + depth) must not exceed "
"the texture depth.")); "the texture depth."));
return false; return false;
@@ -310,7 +297,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (unsizedFormat1 != unsizedFormat2) { if (unsizedFormat1 != unsizedFormat2) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
std::format("MG_Impl/GLImpl", "ValidateBaseInternalFormatMatch", std::format("MG_Impl/GLImpl", "ValidateBaseInternalFormatMatch",
"The base internal format of the two formats do not match ({} vs. {})", "The base internal format of the two formats do not match ({} vs. {})",
MG_Util::ConvertTextureInternalFormatToString(unsizedFormat1).c_str(), MG_Util::ConvertTextureInternalFormatToString(unsizedFormat1).c_str(),
@@ -319,5 +306,4 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
return true; return true;
} // namespace TextureImpl } // namespace TextureImpl
} // namespace TextureImpl } // namespace MobileGL::MG_Impl::GLImpl::TextureImpl
} // namespace MobileGL::MG_Impl::GLImpl
+2 -4
View File
@@ -12,8 +12,7 @@
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/TextureState/TextureObject.h> #include <MG_State/GLState/TextureState/TextureObject.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
namespace TextureImpl {
Bool ValidateTextureTarget(TextureTarget target); Bool ValidateTextureTarget(TextureTarget target);
Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget); Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget);
Bool ValidateTextureName(Uint texture, Bool allowZero = false); Bool ValidateTextureName(Uint texture, Bool allowZero = false);
@@ -34,5 +33,4 @@ namespace MobileGL::MG_Impl::GLImpl {
Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset, Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset,
Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0); Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0);
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2); Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2);
} // namespace TextureImpl } // namespace MobileGL::MG_Impl::GLImpl::TextureImpl
} // namespace MobileGL::MG_Impl::GLImpl
@@ -12,15 +12,14 @@
#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>
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
void DisableVertexAttribArray_State(GLuint index) { void DisableVertexAttribArray_State(GLuint index) {
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return; if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
auto vao = MG_State::pGLContext->GetBoundVertexArray(); auto& vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) { if (!vao) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl",
"EnableVertexAttribArray_State", "EnableVertexAttribArray_State",
"No vertex array object is bound.")); "No vertex array object is bound."));
return; return;
@@ -32,10 +31,10 @@ namespace MobileGL {
void EnableVertexAttribArray_State(GLuint index) { void EnableVertexAttribArray_State(GLuint index) {
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return; if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
auto vao = MG_State::pGLContext->GetBoundVertexArray(); auto& vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) { if (!vao) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl",
"EnableVertexAttribArray_State", "EnableVertexAttribArray_State",
"No vertex array object is bound.")); "No vertex array object is bound."));
return; return;
@@ -51,26 +50,24 @@ namespace MobileGL {
DataType dataType = MG_Util::ConvertGLEnumToDataType(type); DataType dataType = MG_Util::ConvertGLEnumToDataType(type);
if (!VertexArrayImpl::ValidateVertexAttribPointerParams(index, size, dataType, stride)) return; if (!VertexArrayImpl::ValidateVertexAttribPointerParams(index, size, dataType, stride)) return;
auto vao = MG_State::pGLContext->GetBoundVertexArray(); auto& vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) { if (!vao) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, MG_State::pGLContext->RecordError(
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
"VertexAttribPointer_State",
"No vertex array object is bound.")); "No vertex array object is bound."));
return; return;
} }
auto& vboSlot = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex); auto& vboSlot = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex);
auto vbo = vboSlot.GetBoundObject(); auto& vbo = vboSlot.GetBoundObject();
if (!vbo) { if (!vbo) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
"No buffer is bound to GL_ARRAY_BUFFER.")); "No buffer is bound to GL_ARRAY_BUFFER."));
return; return;
} }
SizeT offset = reinterpret_cast<SizeT>(pointer); auto offset = reinterpret_cast<SizeT>(pointer);
vao->SetAttributeFormat(index, size, dataType, false, stride, offset, true); vao->SetAttributeFormat(index, size, dataType, false, stride, offset, true);
vao->BindAttributeBuffer(index, vbo); vao->BindAttributeBuffer(index, vbo);
@@ -84,21 +81,19 @@ namespace MobileGL {
DataType dataType = MG_Util::ConvertGLEnumToDataType(type); DataType dataType = MG_Util::ConvertGLEnumToDataType(type);
if (!VertexArrayImpl::ValidateVertexAttribPointerParams(index, size, dataType, stride)) return; if (!VertexArrayImpl::ValidateVertexAttribPointerParams(index, size, dataType, stride)) return;
auto vao = MG_State::pGLContext->GetBoundVertexArray(); auto& vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) { if (!vao) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, MG_State::pGLContext->RecordError(
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
"VertexAttribPointer_State",
"No vertex array object is bound.")); "No vertex array object is bound."));
return; return;
} }
auto& vboSlot = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex); auto& vboSlot = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex);
auto vbo = vboSlot.GetBoundObject(); auto& vbo = vboSlot.GetBoundObject();
if (!vbo) { if (!vbo) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
"No buffer is bound to GL_ARRAY_BUFFER.")); "No buffer is bound to GL_ARRAY_BUFFER."));
return; return;
} }
@@ -127,8 +122,8 @@ namespace MobileGL {
void DeleteVertexArrays_State(GLsizei n, const GLuint* arrays) { void DeleteVertexArrays_State(GLsizei n, const GLuint* arrays) {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteVertexArrays_State", ErrorCode::InvalidValue,
"n must be non-negative.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteVertexArrays_State", "n must be non-negative."));
return; return;
} }
@@ -151,18 +146,19 @@ namespace MobileGL {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GenVertexArrays_State", "n must be non-negative.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenVertexArrays_State", "n must be non-negative."));
return; return;
} }
auto vaoNames = MG_State::pGLContext->GenVertexArrayNames(n); static thread_local Vector<Uint> vaos;
Copy(vaoNames.data(), arrays, vaoNames.size()); MG_State::pGLContext->GenVertexArrayNames(n, vaos);
Memcpy(arrays, vaos.data(), n * sizeof(GLuint));
} }
GLboolean IsVertexArray_State(GLuint array) { GLboolean IsVertexArray_State(GLuint array) {
if (array == 0) { if (array == 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "IsVertexArray_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "IsVertexArray_State",
"Vertex array name 0 is not supported.")); "Vertex array name 0 is not supported."));
return GL_FALSE; return GL_FALSE;
} }
@@ -170,7 +166,7 @@ namespace MobileGL {
if (!MG_State::pGLContext->ValidateVertexArrayObject(array)) { if (!MG_State::pGLContext->ValidateVertexArrayObject(array)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "IsVertexArray_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "IsVertexArray_State",
std::format("Vertex array object {} does not exist.", array))); std::format("Vertex array object {} does not exist.", array)));
return GL_FALSE; return GL_FALSE;
} }
@@ -180,11 +176,10 @@ namespace MobileGL {
void VertexAttribDivisor_State(GLuint index, GLuint divisor) { void VertexAttribDivisor_State(GLuint index, GLuint divisor) {
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return; if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
auto vao = MG_State::pGLContext->GetBoundVertexArray(); auto& vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) { if (!vao) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, MG_State::pGLContext->RecordError(
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribDivisor_State",
"VertexAttribDivisor_State",
"No vertex array object is bound.")); "No vertex array object is bound."));
return; return;
} }
@@ -229,5 +224,4 @@ namespace MobileGL {
void GenVertexArrays(GLsizei n, GLuint* arrays) { void GenVertexArrays(GLsizei n, GLuint* arrays) {
GenVertexArrays_State(n, arrays); GenVertexArrays_State(n, arrays);
} }
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
@@ -9,8 +9,7 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
namespace MobileGL { namespace MobileGL::MG_Impl::GLImpl {
namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */ /* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void VertexAttribDivisor(GLuint index, GLuint divisor); void VertexAttribDivisor(GLuint index, GLuint divisor);
GLboolean IsVertexArray(GLuint array); GLboolean IsVertexArray(GLuint array);
@@ -22,5 +21,4 @@ namespace MobileGL {
void BindVertexArray(GLuint array); void BindVertexArray(GLuint array);
void DeleteVertexArrays(GLsizei n, const GLuint* arrays); void DeleteVertexArrays(GLsizei n, const GLuint* arrays);
void GenVertexArrays(GLsizei n, GLuint* arrays); void GenVertexArrays(GLsizei n, GLuint* arrays);
} // namespace MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
} // namespace MobileGL
@@ -12,15 +12,13 @@
#include <MG_Util/Converters/MGToGL/DataTypeConverter.h> #include <MG_Util/Converters/MGToGL/DataTypeConverter.h>
#include <MG_Util/Converters/MGToStr/DataTypeConverter.h> #include <MG_Util/Converters/MGToStr/DataTypeConverter.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl::VertexArrayImpl {
namespace VertexArrayImpl {
Bool ValidateVertexArrayName(Uint index) { Bool ValidateVertexArrayName(Uint index) {
Bool isValid = MG_State::pGLContext->ValidateVertexArrayName(index); Bool isValid = MG_State::pGLContext->ValidateVertexArrayName(index);
if (!isValid) { if (!isValid) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateVertexArrayName", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateVertexArrayName",
std::format("Vertex array name {} is not valid.", index))); std::format("Vertex array name {} is not valid.", index)));
return false; return false;
} }
@@ -31,7 +29,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (!MG_State::pGLContext->ValidateVertexArrayObject(index)) { if (!MG_State::pGLContext->ValidateVertexArrayObject(index)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateVertexArrayObject", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateVertexArrayObject",
std::format("Vertex array object {} does not exist.", index))); std::format("Vertex array object {} does not exist.", index)));
return false; return false;
} }
@@ -42,7 +40,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (index >= MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS) { if (index >= MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", "ValidateVertexAttributeIndex", "MG_Impl/GLImpl", "ValidateVertexAttributeIndex",
std::format("Attribute index {} exceeds maximum of {}.", index, std::format("Attribute index {} exceeds maximum of {}.", index,
MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS - 1))); MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS - 1)));
@@ -55,7 +53,7 @@ namespace MobileGL::MG_Impl::GLImpl {
if (size < 1 || size > 4) { if (size < 1 || size > 4) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", "ValidateVertexAttribPointerParams", "MG_Impl/GLImpl", "ValidateVertexAttribPointerParams",
std::format("Invalid size {} for attribute {}. Must be 1-4.", size, index))); std::format("Invalid size {} for attribute {}. Must be 1-4.", size, index)));
return false; return false;
@@ -64,16 +62,16 @@ namespace MobileGL::MG_Impl::GLImpl {
if (type == DataType::Unknown) { if (type == DataType::Unknown) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateVertexAttribPointerParams", MakeUnique<GenericErrorInfo>(
std::format("Invalid type {} for attribute {}.", "MG_Impl/GLImpl", "ValidateVertexAttribPointerParams",
MG_Util::ConvertDataTypeToString(type).c_str(), index))); std::format("Invalid type {} for attribute {}.", MG_Util::ConvertDataTypeToString(type), index)));
return false; return false;
} }
if (stride < 0) { if (stride < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", "ValidateVertexAttribPointerParams", "MG_Impl/GLImpl", "ValidateVertexAttribPointerParams",
std::format("Negative stride {} is not allowed for attribute {}.", stride, index))); std::format("Negative stride {} is not allowed for attribute {}.", stride, index)));
return false; return false;
@@ -81,5 +79,4 @@ namespace MobileGL::MG_Impl::GLImpl {
return true; return true;
} }
} // namespace VertexArrayImpl } // namespace MobileGL::MG_Impl::GLImpl::VertexArrayImpl
} // namespace MobileGL::MG_Impl::GLImpl
@@ -10,11 +10,9 @@
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/VertexArrayState/VertexArrayObject.h> #include <MG_State/GLState/VertexArrayState/VertexArrayObject.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl::VertexArrayImpl {
namespace VertexArrayImpl {
Bool ValidateVertexArrayName(Uint index); Bool ValidateVertexArrayName(Uint index);
Bool ValidateVertexArrayObject(Uint index); Bool ValidateVertexArrayObject(Uint index);
Bool ValidateVertexAttributeIndex(Uint index); Bool ValidateVertexAttributeIndex(Uint index);
Bool ValidateVertexAttribPointerParams(Uint index, SizeT size, DataType type, Int stride); Bool ValidateVertexAttribPointerParams(Uint index, SizeT size, DataType type, Int stride);
} // namespace VertexArrayImpl } // namespace MobileGL::MG_Impl::GLImpl::VertexArrayImpl
} // namespace MobileGL::MG_Impl::GLImpl
+2 -4
View File
@@ -10,9 +10,7 @@
#include <Includes.h> #include <Includes.h>
#include "MG_Impl/GetProcAddress.h" #include "MG_Impl/GetProcAddress.h"
namespace MG_Impl { namespace MG_Impl::GLXImpl {
namespace GLXImpl {
void* GetProcAddress(const char* name); void* GetProcAddress(const char* name);
void* GetProcAddressARB(const char* name); void* GetProcAddressARB(const char* name);
} // namespace GLXImpl } // namespace MG_Impl::GLXImpl
} // namespace MG_Impl
+2 -4
View File
@@ -12,8 +12,7 @@
return (void*)name; \ return (void*)name; \
} }
namespace MobileGL { namespace MobileGL::MG_Impl {
namespace MG_Impl {
void* GetProcAddress(const char* name) { void* GetProcAddress(const char* name) {
MGLOG_D("GetProcAddress(%s)", name); MGLOG_D("GetProcAddress(%s)", name);
GETPROC(eglChooseConfig, name); GETPROC(eglChooseConfig, name);
@@ -1352,5 +1351,4 @@ namespace MobileGL {
MGLOG_W("GetProcAddress(%s) = nullptr!", name); MGLOG_W("GetProcAddress(%s) = nullptr!", name);
return nullptr; return nullptr;
} }
} // namespace MG_Impl } // namespace MobileGL::MG_Impl
} // namespace MobileGL
+2 -4
View File
@@ -9,8 +9,6 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
namespace MobileGL { namespace MobileGL::MG_Impl {
namespace MG_Impl {
void* GetProcAddress(const char* name); void* GetProcAddress(const char* name);
} // namespace MG_Impl } // namespace MobileGL::MG_Impl
} // namespace MobileGL
+5 -3
View File
@@ -18,10 +18,10 @@
namespace MobileGL::MG_Impl { namespace MobileGL::MG_Impl {
void Init() { void Init() {
MGLOG_D("Initializing MobileGL Implementation..."); MGLOG_D("Initializing MobileGL Implementation...");
GLImpl::TextureImpl::pProxyTextureManager = new GLImpl::TextureImpl::ProxyTextureManager(); GLImpl::TextureImpl::pProxyTextureManager = MakeUnique<GLImpl::TextureImpl::ProxyTextureManager>();
// TODO: get real info in EGL // TODO: get real info in EGL
auto fbo0 = MG_State::pGLContext->CreateFramebufferObject(0); auto& fbo0 = MG_State::pGLContext->CreateFramebufferObject(0);
auto colorTex = MakeShared<MG_State::GLState::TextureObject2D>(0); auto colorTex = MakeShared<MG_State::GLState::TextureObject2D>(0);
colorTex->SetInternalFormat(TextureInternalFormat::RGBA8); colorTex->SetInternalFormat(TextureInternalFormat::RGBA8);
colorTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, {{512, 512, 1}, 0}); colorTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, {{512, 512, 1}, 0});
@@ -38,6 +38,8 @@ namespace MobileGL::MG_Impl {
fbo0->AttachTexture(FramebufferAttachmentType::Depth, depthTex); fbo0->AttachTexture(FramebufferAttachmentType::Depth, depthTex);
fbo0->AttachTexture(FramebufferAttachmentType::Stencil, stencilTex); fbo0->AttachTexture(FramebufferAttachmentType::Stencil, stencilTex);
GLImpl::FramebufferImpl::pDefaultFramebufferInfo = GLImpl::FramebufferImpl::pDefaultFramebufferInfo =
new GLImpl::FramebufferImpl::DefaultFramebufferInfo(fbo0, colorTex, depthTex, stencilTex); MakeUnique<GLImpl::FramebufferImpl::DefaultFramebufferInfo>(fbo0, colorTex, depthTex, stencilTex);
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).Bind(fbo0);
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).Bind(fbo0);
} }
} // namespace MobileGL::MG_Impl } // namespace MobileGL::MG_Impl
+7 -5
View File
@@ -16,6 +16,10 @@ namespace MobileGL {
constexpr EGLint EGL_DISPLAY_MINOR_VERSION = 5; constexpr EGLint EGL_DISPLAY_MINOR_VERSION = 5;
} // namespace } // namespace
Bool EGLContext::DisplayLookupKey::operator==(const DisplayLookupKey& rhs) const {
return this->NativeDisplayKey == rhs.NativeDisplayKey && this->Platform == rhs.Platform;
}
SizeT EGLContext::DisplayLookupHasher::operator()(const DisplayLookupKey& key) const { SizeT EGLContext::DisplayLookupHasher::operator()(const DisplayLookupKey& key) const {
const auto nativeHash = std::hash<Uint64>{}(key.NativeDisplayKey); const auto nativeHash = std::hash<Uint64>{}(key.NativeDisplayKey);
const auto platformHash = std::hash<Uint64>{}(static_cast<Uint64>(key.Platform)); const auto platformHash = std::hash<Uint64>{}(static_cast<Uint64>(key.Platform));
@@ -388,8 +392,6 @@ namespace MobileGL {
*value = cfg->SurfaceType; *value = cfg->SurfaceType;
return true; return true;
case EGL_RENDERABLE_TYPE: case EGL_RENDERABLE_TYPE:
*value = cfg->RenderableType;
return true;
case EGL_CONFORMANT: case EGL_CONFORMANT:
*value = cfg->RenderableType; *value = cfg->RenderableType;
return true; return true;
@@ -878,8 +880,8 @@ namespace MobileGL {
Bool EGLContext::MakeCurrent(EGLDisplayHandle display, EGLSurfaceHandle draw, EGLSurfaceHandle read, Bool EGLContext::MakeCurrent(EGLDisplayHandle display, EGLSurfaceHandle draw, EGLSurfaceHandle read,
EGLContextHandle context) { EGLContextHandle context) {
const std::lock_guard<std::recursive_mutex> lock(m_mutex); const std::lock_guard<std::recursive_mutex> lock(m_mutex);
const Bool releaseCurrentRequest = display == EGL_NO_DISPLAY && draw == EGL_NO_SURFACE && const Bool releaseCurrentRequest =
read == EGL_NO_SURFACE && context == nullptr; display == EGL_NO_DISPLAY && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && context == nullptr;
const auto threadKey = CurrentThreadKey(); const auto threadKey = CurrentThreadKey();
if (releaseCurrentRequest) { if (releaseCurrentRequest) {
ReleaseThreadUnlocked(threadKey); ReleaseThreadUnlocked(threadKey);
@@ -1130,6 +1132,6 @@ namespace MobileGL {
} }
} // namespace EGLState } // namespace EGLState
EGLState::EGLContext* pEGLContext; UniquePtr<EGLState::EGLContext> pEGLContext;
} // namespace MG_State } // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
+2 -2
View File
@@ -115,7 +115,7 @@ namespace MobileGL {
Uint64 NativeDisplayKey = 0; Uint64 NativeDisplayKey = 0;
EGLenum Platform = EGL_NONE; EGLenum Platform = EGL_NONE;
Bool operator==(const DisplayLookupKey& rhs) const = default; Bool operator==(const DisplayLookupKey& rhs) const;
}; };
struct DisplayLookupHasher { struct DisplayLookupHasher {
@@ -253,6 +253,6 @@ namespace MobileGL {
}; };
} // namespace EGLState } // namespace EGLState
extern EGLState::EGLContext* pEGLContext; extern UniquePtr<EGLState::EGLContext> pEGLContext;
} // namespace MG_State } // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -7,16 +7,13 @@
// End of Source File Header // End of Source File Header
#include "BufferObject.h" #include "BufferObject.h"
#include "MG_Util/Types.h"
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State {
namespace GLState {
BufferObject::BufferObject(Uint externalIndex) BufferObject::BufferObject(Uint externalIndex)
: m_externalIndex(externalIndex), m_size(0), m_usage(BufferUsage::StaticDraw), m_isMapped(false), : m_externalIndex(externalIndex), m_size(0), m_usage(BufferUsage::StaticDraw), m_isMapped(false),
m_mappingAccess(BufferMappingAccessBit::Null), m_mappingAccess(BufferMappingAccessBit::Null),
m_change(BufferChangeBits::DirtyBit | BufferChangeBits::PreferReallocationBit), m_mappedRange({0, 0}), m_change(BufferChangeBits::DirtyBit | BufferChangeBits::PreferReallocationBit), m_mappedRange({0, 0}),
m_dataPtr(MakeShared<Data>()) { m_dataPtr(MakeShared<Data>()), m_ownsStagingData{} {
m_change.DirtyRanges.reserve(BufferChange::DEFAULT_RESERVED_DIRTY_RANGES_COUNT); m_change.DirtyRanges.reserve(BufferChange::DEFAULT_RESERVED_DIRTY_RANGES_COUNT);
} }
@@ -77,8 +74,8 @@ namespace MobileGL {
SizeT start = m_mappedRange.start + offset; SizeT start = m_mappedRange.start + offset;
SizeT end = start + length; SizeT end = start + length;
MOBILEGL_ASSERT(end <= m_mappedRange.end, MOBILEGL_ASSERT(end <= m_mappedRange.end, "Flush range out of bounds: mappedRange.end (%zu) < end (%zu)",
"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); Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length);
m_change.DirtyRanges.Add({start, end}); m_change.DirtyRanges.Add({start, end});
@@ -88,8 +85,8 @@ namespace MobileGL {
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, "Cannot upload sub data while buffer is 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)", "UploadSubData out of bounds: atOffset (%zu) + data.size (%zu) > m_size (%zu)", atOffset,
atOffset, data.size, m_size); data.size, m_size);
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});
@@ -98,16 +95,15 @@ namespace MobileGL {
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit; m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
} }
void BufferObject::CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, void BufferObject::CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, SizeT size) {
SizeT size) {
MOBILEGL_ASSERT(!m_isMapped, "Cannot copy data while buffer is mapped."); MOBILEGL_ASSERT(!m_isMapped, "Cannot copy data while buffer is mapped.");
MOBILEGL_ASSERT(!src->IsMapped(), "Cannot copy data from a buffer that is mapped."); MOBILEGL_ASSERT(!src->IsMapped(), "Cannot copy data from a buffer that is 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());
MOBILEGL_ASSERT(dstOffset + size <= m_size, MOBILEGL_ASSERT(dstOffset + size <= m_size,
"Destination buffer copy out of bounds: dstOffset (%zu) + size (%zu) > m_size (%zu)", "Destination buffer copy out of bounds: dstOffset (%zu) + size (%zu) > m_size (%zu)", dstOffset,
dstOffset, size, m_size); size, m_size);
const Uint8* srcData = src->m_dataPtr->data() + srcOffset; const Uint8* srcData = src->m_dataPtr->data() + srcOffset;
Memcpy(m_dataPtr->data() + dstOffset, srcData, size); Memcpy(m_dataPtr->data() + dstOffset, srcData, size);
@@ -151,8 +147,7 @@ namespace MobileGL {
m_stagingData.resize(range.end - range.start); m_stagingData.resize(range.end - range.start);
m_ownsStagingData = true; m_ownsStagingData = true;
if (!(access & if (!(access & (BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) {
(BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) {
Memcpy(m_stagingData.data(), m_dataPtr->data() + range.start, m_stagingData.size()); Memcpy(m_stagingData.data(), m_dataPtr->data() + range.start, m_stagingData.size());
} }
@@ -162,8 +157,8 @@ namespace MobileGL {
return m_dataPtr->data() + range.start; return m_dataPtr->data() + range.start;
} }
m_change.Bits |= !(access & BufferMappingAccessBit::InvalidateBuffer || m_change.Bits |=
access & BufferMappingAccessBit::InvalidateRange) !(access & BufferMappingAccessBit::InvalidateBuffer || access & BufferMappingAccessBit::InvalidateRange)
? BufferChangeBits::ForbidInvalidationBit ? BufferChangeBits::ForbidInvalidationBit
: BufferChangeBits::None; : BufferChangeBits::None;
m_change.Bits |= !(access & BufferMappingAccessBit::Unsynchronized) m_change.Bits |= !(access & BufferMappingAccessBit::Unsynchronized)
@@ -171,7 +166,7 @@ namespace MobileGL {
: BufferChangeBits::None; : BufferChangeBits::None;
} }
const SharedPtr<Data> BufferObject::GetDataReadOnly() const { const SharedPtr<Data>& BufferObject::GetDataReadOnly() const {
return m_dataPtr; return m_dataPtr;
} }
@@ -211,6 +206,4 @@ namespace MobileGL {
Uint BufferObject::GetExternalIndex() const { Uint BufferObject::GetExternalIndex() const {
return m_externalIndex; return m_externalIndex;
} }
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -7,7 +7,6 @@
// End of Source File Header // End of Source File Header
#pragma once #pragma once
#include "MG_Util/Types.h"
#include <Includes.h> #include <Includes.h>
#include <MG_Util/Math/VectorTypes.h> #include <MG_Util/Math/VectorTypes.h>
@@ -73,8 +72,7 @@ namespace MobileGL {
VecRange1D DirtyRanges; VecRange1D DirtyRanges;
}; };
namespace MG_State { namespace MG_State::GLState {
namespace GLState {
class BufferObject { class BufferObject {
public: public:
using TargetEnum = BufferTarget; using TargetEnum = BufferTarget;
@@ -96,7 +94,7 @@ namespace MobileGL {
SizeT GetSize() const; SizeT GetSize() const;
BufferUsage GetUsage() const; BufferUsage GetUsage() const;
Range1D GetMappedRange() const; Range1D GetMappedRange() const;
const SharedPtr<Data> GetDataReadOnly() const; const SharedPtr<Data>& GetDataReadOnly() const;
Flags<BufferMappingAccessBit> GetMappingAccess() const; Flags<BufferMappingAccessBit> GetMappingAccess() const;
Uint GetExternalIndex() const; Uint GetExternalIndex() const;
const VecRange1D& GetDirtyRanges() const; const VecRange1D& GetDirtyRanges() const;
@@ -114,6 +112,5 @@ namespace MobileGL {
Vector<Uint8> m_stagingData; Vector<Uint8> m_stagingData;
Bool m_ownsStagingData; Bool m_ownsStagingData;
}; };
} // namespace GLState } // namespace MG_State::GLState
} // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -8,39 +8,39 @@
#include "BufferState.h" #include "BufferState.h"
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State {
namespace GLState {
BufferState::BufferState() : m_indexGenerator(1024, 1) { BufferState::BufferState() : m_indexGenerator(1024, 1) {
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) { for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
m_bindingSlots[i] = BindingSlot<BufferObject>(GlobalBufferTargets[i]); m_bindingSlots[i] = BindingSlot<BufferObject>(GlobalBufferTargets[i]);
} }
} }
SharedPtr<BufferObject> BufferState::GetBufferObject(Uint index) { const SharedPtr<BufferObject>& BufferState::GetBufferObject(Uint index) {
auto it = m_bufferObjects.find(index); auto it = m_bufferObjects.find(index);
if (it != m_bufferObjects.end()) { if (it != m_bufferObjects.end()) {
return it->second; return it->second;
} }
return nullptr; static SharedPtr<BufferObject> nullBufferObject = nullptr;
return nullBufferObject;
} }
Vector<Uint> BufferState::GenerateNames(Uint number) { void BufferState::GenerateNames(Uint number, Vector<Uint>& buffers) {
Vector<Uint> buffers(number); buffers.resize(number);
m_indexGenerator.Generate(number, buffers.data()); m_indexGenerator.Generate(number, buffers.data());
return buffers;
} }
SharedPtr<BufferObject> BufferState::CreateBufferObject(Uint index) { const SharedPtr<BufferObject>& BufferState::CreateBufferObject(Uint index) {
auto bufferObject = MakeShared<BufferObject>(index); auto& bufferObj = m_bufferObjects[index];
m_bufferObjects[index] = bufferObject; if (!bufferObj) {
return bufferObject; bufferObj = MakeShared<BufferObject>(index);
}
return bufferObj;
} }
BindingSlot<BufferObject>& BufferState::GetBindingSlot(BufferTarget target) { BindingSlot<BufferObject>& BufferState::GetBindingSlot(BufferTarget target) {
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) { for (auto& bindingSlot : m_bindingSlots) {
if (m_bindingSlots[i].GetTarget() == target) { if (bindingSlot.GetTarget() == target) {
return m_bindingSlots[i]; return bindingSlot;
} }
} }
MOBILEGL_ASSERT(false, "Invalid BufferTarget enum value: %d", static_cast<int>(target)); MOBILEGL_ASSERT(false, "Invalid BufferTarget enum value: %d", static_cast<int>(target));
@@ -51,9 +51,9 @@ namespace MobileGL {
if (m_indexGenerator.IsValid(index)) { if (m_indexGenerator.IsValid(index)) {
auto it = m_bufferObjects.find(index); auto it = m_bufferObjects.find(index);
if (it != m_bufferObjects.end()) { if (it != m_bufferObjects.end()) {
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) { for (auto& bindingSlot : m_bindingSlots) {
if (m_bindingSlots[i].GetBoundObject() == it->second) { if (bindingSlot.GetBoundObject() == it->second) {
m_bindingSlots[i].Bind(nullptr); bindingSlot.Bind(nullptr);
} }
} }
m_bufferObjects.erase(it); m_bufferObjects.erase(it);
@@ -76,10 +76,7 @@ namespace MobileGL {
return m_bufferBindPointTargets[i][index]; return m_bufferBindPointTargets[i][index];
} }
} }
MOBILEGL_ASSERT(false, "Invalid BufferTarget enum value for binding point: %d", MOBILEGL_ASSERT(false, "Invalid BufferTarget enum value for binding point: %d", static_cast<int>(target));
static_cast<int>(target));
return m_bufferBindPointTargets[0][index]; return m_bufferBindPointTargets[0][index];
} }
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -11,25 +11,22 @@
#include <MG_Util/Miscellany/IndexGenerator.h> #include <MG_Util/Miscellany/IndexGenerator.h>
#include "BufferObject.h" #include "BufferObject.h"
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State {
namespace GLState {
constexpr const auto GlobalBufferTargets = constexpr const auto GlobalBufferTargets =
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::ShaderStorage);
constexpr const auto BufferBindPointTargets = constexpr const auto BufferBindPointTargets = ToArray(BufferTarget::Uniform, BufferTarget::TransformFeedback,
ToArray(BufferTarget::Uniform, BufferTarget::TransformFeedback, BufferTarget::AtomicCounter, BufferTarget::AtomicCounter, BufferTarget::ShaderStorage);
BufferTarget::ShaderStorage);
class BufferState { class BufferState {
public: public:
BufferState(); BufferState();
SharedPtr<BufferObject> GetBufferObject(Uint index); const SharedPtr<BufferObject>& GetBufferObject(Uint index);
Vector<Uint> GenerateNames(Uint number); void GenerateNames(Uint number, Vector<Uint>& buffers);
SharedPtr<BufferObject> CreateBufferObject(Uint index); const SharedPtr<BufferObject>& CreateBufferObject(Uint index);
BindingSlot<BufferObject>& GetBindingSlot(BufferTarget target); BindingSlot<BufferObject>& GetBindingSlot(BufferTarget target);
// For glBindBufferBase / glBindBufferRange // For glBindBufferBase / glBindBufferRange
BindingSlotRange1D<BufferObject>& GetBindingPoint(BufferTarget target, Uint index); BindingSlotRange1D<BufferObject>& GetBindingPoint(BufferTarget target, Uint index);
@@ -48,9 +45,6 @@ namespace MobileGL {
Array<BindingSlot<BufferObject>, GlobalBufferTargets.size()> m_bindingSlots; Array<BindingSlot<BufferObject>, GlobalBufferTargets.size()> m_bindingSlots;
// TODO: query the count somewhere globally? // TODO: query the count somewhere globally?
// For glBindBufferBase / glBindBufferRange // For glBindBufferBase / glBindBufferRange
Array<Array<BindingSlotRange1D<BufferObject>, 16>, BufferBindPointTargets.size()> Array<Array<BindingSlotRange1D<BufferObject>, 16>, BufferBindPointTargets.size()> m_bufferBindPointTargets;
m_bufferBindPointTargets;
}; };
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
+53 -53
View File
@@ -10,42 +10,41 @@
#include "MG_State/GLState/RenderbufferState/RenderbufferObject.h" #include "MG_State/GLState/RenderbufferState/RenderbufferObject.h"
#include "MG_State/EGLState/Core.h" #include "MG_State/EGLState/Core.h"
namespace MobileGL { namespace MobileGL::MG_State {
namespace MG_State {
void Init() { void Init() {
MGLOG_D("Initializing MobileGL State..."); MGLOG_D("Initializing MobileGL State...");
pGLContext = new MG_State::GLState::GLContext(); pGLContext = MakeUnique<GLState::GLContext>();
pEGLContext = new MG_State::EGLState::EGLContext(); pEGLContext = MakeUnique<EGLState::EGLContext>();
} }
namespace GLState { namespace GLState {
// Error // Error
void GLContext::RecordError(ErrorCode code, SharedPtr<ErrorInfo> info) { void GLContext::RecordError(ErrorCode code, UniquePtr<ErrorInfo> info) {
m_errorState.RecordError(code, info); m_errorState.RecordError(code, Move(info));
} }
Bool GLContext::HasGLError() const { Bool GLContext::HasGLError() const {
return m_errorState.HasGLError(); return m_errorState.HasGLError();
} }
Optional<const Error> GLContext::PeekGLError() const { Optional<const Error*> GLContext::PeekGLError() const {
return m_errorState.PeekGLError(); return m_errorState.PeekGLError();
} }
Optional<Error> GLContext::PopGLError() { Optional<UniquePtr<Error>> GLContext::PopGLError() {
return m_errorState.PopGLError(); return Move(m_errorState.PopGLError());
} }
Bool GLContext::HasNonGLError() const { Bool GLContext::HasNonGLError() const {
return m_errorState.HasNonGLError(); return m_errorState.HasNonGLError();
} }
Optional<const Error> GLContext::PeekNonGLError() const { Optional<const Error*> GLContext::PeekNonGLError() const {
return m_errorState.PeekNonGLError(); return m_errorState.PeekNonGLError();
} }
Optional<Error> GLContext::PopNonGLError() { Optional<UniquePtr<Error>> GLContext::PopNonGLError() {
return m_errorState.PopNonGLError(); return Move(m_errorState.PopNonGLError());
} }
void GLContext::ClearErrors() { void GLContext::ClearErrors() {
@@ -53,19 +52,18 @@ namespace MobileGL {
} }
// Buffer // Buffer
Vector<Uint> GLContext::GenBufferNames(Uint number) { void GLContext::GenBufferNames(Uint number, Vector<Uint>& buffers) {
return m_bufferState.GenerateNames(number); m_bufferState.GenerateNames(number, buffers);
} }
SharedPtr<BufferObject> GLContext::GetBufferObject(Uint index) { const SharedPtr<BufferObject>& GLContext::GetBufferObject(Uint index) {
return m_bufferState.GetBufferObject(index); return m_bufferState.GetBufferObject(index);
} }
BindingSlot<BufferObject>& GLContext::GetBufferBindingSlot(BufferTarget target) { BindingSlot<BufferObject>& GLContext::GetBufferBindingSlot(BufferTarget target) {
if (target == BufferTarget::Index) { if (target == BufferTarget::Index) {
const auto& vao = m_vertexArrayState.GetBoundVertexArray(); const auto& vao = m_vertexArrayState.GetBoundVertexArray();
MOBILEGL_ASSERT(vao != nullptr, MOBILEGL_ASSERT(vao != nullptr, "No VAO is currently bound when accessing index buffer binding slot.");
"No VAO is currently bound when accessing index buffer binding slot.");
return vao->GetIndexBufferBindingSlot(); return vao->GetIndexBufferBindingSlot();
} }
@@ -76,7 +74,7 @@ namespace MobileGL {
return m_bufferState.GetBindingPoint(target, index); return m_bufferState.GetBindingPoint(target, index);
} }
SharedPtr<BufferObject> GLContext::CreateBufferObject(Uint index) { const SharedPtr<BufferObject>& GLContext::CreateBufferObject(Uint index) {
return m_bufferState.CreateBufferObject(index); return m_bufferState.CreateBufferObject(index);
} }
@@ -84,8 +82,7 @@ namespace MobileGL {
if (ValidateBufferObject(index)) { if (ValidateBufferObject(index)) {
auto bufferObject = m_bufferState.GetBufferObject(index); auto bufferObject = m_bufferState.GetBufferObject(index);
auto& vaos = m_vertexArrayState.GetAllVertexArrays(); auto& vaos = m_vertexArrayState.GetAllVertexArrays();
for (SizeT i = 0; i < vaos.size(); ++i) { for (auto& vao : vaos) {
auto vao = vaos[i];
if (vao == nullptr) continue; if (vao == nullptr) continue;
if (vao->GetIndexBufferBindingSlot().GetBoundObject() == bufferObject) { if (vao->GetIndexBufferBindingSlot().GetBoundObject() == bufferObject) {
@@ -111,11 +108,11 @@ namespace MobileGL {
} }
// VertexArray // VertexArray
Vector<Uint> GLContext::GenVertexArrayNames(Uint number) { void GLContext::GenVertexArrayNames(Uint number, Vector<Uint>& vertexArrays) {
return m_vertexArrayState.GenerateNames(number); m_vertexArrayState.GenerateNames(number, vertexArrays);
} }
SharedPtr<VertexArrayObject> GLContext::GetVertexArrayObject(Uint index) { const SharedPtr<VertexArrayObject>& GLContext::GetVertexArrayObject(Uint index) {
return m_vertexArrayState.GetVertexArrayObject(index); return m_vertexArrayState.GetVertexArrayObject(index);
} }
@@ -123,7 +120,7 @@ namespace MobileGL {
m_vertexArrayState.Bind(index); m_vertexArrayState.Bind(index);
} }
SharedPtr<VertexArrayObject> GLContext::CreateVertexArrayObject(Uint index) { const SharedPtr<VertexArrayObject>& GLContext::CreateVertexArrayObject(Uint index) {
return m_vertexArrayState.CreateVertexArrayObject(index); return m_vertexArrayState.CreateVertexArrayObject(index);
} }
@@ -139,20 +136,20 @@ namespace MobileGL {
return m_vertexArrayState.ValidateVertexArrayObject(index); return m_vertexArrayState.ValidateVertexArrayObject(index);
} }
SharedPtr<VertexArrayObject> GLContext::GetBoundVertexArray() { const SharedPtr<VertexArrayObject>& GLContext::GetBoundVertexArray() {
return m_vertexArrayState.GetBoundVertexArray(); return m_vertexArrayState.GetBoundVertexArray();
} }
// Texture // Texture
Vector<Uint> GLContext::GenTextureNames(Uint number) { void GLContext::GenTextureNames(Uint number, Vector<Uint>& textures) {
return m_textureState.GenerateNames(number); m_textureState.GenerateNames(number, textures);
} }
SharedPtr<ITextureObject> GLContext::GetTextureObject(Uint index) { const SharedPtr<ITextureObject>& GLContext::GetTextureObject(Uint index) {
return m_textureState.GetTextureObject(index); return m_textureState.GetTextureObject(index);
} }
SharedPtr<ITextureObject> GLContext::CreateTextureObject(Uint index, TextureTarget target) { const SharedPtr<ITextureObject>& GLContext::CreateTextureObject(Uint index, TextureTarget target) {
return m_textureState.CreateTextureObject(index, target); return m_textureState.CreateTextureObject(index, target);
} }
@@ -205,11 +202,11 @@ namespace MobileGL {
return m_programState.ValidateShaderObject(index); return m_programState.ValidateShaderObject(index);
} }
SharedPtr<ProgramObject> GLContext::GetProgramObject(const Uint index) { const SharedPtr<ProgramObject>& GLContext::GetProgramObject(const Uint index) {
return m_programState.GetProgramObject(index); return m_programState.GetProgramObject(index);
} }
SharedPtr<ShaderObject> GLContext::GetShaderObject(const Uint index) { const SharedPtr<ShaderObject>& GLContext::GetShaderObject(const Uint index) {
return m_programState.GetShaderObject(index); return m_programState.GetShaderObject(index);
} }
@@ -217,7 +214,7 @@ namespace MobileGL {
return m_programState.UseProgram(program); return m_programState.UseProgram(program);
} }
SharedPtr<ProgramObject> GLContext::GetCurrentProgram() { const SharedPtr<ProgramObject>& GLContext::GetCurrentProgram() {
return m_programState.GetCurrentProgram(); return m_programState.GetCurrentProgram();
} }
@@ -264,13 +261,13 @@ namespace MobileGL {
m_renderState.GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); m_renderState.GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
} }
void GLContext::SetBlendFuncIndexed(Uint index, BlendFactor srcRGB, BlendFactor dstRGB, void GLContext::SetBlendFuncIndexed(Uint index, BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha,
BlendFactor srcAlpha, BlendFactor dstAlpha) { BlendFactor dstAlpha) {
m_renderState.SetBlendFuncIndexed(index, srcRGB, dstRGB, srcAlpha, dstAlpha); m_renderState.SetBlendFuncIndexed(index, srcRGB, dstRGB, srcAlpha, dstAlpha);
} }
void GLContext::GetBlendFuncIndexed(Uint index, BlendFactor& srcRGB, BlendFactor& dstRGB, void GLContext::GetBlendFuncIndexed(Uint index, BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
BlendFactor& srcAlpha, BlendFactor& dstAlpha) const { BlendFactor& dstAlpha) const {
m_renderState.GetBlendFuncIndexed(index, srcRGB, dstRGB, srcAlpha, dstAlpha); m_renderState.GetBlendFuncIndexed(index, srcRGB, dstRGB, srcAlpha, dstAlpha);
} }
@@ -294,7 +291,7 @@ namespace MobileGL {
m_renderState.SetColorMask(mask); m_renderState.SetColorMask(mask);
} }
const BoolVec4 GLContext::GetColorMask() const { BoolVec4 GLContext::GetColorMask() const {
return m_renderState.GetColorMask(); return m_renderState.GetColorMask();
} }
@@ -318,7 +315,7 @@ namespace MobileGL {
m_renderState.SetClearStencil(stencil); m_renderState.SetClearStencil(stencil);
} }
Int GLContext::GetClearStencil() const { Uint32 GLContext::GetClearStencil() const {
return m_renderState.GetClearStencil(); return m_renderState.GetClearStencil();
} }
@@ -351,11 +348,11 @@ namespace MobileGL {
} }
// Framebuffer // Framebuffer
Vector<Uint> GLContext::GenFramebufferNames(Uint number) { void GLContext::GenFramebufferNames(Uint number, Vector<Uint>& framebuffers) {
return m_framebufferState.GenerateNames(number); m_framebufferState.GenerateNames(number, framebuffers);
} }
SharedPtr<FramebufferObject> GLContext::GetFramebufferObject(Uint index) { const SharedPtr<FramebufferObject>& GLContext::GetFramebufferObject(Uint index) {
return m_framebufferState.GetFramebufferObject(index); return m_framebufferState.GetFramebufferObject(index);
} }
@@ -363,7 +360,7 @@ namespace MobileGL {
return m_framebufferState.GetBindingSlot(target); return m_framebufferState.GetBindingSlot(target);
} }
SharedPtr<FramebufferObject> GLContext::CreateFramebufferObject(Uint index) { const SharedPtr<FramebufferObject>& GLContext::CreateFramebufferObject(Uint index) {
return m_framebufferState.CreateFramebufferObject(index); return m_framebufferState.CreateFramebufferObject(index);
} }
@@ -380,15 +377,15 @@ namespace MobileGL {
} }
// Sampler // Sampler
Vector<Uint> GLContext::GenSamplerNames(Uint number) { void GLContext::GenSamplerNames(Uint number, Vector<Uint>& samplers) {
return m_samplerState.GenerateNames(number); m_samplerState.GenerateNames(number, samplers);
} }
SharedPtr<SamplerObject> GLContext::GetSamplerObject(Uint index) { const SharedPtr<SamplerObject>& GLContext::GetSamplerObject(Uint index) {
return m_samplerState.GetSamplerObject(index); return m_samplerState.GetSamplerObject(index);
} }
SharedPtr<SamplerObject> GLContext::CreateSamplerObject(Uint index) { const SharedPtr<SamplerObject>& GLContext::CreateSamplerObject(Uint index) {
return m_samplerState.CreateSamplerObject(index); return m_samplerState.CreateSamplerObject(index);
} }
@@ -415,11 +412,11 @@ namespace MobileGL {
} }
// Renderbuffer // Renderbuffer
Vector<Uint> GLContext::GenRenderbufferNames(Uint number) { void GLContext::GenRenderbufferNames(Uint number, Vector<Uint>& renderbuffers) {
return m_renderbufferState.GenerateNames(number); m_renderbufferState.GenerateNames(number, renderbuffers);
} }
SharedPtr<RenderbufferObject> GLContext::GetRenderbufferObject(Uint index) { const SharedPtr<RenderbufferObject>& GLContext::GetRenderbufferObject(Uint index) {
return m_renderbufferState.GetRenderbufferObject(index); return m_renderbufferState.GetRenderbufferObject(index);
} }
@@ -427,7 +424,7 @@ namespace MobileGL {
return m_renderbufferState.GetBindingSlot(target); return m_renderbufferState.GetBindingSlot(target);
} }
SharedPtr<RenderbufferObject> GLContext::CreateRenderbufferObject(Uint index) { const SharedPtr<RenderbufferObject>& GLContext::CreateRenderbufferObject(Uint index) {
return m_renderbufferState.CreateRenderbufferObject(index); return m_renderbufferState.CreateRenderbufferObject(index);
} }
@@ -438,8 +435,11 @@ namespace MobileGL {
Bool GLContext::ValidateRenderbufferName(Uint index) const { Bool GLContext::ValidateRenderbufferName(Uint index) const {
return m_renderbufferState.ValidateName(index); return m_renderbufferState.ValidateName(index);
} }
Bool GLContext::ValidateRenderbufferObject(Uint index) const {
return m_renderbufferState.ValidateRenderbufferObject(index);
}
} // namespace GLState } // namespace GLState
GLState::GLContext* pGLContext; UniquePtr<GLState::GLContext> pGLContext;
} // namespace MG_State } // namespace MobileGL::MG_State
} // namespace MobileGL
+30 -30
View File
@@ -30,42 +30,42 @@ namespace MobileGL {
GLContext() = default; GLContext() = default;
// Error // Error
void RecordError(ErrorCode code, SharedPtr<ErrorInfo> info = nullptr); void RecordError(ErrorCode code, UniquePtr<ErrorInfo> info);
Bool HasGLError() const; Bool HasGLError() const;
Optional<const Error> PeekGLError() const; Optional<const Error*> PeekNonGLError() const;
Optional<Error> PopGLError(); Optional<UniquePtr<Error>> PopNonGLError();
Bool HasNonGLError() const; Bool HasNonGLError() const;
Optional<const Error> PeekNonGLError() const; Optional<const Error*> PeekGLError() const;
Optional<Error> PopNonGLError(); Optional<UniquePtr<Error>> PopGLError();
void ClearErrors(); void ClearErrors();
// Buffer // Buffer
Vector<Uint> GenBufferNames(Uint number); void GenBufferNames(Uint number, Vector<Uint>& buffers);
SharedPtr<BufferObject> GetBufferObject(Uint index); const SharedPtr<BufferObject>& GetBufferObject(Uint index);
BindingSlot<BufferObject>& GetBufferBindingSlot(BufferTarget target); BindingSlot<BufferObject>& GetBufferBindingSlot(BufferTarget target);
BindingSlotRange1D<BufferObject>& GetBufferBindingPoint(BufferTarget target, Uint index); BindingSlotRange1D<BufferObject>& GetBufferBindingPoint(BufferTarget target, Uint index);
constexpr SizeT GetBufferBindingPointCount(BufferTarget target) const { constexpr SizeT GetBufferBindingPointCount(BufferTarget target) const {
return m_bufferState.GetBindingPointCount(target); return m_bufferState.GetBindingPointCount(target);
} }
SharedPtr<BufferObject> CreateBufferObject(Uint index); const SharedPtr<BufferObject>& CreateBufferObject(Uint index);
void MarkBufferObjectForDeletion(Uint index); void MarkBufferObjectForDeletion(Uint index);
Bool ValidateBufferName(Uint index) const; Bool ValidateBufferName(Uint index) const;
Bool ValidateBufferObject(Uint index) const; Bool ValidateBufferObject(Uint index) const;
// VertexArray // VertexArray
Vector<Uint> GenVertexArrayNames(Uint number); void GenVertexArrayNames(Uint number, Vector<Uint>& vertexArrays);
SharedPtr<VertexArrayObject> GetVertexArrayObject(Uint index); const SharedPtr<VertexArrayObject>& GetVertexArrayObject(Uint index);
void BindVertexArray(Uint index); void BindVertexArray(Uint index);
SharedPtr<VertexArrayObject> CreateVertexArrayObject(Uint index); const SharedPtr<VertexArrayObject>& CreateVertexArrayObject(Uint index);
void MarkVertexArrayForDeletion(Uint index); void MarkVertexArrayForDeletion(Uint index);
Bool ValidateVertexArrayName(Uint index) const; Bool ValidateVertexArrayName(Uint index) const;
Bool ValidateVertexArrayObject(Uint index) const; Bool ValidateVertexArrayObject(Uint index) const;
SharedPtr<VertexArrayObject> GetBoundVertexArray(); const SharedPtr<VertexArrayObject>& GetBoundVertexArray();
// Texture // Texture
Vector<Uint> GenTextureNames(Uint number); void GenTextureNames(Uint number, Vector<Uint>& textures);
SharedPtr<ITextureObject> GetTextureObject(Uint index); const SharedPtr<ITextureObject>& GetTextureObject(Uint index);
SharedPtr<ITextureObject> CreateTextureObject(Uint index, TextureTarget target); const SharedPtr<ITextureObject>& CreateTextureObject(Uint index, TextureTarget target);
void MarkTextureObjectForDeletion(Uint index); void MarkTextureObjectForDeletion(Uint index);
TextureUnit& GetTextureUnitObject(Int unit); TextureUnit& GetTextureUnitObject(Int unit);
Bool ValidateTextureName(Uint index) const; Bool ValidateTextureName(Uint index) const;
@@ -80,10 +80,10 @@ namespace MobileGL {
void MarkShaderForDeletion(Uint index); void MarkShaderForDeletion(Uint index);
Bool ValidateProgramName(Uint index) const; Bool ValidateProgramName(Uint index) const;
Bool ValidateShaderName(Uint index) const; Bool ValidateShaderName(Uint index) const;
SharedPtr<ProgramObject> GetProgramObject(Uint index); const SharedPtr<ProgramObject>& GetProgramObject(Uint index);
SharedPtr<ShaderObject> GetShaderObject(Uint index); const SharedPtr<ShaderObject>& GetShaderObject(Uint index);
void UseProgram(Uint program); void UseProgram(Uint program);
SharedPtr<ProgramObject> GetCurrentProgram(); const SharedPtr<ProgramObject>& GetCurrentProgram();
// RenderState // RenderState
Uint GetRenderStateParametersVersion() const; Uint GetRenderStateParametersVersion() const;
@@ -106,13 +106,13 @@ namespace MobileGL {
void SetDepthMask(Bool flag); void SetDepthMask(Bool flag);
Bool GetDepthMask() const; Bool GetDepthMask() const;
void SetColorMask(BoolVec4 mask); void SetColorMask(BoolVec4 mask);
const BoolVec4 GetColorMask() const; BoolVec4 GetColorMask() const;
void SetClearColor(FloatVec4 color); void SetClearColor(FloatVec4 color);
const FloatVec4& GetClearColor() const; const FloatVec4& GetClearColor() const;
void SetClearDepth(Float depth); void SetClearDepth(Float depth);
Float GetClearDepth() const; Float GetClearDepth() const;
void SetClearStencil(Int stencil); void SetClearStencil(Int stencil);
Int GetClearStencil() const; Uint32 GetClearStencil() const;
void SetPixelStoreParam(PixelStoreParam param, Int value); void SetPixelStoreParam(PixelStoreParam param, Int value);
Int GetPixelStoreParam(PixelStoreParam param) const; Int GetPixelStoreParam(PixelStoreParam param) const;
PixelStoreParameters GetPixelStoreParameters(Bool isUnpack) const; PixelStoreParameters GetPixelStoreParameters(Bool isUnpack) const;
@@ -122,27 +122,27 @@ namespace MobileGL {
const IntVec4& GetScissorBox() const; // x, y, width, height const IntVec4& GetScissorBox() const; // x, y, width, height
// Framebuffer // Framebuffer
Vector<Uint> GenFramebufferNames(Uint number); void GenFramebufferNames(Uint number, Vector<Uint>& framebuffers);
SharedPtr<FramebufferObject> GetFramebufferObject(Uint index); const SharedPtr<FramebufferObject>& GetFramebufferObject(Uint index);
BindingSlot<FramebufferObject>& GetFramebufferBindingSlot(FramebufferTarget target); BindingSlot<FramebufferObject>& GetFramebufferBindingSlot(FramebufferTarget target);
SharedPtr<FramebufferObject> CreateFramebufferObject(Uint index); const SharedPtr<FramebufferObject>& CreateFramebufferObject(Uint index);
void MarkFramebufferObjectForDeletion(Uint index); void MarkFramebufferObjectForDeletion(Uint index);
Bool ValidateFramebufferName(Uint index) const; Bool ValidateFramebufferName(Uint index) const;
Bool ValidateFramebufferObject(Uint index) const; Bool ValidateFramebufferObject(Uint index) const;
// Sampler // Sampler
Vector<Uint> GenSamplerNames(Uint number); void GenSamplerNames(Uint number, Vector<Uint>& samplers);
SharedPtr<SamplerObject> GetSamplerObject(Uint index); const SharedPtr<SamplerObject>& GetSamplerObject(Uint index);
SharedPtr<SamplerObject> CreateSamplerObject(Uint index); const SharedPtr<SamplerObject>& CreateSamplerObject(Uint index);
void MarkSamplerObjectForDeletion(Uint index); void MarkSamplerObjectForDeletion(Uint index);
Bool ValidateSamplerName(Uint index) const; Bool ValidateSamplerName(Uint index) const;
Bool ValidateSamplerObject(Uint index) const; Bool ValidateSamplerObject(Uint index) const;
// Renderbuffer // Renderbuffer
Vector<Uint> GenRenderbufferNames(Uint number); void GenRenderbufferNames(Uint number, Vector<Uint>& renderbuffers);
SharedPtr<RenderbufferObject> GetRenderbufferObject(Uint index); const SharedPtr<RenderbufferObject>& GetRenderbufferObject(Uint index);
BindingSlot<RenderbufferObject>& GetRenderbufferBindingSlot(RenderbufferTarget target); BindingSlot<RenderbufferObject>& GetRenderbufferBindingSlot(RenderbufferTarget target);
SharedPtr<RenderbufferObject> CreateRenderbufferObject(Uint index); const SharedPtr<RenderbufferObject>& CreateRenderbufferObject(Uint index);
void MarkRenderbufferObjectForDeletion(Uint index); void MarkRenderbufferObjectForDeletion(Uint index);
Bool ValidateRenderbufferName(Uint index) const; Bool ValidateRenderbufferName(Uint index) const;
Bool ValidateRenderbufferObject(Uint index) const; Bool ValidateRenderbufferObject(Uint index) const;
@@ -161,6 +161,6 @@ namespace MobileGL {
}; };
} // namespace GLState } // namespace GLState
extern GLState::GLContext* pGLContext; extern UniquePtr<GLState::GLContext> pGLContext;
} // namespace MG_State } // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
+19 -23
View File
@@ -10,18 +10,16 @@
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h> #include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/MGToGL/ErrorCodeConverter.h> #include <MG_Util/Converters/MGToGL/ErrorCodeConverter.h>
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State { void ErrorState::RecordError(ErrorCode code, UniquePtr<ErrorInfo> info) {
namespace GLState {
void ErrorState::RecordError(ErrorCode code, SharedPtr<ErrorInfo> info) {
if (code == ErrorCode::NoError) { if (code == ErrorCode::NoError) {
MGLOG_E("Recording Non-OpenGL error:\n%s", info->ToString().c_str()); MGLOG_E("Recording Non-OpenGL error:\n%s", info->toString().c_str());
m_nonGLErrors.push_back(Error{code, info}); m_nonGLErrors.push_back(MakeUnique<Error>(code, Move(info)));
} else { } else {
MGLOG_E("Recording OpenGL error (%s):\n%s", MGLOG_E("Recording OpenGL error (%s):\n%s",
MG_Util::ConvertGLEnumToString(MG_Util::ConvertErrorCodeToGLEnum(code)).c_str(), MG_Util::ConvertGLEnumToString(MG_Util::ConvertErrorCodeToGLEnum(code)).c_str(),
info->ToString().c_str()); info->toString().c_str());
m_errors.push_back(Error{code, info}); m_errors.push_back(MakeUnique<Error>(code, Move(info)));
} }
} }
@@ -29,38 +27,36 @@ namespace MobileGL {
return !m_nonGLErrors.empty(); return !m_nonGLErrors.empty();
} }
Optional<const Error> ErrorState::PeekNonGLError() const { Optional<const Error*> ErrorState::PeekNonGLError() const {
if (m_nonGLErrors.empty()) return Optional<const Error>{}; if (m_nonGLErrors.empty()) return Nullopt;
return Optional<const Error>{m_nonGLErrors.front()}; return Optional<const Error*>{m_nonGLErrors.front().get()};
} }
Optional<Error> ErrorState::PopNonGLError() { Optional<UniquePtr<Error>> ErrorState::PopNonGLError() {
if (m_nonGLErrors.empty()) return Optional<const Error>{}; if (m_nonGLErrors.empty()) return Nullopt;
auto error = Move(m_nonGLErrors.front()); auto error = Move(m_nonGLErrors.front());
m_nonGLErrors.erase(m_nonGLErrors.begin()); m_nonGLErrors.erase(m_nonGLErrors.begin());
return Optional<const Error>{error}; return Move(error);
} }
Bool ErrorState::HasGLError() const { Bool ErrorState::HasGLError() const {
return !m_errors.empty(); return !m_errors.empty();
} }
Optional<const Error> ErrorState::PeekGLError() const { Optional<const Error*> ErrorState::PeekGLError() const {
if (m_errors.empty()) return Optional<const Error>{}; if (m_errors.empty()) return Optional<const Error*>{};
return Optional<const Error>{m_errors.front()}; return Optional<const Error*>{m_errors.front().get()};
} }
Optional<Error> ErrorState::PopGLError() { Optional<UniquePtr<Error>> ErrorState::PopGLError() {
if (m_errors.empty()) return Optional<const Error>{}; if (m_errors.empty()) return Nullopt;
auto error = Move(m_errors.front()); auto error = Move(m_errors.front());
m_errors.erase(m_errors.begin()); m_errors.erase(m_errors.begin());
return Optional<const Error>{error}; return Move(error);
} }
void ErrorState::Clear() { void ErrorState::Clear() {
m_errors.clear(); m_errors.clear();
m_nonGLErrors.clear(); m_nonGLErrors.clear();
} }
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
+10 -12
View File
@@ -14,26 +14,24 @@
namespace MobileGL { namespace MobileGL {
struct Error { struct Error {
ErrorCode code; ErrorCode code;
SharedPtr<ErrorInfo> info; UniquePtr<ErrorInfo> info;
}; };
namespace MG_State { namespace MG_State::GLState {
namespace GLState {
class ErrorState { class ErrorState {
public: public:
void RecordError(ErrorCode code, SharedPtr<ErrorInfo> info = nullptr); void RecordError(ErrorCode code, UniquePtr<ErrorInfo> info);
Bool HasNonGLError() const; Bool HasNonGLError() const;
Optional<const Error> PeekNonGLError() const; Optional<const Error*> PeekNonGLError() const;
Optional<Error> PopNonGLError(); Optional<UniquePtr<Error>> PopNonGLError();
Bool HasGLError() const; Bool HasGLError() const;
Optional<const Error> PeekGLError() const; Optional<const Error*> PeekGLError() const;
Optional<Error> PopGLError(); Optional<UniquePtr<Error>> PopGLError();
void Clear(); void Clear();
private: private:
Vector<Error> m_errors; Vector<UniquePtr<Error>> m_errors;
Vector<Error> m_nonGLErrors; Vector<UniquePtr<Error>> m_nonGLErrors;
}; };
} // namespace GLState } // namespace MG_State::GLState
} // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -13,7 +13,7 @@ namespace MobileGL {
class ErrorInfo { class ErrorInfo {
public: public:
virtual ~ErrorInfo() = default; virtual ~ErrorInfo() = default;
virtual String ToString() const = 0; virtual String toString() const = 0;
}; };
class GenericErrorInfo : public ErrorInfo { class GenericErrorInfo : public ErrorInfo {
@@ -24,7 +24,7 @@ namespace MobileGL {
explicit GenericErrorInfo(String m_prefix, String m_prefix_2, String message) explicit GenericErrorInfo(String m_prefix, String m_prefix_2, String message)
: m_message(Move(message)), m_prefix(Move(m_prefix)), m_prefix_2(Move(m_prefix_2)) {} : m_message(Move(message)), m_prefix(Move(m_prefix)), m_prefix_2(Move(m_prefix_2)) {}
String ToString() const override { String toString() const override {
StringStream ss; StringStream ss;
if (m_prefix.has_value()) { if (m_prefix.has_value()) {
ss << "[" << m_prefix.value() << "] "; ss << "[" << m_prefix.value() << "] ";
@@ -9,14 +9,12 @@
#include "FramebufferObject.h" #include "FramebufferObject.h"
#include "MG_Util/Types.h" #include "MG_Util/Types.h"
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State {
namespace GLState {
// FramebufferAttachmentObject // FramebufferAttachmentObject
FramebufferAttachmentObject::FramebufferAttachmentObject( FramebufferAttachmentObject::FramebufferAttachmentObject(
SharedPtr<MG_State::GLState::ITextureObject> texture, Int level) const SharedPtr<MG_State::GLState::ITextureObject>& texture, Int level)
: m_texture(texture), m_textureLevel(level) {} : m_texture(texture), m_textureLevel(level) {}
FramebufferAttachmentObject::FramebufferAttachmentObject(SharedPtr<RenderbufferObject> renderbuffer) FramebufferAttachmentObject::FramebufferAttachmentObject(const SharedPtr<RenderbufferObject>& renderbuffer)
: m_renderbuffer(renderbuffer) {} : m_renderbuffer(renderbuffer) {}
FramebufferAttachmentObject::FramebufferAttachmentObject(Bool IsValid) FramebufferAttachmentObject::FramebufferAttachmentObject(Bool IsValid)
: m_texture(nullptr), m_renderbuffer(nullptr) { : m_texture(nullptr), m_renderbuffer(nullptr) {
@@ -35,11 +33,11 @@ namespace MobileGL {
return m_texture == nullptr && m_renderbuffer == nullptr; return m_texture == nullptr && m_renderbuffer == nullptr;
} }
SharedPtr<MG_State::GLState::ITextureObject> FramebufferAttachmentObject::GetTexture() const { const SharedPtr<MG_State::GLState::ITextureObject>& FramebufferAttachmentObject::GetTexture() const {
return m_texture; return m_texture;
} }
SharedPtr<RenderbufferObject> FramebufferAttachmentObject::GetRenderbuffer() const { const SharedPtr<RenderbufferObject>& FramebufferAttachmentObject::GetRenderbuffer() const {
return m_renderbuffer; return m_renderbuffer;
} }
@@ -62,12 +60,12 @@ namespace MobileGL {
IntVec3 FramebufferAttachmentObject::GetSize() const { IntVec3 FramebufferAttachmentObject::GetSize() const {
if (IsTexture()) { if (IsTexture()) {
// TODO: get correct upload target // TODO: get correct upload target
MOBILEGL_ASSERT(nullptr != dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(m_texture.get()), MOBILEGL_ASSERT(nullptr != static_cast<MG_State::GLState::TextureObjectMipmap*>(m_texture.get()),
"Texture object here should always be an object with mipmap"); "Texture object here should always be an object with mipmap");
auto textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(m_texture.get()); auto textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(m_texture.get());
return textureMipmapObject->GetMipmapTexelSize(TextureUploadTarget::Texture2D, m_textureLevel); return textureMipmapObject->GetMipmapTexelSize(TextureUploadTarget::Texture2D, m_textureLevel);
} else if (IsRenderbuffer()) { } else if (IsRenderbuffer()) {
return IntVec3(m_renderbuffer->GetWidth(), m_renderbuffer->GetHeight(), 1); return {m_renderbuffer->GetWidth(), m_renderbuffer->GetHeight(), 1};
} }
return {0, 0, 0}; return {0, 0, 0};
} }
@@ -77,21 +75,22 @@ namespace MobileGL {
} }
// FramebufferObject // FramebufferObject
FramebufferObject::FramebufferObject(Uint externalIndex) : m_externalIndex(externalIndex) { FramebufferObject::FramebufferObject(Uint externalIndex)
: m_externalIndex(externalIndex), m_attachmentVersions{}, m_drawBuffers{} {
m_attachmentObjects.fill(FramebufferAttachmentObject(false)); m_attachmentObjects.fill(FramebufferAttachmentObject(false));
m_drawBuffers.fill(FramebufferAttachmentType::None); m_drawBuffers.fill(FramebufferAttachmentType::None);
m_drawBuffers[0] = FramebufferAttachmentType::Color0; m_drawBuffers[0] = FramebufferAttachmentType::Color0;
m_attachmentVersions.fill(0); m_attachmentVersions.fill(0);
} }
void FramebufferObject::AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture, void FramebufferObject::AttachTexture(FramebufferAttachmentType type, const SharedPtr<ITextureObject>& texture,
int level) { int level) {
m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(std::move(texture), level); m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(texture, level);
BumpAttachmentVersion(type); BumpAttachmentVersion(type);
} }
void FramebufferObject::AttachRenderbuffer(FramebufferAttachmentType type, void FramebufferObject::AttachRenderbuffer(FramebufferAttachmentType type,
std::shared_ptr<RenderbufferObject> renderbuffer) { const SharedPtr<RenderbufferObject>& renderbuffer) {
m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(renderbuffer); m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(renderbuffer);
BumpAttachmentVersion(type); BumpAttachmentVersion(type);
} }
@@ -105,8 +104,7 @@ namespace MobileGL {
return m_attachmentObjects[static_cast<SizeT>(type)]; return m_attachmentObjects[static_cast<SizeT>(type)];
} }
const FramebufferObject::FramebufferAttachmentObjectArray& FramebufferObject::GetAllAttachmentObjects() const FramebufferObject::FramebufferAttachmentObjectArray& FramebufferObject::GetAllAttachmentObjects() const {
const {
return m_attachmentObjects; return m_attachmentObjects;
} }
@@ -117,11 +115,11 @@ namespace MobileGL {
Int width = -1, height = -1; Int width = -1, height = -1;
Int validAttachmentCount = 0; Int validAttachmentCount = 0;
for (SizeT i = 0; i < m_attachmentObjects.size(); ++i) { for (const auto& attachmentObject : m_attachmentObjects) {
if (!m_attachmentObjects[i].IsValid()) continue; if (!attachmentObject.IsValid()) continue;
++validAttachmentCount; ++validAttachmentCount;
const auto& attachment = m_attachmentObjects[i]; const auto& attachment = attachmentObject;
auto attachmentSize = attachment.GetSize(); auto attachmentSize = attachment.GetSize();
Int w = attachmentSize.x(); Int w = attachmentSize.x();
Int h = attachmentSize.y(); Int h = attachmentSize.y();
@@ -160,6 +158,4 @@ namespace MobileGL {
++m_attachmentVersions[static_cast<SizeT>(type)]; ++m_attachmentVersions[static_cast<SizeT>(type)];
++m_objectVersion; ++m_objectVersion;
} }
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -7,6 +7,7 @@
// End of Source File Header // End of Source File Header
#pragma once #pragma once
#include "MG_Util/Types.h"
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/TextureState/TextureObject.h> #include <MG_State/GLState/TextureState/TextureObject.h>
#include <MG_State/GLState/RenderbufferState/RenderbufferObject.h> #include <MG_State/GLState/RenderbufferState/RenderbufferObject.h>
@@ -62,25 +63,25 @@ namespace MobileGL {
Color29, Color29,
Color30, Color30,
Color31, Color31,
ColorMax = Color31,
FramebufferAttachmentTypeCount, FramebufferAttachmentTypeCount,
Unknown = -1 Unknown = -1
}; };
namespace MG_State { namespace MG_State::GLState {
namespace GLState {
class FramebufferAttachmentObject { class FramebufferAttachmentObject {
public: public:
explicit FramebufferAttachmentObject(SharedPtr<MG_State::GLState::ITextureObject> texture, explicit FramebufferAttachmentObject(const SharedPtr<MG_State::GLState::ITextureObject>& texture,
Int level = 0); Int level = 0);
explicit FramebufferAttachmentObject(SharedPtr<RenderbufferObject> renderbuffer); explicit FramebufferAttachmentObject(const SharedPtr<RenderbufferObject>& renderbuffer);
explicit FramebufferAttachmentObject(Bool IsValid = true); explicit FramebufferAttachmentObject(Bool IsValid = true);
Bool IsTexture() const; Bool IsTexture() const;
Bool IsRenderbuffer() const; Bool IsRenderbuffer() const;
Bool IsEmpty() const; Bool IsEmpty() const;
SharedPtr<MG_State::GLState::ITextureObject> GetTexture() const; const SharedPtr<MG_State::GLState::ITextureObject>& GetTexture() const;
SharedPtr<RenderbufferObject> GetRenderbuffer() const; const SharedPtr<RenderbufferObject>& GetRenderbuffer() const;
Int GetTextureLevel() const; Int GetTextureLevel() const;
Bool IsComplete() const; Bool IsComplete() const;
IntVec3 GetSize() const; IntVec3 GetSize() const;
@@ -107,9 +108,8 @@ namespace MobileGL {
FramebufferObject(Uint externalIndex); FramebufferObject(Uint externalIndex);
void AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture, int level = 0); void AttachTexture(FramebufferAttachmentType type, const SharedPtr<ITextureObject>& texture, int level = 0);
void AttachRenderbuffer(FramebufferAttachmentType type, void AttachRenderbuffer(FramebufferAttachmentType type, const SharedPtr<RenderbufferObject>& renderbuffer);
std::shared_ptr<RenderbufferObject> renderbuffer);
void Detach(FramebufferAttachmentType type); void Detach(FramebufferAttachmentType type);
const FramebufferAttachmentObject& GetAttachment(FramebufferAttachmentType type) const; const FramebufferAttachmentObject& GetAttachment(FramebufferAttachmentType type) const;
const FramebufferAttachmentObjectArray& GetAllAttachmentObjects() const; const FramebufferAttachmentObjectArray& GetAllAttachmentObjects() const;
@@ -120,7 +120,7 @@ namespace MobileGL {
void SetReadBuffer(FramebufferAttachmentType buf) { m_readBuffer = buf; } void SetReadBuffer(FramebufferAttachmentType buf) { m_readBuffer = buf; }
FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; } FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; }
const FramebufferAttachmentVersionArray GetAllFramebufferAttachmentVersions() const { FramebufferAttachmentVersionArray GetAllFramebufferAttachmentVersions() const {
return m_attachmentVersions; return m_attachmentVersions;
} }
@@ -142,6 +142,5 @@ namespace MobileGL {
Uint16 m_objectVersion = 0; Uint16 m_objectVersion = 0;
}; };
} // namespace GLState } // namespace MG_State::GLState
} // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -9,46 +9,47 @@
#include "FramebufferState.h" #include "FramebufferState.h"
#include "MG_State/GLState/FramebufferState/FramebufferObject.h" #include "MG_State/GLState/FramebufferState/FramebufferObject.h"
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State {
namespace GLState {
FramebufferState::FramebufferState() { FramebufferState::FramebufferState() {
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) { for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
m_bindingSlots[i] = BindingSlot<FramebufferObject>(static_cast<FramebufferTarget>(i)); m_bindingSlots[i] = BindingSlot<FramebufferObject>(static_cast<FramebufferTarget>(i));
} }
} }
SharedPtr<FramebufferObject> FramebufferState::GetFramebufferObject(Uint index) { const SharedPtr<FramebufferObject>& FramebufferState::GetFramebufferObject(Uint index) {
auto it = m_framebufferObjects.find(index); auto it = m_framebufferObjects.find(index);
if (it != m_framebufferObjects.end()) { if (it != m_framebufferObjects.end()) {
return it->second; return it->second;
} }
return nullptr; static SharedPtr<FramebufferObject> nullFramebufferObject = nullptr;
return nullFramebufferObject;
} }
Vector<Uint> FramebufferState::GenerateNames(Uint number) { void FramebufferState::GenerateNames(Uint number, Vector<Uint>& buffers) {
Vector<Uint> buffers(number); buffers.resize(number);
m_indexGenerator.Generate(number, buffers.data()); m_indexGenerator.Generate(number, buffers.data());
return buffers;
} }
SharedPtr<FramebufferObject> FramebufferState::CreateFramebufferObject(Uint index) { const SharedPtr<FramebufferObject>& FramebufferState::CreateFramebufferObject(Uint index) {
if (index == 0) { if (index == 0) {
if (!m_indexGenerator.IsValid(0)) { if (!m_indexGenerator.IsValid(0)) {
m_indexGenerator.Insert(0); m_indexGenerator.Insert(0);
} else { } else {
return nullptr; static SharedPtr<FramebufferObject> nullFramebufferObject = nullptr;
return nullFramebufferObject;
} }
} }
auto bufferObject = MakeShared<FramebufferObject>(index); auto& framebufferObject = m_framebufferObjects[index];
m_framebufferObjects[index] = bufferObject; if (!framebufferObject) {
return bufferObject; framebufferObject = MakeShared<FramebufferObject>(index);
}
return framebufferObject;
} }
BindingSlot<FramebufferObject>& FramebufferState::GetBindingSlot(FramebufferTarget target) { BindingSlot<FramebufferObject>& FramebufferState::GetBindingSlot(FramebufferTarget target) {
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) { for (auto& bindingSlot : m_bindingSlots) {
if (m_bindingSlots[i].GetTarget() == target) { if (bindingSlot.GetTarget() == target) {
return m_bindingSlots[i]; return bindingSlot;
} }
} }
MOBILEGL_ASSERT(false, "Invalid FramebufferTarget enum value: %d", static_cast<int>(target)); MOBILEGL_ASSERT(false, "Invalid FramebufferTarget enum value: %d", static_cast<int>(target));
@@ -59,9 +60,9 @@ namespace MobileGL {
if (m_indexGenerator.IsValid(index)) { if (m_indexGenerator.IsValid(index)) {
auto it = m_framebufferObjects.find(index); auto it = m_framebufferObjects.find(index);
if (it != m_framebufferObjects.end()) { if (it != m_framebufferObjects.end()) {
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) { for (auto& bindingSlot : m_bindingSlots) {
if (m_bindingSlots[i].GetBoundObject() == it->second) { if (bindingSlot.GetBoundObject() == it->second) {
m_bindingSlots[i].Bind(nullptr); bindingSlot.Bind(nullptr);
} }
} }
m_framebufferObjects.erase(it); m_framebufferObjects.erase(it);
@@ -77,6 +78,4 @@ namespace MobileGL {
Bool FramebufferState::ValidateFramebufferObject(Uint index) const { Bool FramebufferState::ValidateFramebufferObject(Uint index) const {
return m_framebufferObjects.find(index) != m_framebufferObjects.end(); return m_framebufferObjects.find(index) != m_framebufferObjects.end();
} }
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -11,17 +11,15 @@
#include <MG_Util/Miscellany/IndexGenerator.h> #include <MG_Util/Miscellany/IndexGenerator.h>
#include "FramebufferObject.h" #include "FramebufferObject.h"
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State {
namespace GLState {
class FramebufferState { class FramebufferState {
public: public:
FramebufferState(); FramebufferState();
// FBO 0 should be created by MG_Backend when initializing the context // FBO 0 should be created by MG_Backend when initializing the context
SharedPtr<FramebufferObject> GetFramebufferObject(Uint index); const SharedPtr<FramebufferObject>& GetFramebufferObject(Uint index);
Vector<Uint> GenerateNames(Uint number); void GenerateNames(Uint number, Vector<Uint>& framebuffers);
SharedPtr<FramebufferObject> CreateFramebufferObject(Uint index); const SharedPtr<FramebufferObject>& CreateFramebufferObject(Uint index);
BindingSlot<FramebufferObject>& GetBindingSlot(FramebufferTarget target); BindingSlot<FramebufferObject>& GetBindingSlot(FramebufferTarget target);
void MarkFramebufferObjectForDeletion(Uint index); void MarkFramebufferObjectForDeletion(Uint index);
Bool ValidateName(Uint index) const; Bool ValidateName(Uint index) const;
@@ -33,6 +31,4 @@ namespace MobileGL {
Array<BindingSlot<FramebufferObject>, static_cast<SizeT>(FramebufferTarget::FramebufferTargetCount)> Array<BindingSlot<FramebufferObject>, static_cast<SizeT>(FramebufferTarget::FramebufferTargetCount)>
m_bindingSlots; m_bindingSlots;
}; };
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -7,8 +7,8 @@
// End of Source File Header // End of Source File Header
#include "ProgramObject.h" #include "ProgramObject.h"
#include "MG_Util/Converters/GLToStr/GLEnumConverter.h" #include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include "MG_Util/ShaderTranspiler/Types.h" #include <MG_Util/ShaderTranspiler/Types.h>
#include <MG_Util/ShaderTranspiler/ShaderCompiler.h> #include <MG_Util/ShaderTranspiler/ShaderCompiler.h>
#include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h> #include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h>
#include <MG_Util/Converters/SPIRVCrossToGL/SpvcTypeConverter.h> #include <MG_Util/Converters/SPIRVCrossToGL/SpvcTypeConverter.h>
@@ -18,10 +18,8 @@ layout(location = 0) out vec4 FragColor;
void main() {} void main() {}
)"; )";
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State { bool ProgramObject::ShaderIsAttached(const SharedPtr<ShaderObject>& shader) {
namespace GLState {
bool ProgramObject::ShaderIsAttached(SharedPtr<ShaderObject> shader) {
MGLOG_D("ProgramObject %u: ShaderIsAttached check for shader %p", m_externalIndex, shader.get()); MGLOG_D("ProgramObject %u: ShaderIsAttached check for shader %p", m_externalIndex, shader.get());
auto it = std::find_if(m_shaders.begin(), m_shaders.end(), auto it = std::find_if(m_shaders.begin(), m_shaders.end(),
[shader](const SharedPtr<ShaderObject>& s) { return s.get() == shader.get(); }); [shader](const SharedPtr<ShaderObject>& s) { return s.get() == shader.get(); });
@@ -30,23 +28,22 @@ namespace MobileGL {
return attached; return attached;
} }
bool ProgramObject::AttachShader(SharedPtr<ShaderObject> shader) { bool ProgramObject::AttachShader(const SharedPtr<ShaderObject>& shader) {
MGLOG_D("ProgramObject %u: AttachShader called for shader %p", m_externalIndex, shader.get()); MGLOG_D("ProgramObject %u: AttachShader called for shader %p", m_externalIndex, shader.get());
if (ShaderIsAttached(shader)) { if (ShaderIsAttached(shader)) {
MGLOG_D("ProgramObject %u: AttachShader - shader already attached, skipping", m_externalIndex); MGLOG_D("ProgramObject %u: AttachShader - shader already attached, skipping", m_externalIndex);
return false; return false;
} }
m_shaders.emplace_back(shader); m_shaders.emplace_back(shader);
MGLOG_D("ProgramObject %u: AttachShader - attached successfully, total shaders now %zu", MGLOG_D("ProgramObject %u: AttachShader - attached successfully, total shaders now %zu", m_externalIndex,
m_externalIndex, m_shaders.size()); m_shaders.size());
return true; return true;
} }
SizeT ProgramObject::DetachShader(SharedPtr<ShaderObject> shader) { SizeT ProgramObject::DetachShader(const SharedPtr<ShaderObject>& shader) {
MGLOG_D("DetachShader called for shader %p from ProgramObject %u", shader.get(), m_externalIndex); MGLOG_D("DetachShader called for shader %p from ProgramObject %u", shader.get(), m_externalIndex);
if (!ShaderIsAttached(shader)) { if (!ShaderIsAttached(shader)) {
MGLOG_D("Shader %p is not attached to ProgramObject %u, cannot detach.", shader.get(), MGLOG_D("Shader %p is not attached to ProgramObject %u, cannot detach.", shader.get(), m_externalIndex);
m_externalIndex);
return 0; return 0;
} }
m_detachedShaders.push_back(shader); m_detachedShaders.push_back(shader);
@@ -54,10 +51,10 @@ namespace MobileGL {
return 1; return 1;
} }
SizeT ProgramObject::RemoveShader(SharedPtr<ShaderObject> shader) { SizeT ProgramObject::RemoveShader(const SharedPtr<ShaderObject>& shader) {
MGLOG_D("ProgramObject %u: RemoveShader called for shader %p", m_externalIndex, shader.get()); MGLOG_D("ProgramObject %u: RemoveShader called for shader %p", m_externalIndex, shader.get());
auto count = std::erase_if( auto count =
m_shaders, [shader](const SharedPtr<ShaderObject>& s) { return s.get() == shader.get(); }); std::erase_if(m_shaders, [shader](const SharedPtr<ShaderObject>& s) { return s.get() == shader.get(); });
MGLOG_D("ProgramObject %u: RemoveShader - removed %zu shader(s), remaining %zu", m_externalIndex, count, MGLOG_D("ProgramObject %u: RemoveShader - removed %zu shader(s), remaining %zu", m_externalIndex, count,
m_shaders.size()); m_shaders.size());
@@ -80,15 +77,14 @@ namespace MobileGL {
if (!needsDefaultFS) return; if (!needsDefaultFS) return;
MGLOG_D("ProgramObject %u: No fragment shader attached, adding default fragment shader.", MGLOG_D("ProgramObject %u: No fragment shader attached, adding default fragment shader.", m_externalIndex);
m_externalIndex);
SharedPtr<ShaderObject> defaultFS = MakeShared<ShaderObject>(ShaderStage::Fragment, 0); SharedPtr<ShaderObject> defaultFS = MakeShared<ShaderObject>(ShaderStage::Fragment, 0);
defaultFS->SetShaderSource(kDefaultFragmentShaderSource); defaultFS->SetShaderSource(kDefaultFragmentShaderSource);
defaultFS->Compile(); // TODO: use a global default FS object. defaultFS->Compile(); // TODO: use a global default FS object.
auto status = defaultFS->GetCompileStatus(); auto status = defaultFS->GetCompileStatus();
if (!status) { if (!status) {
MGLOG_E("ProgramObject %u: Failed to compile default fragment shader. InfoLog:\n%s", MGLOG_E("ProgramObject %u: Failed to compile default fragment shader. InfoLog:\n%s", m_externalIndex,
m_externalIndex, defaultFS->GetInfoLog().c_str()); defaultFS->GetInfoLog().c_str());
return; return;
} }
m_shaders.push_back(defaultFS); m_shaders.push_back(defaultFS);
@@ -111,7 +107,7 @@ namespace MobileGL {
} }
std::sort(m_shaders.begin(), m_shaders.end(), std::sort(m_shaders.begin(), m_shaders.end(),
[](SharedPtr<ShaderObject>& a, SharedPtr<ShaderObject>& b) { [](const SharedPtr<ShaderObject>& a, const SharedPtr<ShaderObject>& b) {
return a->GetShaderStage() < b->GetShaderStage(); return a->GetShaderStage() < b->GetShaderStage();
}); });
@@ -121,11 +117,10 @@ namespace MobileGL {
MG_Util::ConvertGLEnumToString(shaderTypes[i]).c_str(), m_shaders[i].get()); MG_Util::ConvertGLEnumToString(shaderTypes[i]).c_str(), m_shaders[i].get());
if (!m_shaders[i]->GetCompileStatus()) { if (!m_shaders[i]->GetCompileStatus()) {
m_infoLog = m_infoLog = std::format("Linking a {} with compilation error, linking will now terminate. Shader error "
std::format("Linking a {} with compilation error, linking will now terminate. Shader error "
"log:\n{}\nShader src:\n{}", "log:\n{}\nShader src:\n{}",
MG_Util::ConvertGLEnumToString(shaderTypes[i]).c_str(), MG_Util::ConvertGLEnumToString(shaderTypes[i]), m_shaders[i]->GetInfoLog(),
m_shaders[i]->GetInfoLog().c_str(), m_shaders[i]->GetShaderSource().c_str()); m_shaders[i]->GetShaderSource());
m_linkStatus = false; m_linkStatus = false;
MGLOG_E("ProgramObject %u: Link failed - shader[%zu] compile status false. InfoLog:\n%s", MGLOG_E("ProgramObject %u: Link failed - shader[%zu] compile status false. InfoLog:\n%s",
m_externalIndex, i, m_infoLog.c_str()); m_externalIndex, i, m_infoLog.c_str());
@@ -140,16 +135,14 @@ namespace MobileGL {
MG_Util::ShaderTranspiler::ProgramAttrib attrib{.shaders = Move(shaders), MG_Util::ShaderTranspiler::ProgramAttrib attrib{.shaders = Move(shaders),
.explicitVertexInLocations = m_explicitAttribLocations, .explicitVertexInLocations = m_explicitAttribLocations,
.explicitFragmentOutLocations = .explicitFragmentOutLocations = m_explicitFragDataLocation};
m_explicitFragDataLocation};
MGLOG_D("ProgramObject %u: Calling ShaderCompiler::LinkProgram", m_externalIndex); MGLOG_D("ProgramObject %u: Calling ShaderCompiler::LinkProgram", m_externalIndex);
auto result = MG_Util::ShaderTranspiler::ShaderCompiler::LinkProgram(attrib); auto result = MG_Util::ShaderTranspiler::ShaderCompiler::LinkProgram(attrib);
if (result) { if (result) {
m_linkStatus = true; m_linkStatus = true;
m_program = result.value(); m_program = result.value();
MGLOG_D("ProgramObject %u: LinkProgram succeeded, TProgram ptr %p", m_externalIndex, MGLOG_D("ProgramObject %u: LinkProgram succeeded, TProgram ptr %p", m_externalIndex, m_program.get());
m_program.get());
} else { } else {
m_linkStatus = false; m_linkStatus = false;
m_infoLog = result.error().log; m_infoLog = result.error().log;
@@ -202,8 +195,7 @@ namespace MobileGL {
// ------------ Uniforms (GL Plain) ---------------- // ------------ Uniforms (GL Plain) ----------------
// Allocate uniform locations // Allocate uniform locations
m_activeUniformCount = m_program->getNumUniformVariables(); m_activeUniformCount = m_program->getNumUniformVariables();
MGLOG_D("ProgramObject %u: Reflection - active uniform count = %d", m_externalIndex, MGLOG_D("ProgramObject %u: Reflection - active uniform count = %d", m_externalIndex, m_activeUniformCount);
m_activeUniformCount);
for (int i = 0; i < m_activeUniformCount; i++) { for (int i = 0; i < m_activeUniformCount; i++) {
auto& uniform = m_program->getUniform(i); auto& uniform = m_program->getUniform(i);
auto location = uniform.layoutLocation(); auto location = uniform.layoutLocation();
@@ -212,8 +204,8 @@ namespace MobileGL {
} }
m_uniformNameMaxLength = std::max(m_uniformNameMaxLength, (Int)uniform.name.length()); m_uniformNameMaxLength = std::max(m_uniformNameMaxLength, (Int)uniform.name.length());
m_uniformLocations[uniform.name] = location; m_uniformLocations[uniform.name] = location;
MGLOG_D("ProgramObject %u: Reflection - uniform[%d] name='%s' layoutLocation=%d", m_externalIndex, MGLOG_D("ProgramObject %u: Reflection - uniform[%d] name='%s' layoutLocation=%d", m_externalIndex, i,
i, uniform.name.c_str(), location); uniform.name.c_str(), location);
} }
MGLOG_D("ProgramObject %u: Reflection - computed m_maxUniformLocation=%u m_uniformNameMaxLength=%d", MGLOG_D("ProgramObject %u: Reflection - computed m_maxUniformLocation=%u m_uniformNameMaxLength=%d",
@@ -266,12 +258,12 @@ namespace MobileGL {
} }
// ------------ 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);
int maxLoc = -1; Int maxLoc = -1;
for (int i = 0; i < inCount; ++i) { for (int i = 0; i < inCount; ++i) {
int loc = m_program->getPipeInput(i).layoutLocation(); Int loc = (Int)m_program->getPipeInput(i).layoutLocation();
if (loc >= 0 && loc != glslang::TQualifier::layoutLocationEnd) maxLoc = std::max(maxLoc, loc); if (loc >= 0 && loc != glslang::TQualifier::layoutLocationEnd) maxLoc = std::max(maxLoc, loc);
MGLOG_D("ProgramObject %u: Reflection - pipe input[%d] name='%s' layoutLocation=%d glType=%u", MGLOG_D("ProgramObject %u: Reflection - pipe input[%d] name='%s' layoutLocation=%d glType=%u",
m_externalIndex, i, m_program->getPipeInput(i).name.c_str(), loc, m_externalIndex, i, m_program->getPipeInput(i).name.c_str(), loc,
@@ -283,8 +275,8 @@ namespace MobileGL {
} }
GLint maxAttribs = 16; // TODO: get from backend GLint maxAttribs = 16; // TODO: get from backend
MGLOG_D("ProgramObject %u: Reflection - computed maxLoc=%d, using maxAttribs=%d", m_externalIndex, MGLOG_D("ProgramObject %u: Reflection - computed maxLoc=%d, using maxAttribs=%d", m_externalIndex, maxLoc,
maxLoc, maxAttribs); maxAttribs);
if (maxLoc >= maxAttribs) { if (maxLoc >= maxAttribs) {
MGLOG_W("ProgramObject %u: ProgramObject::DoReflection - required attrib location %d >= " MGLOG_W("ProgramObject %u: ProgramObject::DoReflection - required attrib location %d >= "
@@ -298,14 +290,14 @@ namespace MobileGL {
for (int i = 0; i < inCount; ++i) { for (int i = 0; i < inCount; ++i) {
auto& inVar = m_program->getPipeInput(i); auto& inVar = m_program->getPipeInput(i);
int location = inVar.layoutLocation(); Int location = (Int)inVar.layoutLocation();
m_attribInNameMaxLength = std::max(m_attribInNameMaxLength, (Int)inVar.name.length()); m_attribInNameMaxLength = std::max(m_attribInNameMaxLength, (Int)inVar.name.length());
if (location >= 0 && location < (int)m_attribs.size()) { if (location >= 0 && location < (int)m_attribs.size()) {
m_attribs[location] = inVar.name; m_attribs[location] = inVar.name;
m_attribTypes[location] = inVar.glDefineType; m_attribTypes[location] = inVar.glDefineType;
MGLOG_D("ProgramObject %u: Reflection - got attrib '%s' at explicit location %d", MGLOG_D("ProgramObject %u: Reflection - got attrib '%s' at explicit location %d", m_externalIndex,
m_externalIndex, inVar.name.c_str(), location); inVar.name.c_str(), location);
} }
// else if (location >= (int)m_attribs.size()) { // else if (location >= (int)m_attribs.size()) {
// MGLOG_W("ProgramObject %u: ProgramObject::DoReflection - attrib location %d >= attribs.size() // MGLOG_W("ProgramObject %u: ProgramObject::DoReflection - attrib location %d >= attribs.size()
@@ -386,7 +378,7 @@ namespace MobileGL {
// } // }
// ---------- UBO ---------- // ---------- UBO ----------
int uboCount = m_program->getNumUniformBlocks(); Int uboCount = m_program->getNumUniformBlocks();
MGLOG_D("ProgramObject %u: Reflection - uniform block count (UBO) = %d", m_externalIndex, uboCount); MGLOG_D("ProgramObject %u: Reflection - uniform block count (UBO) = %d", m_externalIndex, uboCount);
m_uniformBlockBinding.resize(uboCount, -1); m_uniformBlockBinding.resize(uboCount, -1);
for (int i = 0; i < uboCount; i++) { for (int i = 0; i < uboCount; i++) {
@@ -417,22 +409,21 @@ namespace MobileGL {
ShaderAttrib attrib{.shaderType = shaderType, ShaderAttrib attrib{.shaderType = shaderType,
.sourceStr = m_shaders[i]->GetShaderSource(), .sourceStr = m_shaders[i]->GetShaderSource(),
.flags = 0}; // Will need patched glslang to work .flags = 0}; // Will need patched glslang to work
MGLOG_D("ProgramObject %u: GenerateBinary - compiling shader[%zu] type %u", m_externalIndex, i, MGLOG_D("ProgramObject %u: GenerateBinary - compiling shader[%zu] type %u", m_externalIndex, i, shaderType);
shaderType);
auto res = ShaderCompiler::CompileShader(attrib); auto res = ShaderCompiler::CompileShader(attrib);
if (!res) { if (!res) {
MGLOG_E("ProgramObject %u: GenerateBinary - CompileShader failed for shader[%zu], aborting " MGLOG_E("ProgramObject %u: GenerateBinary - CompileShader failed for shader[%zu], aborting "
"binary generation", "binary generation",
m_externalIndex, i); m_externalIndex, i);
MGLOG_E("ProgramObject %u: GenerateBinary - CompileShader return code %d, log:\n%s", MGLOG_E("ProgramObject %u: GenerateBinary - CompileShader return code %d, log:\n%s", m_externalIndex,
m_externalIndex, res.error().errc, res.error().log.c_str()); res.error().errc, res.error().log.c_str());
MGLOG_E("ProgramObject %u: GenerateBinary - last compiled shader src: \n%s", m_externalIndex, MGLOG_E("ProgramObject %u: GenerateBinary - last compiled shader src: \n%s", m_externalIndex,
m_shaders[i]->GetShaderSource().c_str()); m_shaders[i]->GetShaderSource().c_str());
} }
MOBILEGL_ASSERT(res, "CompileShader failed during binary generation"); MOBILEGL_ASSERT(res, "CompileShader failed during binary generation");
shaders[i] = res.value(); shaders[i] = res.value();
MGLOG_D("ProgramObject %u: GenerateBinary - compiled shader[%zu] -> TShader ptr %p", MGLOG_D("ProgramObject %u: GenerateBinary - compiled shader[%zu] -> TShader ptr %p", m_externalIndex, i,
m_externalIndex, i, shaders[i].get()); shaders[i].get());
} }
ProgramAttrib attrib{.shaders = Move(shaders), ProgramAttrib attrib{.shaders = Move(shaders),
@@ -441,11 +432,10 @@ namespace MobileGL {
MGLOG_D("ProgramObject %u: GenerateBinary - linking program for binary", m_externalIndex); MGLOG_D("ProgramObject %u: GenerateBinary - linking program for binary", m_externalIndex);
auto programResult = ShaderCompiler::LinkProgram(attrib); auto programResult = ShaderCompiler::LinkProgram(attrib);
if (!programResult) { if (!programResult) {
MGLOG_E("ProgramObject %u: GenerateBinary - LinkProgram failed during binary generation", MGLOG_E("ProgramObject %u: GenerateBinary - LinkProgram failed during binary generation", m_externalIndex);
m_externalIndex);
} }
MOBILEGL_ASSERT(programResult, "LinkProgram failed during binary generation"); MOBILEGL_ASSERT(programResult, "LinkProgram failed during binary generation");
auto program = programResult.value(); auto& program = programResult.value();
MGLOG_D("ProgramObject %u: GenerateBinary - got linked program object", m_externalIndex); MGLOG_D("ProgramObject %u: GenerateBinary - got linked program object", m_externalIndex);
ProgramBinaryAttrib binaryAttrib{ ProgramBinaryAttrib binaryAttrib{
@@ -497,8 +487,7 @@ namespace MobileGL {
for (const auto& [name, offset] : meta.plainUniformOffsetsInUBO) { for (const auto& [name, offset] : meta.plainUniformOffsetsInUBO) {
if (m_uniformLocations.find(name) != m_uniformLocations.end()) { if (m_uniformLocations.find(name) != m_uniformLocations.end()) {
m_uniformOffsets[m_uniformLocations[name]] = offset; m_uniformOffsets[m_uniformLocations[name]] = offset;
MGLOG_D( MGLOG_D("ProgramObject %u: GenerateBinary - uniform '%s' offset=%u assigned to location %u",
"ProgramObject %u: GenerateBinary - uniform '%s' offset=%u assigned to location %u",
m_externalIndex, name.c_str(), offset, m_uniformLocations[name]); m_externalIndex, name.c_str(), offset, m_uniformLocations[name]);
} else { } else {
MGLOG_D("ProgramObject %u: GenerateBinary - uniform '%s' offset=%u but not found in " MGLOG_D("ProgramObject %u: GenerateBinary - uniform '%s' offset=%u but not found in "
@@ -510,8 +499,7 @@ namespace MobileGL {
for (const auto& [name, size] : meta.plainUniformMemberSizesInBytes) { for (const auto& [name, size] : meta.plainUniformMemberSizesInBytes) {
if (m_uniformLocations.find(name) != m_uniformLocations.end()) { if (m_uniformLocations.find(name) != m_uniformLocations.end()) {
m_uniformSizesInBytes[m_uniformLocations[name]] = size; m_uniformSizesInBytes[m_uniformLocations[name]] = size;
MGLOG_D( MGLOG_D("ProgramObject %u: GenerateBinary - uniform '%s' size=%u assigned to location %u",
"ProgramObject %u: GenerateBinary - uniform '%s' size=%u assigned to location %u",
m_externalIndex, name.c_str(), size, m_uniformLocations[name]); m_externalIndex, name.c_str(), size, m_uniformLocations[name]);
} else { } else {
MGLOG_D("ProgramObject %u: GenerateBinary - uniform '%s' size=%u but not found in " MGLOG_D("ProgramObject %u: GenerateBinary - uniform '%s' size=%u but not found in "
@@ -528,23 +516,23 @@ namespace MobileGL {
} }
} }
void ProgramObject::WaitUntilGenerationCompleted() { void ProgramObject::WaitUntilGenerationCompleted() const {
MGLOG_D("ProgramObject %u: WaitUntilGenerationCompleted called (no-op)", m_externalIndex); MGLOG_D("ProgramObject %u: WaitUntilGenerationCompleted called (no-op)", m_externalIndex);
// currently no-op, but keep log for debugging // currently no-op, but keep log for debugging
// will probably be useful when multi-threaded compilation // will probably be useful when multi-threaded compilation
} }
void ProgramObject::SetExplicitVertexInLocation(Uint index, const char* name) { void ProgramObject::SetExplicitVertexInLocation(Uint index, const char* name) {
MGLOG_D("ProgramObject %u: SetExplicitVertexInLocation called name='%s' index=%u", m_externalIndex, MGLOG_D("ProgramObject %u: SetExplicitVertexInLocation called name='%s' index=%u", m_externalIndex, name,
name, index); index);
m_explicitAttribLocations[name] = index; m_explicitAttribLocations[name] = index;
MGLOG_D("ProgramObject %u: SetExplicitVertexInLocation - stored explicit location for '%s' -> %u", MGLOG_D("ProgramObject %u: SetExplicitVertexInLocation - stored explicit location for '%s' -> %u",
m_externalIndex, name, index); m_externalIndex, name, index);
} }
void ProgramObject::SetExplicitFragmentOutLocation(Uint index, const char* name) { void ProgramObject::SetExplicitFragmentOutLocation(Uint index, const char* name) {
MGLOG_D("ProgramObject %u: SetExplicitFragmentOutLocation called name='%s' index=%u", m_externalIndex, MGLOG_D("ProgramObject %u: SetExplicitFragmentOutLocation called name='%s' index=%u", m_externalIndex, name,
name, index); index);
m_explicitFragDataLocation[name] = index; m_explicitFragDataLocation[name] = index;
MGLOG_D("ProgramObject %u: SetExplicitFragmentOutLocation - stored explicit location for '%s' -> %u", MGLOG_D("ProgramObject %u: SetExplicitFragmentOutLocation - stored explicit location for '%s' -> %u",
m_externalIndex, name, index); m_externalIndex, name, index);
@@ -554,8 +542,6 @@ namespace MobileGL {
// TODO: should retrieve "post-mortem" location from glslang instead // TODO: should retrieve "post-mortem" location from glslang instead
auto it = m_explicitFragDataLocation.find(name); auto it = m_explicitFragDataLocation.find(name);
if (it == m_explicitFragDataLocation.end()) return -1; if (it == m_explicitFragDataLocation.end()) return -1;
return it->second; return (Int)it->second;
} }
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -9,19 +9,18 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
#include "ShaderObject.h" #include "ShaderObject.h"
#include "MG_Util/Metrics/BufferMetrics.h"
#include "MG_Util/ShaderTranspiler/SpvcSession.h"
namespace MobileGL { #include <MG_Util/Metrics/BufferMetrics.h>
namespace MG_State { #include <MG_Util/ShaderTranspiler/SpvcSession.h>
namespace GLState {
namespace MobileGL::MG_State::GLState {
class ProgramObject { class ProgramObject {
public: public:
ProgramObject(Uint externalIndex) : m_externalIndex(externalIndex) {} ProgramObject(Uint externalIndex) : m_externalIndex(externalIndex) {}
bool ShaderIsAttached(SharedPtr<ShaderObject> shader); bool ShaderIsAttached(const SharedPtr<ShaderObject>& shader);
bool AttachShader(SharedPtr<ShaderObject> shader); bool AttachShader(const SharedPtr<ShaderObject>& shader);
SizeT DetachShader(SharedPtr<ShaderObject> shader); SizeT DetachShader(const SharedPtr<ShaderObject>& shader);
SizeT RemoveShader(SharedPtr<ShaderObject> shader); SizeT RemoveShader(const SharedPtr<ShaderObject>& shader);
void Link(Bool addDefaultFSIfMissingForRenderingPipelineProgram = false); void Link(Bool addDefaultFSIfMissingForRenderingPipelineProgram = false);
void MarkAsDeleted(); void MarkAsDeleted();
@@ -33,7 +32,7 @@ namespace MobileGL {
const Vector<SharedPtr<ShaderObject>>& GetAttachedShaders() const; const Vector<SharedPtr<ShaderObject>>& GetAttachedShaders() const;
const String& GetInfoLog() const { return m_infoLog; } const String& GetInfoLog() const { return m_infoLog; }
Int GetUniformMaxLength() const { return m_uniformNameMaxLength; } Int GetUniformMaxLength() const { return m_uniformNameMaxLength; }
Uint GetUniformCount() { return m_activeUniformCount; } Uint GetUniformCount() const { return m_activeUniformCount; }
Uint GetMaxUniformLocation() const { return m_maxUniformLocation; } Uint GetMaxUniformLocation() const { return m_maxUniformLocation; }
Int GetUniformLocation(const String& name) const { Int GetUniformLocation(const String& name) const {
const auto it = m_uniformLocations.find(name); const auto it = m_uniformLocations.find(name);
@@ -58,13 +57,11 @@ namespace MobileGL {
return uniform.name; return uniform.name;
} }
Uint GetUniformOffset(Uint location) const { return m_uniformOffsets[location]; } Uint GetUniformOffset(Uint location) const { return m_uniformOffsets[location]; }
Uint GetUniformSizesInBytes(Uint location) const { Uint GetUniformSizesInBytes(Uint location) const { return MG_Util::GetGLTypeSize(GetUniformType(location)); }
return MG_Util::GetGLTypeSize(GetUniformType(location));
}
Int GetAttributeLocation(const String& name) { Int GetAttributeLocation(const String& name) {
const auto it = std::find(m_attribs.begin(), m_attribs.end(), name); const auto it = std::find(m_attribs.begin(), m_attribs.end(), name);
return (it == m_attribs.end()) ? -1 : std::distance(m_attribs.begin(), it); return (it == m_attribs.end()) ? -1 : (Int)std::distance(m_attribs.begin(), it);
} }
GLenum GetAttribType(Uint index) const { return m_attribTypes[index]; } GLenum GetAttribType(Uint index) const { return m_attribTypes[index]; }
const String& GetAttribName(Uint index) const { return m_attribs[index]; } const String& GetAttribName(Uint index) const { return m_attribs[index]; }
@@ -99,16 +96,16 @@ namespace MobileGL {
} }
Uint GetUBOSizeAt(Uint index) const { Uint GetUBOSizeAt(Uint index) const {
if (!IsActiveUniformBlock(index)) return 0; if (!IsActiveUniformBlock(index)) return 0;
return m_program->getUniformBlock(index).size; return m_program->getUniformBlock((Int)index).size;
} }
const String& GetUniformBlockName(Uint index) const { const String& GetUniformBlockName(Uint index) const {
auto& ubo = m_program->getUniformBlock(index); auto& ubo = m_program->getUniformBlock((Int)index);
return ubo.name; return ubo.name;
} }
// Set by glUniformBlockBinding // Set by glUniformBlockBinding
void SetUniformBlockBinding(Uint index, Uint binding) { m_uniformBlockBinding[index] = binding; } void SetUniformBlockBinding(Uint index, Uint binding) { m_uniformBlockBinding[index] = (Int)binding; }
Uint GetUniformBlockBinding(Uint index) const { return m_uniformBlockBinding[index]; } Uint GetUniformBlockBinding(Uint index) const { return m_uniformBlockBinding[index]; }
@@ -116,9 +113,10 @@ namespace MobileGL {
const Vector<Vector<unsigned>>& GetGeneratedSpirv() const { return m_generatedSpirv; } const Vector<Vector<unsigned>>& GetGeneratedSpirv() const { return m_generatedSpirv; }
Int GetShaderIndexByStage(ShaderStage stage) const { Int GetShaderIndexByStage(ShaderStage stage) const {
auto it = std::find_if(m_shaders.begin(), m_shaders.end(), auto it = std::find_if(m_shaders.begin(), m_shaders.end(), [stage](const SharedPtr<ShaderObject>& shader) {
[stage](const SharedPtr<ShaderObject>& shader) { return shader->GetShaderStage() == stage; }); return shader->GetShaderStage() == stage;
return it == m_shaders.end() ? -1 : std::distance(m_shaders.begin(), it); });
return it == m_shaders.end() ? -1 : (Int)std::distance(m_shaders.begin(), it);
} }
Uint GetExternalIndex() const { return m_externalIndex; } Uint GetExternalIndex() const { return m_externalIndex; }
@@ -129,7 +127,7 @@ namespace MobileGL {
private: private:
void DoReflection(); void DoReflection();
void GenerateBinary(); void GenerateBinary();
void WaitUntilGenerationCompleted(); void WaitUntilGenerationCompleted() const;
void AddDefaultFragmentShaderIfMissing(); void AddDefaultFragmentShaderIfMissing();
const Uint m_externalIndex = 0; const Uint m_externalIndex = 0;
@@ -183,6 +181,4 @@ namespace MobileGL {
Bool m_linkStatus = false; Bool m_linkStatus = false;
Bool m_validateStatus = true; Bool m_validateStatus = true;
}; };
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -8,9 +8,7 @@
#include "ProgramState.h" #include "ProgramState.h"
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State {
namespace GLState {
Uint ProgramState::CreateProgram() { Uint ProgramState::CreateProgram() {
Uint programId = 0; Uint programId = 0;
m_programIndexGenerator.Generate(1, &programId); m_programIndexGenerator.Generate(1, &programId);
@@ -21,8 +19,9 @@ namespace MobileGL {
return programId; return programId;
} }
SharedPtr<ProgramObject> ProgramState::GetProgramObject(const Uint id) { const SharedPtr<ProgramObject>& ProgramState::GetProgramObject(const Uint id) {
if (!CheckIndexAvail(id, m_programObjects)) return nullptr; // FIXME: add error reporting here static SharedPtr<ProgramObject> nullProgramObject = nullptr;
if (!CheckIndexAvail(id, m_programObjects)) return nullProgramObject; // FIXME: add error reporting here
return m_programObjects[id]; return m_programObjects[id];
} }
@@ -57,8 +56,9 @@ namespace MobileGL {
return shaderId; return shaderId;
} }
SharedPtr<ShaderObject> ProgramState::GetShaderObject(const Uint shader) { const SharedPtr<ShaderObject>& ProgramState::GetShaderObject(const Uint shader) {
if (!CheckIndexAvail(shader, m_shaderObjects)) return nullptr; static SharedPtr<ShaderObject> nullShaderObject = nullptr;
if (!CheckIndexAvail(shader, m_shaderObjects)) return nullShaderObject;
return m_shaderObjects[shader]; return m_shaderObjects[shader];
} }
@@ -75,6 +75,4 @@ namespace MobileGL {
Bool ProgramState::ValidateShaderObject(Uint shader) const { Bool ProgramState::ValidateShaderObject(Uint shader) const {
return CheckIndexAvail(shader, m_shaderObjects) && m_shaderObjects[shader] != nullptr; return CheckIndexAvail(shader, m_shaderObjects) && m_shaderObjects[shader] != nullptr;
} }
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -11,26 +11,24 @@
#include <MG_Util/Miscellany/IndexGenerator.h> #include <MG_Util/Miscellany/IndexGenerator.h>
#include "ProgramObject.h" #include "ProgramObject.h"
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State {
namespace GLState {
class ProgramState { class ProgramState {
public: public:
// This function WILL actually create the program object. // This function WILL actually create the program object.
// To retrieve created program object, use GetProgramObject() // To retrieve created program object, use GetProgramObject()
Uint CreateProgram(); Uint CreateProgram();
SharedPtr<ProgramObject> GetProgramObject(Uint id); const SharedPtr<ProgramObject>& GetProgramObject(Uint id);
void MarkProgramObjectForDeletion(Uint program); void MarkProgramObjectForDeletion(Uint program);
Bool ValidateProgramObject(Uint program) const; Bool ValidateProgramObject(Uint program) const;
void UseProgram(Uint program); void UseProgram(Uint program);
Uint CreateShader(ShaderStage stage); Uint CreateShader(ShaderStage stage);
SharedPtr<ShaderObject> GetShaderObject(Uint shader); const SharedPtr<ShaderObject>& GetShaderObject(Uint shader);
void MarkShaderObjectForDeletion(Uint shader); void MarkShaderObjectForDeletion(Uint shader);
Bool ValidateShaderObject(Uint shader) const; Bool ValidateShaderObject(Uint shader) const;
SharedPtr<ProgramObject> GetCurrentProgram() const { return m_currentProgram; } const SharedPtr<ProgramObject>& GetCurrentProgram() const { return m_currentProgram; }
private: private:
template <typename T> template <typename T>
@@ -54,6 +52,4 @@ namespace MobileGL {
SharedPtr<ProgramObject> m_currentProgram; SharedPtr<ProgramObject> m_currentProgram;
}; };
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -13,9 +13,7 @@
#include <MG_Util/ShaderTranspiler/ShaderSourceProcessor.h> #include <MG_Util/ShaderTranspiler/ShaderSourceProcessor.h>
#include <MG_Util/ShaderTranspiler/glslang/UniformTraverser.h> #include <MG_Util/ShaderTranspiler/glslang/UniformTraverser.h>
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State {
namespace GLState {
void ShaderObject::SetShaderSource(const String& source) { void ShaderObject::SetShaderSource(const String& source) {
m_source = source; m_source = source;
} }
@@ -31,8 +29,9 @@ namespace MobileGL {
// Compile for OpenGL here, so that we can do validation and link // Compile for OpenGL here, so that we can do validation and link
// like a real OpenGL driver at linking stage // like a real OpenGL driver at linking stage
// Will compile for other backends later. // Will compile for other backends later.
ShaderAttrib attrib{ ShaderAttrib attrib{.shaderType = MG_Util::ConvertShaderStageToGLEnum(m_stage),
.shaderType = MG_Util::ConvertShaderStageToGLEnum(m_stage), .sourceStr = m_source, .flags = ShaderCompileBits::CompileForOpenGL}; .sourceStr = m_source,
.flags = ShaderCompileBits::CompileForOpenGL};
auto result = ShaderCompiler::CompileShader(attrib); auto result = ShaderCompiler::CompileShader(attrib);
if (result) { if (result) {
@@ -50,6 +49,4 @@ namespace MobileGL {
void ShaderObject::MarkAsDeleted() { void ShaderObject::MarkAsDeleted() {
m_deleteStatus = true; m_deleteStatus = true;
} }
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -21,8 +21,7 @@ namespace MobileGL {
Unknown = -1 Unknown = -1
}; };
namespace MG_State { namespace MG_State::GLState {
namespace GLState {
class ShaderObject { class ShaderObject {
public: public:
ShaderObject(const ShaderStage stage, Uint externalIndex) ShaderObject(const ShaderStage stage, Uint externalIndex)
@@ -35,7 +34,7 @@ namespace MobileGL {
Uint GetExternalIndex() const { return m_externalIndex; } Uint GetExternalIndex() const { return m_externalIndex; }
ShaderStage GetShaderStage() const { return m_stage; } ShaderStage GetShaderStage() const { return m_stage; }
const String& GetShaderSource() const { return m_source; } const String& GetShaderSource() const { return m_source; }
SharedPtr<glslang::TShader> GetCompiledShader() const { return m_shader; } const SharedPtr<glslang::TShader>& GetCompiledShader() const { return m_shader; }
const String& GetInfoLog() const { return m_infoLog; } const String& GetInfoLog() const { return m_infoLog; }
const UnorderedMap<String, Uint>& GetUniformLocations() const { return m_uniforms; } const UnorderedMap<String, Uint>& GetUniformLocations() const { return m_uniforms; }
Bool GetCompileStatus() const { return m_compileStatus; } Bool GetCompileStatus() const { return m_compileStatus; }
@@ -52,6 +51,5 @@ namespace MobileGL {
Bool m_deleteStatus = false; Bool m_deleteStatus = false;
Bool m_compileStatus = false; Bool m_compileStatus = false;
}; };
} // namespace GLState } // namespace MG_State::GLState
} // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -38,8 +38,8 @@ namespace MobileGL {
void RenderState::SetCapability(CapabilityInput cap, Bool enabled) { void RenderState::SetCapability(CapabilityInput cap, Bool enabled) {
#define SET_CAPABILITY(capability, flag) \ #define SET_CAPABILITY(capability, flag) \
case CapabilityInput::capability: \ case CapabilityInput::capability: \
if (m_parameters.capability##Enabled == flag) break; \ if (m_parameters.capability##Enabled == (flag)) break; \
m_parameters.capability##Enabled = flag; \ m_parameters.capability##Enabled = (flag); \
++m_version; \ ++m_version; \
break; break;
@@ -195,7 +195,7 @@ namespace MobileGL {
++m_version; ++m_version;
} }
const BoolVec4 RenderState::GetColorMask() const { BoolVec4 RenderState::GetColorMask() const {
return m_parameters.ColorMask; return m_parameters.ColorMask;
} }
@@ -229,7 +229,7 @@ namespace MobileGL {
++m_version; ++m_version;
} }
Int RenderState::GetClearStencil() const { Uint32 RenderState::GetClearStencil() const {
return m_parameters.ClearStencil; return m_parameters.ClearStencil;
} }
@@ -237,8 +237,8 @@ namespace MobileGL {
void RenderState::SetPixelStoreParam(PixelStoreParam param, Int value) { void RenderState::SetPixelStoreParam(PixelStoreParam param, Int value) {
#define SET_PIXEL_STORE_PARAM(paramNameHead, paramNameTail, val) \ #define SET_PIXEL_STORE_PARAM(paramNameHead, paramNameTail, val) \
case PixelStoreParam::paramNameHead##paramNameTail: \ case PixelStoreParam::paramNameHead##paramNameTail: \
if (m_pixelStore##paramNameHead##Parameters.paramNameTail == val) break; \ if (m_pixelStore##paramNameHead##Parameters.paramNameTail == (val)) break; \
m_pixelStore##paramNameHead##Parameters.paramNameTail = val; \ m_pixelStore##paramNameHead##Parameters.paramNameTail = (val); \
break; break;
switch (param) { switch (param) {
@@ -154,7 +154,7 @@ namespace MobileGL {
// Clear State // Clear State
FloatVec4 ClearColor = FloatVec4(0.0f, 0.0f, 0.0f, 1.0f); FloatVec4 ClearColor = FloatVec4(0.0f, 0.0f, 0.0f, 1.0f);
Float ClearDepth = 1.0f; Float ClearDepth = 1.0f;
Int ClearStencil = 0; Uint32 ClearStencil = 0;
// Cull Face // Cull Face
Bool CullFaceEnabled = false; Bool CullFaceEnabled = false;
@@ -201,7 +201,7 @@ namespace MobileGL {
// Color Mask // Color Mask
void SetColorMask(BoolVec4 mask); void SetColorMask(BoolVec4 mask);
const BoolVec4 GetColorMask() const; BoolVec4 GetColorMask() const;
// Clear State // Clear State
void SetClearColor(FloatVec4 color); void SetClearColor(FloatVec4 color);
@@ -209,7 +209,7 @@ namespace MobileGL {
void SetClearDepth(Float depth); void SetClearDepth(Float depth);
Float GetClearDepth() const; Float GetClearDepth() const;
void SetClearStencil(Int stencil); void SetClearStencil(Int stencil);
Int GetClearStencil() const; Uint32 GetClearStencil() const;
// Pixel Store // Pixel Store
void SetPixelStoreParam(PixelStoreParam param, Int value); void SetPixelStoreParam(PixelStoreParam param, Int value);
@@ -7,40 +7,41 @@
// End of Source File Header // End of Source File Header
#include "RenderbufferState.h" #include "RenderbufferState.h"
#include "MG_Util/Types.h"
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State {
namespace GLState {
RenderbufferState::RenderbufferState() : m_indexGenerator(1024, 1) { RenderbufferState::RenderbufferState() : m_indexGenerator(1024, 1) {
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) { for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
m_bindingSlots[i] = BindingSlot<RenderbufferObject>(static_cast<RenderbufferTarget>(i)); m_bindingSlots[i] = BindingSlot<RenderbufferObject>(static_cast<RenderbufferTarget>(i));
} }
} }
SharedPtr<RenderbufferObject> RenderbufferState::GetRenderbufferObject(Uint index) { const SharedPtr<RenderbufferObject>& RenderbufferState::GetRenderbufferObject(Uint index) {
auto it = m_renderbufferObjects.find(index); auto it = m_renderbufferObjects.find(index);
if (it != m_renderbufferObjects.end()) { if (it != m_renderbufferObjects.end()) {
return it->second; return it->second;
} }
return nullptr; static SharedPtr<RenderbufferObject> nullRenderbufferObject = nullptr;
return nullRenderbufferObject;
} }
Vector<Uint> RenderbufferState::GenerateNames(Uint number) { void RenderbufferState::GenerateNames(Uint number, Vector<Uint>& renderbuffers) {
Vector<Uint> buffers(number); renderbuffers.resize(number);
m_indexGenerator.Generate(number, buffers.data()); m_indexGenerator.Generate(number, renderbuffers.data());
return buffers;
} }
SharedPtr<RenderbufferObject> RenderbufferState::CreateRenderbufferObject(Uint index) { const SharedPtr<RenderbufferObject>& RenderbufferState::CreateRenderbufferObject(Uint index) {
auto bufferObject = MakeShared<RenderbufferObject>(index); auto& bufferObject = m_renderbufferObjects[index];
m_renderbufferObjects[index] = bufferObject; if (!bufferObject) {
bufferObject = MakeShared<RenderbufferObject>(index);
}
return bufferObject; return bufferObject;
} }
BindingSlot<RenderbufferObject>& RenderbufferState::GetBindingSlot(RenderbufferTarget target) { BindingSlot<RenderbufferObject>& RenderbufferState::GetBindingSlot(RenderbufferTarget target) {
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) { for (auto& bindingSlot : m_bindingSlots) {
if (m_bindingSlots[i].GetTarget() == target) { if (bindingSlot.GetTarget() == target) {
return m_bindingSlots[i]; return bindingSlot;
} }
} }
MOBILEGL_ASSERT(false, "Invalid RenderbufferTarget enum value: %d", static_cast<int>(target)); MOBILEGL_ASSERT(false, "Invalid RenderbufferTarget enum value: %d", static_cast<int>(target));
@@ -51,9 +52,9 @@ namespace MobileGL {
if (m_indexGenerator.IsValid(index)) { if (m_indexGenerator.IsValid(index)) {
auto it = m_renderbufferObjects.find(index); auto it = m_renderbufferObjects.find(index);
if (it != m_renderbufferObjects.end()) { if (it != m_renderbufferObjects.end()) {
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) { for (auto& bindingSlot : m_bindingSlots) {
if (m_bindingSlots[i].GetBoundObject() == it->second) { if (bindingSlot.GetBoundObject() == it->second) {
m_bindingSlots[i].Bind(nullptr); bindingSlot.Bind(nullptr);
} }
} }
m_renderbufferObjects.erase(it); m_renderbufferObjects.erase(it);
@@ -69,6 +70,4 @@ namespace MobileGL {
Bool RenderbufferState::ValidateRenderbufferObject(Uint index) const { Bool RenderbufferState::ValidateRenderbufferObject(Uint index) const {
return m_renderbufferObjects.find(index) != m_renderbufferObjects.end(); return m_renderbufferObjects.find(index) != m_renderbufferObjects.end();
} }
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -11,16 +11,14 @@
#include <MG_Util/Miscellany/IndexGenerator.h> #include <MG_Util/Miscellany/IndexGenerator.h>
#include "RenderbufferObject.h" #include "RenderbufferObject.h"
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State {
namespace GLState {
class RenderbufferState { class RenderbufferState {
public: public:
RenderbufferState(); RenderbufferState();
SharedPtr<RenderbufferObject> GetRenderbufferObject(Uint index); const SharedPtr<RenderbufferObject>& GetRenderbufferObject(Uint index);
Vector<Uint> GenerateNames(Uint number); void GenerateNames(Uint number, Vector<Uint>& renderbuffers);
SharedPtr<RenderbufferObject> CreateRenderbufferObject(Uint index); const SharedPtr<RenderbufferObject>& CreateRenderbufferObject(Uint index);
BindingSlot<RenderbufferObject>& GetBindingSlot(RenderbufferTarget target); BindingSlot<RenderbufferObject>& GetBindingSlot(RenderbufferTarget target);
void MarkRenderbufferObjectForDeletion(Uint index); void MarkRenderbufferObjectForDeletion(Uint index);
Bool ValidateName(Uint index) const; Bool ValidateName(Uint index) const;
@@ -32,6 +30,4 @@ namespace MobileGL {
Array<BindingSlot<RenderbufferObject>, static_cast<SizeT>(RenderbufferTarget::RenderbufferTargetCount)> Array<BindingSlot<RenderbufferObject>, static_cast<SizeT>(RenderbufferTarget::RenderbufferTargetCount)>
m_bindingSlots; m_bindingSlots;
}; };
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -8,25 +8,23 @@
#include "SamplerState.h" #include "SamplerState.h"
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State {
namespace GLState {
SamplerState::SamplerState() : m_indexGenerator(1024, 1) {} SamplerState::SamplerState() : m_indexGenerator(1024, 1) {}
Vector<Uint> SamplerState::GenerateNames(Uint number) { void SamplerState::GenerateNames(Uint number, Vector<Uint>& samplers) {
Vector<Uint> names(number); samplers.resize(number);
m_indexGenerator.Generate(number, names.data()); m_indexGenerator.Generate(number, samplers.data());
return names;
} }
SharedPtr<SamplerObject> SamplerState::GetSamplerObject(Uint index) { const SharedPtr<SamplerObject>& SamplerState::GetSamplerObject(Uint index) {
auto it = m_samplerObjects.find(index); auto it = m_samplerObjects.find(index);
return it != m_samplerObjects.end() ? it->second : nullptr; static SharedPtr<SamplerObject> nullSamplerObject = nullptr;
return it != m_samplerObjects.end() ? it->second : nullSamplerObject;
} }
SharedPtr<SamplerObject> SamplerState::CreateSamplerObject(Uint index) { const SharedPtr<SamplerObject>& SamplerState::CreateSamplerObject(Uint index) {
auto sampler = MakeShared<SamplerObject>(index); auto& sampler = m_samplerObjects[index];
m_samplerObjects[index] = sampler; sampler = MakeShared<SamplerObject>(index);
return sampler; return sampler;
} }
@@ -44,6 +42,4 @@ namespace MobileGL {
Bool SamplerState::ValidateSamplerObject(Uint index) const { Bool SamplerState::ValidateSamplerObject(Uint index) const {
return m_samplerObjects.find(index) != m_samplerObjects.end(); return m_samplerObjects.find(index) != m_samplerObjects.end();
} }
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -18,9 +18,9 @@ namespace MobileGL {
public: public:
SamplerState(); SamplerState();
Vector<Uint> GenerateNames(Uint number); void GenerateNames(Uint number, Vector<Uint>& samplers);
SharedPtr<SamplerObject> GetSamplerObject(Uint index); const SharedPtr<SamplerObject>& GetSamplerObject(Uint index);
SharedPtr<SamplerObject> CreateSamplerObject(Uint index); const SharedPtr<SamplerObject>& CreateSamplerObject(Uint index);
void MarkSamplerObjectForDeletion(Uint index); void MarkSamplerObjectForDeletion(Uint index);
Bool ValidateName(Uint index) const; Bool ValidateName(Uint index) const;
Bool ValidateSamplerObject(Uint index) const; Bool ValidateSamplerObject(Uint index) const;
@@ -31,7 +31,7 @@ namespace MobileGL {
return {0, 0, 0}; return {0, 0, 0};
} }
SharedPtr<SamplerObject> TextureObjectBase::GetSamplerObject() const { const SharedPtr<SamplerObject>& TextureObjectBase::GetSamplerObject() const {
return m_sampler; return m_sampler;
} }
@@ -14,9 +14,7 @@
#include <Includes.h> #include <Includes.h>
#include <MG_Util/Math/VectorTypes.h> #include <MG_Util/Math/VectorTypes.h>
namespace MobileGL { namespace MobileGL::MG_State::GLState {
namespace MG_State {
namespace GLState {
class ITextureObject { class ITextureObject {
public: public:
using TargetEnum = TextureTarget; using TargetEnum = TextureTarget;
@@ -28,7 +26,7 @@ namespace MobileGL {
virtual TextureTarget GetTarget() const = 0; virtual TextureTarget GetTarget() const = 0;
virtual const Vector<TextureUploadTarget>& GetUploadTargets() const = 0; virtual const Vector<TextureUploadTarget>& GetUploadTargets() const = 0;
virtual IntVec3 GetBaseSize() const = 0; virtual IntVec3 GetBaseSize() const = 0;
virtual SharedPtr<SamplerObject> GetSamplerObject() const = 0; virtual const SharedPtr<SamplerObject>& GetSamplerObject() const = 0;
virtual void SetInternalFormat(TextureInternalFormat format) = 0; virtual void SetInternalFormat(TextureInternalFormat format) = 0;
virtual Bool IsComplete() const = 0; virtual Bool IsComplete() const = 0;
virtual Uint GetExternalIndex() const = 0; virtual Uint GetExternalIndex() const = 0;
@@ -55,7 +53,7 @@ namespace MobileGL {
TextureInternalFormat GetFormat() const override; TextureInternalFormat GetFormat() const override;
TextureTarget GetTarget() const override; TextureTarget GetTarget() const override;
IntVec3 GetBaseSize() const override; IntVec3 GetBaseSize() const override;
SharedPtr<SamplerObject> GetSamplerObject() const override; const SharedPtr<SamplerObject>& GetSamplerObject() const override;
void SetInternalFormat(TextureInternalFormat format) override; void SetInternalFormat(TextureInternalFormat format) override;
Bool IsComplete() const override; Bool IsComplete() const override;
Uint GetExternalIndex() const override; Uint GetExternalIndex() const override;
@@ -84,8 +82,7 @@ namespace MobileGL {
class TextureObjectMipmap : public TextureObjectBase { class TextureObjectMipmap : public TextureObjectBase {
public: public:
TextureObjectMipmap(TextureTarget target, Uint externalIndex) TextureObjectMipmap(TextureTarget target, Uint externalIndex) : TextureObjectBase(target, externalIndex) {}
: TextureObjectBase(target, externalIndex) {}
TextureStorageType GetStorageType() const override { return TextureStorageType::Mipmap; } TextureStorageType GetStorageType() const override { return TextureStorageType::Mipmap; }
@@ -95,8 +92,7 @@ namespace MobileGL {
virtual void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) = 0; virtual void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) = 0;
virtual void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) = 0; virtual void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) = 0;
virtual void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) = 0; virtual void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) = 0;
virtual void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, virtual void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, Bool dirty = true) = 0;
Bool dirty = true) = 0;
virtual Bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const = 0; virtual Bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const = 0;
}; };
@@ -121,6 +117,4 @@ namespace MobileGL {
protected: protected:
MipmapUploadTargetArray<1> m_textureStorage; MipmapUploadTargetArray<1> m_textureStorage;
}; };
} // namespace GLState } // namespace MobileGL::MG_State::GLState
} // namespace MG_State
} // namespace MobileGL
@@ -8,7 +8,7 @@
#pragma once #pragma once
#include "TextureObject.h" #include "TextureObject.h"
#include "MG_State/GLState/BufferState/BufferObject.h" #include <MG_State/GLState/BufferState/BufferObject.h>
namespace MobileGL { namespace MobileGL {
namespace MG_State { namespace MG_State {

Some files were not shown because too many files have changed in this diff Show More