Compare commits

..
Author SHA1 Message Date
BZLZHH 4bf9c1cae6 [Perf] (MG_Backend/DirectVulkanTMP): Optimize buffer uploads with staging ring + batched copies. 2026-02-21 14:04:05 +08:00
BZLZHH c121328c98 [Feat] (MG_Backend/DirectVulkanTMP): Migrate to Vulkan 1.3 and use dynamic rendering. 2026-02-21 13:17:05 +08:00
BZLZHH 5fe5aae138 [Perf] (MG_Backend/DirectVulkan): Batch layout transitions and Reuse staging buffers. 2026-02-20 22:04:50 +08:00
BZLZHH d2485a3fbe [Improvement] (MG_Backend/DirectVulkanTMP): Rename current DirectVulkan to DirectVulkanTMP. 2026-02-20 16:33:26 +08:00
BZLZHH 3fe0999550 [Misc] (MG_Backend/DirectVulkan): Remove "VulkanRenerer". 2026-02-20 16:27:02 +08:00
BZLZHH 39eb6a9026 [Feat] (MG_Backend/DirectVulkan|MG_Util): Get Vulkan device info. 2026-02-20 16:21:28 +08:00
BZLZHH 99c1697fba Merge branch 'dev' into Feat/Backend-Direct-Vulkan-TMP 2026-02-20 15:27:21 +08:00
BZLZHH 5db5545b33 Merge branch 'dev' into Feat/Backend-Direct-Vulkan-TMP 2026-02-19 02:04:57 +08:00
BZLZHH e63eebf425 [Fix] (MG_Backend/DirectVulkan): Correct viewport setting. 2026-02-16 18:29:03 +08:00
BZLZHH 03d3fcdc66 [Feat|Fix] (MG_Backend): Implement BlitFramebuffer & DrawElementsBaseVertex. 2026-02-16 17:12:33 +08:00
BZLZHH 40fc317f69 [Fix] (MG_Backend/DirectVulkan): Add shader position transforms & correct namespace name. 2026-02-16 14:06:34 +08:00
BZLZHH 3bafdee45d [Feat] (MG_Backend/DirectVulkan): Implement DV::TmpImpl and use. 2026-02-11 02:01:08 +08:00
BZLZHH 188275c004 Merge branch 'Feat/Backend-Direct-Vulkan' of github.com:MobileGL-Dev/MobileGL into Feat/Backend-Direct-Vulkan 2026-02-09 21:03:10 +08:00
215 changed files with 13920 additions and 35422 deletions
+2
View File
@@ -14,6 +14,7 @@ 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,
@@ -62,6 +63,7 @@ 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,
-7
View File
@@ -28,13 +28,6 @@ jobs:
- name: Get CMake - name: Get CMake
uses: lukka/get-cmake@latest uses: lukka/get-cmake@latest
- name: Prepare Vulkan SDK
uses: humbletim/setup-vulkan-sdk@v1.2.1
with:
vulkan-query-version: 1.4.304.1
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Update glslang external sources - name: Update glslang external sources
working-directory: ${{env.BENCH_ROOT}}/3rdparty/glslang working-directory: ${{env.BENCH_ROOT}}/3rdparty/glslang
run: python update_glslang_sources.py run: python update_glslang_sources.py
-80
View File
@@ -1,80 +0,0 @@
name: MobileGL Plugin APK
on:
push:
branches:
- dev
- Feat/Backend-Direct-GLES
- Feat/Backend-Direct-Vulkan
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set artifact metadata
run: |
echo "date_today=$(date +'%Y-%m-%d')" >> "$GITHUB_ENV"
echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_ENV"
- name: Set up JDK
uses: actions/setup-java@v4
with:
distribution: zulu
java-version: '17'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
gradle-version: 8.10.2
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Install Android NDK
run: |
sdkmanager "ndk;27.3.13750724"
echo "ndk.dir=$ANDROID_HOME/ndk/27.3.13750724" >> android-plugin/local.properties
- name: Update glslang external sources
working-directory: 3rdparty/glslang
run: python update_glslang_sources.py
- name: Build plugin APK
run: gradle --no-daemon -p android-plugin :app:assembleRelease
env:
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
- name: Verify signed APK
run: |
APKSIGNER="$(find "$ANDROID_HOME/build-tools" -name apksigner -type f | sort -V | tail -n 1)"
mapfile -t APKS < <(find android-plugin/app/build/outputs/apk -type f -path '*/release/*.apk' | sort)
if [ "${#APKS[@]}" -eq 0 ]; then
echo "::error::No release APKs found under android-plugin/app/build/outputs/apk"
find android-plugin/app/build/outputs/apk -type f -print || true
exit 1
fi
for APK in "${APKS[@]}"; do
if [[ "$APK" == *-unsigned.apk ]]; then
echo "::error::Unsigned release APK produced: $APK"
exit 1
fi
"$APKSIGNER" verify --verbose "$APK"
done
- name: Upload plugin APK
uses: actions/upload-artifact@v4
with:
name: MobileGL-plugin-${{ env.date_today }}-${{ env.short_sha }}
path: |
android-plugin/app/build/outputs/apk/release/*.apk
android-plugin/app/build/outputs/apk/**/release/*.apk
-7
View File
@@ -28,13 +28,6 @@ jobs:
- name: Get CMake - name: Get CMake
uses: lukka/get-cmake@latest uses: lukka/get-cmake@latest
- name: Prepare Vulkan SDK
uses: humbletim/setup-vulkan-sdk@v1.2.1
with:
vulkan-query-version: 1.4.304.1
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Update glslang external sources - name: Update glslang external sources
working-directory: ${{env.TEST_ROOT}}/3rdparty/glslang working-directory: ${{env.TEST_ROOT}}/3rdparty/glslang
run: python update_glslang_sources.py run: python update_glslang_sources.py
-7
View File
@@ -15,10 +15,3 @@ MobileGLCodeManager
.clangd .clangd
MobileGL/MG_Test/build MobileGL/MG_Test/build
/build_* /build_*
/cmake-build*
.idea
MobileGL/MG*/build*
MobileGL/MG*/cmake-build*
/android-plugin/.gradle
/android-plugin/build
/android-plugin/app/build
-12
View File
@@ -16,15 +16,3 @@
[submodule "3rdparty/xxHash"] [submodule "3rdparty/xxHash"]
path = 3rdparty/xxHash path = 3rdparty/xxHash
url = https://github.com/Cyan4973/xxHash.git url = https://github.com/Cyan4973/xxHash.git
[submodule "3rdparty/VulkanMemoryAllocator"]
path = 3rdparty/VulkanMemoryAllocator
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
[submodule "3rdparty/SPIRV-Reflect"]
path = 3rdparty/SPIRV-Reflect
url = https://github.com/KhronosGroup/SPIRV-Reflect.git
+10 -57
View File
@@ -104,20 +104,9 @@ set(SPIRV_CROSS_ENABLE_CPP OFF CACHE BOOL "Disable C++ API target" FORCE)
set(SPIRV_CROSS_CLI OFF CACHE BOOL "Disable CLI binary" FORCE) set(SPIRV_CROSS_CLI OFF CACHE BOOL "Disable CLI binary" FORCE)
set(SPIRV_CROSS_STATIC ON CACHE BOOL "Prefer static libs" FORCE) set(SPIRV_CROSS_STATIC ON CACHE BOOL "Prefer static libs" FORCE)
set(SPIRV_REFLECT_EXECUTABLE OFF CACHE BOOL "Build spirv-reflect executable" FORCE)
set(SPIRV_REFLECT_STATIC_LIB ON CACHE BOOL "Build a SPIRV-Reflect static library" FORCE)
set(SPIRV_REFLECT_BUILD_TESTS OFF CACHE BOOL "Build the SPIRV-Reflect test suite" FORCE)
set(SPIRV_REFLECT_ENABLE_ASSERTS OFF CACHE BOOL "Enable asserts for debugging" FORCE)
set(SPIRV_REFLECT_ENABLE_ASAN OFF CACHE BOOL "Use address sanitization" FORCE)
set(SPIRV_REFLECT_INSTALL OFF CACHE BOOL "Whether to install" FORCE)
# add_subdirectory(3rdparty/DiligentCore) # add_subdirectory(3rdparty/DiligentCore)
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/Vulkan-Headers)
add_subdirectory(3rdparty/Vulkan-Utility-Libraries)
add_subdirectory(3rdparty/SPIRV-Reflect)
set(XXHASH_BUILD_XXHSUM OFF) set(XXHASH_BUILD_XXHSUM OFF)
option(BUILD_SHARED_LIBS OFF) option(BUILD_SHARED_LIBS OFF)
@@ -138,7 +127,6 @@ endif ()
set(SOURCE_FILES set(SOURCE_FILES
MobileGL/Init.cpp MobileGL/Init.cpp
MobileGL/GlobalObjects.cpp MobileGL/GlobalObjects.cpp
MobileGL/ConfigLoader.cpp
MobileGL/MG_Util/Debug/Log.cpp MobileGL/MG_Util/Debug/Log.cpp
@@ -170,8 +158,6 @@ 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
@@ -179,7 +165,6 @@ set(SOURCE_FILES
MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp
MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp
MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.cpp MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.cpp
MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/FlattenInterfaceStructPass.cpp
MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.cpp MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.cpp
MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp
@@ -224,27 +209,16 @@ set(SOURCE_FILES
MobileGL/MG_Backend/DirectGLES/Utils.cpp MobileGL/MG_Backend/DirectGLES/Utils.cpp
MobileGL/MG_Backend/DirectGLES/Managers.cpp MobileGL/MG_Backend/DirectGLES/Managers.cpp
MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp MobileGL/MG_Backend/DirectVulkanTMP/DirectVulkanTMP.cpp
MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp MobileGL/MG_Backend/DirectVulkanTMP/TmpImpl.cpp
MobileGL/MG_Backend/DirectVulkan/VmaImpl.cpp MobileGL/MG_Backend/DirectVulkanTMP/BackendObject_DirectVulkanTMP.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp MobileGL/MG_Backend/DirectVulkanTMP/Renderer/VulkanContext.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.cpp MobileGL/MG_Backend/DirectVulkanTMP/Renderer/SwapchainManager.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.cpp MobileGL/MG_Backend/DirectVulkanTMP/Renderer/PipelineManager.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineFactory.cpp MobileGL/MG_Backend/DirectVulkanTMP/Renderer/FrameContext.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp MobileGL/MG_Backend/DirectVulkanTMP/Managers/ProgramManager.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/BufferArena.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateBuilder.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp
MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.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_State/GLState/Core.cpp MobileGL/MG_State/GLState/Core.cpp
MobileGL/MG_State/EGLState/Core.cpp
MobileGL/MG_State/GLState/ErrorState/Error.cpp MobileGL/MG_State/GLState/ErrorState/Error.cpp
MobileGL/MG_State/GLState/BufferState/BufferState.cpp MobileGL/MG_State/GLState/BufferState/BufferState.cpp
MobileGL/MG_State/GLState/BufferState/BufferObject.cpp MobileGL/MG_State/GLState/BufferState/BufferObject.cpp
@@ -277,19 +251,8 @@ set(MOBILEGL_LINK_LIBRARIES
SPIRV-Tools-opt SPIRV-Tools-opt
SPIRV-Tools SPIRV-Tools
xxHash::xxhash xxHash::xxhash
GPUOpen::VulkanMemoryAllocator
Vulkan::UtilityHeaders
spirv-reflect-static
) )
set(MOBILEGL_COMPILE_DEF
-DVMA_STATIC_VULKAN_FUNCTIONS=0
-DVMA_DYNAMIC_VULKAN_FUNCTIONS=1
-DVMA_VULKAN_VERSION=1001000
)
message(STATUS "MOBILEGL_COMPILE_DEF=${MOBILEGL_COMPILE_DEF}")
set(MOBILEGL_INCLUDE_DIR set(MOBILEGL_INCLUDE_DIR
${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/MobileGL ${CMAKE_SOURCE_DIR}/MobileGL
@@ -322,15 +285,10 @@ target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC
) )
target_link_libraries(${CMAKE_PROJECT_NAME} target_link_libraries(${CMAKE_PROJECT_NAME}
PUBLIC PRIVATE
${MOBILEGL_LINK_LIBRARIES} ${MOBILEGL_LINK_LIBRARIES}
) )
target_compile_definitions(${CMAKE_PROJECT_NAME}
PUBLIC
${MOBILEGL_COMPILE_DEF}
)
if(NOT ANDROID) if(NOT ANDROID)
add_library(${CMAKE_PROJECT_NAME}_s STATIC add_library(${CMAKE_PROJECT_NAME}_s STATIC
${SOURCE_FILES} ${SOURCE_FILES}
@@ -355,14 +313,9 @@ if(NOT ANDROID)
) )
target_link_libraries(${CMAKE_PROJECT_NAME}_s target_link_libraries(${CMAKE_PROJECT_NAME}_s
PUBLIC PRIVATE
${MOBILEGL_LINK_LIBRARIES} ${MOBILEGL_LINK_LIBRARIES}
) )
target_compile_definitions(${CMAKE_PROJECT_NAME}_s
PUBLIC
${MOBILEGL_COMPILE_DEF}
)
endif() endif()
if (TRACY_ENABLE) if (TRACY_ENABLE)
+1 -2
View File
@@ -14,9 +14,8 @@ 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, 6, 0, "-dev", VersionType::Development}; inline const Version CoreVersion = {26, 2, 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;
extern BackendType ActiveBackendType; extern BackendType ActiveBackendType;
} // namespace MobileGL::MG_Config } // namespace MobileGL::MG_Config
-88
View File
@@ -1,88 +0,0 @@
// MobileGL - MobileGL/ConfigLoader.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 "Config.h"
#ifndef _WIN32
extern char** environ;
#endif
namespace MobileGL::MG_ConfigLoader {
static UniquePtr<UnorderedMap<String, String>> acceptedEnvVariablesMap;
static Bool IsAcceptedPrefix(const String& key) {
return (key.compare(0, 6, "LIBGL_") == 0 || key.compare(0, 9, "MOBILEGL_") == 0);
}
inline void InitializeAcceptedEnvVariables() {
if (!acceptedEnvVariablesMap) {
acceptedEnvVariablesMap = MakeUnique<UnorderedMap<String, String>>();
} else {
acceptedEnvVariablesMap->clear();
}
char** envPtr = nullptr;
#ifdef _WIN32
envPtr = _environ;
#else // POSIX
envPtr = ::environ;
#endif
if (envPtr == nullptr) return;
for (char** env = envPtr; *env != nullptr; ++env) {
String entry(*env);
SizeT pos = entry.find('=');
if (pos != String::npos) {
String key = entry.substr(0, pos);
String value = entry.substr(pos + 1);
if (IsAcceptedPrefix(key)) {
(*acceptedEnvVariablesMap)[key] = value;
MGLOG_D("Config: Accepted env variable: %s=%s", key.c_str(), value.c_str());
}
}
}
}
inline void QueryEnvVariable(const String& key, String& outValue, const String& defaultValue) {
auto it = acceptedEnvVariablesMap->find(key);
if (it != acceptedEnvVariablesMap->end()) {
outValue = it->second;
} else {
outValue = defaultValue;
}
}
inline void InitBackendType() {
String backendTypeStr;
QueryEnvVariable("MOBILEGL_BACKEND_TYPE", backendTypeStr, "DirectGLES");
#define ENTRY(backendType) \
if (backendTypeStr == #backendType) { \
MG_Config::ActiveBackendType = BackendType::backendType; \
MGLOG_I("Config: Active backend type set to " #backendType); \
return; \
}
ENTRY(DirectGLES)
ENTRY(DirectVulkan)
ENTRY(Unknown)
MG_Config::ActiveBackendType = BackendType::Unknown;
#undef ENTRY
}
void Init() {
MGLOG_D("Loading configuration from environment variables...");
InitializeAcceptedEnvVariables();
InitBackendType();
// Destroy the map since we won't need it anymore
acceptedEnvVariablesMap.reset();
}
} // namespace MobileGL::MG_ConfigLoader
+1 -7
View File
@@ -34,9 +34,7 @@
#define MOBILEGL_EGL_API MOBILEGL_API #define MOBILEGL_EGL_API MOBILEGL_API
// ====================== MobileGL configurations ======================= // // ====================== MobileGL configurations ======================= //
#ifndef MOBILEGL_LOG_ACTIVE_LEVEL #define MOBILEGL_LOG_ACTIVE_LEVEL MOBILEGL_LOG_LEVEL_INFO
#define MOBILEGL_LOG_ACTIVE_LEVEL MOBILEGL_LOG_LEVEL_DEBUG
#endif
#define MOBILEGL_LOG_ENABLE_CONSOLE 0 #define MOBILEGL_LOG_ENABLE_CONSOLE 0
#define MOBILEGL_LOG_ENABLE_FILE 1 #define MOBILEGL_LOG_ENABLE_FILE 1
@@ -65,7 +63,6 @@
#endif #endif
// =============================== Utils ================================ // // =============================== Utils ================================ //
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
#define MOBILEGL_ASSERT(condition, ...) \ #define MOBILEGL_ASSERT(condition, ...) \
do { \ do { \
if (!(condition)) { \ if (!(condition)) { \
@@ -74,6 +71,3 @@
TRAP; \ TRAP; \
} \ } \
} while (0) } while (0)
#else
#define MOBILEGL_ASSERT(condition, ...)
#endif
+1 -1
View File
@@ -10,7 +10,7 @@
namespace MobileGL { namespace MobileGL {
namespace MG_Config { namespace MG_Config {
BackendType ActiveBackendType; BackendType ActiveBackendType = BackendType::DirectVulkanTMP;
} // namespace MG_Config } // namespace MG_Config
namespace MG_Backend { namespace MG_Backend {
+2 -39
View File
@@ -32,14 +32,13 @@
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <cassert> #include <cassert>
#include <climits>
#include <cstdlib>
#include <cstdarg> #include <cstdarg>
#include <cstring> #include <cstring>
#include <numeric> #include <numeric>
#include <expected> #include <expected>
#include <iostream> #include <iostream>
#include <optional> #include <optional>
#include <xxhash.h>
#include <algorithm> #include <algorithm>
#include <stdexcept> #include <stdexcept>
#include <functional> #include <functional>
@@ -52,9 +51,6 @@
// Include FastSTL // Include FastSTL
#include <FastSTL/UnorderedMap.h> #include <FastSTL/UnorderedMap.h>
// Include xxHash
#include <xxhash.h>
// Include spirv_cross // Include spirv_cross
#include <spirv_cross/spirv_cross_c.h> #include <spirv_cross/spirv_cross_c.h>
@@ -64,9 +60,7 @@
#endif #endif
#include <EGL/egl.h> #include <EGL/egl.h>
#define GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES
#ifndef NO_GL_H
#include "GL/gl.h" #include "GL/gl.h"
#endif
#include <GL/glcorearb.h> #include <GL/glcorearb.h>
#undef GL_GLEXT_PROTOTYPES #undef GL_GLEXT_PROTOTYPES
@@ -98,44 +92,13 @@
#endif #endif
#ifdef __ANDROID__ #ifdef __ANDROID__
#define VK_USE_PLATFORM_ANDROID_KHR
#include <unistd.h> #include <unistd.h>
#include <pthread.h> #include <pthread.h>
#include <android/log.h> #include <android/log.h>
#include <android/native_window.h> #include <android/native_window.h>
#endif #endif
#ifdef __ANDROID__
#define VK_USE_PLATFORM_ANDROID_KHR
#elif _WIN32
#define VK_USE_PLATFORM_WIN32_KHR
#elif defined(__APPLE__)
#define VK_USE_PLATFORM_METAL_EXT
#elif defined(__linux__)
#define VK_USE_PLATFORM_XLIB_KHR
typedef struct _XDisplay Display;
typedef unsigned long XID;
typedef XID Window;
typedef unsigned long VisualID;
#else
#warning "VK_USE_PLATFORM_*_KHR not defined for this platform!"
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
#pragma push_macro("Bool")
#pragma push_macro("None")
#pragma push_macro("Always")
#pragma push_macro("Status")
#pragma push_macro("LSBFirst")
#pragma push_macro("DestroyAll")
#endif
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#if defined(VK_USE_PLATFORM_XLIB_KHR)
#pragma pop_macro("DestroyAll")
#pragma pop_macro("LSBFirst")
#pragma pop_macro("Status")
#pragma pop_macro("Always")
#pragma pop_macro("None")
#pragma pop_macro("Bool")
#endif
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
#include <tracy/Tracy.hpp> #include <tracy/Tracy.hpp>
+13 -16
View File
@@ -8,36 +8,33 @@
#include "Init.h" #include "Init.h"
#include "Config.h" #include "Config.h"
#include <MG_Impl/Init.h>
#include <MG_Backend/BackendObjects.h> #include <MG_Backend/BackendObjects.h>
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
#include <MG_State/EGLState/Core.h>
#include <MG_Impl/GLImpl/Texture/ProxyTexture.h> #include <MG_Impl/GLImpl/Texture/ProxyTexture.h>
#include <MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h> #include <MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h>
namespace MobileGL { namespace MobileGL {
void Initialize() { void MG_Initialize() {
MG_Util::Debug::InitFile(); MG_Util::Debug::InitFile();
MGLOG_I("Initializing MobileGL..."); MGLOG_I("Initializing MobileGL...");
MG_ConfigLoader::Init();
MGLOG_I("Config loaded");
MG_State::Init(); MG_State::Init();
MGLOG_D("MG_State initialized"); MGLOG_D("MobileGL State initialized");
MG_Backend::Init(); MG_Backend::Init();
MGLOG_D("MG_Backend initialized"); MGLOG_D("MobileGL Backend initialized");
MG_Impl::Init(); MG_Impl::Init();
MGLOG_D("MG_Impl initialized"); MGLOG_D("MobileGL Implementation initialized");
glslang::InitializeProcess(); glslang::InitializeProcess();
MGLOG_D("glslang initialized"); MGLOG_D("glslang initialized");
MGLOG_I("MobileGL initialized"); MGLOG_I("MobileGL initialized");
} }
void Destroy() { void MG_Destroy() {
MGLOG_I("MobileGL closing..."); MGLOG_I("MobileGL closing...");
glslang::FinalizeProcess(); glslang::FinalizeProcess();
MG_State::pGLContext.reset(); delete MG_State::pGLContext;
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
@@ -45,11 +42,11 @@ namespace MobileGL {
#if defined(__linux__) || defined(__APPLE__) #if defined(__linux__) || defined(__APPLE__)
__attribute__((constructor)) static void AutoInit() { __attribute__((constructor)) static void AutoInit() {
Initialize(); MG_Initialize();
} }
__attribute__((destructor)) static void AutoDestroy() { __attribute__((destructor)) static void AutoDestroy() {
Destroy(); MG_Destroy();
} }
#endif #endif
@@ -57,11 +54,11 @@ namespace MobileGL {
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) { switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
Initialize(); MG_Initialize();
break; break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
Destroy(); MG_Destroy();
break; break;
} }
return TRUE; return TRUE;
+2 -18
View File
@@ -10,22 +10,6 @@
#include "Includes.h" #include "Includes.h"
namespace MobileGL { namespace MobileGL {
void Initialize(); void MG_Initialize();
void Destroy(); void MG_Destroy();
namespace MG_Util::Debug {
void InitFile();
} // namespace MG_Util::Debug
namespace MG_ConfigLoader {
void Init();
} // namespace MG_ConfigLoader
namespace MG_Backend {
void Init();
} // namespace MG_Backend
namespace MG_Impl {
void Init();
} // namespace MG_Impl
} // namespace MobileGL } // namespace MobileGL
-170
View File
@@ -9,177 +9,7 @@
#include "BackendObject.h" #include "BackendObject.h"
namespace MobileGL::MG_Backend { namespace MobileGL::MG_Backend {
namespace {
Bool IsReleaseCurrentRequest(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
return dpy == EGL_NO_DISPLAY && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT;
}
std::thread::id CurrentThreadKey() {
return std::this_thread::get_id();
}
} // namespace
Bool BackendObject::InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (dpy == EGL_NO_DISPLAY) {
MGLOG_E("InitializeEGLDisplay failed: invalid EGLDisplay");
return false;
}
if (m_eglDisplayInitialized && m_eglDisplay != dpy) {
MGLOG_E("InitializeEGLDisplay failed: backend already bound to a different EGLDisplay");
return false;
}
m_eglDisplay = dpy;
m_eglDisplayInitialized = true;
if (major) {
*major = 1;
}
if (minor) {
*minor = 5;
}
return true;
}
Bool BackendObject::CreateEGLWindowSurface(const WindowHandle& handle) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_eglDisplayInitialized) {
MGLOG_E("CreateEGLWindowSurface failed: EGL display is not initialized");
return false;
}
if (handle.Backend == WindowBackend::Unknown || !handle.Handle) {
MGLOG_E("CreateEGLWindowSurface failed: invalid native window handle");
return false;
}
if (m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Window &&
m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle) {
return true;
}
SetWindowHandle(handle);
if (!InitWindowSurface()) {
MGLOG_E("CreateEGLWindowSurface failed: backend InitWindowSurface failed");
return false;
}
m_eglSurfaceInitialized = true;
m_eglSurfaceKind = SurfaceKind::Window;
m_eglCurrentThreads.clear();
m_backendCapabilitiesInitialized = false;
return true;
}
Bool BackendObject::CreateEGLPbufferSurface(EGLint width, EGLint height) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_eglDisplayInitialized) {
MGLOG_E("CreateEGLPbufferSurface failed: EGL display is not initialized");
return false;
}
if (width <= 0 || height <= 0) {
MGLOG_E("CreateEGLPbufferSurface failed: invalid size %dx%d", width, height);
return false;
}
if (m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Pbuffer) {
return true;
}
if (!InitPbufferSurface(width, height)) {
MGLOG_E("CreateEGLPbufferSurface failed: backend InitPbufferSurface failed");
return false;
}
m_eglSurfaceInitialized = true;
m_eglSurfaceKind = SurfaceKind::Pbuffer;
m_eglCurrentThreads.clear();
m_backendCapabilitiesInitialized = false;
return true;
}
Bool BackendObject::MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
const auto threadKey = CurrentThreadKey();
if (IsReleaseCurrentRequest(dpy, draw, read, ctx)) {
m_eglCurrentThreads.erase(threadKey);
return true;
}
if (!m_eglDisplayInitialized || m_eglDisplay != dpy) {
MGLOG_E("MakeEGLCurrent failed: EGL display mismatch or not initialized");
return false;
}
if (!m_eglSurfaceInitialized) {
MGLOG_E("MakeEGLCurrent failed: EGL surface is not initialized");
return false;
}
if (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE || ctx == EGL_NO_CONTEXT) {
MGLOG_E("MakeEGLCurrent failed: draw/read/context is invalid");
return false;
}
if (!m_backendCapabilitiesInitialized) {
if (!InitCapabilities()) {
MGLOG_E("MakeEGLCurrent failed: InitCapabilities failed");
return false;
}
m_backendCapabilitiesInitialized = true;
}
m_eglCurrentThreads[threadKey] = true;
return true;
}
void BackendObject::ResetEGLRuntimeState() {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
m_eglSurfaceInitialized = false;
m_backendCapabilitiesInitialized = false;
m_eglSurfaceKind = SurfaceKind::None;
m_eglCurrentThreads.clear();
}
Bool BackendObject::SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_eglDisplayInitialized || m_eglDisplay != dpy) {
MGLOG_E("SwapEGLBuffers failed: EGL display mismatch or not initialized");
return false;
}
if (m_eglCurrentThreads.find(CurrentThreadKey()) == m_eglCurrentThreads.end()) {
MGLOG_E("SwapEGLBuffers failed: no current context attached");
return false;
}
if (!m_eglSurfaceInitialized || draw == EGL_NO_SURFACE) {
MGLOG_E("SwapEGLBuffers failed: invalid draw surface");
return false;
}
const auto& backendFunctions = GetBackendFunctions();
if (!backendFunctions.Present) {
MGLOG_E("SwapEGLBuffers failed: backend Present function is null");
return false;
}
backendFunctions.Present();
return true;
}
void BackendObject::ReleaseEGLResources() {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
ResetEGLRuntimeState();
m_eglDisplay = EGL_NO_DISPLAY;
m_eglDisplayInitialized = false;
m_windowHandle = {};
}
void BackendObject::SetWindowHandle(const WindowHandle& handle) { void BackendObject::SetWindowHandle(const WindowHandle& handle) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
m_windowHandle = handle; m_windowHandle = handle;
} }
Bool BackendObject::InitPbufferSurface(EGLint width, EGLint height) {
(void)width;
(void)height;
return false;
}
} // namespace MobileGL::MG_Backend } // namespace MobileGL::MG_Backend
+3 -72
View File
@@ -8,17 +8,11 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
#include "MG_State/GLState/TextureState/TextureEnum.h"
namespace MobileGL { namespace MobileGL {
namespace MG_State::GLState {
class FramebufferObject;
class ITextureObject;
}
enum class BackendType { enum class BackendType {
DirectGLES, DirectGLES,
DirectVulkan, DirectVulkanTMP,
BackendTypeCount, BackendTypeCount,
Unknown = -1 Unknown = -1
}; };
@@ -37,10 +31,6 @@ namespace MobileGL {
void (*MultiDrawElementsIndirect)(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, void (*MultiDrawElementsIndirect)(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount,
GLsizei stride); GLsizei stride);
void (*MultiDrawArraysIndirect)(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride); void (*MultiDrawArraysIndirect)(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
void (*MultiDrawElementsIndirectCount)(GLenum mode, GLenum type, const void* indirect,
GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
void (*MultiDrawArraysIndirectCount)(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void (*DrawRangeElementsBaseVertex)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void (*DrawRangeElementsBaseVertex)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex); const void* indices, GLint basevertex);
void (*DrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void (*DrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
@@ -64,17 +54,8 @@ namespace MobileGL {
void (*ClearBufferfv)(GLenum buffer, GLint drawbuffer, const GLfloat* value); void (*ClearBufferfv)(GLenum buffer, GLint drawbuffer, const GLfloat* value);
void (*ClearBufferuiv)(GLenum buffer, GLint drawbuffer, const GLuint* value); void (*ClearBufferuiv)(GLenum buffer, GLint drawbuffer, const GLuint* value);
void (*ClearBufferiv)(GLenum buffer, GLint drawbuffer, const GLint* value); void (*ClearBufferiv)(GLenum buffer, GLint drawbuffer, const GLint* value);
void (*ClearNamedFramebufferfv)(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLfloat* value);
void (*ClearNamedFramebufferfi)(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void (*BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, void (*BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
void (*BlitNamedFramebuffer)(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
void (*CopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, void (*CopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
GLsizei height, GLint border); GLsizei height, GLint border);
void (*CopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, void (*CopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
@@ -83,27 +64,6 @@ namespace MobileGL {
void (*ReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void (*ReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
void* pixels); void* pixels);
void (*GetTexImage)(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels); void (*GetTexImage)(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
void (*GetTextureImage)(const SharedPtr<MG_State::GLState::ITextureObject>& texture,
TextureUploadTarget uploadTarget, GLint level, GLenum format, GLenum type,
GLsizei bufSize, GLvoid* pixels);
void (*DispatchCompute)(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
void (*DispatchComputeIndirect)(GLintptr indirect);
void (*MemoryBarrier)(GLbitfield barriers);
void (*MemoryBarrierByRegion)(GLbitfield barriers);
void (*BindImageTexture)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer,
GLenum access, GLenum format);
void (*GetIntegeri_v)(GLenum target, GLuint index, GLint* data);
void (*GetInteger64i_v)(GLenum target, GLuint index, GLint64* data);
void (*GetProgramiv)(GLuint program, GLenum pname, GLint* params);
void (*GetProgramInterfaceiv)(GLuint program, GLenum programInterface, GLenum pname, GLint* params);
GLuint (*GetProgramResourceIndex)(GLuint program, GLenum programInterface, const GLchar* name);
void (*GetProgramResourceName)(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize,
GLsizei* length, GLchar* name);
void (*GetProgramResourceiv)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount,
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params);
GLint (*GetProgramResourceLocation)(GLuint program, GLenum programInterface, const GLchar* name);
GLint (*GetProgramResourceLocationIndex)(GLuint program, GLenum programInterface, const GLchar* name);
void (*ShaderStorageBlockBinding)(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
}; };
struct GlobalBackendFunctionsTable { struct GlobalBackendFunctionsTable {
GLFunctionsTable GL; GLFunctionsTable GL;
@@ -112,16 +72,10 @@ namespace MobileGL {
struct DynamicBackendParameters { struct DynamicBackendParameters {
SizeT UniformBufferOffsetAlignment = 256; SizeT UniformBufferOffsetAlignment = 256;
SizeT MaxShaderStorageBlockSize = 128 * 1024 * 1024;
Uint32 SubgroupSize = 0;
Uint32 SubgroupSupportedStages = 0;
Uint32 SubgroupSupportedFeatures = 0;
Bool SubgroupQuadOperationsInAllStages = false;
}; };
enum class WindowBackend { enum class WindowBackend {
Android, Android,
X11,
// TODO: X11, Wayland, Windows, macOS, etc. // TODO: X11, Wayland, Windows, macOS, etc.
WindowBackendCount, WindowBackendCount,
Unknown = -1 Unknown = -1
@@ -137,15 +91,8 @@ namespace MobileGL {
virtual ~BackendObject() = default; virtual ~BackendObject() = default;
virtual void Initialize() = 0; virtual void Initialize() = 0;
virtual Bool InitCapabilities() = 0; virtual void InitCapabilities() = 0;
virtual Bool InitWindowSurface() = 0; virtual void InitWindowSurface() = 0;
virtual Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor);
virtual Bool CreateEGLWindowSurface(const WindowHandle& handle);
virtual Bool CreateEGLPbufferSurface(EGLint width, EGLint height);
virtual Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
virtual Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw);
virtual void ReleaseEGLResources();
void SetWindowHandle(const WindowHandle& handle); void SetWindowHandle(const WindowHandle& handle);
@@ -156,23 +103,7 @@ namespace MobileGL {
virtual BackendType GetBackendType() const = 0; virtual BackendType GetBackendType() const = 0;
protected: protected:
enum class SurfaceKind {
None,
Window,
Pbuffer
};
void ResetEGLRuntimeState();
virtual Bool InitPbufferSurface(EGLint width, EGLint height);
mutable std::recursive_mutex m_eglStateMutex;
WindowHandle m_windowHandle; WindowHandle m_windowHandle;
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
Bool m_eglDisplayInitialized = false;
Bool m_eglSurfaceInitialized = false;
Bool m_backendCapabilitiesInitialized = false;
SurfaceKind m_eglSurfaceKind = SurfaceKind::None;
UnorderedMap<std::thread::id, Bool> m_eglCurrentThreads;
}; };
} // namespace MG_Backend } // namespace MG_Backend
} // namespace MobileGL } // namespace MobileGL
+3 -1
View File
@@ -10,9 +10,11 @@
#include <Includes.h> #include <Includes.h>
#include "BackendObject.h" #include "BackendObject.h"
#include "DirectGLES/BackendObject_DirectGLES.h" #include "DirectGLES/BackendObject_DirectGLES.h"
#include "DirectVulkan/BackendObject_DirectVulkan.h" #include "DirectVulkanTMP/BackendObject_DirectVulkanTMP.h"
namespace MobileGL::MG_Backend { namespace MobileGL::MG_Backend {
extern UniquePtr<BackendObject> pActiveBackendObject; extern UniquePtr<BackendObject> pActiveBackendObject;
extern GlobalBackendFunctionsTable gBackendFunctionsTable; extern GlobalBackendFunctionsTable gBackendFunctionsTable;
void Init();
} // namespace MobileGL::MG_Backend } // namespace MobileGL::MG_Backend
@@ -13,24 +13,16 @@
#include <format> #include <format>
namespace MobileGL::MG_Backend::DirectGLES { namespace MobileGL::MG_Backend::DirectGLES {
namespace {
Bool IsReleaseCurrentRequest(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
return dpy == EGL_NO_DISPLAY && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT;
}
} // namespace
BackendObject_DirectGLES::~BackendObject_DirectGLES() { BackendObject_DirectGLES::~BackendObject_DirectGLES() {
DestroyEGLContext(); DestroyEGLContext();
} }
Bool BackendObject_DirectGLES::InitWindowSurface() { void BackendObject_DirectGLES::InitWindowSurface() {
// Only use EGL for now // Only use EGL for now
auto nativeWindow = reinterpret_cast<NativeWindowType>(m_windowHandle.Handle); auto nativeWindow = reinterpret_cast<NativeWindowType>(m_windowHandle.Handle);
if (!DirectGLES::InitWindowSurface(nativeWindow)) { if (!DirectGLES::InitWindowSurface(nativeWindow)) {
MGLOG_E("Failed to initialize window surface for DirectGLES backend"); MGLOG_E("Failed to initialize window surface for DirectGLES backend");
return false;
} }
return true;
} }
void BackendObject_DirectGLES::Initialize() { void BackendObject_DirectGLES::Initialize() {
@@ -48,75 +40,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
DirectGLES::SetGLESFuncsTable(m_GLESFunctions); DirectGLES::SetGLESFuncsTable(m_GLESFunctions);
} }
Bool BackendObject_DirectGLES::InitCapabilities() { void BackendObject_DirectGLES::InitCapabilities() {
if (!m_initialized) { if (!m_initialized) {
MGLOG_E("DirectGLES backend not initialized"); MGLOG_E("DirectGLES backend not initialized");
return false; return;
} }
if (!MG_Util::BackendLoader::FillInGLESCapabilities(m_GLESCapabilities, m_GLESFunctions)) { if (!MG_Util::BackendLoader::FillInGLESCapabilities(m_GLESCapabilities, m_GLESFunctions)) {
MGLOG_E("Failed to fill in GLES capabilities for DirectGLES backend"); MGLOG_E("Failed to fill in GLES capabilities for DirectGLES backend");
return false; return;
} }
DirectGLES::SetGLESCapabilities(m_GLESCapabilities); DirectGLES::SetGLESCapabilities(m_GLESCapabilities);
UpdateDynamicBackendParameters(); UpdateDynamicBackendParameters();
return true;
}
Bool BackendObject_DirectGLES::InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) {
if (!m_initialized) {
MGLOG_E("DirectGLES backend not initialized");
return false;
}
return BackendObject::InitializeEGLDisplay(dpy, major, minor);
}
Bool BackendObject_DirectGLES::CreateEGLWindowSurface(const WindowHandle& handle) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_initialized) {
MGLOG_E("DirectGLES backend not initialized");
return false;
}
if ((handle.Backend != WindowBackend::Android && handle.Backend != WindowBackend::X11) || !handle.Handle) {
MGLOG_E("DirectGLES backend only supports Android and X11 native windows");
return false;
}
const Bool sameHandle = m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Window &&
m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
if (sameHandle) {
return true;
}
if (m_eglSurfaceInitialized) {
DestroyEGLContext();
ResetEGLRuntimeState();
}
return BackendObject::CreateEGLWindowSurface(handle);
}
Bool BackendObject_DirectGLES::InitPbufferSurface(EGLint width, EGLint height) {
return DirectGLES::InitPbufferSurface(width, height);
}
Bool BackendObject_DirectGLES::MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
if (IsReleaseCurrentRequest(dpy, draw, read, ctx)) {
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
}
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
}
Bool BackendObject_DirectGLES::SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) {
return BackendObject::SwapEGLBuffers(dpy, draw);
}
void BackendObject_DirectGLES::ReleaseEGLResources() {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
DestroyEGLContext();
BackendObject::ReleaseEGLResources();
} }
const RendererInfo& BackendObject_DirectGLES::GetRendererInfo() const { const RendererInfo& BackendObject_DirectGLES::GetRendererInfo() const {
@@ -129,13 +64,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
.TargetGLVersion = {3, 3, 0}, // Target OpenGL Version .TargetGLVersion = {3, 3, 0}, // Target OpenGL Version
.TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version .TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions .Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
V_OpenGL33, E_GL_ARB_draw_buffers_blend, E_GL_ARB_compute_shader, V_OpenGL33, E_GL_ARB_draw_buffers_blend},
E_GL_ARB_shader_storage_buffer_object, E_GL_ARB_shader_image_load_store,
E_GL_ARB_program_interface_query, E_GL_ARB_framebuffer_object,
E_GL_EXT_framebuffer_object, E_GL_ARB_depth_texture, E_GL_ARB_buffer_storage,
E_GL_ARB_texture_storage, E_GL_ARB_direct_state_access,
E_GL_ARB_multi_draw_indirect, E_GL_ARB_indirect_parameters,
E_GL_ARB_shader_draw_parameters},
.IsCompatibilityProfile = false // Is Compatibility Profile .IsCompatibilityProfile = false // Is Compatibility Profile
}, },
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability .StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
@@ -169,7 +98,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
funcsTable.GL.MultiDrawElements = MultiDrawElements; funcsTable.GL.MultiDrawElements = MultiDrawElements;
funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex; funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex;
funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect; funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect;
funcsTable.GL.MultiDrawElementsIndirectCount = MultiDrawElementsIndirectCount;
funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect; funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect;
funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex; funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex;
funcsTable.GL.DrawRangeElements = DrawRangeElements; funcsTable.GL.DrawRangeElements = DrawRangeElements;
@@ -181,30 +109,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
funcsTable.GL.DrawArraysInstanced = DrawArraysInstanced; funcsTable.GL.DrawArraysInstanced = DrawArraysInstanced;
funcsTable.GL.DrawElementsIndirect = DrawElementsIndirect; funcsTable.GL.DrawElementsIndirect = DrawElementsIndirect;
funcsTable.GL.DrawArraysIndirect = DrawArraysIndirect; funcsTable.GL.DrawArraysIndirect = DrawArraysIndirect;
funcsTable.GL.DispatchCompute = DispatchCompute;
funcsTable.GL.DispatchComputeIndirect = DispatchComputeIndirect;
funcsTable.GL.MemoryBarrier = MemoryBarrier;
funcsTable.GL.MemoryBarrierByRegion = MemoryBarrierByRegion;
funcsTable.GL.BindImageTexture = BindImageTexture;
funcsTable.GL.GetIntegeri_v = GetIntegeri_v;
funcsTable.GL.GetInteger64i_v = GetInteger64i_v;
funcsTable.GL.GetProgramiv = GetProgramiv;
funcsTable.GL.GetProgramInterfaceiv = GetProgramInterfaceiv;
funcsTable.GL.GetProgramResourceIndex = GetProgramResourceIndex;
funcsTable.GL.GetProgramResourceName = GetProgramResourceName;
funcsTable.GL.GetProgramResourceiv = GetProgramResourceiv;
funcsTable.GL.GetProgramResourceLocation = GetProgramResourceLocation;
funcsTable.GL.GetProgramResourceLocationIndex = GetProgramResourceLocationIndex;
funcsTable.GL.ShaderStorageBlockBinding = ShaderStorageBlockBinding;
funcsTable.GL.Clear = Clear; funcsTable.GL.Clear = Clear;
funcsTable.GL.ClearBufferfi = ClearBufferfi; funcsTable.GL.ClearBufferfi = ClearBufferfi;
funcsTable.GL.ClearBufferfv = ClearBufferfv; funcsTable.GL.ClearBufferfv = ClearBufferfv;
funcsTable.GL.ClearBufferuiv = ClearBufferuiv; funcsTable.GL.ClearBufferuiv = ClearBufferuiv;
funcsTable.GL.ClearBufferiv = ClearBufferiv; funcsTable.GL.ClearBufferiv = ClearBufferiv;
funcsTable.GL.ClearNamedFramebufferfv = ClearNamedFramebufferfv;
funcsTable.GL.ClearNamedFramebufferfi = ClearNamedFramebufferfi;
funcsTable.GL.BlitFramebuffer = BlitFramebuffer; funcsTable.GL.BlitFramebuffer = BlitFramebuffer;
funcsTable.GL.BlitNamedFramebuffer = BlitNamedFramebuffer;
funcsTable.GL.CopyTexImage2D = CopyTexImage2D; funcsTable.GL.CopyTexImage2D = CopyTexImage2D;
funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D; funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D;
funcsTable.GL.GenerateMipmap = GenerateMipmap; funcsTable.GL.GenerateMipmap = GenerateMipmap;
@@ -17,13 +17,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
~BackendObject_DirectGLES() override; ~BackendObject_DirectGLES() override;
void Initialize() override; void Initialize() override;
Bool InitCapabilities() override; void InitCapabilities() override;
Bool InitWindowSurface() override; void InitWindowSurface() override;
Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) override;
Bool CreateEGLWindowSurface(const WindowHandle& handle) override;
Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) override;
Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) override;
void ReleaseEGLResources() override;
const RendererInfo& GetRendererInfo() const override; const RendererInfo& GetRendererInfo() const override;
String GetBackendAPIVersionString() const override; String GetBackendAPIVersionString() const override;
@@ -36,7 +31,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
private: private:
void UpdateDynamicBackendParameters(); void UpdateDynamicBackendParameters();
Bool InitPbufferSurface(EGLint width, EGLint height) override;
Bool m_initialized = false; Bool m_initialized = false;
MG_External::EGLFunctionsTable m_EGLFunctions; MG_External::EGLFunctionsTable m_EGLFunctions;
File diff suppressed because it is too large Load Diff
@@ -8,7 +8,6 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
#include <MG_State/GLState/TextureState/TextureState.h> #include <MG_State/GLState/TextureState/TextureState.h>
#include <MG_State/GLState/SamplerState/SamplerObject.h> #include <MG_State/GLState/SamplerState/SamplerObject.h>
#include <MG_Util/BackendLoaders/OpenGL/Loader.h> #include <MG_Util/BackendLoaders/OpenGL/Loader.h>
@@ -31,8 +30,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices, void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount, const GLint* basevertex); GLsizei drawcount, const GLint* basevertex);
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride); void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride);
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride); void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex); const void* indices, GLint basevertex);
@@ -49,17 +46,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
GLuint baseinstance); GLuint baseinstance);
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
void DrawArraysIndirect(GLenum mode, const void* indirect); void DrawArraysIndirect(GLenum mode, const void* indirect);
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
GLint dstY1, GLbitfield mask, GLenum filter); GLint dstY1, GLbitfield mask, GLenum filter);
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
GLsizei height, GLint border); GLsizei height, GLint border);
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
@@ -68,26 +56,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
const GLubyte* GetString(GLenum name); const GLubyte* GetString(GLenum name);
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels); void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
void DispatchComputeIndirect(GLintptr indirect);
void MemoryBarrier(GLbitfield barriers);
void MemoryBarrierByRegion(GLbitfield barriers);
void BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access,
GLenum format);
void GetIntegeri_v(GLenum target, GLuint index, GLint* data);
void GetInteger64i_v(GLenum target, GLuint index, GLint64* data);
void GetProgramiv(GLuint program, GLenum pname, GLint* params);
void GetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint* params);
GLuint GetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar* name);
void GetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length,
GLchar* name);
void GetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount,
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params);
GLint GetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar* name);
GLint GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, const GLchar* name);
void ShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
Bool InitWindowSurface(NativeWindowType window); Bool InitWindowSurface(NativeWindowType window);
Bool InitPbufferSurface(EGLint width, EGLint height);
void Present(); void Present();
void SetEGLFuncsTable(const MG_External::EGLFunctionsTable& eglFuncs); void SetEGLFuncsTable(const MG_External::EGLFunctionsTable& eglFuncs);
void SetGLESFuncsTable(const MG_External::GLESFunctionsTable& glesFuncs); void SetGLESFuncsTable(const MG_External::GLESFunctionsTable& glesFuncs);
+106 -319
View File
@@ -7,6 +7,10 @@
// 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"
@@ -14,7 +18,6 @@
#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>
@@ -23,63 +26,9 @@
#include <MG_Util/Converters/GLToMG/FramebufferEnumConverter.h> #include <MG_Util/Converters/GLToMG/FramebufferEnumConverter.h>
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h> #include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
#include <MG_State/GLState/FramebufferState/FramebufferObject.h> #include <MG_State/GLState/FramebufferState/FramebufferObject.h>
#include <cctype>
namespace MobileGL::MG_Backend::DirectGLES { namespace MobileGL::MG_Backend::DirectGLES {
constexpr Bool PREFER_MAP_BUFFER_RANGE_FOR_BUFFER_SYNC = true; constexpr Bool PREFER_MAP_BUFFER_RANGE_FOR_BUFFER_SYNC = true;
constexpr const char* BASE_INSTANCE_UNIFORM_NAME = "mg_BaseInstance";
static Uint ResolveBackendEsslVersion() {
const auto& version = g_GLESCapabilities.GLESVersion;
if (version.Major > 3 || (version.Major == 3 && version.Minor >= 2)) {
return 320;
}
if (version.Major == 3 && version.Minor >= 1) {
return 310;
}
return 300;
}
String ReplaceIdentifier(String source, const String& from, const String& to) {
SizeT pos = 0;
while ((pos = source.find(from, pos)) != String::npos) {
const Bool leftIsIdent = pos > 0 &&
(std::isalnum(static_cast<unsigned char>(source[pos - 1])) || source[pos - 1] == '_');
const SizeT end = pos + from.size();
const Bool rightIsIdent = end < source.size() &&
(std::isalnum(static_cast<unsigned char>(source[end])) || source[end] == '_');
if (!leftIsIdent && !rightIsIdent) {
source.replace(pos, from.size(), to);
pos += to.size();
} else {
pos = end;
}
}
return source;
}
String InjectUniformAfterVersion(String source, const String& declaration) {
const SizeT versionPos = source.find("#version");
if (versionPos == String::npos) {
return declaration + "\n" + source;
}
const SizeT lineEnd = source.find('\n', versionPos);
if (lineEnd == String::npos) {
return source + "\n" + declaration + "\n";
}
source.insert(lineEnd + 1, declaration + "\n");
return source;
}
String EmulateBaseInstanceInVertexShader(String source, GLenum shaderType) {
if (shaderType != GL_VERTEX_SHADER || source.find("gl_BaseInstance") == String::npos) {
return source;
}
source = ReplaceIdentifier(std::move(source), "gl_BaseInstance", BASE_INSTANCE_UNIFORM_NAME);
return InjectUniformAfterVersion(std::move(source),
String("uniform highp int ") + BASE_INSTANCE_UNIFORM_NAME + ";");
}
namespace BufferImpl { namespace BufferImpl {
BackendBufferObject::BackendBufferObject() { BackendBufferObject::BackendBufferObject() {
@@ -95,7 +44,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void BackendBufferObject::SyncToBackend(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) { void BackendBufferObject::SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -156,7 +105,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
void BackendBufferObject::SyncToBackend_glBufferData( void BackendBufferObject::SyncToBackend_glBufferData(
const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) { SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -168,11 +117,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, (GLsizeiptr)size, data, usage); g_GLESFuncs.glBufferData(TempBufferTarget, size, data, usage);
} }
void BackendBufferObject::SyncToBackend_glBufferSubData( void BackendBufferObject::SyncToBackend_glBufferSubData(
const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) { SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -181,7 +130,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;
@@ -189,21 +138,20 @@ namespace MobileGL::MG_Backend::DirectGLES {
for (const auto& range : ranges) { for (const auto& range : ranges) {
Bind(); Bind();
g_GLESFuncs.glBufferSubData(TempBufferTarget, (GLintptr)range.start, g_GLESFuncs.glBufferSubData(TempBufferTarget, range.start, range.end - 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(
const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, Bool invalidate, Bool unsynchronized) { 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;
@@ -211,9 +159,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( void* mappedData = g_GLESFuncs.glMapBufferRange(TempBufferTarget, minStart, maxEnd - minStart,
TempBufferTarget, (GLintptr)minStart, (GLintptr)(maxEnd - minStart), (invalidate ? GL_MAP_INVALIDATE_RANGE_BIT : 0) |
(invalidate ? GL_MAP_INVALIDATE_RANGE_BIT : 0) | (unsynchronized ? GL_MAP_UNSYNCHRONIZED_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) {
@@ -221,8 +169,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, (GLintptr)(range.start - minStart), g_GLESFuncs.glFlushMappedBufferRange(TempBufferTarget, range.start - minStart,
(GLintptr)(range.end - range.start)); range.end - range.start);
} }
g_GLESFuncs.glUnmapBuffer(TempBufferTarget); g_GLESFuncs.glUnmapBuffer(TempBufferTarget);
} else { } else {
@@ -243,39 +191,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glBindBuffer(target, m_backendBufferId); g_GLESFuncs.glBindBuffer(target, m_backendBufferId);
} }
StateBackendObjectRegistry<MG_State::GLState::BufferObject, BackendBufferObject> g_backendBufferObjects; UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>> g_backendBufferObjects;
BackendBufferObject* g_boundVertexBufferObject = nullptr; BackendBufferObject* g_boundVertexBufferObject = nullptr;
} // namespace BufferImpl } // namespace BufferImpl
namespace VertexArrayImpl { namespace VertexArrayImpl {
namespace {
SizeT GetDataTypeSize(DataType type) {
switch (type) {
case DataType::Int8:
case DataType::Uint8:
return 1;
case DataType::Int16:
case DataType::Uint16:
case DataType::Float16:
return 2;
case DataType::Int32:
case DataType::Uint32:
case DataType::Float32:
case DataType::Fixed32:
return 4;
case DataType::Float64:
return 8;
default:
return 0;
}
}
} // namespace
BackendVertexArrayObject::BackendVertexArrayObject() { BackendVertexArrayObject::BackendVertexArrayObject() {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
m_clientAttributeBufferIds.fill(0);
g_GLESFuncs.glGenVertexArrays(1, &m_backendVAOId); g_GLESFuncs.glGenVertexArrays(1, &m_backendVAOId);
if (m_backendVAOId == 0) { if (m_backendVAOId == 0) {
MGLOG_E("Failed to generate vertex array object."); MGLOG_E("Failed to generate vertex array object.");
@@ -285,46 +209,32 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
BackendVertexArrayObject::~BackendVertexArrayObject() { void BackendVertexArrayObject::Bind() {
if (m_backendVAOId != 0) {
g_GLESFuncs.glDeleteVertexArrays(1, &m_backendVAOId);
m_backendVAOId = 0;
}
for (auto& bufferId : m_clientAttributeBufferIds) {
if (bufferId != 0) {
g_GLESFuncs.glDeleteBuffers(1, &bufferId);
bufferId = 0;
}
}
}
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);
} }
inline Bool BindAttributeBuffer(const MG_State::GLState::VertexAttribute& attrib) { void BackendVertexArrayObject::BindAttributeBuffer(Uint index,
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 false; return;
} }
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObject.get()); const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObject);
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 false; return;
} }
const auto& backendBufferObject = backendBufferIt->second; const auto& backendBufferObject = backendBufferIt->second;
backendBufferObject->Bind(GL_ARRAY_BUFFER); backendBufferObject->Bind(GL_ARRAY_BUFFER);
return true;
} }
void BackendVertexArrayObject::SyncToBackend( void BackendVertexArrayObject::SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject) {
const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -358,9 +268,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
m_syncedAttributeVersions[attribIndex].BufferVersion; m_syncedAttributeVersions[attribIndex].BufferVersion;
if (!needsSyncFormat && !needsSyncBuffer) continue; if (!needsSyncFormat && !needsSyncBuffer) continue;
if (!BindAttributeBuffer(attrib)) { BindAttributeBuffer(attribIndex, attrib);
continue;
}
if (!attrib.IsInteger) { if (!attrib.IsInteger) {
g_GLESFuncs.glVertexAttribPointer( g_GLESFuncs.glVertexAttribPointer(
@@ -380,82 +288,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
Uint16 currentIndexBufferVersion = stateVAOObject->GetIndexBufferBindingSlot().GetVersion(); Uint16 currentIndexBufferVersion = stateVAOObject->GetIndexBufferBindingSlot().GetVersion();
if (currentIndexBufferVersion != m_syncedIndexBufferVersion) { if (currentIndexBufferVersion != m_syncedIndexBufferVersion) {
const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject(); const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
Bool indexBufferSynced = false;
if (indexBufferBinding) { if (indexBufferBinding) {
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding.get()); const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding);
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);
indexBufferSynced = true;
} else { } else {
MGLOG_W("No backend buffer found for index buffer binding, cannot bind index buffer."); MGLOG_W("No backend buffer found for index buffer binding, cannot bind index buffer.");
} }
} else {
g_GLESFuncs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
indexBufferSynced = true;
} }
if (indexBufferSynced) {
m_syncedIndexBufferVersion = currentIndexBufferVersion; m_syncedIndexBufferVersion = currentIndexBufferVersion;
} }
}
m_syncedAttributeVersions = allAttributeVersions; m_syncedAttributeVersions = allAttributeVersions;
} }
void BackendVertexArrayObject::SyncClientSideAttributesForDrawArrays( UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>>
const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject, GLint first, GLsizei count) {
if (!stateVAOObject || count <= 0 || first < 0) {
return;
}
Bind();
const auto& allAttributes = stateVAOObject->GetAllAttributes();
for (Uint attribIndex = 0; attribIndex < allAttributes.size(); ++attribIndex) {
const auto& attrib = allAttributes[attribIndex];
if (!attrib.Enabled || attrib.Buffer) {
continue;
}
const auto* clientData = reinterpret_cast<const Uint8*>(attrib.Offset);
const SizeT componentSize = GetDataTypeSize(attrib.Type);
if (!clientData || componentSize == 0 || attrib.Size <= 0) {
continue;
}
const SizeT elementSize = componentSize * static_cast<SizeT>(attrib.Size);
const SizeT stride = attrib.Stride > 0 ? static_cast<SizeT>(attrib.Stride) : elementSize;
const SizeT uploadSize = static_cast<SizeT>(first + count - 1) * stride + elementSize;
auto& bufferId = m_clientAttributeBufferIds[attribIndex];
if (bufferId == 0) {
g_GLESFuncs.glGenBuffers(1, &bufferId);
if (bufferId == 0) {
MGLOG_E("Failed to create client-side vertex attribute upload buffer.");
continue;
}
}
g_GLESFuncs.glBindBuffer(GL_ARRAY_BUFFER, bufferId);
g_GLESFuncs.glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(uploadSize), clientData,
GL_STREAM_DRAW);
if (!attrib.IsInteger) {
g_GLESFuncs.glVertexAttribPointer(
attribIndex, attrib.Size, MG_Util::ConvertDataTypeToGLEnum(attrib.Type),
attrib.Normalized ? GL_TRUE : GL_FALSE, static_cast<GLsizei>(stride), nullptr);
} else {
g_GLESFuncs.glVertexAttribIPointer(attribIndex, attrib.Size,
MG_Util::ConvertDataTypeToGLEnum(attrib.Type),
static_cast<GLsizei>(stride), nullptr);
}
}
BufferImpl::g_boundVertexBufferObject = nullptr;
}
StateBackendObjectRegistry<MG_State::GLState::VertexArrayObject, BackendVertexArrayObject>
g_backendVertexArrayObjects; g_backendVertexArrayObjects;
} // namespace VertexArrayImpl } // namespace VertexArrayImpl
@@ -488,7 +336,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_boundTexturesCache[unit][targetN] = this; g_boundTexturesCache[unit][targetN] = this;
} }
Uint BackendTextureObject::GetBackendTextureId() const { Uint BackendTextureObject::GetBackendTextureId() {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -496,7 +344,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
void BackendTextureObject::SyncMipmapsToBackend( void BackendTextureObject::SyncMipmapsToBackend(
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) { 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;
@@ -505,6 +353,7 @@ 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());
@@ -532,7 +381,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
Bind(target); Bind(target);
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { 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();
@@ -565,7 +414,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);
@@ -580,22 +429,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");
DebugImpl::ErrorLopper::Clear(); 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( g_GLESFuncs.glTexImage2D(glUploadTarget, static_cast<GLint>(level), glInternalFormat,
glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat, static_cast<GLsizei>(levelTexelSize.x()),
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()), static_cast<GLsizei>(levelTexelSize.y()), 0, glFormat, glType,
0, glFormat, glType, pData); pData);
break; break;
} }
case TextureTarget::Texture3D: { case TextureTarget::Texture3D: {
g_GLESFuncs.glTexImage3D( g_GLESFuncs.glTexImage3D(
glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat, glUploadTarget, static_cast<GLint>(level), 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;
@@ -605,9 +454,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
MG_Util::ConvertTextureTargetToString(textureTarget).c_str()); MG_Util::ConvertTextureTargetToString(textureTarget).c_str());
} }
} }
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__, errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, glUploadTarget,
glUploadTarget, glInternalFormat, glFormat, glType, glInternalFormat, glFormat, glType, pData](GLenum err) {
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(),
@@ -630,7 +478,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;
@@ -651,8 +499,7 @@ 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);
DebugImpl::ErrorLopper::Loop( errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
[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());
}); });
@@ -671,27 +518,22 @@ 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();
if (!buffer) {
MGLOG_D("Texture buffer object with ID: %u has no bound buffer, skipping sync.",
stateTextureObject->GetExternalIndex());
return;
}
auto bufferIndex = buffer->GetExternalIndex(); auto bufferIndex = buffer->GetExternalIndex();
currentTextureInfo.bufferExternalIndex = bufferIndex; currentTextureInfo.bufferExternalIndex = bufferIndex;
Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo); Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo);
MGLOG_D("Texture state changed significantly or not initialized, regenerating texture (tex buffer) "
"with ID: %u",
m_backendTextureId);
// Need to sync texture buffer if not synced yet // Need to sync texture buffer if not synced yet
auto& backendBuffers = BufferImpl::g_backendBufferObjects; auto& backendBuffers = BufferImpl::g_backendBufferObjects;
SharedPtr<BufferImpl::BackendBufferObject> backendBufferObject; SharedPtr<BufferImpl::BackendBufferObject> backendBufferObject;
const auto& backendBufferIt = backendBuffers.find(buffer.get()); const auto& backendBufferIt = backendBuffers.find(buffer);
if (backendBufferIt == backendBuffers.end()) { if (backendBufferIt == backendBuffers.end()) {
auto& backendBufferSlot = backendBuffers.GetOrCreate(buffer); backendBufferObject = MakeShared<BufferImpl::BackendBufferObject>();
if (!backendBufferSlot) { backendBuffers[buffer] = backendBufferObject;
backendBufferSlot = MakeShared<BufferImpl::BackendBufferObject>();
}
backendBufferObject = backendBufferSlot;
} else { } else {
backendBufferObject = backendBufferIt->second; backendBufferObject = backendBufferIt->second;
} }
@@ -704,26 +546,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
TextureImpl::GenerateTextureFormatInfo(textureBufferObject->GetFormat(), &glInternalFormat, &glFormat, TextureImpl::GenerateTextureFormatInfo(textureBufferObject->GetFormat(), &glInternalFormat, &glFormat,
&glType); &glType);
if (needsRegeneration) {
MGLOG_D("Texture state changed significantly or not initialized, regenerating texture buffer with "
"ID: %u, buffer ID: %u, buffer size: %zu, format: %s",
m_backendTextureId, backendId, buffer->GetSize(),
MG_Util::ConvertGLEnumToString(glInternalFormat).c_str());
g_GLESFuncs.glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId); g_GLESFuncs.glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId);
DebugImpl::ErrorLopper::Loop(
[file = __FILE__, line = __LINE__, func = __func__, glInternalFormat, backendId](GLenum err) {
MGLOG_D("%s(%s:%d) glTexBuffer(format=%s, buffer=%u) ES error: %s",
func, file, line, MG_Util::ConvertGLEnumToString(glInternalFormat).c_str(),
backendId, MG_Util::ConvertGLEnumToString(err).c_str());
});
}
break; break;
} }
default: default:
THROW_UNIMPL_EXCEPTION; THROW_UNIMPL_EXCEPTION;
} }
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { 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());
}); });
@@ -731,11 +561,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
void BackendTextureObject::SyncBuiltinSamplerToBackend( void BackendTextureObject::SyncBuiltinSamplerToBackend(
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) { 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;
@@ -764,7 +594,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
Bind(target); Bind(target);
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { 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());
}); });
@@ -777,8 +607,7 @@ 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; \
DebugImpl::ErrorLopper::Loop( \ errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, \
[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()); \
@@ -787,29 +616,25 @@ 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(target, GL_TEXTURE_MIN_FILTER, g_GLESFuncs.glTexParameteri(
(GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.minFilter, target, GL_TEXTURE_MIN_FILTER,
samplerParams.mipmapMode)); MG_Util::ConvertSamplerFilterModeToGLEnum(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.glTexParameteri( g_GLESFuncs.glTexParameteri(
target, GL_TEXTURE_MAG_FILTER, target, GL_TEXTURE_MAG_FILTER,
(GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None)); MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None));
m_cacheSamplerParameters.magFilter = samplerParams.magFilter; m_cacheSamplerParameters.magFilter = samplerParams.magFilter;
} }
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { 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());
}); });
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapS, GL_TEXTURE_WRAP_S, WrapMode) SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapS, GL_TEXTURE_WRAP_S, WrapMode)
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapT, GL_TEXTURE_WRAP_T, WrapMode) SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapT, GL_TEXTURE_WRAP_T, WrapMode)
if (SupportsWrapR(targetInternal)) {
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapR, GL_TEXTURE_WRAP_R, WrapMode) SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapR, GL_TEXTURE_WRAP_R, WrapMode)
} else {
m_cacheSamplerParameters.wrapR = samplerParams.wrapR;
}
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareFunc, GL_TEXTURE_COMPARE_FUNC, CompareFunc) SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareFunc, GL_TEXTURE_COMPARE_FUNC, CompareFunc)
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareMode, GL_TEXTURE_COMPARE_MODE, CompareMode) SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareMode, GL_TEXTURE_COMPARE_MODE, CompareMode)
if (m_cacheSamplerParameters.minLod != samplerParams.minLod) { if (m_cacheSamplerParameters.minLod != samplerParams.minLod) {
@@ -820,18 +645,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;
} }
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { 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(
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) { 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;
@@ -858,7 +683,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
Bind(target); Bind(target);
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { 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());
}); });
@@ -871,14 +696,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();
} }
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { 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();
} }
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { 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());
}); });
@@ -895,7 +720,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;
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { 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());
}); });
} }
@@ -905,7 +730,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;
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { 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());
}); });
} }
@@ -935,7 +760,8 @@ 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;
StateBackendObjectRegistry<MG_State::GLState::ITextureObject, BackendTextureObject> g_backendTextureObjects; UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>>
g_backendTextureObjects;
} // namespace TextureImpl } // namespace TextureImpl
namespace FramebufferImpl { namespace FramebufferImpl {
@@ -952,7 +778,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void BackendFramebufferObject::Bind(FramebufferTarget target) const { void BackendFramebufferObject::Bind(FramebufferTarget target) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -962,37 +788,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId); g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId);
} }
void BackendFramebufferObject::InvalidateSyncedState() { Bool BackendFramebufferObject::SyncAttachmentObject(
std::fill(std::begin(m_frontendDrawBuffers), std::end(m_frontendDrawBuffers), GLenum glFBOTarget, const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
FramebufferAttachmentType::Unknown);
std::fill(std::begin(m_backendDrawBuffers), std::end(m_backendDrawBuffers), GL_NONE);
m_frontendReadBuffer = FramebufferAttachmentType::Unknown;
m_backendReadBuffer = GL_NONE;
std::fill(m_syncedFrontendAttachmentVersions.begin(), m_syncedFrontendAttachmentVersions.end(),
static_cast<Uint16>(~0u));
}
static Bool SyncAttachmentObject(GLenum glFBOTarget,
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
GLenum glBackendAttachment) { GLenum glBackendAttachment) {
if (attachmentObject.IsTexture()) { if (attachmentObject.IsTexture()) {
const auto& textureObject = attachmentObject.GetTexture(); const auto& textureObject = attachmentObject.GetTexture();
SharedPtr<TextureImpl::BackendTextureObject> backendTextureObject; const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) { if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
auto& backendTextureSlot = TextureImpl::g_backendTextureObjects.GetOrCreate(textureObject);
if (!backendTextureSlot) {
backendTextureSlot = MakeShared<TextureImpl::BackendTextureObject>();
}
backendTextureObject = backendTextureSlot;
} else {
backendTextureObject = backendTextureIt->second;
}
if (!backendTextureObject) {
MGLOG_E("%s: No backend texture found for FBO attachment, cannot bind texture.", __func__); MGLOG_E("%s: No backend texture found for FBO attachment, cannot bind texture.", __func__);
return false; return false;
} }
backendTextureObject->SyncMipmapsToBackend(textureObject); const auto& backendTextureObject = backendTextureIt->second;
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget()); auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
backendTextureObject->Bind(glTextureTarget); backendTextureObject->Bind(glTextureTarget);
g_GLESFuncs.glFramebufferTexture2D(glFBOTarget, glBackendAttachment, glTextureTarget, g_GLESFuncs.glFramebufferTexture2D(glFBOTarget, glBackendAttachment, glTextureTarget,
@@ -1001,15 +807,11 @@ 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.get()); RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject; SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) { if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
auto& backendRenderbufferSlot = backendRenderbufferObject = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
RenderbufferImpl::g_backendRenderbufferObjects.GetOrCreate(renderbufferObject); RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject;
if (!backendRenderbufferSlot) {
backendRenderbufferSlot = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
}
backendRenderbufferObject = backendRenderbufferSlot;
} else { } else {
backendRenderbufferObject = backendRenderbufferIt->second; backendRenderbufferObject = backendRenderbufferIt->second;
} }
@@ -1022,8 +824,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
return true; return true;
} }
void BackendFramebufferObject::SyncToBackend( void BackendFramebufferObject::SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, FramebufferTarget asTarget) { FramebufferTarget asTarget) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -1051,7 +853,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;
@@ -1090,7 +892,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];
auto frontendType = static_cast<FramebufferAttachmentType>(i); FramebufferAttachmentType 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)
@@ -1100,10 +902,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
// relevant FRONTEND!!! version should be checked and updated // relevant FRONTEND!!! version should be checked and updated
if (m_syncedFrontendAttachmentVersions[i] != attachmentVersions[i]) { if (m_syncedFrontendAttachmentVersions[i] != attachmentVersions[i]) {
if (SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment)) { SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment);
m_syncedFrontendAttachmentVersions[i] = attachmentVersions[i]; m_syncedFrontendAttachmentVersions[i] = attachmentVersions[i];
} }
}
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG #if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
else { else {
MGLOG_D("%s: Skipped SyncAttachmentObject(target=%s, frontendObj=(%dx%dx%d, %s), backendAtt=%s), " MGLOG_D("%s: Skipped SyncAttachmentObject(target=%s, frontendObj=(%dx%dx%d, %s), backendAtt=%s), "
@@ -1114,9 +915,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
MG_Util::ConvertFramebufferAttachmentTypeToString(frontendType).c_str(), MG_Util::ConvertFramebufferAttachmentTypeToString(frontendType).c_str(),
MG_Util::ConvertGLEnumToString(glBackendAttachment).c_str(), MG_Util::ConvertGLEnumToString(glBackendAttachment).c_str(),
m_syncedFrontendAttachmentVersions[i]); m_syncedFrontendAttachmentVersions[i]);
if (!attachmentObject.IsTexture() && !attachmentObject.IsRenderbuffer()) {
continue;
}
GLint objectType = GL_NONE; GLint objectType = GL_NONE;
g_GLESFuncs.glGetFramebufferAttachmentParameteriv( g_GLESFuncs.glGetFramebufferAttachmentParameteriv(
glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &objectType); glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &objectType);
@@ -1130,7 +928,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.get()); auto backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
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();
@@ -1146,8 +944,7 @@ 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 = auto backendRboIt = RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
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.");
@@ -1178,13 +975,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
return glBackendReadBuffer; return glBackendReadBuffer;
} }
StateBackendObjectRegistry<MG_State::GLState::FramebufferObject, BackendFramebufferObject> UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<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 {
StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl> g_backendProgramObjects; UnorderedMap<SharedPtr<MG_State::GLState::ProgramObject>, SharedPtr<BackendProgramObjectImpl>>
g_backendProgramObjects;
BackendProgramObjectImpl::BackendProgramObjectImpl() { BackendProgramObjectImpl::BackendProgramObjectImpl() {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
@@ -1210,8 +1008,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void BackendProgramObjectImpl::SyncToBackend( void BackendProgramObjectImpl::SyncToBackend(SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject) {
const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -1271,14 +1068,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
String source; String source;
auto& spirvCode = shaderSpirvs[index]; auto& spirvCode = shaderSpirvs[index];
MG_Util::ShaderTranspiler::SpvcSession spvcSession(spirvCode, MG_Util::ShaderTranspiler::SpvcSession spvcSession(spirvCode);
MG_Util::ShaderTranspiler::SessionUsageBit::Transpile);
spvc_compiler_options options; spvc_compiler_options options;
spvcSession.CreateOptions(&options); spvcSession.CreateOptions(&options);
spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, // TODO: check ESSL version supported by backend driver
ResolveBackendEsslVersion()); spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, 320);
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_TRUE); spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_TRUE);
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, SPVC_FALSE); spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, SPVC_FALSE);
@@ -1300,8 +1096,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
source = RemoveLayoutBinding(source); source = RemoveLayoutBinding(source);
source = ProcessOutColorLocations(source); source = ProcessOutColorLocations(source);
source = ForceFlatIntegerVaryings(source, glShaderType);
source = EmulateBaseInstanceInVertexShader(std::move(source), glShaderType);
source = ForceSupporterOutput(source); source = ForceSupporterOutput(source);
// Patch for Photon compiler precision issue // Patch for Photon compiler precision issue
@@ -1352,8 +1146,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
} else { } else {
MGLOG_D("Program linked successfully. ID: %u", m_backendProgramId); MGLOG_D("Program linked successfully. ID: %u", m_backendProgramId);
} }
m_baseInstanceUniformLocation = g_GLESFuncs.glGetUniformLocation(m_backendProgramId,
BASE_INSTANCE_UNIFORM_NAME);
// Create global UBO // Create global UBO
if (stateProgramObject->GetUBOSize() > 0) { if (stateProgramObject->GetUBOSize() > 0) {
@@ -1369,20 +1161,13 @@ 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() const { void BackendProgramObjectImpl::Use() {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
MGLOG_D("Using program %u", m_backendProgramId); MGLOG_D("Using program %u", m_backendProgramId);
g_GLESFuncs.glUseProgram(m_backendProgramId); g_GLESFuncs.glUseProgram(m_backendProgramId);
} }
void BackendProgramObjectImpl::SetBaseInstance(Uint32 baseInstance) const {
if (m_baseInstanceUniformLocation < 0) {
return;
}
g_GLESFuncs.glUniform1i(m_baseInstanceUniformLocation, static_cast<GLint>(baseInstance));
}
} // namespace PrgramImpl } // namespace PrgramImpl
namespace SamplerImpl { namespace SamplerImpl {
@@ -1399,8 +1184,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void BackendSamplerObject::SyncToBackend( void BackendSamplerObject::SyncToBackend(SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject) {
const SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -1426,22 +1210,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, \
(GLint)MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)); \ 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(m_backendSamplerId, GL_TEXTURE_MIN_FILTER, g_GLESFuncs.glSamplerParameteri(
(GLint)MG_Util::ConvertSamplerFilterModeToGLEnum( m_backendSamplerId, GL_TEXTURE_MIN_FILTER,
samplerParams.minFilter, samplerParams.mipmapMode)); MG_Util::ConvertSamplerFilterModeToGLEnum(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,
(GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None)); MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None));
m_cacheSamplerParameters.magFilter = samplerParams.magFilter; m_cacheSamplerParameters.magFilter = samplerParams.magFilter;
} }
@@ -1472,7 +1256,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_boundSamplersCache[unit] = this; g_boundSamplersCache[unit] = this;
} }
Uint BackendSamplerObject::GetBackendSamplerId() const { Uint BackendSamplerObject::GetBackendSamplerId() {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -1487,7 +1271,8 @@ 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;
StateBackendObjectRegistry<MG_State::GLState::SamplerObject, BackendSamplerObject> g_backendSamplerObjects; UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>>
g_backendSamplerObjects;
} // namespace SamplerImpl } // namespace SamplerImpl
namespace RenderbufferImpl { namespace RenderbufferImpl {
@@ -1502,7 +1287,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void BackendRenderbufferObject::Bind() const { void BackendRenderbufferObject::Bind() {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -1549,7 +1334,9 @@ 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);
} }
StateBackendObjectRegistry<MG_State::GLState::RenderbufferObject, BackendRenderbufferObject> UnorderedMap<SharedPtr<MG_State::GLState::RenderbufferObject>, SharedPtr<BackendRenderbufferObject>>
g_backendRenderbufferObjects; g_backendRenderbufferObjects;
} // namespace RenderbufferImpl } // namespace RenderbufferImpl
namespace Utils {} // namespace Utils
} // namespace MobileGL::MG_Backend::DirectGLES } // namespace MobileGL::MG_Backend::DirectGLES
+34 -135
View File
@@ -15,115 +15,19 @@
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
namespace MobileGL::MG_Backend::DirectGLES { namespace MobileGL::MG_Backend::DirectGLES {
String EmulateBaseInstanceInVertexShader(String source, GLenum shaderType);
template <typename StateObject, typename BackendObject>
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(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject); void SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
Uint GetBackendBufferId() const { return m_backendBufferId; } Uint GetBackendBufferId() { return m_backendBufferId; }
void Bind(GLenum target = TempBufferTarget); void Bind(GLenum target = TempBufferTarget);
private: private:
void SyncToBackend_glBufferData(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject); void SyncToBackend_glBufferData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
void SyncToBackend_glBufferSubData(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject); void SyncToBackend_glBufferSubData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
void SyncToBackend_glMapBufferRange(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, void SyncToBackend_glMapBufferRange(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;
@@ -132,30 +36,29 @@ namespace MobileGL::MG_Backend::DirectGLES {
}; };
extern BackendBufferObject* g_boundVertexBufferObject; extern BackendBufferObject* g_boundVertexBufferObject;
extern StateBackendObjectRegistry<MG_State::GLState::BufferObject, BackendBufferObject> g_backendBufferObjects; extern UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>>
g_backendBufferObjects;
} // namespace BufferImpl } // namespace BufferImpl
namespace VertexArrayImpl { namespace VertexArrayImpl {
class BackendVertexArrayObject { class BackendVertexArrayObject {
public: public:
BackendVertexArrayObject(); BackendVertexArrayObject();
~BackendVertexArrayObject(); void SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
void SyncToBackend(const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject); Uint GetBackendVertexArrayId() { return m_backendVAOId; }
void SyncClientSideAttributesForDrawArrays( void Bind();
const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject, GLint first, GLsizei count);
Uint GetBackendVertexArrayId() const { return m_backendVAOId; }
void Bind() const;
private: private:
void BindAttributeBuffer(Uint index, const MG_State::GLState::VertexAttribute& attrib);
Uint m_backendVAOId = 0; Uint m_backendVAOId = 0;
Array<Uint, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS> m_clientAttributeBufferIds;
Bool m_isInitialized = false; Bool m_isInitialized = false;
Uint16 m_syncedIndexBufferVersion = 0; Uint16 m_syncedIndexBufferVersion = 0;
Array<MG_State::GLState::VertexAttributeVersion, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS> Array<MG_State::GLState::VertexAttributeVersion, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS>
m_syncedAttributeVersions; m_syncedAttributeVersions;
}; };
extern StateBackendObjectRegistry<MG_State::GLState::VertexArrayObject, BackendVertexArrayObject> extern UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>>
g_backendVertexArrayObjects; g_backendVertexArrayObjects;
} // namespace VertexArrayImpl } // namespace VertexArrayImpl
@@ -168,10 +71,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
return true; return true;
} }
inline Bool SupportsWrapR(TextureTarget target) {
return target == TextureTarget::Texture3D || target == TextureTarget::TextureCubeMap;
}
struct StateTextureBasicInfo { // Used for tracking texture state changes struct StateTextureBasicInfo { // Used for tracking texture state changes
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown; TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
SizeT width = 0; SizeT width = 0;
@@ -193,11 +92,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
class BackendTextureObject { class BackendTextureObject {
public: public:
BackendTextureObject(); BackendTextureObject();
void SyncMipmapsToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject); void SyncMipmapsToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
void SyncBuiltinSamplerToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject); void SyncBuiltinSamplerToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
void SyncTextureParamsToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject); void SyncTextureParamsToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
void Bind(GLenum target, Uint unit = TempTextureUnit); void Bind(GLenum target, Uint unit = TempTextureUnit);
Uint GetBackendTextureId() const; Uint GetBackendTextureId();
private: private:
Uint m_backendTextureId = 0; Uint m_backendTextureId = 0;
@@ -214,7 +113,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 StateBackendObjectRegistry<MG_State::GLState::ITextureObject, BackendTextureObject> extern UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<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>
@@ -226,11 +125,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
class BackendFramebufferObject { class BackendFramebufferObject {
public: public:
BackendFramebufferObject(); BackendFramebufferObject();
void SyncToBackend(const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, void SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
FramebufferTarget asTarget); FramebufferTarget asTarget);
void InvalidateSyncedState(); 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;
@@ -258,7 +159,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
FramebufferObject::FramebufferAttachmentVersionArray m_syncedFrontendAttachmentVersions = {0}; FramebufferObject::FramebufferAttachmentVersionArray m_syncedFrontendAttachmentVersions = {0};
}; };
extern StateBackendObjectRegistry<MG_State::GLState::FramebufferObject, BackendFramebufferObject> extern UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<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
@@ -268,20 +169,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
public: public:
BackendProgramObjectImpl(); BackendProgramObjectImpl();
~BackendProgramObjectImpl(); ~BackendProgramObjectImpl();
void SyncToBackend(const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject); void SyncToBackend(SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject);
void Use() const; void Use();
void SetBaseInstance(Uint32 baseInstance) const;
Uint GetBackendProgramId() const { return m_backendProgramId; } Uint GetBackendProgramId() const { return m_backendProgramId; }
Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; } Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; }
private: private:
Uint m_backendProgramId = 0; Uint m_backendProgramId = 0;
Uint m_backendGlobalUBOId = 0; Uint m_backendGlobalUBOId = 0;
Int m_baseInstanceUniformLocation = -1;
Bool m_isInitialized = false; Bool m_isInitialized = false;
}; };
extern StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl> extern UnorderedMap<SharedPtr<MG_State::GLState::ProgramObject>, SharedPtr<BackendProgramObjectImpl>>
g_backendProgramObjects; g_backendProgramObjects;
} // namespace PrgramImpl } // namespace PrgramImpl
@@ -289,9 +188,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
class BackendSamplerObject { class BackendSamplerObject {
public: public:
BackendSamplerObject(); BackendSamplerObject();
void SyncToBackend(const SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject); void SyncToBackend(SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject);
void Bind(Uint unit); void Bind(Uint unit);
Uint GetBackendSamplerId() const; Uint GetBackendSamplerId();
private: private:
Uint m_backendSamplerId = 0; Uint m_backendSamplerId = 0;
@@ -304,7 +203,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 StateBackendObjectRegistry<MG_State::GLState::SamplerObject, BackendSamplerObject> extern UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>>
g_backendSamplerObjects; g_backendSamplerObjects;
} // namespace SamplerImpl } // namespace SamplerImpl
@@ -313,8 +212,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() const { return m_backendRBOId; } Uint GetBackendRenderbufferId() { return m_backendRBOId; }
void Bind() const; void Bind();
private: private:
Uint m_backendRBOId = 0; Uint m_backendRBOId = 0;
@@ -324,7 +223,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
Int m_cacheHeight = 0; Int m_cacheHeight = 0;
}; };
extern StateBackendObjectRegistry<MG_State::GLState::RenderbufferObject, BackendRenderbufferObject> extern UnorderedMap<SharedPtr<MG_State::GLState::RenderbufferObject>, SharedPtr<BackendRenderbufferObject>>
g_backendRenderbufferObjects; g_backendRenderbufferObjects;
} // namespace RenderbufferImpl } // namespace RenderbufferImpl
} // namespace MobileGL::MG_Backend::DirectGLES } // namespace MobileGL::MG_Backend::DirectGLES
+9 -31
View File
@@ -19,6 +19,10 @@
#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) {
@@ -32,6 +36,9 @@ 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
@@ -101,37 +108,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
return result; return result;
} }
String ForceFlatIntegerVaryings(const String& glslCode, GLenum shaderType) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
String result = glslCode;
const String integerType = R"((?:(?:lowp|mediump|highp)\s+)?(?:u?int|[iu]vec[234])\b)";
auto addFlatQualifier = [&result, &integerType](const String& qualifier) {
const std::regex pattern("(layout\\s*\\([^)]*\\)\\s*)(?!(?:flat|smooth|noperspective)\\s)(" +
qualifier + "\\s+" + integerType + ")");
result = std::regex_replace(result, pattern, "$1flat $2");
};
switch (shaderType) {
case GL_VERTEX_SHADER:
addFlatQualifier("out");
break;
case GL_GEOMETRY_SHADER:
addFlatQualifier("in");
addFlatQualifier("out");
break;
case GL_FRAGMENT_SHADER:
addFlatQualifier("in");
break;
default:
break;
}
return result;
}
String RemoveLayoutBinding(const String& glslCode) { String RemoveLayoutBinding(const String& glslCode) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
@@ -190,6 +166,7 @@ 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:
@@ -199,6 +176,7 @@ 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 -4
View File
@@ -14,15 +14,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
namespace DebugImpl { namespace DebugImpl {
class ErrorLopper { class ErrorLopper {
public: public:
static void Loop(const std::function<void(GLenum)>&); void Loop(std::function<void(GLenum)>);
static void Clear(); void Clear();
ErrorLopper(); ErrorLopper();
~ErrorLopper(); ~ErrorLopper();
}; };
class OpenGLScopeMarker { class OpenGLScopeMarker {
public: public:
explicit OpenGLScopeMarker(const String& scopeName); explicit OpenGLScopeMarker(String scopeName);
~OpenGLScopeMarker(); ~OpenGLScopeMarker();
}; };
} // namespace DebugImpl } // namespace DebugImpl
@@ -43,7 +43,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
namespace PrgramImpl { namespace PrgramImpl {
String ProcessOutColorLocations(const String& glslCode); String ProcessOutColorLocations(const String& glslCode);
String ForceSupporterOutput(const String& glslCode); String ForceSupporterOutput(const String& glslCode);
String ForceFlatIntegerVaryings(const String& glslCode, GLenum shaderType);
String RemoveLayoutBinding(const String& glslCode); String RemoveLayoutBinding(const String& glslCode);
} // namespace PrgramImpl } // namespace PrgramImpl
@@ -1,305 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.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 "BackendObject_DirectVulkan.h"
#include "MG_Backend/BackendObject.h"
#include "DirectVulkan.h"
namespace MobileGL::MG_Backend::DirectVulkan {
namespace {
Bool IsReleaseCurrentRequest(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
return dpy == EGL_NO_DISPLAY && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT;
}
} // namespace
BackendObject_DirectVulkan::~BackendObject_DirectVulkan() = default;
BackendObject_DirectVulkan::BackendObject_DirectVulkan():
m_rendererInfo{
.RendererName = "Magma",
.BackendName = "Direct (Vulkan)",
.ExtraVendor = Nullopt,
.RendererGLInfo =
{
.TargetGLVersion = {3, 3, 0},
.TargetGLSLVersion = {4, 6, 0},
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32,
V_OpenGL33, E_GL_ARB_draw_buffers_blend, E_GL_ARB_compute_shader,
E_GL_ARB_shader_storage_buffer_object, E_GL_ARB_shader_image_load_store,
E_GL_ARB_program_interface_query, E_GL_ARB_framebuffer_object,
E_GL_ARB_multi_draw_indirect, E_GL_ARB_indirect_parameters,
E_GL_EXT_framebuffer_object, E_GL_ARB_depth_texture, E_GL_ARB_buffer_storage,
E_GL_ARB_texture_storage, E_GL_ARB_direct_state_access,
E_GL_ARB_shader_draw_parameters, E_GL_ARB_gpu_shader_int64},
.IsCompatibilityProfile = false
},
.StaticBackendCapability = {.AllowVSOnlyPrograms = false}} {}
Bool BackendObject_DirectVulkan::InitWindowSurface() {
if (!m_windowHandle.Handle) {
MGLOG_E("Cannot initialize DirectVulkan window surface: native window handle is null");
return false;
}
auto nativeWindow = reinterpret_cast<NativeWindowType>(m_windowHandle.Handle);
pVulkanRenderer = MakeUnique<MG_Backend::DirectVulkan::VulkanRenderer>(nativeWindow);
MOBILEGL_ASSERT(pVulkanRenderer != nullptr, "InitWindowSurface: VulkanRenderer creation failed");
pVulkanRenderer->Initialize();
return true;
}
void BackendObject_DirectVulkan::Initialize() {
m_initialized = true;
}
Bool BackendObject_DirectVulkan::InitCapabilities() {
if (!m_initialized) {
MGLOG_E("Cannot initialize capabilities before backend is initialized");
return false;
}
if (!pVulkanRenderer) {
MGLOG_E("Cannot initialize capabilities: Vulkan renderer has not been created");
return false;
}
const auto& physicalDevice = pVulkanRenderer->GetPhysicalDevice();
if (!MG_Util::BackendLoader::QueryVulkanCapabilities(m_vulkanCaps, pVulkanRenderer->GetInstance(),
physicalDevice.handle)) {
MGLOG_W("DirectVulkan: failed to query extended Vulkan capabilities, using basic properties");
MG_Util::BackendLoader::FillInVulkanCapabilities(m_vulkanCaps, physicalDevice.properties);
}
UpdateDynamicBackendParameters();
UpdateAdvertisedExtensions();
return true;
}
Bool BackendObject_DirectVulkan::InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) {
if (!m_initialized) {
MGLOG_E("DirectVulkan backend not initialized");
return false;
}
return BackendObject::InitializeEGLDisplay(dpy, major, minor);
}
Bool BackendObject_DirectVulkan::CreateEGLWindowSurface(const WindowHandle& handle) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_initialized) {
MGLOG_E("DirectVulkan backend not initialized");
return false;
}
if (!handle.Handle || (handle.Backend != WindowBackend::Android && handle.Backend != WindowBackend::X11)) {
MGLOG_E("DirectVulkan backend only supports Android and X11 native windows");
return false;
}
const Bool sameHandle = m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Window &&
m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
if (sameHandle) {
return true;
}
if (m_eglSurfaceInitialized || pVulkanRenderer) {
pVulkanRenderer.reset();
ResetEGLRuntimeState();
}
return BackendObject::CreateEGLWindowSurface(handle);
}
Bool BackendObject_DirectVulkan::MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (IsReleaseCurrentRequest(dpy, draw, read, ctx)) {
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
}
if (!pVulkanRenderer) {
MGLOG_E("DirectVulkan renderer is not initialized");
return false;
}
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
}
Bool BackendObject_DirectVulkan::SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!pVulkanRenderer) {
MGLOG_E("DirectVulkan renderer is not initialized");
return false;
}
return BackendObject::SwapEGLBuffers(dpy, draw);
}
void BackendObject_DirectVulkan::ReleaseEGLResources() {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
pVulkanRenderer.reset();
BackendObject::ReleaseEGLResources();
}
const RendererInfo& BackendObject_DirectVulkan::GetRendererInfo() const {
return m_rendererInfo;
}
String BackendObject_DirectVulkan::GetBackendAPIVersionString() const {
if (!m_initialized) {
return "<uninitialized DirectVulkan backend>";
}
// Format:
// <GPU Name>, Vulkan <Vulkan Version>, Driver <Driver Version>
String str = m_vulkanCaps.DeviceName + ", Vulkan " + m_vulkanCaps.VulkanAPIVersion.toString() + ", Driver " +
m_vulkanCaps.DriverVersionString;
return str;
}
BackendType BackendObject_DirectVulkan::GetBackendType() const {
return BackendType::DirectVulkan;
}
const GlobalBackendFunctionsTable& BackendObject_DirectVulkan::GetBackendFunctions() const {
static GlobalBackendFunctionsTable funcsTable;
static Bool funcsTableInitialized = false;
if (!funcsTableInitialized) {
funcsTable.Present = Present;
funcsTable.GL.DrawArrays = DrawArrays;
funcsTable.GL.DrawElements = DrawElements;
funcsTable.GL.DrawElementsBaseVertex = DrawElementsBaseVertex;
funcsTable.GL.MultiDrawElements = MultiDrawElements;
funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex;
funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect;
funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect;
funcsTable.GL.MultiDrawElementsIndirectCount = MultiDrawElementsIndirectCount;
funcsTable.GL.MultiDrawArraysIndirectCount = MultiDrawArraysIndirectCount;
funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex;
funcsTable.GL.DrawRangeElements = DrawRangeElements;
funcsTable.GL.DrawElementsInstancedBaseVertexBaseInstance = DrawElementsInstancedBaseVertexBaseInstance;
funcsTable.GL.DrawElementsInstancedBaseVertex = DrawElementsInstancedBaseVertex;
funcsTable.GL.DrawElementsInstancedBaseInstance = DrawElementsInstancedBaseInstance;
funcsTable.GL.DrawElementsInstanced = DrawElementsInstanced;
funcsTable.GL.DrawArraysInstancedBaseInstance = DrawArraysInstancedBaseInstance;
funcsTable.GL.DrawArraysInstanced = DrawArraysInstanced;
funcsTable.GL.DrawElementsIndirect = DrawElementsIndirect;
funcsTable.GL.DrawArraysIndirect = DrawArraysIndirect;
funcsTable.GL.Clear = Clear;
funcsTable.GL.ClearBufferfi = ClearBufferfi;
funcsTable.GL.ClearBufferfv = ClearBufferfv;
funcsTable.GL.ClearBufferuiv = ClearBufferuiv;
funcsTable.GL.ClearBufferiv = ClearBufferiv;
funcsTable.GL.ClearNamedFramebufferfv = ClearNamedFramebufferfv;
funcsTable.GL.ClearNamedFramebufferfi = ClearNamedFramebufferfi;
funcsTable.GL.BlitFramebuffer = BlitFramebuffer;
funcsTable.GL.BlitNamedFramebuffer = BlitNamedFramebuffer;
funcsTable.GL.CopyTexImage2D = CopyTexImage2D;
funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D;
funcsTable.GL.GenerateMipmap = GenerateMipmap;
funcsTable.GL.ReadPixels = ReadPixels;
funcsTable.GL.GetTexImage = GetTexImage;
funcsTable.GL.GetTextureImage = GetTextureImage;
funcsTable.GL.DispatchCompute = DispatchCompute;
funcsTable.GL.DispatchComputeIndirect = DispatchComputeIndirect;
funcsTable.GL.MemoryBarrier = MemoryBarrier;
funcsTable.GL.MemoryBarrierByRegion = MemoryBarrierByRegion;
funcsTable.GL.BindImageTexture = BindImageTexture;
funcsTable.GL.GetIntegeri_v = GetIntegeri_v;
funcsTable.GL.GetInteger64i_v = GetInteger64i_v;
funcsTable.GL.GetProgramiv = GetProgramiv;
funcsTable.GL.GetProgramInterfaceiv = GetProgramInterfaceiv;
funcsTable.GL.GetProgramResourceIndex = GetProgramResourceIndex;
funcsTable.GL.GetProgramResourceName = GetProgramResourceName;
funcsTable.GL.GetProgramResourceiv = GetProgramResourceiv;
funcsTable.GL.GetProgramResourceLocation = GetProgramResourceLocation;
funcsTable.GL.GetProgramResourceLocationIndex = GetProgramResourceLocationIndex;
funcsTable.GL.ShaderStorageBlockBinding = ShaderStorageBlockBinding;
funcsTableInitialized = true;
}
return funcsTable;
}
const DynamicBackendParameters& BackendObject_DirectVulkan::GetDynamicParameters() const {
return m_dynamicParameters;
}
void BackendObject_DirectVulkan::ApplyVulkanCapabilitiesForTesting(
const MG_External::VulkanCapabilities& capabilities) {
m_vulkanCaps = capabilities;
UpdateDynamicBackendParameters();
UpdateAdvertisedExtensions();
}
void BackendObject_DirectVulkan::UpdateAdvertisedExtensions() {
auto& extensions = m_rendererInfo.RendererGLInfo.Extensions;
extensions.erase(std::remove(extensions.begin(), extensions.end(), E_GL_KHR_shader_subgroup),
extensions.end());
if (m_vulkanCaps.SupportsShaderSubgroup) {
extensions.push_back(E_GL_KHR_shader_subgroup);
}
}
void BackendObject_DirectVulkan::UpdateDynamicBackendParameters() {
const auto mapShaderStages = [](Uint32 vkStages) {
Uint32 glStages = 0;
if ((vkStages & VK_SHADER_STAGE_VERTEX_BIT) != 0) glStages |= GL_VERTEX_SHADER_BIT;
if ((vkStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) glStages |= GL_TESS_CONTROL_SHADER_BIT;
if ((vkStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0) {
glStages |= GL_TESS_EVALUATION_SHADER_BIT;
}
if ((vkStages & VK_SHADER_STAGE_GEOMETRY_BIT) != 0) glStages |= GL_GEOMETRY_SHADER_BIT;
if ((vkStages & VK_SHADER_STAGE_FRAGMENT_BIT) != 0) glStages |= GL_FRAGMENT_SHADER_BIT;
if ((vkStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0) glStages |= GL_COMPUTE_SHADER_BIT;
return glStages;
};
const auto mapSubgroupFeatures = [](Uint32 vkFeatures) {
Uint32 glFeatures = 0;
if ((vkFeatures & VK_SUBGROUP_FEATURE_BASIC_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_BASIC_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_VOTE_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_VOTE_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_BALLOT_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_QUAD_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_QUAD_BIT_KHR;
}
return glFeatures;
};
static constexpr SizeT kMaxAdvertisedShaderStorageBlockSize = 512ull * 1024ull * 1024ull;
m_dynamicParameters.UniformBufferOffsetAlignment = m_vulkanCaps.UniformBufferOffsetAlignment;
m_dynamicParameters.MaxShaderStorageBlockSize =
std::min(m_vulkanCaps.MaxShaderStorageBlockSize, kMaxAdvertisedShaderStorageBlockSize);
if (m_vulkanCaps.SupportsShaderSubgroup) {
m_dynamicParameters.SubgroupSize = m_vulkanCaps.SubgroupSize;
m_dynamicParameters.SubgroupSupportedStages = mapShaderStages(m_vulkanCaps.SubgroupSupportedStages);
m_dynamicParameters.SubgroupSupportedFeatures = mapSubgroupFeatures(m_vulkanCaps.SubgroupSupportedOperations);
m_dynamicParameters.SubgroupQuadOperationsInAllStages = m_vulkanCaps.SubgroupQuadOperationsInAllStages;
} else {
m_dynamicParameters.SubgroupSize = 0;
m_dynamicParameters.SubgroupSupportedStages = 0;
m_dynamicParameters.SubgroupSupportedFeatures = 0;
m_dynamicParameters.SubgroupQuadOperationsInAllStages = false;
}
if (m_dynamicParameters.MaxShaderStorageBlockSize != m_vulkanCaps.MaxShaderStorageBlockSize) {
MGLOG_I("DirectVulkan: clamped GL_MAX_SHADER_STORAGE_BLOCK_SIZE from %zu to %zu",
m_vulkanCaps.MaxShaderStorageBlockSize,
m_dynamicParameters.MaxShaderStorageBlockSize);
}
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,775 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/DirectVulkan.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 "DirectVulkan.h"
#include "DirectVulkanResourceState.h"
#include "MG_State/GLState/Core.h"
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
#include "MG_Util/Miscellany/IndexGenerator.h"
#include <cstring>
#include <spirv_reflect.h>
namespace MobileGL::MG_Backend::DirectVulkan {
UniquePtr<VulkanRenderer> pVulkanRenderer = nullptr;
namespace {
struct BufferVariableResource {
String name;
GLuint blockIndex = 0;
GLint offset = 0;
GLint size = 0;
};
struct StorageBlockResource {
String name;
GLuint binding = 0;
GLint dataSize = 0;
Vector<GLuint> activeVariables;
};
struct ProgramResourceCache {
Uint32 backendStateVersion = 0;
Vector<StorageBlockResource> storageBlocks;
Vector<BufferVariableResource> bufferVariables;
GLint computeWorkGroupSize[3] = {1, 1, 1};
};
UnorderedMap<GLuint, ProgramResourceCache> g_programResourceCaches;
String NormalizeDescriptorName(const SpvReflectDescriptorBinding& binding) {
const char* rawName = binding.name;
if (binding.type_description != nullptr && binding.type_description->type_name != nullptr) {
rawName = binding.type_description->type_name;
}
if (rawName == nullptr) {
return {};
}
String name = rawName;
const auto arraySuffix = name.find("[0]");
if (arraySuffix != String::npos) {
name = name.substr(0, arraySuffix);
}
return name;
}
void AddBufferVariablesRecursive(const SpvReflectBlockVariable& variable, const String& prefix,
GLuint blockIndex, Vector<BufferVariableResource>& variables,
Vector<GLuint>& activeVariables) {
for (Uint32 memberIndex = 0; memberIndex < variable.member_count; ++memberIndex) {
const auto& member = variable.members[memberIndex];
String name = prefix;
if (!name.empty()) {
name += ".";
}
name += member.name ? member.name : "";
if (member.member_count > 0) {
AddBufferVariablesRecursive(member, name, blockIndex, variables, activeVariables);
continue;
}
BufferVariableResource resource{};
resource.name = name;
resource.blockIndex = blockIndex;
resource.offset = static_cast<GLint>(member.offset);
resource.size = static_cast<GLint>(member.size);
const GLuint variableIndex = static_cast<GLuint>(variables.size());
variables.push_back(resource);
activeVariables.push_back(variableIndex);
}
}
ProgramResourceCache& GetProgramResourceCache(const MG_State::GLState::ProgramObject& program) {
auto& cache = g_programResourceCaches[program.GetExternalIndex()];
const Uint32 backendStateVersion = program.GetBackendStateVersion();
if (cache.backendStateVersion == backendStateVersion &&
(!cache.storageBlocks.empty() || !cache.bufferVariables.empty())) {
return cache;
}
cache = {};
cache.backendStateVersion = backendStateVersion;
Vector<SpvReflectShaderModule> modules;
Vector<Bool> validModules;
const auto& spirvs = program.GetGeneratedSpirv();
for (const auto& spirv : spirvs) {
if (spirv.empty()) {
continue;
}
SpvReflectShaderModule module{};
const SpvReflectResult result =
spvReflectCreateShaderModule(spirv.size() * sizeof(Uint), spirv.data(), &module);
if (result != SPV_REFLECT_RESULT_SUCCESS) {
continue;
}
modules.push_back(module);
validModules.push_back(true);
}
for (auto& module : modules) {
for (Uint32 entryIndex = 0; entryIndex < module.entry_point_count; ++entryIndex) {
const auto& entryPoint = module.entry_points[entryIndex];
if ((entryPoint.shader_stage & SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT) == 0) {
continue;
}
cache.computeWorkGroupSize[0] = static_cast<GLint>(std::max<Uint32>(entryPoint.local_size.x, 1));
cache.computeWorkGroupSize[1] = static_cast<GLint>(std::max<Uint32>(entryPoint.local_size.y, 1));
cache.computeWorkGroupSize[2] = static_cast<GLint>(std::max<Uint32>(entryPoint.local_size.z, 1));
}
uint32_t bindingCount = 0;
SpvReflectResult result = spvReflectEnumerateDescriptorBindings(&module, &bindingCount, nullptr);
if (result != SPV_REFLECT_RESULT_SUCCESS || bindingCount == 0) {
continue;
}
Vector<SpvReflectDescriptorBinding*> bindings(bindingCount);
result = spvReflectEnumerateDescriptorBindings(&module, &bindingCount, bindings.data());
if (result != SPV_REFLECT_RESULT_SUCCESS) {
continue;
}
std::sort(bindings.begin(), bindings.end(), [](const auto* lhs, const auto* rhs) {
const String lhsName = lhs ? NormalizeDescriptorName(*lhs) : String();
const String rhsName = rhs ? NormalizeDescriptorName(*rhs) : String();
if (lhsName != rhsName) return lhsName < rhsName;
return lhs->binding < rhs->binding;
});
for (const auto* binding : bindings) {
if (binding == nullptr ||
binding->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) {
continue;
}
const String blockName = NormalizeDescriptorName(*binding);
if (blockName.empty()) {
continue;
}
const auto existing = std::find_if(
cache.storageBlocks.begin(), cache.storageBlocks.end(),
[&](const StorageBlockResource& block) { return block.name == blockName; });
if (existing != cache.storageBlocks.end()) {
continue;
}
StorageBlockResource block{};
block.name = blockName;
block.binding = binding->binding;
block.dataSize = static_cast<GLint>(binding->block.size);
const GLuint blockIndex = static_cast<GLuint>(cache.storageBlocks.size());
AddBufferVariablesRecursive(binding->block, blockName, blockIndex, cache.bufferVariables,
block.activeVariables);
cache.storageBlocks.push_back(block);
}
}
for (SizeT i = 0; i < modules.size(); ++i) {
if (validModules[i]) {
spvReflectDestroyShaderModule(&modules[i]);
}
}
return cache;
}
MG_State::GLState::ProgramObject* TryGetDirectVulkanProgram(GLuint program) {
if (!MG_State::pGLContext || !MG_State::pGLContext->ValidateProgramName(program)) {
return nullptr;
}
auto& programObject = MG_State::pGLContext->GetProgramObject(program);
return programObject.get();
}
void CopyResourceName(const String& source, GLsizei bufSize, GLsizei* length, GLchar* name) {
const GLsizei writtenLength = static_cast<GLsizei>(source.size());
if (length) {
*length = writtenLength;
}
if (name && bufSize > 0) {
const GLsizei copyLength = std::min<GLsizei>(bufSize - 1, writtenLength);
std::memcpy(name, source.data(), static_cast<SizeT>(copyLength));
name[copyLength] = '\0';
}
}
} // namespace
GLuint GetShaderStorageBlockIndex(const MG_State::GLState::ProgramObject& program, const String& name) {
auto& cache = GetProgramResourceCache(program);
const auto it = std::find_if(cache.storageBlocks.begin(), cache.storageBlocks.end(),
[&](const StorageBlockResource& block) { return block.name == name; });
return it == cache.storageBlocks.end()
? GL_INVALID_INDEX
: static_cast<GLuint>(std::distance(cache.storageBlocks.begin(), it));
}
GLuint GetShaderStorageBlockBinding(const MG_State::GLState::ProgramObject& program, GLuint blockIndex) {
auto& cache = GetProgramResourceCache(program);
if (blockIndex >= cache.storageBlocks.size()) {
return 0;
}
return cache.storageBlocks[blockIndex].binding;
}
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferfi called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferfi called with null GL context");
pVulkanRenderer->ClearBufferfi(buffer, drawbuffer, depth, stencil);
}
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferfv called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferfv called with null GL context");
pVulkanRenderer->ClearBufferfv(buffer, drawbuffer, value);
}
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferuiv called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferuiv called with null GL context");
pVulkanRenderer->ClearBufferuiv(buffer, drawbuffer, value);
}
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferiv called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferiv called with null GL context");
pVulkanRenderer->ClearBufferiv(buffer, drawbuffer, value);
}
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, const GLfloat* value) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferfv called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearNamedFramebufferfv called with null GL context");
pVulkanRenderer->ClearNamedFramebufferfv(framebuffer, buffer, drawbuffer, value);
}
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, GLfloat depth, GLint stencil) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferfi called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearNamedFramebufferfi called with null GL context");
pVulkanRenderer->ClearNamedFramebufferfi(framebuffer, buffer, drawbuffer, depth, stencil);
}
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsIndirect called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElementsIndirect called with null GL context");
pVulkanRenderer->MultiDrawElementsIndirectCount(mode, type, indirect, 0, drawcount, stride);
}
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {
MGLOG_W("DirectVulkan::MultiDrawArraysIndirect is not implemented yet (drawcount=%d)", drawcount);
}
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsIndirectCount called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElementsIndirectCount called with null GL context");
pVulkanRenderer->MultiDrawElementsIndirectCount(mode, type, indirect, drawcount, maxdrawcount, stride);
}
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
MGLOG_W("DirectVulkan::MultiDrawArraysIndirectCount is not implemented yet (maxdrawcount=%d)", maxdrawcount);
}
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex) {}
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices) {}
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLint basevertex, GLuint baseinstance) {}
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLint basevertex) {}
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLuint baseinstance) {}
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) {}
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect) {}
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
GLuint baseinstance) {}
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) {}
void DrawArraysIndirect(GLenum mode, const void* indirect) {}
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
GLsizei height, GLint border) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyTexImage2D called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::CopyTexImage2D called with null GL context");
pVulkanRenderer->CopyTexSubImage2D(target, level, 0, 0, x, y, width, height);
}
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
GLsizei height) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyTexSubImage2D called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::CopyTexSubImage2D called with null GL context");
pVulkanRenderer->CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
}
void GenerateMipmap(GLenum target) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GenerateMipmap called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::GenerateMipmap called with null GL context");
pVulkanRenderer->GenerateMipmap(target);
}
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DispatchCompute called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DispatchCompute called with null GL context");
pVulkanRenderer->DispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
}
void DispatchComputeIndirect(GLintptr indirect) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DispatchComputeIndirect called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DispatchComputeIndirect called with null GL context");
pVulkanRenderer->DispatchComputeIndirect(indirect);
}
void MemoryBarrier(GLbitfield barriers) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MemoryBarrier called with null VulkanRenderer");
pVulkanRenderer->MemoryBarrier(barriers);
}
void MemoryBarrierByRegion(GLbitfield barriers) {
MemoryBarrier(barriers);
}
void BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access,
GLenum format) {
(void)unit;
(void)texture;
(void)level;
(void)layered;
(void)layer;
(void)access;
(void)format;
}
void GetIntegeri_v(GLenum target, GLuint index, GLint* data) {
if (!data) return;
switch (target) {
case GL_MAX_COMPUTE_WORK_GROUP_COUNT:
if (!pVulkanRenderer || index >= 3) {
*data = 0;
return;
}
*data = static_cast<GLint>(
pVulkanRenderer->GetPhysicalDevice().properties.limits.maxComputeWorkGroupCount[index]);
return;
case GL_MAX_COMPUTE_WORK_GROUP_SIZE:
if (!pVulkanRenderer || index >= 3) {
*data = 0;
return;
}
*data = static_cast<GLint>(
pVulkanRenderer->GetPhysicalDevice().properties.limits.maxComputeWorkGroupSize[index]);
return;
case GL_SHADER_STORAGE_BUFFER_BINDING: {
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, index);
auto& obj = point.GetBoundObject();
*data = obj ? static_cast<GLint>(obj->GetExternalIndex()) : 0;
return;
}
case GL_SHADER_STORAGE_BUFFER_START: {
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, index);
*data = static_cast<GLint>(point.GetRange().start);
return;
}
case GL_SHADER_STORAGE_BUFFER_SIZE: {
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, index);
auto& obj = point.GetBoundObject();
if (!obj) {
*data = 0;
return;
}
const auto& range = point.GetRange();
const auto start = std::min(range.start, obj->GetSize());
const auto end = std::min(range.end, obj->GetSize());
*data = static_cast<GLint>(end - start);
return;
}
case GL_IMAGE_BINDING_NAME:
case GL_IMAGE_BINDING_LEVEL:
case GL_IMAGE_BINDING_LAYERED:
case GL_IMAGE_BINDING_LAYER:
case GL_IMAGE_BINDING_ACCESS:
case GL_IMAGE_BINDING_FORMAT: {
if (index >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
*data = 0;
return;
}
auto& imageBinding = MG_State::pGLContext->GetImageTextureBinding(static_cast<Int>(index));
if (target == GL_IMAGE_BINDING_NAME) {
*data = imageBinding.Texture ? static_cast<GLint>(imageBinding.Texture->GetExternalIndex()) : 0;
} else if (target == GL_IMAGE_BINDING_LEVEL) {
*data = imageBinding.Level;
} else if (target == GL_IMAGE_BINDING_LAYERED) {
*data = imageBinding.Layered;
} else if (target == GL_IMAGE_BINDING_LAYER) {
*data = imageBinding.Layer;
} else if (target == GL_IMAGE_BINDING_ACCESS) {
*data = static_cast<GLint>(imageBinding.Access);
} else {
*data = static_cast<GLint>(imageBinding.Format);
}
return;
}
default:
*data = 0;
return;
}
}
void GetInteger64i_v(GLenum target, GLuint index, GLint64* data) {
if (!data) return;
switch (target) {
case GL_SHADER_STORAGE_BUFFER_START: {
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, index);
*data = static_cast<GLint64>(point.GetRange().start);
return;
}
case GL_SHADER_STORAGE_BUFFER_SIZE: {
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, index);
auto& obj = point.GetBoundObject();
if (!obj) {
*data = 0;
return;
}
const auto& range = point.GetRange();
const auto start = std::min(range.start, obj->GetSize());
const auto end = std::min(range.end, obj->GetSize());
*data = static_cast<GLint64>(end - start);
return;
}
default:
*data = 0;
return;
}
}
void GetProgramiv(GLuint program, GLenum pname, GLint* params) {
if (!params) return;
auto* programObject = TryGetDirectVulkanProgram(program);
if (!programObject) {
params[0] = 0;
return;
}
switch (pname) {
case GL_COMPUTE_WORK_GROUP_SIZE: {
auto& cache = GetProgramResourceCache(*programObject);
params[0] = cache.computeWorkGroupSize[0];
params[1] = cache.computeWorkGroupSize[1];
params[2] = cache.computeWorkGroupSize[2];
return;
}
default:
params[0] = 0;
return;
}
}
void GetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint* params) {
if (!params) return;
auto* programObject = TryGetDirectVulkanProgram(program);
if (!programObject) return;
auto& cache = GetProgramResourceCache(*programObject);
if (programInterface == GL_SHADER_STORAGE_BLOCK) {
if (pname == GL_ACTIVE_RESOURCES) {
*params = static_cast<GLint>(cache.storageBlocks.size());
} else if (pname == GL_MAX_NAME_LENGTH) {
SizeT maxLength = 0;
for (const auto& block : cache.storageBlocks) maxLength = std::max(maxLength, block.name.size() + 1);
*params = static_cast<GLint>(maxLength);
} else {
*params = 0;
}
return;
}
if (programInterface == GL_BUFFER_VARIABLE) {
if (pname == GL_ACTIVE_RESOURCES) {
*params = static_cast<GLint>(cache.bufferVariables.size());
} else if (pname == GL_MAX_NAME_LENGTH) {
SizeT maxLength = 0;
for (const auto& var : cache.bufferVariables) maxLength = std::max(maxLength, var.name.size() + 1);
*params = static_cast<GLint>(maxLength);
} else {
*params = 0;
}
return;
}
*params = 0;
}
GLuint GetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar* name) {
if (!name) return GL_INVALID_INDEX;
auto* programObject = TryGetDirectVulkanProgram(program);
if (!programObject) return GL_INVALID_INDEX;
auto& cache = GetProgramResourceCache(*programObject);
if (programInterface == GL_SHADER_STORAGE_BLOCK) {
return GetShaderStorageBlockIndex(*programObject, name);
}
if (programInterface == GL_BUFFER_VARIABLE) {
const String resourceName = name;
const auto it = std::find_if(cache.bufferVariables.begin(), cache.bufferVariables.end(),
[&](const BufferVariableResource& var) { return var.name == resourceName; });
return it == cache.bufferVariables.end()
? GL_INVALID_INDEX
: static_cast<GLuint>(std::distance(cache.bufferVariables.begin(), it));
}
return GL_INVALID_INDEX;
}
void GetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize,
GLsizei* length, GLchar* name) {
auto* programObject = TryGetDirectVulkanProgram(program);
if (!programObject) return;
auto& cache = GetProgramResourceCache(*programObject);
if (programInterface == GL_SHADER_STORAGE_BLOCK && index < cache.storageBlocks.size()) {
CopyResourceName(cache.storageBlocks[index].name, bufSize, length, name);
return;
}
if (programInterface == GL_BUFFER_VARIABLE && index < cache.bufferVariables.size()) {
CopyResourceName(cache.bufferVariables[index].name, bufSize, length, name);
return;
}
if (length) *length = 0;
if (name && bufSize > 0) name[0] = '\0';
}
void GetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount,
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params) {
auto* programObject = TryGetDirectVulkanProgram(program);
if (!programObject || !props || !params || bufSize <= 0) return;
auto& cache = GetProgramResourceCache(*programObject);
GLsizei written = 0;
auto writeValue = [&](GLint value) {
if (written < bufSize) {
params[written++] = value;
}
};
for (GLsizei propIndex = 0; propIndex < propCount; ++propIndex) {
const GLenum prop = props[propIndex];
if (programInterface == GL_SHADER_STORAGE_BLOCK && index < cache.storageBlocks.size()) {
const auto& block = cache.storageBlocks[index];
switch (prop) {
case GL_NAME_LENGTH:
writeValue(static_cast<GLint>(block.name.size() + 1));
break;
case GL_BUFFER_BINDING:
writeValue(static_cast<GLint>(block.binding));
break;
case GL_BUFFER_DATA_SIZE:
writeValue(block.dataSize);
break;
case GL_NUM_ACTIVE_VARIABLES:
writeValue(static_cast<GLint>(block.activeVariables.size()));
break;
case GL_ACTIVE_VARIABLES:
for (const auto variable : block.activeVariables) writeValue(static_cast<GLint>(variable));
break;
default:
writeValue(0);
break;
}
} else if (programInterface == GL_BUFFER_VARIABLE && index < cache.bufferVariables.size()) {
const auto& var = cache.bufferVariables[index];
switch (prop) {
case GL_NAME_LENGTH:
writeValue(static_cast<GLint>(var.name.size() + 1));
break;
case GL_TYPE:
writeValue(GL_FLOAT);
break;
case GL_ARRAY_SIZE:
writeValue(1);
break;
case GL_OFFSET:
writeValue(var.offset);
break;
case GL_BLOCK_INDEX:
writeValue(static_cast<GLint>(var.blockIndex));
break;
case GL_ARRAY_STRIDE:
case GL_MATRIX_STRIDE:
case GL_TOP_LEVEL_ARRAY_SIZE:
case GL_TOP_LEVEL_ARRAY_STRIDE:
case GL_IS_ROW_MAJOR:
writeValue(0);
break;
default:
writeValue(0);
break;
}
} else {
writeValue(0);
}
}
if (length) *length = written;
}
GLint GetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar* name) {
auto* programObject = TryGetDirectVulkanProgram(program);
if (!programObject || !name) return -1;
if (programInterface == GL_UNIFORM) {
return programObject->GetUniformLocation(name);
}
return -1;
}
GLint GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, const GLchar* name) {
(void)program;
(void)programInterface;
(void)name;
return -1;
}
void ShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding) {
auto* programObject = TryGetDirectVulkanProgram(program);
if (!programObject) return;
auto& cache = GetProgramResourceCache(*programObject);
if (storageBlockIndex >= cache.storageBlocks.size()) {
return;
}
cache.storageBlocks[storageBlockIndex].binding = storageBlockBinding;
}
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ReadPixels called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ReadPixels called with null GL context");
pVulkanRenderer->ReadPixels(x, y, width, height, format, type, pixels);
}
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GetTexImage called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::GetTexImage called with null GL context");
pVulkanRenderer->GetTexImage(target, level, format, type, pixels);
}
void GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget uploadTarget,
GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid* pixels) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GetTextureImage called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::GetTextureImage called with null GL context");
pVulkanRenderer->GetTextureImage(texture, uploadTarget, level, format, type, bufSize, pixels);
}
void Clear(GLbitfield mask) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Clear called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::Clear called with null GL context");
pVulkanRenderer->Clear(mask);
}
void DrawArrays(GLenum mode, GLint first, GLsizei count) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArrays called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawArrays called with null GL context");
DrawCmd payload{};
payload.mode = mode;
payload.params.firstVertex = first;
payload.params.vertexCount = count;
pVulkanRenderer->DrawArrays(payload);
}
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElements called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElements called with null GL context");
DrawIndexedCmd payload{};
payload.mode = mode;
payload.indexBufferView.indexType = type;
payload.indexBufferView.indexByteOffset = reinterpret_cast<SizeT>(indices);
payload.indexBufferView.indexByteSize = count * MG_Util::GetGLTypeSize(type);
payload.params.indexCount = count;
payload.params.instanceCount = 1;
pVulkanRenderer->DrawElements(payload);
}
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElements called with null GL context");
// Vector<DrawElementCmd> cmds;
// cmds.reserve(static_cast<SizeT>(drawcount));
// for (GLsizei i = 0; i < drawcount; ++i) {
// if (count[i] == 0) {
// continue;
// }
//
// DrawElementCmd payload{};
// payload.mode = mode;
// payload.firstVertex = 0;
// payload.indexCount = count[i];
// payload.indexType = type;
// payload.indexByteOffset = reinterpret_cast<SizeT>(indices[i]);
// cmds.push_back(payload);
// }
//
// if (cmds.empty()) {
// return;
// }
// pVulkanRenderer->MultiDrawElements(cmds);
}
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");
DrawIndexedCmd payload{};
payload.mode = mode;
payload.indexBufferView.indexType = type;
payload.indexBufferView.indexByteOffset = reinterpret_cast<SizeT>(indices);
payload.indexBufferView.indexByteSize = count * MG_Util::GetGLTypeSize(type);
payload.params.indexCount = count;
payload.params.instanceCount = 1;
payload.params.firstIndex = 0;
payload.params.vertexOffset = basevertex;
payload.params.firstInstance = 0;
pVulkanRenderer->DrawElements(payload);
}
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount, const GLint* basevertex) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElements called with null GL context");
MultiDrawIndexedCmd payload{};
payload.mode = mode;
payload.indexBufferView.indexType = type;
// TODO: allocate draw cmd buf elsewhere
static Vector<DrawIndexedCmdParam> params;
params.clear();
params.resize(drawcount);
for (GLsizei i = 0; i < drawcount; ++i) {
if (count[i] == 0) {
continue;
}
// TODO: this index view needs a redesign, now there's a lotta redundant uploads
payload.indexBufferView.indexByteOffset = 0;
payload.indexBufferView.indexByteSize =
std::max(reinterpret_cast<SizeT>(indices[i]) + count[i] * MG_Util::GetGLTypeSize(type),
payload.indexBufferView.indexByteSize);
auto& param = params[i];
param.indexCount = count[i];
param.instanceCount = 1;
param.firstIndex = reinterpret_cast<SizeT>(indices[i]) / MG_Util::GetGLTypeSize(type);
param.vertexOffset = basevertex[i];
param.firstInstance = 0;
}
payload.drawCount = drawcount;
payload.pParams = params.data();
pVulkanRenderer->MultiDrawElements(payload);
}
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
GLint dstY1, GLbitfield mask, GLenum filter) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitFramebuffer called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::BlitFramebuffer called with null GL context");
pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
}
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitNamedFramebuffer called with null VulkanRenderer");
pVulkanRenderer->BlitNamedFramebuffer(readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0,
dstY0, dstX1, dstY1, mask, filter);
}
void Present() {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Present called with null VulkanRenderer");
pVulkanRenderer->Present();
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,20 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/DirectVulkanResourceState.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 <Includes.h>
namespace MobileGL::MG_State::GLState {
class ProgramObject;
}
namespace MobileGL::MG_Backend::DirectVulkan {
GLuint GetShaderStorageBlockIndex(const MG_State::GLState::ProgramObject& program, const String& name);
GLuint GetShaderStorageBlockBinding(const MG_State::GLState::ProgramObject& program, GLuint blockIndex);
}
@@ -1,138 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/BufferArena.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 "BufferArena.h"
namespace MobileGL::MG_Backend::DirectVulkan {
Bool BufferArena::Initialize(const BufferArenaDesc& desc) {
Shutdown();
MOBILEGL_ASSERT(desc.allocator != nullptr, "BufferArena::Initialize requires valid allocator");
MOBILEGL_ASSERT(desc.frameCount > 0, "BufferArena::Initialize requires non-zero frame count");
MOBILEGL_ASSERT(desc.usage != 0, "BufferArena::Initialize requires non-zero buffer usage");
m_desc = desc;
m_frames.clear();
m_frames.resize(desc.frameCount);
m_deferredReleases.resize(desc.frameCount);
return true;
}
void BufferArena::Shutdown() {
for (auto& frame : m_frames) {
frame.buffer.Destroy();
frame.writeCursor = 0;
}
m_frames.clear();
m_deferredReleases.clear();
m_desc = {};
}
void BufferArena::BeginFrame(Uint32 frameIndex) {
CollectDeferredReleases(frameIndex);
ResetFrame(frameIndex);
}
void BufferArena::ResetFrame(Uint32 frameIndex) {
AssertValidFrameIndex(frameIndex);
m_frames[frameIndex].writeCursor = 0;
}
void BufferArena::CollectDeferredReleases(Uint32 frameIndex) {
AssertValidFrameIndex(frameIndex);
m_deferredReleases[frameIndex].clear();
}
Bool BufferArena::Allocate(Uint32 frameIndex, VkDeviceSize size, VkDeviceSize alignment, BufferSlice& outSlice) {
AssertValidFrameIndex(frameIndex);
MOBILEGL_ASSERT(size > 0, "BufferArena::Allocate requires non-zero size");
auto& frame = m_frames[frameIndex];
const VkDeviceSize resolvedAlignment = alignment > 0 ? alignment : 1;
const VkDeviceSize offset = (frame.writeCursor + resolvedAlignment - 1) & ~(resolvedAlignment - 1);
const VkDeviceSize endOffset = offset + size;
if (!EnsureCapacity(frameIndex, endOffset)) {
return false;
}
frame.writeCursor = endOffset;
outSlice = frame.buffer.GetSlice(offset, size);
return outSlice.IsValid();
}
Bool BufferArena::Upload(Uint32 frameIndex, const void* data, VkDeviceSize size, VkDeviceSize alignment,
BufferSlice& outSlice) {
MOBILEGL_ASSERT(data != nullptr || size == 0, "BufferArena::Upload data pointer is null");
if (!Allocate(frameIndex, size, alignment, outSlice)) {
return false;
}
if (outSlice.mapped != nullptr) {
Memcpy(outSlice.mapped, data, static_cast<SizeT>(size));
return true;
}
return m_frames[frameIndex].buffer.Upload(data, size, outSlice.offset);
}
VkDeviceSize BufferArena::GetWriteCursor(Uint32 frameIndex) const {
AssertValidFrameIndex(frameIndex);
return m_frames[frameIndex].writeCursor;
}
Uint32 BufferArena::GetFrameCount() const {
return static_cast<Uint32>(m_frames.size());
}
Bool BufferArena::EnsureCapacity(Uint32 frameIndex, VkDeviceSize requiredEndOffset) {
AssertValidFrameIndex(frameIndex);
auto& frame = m_frames[frameIndex];
auto& buffer = frame.buffer;
if (buffer.IsValid() && buffer.GetSize() >= requiredEndOffset) {
return true;
}
VkDeviceSize newCapacity = buffer.IsValid() ? buffer.GetSize() : 0;
if (newCapacity < m_desc.minBufferSize) {
newCapacity = m_desc.minBufferSize;
}
if (newCapacity == 0) {
newCapacity = requiredEndOffset;
}
while (newCapacity < requiredEndOffset) {
newCapacity *= 2;
}
if (buffer.IsValid()) {
m_deferredReleases[frameIndex].push_back(std::move(buffer));
}
VkBufferObjectDesc bufferDesc{};
bufferDesc.allocator = m_desc.allocator;
bufferDesc.size = newCapacity;
bufferDesc.usage = m_desc.usage;
bufferDesc.memoryUsage = m_desc.memoryUsage;
bufferDesc.allocationFlags = m_desc.allocationFlags;
if (!buffer.Create(bufferDesc)) {
return false;
}
if (m_desc.persistentlyMapped && buffer.Map() == nullptr) {
buffer.Destroy();
return false;
}
frame.writeCursor = 0;
return true;
}
void BufferArena::AssertValidFrameIndex(Uint32 frameIndex) const {
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "BufferArena frame index out of range");
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,56 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/BufferArena.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 "BufferSlice.h"
#include "VkBufferObject.h"
#include "../VkIncludes.h"
#include <Includes.h>
#include <vk_mem_alloc.h>
namespace MobileGL::MG_Backend::DirectVulkan {
struct BufferArenaDesc {
VmaAllocator allocator = nullptr;
Uint32 frameCount = 0;
VkBufferUsageFlags usage = 0;
VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
VmaAllocationCreateFlags allocationFlags = 0;
VkDeviceSize minBufferSize = 0;
Bool persistentlyMapped = false;
};
class BufferArena {
public:
Bool Initialize(const BufferArenaDesc& desc);
void Shutdown();
void BeginFrame(Uint32 frameIndex);
void ResetFrame(Uint32 frameIndex);
void CollectDeferredReleases(Uint32 frameIndex);
Bool Allocate(Uint32 frameIndex, VkDeviceSize size, VkDeviceSize alignment, BufferSlice& outSlice);
Bool Upload(Uint32 frameIndex, const void* data, VkDeviceSize size, VkDeviceSize alignment, BufferSlice& outSlice);
VkDeviceSize GetWriteCursor(Uint32 frameIndex) const;
Uint32 GetFrameCount() const;
private:
struct FrameResources {
VkBufferObject buffer;
VkDeviceSize writeCursor = 0;
};
Bool EnsureCapacity(Uint32 frameIndex, VkDeviceSize requiredEndOffset);
void AssertValidFrameIndex(Uint32 frameIndex) const;
BufferArenaDesc m_desc{};
Vector<FrameResources> m_frames;
Vector<Vector<VkBufferObject>> m_deferredReleases;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,23 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/BufferSlice.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>
namespace MobileGL::MG_Backend::DirectVulkan {
struct BufferSlice {
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceSize offset = 0;
VkDeviceSize size = 0;
void* mapped = nullptr;
Bool IsValid() const { return buffer != VK_NULL_HANDLE; }
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,284 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.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 "FrameContext.h"
namespace MobileGL::MG_Backend::DirectVulkan {
VkResult FrameContext::Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount) {
Destroy(device, commandPool);
m_frames.assign(frameCount, {});
currentFrameIndex = 0;
Vector<VkCommandBuffer> commandBuffers(frameCount, VK_NULL_HANDLE);
VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = frameCount;
VkResult result = vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data());
if (result != VK_SUCCESS) {
return result;
}
for (Uint32 i = 0; i < frameCount; ++i) {
m_frames[i].commandBuffer = commandBuffers[i];
}
VkSemaphoreCreateInfo semaphoreInfo{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
VkFenceCreateInfo fenceInfo{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
for (Uint32 i = 0; i < frameCount; ++i) {
result = CreateSyncObjectsForFrame(device, i, semaphoreInfo, fenceInfo);
if (result != VK_SUCCESS) {
Destroy(device, commandPool);
return result;
}
}
return VK_SUCCESS;
}
void FrameContext::Destroy(VkDevice device, VkCommandPool commandPool) {
const Uint32 frameCount = static_cast<Uint32>(m_frames.size());
Vector<VkCommandBuffer> commandBuffers(frameCount, VK_NULL_HANDLE);
for (Uint32 i = 0; i < frameCount; ++i) {
commandBuffers[i] = m_frames[i].commandBuffer;
}
for (Uint32 i = 0; i < frameCount; ++i) {
DestroySyncObjectsForFrame(device, i);
}
DestroySwapchainSemaphores(device);
if (device != VK_NULL_HANDLE && commandPool != VK_NULL_HANDLE && !m_frames.empty()) {
vkFreeCommandBuffers(device, commandPool, frameCount, commandBuffers.data());
}
m_frames.clear();
currentFrameIndex = 0;
}
FrameContext::FrameData& FrameContext::GetCurrent() {
MOBILEGL_ASSERT(!m_frames.empty(), "FrameContext is not initialized");
return m_frames[currentFrameIndex];
}
const FrameContext::FrameData& FrameContext::GetCurrent() const {
MOBILEGL_ASSERT(!m_frames.empty(), "FrameContext is not initialized");
return m_frames[currentFrameIndex];
}
Bool FrameContext::IsCommandRecording() const {
return GetCurrent().isCommandRecording;
}
void FrameContext::AdvanceToNext() {
MOBILEGL_ASSERT(!m_frames.empty(), "FrameContext is not initialized");
currentFrameIndex = (currentFrameIndex + 1) % static_cast<Uint32>(m_frames.size());
GetCurrent().isCommandRecording = false;
GetCurrent().hasCommandBufferRecorded = false;
}
VkCommandBuffer& FrameContext::BeginCommandRecording(VkCommandBufferUsageFlags flags,
const VkCommandBufferInheritanceInfo* pInheritanceInfo) {
auto& frame = GetCurrent();
MOBILEGL_ASSERT(!frame.isCommandRecording, "BeginCommandRecording called while command buffer is already recording");
frame.hasCommandBufferRecorded = false;
VK_VERIFY(vkResetCommandBuffer(frame.commandBuffer, 0), "BeginCommandRecording, vkResetCommandBuffer");
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = flags;
beginInfo.pInheritanceInfo = pInheritanceInfo;
VK_VERIFY(vkBeginCommandBuffer(frame.commandBuffer, &beginInfo), "BeginCommandRecording, vkBeginCommandBuffer");
frame.isCommandRecording = true;
return frame.commandBuffer;
}
void FrameContext::EndCommandRecording() {
auto& frame = GetCurrent();
MOBILEGL_ASSERT(frame.isCommandRecording, "EndCommandRecording called without active command buffer recording");
VK_VERIFY(vkEndCommandBuffer(frame.commandBuffer), "EndCommandRecording, vkEndCommandBuffer");
frame.isCommandRecording = false;
frame.hasCommandBufferRecorded = true;
}
VkResult FrameContext::InitializeSwapchainSemaphores(VkDevice device, Uint32 swapchainImageCount) {
DestroySwapchainSemaphores(device);
if (swapchainImageCount == 0) {
return VK_SUCCESS;
}
m_swapchainImageRenderFinishedSemaphores.assign(swapchainImageCount, VK_NULL_HANDLE);
VkSemaphoreCreateInfo semaphoreInfo{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
for (Uint32 imageIndex = 0; imageIndex < swapchainImageCount; ++imageIndex) {
VkResult result =
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &m_swapchainImageRenderFinishedSemaphores[imageIndex]);
if (result != VK_SUCCESS) {
DestroySwapchainSemaphores(device);
return result;
}
}
return VK_SUCCESS;
}
void FrameContext::DestroySwapchainSemaphores(VkDevice device) {
if (device != VK_NULL_HANDLE) {
for (auto semaphore : m_swapchainImageRenderFinishedSemaphores) {
if (semaphore != VK_NULL_HANDLE) {
vkDestroySemaphore(device, semaphore, nullptr);
}
}
}
m_swapchainImageRenderFinishedSemaphores.clear();
}
Bool FrameContext::TransitionToPresent(VkImage image, VkImageLayout oldLayout, VkImageLayout presentLayout) {
auto& frame = GetCurrent();
if (frame.hasCommandBufferRecorded || frame.isCommandRecording || oldLayout == presentLayout ||
oldLayout == VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR) {
return false;
}
auto& commandBuffer = BeginCommandRecording();
VkImageMemoryBarrier presentBarrier{};
presentBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
presentBarrier.srcAccessMask = 0;
presentBarrier.dstAccessMask = 0;
presentBarrier.oldLayout = oldLayout;
presentBarrier.newLayout = presentLayout;
presentBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
presentBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
presentBarrier.image = image;
presentBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
presentBarrier.subresourceRange.baseMipLevel = 0;
presentBarrier.subresourceRange.levelCount = 1;
presentBarrier.subresourceRange.baseArrayLayer = 0;
presentBarrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0,
nullptr, 0, nullptr, 1, &presentBarrier);
EndCommandRecording();
return true;
}
FrameContext::SubmitInfoPacket FrameContext::GetSubmitInfo(Bool shouldSubmitCommandBuffer,
Uint32 swapchainImageIndex) const {
const auto& frame = GetCurrent();
MOBILEGL_ASSERT(!frame.isCommandRecording, "GetSubmitInfo called while command buffer recording is still active");
AssertValidSwapchainImageIndex(swapchainImageIndex);
SubmitInfoPacket packet{};
packet.waitSemaphore = frame.imageAvailableSemaphore;
packet.signalSemaphore = m_swapchainImageRenderFinishedSemaphores[swapchainImageIndex];
packet.commandBuffer = frame.commandBuffer;
packet.submitInfo.waitSemaphoreCount = frame.imageAvailableSemaphoreConsumed ? 0U : 1U;
packet.submitInfo.pWaitSemaphores = frame.imageAvailableSemaphoreConsumed ? nullptr : &packet.waitSemaphore;
packet.submitInfo.pWaitDstStageMask = frame.imageAvailableSemaphoreConsumed ? nullptr : &packet.waitDstStageMask;
packet.submitInfo.commandBufferCount = shouldSubmitCommandBuffer ? 1U : 0U;
packet.submitInfo.pCommandBuffers = shouldSubmitCommandBuffer ? &packet.commandBuffer : nullptr;
packet.submitInfo.signalSemaphoreCount = 1;
packet.submitInfo.pSignalSemaphores = &packet.signalSemaphore;
return packet;
}
FrameContext::PresentInfoPacket FrameContext::GetPresentInfo(VkSwapchainKHR swapchain, const Uint32& imageIndex) const {
AssertValidSwapchainImageIndex(imageIndex);
PresentInfoPacket packet{};
packet.waitSemaphore = m_swapchainImageRenderFinishedSemaphores[imageIndex];
packet.swapchain = swapchain;
packet.imageIndex = &imageIndex;
packet.presentInfo.waitSemaphoreCount = 1;
packet.presentInfo.pWaitSemaphores = &packet.waitSemaphore;
packet.presentInfo.swapchainCount = 1;
packet.presentInfo.pSwapchains = &packet.swapchain;
packet.presentInfo.pImageIndices = packet.imageIndex;
packet.presentInfo.pResults = nullptr;
return packet;
}
VkResult FrameContext::WaitAndAcquireNextImage(VkDevice device, VkSwapchainKHR swapchain, Uint32& outImageIndex,
Uint64 timeout, VkFence acquireFence) {
auto& frame = GetCurrent();
VkResult result = vkWaitForFences(device, 1, &frame.imageInFlightFence, VK_TRUE, timeout);
if (result != VK_SUCCESS) {
return result;
}
result = vkResetFences(device, 1, &frame.imageInFlightFence);
if (result != VK_SUCCESS) {
return result;
}
frame.imageAvailableSemaphoreConsumed = false;
return vkAcquireNextImageKHR(device, swapchain, timeout, frame.imageAvailableSemaphore, acquireFence,
&outImageIndex);
}
Uint32 FrameContext::GetCurrentFrameIndex() const {
return currentFrameIndex;
}
Uint32 FrameContext::GetFrameCount() const {
return static_cast<Uint32>(m_frames.size());
}
void FrameContext::AssertValidFrameIndex(Uint32 frameIndex) const {
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "FrameContext index out of range");
}
void FrameContext::AssertValidSwapchainImageIndex(Uint32 imageIndex) const {
MOBILEGL_ASSERT(imageIndex < m_swapchainImageRenderFinishedSemaphores.size(),
"FrameContext swapchain image index out of range");
}
VkResult FrameContext::CreateSyncObjectsForFrame(VkDevice device, Uint32 frameIndex,
const VkSemaphoreCreateInfo& semaphoreInfo,
const VkFenceCreateInfo& fenceInfo) {
AssertValidFrameIndex(frameIndex);
DestroySyncObjectsForFrame(device, frameIndex);
auto& frame = m_frames[frameIndex];
VkResult result =
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &frame.imageAvailableSemaphore);
if (result != VK_SUCCESS) {
return result;
}
result = vkCreateFence(device, &fenceInfo, nullptr, &frame.imageInFlightFence);
if (result != VK_SUCCESS) {
vkDestroySemaphore(device, frame.imageAvailableSemaphore, nullptr);
frame.imageAvailableSemaphore = VK_NULL_HANDLE;
return result;
}
frame.hasCommandBufferRecorded = false;
frame.isCommandRecording = false;
frame.imageAvailableSemaphoreConsumed = false;
return VK_SUCCESS;
}
void FrameContext::DestroySyncObjectsForFrame(VkDevice device, Uint32 frameIndex) {
AssertValidFrameIndex(frameIndex);
auto& frame = m_frames[frameIndex];
if (device != VK_NULL_HANDLE && frame.imageInFlightFence != VK_NULL_HANDLE) {
vkDestroyFence(device, frame.imageInFlightFence, nullptr);
}
frame.imageInFlightFence = VK_NULL_HANDLE;
if (device != VK_NULL_HANDLE && frame.imageAvailableSemaphore != VK_NULL_HANDLE) {
vkDestroySemaphore(device, frame.imageAvailableSemaphore, nullptr);
}
frame.imageAvailableSemaphore = VK_NULL_HANDLE;
frame.isCommandRecording = false;
frame.hasCommandBufferRecorded = false;
frame.imageAvailableSemaphoreConsumed = false;
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,77 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.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>
namespace MobileGL::MG_Backend::DirectVulkan {
class FrameContext {
public:
struct SubmitInfoPacket {
VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkSemaphore waitSemaphore = VK_NULL_HANDLE;
VkSemaphore signalSemaphore = VK_NULL_HANDLE;
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
VkSubmitInfo submitInfo{VK_STRUCTURE_TYPE_SUBMIT_INFO};
};
struct PresentInfoPacket {
VkSemaphore waitSemaphore = VK_NULL_HANDLE;
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
const Uint32* imageIndex = nullptr;
VkPresentInfoKHR presentInfo{VK_STRUCTURE_TYPE_PRESENT_INFO_KHR};
};
struct FrameData {
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
VkSemaphore imageAvailableSemaphore = VK_NULL_HANDLE;
VkFence imageInFlightFence = VK_NULL_HANDLE;
Bool isCommandRecording = false;
Bool hasCommandBufferRecorded = false;
Bool imageAvailableSemaphoreConsumed = false;
};
VkResult Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount);
void Destroy(VkDevice device, VkCommandPool commandPool);
// Lifecycle functions
FrameData& GetCurrent();
const FrameData& GetCurrent() const;
Bool IsCommandRecording() const;
void AdvanceToNext();
VkCommandBuffer& BeginCommandRecording(VkCommandBufferUsageFlags flags = 0,
const VkCommandBufferInheritanceInfo* pInheritanceInfo = nullptr);
void EndCommandRecording();
VkResult InitializeSwapchainSemaphores(VkDevice device, Uint32 swapchainImageCount);
void DestroySwapchainSemaphores(VkDevice device);
Bool TransitionToPresent(VkImage image, VkImageLayout oldLayout,
VkImageLayout presentLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
SubmitInfoPacket GetSubmitInfo(Bool shouldSubmitCommandBuffer, Uint32 swapchainImageIndex) const;
PresentInfoPacket GetPresentInfo(VkSwapchainKHR swapchain, const Uint32& imageIndex) const;
VkResult WaitAndAcquireNextImage(VkDevice device, VkSwapchainKHR swapchain, Uint32& outImageIndex,
Uint64 timeout = UINT64_MAX, VkFence acquireFence = VK_NULL_HANDLE);
Uint32 GetCurrentFrameIndex() const;
Uint32 GetFrameCount() const;
private:
void AssertValidFrameIndex(Uint32 frameIndex) const;
void AssertValidSwapchainImageIndex(Uint32 imageIndex) const;
VkResult CreateSyncObjectsForFrame(VkDevice device, Uint32 frameIndex,
const VkSemaphoreCreateInfo& semaphoreInfo,
const VkFenceCreateInfo& fenceInfo);
void DestroySyncObjectsForFrame(VkDevice device, Uint32 frameIndex);
Vector<FrameData> m_frames;
Vector<VkSemaphore> m_swapchainImageRenderFinishedSemaphores;
Uint32 currentFrameIndex = 0;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,148 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineFactory.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 "PipelineFactory.h"
namespace MobileGL::MG_Backend::DirectVulkan {
PipelineFactory::PipelineFactory(VkDevice device, const VulkanRendererConfig& config):
m_device(device), m_config(config) {
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "PipelineFactory: device is null");
VkPipelineCacheCreateInfo pipelineCacheInfo{VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO};
VK_VERIFY(vkCreatePipelineCache(m_device, &pipelineCacheInfo, nullptr, &m_pipelineCache),
"vkCreatePipelineCache");
}
PipelineFactory::~PipelineFactory() {
DestroyAll();
if (m_pipelineCache != VK_NULL_HANDLE) {
vkDestroyPipelineCache(m_device, m_pipelineCache, nullptr);
m_pipelineCache = VK_NULL_HANDLE;
}
}
PipelineFactory::HashType PipelineFactory::ComputeHash(const PipelineCreatePayload& payload) const {
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.programHash, sizeof(payload.programHash)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.vertexInputHash, sizeof(payload.vertexInputHash)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.pipelineLayout, sizeof(payload.pipelineLayout)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.renderPass, sizeof(payload.renderPass)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.colorAttachmentCount, sizeof(payload.colorAttachmentCount)));
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.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.depthWriteEnable, sizeof(payload.depthWriteEnable)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthCompareOp, sizeof(payload.depthCompareOp)));
if (payload.colorAttachmentCount > 0) {
XXHASH_VERIFY(XXH64_update(
m_hashState,
payload.colorBlendAttachments.data(),
sizeof(payload.colorBlendAttachments[0]) * payload.colorAttachmentCount));
}
return XXH64_digest(m_hashState);
}
VkPipeline PipelineFactory::GetOrCreatePipeline(const PipelineCreatePayload& payload) {
const HashType hash = ComputeHash(payload);
auto it = m_cache.find(hash);
if (it != m_cache.end()) {
return it->second;
}
VkPipeline pipeline = CreatePipeline(payload);
m_cache.emplace(hash, pipeline);
return pipeline;
}
void PipelineFactory::DestroyAll() {
for (auto& pair : m_cache) {
if (pair.second != VK_NULL_HANDLE) {
vkDestroyPipeline(m_device, pair.second, nullptr);
}
}
m_cache.clear();
}
VkPipeline PipelineFactory::CreatePipeline(const PipelineCreatePayload& payload) const {
MOBILEGL_ASSERT(payload.stages != nullptr && !payload.stages->empty(), "PipelineFactory: stages are empty");
MOBILEGL_ASSERT(payload.vertexInputState != nullptr, "PipelineFactory: vertexInputState is null");
MOBILEGL_ASSERT(payload.pipelineLayout != VK_NULL_HANDLE, "PipelineFactory: pipelineLayout is null");
MOBILEGL_ASSERT(payload.renderPass != VK_NULL_HANDLE, "PipelineFactory: renderPass is null");
MOBILEGL_ASSERT(payload.colorAttachmentCount <= PipelineCreatePayload::kMaxColorAttachments,
"PipelineFactory: colorAttachmentCount=%u is unexpectedly large",
payload.colorAttachmentCount);
MGLOG_D("PipelineFactory::CreatePipeline: programHash=0x%llx vertexInputHash=0x%llx colorAttachmentCount=%u subpass=%u",
static_cast<unsigned long long>(payload.programHash),
static_cast<unsigned long long>(payload.vertexInputHash),
payload.colorAttachmentCount,
payload.subpass);
static constexpr VkDynamicState kDynamicStates[] = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR
};
VkPipelineDynamicStateCreateInfo dynamicState{};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.dynamicStateCount = static_cast<uint32_t>(std::size(kDynamicStates));
dynamicState.pDynamicStates = kDynamicStates;
VkPipelineInputAssemblyStateCreateInfo ia{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO};
ia.topology = payload.topology;
VkPipelineViewportStateCreateInfo vpci{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO};
vpci.viewportCount = 1;
vpci.scissorCount = 1;
VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO};
raster.polygonMode = VK_POLYGON_MODE_FILL;
raster.cullMode = payload.cullMode;
raster.frontFace = payload.frontFace;
raster.lineWidth = 1.0f;
VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO};
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineDepthStencilStateCreateInfo depthStencil{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO};
depthStencil.depthTestEnable = payload.depthTestEnable ? VK_TRUE : VK_FALSE;
depthStencil.depthWriteEnable = payload.depthWriteEnable ? VK_TRUE : VK_FALSE;
depthStencil.depthCompareOp = payload.depthCompareOp;
depthStencil.depthBoundsTestEnable = VK_FALSE;
depthStencil.stencilTestEnable = VK_FALSE;
Vector<VkPipelineColorBlendAttachmentState> colorAttachments(payload.colorAttachmentCount);
for (Uint32 i = 0; i < payload.colorAttachmentCount; ++i) {
colorAttachments[i] = payload.colorBlendAttachments[i];
}
VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
blend.attachmentCount = payload.colorAttachmentCount;
blend.pAttachments = colorAttachments.empty() ? nullptr : colorAttachments.data();
VkGraphicsPipelineCreateInfo gpi{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};
gpi.stageCount = static_cast<Uint32>(payload.stages->size());
gpi.pStages = payload.stages->data();
gpi.pVertexInputState = payload.vertexInputState;
gpi.pInputAssemblyState = &ia;
gpi.pViewportState = &vpci;
gpi.pRasterizationState = &raster;
gpi.pMultisampleState = &ms;
gpi.pDepthStencilState = &depthStencil;
gpi.pColorBlendState = &blend;
gpi.pDynamicState = &dynamicState;
gpi.layout = payload.pipelineLayout;
gpi.renderPass = payload.renderPass;
gpi.subpass = payload.subpass;
VkPipeline pipeline = VK_NULL_HANDLE;
VK_VERIFY(vkCreateGraphicsPipelines(m_device, m_pipelineCache, 1, &gpi, nullptr, &pipeline),
"vkCreateGraphicsPipelines");
return pipeline;
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,58 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineFactory.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 "Config.h"
#include "../VkIncludes.h"
#include "MG_State/GLState/FramebufferState/FramebufferObject.h"
#include <Includes.h>
namespace MobileGL::MG_Backend::DirectVulkan {
class PipelineFactory {
public:
using HashType = Uint64;
struct PipelineCreatePayload {
static constexpr Uint32 kMaxColorAttachments = MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS;
HashType programHash = 0;
HashType vertexInputHash = 0;
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
VkRenderPass renderPass = VK_NULL_HANDLE;
Uint32 colorAttachmentCount = 1;
Uint32 subpass = 0;
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
Bool depthTestEnable = false;
Bool depthWriteEnable = false;
VkCompareOp depthCompareOp = VK_COMPARE_OP_ALWAYS;
Array<VkPipelineColorBlendAttachmentState, kMaxColorAttachments> colorBlendAttachments{};
const Vector<VkPipelineShaderStageCreateInfo>* stages = nullptr;
const VkPipelineVertexInputStateCreateInfo* vertexInputState = nullptr;
};
explicit PipelineFactory(VkDevice device, const VulkanRendererConfig& config);
~PipelineFactory();
PipelineFactory(const PipelineFactory&) = delete;
HashType ComputeHash(const PipelineCreatePayload& payload) const;
VkPipeline GetOrCreatePipeline(const PipelineCreatePayload& payload);
void DestroyAll();
private:
VkPipeline CreatePipeline(const PipelineCreatePayload& payload) const;
VkDevice m_device = VK_NULL_HANDLE;
const VulkanRendererConfig& m_config;
VkPipelineCache m_pipelineCache = VK_NULL_HANDLE;
UnorderedMap<HashType, VkPipeline> m_cache;
static inline XXH64_state_t* m_hashState = XXH64_createState();
};
} // namespace MobileGL::MG_Backend::DirectVulkan
File diff suppressed because it is too large Load Diff
@@ -1,207 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.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 "MG_State/GLState/ProgramState/ProgramObject.h"
#include "MG_State/GLState/ProgramState/ShaderObject.h"
#include "MG_State/GLState/TextureState/TextureEnum.h"
#include <Includes.h>
namespace MobileGL::MG_Backend::DirectVulkan {
class ProgramFactory {
public:
enum class DescriptorBindingKind : Uint8 {
None = 0,
UniformBufferDynamic,
CombinedImageSampler,
UniformTexelBuffer,
StorageBuffer,
StorageImage
};
enum class CompileOptionBit : Uint {
None = 0,
PositionYFlip = 1 << 0,
PositionZRemap = 1 << 1,
SurfaceRotate90 = 1 << 2,
SurfaceRotate180 = 1 << 3,
SurfaceRotate270 = 1 << 4,
};
using CompileOptionFlags = Flags<CompileOptionBit>;
using HashType = Uint64;
struct VkProgramObject {
static constexpr Uint32 kMaxVertexInputLocations = 32;
HashType hash = 0;
Vector<VkPipelineShaderStageCreateInfo> stages;
Vector<VkShaderModule> modules;
// Layout data (previously in separate VkProgramLayout)
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
Vector<DescriptorBindingKind> bindingKinds;
Vector<Uint32> dynamicBindings;
Vector<Int> uniformBlockIndexByBinding;
Vector<String> samplerNameByBinding;
Vector<Int> samplerUniformLocationByBinding;
Vector<TextureTarget> samplerTextureTargetByBinding;
Vector<String> storageBlockNameByBinding;
Vector<Int> storageBlockIndexByBinding;
Int globalUboBinding = -1;
Uint32 activeVertexInputLocationMask = 0;
Array<GLenum, kMaxVertexInputLocations> vertexInputTypes{};
Uint32 activeFragmentOutputLocationMask = 0;
Array<GLenum, kMaxVertexInputLocations> fragmentOutputTypes{};
ShaderStage rasterizationProducerStage = ShaderStage::Unknown;
Uint32 producerOutputComponentCount = 0;
Uint32 fragmentInputComponentCount = 0;
static inline VkDevice s_device = VK_NULL_HANDLE;
VkProgramObject() = default;
VkProgramObject(const VkProgramObject&) = delete;
VkProgramObject& operator=(const VkProgramObject&) = delete;
VkProgramObject(VkProgramObject&& other) noexcept {
hash = other.hash;
stages = std::move(other.stages);
modules = std::move(other.modules);
descriptorSetLayout = other.descriptorSetLayout;
pipelineLayout = other.pipelineLayout;
bindingKinds = std::move(other.bindingKinds);
dynamicBindings = std::move(other.dynamicBindings);
uniformBlockIndexByBinding = std::move(other.uniformBlockIndexByBinding);
samplerNameByBinding = std::move(other.samplerNameByBinding);
samplerUniformLocationByBinding = std::move(other.samplerUniformLocationByBinding);
samplerTextureTargetByBinding = std::move(other.samplerTextureTargetByBinding);
storageBlockNameByBinding = std::move(other.storageBlockNameByBinding);
storageBlockIndexByBinding = std::move(other.storageBlockIndexByBinding);
globalUboBinding = other.globalUboBinding;
activeVertexInputLocationMask = other.activeVertexInputLocationMask;
vertexInputTypes = other.vertexInputTypes;
activeFragmentOutputLocationMask = other.activeFragmentOutputLocationMask;
fragmentOutputTypes = other.fragmentOutputTypes;
rasterizationProducerStage = other.rasterizationProducerStage;
producerOutputComponentCount = other.producerOutputComponentCount;
fragmentInputComponentCount = other.fragmentInputComponentCount;
other.hash = 0;
other.descriptorSetLayout = VK_NULL_HANDLE;
other.pipelineLayout = VK_NULL_HANDLE;
other.globalUboBinding = -1;
other.activeVertexInputLocationMask = 0;
other.activeFragmentOutputLocationMask = 0;
other.rasterizationProducerStage = ShaderStage::Unknown;
other.producerOutputComponentCount = 0;
other.fragmentInputComponentCount = 0;
}
VkProgramObject& operator=(VkProgramObject&& other) noexcept {
if (this == &other) {
return *this;
}
Destroy();
hash = other.hash;
stages = std::move(other.stages);
modules = std::move(other.modules);
descriptorSetLayout = other.descriptorSetLayout;
pipelineLayout = other.pipelineLayout;
bindingKinds = std::move(other.bindingKinds);
dynamicBindings = std::move(other.dynamicBindings);
uniformBlockIndexByBinding = std::move(other.uniformBlockIndexByBinding);
samplerNameByBinding = std::move(other.samplerNameByBinding);
samplerUniformLocationByBinding = std::move(other.samplerUniformLocationByBinding);
samplerTextureTargetByBinding = std::move(other.samplerTextureTargetByBinding);
storageBlockNameByBinding = std::move(other.storageBlockNameByBinding);
storageBlockIndexByBinding = std::move(other.storageBlockIndexByBinding);
globalUboBinding = other.globalUboBinding;
activeVertexInputLocationMask = other.activeVertexInputLocationMask;
vertexInputTypes = other.vertexInputTypes;
activeFragmentOutputLocationMask = other.activeFragmentOutputLocationMask;
fragmentOutputTypes = other.fragmentOutputTypes;
rasterizationProducerStage = other.rasterizationProducerStage;
producerOutputComponentCount = other.producerOutputComponentCount;
fragmentInputComponentCount = other.fragmentInputComponentCount;
other.hash = 0;
other.descriptorSetLayout = VK_NULL_HANDLE;
other.pipelineLayout = VK_NULL_HANDLE;
other.globalUboBinding = -1;
other.activeVertexInputLocationMask = 0;
other.activeFragmentOutputLocationMask = 0;
other.rasterizationProducerStage = ShaderStage::Unknown;
other.producerOutputComponentCount = 0;
other.fragmentInputComponentCount = 0;
return *this;
}
~VkProgramObject() {
Destroy();
}
private:
void Destroy() {
if (s_device != VK_NULL_HANDLE) {
if (pipelineLayout != VK_NULL_HANDLE) {
vkDestroyPipelineLayout(s_device, pipelineLayout, nullptr);
pipelineLayout = VK_NULL_HANDLE;
}
if (descriptorSetLayout != VK_NULL_HANDLE) {
vkDestroyDescriptorSetLayout(s_device, descriptorSetLayout, nullptr);
descriptorSetLayout = VK_NULL_HANDLE;
}
for (auto module : modules) {
if (module != VK_NULL_HANDLE) {
vkDestroyShaderModule(s_device, module, nullptr);
}
}
}
modules.clear();
stages.clear();
}
};
explicit ProgramFactory(VkDevice device, const VulkanRendererConfig& config, Uint32 maxBindings = 16)
: m_device(device), m_config(config), m_maxBindings(maxBindings) {
VkProgramObject::s_device = device;
}
~ProgramFactory() = default;
ProgramFactory(const ProgramFactory&) = delete;
HashType ComputeHash(const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags) const;
const VkProgramObject& GetOrCreateProgram(
const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags);
static VkShaderStageFlagBits ToVkStage(ShaderStage stage);
private:
struct ProgramLookupCache {
const MG_State::GLState::ProgramObject* program = nullptr;
Uint32 backendStateVersion = 0;
CompileOptionFlags flags{};
HashType hash = 0;
};
static TextureTarget UniformTypeToTextureTarget(GLenum glType);
void ReflectVertexInputs(const Vector<SharedPtr<MG_State::GLState::ShaderObject>>& shaders,
const Vector<Vector<Uint>>& spirv,
VkProgramObject& entry) const;
void ReflectFragmentOutputs(const Vector<SharedPtr<MG_State::GLState::ShaderObject>>& shaders,
const Vector<Vector<Uint>>& spirv,
VkProgramObject& entry) const;
void ReflectLayout(const MG_State::GLState::ProgramObject& program, const Vector<Vector<Uint>>& spirv,
VkProgramObject& entry) const;
VkDevice m_device = VK_NULL_HANDLE;
Uint32 m_maxBindings = 0;
UnorderedMap<HashType, VkProgramObject> m_cache;
const VulkanRendererConfig& m_config;
mutable ProgramLookupCache m_lastLookup;
static inline XXH64_state_t* m_hashState = XXH64_createState();
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,433 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.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 "SwapchainObject.h"
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
#include "MG_State/GLState/TextureState/TextureObject2D.h"
#if defined(__has_include)
#if __has_include(<vulkan/vk_enum_string_helper.h>)
#include <vulkan/vk_enum_string_helper.h>
#define MOBILEGL_HAS_VK_ENUM_STRING_HELPER 1
#else
#define MOBILEGL_HAS_VK_ENUM_STRING_HELPER 0
#endif
#else
#define MOBILEGL_HAS_VK_ENUM_STRING_HELPER 0
#endif
#if !MOBILEGL_HAS_VK_ENUM_STRING_HELPER
static const char* string_VkFormat(VkFormat) {
return "VkFormat(unknown)";
}
static const char* string_VkColorSpaceKHR(VkColorSpaceKHR) {
return "VkColorSpaceKHR(unknown)";
}
static const char* string_VkPresentModeKHR(VkPresentModeKHR) {
return "VkPresentModeKHR(unknown)";
}
static const char* string_VkSurfaceTransformFlagBitsKHR(VkSurfaceTransformFlagBitsKHR) {
return "VkSurfaceTransformFlagBitsKHR(unknown)";
}
#endif
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,
VkSurfaceKHR surface) {
SwapchainCapabilities swapchainCapabilities{};
VK_VERIFY(
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &swapchainCapabilities.capabilities));
Uint32 formatCount = 0;
VK_VERIFY(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr));
if (formatCount != 0) {
swapchainCapabilities.surfaceFormats.resize(formatCount);
VK_VERIFY(vkGetPhysicalDeviceSurfaceFormatsKHR(
physicalDevice, surface, &formatCount, swapchainCapabilities.surfaceFormats.data()));
}
Uint32 presentModeCount = 0;
VK_VERIFY(
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr));
if (presentModeCount != 0) {
swapchainCapabilities.presentModes.resize(presentModeCount);
VK_VERIFY(vkGetPhysicalDeviceSurfacePresentModesKHR(
physicalDevice, surface, &presentModeCount, swapchainCapabilities.presentModes.data()));
}
return swapchainCapabilities;
}
VkSurfaceFormatKHR SwapchainObject::ChooseSwapchainSurfaceFormat(
const Vector<VkSurfaceFormatKHR>& availableFormats) {
for (const auto& availableFormat : availableFormats) {
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB &&
availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
return availableFormat;
}
}
// TODO: Properly rank other formats
return availableFormats[0];
}
VkPresentModeKHR SwapchainObject::ChooseSwapchainPresentMode(
const Vector<VkPresentModeKHR>& availablePresentModes) {
for (auto desiredPresentMode : s_desiredPresentModes) {
for (const auto& presentMode : availablePresentModes) {
if (presentMode == desiredPresentMode) {
return presentMode;
}
}
}
// TODO: Properly rank other modes
return availablePresentModes[0];
}
void SwapchainObject::Create(VkDevice device, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
Uint32 graphicsQueueFamily, Uint32 presentQueueFamily, Uint32 minImageCountHint) {
const auto swapchainCapabilities = GetSwapchainCapabilities(physicalDevice, surface);
MOBILEGL_ASSERT(swapchainCapabilities.IsComplete(),
"SwapchainObject::Create failed: incomplete swapchain capabilities");
MGLOG_I("Got %d surface formats:", swapchainCapabilities.surfaceFormats.size());
for (const auto& sf : swapchainCapabilities.surfaceFormats) {
MGLOG_I(" [%s, %s]", string_VkFormat(sf.format), string_VkColorSpaceKHR(sf.colorSpace));
}
const auto pickedSurfaceFormat = ChooseSwapchainSurfaceFormat(swapchainCapabilities.surfaceFormats);
MGLOG_I("Picked surface format: [%s, %s]", string_VkFormat(pickedSurfaceFormat.format),
string_VkColorSpaceKHR(pickedSurfaceFormat.colorSpace));
MGLOG_I("Got %d present modes:", swapchainCapabilities.presentModes.size());
for (const auto& pm : swapchainCapabilities.presentModes) {
MGLOG_I(" %s", string_VkPresentModeKHR(pm));
}
const auto presentMode = ChooseSwapchainPresentMode(swapchainCapabilities.presentModes);
MGLOG_I("Picked present mode: %s", string_VkPresentModeKHR(presentMode));
const auto& swapchainCaps = swapchainCapabilities.capabilities;
const auto targetImageCount = std::max<Uint32>(minImageCountHint, swapchainCaps.minImageCount);
MGLOG_I("Set minImageCount = %u", targetImageCount);
MGLOG_I("Swapchain currentTransform = %s",
string_VkSurfaceTransformFlagBitsKHR(swapchainCaps.currentTransform));
VkSwapchainCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};
createInfo.surface = surface;
createInfo.minImageCount = targetImageCount;
createInfo.imageFormat = pickedSurfaceFormat.format;
createInfo.imageColorSpace = pickedSurfaceFormat.colorSpace;
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;
const VkImageUsageFlags requiredImageUsage =
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
MOBILEGL_ASSERT((swapchainCaps.supportedUsageFlags & requiredImageUsage) == requiredImageUsage,
"Swapchain does not support required usage flags (COLOR_ATTACHMENT | TRANSFER_DST). "
"supportedUsageFlags=0x%x",
static_cast<Uint32>(swapchainCaps.supportedUsageFlags));
VkImageUsageFlags imageUsage = requiredImageUsage;
if ((swapchainCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) != 0) {
imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
createInfo.imageUsage = imageUsage;
MGLOG_I("Swapchain imageUsage = 0x%x (supportedUsageFlags = 0x%x)", static_cast<Uint32>(createInfo.imageUsage),
static_cast<Uint32>(swapchainCaps.supportedUsageFlags));
Uint32 queueFamilyIndices[] = {graphicsQueueFamily, presentQueueFamily};
if (graphicsQueueFamily != presentQueueFamily) {
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
createInfo.queueFamilyIndexCount = 2;
createInfo.pQueueFamilyIndices = queueFamilyIndices;
} else {
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr;
}
createInfo.preTransform = swapchainCaps.currentTransform;
MGLOG_I("Set swapchain preTransform = %s", string_VkSurfaceTransformFlagBitsKHR(createInfo.preTransform));
const VkCompositeAlphaFlagBitsKHR compositeAlphaCandidates[] = {
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
};
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
for (auto candidate : compositeAlphaCandidates) {
if ((swapchainCaps.supportedCompositeAlpha & candidate) != 0) {
createInfo.compositeAlpha = candidate;
break;
}
}
createInfo.presentMode = presentMode;
createInfo.clipped = VK_TRUE;
createInfo.oldSwapchain = VK_NULL_HANDLE;
m_surfaceFormat = {createInfo.imageFormat, createInfo.imageColorSpace};
m_extent = createInfo.imageExtent;
m_preTransform = createInfo.preTransform;
VK_VERIFY(vkCreateSwapchainKHR(device, &createInfo, nullptr, &m_swapchain));
Uint32 imageCount = 0;
VK_VERIFY(vkGetSwapchainImagesKHR(device, m_swapchain, &imageCount, nullptr));
m_images.resize(imageCount, VK_NULL_HANDLE);
VK_VERIFY(vkGetSwapchainImagesKHR(device, m_swapchain, &imageCount, m_images.data()));
m_imageLayouts.assign(imageCount, VK_IMAGE_LAYOUT_UNDEFINED);
CreateImageViews(device);
CreateDepthStencilResources(device, physicalDevice);
MGLOG_I("Swapchain created, extent = %dx%d, swapchain imageCount = %d", m_extent.width, m_extent.height,
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 | VK_IMAGE_USAGE_TRANSFER_SRC_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) {
DestroyDepthStencilResources(device);
for (auto imageView : m_imageViews) {
vkDestroyImageView(device, imageView, nullptr);
}
m_imageViews.clear();
if (m_swapchain != VK_NULL_HANDLE) {
vkDestroySwapchainKHR(device, m_swapchain, nullptr);
m_swapchain = VK_NULL_HANDLE;
}
m_images.clear();
m_imageLayouts.clear();
m_preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
}
VkImage SwapchainObject::GetImage(Uint32 index) const {
MOBILEGL_ASSERT(index < m_images.size(), "Swapchain image index out of range");
return m_images[index];
}
VkImageLayout SwapchainObject::GetImageLayout(Uint32 index) const {
MOBILEGL_ASSERT(index < m_imageLayouts.size(), "Swapchain image layout index out of range");
return m_imageLayouts[index];
}
void SwapchainObject::SetImageLayout(Uint32 index, VkImageLayout layout) {
MOBILEGL_ASSERT(index < m_imageLayouts.size(), "Swapchain image layout index out of range");
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) {
m_imageViews.resize(m_images.size(), VK_NULL_HANDLE);
for (SizeT i = 0; i < m_imageViews.size(); i++) {
VkImageViewCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
createInfo.image = m_images[i];
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
createInfo.format = m_surfaceFormat.format;
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
createInfo.subresourceRange.baseMipLevel = 0;
createInfo.subresourceRange.levelCount = 1;
createInfo.subresourceRange.baseArrayLayer = 0;
createInfo.subresourceRange.layerCount = 1;
VK_VERIFY(vkCreateImageView(device, &createInfo, nullptr, &m_imageViews[i]));
}
MGLOG_I("Swapchain image views created");
}
#undef VK_VERIFY
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,77 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.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 <Includes.h>
#include "../VkIncludes.h"
namespace MobileGL::MG_Backend::DirectVulkan {
class SwapchainObject {
public:
struct SwapchainCapabilities {
VkSurfaceCapabilitiesKHR capabilities;
Vector<VkSurfaceFormatKHR> surfaceFormats;
Vector<VkPresentModeKHR> presentModes;
Bool IsComplete() const {
return !surfaceFormats.empty() && !presentModes.empty();
}
};
static SwapchainCapabilities GetSwapchainCapabilities(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface);
static VkSurfaceFormatKHR ChooseSwapchainSurfaceFormat(const Vector<VkSurfaceFormatKHR>& availableFormats);
static VkPresentModeKHR ChooseSwapchainPresentMode(const Vector<VkPresentModeKHR>& availablePresentModes);
void Create(VkDevice device, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, Uint32 graphicsQueueFamily,
Uint32 presentQueueFamily, Uint32 minImageCountHint);
void Shutdown(VkDevice device);
VkSwapchainKHR GetHandle() const { return m_swapchain; }
const VkSurfaceFormatKHR& GetSurfaceFormat() const { return m_surfaceFormat; }
VkExtent2D GetExtent() const { return m_extent; }
VkSurfaceTransformFlagBitsKHR GetPreTransform() const { return m_preTransform; }
const Vector<VkImage>& GetImages() const { return m_images; }
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;
VkImageLayout GetImageLayout(Uint32 index) const;
void SetImageLayout(Uint32 index, VkImageLayout layout);
SizeT GetImageCount() const { return m_images.size(); }
private:
void CreateImageViews(VkDevice device);
void CreateDepthStencilResources(VkDevice device, VkPhysicalDevice physicalDevice);
void DestroyDepthStencilResources(VkDevice device);
static constexpr VkPresentModeKHR s_desiredPresentModes[] {
VK_PRESENT_MODE_MAILBOX_KHR,
VK_PRESENT_MODE_IMMEDIATE_KHR,
VK_PRESENT_MODE_FIFO_RELAXED_KHR,
VK_PRESENT_MODE_FIFO_KHR
};
VkSwapchainKHR m_swapchain = VK_NULL_HANDLE;
VkSurfaceFormatKHR m_surfaceFormat{};
VkExtent2D m_extent{};
VkSurfaceTransformFlagBitsKHR m_preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
Vector<VkImage> m_images;
Vector<VkImageView> m_imageViews;
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
@@ -1,953 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.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 "UniformManager.h"
#include "MG_Backend/DirectVulkan/DirectVulkanResourceState.h"
#include "MG_State/GLState/Core.h"
#include "MG_State/GLState/ProgramState/ProgramObject.h"
#include "MG_State/GLState/TextureState/TextureObject2D.h"
#include "MG_State/GLState/TextureState/TextureObjectBuffer.h"
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
#include "MG_Util/Metrics/TextureMetrics.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <limits>
namespace MobileGL::MG_Backend::DirectVulkan {
namespace {
constexpr Uint kFallbackTexture2DExternalIndex = 0xFFFFFF00u;
}
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;
}
}
static Int ResolveSamplerUnitIndex(const MG_State::GLState::ProgramObject& program, Int location, Uint32 binding) {
MOBILEGL_ASSERT(location >= -1, "ResolveSamplerUnitIndex: invalid sampler location for binding %u", binding);
if (location < 0) {
return 0;
}
const Int uniformUnit = program.GetUniformSamplerOrImageUnitIndex(static_cast<Uint>(location));
MOBILEGL_ASSERT(uniformUnit >= -1,
"ResolveSamplerUnitIndex: invalid texture unit for binding %u location %d (unit=%d)", binding,
location, uniformUnit);
return uniformUnit >= 0 ? uniformUnit : 0;
}
static Bool ShouldDumpDescriptorStats() {
static const Bool enabled = [] {
const char* value = std::getenv("MOBILEGL_DESCRIPTOR_STATS");
return value != nullptr && value[0] != '\0' && std::strcmp(value, "0") != 0;
}();
return enabled;
}
Bool UniformManager::Initialize(VkDevice device, VkBufferManager* bufferManager,
ProgramFactory* programFactory,
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
Uint32 maxBindings, Uint32 setsPerFrame,
VkTextureManager* textureManager, VkSamplerManager* samplerManager) {
Shutdown();
MOBILEGL_ASSERT(device != VK_NULL_HANDLE, "UniformDescriptorBinder::Initialize requires valid VkDevice");
MOBILEGL_ASSERT(bufferManager != nullptr, "UniformDescriptorBinder::Initialize requires valid buffer manager");
MOBILEGL_ASSERT(programFactory != nullptr,
"UniformDescriptorBinder::Initialize requires valid program factory");
MOBILEGL_ASSERT(frameCount > 0, "UniformDescriptorBinder::Initialize requires frameCount > 0");
MOBILEGL_ASSERT(maxBindings > 0, "UniformDescriptorBinder::Initialize requires maxBindings > 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_bufferManager = bufferManager;
m_programFactory = programFactory;
m_minDynamicOffsetAlignment = std::max<VkDeviceSize>(1, minUniformBufferOffsetAlignment);
m_frameCount = frameCount;
m_maxBindings = maxBindings;
m_setsPerFrame = setsPerFrame;
m_peakDescriptorSetsObserved = 0;
m_textureManager = textureManager;
m_samplerManager = samplerManager;
m_frames.resize(m_frameCount);
for (Uint32 frameIndex = 0; frameIndex < m_frameCount; ++frameIndex) {
auto& frame = m_frames[frameIndex];
frame.activeDescriptorPoolIndex = 0;
frame.allocatedSetsThisFrame = 0;
frame.peakAllocatedSetsThisFrame = 0;
frame.descriptorPools.clear();
VkDescriptorPool initialPool = VK_NULL_HANDLE;
if (!CreateDescriptorPool(m_setsPerFrame, initialPool)) {
MGLOG_E("UniformDescriptorBinder::Initialize failed: cannot create frame descriptor pool %u",
frameIndex);
Shutdown();
return false;
}
frame.descriptorPools.push_back({initialPool, m_setsPerFrame, 0});
MGLOG_D("UniformDescriptorBinder: frame %u descriptor pool created (maxSets=%u)", frameIndex,
m_setsPerFrame);
}
return true;
}
void UniformManager::Shutdown() {
for (auto& frame : m_frames) {
if (m_device != VK_NULL_HANDLE) {
for (auto& view : frame.texelBufferViews) {
if (view != VK_NULL_HANDLE) {
vkDestroyBufferView(m_device, view, nullptr);
}
}
frame.texelBufferViews.clear();
frame.descriptorSetCacheByLayout.clear();
for (auto& bucket : frame.descriptorPools) {
if (bucket.handle != VK_NULL_HANDLE) {
vkDestroyDescriptorPool(m_device, bucket.handle, nullptr);
bucket.handle = VK_NULL_HANDLE;
}
}
}
frame.descriptorPools.clear();
frame.activeDescriptorPoolIndex = 0;
frame.allocatedSetsThisFrame = 0;
frame.peakAllocatedSetsThisFrame = 0;
}
m_frames.clear();
m_bufferManager = nullptr;
m_programFactory = nullptr;
m_device = VK_NULL_HANDLE;
m_minDynamicOffsetAlignment = 1;
m_frameCount = 0;
m_maxBindings = 0;
m_setsPerFrame = 0;
m_peakDescriptorSetsObserved = 0;
m_textureManager = nullptr;
m_samplerManager = nullptr;
m_fallbackTexture2D.reset();
}
void UniformManager::BeginFrame(Uint32 frameIndex) {
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "UniformDescriptorBinder::BeginFrame invalid frame index");
auto& frame = m_frames[frameIndex];
for (auto& view : frame.texelBufferViews) {
if (view != VK_NULL_HANDLE) {
vkDestroyBufferView(m_device, view, nullptr);
}
}
frame.texelBufferViews.clear();
if (frame.peakAllocatedSetsThisFrame > m_peakDescriptorSetsObserved) {
m_peakDescriptorSetsObserved = frame.peakAllocatedSetsThisFrame;
MGLOG_D(
"UniformDescriptorBinder: new descriptor set peak observed=%u (base setsPerFrame=%u, frame=%u, pools=%zu)",
m_peakDescriptorSetsObserved, m_setsPerFrame, frameIndex, frame.descriptorPools.size());
}
frame.activeDescriptorPoolIndex = 0;
frame.allocatedSetsThisFrame = 0;
frame.peakAllocatedSetsThisFrame = 0;
for (auto& cacheEntryPair : frame.descriptorSetCacheByLayout) {
cacheEntryPair.second.cursor = 0;
}
}
Bool UniformManager::ResolveSamplerDescriptor(VkCommandBuffer commandBuffer,
const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj,
Uint32 binding, VkDescriptorImageInfo& outImageInfo) const {
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptor: texture manager is null");
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptor: sampler manager is null");
MOBILEGL_ASSERT(binding < programObj.samplerNameByBinding.size(),
"ResolveSamplerDescriptor: sampler binding %u name lookup out of range", binding);
SharedPtr<MG_State::GLState::ITextureObject> texture;
const Bool resolvedTexture = ResolveSamplerTexture(program, programObj, binding, texture);
if (!resolvedTexture) {
MGLOG_E("ResolveSamplerDescriptor: failed to resolve sampler texture for binding %u ('%s')", binding,
programObj.samplerNameByBinding[binding].c_str());
return false;
}
const Int location = programObj.samplerUniformLocationByBinding[binding];
const Int unit = ResolveSamplerUnitIndex(program, location, binding);
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
const auto samplerOverride = textureUnit.GetSamplerObject();
const auto preferredTarget = programObj.samplerTextureTargetByBinding[binding];
if (texture == nullptr) {
texture = GetFallbackTexture(preferredTarget);
MOBILEGL_ASSERT(texture != nullptr,
"ResolveSamplerDescriptor: no fallback texture available for binding=%u location=%d unit=%d target=%d",
binding, location, unit, static_cast<Int>(preferredTarget));
MGLOG_W(
"ResolveSamplerDescriptor: using fallback texture for unbound sampler binding=%u ('%s') location=%d unit=%d target=%d",
binding, programObj.samplerNameByBinding[binding].c_str(), location, unit,
static_cast<Int>(preferredTarget));
}
const MG_State::GLState::SamplerObject* samplerToUse =
samplerOverride ? samplerOverride.get() : texture->GetSamplerObject().get();
if (samplerToUse == nullptr) {
MGLOG_E(
"ResolveSamplerDescriptor: sampler binding %u ('%s') has no sampler object (textureId=%d location=%d unit=%d)",
binding, programObj.samplerNameByBinding[binding].c_str(), texture->GetExternalIndex(), location,
unit);
return false;
}
VkTextureManager::TextureResource* resource = m_textureManager->SyncTextureAndGetDescriptor(*texture);
if (resource == nullptr) {
MGLOG_E(
"ResolveSamplerDescriptor: sampler binding %u ('%s') failed to create/sync texture resource (textureId=%d target=%d location=%d unit=%d)",
binding, programObj.samplerNameByBinding[binding].c_str(), texture->GetExternalIndex(),
static_cast<Int>(texture->GetTarget()), location, unit);
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)) {
MGLOG_W("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));
}
const Bool readyForSampling = m_textureManager->TransitionTextureForSampling(commandBuffer, *texture);
if (!readyForSampling) {
MGLOG_E("ResolveSamplerDescriptor: failed to transition textureId=%d for sampler binding=%u",
texture->GetExternalIndex(), binding);
return false;
}
resource = m_textureManager->SyncTextureAndGetDescriptor(*texture);
MOBILEGL_ASSERT(resource != nullptr,
"ResolveSamplerDescriptor: failed to resync textureId=%d after sampling transition",
texture->GetExternalIndex());
MOBILEGL_ASSERT(IsValidSampledImageLayout(resource->layout),
"ResolveSamplerDescriptor: invalid sampled image layout=%d for textureId=%d, binding=%u",
static_cast<Int>(resource->layout), texture->GetExternalIndex(), binding);
}
outImageInfo = {
.sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse, *texture),
.imageView = resource->sampledView != VK_NULL_HANDLE ? resource->sampledView : resource->fullView,
.imageLayout = resource->layout,
};
if (ShouldDumpDescriptorStats()) {
std::fprintf(stderr,
"MOBILEGL_DESCRIPTOR_STATS program=%u binding=%u name=%s location=%d unit=%d "
"texture=%u target=%d sampler=%p imageView=%p layout=%d\n",
program.GetExternalIndex(),
binding,
programObj.samplerNameByBinding[binding].c_str(),
location,
unit,
texture->GetExternalIndex(),
static_cast<Int>(texture->GetTarget()),
reinterpret_cast<void*>(outImageInfo.sampler),
reinterpret_cast<void*>(outImageInfo.imageView),
static_cast<Int>(outImageInfo.imageLayout));
}
return outImageInfo.sampler != VK_NULL_HANDLE;
}
Bool UniformManager::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");
MOBILEGL_ASSERT(samplerBindingOverride.texture != nullptr,
"ResolveSamplerDescriptorOverride: override texture is null for binding %u",
samplerBindingOverride.binding);
MOBILEGL_ASSERT(samplerBindingOverride.sampler != nullptr,
"ResolveSamplerDescriptorOverride: override sampler is null for binding %u",
samplerBindingOverride.binding);
auto* resource = m_textureManager->SyncTextureAndGetDescriptor(*samplerBindingOverride.texture);
MOBILEGL_ASSERT(resource != nullptr,
"ResolveSamplerDescriptorOverride: failed to sync override texture resource for binding %u textureId=%d",
samplerBindingOverride.binding, samplerBindingOverride.texture->GetExternalIndex());
MOBILEGL_ASSERT(IsValidSampledImageLayout(resource->layout),
"ResolveSamplerDescriptorOverride: invalid layout %d for binding %u textureId=%d",
static_cast<Int>(resource->layout), samplerBindingOverride.binding,
samplerBindingOverride.texture->GetExternalIndex());
outImageInfo = {
.sampler = m_samplerManager->GetOrCreateSampler(*samplerBindingOverride.sampler,
*samplerBindingOverride.texture),
.imageView = samplerBindingOverride.imageView != VK_NULL_HANDLE ?
samplerBindingOverride.imageView :
(resource->sampledView != VK_NULL_HANDLE ? resource->sampledView : resource->fullView),
.imageLayout = resource->layout,
};
return outImageInfo.sampler != VK_NULL_HANDLE;
}
Bool UniformManager::ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) {
outTexture.reset();
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveSamplerTexture: GL context is null");
MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(),
"ResolveSamplerTexture: sampler location binding %u out of range", binding);
MOBILEGL_ASSERT(binding < programObj.samplerTextureTargetByBinding.size(),
"ResolveSamplerTexture: sampler target binding %u out of range", binding);
const Int location = programObj.samplerUniformLocationByBinding[binding];
const Int unit = ResolveSamplerUnitIndex(program, location, binding);
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
const TextureTarget preferredTarget = programObj.samplerTextureTargetByBinding[binding];
outTexture = textureUnit.GetBindingSlot(preferredTarget).GetBoundObject();
return true;
}
Bool UniformManager::ResolveTexelBufferDescriptor(const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj,
Uint32 binding, Uint32 frameIndex,
VkBufferView& outBufferView) {
outBufferView = VK_NULL_HANDLE;
MOBILEGL_ASSERT(m_bufferManager != nullptr, "ResolveTexelBufferDescriptor: buffer manager is null");
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "ResolveTexelBufferDescriptor: frame index out of range");
SharedPtr<MG_State::GLState::ITextureObject> texture;
if (!ResolveSamplerTexture(program, programObj, binding, texture) || texture == nullptr) {
MGLOG_E("ResolveTexelBufferDescriptor: texture buffer binding %u ('%s') is unbound", binding,
programObj.samplerNameByBinding[binding].c_str());
return false;
}
if (texture->GetStorageType() != TextureStorageType::Buffer ||
texture->GetTarget() != TextureTarget::TextureBuffer) {
MGLOG_E(
"ResolveTexelBufferDescriptor: binding %u ('%s') expected texture buffer, got textureId=%u target=%d storage=%d",
binding, programObj.samplerNameByBinding[binding].c_str(), texture->GetExternalIndex(),
static_cast<Int>(texture->GetTarget()), static_cast<Int>(texture->GetStorageType()));
return false;
}
auto* textureBuffer = static_cast<MG_State::GLState::TextureObjectBuffer*>(texture.get());
const auto bufferObject = textureBuffer->GetBufferBindingSlot().GetBoundObject();
if (bufferObject == nullptr) {
MGLOG_E("ResolveTexelBufferDescriptor: texture buffer binding %u ('%s') has no GL buffer bound",
binding, programObj.samplerNameByBinding[binding].c_str());
return false;
}
BufferSlice slice{};
if (!m_bufferManager->SyncResidentBuffer(BufferKind::TextureBuffer, bufferObject, slice) || !slice.IsValid()) {
MGLOG_E("ResolveTexelBufferDescriptor: failed to sync GL buffer %u for texture buffer %u",
bufferObject->GetExternalIndex(), texture->GetExternalIndex());
return false;
}
const auto internalFormat = textureBuffer->GetFormat();
const VkFormat vkFormat = MG_Util::ConvertTextureInternalFormatToVkEnum(internalFormat);
if (vkFormat == VK_FORMAT_UNDEFINED) {
MGLOG_E("ResolveTexelBufferDescriptor: unsupported texture buffer internal format %d",
static_cast<Int>(internalFormat));
return false;
}
const VkDeviceSize texelSize =
static_cast<VkDeviceSize>(MG_Util::GetSizedInternalFormatSizeInBytes(internalFormat));
VkDeviceSize viewRange = slice.size;
if (texelSize > 0) {
viewRange = (viewRange / texelSize) * texelSize;
}
if (viewRange == 0) {
MGLOG_E("ResolveTexelBufferDescriptor: texture buffer %u has empty view range", texture->GetExternalIndex());
return false;
}
VkBufferViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
viewInfo.buffer = slice.buffer;
viewInfo.format = vkFormat;
viewInfo.offset = slice.offset;
viewInfo.range = viewRange;
VkBufferView bufferView = VK_NULL_HANDLE;
const VkResult result = vkCreateBufferView(m_device, &viewInfo, nullptr, &bufferView);
if (result != VK_SUCCESS || bufferView == VK_NULL_HANDLE) {
MGLOG_E("ResolveTexelBufferDescriptor: vkCreateBufferView failed result=%d format=%d range=%zu",
result, static_cast<Int>(vkFormat), static_cast<SizeT>(viewRange));
return false;
}
m_frames[frameIndex].texelBufferViews.push_back(bufferView);
outBufferView = bufferView;
return true;
}
Bool UniformManager::ResolveStorageBufferDescriptor(const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj,
Uint32 binding,
VkDescriptorBufferInfo& outBufferInfo) const {
outBufferInfo = {};
MOBILEGL_ASSERT(m_bufferManager != nullptr, "ResolveStorageBufferDescriptor: buffer manager is null");
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveStorageBufferDescriptor: GL context is null");
MOBILEGL_ASSERT(binding < programObj.storageBlockIndexByBinding.size(),
"ResolveStorageBufferDescriptor: binding %u out of range", binding);
const Int blockIndex = programObj.storageBlockIndexByBinding[binding];
MOBILEGL_ASSERT(blockIndex >= 0, "ResolveStorageBufferDescriptor: no SSBO block mapped to binding %u",
binding);
const GLuint frontendBinding =
GetShaderStorageBlockBinding(program, static_cast<GLuint>(blockIndex));
const Uint32 bindingPointCount =
static_cast<Uint32>(MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::ShaderStorage));
MOBILEGL_ASSERT(frontendBinding < bindingPointCount,
"ResolveStorageBufferDescriptor: frontend SSBO binding %u out of range for block '%s'",
frontendBinding, programObj.storageBlockNameByBinding[binding].c_str());
auto& bindingPoint = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, frontendBinding);
const auto bufferObject = bindingPoint.GetBoundObject();
if (bufferObject == nullptr) {
MGLOG_E("ResolveStorageBufferDescriptor: no SSBO bound at frontend binding %u for block '%s'",
frontendBinding, programObj.storageBlockNameByBinding[binding].c_str());
return false;
}
BufferSlice slice{};
if (!m_bufferManager->SyncResidentBuffer(BufferKind::ShaderStorage, bufferObject, slice) || !slice.IsValid()) {
MGLOG_E("ResolveStorageBufferDescriptor: failed to sync GL buffer %u for block '%s'",
bufferObject->GetExternalIndex(), programObj.storageBlockNameByBinding[binding].c_str());
return false;
}
const auto range = bindingPoint.GetRange();
const VkDeviceSize bufferSize = static_cast<VkDeviceSize>(bufferObject->GetSize());
VkDeviceSize rangeStart = static_cast<VkDeviceSize>(std::min(range.start, bufferObject->GetSize()));
VkDeviceSize rangeEnd = static_cast<VkDeviceSize>(std::min(range.end, bufferObject->GetSize()));
if (rangeEnd <= rangeStart) {
rangeStart = 0;
rangeEnd = bufferSize;
}
if (rangeEnd <= rangeStart) {
MGLOG_E("ResolveStorageBufferDescriptor: empty SSBO range for block '%s'",
programObj.storageBlockNameByBinding[binding].c_str());
return false;
}
outBufferInfo.buffer = slice.buffer;
outBufferInfo.offset = slice.offset + rangeStart;
outBufferInfo.range = rangeEnd - rangeStart;
return true;
}
Bool UniformManager::ResolveStorageImageDescriptor(VkCommandBuffer commandBuffer,
const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj,
Uint32 binding,
VkDescriptorImageInfo& outImageInfo) const {
outImageInfo = {};
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveStorageImageDescriptor: texture manager is null");
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveStorageImageDescriptor: GL context is null");
MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(),
"ResolveStorageImageDescriptor: binding %u out of range", binding);
const Int location = programObj.samplerUniformLocationByBinding[binding];
if (location < 0) {
MGLOG_E("ResolveStorageImageDescriptor: storage image binding %u has no uniform location", binding);
return false;
}
const Int imageUnit = program.GetUniformSamplerOrImageUnitIndex(static_cast<Uint>(location));
if (imageUnit < 0 || imageUnit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
MGLOG_E("ResolveStorageImageDescriptor: image unit %d out of range for binding %u",
imageUnit, binding);
return false;
}
auto& imageBinding = MG_State::pGLContext->GetImageTextureBinding(imageUnit);
if (imageBinding.Texture == nullptr) {
MGLOG_E("ResolveStorageImageDescriptor: image unit %d is unbound for binding %u", imageUnit, binding);
return false;
}
const Bool ready = m_textureManager->TransitionTextureForStorageImage(commandBuffer, *imageBinding.Texture);
if (!ready) {
MGLOG_E("ResolveStorageImageDescriptor: failed to transition textureId=%d for image unit %d",
imageBinding.Texture->GetExternalIndex(), imageUnit);
return false;
}
auto* resource = m_textureManager->SyncTextureAndGetDescriptor(*imageBinding.Texture);
if (resource == nullptr) {
return false;
}
const Uint32 mipLevel = static_cast<Uint32>(std::max<GLint>(0, imageBinding.Level));
VkImageView view = m_textureManager->GetOrCreateViewAtMipLevel(*imageBinding.Texture, mipLevel);
if (view == VK_NULL_HANDLE) {
view = resource->fullView;
}
outImageInfo.sampler = VK_NULL_HANDLE;
outImageInfo.imageView = view;
outImageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
return outImageInfo.imageView != VK_NULL_HANDLE;
}
SharedPtr<MG_State::GLState::ITextureObject> UniformManager::GetFallbackTexture(TextureTarget target) const {
MOBILEGL_ASSERT(target == TextureTarget::Texture2D || target == TextureTarget::TextureRectangle,
"UniformManager::GetFallbackTexture: unsupported fallback target=%d",
static_cast<Int>(target));
if (m_fallbackTexture2D == nullptr) {
auto fallbackTexture = MakeShared<MG_State::GLState::TextureObject2D>(kFallbackTexture2DExternalIndex);
fallbackTexture->SetInternalFormat(TextureInternalFormat::RGBA8);
fallbackTexture->AllocateStorage(TextureUploadTarget::Texture2D, 0,
{.texelSize = {1, 1, 1}, .byteSize = 4});
fallbackTexture->MarkStorageDirty(TextureUploadTarget::Texture2D, 0, true);
m_fallbackTexture2D = fallbackTexture;
}
return m_fallbackTexture2D;
}
Bool UniformManager::CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj,
Vector<MG_State::GLState::ITextureObject*>& outTextures) {
outTextures.clear();
const Uint32 bindingCount =
std::min<Uint32>(m_maxBindings, static_cast<Uint32>(programObj.bindingKinds.size()));
for (Uint32 binding = 0; binding < bindingCount; ++binding) {
if (programObj.bindingKinds[binding] != ProgramFactory::DescriptorBindingKind::CombinedImageSampler) {
continue;
}
SharedPtr<MG_State::GLState::ITextureObject> texture;
if (!ResolveSamplerTexture(program, programObj, binding, texture) || !texture) {
continue;
}
auto found = std::find(outTextures.begin(), outTextures.end(), texture.get());
if (found == outTextures.end()) {
outTextures.push_back(texture.get());
}
}
return true;
}
Bool UniformManager::ResolveUniformBufferPayload(const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
const void*& outData, VkDeviceSize& outSize) const {
outData = nullptr;
outSize = 0;
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveUniformBufferPayload: GL context is null");
MOBILEGL_ASSERT(binding < programObj.bindingKinds.size(),
"ResolveUniformBufferPayload: binding %u out of range", binding);
MOBILEGL_ASSERT(programObj.bindingKinds[binding] == ProgramFactory::DescriptorBindingKind::UniformBufferDynamic,
"ResolveUniformBufferPayload: binding %u is not a uniform buffer descriptor", binding);
if (programObj.globalUboBinding == static_cast<Int>(binding)) {
outData = program.GetUBOData();
outSize = static_cast<VkDeviceSize>(program.GetUBOSize());
static const Array<Uint8, 16> emptyGlobalUbo{};
if (outData == nullptr || outSize == 0) {
outData = emptyGlobalUbo.data();
outSize = static_cast<VkDeviceSize>(emptyGlobalUbo.size());
}
return outData != nullptr && outSize > 0;
}
MOBILEGL_ASSERT(binding < programObj.uniformBlockIndexByBinding.size(),
"ResolveUniformBufferPayload: UBO mapping binding %u out of range", binding);
const Int blockIndex = programObj.uniformBlockIndexByBinding[binding];
MOBILEGL_ASSERT(blockIndex >= 0,
"ResolveUniformBufferPayload: no uniform block mapped to descriptor binding %u", binding);
const Uint32 activeUniformBlockCount = static_cast<Uint32>(program.GetActiveUniformBlocksCount());
MOBILEGL_ASSERT(static_cast<Uint32>(blockIndex) < activeUniformBlockCount,
"ResolveUniformBufferPayload: uniform block index %d out of range (count=%u)", blockIndex,
activeUniformBlockCount);
const Uint32 frontendBinding = program.GetUniformBlockBinding(static_cast<Uint32>(blockIndex));
const Uint32 uniformBindingPointCount =
static_cast<Uint32>(MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform));
MOBILEGL_ASSERT(frontendBinding < uniformBindingPointCount,
"ResolveUniformBufferPayload: frontend UBO binding %u out of range for block '%s'",
frontendBinding, program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
auto& bindingPoint = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, frontendBinding);
const auto bufferObject = bindingPoint.GetBoundObject();
MOBILEGL_ASSERT(bufferObject != nullptr,
"ResolveUniformBufferPayload: no UBO bound at frontend binding %u for block '%s'",
frontendBinding, program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
bufferObject->MarkPersistentMappedRangeDirty();
const auto bufferData = bufferObject->GetDataReadOnly();
MOBILEGL_ASSERT(bufferData != nullptr && !bufferData->empty(),
"ResolveUniformBufferPayload: bound UBO data is empty for block '%s'",
program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
const auto range = bindingPoint.GetRange();
const VkDeviceSize bufferSize = static_cast<VkDeviceSize>(bufferObject->GetSize());
const VkDeviceSize rangeStart = static_cast<VkDeviceSize>(range.start);
MOBILEGL_ASSERT(rangeStart < bufferSize,
"ResolveUniformBufferPayload: UBO range start %zu exceeds buffer size %zu for block '%s'",
static_cast<SizeT>(rangeStart), static_cast<SizeT>(bufferSize),
program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
VkDeviceSize rangeEnd = static_cast<VkDeviceSize>(range.end);
if (rangeEnd > bufferSize) {
rangeEnd = bufferSize;
}
MOBILEGL_ASSERT(rangeEnd > rangeStart,
"ResolveUniformBufferPayload: invalid UBO range [%zu, %zu) for block '%s'",
static_cast<SizeT>(rangeStart), static_cast<SizeT>(rangeEnd),
program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
const VkDeviceSize blockSize = static_cast<VkDeviceSize>(program.GetUBOSizeAt(static_cast<Uint32>(blockIndex)));
MOBILEGL_ASSERT(blockSize > 0,
"ResolveUniformBufferPayload: reflected UBO size is zero for block '%s'",
program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
const VkDeviceSize available = rangeEnd - rangeStart;
MOBILEGL_ASSERT(available >= blockSize,
"ResolveUniformBufferPayload: bound range %zu is smaller than UBO size %zu for block '%s'",
static_cast<SizeT>(available), static_cast<SizeT>(blockSize),
program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
outData = bufferData->data() + static_cast<SizeT>(rangeStart);
outSize = blockSize;
return true;
}
Bool UniformManager::CreateDescriptorPool(Uint32 maxSets, VkDescriptorPool& outPool) const {
outPool = VK_NULL_HANDLE;
if (m_device == VK_NULL_HANDLE || maxSets == 0 || m_maxBindings == 0) {
return false;
}
const Uint64 descriptorCount64 = static_cast<Uint64>(maxSets) * static_cast<Uint64>(m_maxBindings);
if (descriptorCount64 > static_cast<Uint64>(std::numeric_limits<Uint32>::max())) {
MGLOG_E("UniformDescriptorBinder::CreateDescriptorPool failed: descriptorCount overflow");
return false;
}
const Uint32 descriptorCount = static_cast<Uint32>(descriptorCount64);
VkDescriptorPoolSize poolSizes[5]{};
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
poolSizes[0].descriptorCount = descriptorCount;
poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
poolSizes[1].descriptorCount = descriptorCount;
poolSizes[2].type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
poolSizes[2].descriptorCount = descriptorCount;
poolSizes[3].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
poolSizes[3].descriptorCount = descriptorCount;
poolSizes[4].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
poolSizes[4].descriptorCount = descriptorCount;
VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.maxSets = maxSets;
poolInfo.poolSizeCount = static_cast<Uint32>(std::size(poolSizes));
poolInfo.pPoolSizes = poolSizes;
const VkResult result = vkCreateDescriptorPool(m_device, &poolInfo, nullptr, &outPool);
if (result != VK_SUCCESS) {
MGLOG_E("UniformDescriptorBinder::CreateDescriptorPool failed: vkCreateDescriptorPool returned %d",
result);
return false;
}
return true;
}
Bool UniformManager::GrowFrameDescriptorPool(FrameResources& frame, Uint32 frameIndex) {
if (frame.descriptorPools.empty()) {
return false;
}
const auto& currentBucket = frame.descriptorPools[frame.activeDescriptorPoolIndex];
const Uint32 currentMaxSets = std::max<Uint32>(1, currentBucket.maxSets);
const Uint32 grownMaxSets = currentMaxSets <= (std::numeric_limits<Uint32>::max() / 2) ? (currentMaxSets * 2)
: currentMaxSets;
VkDescriptorPool grownPool = VK_NULL_HANDLE;
if (!CreateDescriptorPool(grownMaxSets, grownPool)) {
MGLOG_E("UniformDescriptorBinder::GrowFrameDescriptorPool failed: cannot create grown pool (%u -> %u sets)",
currentMaxSets, grownMaxSets);
return false;
}
frame.descriptorPools.push_back({grownPool, grownMaxSets, 0});
frame.activeDescriptorPoolIndex = static_cast<Uint32>(frame.descriptorPools.size() - 1);
MGLOG_D(
"UniformDescriptorBinder: frame %u descriptor pool exhausted, grew pool (%u -> %u sets), poolCount=%zu",
frameIndex, currentMaxSets, grownMaxSets, frame.descriptorPools.size());
return true;
}
VkResult UniformManager::AllocateDescriptorSetsFromActivePool(Uint32 frameIndex, const ProgramFactory::VkProgramObject& programObj, VkDescriptorSet& outDescriptorSet) {
auto& frame = m_frames[frameIndex];
if (frame.activeDescriptorPoolIndex >= frame.descriptorPools.size()) {
frame.activeDescriptorPoolIndex = 0;
}
if (frame.descriptorPools[frame.activeDescriptorPoolIndex].allocatedSets >=
frame.descriptorPools[frame.activeDescriptorPoolIndex].maxSets) {
const auto availableBucket = std::find_if(
frame.descriptorPools.begin(), frame.descriptorPools.end(),
[](const DescriptorPoolBucket& candidate) { return candidate.allocatedSets < candidate.maxSets; });
if (availableBucket == frame.descriptorPools.end()) {
outDescriptorSet = VK_NULL_HANDLE;
return VK_ERROR_OUT_OF_POOL_MEMORY;
}
frame.activeDescriptorPoolIndex =
static_cast<Uint32>(std::distance(frame.descriptorPools.begin(), availableBucket));
}
auto& bucket = frame.descriptorPools[frame.activeDescriptorPoolIndex];
if (bucket.allocatedSets >= bucket.maxSets) {
outDescriptorSet = VK_NULL_HANDLE;
return VK_ERROR_OUT_OF_POOL_MEMORY;
}
VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorSetCount = 1;
allocInfo.pSetLayouts = &programObj.descriptorSetLayout;
allocInfo.descriptorPool = bucket.handle;
VkResult result = vkAllocateDescriptorSets(m_device, &allocInfo, &outDescriptorSet);
if (result == VK_SUCCESS) {
++bucket.allocatedSets;
}
return result;
}
VkResult UniformManager::AcquireDescriptorSet(Uint32 frameIndex,
const ProgramFactory::VkProgramObject& programObj,
VkDescriptorSet& outDescriptorSet) {
auto& frame = m_frames[frameIndex];
auto& cache = frame.descriptorSetCacheByLayout[programObj.descriptorSetLayout];
if (cache.cursor < cache.sets.size()) {
outDescriptorSet = cache.sets[cache.cursor++];
} else {
VkResult allocResult = AllocateDescriptorSetsFromActivePool(frameIndex, programObj, outDescriptorSet);
if (allocResult == VK_ERROR_OUT_OF_POOL_MEMORY || allocResult == VK_ERROR_FRAGMENTED_POOL) {
if (!GrowFrameDescriptorPool(frame, frameIndex)) {
MGLOG_E("UniformDescriptorBinder::AcquireDescriptorSet failed: descriptor pool growth failed");
return allocResult;
}
allocResult = AllocateDescriptorSetsFromActivePool(frameIndex, programObj, outDescriptorSet);
}
if (allocResult != VK_SUCCESS || outDescriptorSet == VK_NULL_HANDLE) {
return allocResult;
}
cache.sets.push_back(outDescriptorSet);
++cache.cursor;
MGLOG_D("UniformDescriptorBinder: cached descriptor set count for frame=%u grew to %zu", frameIndex,
cache.sets.size());
}
++frame.allocatedSetsThisFrame;
frame.peakAllocatedSetsThisFrame =
std::max(frame.peakAllocatedSetsThisFrame, frame.allocatedSetsThisFrame);
return VK_SUCCESS;
}
Bool UniformManager::BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj,
Uint32 frameIndex,
VkPipelineBindPoint bindPoint,
const SamplerBindingOverride* samplerBindingOverride) {
auto& frame = m_frames[frameIndex];
if (frame.descriptorPools.empty()) {
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: frame descriptor pools are invalid");
return false;
}
if (frame.activeDescriptorPoolIndex >= frame.descriptorPools.size()) {
frame.activeDescriptorPoolIndex = 0;
}
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
VkResult allocResult = AcquireDescriptorSet(frameIndex, programObj, descriptorSet);
if (allocResult != VK_SUCCESS || descriptorSet == VK_NULL_HANDLE) {
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: descriptor set acquire returned %d",
allocResult);
return false;
}
MOBILEGL_ASSERT(m_textureManager != nullptr, "BindProgramUniformBuffers: texture manager is null");
MOBILEGL_ASSERT(m_samplerManager != nullptr, "BindProgramUniformBuffers: sampler manager is null");
MOBILEGL_ASSERT(m_bufferManager != nullptr, "BindProgramUniformBuffers: buffer manager is null");
Vector<VkWriteDescriptorSet> writes;
writes.reserve(m_maxBindings);
Vector<VkDescriptorBufferInfo> bufferInfos;
Vector<VkDescriptorImageInfo> imageInfos;
Vector<VkBufferView> texelBufferViews;
Vector<Uint32> dynamicOffsets;
bufferInfos.reserve(m_maxBindings);
imageInfos.reserve(m_maxBindings);
texelBufferViews.reserve(m_maxBindings);
dynamicOffsets.reserve(programObj.dynamicBindings.size());
const Uint32 bindingCount =
std::min<Uint32>(m_maxBindings, static_cast<Uint32>(programObj.bindingKinds.size()));
for (Uint32 binding = 0; binding < bindingCount; ++binding) {
const auto kind = programObj.bindingKinds[binding];
if (kind == ProgramFactory::DescriptorBindingKind::None) {
continue;
}
VkWriteDescriptorSet write{};
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write.dstSet = descriptorSet;
write.dstBinding = binding;
write.dstArrayElement = 0;
write.descriptorCount = 1;
if (kind == ProgramFactory::DescriptorBindingKind::UniformBufferDynamic) {
const void* payload = nullptr;
VkDeviceSize payloadSize = 0;
const Bool hasPayload = ResolveUniformBufferPayload(program, programObj, binding, payload, payloadSize);
MOBILEGL_ASSERT(hasPayload && payload != nullptr && payloadSize > 0,
"UniformDescriptorBinder::BindProgramUniformBuffers failed: missing UBO payload on binding %u",
binding);
BufferSlice slice{};
if (!m_bufferManager->UploadTransient(BufferKind::Uniform, frameIndex, payload, payloadSize,
m_minDynamicOffsetAlignment, slice)) {
MOBILEGL_ASSERT(false, "UniformDescriptorBinder::BindProgramUniformBuffers failed: UBO upload failed on binding %u",
binding);
return false;
}
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = slice.buffer;
bufferInfo.offset = 0;
bufferInfo.range = payloadSize;
bufferInfos.push_back(bufferInfo);
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
write.pBufferInfo = &bufferInfos.back();
writes.push_back(write);
dynamicOffsets.push_back(static_cast<Uint32>(slice.offset));
} else if (kind == ProgramFactory::DescriptorBindingKind::UniformTexelBuffer) {
VkBufferView bufferView = VK_NULL_HANDLE;
if (!ResolveTexelBufferDescriptor(program, programObj, binding, frameIndex, bufferView) ||
bufferView == VK_NULL_HANDLE) {
MGLOG_E(
"UniformDescriptorBinder::BindProgramUniformBuffers failed: texture buffer binding %u has no valid descriptor",
binding);
return false;
}
texelBufferViews.push_back(bufferView);
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
write.pTexelBufferView = &texelBufferViews.back();
writes.push_back(write);
} else if (kind == ProgramFactory::DescriptorBindingKind::StorageBuffer) {
VkDescriptorBufferInfo bufferInfo{};
if (!ResolveStorageBufferDescriptor(program, programObj, binding, bufferInfo)) {
MGLOG_E(
"UniformDescriptorBinder::BindProgramUniformBuffers failed: storage buffer binding %u has no valid descriptor",
binding);
return false;
}
bufferInfos.push_back(bufferInfo);
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
write.pBufferInfo = &bufferInfos.back();
writes.push_back(write);
} else if (kind == ProgramFactory::DescriptorBindingKind::StorageImage) {
VkDescriptorImageInfo imageInfo{};
if (!ResolveStorageImageDescriptor(commandBuffer, program, programObj, binding, imageInfo)) {
MGLOG_E(
"UniformDescriptorBinder::BindProgramUniformBuffers failed: storage image binding %u has no valid descriptor",
binding);
return false;
}
imageInfos.push_back(imageInfo);
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
write.pImageInfo = &imageInfos.back();
writes.push_back(write);
} else {
VkDescriptorImageInfo 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, programObj, binding, imageInfo);
}
if (!hasImage) {
MGLOG_E(
"UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has no valid texture descriptor",
binding);
return false;
}
if (imageInfo.sampler == VK_NULL_HANDLE || imageInfo.imageView == VK_NULL_HANDLE) {
MGLOG_E(
"UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has null sampler or imageView",
binding);
return false;
}
imageInfos.push_back(imageInfo);
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write.pImageInfo = &imageInfos.back();
writes.push_back(write);
}
}
if (!writes.empty()) {
vkUpdateDescriptorSets(m_device, static_cast<Uint32>(writes.size()), writes.data(), 0, nullptr);
}
vkCmdBindDescriptorSets(commandBuffer, bindPoint, programObj.pipelineLayout, 0, 1,
&descriptorSet, static_cast<Uint32>(dynamicOffsets.size()), dynamicOffsets.data());
return true;
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,118 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.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 "ProgramFactory.h"
#include "VkBufferManager.h"
#include "VkSamplerManager.h"
#include "VkTextureManager.h"
#include "../VkIncludes.h"
#include <Includes.h>
namespace MobileGL::MG_State::GLState {
class ITextureObject;
class ProgramObject;
class SamplerObject;
}
namespace MobileGL::MG_Backend::DirectVulkan {
class UniformManager {
public:
struct SamplerBindingOverride {
Uint32 binding = 0;
MG_State::GLState::ITextureObject* texture = nullptr;
const MG_State::GLState::SamplerObject* sampler = nullptr;
VkImageView imageView = VK_NULL_HANDLE;
};
Bool Initialize(VkDevice device, VkBufferManager* bufferManager,
ProgramFactory* programFactory,
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
Uint32 maxBindings = 16, Uint32 setsPerFrame = 64,
VkTextureManager* textureManager = nullptr, VkSamplerManager* samplerManager = nullptr);
void Shutdown();
void BeginFrame(Uint32 frameIndex);
Bool CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj,
Vector<MG_State::GLState::ITextureObject*>& outTextures);
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj,
Uint32 frameIndex,
VkPipelineBindPoint bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
const SamplerBindingOverride* samplerBindingOverride = nullptr);
private:
struct DescriptorPoolBucket {
VkDescriptorPool handle = VK_NULL_HANDLE;
Uint32 maxSets = 0;
Uint32 allocatedSets = 0;
};
struct DescriptorSetCacheEntry {
Vector<VkDescriptorSet> sets;
Uint32 cursor = 0;
};
struct FrameResources {
Vector<DescriptorPoolBucket> descriptorPools;
UnorderedMap<VkDescriptorSetLayout, DescriptorSetCacheEntry> descriptorSetCacheByLayout;
Vector<VkBufferView> texelBufferViews;
Uint32 activeDescriptorPoolIndex = 0;
Uint32 allocatedSetsThisFrame = 0;
Uint32 peakAllocatedSetsThisFrame = 0;
};
static Bool ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
SharedPtr<MG_State::GLState::ITextureObject>& outTexture);
SharedPtr<MG_State::GLState::ITextureObject> GetFallbackTexture(TextureTarget target) const;
Bool ResolveSamplerDescriptor(VkCommandBuffer commandBuffer, const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
VkDescriptorImageInfo& outImageInfo) const;
Bool ResolveSamplerDescriptorOverride(const SamplerBindingOverride& samplerBindingOverride,
VkDescriptorImageInfo& outImageInfo) const;
Bool ResolveTexelBufferDescriptor(const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
Uint32 frameIndex, VkBufferView& outBufferView);
Bool ResolveStorageBufferDescriptor(const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
VkDescriptorBufferInfo& outBufferInfo) const;
Bool ResolveStorageImageDescriptor(VkCommandBuffer commandBuffer,
const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
VkDescriptorImageInfo& outImageInfo) const;
Bool ResolveUniformBufferPayload(const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
const void*& outData, VkDeviceSize& outSize) const;
Bool CreateDescriptorPool(Uint32 maxSets, VkDescriptorPool& outPool) const;
Bool GrowFrameDescriptorPool(FrameResources& frame, Uint32 frameIndex);
VkResult AllocateDescriptorSetsFromActivePool(
Uint32 frameIndex, const ProgramFactory::VkProgramObject& programObj, VkDescriptorSet& outDescriptorSet);
VkResult AcquireDescriptorSet(Uint32 frameIndex,
const ProgramFactory::VkProgramObject& programObj,
VkDescriptorSet& outDescriptorSet);
VkDevice m_device = VK_NULL_HANDLE;
VkBufferManager* m_bufferManager = nullptr;
ProgramFactory* m_programFactory = nullptr;
Vector<FrameResources> m_frames;
VkDeviceSize m_minDynamicOffsetAlignment = 1;
Uint32 m_frameCount = 0;
Uint32 m_maxBindings = 0;
Uint32 m_setsPerFrame = 0;
Uint32 m_peakDescriptorSetsObserved = 0;
VkTextureManager* m_textureManager = nullptr;
VkSamplerManager* m_samplerManager = nullptr;
mutable SharedPtr<MG_State::GLState::ITextureObject> m_fallbackTexture2D;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,64 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateBuilder.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 "VertexInputStateBuilder.h"
namespace MobileGL::MG_Backend::DirectVulkan {
VertexInputStateBuilder::VertexInputStateBuilder() {
Reset();
}
void VertexInputStateBuilder::Reset() {
m_bindings.clear();
m_attributes.clear();
m_state = {};
m_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
m_state.vertexBindingDescriptionCount = 0;
m_state.pVertexBindingDescriptions = nullptr;
m_state.vertexAttributeDescriptionCount = 0;
m_state.pVertexAttributeDescriptions = nullptr;
}
VertexInputStateBuilder& VertexInputStateBuilder::AddBinding(
Uint32 binding, Uint32 stride, VkVertexInputRate inputRate) {
VkVertexInputBindingDescription desc{};
desc.binding = binding;
desc.stride = stride;
desc.inputRate = inputRate;
m_bindings.push_back(desc);
return *this;
}
VertexInputStateBuilder& VertexInputStateBuilder::AddAttribute(
Uint32 location, Uint32 binding, VkFormat format, Uint32 offset) {
VkVertexInputAttributeDescription desc{};
desc.location = location;
desc.binding = binding;
desc.format = format;
desc.offset = offset;
m_attributes.push_back(desc);
return *this;
}
const VkPipelineVertexInputStateCreateInfo& VertexInputStateBuilder::Build() {
m_state.vertexBindingDescriptionCount = static_cast<Uint32>(m_bindings.size());
m_state.pVertexBindingDescriptions = m_bindings.empty() ? nullptr : m_bindings.data();
m_state.vertexAttributeDescriptionCount = static_cast<Uint32>(m_attributes.size());
m_state.pVertexAttributeDescriptions = m_attributes.empty() ? nullptr : m_attributes.data();
return m_state;
}
const Vector<VkVertexInputBindingDescription>& VertexInputStateBuilder::GetBindings() const {
return m_bindings;
}
const Vector<VkVertexInputAttributeDescription>& VertexInputStateBuilder::GetAttributes() const {
return m_attributes;
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,31 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateBuilder.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 <Includes.h>
namespace MobileGL::MG_Backend::DirectVulkan {
class VertexInputStateBuilder {
public:
VertexInputStateBuilder();
void Reset();
VertexInputStateBuilder& AddBinding(
Uint32 binding, Uint32 stride, VkVertexInputRate inputRate = VK_VERTEX_INPUT_RATE_VERTEX);
VertexInputStateBuilder& AddAttribute(Uint32 location, Uint32 binding, VkFormat format, Uint32 offset);
const VkPipelineVertexInputStateCreateInfo& Build();
const Vector<VkVertexInputBindingDescription>& GetBindings() const;
const Vector<VkVertexInputAttributeDescription>& GetAttributes() const;
private:
VkPipelineVertexInputStateCreateInfo m_state{};
Vector<VkVertexInputBindingDescription> m_bindings;
Vector<VkVertexInputAttributeDescription> m_attributes;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,225 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.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 "VertexInputStateFactory.h"
#include "MG_Util/Converters/MGToStr/DataTypeConverter.h"
#include <utility>
namespace MobileGL::MG_Backend::DirectVulkan {
VertexInputStateFactory::HashType VertexInputStateFactory::ComputeHash(
const MG_State::GLState::VertexArrayObject& vao) const {
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion));
for (Int i = 0; i < MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS; ++i) {
const auto& attr = vao.GetAttribute(i);
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Enabled, sizeof(attr.Enabled)));
if (!attr.Enabled) {
continue;
}
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Size, sizeof(attr.Size)));
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Type, sizeof(attr.Type)));
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Normalized, sizeof(attr.Normalized)));
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Stride, sizeof(attr.Stride)));
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Offset, sizeof(attr.Offset)));
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.IsInteger, sizeof(attr.IsInteger)));
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Divisor, sizeof(attr.Divisor)));
const SizeT bufferKey = reinterpret_cast<SizeT>(attr.Buffer.get());
XXHASH_VERIFY(XXH64_update(m_hashState, &bufferKey, sizeof(bufferKey)));
}
return XXH64_digest(m_hashState);
}
const VertexInputStateFactory::BackendVertexInputState& VertexInputStateFactory::GetOrCreateVertexInputState(
const MG_State::GLState::VertexArrayObject& vao) {
const HashType hash = ComputeHash(vao);
return GetOrCreateVertexInputState(vao, hash);
}
const VertexInputStateFactory::BackendVertexInputState& VertexInputStateFactory::GetOrCreateVertexInputState(
const MG_State::GLState::VertexArrayObject& vao, HashType hash) {
auto it = m_cache.find(hash);
if (it != m_cache.end()) {
return it->second;
}
VertexInputStateBuilder builder;
Vector<SizeT> bindingBufferKeys;
Vector<SizeT> bindingBaseOffsets;
Vector<Uint32> bindingAttributeLocations;
Vector<Bool> bindingUsesClientMemory;
for (Uint32 location = 0; location < MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS; ++location) {
const auto& attr = vao.GetAttribute(location);
if (!attr.Enabled) {
continue;
}
const auto vkFormat = ToVkVertexFormat(attr.Type, attr.Size, attr.Normalized, attr.IsInteger);
if (vkFormat == VK_FORMAT_UNDEFINED) {
MGLOG_D("Skipping unsupported vertex attribute layout (location=%u, type=%s, size=%d)",
location, MG_Util::ConvertDataTypeToString(attr.Type).c_str(), attr.Size);
continue;
}
const SizeT componentSize = GetComponentSize(attr.Type);
if (componentSize == 0) {
MGLOG_D("Skipping vertex attribute with unknown component size (location=%u, type=%s)",
location, MG_Util::ConvertDataTypeToString(attr.Type).c_str());
continue;
}
const Uint32 stride = attr.Stride > 0
? static_cast<Uint32>(attr.Stride)
: static_cast<Uint32>(componentSize * static_cast<SizeT>(attr.Size));
const VkVertexInputRate inputRate =
(attr.Divisor == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
const SizeT bufferKey = reinterpret_cast<SizeT>(attr.Buffer.get());
const Uint32 binding = static_cast<Uint32>(bindingBufferKeys.size());
bindingBufferKeys.push_back(bufferKey);
bindingBaseOffsets.push_back(attr.Buffer ? attr.Offset : 0);
bindingAttributeLocations.push_back(location);
bindingUsesClientMemory.push_back(attr.Buffer == nullptr);
builder.AddBinding(binding, stride, inputRate);
builder.AddAttribute(location, binding, vkFormat, 0);
}
const auto& state = builder.Build();
auto& entry = m_cache[hash];
entry.hash = hash;
entry.bindings = builder.GetBindings();
entry.attributes = builder.GetAttributes();
entry.bindingBufferKeys = std::move(bindingBufferKeys);
entry.bindingBaseOffsets = std::move(bindingBaseOffsets);
entry.bindingAttributeLocations = std::move(bindingAttributeLocations);
entry.bindingUsesClientMemory = std::move(bindingUsesClientMemory);
entry.state = state;
entry.state.pVertexBindingDescriptions = entry.bindings.empty() ? nullptr : entry.bindings.data();
entry.state.pVertexAttributeDescriptions = entry.attributes.empty() ? nullptr : entry.attributes.data();
return entry;
}
VkFormat VertexInputStateFactory::ToVkVertexFormat(DataType type, Int size, Bool normalized, Bool isInteger) {
switch (type) {
case DataType::Float32:
switch (size) {
case 1: return VK_FORMAT_R32_SFLOAT;
case 2: return VK_FORMAT_R32G32_SFLOAT;
case 3: return VK_FORMAT_R32G32B32_SFLOAT;
case 4: return VK_FORMAT_R32G32B32A32_SFLOAT;
default: return VK_FORMAT_UNDEFINED;
}
case DataType::Int32:
if (!isInteger || normalized) return VK_FORMAT_UNDEFINED;
switch (size) {
case 1: return VK_FORMAT_R32_SINT;
case 2: return VK_FORMAT_R32G32_SINT;
case 3: return VK_FORMAT_R32G32B32_SINT;
case 4: return VK_FORMAT_R32G32B32A32_SINT;
default: return VK_FORMAT_UNDEFINED;
}
case DataType::Uint32:
if (!isInteger || normalized) return VK_FORMAT_UNDEFINED;
switch (size) {
case 1: return VK_FORMAT_R32_UINT;
case 2: return VK_FORMAT_R32G32_UINT;
case 3: return VK_FORMAT_R32G32B32_UINT;
case 4: return VK_FORMAT_R32G32B32A32_UINT;
default: return VK_FORMAT_UNDEFINED;
}
case DataType::Int16:
switch (size) {
case 1:
return isInteger ? VK_FORMAT_R16_SINT : (normalized ? VK_FORMAT_R16_SNORM : VK_FORMAT_R16_SSCALED);
case 2:
return isInteger ? VK_FORMAT_R16G16_SINT
: (normalized ? VK_FORMAT_R16G16_SNORM : VK_FORMAT_R16G16_SSCALED);
case 3:
return isInteger ? VK_FORMAT_R16G16B16_SINT
: (normalized ? VK_FORMAT_R16G16B16_SNORM : VK_FORMAT_R16G16B16_SSCALED);
case 4:
return isInteger ? VK_FORMAT_R16G16B16A16_SINT
: (normalized ? VK_FORMAT_R16G16B16A16_SNORM : VK_FORMAT_R16G16B16A16_SSCALED);
default: return VK_FORMAT_UNDEFINED;
}
case DataType::Uint16:
switch (size) {
case 1:
return isInteger ? VK_FORMAT_R16_UINT : (normalized ? VK_FORMAT_R16_UNORM : VK_FORMAT_R16_USCALED);
case 2:
return isInteger ? VK_FORMAT_R16G16_UINT
: (normalized ? VK_FORMAT_R16G16_UNORM : VK_FORMAT_R16G16_USCALED);
case 3:
return isInteger ? VK_FORMAT_R16G16B16_UINT
: (normalized ? VK_FORMAT_R16G16B16_UNORM : VK_FORMAT_R16G16B16_USCALED);
case 4:
return isInteger ? VK_FORMAT_R16G16B16A16_UINT
: (normalized ? VK_FORMAT_R16G16B16A16_UNORM : VK_FORMAT_R16G16B16A16_USCALED);
default: return VK_FORMAT_UNDEFINED;
}
case DataType::Int8:
switch (size) {
case 1:
return isInteger ? VK_FORMAT_R8_SINT : (normalized ? VK_FORMAT_R8_SNORM : VK_FORMAT_R8_SSCALED);
case 2:
return isInteger ? VK_FORMAT_R8G8_SINT
: (normalized ? VK_FORMAT_R8G8_SNORM : VK_FORMAT_R8G8_SSCALED);
case 3:
return isInteger ? VK_FORMAT_R8G8B8_SINT
: (normalized ? VK_FORMAT_R8G8B8_SNORM : VK_FORMAT_R8G8B8_SSCALED);
case 4:
return isInteger ? VK_FORMAT_R8G8B8A8_SINT
: (normalized ? VK_FORMAT_R8G8B8A8_SNORM : VK_FORMAT_R8G8B8A8_SSCALED);
default: return VK_FORMAT_UNDEFINED;
}
case DataType::Uint8:
switch (size) {
case 1:
return isInteger ? VK_FORMAT_R8_UINT : (normalized ? VK_FORMAT_R8_UNORM : VK_FORMAT_R8_USCALED);
case 2:
return isInteger ? VK_FORMAT_R8G8_UINT
: (normalized ? VK_FORMAT_R8G8_UNORM : VK_FORMAT_R8G8_USCALED);
case 3:
return isInteger ? VK_FORMAT_R8G8B8_UINT
: (normalized ? VK_FORMAT_R8G8B8_UNORM : VK_FORMAT_R8G8B8_USCALED);
case 4:
return isInteger ? VK_FORMAT_R8G8B8A8_UINT
: (normalized ? VK_FORMAT_R8G8B8A8_UNORM : VK_FORMAT_R8G8B8A8_USCALED);
default: return VK_FORMAT_UNDEFINED;
}
default:
return VK_FORMAT_UNDEFINED;
}
}
SizeT VertexInputStateFactory::GetComponentSize(DataType type) {
switch (type) {
case DataType::Int8:
case DataType::Uint8:
return 1;
case DataType::Int16:
case DataType::Uint16:
case DataType::Float16:
return 2;
case DataType::Int32:
case DataType::Uint32:
case DataType::Float32:
case DataType::Fixed32:
return 4;
case DataType::Float64:
return 8;
default:
return 0;
}
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,53 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.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 "Config.h"
#include "VertexInputStateBuilder.h"
#include "MG_State/GLState/VertexArrayState/VertexArrayObject.h"
#include <Includes.h>
#include "../VkIncludes.h"
namespace MobileGL::MG_Backend::DirectVulkan {
class VertexInputStateFactory {
public:
using HashType = Uint64;
struct BackendVertexInputState {
HashType hash = 0;
Vector<VkVertexInputBindingDescription> bindings;
Vector<VkVertexInputAttributeDescription> attributes;
Vector<SizeT> bindingBufferKeys;
Vector<SizeT> bindingBaseOffsets;
Vector<Uint32> bindingAttributeLocations;
Vector<Bool> bindingUsesClientMemory;
VkPipelineVertexInputStateCreateInfo state{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO
};
};
explicit VertexInputStateFactory(const VulkanRendererConfig& config):
m_config(config) {}
~VertexInputStateFactory() = default;
VertexInputStateFactory(const VertexInputStateFactory&) = delete;
HashType ComputeHash(const MG_State::GLState::VertexArrayObject& vao) const;
const BackendVertexInputState& GetOrCreateVertexInputState(
const MG_State::GLState::VertexArrayObject& vao, HashType hash);
const BackendVertexInputState& GetOrCreateVertexInputState(const MG_State::GLState::VertexArrayObject& vao);
static SizeT GetComponentSize(DataType type);
private:
static VkFormat ToVkVertexFormat(DataType type, Int size, Bool normalized, Bool isInteger);
const VulkanRendererConfig& m_config;
UnorderedMap<HashType, BackendVertexInputState> m_cache;
static inline XXH64_state_t* m_hashState = XXH64_createState();
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,254 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.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 "VkBufferManager.h"
namespace MobileGL::MG_Backend::DirectVulkan {
namespace {
constexpr Uint32 kResidentBufferGCInterval = 60;
constexpr VmaAllocationCreateFlags kResidentBufferAllocationFlags =
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
} // namespace
Bool VkBufferManager::Initialize(const VkBufferManagerInitInfo& initInfo) {
Shutdown();
MOBILEGL_ASSERT(initInfo.allocator != nullptr, "VkBufferManager::Initialize requires valid allocator");
MOBILEGL_ASSERT(initInfo.frameCount > 0, "VkBufferManager::Initialize requires non-zero frame count");
m_initInfo = initInfo;
m_deferredResidentReleases.resize(initInfo.frameCount);
m_currentFrameIndex = 0;
return InitializeTransientArenas();
}
void VkBufferManager::Shutdown() {
m_transientUploadArena.Shutdown();
DestroyResidentBuffers();
DestroyDeferredResidentReleases();
m_initInfo = {};
m_currentFrameIndex = 0;
m_residentGcTick = 0;
}
Bool VkBufferManager::RecreateTransientArenas(Uint32 frameCount) {
MOBILEGL_ASSERT(m_initInfo.allocator != nullptr, "VkBufferManager::RecreateTransientArenas requires initialized manager");
MOBILEGL_ASSERT(frameCount > 0, "VkBufferManager::RecreateTransientArenas requires non-zero frame count");
m_transientUploadArena.Shutdown();
m_initInfo.frameCount = frameCount;
DestroyDeferredResidentReleases();
m_deferredResidentReleases.resize(frameCount);
m_currentFrameIndex = 0;
return InitializeTransientArenas();
}
void VkBufferManager::BeginFrame(Uint32 frameIndex) {
MOBILEGL_ASSERT(frameIndex < m_deferredResidentReleases.size(),
"VkBufferManager::BeginFrame frame index out of range");
m_currentFrameIndex = frameIndex;
CollectDeferredResidentReleases(frameIndex);
m_transientUploadArena.BeginFrame(frameIndex);
}
Bool VkBufferManager::UploadTransient(BufferKind kind, Uint32 frameIndex, const void* data,
VkDeviceSize size, VkDeviceSize alignment, BufferSlice& outSlice) {
(void)kind;
return m_transientUploadArena.Upload(frameIndex, data, size, alignment, outSlice);
}
Bool VkBufferManager::InitializeTransientArenas() {
return m_transientUploadArena.Initialize({
.allocator = m_initInfo.allocator,
.frameCount = m_initInfo.frameCount,
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
.memoryUsage = m_initInfo.transientMemoryUsage,
.allocationFlags = m_initInfo.transientAllocationFlags,
.minBufferSize = m_initInfo.minUploadBytes,
.persistentlyMapped = m_initInfo.transientPersistentMapping,
});
}
Bool VkBufferManager::SyncResidentBuffer(BufferKind kind,
const SharedPtr<MG_State::GLState::BufferObject>& bufferObject,
BufferSlice& outSlice) {
const VkBufferUsageFlags requiredUsage = GetVkBufferUsage(kind);
MOBILEGL_ASSERT(requiredUsage != 0,
"VkBufferManager::SyncResidentBuffer unsupported resident buffer kind");
MOBILEGL_ASSERT(bufferObject != nullptr, "VkBufferManager::SyncResidentBuffer requires valid buffer object");
CollectResidentGarbageIfNeeded();
const auto* bufferData = bufferObject->GetDataReadOnly().get();
MOBILEGL_ASSERT(bufferData != nullptr, "VkBufferManager::SyncResidentBuffer requires frontend buffer data");
bufferObject->MarkPersistentMappedRangeDirty();
const VkDeviceSize bufferSize = static_cast<VkDeviceSize>(bufferObject->GetSize());
if (bufferSize == 0) {
MGLOG_E("VkBufferManager::SyncResidentBuffer failed: buffer size is zero");
return false;
}
auto& entry = m_residentBuffers[bufferObject.get()];
entry.aliveRef = bufferObject;
const auto changeBits = bufferObject->GetChangeBits();
const Bool needsRecreate = !entry.buffer.IsValid() || entry.size != bufferSize ||
((entry.usage & requiredUsage) != requiredUsage) ||
(changeBits & BufferChangeBits::PreferReallocationBit);
if (needsRecreate) {
const VkBufferUsageFlags recreatedUsage = entry.usage | requiredUsage;
DeferResidentRelease(std::move(entry.buffer));
const Bool created = entry.buffer.Create({
.allocator = m_initInfo.allocator,
.size = bufferSize,
.usage = recreatedUsage,
.memoryUsage = VMA_MEMORY_USAGE_AUTO,
.allocationFlags = kResidentBufferAllocationFlags,
});
if (!created || entry.buffer.Map() == nullptr) {
MGLOG_E("VkBufferManager::SyncResidentBuffer failed: unable to create resident buffer");
entry.buffer.Destroy();
entry.size = 0;
entry.usage = 0;
return false;
}
if (!entry.buffer.Upload(bufferData->data(), bufferSize, 0)) {
MGLOG_E("VkBufferManager::SyncResidentBuffer failed: initial upload failed");
entry.buffer.Destroy();
entry.size = 0;
entry.usage = 0;
return false;
}
entry.size = bufferSize;
entry.usage = recreatedUsage;
bufferObject->ClearDirty();
outSlice = entry.buffer.GetSlice(0, bufferSize);
return true;
}
if (changeBits & BufferChangeBits::DirtyBit) {
const auto& dirtyRanges = bufferObject->GetDirtyRanges();
for (const auto& range : dirtyRanges) {
const VkDeviceSize rangeOffset = static_cast<VkDeviceSize>(range.start);
const VkDeviceSize rangeSize = static_cast<VkDeviceSize>(range.end - range.start);
if (rangeSize == 0) {
continue;
}
if (!entry.buffer.Upload(bufferData->data() + range.start, rangeSize, rangeOffset)) {
MGLOG_E("VkBufferManager::SyncResidentBuffer failed: dirty range upload failed");
return false;
}
}
bufferObject->ClearDirty();
}
outSlice = entry.buffer.GetSlice(0, bufferSize);
return true;
}
void VkBufferManager::DowngradeResidentBufferToTransient(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject) {
if (bufferObject == nullptr) {
return;
}
auto it = m_residentBuffers.find(bufferObject.get());
if (it == m_residentBuffers.end()) {
return;
}
DeferResidentRelease(std::move(it->second.buffer));
m_residentBuffers.erase(it);
}
void VkBufferManager::DeferResidentRelease(VkBufferObject&& buffer) {
if (!buffer.IsValid()) {
return;
}
if (m_deferredResidentReleases.empty()) {
buffer.Destroy();
return;
}
MOBILEGL_ASSERT(m_currentFrameIndex < m_deferredResidentReleases.size(),
"VkBufferManager::DeferResidentRelease current frame index out of range");
m_deferredResidentReleases[m_currentFrameIndex].push_back(std::move(buffer));
}
void VkBufferManager::CollectDeferredResidentReleases(Uint32 frameIndex) {
MOBILEGL_ASSERT(frameIndex < m_deferredResidentReleases.size(),
"VkBufferManager::CollectDeferredResidentReleases frame index out of range");
m_deferredResidentReleases[frameIndex].clear();
}
VkBufferUsageFlags VkBufferManager::GetVkBufferUsage(BufferKind kind) {
switch (kind) {
case BufferKind::Vertex:
case BufferKind::Index:
// A GL buffer can be rebound between ARRAY_BUFFER and ELEMENT_ARRAY_BUFFER,
// and may even be used as both within the same draw setup. Keep resident
// vertex/index buffers compatible with both roles from the start so we
// never need to recreate a buffer after it has already been bound.
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
case BufferKind::Uniform:
return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
case BufferKind::TextureBuffer:
return VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
case BufferKind::ShaderStorage:
return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
case BufferKind::Indirect:
return VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
default:
return 0;
}
}
void VkBufferManager::CollectResidentGarbageIfNeeded() {
++m_residentGcTick;
if (m_residentGcTick < kResidentBufferGCInterval) {
return;
}
CollectResidentGarbageNow();
m_residentGcTick = 0;
}
void VkBufferManager::CollectResidentGarbageNow() {
Vector<MG_State::GLState::BufferObject*> staleBuffers;
staleBuffers.reserve(m_residentBuffers.size());
for (const auto& [rawBuffer, entry] : m_residentBuffers) {
if (entry.aliveRef.expired()) {
staleBuffers.push_back(rawBuffer);
}
}
for (const auto* rawBuffer : staleBuffers) {
auto it = m_residentBuffers.find(const_cast<MG_State::GLState::BufferObject*>(rawBuffer));
if (it == m_residentBuffers.end()) {
continue;
}
DeferResidentRelease(std::move(it->second.buffer));
m_residentBuffers.erase(it);
}
}
void VkBufferManager::DestroyDeferredResidentReleases() {
for (auto& deferredReleases : m_deferredResidentReleases) {
deferredReleases.clear();
}
m_deferredResidentReleases.clear();
}
void VkBufferManager::DestroyResidentBuffers() {
for (auto& [_, entry] : m_residentBuffers) {
entry.buffer.Destroy();
}
m_residentBuffers.clear();
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,75 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.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 "BufferArena.h"
#include "MG_State/GLState/BufferState/BufferObject.h"
#include "../VkIncludes.h"
#include <Includes.h>
#include <vk_mem_alloc.h>
namespace MobileGL::MG_Backend::DirectVulkan {
enum class BufferKind : Uint8 {
Vertex,
Index,
Uniform,
TextureBuffer,
ShaderStorage,
Indirect,
};
struct VkBufferManagerInitInfo {
VmaAllocator allocator = nullptr;
Uint32 frameCount = 0;
VkDeviceSize minUploadBytes = 4 * 1024 * 1024;
VmaMemoryUsage transientMemoryUsage = VMA_MEMORY_USAGE_AUTO;
VmaAllocationCreateFlags transientAllocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
Bool transientPersistentMapping = false;
};
class VkBufferManager {
public:
Bool Initialize(const VkBufferManagerInitInfo& initInfo);
void Shutdown();
// Recreate all per-frame transient arenas
Bool RecreateTransientArenas(Uint32 frameCount);
void BeginFrame(Uint32 frameIndex);
Bool UploadTransient(BufferKind kind, Uint32 frameIndex, const void* data, VkDeviceSize size,
VkDeviceSize alignment, BufferSlice& outSlice);
Bool SyncResidentBuffer(BufferKind kind, const SharedPtr<MG_State::GLState::BufferObject>& bufferObject,
BufferSlice& outSlice);
void DowngradeResidentBufferToTransient(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject);
private:
struct ResidentBufferEntry {
WeakPtr<MG_State::GLState::BufferObject> aliveRef;
VkBufferObject buffer;
VkDeviceSize size = 0;
VkBufferUsageFlags usage = 0;
};
Bool InitializeTransientArenas();
static VkBufferUsageFlags GetVkBufferUsage(BufferKind kind);
void DeferResidentRelease(VkBufferObject&& buffer);
void CollectDeferredResidentReleases(Uint32 frameIndex);
void CollectResidentGarbageIfNeeded();
void CollectResidentGarbageNow();
void DestroyDeferredResidentReleases();
void DestroyResidentBuffers();
VkBufferManagerInitInfo m_initInfo{};
BufferArena m_transientUploadArena;
UnorderedMap<MG_State::GLState::BufferObject*, ResidentBufferEntry> m_residentBuffers;
Vector<Vector<VkBufferObject>> m_deferredResidentReleases;
Uint32 m_currentFrameIndex = 0;
Uint32 m_residentGcTick = 0;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,169 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.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 "VkBufferObject.h"
namespace MobileGL::MG_Backend::DirectVulkan {
VkBufferObject::VkBufferObject(VkBufferObject&& other) noexcept {
m_allocator = other.m_allocator;
m_buffer = other.m_buffer;
m_allocation = other.m_allocation;
m_mappedData = other.m_mappedData;
m_size = other.m_size;
other.m_allocator = nullptr;
other.m_buffer = VK_NULL_HANDLE;
other.m_allocation = nullptr;
other.m_mappedData = nullptr;
other.m_size = 0;
}
VkBufferObject& VkBufferObject::operator=(VkBufferObject&& other) noexcept {
if (this == &other) {
return *this;
}
Destroy();
m_allocator = other.m_allocator;
m_buffer = other.m_buffer;
m_allocation = other.m_allocation;
m_mappedData = other.m_mappedData;
m_size = other.m_size;
other.m_allocator = nullptr;
other.m_buffer = VK_NULL_HANDLE;
other.m_allocation = nullptr;
other.m_mappedData = nullptr;
other.m_size = 0;
return *this;
}
VkBufferObject::~VkBufferObject() {
Destroy();
}
Bool VkBufferObject::Create(const VkBufferObjectDesc& desc) {
return Create(desc.allocator, desc.size, desc.usage, desc.memoryUsage, desc.allocationFlags);
}
Bool VkBufferObject::Create(VmaAllocator allocator, VkDeviceSize size, VkBufferUsageFlags usage,
VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocationFlags) {
MOBILEGL_ASSERT(allocator != nullptr, "VkBufferObject::Create requires valid VMA allocator");
MOBILEGL_ASSERT(size > 0, "VkBufferObject::Create requires non-zero size");
Destroy();
m_allocator = allocator;
VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size;
bufferInfo.usage = usage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo allocationInfo{};
allocationInfo.usage = memoryUsage;
allocationInfo.flags = allocationFlags;
const VkResult result =
vmaCreateBuffer(m_allocator, &bufferInfo, &allocationInfo, &m_buffer, &m_allocation, nullptr);
if (result != VK_SUCCESS) {
MGLOG_E("VkBufferObject::Create failed: vmaCreateBuffer returned %d", result);
m_allocator = nullptr;
m_buffer = VK_NULL_HANDLE;
m_allocation = nullptr;
m_size = 0;
return false;
}
m_size = size;
return true;
}
void VkBufferObject::Destroy() {
Unmap();
if (m_allocator != nullptr && m_buffer != VK_NULL_HANDLE && m_allocation != nullptr) {
vmaDestroyBuffer(m_allocator, m_buffer, m_allocation);
}
m_buffer = VK_NULL_HANDLE;
m_allocation = nullptr;
m_allocator = nullptr;
m_size = 0;
}
void* VkBufferObject::Map() {
MOBILEGL_ASSERT(IsValid(), "VkBufferObject::Map called on invalid buffer");
if (m_mappedData != nullptr) {
return m_mappedData;
}
const VkResult mapResult = vmaMapMemory(m_allocator, m_allocation, &m_mappedData);
if (mapResult != VK_SUCCESS || m_mappedData == nullptr) {
MGLOG_E("VkBufferObject::Map failed: vmaMapMemory returned %d", mapResult);
m_mappedData = nullptr;
return nullptr;
}
return m_mappedData;
}
void VkBufferObject::Unmap() {
if (!IsValid() || m_mappedData == nullptr) {
m_mappedData = nullptr;
return;
}
vmaUnmapMemory(m_allocator, m_allocation);
m_mappedData = nullptr;
}
Bool VkBufferObject::Upload(const void* data, VkDeviceSize size, VkDeviceSize offset) {
MOBILEGL_ASSERT(IsValid(), "VkBufferObject::Upload called on invalid buffer");
MOBILEGL_ASSERT(data != nullptr || size == 0, "VkBufferObject::Upload data pointer is null");
MOBILEGL_ASSERT(offset + size <= m_size, "VkBufferObject::Upload out of range");
if (size == 0) {
return true;
}
const Bool wasMapped = IsMapped();
void* mapped = wasMapped ? m_mappedData : Map();
if (mapped == nullptr) {
MGLOG_E("VkBufferObject::Upload failed: unable to map buffer");
return false;
}
Memcpy(static_cast<Uint8*>(mapped) + offset, data, static_cast<SizeT>(size));
const VkResult flushResult = vmaFlushAllocation(m_allocator, m_allocation, offset, size);
if (flushResult != VK_SUCCESS) {
MGLOG_E("VkBufferObject::Upload failed: vmaFlushAllocation returned %d", flushResult);
if (!wasMapped) {
Unmap();
}
return false;
}
if (!wasMapped) {
Unmap();
}
return true;
}
BufferSlice VkBufferObject::GetSlice(VkDeviceSize offset, VkDeviceSize size) const {
MOBILEGL_ASSERT(offset <= m_size, "VkBufferObject::GetSlice offset out of range");
const VkDeviceSize resolvedSize = (size == VK_WHOLE_SIZE) ? (m_size - offset) : size;
MOBILEGL_ASSERT(offset + resolvedSize <= m_size, "VkBufferObject::GetSlice range out of bounds");
BufferSlice slice{};
slice.buffer = m_buffer;
slice.offset = offset;
slice.size = resolvedSize;
slice.mapped = (m_mappedData != nullptr) ? static_cast<Uint8*>(m_mappedData) + offset : nullptr;
return slice;
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,58 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.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 "BufferSlice.h"
#include "../VkIncludes.h"
#include <Includes.h>
#include <vk_mem_alloc.h>
namespace MobileGL::MG_Backend::DirectVulkan {
struct VkBufferObjectDesc {
VmaAllocator allocator = nullptr;
VkDeviceSize size = 0;
VkBufferUsageFlags usage = 0;
VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
VmaAllocationCreateFlags allocationFlags = 0;
};
class VkBufferObject {
public:
VkBufferObject() = default;
~VkBufferObject();
VkBufferObject(const VkBufferObject&) = delete;
VkBufferObject& operator=(const VkBufferObject&) = delete;
VkBufferObject(VkBufferObject&& other) noexcept;
VkBufferObject& operator=(VkBufferObject&& other) noexcept;
Bool Create(const VkBufferObjectDesc& desc);
Bool Create(VmaAllocator allocator, VkDeviceSize size, VkBufferUsageFlags usage,
VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocationFlags = 0);
void Destroy();
void* Map();
void Unmap();
Bool Upload(const void* data, VkDeviceSize size, VkDeviceSize offset = 0);
VkBuffer GetHandle() const { return m_buffer; }
VkDeviceSize GetSize() const { return m_size; }
BufferSlice GetSlice(VkDeviceSize offset = 0, VkDeviceSize size = VK_WHOLE_SIZE) const;
void* GetMappedData() const { return m_mappedData; }
Bool IsMapped() const { return m_mappedData != nullptr; }
Bool IsValid() const { return m_allocator != nullptr && m_buffer != VK_NULL_HANDLE && m_allocation != nullptr; }
private:
VmaAllocator m_allocator = nullptr;
VkBuffer m_buffer = VK_NULL_HANDLE;
VmaAllocation m_allocation = nullptr;
void* m_mappedData = nullptr;
VkDeviceSize m_size = 0;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,155 +0,0 @@
// 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"
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
#include "MG_Util/Converters/MGToStr/TextureEnumConverter.h"
namespace MobileGL::MG_Backend::DirectVulkan {
static SharedPtr<MG_State::GLState::ITextureObject> GetClearableAttachmentTexture(
const MG_State::GLState::FramebufferObject& drawFbo, FramebufferAttachmentType attachmentType) {
if (attachmentType == FramebufferAttachmentType::None) {
return nullptr;
}
const auto& attachment = drawFbo.GetAttachment(attachmentType);
if (!attachment.IsTexture() || attachment.IsRenderbuffer()) {
return nullptr;
}
return attachment.GetTexture();
}
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) {
auto texture = GetClearableAttachmentTexture(drawFbo, drawbuf);
if (!texture) {
continue;
}
QueueClear({
.mask = GL_COLOR_BUFFER_BIT,
.color = clearPayload.color
}, texture);
MGLOG_D("%s: %s (texture %d) - color = (%.2f, %.2f, %.2f, %.2f)", __func__,
MG_Util::ConvertFramebufferAttachmentTypeToString(drawbuf).c_str(),
texture->GetExternalIndex(),
clearPayload.color[0], clearPayload.color[1], clearPayload.color[2], clearPayload.color[3]);
}
}
if (mask & GL_DEPTH_BUFFER_BIT) {
auto texture = GetClearableAttachmentTexture(drawFbo, FramebufferAttachmentType::Depth);
if (texture) {
QueueClear({
.mask = GL_DEPTH_BUFFER_BIT,
.depth = clearPayload.depth,
}, texture);
MGLOG_D("%s: Depth (texture %d) - depth = (%.2f)", __func__,
texture->GetExternalIndex(), clearPayload.depth);
}
}
if (mask & GL_STENCIL_BUFFER_BIT) {
auto texture = GetClearableAttachmentTexture(drawFbo, FramebufferAttachmentType::Stencil);
if (texture) {
QueueClear({
.mask = GL_STENCIL_BUFFER_BIT,
.stencil = clearPayload.stencil,
}, texture);
MGLOG_D("%s: Stencil (texture %d) - stencil = (%u)", __func__,
texture->GetExternalIndex(), clearPayload.stencil);
}
}
}
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
const SharedPtr<MG_State::GLState::ITextureObject>& texture) {
if (clearPayload.mask == 0) {
return;
}
WeakPtr<MG_State::GLState::ITextureObject> weakTexturePtr = texture;
if (weakTexturePtr.expired())
return;
auto* pTexture = weakTexturePtr.lock().get();
m_aliveObjects[pTexture] = weakTexturePtr;
auto& pending = m_pendingClears[pTexture];
pending.mask |= clearPayload.mask;
if (clearPayload.mask & GL_COLOR_BUFFER_BIT) {
pending.color = clearPayload.color;
}
if (clearPayload.mask & GL_DEPTH_BUFFER_BIT) {
pending.depth = clearPayload.depth;
}
if (clearPayload.mask & GL_STENCIL_BUFFER_BIT) {
pending.stencil = clearPayload.stencil;
}
}
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()) {
MGLOG_D("%s: Failed getting pending clear for texture %d", __func__, texture->GetExternalIndex());
return false;
}
outPayload = m_pendingClears[texture];
MGLOG_D("%s: Got pending clear for texture %d (%s), mask=0x%x clear value: color = (%.2f, %.2f, %.2f, %.2f), depth = (%.2f), stencil = (%u)", __func__,
texture->GetExternalIndex(),
MG_Util::ConvertTextureInternalFormatToString(texture->GetFormat()).c_str(),
static_cast<Uint32>(outPayload.mask),
outPayload.color[0], outPayload.color[1], outPayload.color[2], outPayload.color[3],
outPayload.depth,
outPayload.stencil);
return true;
}
void VkClearManager::PopPendingClear(MG_State::GLState::ITextureObject* texture) {
MGLOG_D("%s: Pop pending clear for texture %d", __func__, texture->GetExternalIndex());
m_aliveObjects.erase(texture);
m_pendingClears.erase(texture);
}
SizeT VkClearManager::CollectGarbage() {
m_gcCounter++;
if (m_gcCounter != 0) {
return 0;
}
SizeT count = 0;
for (auto it = m_aliveObjects.begin(); it != m_aliveObjects.end();) {
auto current = it++;
if (current->second.expired()) {
m_pendingClears.erase(current->first);
m_aliveObjects.erase(current);
++count;
}
}
return count;
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,50 +0,0 @@
// 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 {
GLbitfield mask = 0;
FloatVec4 color = FloatVec4(0.0f, 0.0f, 0.0f, 0.0f);
Float depth = 1.0f;
Uint32 stencil = 0;
};
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,606 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.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 "VkRenderPassManager.h"
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
#include "MG_State/GLState/TextureState/TextureObject2D.h"
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
#include "MG_Util/Metrics/TextureMetrics.h"
namespace MobileGL::MG_Backend::DirectVulkan {
static Float ResolveColorClearAlpha(const MG_State::GLState::ITextureObject* texture, Float requestedAlpha) {
if (texture != nullptr && MG_Util::GetBaseInternalFormatComponentCount(texture->GetFormat()) == 3) {
return 1.0f;
}
return requestedAlpha;
}
static MG_State::GLState::ITextureObject* ResolveCompleteColorAttachmentTexture(
const MG_State::GLState::FramebufferObject& fbo,
FramebufferAttachmentType attachmentType,
Uint32 drawBufferIndex) {
if (attachmentType == FramebufferAttachmentType::None) {
return nullptr;
}
const auto& attachment = fbo.GetAttachment(attachmentType);
if (!attachment.IsTexture()) {
if (attachment.IsEmpty()) {
MGLOG_D("GetOrCreateRenderPass: draw buffer slot %u (%s) on FBO %u has no bound color attachment; using VK_ATTACHMENT_UNUSED",
drawBufferIndex,
MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(),
fbo.GetExternalIndex());
}
return nullptr;
}
if (!attachment.IsComplete()) {
MGLOG_W("GetOrCreateRenderPass: draw buffer slot %u (%s) on FBO %u has an incomplete texture attachment; using VK_ATTACHMENT_UNUSED",
drawBufferIndex,
MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(),
fbo.GetExternalIndex());
return nullptr;
}
auto* texture = attachment.GetTexture().get();
if (texture == nullptr) {
MGLOG_W("GetOrCreateRenderPass: draw buffer slot %u (%s) on FBO %u resolved to a null texture; using VK_ATTACHMENT_UNUSED",
drawBufferIndex,
MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(),
fbo.GetExternalIndex());
return nullptr;
}
return texture;
}
DepthStencilAttachmentLoadInfo ResolveDepthStencilAttachmentLoadInfo(
VkImageLayout trackedLayout, Bool clearDepth, Bool clearStencil) {
DepthStencilAttachmentLoadInfo info{};
info.depthLoadOp = clearDepth
? VK_ATTACHMENT_LOAD_OP_CLEAR
: (trackedLayout == VK_IMAGE_LAYOUT_UNDEFINED ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
: VK_ATTACHMENT_LOAD_OP_LOAD);
info.stencilLoadOp = clearStencil
? VK_ATTACHMENT_LOAD_OP_CLEAR
: (trackedLayout == VK_IMAGE_LAYOUT_UNDEFINED ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
: VK_ATTACHMENT_LOAD_OP_LOAD);
info.initialLayout =
(trackedLayout == VK_IMAGE_LAYOUT_UNDEFINED || (clearDepth && clearStencil)) ? VK_IMAGE_LAYOUT_UNDEFINED
: trackedLayout;
return info;
}
VkRenderPassManager::VkRenderPassManager(VkDevice device,
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;
}
VkRenderPassManager::~VkRenderPassManager() {}
Bool VkRenderPassManager::Initialize() {
return true;
}
void VkRenderPassManager::Shutdown() {
}
VkRenderPassManager::HashType VkRenderPassManager::ComputeHash(
const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex, Bool includePendingClear) const {
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)));
}
auto& drawBuffers = fbo.GetDrawBuffers();
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 (att.IsTexture()) {
const Int textureLevel = att.GetTextureLevel();
XXHASH_VERIFY(XXH64_update(m_hashState, &textureLevel, sizeof(textureLevel)));
Uint64 imageIdentity = 0;
auto* texture = att.GetTexture().get();
auto* resource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
if (resource != nullptr) {
imageIdentity = reinterpret_cast<Uint64>(resource->image);
}
XXHASH_VERIFY(XXH64_update(m_hashState, &imageIdentity, sizeof(imageIdentity)));
}
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.mask, sizeof(clearPayload.mask)));
}
}
VkImageLayout currentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
if (isDefaultFbo) {
if (attachment >= FramebufferAttachmentType::Color0 &&
attachment <= FramebufferAttachmentType::Color31) {
currentLayout = m_swapchainObject.GetImageLayout(swapchainImageIndex);
} else if (attachment == FramebufferAttachmentType::Depth ||
attachment == FramebufferAttachmentType::Stencil) {
currentLayout = m_swapchainObject.GetDepthStencilImageLayout(swapchainImageIndex);
}
} else {
auto* textureResource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
if (textureResource != nullptr) {
currentLayout = textureResource->layout;
}
}
XXHASH_VERIFY(XXH64_update(m_hashState, &currentLayout, sizeof(currentLayout)));
}
};
for (Int i = 0; i < validDrawBufCount; ++i) {
auto drawbuf = drawBuffers[i];
combineFramebufferAttachmentObjHash(drawbuf);
}
combineFramebufferAttachmentObjHash(FramebufferAttachmentType::Depth);
combineFramebufferAttachmentObjHash(FramebufferAttachmentType::Stencil);
return XXH64_digest(m_hashState);
}
RenderPassEntry& VkRenderPassManager::GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo,
Uint32 swapchainImageIndex) {
auto hasPendingClearOnFramebuffer = [&]() -> Bool {
const auto& drawBuffers = fbo.GetDrawBuffers();
for (auto attachment : drawBuffers) {
if (attachment == FramebufferAttachmentType::None) {
continue;
}
const auto& att = fbo.GetAttachment(attachment);
if (att.IsTexture() && m_clearManager.HasPendingClear(att.GetTexture().get())) {
return true;
}
}
const auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth);
if (depthAtt.IsTexture() && m_clearManager.HasPendingClear(depthAtt.GetTexture().get())) {
return true;
}
const auto& stencilAtt = fbo.GetAttachment(FramebufferAttachmentType::Stencil);
if (stencilAtt.IsTexture() && m_clearManager.HasPendingClear(stencilAtt.GetTexture().get())) {
return true;
}
return false;
};
// retrieve from cache first
auto* activeRenderPass = GetActiveRenderPass();
auto compatibilityHash = ComputeHash(fbo, swapchainImageIndex, false);
if (activeRenderPass != nullptr &&
activeRenderPass->CompatibleWith(compatibilityHash) &&
!hasPendingClearOnFramebuffer()) {
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;
}
auto hash = ComputeHash(fbo, swapchainImageIndex, true);
auto it = m_renderPasses.find(hash);
if (it != m_renderPasses.end())
return it->second;
Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
// Color attachment
auto& drawbufs = fbo.GetDrawBuffers();
const Uint32 colorAttachmentSlotCount = static_cast<Uint32>(drawbufs.size());
Int width = 0;
Int height = 0;
Vector<VkAttachmentDescription> attachmentDescriptions;
attachmentDescriptions.reserve(colorAttachmentSlotCount + 1);
// Keep the full GL draw buffer slot span so fragment outputs targeting GL_NONE map to VK_ATTACHMENT_UNUSED.
Vector<VkAttachmentReference> colorAttachmentRefs(colorAttachmentSlotCount);
for (auto& attachmentRef : colorAttachmentRefs) {
attachmentRef.attachment = VK_ATTACHMENT_UNUSED;
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
Vector<PendingClearAttachmentInfo> pendingClearAttachments;
pendingClearAttachments.reserve(colorAttachmentSlotCount + 1);
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
trackedAttachmentLayouts.reserve(colorAttachmentSlotCount + 1);
auto& textureResources = RenderPassEntry::s_textureResourcesScratch;
textureResources.clear();
textureResources.reserve(colorAttachmentSlotCount + 1);
Vector<VkImageView> attachmentViews;
attachmentViews.reserve(colorAttachmentSlotCount + 1);
// This should automatically work on default & offscreen FBO
// assuming default FBO has the right param
for (Uint32 i = 0; i < colorAttachmentSlotCount; ++i) {
auto drawbuf = drawbufs[i];
auto* texture = ResolveCompleteColorAttachmentTexture(fbo, drawbuf, i);
if (texture == nullptr)
continue;
auto& att = fbo.GetAttachment(drawbuf);
const Uint32 attachmentMipLevel = static_cast<Uint32>(std::max(att.GetTextureLevel(), 0));
const auto textureTarget = texture->GetTarget();
const Uint32 attachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
attachmentDescriptions.emplace_back();
// Color attachment description
VkAttachmentDescription& desc = attachmentDescriptions.back();
switch (textureTarget) {
case TextureTarget::Texture2D: {
auto* texture2d =
static_cast<MG_State::GLState::TextureObject2D*>(texture);
desc.flags = 0;
desc.format = isDefaultFbo ?
m_swapchainObject.GetSurfaceFormat().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 = attachmentIndex,
.texture = texture
});
}
if (width == 0)
width = att.GetSize().x();
if (height == 0)
height = att.GetSize().y();
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,
});
textureResources.emplace_back(nullptr);
attachmentViews.emplace_back(swapchainViews[swapchainImageIndex]);
} else {
auto* textureResource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
MOBILEGL_ASSERT(textureResource,
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i);
textureResources.emplace_back(textureResource);
desc.format = textureResource->format;
trackedColorLayout = textureResource->layout;
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
.target = TrackedAttachmentTarget::Texture,
.texture = texture,
.textureMipLevel = attachmentMipLevel,
.finalLayout = desc.finalLayout,
});
attachmentViews.emplace_back(m_textureManager.GetOrCreateViewAtMipLevel(*texture, attachmentMipLevel));
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at color attachment %d", i);
}
if (!hasClear && trackedColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
MGLOG_W("GetOrCreateRenderPass: color attachment textureId=%d starts with undefined layout and no clear; "
"using LOAD_OP_DONT_CARE",
texture->GetExternalIndex());
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");
}
// Attachment reference
VkAttachmentReference& attachmentRef = colorAttachmentRefs[i];
attachmentRef.attachment = attachmentIndex;
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
// Depth attachment description
auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth);
VkAttachmentDescription depthAttachmentDescription;
VkAttachmentReference depthAttachmentRef;
depthAttachmentRef.attachment = VK_ATTACHMENT_UNUSED;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkTextureManager::TextureResource* depthTextureResource = nullptr;
if (depthAtt.IsComplete() && depthAtt.IsTexture()) {
auto& texture = *depthAtt.GetTexture();
const Uint32 attachmentMipLevel = static_cast<Uint32>(std::max(depthAtt.GetTextureLevel(), 0));
const Uint32 depthAttachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
ClearAttachmentPayload clearPayload{};
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
Bool clearDepth = hasClear && (clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0;
Bool clearStencil = hasClear && (clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0;
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 = isDefaultFbo ?
m_swapchainObject.GetDepthStencilFormat() :
MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
if (!isDefaultFbo) {
depthAttachmentDescription.format = depthTextureResource->format;
}
depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
const auto loadInfo =
ResolveDepthStencilAttachmentLoadInfo(trackedDepthLayout, clearDepth, clearStencil);
depthAttachmentDescription.loadOp = loadInfo.depthLoadOp;
depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachmentDescription.stencilLoadOp = loadInfo.stencilLoadOp;
depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthAttachmentDescription.initialLayout = loadInfo.initialLayout;
if (trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED && (!clearDepth || !clearStencil)) {
MGLOG_W("GetOrCreateRenderPass: depth/stencil attachment textureId=%d starts with undefined layout "
"and partial/no clear; using DONT_CARE for uncleared aspects",
texture.GetExternalIndex());
}
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(depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED ||
depthAttachmentDescription.loadOp != VK_ATTACHMENT_LOAD_OP_LOAD,
"GetOrCreateRenderPass: depth attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD",
texture.GetExternalIndex());
MOBILEGL_ASSERT(depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED ||
depthAttachmentDescription.stencilLoadOp != VK_ATTACHMENT_LOAD_OP_LOAD,
"GetOrCreateRenderPass: stencil attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD",
texture.GetExternalIndex());
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
.target = TrackedAttachmentTarget::Texture,
.texture = &texture,
.textureMipLevel = attachmentMipLevel,
.finalLayout = depthAttachmentDescription.finalLayout,
});
textureResources.emplace_back(depthTextureResource);
attachmentViews.emplace_back(m_textureManager.GetOrCreateViewAtMipLevel(texture, attachmentMipLevel));
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at depth attachment");
if (width == 0 || height == 0) {
width = depthAtt.GetSize().x();
height = depthAtt.GetSize().y();
}
}
attachmentDescriptions.emplace_back(depthAttachmentDescription);
depthAttachmentRef.attachment = depthAttachmentIndex;
}
const Bool hasDepthStencilAttachment = depthAttachmentRef.attachment != VK_ATTACHMENT_UNUSED;
// Subpass
VkSubpassDescription subpassDesc;
subpassDesc.flags = 0;
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDesc.inputAttachmentCount = 0;
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;
// Render Pass
VkRenderPassCreateInfo renderPassCreateInfo;
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassCreateInfo.pNext = VK_NULL_HANDLE;
renderPassCreateInfo.flags = 0;
renderPassCreateInfo.attachmentCount = attachmentDescriptions.size();
renderPassCreateInfo.pAttachments = attachmentDescriptions.data();
renderPassCreateInfo.subpassCount = 1;
renderPassCreateInfo.pSubpasses = &subpassDesc;
renderPassCreateInfo.dependencyCount = 0;
renderPassCreateInfo.pDependencies = nullptr;
VkRenderPass renderPass = VK_NULL_HANDLE;
VK_VERIFY(vkCreateRenderPass(m_device, &renderPassCreateInfo, nullptr, &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()),
static_cast<Uint32>(colorAttachmentRefs.size()),
hasDepthStencilAttachment,
extent,
1 };
MGLOG_D("VkRenderPassManager::GetOrCreateRenderPass: hash=0x%llx compatibilityHash=0x%llx attachmentCount=%u colorAttachmentCount=%u extent=%dx%d",
static_cast<unsigned long long>(hash),
static_cast<unsigned long long>(compatibilityHash),
renderPassEntry.attachmentCount,
renderPassEntry.colorAttachmentCount,
extent.x(),
extent.y());
auto [insertedIt, _] = m_renderPasses.emplace(hash, Move(renderPassEntry));
return insertedIt->second;
}
Bool VkRenderPassManager::BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry) {
// TODO: Transition all the attachments into proper layout before starting the render pass
VkRenderPassBeginInfo renderPassBeginInfo;
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.mask & GL_COLOR_BUFFER_BIT) != 0) {
clearValues[pending.attachmentIndex].color = {
clearPayload.color.x(),
clearPayload.color.y(),
clearPayload.color.z(),
ResolveColorClearAlpha(pending.texture, clearPayload.color.w())
};
}
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
clearValues[pending.attachmentIndex].depthStencil.depth = clearPayload.depth;
}
if ((clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0) {
clearValues[pending.attachmentIndex].depthStencil.stencil = clearPayload.stencil;
}
}
renderPassBeginInfo.clearValueCount = static_cast<Uint32>(clearValues.size());
renderPassBeginInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
s_clearManager->PopPendingClear(pending.texture);
}
s_activeRenderPass.hash = renderPassEntry.hash;
s_activeRenderPass.compatibilityHash = renderPassEntry.compatibilityHash;
s_activeRenderPass.trackedAttachmentLayouts = renderPassEntry.trackedAttachmentLayouts;
s_activeRenderPass.extent = renderPassEntry.extent;
s_hasActiveRenderPass = true;
return true;
}
Bool VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) {
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->UpdateTrackedImageLayoutAfterAttachmentWrite(
commandBuffer,
trackedAttachment.texture,
trackedAttachment.textureMipLevel,
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
@@ -1,169 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.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 "SwapchainObject.h"
#include "VkClearManager.h"
#include "VkTextureManager.h"
#include "../VkIncludes.h"
#include "../VulkanRendererConfig.h"
#include "MG_State/GLState/FramebufferState/FramebufferObject.h"
#include <Includes.h>
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 textureMipLevel = 0;
Uint32 swapchainImageIndex = 0;
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
};
struct DepthStencilAttachmentLoadInfo {
VkAttachmentLoadOp depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
VkAttachmentLoadOp stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
};
DepthStencilAttachmentLoadInfo ResolveDepthStencilAttachmentLoadInfo(
VkImageLayout trackedLayout, Bool clearDepth, Bool clearStencil);
struct RenderPassEntry {
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;
Uint32 colorAttachmentCount = 0;
Bool hasDepthStencilAttachment = false;
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(colorAttachmentCount, that.colorAttachmentCount);
std::swap(hasDepthStencilAttachment, that.hasDepthStencilAttachment);
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,
Uint32 colorAttachmentCount,
Bool hasDepthStencilAttachment,
IntVec2 extent, int subpass):
hash(hash),
renderPass(renderpass),
framebuffer(framebuffer),
compatibilityHash(compatibilityHash),
pendingClearAttachments(Move(pendingClearAttachments)),
trackedAttachmentLayouts(Move(trackedAttachmentLayouts)),
attachmentCount(attachmentCount),
colorAttachmentCount(colorAttachmentCount),
hasDepthStencilAttachment(hasDepthStencilAttachment),
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 {
public:
using HashType = Uint64;
VkRenderPassManager(VkDevice device,
const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager,
SwapchainObject& swapchainObject);
~VkRenderPassManager();
Bool Initialize();
void Shutdown();
HashType ComputeHash(
const MG_State::GLState::FramebufferObject& fbo,
Uint32 swapchainImageIndex,
Bool includePendingClear = true) const;
RenderPassEntry& GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex);
static Bool BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry);
static Bool EndRenderPass(VkCommandBuffer commandBuffer);
static ActiveRenderPassInfo* GetActiveRenderPass();
private:
VkDevice m_device = VK_NULL_HANDLE;
const VulkanRendererConfig& m_config;
VkClearManager& m_clearManager;
VkTextureManager& m_textureManager;
SwapchainObject& m_swapchainObject;
UnorderedMap<Uint64, RenderPassEntry> m_renderPasses;
static inline XXH64_state_t* m_hashState = XXH64_createState();
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
@@ -1,247 +0,0 @@
// 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"
#include <algorithm>
#include <cmath>
namespace MobileGL::MG_Backend::DirectVulkan {
namespace {
Bool UsesBorderColor(const MG_State::GLState::SamplerObject& sampler) {
return sampler.GetWrapS() == SamplerWrapMode::ClampToBorder ||
sampler.GetWrapT() == SamplerWrapMode::ClampToBorder ||
sampler.GetWrapR() == SamplerWrapMode::ClampToBorder;
}
Bool IsDepthTextureFormat(TextureInternalFormat format) {
switch (format) {
case TextureInternalFormat::DepthComponent:
case TextureInternalFormat::DepthComponent16:
case TextureInternalFormat::DepthComponent24:
case TextureInternalFormat::DepthComponent32:
case TextureInternalFormat::DepthComponent32F:
case TextureInternalFormat::Depth24Stencil8:
case TextureInternalFormat::Depth32FStencil8:
case TextureInternalFormat::DepthStencil:
return true;
default:
return false;
}
}
Bool NearlyEqual(Float lhs, Float rhs) {
return std::fabs(lhs - rhs) <= 1e-6f;
}
Float ResolveEffectiveMaxLod(const MG_State::GLState::SamplerObject& sampler) {
if (sampler.GetMipmapMode() == SamplerMipmapMode::None) {
return 0.0f;
}
return sampler.GetMaxLod();
}
Float ResolveEffectiveMinLod(const MG_State::GLState::SamplerObject& sampler, Float effectiveMaxLod) {
return std::min(sampler.GetMinLod(), effectiveMaxLod);
}
} // namespace
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 MG_State::GLState::ITextureObject& texture) 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 maxLod = ResolveEffectiveMaxLod(sampler);
const auto minLod = ResolveEffectiveMinLod(sampler, maxLod);
XXHASH_VERIFY(XXH64_update(m_hashState, &minLod, sizeof(minLod)));
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 = ResolveCompareFunc(sampler, texture);
XXHASH_VERIFY(XXH64_update(m_hashState, &compareFunc, sizeof(compareFunc)));
const auto borderColor = ResolveVkBorderColor(sampler, texture);
XXHASH_VERIFY(XXH64_update(m_hashState, &borderColor, sizeof(borderColor)));
return XXH64_digest(m_hashState);
}
VkSampler VkSamplerManager::GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler,
const MG_State::GLState::ITextureObject& texture) {
const Uint64 key = BuildSamplerKey(sampler, texture);
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(ResolveCompareFunc(sampler, texture));
samplerInfo.maxLod = ResolveEffectiveMaxLod(sampler);
samplerInfo.minLod = ResolveEffectiveMinLod(sampler, samplerInfo.maxLod);
samplerInfo.borderColor = ResolveVkBorderColor(sampler, texture);
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;
}
}
SamplerCompareFunc VkSamplerManager::ResolveCompareFunc(const MG_State::GLState::SamplerObject& sampler,
const MG_State::GLState::ITextureObject& texture) {
const auto compareFunc = sampler.GetSamplerCompareFunc();
if (sampler.GetCompareMode() == SamplerCompareMode::CompareToTexture &&
IsDepthTextureFormat(texture.GetFormat()) && compareFunc == SamplerCompareFunc::Always) {
return SamplerCompareFunc::LessEqual;
}
return compareFunc;
}
VkBorderColor VkSamplerManager::ResolveVkBorderColor(const MG_State::GLState::SamplerObject& sampler,
const MG_State::GLState::ITextureObject& texture) {
if (!UsesBorderColor(sampler)) {
return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
}
const auto& borderColor = texture.GetBorderColor();
const Bool isDepthTexture = IsDepthTextureFormat(texture.GetFormat());
if (isDepthTexture) {
if (NearlyEqual(borderColor.x(), 1.0f)) {
return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
}
if (NearlyEqual(borderColor.x(), 0.0f)) {
return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
}
}
const Bool rgbZero = NearlyEqual(borderColor.x(), 0.0f) && NearlyEqual(borderColor.y(), 0.0f) &&
NearlyEqual(borderColor.z(), 0.0f);
if (rgbZero && NearlyEqual(borderColor.w(), 0.0f)) {
return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
}
if (rgbZero && NearlyEqual(borderColor.w(), 1.0f)) {
return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
}
if (NearlyEqual(borderColor.x(), 1.0f) && NearlyEqual(borderColor.y(), 1.0f) &&
NearlyEqual(borderColor.z(), 1.0f) && NearlyEqual(borderColor.w(), 1.0f)) {
return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
}
return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,58 +0,0 @@
// 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;
class ITextureObject;
}
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,
const MG_State::GLState::ITextureObject& texture);
private:
struct SamplerCacheEntry {
VkSampler handle = VK_NULL_HANDLE;
Uint externalIndex = 0;
Uint16 version = 0;
};
Uint64 BuildSamplerKey(const MG_State::GLState::SamplerObject& sampler,
const MG_State::GLState::ITextureObject& texture) const;
static VkFilter ToVkFilter(SamplerFilterMode mode);
static VkSamplerMipmapMode ToVkMipmapMode(SamplerMipmapMode mode);
static VkSamplerAddressMode ToVkAddressMode(SamplerWrapMode mode);
static VkCompareOp ToVkCompareOp(SamplerCompareFunc func);
static SamplerCompareFunc ResolveCompareFunc(const MG_State::GLState::SamplerObject& sampler,
const MG_State::GLState::ITextureObject& texture);
static VkBorderColor ResolveVkBorderColor(const MG_State::GLState::SamplerObject& sampler,
const MG_State::GLState::ITextureObject& texture);
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
File diff suppressed because it is too large Load Diff
@@ -1,189 +0,0 @@
// 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;
Uint32 frameCount = 0;
};
struct TextureResource {
VkImage image = VK_NULL_HANDLE;
VmaAllocation allocation = nullptr;
VkImageView fullView = VK_NULL_HANDLE;
VkImageView sampledView = VK_NULL_HANDLE;
Vector<VkImageView> perMipViews;
Vector<VkImageView> perMipSampledViews;
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
VkExtent2D extent = {0, 0};
Uint32 depth = 1;
Uint32 arrayLayers = 1;
Uint32 mipLevels = 1;
Uint32 sampledBaseMipLevel = 0;
Uint32 sampledLevelCount = 1;
VkFormat format = VK_FORMAT_UNDEFINED;
VkImageAspectFlags aspect = VK_IMAGE_ASPECT_NONE;
VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_2D;
Uint16 syncedTextureParamsVersion = 0;
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->fullView, that.fullView);
std::swap(this->sampledView, that.sampledView);
std::swap(this->perMipViews, that.perMipViews);
std::swap(this->perMipSampledViews, that.perMipSampledViews);
std::swap(this->layout, that.layout);
std::swap(this->extent, that.extent);
std::swap(this->depth, that.depth);
std::swap(this->arrayLayers, that.arrayLayers);
std::swap(this->mipLevels, that.mipLevels);
std::swap(this->sampledBaseMipLevel, that.sampledBaseMipLevel);
std::swap(this->sampledLevelCount, that.sampledLevelCount);
std::swap(this->format, that.format);
std::swap(this->aspect, that.aspect);
std::swap(this->viewType, that.viewType);
std::swap(this->syncedTextureParamsVersion, that.syncedTextureParamsVersion);
}
void Reset() {
if (fullView != VK_NULL_HANDLE) {
vkDestroyImageView(s_device, fullView, nullptr);
}
if (sampledView != VK_NULL_HANDLE) {
vkDestroyImageView(s_device, sampledView, nullptr);
}
for (const auto attachmentView : perMipViews) {
if (attachmentView != VK_NULL_HANDLE) {
vkDestroyImageView(s_device, attachmentView, nullptr);
}
}
for (const auto sampledView : perMipSampledViews) {
if (sampledView != VK_NULL_HANDLE) {
vkDestroyImageView(s_device, sampledView, nullptr);
}
}
if (image != VK_NULL_HANDLE && allocation != nullptr) {
vmaDestroyImage(s_allocator, image, allocation);
}
fullView = VK_NULL_HANDLE;
sampledView = VK_NULL_HANDLE;
perMipViews.clear();
perMipSampledViews.clear();
image = VK_NULL_HANDLE;
allocation = nullptr;
layout = VK_IMAGE_LAYOUT_UNDEFINED;
extent = {0, 0};
depth = 1;
arrayLayers = 1;
mipLevels = 1;
sampledBaseMipLevel = 0;
sampledLevelCount = 1;
format = VK_FORMAT_UNDEFINED;
aspect = VK_IMAGE_ASPECT_NONE;
viewType = VK_IMAGE_VIEW_TYPE_2D;
syncedTextureParamsVersion = 0;
}
~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();
void BeginFrame(Uint32 frameIndex);
TextureResource* SyncTextureAndGetDescriptor(
MG_State::GLState::ITextureObject& texture);
VkImageView GetOrCreateViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel);
VkImageView GetOrCreateSampledViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel);
void UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout);
void UpdateTrackedImageLayoutAfterAttachmentWrite(VkCommandBuffer commandBuffer,
MG_State::GLState::ITextureObject* texture,
Uint32 writtenMipLevel,
VkImageLayout newLayout);
Bool TransitionTextureForSampling(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture);
Bool TransitionTextureForStorageImage(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture);
static VkImageAspectFlags ResolveSampledImageViewAspectMask(VkImageAspectFlags imageAspect);
static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout,
VkImageLayout newLayout, VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask,
Uint32 baseMipLevel = 0, Uint32 levelCount = 1,
Uint32 layerCount = 1);
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 SyncTextureViews(const MG_State::GLState::ITextureObject& texture, TextureResource& resource);
VkImageView CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspect,
VkImageViewType viewType, Uint32 baseMipLevel, Uint32 levelCount,
Uint32 layerCount,
const VkComponentMapping* components = nullptr) const;
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 void ResolveViewMipRange(const MG_State::GLState::ITextureObject& texture, Uint32 mipLevels,
Uint32& outBaseMipLevel, Uint32& outLevelCount);
static VkImageAspectFlags GetAspectMaskForFormat(VkFormat format);
void DeferResourceRelease(TextureResource&& resource);
void DeferViewRelease(VkImageView view);
void CollectDeferredReleases(Uint32 frameIndex);
void DestroyDeferredReleases();
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;
Uint32 m_currentFrameIndex = 0;
Uint8 m_gcCounter = 0;
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
UnorderedMap<MG_State::GLState::ITextureObject*, TextureResource> m_textureResources;
Vector<Vector<TextureResource>> m_deferredReleases;
Vector<Vector<VkImageView>> m_deferredViewReleases;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
File diff suppressed because it is too large Load Diff
@@ -1,337 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.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 "Config.h"
#include "FrameContext.h"
#include "PipelineFactory.h"
#include "ProgramFactory.h"
#include "SwapchainObject.h"
#include "UniformManager.h"
#include "VertexInputStateFactory.h"
#include "VkBufferObject.h"
#include "VkBufferManager.h"
#include "VkClearManager.h"
#include "VkRenderPassManager.h"
#include "VkSamplerManager.h"
#include "VkTextureManager.h"
#include "MG_Util/Math/VectorTypes.h"
#include <Includes.h>
#include <vk_mem_alloc.h>
#include "../VkIncludes.h"
namespace MobileGL::MG_State::GLState {
class FramebufferObject;
class ProgramObject;
class SamplerObject;
class VertexArrayObject;
} // namespace MobileGL::MG_State::GLState
namespace MobileGL::MG_Backend::DirectVulkan {
enum class DrawSetupAspect: Uint8 {
FramebufferObject = 1 << 0,
VertexArrayObject = 1 << 1,
UniformBuffer = 1 << 2,
VertexBuffer = 1 << 3,
IndexBuffer = 1 << 4,
IndirectDrawBuffer = 1 << 5,
Viewport = 1 << 6,
Scissor = 1 << 7,
};
struct DrawCmdParam {
Uint32 vertexCount = 0;
Uint32 instanceCount = 1;
Uint32 firstVertex = 0;
Uint32 firstInstance = 0;
};
struct DrawIndexedCmdParam {
Uint32 indexCount = 0;
Uint32 instanceCount = 1;
Uint32 firstIndex = 0;
Int32 vertexOffset = 0;
Int32 firstInstance = 0;
};
struct DrawCmd {
GLenum mode = GL_TRIANGLES;
DrawCmdParam params;
};
struct IndexBufferView {
GLenum indexType = GL_UNSIGNED_SHORT;
SizeT indexByteOffset = 0;
SizeT indexByteSize = 0;
};
struct DrawIndexedCmd {
GLenum mode = GL_TRIANGLES;
IndexBufferView indexBufferView;
DrawIndexedCmdParam params;
};
struct MultiDrawIndexedCmd {
GLenum mode = GL_TRIANGLES;
IndexBufferView indexBufferView;
Uint32 drawCount = 0;
DrawIndexedCmdParam* pParams = nullptr;
};
struct QueueFamilyIndices {
Int32 graphicsFamily = -1;
Int32 presentFamily = -1;
};
struct PhysicalDevice {
QueueFamilyIndices queueFamilies;
VkPhysicalDeviceProperties properties;
VkPhysicalDevice handle = VK_NULL_HANDLE;
Bool IsComplete() const {
return handle != VK_NULL_HANDLE && queueFamilies.graphicsFamily != -1 && queueFamilies.presentFamily != -1;
}
};
class VulkanRenderer {
public:
VulkanRenderer(NativeWindowType window, const VulkanRendererConfig& cfg = {});
~VulkanRenderer();
void Initialize();
void Shutdown();
Bool SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags<DrawSetupAspect> aspects,
const DrawCmdParam& drawParams,
const IndexBufferView* pIndexBufferView = nullptr);
void ClearAttachmentsOnActiveRenderPass(VkCommandBuffer commandBuffer,
const RenderPassEntry& compatibleRenderPassEntry);
void Clear(GLbitfield mask);
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFbo,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFbo,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLint x, GLint y, GLsizei width, GLsizei height);
void GenerateMipmap(GLenum target);
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
void GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& texture,
TextureUploadTarget uploadTarget, GLint level, GLenum format, GLenum type,
GLsizei bufSize, GLvoid* pixels);
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
void DispatchComputeIndirect(GLintptr indirect);
void MemoryBarrier(GLbitfield barriers);
static VkMemoryBarrier BuildMemoryBarrierForGlBarriers(GLbitfield barriers);
void DrawArrays(const DrawCmd& payload);
void DrawElements(const DrawIndexedCmd& payload);
void MultiDrawElements(const MultiDrawIndexedCmd& payloads);
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void Present();
const PhysicalDevice& GetPhysicalDevice() const;
VkInstance GetInstance() const;
Bool IsDrawIndirectCountExtensionEnabled() const;
void RecreateSwapchain();
private:
struct BlitUniformData {
float srcRect[4] = {0.f, 0.f, 1.f, 1.f};
float dstRect[4] = {0.f, 0.f, 1.f, 1.f};
Int surfaceTransform = 0;
Int padding[3] = {0, 0, 0};
};
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;
};
struct DepthMipmapResources {
SharedPtr<MG_State::GLState::ProgramObject> program;
Int srcRectLocation = -1;
Int dstRectLocation = -1;
Int surfaceTransformLocation = -1;
Int srcTexelSizeLocation = -1;
Uint32 samplerBinding = 0;
};
struct DeferredDepthMipmapCleanup {
Vector<VkImageView> imageViews;
Vector<VkFramebuffer> framebuffers;
Vector<VkRenderPass> renderPasses;
Vector<VkPipeline> pipelines;
};
void QueueClearBufferPayload(GLenum buffer, GLint drawbuffer, const ClearAttachmentPayload& clearPayload);
void QueueClearBufferPayloadForFramebuffer(const MG_State::GLState::FramebufferObject& framebuffer,
GLenum buffer, GLint drawbuffer,
const ClearAttachmentPayload& clearPayload);
NativeWindowType m_window = 0;
void* m_platformDisplay = nullptr;
void* m_platformLibrary = nullptr;
void* m_platformCloseDisplay = nullptr;
VulkanRendererConfig m_config;
// Vulkan objects
Bool m_validationLayersEnabled = false;
Vector<VkExtensionProperties> m_extensions;
VkInstance m_instance = VK_NULL_HANDLE;
VkDebugUtilsMessengerEXT m_debugMessenger = VK_NULL_HANDLE;
PhysicalDevice m_physicalDevice;
VkDevice m_device = VK_NULL_HANDLE;
VmaAllocator m_allocator = nullptr;
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
SwapchainObject m_swapchainObject;
VkQueue m_graphicsQueue = VK_NULL_HANDLE;
VkQueue m_presentQueue = VK_NULL_HANDLE;
Bool m_drawIndirectCountExtensionEnabled = false;
Bool m_indexTypeUint8ExtensionEnabled = false;
using PFNDrawIndexedIndirectCountFunc = void(VKAPI_PTR*)(VkCommandBuffer commandBuffer, VkBuffer buffer,
VkDeviceSize offset, VkBuffer countBuffer,
VkDeviceSize countBufferOffset, Uint32 maxDrawCount,
Uint32 stride);
static inline PFNDrawIndexedIndirectCountFunc s_vkCmdDrawIndexedIndirectCount = nullptr;
VkCommandPool m_commandPool = VK_NULL_HANDLE;
struct TransientBufferSliceCacheEntry {
BufferSlice slice;
Uint64 changeSerial = 0;
SizeT size = 0;
};
VkBufferManager m_bufferManager;
UnorderedMap<const MG_State::GLState::BufferObject*, TransientBufferSliceCacheEntry>
m_transientVertexIndexBufferSlicesThisFrame;
Uint m_imageIndexAcquired = 0;
FrameContext m_frameContext;
UniquePtr<PipelineFactory> m_pipelineFactory;
UnorderedMap<ProgramFactory::HashType, VkPipeline> m_computePipelines;
UniquePtr<ProgramFactory> m_programFactory;
UniquePtr<UniformManager> m_uniformManager;
UniquePtr<VertexInputStateFactory> m_vertexInputStateFactory;
UniquePtr<VkClearManager> m_clearManager;
UniquePtr<VkRenderPassManager> m_renderPassManager;
UniquePtr<VkTextureManager> m_textureManager;
UniquePtr<VkSamplerManager> m_samplerManager;
BlitResources m_blitResources;
DepthMipmapResources m_depthMipmapResources;
Vector<DeferredDepthMipmapCleanup> m_deferredDepthMipmapCleanup;
void CreateInstance();
VkResult SetupDebugMessenger();
VkResult DestroyDebugMessenger();
VkDebugUtilsMessengerCreateInfoEXT PopulateDebugMessengerCreateInfo();
void CreateSurface();
void PickPhysicalDevice();
void CreateLogicalDeviceAndQueues();
void CreateAllocator();
void DestroyAllocator();
void CreateSwapchain();
void CreateCommandPool();
VkPipeline GetOrCreatePipeline(
GLenum mode,
const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj,
ProgramFactory::CompileOptionFlags transformFlags,
const MG_State::GLState::VertexArrayObject& vao,
const RenderPassEntry& renderPassEntry);
VkPipeline GetOrCreateComputePipeline(const ProgramFactory::VkProgramObject& programObj);
void DestroyComputePipelines();
Bool UploadAndBindVertexBuffers(VkCommandBuffer commandBuffer, const MG_State::GLState::VertexArrayObject& vao,
const DrawCmdParam& drawParams);
Bool UploadAndBindIndexBuffer(FrameContext::FrameData& frame,
const MG_State::GLState::VertexArrayObject& vao,
const IndexBufferView* pIndexBufferView = nullptr);
Bool InitializeBlitResources();
Bool InitializeDepthMipmapResources();
void ShutdownBlitResources();
void ShutdownDepthMipmapResources();
void CollectDeferredDepthMipmapCleanup(Uint32 frameIndex);
void DestroyDeferredDepthMipmapCleanup();
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);
Bool GenerateDepthMipmapWithShader(FrameContext::FrameData& frame,
MG_State::GLState::ITextureObject& texture,
VkTextureManager::TextureResource& resource,
Uint32 baseMipLevel,
Uint32 generateMipLevelCount,
const IntVec3& storageBaseTexelSize,
VkImageLayout originalLayout,
VkImageLayout finalLayout);
Bool SubmitReadbackCommandsAndWait(FrameContext::FrameData& frame);
void ShutdownSwapchain();
// Static functions
static Int GetPresentQueueFamilyIndex(const PhysicalDevice& physicalDevice, VkSurfaceKHR surface,
const Vector<VkQueueFamilyProperties>& queueFamilies,
Int preferredFamilyIndex = -1);
static Vector<VkQueueFamilyProperties> GetQueueFamilyFromPhysicalDevice(VkPhysicalDevice device);
static Int GetQueueFamilyIndex(const Vector<VkQueueFamilyProperties>& queueFamilies, VkQueueFlagBits flag);
static Vector<VkExtensionProperties> EnumerateInstanceExtensions();
static Vector<VkExtensionProperties> EnumerateDeviceExtensions(VkPhysicalDevice device);
static Bool IsExtensionSupported(const Vector<VkExtensionProperties>& availableExtensions,
const char* extensionName);
static Bool IsExtensionAlreadyEnabled(const Vector<const char*>& enabledExtensions, const char* extensionName);
static Bool EnableOptionalDeviceExtension(const Vector<VkExtensionProperties>& availableExtensions,
Vector<const char*>& inOutEnabledExtensions,
const char* extensionName);
void ResolveOptionalDeviceExtensions(const Vector<VkExtensionProperties>& availableExtensions,
Vector<const char*>& inOutEnabledExtensions);
static Bool IsNecessaryDeviceExtensionSupported(VkPhysicalDevice device);
static Bool GetMoreCapablePhysicalDevice(VkPhysicalDevice newVkDevice, VkSurfaceKHR surface,
const PhysicalDevice& compareWithDevice,
PhysicalDevice& outBetterDevice);
static constexpr const char* s_validationLayerNames[] = {"VK_LAYER_KHRONOS_validation"};
static constexpr const char* s_deviceExtensionNames[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
static Bool CheckValidationLayerSupport();
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData);
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -1,25 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/VkIncludes.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 "VulkanRendererConfig.h"
#define VK_VERIFY(expr, ...) \
do { \
VkResult _vk_verify_result = (expr); \
MOBILEGL_ASSERT(_vk_verify_result == VK_SUCCESS, "Vulkan error %d at %s:%d" __VA_OPT__(" - ") __VA_ARGS__, _vk_verify_result, __FILE__, __LINE__); \
} while (0)
#define ENUM_STR_CASE(c) case c: return #c;
#define XXHASH_VERIFY(expr, ...) \
do { \
XXH_errorcode _xxh_verify_result = (expr); \
MOBILEGL_ASSERT(_xxh_verify_result == XXH_OK, "XXHash error %d at %s:%d" __VA_OPT__(" - ") __VA_ARGS__, _xxh_verify_result, __FILE__, __LINE__); \
} while (0)
@@ -1,24 +0,0 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRendererConfig.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 "Config.h"
namespace MobileGL::MG_Backend::DirectVulkan {
struct VulkanRendererConfig {
Uint32 MaxFramesInFlight = 2;
String AppName = "MobileGL-VulkanRenderer";
MobileGL::Version Version = MG_Config::CoreVersion;
Uint64 CacheVersion = MG_Config::CacheVersion;
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
Bool EnableValidationLayers = true;
#else
Bool EnableValidationLayers = false;
#endif
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -0,0 +1,119 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/BackendObject_DirectVulkanTMP.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 "BackendObject_DirectVulkanTMP.h"
#include "MG_Backend/BackendObject.h"
#include "DirectVulkanTMP.h"
#include "TmpImpl.h"
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
namespace MobileGL::MG_Backend::DirectVulkanTMP {
BackendObject_DirectVulkanTMP::~BackendObject_DirectVulkanTMP() = default;
void BackendObject_DirectVulkanTMP::InitWindowSurface() {
auto nativeWindow = reinterpret_cast<NativeWindowType>(m_windowHandle.Handle);
if (!DirectVulkanTMP::InitWindowSurface(nativeWindow)) {
MGLOG_E("Failed to initialize window surface for DirectVulkanTMP backend");
}
}
void BackendObject_DirectVulkanTMP::Initialize() {
m_initialized = true;
}
void BackendObject_DirectVulkanTMP::InitCapabilities() {
if (!m_initialized) {
MGLOG_E("Cannot initialize capabilities before backend is initialized");
return;
}
MG_Util::BackendLoader::QueryVulkanCapabilities(m_vulkanCaps,
DirectVulkanTMP::GetVulkanState().ctx->GetPhysicalDevice());
UpdateDynamicBackendParameters();
}
const RendererInfo& BackendObject_DirectVulkanTMP::GetRendererInfo() const {
static RendererInfo RendererInfo = {
.RendererName = "Magma-TMP", // Renderer Name
.BackendName = "Direct (Vulkan) TMP", // Backend Name
.ExtraVendor = Nullopt, // Extra vendor
.RendererGLInfo =
{
.TargetGLVersion = {3, 3, 0}, // Target OpenGL Version
.TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
V_OpenGL33},
.IsCompatibilityProfile = false // Is Compatibility Profile
},
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
};
return RendererInfo;
}
String BackendObject_DirectVulkanTMP::GetBackendAPIVersionString() const {
if (!m_initialized) {
return "<uninitialized DirectVulkanTMP backend>";
}
// Format:
// <GPU Name>, Vulkan <Vulkan Version>, Driver <Driver Version>
// TODO
String str = m_vulkanCaps.DeviceName + ", Vulkan " + m_vulkanCaps.VulkanAPIVersion.toString() + ", Driver " +
m_vulkanCaps.DriverVersionString;
return str;
}
BackendType BackendObject_DirectVulkanTMP::GetBackendType() const {
return BackendType::DirectVulkanTMP;
}
const GlobalBackendFunctionsTable& BackendObject_DirectVulkanTMP::GetBackendFunctions() const {
static GlobalBackendFunctionsTable funcsTable;
static Bool funcsTableInitialized = false;
if (!funcsTableInitialized) {
funcsTable.Present = DirectVulkanTMP::Present;
funcsTable.GL.DrawArrays = DrawArrays;
funcsTable.GL.DrawElements = DrawElements;
funcsTable.GL.DrawElementsBaseVertex = DrawElementsBaseVertex;
funcsTable.GL.MultiDrawElements = MultiDrawElements;
funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex;
funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect;
funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect;
funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex;
funcsTable.GL.DrawRangeElements = DrawRangeElements;
funcsTable.GL.DrawElementsInstancedBaseVertexBaseInstance = DrawElementsInstancedBaseVertexBaseInstance;
funcsTable.GL.DrawElementsInstancedBaseVertex = DrawElementsInstancedBaseVertex;
funcsTable.GL.DrawElementsInstancedBaseInstance = DrawElementsInstancedBaseInstance;
funcsTable.GL.DrawElementsInstanced = DrawElementsInstanced;
funcsTable.GL.DrawArraysInstancedBaseInstance = DrawArraysInstancedBaseInstance;
funcsTable.GL.DrawArraysInstanced = DrawArraysInstanced;
funcsTable.GL.DrawElementsIndirect = DrawElementsIndirect;
funcsTable.GL.DrawArraysIndirect = DrawArraysIndirect;
funcsTable.GL.Clear = Clear;
funcsTable.GL.ClearBufferfi = ClearBufferfi;
funcsTable.GL.ClearBufferfv = ClearBufferfv;
funcsTable.GL.ClearBufferuiv = ClearBufferuiv;
funcsTable.GL.ClearBufferiv = ClearBufferiv;
funcsTable.GL.BlitFramebuffer = BlitFramebuffer;
funcsTable.GL.CopyTexImage2D = CopyTexImage2D;
funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D;
funcsTable.GL.GenerateMipmap = GenerateMipmap;
funcsTable.GL.ReadPixels = ReadPixels;
funcsTable.GL.GetTexImage = GetTexImage;
funcsTableInitialized = true;
}
return funcsTable;
}
const DynamicBackendParameters& BackendObject_DirectVulkanTMP::GetDynamicParameters() const {
return m_dynamicParameters;
}
void BackendObject_DirectVulkanTMP::UpdateDynamicBackendParameters() {
m_dynamicParameters.UniformBufferOffsetAlignment = m_vulkanCaps.UniformBufferOffsetAlignment;
}
} // namespace MobileGL::MG_Backend::DirectVulkanTMP
@@ -1,4 +1,4 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h // MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/BackendObject_DirectVulkanTMP.h
// Copyright (c) 2025-2026 MobileGL-Dev // Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0: // Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt // https://www.gnu.org/licenses/gpl-3.0.txt
@@ -11,35 +11,26 @@
#include "../BackendObject.h" #include "../BackendObject.h"
#include <MG_Util/BackendLoaders/Vulkan/Loader.h> #include <MG_Util/BackendLoaders/Vulkan/Loader.h>
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkanTMP {
class BackendObject_DirectVulkan : public BackendObject { class BackendObject_DirectVulkanTMP : public BackendObject {
public: public:
BackendObject_DirectVulkan(); ~BackendObject_DirectVulkanTMP() override;
~BackendObject_DirectVulkan() override;
void Initialize() override; void Initialize() override;
Bool InitWindowSurface() override; void InitWindowSurface() override;
Bool InitCapabilities() override; void InitCapabilities() override;
Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) override;
Bool CreateEGLWindowSurface(const WindowHandle& handle) override;
Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) override;
Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) override;
void ReleaseEGLResources() override;
const RendererInfo& GetRendererInfo() const override; const RendererInfo& GetRendererInfo() const override;
String GetBackendAPIVersionString() const override; String GetBackendAPIVersionString() const override;
const GlobalBackendFunctionsTable& GetBackendFunctions() const override; const GlobalBackendFunctionsTable& GetBackendFunctions() const override;
const DynamicBackendParameters& GetDynamicParameters() const override; const DynamicBackendParameters& GetDynamicParameters() const override;
BackendType GetBackendType() const override; BackendType GetBackendType() const override;
void ApplyVulkanCapabilitiesForTesting(const MG_External::VulkanCapabilities& capabilities);
private: private:
void UpdateAdvertisedExtensions();
void UpdateDynamicBackendParameters(); void UpdateDynamicBackendParameters();
Bool m_initialized = false; Bool m_initialized = false;
DynamicBackendParameters m_dynamicParameters; DynamicBackendParameters m_dynamicParameters;
MG_External::VulkanCapabilities m_vulkanCaps; MG_External::VulkanCapabilities m_vulkanCaps;
RendererInfo m_rendererInfo;
}; };
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkanTMP
@@ -0,0 +1,74 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/DirectVulkanTMP.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 "DirectVulkanTMP.h"
#include "TmpImpl.h"
namespace MobileGL::MG_Backend::DirectVulkanTMP {
void Clear(GLbitfield mask) {
MobileGL::MG_Backend::DirectVulkanTMP::TmpImpl::Clear(mask);
}
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
MobileGL::MG_Backend::DirectVulkanTMP::TmpImpl::DrawElements(mode, count, type, indices);
}
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {}
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {}
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {}
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {}
void DrawArrays(GLenum mode, GLint first, GLsizei count) {}
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) {}
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount) {}
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount, const GLint* basevertex) {}
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 DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex) {}
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices) {}
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLint basevertex, GLuint baseinstance) {}
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLint basevertex) {}
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLuint baseinstance) {}
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) {}
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect) {}
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
GLuint baseinstance) {}
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) {}
void DrawArraysIndirect(GLenum mode, const void* indirect) {}
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
GLint dstY1, GLbitfield mask, GLenum filter) {}
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
GLsizei height, GLint border) {}
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
GLsizei height) {}
void GenerateMipmap(GLenum target) {}
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {}
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {}
Bool InitWindowSurface(NativeWindowType window) {
if (!window) {
MGLOG_E("Cannot initialize Vulkan window surface: invalid window handle");
return false;
}
TmpImpl::InitVulkan(window);
return true;
}
void Present() {
TmpImpl::Present();
}
const TmpImpl::VulkanState& GetVulkanState() {
return TmpImpl::GetVulkanState();
}
} // namespace MobileGL::MG_Backend::DirectVulkanTMP
@@ -1,4 +1,4 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/DirectVulkan.h // MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/DirectVulkanTMP.h
// Copyright (c) 2025-2026 MobileGL-Dev // Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0: // Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt // https://www.gnu.org/licenses/gpl-3.0.txt
@@ -8,19 +8,16 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
#include "Renderer/VulkanRenderer.h"
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkanTMP {
extern UniquePtr<VulkanRenderer> pVulkanRenderer; namespace TmpImpl {
class VulkanState;
} // namespace TmpImpl
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value); void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value); void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value); void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, const GLfloat* value);
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, GLfloat depth, GLint stencil);
void Clear(GLbitfield mask); void Clear(GLbitfield mask);
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices); void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
void DrawArrays(GLenum mode, GLint first, GLsizei count); void DrawArrays(GLenum mode, GLint first, GLsizei count);
@@ -31,10 +28,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
GLsizei drawcount, const GLint* basevertex); GLsizei drawcount, const GLint* basevertex);
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride); void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride);
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride); void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex); const void* indices, GLint basevertex);
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices); void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
@@ -52,37 +45,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void DrawArraysIndirect(GLenum mode, const void* indirect); void DrawArraysIndirect(GLenum mode, const void* indirect);
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
GLint dstY1, GLbitfield mask, GLenum filter); GLint dstY1, GLbitfield mask, GLenum filter);
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
GLsizei height, GLint border); GLsizei height, GLint border);
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
GLsizei height); GLsizei height);
void GenerateMipmap(GLenum target); void GenerateMipmap(GLenum target);
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
void DispatchComputeIndirect(GLintptr indirect);
void MemoryBarrier(GLbitfield barriers);
void MemoryBarrierByRegion(GLbitfield barriers);
void BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access,
GLenum format);
void GetIntegeri_v(GLenum target, GLuint index, GLint* data);
void GetInteger64i_v(GLenum target, GLuint index, GLint64* data);
void GetProgramiv(GLuint program, GLenum pname, GLint* params);
void GetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint* params);
GLuint GetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar* name);
void GetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize,
GLsizei* length, GLchar* name);
void GetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount,
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params);
GLint GetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar* name);
GLint GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, const GLchar* name);
void ShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels); void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
void GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget uploadTarget, Bool InitWindowSurface(NativeWindowType window);
GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid* pixels);
void Present(); void Present();
} // namespace MobileGL::MG_Backend::DirectVulkan const TmpImpl::VulkanState& GetVulkanState();
} // namespace MobileGL::MG_Backend::DirectVulkanTMP
@@ -0,0 +1,447 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Managers/ProgramManager.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 "ProgramManager.h"
#include "MG_Util/Debug/Log.h"
#include "spirv-tools/libspirv.h"
#include "spirv-tools/optimizer.hpp"
#include "source/opt/constants.h"
#include "source/opt/instruction.h"
#include "source/opt/ir_builder.h"
#include "source/opt/ir_context.h"
#include "source/opt/module.h"
#include "source/opt/pass.h"
#include "source/opt/type_manager.h"
#include <bit>
namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager {
namespace {
using ProgramObject = MG_State::GLState::ProgramObject;
using ShaderObject = MG_State::GLState::ShaderObject;
struct PositionTargetInfo {
uint32_t variableId = 0;
uint32_t vectorTypeId = 0;
uint32_t floatTypeId = 0;
uint32_t vectorPtrTypeId = 0;
uint32_t memberIndex = 0;
bool isMember = false;
};
bool IsVec4Float32(spvtools::opt::IRContext* context, uint32_t typeId, uint32_t* outFloatTypeId) {
auto* vecInst = context->get_def_use_mgr()->GetDef(typeId);
if (!vecInst || vecInst->opcode() != spv::Op::OpTypeVector) return false;
if (vecInst->GetSingleWordInOperand(1) != 4) return false;
const uint32_t floatTypeId = vecInst->GetSingleWordInOperand(0);
auto* floatInst = context->get_def_use_mgr()->GetDef(floatTypeId);
if (!floatInst || floatInst->opcode() != spv::Op::OpTypeFloat) return false;
if (floatInst->GetSingleWordInOperand(0) != 32) return false;
if (outFloatTypeId) *outFloatTypeId = floatTypeId;
return true;
}
bool ResolveDirectPositionTarget(spvtools::opt::IRContext* context, uint32_t variableId,
PositionTargetInfo* outTarget) {
auto* varInst = context->get_def_use_mgr()->GetDef(variableId);
if (!varInst || varInst->opcode() != spv::Op::OpVariable) return false;
if (varInst->GetSingleWordInOperand(0) != static_cast<uint32_t>(spv::StorageClass::Output)) return false;
auto* ptrTypeInst = context->get_def_use_mgr()->GetDef(varInst->type_id());
if (!ptrTypeInst || ptrTypeInst->opcode() != spv::Op::OpTypePointer) return false;
if (ptrTypeInst->GetSingleWordInOperand(0) != static_cast<uint32_t>(spv::StorageClass::Output))
return false;
PositionTargetInfo target{};
target.variableId = variableId;
target.vectorTypeId = ptrTypeInst->GetSingleWordInOperand(1);
if (!IsVec4Float32(context, target.vectorTypeId, &target.floatTypeId)) return false;
target.vectorPtrTypeId = varInst->type_id();
target.isMember = false;
*outTarget = target;
return true;
}
uint32_t FindOutputVectorPointerTypeId(spvtools::opt::IRContext* context, uint32_t vectorTypeId) {
auto* vectorType = context->get_type_mgr()->GetType(vectorTypeId);
if (!vectorType) return 0;
spvtools::opt::analysis::Pointer ptrType(vectorType, spv::StorageClass::Output);
return context->get_type_mgr()->GetTypeInstruction(&ptrType);
}
bool ResolveMemberPositionTarget(spvtools::opt::IRContext* context, uint32_t structTypeId, uint32_t memberIndex,
PositionTargetInfo* outTarget) {
auto* structInst = context->get_def_use_mgr()->GetDef(structTypeId);
if (!structInst || structInst->opcode() != spv::Op::OpTypeStruct) return false;
if (memberIndex >= structInst->NumInOperands()) return false;
const uint32_t vectorTypeId = structInst->GetSingleWordInOperand(memberIndex);
uint32_t floatTypeId = 0;
if (!IsVec4Float32(context, vectorTypeId, &floatTypeId)) return false;
const uint32_t vectorPtrTypeId = FindOutputVectorPointerTypeId(context, vectorTypeId);
if (vectorPtrTypeId == 0) return false;
for (auto& inst : context->module()->types_values()) {
if (inst.opcode() != spv::Op::OpVariable) continue;
if (inst.GetSingleWordInOperand(0) != static_cast<uint32_t>(spv::StorageClass::Output)) continue;
auto* ptrTypeInst = context->get_def_use_mgr()->GetDef(inst.type_id());
if (!ptrTypeInst || ptrTypeInst->opcode() != spv::Op::OpTypePointer) continue;
if (ptrTypeInst->GetSingleWordInOperand(0) != static_cast<uint32_t>(spv::StorageClass::Output))
continue;
if (ptrTypeInst->GetSingleWordInOperand(1) != structTypeId) continue;
PositionTargetInfo target{};
target.variableId = inst.result_id();
target.vectorTypeId = vectorTypeId;
target.floatTypeId = floatTypeId;
target.vectorPtrTypeId = vectorPtrTypeId;
target.memberIndex = memberIndex;
target.isMember = true;
*outTarget = target;
return true;
}
return false;
}
bool FindPositionTarget(spvtools::opt::IRContext* context, PositionTargetInfo* outTarget) {
Vector<Pair<uint32_t, uint32_t>> memberCandidates;
constexpr uint32_t kDecorationBuiltIn = static_cast<uint32_t>(spv::Decoration::BuiltIn);
constexpr uint32_t kBuiltInPosition = static_cast<uint32_t>(spv::BuiltIn::Position);
for (auto& inst : context->module()->annotations()) {
if (inst.opcode() == spv::Op::OpDecorate) {
if (inst.NumInOperands() < 3) continue;
if (inst.GetSingleWordInOperand(1) != kDecorationBuiltIn) continue;
if (inst.GetSingleWordInOperand(2) != kBuiltInPosition) continue;
if (ResolveDirectPositionTarget(context, inst.GetSingleWordInOperand(0), outTarget)) return true;
} else if (inst.opcode() == spv::Op::OpMemberDecorate) {
if (inst.NumInOperands() < 4) continue;
if (inst.GetSingleWordInOperand(2) != kDecorationBuiltIn) continue;
if (inst.GetSingleWordInOperand(3) != kBuiltInPosition) continue;
memberCandidates.emplace_back(inst.GetSingleWordInOperand(0), inst.GetSingleWordInOperand(1));
}
}
for (const auto& [structTypeId, memberIndex] : memberCandidates) {
if (ResolveMemberPositionTarget(context, structTypeId, memberIndex, outTarget)) return true;
}
return false;
}
bool InsertPositionFixup(spvtools::opt::IRContext* context, spvtools::opt::Instruction* insertBefore,
const PositionTargetInfo& target, uint32_t halfConstId, bool doYFlip, bool doZRemap) {
using namespace spvtools::opt;
InstructionBuilder builder(context, insertBefore,
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
uint32_t positionPtrId = target.variableId;
if (target.isMember) {
const uint32_t memberIndexId = builder.GetUintConstantId(target.memberIndex);
if (memberIndexId == 0) return false;
auto* access = builder.AddAccessChain(target.vectorPtrTypeId, target.variableId, {memberIndexId});
if (!access) return false;
positionPtrId = access->result_id();
}
auto* position = builder.AddLoad(target.vectorTypeId, positionPtrId);
if (!position) return false;
auto* x = builder.AddCompositeExtract(target.floatTypeId, position->result_id(), {0});
auto* y = builder.AddCompositeExtract(target.floatTypeId, position->result_id(), {1});
auto* z = builder.AddCompositeExtract(target.floatTypeId, position->result_id(), {2});
auto* w = builder.AddCompositeExtract(target.floatTypeId, position->result_id(), {3});
if (!x || !y || !z || !w) return false;
if (!doYFlip && !doZRemap) return false;
uint32_t yValueId = y->result_id();
if (doYFlip) {
auto* negY = builder.AddUnaryOp(target.floatTypeId, spv::Op::OpFNegate, y->result_id());
if (!negY) return false;
yValueId = negY->result_id();
}
uint32_t zValueId = z->result_id();
if (doZRemap) {
auto* zPlusW = builder.AddBinaryOp(target.floatTypeId, spv::Op::OpFAdd, z->result_id(), w->result_id());
if (!zPlusW) return false;
auto* mappedZ =
builder.AddBinaryOp(target.floatTypeId, spv::Op::OpFMul, zPlusW->result_id(), halfConstId);
if (!mappedZ) return false;
zValueId = mappedZ->result_id();
}
auto* fixedPosition = builder.AddCompositeConstruct(target.vectorTypeId,
{x->result_id(), yValueId, zValueId, w->result_id()});
if (!fixedPosition) return false;
return builder.AddStore(positionPtrId, fixedPosition->result_id()) != nullptr;
}
class GlToVulkanPositionFixPass final : public spvtools::opt::Pass {
public:
const char* name() const override { return "gl-to-vulkan-position-fix"; }
explicit GlToVulkanPositionFixPass(ShaderTransformFlags transformFlags)
: m_transformFlags(transformFlags) {}
Status Process() override {
if (!m_transformFlags) return Status::SuccessWithoutChange;
PositionTargetInfo target{};
if (!FindPositionTarget(context(), &target)) return Status::SuccessWithoutChange;
auto* floatType = context()->get_type_mgr()->GetType(target.floatTypeId);
if (!floatType) return Status::SuccessWithoutChange;
const uint32_t halfBits = std::bit_cast<uint32_t>(0.5f);
const auto* halfConst = context()->get_constant_mgr()->GetConstant(floatType, {halfBits});
auto* halfInst = context()->get_constant_mgr()->GetDefiningInstruction(halfConst);
if (!halfInst) return Status::SuccessWithoutChange;
const uint32_t halfConstId = halfInst->result_id();
const bool doYFlip = (m_transformFlags & ShaderTransformBit::PositionYFlip);
const bool doZRemap = (m_transformFlags & ShaderTransformBit::PositionZRemap);
bool modified = false;
for (auto& entryPoint : get_module()->entry_points()) {
if (entryPoint.opcode() != spv::Op::OpEntryPoint) continue;
if (entryPoint.NumInOperands() < 2) continue;
const auto model = static_cast<spv::ExecutionModel>(entryPoint.GetSingleWordInOperand(0));
if (model != spv::ExecutionModel::Vertex && model != spv::ExecutionModel::TessellationEvaluation &&
model != spv::ExecutionModel::Geometry) {
continue;
}
auto* function = context()->GetFunction(entryPoint.GetSingleWordInOperand(1));
if (!function) continue;
for (auto& bb : *function) {
for (auto instIter = bb.begin(); instIter != bb.end(); ++instIter) {
auto* inst = &*instIter;
const bool needsFixup =
(model == spv::ExecutionModel::Geometry && inst->opcode() == spv::Op::OpEmitVertex) ||
(model != spv::ExecutionModel::Geometry && inst->opcode() == spv::Op::OpReturn);
if (!needsFixup) continue;
modified |= InsertPositionFixup(context(), inst, target, halfConstId, doYFlip, doZRemap);
}
}
}
if (!modified) return Status::SuccessWithoutChange;
context()->InvalidateAnalysesExceptFor(spvtools::opt::IRContext::kAnalysisDefUse |
spvtools::opt::IRContext::kAnalysisInstrToBlockMapping);
return Status::SuccessWithChange;
}
private:
ShaderTransformFlags m_transformFlags;
};
spvtools::Optimizer::PassToken CreateGlToVulkanPositionFixPass(ShaderTransformFlags transformFlags) {
return spvtools::Optimizer::PassToken(MakeUnique<GlToVulkanPositionFixPass>(transformFlags));
}
bool TransformSpirvForVulkanPositionFix(const Vector<Uint32>& input, Vector<Uint32>& output,
ShaderTransformFlags transformFlags) {
if (input.empty()) {
output.clear();
return true;
}
if (!transformFlags) {
output = input;
return true;
}
spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_3);
spvtools::OptimizerOptions options;
options.set_run_validator(false);
optimizer.RegisterPass(CreateGlToVulkanPositionFixPass(transformFlags));
const bool success = optimizer.Run(input.data(), input.size(), &output, options);
if (!success) {
MGLOG_E("Vulkan: failed to run GL->Vulkan position fix pass");
output = input;
}
return success;
}
ShaderStage PickClipFixupStage(const Vector<SharedPtr<ShaderObject>>& shaders) {
bool hasGeometry = false;
bool hasTessEval = false;
bool hasVertex = false;
for (const auto& shader : shaders) {
if (!shader) continue;
const auto stage = shader->GetShaderStage();
hasGeometry |= (stage == ShaderStage::Geometry);
hasTessEval |= (stage == ShaderStage::TessEval);
hasVertex |= (stage == ShaderStage::Vertex);
}
if (hasGeometry) return ShaderStage::Geometry;
if (hasTessEval) return ShaderStage::TessEval;
if (hasVertex) return ShaderStage::Vertex;
return ShaderStage::Unknown;
}
} // namespace
ProgramManager::~ProgramManager() {
for (auto& [_, stages] : m_cache) {
DestroyStages(stages);
}
m_cache.clear();
}
ProgramManager::HashType ProgramManager::ComputeSourceSpvHash(MG_State::GLState::ProgramObject* program) const {
if (!program) return 0;
XXH64_state_t* state = XXH64_createState();
XXH64_reset(state, 0xC0FFEEu);
auto& spirvs = program->GetGeneratedSpirv();
for (const auto& spv : spirvs) {
if (spv.empty()) continue;
XXH64_update(state, spv.data(), spv.size() * sizeof(Uint));
}
HashType hash = XXH64_digest(state);
XXH64_freeState(state);
return hash;
}
ProgramManager::HashType ProgramManager::ComputeSpvHash(const Vector<Vector<Uint32>>& spirvs) const {
XXH64_state_t* state = XXH64_createState();
XXH64_reset(state, 0xC0FFEEu);
for (const auto& spv : spirvs) {
if (spv.empty()) continue;
XXH64_update(state, spv.data(), spv.size() * sizeof(Uint32));
}
HashType hash = XXH64_digest(state);
XXH64_freeState(state);
return hash;
}
void ProgramManager::BuildPipelineSpirvModules(MG_State::GLState::ProgramObject* program,
Vector<Vector<Uint32>>& outSpirvs,
ShaderTransformFlags transformFlags) const {
outSpirvs.clear();
if (!program) return;
auto& spirvs = program->GetGeneratedSpirv();
auto& shaders = program->GetAttachedShaders();
const ShaderStage fixupStage = PickClipFixupStage(shaders);
outSpirvs.reserve(spirvs.size());
for (SizeT i = 0; i < spirvs.size(); ++i) {
Vector<Uint32> module = spirvs[i];
ShaderStage stage = ShaderStage::Unknown;
if (i < shaders.size() && shaders[i]) stage = shaders[i]->GetShaderStage();
if (!module.empty() && fixupStage != ShaderStage::Unknown && stage == fixupStage) {
Vector<Uint32> transformed;
TransformSpirvForVulkanPositionFix(module, transformed, transformFlags);
module = Move(transformed);
}
outSpirvs.push_back(Move(module));
}
}
ProgramManager::HashType ProgramManager::ComputeSpvHash(MG_State::GLState::ProgramObject* program,
ShaderTransformFlags transformFlags) const {
Vector<Vector<Uint32>> spirvs;
BuildPipelineSpirvModules(program, spirvs, transformFlags);
return ComputeSpvHash(spirvs);
}
ProgramManager::HashType ProgramManager::ComputeProgramHash(MG_State::GLState::ProgramObject* program,
ShaderTransformFlags transformFlags) const {
if (!program) return 0;
const HashType sourceHash = ComputeSourceSpvHash(program);
auto it = m_cache.find(program);
if (it != m_cache.end() && it->second.sourceHash == sourceHash) return it->second.hash;
return ComputeSpvHash(program, transformFlags);
}
VkShaderStageFlagBits ProgramManager::ToVkStage(ShaderStage stage) const {
switch (stage) {
case ShaderStage::Vertex:
return VK_SHADER_STAGE_VERTEX_BIT;
case ShaderStage::Fragment:
return VK_SHADER_STAGE_FRAGMENT_BIT;
case ShaderStage::Geometry:
return VK_SHADER_STAGE_GEOMETRY_BIT;
case ShaderStage::TessControl:
return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
case ShaderStage::TessEval:
return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
case ShaderStage::Compute:
return VK_SHADER_STAGE_COMPUTE_BIT;
default:
return VK_SHADER_STAGE_ALL_GRAPHICS;
}
}
void ProgramManager::DestroyStages(ProgramStages& stages) {
for (auto module : stages.modules) {
if (module != VK_NULL_HANDLE) {
vkDestroyShaderModule(m_ctx.GetDevice(), module, nullptr);
}
}
stages.modules.clear();
stages.stages.clear();
stages.sourceHash = 0;
stages.hash = 0;
}
Vector<VkPipelineShaderStageCreateInfo>& ProgramManager::CreatePipelineShaderStages(
MG_State::GLState::ProgramObject* program, ShaderTransformFlags transformFlags) {
auto& entry = m_cache[program];
HashType sourceHash = ComputeSourceSpvHash(program);
if (!entry.stages.empty() && entry.sourceHash == sourceHash) return entry.stages;
DestroyStages(entry);
entry.sourceHash = sourceHash;
if (!program) return entry.stages;
Vector<Vector<Uint32>> spirvs;
BuildPipelineSpirvModules(program, spirvs, transformFlags);
entry.hash = ComputeSpvHash(spirvs);
auto& shaders = program->GetAttachedShaders();
for (SizeT i = 0; i < spirvs.size(); ++i) {
auto& spv = spirvs[i];
if (spv.empty()) continue;
VkShaderModuleCreateInfo smci{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
smci.codeSize = spv.size() * sizeof(Uint);
smci.pCode = spv.data();
VkShaderModule module = VK_NULL_HANDLE;
VK_VERIFY(vkCreateShaderModule(m_ctx.GetDevice(), &smci, nullptr, &module), "vkCreateShaderModule");
VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
ShaderStage shaderStage = ShaderStage::Unknown;
if (i < shaders.size() && shaders[i]) shaderStage = shaders[i]->GetShaderStage();
stage.stage = ToVkStage(shaderStage);
stage.module = module;
stage.pName = "main";
entry.modules.push_back(module);
entry.stages.push_back(stage);
}
return entry.stages;
}
} // namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager
@@ -0,0 +1,58 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Managers/ProgramManager.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 <Includes.h>
#include "../Renderer/VulkanContext.h"
#include "../Renderer/VkCommon.h"
#include "MG_State/GLState/ProgramState/ProgramObject.h"
namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager {
enum class ShaderTransformBit : Uint {
None = 0,
PositionYFlip = 1 << 0,
PositionZRemap = 1 << 1,
};
using ShaderTransformFlags = Flags<ShaderTransformBit>;
class ProgramManager {
public:
using HashType = Uint64;
explicit ProgramManager(VulkanContext& ctx) : m_ctx(ctx) {}
~ProgramManager();
ProgramManager(const ProgramManager&) = delete;
ProgramManager& operator=(const ProgramManager&) = delete;
Vector<VkPipelineShaderStageCreateInfo>& CreatePipelineShaderStages(
MG_State::GLState::ProgramObject* program,
ShaderTransformFlags transformFlags = ShaderTransformBit::PositionZRemap);
HashType ComputeProgramHash(MG_State::GLState::ProgramObject* program,
ShaderTransformFlags transformFlags = ShaderTransformBit::PositionZRemap) const;
private:
struct ProgramStages {
HashType sourceHash = 0;
HashType hash = 0;
Vector<VkPipelineShaderStageCreateInfo> stages;
Vector<VkShaderModule> modules;
};
void DestroyStages(ProgramStages& stages);
HashType ComputeSourceSpvHash(MG_State::GLState::ProgramObject* program) const;
HashType ComputeSpvHash(MG_State::GLState::ProgramObject* program, ShaderTransformFlags transformFlags) const;
HashType ComputeSpvHash(const Vector<Vector<Uint32>>& spirvs) const;
void BuildPipelineSpirvModules(MG_State::GLState::ProgramObject* program, Vector<Vector<Uint32>>& outSpirvs,
ShaderTransformFlags transformFlags) const;
VkShaderStageFlagBits ToVkStage(ShaderStage stage) const;
VulkanContext& m_ctx;
UnorderedMap<const MG_State::GLState::ProgramObject*, ProgramStages> m_cache;
};
} // namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager
@@ -0,0 +1,49 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Renderer/FrameContext.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 "FrameContext.h"
namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager {
void FrameContext::Initialize(VulkanContext& ctx, VkCommandPool pool) {
CommandPool = pool;
VkCommandBufferAllocateInfo abci{VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO};
abci.commandPool = pool;
abci.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
abci.commandBufferCount = 1;
VK_VERIFY(vkAllocateCommandBuffers(ctx.GetDevice(), &abci, &CommandBuffer), "vkAllocateCommandBuffers");
VkSemaphoreCreateInfo sci{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
VK_VERIFY(vkCreateSemaphore(ctx.GetDevice(), &sci, nullptr, &ImageAvailable), "vkCreateSemaphore");
VK_VERIFY(vkCreateSemaphore(ctx.GetDevice(), &sci, nullptr, &RenderFinished), "vkCreateSemaphore");
VkFenceCreateInfo fci{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
fci.flags = VK_FENCE_CREATE_SIGNALED_BIT;
VK_VERIFY(vkCreateFence(ctx.GetDevice(), &fci, nullptr, &InFlightFence), "vkCreateFence");
}
void FrameContext::Cleanup(VulkanContext& ctx) {
auto device = ctx.GetDevice();
if (InFlightFence != VK_NULL_HANDLE) {
vkDestroyFence(device, InFlightFence, nullptr);
InFlightFence = VK_NULL_HANDLE;
}
if (ImageAvailable != VK_NULL_HANDLE) {
vkDestroySemaphore(device, ImageAvailable, nullptr);
ImageAvailable = VK_NULL_HANDLE;
}
if (RenderFinished != VK_NULL_HANDLE) {
vkDestroySemaphore(device, RenderFinished, nullptr);
RenderFinished = VK_NULL_HANDLE;
}
if (CommandBuffer != VK_NULL_HANDLE) {
vkFreeCommandBuffers(device, CommandPool, 1, &CommandBuffer);
CommandBuffer = VK_NULL_HANDLE;
}
CommandPool = VK_NULL_HANDLE;
}
} // namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager
@@ -0,0 +1,42 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Renderer/FrameContext.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 <Includes.h>
#include "VulkanContext.h"
#include "VkCommon.h"
namespace MobileGL::MG_Backend::DirectVulkanTMP {
struct TrashBuffer {
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
Bool mapped = false;
};
struct TrashImage {
VkImage image = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
Vector<VkImageView> mipViews;
};
namespace VkManager {
struct FrameContext {
VkCommandBuffer CommandBuffer = VK_NULL_HANDLE;
VkSemaphore ImageAvailable = VK_NULL_HANDLE;
VkSemaphore RenderFinished = VK_NULL_HANDLE;
VkFence InFlightFence = VK_NULL_HANDLE;
Uint32 CurrentImageIndex = 0;
VkCommandPool CommandPool = VK_NULL_HANDLE;
Vector<TrashBuffer> TrashBuffers;
Vector<TrashImage> TrashImages;
// VkCommandPool CommandPool = VK_NULL_HANDLE;
void Initialize(VulkanContext& ctx, VkCommandPool pool);
void Cleanup(VulkanContext& ctx);
};
} // namespace VkManager
} // namespace MobileGL::MG_Backend::DirectVulkanTMP
@@ -1,4 +1,4 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkan/VmaImpl.cpp // MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Renderer/PipelineManager.cpp
// Copyright (c) 2025-2026 MobileGL-Dev // Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0: // Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt // https://www.gnu.org/licenses/gpl-3.0.txt
@@ -6,5 +6,6 @@
// SPDX-License-Identifier: LGPL-3.0-only // SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header // End of Source File Header
#define VMA_IMPLEMENTATION #include <Includes.h>
#include <vk_mem_alloc.h>
namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager {}
@@ -0,0 +1,166 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Renderer/SwapchainManager.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 "SwapchainManager.h"
namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager {
namespace {
VkSurfaceFormatKHR ChooseSurfaceFormat(const Vector<VkSurfaceFormatKHR>& formats) {
for (const auto& f : formats) {
if ((f.format == VK_FORMAT_R8G8B8A8_UNORM || f.format == VK_FORMAT_B8G8R8A8_UNORM) &&
f.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
return f;
}
}
return formats.empty() ? VkSurfaceFormatKHR{VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}
: formats[0];
}
VkPresentModeKHR ChoosePresentMode(const Vector<VkPresentModeKHR>& modes) {
for (const auto& m : modes) {
if (m == VK_PRESENT_MODE_MAILBOX_KHR) return m;
}
return VK_PRESENT_MODE_FIFO_KHR;
}
VkExtent2D ChooseExtent(const VkSurfaceCapabilitiesKHR& caps, ANativeWindow* window) {
if (caps.currentExtent.width != UINT32_MAX) return caps.currentExtent;
// try to get frontend viewport size
VkExtent2D extent{640, 480};
#ifdef VK_USE_PLATFORM_ANDROID_KHR
if (window) {
extent.width = static_cast<Uint32>(ANativeWindow_getWidth(window));
extent.height = static_cast<Uint32>(ANativeWindow_getHeight(window));
}
#else
(void)window;
#endif
extent.width = std::max(caps.minImageExtent.width, std::min(caps.maxImageExtent.width, extent.width));
extent.height = std::max(caps.minImageExtent.height, std::min(caps.maxImageExtent.height, extent.height));
return extent;
}
} // namespace
SwapchainManager::~SwapchainManager() {
DestroySwapchain();
}
void SwapchainManager::Initialize() {
CreateSwapchain(VK_NULL_HANDLE);
}
void SwapchainManager::Recreate() {
DestroySwapchain();
CreateSwapchain(VK_NULL_HANDLE);
}
void SwapchainManager::SetFramebuffers(Vector<VkFramebuffer>&& framebuffers) {
m_framebuffers = Move(framebuffers);
}
void SwapchainManager::DestroySwapchain() {
auto device = m_ctx.GetDevice();
if (device == VK_NULL_HANDLE) return;
for (auto fb : m_framebuffers) {
if (fb != VK_NULL_HANDLE) vkDestroyFramebuffer(device, fb, nullptr);
}
m_framebuffers.clear();
for (auto view : m_imageViews) {
if (view != VK_NULL_HANDLE) vkDestroyImageView(device, view, nullptr);
}
m_imageViews.clear();
m_images.clear();
m_imagesInFlight.clear();
if (m_swapchain != VK_NULL_HANDLE) {
vkDestroySwapchainKHR(device, m_swapchain, nullptr);
m_swapchain = VK_NULL_HANDLE;
}
m_format = VK_FORMAT_UNDEFINED;
m_extent = {0, 0};
}
void SwapchainManager::CreateSwapchain(VkSwapchainKHR oldSwapchain) {
VkSurfaceCapabilitiesKHR caps{};
VK_VERIFY(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_ctx.GetPhysicalDevice(), m_ctx.GetSurface(), &caps),
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
Uint32 fmtCount = 0;
vkGetPhysicalDeviceSurfaceFormatsKHR(m_ctx.GetPhysicalDevice(), m_ctx.GetSurface(), &fmtCount, nullptr);
Vector<VkSurfaceFormatKHR> formats(fmtCount);
if (fmtCount > 0) {
vkGetPhysicalDeviceSurfaceFormatsKHR(m_ctx.GetPhysicalDevice(), m_ctx.GetSurface(), &fmtCount,
formats.data());
}
Uint32 modeCount = 0;
vkGetPhysicalDeviceSurfacePresentModesKHR(m_ctx.GetPhysicalDevice(), m_ctx.GetSurface(), &modeCount, nullptr);
Vector<VkPresentModeKHR> modes(modeCount);
if (modeCount > 0) {
vkGetPhysicalDeviceSurfacePresentModesKHR(m_ctx.GetPhysicalDevice(), m_ctx.GetSurface(), &modeCount,
modes.data());
}
VkSurfaceFormatKHR surfaceFormat = ChooseSurfaceFormat(formats);
VkPresentModeKHR presentMode = ChoosePresentMode(modes);
VkExtent2D extent;
if (m_viewportSize.x() == 0 || m_viewportSize.y() == 0) {
extent = ChooseExtent(caps, m_ctx.GetWindow());
} else {
extent = {m_viewportSize.x(), m_viewportSize.y()};
}
Uint32 imageCount = caps.minImageCount + 1;
if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) imageCount = caps.maxImageCount;
VkSwapchainCreateInfoKHR sci{VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};
sci.surface = m_ctx.GetSurface();
sci.minImageCount = imageCount;
sci.imageFormat = surfaceFormat.format;
sci.imageColorSpace = surfaceFormat.colorSpace;
sci.imageExtent = extent;
sci.imageArrayLayers = 1;
sci.imageUsage =
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
sci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
sci.preTransform = caps.currentTransform;
sci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
sci.presentMode = presentMode;
sci.clipped = VK_TRUE;
sci.oldSwapchain = oldSwapchain;
VK_VERIFY(vkCreateSwapchainKHR(m_ctx.GetDevice(), &sci, nullptr, &m_swapchain), "vkCreateSwapchainKHR");
Uint32 actualCount = 0;
vkGetSwapchainImagesKHR(m_ctx.GetDevice(), m_swapchain, &actualCount, nullptr);
m_images.resize(actualCount);
vkGetSwapchainImagesKHR(m_ctx.GetDevice(), m_swapchain, &actualCount, m_images.data());
m_imageViews.clear();
m_imageViews.reserve(actualCount);
for (auto image : m_images) {
VkImageViewCreateInfo ivci{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
ivci.image = image;
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
ivci.format = surfaceFormat.format;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
ivci.subresourceRange.baseMipLevel = 0;
ivci.subresourceRange.levelCount = 1;
ivci.subresourceRange.baseArrayLayer = 0;
ivci.subresourceRange.layerCount = 1;
VkImageView view = VK_NULL_HANDLE;
VK_VERIFY(vkCreateImageView(m_ctx.GetDevice(), &ivci, nullptr, &view), "vkCreateImageView swapchain");
m_imageViews.push_back(view);
}
m_imagesInFlight.assign(actualCount, VK_NULL_HANDLE);
m_format = surfaceFormat.format;
m_extent = extent;
}
} // namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager
@@ -0,0 +1,52 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Renderer/SwapchainManager.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 <Includes.h>
#include "MG_Util/Math/VectorTypes.h"
#include "VulkanContext.h"
#include "VkCommon.h"
namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager {
class SwapchainManager {
public:
explicit SwapchainManager(VulkanContext& ctx) : m_ctx(ctx) {}
~SwapchainManager();
SwapchainManager(const SwapchainManager&) = delete;
SwapchainManager& operator=(const SwapchainManager&) = delete;
void Initialize();
void Recreate();
void SetViewportSize(const UintVec2& size) { m_viewportSize = size; }
VkSwapchainKHR GetSwapchain() const { return m_swapchain; }
VkFormat GetFormat() const { return m_format; }
VkExtent2D GetExtent() const { return m_extent; }
const Vector<VkImage>& GetImages() const { return m_images; }
const Vector<VkImageView>& GetImageViews() const { return m_imageViews; }
const Vector<VkFramebuffer>& GetFramebuffers() const { return m_framebuffers; }
void SetFramebuffers(Vector<VkFramebuffer>&& framebuffers);
Vector<VkFence>& GetImagesInFlight() { return m_imagesInFlight; }
const UintVec2& GetViewportSize() const { return m_viewportSize; }
private:
void CreateSwapchain(VkSwapchainKHR oldSwapchain);
void DestroySwapchain();
VulkanContext& m_ctx;
VkSwapchainKHR m_swapchain = VK_NULL_HANDLE;
VkFormat m_format = VK_FORMAT_UNDEFINED;
VkExtent2D m_extent{0, 0};
Vector<VkImage> m_images;
Vector<VkImageView> m_imageViews;
Vector<VkFramebuffer> m_framebuffers;
Vector<VkFence> m_imagesInFlight;
UintVec2 m_viewportSize{0, 0};
};
} // namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager
@@ -0,0 +1,22 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Renderer/VkCommon.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 <Includes.h>
namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager {
inline void VkCheck(VkResult result, const char* msg) {
if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) return;
MGLOG_E("Vulkan error %d at %s", static_cast<Int>(result), msg ? msg : "(unknown)");
throw RuntimeError(msg ? msg : "Vulkan error");
}
} // namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager
#ifndef VK_VERIFY
#define VK_VERIFY(res, msg) ::MobileGL::MG_Backend::DirectVulkanTMP::VkManager::VkCheck((res), (msg))
#endif
@@ -0,0 +1,191 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Renderer/VulkanContext.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 "VulkanContext.h"
namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager {
namespace {
Bool CheckDeviceExtensionSupport(VkPhysicalDevice device, const Vector<const char*>& required) {
Uint32 count = 0;
vkEnumerateDeviceExtensionProperties(device, nullptr, &count, nullptr);
Vector<VkExtensionProperties> props(count);
if (count > 0) vkEnumerateDeviceExtensionProperties(device, nullptr, &count, props.data());
for (auto* ext : required) {
Bool found = false;
for (const auto& p : props) {
if (std::strcmp(p.extensionName, ext) == 0) {
found = true;
break;
}
}
if (!found) return false;
}
return true;
}
Bool FindGraphicsQueueFamily(VkPhysicalDevice device, VkSurfaceKHR surface, Uint32& outFamily) {
Uint32 count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &count, nullptr);
if (count == 0) return false;
Vector<VkQueueFamilyProperties> props(count);
vkGetPhysicalDeviceQueueFamilyProperties(device, &count, props.data());
for (Uint32 i = 0; i < count; ++i) {
if (!(props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) continue;
if (surface != VK_NULL_HANDLE) {
VkBool32 presentSupport = VK_FALSE;
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
if (!presentSupport) continue;
}
outFamily = i;
return true;
}
return false;
}
Bool SupportsDynamicRendering(VkPhysicalDevice device) {
VkPhysicalDeviceVulkan13Features vk13{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES};
VkPhysicalDeviceFeatures2 features2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
features2.pNext = &vk13;
vkGetPhysicalDeviceFeatures2(device, &features2);
return vk13.dynamicRendering == VK_TRUE;
}
Bool SupportsTimelineSemaphore(VkPhysicalDevice device) {
VkPhysicalDeviceVulkan12Features vk12{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES};
VkPhysicalDeviceFeatures2 features2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
features2.pNext = &vk12;
vkGetPhysicalDeviceFeatures2(device, &features2);
return vk12.timelineSemaphore == VK_TRUE;
}
} // namespace
VulkanContext::~VulkanContext() {
Cleanup();
}
void VulkanContext::Initialize(ANativeWindow* window, const char* appName) {
if (m_instance != VK_NULL_HANDLE) return;
m_window = window;
CreateInstance(appName ? appName : "MobileGL-Vulkan");
CreateSurface(window);
PickPhysicalDevice();
CreateDevice();
}
void VulkanContext::Cleanup() {
if (m_device != VK_NULL_HANDLE) {
vkDeviceWaitIdle(m_device);
vkDestroyDevice(m_device, nullptr);
m_device = VK_NULL_HANDLE;
}
if (m_surface != VK_NULL_HANDLE) {
vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
m_surface = VK_NULL_HANDLE;
}
if (m_instance != VK_NULL_HANDLE) {
vkDestroyInstance(m_instance, nullptr);
m_instance = VK_NULL_HANDLE;
}
m_physicalDevice = VK_NULL_HANDLE;
m_graphicsQueue = VK_NULL_HANDLE;
m_graphicsQueueFamily = ~0u;
m_window = nullptr;
}
void VulkanContext::CreateInstance(const char* appName) {
VkApplicationInfo app{VK_STRUCTURE_TYPE_APPLICATION_INFO};
app.pApplicationName = appName;
app.applicationVersion = VK_MAKE_VERSION(1, 3, 0);
app.pEngineName = "MobileGL";
app.engineVersion = VK_MAKE_VERSION(1, 3, 0);
app.apiVersion = VK_API_VERSION_1_3;
Vector<const char*> extensions;
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef VK_USE_PLATFORM_ANDROID_KHR
extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
#endif
VkInstanceCreateInfo ici{VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO};
ici.pApplicationInfo = &app;
ici.enabledExtensionCount = static_cast<Uint32>(extensions.size());
ici.ppEnabledExtensionNames = extensions.data();
VK_VERIFY(vkCreateInstance(&ici, nullptr, &m_instance), "vkCreateInstance");
}
void VulkanContext::CreateSurface(ANativeWindow* window) {
if (!window) return;
#ifdef VK_USE_PLATFORM_ANDROID_KHR
VkAndroidSurfaceCreateInfoKHR sci{VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR};
sci.window = window;
VK_VERIFY(vkCreateAndroidSurfaceKHR(m_instance, &sci, nullptr, &m_surface), "vkCreateAndroidSurfaceKHR");
#else
(void)window;
#endif
}
void VulkanContext::PickPhysicalDevice() {
Uint32 count = 0;
VK_VERIFY(vkEnumeratePhysicalDevices(m_instance, &count, nullptr), "vkEnumeratePhysicalDevices");
if (count == 0) throw RuntimeError("No Vulkan physical devices found");
Vector<VkPhysicalDevice> devices(count);
VK_VERIFY(vkEnumeratePhysicalDevices(m_instance, &count, devices.data()), "vkEnumeratePhysicalDevices list");
Vector<const char*> requiredExts = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
for (auto device : devices) {
Uint32 family = ~0u;
if (!FindGraphicsQueueFamily(device, m_surface, family)) continue;
if (!CheckDeviceExtensionSupport(device, requiredExts)) continue;
if (!SupportsDynamicRendering(device)) continue;
m_physicalDevice = device;
m_graphicsQueueFamily = family;
break;
}
if (m_physicalDevice == VK_NULL_HANDLE) {
throw RuntimeError("No suitable Vulkan physical device found");
}
}
void VulkanContext::CreateDevice() {
float priority = 1.0f;
VkDeviceQueueCreateInfo qci{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO};
qci.queueFamilyIndex = m_graphicsQueueFamily;
qci.queueCount = 1;
qci.pQueuePriorities = &priority;
Vector<const char*> deviceExtensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
VkPhysicalDeviceFeatures features{};
VkPhysicalDeviceVulkan13Features vk13{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES};
vk13.dynamicRendering = VK_TRUE;
VkPhysicalDeviceVulkan12Features vk12{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES};
vk12.timelineSemaphore = SupportsTimelineSemaphore(m_physicalDevice) ? VK_TRUE : VK_FALSE;
VkPhysicalDeviceFeatures2 features2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
features2.features = features;
vk13.pNext = &vk12;
features2.pNext = &vk13;
VkDeviceCreateInfo dci{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};
dci.pNext = &features2;
dci.queueCreateInfoCount = 1;
dci.pQueueCreateInfos = &qci;
dci.enabledExtensionCount = static_cast<Uint32>(deviceExtensions.size());
dci.ppEnabledExtensionNames = deviceExtensions.data();
dci.pEnabledFeatures = nullptr;
VK_VERIFY(vkCreateDevice(m_physicalDevice, &dci, nullptr, &m_device), "vkCreateDevice");
vkGetDeviceQueue(m_device, m_graphicsQueueFamily, 0, &m_graphicsQueue);
}
} // namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager
@@ -0,0 +1,47 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Renderer/VulkanContext.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 <Includes.h>
#include "VkCommon.h"
namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager {
class VulkanContext {
public:
VulkanContext() = default;
~VulkanContext();
VulkanContext(const VulkanContext&) = delete;
VulkanContext& operator=(const VulkanContext&) = delete;
void Initialize(ANativeWindow* window, const char* appName);
void Cleanup();
VkInstance GetInstance() const { return m_instance; }
VkPhysicalDevice GetPhysicalDevice() const { return m_physicalDevice; }
VkDevice GetDevice() const { return m_device; }
VkQueue GetGraphicsQueue() const { return m_graphicsQueue; }
Uint32 GetGraphicsQueueFamily() const { return m_graphicsQueueFamily; }
VkSurfaceKHR GetSurface() const { return m_surface; }
ANativeWindow* GetWindow() const { return m_window; }
private:
void CreateInstance(const char* appName);
void CreateSurface(ANativeWindow* window);
void PickPhysicalDevice();
void CreateDevice();
VkInstance m_instance = VK_NULL_HANDLE;
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
VkDevice m_device = VK_NULL_HANDLE;
VkQueue m_graphicsQueue = VK_NULL_HANDLE;
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
Uint32 m_graphicsQueueFamily = ~0u;
ANativeWindow* m_window = nullptr;
};
} // namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,308 @@
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/TmpImpl.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 <Includes.h>
#include "Renderer/VkCommon.h"
#include "Renderer/VulkanContext.h"
#include "Renderer/SwapchainManager.h"
#include "Renderer/FrameContext.h"
#include "Managers/ProgramManager.h"
#include <MG_State/GLState/Core.h>
namespace MobileGL::MG_Backend::DirectVulkanTMP::TmpImpl {
namespace DV = MobileGL::MG_Backend::DirectVulkanTMP::VkManager;
using BufferObject = MobileGL::MG_State::GLState::BufferObject;
using ProgramObject = MobileGL::MG_State::GLState::ProgramObject;
using VertexArrayObject = MobileGL::MG_State::GLState::VertexArrayObject;
using FramebufferObject = MobileGL::MG_State::GLState::FramebufferObject;
using FramebufferAttachmentObject = MobileGL::MG_State::GLState::FramebufferAttachmentObject;
using ITextureObject = MobileGL::MG_State::GLState::ITextureObject;
using RenderbufferObject = MobileGL::MG_State::GLState::RenderbufferObject;
using SamplerObject = MobileGL::MG_State::GLState::SamplerObject;
using TextureObjectMipmap = MobileGL::MG_State::GLState::TextureObjectMipmap;
using TrashImage = MobileGL::MG_Backend::DirectVulkanTMP::TrashImage;
struct BufferResource {
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
VkDeviceSize size = 0;
VkDeviceSize offset = 0;
VkBufferUsageFlags usage = 0;
VkMemoryPropertyFlags props = 0;
void* mapped = nullptr;
Bool fromRing = false;
Uint32 lastUsedFrame = ~0u;
};
struct BufferResourceSet {
Vector<BufferResource> perFrame;
};
struct PendingBufferCopyBatch {
VkBuffer src = VK_NULL_HANDLE;
VkBuffer dst = VK_NULL_HANDLE;
Vector<VkBufferCopy> regions;
};
struct StagingRing {
BufferResource buffer;
VkDeviceSize capacity = 0;
VkDeviceSize head = 0;
};
struct TextureResource {
VkImage image = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
UnorderedMap<Uint32, VkImageView> mipViews;
VkFormat format = VK_FORMAT_UNDEFINED;
VkExtent3D extent{0, 0, 1};
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
Uint32 mipLevels = 1;
Uint16 paramsVersion = 0;
bool valid = false;
};
struct RenderbufferResource {
VkImage image = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
VkFormat format = VK_FORMAT_UNDEFINED;
VkExtent2D extent{0, 0};
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
bool valid = false;
};
struct SamplerResource {
VkSampler sampler = VK_NULL_HANDLE;
Uint16 version = 0;
SamplerParameters params{};
};
struct PendingClearInfo {
GLbitfield mask = 0;
FloatVec4 clearColor = {0.0f, 0.0f, 0.0f, 1.0f};
Float clearDepth = 1.0f;
};
struct UniformBindingInfo {
String name;
Uint32 binding = 0;
Uint32 set = 0;
Uint32 blockIndex = 0xFFFFFFFFu;
VkShaderStageFlags stages = 0;
};
struct SamplerBindingInfo {
String name;
Uint32 binding = 0;
Uint32 set = 0;
VkShaderStageFlags stages = 0;
};
struct ProgramResource {
ProgramObject* program = nullptr;
Uint64 spvHash = 0;
DV::ProgramManager::HashType programHash = 0;
Vector<VkPipelineShaderStageCreateInfo>* shaderStages = nullptr;
VkDescriptorSetLayout setLayout = VK_NULL_HANDLE;
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
struct UboPool {
Vector<BufferResource> buffers;
Uint32 cursor = 0;
};
Vector<UboPool> uboPools;
SizeT uboSize = 0;
Int32 uboBinding = -1;
Uint32 uniformDescriptorCount = 0;
Uint32 samplerDescriptorCount = 0;
Vector<UniformBindingInfo> uniformBindings;
Vector<SamplerBindingInfo> samplerBindings;
UnorderedMap<String, Uint32> samplerBindingByName;
UnorderedMap<Uint64, VkPipeline> pipelines;
};
struct DescriptorPoolConfig {
Uint32 maxSets = 0;
Uint32 uniformCount = 0;
Uint32 samplerCount = 0;
};
struct FrameDescriptorPools {
Vector<VkDescriptorPool> pools;
DescriptorPoolConfig config;
Uint32 activePool = 0;
};
struct VertexAttribKey {
Uint8 enabled = 0;
Uint8 size = 0;
Uint8 type = 0;
Uint8 normalized = 0;
Uint8 isInteger = 0;
Uint8 divisor = 0;
Uint16 pad = 0;
Uint32 stride = 0;
Uint64 offset = 0;
};
struct AttachmentInfo {
FramebufferAttachmentType type = FramebufferAttachmentType::None;
VkImageView view = VK_NULL_HANDLE;
VkFormat format = VK_FORMAT_UNDEFINED;
VkImageAspectFlags aspect = 0;
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
ITextureObject* texture = nullptr;
RenderbufferObject* renderbuffer = nullptr;
};
struct BackendFramebufferObject {
VkExtent2D extent{0, 0};
Uint32 colorAttachmentCount = 0;
Bool hasDepth = false;
VkFormat depthFormat = VK_FORMAT_UNDEFINED;
VkFormat depthAttachmentFormat = VK_FORMAT_UNDEFINED;
VkFormat stencilAttachmentFormat = VK_FORMAT_UNDEFINED;
Uint64 renderingCompatHash = 0;
Vector<AttachmentInfo> attachments;
Vector<VkFormat> colorAttachmentFormats;
Array<Int32, static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)> attachmentIndex =
{};
FramebufferObject::FramebufferAttachmentVersionArray syncedAttachmentVersions = {0};
FramebufferObject::FramebufferAttachmentArray frontendDrawBuffers = {FramebufferAttachmentType::None};
Array<Int32, FramebufferObject::MAX_DRAW_BUFFERS> drawBufferAttachmentIndices = {};
FramebufferAttachmentType frontendReadBuffer = FramebufferAttachmentType::Color0;
Uint64 configHash = 0;
Uint16 objectVersion = 0;
Bool IsValid() const { return !attachments.empty() && extent.width > 0 && extent.height > 0; }
};
struct VulkanState {
UniquePtr<DV::VulkanContext> ctx;
UniquePtr<DV::SwapchainManager> swapchain;
UniquePtr<DV::ProgramManager> programMgr;
VkCommandPool commandPool = VK_NULL_HANDLE;
Vector<UniquePtr<DV::FrameContext>> frames;
Vector<FrameDescriptorPools> frameDescriptorPools;
Vector<BufferResource> stagingPool;
Vector<Vector<BufferResource>> stagingPending;
Uint32 currentFrame = 0;
Uint32 maxFramesInFlight = 2;
Bool initialized = false;
UintVec2 viewportSize{0, 0};
VkImage depthImage = VK_NULL_HANDLE;
VkDeviceMemory depthMemory = VK_NULL_HANDLE;
VkImageView depthView = VK_NULL_HANDLE;
VkFormat depthFormat = VK_FORMAT_UNDEFINED;
Uint64 defaultRenderingCompatHash = 0;
BufferResource nullUbo;
TextureResource defaultTexture;
SamplerResource defaultSampler;
UnorderedMap<const BufferObject*, BufferResourceSet> buffers;
UnorderedMap<const ITextureObject*, TextureResource> textures;
UnorderedMap<const RenderbufferObject*, RenderbufferResource> renderbuffers;
UnorderedMap<const SamplerObject*, SamplerResource> samplers;
UnorderedMap<const ProgramObject*, ProgramResource> programs;
UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>> framebuffers;
Vector<PendingBufferCopyBatch> pendingBufferCopies;
Vector<StagingRing> stagingRings;
VkExtent2D activeExtent{0, 0};
Vector<VkImageView> activeColorViews;
Vector<VkImageLayout> activeColorLayouts;
Vector<VkFormat> activeColorFormats;
Vector<Int32> activeColorAttachmentIndices;
VkImageView activeDepthView = VK_NULL_HANDLE;
VkImageLayout activeDepthLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImageView activeStencilView = VK_NULL_HANDLE;
VkImageLayout activeStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Uint32 activeSwapchainImageIndex = ~0u;
Uint32 activeColorAttachmentCount = 1;
Bool activeHasDepth = false;
VkFormat activeDepthFormat = VK_FORMAT_UNDEFINED;
VkFormat activeDepthAttachmentFormat = VK_FORMAT_UNDEFINED;
VkFormat activeStencilAttachmentFormat = VK_FORMAT_UNDEFINED;
Uint64 activeRenderingCompatHash = 0;
Uint64 activeRenderingConfigHash = 0;
SharedPtr<MG_State::GLState::FramebufferObject> activeStateFBO = nullptr;
SharedPtr<BackendFramebufferObject> activeBackendFBO = nullptr;
Bool activeIsDefault = true;
Bool activeDefaultColorWrites = true;
Uint64 recordingRenderingConfigHash = 0;
Bool cmdBufferBegun = false;
Bool recording = false;
Bool frameSubmitted = false;
FloatVec4 clearColor = {0.0f, 0.0f, 0.0f, 1.0f};
Float clearDepth = 1.0f;
UnorderedMap<SharedPtr<FramebufferObject>, PendingClearInfo> pendingClears;
Vector<VkImageLayout> swapchainImageLayouts;
PFN_vkCmdBeginRendering pfnCmdBeginRendering = nullptr;
PFN_vkCmdEndRendering pfnCmdEndRendering = nullptr;
PFN_vkWaitSemaphores pfnWaitSemaphores = nullptr;
VkSemaphore timelineSemaphore = VK_NULL_HANDLE;
Uint64 timelineValue = 0;
};
void Present();
void FrameBegin();
void InitVulkan(ANativeWindow* window);
const VulkanState& GetVulkanState();
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
void Clear(GLbitfield mask);
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
void DrawArrays(GLenum mode, GLint first, GLsizei count);
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex);
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount);
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount, const GLint* basevertex);
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 DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex);
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLint basevertex, GLuint baseinstance);
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLint basevertex);
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLuint baseinstance);
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount);
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect);
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
GLuint baseinstance);
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
void DrawArraysIndirect(GLenum mode, const void* indirect);
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
GLint dstY1, GLbitfield mask, GLenum filter);
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
GLsizei height, GLint border);
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
GLsizei height);
void GenerateMipmap(GLenum target);
} // namespace MobileGL::MG_Backend::DirectVulkanTMP::TmpImpl
+2 -2
View File
@@ -52,8 +52,8 @@ namespace MobileGL::MG_Backend {
case BackendType::DirectGLES: case BackendType::DirectGLES:
pActiveBackendObject = MakeUnique<DirectGLES::BackendObject_DirectGLES>(); pActiveBackendObject = MakeUnique<DirectGLES::BackendObject_DirectGLES>();
break; break;
case BackendType::DirectVulkan: case BackendType::DirectVulkanTMP:
pActiveBackendObject = MakeUnique<DirectVulkan::BackendObject_DirectVulkan>(); pActiveBackendObject = MakeUnique<DirectVulkanTMP::BackendObject_DirectVulkanTMP>();
break; break;
case BackendType::Unknown: case BackendType::Unknown:
default: default:
+2 -2
View File
@@ -61,7 +61,7 @@ static void BM_CreateBufferObjectsAndBindBuffer(benchmark::State& state) {
BENCHMARK(BM_CreateBufferObjectsAndBindBuffer)->Unit(benchmark::kMillisecond)->UseRealTime(); BENCHMARK(BM_CreateBufferObjectsAndBindBuffer)->Unit(benchmark::kMillisecond)->UseRealTime();
static void BM_DeleteBufferObjects(benchmark::State& state) { static void BM_DeleteBufferObjects(benchmark::State& state) {
Initialize(); MG_Initialize();
std::vector<GLuint> buffers(BUFFER_COUNT); std::vector<GLuint> buffers(BUFFER_COUNT);
for (auto _ : state) { for (auto _ : state) {
@@ -179,7 +179,7 @@ static void BM_UpdateDataPartially(benchmark::State& state) {
BENCHMARK(BM_UpdateDataPartially)->Unit(benchmark::kMillisecond)->UseRealTime(); BENCHMARK(BM_UpdateDataPartially)->Unit(benchmark::kMillisecond)->UseRealTime();
int main(int argc, char** argv) { int main(int argc, char** argv) {
Initialize(); MG_Initialize();
benchmark ::MaybeReenterWithoutASLR(argc, argv); benchmark ::MaybeReenterWithoutASLR(argc, argv);
char arg0_default[] = "benchmark"; char arg0_default[] = "benchmark";
char* args_default = reinterpret_cast<char*>(arg0_default); char* args_default = reinterpret_cast<char*>(arg0_default);
@@ -221,7 +221,7 @@ static void BM_CompileAndLink(benchmark::State& state) {
BENCHMARK(BM_CompileAndLink)->Unit(benchmark::kMillisecond); BENCHMARK(BM_CompileAndLink)->Unit(benchmark::kMillisecond);
int main(int argc, char** argv) { int main(int argc, char** argv) {
Initialize(); MG_Initialize();
benchmark ::MaybeReenterWithoutASLR(argc, argv); benchmark ::MaybeReenterWithoutASLR(argc, argv);
char arg0_default[] = "benchmark"; char arg0_default[] = "benchmark";
char* args_default = reinterpret_cast<char*>(arg0_default); char* args_default = reinterpret_cast<char*>(arg0_default);
+69 -451
View File
@@ -9,488 +9,178 @@
#include "EGLImpl.h" #include "EGLImpl.h"
#include "../GetProcAddress.h" #include "../GetProcAddress.h"
#include <MG_Backend/BackendObjects.h> #include <MG_Backend/BackendObjects.h>
#include <MG_State/EGLState/Core.h>
#include <type_traits>
namespace MobileGL::MG_Impl::EGLImpl { namespace MobileGL::MG_Impl::EGLImpl {
namespace {
using EGLStateContext = MG_State::EGLState::EGLContext;
EGLStateContext* GetState() {
if (!MG_State::pEGLContext) {
MGLOG_E("pEGLContext is null. MG_State may not be initialized.");
}
return MG_State::pEGLContext.get();
}
MG_Backend::BackendObject* GetBackendObject(EGLStateContext* state) {
auto* backendObject = MG_Backend::pActiveBackendObject.get();
if (!backendObject && state) {
state->SetError(EGL_NOT_INITIALIZED);
}
return backendObject;
}
MG_Backend::WindowBackend DetectWindowBackend() {
#if defined(ANDROID) || defined(__ANDROID__)
return MG_Backend::WindowBackend::Android;
#elif defined(__linux__)
return MG_Backend::WindowBackend::X11;
#else
return MG_Backend::WindowBackend::Unknown;
#endif
}
EGLint GetAttribValue(const EGLint* attribList, EGLint attrib, EGLint defaultValue) {
if (!attribList) {
return defaultValue;
}
for (SizeT i = 0; attribList[i] != EGL_NONE; i += 2) {
if (attribList[i] == attrib) {
return attribList[i + 1];
}
}
return defaultValue;
}
template <typename NativeType>
Bool IsNullNativeHandle(NativeType nativeHandle) {
if constexpr (std::is_pointer_v<NativeType>) {
return nativeHandle == nullptr;
} else {
return nativeHandle == 0;
}
}
template <typename NativeType>
void* ToVoidHandle(NativeType nativeHandle) {
if constexpr (std::is_pointer_v<NativeType>) {
return reinterpret_cast<void*>(nativeHandle);
} else {
return reinterpret_cast<void*>(static_cast<SizeT>(nativeHandle));
}
}
} // namespace
EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window,
const EGLint* attrib_list) { const EGLint* attrib_list) {
auto* state = GetState(); MGLOG_D("EGLImpl::CreateWindowSurface called with window=%p", window);
if (!state) { const auto& activeBackendObject = MG_Backend::pActiveBackendObject;
return EGL_NO_SURFACE; if (!activeBackendObject) {
}
if (!state->IsDisplayInitialized(dpy)) {
state->SetError(EGL_NOT_INITIALIZED);
return EGL_NO_SURFACE;
}
if (!state->ValidateConfigOnDisplay(dpy, config)) {
state->SetError(EGL_BAD_CONFIG);
return EGL_NO_SURFACE;
}
if (IsNullNativeHandle(window)) {
state->SetError(EGL_BAD_NATIVE_WINDOW);
return EGL_NO_SURFACE;
}
auto* backendObject = GetBackendObject(state);
if (!backendObject) {
MGLOG_E("activeBackendObject not initialized!"); MGLOG_E("activeBackendObject not initialized!");
return EGL_NO_SURFACE; return EGL_NO_SURFACE;
} }
activeBackendObject->SetWindowHandle({MG_Backend::WindowBackend::Android, reinterpret_cast<void*>(window)});
const MG_Backend::WindowHandle windowHandle = { activeBackendObject->InitWindowSurface();
.Backend = DetectWindowBackend(), return (EGLSurface)1;
.Handle = ToVoidHandle(window),
};
if (!backendObject->CreateEGLWindowSurface(windowHandle)) {
state->SetError(EGL_BAD_NATIVE_WINDOW);
return EGL_NO_SURFACE;
}
return state->CreateWindowSurface(dpy, config, window, attrib_list);
} }
EGLBoolean SwapBuffers(EGLDisplay dpy, EGLSurface draw) { EGLBoolean SwapBuffers(EGLDisplay dpy, EGLSurface draw) {
auto* state = GetState(); MGLOG_D("EGLImpl::SwapBuffers called with dpy=%p", dpy);
if (!state) { if (!MG_Backend::gBackendFunctionsTable.Present) {
return EGL_FALSE; MGLOG_E("MG_Backend::gBackendFunctionsTable.Present not initialized!");
}
if (!state->ValidateSurfaceOnDisplay(dpy, draw)) {
state->SetError(EGL_BAD_SURFACE);
return EGL_FALSE;
}
auto* backendObject = GetBackendObject(state);
if (!backendObject) {
MGLOG_E("activeBackendObject not initialized!");
return EGL_FALSE;
}
if (!backendObject->SwapEGLBuffers(dpy, draw)) {
state->SetError(EGL_BAD_SURFACE);
return EGL_FALSE; return EGL_FALSE;
} }
MG_Backend::gBackendFunctionsTable.Present();
return EGL_TRUE; return EGL_TRUE;
} }
EGLBoolean ChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, EGLint config_size, EGLBoolean ChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, EGLint config_size,
EGLint* num_config) { EGLint* num_config) {
auto* state = GetState(); *num_config = 1;
if (!state) { return EGL_TRUE;
return EGL_FALSE;
}
return state->ChooseConfig(dpy, attrib_list, configs, config_size, num_config) ? EGL_TRUE : EGL_FALSE;
} }
EGLContext CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext shareCtx, const EGLint* attrib_list) { EGLContext CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext shareCtx, const EGLint* attrib_list) {
auto* state = GetState(); return (EGLContext)1;
if (!state) {
return EGL_NO_CONTEXT;
}
return state->CreateContext(dpy, config, shareCtx, attrib_list);
} }
EGLBoolean Initialize(EGLDisplay dpy, EGLint* major, EGLint* minor) { EGLBoolean Initialize(EGLDisplay dpy, EGLint* major, EGLint* minor) {
auto* state = GetState(); if (major) *major = 1;
if (!state) { if (minor) *minor = 5;
return EGL_FALSE;
}
if (!state->InitializeDisplay(dpy, major, minor)) {
return EGL_FALSE;
}
auto* backendObject = GetBackendObject(state);
if (!backendObject) {
MGLOG_E("activeBackendObject not initialized!");
return EGL_FALSE;
}
if (!backendObject->InitializeEGLDisplay(dpy, major, minor)) {
state->SetError(EGL_NOT_INITIALIZED);
return EGL_FALSE;
}
return EGL_TRUE; return EGL_TRUE;
} }
EGLDisplay GetDisplay(NativeDisplayType display) { EGLDisplay GetDisplay(NativeDisplayType display) {
auto* state = GetState(); return (EGLDisplay)1;
if (!state) {
return EGL_NO_DISPLAY;
}
return state->GetDisplay(display);
} }
EGLint GetError() { EGLint GetError() {
auto* state = GetState(); return EGL_SUCCESS;
if (!state) {
return EGL_NOT_INITIALIZED;
}
return state->ConsumeError();
} }
EGLBoolean MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { EGLBoolean MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
auto* state = GetState(); MGLOG_D("EGLImpl::CreateWindowSurface called with window=%p", window);
if (!state) { const auto& activeBackendObject = MG_Backend::pActiveBackendObject;
return EGL_FALSE; if (!activeBackendObject) {
}
const auto oldDisplay = state->GetCurrentDisplay();
const auto oldDraw = state->GetCurrentSurface(EGL_DRAW);
const auto oldRead = state->GetCurrentSurface(EGL_READ);
const auto oldContext = state->GetCurrentContext();
if (!state->MakeCurrent(dpy, draw, read, ctx)) {
return EGL_FALSE;
}
const Bool releaseCurrentRequest =
dpy == EGL_NO_DISPLAY && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT;
if (releaseCurrentRequest) {
if (auto* backendObject = MG_Backend::pActiveBackendObject.get()) {
(void)backendObject->MakeEGLCurrent(dpy, draw, read, ctx);
}
return EGL_TRUE;
}
auto* backendObject = GetBackendObject(state);
if (!backendObject) {
MGLOG_E("activeBackendObject not initialized!"); MGLOG_E("activeBackendObject not initialized!");
state->MakeCurrent(oldDisplay, oldDraw, oldRead, oldContext);
return EGL_FALSE;
}
if (!backendObject->MakeEGLCurrent(dpy, draw, read, ctx)) {
state->SetError(EGL_BAD_ACCESS);
state->MakeCurrent(oldDisplay, oldDraw, oldRead, oldContext);
return EGL_FALSE; return EGL_FALSE;
} }
activeBackendObject->InitCapabilities();
return EGL_TRUE; return EGL_TRUE;
} }
EGLBoolean DestroyContext(EGLDisplay dpy, EGLContext ctx) { EGLBoolean DestroyContext(EGLDisplay dpy, EGLContext ctx) {
auto* state = GetState(); return EGL_TRUE;
if (!state) {
return EGL_FALSE;
}
return state->DestroyContext(dpy, ctx) ? EGL_TRUE : EGL_FALSE;
} }
EGLBoolean DestroySurface(EGLDisplay dpy, EGLSurface surface) { EGLBoolean DestroySurface(EGLDisplay dpy, EGLSurface surface) {
auto* state = GetState(); return EGL_TRUE;
if (!state) {
return EGL_FALSE;
}
return state->DestroySurface(dpy, surface) ? EGL_TRUE : EGL_FALSE;
} }
EGLBoolean Terminate(EGLDisplay dpy) { EGLBoolean Terminate(EGLDisplay dpy) {
auto* state = GetState();
if (!state) {
return EGL_FALSE;
}
if (!state->TerminateDisplay(dpy)) {
return EGL_FALSE;
}
if (auto* backendObject = MG_Backend::pActiveBackendObject.get()) {
backendObject->ReleaseEGLResources();
}
return EGL_TRUE; return EGL_TRUE;
} }
EGLBoolean ReleaseThread() { EGLBoolean ReleaseThread() {
auto* state = GetState();
if (!state) {
return EGL_FALSE;
}
state->ReleaseThread();
return EGL_TRUE; return EGL_TRUE;
} }
EGLContext GetCurrentContext() { EGLContext GetCurrentContext() {
auto* state = GetState(); return (EGLContext)1;
if (!state) {
return EGL_NO_CONTEXT;
}
return state->GetCurrentContext();
} }
EGLBoolean GetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value) { EGLBoolean GetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value) {
auto* state = GetState(); if (attribute == EGL_NATIVE_VISUAL_ID) {
if (!state) { #if defined(ANDROID)
*value = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
return EGL_TRUE;
#elif defined(__linux__)
*value = 0;
return EGL_TRUE;
#elif defined(_WIN32)
*value = 0;
return EGL_TRUE;
#else
*value = 0;
return EGL_FALSE; return EGL_FALSE;
#endif
} }
return state->GetConfigAttrib(dpy, config, attribute, value) ? EGL_TRUE : EGL_FALSE; return EGL_TRUE;
} }
EGLBoolean BindAPI(EGLenum api) { EGLBoolean BindAPI(EGLenum api) {
auto* state = GetState();
if (!state) {
return EGL_FALSE;
}
switch (api) {
case EGL_OPENGL_API:
case EGL_OPENGL_ES_API:
case EGL_OPENVG_API:
state->SetBoundAPI(api);
return EGL_TRUE; return EGL_TRUE;
default:
state->SetError(EGL_BAD_PARAMETER);
return EGL_FALSE;
}
} }
EGLSurface GetCurrentSurface(EGLint readdraw) { EGLSurface GetCurrentSurface(EGLint readdraw) {
auto* state = GetState(); return (EGLSurface)1;
if (!state) {
return EGL_NO_SURFACE;
}
return state->GetCurrentSurface(readdraw);
} }
EGLBoolean QuerySurface(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint* value) { EGLBoolean QuerySurface(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint* value) {
auto* state = GetState(); return EGL_TRUE;
if (!state) {
return EGL_FALSE;
}
return state->QuerySurface(display, surface, attribute, value) ? EGL_TRUE : EGL_FALSE;
} }
char const* QueryString(EGLDisplay display, EGLint name) { char const* QueryString(EGLDisplay display, EGLint name) {
auto* state = GetState();
if (!state) {
return nullptr;
}
if (display != EGL_NO_DISPLAY && !state->ValidateDisplay(display)) {
state->SetError(EGL_BAD_DISPLAY);
return nullptr;
}
switch (name) {
case EGL_VENDOR:
return "MobileGL";
case EGL_VERSION:
return "1.5 MobileGL";
case EGL_CLIENT_APIS:
return "OpenGL OpenGL_ES";
case EGL_EXTENSIONS:
return ""; return "";
default:
state->SetError(EGL_BAD_PARAMETER);
return nullptr;
}
} }
EGLBoolean SwapInterval(EGLDisplay dpy, EGLint interval) { EGLBoolean SwapInterval(EGLDisplay dpy, EGLint interval) {
auto* state = GetState(); return EGL_TRUE;
if (!state) {
return EGL_FALSE;
}
return state->SwapInterval(dpy, interval) ? EGL_TRUE : EGL_FALSE;
} }
EGLSurface CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list) { EGLSurface CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list) {
auto* state = GetState(); return (EGLSurface)1;
if (!state) {
return EGL_NO_SURFACE;
}
const EGLint width = GetAttribValue(attrib_list, EGL_WIDTH, 1);
const EGLint height = GetAttribValue(attrib_list, EGL_HEIGHT, 1);
EGLSurface surface = state->CreatePbufferSurface(dpy, config, attrib_list);
if (surface == EGL_NO_SURFACE) {
return EGL_NO_SURFACE;
}
auto* backendObject = GetBackendObject(state);
if (!backendObject) {
return EGL_NO_SURFACE;
}
if (!backendObject->CreateEGLPbufferSurface(width, height)) {
state->DestroySurface(dpy, surface);
state->SetError(EGL_BAD_ALLOC);
return EGL_NO_SURFACE;
}
return surface;
} }
EGLBoolean BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { EGLBoolean BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
auto* state = GetState();
if (!state) {
return EGL_FALSE;
}
if (!state->ValidateSurfaceOnDisplay(dpy, surface)) {
state->SetError(EGL_BAD_SURFACE);
return EGL_FALSE;
}
if (buffer != EGL_BACK_BUFFER) {
state->SetError(EGL_BAD_PARAMETER);
return EGL_FALSE;
}
return EGL_TRUE; return EGL_TRUE;
} }
EGLBoolean ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { EGLBoolean ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
auto* state = GetState();
if (!state) {
return EGL_FALSE;
}
if (!state->ValidateSurfaceOnDisplay(dpy, surface)) {
state->SetError(EGL_BAD_SURFACE);
return EGL_FALSE;
}
if (buffer != EGL_BACK_BUFFER) {
state->SetError(EGL_BAD_PARAMETER);
return EGL_FALSE;
}
return EGL_TRUE; return EGL_TRUE;
} }
EGLBoolean CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) { EGLBoolean CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) {
auto* state = GetState();
if (!state) {
return EGL_FALSE;
}
if (!state->ValidateSurfaceOnDisplay(dpy, surface)) {
state->SetError(EGL_BAD_SURFACE);
return EGL_FALSE;
}
if (IsNullNativeHandle(target)) {
state->SetError(EGL_BAD_NATIVE_PIXMAP);
return EGL_FALSE;
}
return EGL_TRUE; return EGL_TRUE;
} }
EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config,
const EGLint* attrib_list) { const EGLint* attrib_list) {
auto* state = GetState(); return (EGLSurface)1;
if (!state) {
return EGL_NO_SURFACE;
}
return state->CreatePbufferFromClientBuffer(dpy, buftype, buffer, config, attrib_list);
} }
EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap,
const EGLint* attrib_list) { const EGLint* attrib_list) {
auto* state = GetState(); return (EGLSurface)1;
if (!state) {
return EGL_NO_SURFACE;
}
return state->CreatePixmapSurface(dpy, config, pixmap, attrib_list);
} }
EGLBoolean GetConfigs(EGLDisplay dpy, EGLConfig* configs, EGLint config_size, EGLint* num_config) { EGLBoolean GetConfigs(EGLDisplay dpy, EGLConfig* configs, EGLint config_size, EGLint* num_config) {
auto* state = GetState(); if (num_config) {
if (!state) { *num_config = 1;
return EGL_FALSE;
} }
return state->GetConfigs(dpy, configs, config_size, num_config) ? EGL_TRUE : EGL_FALSE; if (configs && config_size > 0) {
configs[0] = (EGLConfig)1;
}
return EGL_TRUE;
} }
EGLDisplay GetCurrentDisplay() { EGLDisplay GetCurrentDisplay() {
auto* state = GetState(); return (EGLDisplay)1;
if (!state) {
return EGL_NO_DISPLAY;
}
return state->GetCurrentDisplay();
} }
EGLenum QueryAPI() { EGLenum QueryAPI() {
auto* state = GetState();
if (!state) {
return EGL_OPENGL_API; return EGL_OPENGL_API;
} }
return state->GetBoundAPI();
}
EGLBoolean QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint* value) { EGLBoolean QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint* value) {
auto* state = GetState(); if (value) {
if (!state) { *value = 1;
return EGL_FALSE;
} }
return state->QueryContext(dpy, ctx, attribute, value) ? EGL_TRUE : EGL_FALSE; return EGL_TRUE;
} }
EGLBoolean SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) { EGLBoolean SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) {
(void)value;
auto* state = GetState();
if (!state) {
return EGL_FALSE;
}
if (!state->ValidateSurfaceOnDisplay(dpy, surface)) {
state->SetError(EGL_BAD_SURFACE);
return EGL_FALSE;
}
switch (attribute) {
case EGL_MIPMAP_LEVEL:
case EGL_SWAP_BEHAVIOR:
case EGL_TEXTURE_FORMAT:
case EGL_TEXTURE_TARGET:
case EGL_MIPMAP_TEXTURE:
return EGL_TRUE; return EGL_TRUE;
default:
state->SetError(EGL_BAD_ATTRIBUTE);
return EGL_FALSE;
}
} }
EGLBoolean WaitClient() { EGLBoolean WaitClient() {
@@ -502,132 +192,60 @@ namespace MobileGL::MG_Impl::EGLImpl {
} }
EGLBoolean WaitNative(EGLint engine) { EGLBoolean WaitNative(EGLint engine) {
(void)engine;
return EGL_TRUE; return EGL_TRUE;
} }
EGLSync CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib* attrib_list) { EGLSync CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib* attrib_list) {
auto* state = GetState(); return reinterpret_cast<EGLSync>(0x1);
if (!state) {
return EGL_NO_SYNC;
}
return state->CreateSync(dpy, type, attrib_list);
} }
EGLBoolean DestroySync(EGLDisplay dpy, EGLSync sync) { EGLBoolean DestroySync(void* dpy, void* sync) {
auto* state = GetState(); return EGL_TRUE;
if (!state) {
return EGL_FALSE;
}
return state->DestroySync(dpy, sync) ? EGL_TRUE : EGL_FALSE;
} }
EGLint ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout) { EGLint ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout) {
auto* state = GetState(); return EGL_CONDITION_SATISFIED;
if (!state) {
return EGL_FALSE;
}
return state->ClientWaitSync(dpy, sync, flags, timeout);
} }
EGLBoolean GetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib* value) { EGLBoolean GetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib* value) {
auto* state = GetState(); if (value) {
if (!state) { *value = 1;
return EGL_FALSE;
} }
return state->GetSyncAttrib(dpy, sync, attribute, value) ? EGL_TRUE : EGL_FALSE; return EGL_TRUE;
} }
EGLImage CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, EGLImage CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer,
const EGLAttrib* attrib_list) { const EGLAttrib* attrib_list) {
auto* state = GetState(); return reinterpret_cast<EGLImage>(0x1);
if (!state) {
return EGL_NO_IMAGE;
}
return state->CreateImage(dpy, ctx, target, buffer, attrib_list);
} }
EGLBoolean DestroyImage(EGLDisplay dpy, EGLImage image) { EGLBoolean DestroyImage(EGLDisplay dpy, EGLImage image) {
auto* state = GetState(); return EGL_TRUE;
if (!state) {
return EGL_FALSE;
}
return state->DestroyImage(dpy, image) ? EGL_TRUE : EGL_FALSE;
} }
EGLDisplay GetPlatformDisplay(EGLenum platform, void* native_display, const EGLAttrib* attrib_list) { EGLDisplay GetPlatformDisplay(EGLenum platform, void* native_display, const EGLAttrib* attrib_list) {
(void)attrib_list; return reinterpret_cast<EGLDisplay>(0x1);
auto* state = GetState();
if (!state) {
return EGL_NO_DISPLAY;
}
return state->GetPlatformDisplay(platform, native_display);
} }
EGLSurface CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void* native_window, EGLSurface CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void* native_window,
const EGLAttrib* attrib_list) { const EGLAttrib* attrib_list) {
auto* state = GetState(); return reinterpret_cast<EGLSurface>(0x1);
if (!state) {
return EGL_NO_SURFACE;
}
if (native_window == nullptr) {
state->SetError(EGL_BAD_NATIVE_WINDOW);
return EGL_NO_SURFACE;
}
if (!state->IsDisplayInitialized(dpy)) {
state->SetError(EGL_NOT_INITIALIZED);
return EGL_NO_SURFACE;
}
if (!state->ValidateConfigOnDisplay(dpy, config)) {
state->SetError(EGL_BAD_CONFIG);
return EGL_NO_SURFACE;
}
auto* backendObject = GetBackendObject(state);
if (!backendObject) {
MGLOG_E("activeBackendObject not initialized!");
return EGL_NO_SURFACE;
}
const MG_Backend::WindowHandle windowHandle = {
.Backend = DetectWindowBackend(),
.Handle = native_window,
};
if (!backendObject->CreateEGLWindowSurface(windowHandle)) {
state->SetError(EGL_BAD_NATIVE_WINDOW);
return EGL_NO_SURFACE;
}
return state->CreatePlatformWindowSurface(dpy, config, native_window, attrib_list);
} }
EGLSurface CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void* native_pixmap, EGLSurface CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void* native_pixmap,
const EGLAttrib* attrib_list) { const EGLAttrib* attrib_list) {
auto* state = GetState(); return reinterpret_cast<EGLSurface>(0x1);
if (!state) {
return EGL_NO_SURFACE;
}
return state->CreatePlatformPixmapSurface(dpy, config, native_pixmap, attrib_list);
} }
EGLBoolean WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) { EGLBoolean WaitSync(void* dpy, void* sync, int flags) {
auto* state = GetState(); return EGL_TRUE;
if (!state) {
return EGL_FALSE;
}
return state->WaitSync(dpy, sync, flags) ? EGL_TRUE : EGL_FALSE;
} }
__eglMustCastToProperFunctionPointerType GetProcAddress(const char* name) { __eglMustCastToProperFunctionPointerType GetProcAddress(const char* name) {
if (!name) {
return nullptr;
}
MGLOG_D("eglGetProcAddress(%s)", name); MGLOG_D("eglGetProcAddress(%s)", name);
void* proc = MG_Impl::GetProcAddress(name); void* proc = MG_Impl::GetProcAddress(name);
if (!proc) { if (!proc) {
MGLOG_W("Failed to get function: %s", name); MGLOG_W("Failed to get function: %s", (const char*)name);
return nullptr; return nullptr;
} }
return (__eglMustCastToProperFunctionPointerType)proc; return (__eglMustCastToProperFunctionPointerType)proc;
+2 -2
View File
@@ -48,7 +48,7 @@ namespace MobileGL::MG_Impl::EGLImpl {
EGLBoolean WaitGL(); EGLBoolean WaitGL();
EGLBoolean WaitNative(EGLint engine); EGLBoolean WaitNative(EGLint engine);
EGLSync CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib* attrib_list); EGLSync CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib* attrib_list);
EGLBoolean DestroySync(EGLDisplay dpy, EGLSync sync); EGLBoolean DestroySync(void* dpy, void* sync);
EGLint ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout); EGLint ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
EGLBoolean GetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib* value); EGLBoolean GetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib* value);
EGLImage CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, EGLImage CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer,
@@ -59,6 +59,6 @@ namespace MobileGL::MG_Impl::EGLImpl {
const EGLAttrib* attrib_list); const EGLAttrib* attrib_list);
EGLSurface CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void* native_pixmap, EGLSurface CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void* native_pixmap,
const EGLAttrib* attrib_list); const EGLAttrib* attrib_list);
EGLBoolean WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags); EGLBoolean WaitSync(void* dpy, void* sync, int flags);
__eglMustCastToProperFunctionPointerType GetProcAddress(const char* name); __eglMustCastToProperFunctionPointerType GetProcAddress(const char* name);
} // namespace MobileGL::MG_Impl::EGLImpl } // namespace MobileGL::MG_Impl::EGLImpl
File diff suppressed because it is too large Load Diff
+4 -21
View File
@@ -9,34 +9,16 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL {
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);
void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params);
void GetBufferPointerv(GLenum target, GLenum pname, void** params);
GLboolean IsBuffer(GLuint buffer); GLboolean IsBuffer(GLuint buffer);
void DeleteBuffers(GLsizei n, const GLuint* buffers); void DeleteBuffers(GLsizei n, const GLuint* buffers);
void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length); void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
GLboolean UnmapBuffer(GLenum target); GLboolean UnmapBuffer(GLenum target);
void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
void* MapBuffer(GLenum target, GLenum access); void* MapBuffer(GLenum target, GLenum access);
void BufferStorage(GLenum target, GLsizeiptr size, const void* data, GLbitfield flags);
void CreateBuffers(GLsizei n, GLuint* buffers);
void NamedBufferStorage(GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags);
void NamedBufferData(GLuint buffer, GLsizeiptr size, const void* data, GLenum usage);
void NamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data);
void CopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset,
GLsizeiptr size);
void ClearNamedBufferData(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data);
void ClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format,
GLenum type, const void* data);
void* MapNamedBuffer(GLuint buffer, GLenum access);
void* MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
GLboolean UnmapNamedBuffer(GLuint buffer);
void FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length);
void GetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint* params);
void GetNamedBufferParameteri64v(GLuint buffer, GLenum pname, GLint64* params);
void GetNamedBufferPointerv(GLuint buffer, GLenum pname, void** params);
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset,
GLsizeiptr size); GLsizeiptr size);
void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data); void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
@@ -46,4 +28,5 @@ namespace MobileGL::MG_Impl::GLImpl {
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 MobileGL::MG_Impl::GLImpl } // namespace MG_Impl::GLImpl
} // namespace MobileGL
+16 -11
View File
@@ -13,14 +13,16 @@
#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::BufferImpl { namespace MobileGL::MG_Impl::GLImpl {
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, MakeUnique<GenericErrorInfo>( ErrorCode::InvalidEnum,
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;
@@ -28,7 +30,7 @@ namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
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,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
"ValidateBufferTarget", "ValidateBufferTarget",
"No vertex array object is bound.")); "No vertex array object is bound."));
return false; return false;
@@ -44,7 +46,8 @@ namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
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, MakeUnique<GenericErrorInfo>( ErrorCode::InvalidEnum,
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;
@@ -56,8 +59,9 @@ namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
if (index == 0) { if (index == 0) {
if (allowZero) return true; if (allowZero) return true;
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName", MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
"ValidateBufferName",
"Buffer name 0 is not valid.")); "Buffer name 0 is not valid."));
return false; return false;
} }
@@ -65,7 +69,7 @@ namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
if (isValid) return true; if (isValid) return true;
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName", MakeShared<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;
} }
@@ -79,7 +83,7 @@ namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
String glUsageStr = ConvertGLEnumToString(ConvertBufferUsageToGLEnum(usage)); String glUsageStr = ConvertGLEnumToString(ConvertBufferUsageToGLEnum(usage));
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>( MakeShared<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;
@@ -88,7 +92,7 @@ namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
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,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
"ValidateBufferMappingAccess", "ValidateBufferMappingAccess",
"Access bits cannot be null.")); "Access bits cannot be null."));
return false; return false;
@@ -102,11 +106,12 @@ namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
if ((accessBits & validBits) != accessBits) { if ((accessBits & validBits) != accessBits) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferMappingAccess", MakeShared<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 MobileGL::MG_Impl::GLImpl::BufferImpl } // namespace BufferImpl
} // namespace MobileGL::MG_Impl::GLImpl
+4 -2
View File
@@ -10,10 +10,12 @@
#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::BufferImpl { namespace MobileGL::MG_Impl::GLImpl {
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 MobileGL::MG_Impl::GLImpl::BufferImpl } // namespace BufferImpl
} // namespace MobileGL::MG_Impl::GLImpl
@@ -73,24 +73,6 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirect(mode, indirect, drawcount, stride); MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirect(mode, indirect, drawcount, stride);
} }
void MultiDrawElementsIndirectCount_Backend(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_Backend::gBackendFunctionsTable.GL.MultiDrawElementsIndirectCount(mode, type, indirect, drawcount,
maxdrawcount, stride);
}
void MultiDrawArraysIndirectCount_Backend(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirectCount(mode, indirect, drawcount, maxdrawcount,
stride);
}
void DrawRangeElementsBaseVertex_Backend(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void DrawRangeElementsBaseVertex_Backend(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex) { const void* indices, GLint basevertex) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
@@ -174,52 +156,6 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */ /* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ) {
auto dispatchCompute = MG_Backend::gBackendFunctionsTable.GL.DispatchCompute;
if (!dispatchCompute) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Backend does not support compute dispatch."));
return;
}
dispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
}
void DispatchComputeIndirect(GLintptr indirect) {
auto dispatchComputeIndirect = MG_Backend::gBackendFunctionsTable.GL.DispatchComputeIndirect;
if (!dispatchComputeIndirect) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not support indirect compute dispatch."));
return;
}
dispatchComputeIndirect(indirect);
}
void MemoryBarrier(GLbitfield barriers) {
auto memoryBarrier = MG_Backend::gBackendFunctionsTable.GL.MemoryBarrier;
if (!memoryBarrier) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Backend does not support memory barriers."));
return;
}
memoryBarrier(barriers);
}
void MemoryBarrierByRegion(GLbitfield barriers) {
auto memoryBarrierByRegion = MG_Backend::gBackendFunctionsTable.GL.MemoryBarrierByRegion;
if (!memoryBarrierByRegion) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not support regional memory barriers."));
return;
}
memoryBarrierByRegion(barriers);
}
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) { void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {
MultiDrawElementsIndirect_Backend(mode, type, indirect, drawcount, stride); MultiDrawElementsIndirect_Backend(mode, type, indirect, drawcount, stride);
} }
@@ -228,32 +164,6 @@ namespace MobileGL::MG_Impl::GLImpl {
MultiDrawArraysIndirect_Backend(mode, indirect, drawcount, stride); MultiDrawArraysIndirect_Backend(mode, indirect, drawcount, stride);
} }
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
auto multiDrawElementsIndirectCount = MG_Backend::gBackendFunctionsTable.GL.MultiDrawElementsIndirectCount;
if (!multiDrawElementsIndirectCount) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not support indirect-parameter indexed draws."));
return;
}
MultiDrawElementsIndirectCount_Backend(mode, type, indirect, drawcount, maxdrawcount, stride);
}
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
auto multiDrawArraysIndirectCount = MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirectCount;
if (!multiDrawArraysIndirectCount) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not support indirect-parameter array draws."));
return;
}
MultiDrawArraysIndirectCount_Backend(mode, indirect, drawcount, maxdrawcount, stride);
}
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex) { const void* indices, GLint basevertex) {
DrawRangeElementsBaseVertex_Backend(mode, start, end, count, type, indices, basevertex); DrawRangeElementsBaseVertex_Backend(mode, start, end, count, type, indices, basevertex);
+6 -11
View File
@@ -9,18 +9,12 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL {
namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */ /* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ); void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount,
void DispatchComputeIndirect(GLintptr indirect); GLsizei stride);
void MemoryBarrier(GLbitfield barriers);
void MemoryBarrierByRegion(GLbitfield barriers);
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride);
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride); void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex); const void* indices, GLint basevertex);
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices); void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
@@ -44,4 +38,5 @@ namespace MobileGL::MG_Impl::GLImpl {
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 MobileGL::MG_Impl::GLImpl } // namespace MG_Impl::GLImpl
} // namespace MobileGL
+153 -215
View File
@@ -10,7 +10,6 @@
#include "../Buffer/GL_Buffer.h" #include "../Buffer/GL_Buffer.h"
#include "../Getter/GL_Getter.h" #include "../Getter/GL_Getter.h"
#include "../Sampler/GL_Sampler.h" #include "../Sampler/GL_Sampler.h"
#include "../Sync/GL_Sync.h"
#include "../Texture/GL_Texture.h" #include "../Texture/GL_Texture.h"
#include "../Drawing/GL_Drawing.h" #include "../Drawing/GL_Drawing.h"
#include "../Program/GL_Program.h" #include "../Program/GL_Program.h"
@@ -18,7 +17,8 @@
#include "../Framebuffer/GL_Framebuffer.h" #include "../Framebuffer/GL_Framebuffer.h"
#include "../VertexArray/GL_VertexArray.h" #include "../VertexArray/GL_VertexArray.h"
#define DECLARE_GL_FUNCTION_STUB_HEAD(type, name, ...) MOBILEGL_GL_API type gl##name(__VA_ARGS__) { #define DECLARE_GL_FUNCTION_STUB_HEAD(type,name,...) \
MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
#define DECLARE_GL_FUNCTION_STUB_END(type,name,...) \ #define DECLARE_GL_FUNCTION_STUB_END(type,name,...) \
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \ MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
@@ -29,7 +29,8 @@
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \ MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
} }
#define DECLARE_GL_FUNCTION_HEAD(type, name, ...) MOBILEGL_GL_API type gl##name(__VA_ARGS__) { #define DECLARE_GL_FUNCTION_HEAD(type,name,...) \
MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
#define DECLARE_GL_FUNCTION_END(type,name,...) \ #define DECLARE_GL_FUNCTION_END(type,name,...) \
@@ -68,7 +69,7 @@ DECLARE_GL_FUNCTION_HEAD(void, BindRenderbuffer, GLenum target, GLuint renderbuf
DECLARE_GL_FUNCTION_HEAD(void, BindTexture, GLenum target, GLuint texture) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindTexture, target, texture) DECLARE_GL_FUNCTION_HEAD(void, BindTexture, GLenum target, GLuint texture) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindTexture, target, texture)
DECLARE_GL_FUNCTION_HEAD(void, BlendColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendColor, red, green, blue, alpha) DECLARE_GL_FUNCTION_HEAD(void, BlendColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendColor, red, green, blue, alpha)
DECLARE_GL_FUNCTION_HEAD(void, BlendEquation, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquation, mode) DECLARE_GL_FUNCTION_HEAD(void, BlendEquation, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquation, mode)
DECLARE_GL_FUNCTION_HEAD(void, BlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquationSeparate, modeRGB, modeAlpha) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationSeparate, modeRGB, modeAlpha)
DECLARE_GL_FUNCTION_HEAD(void, BlendFunc, GLenum sfactor, GLenum dfactor) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFunc, sfactor, dfactor) DECLARE_GL_FUNCTION_HEAD(void, BlendFunc, GLenum sfactor, GLenum dfactor) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFunc, sfactor, dfactor)
DECLARE_GL_FUNCTION_HEAD(void, BlendFuncSeparate, GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFuncSeparate, sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha) DECLARE_GL_FUNCTION_HEAD(void, BlendFuncSeparate, GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFuncSeparate, sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha)
DECLARE_GL_FUNCTION_HEAD(void, BufferData, GLenum target, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BufferData, target, size, data, usage) DECLARE_GL_FUNCTION_HEAD(void, BufferData, GLenum target, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BufferData, target, size, data, usage)
@@ -103,8 +104,8 @@ DECLARE_GL_FUNCTION_HEAD(void, DrawArrays, GLenum mode, GLint first, GLsizei cou
DECLARE_GL_FUNCTION_HEAD(void, DrawElements, GLenum mode, GLsizei count, GLenum type, const void* indices) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElements, mode, count, type, indices) DECLARE_GL_FUNCTION_HEAD(void, DrawElements, GLenum mode, GLsizei count, GLenum type, const void* indices) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElements, mode, count, type, indices)
DECLARE_GL_FUNCTION_HEAD(void, Enable, GLenum cap) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Enable, cap) DECLARE_GL_FUNCTION_HEAD(void, Enable, GLenum cap) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Enable, cap)
DECLARE_GL_FUNCTION_HEAD(void, EnableVertexAttribArray, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexAttribArray, index) DECLARE_GL_FUNCTION_HEAD(void, EnableVertexAttribArray, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexAttribArray, index)
MOBILEGL_GL_API void glFinish() { MGLOG_D("Implementing function: %s(...)", __FUNCTION__); } DECLARE_GL_FUNCTION_STUB_HEAD(void, Finish) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Finish)
MOBILEGL_GL_API void glFlush() { MGLOG_D("Implementing function: %s(...)", __FUNCTION__); } DECLARE_GL_FUNCTION_STUB_HEAD(void, Flush) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Flush)
DECLARE_GL_FUNCTION_HEAD(void, FramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer) DECLARE_GL_FUNCTION_HEAD(void, FramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer)
DECLARE_GL_FUNCTION_HEAD(void, FramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferTexture2D, target, attachment, textarget, texture, level) DECLARE_GL_FUNCTION_HEAD(void, FramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferTexture2D, target, attachment, textarget, texture, level)
DECLARE_GL_FUNCTION_HEAD(void, FrontFace, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FrontFace, mode) DECLARE_GL_FUNCTION_HEAD(void, FrontFace, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FrontFace, mode)
@@ -215,7 +216,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, EndQuery, GLenum target) DECLARE_GL_FUNCTION
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryiv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryiv, target, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryiv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryiv, target, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryObjectuiv, GLuint id, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryObjectuiv, id, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryObjectuiv, GLuint id, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryObjectuiv, id, pname, params)
DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapBuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLboolean, UnmapBuffer, target) DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapBuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLboolean, UnmapBuffer, target)
DECLARE_GL_FUNCTION_HEAD(void, GetBufferPointerv, GLenum target, GLenum pname, void** params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetBufferPointerv, target, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBufferPointerv, GLenum target, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBufferPointerv, target, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, DrawBuffers, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawBuffers, n, bufs) DECLARE_GL_FUNCTION_HEAD(void, DrawBuffers, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawBuffers, n, bufs)
DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix2x3fv, location, count, transpose, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix2x3fv, location, count, transpose, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix3x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix3x2fv, location, count, transpose, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix3x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix3x2fv, location, count, transpose, value)
@@ -232,7 +233,7 @@ DECLARE_GL_FUNCTION_HEAD(void, BindVertexArray, GLuint array) DECLARE_GL_FUNCTIO
DECLARE_GL_FUNCTION_HEAD(void, DeleteVertexArrays, GLsizei n, const GLuint* arrays) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteVertexArrays, n, arrays) DECLARE_GL_FUNCTION_HEAD(void, DeleteVertexArrays, GLsizei n, const GLuint* arrays) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteVertexArrays, n, arrays)
DECLARE_GL_FUNCTION_HEAD(void, GenVertexArrays, GLsizei n, GLuint* arrays) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GenVertexArrays, n, arrays) DECLARE_GL_FUNCTION_HEAD(void, GenVertexArrays, GLsizei n, GLuint* arrays) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GenVertexArrays, n, arrays)
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsVertexArray, GLuint array) DECLARE_GL_FUNCTION_END(GLboolean, IsVertexArray, array) DECLARE_GL_FUNCTION_HEAD(GLboolean, IsVertexArray, GLuint array) DECLARE_GL_FUNCTION_END(GLboolean, IsVertexArray, array)
DECLARE_GL_FUNCTION_HEAD(void, GetIntegeri_v, GLenum target, GLuint index, GLint* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetIntegeri_v, target, index, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetIntegeri_v, GLenum target, GLuint index, GLint* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetIntegeri_v, target, index, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BeginTransformFeedback, GLenum primitiveMode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BeginTransformFeedback, primitiveMode) DECLARE_GL_FUNCTION_STUB_HEAD(void, BeginTransformFeedback, GLenum primitiveMode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BeginTransformFeedback, primitiveMode)
DECLARE_GL_FUNCTION_STUB_HEAD(void, EndTransformFeedback) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EndTransformFeedback) DECLARE_GL_FUNCTION_STUB_HEAD(void, EndTransformFeedback) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EndTransformFeedback)
DECLARE_GL_FUNCTION_HEAD(void, BindBufferRange, GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindBufferRange, target, index, buffer, offset, size) DECLARE_GL_FUNCTION_HEAD(void, BindBufferRange, GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindBufferRange, target, index, buffer, offset, size)
@@ -248,11 +249,11 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribI4iv, GLuint index, const GLint*
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribI4uiv, GLuint index, const GLuint* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribI4uiv, index, v) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribI4uiv, GLuint index, const GLuint* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribI4uiv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetUniformuiv, GLuint program, GLint location, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetUniformuiv, program, location, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetUniformuiv, GLuint program, GLint location, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetUniformuiv, program, location, params)
DECLARE_GL_FUNCTION_HEAD(GLint, GetFragDataLocation, GLuint program, const GLchar* name) DECLARE_GL_FUNCTION_END(GLint, GetFragDataLocation, program, name) DECLARE_GL_FUNCTION_HEAD(GLint, GetFragDataLocation, GLuint program, const GLchar* name) DECLARE_GL_FUNCTION_END(GLint, GetFragDataLocation, program, name)
DECLARE_GL_FUNCTION_HEAD(void, Uniform1ui, GLint location, GLuint v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform1ui, location, v0) DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform1ui, GLint location, GLuint v0) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform1ui, location, v0)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2ui, GLint location, GLuint v0, GLuint v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2ui, location, v0, v1) DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2ui, GLint location, GLuint v0, GLuint v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2ui, location, v0, v1)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3ui, GLint location, GLuint v0, GLuint v1, GLuint v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3ui, location, v0, v1, v2) DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3ui, GLint location, GLuint v0, GLuint v1, GLuint v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3ui, location, v0, v1, v2)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4ui, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4ui, location, v0, v1, v2, v3) DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4ui, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4ui, location, v0, v1, v2, v3)
DECLARE_GL_FUNCTION_HEAD(void, Uniform1uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform1uiv, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform1uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform1uiv, location, count, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2uiv, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2uiv, location, count, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3uiv, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3uiv, location, count, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4uiv, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4uiv, location, count, value)
@@ -269,15 +270,15 @@ DECLARE_GL_FUNCTION_HEAD(void, GetActiveUniformBlockName, GLuint program, GLuint
DECLARE_GL_FUNCTION_HEAD(void, UniformBlockBinding, GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformBlockBinding, program, uniformBlockIndex, uniformBlockBinding) DECLARE_GL_FUNCTION_HEAD(void, UniformBlockBinding, GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformBlockBinding, program, uniformBlockIndex, uniformBlockBinding)
DECLARE_GL_FUNCTION_HEAD(void, DrawArraysInstanced, GLenum mode, GLint first, GLsizei count, GLsizei instancecount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawArraysInstanced, mode, first, count, instancecount) DECLARE_GL_FUNCTION_HEAD(void, DrawArraysInstanced, GLenum mode, GLint first, GLsizei count, GLsizei instancecount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawArraysInstanced, mode, first, count, instancecount)
DECLARE_GL_FUNCTION_HEAD(void, DrawElementsInstanced, GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsInstanced, mode, count, type, indices, instancecount) DECLARE_GL_FUNCTION_HEAD(void, DrawElementsInstanced, GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsInstanced, mode, count, type, indices, instancecount)
DECLARE_GL_FUNCTION_HEAD(GLsync, FenceSync, GLenum condition, GLbitfield flags) DECLARE_GL_FUNCTION_END(GLsync, FenceSync, condition, flags) DECLARE_GL_FUNCTION_STUB_HEAD(GLsync, FenceSync, GLenum condition, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END(GLsync, FenceSync, condition, flags)
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsSync, GLsync sync) DECLARE_GL_FUNCTION_END(GLboolean, IsSync, sync) DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, IsSync, GLsync sync) DECLARE_GL_FUNCTION_STUB_END(GLboolean, IsSync, sync)
DECLARE_GL_FUNCTION_HEAD(void, DeleteSync, GLsync sync) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteSync, sync) DECLARE_GL_FUNCTION_STUB_HEAD(void, DeleteSync, GLsync sync) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DeleteSync, sync)
DECLARE_GL_FUNCTION_HEAD(GLenum, ClientWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_END(GLenum, ClientWaitSync, sync, flags, timeout) DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, ClientWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_STUB_END(GLenum, ClientWaitSync, sync, flags, timeout)
DECLARE_GL_FUNCTION_HEAD(void, WaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_END_NO_RETURN(void, WaitSync, sync, flags, timeout) DECLARE_GL_FUNCTION_STUB_HEAD(void, WaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, WaitSync, sync, flags, timeout)
DECLARE_GL_FUNCTION_HEAD(void, GetInteger64v, GLenum pname, GLint64* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetInteger64v, pname, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetInteger64v, GLenum pname, GLint64* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetInteger64v, pname, data)
DECLARE_GL_FUNCTION_HEAD(void, GetSynciv, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetSynciv, sync, pname, bufSize, length, values) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetSynciv, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetSynciv, sync, pname, bufSize, length, values)
DECLARE_GL_FUNCTION_HEAD(void, GetInteger64i_v, GLenum target, GLuint index, GLint64* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetInteger64i_v, target, index, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetInteger64i_v, GLenum target, GLuint index, GLint64* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetInteger64i_v, target, index, data)
DECLARE_GL_FUNCTION_HEAD(void, GetBufferParameteri64v, GLenum target, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetBufferParameteri64v, target, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBufferParameteri64v, GLenum target, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBufferParameteri64v, target, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GenSamplers, GLsizei count, GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GenSamplers, count, samplers) DECLARE_GL_FUNCTION_HEAD(void, GenSamplers, GLsizei count, GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GenSamplers, count, samplers)
DECLARE_GL_FUNCTION_HEAD(void, DeleteSamplers, GLsizei count, const GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteSamplers, count, samplers) DECLARE_GL_FUNCTION_HEAD(void, DeleteSamplers, GLsizei count, const GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteSamplers, count, samplers)
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsSampler, GLuint sampler) DECLARE_GL_FUNCTION_END(GLboolean, IsSampler, sampler) DECLARE_GL_FUNCTION_HEAD(GLboolean, IsSampler, GLuint sampler) DECLARE_GL_FUNCTION_END(GLboolean, IsSampler, sampler)
@@ -303,17 +304,17 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateSubFramebuffer, GLenum target, GLs
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage2D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage2D, target, levels, internalformat, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage2D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage2D, target, levels, internalformat, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage3D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage3D, target, levels, internalformat, width, height, depth) DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage3D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage3D, target, levels, internalformat, width, height, depth)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetInternalformativ, GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetInternalformativ, target, internalformat, pname, bufSize, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetInternalformativ, GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetInternalformativ, target, internalformat, pname, bufSize, params)
DECLARE_GL_FUNCTION_HEAD(void, DispatchCompute, GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DispatchCompute, num_groups_x, num_groups_y, num_groups_z) DECLARE_GL_FUNCTION_STUB_HEAD(void, DispatchCompute, GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DispatchCompute, num_groups_x, num_groups_y, num_groups_z)
DECLARE_GL_FUNCTION_HEAD(void, DispatchComputeIndirect, GLintptr indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DispatchComputeIndirect, indirect) DECLARE_GL_FUNCTION_STUB_HEAD(void, DispatchComputeIndirect, GLintptr indirect) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DispatchComputeIndirect, indirect)
DECLARE_GL_FUNCTION_HEAD(void, DrawArraysIndirect, GLenum mode, const void* indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawArraysIndirect, mode, indirect) DECLARE_GL_FUNCTION_HEAD(void, DrawArraysIndirect, GLenum mode, const void* indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawArraysIndirect, mode, indirect)
DECLARE_GL_FUNCTION_HEAD(void, DrawElementsIndirect, GLenum mode, GLenum type, const void* indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsIndirect, mode, type, indirect) DECLARE_GL_FUNCTION_HEAD(void, DrawElementsIndirect, GLenum mode, GLenum type, const void* indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsIndirect, mode, type, indirect)
DECLARE_GL_FUNCTION_STUB_HEAD(void, FramebufferParameteri, GLenum target, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FramebufferParameteri, target, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, FramebufferParameteri, GLenum target, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FramebufferParameteri, target, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetFramebufferParameteriv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetFramebufferParameteriv, target, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetFramebufferParameteriv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetFramebufferParameteriv, target, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GetProgramInterfaceiv, GLuint program, GLenum programInterface, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetProgramInterfaceiv, program, programInterface, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramInterfaceiv, GLuint program, GLenum programInterface, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramInterfaceiv, program, programInterface, pname, params)
DECLARE_GL_FUNCTION_HEAD(GLuint, GetProgramResourceIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_END(GLuint, GetProgramResourceIndex, program, programInterface, name) DECLARE_GL_FUNCTION_STUB_HEAD(GLuint, GetProgramResourceIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END(GLuint, GetProgramResourceIndex, program, programInterface, name)
DECLARE_GL_FUNCTION_HEAD(void, GetProgramResourceName, GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length, GLchar* name) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetProgramResourceName, program, programInterface, index, bufSize, length, name) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramResourceName, GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length, GLchar* name) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramResourceName, program, programInterface, index, bufSize, length, name)
DECLARE_GL_FUNCTION_HEAD(void, GetProgramResourceiv, GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetProgramResourceiv, program, programInterface, index, propCount, props, bufSize, length, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramResourceiv, GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramResourceiv, program, programInterface, index, propCount, props, bufSize, length, params)
DECLARE_GL_FUNCTION_HEAD(GLint, GetProgramResourceLocation, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_END(GLint, GetProgramResourceLocation, program, programInterface, name) DECLARE_GL_FUNCTION_STUB_HEAD(GLint, GetProgramResourceLocation, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END(GLint, GetProgramResourceLocation, program, programInterface, name)
DECLARE_GL_FUNCTION_STUB_HEAD(void, UseProgramStages, GLuint pipeline, GLbitfield stages, GLuint program) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UseProgramStages, pipeline, stages, program) DECLARE_GL_FUNCTION_STUB_HEAD(void, UseProgramStages, GLuint pipeline, GLbitfield stages, GLuint program) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UseProgramStages, pipeline, stages, program)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ActiveShaderProgram, GLuint pipeline, GLuint program) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ActiveShaderProgram, pipeline, program) DECLARE_GL_FUNCTION_STUB_HEAD(void, ActiveShaderProgram, GLuint pipeline, GLuint program) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ActiveShaderProgram, pipeline, program)
DECLARE_GL_FUNCTION_STUB_HEAD(GLuint, CreateShaderProgramv, GLenum type, GLsizei count, const GLchar* const* strings) DECLARE_GL_FUNCTION_STUB_END(GLuint, CreateShaderProgramv, type, count, strings) DECLARE_GL_FUNCTION_STUB_HEAD(GLuint, CreateShaderProgramv, GLenum type, GLsizei count, const GLchar* const* strings) DECLARE_GL_FUNCTION_STUB_END(GLuint, CreateShaderProgramv, type, count, strings)
@@ -322,33 +323,33 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, DeleteProgramPipelines, GLsizei n, const GLu
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenProgramPipelines, GLsizei n, GLuint* pipelines) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenProgramPipelines, n, pipelines) DECLARE_GL_FUNCTION_STUB_HEAD(void, GenProgramPipelines, GLsizei n, GLuint* pipelines) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenProgramPipelines, n, pipelines)
DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, IsProgramPipeline, GLuint pipeline) DECLARE_GL_FUNCTION_STUB_END(GLboolean, IsProgramPipeline, pipeline) DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, IsProgramPipeline, GLuint pipeline) DECLARE_GL_FUNCTION_STUB_END(GLboolean, IsProgramPipeline, pipeline)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramPipelineiv, GLuint pipeline, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramPipelineiv, pipeline, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramPipelineiv, GLuint pipeline, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramPipelineiv, pipeline, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform1i, GLuint program, GLint location, GLint v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1i, program, location, v0) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1i, GLuint program, GLint location, GLint v0) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1i, program, location, v0)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2i, GLuint program, GLint location, GLint v0, GLint v1) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2i, program, location, v0, v1) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform2i, GLuint program, GLint location, GLint v0, GLint v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform2i, program, location, v0, v1)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform3i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform3i, program, location, v0, v1, v2) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform3i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform3i, program, location, v0, v1, v2)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform4i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform4i, program, location, v0, v1, v2, v3) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform4i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform4i, program, location, v0, v1, v2, v3)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform1ui, GLuint program, GLint location, GLuint v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1ui, program, location, v0) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1ui, GLuint program, GLint location, GLuint v0) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1ui, program, location, v0)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2ui, GLuint program, GLint location, GLuint v0, GLuint v1) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2ui, program, location, v0, v1) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform2ui, GLuint program, GLint location, GLuint v0, GLuint v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform2ui, program, location, v0, v1)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform3ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform3ui, program, location, v0, v1, v2) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform3ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform3ui, program, location, v0, v1, v2)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform4ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform4ui, program, location, v0, v1, v2, v3) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform4ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform4ui, program, location, v0, v1, v2, v3)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform1f, GLuint program, GLint location, GLfloat v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1f, program, location, v0) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1f, GLuint program, GLint location, GLfloat v0) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1f, program, location, v0)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2f, GLuint program, GLint location, GLfloat v0, GLfloat v1) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2f, program, location, v0, v1) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform2f, GLuint program, GLint location, GLfloat v0, GLfloat v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform2f, program, location, v0, v1)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform3f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform3f, program, location, v0, v1, v2) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform3f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform3f, program, location, v0, v1, v2)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform4f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform4f, program, location, v0, v1, v2, v3) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform4f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform4f, program, location, v0, v1, v2, v3)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform1iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1iv, program, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1iv, program, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2iv, program, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform2iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform2iv, program, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform3iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform3iv, program, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform3iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform3iv, program, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform4iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform4iv, program, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform4iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform4iv, program, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform1uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1uiv, program, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1uiv, program, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2uiv, program, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform2uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform2uiv, program, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform3uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform3uiv, program, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform3uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform3uiv, program, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform4uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform4uiv, program, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform4uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform4uiv, program, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform1fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1fv, program, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1fv, program, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2fv, program, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform2fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform2fv, program, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform3fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform3fv, program, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform3fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform3fv, program, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform4fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform4fv, program, location, count, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform4fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform4fv, program, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniformMatrix2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniformMatrix2fv, program, location, count, transpose, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix2fv, program, location, count, transpose, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniformMatrix3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniformMatrix3fv, program, location, count, transpose, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix3fv, program, location, count, transpose, value)
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniformMatrix4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniformMatrix4fv, program, location, count, transpose, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix4fv, program, location, count, transpose, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix2x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix2x3fv, program, location, count, transpose, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix2x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix2x3fv, program, location, count, transpose, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix3x2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix3x2fv, program, location, count, transpose, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix3x2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix3x2fv, program, location, count, transpose, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix2x4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix2x4fv, program, location, count, transpose, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix2x4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix2x4fv, program, location, count, transpose, value)
@@ -357,10 +358,10 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix3x4fv, GLuint program, G
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix4x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix4x3fv, program, location, count, transpose, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix4x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix4x3fv, program, location, count, transpose, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ValidateProgramPipeline, GLuint pipeline) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ValidateProgramPipeline, pipeline) DECLARE_GL_FUNCTION_STUB_HEAD(void, ValidateProgramPipeline, GLuint pipeline) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ValidateProgramPipeline, pipeline)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramPipelineInfoLog, GLuint pipeline, GLsizei bufSize, GLsizei* length, GLchar* infoLog) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramPipelineInfoLog, pipeline, bufSize, length, infoLog) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramPipelineInfoLog, GLuint pipeline, GLsizei bufSize, GLsizei* length, GLchar* infoLog) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramPipelineInfoLog, pipeline, bufSize, length, infoLog)
DECLARE_GL_FUNCTION_HEAD(void, BindImageTexture, GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindImageTexture, unit, texture, level, layered, layer, access, format) DECLARE_GL_FUNCTION_STUB_HEAD(void, BindImageTexture, GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindImageTexture, unit, texture, level, layered, layer, access, format)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBooleani_v, GLenum target, GLuint index, GLboolean* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBooleani_v, target, index, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBooleani_v, GLenum target, GLuint index, GLboolean* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBooleani_v, target, index, data)
DECLARE_GL_FUNCTION_HEAD(void, MemoryBarrier, GLbitfield barriers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MemoryBarrier, barriers) DECLARE_GL_FUNCTION_STUB_HEAD(void, MemoryBarrier, GLbitfield barriers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MemoryBarrier, barriers)
DECLARE_GL_FUNCTION_HEAD(void, MemoryBarrierByRegion, GLbitfield barriers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MemoryBarrierByRegion, barriers) DECLARE_GL_FUNCTION_STUB_HEAD(void, MemoryBarrierByRegion, GLbitfield barriers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MemoryBarrierByRegion, barriers)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetMultisamplefv, GLenum pname, GLuint index, GLfloat* val) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetMultisamplefv, pname, index, val) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetMultisamplefv, GLenum pname, GLuint index, GLfloat* val) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetMultisamplefv, pname, index, val)
DECLARE_GL_FUNCTION_HEAD(void, SampleMaski, GLuint maskNumber, GLbitfield mask) DECLARE_GL_FUNCTION_END_NO_RETURN(void, SampleMaski, maskNumber, mask) DECLARE_GL_FUNCTION_HEAD(void, SampleMaski, GLuint maskNumber, GLbitfield mask) DECLARE_GL_FUNCTION_END_NO_RETURN(void, SampleMaski, maskNumber, mask)
@@ -386,14 +387,14 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetObjectPtrLabel, const void* ptr, GLsizei
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetPointerv, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetPointerv, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetPointerv, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetPointerv, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, Enablei, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Enablei, target, index) DECLARE_GL_FUNCTION_HEAD(void, Enablei, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Enablei, target, index)
DECLARE_GL_FUNCTION_HEAD(void, Disablei, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Disablei, target, index) DECLARE_GL_FUNCTION_HEAD(void, Disablei, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Disablei, target, index)
DECLARE_GL_FUNCTION_HEAD(void, BlendEquationi, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquationi, buf, mode) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationi, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationi, buf, mode)
DECLARE_GL_FUNCTION_HEAD(void, BlendEquationiARB, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquationi, buf, mode) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationiARB, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationi, buf, mode)
DECLARE_GL_FUNCTION_HEAD(void, BlendEquationSeparatei, GLuint buf, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquationSeparatei, buf, modeRGB, modeAlpha) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationSeparatei, GLuint buf, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationSeparatei, buf, modeRGB, modeAlpha)
DECLARE_GL_FUNCTION_HEAD(void, BlendEquationSeparateiARB, GLuint buf, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquationSeparatei, buf, modeRGB, modeAlpha) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationSeparateiARB, GLuint buf, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationSeparatei, buf, modeRGB, modeAlpha)
DECLARE_GL_FUNCTION_HEAD(void, BlendFunci, GLuint buf, GLenum src, GLenum dst) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFunci, buf, src, dst) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFunci, GLuint buf, GLenum src, GLenum dst) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFunci, buf, src, dst)
DECLARE_GL_FUNCTION_HEAD(void, BlendFunciARB, GLuint buf, GLenum src, GLenum dst) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFunci, buf, src, dst) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFunciARB, GLuint buf, GLenum src, GLenum dst) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFunci, buf, src, dst)
DECLARE_GL_FUNCTION_HEAD(void, BlendFuncSeparatei, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha) DECLARE_GL_FUNCTION_HEAD(void, BlendFuncSeparatei, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha)
DECLARE_GL_FUNCTION_HEAD(void, BlendFuncSeparateiARB, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFuncSeparateiARB, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ColorMaski, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ColorMaski, index, r, g, b, a) DECLARE_GL_FUNCTION_STUB_HEAD(void, ColorMaski, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ColorMaski, index, r, g, b, a)
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsEnabledi, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END(GLboolean, IsEnabledi, target, index) DECLARE_GL_FUNCTION_HEAD(GLboolean, IsEnabledi, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END(GLboolean, IsEnabledi, target, index)
DECLARE_GL_FUNCTION_HEAD(void, DrawElementsBaseVertex, GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsBaseVertex, mode, count, type, indices, basevertex) DECLARE_GL_FUNCTION_HEAD(void, DrawElementsBaseVertex, GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsBaseVertex, mode, count, type, indices, basevertex)
@@ -846,7 +847,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4usv, GLuint index, const GLusho
DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveRestartIndex, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PrimitiveRestartIndex, index) DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveRestartIndex, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PrimitiveRestartIndex, index)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetActiveUniformName, GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetActiveUniformName, program, uniformIndex, bufSize, length, uniformName) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetActiveUniformName, GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetActiveUniformName, program, uniformIndex, bufSize, length, uniformName)
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsBaseVertex, mode, count, type, indices, drawcount, basevertex) DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsBaseVertex, mode, count, type, indices, drawcount, basevertex)
DECLARE_GL_FUNCTION_HEAD(void, ProvokingVertex, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProvokingVertex, mode) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProvokingVertex, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProvokingVertex, mode)
DECLARE_GL_FUNCTION_HEAD(void, TexImage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations) DECLARE_GL_FUNCTION_HEAD(void, TexImage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations)
DECLARE_GL_FUNCTION_HEAD(void, TexImage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage3DMultisample, target, samples, internalformat, width, height, depth, fixedsamplelocations) DECLARE_GL_FUNCTION_HEAD(void, TexImage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage3DMultisample, target, samples, internalformat, width, height, depth, fixedsamplelocations)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindFragDataLocationIndexed, GLuint program, GLuint colorNumber, GLuint index, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindFragDataLocationIndexed, program, colorNumber, index, name) DECLARE_GL_FUNCTION_STUB_HEAD(void, BindFragDataLocationIndexed, GLuint program, GLuint colorNumber, GLuint index, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindFragDataLocationIndexed, program, colorNumber, index, name)
@@ -976,11 +977,11 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateBufferSubData, GLuint buffer, GLin
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateBufferData, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateBufferData, buffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateBufferData, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateBufferData, buffer)
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawArraysIndirect, GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawArraysIndirect, mode, indirect, drawcount, stride) DECLARE_GL_FUNCTION_HEAD(void, MultiDrawArraysIndirect, GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawArraysIndirect, mode, indirect, drawcount, stride)
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsIndirect, GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsIndirect, mode, type, indirect, drawcount, stride) DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsIndirect, GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsIndirect, mode, type, indirect, drawcount, stride)
DECLARE_GL_FUNCTION_HEAD(GLint, GetProgramResourceLocationIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_END(GLint, GetProgramResourceLocationIndex, program, programInterface, name) DECLARE_GL_FUNCTION_STUB_HEAD(GLint, GetProgramResourceLocationIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END(GLint, GetProgramResourceLocationIndex, program, programInterface, name)
DECLARE_GL_FUNCTION_HEAD(void, ShaderStorageBlockBinding, GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ShaderStorageBlockBinding, program, storageBlockIndex, storageBlockBinding) DECLARE_GL_FUNCTION_STUB_HEAD(void, ShaderStorageBlockBinding, GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ShaderStorageBlockBinding, program, storageBlockIndex, storageBlockBinding)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureView, GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureView, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureView, GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureView, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribLFormat, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribLFormat, attribindex, size, type, relativeoffset) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribLFormat, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribLFormat, attribindex, size, type, relativeoffset)
DECLARE_GL_FUNCTION_HEAD(void, BufferStorage, GLenum target, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BufferStorage, target, size, data, flags) DECLARE_GL_FUNCTION_STUB_HEAD(void, BufferStorage, GLenum target, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BufferStorage, target, size, data, flags)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexImage, GLuint texture, GLint level, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexImage, texture, level, format, type, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexImage, GLuint texture, GLint level, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexImage, texture, level, format, type, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindBuffersBase, GLenum target, GLuint first, GLsizei count, const GLuint* buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindBuffersBase, target, first, count, buffers) DECLARE_GL_FUNCTION_STUB_HEAD(void, BindBuffersBase, GLenum target, GLuint first, GLsizei count, const GLuint* buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindBuffersBase, target, first, count, buffers)
@@ -996,51 +997,51 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, TransformFeedbackBufferRange, GLuint xfb, GL
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbackiv, GLuint xfb, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbackiv, xfb, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbackiv, GLuint xfb, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbackiv, xfb, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki_v, GLuint xfb, GLenum pname, GLuint index, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki_v, xfb, pname, index, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki_v, GLuint xfb, GLenum pname, GLuint index, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki_v, xfb, pname, index, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki64_v, GLuint xfb, GLenum pname, GLuint index, GLint64* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki64_v, xfb, pname, index, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki64_v, GLuint xfb, GLenum pname, GLuint index, GLint64* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki64_v, xfb, pname, index, param)
DECLARE_GL_FUNCTION_HEAD(void, CreateBuffers, GLsizei n, GLuint* buffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateBuffers, n, buffers) DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateBuffers, GLsizei n, GLuint* buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateBuffers, n, buffers)
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferStorage, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferStorage, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags)
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferData, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferData, buffer, size, data, usage) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferData, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferData, buffer, size, data, usage)
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferSubData, buffer, offset, size, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferSubData, buffer, offset, size, data)
DECLARE_GL_FUNCTION_HEAD(void, CopyNamedBufferSubData, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CopyNamedBufferSubData, readBuffer, writeBuffer, readOffset, writeOffset, size) DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyNamedBufferSubData, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyNamedBufferSubData, readBuffer, writeBuffer, readOffset, writeOffset, size)
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedBufferData, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedBufferData, buffer, internalformat, format, type, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferData, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferData, buffer, internalformat, format, type, data)
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedBufferSubData, GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedBufferSubData, buffer, internalformat, offset, size, format, type, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferSubData, GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferSubData, buffer, internalformat, offset, size, format, type, data)
DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapNamedBuffer, GLuint buffer) DECLARE_GL_FUNCTION_END(GLboolean, UnmapNamedBuffer, buffer) DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, UnmapNamedBuffer, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END(GLboolean, UnmapNamedBuffer, buffer)
DECLARE_GL_FUNCTION_HEAD(void, FlushMappedNamedBufferRange, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length) DECLARE_GL_FUNCTION_STUB_HEAD(void, FlushMappedNamedBufferRange, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length)
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameteriv, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferParameteriv, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameteri64v, GLuint buffer, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteri64v, buffer, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferParameteri64v, GLuint buffer, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferParameteri64v, buffer, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferPointerv, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferPointerv, buffer, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferPointerv, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferPointerv, buffer, pname, *params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubData, buffer, offset, size, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubData, buffer, offset, size, data)
DECLARE_GL_FUNCTION_HEAD(void, CreateFramebuffers, GLsizei n, GLuint* framebuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateFramebuffers, n, framebuffers) DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateFramebuffers, GLsizei n, GLuint* framebuffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateFramebuffers, n, framebuffers)
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferRenderbuffer, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferRenderbuffer, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteri, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteri, framebuffer, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteri, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteri, framebuffer, pname, param)
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferTexture, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferTexture, framebuffer, attachment, texture, level) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture, framebuffer, attachment, texture, level)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTextureLayer, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTextureLayer, framebuffer, attachment, texture, level, layer) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTextureLayer, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTextureLayer, framebuffer, attachment, texture, level, layer)
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferDrawBuffer, GLuint framebuffer, GLenum buf) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferDrawBuffer, framebuffer, buf) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferDrawBuffer, GLuint framebuffer, GLenum buf) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferDrawBuffer, framebuffer, buf)
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferDrawBuffers, GLuint framebuffer, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferDrawBuffers, framebuffer, n, bufs) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferDrawBuffers, GLuint framebuffer, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferDrawBuffers, framebuffer, n, bufs)
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferReadBuffer, GLuint framebuffer, GLenum src) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferReadBuffer, framebuffer, src) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferReadBuffer, GLuint framebuffer, GLenum src) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferReadBuffer, framebuffer, src)
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferData, framebuffer, numAttachments, attachments) DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferData, framebuffer, numAttachments, attachments)
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferSubData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferSubData, framebuffer, numAttachments, attachments, x, y, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferSubData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferSubData, framebuffer, numAttachments, attachments, x, y, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferiv, framebuffer, buffer, drawbuffer, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferiv, framebuffer, buffer, drawbuffer, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferuiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferuiv, framebuffer, buffer, drawbuffer, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferuiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferuiv, framebuffer, buffer, drawbuffer, value)
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedFramebufferfv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedFramebufferfv, framebuffer, buffer, drawbuffer, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferfv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferfv, framebuffer, buffer, drawbuffer, value)
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedFramebufferfi, GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedFramebufferfi, framebuffer, buffer, drawbuffer, depth, stencil) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferfi, GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferfi, framebuffer, buffer, drawbuffer, depth, stencil)
DECLARE_GL_FUNCTION_HEAD(void, BlitNamedFramebuffer, GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlitNamedFramebuffer, readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlitNamedFramebuffer, GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlitNamedFramebuffer, readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter)
DECLARE_GL_FUNCTION_HEAD(GLenum, CheckNamedFramebufferStatus, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLenum, CheckNamedFramebufferStatus, framebuffer, target) DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, CheckNamedFramebufferStatus, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_STUB_END(GLenum, CheckNamedFramebufferStatus, framebuffer, target)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferParameteriv, GLuint framebuffer, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferParameteriv, framebuffer, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferParameteriv, GLuint framebuffer, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferParameteriv, framebuffer, pname, param)
DECLARE_GL_FUNCTION_HEAD(void, GetNamedFramebufferAttachmentParameteriv, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameteriv, framebuffer, attachment, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferAttachmentParameteriv, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameteriv, framebuffer, attachment, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, CreateRenderbuffers, GLsizei n, GLuint* renderbuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateRenderbuffers, n, renderbuffers) DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateRenderbuffers, GLsizei n, GLuint* renderbuffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateRenderbuffers, n, renderbuffers)
DECLARE_GL_FUNCTION_HEAD(void, NamedRenderbufferStorage, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedRenderbufferStorage, renderbuffer, internalformat, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorage, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorage, renderbuffer, internalformat, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisample, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisample, renderbuffer, samples, internalformat, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisample, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisample, renderbuffer, samples, internalformat, width, height)
DECLARE_GL_FUNCTION_HEAD(void, GetNamedRenderbufferParameteriv, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedRenderbufferParameteriv, renderbuffer, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedRenderbufferParameteriv, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedRenderbufferParameteriv, renderbuffer, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, CreateTextures, GLenum target, GLsizei n, GLuint* textures) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateTextures, target, n, textures) DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateTextures, GLenum target, GLsizei n, GLuint* textures) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateTextures, target, n, textures)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBuffer, GLuint texture, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBuffer, texture, internalformat, buffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBuffer, GLuint texture, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBuffer, texture, internalformat, buffer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferRange, GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferRange, texture, internalformat, buffer, offset, size) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferRange, GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferRange, texture, internalformat, buffer, offset, size)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage1D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage1D, texture, levels, internalformat, width) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage1D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage1D, texture, levels, internalformat, width)
DECLARE_GL_FUNCTION_HEAD(void, TextureStorage2D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureStorage2D, texture, levels, internalformat, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage2D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage2D, texture, levels, internalformat, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage3D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage3D, texture, levels, internalformat, width, height, depth) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage3D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage3D, texture, levels, internalformat, width, height, depth)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage2DMultisample, GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage2DMultisample, texture, samples, internalformat, width, height, fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage2DMultisample, GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage2DMultisample, texture, samples, internalformat, width, height, fixedsamplelocations)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage3DMultisample, GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage3DMultisample, texture, samples, internalformat, width, height, depth, fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage3DMultisample, GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage3DMultisample, texture, samples, internalformat, width, height, depth, fixedsamplelocations)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage1D, texture, level, xoffset, width, format, type, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage1D, texture, level, xoffset, width, format, type, pixels)
DECLARE_GL_FUNCTION_HEAD(void, TextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureSubImage2D, texture, level, xoffset, yoffset, width, height, format, type, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage2D, texture, level, xoffset, yoffset, width, height, format, type, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage3D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage3D, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage3D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage3D, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTextureSubImage1D, texture, level, xoffset, width, format, imageSize, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTextureSubImage1D, texture, level, xoffset, width, format, imageSize, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTextureSubImage2D, texture, level, xoffset, yoffset, width, height, format, imageSize, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTextureSubImage2D, texture, level, xoffset, yoffset, width, height, format, imageSize, data)
@@ -1048,31 +1049,31 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage3D, GLuint texture,
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage1D, texture, level, xoffset, x, y, width) DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage1D, texture, level, xoffset, x, y, width)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage2D, texture, level, xoffset, yoffset, x, y, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage2D, texture, level, xoffset, yoffset, x, y, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage3D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage3D, texture, level, xoffset, yoffset, zoffset, x, y, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage3D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage3D, texture, level, xoffset, yoffset, zoffset, x, y, width, height)
DECLARE_GL_FUNCTION_HEAD(void, TextureParameterf, GLuint texture, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureParameterf, texture, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterf, GLuint texture, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterf, texture, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterfv, GLuint texture, GLenum pname, const GLfloat* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterfv, texture, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterfv, GLuint texture, GLenum pname, const GLfloat* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterfv, texture, pname, param)
DECLARE_GL_FUNCTION_HEAD(void, TextureParameteri, GLuint texture, GLenum pname, GLint param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureParameteri, texture, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameteri, GLuint texture, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameteri, texture, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterIiv, GLuint texture, GLenum pname, const GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterIiv, texture, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterIiv, GLuint texture, GLenum pname, const GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterIiv, texture, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterIuiv, GLuint texture, GLenum pname, const GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterIuiv, texture, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterIuiv, GLuint texture, GLenum pname, const GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterIuiv, texture, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, TextureParameteriv, GLuint texture, GLenum pname, const GLint* param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureParameteriv, texture, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameteriv, GLuint texture, GLenum pname, const GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameteriv, texture, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateTextureMipmap, GLuint texture) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateTextureMipmap, texture) DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateTextureMipmap, GLuint texture) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateTextureMipmap, texture)
DECLARE_GL_FUNCTION_HEAD(void, BindTextureUnit, GLuint unit, GLuint texture) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindTextureUnit, unit, texture) DECLARE_GL_FUNCTION_STUB_HEAD(void, BindTextureUnit, GLuint unit, GLuint texture) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindTextureUnit, unit, texture)
DECLARE_GL_FUNCTION_HEAD(void, GetTextureImage, GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureImage, texture, level, format, type, bufSize, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureImage, GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureImage, texture, level, format, type, bufSize, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetCompressedTextureImage, GLuint texture, GLint level, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetCompressedTextureImage, texture, level, bufSize, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetCompressedTextureImage, GLuint texture, GLint level, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetCompressedTextureImage, texture, level, bufSize, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureLevelParameterfv, GLuint texture, GLint level, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureLevelParameterfv, texture, level, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureLevelParameterfv, GLuint texture, GLint level, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureLevelParameterfv, texture, level, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GetTextureLevelParameteriv, GLuint texture, GLint level, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureLevelParameteriv, texture, level, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureLevelParameteriv, GLuint texture, GLint level, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureLevelParameteriv, texture, level, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterfv, GLuint texture, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterfv, texture, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterfv, GLuint texture, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterfv, texture, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterIiv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterIiv, texture, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterIiv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterIiv, texture, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterIuiv, GLuint texture, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterIuiv, texture, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterIuiv, GLuint texture, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterIuiv, texture, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GetTextureParameteriv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureParameteriv, texture, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameteriv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameteriv, texture, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, CreateVertexArrays, GLsizei n, GLuint* arrays) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateVertexArrays, n, arrays) DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateVertexArrays, GLsizei n, GLuint* arrays) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateVertexArrays, n, arrays)
DECLARE_GL_FUNCTION_HEAD(void, DisableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DisableVertexArrayAttrib, vaobj, index) DECLARE_GL_FUNCTION_STUB_HEAD(void, DisableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DisableVertexArrayAttrib, vaobj, index)
DECLARE_GL_FUNCTION_HEAD(void, EnableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexArrayAttrib, vaobj, index) DECLARE_GL_FUNCTION_STUB_HEAD(void, EnableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableVertexArrayAttrib, vaobj, index)
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayElementBuffer, GLuint vaobj, GLuint buffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayElementBuffer, vaobj, buffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayElementBuffer, GLuint vaobj, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayElementBuffer, vaobj, buffer)
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayVertexBuffer, GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayVertexBuffer, vaobj, bindingindex, buffer, offset, stride) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexBuffer, GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexBuffer, vaobj, bindingindex, buffer, offset, stride)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexBuffers, GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, const GLsizei* strides) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexBuffers, vaobj, first, count, buffers, offsets, strides) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexBuffers, GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, const GLsizei* strides) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexBuffers, vaobj, first, count, buffers, offsets, strides)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribBinding, GLuint vaobj, GLuint attribindex, GLuint bindingindex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribBinding, vaobj, attribindex, bindingindex) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribBinding, GLuint vaobj, GLuint attribindex, GLuint bindingindex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribBinding, vaobj, attribindex, bindingindex)
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayAttribFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayAttribFormat, vaobj, attribindex, size, type, normalized, relativeoffset) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribFormat, vaobj, attribindex, size, type, normalized, relativeoffset)
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayAttribIFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayAttribIFormat, vaobj, attribindex, size, type, relativeoffset) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribIFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribIFormat, vaobj, attribindex, size, type, relativeoffset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribLFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribLFormat, vaobj, attribindex, size, type, relativeoffset) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribLFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribLFormat, vaobj, attribindex, size, type, relativeoffset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayBindingDivisor, GLuint vaobj, GLuint bindingindex, GLuint divisor) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayBindingDivisor, vaobj, bindingindex, divisor) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayBindingDivisor, GLuint vaobj, GLuint bindingindex, GLuint divisor) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayBindingDivisor, vaobj, bindingindex, divisor)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayiv, GLuint vaobj, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayiv, vaobj, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayiv, GLuint vaobj, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayiv, vaobj, pname, param)
@@ -1085,7 +1086,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjecti64v, GLuint id, GLuint
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectiv, id, buffer, pname, offset) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectiv, id, buffer, pname, offset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectui64v, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectui64v, id, buffer, pname, offset) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectui64v, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectui64v, id, buffer, pname, offset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectuiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectuiv, id, buffer, pname, offset) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectuiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectuiv, id, buffer, pname, offset)
DECLARE_GL_FUNCTION_HEAD(void, GetTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetCompressedTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetCompressedTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, bufSize, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetCompressedTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetCompressedTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, bufSize, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnCompressedTexImage, GLenum target, GLint lod, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnCompressedTexImage, target, lod, bufSize, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnCompressedTexImage, GLenum target, GLint lod, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnCompressedTexImage, target, lod, bufSize, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnTexImage, GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnTexImage, target, level, format, type, bufSize, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnTexImage, GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnTexImage, target, level, format, type, bufSize, pixels)
@@ -1104,8 +1105,8 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnHistogram, GLenum target, GLboolean rese
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnMinmax, GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void* values) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnMinmax, target, reset, format, type, bufSize, values) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnMinmax, GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void* values) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnMinmax, target, reset, format, type, bufSize, values)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBarrier, void) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBarrier, ) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBarrier, void) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBarrier, )
DECLARE_GL_FUNCTION_STUB_HEAD(void, SpecializeShader, GLuint shader, const GLchar* pEntryPoint, GLuint numSpecializationConstants, const GLuint* pConstantIndex, const GLuint* pConstantValue) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SpecializeShader, shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue) DECLARE_GL_FUNCTION_STUB_HEAD(void, SpecializeShader, GLuint shader, const GLchar* pEntryPoint, GLuint numSpecializationConstants, const GLuint* pConstantIndex, const GLuint* pConstantValue) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SpecializeShader, shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue)
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawArraysIndirectCount, GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawArraysIndirectCount, mode, indirect, drawcount, maxdrawcount, stride) DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawArraysIndirectCount, GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawArraysIndirectCount, mode, indirect, drawcount, maxdrawcount, stride)
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsIndirectCount, GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsIndirectCount, mode, type, indirect, drawcount, maxdrawcount, stride) DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElementsIndirectCount, GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElementsIndirectCount, mode, type, indirect, drawcount, maxdrawcount, stride)
DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffsetClamp, GLfloat factor, GLfloat units, GLfloat clamp) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffsetClamp, factor, units, clamp) DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffsetClamp, GLfloat factor, GLfloat units, GLfloat clamp) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffsetClamp, factor, units, clamp)
DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveBoundingBoxARB, GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) DECLARE_GL_FUNCTION_STUB_END(void, PrimitiveBoundingBoxARB, minX, minY, minZ, minW, maxX, maxY, maxZ, maxW) DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveBoundingBoxARB, GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) DECLARE_GL_FUNCTION_STUB_END(void, PrimitiveBoundingBoxARB, minX, minY, minZ, minW, maxX, maxY, maxZ, maxW)
DECLARE_GL_FUNCTION_STUB_HEAD(GLuint64, GetTextureHandleARB, GLuint texture) DECLARE_GL_FUNCTION_STUB_END(GLuint64, GetTextureHandleARB, texture) DECLARE_GL_FUNCTION_STUB_HEAD(GLuint64, GetTextureHandleARB, GLuint texture) DECLARE_GL_FUNCTION_STUB_END(GLuint64, GetTextureHandleARB, texture)
@@ -1214,8 +1215,8 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, Histogram, GLenum target, GLsizei width, GLe
DECLARE_GL_FUNCTION_STUB_HEAD(void, Minmax, GLenum target, GLenum internalformat, GLboolean sink) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Minmax, target, internalformat, sink) DECLARE_GL_FUNCTION_STUB_HEAD(void, Minmax, GLenum target, GLenum internalformat, GLboolean sink) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Minmax, target, internalformat, sink)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ResetHistogram, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ResetHistogram, target) DECLARE_GL_FUNCTION_STUB_HEAD(void, ResetHistogram, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ResetHistogram, target)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ResetMinmax, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ResetMinmax, target) DECLARE_GL_FUNCTION_STUB_HEAD(void, ResetMinmax, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ResetMinmax, target)
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawArraysIndirectCountARB, GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawArraysIndirectCount, mode, indirect, drawcount, maxdrawcount, stride) DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawArraysIndirectCountARB, GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawArraysIndirectCountARB, mode, indirect, drawcount, maxdrawcount, stride)
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsIndirectCountARB, GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsIndirectCount, mode, type, indirect, drawcount, maxdrawcount, stride) DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElementsIndirectCountARB, GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElementsIndirectCountARB, mode, type, indirect, drawcount, maxdrawcount, stride)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CurrentPaletteMatrixARB, GLint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CurrentPaletteMatrixARB, index) DECLARE_GL_FUNCTION_STUB_HEAD(void, CurrentPaletteMatrixARB, GLint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CurrentPaletteMatrixARB, index)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixIndexubvARB, GLint size, const GLubyte* indices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixIndexubvARB, size, indices) DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixIndexubvARB, GLint size, const GLubyte* indices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixIndexubvARB, size, indices)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixIndexusvARB, GLint size, const GLushort* indices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixIndexusvARB, size, indices) DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixIndexusvARB, GLint size, const GLushort* indices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixIndexusvARB, size, indices)
@@ -1845,11 +1846,11 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixLoadTransposefEXT, GLenum mode, const
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixLoadTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixLoadTransposedEXT, mode, m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixLoadTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixLoadTransposedEXT, mode, m)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposefEXT, GLenum mode, const GLfloat* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposefEXT, mode, m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposefEXT, GLenum mode, const GLfloat* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposefEXT, mode, m)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposedEXT, mode, m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposedEXT, mode, m)
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferDataEXT, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferData, buffer, size, data, usage) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferDataEXT, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferDataEXT, buffer, size, data, usage)
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferSubData, buffer, offset, size, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferSubDataEXT, buffer, offset, size, data)
DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapNamedBufferEXT, GLuint buffer) DECLARE_GL_FUNCTION_END(GLboolean, UnmapNamedBuffer, buffer) DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, UnmapNamedBufferEXT, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END(GLboolean, UnmapNamedBufferEXT, buffer)
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameterivEXT, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferParameterivEXT, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferParameterivEXT, buffer, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferPointervEXT, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferPointerv, buffer, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferPointervEXT, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferPointervEXT, buffer, pname, *params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubDataEXT, buffer, offset, size, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubDataEXT, buffer, offset, size, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferEXT, GLuint texture, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferEXT, texture, target, internalformat, buffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferEXT, GLuint texture, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferEXT, texture, target, internalformat, buffer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiTexBufferEXT, GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiTexBufferEXT, texunit, target, internalformat, buffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiTexBufferEXT, GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiTexBufferEXT, texunit, target, internalformat, buffer)
@@ -1884,15 +1885,15 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramLocalParameterdvEXT, GLuint p
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramLocalParameterfvEXT, GLuint program, GLenum target, GLuint index, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramLocalParameterfvEXT, program, target, index, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramLocalParameterfvEXT, GLuint program, GLenum target, GLuint index, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramLocalParameterfvEXT, program, target, index, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramivEXT, GLuint program, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramivEXT, program, target, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramivEXT, GLuint program, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramivEXT, program, target, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramStringEXT, GLuint program, GLenum target, GLenum pname, void* string) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramStringEXT, program, target, pname, string) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramStringEXT, GLuint program, GLenum target, GLenum pname, void* string) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramStringEXT, program, target, pname, string)
DECLARE_GL_FUNCTION_HEAD(void, NamedRenderbufferStorageEXT, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedRenderbufferStorage, renderbuffer, internalformat, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageEXT, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageEXT, renderbuffer, internalformat, width, height)
DECLARE_GL_FUNCTION_HEAD(void, GetNamedRenderbufferParameterivEXT, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedRenderbufferParameteriv, renderbuffer, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedRenderbufferParameterivEXT, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedRenderbufferParameterivEXT, renderbuffer, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisampleEXT, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisampleEXT, renderbuffer, samples, internalformat, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisampleEXT, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisampleEXT, renderbuffer, samples, internalformat, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisampleCoverageEXT, GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisampleCoverageEXT, renderbuffer, coverageSamples, colorSamples, internalformat, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisampleCoverageEXT, GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisampleCoverageEXT, renderbuffer, coverageSamples, colorSamples, internalformat, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, CheckNamedFramebufferStatusEXT, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_STUB_END(GLenum, CheckNamedFramebufferStatusEXT, framebuffer, target) DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, CheckNamedFramebufferStatusEXT, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_STUB_END(GLenum, CheckNamedFramebufferStatusEXT, framebuffer, target)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture1DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture1DEXT, framebuffer, attachment, textarget, texture, level) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture1DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture1DEXT, framebuffer, attachment, textarget, texture, level)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture2DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture2DEXT, framebuffer, attachment, textarget, texture, level) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture2DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture2DEXT, framebuffer, attachment, textarget, texture, level)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture3DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture3DEXT, framebuffer, attachment, textarget, texture, level, zoffset) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture3DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture3DEXT, framebuffer, attachment, textarget, texture, level, zoffset)
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferRenderbufferEXT, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferRenderbufferEXT, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferRenderbufferEXT, framebuffer, attachment, renderbuffertarget, renderbuffer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferAttachmentParameterivEXT, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameterivEXT, framebuffer, attachment, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferAttachmentParameterivEXT, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameterivEXT, framebuffer, attachment, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateTextureMipmapEXT, GLuint texture, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateTextureMipmapEXT, texture, target) DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateTextureMipmapEXT, GLuint texture, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateTextureMipmapEXT, texture, target)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateMultiTexMipmapEXT, GLenum texunit, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateMultiTexMipmapEXT, texunit, target) DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateMultiTexMipmapEXT, GLenum texunit, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateMultiTexMipmapEXT, texunit, target)
@@ -1918,16 +1919,16 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexAttribOffsetEXT, GLuint vao
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexAttribIOffsetEXT, GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexAttribIOffsetEXT, vaobj, buffer, index, size, type, stride, offset) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexAttribIOffsetEXT, GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexAttribIOffsetEXT, vaobj, buffer, index, size, type, stride, offset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, EnableVertexArrayEXT, GLuint vaobj, GLenum array) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableVertexArrayEXT, vaobj, array) DECLARE_GL_FUNCTION_STUB_HEAD(void, EnableVertexArrayEXT, GLuint vaobj, GLenum array) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableVertexArrayEXT, vaobj, array)
DECLARE_GL_FUNCTION_STUB_HEAD(void, DisableVertexArrayEXT, GLuint vaobj, GLenum array) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DisableVertexArrayEXT, vaobj, array) DECLARE_GL_FUNCTION_STUB_HEAD(void, DisableVertexArrayEXT, GLuint vaobj, GLenum array) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DisableVertexArrayEXT, vaobj, array)
DECLARE_GL_FUNCTION_HEAD(void, EnableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexArrayAttrib, vaobj, index) DECLARE_GL_FUNCTION_STUB_HEAD(void, EnableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableVertexArrayAttribEXT, vaobj, index)
DECLARE_GL_FUNCTION_HEAD(void, DisableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DisableVertexArrayAttrib, vaobj, index) DECLARE_GL_FUNCTION_STUB_HEAD(void, DisableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DisableVertexArrayAttribEXT, vaobj, index)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegervEXT, GLuint vaobj, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIntegervEXT, vaobj, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegervEXT, GLuint vaobj, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIntegervEXT, vaobj, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointervEXT, GLuint vaobj, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointervEXT, vaobj, pname, *param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointervEXT, GLuint vaobj, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointervEXT, vaobj, pname, *param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIntegeri_vEXT, vaobj, index, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIntegeri_vEXT, vaobj, index, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointeri_vEXT, vaobj, index, pname, *param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointeri_vEXT, vaobj, index, pname, *param)
DECLARE_GL_FUNCTION_HEAD(void, FlushMappedNamedBufferRangeEXT, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length) DECLARE_GL_FUNCTION_STUB_HEAD(void, FlushMappedNamedBufferRangeEXT, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FlushMappedNamedBufferRangeEXT, buffer, offset, length)
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferStorageEXT, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferStorageEXT, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferStorageEXT, buffer, size, data, flags)
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedBufferDataEXT, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedBufferData, buffer, internalformat, format, type, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferDataEXT, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferDataEXT, buffer, internalformat, format, type, data)
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedBufferSubDataEXT, GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedBufferSubData, buffer, internalformat, offset, size, format, type, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferSubDataEXT, GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferSubDataEXT, buffer, internalformat, offset, size, format, type, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteriEXT, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteriEXT, framebuffer, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteriEXT, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteriEXT, framebuffer, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferParameterivEXT, GLuint framebuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferParameterivEXT, framebuffer, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferParameterivEXT, GLuint framebuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferParameterivEXT, framebuffer, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1dEXT, GLuint program, GLint location, GLdouble x) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1dEXT, program, location, x) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1dEXT, GLuint program, GLint location, GLdouble x) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1dEXT, program, location, x)
@@ -2045,7 +2046,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetPixelTransformParameterfvEXT, GLenum targ
DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfEXT, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfEXT, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfEXT, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfEXT, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfvEXT, GLenum pname, const GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfvEXT, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfvEXT, GLenum pname, const GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfvEXT, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffsetClampEXT, GLfloat factor, GLfloat units, GLfloat clamp) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffsetClampEXT, factor, units, clamp) DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffsetClampEXT, GLfloat factor, GLfloat units, GLfloat clamp) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffsetClampEXT, factor, units, clamp)
DECLARE_GL_FUNCTION_HEAD(void, ProvokingVertexEXT, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProvokingVertex, mode) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProvokingVertexEXT, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProvokingVertexEXT, mode)
DECLARE_GL_FUNCTION_STUB_HEAD(void, RasterSamplesEXT, GLuint samples, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, RasterSamplesEXT, samples, fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_HEAD(void, RasterSamplesEXT, GLuint samples, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, RasterSamplesEXT, samples, fixedsamplelocations)
DECLARE_GL_FUNCTION_STUB_HEAD(void, SecondaryColor3bEXT, GLbyte red, GLbyte green, GLbyte blue) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SecondaryColor3bEXT, red, green, blue) DECLARE_GL_FUNCTION_STUB_HEAD(void, SecondaryColor3bEXT, GLbyte red, GLbyte green, GLbyte blue) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SecondaryColor3bEXT, red, green, blue)
DECLARE_GL_FUNCTION_STUB_HEAD(void, SecondaryColor3bvEXT, const GLbyte* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SecondaryColor3bvEXT, v) DECLARE_GL_FUNCTION_STUB_HEAD(void, SecondaryColor3bvEXT, const GLbyte* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SecondaryColor3bvEXT, v)
@@ -2879,69 +2880,6 @@ MOBILEGL_GL_API void glGetFramebufferParameterivEXT(GLenum target, GLenum pname,
glGetFramebufferParameteriv(target, pname, params); glGetFramebufferParameteriv(target, pname, params);
} }
MOBILEGL_GL_API void glBindFramebufferEXT(GLenum target, GLuint framebuffer) {
glBindFramebuffer(target, framebuffer);
}
MOBILEGL_GL_API void glBindRenderbufferEXT(GLenum target, GLuint renderbuffer) {
glBindRenderbuffer(target, renderbuffer);
}
MOBILEGL_GL_API GLenum glCheckFramebufferStatusEXT(GLenum target) {
return glCheckFramebufferStatus(target);
}
MOBILEGL_GL_API void glDeleteFramebuffersEXT(GLsizei n, const GLuint* framebuffers) {
glDeleteFramebuffers(n, framebuffers);
}
MOBILEGL_GL_API void glDeleteRenderbuffersEXT(GLsizei n, const GLuint* renderbuffers) {
glDeleteRenderbuffers(n, renderbuffers);
}
MOBILEGL_GL_API void glFramebufferRenderbufferEXT(GLenum target, GLenum attachment, GLenum renderbuffertarget,
GLuint renderbuffer) {
glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
}
MOBILEGL_GL_API void glFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
GLint level) {
glFramebufferTexture2D(target, attachment, textarget, texture, level);
}
MOBILEGL_GL_API void glGenFramebuffersEXT(GLsizei n, GLuint* framebuffers) {
glGenFramebuffers(n, framebuffers);
}
MOBILEGL_GL_API void glGenRenderbuffersEXT(GLsizei n, GLuint* renderbuffers) {
glGenRenderbuffers(n, renderbuffers);
}
MOBILEGL_GL_API void glGenerateMipmapEXT(GLenum target) {
glGenerateMipmap(target);
}
MOBILEGL_GL_API void glGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, GLenum pname,
GLint* params) {
glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
}
MOBILEGL_GL_API void glGetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint* params) {
glGetRenderbufferParameteriv(target, pname, params);
}
MOBILEGL_GL_API GLboolean glIsFramebufferEXT(GLuint framebuffer) {
return glIsFramebuffer(framebuffer);
}
MOBILEGL_GL_API GLboolean glIsRenderbufferEXT(GLuint renderbuffer) {
return glIsRenderbuffer(renderbuffer);
}
MOBILEGL_GL_API void glRenderbufferStorageEXT(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
glRenderbufferStorage(target, internalformat, width, height);
}
MOBILEGL_GL_API GLenum glGetGraphicsResetStatusARB(void) { MOBILEGL_GL_API GLenum glGetGraphicsResetStatusARB(void) {
return glGetGraphicsResetStatus(); return glGetGraphicsResetStatus();
} }
@@ -2964,8 +2902,8 @@ MOBILEGL_GL_API void glGetObjectLabelEXT(GLenum identifier, GLuint name, GLsizei
} }
MOBILEGL_GL_API void* glMapNamedBuffer(GLuint buffer, GLenum access) { MOBILEGL_GL_API void* glMapNamedBuffer(GLuint buffer, GLenum access) {
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); MGLOG_W("Stub function: %s(...)", __FUNCTION__);
return MobileGL::MG_Impl::GLImpl::MapNamedBuffer(buffer, access); return nullptr;
} }
MOBILEGL_GL_API void* glMapNamedBufferEXT(GLuint buffer, GLenum access) { MOBILEGL_GL_API void* glMapNamedBufferEXT(GLuint buffer, GLenum access) {
@@ -2973,8 +2911,8 @@ MOBILEGL_GL_API void* glMapNamedBufferEXT(GLuint buffer, GLenum access) {
} }
MOBILEGL_GL_API void* glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) { MOBILEGL_GL_API void* glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) {
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); MGLOG_W("Stub function: %s(...)", __FUNCTION__);
return MobileGL::MG_Impl::GLImpl::MapNamedBufferRange(buffer, offset, length, access); return nullptr;
} }
MOBILEGL_GL_API void* glMapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) { MOBILEGL_GL_API void* glMapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) {
@@ -3087,48 +3025,48 @@ MOBILEGL_GL_API void glProgramUniform4uivEXT(GLuint program, GLint location, GLs
glProgramUniform4uiv(program, location, count, value); glProgramUniform4uiv(program, location, count, value);
} }
MOBILEGL_GL_API void glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, MOBILEGL_GL_API void glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsizei count,
const GLfloat* value) { GLboolean transpose, const GLfloat* value) {
glProgramUniformMatrix2fv(program, location, count, transpose, value); glProgramUniformMatrix2fv(program, location, count, transpose, value);
} }
MOBILEGL_GL_API void glProgramUniformMatrix2x3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, MOBILEGL_GL_API void glProgramUniformMatrix2x3fvEXT(GLuint program, GLint location, GLsizei count,
const GLfloat* value) { GLboolean transpose, const GLfloat* value) {
glProgramUniformMatrix2x3fv(program, location, count, transpose, value); glProgramUniformMatrix2x3fv(program, location, count, transpose, value);
} }
MOBILEGL_GL_API void glProgramUniformMatrix2x4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, MOBILEGL_GL_API void glProgramUniformMatrix2x4fvEXT(GLuint program, GLint location, GLsizei count,
const GLfloat* value) { GLboolean transpose, const GLfloat* value) {
glProgramUniformMatrix2x4fv(program, location, count, transpose, value); glProgramUniformMatrix2x4fv(program, location, count, transpose, value);
} }
MOBILEGL_GL_API void glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, MOBILEGL_GL_API void glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsizei count,
const GLfloat* value) { GLboolean transpose, const GLfloat* value) {
glProgramUniformMatrix3fv(program, location, count, transpose, value); glProgramUniformMatrix3fv(program, location, count, transpose, value);
} }
MOBILEGL_GL_API void glProgramUniformMatrix3x2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, MOBILEGL_GL_API void glProgramUniformMatrix3x2fvEXT(GLuint program, GLint location, GLsizei count,
const GLfloat* value) { GLboolean transpose, const GLfloat* value) {
glProgramUniformMatrix3x2fv(program, location, count, transpose, value); glProgramUniformMatrix3x2fv(program, location, count, transpose, value);
} }
MOBILEGL_GL_API void glProgramUniformMatrix3x4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, MOBILEGL_GL_API void glProgramUniformMatrix3x4fvEXT(GLuint program, GLint location, GLsizei count,
const GLfloat* value) { GLboolean transpose, const GLfloat* value) {
glProgramUniformMatrix3x4fv(program, location, count, transpose, value); glProgramUniformMatrix3x4fv(program, location, count, transpose, value);
} }
MOBILEGL_GL_API void glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, MOBILEGL_GL_API void glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count,
const GLfloat* value) { GLboolean transpose, const GLfloat* value) {
glProgramUniformMatrix4fv(program, location, count, transpose, value); glProgramUniformMatrix4fv(program, location, count, transpose, value);
} }
MOBILEGL_GL_API void glProgramUniformMatrix4x2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, MOBILEGL_GL_API void glProgramUniformMatrix4x2fvEXT(GLuint program, GLint location, GLsizei count,
const GLfloat* value) { GLboolean transpose, const GLfloat* value) {
glProgramUniformMatrix4x2fv(program, location, count, transpose, value); glProgramUniformMatrix4x2fv(program, location, count, transpose, value);
} }
MOBILEGL_GL_API void glProgramUniformMatrix4x3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, MOBILEGL_GL_API void glProgramUniformMatrix4x3fvEXT(GLuint program, GLint location, GLsizei count,
const GLfloat* value) { GLboolean transpose, const GLfloat* value) {
glProgramUniformMatrix4x3fv(program, location, count, transpose, value); glProgramUniformMatrix4x3fv(program, location, count, transpose, value);
} }
File diff suppressed because it is too large Load Diff
@@ -11,7 +11,8 @@
#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 {
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);
@@ -24,36 +25,19 @@ namespace MobileGL::MG_Impl::GLImpl {
GLboolean IsRenderbuffer(GLuint renderbuffer); GLboolean IsRenderbuffer(GLuint renderbuffer);
void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params); void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
void GenRenderbuffers(GLsizei n, GLuint* renderbuffers); void GenRenderbuffers(GLsizei n, GLuint* renderbuffers);
void CreateRenderbuffers(GLsizei n, GLuint* renderbuffers);
void NamedRenderbufferStorage(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);
void GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, GLint* params);
void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
void NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget,
GLuint renderbuffer);
void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers); void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
void BindRenderbuffer(GLenum target, GLuint renderbuffer); void BindRenderbuffer(GLenum target, GLuint renderbuffer);
void SampleMaski(GLuint maskNumber, GLbitfield mask); void SampleMaski(GLuint maskNumber, GLbitfield mask);
GLboolean IsFramebuffer(GLuint framebuffer); GLboolean IsFramebuffer(GLuint framebuffer);
void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params); void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
void GenFramebuffers(GLsizei n, GLuint* framebuffers); void GenFramebuffers(GLsizei n, GLuint* framebuffers);
void CreateFramebuffers(GLsizei n, GLuint* framebuffers);
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
void FramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, void FramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level,
GLint zoffset); GLint zoffset);
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
void FramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); void FramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
void FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level); void FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level);
void NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);
void NamedFramebufferDrawBuffer(GLuint framebuffer, GLenum buf);
void NamedFramebufferDrawBuffers(GLuint framebuffer, GLsizei n, const GLenum* bufs);
void NamedFramebufferReadBuffer(GLuint framebuffer, GLenum src);
void ClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
GLenum CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target);
void GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params);
void BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1,
GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
GLenum filter);
void DrawBuffer(GLenum buf); void DrawBuffer(GLenum buf);
void DrawBuffers(GLsizei n, const GLenum* bufs); void DrawBuffers(GLsizei n, const GLenum* bufs);
void ReadBuffer(GLenum src); void ReadBuffer(GLenum src);
@@ -71,6 +55,7 @@ namespace MobileGL::MG_Impl::GLImpl {
SharedPtr<MG_State::GLState::ITextureObject> stencilAttachment; SharedPtr<MG_State::GLState::ITextureObject> stencilAttachment;
}; };
extern UniquePtr<DefaultFramebufferInfo> pDefaultFramebufferInfo; extern DefaultFramebufferInfo* pDefaultFramebufferInfo;
} // namespace FramebufferImpl } // namespace FramebufferImpl
} // namespace MobileGL::MG_Impl::GLImpl } // namespace MG_Impl::GLImpl
} // namespace MobileGL
@@ -13,14 +13,16 @@
#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::FramebufferImpl { namespace MobileGL::MG_Impl::GLImpl {
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, MakeUnique<GenericErrorInfo>( ErrorCode::InvalidEnum,
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;
@@ -32,7 +34,7 @@ namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
if (index == 0 && !allowZero) { if (index == 0 && !allowZero) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName", MakeShared<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;
} }
@@ -40,7 +42,7 @@ namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
if (isValid) return true; if (isValid) return true;
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName", MakeShared<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;
} }
@@ -52,7 +54,7 @@ namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
String glAttachmentStr = ConvertGLEnumToString(ConvertFramebufferAttachmentTypeToGLEnum(attachment)); String glAttachmentStr = ConvertGLEnumToString(ConvertFramebufferAttachmentTypeToGLEnum(attachment));
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>( MakeShared<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;
@@ -67,7 +69,7 @@ namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
String glTargetStr = ConvertGLEnumToString(ConvertRenderbufferTargetToGLEnum(target)); String glTargetStr = ConvertGLEnumToString(ConvertRenderbufferTargetToGLEnum(target));
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>( MakeShared<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;
@@ -79,7 +81,7 @@ namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
if (index == 0 && !allowZero) { if (index == 0 && !allowZero) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName", MakeShared<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;
} }
@@ -87,8 +89,9 @@ namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
if (isValid) return true; if (isValid) return true;
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName", MakeShared<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 MobileGL::MG_Impl::GLImpl::FramebufferImpl } // namespace FramebufferImpl
} // namespace MobileGL::MG_Impl::GLImpl
@@ -10,10 +10,12 @@
#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::FramebufferImpl { namespace MobileGL::MG_Impl::GLImpl {
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 MobileGL::MG_Impl::GLImpl::FramebufferImpl } // namespace FramebufferImpl
} // namespace MobileGL::MG_Impl::GLImpl
+44 -179
View File
@@ -76,12 +76,12 @@ namespace MobileGL::MG_Impl::GLImpl {
MGLOG_D("shadingLanguageVersion: %s", shadingLanguageVersion.c_str()); MGLOG_D("shadingLanguageVersion: %s", shadingLanguageVersion.c_str());
return (const GLubyte*)shadingLanguageVersion.c_str(); return (const GLubyte*)shadingLanguageVersion.c_str();
case GL_EXTENSIONS: case GL_EXTENSIONS:
extensionsString.clear(); if (extensionsString.empty()) {
for (auto& ext : rendererInfo.RendererGLInfo.Extensions) { for (auto& ext : rendererInfo.RendererGLInfo.Extensions) {
if (!extensionsString.empty()) { extensionsString += MG_Util::ConvertGLExtToString(ext);
extensionsString += " "; extensionsString += " ";
} }
extensionsString += MG_Util::ConvertGLExtToString(ext); extensionsString.pop_back();
} }
return (const GLubyte*)extensionsString.c_str(); return (const GLubyte*)extensionsString.c_str();
default: default:
@@ -108,95 +108,24 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
static Vector<String> extStrings; static Vector<String> extStrings;
extStrings.clear(); static Bool initialized = false;
if (!initialized) {
extStrings.reserve(exts.size()); extStrings.reserve(exts.size());
for (const auto& ext : exts) { for (const auto& ext : exts) {
extStrings.emplace_back(MG_Util::ConvertGLExtToString(ext)); extStrings.emplace_back(MG_Util::ConvertGLExtToString(ext));
} }
initialized = true;
}
return (const GLubyte*)extStrings[index].c_str(); return (const GLubyte*)extStrings[index].c_str();
} }
void GetIntegeri_v(GLenum target, GLuint index, GLint* data) {
if (!data) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "data pointer cannot be null"));
return;
}
auto getIntegeri = MG_Backend::gBackendFunctionsTable.GL.GetIntegeri_v;
if (!getIntegeri) {
*data = 0;
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Backend does not support indexed integer queries."));
return;
}
getIntegeri(target, index, data);
}
void GetInteger64i_v(GLenum target, GLuint index, GLint64* data) {
if (!data) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "data pointer cannot be null"));
return;
}
auto getInteger64i = MG_Backend::gBackendFunctionsTable.GL.GetInteger64i_v;
if (!getInteger64i) {
*data = 0;
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Backend does not support indexed integer queries."));
return;
}
getInteger64i(target, index, data);
}
void GetInteger64v(GLenum pname, GLint64* data) {
MGLOG_D("glGetInteger64v, pname: %s", MG_Util::ConvertGLEnumToString(pname).c_str());
if (!data) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "data pointer cannot be null"));
return;
}
switch (pname) {
case GL_MAX_SHADER_STORAGE_BLOCK_SIZE:
if (MG_Backend::pActiveBackendObject) {
*data = static_cast<GLint64>(
MG_Backend::pActiveBackendObject->GetDynamicParameters().MaxShaderStorageBlockSize);
} else {
*data = static_cast<GLint64>(MG_Backend::DynamicBackendParameters{}.MaxShaderStorageBlockSize);
}
return;
case GL_SUBGROUP_SIZE_KHR:
case GL_SUBGROUP_SUPPORTED_STAGES_KHR:
case GL_SUBGROUP_SUPPORTED_FEATURES_KHR:
case GL_SUBGROUP_QUAD_ALL_STAGES_KHR: {
GLint params = 0;
GetIntegerv(pname, &params);
*data = static_cast<GLint64>(params);
return;
}
default:
*data = 0;
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::format("Unsupported integer64 pname {}.",
MG_Util::ConvertGLEnumToString(pname))));
return;
}
}
void GetIntegerv(GLenum pname, GLint* params) { void GetIntegerv(GLenum pname, GLint* params) {
MGLOG_D("glGetIntegerv, pname: %s", MG_Util::ConvertGLEnumToString(pname).c_str()); MGLOG_D("glGetIntegerv, pname: %s", MG_Util::ConvertGLEnumToString(pname).c_str());
if (!params) { if (!params) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv", "params pointer cannot be null")); MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv", "params pointer cannot be null"));
return; return;
} }
@@ -206,7 +135,6 @@ namespace MobileGL::MG_Impl::GLImpl {
return; return;
} }
const auto& rendererInfo = activeBackendObject->GetRendererInfo(); const auto& rendererInfo = activeBackendObject->GetRendererInfo();
const auto& dynamicParameters = activeBackendObject->GetDynamicParameters();
switch (pname) { switch (pname) {
case GL_ACTIVE_TEXTURE: case GL_ACTIVE_TEXTURE:
@@ -216,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 = (GLint)obj->GetExternalIndex(); *params = obj->GetExternalIndex();
else else
*params = 0; *params = 0;
break; break;
@@ -232,39 +160,31 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_BLEND_DST_ALPHA: { case GL_BLEND_DST_ALPHA: {
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha; BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha;
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
*params = static_cast<GLint>(MG_Util::ConvertBlendFactorToGLEnum(dstAlpha)); *params = static_cast<GLint>(dstAlpha);
break; break;
} }
case GL_BLEND_DST_RGB: { case GL_BLEND_DST_RGB: {
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha; BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha;
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
*params = static_cast<GLint>(MG_Util::ConvertBlendFactorToGLEnum(dstRGB)); *params = static_cast<GLint>(dstRGB);
break; break;
} }
case GL_BLEND_EQUATION_RGB: { case GL_BLEND_EQUATION_RGB:
BlendEquation colorEquation = BlendEquation::Add; *params = 0; // TODO
BlendEquation alphaEquation = BlendEquation::Add;
MG_State::pGLContext->GetBlendEquation(colorEquation, alphaEquation);
*params = static_cast<GLint>(MG_Util::ConvertBlendEquationToGLEnum(colorEquation));
break; break;
} case GL_BLEND_EQUATION_ALPHA:
case GL_BLEND_EQUATION_ALPHA: { *params = 0; // TODO
BlendEquation colorEquation = BlendEquation::Add;
BlendEquation alphaEquation = BlendEquation::Add;
MG_State::pGLContext->GetBlendEquation(colorEquation, alphaEquation);
*params = static_cast<GLint>(MG_Util::ConvertBlendEquationToGLEnum(alphaEquation));
break; break;
}
case GL_BLEND_SRC_ALPHA: { case GL_BLEND_SRC_ALPHA: {
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha; BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha;
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
*params = static_cast<GLint>(MG_Util::ConvertBlendFactorToGLEnum(srcAlpha)); *params = static_cast<GLint>(srcAlpha);
break; break;
} }
case GL_BLEND_SRC_RGB: { case GL_BLEND_SRC_RGB: {
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha; BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha;
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
*params = static_cast<GLint>(MG_Util::ConvertBlendFactorToGLEnum(srcRGB)); *params = static_cast<GLint>(srcRGB);
break; break;
} }
case GL_COLOR_CLEAR_VALUE: case GL_COLOR_CLEAR_VALUE:
@@ -284,60 +204,42 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_COMPRESSED_TEXTURE_FORMATS: case GL_COMPRESSED_TEXTURE_FORMATS:
*params = 0; // TODO *params = 0; // TODO
break; break;
case GL_SUBGROUP_SIZE_KHR:
*params = static_cast<GLint>(dynamicParameters.SubgroupSize);
break;
case GL_SUBGROUP_SUPPORTED_STAGES_KHR:
*params = static_cast<GLint>(dynamicParameters.SubgroupSupportedStages);
break;
case GL_SUBGROUP_SUPPORTED_FEATURES_KHR:
*params = static_cast<GLint>(dynamicParameters.SubgroupSupportedFeatures);
break;
case GL_SUBGROUP_QUAD_ALL_STAGES_KHR:
*params = dynamicParameters.SubgroupQuadOperationsInAllStages ? GL_TRUE : GL_FALSE;
break;
case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS: case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS:
*params = 16; // TODO: use backend value *params = 0; // TODO
break; break;
case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS:
*params = 96; // TODO: use backend value *params = 0; // TODO
break; break;
case GL_MAX_COMPUTE_UNIFORM_BLOCKS: case GL_MAX_COMPUTE_UNIFORM_BLOCKS:
*params = 14; // TODO: use backend value *params = 0; // TODO
break; break;
case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS: case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS:
*params = MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; // TODO: use backend value *params = 0; // TODO
break; break;
case GL_MAX_COMPUTE_UNIFORM_COMPONENTS: case GL_MAX_COMPUTE_UNIFORM_COMPONENTS:
*params = 1024 * 4; // TODO: use backend value *params = 0; // TODO
break; break;
case GL_MAX_COMPUTE_ATOMIC_COUNTERS: case GL_MAX_COMPUTE_ATOMIC_COUNTERS:
*params = 8; // TODO: use backend value *params = 0; // TODO
break; break;
case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS: case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS:
*params = 8; // TODO: use backend value *params = 0; // TODO
break; break;
case GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS: case GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS:
*params = 1024 * 228; // TODO: use backend value *params = 0; // TODO
break; break;
case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS: case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS:
*params = 1024; // TODO: use backend value *params = 0; // TODO
break; break;
case GL_MAX_COMPUTE_WORK_GROUP_COUNT: case GL_MAX_COMPUTE_WORK_GROUP_COUNT:
GetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &params[0]); *params = 0; // TODO
GetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &params[1]);
GetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &params[2]);
break; break;
case GL_MAX_COMPUTE_WORK_GROUP_SIZE: case GL_MAX_COMPUTE_WORK_GROUP_SIZE:
GetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &params[0]); *params = 0; // TODO
GetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &params[1]);
GetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &params[2]);
break; break;
case GL_DISPATCH_INDIRECT_BUFFER_BINDING: { case GL_DISPATCH_INDIRECT_BUFFER_BINDING:
auto& obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DispatchIndirect).GetBoundObject(); *params = 0; // TODO
*params = obj ? static_cast<GLint>(obj->GetExternalIndex()) : 0;
break; break;
}
case GL_MAX_DEBUG_GROUP_STACK_DEPTH: case GL_MAX_DEBUG_GROUP_STACK_DEPTH:
*params = 0; // TODO *params = 0; // TODO
break; break;
@@ -350,22 +252,16 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_CULL_FACE: case GL_CULL_FACE:
*params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace) ? GL_TRUE : GL_FALSE; *params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace) ? GL_TRUE : GL_FALSE;
break; break;
case GL_CULL_FACE_MODE:
*params = static_cast<GLint>(MG_Util::ConvertCullFaceModeToGLEnum(MG_State::pGLContext->GetCullFaceMode()));
break;
case GL_FRONT_FACE:
*params = static_cast<GLint>(MG_Util::ConvertFrontFaceModeToGLEnum(MG_State::pGLContext->GetFrontFaceMode()));
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 ? (GLint)currentProgram->GetExternalIndex() : 0; *params = currentProgram ? currentProgram->GetExternalIndex() : 0;
break; break;
} }
case GL_DEPTH_CLEAR_VALUE: case GL_DEPTH_CLEAR_VALUE:
*params = (GLint)MG_State::pGLContext->GetClearDepth(); *params = MG_State::pGLContext->GetClearDepth();
break; break;
case GL_DEPTH_FUNC: case GL_DEPTH_FUNC:
*params = (GLint)MG_Util::ConvertDepthTestFuncToGLEnum(MG_State::pGLContext->GetDepthFunc()); *params = MG_Util::ConvertDepthTestFuncToGLEnum(MG_State::pGLContext->GetDepthFunc());
break; break;
case GL_DEPTH_RANGE: case GL_DEPTH_RANGE:
*params = 0; // TODO *params = 0; // TODO
@@ -390,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 ? (GLint)FBO->GetExternalIndex() : 0; *params = FBO ? 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 ? (GLint)FBO->GetExternalIndex() : 0; *params = FBO ? FBO->GetExternalIndex() : 0;
break; break;
} }
case GL_ELEMENT_ARRAY_BUFFER_BINDING: { case GL_ELEMENT_ARRAY_BUFFER_BINDING: {
@@ -404,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 ? (GLint)bufferObject->GetExternalIndex() : 0; *params = bufferObject ? bufferObject->GetExternalIndex() : 0;
break; break;
} }
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT: case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
@@ -530,22 +426,6 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_MAX_GEOMETRY_UNIFORM_COMPONENTS: case GL_MAX_GEOMETRY_UNIFORM_COMPONENTS:
*params = 1024 * 4; // TODO *params = 1024 * 4; // TODO
break; break;
case GL_MAX_IMAGE_UNITS:
*params = MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; // TODO: use backend value
break;
case GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS:
*params = MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS +
MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS;
break;
case GL_MAX_COMBINED_IMAGE_UNIFORMS:
*params = MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; // TODO: use backend value
break;
case GL_MAX_IMAGE_SAMPLES:
*params = 0; // multisampled image load/store is not exposed by the DirectGLES frontend
break;
case GL_MAX_COMPUTE_IMAGE_UNIFORMS:
*params = MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; // TODO: use backend value
break;
case GL_MAX_INTEGER_SAMPLES: case GL_MAX_INTEGER_SAMPLES:
*params = 16; // TODO *params = 16; // TODO
break; break;
@@ -691,11 +571,6 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_PIXEL_UNPACK_BUFFER_BINDING: case GL_PIXEL_UNPACK_BUFFER_BINDING:
*params = 0; // TODO *params = 0; // TODO
break; break;
case GL_PARAMETER_BUFFER_BINDING_ARB: {
auto& obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Parameter).GetBoundObject();
*params = obj ? static_cast<GLint>(obj->GetExternalIndex()) : 0;
break;
}
case GL_POINT_FADE_THRESHOLD_SIZE: case GL_POINT_FADE_THRESHOLD_SIZE:
*params = 0; // TODO *params = 0; // TODO
break; break;
@@ -712,16 +587,11 @@ namespace MobileGL::MG_Impl::GLImpl {
*params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ProgramPointSize) ? GL_TRUE : GL_FALSE; *params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ProgramPointSize) ? GL_TRUE : GL_FALSE;
break; break;
case GL_PROVOKING_VERTEX: case GL_PROVOKING_VERTEX:
*params = static_cast<GLint>( *params = 0; // TODO
MG_Util::ConvertProvokingVertexModeToGLEnum(MG_State::pGLContext->GetProvokingVertexMode()));
break; break;
case GL_POINT_SIZE: case GL_POINT_SIZE:
*params = 0; // TODO *params = 0; // TODO
break; break;
case GL_POLYGON_MODE:
params[0] = GL_FILL;
params[1] = GL_FILL;
break;
case GL_POINT_SIZE_GRANULARITY: case GL_POINT_SIZE_GRANULARITY:
*params = 0; // TODO *params = 0; // TODO
break; break;
@@ -789,13 +659,11 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_SHADER_COMPILER: case GL_SHADER_COMPILER:
*params = 0; // TODO *params = 0; // TODO
break; break;
case GL_SHADER_STORAGE_BUFFER_BINDING: { case GL_SHADER_STORAGE_BUFFER_BINDING:
auto& obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::ShaderStorage).GetBoundObject(); *params = 0; // TODO
*params = obj ? static_cast<GLint>(obj->GetExternalIndex()) : 0;
break; break;
}
case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT: case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT:
*params = 256; // TODO: use backend value *params = 0; // TODO
break; break;
case GL_SHADER_STORAGE_BUFFER_START: case GL_SHADER_STORAGE_BUFFER_START:
*params = 0; // TODO *params = 0; // TODO
@@ -1016,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,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv", MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv",
std::format("Invalid enum: 0x{:X}", pname))); std::format("Invalid enum: 0x{:X}", pname)));
break; break;
@@ -1024,10 +892,7 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
GLenum GetError() { GLenum GetError() {
auto error = MG_State::pGLContext->PopGLError(); ErrorCode errorCode = MG_State::pGLContext->PopGLError().value_or(Error{ErrorCode::NoError, nullptr}).code;
if (!error || !error->get()) { return MG_Util::ConvertErrorCodeToGLEnum(errorCode);
return GL_NO_ERROR;
}
return MG_Util::ConvertErrorCodeToGLEnum(error->get()->code);
} }
} // namespace MobileGL::MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
@@ -14,8 +14,5 @@ namespace MobileGL::MG_Impl::GLImpl {
const GLubyte* GetString(GLenum name); const GLubyte* GetString(GLenum name);
const GLubyte* GetStringi(GLenum name, GLuint index); const GLubyte* GetStringi(GLenum name, GLuint index);
void GetIntegerv(GLenum pname, GLint* params); void GetIntegerv(GLenum pname, GLint* params);
void GetInteger64v(GLenum pname, GLint64* data);
void GetIntegeri_v(GLenum target, GLuint index, GLint* data);
void GetInteger64i_v(GLenum target, GLuint index, GLint64* data);
GLenum GetError(); GLenum GetError();
} // namespace MobileGL::MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl

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