mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 04:38:30 +09:00
Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4bf9c1cae6 | ||
|
|
c121328c98 | ||
|
|
5fe5aae138 | ||
|
|
d2485a3fbe | ||
|
|
3fe0999550 | ||
|
|
39eb6a9026 | ||
|
|
99c1697fba | ||
|
|
5db5545b33 | ||
|
|
e63eebf425 | ||
|
|
03d3fcdc66 | ||
|
|
40fc317f69 | ||
|
|
3bafdee45d | ||
|
|
188275c004 |
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -15,7 +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*
|
|
||||||
@@ -16,12 +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
|
|
||||||
|
|||||||
Vendored
-1
Submodule 3rdparty/Vulkan-Headers deleted from ad9ce1235e
Vendored
-1
Submodule 3rdparty/Vulkan-Utility-Libraries deleted from 738ec97a3f
Vendored
-1
Submodule 3rdparty/VulkanMemoryAllocator deleted from e722e57c89
+10
-45
@@ -107,9 +107,6 @@ set(SPIRV_CROSS_STATIC ON CACHE BOOL "Prefer static libs" 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)
|
|
||||||
|
|
||||||
set(XXHASH_BUILD_XXHSUM OFF)
|
set(XXHASH_BUILD_XXHSUM OFF)
|
||||||
option(BUILD_SHARED_LIBS OFF)
|
option(BUILD_SHARED_LIBS OFF)
|
||||||
@@ -130,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
|
||||||
|
|
||||||
@@ -162,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
|
||||||
|
|
||||||
@@ -215,25 +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/UniformDescriptorBinder.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
|
||||||
@@ -266,18 +251,8 @@ set(MOBILEGL_LINK_LIBRARIES
|
|||||||
SPIRV-Tools-opt
|
SPIRV-Tools-opt
|
||||||
SPIRV-Tools
|
SPIRV-Tools
|
||||||
xxHash::xxhash
|
xxHash::xxhash
|
||||||
GPUOpen::VulkanMemoryAllocator
|
|
||||||
Vulkan::UtilityHeaders
|
|
||||||
)
|
)
|
||||||
|
|
||||||
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
|
||||||
@@ -310,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}
|
||||||
@@ -343,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
@@ -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, 3, 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
|
||||||
|
|||||||
@@ -1,84 +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"
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -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
-15
@@ -38,6 +38,7 @@
|
|||||||
#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>
|
||||||
@@ -50,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>
|
||||||
|
|
||||||
@@ -62,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
|
||||||
|
|
||||||
@@ -96,21 +92,12 @@
|
|||||||
#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
|
|
||||||
#else
|
|
||||||
#warning "VK_USE_PLATFORM_*_KHR not defined for this platform!"
|
|
||||||
#endif
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
|
|||||||
+13
-16
@@ -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
@@ -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
|
||||||
@@ -9,133 +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_eglWindowSurfaceInitialized && 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_eglWindowSurfaceInitialized = true;
|
|
||||||
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_eglWindowSurfaceInitialized) {
|
|
||||||
MGLOG_E("MakeEGLCurrent failed: EGL window 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_eglWindowSurfaceInitialized = false;
|
|
||||||
m_backendCapabilitiesInitialized = false;
|
|
||||||
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_eglWindowSurfaceInitialized || 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::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;
|
||||||
}
|
}
|
||||||
} // namespace MobileGL::MG_Backend
|
} // namespace MobileGL::MG_Backend
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
enum class BackendType {
|
enum class BackendType {
|
||||||
DirectGLES,
|
DirectGLES,
|
||||||
DirectVulkan,
|
DirectVulkanTMP,
|
||||||
BackendTypeCount,
|
BackendTypeCount,
|
||||||
Unknown = -1
|
Unknown = -1
|
||||||
};
|
};
|
||||||
@@ -91,13 +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 MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
|
|
||||||
virtual Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw);
|
|
||||||
|
|
||||||
void SetWindowHandle(const WindowHandle& handle);
|
void SetWindowHandle(const WindowHandle& handle);
|
||||||
|
|
||||||
@@ -108,15 +103,7 @@ namespace MobileGL {
|
|||||||
virtual BackendType GetBackendType() const = 0;
|
virtual BackendType GetBackendType() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ResetEGLRuntimeState();
|
|
||||||
|
|
||||||
mutable std::recursive_mutex m_eglStateMutex;
|
|
||||||
WindowHandle m_windowHandle;
|
WindowHandle m_windowHandle;
|
||||||
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
|
|
||||||
Bool m_eglDisplayInitialized = false;
|
|
||||||
Bool m_eglWindowSurfaceInitialized = false;
|
|
||||||
Bool m_backendCapabilitiesInitialized = false;
|
|
||||||
UnorderedMap<std::thread::id, Bool> m_eglCurrentThreads;
|
|
||||||
};
|
};
|
||||||
} // namespace MG_Backend
|
} // namespace MG_Backend
|
||||||
} // namespace MobileGL
|
} // namespace MobileGL
|
||||||
|
|||||||
@@ -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,65 +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.Handle) {
|
|
||||||
MGLOG_E("DirectGLES backend only supports Android native windows");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Bool sameHandle =
|
|
||||||
m_eglWindowSurfaceInitialized && m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
|
|
||||||
if (sameHandle) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_eglWindowSurfaceInitialized) {
|
|
||||||
DestroyEGLContext();
|
|
||||||
ResetEGLRuntimeState();
|
|
||||||
}
|
|
||||||
|
|
||||||
return BackendObject::CreateEGLWindowSurface(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const RendererInfo& BackendObject_DirectGLES::GetRendererInfo() const {
|
const RendererInfo& BackendObject_DirectGLES::GetRendererInfo() const {
|
||||||
|
|||||||
@@ -17,12 +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;
|
|
||||||
|
|
||||||
const RendererInfo& GetRendererInfo() const override;
|
const RendererInfo& GetRendererInfo() const override;
|
||||||
String GetBackendAPIVersionString() const override;
|
String GetBackendAPIVersionString() const override;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "DirectGLES.h"
|
#include "DirectGLES.h"
|
||||||
#include "EGL/egl.h"
|
#include "EGL/egl.h"
|
||||||
#include "MG_Util/Types.h"
|
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "Managers.h"
|
#include "Managers.h"
|
||||||
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
||||||
@@ -46,7 +45,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
namespace DebugImpl {
|
namespace DebugImpl {
|
||||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||||
void ErrorLopper::Loop(const std::function<void(GLenum)>& func) {
|
void ErrorLopper::Loop(std::function<void(GLenum)> func) {
|
||||||
GLenum err = g_GLESFuncs.glGetError();
|
GLenum err = g_GLESFuncs.glGetError();
|
||||||
while (err != GL_NO_ERROR) {
|
while (err != GL_NO_ERROR) {
|
||||||
func(err);
|
func(err);
|
||||||
@@ -69,14 +68,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
void ErrorLopper::Loop(const std::function<void(GLenum)>& func) {}
|
void ErrorLopper::Loop(std::function<void(GLenum)> func) {}
|
||||||
void ErrorLopper::Clear() {}
|
void ErrorLopper::Clear() {}
|
||||||
ErrorLopper::ErrorLopper() = default;
|
ErrorLopper::ErrorLopper() {}
|
||||||
ErrorLopper::~ErrorLopper() = default;
|
ErrorLopper::~ErrorLopper() {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||||
OpenGLScopeMarker::OpenGLScopeMarker(const String& scopeName) {
|
OpenGLScopeMarker::OpenGLScopeMarker(String scopeName) {
|
||||||
g_GLESFuncs.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, scopeName.c_str());
|
g_GLESFuncs.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, scopeName.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +83,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_GLESFuncs.glPopDebugGroup();
|
g_GLESFuncs.glPopDebugGroup();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
OpenGLScopeMarker::OpenGLScopeMarker(const String& scopeName) {}
|
OpenGLScopeMarker::OpenGLScopeMarker(String scopeName) {}
|
||||||
|
|
||||||
OpenGLScopeMarker::~OpenGLScopeMarker() {}
|
OpenGLScopeMarker::~OpenGLScopeMarker() {}
|
||||||
#endif
|
#endif
|
||||||
@@ -93,28 +92,31 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// TODO: deletion for deleted objects
|
// TODO: deletion for deleted objects
|
||||||
|
|
||||||
namespace BufferImpl {
|
namespace BufferImpl {
|
||||||
void CreateAndSyncBufferObject(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject) {
|
void CreateAndSyncBufferObject(SharedPtr<MG_State::GLState::BufferObject>& bufferObject) {
|
||||||
if (!(bufferObject->GetChangeBits() & BufferChangeBits::DirtyBit)) return;
|
if (!(bufferObject->GetChangeBits() & BufferChangeBits::DirtyBit)) return;
|
||||||
|
|
||||||
const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject.get());
|
const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject);
|
||||||
Bool exist = (backendBufferIt != g_backendBufferObjects.end());
|
SharedPtr<BackendBufferObject> backendBufferObject;
|
||||||
auto& backendObj = exist ? backendBufferIt->second : g_backendBufferObjects.GetOrCreate(bufferObject);
|
if (backendBufferIt == g_backendBufferObjects.end()) {
|
||||||
if (!exist) {
|
backendBufferObject = MakeShared<BackendBufferObject>();
|
||||||
backendObj = MakeShared<BackendBufferObject>();
|
g_backendBufferObjects[bufferObject] = backendBufferObject;
|
||||||
|
} else {
|
||||||
|
backendBufferObject = backendBufferIt->second;
|
||||||
}
|
}
|
||||||
backendObj->SyncToBackend(bufferObject);
|
backendBufferObject->SyncToBackend(bufferObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyncNeccessaryBuffers(Bool includeIBO = false, Bool includeIndirectBuffer = false) {
|
void SyncNeccessaryBuffers(Bool includeIBO = false, Bool includeIndirectBuffer = false) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
g_backendBufferObjects.CollectGarbageIfNeeded();
|
|
||||||
|
|
||||||
// All buffers we need are:
|
// All buffers we need are:
|
||||||
// 1.VBO 2.IBO (if needed) 3.UBO 4.IndirectBuffer (if needed) 5.SSBO (TODO)
|
// 1.VBO 2.IBO (if needed) 3.UBO 4.IndirectBuffer (if needed) 5.SSBO (TODO)
|
||||||
// PBO is not needed since it should be handled in frontend
|
// PBO is not needed since it should be handled in frontend
|
||||||
|
|
||||||
|
// static Vector<SharedPtr<MG_State::GLState::BufferObject>> buffersToSync;
|
||||||
|
// buffersToSync.clear();
|
||||||
|
|
||||||
const auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
|
const auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
|
||||||
if (!currentVAOObject) {
|
if (!currentVAOObject) {
|
||||||
MGLOG_E("No VAO is currently bound, cannot sync necessary buffers.");
|
MGLOG_E("No VAO is currently bound, cannot sync necessary buffers.");
|
||||||
@@ -124,7 +126,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// VBO
|
// VBO
|
||||||
for (const auto& attrib : currentVAOObject->GetAllAttributes()) {
|
for (const auto& attrib : currentVAOObject->GetAllAttributes()) {
|
||||||
if (!attrib.Enabled) continue;
|
if (!attrib.Enabled) continue;
|
||||||
auto& bufferObject = attrib.Buffer;
|
auto bufferObject = attrib.Buffer;
|
||||||
if (bufferObject) {
|
if (bufferObject) {
|
||||||
CreateAndSyncBufferObject(bufferObject);
|
CreateAndSyncBufferObject(bufferObject);
|
||||||
}
|
}
|
||||||
@@ -132,7 +134,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// IBO
|
// IBO
|
||||||
if (includeIBO) {
|
if (includeIBO) {
|
||||||
auto& possibleIBO = currentVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
|
auto possibleIBO = currentVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
|
||||||
if (possibleIBO) {
|
if (possibleIBO) {
|
||||||
CreateAndSyncBufferObject(possibleIBO);
|
CreateAndSyncBufferObject(possibleIBO);
|
||||||
}
|
}
|
||||||
@@ -140,7 +142,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// Indirect Buffer Object
|
// Indirect Buffer Object
|
||||||
if (includeIndirectBuffer) {
|
if (includeIndirectBuffer) {
|
||||||
auto& possibleIndirectBuffer =
|
auto possibleIndirectBuffer =
|
||||||
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
|
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
|
||||||
if (possibleIndirectBuffer) {
|
if (possibleIndirectBuffer) {
|
||||||
CreateAndSyncBufferObject(possibleIndirectBuffer);
|
CreateAndSyncBufferObject(possibleIndirectBuffer);
|
||||||
@@ -151,7 +153,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
auto uboBindingPointCnt = MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform);
|
auto uboBindingPointCnt = MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform);
|
||||||
for (SizeT i = 0; i < uboBindingPointCnt; ++i) {
|
for (SizeT i = 0; i < uboBindingPointCnt; ++i) {
|
||||||
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, i);
|
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, i);
|
||||||
auto& obj = point.GetBoundObject();
|
auto obj = point.GetBoundObject();
|
||||||
if (obj) {
|
if (obj) {
|
||||||
CreateAndSyncBufferObject(obj);
|
CreateAndSyncBufferObject(obj);
|
||||||
}
|
}
|
||||||
@@ -164,49 +166,48 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
g_backendVertexArrayObjects.CollectGarbageIfNeeded();
|
auto currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
|
||||||
|
|
||||||
auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
|
|
||||||
if (!currentVAOObject) {
|
if (!currentVAOObject) {
|
||||||
MGLOG_E("No VAO is currently bound, cannot sync current VAO.");
|
MGLOG_E("No VAO is currently bound, cannot sync current VAO.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& backendVAOIt = g_backendVertexArrayObjects.find(currentVAOObject.get());
|
const auto& backendVAOIt = g_backendVertexArrayObjects.find(currentVAOObject);
|
||||||
Bool exist = (backendVAOIt != g_backendVertexArrayObjects.end());
|
SharedPtr<VertexArrayImpl::BackendVertexArrayObject> backendVAOObject;
|
||||||
auto& backendObj = exist ? backendVAOIt->second : g_backendVertexArrayObjects.GetOrCreate(currentVAOObject);
|
if (backendVAOIt == g_backendVertexArrayObjects.end()) {
|
||||||
if (!exist) {
|
backendVAOObject = MakeShared<VertexArrayImpl::BackendVertexArrayObject>();
|
||||||
backendObj = MakeShared<VertexArrayImpl::BackendVertexArrayObject>();
|
g_backendVertexArrayObjects[currentVAOObject] = backendVAOObject;
|
||||||
|
} else {
|
||||||
|
backendVAOObject = backendVAOIt->second;
|
||||||
}
|
}
|
||||||
backendObj->SyncToBackend(currentVAOObject);
|
backendVAOObject->SyncToBackend(currentVAOObject);
|
||||||
}
|
}
|
||||||
} // namespace VertexArrayImpl
|
} // namespace VertexArrayImpl
|
||||||
|
|
||||||
namespace TextureImpl {
|
namespace TextureImpl {
|
||||||
SharedPtr<BackendTextureObject>& SyncTextureObjectToBackend(
|
SharedPtr<BackendTextureObject> SyncTextureObjectToBackend(
|
||||||
const SharedPtr<MG_State::GLState::ITextureObject>& textureObject) {
|
SharedPtr<MG_State::GLState::ITextureObject>& textureObject) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
const auto& backendTextureIt = g_backendTextureObjects.find(textureObject.get());
|
const auto& backendTextureIt = g_backendTextureObjects.find(textureObject);
|
||||||
Bool exist = (backendTextureIt != g_backendTextureObjects.end());
|
SharedPtr<BackendTextureObject> backendTextureObject;
|
||||||
auto& backendObj = exist ? backendTextureIt->second : g_backendTextureObjects.GetOrCreate(textureObject);
|
if (backendTextureIt == g_backendTextureObjects.end()) {
|
||||||
if (!exist) {
|
backendTextureObject = MakeShared<BackendTextureObject>();
|
||||||
backendObj = MakeShared<BackendTextureObject>();
|
g_backendTextureObjects[textureObject] = backendTextureObject;
|
||||||
|
} else {
|
||||||
|
backendTextureObject = backendTextureIt->second;
|
||||||
}
|
}
|
||||||
backendObj->SyncTextureParamsToBackend(textureObject);
|
backendTextureObject->SyncTextureParamsToBackend(textureObject);
|
||||||
backendObj->SyncBuiltinSamplerToBackend(textureObject);
|
backendTextureObject->SyncBuiltinSamplerToBackend(textureObject);
|
||||||
backendObj->SyncMipmapsToBackend(textureObject);
|
backendTextureObject->SyncMipmapsToBackend(textureObject);
|
||||||
|
return backendTextureObject;
|
||||||
return backendObj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyncNeccessaryTextures() {
|
void SyncNeccessaryTextures() {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
g_backendTextureObjects.CollectGarbageIfNeeded();
|
|
||||||
|
|
||||||
// All textures we need are:
|
// All textures we need are:
|
||||||
// 1. textures bound to texture units (TODO: only sync ones that are used in current program)
|
// 1. textures bound to texture units (TODO: only sync ones that are used in current program)
|
||||||
// 2. textures used in current FBO
|
// 2. textures used in current FBO
|
||||||
@@ -215,7 +216,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
for (int index = 0; index < MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; ++index) {
|
for (int index = 0; index < MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; ++index) {
|
||||||
auto& unit = MG_State::pGLContext->GetTextureUnitObject(index);
|
auto& unit = MG_State::pGLContext->GetTextureUnitObject(index);
|
||||||
for (const auto& bindingSlot : unit.GetAllBindingSlots()) {
|
for (const auto& bindingSlot : unit.GetAllBindingSlots()) {
|
||||||
auto& textureObject = bindingSlot.GetBoundObject();
|
auto textureObject = bindingSlot.GetBoundObject();
|
||||||
if (textureObject) {
|
if (textureObject) {
|
||||||
SyncTextureObjectToBackend(textureObject);
|
SyncTextureObjectToBackend(textureObject);
|
||||||
}
|
}
|
||||||
@@ -227,7 +228,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
if (currentFBO) {
|
if (currentFBO) {
|
||||||
for (const auto& attachment : currentFBO->GetAllAttachmentObjects()) {
|
for (const auto& attachment : currentFBO->GetAllAttachmentObjects()) {
|
||||||
if (!attachment.IsTexture()) continue;
|
if (!attachment.IsTexture()) continue;
|
||||||
auto& textureObject = attachment.GetTexture();
|
auto textureObject = attachment.GetTexture();
|
||||||
if (textureObject) {
|
if (textureObject) {
|
||||||
SyncTextureObjectToBackend(textureObject);
|
SyncTextureObjectToBackend(textureObject);
|
||||||
}
|
}
|
||||||
@@ -241,20 +242,16 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
g_backendFramebufferObjects.CollectGarbageIfNeeded();
|
|
||||||
TextureImpl::g_backendTextureObjects.CollectGarbageIfNeeded();
|
|
||||||
RenderbufferImpl::g_backendRenderbufferObjects.CollectGarbageIfNeeded();
|
|
||||||
|
|
||||||
const FramebufferTarget fboTargets[] = {FramebufferTarget::Draw, FramebufferTarget::Read};
|
const FramebufferTarget fboTargets[] = {FramebufferTarget::Draw, FramebufferTarget::Read};
|
||||||
|
|
||||||
MG_State::GLState::FramebufferObject* lastUpdatedFBO = nullptr;
|
MG_State::GLState::FramebufferObject* lastUpdatedFBO = nullptr;
|
||||||
|
|
||||||
for (auto& target : fboTargets) {
|
for (auto target : fboTargets) {
|
||||||
auto& slot = MG_State::pGLContext->GetFramebufferBindingSlot(target);
|
auto slot = MG_State::pGLContext->GetFramebufferBindingSlot(target);
|
||||||
auto version = slot.GetVersion();
|
auto version = slot.GetVersion();
|
||||||
if (version == g_fboBindVersions[SizeT(target)]) continue;
|
if (version == g_fboBindVersions[SizeT(target)]) continue;
|
||||||
|
|
||||||
auto& currentFBO = slot.GetBoundObject();
|
auto currentFBO = slot.GetBoundObject();
|
||||||
|
|
||||||
if (!currentFBO) {
|
if (!currentFBO) {
|
||||||
MGLOG_E("No FBO is currently bound, cannot sync current FBO.");
|
MGLOG_E("No FBO is currently bound, cannot sync current FBO.");
|
||||||
@@ -266,18 +263,20 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentFBO.get() == lastUpdatedFBO) {
|
const auto& backendFBOIt = g_backendFramebufferObjects.find(currentFBO);
|
||||||
MGLOG_D("Draw FBO and read FBO are the same, skipping sync.");
|
SharedPtr<BackendFramebufferObject> backendFBOObject;
|
||||||
continue;
|
if (backendFBOIt == g_backendFramebufferObjects.end()) {
|
||||||
|
backendFBOObject = MakeShared<BackendFramebufferObject>();
|
||||||
|
g_backendFramebufferObjects[currentFBO] = backendFBOObject;
|
||||||
|
} else {
|
||||||
|
backendFBOObject = backendFBOIt->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& backendFBOIt = g_backendFramebufferObjects.find(currentFBO.get());
|
if (currentFBO.get() == lastUpdatedFBO) {
|
||||||
Bool exist = (backendFBOIt != g_backendFramebufferObjects.end());
|
MGLOG_D("Draw FBO and read FBO are the same, skipping sync.");
|
||||||
auto& backendObj = exist ? backendFBOIt->second : g_backendFramebufferObjects.GetOrCreate(currentFBO);
|
} else {
|
||||||
if (!exist) {
|
backendFBOObject->SyncToBackend(currentFBO, target);
|
||||||
backendObj = MakeShared<BackendFramebufferObject>();
|
|
||||||
}
|
}
|
||||||
backendObj->SyncToBackend(currentFBO, target);
|
|
||||||
|
|
||||||
lastUpdatedFBO = currentFBO.get();
|
lastUpdatedFBO = currentFBO.get();
|
||||||
}
|
}
|
||||||
@@ -467,23 +466,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
g_backendProgramObjects.CollectGarbageIfNeeded();
|
auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||||
SamplerImpl::g_backendSamplerObjects.CollectGarbageIfNeeded();
|
|
||||||
|
|
||||||
auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
|
||||||
if (!currentProgram || !currentProgram->GetLinkStatus()) {
|
if (!currentProgram || !currentProgram->GetLinkStatus()) {
|
||||||
g_GLESFuncs.glUseProgram(0);
|
g_GLESFuncs.glUseProgram(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto& backendProgramIt = g_backendProgramObjects.find(currentProgram.get());
|
const auto& backendProgramIt = g_backendProgramObjects.find(currentProgram);
|
||||||
Bool exist = (backendProgramIt != g_backendProgramObjects.end());
|
SharedPtr<BackendProgramObjectImpl> backendProgram;
|
||||||
auto& backendObj = exist ? backendProgramIt->second : g_backendProgramObjects.GetOrCreate(currentProgram);
|
if (backendProgramIt == g_backendProgramObjects.end()) {
|
||||||
if (!exist) {
|
backendProgram = MakeShared<BackendProgramObjectImpl>();
|
||||||
backendObj = MakeShared<BackendProgramObjectImpl>();
|
g_backendProgramObjects[currentProgram] = backendProgram;
|
||||||
backendObj->SyncToBackend(currentProgram);
|
backendProgram->SyncToBackend(currentProgram);
|
||||||
} else {
|
} else {
|
||||||
if (!backendObj->GetBackendProgramId()) {
|
backendProgram = backendProgramIt->second;
|
||||||
backendObj->SyncToBackend(currentProgram);
|
if (!backendProgram->GetBackendProgramId()) {
|
||||||
|
backendProgram->SyncToBackend(currentProgram);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -498,7 +495,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
const auto& currentFBO = slot.GetBoundObject();
|
const auto& currentFBO = slot.GetBoundObject();
|
||||||
if (currentFBO && currentFBO != MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO) {
|
if (currentFBO && currentFBO != MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO) {
|
||||||
const auto& backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find(currentFBO.get());
|
const auto& backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find(currentFBO);
|
||||||
if (backendFBOIt != FramebufferImpl::g_backendFramebufferObjects.end()) {
|
if (backendFBOIt != FramebufferImpl::g_backendFramebufferObjects.end()) {
|
||||||
backendFBOIt->second->Bind(target);
|
backendFBOIt->second->Bind(target);
|
||||||
} else {
|
} else {
|
||||||
@@ -531,7 +528,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
#endif
|
#endif
|
||||||
const auto& currentVAO = MG_State::pGLContext->GetBoundVertexArray();
|
const auto& currentVAO = MG_State::pGLContext->GetBoundVertexArray();
|
||||||
if (currentVAO) {
|
if (currentVAO) {
|
||||||
const auto& backendVAOIt = VertexArrayImpl::g_backendVertexArrayObjects.find(currentVAO.get());
|
const auto& backendVAOIt = VertexArrayImpl::g_backendVertexArrayObjects.find(currentVAO);
|
||||||
if (backendVAOIt != VertexArrayImpl::g_backendVertexArrayObjects.end()) {
|
if (backendVAOIt != VertexArrayImpl::g_backendVertexArrayObjects.end()) {
|
||||||
backendVAOIt->second->Bind();
|
backendVAOIt->second->Bind();
|
||||||
}
|
}
|
||||||
@@ -559,7 +556,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MG_Util::ConvertTextureTargetToString(target).c_str());
|
MG_Util::ConvertTextureTargetToString(target).c_str());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
||||||
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) continue;
|
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) continue;
|
||||||
|
|
||||||
GLenum targetGL = MG_Util::ConvertTextureTargetToGLEnum(target);
|
GLenum targetGL = MG_Util::ConvertTextureTargetToGLEnum(target);
|
||||||
@@ -569,7 +566,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// Bind sampler object if necessary
|
// Bind sampler object if necessary
|
||||||
const auto& samplerObject = textureUnit.GetSamplerObject();
|
const auto& samplerObject = textureUnit.GetSamplerObject();
|
||||||
if (samplerObject) {
|
if (samplerObject) {
|
||||||
const auto& backendSamplerIt = SamplerImpl::g_backendSamplerObjects.find(samplerObject.get());
|
const auto& backendSamplerIt = SamplerImpl::g_backendSamplerObjects.find(samplerObject);
|
||||||
if (backendSamplerIt != SamplerImpl::g_backendSamplerObjects.end()) {
|
if (backendSamplerIt != SamplerImpl::g_backendSamplerObjects.end()) {
|
||||||
backendSamplerIt->second->Bind(unit);
|
backendSamplerIt->second->Bind(unit);
|
||||||
}
|
}
|
||||||
@@ -584,7 +581,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedNC("BindCurrentProgram", TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedNC("BindCurrentProgram", TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
const auto& backendProgramIt = PrgramImpl::g_backendProgramObjects.find(currentProgram.get());
|
const auto& backendProgramIt = PrgramImpl::g_backendProgramObjects.find(currentProgram);
|
||||||
if (backendProgramIt != PrgramImpl::g_backendProgramObjects.end()) {
|
if (backendProgramIt != PrgramImpl::g_backendProgramObjects.end()) {
|
||||||
backendProgramIt->second->Use();
|
backendProgramIt->second->Use();
|
||||||
auto backendProgramId = backendProgramIt->second->GetBackendProgramId();
|
auto backendProgramId = backendProgramIt->second->GetBackendProgramId();
|
||||||
@@ -626,11 +623,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// Connect buffer to backend binding point
|
// Connect buffer to backend binding point
|
||||||
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, binding);
|
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, binding);
|
||||||
auto& bufferObj = point.GetBoundObject();
|
auto bufferObj = point.GetBoundObject();
|
||||||
auto range = point.GetRange();
|
auto range = point.GetRange();
|
||||||
|
|
||||||
if (bufferObj) {
|
if (bufferObj) {
|
||||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObj.get());
|
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObj);
|
||||||
if (backendBufferIt != BufferImpl::g_backendBufferObjects.end()) {
|
if (backendBufferIt != BufferImpl::g_backendBufferObjects.end()) {
|
||||||
const auto& backendBufferObject = backendBufferIt->second;
|
const auto& backendBufferObject = backendBufferIt->second;
|
||||||
backendBufferObject->Bind(GL_UNIFORM_BUFFER);
|
backendBufferObject->Bind(GL_UNIFORM_BUFFER);
|
||||||
@@ -638,9 +635,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_GLESFuncs.glBindBufferBase(GL_UNIFORM_BUFFER, lastUBOBinding,
|
g_GLESFuncs.glBindBufferBase(GL_UNIFORM_BUFFER, lastUBOBinding,
|
||||||
backendBufferObject->GetBackendBufferId());
|
backendBufferObject->GetBackendBufferId());
|
||||||
} else {
|
} else {
|
||||||
g_GLESFuncs.glBindBufferRange(
|
g_GLESFuncs.glBindBufferRange(GL_UNIFORM_BUFFER, lastUBOBinding,
|
||||||
GL_UNIFORM_BUFFER, lastUBOBinding, backendBufferObject->GetBackendBufferId(),
|
backendBufferObject->GetBackendBufferId(),
|
||||||
(GLintptr)range.start, (GLintptr)(range.end - range.start));
|
range.start, range.end - range.start);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
MGLOG_E("No backend buffer found for UBO binding, cannot bind UBO.");
|
MGLOG_E("No backend buffer found for UBO binding, cannot bind UBO.");
|
||||||
@@ -663,18 +660,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
backendProgramIt->second->GetBackendProgramId(), name.c_str());
|
backendProgramIt->second->GetBackendProgramId(), name.c_str());
|
||||||
g_GLESFuncs.glUniform1i(locAtBackend, unit);
|
g_GLESFuncs.glUniform1i(locAtBackend, unit);
|
||||||
|
|
||||||
auto& samplerObject = MG_State::pGLContext->GetTextureUnitObject(unit).GetSamplerObject();
|
auto samplerObject = MG_State::pGLContext->GetTextureUnitObject(unit).GetSamplerObject();
|
||||||
|
|
||||||
if (samplerObject) {
|
if (samplerObject) {
|
||||||
const auto& backendSamplerIt =
|
const auto& backendSamplerIt = SamplerImpl::g_backendSamplerObjects.find(samplerObject);
|
||||||
SamplerImpl::g_backendSamplerObjects.find(samplerObject.get());
|
SharedPtr<SamplerImpl::BackendSamplerObject> backendSamplerObject;
|
||||||
Bool exist = (backendSamplerIt != SamplerImpl::g_backendSamplerObjects.end());
|
if (backendSamplerIt == SamplerImpl::g_backendSamplerObjects.end()) {
|
||||||
auto& backendObj = exist ? backendSamplerIt->second
|
backendSamplerObject = MakeShared<SamplerImpl::BackendSamplerObject>();
|
||||||
: SamplerImpl::g_backendSamplerObjects.GetOrCreate(samplerObject);
|
SamplerImpl::g_backendSamplerObjects[samplerObject] = backendSamplerObject;
|
||||||
if (!exist) {
|
} else {
|
||||||
backendObj = MakeShared<SamplerImpl::BackendSamplerObject>();
|
backendSamplerObject = backendSamplerIt->second;
|
||||||
}
|
}
|
||||||
backendObj->SyncToBackend(samplerObject);
|
backendSamplerObject->SyncToBackend(samplerObject);
|
||||||
} else {
|
} else {
|
||||||
SamplerImpl::UnbindSampler(unit);
|
SamplerImpl::UnbindSampler(unit);
|
||||||
}
|
}
|
||||||
@@ -848,29 +845,30 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
|
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
|
||||||
DebugImpl::OpenGLScopeMarker marker(__func__);
|
DebugImpl::OpenGLScopeMarker marker(__func__);
|
||||||
#endif
|
#endif
|
||||||
|
DebugImpl::ErrorLopper errorLopper;
|
||||||
|
|
||||||
TextureImpl::SyncNeccessaryTextures();
|
TextureImpl::SyncNeccessaryTextures();
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
FramebufferImpl::SyncCurrentFBO();
|
FramebufferImpl::SyncCurrentFBO();
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
RenderStateImpl::SyncRenderState();
|
RenderStateImpl::SyncRenderState();
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
|
|
||||||
BindCurrentFBO(FramebufferTarget::Draw);
|
BindCurrentFBO(FramebufferTarget::Draw);
|
||||||
BindCurrentFBO(FramebufferTarget::Read);
|
BindCurrentFBO(FramebufferTarget::Read);
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
MGLOG_D("ES %s(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)", __func__, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0,
|
MGLOG_D("ES %s(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)", __func__, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0,
|
||||||
dstX1, dstY1, mask, MG_Util::ConvertGLEnumToString(filter).c_str());
|
dstX1, dstY1, mask, MG_Util::ConvertGLEnumToString(filter).c_str());
|
||||||
g_GLESFuncs.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
g_GLESFuncs.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -897,14 +895,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MG_Util::ConvertTextureTargetToString(textureTarget).c_str());
|
MG_Util::ConvertTextureTargetToString(textureTarget).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
||||||
Bool exist = (backendTextureIt != TextureImpl::g_backendTextureObjects.end());
|
SharedPtr<TextureImpl::BackendTextureObject> backendTextureObject;
|
||||||
auto& backendObj =
|
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
||||||
exist ? backendTextureIt->second : TextureImpl::g_backendTextureObjects.GetOrCreate(textureObject);
|
backendTextureObject = MakeShared<TextureImpl::BackendTextureObject>();
|
||||||
if (!exist) {
|
TextureImpl::g_backendTextureObjects[textureObject] = backendTextureObject;
|
||||||
backendObj = MakeShared<TextureImpl::BackendTextureObject>();
|
} else {
|
||||||
|
backendTextureObject = backendTextureIt->second;
|
||||||
}
|
}
|
||||||
backendObj->Bind(target, unit);
|
backendTextureObject->Bind(target, unit);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -954,15 +953,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
DebugImpl::ErrorLopper errorLopper;
|
DebugImpl::ErrorLopper errorLopper;
|
||||||
MGLOG_D("%s: Backend", __func__);
|
MGLOG_D("%s: Backend", __func__);
|
||||||
TextureImpl::SyncNeccessaryTextures();
|
TextureImpl::SyncNeccessaryTextures();
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
FramebufferImpl::SyncCurrentFBO();
|
FramebufferImpl::SyncCurrentFBO();
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
RenderStateImpl::SyncRenderState();
|
RenderStateImpl::SyncRenderState();
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
if (!UpdateTextureBindingAtTarget(target)) return;
|
if (!UpdateTextureBindingAtTarget(target)) return;
|
||||||
@@ -970,10 +969,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// Bind necessary FBO and texture
|
// Bind necessary FBO and texture
|
||||||
BindCurrentFBO(FramebufferTarget::Read);
|
BindCurrentFBO(FramebufferTarget::Read);
|
||||||
Uint activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
|
Uint activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
|
||||||
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject((Int)activeTextureUnit)
|
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit)
|
||||||
.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target))
|
.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target))
|
||||||
.GetBoundObject();
|
.GetBoundObject();
|
||||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
||||||
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
||||||
MGLOG_E("CopyTexSubImage2D: No backend texture found for texture %u.",
|
MGLOG_E("CopyTexSubImage2D: No backend texture found for texture %u.",
|
||||||
textureObject ? textureObject->GetExternalIndex() : 0);
|
textureObject ? textureObject->GetExternalIndex() : 0);
|
||||||
@@ -999,19 +998,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
if (!isDepthFormat) {
|
if (!isDepthFormat) {
|
||||||
g_GLESFuncs.glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
|
g_GLESFuncs.glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
MGLOG_D("%s: Backend depth", __func__);
|
MGLOG_D("%s: Backend depth", __func__);
|
||||||
g_GLESFuncs.glTexImage2D(target, level, (GLint)internalformat, width, height, border, format, type,
|
g_GLESFuncs.glTexImage2D(target, level, (GLint)internalformat, width, height, border, format, type,
|
||||||
nullptr);
|
nullptr);
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
|
|
||||||
auto currentTex = (GLint)backendTextureIt->second->GetBackendTextureId();
|
GLint currentTex = backendTextureIt->second->GetBackendTextureId();
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1027,7 +1026,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_GLESFuncs.glBlitFramebuffer(x, y, x + width, y + height, 0, 0, width, height,
|
g_GLESFuncs.glBlitFramebuffer(x, y, x + width, y + height, 0, 0, width, height,
|
||||||
GL_DEPTH_BUFFER_BIT | (isStencilFormat ? GL_STENCIL_BUFFER_BIT : 0),
|
GL_DEPTH_BUFFER_BIT | (isStencilFormat ? GL_STENCIL_BUFFER_BIT : 0),
|
||||||
GL_NEAREST);
|
GL_NEAREST);
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1042,15 +1041,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
MGLOG_D("%s: Backend", __func__);
|
MGLOG_D("%s: Backend", __func__);
|
||||||
TextureImpl::SyncNeccessaryTextures();
|
TextureImpl::SyncNeccessaryTextures();
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
FramebufferImpl::SyncCurrentFBO();
|
FramebufferImpl::SyncCurrentFBO();
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
RenderStateImpl::SyncRenderState();
|
RenderStateImpl::SyncRenderState();
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1058,11 +1057,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// Bind necessary FBO and texture
|
// Bind necessary FBO and texture
|
||||||
BindCurrentFBO(FramebufferTarget::Read);
|
BindCurrentFBO(FramebufferTarget::Read);
|
||||||
auto activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
|
Uint activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
|
||||||
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit)
|
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit)
|
||||||
.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target))
|
.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target))
|
||||||
.GetBoundObject();
|
.GetBoundObject();
|
||||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
||||||
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
||||||
MGLOG_E("CopyTexSubImage2D: No backend texture found for texture %u.",
|
MGLOG_E("CopyTexSubImage2D: No backend texture found for texture %u.",
|
||||||
textureObject ? textureObject->GetExternalIndex() : 0);
|
textureObject ? textureObject->GetExternalIndex() : 0);
|
||||||
@@ -1070,12 +1069,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
backendTextureIt->second->Bind(target, activeTextureUnit);
|
backendTextureIt->second->Bind(target, activeTextureUnit);
|
||||||
|
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
GLenum internalFormat;
|
GLenum internalFormat;
|
||||||
g_GLESFuncs.glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&internalFormat);
|
g_GLESFuncs.glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&internalFormat);
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
auto mgInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalFormat);
|
auto mgInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalFormat);
|
||||||
@@ -1085,19 +1084,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
if (!isDepthFormat) {
|
if (!isDepthFormat) {
|
||||||
g_GLESFuncs.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
|
g_GLESFuncs.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
MGLOG_D("%s: Backend depth", __func__);
|
MGLOG_D("%s: Backend depth", __func__);
|
||||||
auto currentTex = backendTextureIt->second->GetBackendTextureId();
|
GLint currentTex = backendTextureIt->second->GetBackendTextureId();
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
GLenum attachment = isStencilFormat ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
|
GLenum attachment = isStencilFormat ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
|
||||||
TempFBOBinder tempFBOBinder(false);
|
TempFBOBinder tempFBOBinder(false);
|
||||||
g_GLESFuncs.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target, currentTex, level);
|
g_GLESFuncs.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target, currentTex, level);
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
if (g_GLESFuncs.glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
if (g_GLESFuncs.glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
@@ -1108,7 +1107,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_GLESFuncs.glBlitFramebuffer(
|
g_GLESFuncs.glBlitFramebuffer(
|
||||||
x, y, x + width, y + height, xoffset, yoffset, xoffset + width, yoffset + height,
|
x, y, x + width, y + height, xoffset, yoffset, xoffset + width, yoffset + height,
|
||||||
GL_DEPTH_BUFFER_BIT | (isStencilFormat ? GL_STENCIL_BUFFER_BIT : 0), GL_NEAREST);
|
GL_DEPTH_BUFFER_BIT | (isStencilFormat ? GL_STENCIL_BUFFER_BIT : 0), GL_NEAREST);
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1121,8 +1120,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
auto unitIndex = MG_State::pGLContext->GetActiveTextureUnit();
|
auto unitIndex = MG_State::pGLContext->GetActiveTextureUnit();
|
||||||
auto& unit = MG_State::pGLContext->GetTextureUnitObject(unitIndex);
|
auto& unit = MG_State::pGLContext->GetTextureUnitObject(unitIndex);
|
||||||
auto& slot = unit.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target));
|
auto& slot = unit.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target));
|
||||||
auto& texture = slot.GetBoundObject();
|
auto texture = slot.GetBoundObject();
|
||||||
auto& backendTexture = TextureImpl::SyncTextureObjectToBackend(texture);
|
auto backendTexture = TextureImpl::SyncTextureObjectToBackend(texture);
|
||||||
|
|
||||||
backendTexture->Bind(target, unitIndex);
|
backendTexture->Bind(target, unitIndex);
|
||||||
g_GLESFuncs.glGenerateMipmap(target);
|
g_GLESFuncs.glGenerateMipmap(target);
|
||||||
@@ -1185,7 +1184,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
PixelStoreParameters m_prevParams;
|
PixelStoreParameters m_prevParams;
|
||||||
|
|
||||||
static PixelStoreParameters QueryCurrentGLPixelStoreParams(Bool isUnpack) {
|
PixelStoreParameters QueryCurrentGLPixelStoreParams(Bool isUnpack) {
|
||||||
PixelStoreParameters p;
|
PixelStoreParameters p;
|
||||||
if (!isUnpack) {
|
if (!isUnpack) {
|
||||||
g_GLESFuncs.glGetIntegerv(GL_PACK_ALIGNMENT, (GLint*)&p.Alignment);
|
g_GLESFuncs.glGetIntegerv(GL_PACK_ALIGNMENT, (GLint*)&p.Alignment);
|
||||||
@@ -1215,7 +1214,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Sync(Bool isUnpack, const PixelStoreParameters& params) {
|
void Sync(Bool isUnpack, const PixelStoreParameters& params) {
|
||||||
if (!isUnpack) {
|
if (!isUnpack) {
|
||||||
g_GLESFuncs.glPixelStorei(GL_PACK_ALIGNMENT, params.Alignment);
|
g_GLESFuncs.glPixelStorei(GL_PACK_ALIGNMENT, params.Alignment);
|
||||||
g_GLESFuncs.glPixelStorei(GL_PACK_ROW_LENGTH, params.RowLength);
|
g_GLESFuncs.glPixelStorei(GL_PACK_ROW_LENGTH, params.RowLength);
|
||||||
@@ -1272,7 +1271,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle PBO
|
// Handle PBO
|
||||||
auto& pixelPackBufferObject =
|
auto pixelPackBufferObject =
|
||||||
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||||
Bool usePBO;
|
Bool usePBO;
|
||||||
GLuint prevPixelPackBuffer = 0;
|
GLuint prevPixelPackBuffer = 0;
|
||||||
@@ -1280,7 +1279,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
BufferImpl::CreateAndSyncBufferObject(pixelPackBufferObject);
|
BufferImpl::CreateAndSyncBufferObject(pixelPackBufferObject);
|
||||||
MGLOG_D("ReadPixels: Using PBO %u", pixelPackBufferObject->GetExternalIndex());
|
MGLOG_D("ReadPixels: Using PBO %u", pixelPackBufferObject->GetExternalIndex());
|
||||||
usePBO = true;
|
usePBO = true;
|
||||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(pixelPackBufferObject.get());
|
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(pixelPackBufferObject);
|
||||||
|
|
||||||
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
|
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
|
||||||
MGLOG_E("ReadPixels: No backend buffer found for PBO %u.",
|
MGLOG_E("ReadPixels: No backend buffer found for PBO %u.",
|
||||||
@@ -1300,8 +1299,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
if (usePBO) {
|
if (usePBO) {
|
||||||
// pull back to client memory if PBO is used
|
// pull back to client memory if PBO is used
|
||||||
MGLOG_D("ReadPixels: PBO used, mapping buffer to client memory");
|
MGLOG_D("ReadPixels: PBO used, mapping buffer to client memory");
|
||||||
GLvoid* pboMappedPtr = g_GLESFuncs.glMapBufferRange(
|
GLvoid* pboMappedPtr = g_GLESFuncs.glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0,
|
||||||
GL_PIXEL_PACK_BUFFER, 0, (GLsizeiptr)pixelPackBufferObject->GetSize(), GL_MAP_READ_BIT);
|
pixelPackBufferObject->GetSize(), GL_MAP_READ_BIT);
|
||||||
if (pboMappedPtr) {
|
if (pboMappedPtr) {
|
||||||
MGLOG_D("ReadPixels: Copying data from PBO to client memory");
|
MGLOG_D("ReadPixels: Copying data from PBO to client memory");
|
||||||
SizeT size = pixelPackBufferObject->GetSize();
|
SizeT size = pixelPackBufferObject->GetSize();
|
||||||
@@ -1346,7 +1345,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MGLOG_D("GetTexImage: SyncCurrentFBO()");
|
MGLOG_D("GetTexImage: SyncCurrentFBO()");
|
||||||
FramebufferImpl::SyncCurrentFBO();
|
FramebufferImpl::SyncCurrentFBO();
|
||||||
|
|
||||||
auto activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
|
Uint activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
|
||||||
MGLOG_D("GetTexImage: active texture unit = %u", activeTextureUnit);
|
MGLOG_D("GetTexImage: active texture unit = %u", activeTextureUnit);
|
||||||
|
|
||||||
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit)
|
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit)
|
||||||
@@ -1356,7 +1355,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MGLOG_D("GetTexImage: bound texture object = %p (name=%u)", textureObject.get(),
|
MGLOG_D("GetTexImage: bound texture object = %p (name=%u)", textureObject.get(),
|
||||||
textureObject ? textureObject->GetExternalIndex() : 0);
|
textureObject ? textureObject->GetExternalIndex() : 0);
|
||||||
|
|
||||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
||||||
|
|
||||||
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
||||||
MGLOG_E("GetTexImage: No backend texture found for texture %u.",
|
MGLOG_E("GetTexImage: No backend texture found for texture %u.",
|
||||||
@@ -1384,14 +1383,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
|
|
||||||
MGLOG_D("GetTexImage: Applying TempPixelStoreParameterSync (PACK)");
|
MGLOG_D("GetTexImage: Applying TempPixelStoreParameterSync (PACK)");
|
||||||
TempPixelStoreParameterSync tempPackParamsSync(false);
|
TempPixelStoreParameterSync tempPackParamsSync(false);
|
||||||
|
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1405,7 +1404,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
||||||
|
|
||||||
auto& levelRange = textureMipmapObject->GetLevelRange();
|
auto levelRange = textureMipmapObject->GetLevelRange();
|
||||||
MGLOG_D("GetTexImage: mipmap level range = [%d, %d)", levelRange.x(), levelRange.y());
|
MGLOG_D("GetTexImage: mipmap level range = [%d, %d)", levelRange.x(), levelRange.y());
|
||||||
|
|
||||||
if (level < levelRange.x() || level >= levelRange.y()) {
|
if (level < levelRange.x() || level >= levelRange.y()) {
|
||||||
@@ -1422,7 +1421,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MGLOG_D("GetTexImage: mip level %d size = %dx%d", level, size.x(), size.y());
|
MGLOG_D("GetTexImage: mip level %d size = %dx%d", level, size.x(), size.y());
|
||||||
|
|
||||||
// Handle PBO
|
// Handle PBO
|
||||||
auto& pixelPackBufferObject =
|
auto pixelPackBufferObject =
|
||||||
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||||
Bool usePBO;
|
Bool usePBO;
|
||||||
GLuint prevPixelPackBuffer = 0;
|
GLuint prevPixelPackBuffer = 0;
|
||||||
@@ -1430,7 +1429,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
BufferImpl::CreateAndSyncBufferObject(pixelPackBufferObject);
|
BufferImpl::CreateAndSyncBufferObject(pixelPackBufferObject);
|
||||||
MGLOG_D("GetTexImage: Using PBO %u", pixelPackBufferObject->GetExternalIndex());
|
MGLOG_D("GetTexImage: Using PBO %u", pixelPackBufferObject->GetExternalIndex());
|
||||||
usePBO = true;
|
usePBO = true;
|
||||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(pixelPackBufferObject.get());
|
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(pixelPackBufferObject);
|
||||||
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
|
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
|
||||||
MGLOG_E("GetTexImage: No backend buffer found for PBO %u.",
|
MGLOG_E("GetTexImage: No backend buffer found for PBO %u.",
|
||||||
pixelPackBufferObject ? pixelPackBufferObject->GetExternalIndex() : 0);
|
pixelPackBufferObject ? pixelPackBufferObject->GetExternalIndex() : 0);
|
||||||
@@ -1444,7 +1443,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MGLOG_D("GetTexImage: Not using PBO");
|
MGLOG_D("GetTexImage: Not using PBO");
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
MGLOG_D("GetTexImage: glReadPixels(0, 0, %d, %d, %s, %s, %p)", size.x(), size.y(),
|
MGLOG_D("GetTexImage: glReadPixels(0, 0, %d, %d, %s, %s, %p)", size.x(), size.y(),
|
||||||
@@ -1452,14 +1451,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
pixels);
|
pixels);
|
||||||
g_GLESFuncs.glReadPixels(0, 0, size.x(), size.y(), esFormat, esType, pixels);
|
g_GLESFuncs.glReadPixels(0, 0, size.x(), size.y(), esFormat, esType, pixels);
|
||||||
|
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
if (usePBO) {
|
if (usePBO) {
|
||||||
// pull back to client memory if PBO is used
|
// pull back to client memory if PBO is used
|
||||||
MGLOG_D("ReadPixels: PBO used, mapping buffer to client memory");
|
MGLOG_D("ReadPixels: PBO used, mapping buffer to client memory");
|
||||||
GLvoid* pboMappedPtr = g_GLESFuncs.glMapBufferRange(
|
GLvoid* pboMappedPtr = g_GLESFuncs.glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0,
|
||||||
GL_PIXEL_PACK_BUFFER, 0, (GLsizeiptr)pixelPackBufferObject->GetSize(), GL_MAP_READ_BIT);
|
pixelPackBufferObject->GetSize(), GL_MAP_READ_BIT);
|
||||||
if (pboMappedPtr) {
|
if (pboMappedPtr) {
|
||||||
MGLOG_D("ReadPixels: Copying data from PBO to client memory");
|
MGLOG_D("ReadPixels: Copying data from PBO to client memory");
|
||||||
SizeT size = pixelPackBufferObject->GetSize();
|
SizeT size = pixelPackBufferObject->GetSize();
|
||||||
@@ -1480,7 +1479,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
MGLOG_D("GetTexImage: finished");
|
MGLOG_D("GetTexImage: finished");
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -41,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
|
||||||
@@ -102,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
|
||||||
@@ -114,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
|
||||||
@@ -127,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;
|
||||||
@@ -135,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;
|
||||||
@@ -157,18 +159,18 @@ 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) {
|
||||||
MGLOG_D("Mapped buffer data successfully for object with ID: %u", m_backendBufferId);
|
MGLOG_D("Mapped buffer data successfully for object with ID: %u", m_backendBufferId);
|
||||||
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 {
|
||||||
@@ -189,7 +191,7 @@ 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
|
||||||
|
|
||||||
@@ -207,21 +209,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendVertexArrayObject::Bind() const {
|
void BackendVertexArrayObject::Bind() {
|
||||||
#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 void 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;
|
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;
|
return;
|
||||||
@@ -231,8 +234,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
backendBufferObject->Bind(GL_ARRAY_BUFFER);
|
backendBufferObject->Bind(GL_ARRAY_BUFFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
@@ -266,7 +268,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
m_syncedAttributeVersions[attribIndex].BufferVersion;
|
m_syncedAttributeVersions[attribIndex].BufferVersion;
|
||||||
if (!needsSyncFormat && !needsSyncBuffer) continue;
|
if (!needsSyncFormat && !needsSyncBuffer) continue;
|
||||||
|
|
||||||
BindAttributeBuffer(attrib);
|
BindAttributeBuffer(attribIndex, attrib);
|
||||||
|
|
||||||
if (!attrib.IsInteger) {
|
if (!attrib.IsInteger) {
|
||||||
g_GLESFuncs.glVertexAttribPointer(
|
g_GLESFuncs.glVertexAttribPointer(
|
||||||
@@ -287,7 +289,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
if (currentIndexBufferVersion != m_syncedIndexBufferVersion) {
|
if (currentIndexBufferVersion != m_syncedIndexBufferVersion) {
|
||||||
const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
|
const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
|
||||||
if (indexBufferBinding) {
|
if (indexBufferBinding) {
|
||||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding.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);
|
||||||
@@ -301,7 +303,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
m_syncedAttributeVersions = allAttributeVersions;
|
m_syncedAttributeVersions = allAttributeVersions;
|
||||||
}
|
}
|
||||||
|
|
||||||
StateBackendObjectRegistry<MG_State::GLState::VertexArrayObject, BackendVertexArrayObject>
|
UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>>
|
||||||
g_backendVertexArrayObjects;
|
g_backendVertexArrayObjects;
|
||||||
} // namespace VertexArrayImpl
|
} // namespace VertexArrayImpl
|
||||||
|
|
||||||
@@ -334,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
|
||||||
@@ -342,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;
|
||||||
@@ -351,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());
|
||||||
@@ -378,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();
|
||||||
@@ -411,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);
|
||||||
@@ -426,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;
|
||||||
@@ -451,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(),
|
||||||
@@ -476,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;
|
||||||
@@ -497,11 +499,10 @@ 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());
|
});
|
||||||
});
|
|
||||||
auto texelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
|
auto texelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
|
||||||
g_GLESFuncs.glTexSubImage2D(glUploadTarget, static_cast<GLint>(level), 0, 0,
|
g_GLESFuncs.glTexSubImage2D(glUploadTarget, static_cast<GLint>(level), 0, 0,
|
||||||
static_cast<GLsizei>(texelSize.x()),
|
static_cast<GLsizei>(texelSize.x()),
|
||||||
@@ -517,7 +518,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
auto* textureBufferObject =
|
auto* textureBufferObject =
|
||||||
static_cast<MG_State::GLState::TextureObjectBuffer*>(stateTextureObject.get());
|
static_cast<MG_State::GLState::TextureObjectBuffer*>(stateTextureObject.get());
|
||||||
auto& slot = textureBufferObject->GetBufferBindingSlot();
|
auto& slot = textureBufferObject->GetBufferBindingSlot();
|
||||||
auto& buffer = slot.GetBoundObject();
|
auto buffer = slot.GetBoundObject();
|
||||||
auto bufferIndex = buffer->GetExternalIndex();
|
auto bufferIndex = buffer->GetExternalIndex();
|
||||||
currentTextureInfo.bufferExternalIndex = bufferIndex;
|
currentTextureInfo.bufferExternalIndex = bufferIndex;
|
||||||
|
|
||||||
@@ -529,13 +530,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// Need to sync texture buffer if not synced yet
|
// Need to sync texture buffer if not synced yet
|
||||||
auto& backendBuffers = BufferImpl::g_backendBufferObjects;
|
auto& backendBuffers = BufferImpl::g_backendBufferObjects;
|
||||||
SharedPtr<BufferImpl::BackendBufferObject> backendBufferObject;
|
SharedPtr<BufferImpl::BackendBufferObject> backendBufferObject;
|
||||||
const auto& backendBufferIt = backendBuffers.find(buffer.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;
|
||||||
}
|
}
|
||||||
@@ -555,7 +553,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
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());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -563,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;
|
||||||
@@ -596,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());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -609,29 +607,28 @@ 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()); \
|
}); \
|
||||||
}); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -648,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;
|
||||||
@@ -686,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());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -699,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());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -723,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());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -733,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());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -763,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 {
|
||||||
@@ -780,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
|
||||||
@@ -790,12 +788,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId);
|
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool SyncAttachmentObject(GLenum glFBOTarget,
|
Bool BackendFramebufferObject::SyncAttachmentObject(
|
||||||
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
|
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();
|
||||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
||||||
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
||||||
MGLOG_E("%s: No backend texture found for FBO attachment, cannot bind texture.", __func__);
|
MGLOG_E("%s: No backend texture found for FBO attachment, cannot bind texture.", __func__);
|
||||||
return false;
|
return false;
|
||||||
@@ -809,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;
|
||||||
}
|
}
|
||||||
@@ -830,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
|
||||||
@@ -859,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;
|
||||||
@@ -898,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)
|
||||||
@@ -934,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();
|
||||||
@@ -950,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.");
|
||||||
@@ -982,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
|
||||||
@@ -1014,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
|
||||||
@@ -1168,7 +1161,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MGLOG_D("Program sync completed. backend ID %u", m_backendProgramId);
|
MGLOG_D("Program sync completed. backend ID %u", m_backendProgramId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendProgramObjectImpl::Use() const {
|
void BackendProgramObjectImpl::Use() {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
@@ -1191,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
|
||||||
@@ -1218,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1264,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
|
||||||
@@ -1279,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 {
|
||||||
@@ -1294,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
|
||||||
@@ -1341,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
|
||||||
|
|||||||
@@ -15,113 +15,19 @@
|
|||||||
#include <MG_State/GLState/Core.h>
|
#include <MG_State/GLState/Core.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectGLES {
|
namespace MobileGL::MG_Backend::DirectGLES {
|
||||||
template <typename StateObject, typename BackendObject>
|
|
||||||
class StateBackendObjectRegistry {
|
|
||||||
public:
|
|
||||||
using StatePtr = SharedPtr<StateObject>;
|
|
||||||
using StateWeakPtr = std::weak_ptr<StateObject>;
|
|
||||||
using BackendPtr = SharedPtr<BackendObject>;
|
|
||||||
using BackendMap = UnorderedMap<StateObject*, BackendPtr>;
|
|
||||||
using StateRefMap = UnorderedMap<StateObject*, StateWeakPtr>;
|
|
||||||
using iterator = typename BackendMap::iterator;
|
|
||||||
using const_iterator = typename BackendMap::const_iterator;
|
|
||||||
|
|
||||||
BackendPtr& GetOrCreate(const StatePtr& stateObj) {
|
|
||||||
MOBILEGL_ASSERT(stateObj != nullptr, "State object must not be null");
|
|
||||||
|
|
||||||
auto* key = stateObj.get();
|
|
||||||
auto trackedStateIt = m_stateRefs.find(key);
|
|
||||||
if (trackedStateIt != m_stateRefs.end() && trackedStateIt->second.expired()) {
|
|
||||||
EraseByKey(key);
|
|
||||||
}
|
|
||||||
m_stateRefs[key] = stateObj;
|
|
||||||
return m_backendObjects[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator find(StateObject* stateObj) {
|
|
||||||
if (!IsAlive(stateObj)) {
|
|
||||||
EraseByKey(stateObj);
|
|
||||||
return m_backendObjects.end();
|
|
||||||
}
|
|
||||||
return m_backendObjects.find(stateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator find(StateObject* stateObj) const {
|
|
||||||
return const_cast<StateBackendObjectRegistry*>(this)->find(stateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator end() { return m_backendObjects.end(); }
|
|
||||||
const_iterator end() const { return m_backendObjects.end(); }
|
|
||||||
|
|
||||||
void CollectGarbageIfNeeded() {
|
|
||||||
++m_gcTick;
|
|
||||||
if (m_gcTick < kGCInterval) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CollectGarbage();
|
|
||||||
m_gcTick = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CollectGarbageNow() { CollectGarbage(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool IsAlive(StateObject* stateObj) const {
|
|
||||||
const auto trackedStateIt = m_stateRefs.find(stateObj);
|
|
||||||
if (trackedStateIt == m_stateRefs.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !trackedStateIt->second.expired();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EraseByKey(StateObject* stateObj) {
|
|
||||||
m_stateRefs.erase(stateObj);
|
|
||||||
m_backendObjects.erase(stateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CollectGarbage() {
|
|
||||||
if (m_isCollecting) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_isCollecting = true;
|
|
||||||
|
|
||||||
Vector<StateObject*> staleKeys;
|
|
||||||
staleKeys.reserve(m_stateRefs.size());
|
|
||||||
for (const auto& [stateKey, stateWeakRef] : m_stateRefs) {
|
|
||||||
if (stateWeakRef.expired()) {
|
|
||||||
staleKeys.push_back(stateKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto* stateKey : staleKeys) {
|
|
||||||
m_stateRefs.erase(stateKey);
|
|
||||||
m_backendObjects.erase(stateKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_isCollecting = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr Uint32 kGCInterval = 1024;
|
|
||||||
StateRefMap m_stateRefs;
|
|
||||||
BackendMap m_backendObjects;
|
|
||||||
Uint32 m_gcTick = 0;
|
|
||||||
Bool m_isCollecting = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace BufferImpl {
|
namespace BufferImpl {
|
||||||
const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
|
const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
|
||||||
class BackendBufferObject {
|
class BackendBufferObject {
|
||||||
public:
|
public:
|
||||||
BackendBufferObject();
|
BackendBufferObject();
|
||||||
void SyncToBackend(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;
|
||||||
@@ -130,18 +36,21 @@ 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();
|
||||||
void SyncToBackend(const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
|
void SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
|
||||||
Uint GetBackendVertexArrayId() const { return m_backendVAOId; }
|
Uint GetBackendVertexArrayId() { return m_backendVAOId; }
|
||||||
void Bind() const;
|
void Bind();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void BindAttributeBuffer(Uint index, const MG_State::GLState::VertexAttribute& attrib);
|
||||||
|
|
||||||
Uint m_backendVAOId = 0;
|
Uint m_backendVAOId = 0;
|
||||||
Bool m_isInitialized = false;
|
Bool m_isInitialized = false;
|
||||||
Uint16 m_syncedIndexBufferVersion = 0;
|
Uint16 m_syncedIndexBufferVersion = 0;
|
||||||
@@ -149,7 +58,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
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
|
||||||
|
|
||||||
@@ -183,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;
|
||||||
@@ -204,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>
|
||||||
@@ -216,10 +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);
|
||||||
Uint GetBackendFramebufferId() const { return m_backendFBOId; }
|
Uint GetBackendFramebufferId() { return m_backendFBOId; }
|
||||||
void Bind(FramebufferTarget target) const;
|
void Bind(FramebufferTarget target);
|
||||||
|
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;
|
||||||
|
|
||||||
@@ -247,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
|
||||||
@@ -257,8 +169,8 @@ 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();
|
||||||
Uint GetBackendProgramId() const { return m_backendProgramId; }
|
Uint GetBackendProgramId() const { return m_backendProgramId; }
|
||||||
Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; }
|
Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; }
|
||||||
|
|
||||||
@@ -268,7 +180,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
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
|
||||||
|
|
||||||
@@ -276,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;
|
||||||
@@ -291,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
|
||||||
|
|
||||||
@@ -300,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;
|
||||||
@@ -311,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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -159,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:
|
||||||
@@ -168,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;
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -1,187 +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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
MG_Util::BackendLoader::FillInVulkanCapabilities(m_vulkanCaps, pVulkanRenderer->GetPhysicalDevice().properties);
|
|
||||||
UpdateDynamicBackendParameters();
|
|
||||||
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.Backend != WindowBackend::Android || !handle.Handle) {
|
|
||||||
MGLOG_E("DirectVulkan backend only supports Android native windows");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Bool sameHandle =
|
|
||||||
m_eglWindowSurfaceInitialized && m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
|
|
||||||
if (sameHandle) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_eglWindowSurfaceInitialized || 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
const RendererInfo& BackendObject_DirectVulkan::GetRendererInfo() const {
|
|
||||||
static RendererInfo RendererInfo = {
|
|
||||||
.RendererName = "Magma", // Renderer Name
|
|
||||||
.BackendName = "Direct (Vulkan)", // Backend Name
|
|
||||||
.ExtraVendor = Nullopt, // Extra vendor
|
|
||||||
.RendererGLInfo =
|
|
||||||
{
|
|
||||||
.TargetGLVersion = {3, 3, 0}, // Target OpenGL Version
|
|
||||||
.TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version
|
|
||||||
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
|
|
||||||
V_OpenGL33},
|
|
||||||
.IsCompatibilityProfile = false // Is Compatibility Profile
|
|
||||||
},
|
|
||||||
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
|
|
||||||
};
|
|
||||||
return 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.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_DirectVulkan::GetDynamicParameters() const {
|
|
||||||
return m_dynamicParameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackendObject_DirectVulkan::UpdateDynamicBackendParameters() {
|
|
||||||
m_dynamicParameters.UniformBufferOffsetAlignment = m_vulkanCaps.UniformBufferOffsetAlignment;
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,281 +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 = 1;
|
|
||||||
packet.submitInfo.pWaitSemaphores = &packet.waitSemaphore;
|
|
||||||
packet.submitInfo.pWaitDstStageMask = &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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,76 +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;
|
|
||||||
};
|
|
||||||
|
|
||||||
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,131 +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() {
|
|
||||||
DestroyAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
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.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)));
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.blendEnable, sizeof(payload.blendEnable)));
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.srcColorBlendFactor, sizeof(payload.srcColorBlendFactor)));
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.dstColorBlendFactor, sizeof(payload.dstColorBlendFactor)));
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.srcAlphaBlendFactor, sizeof(payload.srcAlphaBlendFactor)));
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.dstAlphaBlendFactor, sizeof(payload.dstAlphaBlendFactor)));
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.colorWriteMask, sizeof(payload.colorWriteMask)));
|
|
||||||
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");
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
VkPipelineColorBlendAttachmentState colorAttach{};
|
|
||||||
colorAttach.colorWriteMask = payload.colorWriteMask;
|
|
||||||
colorAttach.blendEnable = payload.blendEnable ? VK_TRUE : VK_FALSE;
|
|
||||||
colorAttach.srcColorBlendFactor = payload.srcColorBlendFactor;
|
|
||||||
colorAttach.dstColorBlendFactor = payload.dstColorBlendFactor;
|
|
||||||
colorAttach.colorBlendOp = VK_BLEND_OP_ADD;
|
|
||||||
colorAttach.srcAlphaBlendFactor = payload.srcAlphaBlendFactor;
|
|
||||||
colorAttach.dstAlphaBlendFactor = payload.dstAlphaBlendFactor;
|
|
||||||
colorAttach.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
||||||
VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
|
|
||||||
blend.attachmentCount = 1;
|
|
||||||
blend.pAttachments = &colorAttach;
|
|
||||||
|
|
||||||
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, VK_NULL_HANDLE, 1, &gpi, nullptr, &pipeline),
|
|
||||||
"vkCreateGraphicsPipelines");
|
|
||||||
return pipeline;
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,61 +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 <Includes.h>
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
|
||||||
class PipelineFactory {
|
|
||||||
public:
|
|
||||||
using HashType = Uint64;
|
|
||||||
|
|
||||||
struct PipelineCreatePayload {
|
|
||||||
HashType programHash = 0;
|
|
||||||
HashType vertexInputHash = 0;
|
|
||||||
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
|
||||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
|
||||||
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;
|
|
||||||
Bool blendEnable = false;
|
|
||||||
VkBlendFactor srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
||||||
VkBlendFactor dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
|
|
||||||
VkBlendFactor srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
||||||
VkBlendFactor dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
|
||||||
VkColorComponentFlags colorWriteMask =
|
|
||||||
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
|
||||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
||||||
const Vector<VkPipelineShaderStageCreateInfo>* stages = nullptr;
|
|
||||||
const VkPipelineVertexInputStateCreateInfo* vertexInputState = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit PipelineFactory(VkDevice device, const VulkanRendererConfig& config):
|
|
||||||
m_device(device), m_config(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;
|
|
||||||
UnorderedMap<HashType, VkPipeline> m_cache;
|
|
||||||
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
|
||||||
};
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,92 +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 <Includes.h>
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
|
||||||
class ProgramFactory {
|
|
||||||
public:
|
|
||||||
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 {
|
|
||||||
HashType hash = 0;
|
|
||||||
Vector<VkPipelineShaderStageCreateInfo> stages;
|
|
||||||
Vector<VkShaderModule> modules;
|
|
||||||
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);
|
|
||||||
other.hash = 0;
|
|
||||||
}
|
|
||||||
VkProgramObject& operator=(VkProgramObject&& other) noexcept {
|
|
||||||
if (this == &other) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
DestroyModules();
|
|
||||||
stages.clear();
|
|
||||||
hash = other.hash;
|
|
||||||
stages = std::move(other.stages);
|
|
||||||
modules = std::move(other.modules);
|
|
||||||
other.hash = 0;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~VkProgramObject() {
|
|
||||||
DestroyModules();
|
|
||||||
stages.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void DestroyModules() {
|
|
||||||
for (auto module : modules) {
|
|
||||||
if (module != VK_NULL_HANDLE && s_device != VK_NULL_HANDLE) {
|
|
||||||
vkDestroyShaderModule(s_device, module, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
modules.clear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit ProgramFactory(VkDevice device, const VulkanRendererConfig& config)
|
|
||||||
: m_device(device), m_config(config) {
|
|
||||||
VkProgramObject::s_device = device;
|
|
||||||
}
|
|
||||||
~ProgramFactory();
|
|
||||||
ProgramFactory(const ProgramFactory&) = delete;
|
|
||||||
|
|
||||||
HashType ComputeHash(const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags) const;
|
|
||||||
Vector<VkPipelineShaderStageCreateInfo>& GetOrCreatePipelineShaderStages(
|
|
||||||
const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags);
|
|
||||||
|
|
||||||
static VkShaderStageFlagBits ToVkStage(ShaderStage stage);
|
|
||||||
|
|
||||||
private:
|
|
||||||
VkDevice m_device = VK_NULL_HANDLE;
|
|
||||||
UnorderedMap<HashType, VkProgramObject> m_cache;
|
|
||||||
const VulkanRendererConfig& m_config;
|
|
||||||
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;
|
|
||||||
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,985 +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 "UniformDescriptorBinder.h"
|
|
||||||
|
|
||||||
#include "MG_State/GLState/Core.h"
|
|
||||||
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
|
||||||
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
|
|
||||||
#include "MG_Util/ShaderTranspiler/Types.h"
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
|
||||||
static Bool FindFramebufferAttachmentForTexture(const MG_State::GLState::FramebufferObject& framebuffer,
|
|
||||||
const MG_State::GLState::ITextureObject& texture,
|
|
||||||
FramebufferAttachmentType& outAttachment, Int& outLevel) {
|
|
||||||
const auto& attachments = framebuffer.GetAllAttachmentObjects();
|
|
||||||
for (SizeT i = 0; i < attachments.size(); ++i) {
|
|
||||||
const auto attachmentType = static_cast<FramebufferAttachmentType>(i);
|
|
||||||
if (attachmentType == FramebufferAttachmentType::None) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& attachment = attachments[i];
|
|
||||||
if (!attachment.IsTexture()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto attachedTexture = attachment.GetTexture();
|
|
||||||
if (attachedTexture && attachedTexture.get() == &texture) {
|
|
||||||
outAttachment = attachmentType;
|
|
||||||
outLevel = attachment.GetTextureLevel();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Bool IsValidSampledImageLayout(VkImageLayout layout) {
|
|
||||||
switch (layout) {
|
|
||||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
|
||||||
case VK_IMAGE_LAYOUT_GENERAL:
|
|
||||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
|
|
||||||
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
|
|
||||||
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceSize UniformDescriptorBinder::AlignUp(VkDeviceSize value, VkDeviceSize alignment) {
|
|
||||||
if (alignment == 0) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
return (value + alignment - 1) / alignment * alignment;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint64 UniformDescriptorBinder::ComputeProgramHash(const MG_State::GLState::ProgramObject& program) {
|
|
||||||
XXH64_state_t* state = XXH64_createState();
|
|
||||||
XXHASH_VERIFY(XXH64_reset(state, 0xC0D3A11ULL));
|
|
||||||
const auto& spirv = program.GetGeneratedSpirv();
|
|
||||||
for (const auto& module : spirv) {
|
|
||||||
XXHASH_VERIFY(XXH64_update(state, module.data(), module.size() * sizeof(Uint)));
|
|
||||||
}
|
|
||||||
const Uint32 blockCount = static_cast<Uint32>(program.GetActiveUniformBlocksCount());
|
|
||||||
XXHASH_VERIFY(XXH64_update(state, &blockCount, sizeof(blockCount)));
|
|
||||||
for (Uint32 i = 0; i < blockCount; ++i) {
|
|
||||||
const Uint32 binding = program.GetUniformBlockBinding(i);
|
|
||||||
XXHASH_VERIFY(XXH64_update(state, &binding, sizeof(binding)));
|
|
||||||
}
|
|
||||||
const Uint64 hash = XXH64_digest(state);
|
|
||||||
XXH64_freeState(state);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::IsSamplerUniformType(GLenum glType) {
|
|
||||||
switch (glType) {
|
|
||||||
case GL_SAMPLER_1D:
|
|
||||||
case GL_SAMPLER_2D:
|
|
||||||
case GL_SAMPLER_3D:
|
|
||||||
case GL_SAMPLER_CUBE:
|
|
||||||
case GL_SAMPLER_1D_SHADOW:
|
|
||||||
case GL_SAMPLER_2D_SHADOW:
|
|
||||||
case GL_SAMPLER_1D_ARRAY:
|
|
||||||
case GL_SAMPLER_2D_ARRAY:
|
|
||||||
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
|
||||||
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
|
||||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
case GL_SAMPLER_CUBE_SHADOW:
|
|
||||||
case GL_SAMPLER_BUFFER:
|
|
||||||
case GL_SAMPLER_2D_RECT:
|
|
||||||
case GL_SAMPLER_2D_RECT_SHADOW:
|
|
||||||
case GL_INT_SAMPLER_1D:
|
|
||||||
case GL_INT_SAMPLER_2D:
|
|
||||||
case GL_INT_SAMPLER_3D:
|
|
||||||
case GL_INT_SAMPLER_CUBE:
|
|
||||||
case GL_INT_SAMPLER_1D_ARRAY:
|
|
||||||
case GL_INT_SAMPLER_2D_ARRAY:
|
|
||||||
case GL_INT_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
case GL_INT_SAMPLER_BUFFER:
|
|
||||||
case GL_INT_SAMPLER_2D_RECT:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_1D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_3D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_CUBE:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_BUFFER:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureTarget UniformDescriptorBinder::UniformTypeToTextureTarget(GLenum glType) {
|
|
||||||
switch (glType) {
|
|
||||||
case GL_SAMPLER_1D:
|
|
||||||
case GL_INT_SAMPLER_1D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_1D:
|
|
||||||
return TextureTarget::Texture1D;
|
|
||||||
case GL_SAMPLER_3D:
|
|
||||||
case GL_INT_SAMPLER_3D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_3D:
|
|
||||||
return TextureTarget::Texture3D;
|
|
||||||
case GL_SAMPLER_CUBE:
|
|
||||||
case GL_SAMPLER_CUBE_SHADOW:
|
|
||||||
case GL_INT_SAMPLER_CUBE:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_CUBE:
|
|
||||||
return TextureTarget::TextureCubeMap;
|
|
||||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
case GL_INT_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
return TextureTarget::Texture2DMultisample;
|
|
||||||
case GL_SAMPLER_BUFFER:
|
|
||||||
case GL_INT_SAMPLER_BUFFER:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_BUFFER:
|
|
||||||
return TextureTarget::TextureBuffer;
|
|
||||||
case GL_SAMPLER_1D_ARRAY:
|
|
||||||
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
|
||||||
case GL_INT_SAMPLER_1D_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
|
|
||||||
return TextureTarget::Texture1DArray;
|
|
||||||
case GL_SAMPLER_2D_ARRAY:
|
|
||||||
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
|
||||||
case GL_INT_SAMPLER_2D_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
|
||||||
return TextureTarget::Texture2DArray;
|
|
||||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
return TextureTarget::Texture2DMultisampleArray;
|
|
||||||
case GL_SAMPLER_2D_RECT:
|
|
||||||
case GL_SAMPLER_2D_RECT_SHADOW:
|
|
||||||
case GL_INT_SAMPLER_2D_RECT:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
|
|
||||||
return TextureTarget::TextureRectangle;
|
|
||||||
case GL_SAMPLER_2D:
|
|
||||||
case GL_SAMPLER_2D_SHADOW:
|
|
||||||
case GL_INT_SAMPLER_2D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D:
|
|
||||||
default:
|
|
||||||
return TextureTarget::Texture2D;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::Initialize(VkDevice device, VmaAllocator allocator,
|
|
||||||
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
|
|
||||||
Uint32 maxBindings, Uint32 setsPerFrame, VkDeviceSize perFrameUploadBytes,
|
|
||||||
VkTextureManager* textureManager, VkSamplerManager* samplerManager) {
|
|
||||||
Shutdown();
|
|
||||||
|
|
||||||
MOBILEGL_ASSERT(device != VK_NULL_HANDLE, "UniformDescriptorBinder::Initialize requires valid VkDevice");
|
|
||||||
MOBILEGL_ASSERT(allocator != nullptr, "UniformDescriptorBinder::Initialize requires valid VMA allocator");
|
|
||||||
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_allocator = allocator;
|
|
||||||
m_minDynamicOffsetAlignment = std::max<VkDeviceSize>(1, minUniformBufferOffsetAlignment);
|
|
||||||
m_perFrameUploadBytes = perFrameUploadBytes;
|
|
||||||
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.writeCursor = 0;
|
|
||||||
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);
|
|
||||||
|
|
||||||
const Bool created = frame.uploadBuffer.Create(
|
|
||||||
m_allocator, m_perFrameUploadBytes, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO,
|
|
||||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT);
|
|
||||||
if (!created) {
|
|
||||||
MGLOG_E("UniformDescriptorBinder::Initialize failed: cannot create frame upload buffer %u", frameIndex);
|
|
||||||
Shutdown();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UniformDescriptorBinder::Shutdown() {
|
|
||||||
for (auto& frame : m_frames) {
|
|
||||||
frame.uploadBuffer.Destroy();
|
|
||||||
if (m_device != VK_NULL_HANDLE) {
|
|
||||||
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;
|
|
||||||
frame.writeCursor = 0;
|
|
||||||
}
|
|
||||||
m_frames.clear();
|
|
||||||
DestroyProgramLayouts();
|
|
||||||
|
|
||||||
m_allocator = nullptr;
|
|
||||||
m_device = VK_NULL_HANDLE;
|
|
||||||
m_minDynamicOffsetAlignment = 1;
|
|
||||||
m_perFrameUploadBytes = 0;
|
|
||||||
m_frameCount = 0;
|
|
||||||
m_maxBindings = 0;
|
|
||||||
m_setsPerFrame = 0;
|
|
||||||
m_peakDescriptorSetsObserved = 0;
|
|
||||||
m_textureManager = nullptr;
|
|
||||||
m_samplerManager = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UniformDescriptorBinder::BeginFrame(Uint32 frameIndex) {
|
|
||||||
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "UniformDescriptorBinder::BeginFrame invalid frame index");
|
|
||||||
auto& frame = m_frames[frameIndex];
|
|
||||||
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.writeCursor = 0;
|
|
||||||
frame.activeDescriptorPoolIndex = 0;
|
|
||||||
frame.allocatedSetsThisFrame = 0;
|
|
||||||
frame.peakAllocatedSetsThisFrame = 0;
|
|
||||||
for (auto& bucket : frame.descriptorPools) {
|
|
||||||
bucket.allocatedSets = 0;
|
|
||||||
if (bucket.handle == VK_NULL_HANDLE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
VK_VERIFY(vkResetDescriptorPool(m_device, bucket.handle, 0),
|
|
||||||
"UniformDescriptorBinder::BeginFrame, vkResetDescriptorPool");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::ReflectBindingKinds(const MG_State::GLState::ProgramObject& program,
|
|
||||||
Vector<BindingKind>& outKinds) const {
|
|
||||||
outKinds.assign(m_maxBindings, BindingKind::None);
|
|
||||||
|
|
||||||
const auto& spirv = program.GetGeneratedSpirv();
|
|
||||||
for (const auto& module : spirv) {
|
|
||||||
if (module.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
spvc_context context = nullptr;
|
|
||||||
spvc_parsed_ir ir = nullptr;
|
|
||||||
spvc_compiler compiler = nullptr;
|
|
||||||
spvc_resources resources = nullptr;
|
|
||||||
|
|
||||||
if (spvc_context_create(&context) != SPVC_SUCCESS) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const spvc_result parseResult = spvc_context_parse_spirv(context, module.data(), module.size(), &ir);
|
|
||||||
if (parseResult != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const spvc_result compilerResult =
|
|
||||||
spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler);
|
|
||||||
if (compilerResult != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spvc_compiler_create_shader_resources(compiler, &resources) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto applyBindings = [&](spvc_resource_type resourceType, BindingKind kind) {
|
|
||||||
const spvc_reflected_resource* list = nullptr;
|
|
||||||
size_t count = 0;
|
|
||||||
if (spvc_resources_get_resource_list_for_type(resources, resourceType, &list, &count) != SPVC_SUCCESS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
const Uint32 binding =
|
|
||||||
spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
|
|
||||||
if (binding >= m_maxBindings) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (kind == BindingKind::CombinedImageSampler) {
|
|
||||||
outKinds[binding] = BindingKind::CombinedImageSampler;
|
|
||||||
} else if (outKinds[binding] == BindingKind::None) {
|
|
||||||
outKinds[binding] = kind;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
applyBindings(SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, BindingKind::UniformBufferDynamic);
|
|
||||||
applyBindings(SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, BindingKind::CombinedImageSampler);
|
|
||||||
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::ReflectSamplerBindings(const MG_State::GLState::ProgramObject& program,
|
|
||||||
ProgramLayout& layout) const {
|
|
||||||
layout.samplerUniformLocationByBinding.assign(m_maxBindings, -1);
|
|
||||||
layout.samplerTextureTargetByBinding.assign(m_maxBindings, TextureTarget::Texture2D);
|
|
||||||
|
|
||||||
const auto& spirv = program.GetGeneratedSpirv();
|
|
||||||
for (const auto& module : spirv) {
|
|
||||||
if (module.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
spvc_context context = nullptr;
|
|
||||||
spvc_parsed_ir ir = nullptr;
|
|
||||||
spvc_compiler compiler = nullptr;
|
|
||||||
spvc_resources resources = nullptr;
|
|
||||||
|
|
||||||
if (spvc_context_create(&context) != SPVC_SUCCESS) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (spvc_context_parse_spirv(context, module.data(), module.size(), &ir) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP,
|
|
||||||
&compiler) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (spvc_compiler_create_shader_resources(compiler, &resources) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const spvc_reflected_resource* list = nullptr;
|
|
||||||
size_t count = 0;
|
|
||||||
if (spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, &list, &count) ==
|
|
||||||
SPVC_SUCCESS) {
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
const Uint32 binding =
|
|
||||||
spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
|
|
||||||
if (binding >= m_maxBindings) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String uniformName = list[i].name ? list[i].name : "";
|
|
||||||
Int location = program.GetUniformLocation(uniformName);
|
|
||||||
if (location < 0) {
|
|
||||||
const auto arraySuffix = uniformName.find("[0]");
|
|
||||||
if (arraySuffix != String::npos) {
|
|
||||||
uniformName = uniformName.substr(0, arraySuffix);
|
|
||||||
location = program.GetUniformLocation(uniformName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (location < 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
layout.samplerUniformLocationByBinding[binding] = location;
|
|
||||||
layout.samplerTextureTargetByBinding[binding] =
|
|
||||||
UniformTypeToTextureTarget(program.GetUniformType(static_cast<Uint>(location)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::ReflectGlobalUboBinding(const MG_State::GLState::ProgramObject& program,
|
|
||||||
ProgramLayout& layout) const {
|
|
||||||
layout.globalUboBinding = -1;
|
|
||||||
|
|
||||||
const auto& spirv = program.GetGeneratedSpirv();
|
|
||||||
for (const auto& module : spirv) {
|
|
||||||
if (module.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
spvc_context context = nullptr;
|
|
||||||
spvc_parsed_ir ir = nullptr;
|
|
||||||
spvc_compiler compiler = nullptr;
|
|
||||||
spvc_resources resources = nullptr;
|
|
||||||
|
|
||||||
if (spvc_context_create(&context) != SPVC_SUCCESS) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (spvc_context_parse_spirv(context, module.data(), module.size(), &ir) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP,
|
|
||||||
&compiler) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (spvc_compiler_create_shader_resources(compiler, &resources) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const spvc_reflected_resource* list = nullptr;
|
|
||||||
size_t count = 0;
|
|
||||||
if (spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count) ==
|
|
||||||
SPVC_SUCCESS) {
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
const char* name = list[i].name ? list[i].name : "";
|
|
||||||
if (std::strstr(name, MG_Util::ShaderTranspiler::GLOBAL_UBO_NAME) == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const Uint32 binding =
|
|
||||||
spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
|
|
||||||
if (binding < m_maxBindings) {
|
|
||||||
layout.globalUboBinding = static_cast<Int>(binding);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
if (layout.globalUboBinding >= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::ResolveSamplerDescriptor(VkCommandBuffer commandBuffer,
|
|
||||||
const MG_State::GLState::ProgramObject& program,
|
|
||||||
const ProgramLayout& layout, Uint32 binding,
|
|
||||||
VkDescriptorImageInfo& outImageInfo) const {
|
|
||||||
(void)commandBuffer;
|
|
||||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptor: texture manager is null");
|
|
||||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptor: sampler manager is null");
|
|
||||||
SharedPtr<MG_State::GLState::ITextureObject> texture;
|
|
||||||
if (!ResolveSamplerTexture(program, layout, binding, texture)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Int location = layout.samplerUniformLocationByBinding[binding];
|
|
||||||
const Int unit = program.GetUniformSamplerOrImageUnitIndex(static_cast<Uint>(location));
|
|
||||||
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
|
||||||
const auto samplerOverride = textureUnit.GetSamplerObject();
|
|
||||||
if (!texture) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MG_State::GLState::SamplerObject* samplerToUse = samplerOverride ? samplerOverride.get() : texture->GetSamplerObject().get();
|
|
||||||
if (!samplerToUse) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
VkTextureManager::TextureResource* resource =
|
|
||||||
m_textureManager->SyncTextureAndGetDescriptor(*texture);
|
|
||||||
if (resource == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!IsValidSampledImageLayout(resource->layout)) {
|
|
||||||
auto drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
|
||||||
FramebufferAttachmentType attachmentType = FramebufferAttachmentType::None;
|
|
||||||
Int attachmentLevel = 0;
|
|
||||||
if (drawFbo &&
|
|
||||||
FindFramebufferAttachmentForTexture(*drawFbo, *texture, attachmentType, attachmentLevel)) {
|
|
||||||
MOBILEGL_ASSERT(false,
|
|
||||||
"ResolveSamplerDescriptor: framebuffer feedback loop detected: textureId=%d is bound "
|
|
||||||
"for sampling at binding=%u, but is also attached to drawFbo=%u as %s (level=%d, "
|
|
||||||
"trackedLayout=%d)",
|
|
||||||
texture->GetExternalIndex(), binding, drawFbo->GetExternalIndex(),
|
|
||||||
MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(),
|
|
||||||
attachmentLevel, static_cast<Int>(resource->layout));
|
|
||||||
}
|
|
||||||
|
|
||||||
MOBILEGL_ASSERT(false,
|
|
||||||
"ResolveSamplerDescriptor: invalid sampled image layout=%d for textureId=%d, binding=%u",
|
|
||||||
static_cast<Int>(resource->layout), texture->GetExternalIndex(), binding);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
outImageInfo = {
|
|
||||||
.sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse),
|
|
||||||
.imageView = resource->view,
|
|
||||||
.imageLayout = resource->layout,
|
|
||||||
};
|
|
||||||
return outImageInfo.sampler != VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::ResolveSamplerDescriptorOverride(
|
|
||||||
const SamplerBindingOverride& samplerBindingOverride,
|
|
||||||
VkDescriptorImageInfo& outImageInfo) const {
|
|
||||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptorOverride: texture manager is null");
|
|
||||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptorOverride: sampler manager is null");
|
|
||||||
if (samplerBindingOverride.texture == nullptr || samplerBindingOverride.sampler == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* resource = m_textureManager->SyncTextureAndGetDescriptor(*samplerBindingOverride.texture);
|
|
||||||
if (resource == nullptr || !IsValidSampledImageLayout(resource->layout)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
outImageInfo = {
|
|
||||||
.sampler = m_samplerManager->GetOrCreateSampler(*samplerBindingOverride.sampler),
|
|
||||||
.imageView = resource->view,
|
|
||||||
.imageLayout = resource->layout,
|
|
||||||
};
|
|
||||||
return outImageInfo.sampler != VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
|
||||||
const ProgramLayout& layout, Uint32 binding,
|
|
||||||
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const {
|
|
||||||
outTexture.reset();
|
|
||||||
if (!MG_State::pGLContext || binding >= layout.samplerUniformLocationByBinding.size()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Int location = layout.samplerUniformLocationByBinding[binding];
|
|
||||||
if (location < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Int unit = program.GetUniformSamplerOrImageUnitIndex(static_cast<Uint>(location));
|
|
||||||
if (unit < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
|
||||||
const TextureTarget preferredTarget = layout.samplerTextureTargetByBinding[binding];
|
|
||||||
outTexture = textureUnit.GetBindingSlot(preferredTarget).GetBoundObject();
|
|
||||||
return outTexture != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
|
|
||||||
Vector<MG_State::GLState::ITextureObject*>& outTextures) {
|
|
||||||
outTextures.clear();
|
|
||||||
ProgramLayout* layout = GetOrCreateProgramLayout(program);
|
|
||||||
if (layout == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Uint32 binding = 0; binding < m_maxBindings; ++binding) {
|
|
||||||
if (layout->bindingKinds[binding] != BindingKind::CombinedImageSampler) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedPtr<MG_State::GLState::ITextureObject> texture;
|
|
||||||
if (!ResolveSamplerTexture(program, *layout, 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniformDescriptorBinder::ProgramLayout* UniformDescriptorBinder::GetOrCreateProgramLayout(
|
|
||||||
const MG_State::GLState::ProgramObject& program) {
|
|
||||||
const Uint64 hash = ComputeProgramHash(program);
|
|
||||||
auto it = m_programLayouts.find(hash);
|
|
||||||
if (it != m_programLayouts.end()) {
|
|
||||||
return &it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgramLayout layout{};
|
|
||||||
layout.hash = hash;
|
|
||||||
if (!ReflectBindingKinds(program, layout.bindingKinds)) {
|
|
||||||
MGLOG_E("UniformDescriptorBinder::GetOrCreateProgramLayout failed: reflection failed");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!ReflectSamplerBindings(program, layout)) {
|
|
||||||
MGLOG_E("UniformDescriptorBinder::GetOrCreateProgramLayout failed: sampler reflection failed");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!ReflectGlobalUboBinding(program, layout)) {
|
|
||||||
MGLOG_E("UniformDescriptorBinder::GetOrCreateProgramLayout failed: global UBO reflection failed");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<VkDescriptorSetLayoutBinding> bindings;
|
|
||||||
bindings.reserve(m_maxBindings);
|
|
||||||
for (Uint32 binding = 0; binding < m_maxBindings; ++binding) {
|
|
||||||
const auto kind = layout.bindingKinds[binding];
|
|
||||||
if (kind == BindingKind::None) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorSetLayoutBinding layoutBinding{};
|
|
||||||
layoutBinding.binding = binding;
|
|
||||||
layoutBinding.descriptorCount = 1;
|
|
||||||
layoutBinding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS;
|
|
||||||
layoutBinding.pImmutableSamplers = nullptr;
|
|
||||||
if (kind == BindingKind::UniformBufferDynamic) {
|
|
||||||
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
|
||||||
layout.dynamicBindings.push_back(binding);
|
|
||||||
} else {
|
|
||||||
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
}
|
|
||||||
bindings.push_back(layoutBinding);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorSetLayoutCreateInfo setLayoutInfo{};
|
|
||||||
setLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
|
||||||
setLayoutInfo.bindingCount = static_cast<Uint32>(bindings.size());
|
|
||||||
setLayoutInfo.pBindings = bindings.data();
|
|
||||||
VK_VERIFY(vkCreateDescriptorSetLayout(m_device, &setLayoutInfo, nullptr, &layout.descriptorSetLayout),
|
|
||||||
"UniformDescriptorBinder::GetOrCreateProgramLayout, vkCreateDescriptorSetLayout");
|
|
||||||
|
|
||||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
|
||||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
|
||||||
pipelineLayoutInfo.setLayoutCount = 1;
|
|
||||||
pipelineLayoutInfo.pSetLayouts = &layout.descriptorSetLayout;
|
|
||||||
VK_VERIFY(vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &layout.pipelineLayout),
|
|
||||||
"UniformDescriptorBinder::GetOrCreateProgramLayout, vkCreatePipelineLayout");
|
|
||||||
|
|
||||||
auto [insertIt, _] = m_programLayouts.emplace(hash, std::move(layout));
|
|
||||||
return &insertIt->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkPipelineLayout UniformDescriptorBinder::GetOrCreatePipelineLayout(const MG_State::GLState::ProgramObject& program) {
|
|
||||||
auto* layout = GetOrCreateProgramLayout(program);
|
|
||||||
return layout ? layout->pipelineLayout : VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::AllocateUploadRegion(FrameResources& frame, VkDeviceSize size, VkDeviceSize& outOffset) {
|
|
||||||
const VkDeviceSize alignedOffset = AlignUp(frame.writeCursor, m_minDynamicOffsetAlignment);
|
|
||||||
if (alignedOffset + size > m_perFrameUploadBytes) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
outOffset = alignedOffset;
|
|
||||||
frame.writeCursor = alignedOffset + size;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::GatherBindingPayloads(const MG_State::GLState::ProgramObject& program,
|
|
||||||
Vector<const void*>& outData,
|
|
||||||
Vector<VkDeviceSize>& outSizes) const {
|
|
||||||
outData.assign(m_maxBindings, nullptr);
|
|
||||||
outSizes.assign(m_maxBindings, 0);
|
|
||||||
|
|
||||||
const Uint32 activeUniformBlockCount = static_cast<Uint32>(program.GetActiveUniformBlocksCount());
|
|
||||||
const Uint32 uniformBindingPointCount =
|
|
||||||
static_cast<Uint32>(MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform));
|
|
||||||
|
|
||||||
for (Uint32 blockIndex = 0; blockIndex < activeUniformBlockCount; ++blockIndex) {
|
|
||||||
const Uint32 binding = program.GetUniformBlockBinding(blockIndex);
|
|
||||||
if (binding >= m_maxBindings) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceSize blockSize = static_cast<VkDeviceSize>(program.GetUBOSizeAt(blockIndex));
|
|
||||||
if (blockSize == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (binding >= uniformBindingPointCount) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto& bindingPoint = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, binding);
|
|
||||||
const auto bufferObject = bindingPoint.GetBoundObject();
|
|
||||||
if (!bufferObject) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto bufferData = bufferObject->GetDataReadOnly();
|
|
||||||
if (!bufferData || bufferData->empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto range = bindingPoint.GetRange();
|
|
||||||
const VkDeviceSize bufferSize = static_cast<VkDeviceSize>(bufferObject->GetSize());
|
|
||||||
VkDeviceSize rangeStart = static_cast<VkDeviceSize>(range.start);
|
|
||||||
VkDeviceSize rangeEnd = static_cast<VkDeviceSize>(range.end);
|
|
||||||
|
|
||||||
if (rangeStart >= bufferSize) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (rangeEnd <= rangeStart || rangeEnd > bufferSize) {
|
|
||||||
rangeEnd = bufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceSize available = rangeEnd - rangeStart;
|
|
||||||
if (available == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
outData[binding] = bufferData->data() + static_cast<SizeT>(rangeStart);
|
|
||||||
outSizes[binding] = std::min(blockSize, available);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::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[2]{};
|
|
||||||
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;
|
|
||||||
|
|
||||||
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 UniformDescriptorBinder::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
|
||||||
const MG_State::GLState::ProgramObject& program,
|
|
||||||
Uint32 frameIndex) {
|
|
||||||
return BindProgramUniformBuffers(commandBuffer, program, frameIndex, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
|
||||||
const MG_State::GLState::ProgramObject& program,
|
|
||||||
Uint32 frameIndex,
|
|
||||||
const SamplerBindingOverride* samplerBindingOverride) {
|
|
||||||
ProgramLayout* layout = GetOrCreateProgramLayout(program);
|
|
||||||
MOBILEGL_ASSERT(layout != nullptr,
|
|
||||||
"UniformDescriptorBinder::BindProgramUniformBuffers: program layout is null");
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorSetAllocateInfo allocInfo{};
|
|
||||||
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
|
||||||
allocInfo.descriptorSetCount = 1;
|
|
||||||
allocInfo.pSetLayouts = &layout->descriptorSetLayout;
|
|
||||||
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
auto allocateFromActivePool = [&](VkResult& outResult) {
|
|
||||||
auto& bucket = frame.descriptorPools[frame.activeDescriptorPoolIndex];
|
|
||||||
allocInfo.descriptorPool = bucket.handle;
|
|
||||||
outResult = vkAllocateDescriptorSets(m_device, &allocInfo, &descriptorSet);
|
|
||||||
if (outResult == VK_SUCCESS) {
|
|
||||||
++bucket.allocatedSets;
|
|
||||||
++frame.allocatedSetsThisFrame;
|
|
||||||
frame.peakAllocatedSetsThisFrame = std::max(frame.peakAllocatedSetsThisFrame, frame.allocatedSetsThisFrame);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
VkResult allocResult = VK_SUCCESS;
|
|
||||||
allocateFromActivePool(allocResult);
|
|
||||||
if (allocResult == VK_ERROR_OUT_OF_POOL_MEMORY || allocResult == VK_ERROR_FRAGMENTED_POOL) {
|
|
||||||
if (!GrowFrameDescriptorPool(frame, frameIndex)) {
|
|
||||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: descriptor pool growth failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
allocateFromActivePool(allocResult);
|
|
||||||
}
|
|
||||||
if (allocResult != VK_SUCCESS || descriptorSet == VK_NULL_HANDLE) {
|
|
||||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: vkAllocateDescriptorSets returned %d",
|
|
||||||
allocResult);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<const void*> bindingData;
|
|
||||||
Vector<VkDeviceSize> bindingSizes;
|
|
||||||
if (!GatherBindingPayloads(program, bindingData, bindingSizes)) {
|
|
||||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: cannot gather UBO payloads");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const Uint8 kFallbackData[16] = {};
|
|
||||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "BindProgramUniformBuffers: texture manager is null");
|
|
||||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "BindProgramUniformBuffers: sampler manager is null");
|
|
||||||
|
|
||||||
Vector<VkWriteDescriptorSet> writes;
|
|
||||||
writes.reserve(m_maxBindings);
|
|
||||||
Vector<VkDescriptorBufferInfo> bufferInfos;
|
|
||||||
Vector<VkDescriptorImageInfo> imageInfos;
|
|
||||||
Vector<Uint32> dynamicOffsets;
|
|
||||||
bufferInfos.reserve(m_maxBindings);
|
|
||||||
imageInfos.reserve(m_maxBindings);
|
|
||||||
dynamicOffsets.reserve(layout->dynamicBindings.size());
|
|
||||||
|
|
||||||
for (Uint32 binding = 0; binding < m_maxBindings; ++binding) {
|
|
||||||
const auto kind = layout->bindingKinds[binding];
|
|
||||||
if (kind == BindingKind::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 == BindingKind::UniformBufferDynamic) {
|
|
||||||
const void* payload = bindingData[binding];
|
|
||||||
VkDeviceSize payloadSize = bindingSizes[binding];
|
|
||||||
if (payload == nullptr || payloadSize == 0) {
|
|
||||||
if (layout->globalUboBinding == static_cast<Int>(binding)) {
|
|
||||||
const void* globalUboData = program.GetUBOData();
|
|
||||||
const VkDeviceSize globalUboSize = static_cast<VkDeviceSize>(program.GetUBOSize());
|
|
||||||
if (globalUboData != nullptr && globalUboSize > 0) {
|
|
||||||
payload = globalUboData;
|
|
||||||
payloadSize = globalUboSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (payload == nullptr || payloadSize == 0) {
|
|
||||||
payload = kFallbackData;
|
|
||||||
payloadSize = sizeof(kFallbackData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceSize payloadOffset = 0;
|
|
||||||
if (!AllocateUploadRegion(frame, payloadSize, payloadOffset)) {
|
|
||||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: frame upload buffer exhausted");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!frame.uploadBuffer.Upload(payload, payloadSize, payloadOffset)) {
|
|
||||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: UBO upload failed on binding %u",
|
|
||||||
binding);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorBufferInfo bufferInfo{};
|
|
||||||
bufferInfo.buffer = frame.uploadBuffer.GetHandle();
|
|
||||||
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>(payloadOffset));
|
|
||||||
} 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, *layout, 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, VK_PIPELINE_BIND_POINT_GRAPHICS, layout->pipelineLayout, 0, 1, &descriptorSet,
|
|
||||||
static_cast<Uint32>(dynamicOffsets.size()), dynamicOffsets.data());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UniformDescriptorBinder::DestroyProgramLayouts() {
|
|
||||||
for (auto& [_, layout] : m_programLayouts) {
|
|
||||||
if (layout.pipelineLayout != VK_NULL_HANDLE) {
|
|
||||||
vkDestroyPipelineLayout(m_device, layout.pipelineLayout, nullptr);
|
|
||||||
layout.pipelineLayout = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
if (layout.descriptorSetLayout != VK_NULL_HANDLE) {
|
|
||||||
vkDestroyDescriptorSetLayout(m_device, layout.descriptorSetLayout, nullptr);
|
|
||||||
layout.descriptorSetLayout = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_programLayouts.clear();
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,119 +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 "VkBufferObject.h"
|
|
||||||
#include "VkSamplerManager.h"
|
|
||||||
#include "VkTextureManager.h"
|
|
||||||
#include "../VkIncludes.h"
|
|
||||||
#include <Includes.h>
|
|
||||||
#include <vk_mem_alloc.h>
|
|
||||||
|
|
||||||
namespace MobileGL::MG_State::GLState {
|
|
||||||
class ITextureObject;
|
|
||||||
class ProgramObject;
|
|
||||||
class SamplerObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
|
||||||
class UniformDescriptorBinder {
|
|
||||||
public:
|
|
||||||
enum class BindingKind : Uint8 {
|
|
||||||
None = 0,
|
|
||||||
UniformBufferDynamic,
|
|
||||||
CombinedImageSampler
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SamplerBindingOverride {
|
|
||||||
Uint32 binding = 0;
|
|
||||||
MG_State::GLState::ITextureObject* texture = nullptr;
|
|
||||||
const MG_State::GLState::SamplerObject* sampler = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
Bool Initialize(VkDevice device, VmaAllocator allocator, VkDeviceSize minUniformBufferOffsetAlignment,
|
|
||||||
Uint32 frameCount, Uint32 maxBindings = 16, Uint32 setsPerFrame = 64,
|
|
||||||
VkDeviceSize perFrameUploadBytes = 4 * 1024 * 1024,
|
|
||||||
VkTextureManager* textureManager = nullptr, VkSamplerManager* samplerManager = nullptr);
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
void BeginFrame(Uint32 frameIndex);
|
|
||||||
VkPipelineLayout GetOrCreatePipelineLayout(const MG_State::GLState::ProgramObject& program);
|
|
||||||
Bool CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
|
|
||||||
Vector<MG_State::GLState::ITextureObject*>& outTextures);
|
|
||||||
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
|
||||||
const MG_State::GLState::ProgramObject& program, Uint32 frameIndex);
|
|
||||||
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
|
||||||
const MG_State::GLState::ProgramObject& program, Uint32 frameIndex,
|
|
||||||
const SamplerBindingOverride* samplerBindingOverride);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct DescriptorPoolBucket {
|
|
||||||
VkDescriptorPool handle = VK_NULL_HANDLE;
|
|
||||||
Uint32 maxSets = 0;
|
|
||||||
Uint32 allocatedSets = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FrameResources {
|
|
||||||
VkBufferObject uploadBuffer;
|
|
||||||
Vector<DescriptorPoolBucket> descriptorPools;
|
|
||||||
Uint32 activeDescriptorPoolIndex = 0;
|
|
||||||
Uint32 allocatedSetsThisFrame = 0;
|
|
||||||
Uint32 peakAllocatedSetsThisFrame = 0;
|
|
||||||
VkDeviceSize writeCursor = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ProgramLayout {
|
|
||||||
Uint64 hash = 0;
|
|
||||||
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
|
|
||||||
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
|
||||||
Vector<BindingKind> bindingKinds;
|
|
||||||
Vector<Uint32> dynamicBindings;
|
|
||||||
Vector<Int> samplerUniformLocationByBinding;
|
|
||||||
Vector<TextureTarget> samplerTextureTargetByBinding;
|
|
||||||
Int globalUboBinding = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
static VkDeviceSize AlignUp(VkDeviceSize value, VkDeviceSize alignment);
|
|
||||||
static Uint64 ComputeProgramHash(const MG_State::GLState::ProgramObject& program);
|
|
||||||
static Bool IsSamplerUniformType(GLenum glType);
|
|
||||||
static TextureTarget UniformTypeToTextureTarget(GLenum glType);
|
|
||||||
Bool ReflectSamplerBindings(const MG_State::GLState::ProgramObject& program, ProgramLayout& layout) const;
|
|
||||||
Bool ReflectGlobalUboBinding(const MG_State::GLState::ProgramObject& program, ProgramLayout& layout) const;
|
|
||||||
Bool ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program, const ProgramLayout& layout,
|
|
||||||
Uint32 binding, SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const;
|
|
||||||
Bool ResolveSamplerDescriptor(VkCommandBuffer commandBuffer, const MG_State::GLState::ProgramObject& program,
|
|
||||||
const ProgramLayout& layout, Uint32 binding,
|
|
||||||
VkDescriptorImageInfo& outImageInfo) const;
|
|
||||||
Bool ResolveSamplerDescriptorOverride(const SamplerBindingOverride& samplerBindingOverride,
|
|
||||||
VkDescriptorImageInfo& outImageInfo) const;
|
|
||||||
Bool ReflectBindingKinds(const MG_State::GLState::ProgramObject& program, Vector<BindingKind>& outKinds) const;
|
|
||||||
ProgramLayout* GetOrCreateProgramLayout(const MG_State::GLState::ProgramObject& program);
|
|
||||||
Bool AllocateUploadRegion(FrameResources& frame, VkDeviceSize size, VkDeviceSize& outOffset);
|
|
||||||
Bool GatherBindingPayloads(const MG_State::GLState::ProgramObject& program, Vector<const void*>& outData,
|
|
||||||
Vector<VkDeviceSize>& outSizes) const;
|
|
||||||
Bool CreateDescriptorPool(Uint32 maxSets, VkDescriptorPool& outPool) const;
|
|
||||||
Bool GrowFrameDescriptorPool(FrameResources& frame, Uint32 frameIndex);
|
|
||||||
void DestroyProgramLayouts();
|
|
||||||
|
|
||||||
VkDevice m_device = VK_NULL_HANDLE;
|
|
||||||
VmaAllocator m_allocator = nullptr;
|
|
||||||
Vector<FrameResources> m_frames;
|
|
||||||
UnorderedMap<Uint64, ProgramLayout> m_programLayouts;
|
|
||||||
|
|
||||||
VkDeviceSize m_minDynamicOffsetAlignment = 1;
|
|
||||||
VkDeviceSize m_perFrameUploadBytes = 0;
|
|
||||||
Uint32 m_frameCount = 0;
|
|
||||||
Uint32 m_maxBindings = 0;
|
|
||||||
Uint32 m_setsPerFrame = 0;
|
|
||||||
Uint32 m_peakDescriptorSetsObserved = 0;
|
|
||||||
VkTextureManager* m_textureManager = nullptr;
|
|
||||||
VkSamplerManager* m_samplerManager = nullptr;
|
|
||||||
};
|
|
||||||
} // 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,237 +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);
|
|
||||||
auto it = m_cache.find(hash);
|
|
||||||
if (it != m_cache.end()) {
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexInputStateBuilder builder;
|
|
||||||
UnorderedMap<SizeT, Uint32> bindingByBufferKey;
|
|
||||||
UnorderedMap<SizeT, Uint32> strideByBufferKey;
|
|
||||||
UnorderedMap<SizeT, VkVertexInputRate> inputRateByBufferKey;
|
|
||||||
Vector<SizeT> bindingBufferKeys;
|
|
||||||
|
|
||||||
for (Uint32 location = 0; location < MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS; ++location) {
|
|
||||||
const auto& attr = vao.GetAttribute(location);
|
|
||||||
if (!attr.Enabled || !attr.Buffer) {
|
|
||||||
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());
|
|
||||||
Uint32 binding = 0;
|
|
||||||
auto itBinding = bindingByBufferKey.find(bufferKey);
|
|
||||||
if (itBinding == bindingByBufferKey.end()) {
|
|
||||||
binding = static_cast<Uint32>(bindingByBufferKey.size());
|
|
||||||
bindingByBufferKey.emplace(bufferKey, binding);
|
|
||||||
strideByBufferKey.emplace(bufferKey, stride);
|
|
||||||
inputRateByBufferKey.emplace(bufferKey, inputRate);
|
|
||||||
bindingBufferKeys.push_back(bufferKey);
|
|
||||||
builder.AddBinding(binding, stride, inputRate);
|
|
||||||
} else {
|
|
||||||
binding = itBinding->second;
|
|
||||||
if (strideByBufferKey[bufferKey] != stride) {
|
|
||||||
MGLOG_D("Skipping vertex attribute at location %u: stride mismatch (%u vs %u) on same buffer",
|
|
||||||
location, stride, strideByBufferKey[bufferKey]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (inputRateByBufferKey[bufferKey] != inputRate) {
|
|
||||||
MGLOG_D("Skipping vertex attribute at location %u: input-rate mismatch on same buffer", location);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.AddAttribute(location, binding, vkFormat, static_cast<Uint32>(attr.Offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
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.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,48 +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;
|
|
||||||
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);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static VkFormat ToVkVertexFormat(DataType type, Int size, Bool normalized, Bool isInteger);
|
|
||||||
static SizeT GetComponentSize(DataType type);
|
|
||||||
|
|
||||||
const VulkanRendererConfig& m_config;
|
|
||||||
UnorderedMap<HashType, BackendVertexInputState> m_cache;
|
|
||||||
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
|
||||||
};
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,110 +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_size = other.m_size;
|
|
||||||
|
|
||||||
other.m_allocator = nullptr;
|
|
||||||
other.m_buffer = VK_NULL_HANDLE;
|
|
||||||
other.m_allocation = 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_size = other.m_size;
|
|
||||||
|
|
||||||
other.m_allocator = nullptr;
|
|
||||||
other.m_buffer = VK_NULL_HANDLE;
|
|
||||||
other.m_allocation = nullptr;
|
|
||||||
other.m_size = 0;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkBufferObject::~VkBufferObject() {
|
|
||||||
Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
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() {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* mapped = nullptr;
|
|
||||||
const VkResult mapResult = vmaMapMemory(m_allocator, m_allocation, &mapped);
|
|
||||||
if (mapResult != VK_SUCCESS || mapped == nullptr) {
|
|
||||||
MGLOG_E("VkBufferObject::Upload failed: vmaMapMemory returned %d", mapResult);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Memcpy(static_cast<Uint8*>(mapped) + offset, data, static_cast<SizeT>(size));
|
|
||||||
vmaUnmapMemory(m_allocator, m_allocation);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,42 +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 "../VkIncludes.h"
|
|
||||||
#include <Includes.h>
|
|
||||||
#include <vk_mem_alloc.h>
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
|
||||||
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(VmaAllocator allocator, VkDeviceSize size, VkBufferUsageFlags usage,
|
|
||||||
VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocationFlags = 0);
|
|
||||||
void Destroy();
|
|
||||||
|
|
||||||
Bool Upload(const void* data, VkDeviceSize size, VkDeviceSize offset = 0);
|
|
||||||
|
|
||||||
VkBuffer GetHandle() const { return m_buffer; }
|
|
||||||
VkDeviceSize GetSize() const { return m_size; }
|
|
||||||
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;
|
|
||||||
VkDeviceSize m_size = 0;
|
|
||||||
};
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,99 +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"
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
|
||||||
Bool VkClearManager::Initialize() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VkClearManager::Shutdown() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void VkClearManager::QueueClear(GLbitfield mask, const ClearFramebufferPayload& clearPayload,
|
|
||||||
const MG_State::GLState::FramebufferObject& drawFbo) {
|
|
||||||
if (mask & GL_COLOR_BUFFER_BIT) {
|
|
||||||
auto& drawbufs = drawFbo.GetDrawBuffers();
|
|
||||||
// This should automatically work on default & offscreen FBO
|
|
||||||
for (auto drawbuf: drawbufs) {
|
|
||||||
if (drawbuf == FramebufferAttachmentType::None ||
|
|
||||||
drawFbo.GetAttachment(drawbuf).IsRenderbuffer())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
QueueClear({
|
|
||||||
.color = clearPayload.color,
|
|
||||||
.attachmentType = drawbuf
|
|
||||||
}, drawFbo.GetAttachment(drawbuf).GetTexture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mask & GL_DEPTH_BUFFER_BIT &&
|
|
||||||
!drawFbo.GetAttachment(FramebufferAttachmentType::Depth).IsRenderbuffer()) {
|
|
||||||
QueueClear({
|
|
||||||
.depth = clearPayload.depth,
|
|
||||||
.attachmentType = FramebufferAttachmentType::Depth,
|
|
||||||
}, drawFbo.GetAttachment(FramebufferAttachmentType::Depth).GetTexture());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mask & GL_STENCIL_BUFFER_BIT &&
|
|
||||||
!drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).IsRenderbuffer()) {
|
|
||||||
QueueClear({
|
|
||||||
.stencil = clearPayload.stencil,
|
|
||||||
.attachmentType = FramebufferAttachmentType::Stencil,
|
|
||||||
}, drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).GetTexture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
|
|
||||||
const SharedPtr<MG_State::GLState::ITextureObject>& texture) {
|
|
||||||
WeakPtr<MG_State::GLState::ITextureObject> weakTexturePtr = texture;
|
|
||||||
if (weakTexturePtr.expired())
|
|
||||||
return;
|
|
||||||
auto* pTexture = weakTexturePtr.lock().get();
|
|
||||||
m_aliveObjects[pTexture] = weakTexturePtr;
|
|
||||||
m_pendingClears[pTexture] = clearPayload;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) {
|
|
||||||
return m_pendingClears.find(texture) != m_pendingClears.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool VkClearManager::GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload) {
|
|
||||||
if (m_aliveObjects.find(texture) == m_aliveObjects.end() ||
|
|
||||||
m_pendingClears.find(texture) == m_pendingClears.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
outPayload = m_pendingClears[texture];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VkClearManager::PopPendingClear(MG_State::GLState::ITextureObject* texture) {
|
|
||||||
m_aliveObjects.erase(texture);
|
|
||||||
m_pendingClears.erase(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
SizeT VkClearManager::CollectGarbage() {
|
|
||||||
m_gcCounter++;
|
|
||||||
if (m_gcCounter != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SizeT count = 0;
|
|
||||||
for (const auto& [raw, weak]: m_aliveObjects) {
|
|
||||||
if (weak.expired()) {
|
|
||||||
count++;
|
|
||||||
m_pendingClears.erase(raw);
|
|
||||||
m_aliveObjects.erase(raw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,52 +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 {
|
|
||||||
union {
|
|
||||||
FloatVec4 color;
|
|
||||||
Float depth{};
|
|
||||||
Uint32 stencil;
|
|
||||||
};
|
|
||||||
FramebufferAttachmentType attachmentType = FramebufferAttachmentType::Color0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VkClearManager {
|
|
||||||
public:
|
|
||||||
Bool Initialize();
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
void QueueClear(GLbitfield mask, const ClearFramebufferPayload& clearPayload, const MG_State::GLState::FramebufferObject& drawFbo);
|
|
||||||
void QueueClear(
|
|
||||||
const ClearAttachmentPayload& clearPayload,
|
|
||||||
const SharedPtr<MG_State::GLState::ITextureObject>& texture);
|
|
||||||
Bool HasPendingClear(MG_State::GLState::ITextureObject* texture);
|
|
||||||
Bool GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload);
|
|
||||||
void PopPendingClear(MG_State::GLState::ITextureObject* texture);
|
|
||||||
SizeT CollectGarbage();
|
|
||||||
private:
|
|
||||||
Uint8 m_gcCounter = 0;
|
|
||||||
UnorderedMap<MG_State::GLState::ITextureObject*, ClearAttachmentPayload> m_pendingClears;
|
|
||||||
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
|
|
||||||
};
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,470 +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/MGToVk/TextureEnumConverter.h"
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
|
||||||
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 (includePendingClear && att.IsTexture()) {
|
|
||||||
auto* texture = att.GetTexture().get();
|
|
||||||
auto hasClear = m_clearManager.HasPendingClear(texture);
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &hasClear, sizeof(hasClear)));
|
|
||||||
if (hasClear) {
|
|
||||||
ClearAttachmentPayload clearPayload{};
|
|
||||||
Bool hasPayload = m_clearManager.GetPendingClear(texture, clearPayload);
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &hasPayload, sizeof(hasPayload)));
|
|
||||||
if (hasPayload) {
|
|
||||||
XXHASH_VERIFY(XXH64_update(
|
|
||||||
m_hashState, &clearPayload.attachmentType, sizeof(clearPayload.attachmentType)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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* resource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
|
||||||
if (resource != nullptr) {
|
|
||||||
currentLayout = resource->layout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, ¤tLayout, 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) {
|
|
||||||
// retrieve from cache first
|
|
||||||
auto* activeRenderPass = GetActiveRenderPass();
|
|
||||||
auto compatibilityHash = ComputeHash(fbo, swapchainImageIndex, false);
|
|
||||||
if (activeRenderPass != nullptr && activeRenderPass->CompatibleWith(compatibilityHash)) {
|
|
||||||
auto activeIt = m_renderPasses.find(activeRenderPass->hash);
|
|
||||||
MOBILEGL_ASSERT(activeIt != m_renderPasses.end(),
|
|
||||||
"GetOrCreateRenderPass: active render pass hash=0x%llx is missing from cache",
|
|
||||||
static_cast<unsigned long long>(activeRenderPass->hash));
|
|
||||||
return activeIt->second;
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
Int validDrawBufCount = 0;
|
|
||||||
for (Int i = 0; i < drawbufs.size(); ++i) {
|
|
||||||
auto drawbuf = drawbufs[i];
|
|
||||||
if (drawbuf != FramebufferAttachmentType::None)
|
|
||||||
validDrawBufCount = std::max(validDrawBufCount, i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Int width = 0;
|
|
||||||
Int height = 0;
|
|
||||||
Vector<VkAttachmentDescription> attachmentDescriptions(validDrawBufCount);
|
|
||||||
Vector<VkAttachmentReference> colorAttachmentRefs(validDrawBufCount);
|
|
||||||
Vector<PendingClearAttachmentInfo> pendingClearAttachments;
|
|
||||||
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
|
||||||
auto& textureResources = RenderPassEntry::s_textureResourcesScratch;
|
|
||||||
textureResources.clear();
|
|
||||||
textureResources.resize(validDrawBufCount, nullptr);
|
|
||||||
Vector<VkImageView> attachmentViews(validDrawBufCount, VK_NULL_HANDLE);
|
|
||||||
// This should automatically work on default & offscreen FBO
|
|
||||||
// assuming default FBO has the right param
|
|
||||||
for (Int i = 0; i < validDrawBufCount; ++i) {
|
|
||||||
auto drawbuf = drawbufs[i];
|
|
||||||
if (drawbuf == FramebufferAttachmentType::None ||
|
|
||||||
fbo.GetAttachment(drawbuf).IsRenderbuffer())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto& att = fbo.GetAttachment(drawbuf);
|
|
||||||
auto* texture = att.GetTexture().get();
|
|
||||||
const auto textureTarget = texture->GetTarget();
|
|
||||||
|
|
||||||
// Color attachment description
|
|
||||||
VkAttachmentDescription& desc = attachmentDescriptions[i];
|
|
||||||
switch (textureTarget) {
|
|
||||||
case TextureTarget::Texture2D: {
|
|
||||||
auto* texture2d =
|
|
||||||
static_cast<MG_State::GLState::TextureObject2D*>(texture);
|
|
||||||
desc.flags = 0;
|
|
||||||
desc.format =
|
|
||||||
MG_Util::ConvertTextureInternalFormatToVkEnum(
|
|
||||||
texture2d->GetFormat());
|
|
||||||
desc.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
ClearAttachmentPayload clearPayload{};
|
|
||||||
Bool hasClear = m_clearManager.GetPendingClear(texture, clearPayload);
|
|
||||||
VkImageLayout trackedColorLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
desc.loadOp = hasClear ?
|
|
||||||
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
|
||||||
VK_ATTACHMENT_LOAD_OP_LOAD;
|
|
||||||
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
||||||
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
||||||
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
||||||
desc.finalLayout = isDefaultFbo ?
|
|
||||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR :
|
|
||||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
||||||
if (hasClear) {
|
|
||||||
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
|
||||||
.attachmentIndex = static_cast<Uint32>(i),
|
|
||||||
.texture = texture
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (width == 0)
|
|
||||||
width = texture2d->GetBaseSize().x();
|
|
||||||
if (height == 0)
|
|
||||||
height = texture2d->GetBaseSize().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,
|
|
||||||
});
|
|
||||||
attachmentViews[i] = swapchainViews[swapchainImageIndex];
|
|
||||||
} else {
|
|
||||||
textureResources[i] = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
|
||||||
MOBILEGL_ASSERT(textureResources[i],
|
|
||||||
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i);
|
|
||||||
trackedColorLayout = textureResources[i]->layout;
|
|
||||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
|
||||||
.target = TrackedAttachmentTarget::Texture,
|
|
||||||
.texture = texture,
|
|
||||||
.finalLayout = desc.finalLayout,
|
|
||||||
});
|
|
||||||
attachmentViews[i] = textureResources[i]->view;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = i;
|
|
||||||
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 depthAttachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
|
|
||||||
ClearAttachmentPayload clearPayload{};
|
|
||||||
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
|
|
||||||
Bool clearDepth = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Depth;
|
|
||||||
Bool clearStencil = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Stencil;
|
|
||||||
VkImageLayout trackedDepthLayout = isDefaultFbo ?
|
|
||||||
m_swapchainObject.GetDepthStencilImageLayout(swapchainImageIndex) :
|
|
||||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
|
||||||
if (!isDefaultFbo) {
|
|
||||||
depthTextureResource = m_textureManager.SyncTextureAndGetDescriptor(texture);
|
|
||||||
MOBILEGL_ASSERT(depthTextureResource,
|
|
||||||
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment");
|
|
||||||
trackedDepthLayout = depthTextureResource->layout;
|
|
||||||
}
|
|
||||||
depthAttachmentDescription.flags = 0;
|
|
||||||
depthAttachmentDescription.format =
|
|
||||||
MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
|
|
||||||
depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
depthAttachmentDescription.loadOp = clearDepth ?
|
|
||||||
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
|
||||||
VK_ATTACHMENT_LOAD_OP_LOAD;
|
|
||||||
depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
||||||
depthAttachmentDescription.stencilLoadOp = clearStencil ?
|
|
||||||
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
|
||||||
VK_ATTACHMENT_LOAD_OP_LOAD;
|
|
||||||
depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
||||||
depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
|
||||||
if (trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
|
||||||
if (!clearDepth) {
|
|
||||||
depthAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
||||||
}
|
|
||||||
if (!clearStencil) {
|
|
||||||
depthAttachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
depthAttachmentDescription.initialLayout =
|
|
||||||
(clearDepth && clearStencil) || trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED ?
|
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED :
|
|
||||||
trackedDepthLayout;
|
|
||||||
if (hasClear) {
|
|
||||||
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
|
||||||
.attachmentIndex = depthAttachmentIndex,
|
|
||||||
.texture = &texture
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (isDefaultFbo) {
|
|
||||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
|
||||||
.target = TrackedAttachmentTarget::SwapchainDepthStencil,
|
|
||||||
.swapchainImageIndex = swapchainImageIndex,
|
|
||||||
.finalLayout = depthAttachmentDescription.finalLayout,
|
|
||||||
});
|
|
||||||
attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex));
|
|
||||||
} else {
|
|
||||||
MOBILEGL_ASSERT(clearDepth || clearStencil || depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED,
|
|
||||||
"GetOrCreateRenderPass: depth attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD",
|
|
||||||
texture.GetExternalIndex());
|
|
||||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
|
||||||
.target = TrackedAttachmentTarget::Texture,
|
|
||||||
.texture = &texture,
|
|
||||||
.finalLayout = depthAttachmentDescription.finalLayout,
|
|
||||||
});
|
|
||||||
textureResources.emplace_back(depthTextureResource);
|
|
||||||
attachmentViews.emplace_back(depthTextureResource->view);
|
|
||||||
if (width == 0 || height == 0) {
|
|
||||||
auto texture2d = static_cast<MG_State::GLState::TextureObject2D*>(&texture);
|
|
||||||
width = texture2d->GetBaseSize().x();
|
|
||||||
height = texture2d->GetBaseSize().y();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
attachmentDescriptions.emplace_back(depthAttachmentDescription);
|
|
||||||
depthAttachmentRef.attachment = depthAttachmentIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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()),
|
|
||||||
extent,
|
|
||||||
1 };
|
|
||||||
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.attachmentType >= FramebufferAttachmentType::Color0 &&
|
|
||||||
clearPayload.attachmentType <= FramebufferAttachmentType::Color31) {
|
|
||||||
clearValues[pending.attachmentIndex].color = {
|
|
||||||
clearPayload.color.x(),
|
|
||||||
clearPayload.color.y(),
|
|
||||||
clearPayload.color.z(),
|
|
||||||
clearPayload.color.w()
|
|
||||||
};
|
|
||||||
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Depth) {
|
|
||||||
clearValues[pending.attachmentIndex].depthStencil.depth = clearPayload.depth;
|
|
||||||
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Stencil) {
|
|
||||||
clearValues[pending.attachmentIndex].depthStencil.stencil = clearPayload.stencil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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->UpdateTrackedImageLayout(trackedAttachment.texture, trackedAttachment.finalLayout);
|
|
||||||
break;
|
|
||||||
case TrackedAttachmentTarget::SwapchainColor:
|
|
||||||
MOBILEGL_ASSERT(s_swapchainObject != nullptr, "EndRenderPass: swapchain object is null");
|
|
||||||
s_swapchainObject->SetImageLayout(trackedAttachment.swapchainImageIndex, trackedAttachment.finalLayout);
|
|
||||||
break;
|
|
||||||
case TrackedAttachmentTarget::SwapchainDepthStencil:
|
|
||||||
MOBILEGL_ASSERT(s_swapchainObject != nullptr, "EndRenderPass: swapchain object is null");
|
|
||||||
s_swapchainObject->SetDepthStencilImageLayout(trackedAttachment.swapchainImageIndex,
|
|
||||||
trackedAttachment.finalLayout);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
MOBILEGL_ASSERT(false, "EndRenderPass: unsupported tracked attachment target=%d",
|
|
||||||
static_cast<Int>(trackedAttachment.target));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s_activeRenderPass = {};
|
|
||||||
s_hasActiveRenderPass = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ActiveRenderPassInfo* VkRenderPassManager::GetActiveRenderPass() {
|
|
||||||
return s_hasActiveRenderPass ? &s_activeRenderPass : nullptr;
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,151 +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 swapchainImageIndex = 0;
|
|
||||||
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RenderPassEntry {
|
|
||||||
static inline VkDevice s_device;
|
|
||||||
static inline Vector<VkTextureManager::TextureResource*> s_textureResourcesScratch;
|
|
||||||
Uint64 hash = 0;
|
|
||||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
|
||||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
|
||||||
Uint64 compatibilityHash = 0;
|
|
||||||
Vector<PendingClearAttachmentInfo> pendingClearAttachments;
|
|
||||||
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
|
||||||
Uint32 attachmentCount = 0;
|
|
||||||
IntVec2 extent = {0, 0};
|
|
||||||
Uint32 subpass = 0;
|
|
||||||
|
|
||||||
RenderPassEntry() = default;
|
|
||||||
RenderPassEntry(const RenderPassEntry&) = delete;
|
|
||||||
RenderPassEntry(RenderPassEntry&& that) noexcept {
|
|
||||||
std::swap(hash, that.hash);
|
|
||||||
std::swap(renderPass, that.renderPass);
|
|
||||||
std::swap(framebuffer, that.framebuffer);
|
|
||||||
std::swap(compatibilityHash, that.compatibilityHash);
|
|
||||||
std::swap(pendingClearAttachments, that.pendingClearAttachments);
|
|
||||||
std::swap(trackedAttachmentLayouts, that.trackedAttachmentLayouts);
|
|
||||||
std::swap(attachmentCount, that.attachmentCount);
|
|
||||||
std::swap(extent, that.extent);
|
|
||||||
std::swap(subpass, that.subpass);
|
|
||||||
}
|
|
||||||
RenderPassEntry(
|
|
||||||
Uint64 hash,
|
|
||||||
VkRenderPass renderpass,
|
|
||||||
VkFramebuffer framebuffer,
|
|
||||||
Uint64 compatibilityHash,
|
|
||||||
const Vector<PendingClearAttachmentInfo>& pendingClearAttachments,
|
|
||||||
const Vector<TrackedAttachmentLayoutInfo>& trackedAttachmentLayouts,
|
|
||||||
Uint32 attachmentCount,
|
|
||||||
IntVec2 extent, int subpass):
|
|
||||||
hash(hash),
|
|
||||||
renderPass(renderpass),
|
|
||||||
framebuffer(framebuffer),
|
|
||||||
compatibilityHash(compatibilityHash),
|
|
||||||
pendingClearAttachments(Move(pendingClearAttachments)),
|
|
||||||
trackedAttachmentLayouts(Move(trackedAttachmentLayouts)),
|
|
||||||
attachmentCount(attachmentCount),
|
|
||||||
extent(extent),
|
|
||||||
subpass(subpass)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~RenderPassEntry() {
|
|
||||||
if (renderPass != VK_NULL_HANDLE) {
|
|
||||||
vkDestroyRenderPass(s_device, renderPass, nullptr);
|
|
||||||
}
|
|
||||||
if (framebuffer != VK_NULL_HANDLE) {
|
|
||||||
vkDestroyFramebuffer(s_device, framebuffer, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool CompatibleWith(const RenderPassEntry& that) const {
|
|
||||||
return this->compatibilityHash == that.compatibilityHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool CompatibleWith(Uint64 compatibilityHash) const {
|
|
||||||
return this->compatibilityHash == compatibilityHash;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ActiveRenderPassInfo {
|
|
||||||
Uint64 hash = 0;
|
|
||||||
Uint64 compatibilityHash = 0;
|
|
||||||
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
|
||||||
IntVec2 extent = {0, 0};
|
|
||||||
|
|
||||||
Bool CompatibleWith(const RenderPassEntry& that) const {
|
|
||||||
return compatibilityHash == that.compatibilityHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool CompatibleWith(Uint64 thatCompatibilityHash) const {
|
|
||||||
return compatibilityHash == thatCompatibilityHash;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class VkRenderPassManager {
|
|
||||||
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,156 +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"
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
|
||||||
Bool VkSamplerManager::Initialize(const InitInfo& initInfo) {
|
|
||||||
Shutdown();
|
|
||||||
|
|
||||||
m_device = initInfo.device;
|
|
||||||
m_config = initInfo.config;
|
|
||||||
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE && m_config != nullptr,
|
|
||||||
"VkSamplerManager::Initialize failed: invalid initialization info");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VkSamplerManager::Shutdown() {
|
|
||||||
for (auto& [_, sampler] : m_samplers) {
|
|
||||||
if (m_device != VK_NULL_HANDLE && sampler.handle != VK_NULL_HANDLE) {
|
|
||||||
vkDestroySampler(m_device, sampler.handle, nullptr);
|
|
||||||
}
|
|
||||||
sampler.handle = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
m_samplers.clear();
|
|
||||||
|
|
||||||
m_device = VK_NULL_HANDLE;
|
|
||||||
m_config = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint64 VkSamplerManager::BuildSamplerKey(const MG_State::GLState::SamplerObject& sampler) const {
|
|
||||||
MOBILEGL_ASSERT(m_config != nullptr, "VkSamplerManager::BuildSamplerKey: m_config is null");
|
|
||||||
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config->CacheVersion));
|
|
||||||
|
|
||||||
const auto minFilter = sampler.GetMinFilter();
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &minFilter, sizeof(minFilter)));
|
|
||||||
const auto magFilter = sampler.GetMagFilter();
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &magFilter, sizeof(magFilter)));
|
|
||||||
const auto mipmapMode = sampler.GetMipmapMode();
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &mipmapMode, sizeof(mipmapMode)));
|
|
||||||
const auto wrapS = sampler.GetWrapS();
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapS, sizeof(wrapS)));
|
|
||||||
const auto wrapT = sampler.GetWrapT();
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapT, sizeof(wrapT)));
|
|
||||||
const auto wrapR = sampler.GetWrapR();
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapR, sizeof(wrapR)));
|
|
||||||
const auto minLod = sampler.GetMinLod();
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &minLod, sizeof(minLod)));
|
|
||||||
const auto maxLod = sampler.GetMaxLod();
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &maxLod, sizeof(maxLod)));
|
|
||||||
const auto lodBias = sampler.GetLodBias();
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &lodBias, sizeof(lodBias)));
|
|
||||||
const auto compareMode = sampler.GetCompareMode();
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &compareMode, sizeof(compareMode)));
|
|
||||||
const auto compareFunc = sampler.GetSamplerCompareFunc();
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &compareFunc, sizeof(compareFunc)));
|
|
||||||
return XXH64_digest(m_hashState);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSampler VkSamplerManager::GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler) {
|
|
||||||
const Uint64 key = BuildSamplerKey(sampler);
|
|
||||||
auto it = m_samplers.find(key);
|
|
||||||
if (it != m_samplers.end()) {
|
|
||||||
return it->second.handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSamplerCreateInfo samplerInfo{};
|
|
||||||
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
|
||||||
samplerInfo.magFilter = ToVkFilter(sampler.GetMagFilter());
|
|
||||||
samplerInfo.minFilter = ToVkFilter(sampler.GetMinFilter());
|
|
||||||
samplerInfo.mipmapMode = ToVkMipmapMode(sampler.GetMipmapMode());
|
|
||||||
samplerInfo.addressModeU = ToVkAddressMode(sampler.GetWrapS());
|
|
||||||
samplerInfo.addressModeV = ToVkAddressMode(sampler.GetWrapT());
|
|
||||||
samplerInfo.addressModeW = ToVkAddressMode(sampler.GetWrapR());
|
|
||||||
samplerInfo.mipLodBias = sampler.GetLodBias();
|
|
||||||
samplerInfo.anisotropyEnable = VK_FALSE;
|
|
||||||
samplerInfo.maxAnisotropy = 1.0f;
|
|
||||||
samplerInfo.compareEnable = sampler.GetCompareMode() == SamplerCompareMode::CompareToTexture ? VK_TRUE : VK_FALSE;
|
|
||||||
samplerInfo.compareOp = ToVkCompareOp(sampler.GetSamplerCompareFunc());
|
|
||||||
samplerInfo.minLod = sampler.GetMinLod();
|
|
||||||
samplerInfo.maxLod = sampler.GetMaxLod();
|
|
||||||
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
|
||||||
samplerInfo.unnormalizedCoordinates = VK_FALSE;
|
|
||||||
|
|
||||||
VkSampler vkSampler = VK_NULL_HANDLE;
|
|
||||||
VK_VERIFY(vkCreateSampler(m_device, &samplerInfo, nullptr, &vkSampler), "vkCreateSampler(texture)");
|
|
||||||
|
|
||||||
SamplerCacheEntry entry{};
|
|
||||||
entry.handle = vkSampler;
|
|
||||||
entry.externalIndex = sampler.GetExternalIndex();
|
|
||||||
entry.version = sampler.GetVersion();
|
|
||||||
m_samplers[key] = entry;
|
|
||||||
return vkSampler;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkFilter VkSamplerManager::ToVkFilter(SamplerFilterMode mode) {
|
|
||||||
return mode == SamplerFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSamplerMipmapMode VkSamplerManager::ToVkMipmapMode(SamplerMipmapMode mode) {
|
|
||||||
switch (mode) {
|
|
||||||
case SamplerMipmapMode::Nearest:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
||||||
case SamplerMipmapMode::Linear:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
case SamplerMipmapMode::None:
|
|
||||||
default:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSamplerAddressMode VkSamplerManager::ToVkAddressMode(SamplerWrapMode mode) {
|
|
||||||
switch (mode) {
|
|
||||||
case SamplerWrapMode::ClampToEdge:
|
|
||||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
case SamplerWrapMode::MirroredRepeat:
|
|
||||||
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
|
||||||
case SamplerWrapMode::Repeat:
|
|
||||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
||||||
case SamplerWrapMode::ClampToBorder:
|
|
||||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
|
||||||
case SamplerWrapMode::MirrorClampToEdge:
|
|
||||||
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
|
||||||
default:
|
|
||||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkCompareOp VkSamplerManager::ToVkCompareOp(SamplerCompareFunc func) {
|
|
||||||
switch (func) {
|
|
||||||
case SamplerCompareFunc::Never:
|
|
||||||
return VK_COMPARE_OP_NEVER;
|
|
||||||
case SamplerCompareFunc::Less:
|
|
||||||
return VK_COMPARE_OP_LESS;
|
|
||||||
case SamplerCompareFunc::Equal:
|
|
||||||
return VK_COMPARE_OP_EQUAL;
|
|
||||||
case SamplerCompareFunc::LessEqual:
|
|
||||||
return VK_COMPARE_OP_LESS_OR_EQUAL;
|
|
||||||
case SamplerCompareFunc::Greater:
|
|
||||||
return VK_COMPARE_OP_GREATER;
|
|
||||||
case SamplerCompareFunc::NotEqual:
|
|
||||||
return VK_COMPARE_OP_NOT_EQUAL;
|
|
||||||
case SamplerCompareFunc::GreaterEqual:
|
|
||||||
return VK_COMPARE_OP_GREATER_OR_EQUAL;
|
|
||||||
case SamplerCompareFunc::Always:
|
|
||||||
default:
|
|
||||||
return VK_COMPARE_OP_ALWAYS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,51 +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;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
|
||||||
class VkSamplerManager {
|
|
||||||
public:
|
|
||||||
struct InitInfo {
|
|
||||||
VkDevice device = VK_NULL_HANDLE;
|
|
||||||
const VulkanRendererConfig* config = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
Bool Initialize(const InitInfo& initInfo);
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
VkSampler GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct SamplerCacheEntry {
|
|
||||||
VkSampler handle = VK_NULL_HANDLE;
|
|
||||||
Uint externalIndex = 0;
|
|
||||||
Uint16 version = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
Uint64 BuildSamplerKey(const MG_State::GLState::SamplerObject& sampler) const;
|
|
||||||
static VkFilter ToVkFilter(SamplerFilterMode mode);
|
|
||||||
static VkSamplerMipmapMode ToVkMipmapMode(SamplerMipmapMode mode);
|
|
||||||
static VkSamplerAddressMode ToVkAddressMode(SamplerWrapMode mode);
|
|
||||||
static VkCompareOp ToVkCompareOp(SamplerCompareFunc func);
|
|
||||||
|
|
||||||
VkDevice m_device = VK_NULL_HANDLE;
|
|
||||||
const VulkanRendererConfig* m_config = nullptr;
|
|
||||||
UnorderedMap<Uint64, SamplerCacheEntry> m_samplers;
|
|
||||||
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
|
||||||
};
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,526 +0,0 @@
|
|||||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp
|
|
||||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
|
||||||
// Licensed under the GNU Lesser General Public License v3.0:
|
|
||||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
|
||||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
|
||||||
// SPDX-License-Identifier: LGPL-3.0-only
|
|
||||||
// End of Source File Header
|
|
||||||
|
|
||||||
#include "VkTextureManager.h"
|
|
||||||
|
|
||||||
#include "MG_State/GLState/Core.h"
|
|
||||||
#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
|
||||||
static constexpr VkPipelineStageFlags kGraphicsSampledReadStages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
|
||||||
|
|
||||||
static Bool IsValidSampledImageLayout(VkImageLayout layout) {
|
|
||||||
switch (layout) {
|
|
||||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
|
||||||
case VK_IMAGE_LAYOUT_GENERAL:
|
|
||||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
|
|
||||||
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
|
|
||||||
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool VkTextureManager::Initialize(const InitInfo& initInfo) {
|
|
||||||
Shutdown();
|
|
||||||
|
|
||||||
m_device = initInfo.device;
|
|
||||||
m_physicalDevice = initInfo.physicalDevice;
|
|
||||||
m_allocator = initInfo.allocator;
|
|
||||||
m_commandPool = initInfo.commandPool;
|
|
||||||
m_graphicsQueue = initInfo.graphicsQueue;
|
|
||||||
|
|
||||||
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE && m_physicalDevice != VK_NULL_HANDLE && m_allocator != nullptr &&
|
|
||||||
m_commandPool != VK_NULL_HANDLE && m_graphicsQueue != VK_NULL_HANDLE,
|
|
||||||
"VkTextureManager::Initialize failed: invalid initialization info");
|
|
||||||
|
|
||||||
TextureResource::s_device = m_device;
|
|
||||||
TextureResource::s_allocator = m_allocator;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VkTextureManager::Shutdown() {
|
|
||||||
m_textureResources.clear();
|
|
||||||
|
|
||||||
m_device = VK_NULL_HANDLE;
|
|
||||||
m_physicalDevice = VK_NULL_HANDLE;
|
|
||||||
m_allocator = nullptr;
|
|
||||||
m_commandPool = VK_NULL_HANDLE;
|
|
||||||
m_graphicsQueue = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkTextureManager::TextureResource* VkTextureManager::SyncTextureAndGetDescriptor(MG_State::GLState::ITextureObject& texture) {
|
|
||||||
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "SyncTextureAndGetDescriptor: m_device == VK_NULL_HANDLE");
|
|
||||||
|
|
||||||
auto it = m_textureResources.find(&texture);
|
|
||||||
if (it == m_textureResources.end()) {
|
|
||||||
TextureResource initial{};
|
|
||||||
auto [insertIt, _] = m_textureResources.emplace(&texture, Move(initial));
|
|
||||||
it = insertIt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SyncTexture(texture, it->second)) {
|
|
||||||
MGLOG_D("%s: Syncing texture %d failed", __func__, texture.GetExternalIndex());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &(it->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VkTextureManager::UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout) {
|
|
||||||
MOBILEGL_ASSERT(texture != nullptr, "UpdateTrackedImageLayout: texture is null");
|
|
||||||
auto it = m_textureResources.find(texture);
|
|
||||||
MOBILEGL_ASSERT(it != m_textureResources.end(),
|
|
||||||
"UpdateTrackedImageLayout: textureId=%d has no tracked resource", texture->GetExternalIndex());
|
|
||||||
MOBILEGL_ASSERT(it->second.image != VK_NULL_HANDLE,
|
|
||||||
"UpdateTrackedImageLayout: textureId=%d has null image", texture->GetExternalIndex());
|
|
||||||
it->second.layout = newLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool VkTextureManager::TransitionTextureForSampling(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture) {
|
|
||||||
TextureResource* resource = SyncTextureAndGetDescriptor(texture);
|
|
||||||
if (resource == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (IsValidSampledImageLayout(resource->layout)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (resource->layout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
|
||||||
MGLOG_W("TransitionTextureForSampling: textureId=%d is still in VK_IMAGE_LAYOUT_UNDEFINED before sampling",
|
|
||||||
texture.GetExternalIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageLayout targetLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
||||||
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
|
||||||
VkAccessFlags srcAccessMask = 0;
|
|
||||||
if ((resource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
|
|
||||||
MOBILEGL_ASSERT(resource->layout == VK_IMAGE_LAYOUT_UNDEFINED ||
|
|
||||||
resource->layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
|
||||||
"TransitionTextureForSampling: unsupported color layout=%d for textureId=%d",
|
|
||||||
static_cast<Int>(resource->layout), texture.GetExternalIndex());
|
|
||||||
if (resource->layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
|
||||||
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
||||||
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
|
||||||
}
|
|
||||||
targetLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
||||||
} else if ((resource->aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) {
|
|
||||||
MOBILEGL_ASSERT(resource->layout == VK_IMAGE_LAYOUT_UNDEFINED ||
|
|
||||||
resource->layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
|
||||||
"TransitionTextureForSampling: unsupported depth/stencil layout=%d for textureId=%d",
|
|
||||||
static_cast<Int>(resource->layout), texture.GetExternalIndex());
|
|
||||||
if (resource->layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
|
||||||
srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
|
||||||
srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
|
||||||
}
|
|
||||||
targetLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
|
||||||
} else {
|
|
||||||
MOBILEGL_ASSERT(false, "TransitionTextureForSampling: unsupported aspect mask=0x%x for textureId=%d",
|
|
||||||
static_cast<Uint32>(resource->aspect), texture.GetExternalIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
const Bool ok = TransitionImageLayout(commandBuffer, resource->image, resource->layout, targetLayout, srcStageMask,
|
|
||||||
kGraphicsSampledReadStages, srcAccessMask,
|
|
||||||
VK_ACCESS_SHADER_READ_BIT, resource->aspect);
|
|
||||||
MOBILEGL_ASSERT(ok, "TransitionTextureForSampling: transition failed for textureId=%d", texture.GetExternalIndex());
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool VkTextureManager::TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image,
|
|
||||||
VkImageLayout& trackedLayout, VkImageLayout newLayout,
|
|
||||||
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
|
|
||||||
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask,
|
|
||||||
VkImageAspectFlags aspectMask) {
|
|
||||||
MOBILEGL_ASSERT(image != VK_NULL_HANDLE, "TransitionImageLayout: m_image == VK_NULL_HANDLE");
|
|
||||||
MOBILEGL_ASSERT(!((dstAccessMask & VK_ACCESS_TRANSFER_READ_BIT) != 0 &&
|
|
||||||
(dstStageMask & VK_PIPELINE_STAGE_TRANSFER_BIT) == 0),
|
|
||||||
"TransitionImageLayout: invalid dstAccess/dstStage pair (dstAccess=0x%x, dstStage=0x%x, oldLayout=%d, newLayout=%d)",
|
|
||||||
static_cast<Uint32>(dstAccessMask), static_cast<Uint32>(dstStageMask), static_cast<Int>(trackedLayout),
|
|
||||||
static_cast<Int>(newLayout));
|
|
||||||
|
|
||||||
if (trackedLayout == newLayout) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageMemoryBarrier barrier{};
|
|
||||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
||||||
barrier.srcAccessMask = srcAccessMask;
|
|
||||||
barrier.dstAccessMask = dstAccessMask;
|
|
||||||
barrier.oldLayout = trackedLayout;
|
|
||||||
barrier.newLayout = newLayout;
|
|
||||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
||||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
||||||
barrier.image = image;
|
|
||||||
barrier.subresourceRange.aspectMask = aspectMask;
|
|
||||||
barrier.subresourceRange.baseMipLevel = 0;
|
|
||||||
barrier.subresourceRange.levelCount = 1;
|
|
||||||
barrier.subresourceRange.baseArrayLayer = 0;
|
|
||||||
barrier.subresourceRange.layerCount = 1;
|
|
||||||
vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
|
||||||
|
|
||||||
trackedLayout = newLayout;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SizeT VkTextureManager::CollectGarbage() {
|
|
||||||
m_gcCounter++;
|
|
||||||
if (m_gcCounter != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
SizeT count = 0;
|
|
||||||
for (const auto& [raw, weak]: m_aliveObjects) {
|
|
||||||
if (weak.expired()) {
|
|
||||||
count++;
|
|
||||||
m_textureResources.erase(raw);
|
|
||||||
m_aliveObjects.erase(raw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool VkTextureManager::SyncTexture(MG_State::GLState::ITextureObject &texture,
|
|
||||||
TextureResource &outResource) {
|
|
||||||
TextureUploadTarget uploadTarget = TextureUploadTarget::Unknown;
|
|
||||||
IntVec3 texelSize{0, 0, 0};
|
|
||||||
SizeT byteSize = 0;
|
|
||||||
Uint32 mipLevelCount = 0;
|
|
||||||
if (!CheckMipmapCompleteness(texture, uploadTarget, texelSize, byteSize, mipLevelCount)) {
|
|
||||||
MGLOG_D("%s: mipmap not complete", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* mipTexture = dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(&texture);
|
|
||||||
if (!mipTexture) {
|
|
||||||
MGLOG_D("%s: not TextureObjectMipmap", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SyncTextureResource(texture, uploadTarget, texelSize, byteSize, mipLevelCount, outResource)) {
|
|
||||||
MGLOG_D("%s: SyncTextureResource failed", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool hasDirtyMipLevel = false;
|
|
||||||
for (Uint32 level = 0; level < mipLevelCount; ++level) {
|
|
||||||
if (mipTexture->IsStorageDirty(uploadTarget, level)) {
|
|
||||||
hasDirtyMipLevel = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!hasDirtyMipLevel) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UploadDirtyMipLevels(*mipTexture, uploadTarget, outResource)) {
|
|
||||||
MGLOG_D("%s: UploadDirtyMipLevels failed", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool VkTextureManager::SyncTextureResource(const MG_State::GLState::ITextureObject &texture,
|
|
||||||
TextureUploadTarget uploadTarget,
|
|
||||||
const IntVec3 &texelSize, SizeT byteSize, Uint32 mipLevels,
|
|
||||||
TextureResource &resource) {
|
|
||||||
const VkFormat format = MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
|
|
||||||
if (format == VK_FORMAT_UNDEFINED) {
|
|
||||||
MGLOG_D("%s: format == VK_FORMAT_UNDEFINED", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (texelSize.x() <= 0 || texelSize.y() <= 0 /*|| byteSize == 0*/) {
|
|
||||||
MGLOG_D("%s: texelSize or byteSize is zero", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (mipLevels == 0) {
|
|
||||||
MGLOG_D("%s: no mip levels", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (uploadTarget != TextureUploadTarget::Texture2D) {
|
|
||||||
MGLOG_D("%s: not Texture2D, unsupported", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Bool compatible = resource.image != VK_NULL_HANDLE && resource.format == format &&
|
|
||||||
resource.extent.width == static_cast<Uint32>(texelSize.x()) &&
|
|
||||||
resource.extent.height == static_cast<Uint32>(texelSize.y()) &&
|
|
||||||
resource.mipLevels == mipLevels;
|
|
||||||
if (compatible) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
resource.Reset();
|
|
||||||
|
|
||||||
auto aspect = GetAspectMaskForFormat(format);
|
|
||||||
|
|
||||||
VkImageCreateInfo imageInfo{};
|
|
||||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
||||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
|
||||||
imageInfo.extent.width = static_cast<Uint32>(texelSize.x());
|
|
||||||
imageInfo.extent.height = static_cast<Uint32>(texelSize.y());
|
|
||||||
imageInfo.extent.depth = 1;
|
|
||||||
imageInfo.mipLevels = mipLevels;
|
|
||||||
imageInfo.arrayLayers = 1;
|
|
||||||
imageInfo.format = format;
|
|
||||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
||||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
imageInfo.usage =
|
|
||||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
|
||||||
((aspect & VK_IMAGE_ASPECT_COLOR_BIT) ?
|
|
||||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : 0) |
|
|
||||||
((aspect & VK_IMAGE_ASPECT_DEPTH_BIT || aspect & VK_IMAGE_ASPECT_STENCIL_BIT) ?
|
|
||||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : 0);
|
|
||||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
VmaAllocationCreateInfo allocationInfo{};
|
|
||||||
allocationInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
|
||||||
allocationInfo.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
|
||||||
VK_VERIFY(vmaCreateImage(m_allocator, &imageInfo, &allocationInfo, &resource.image, &resource.allocation, nullptr),
|
|
||||||
"vmaCreateImage(texture)");
|
|
||||||
|
|
||||||
VkImageViewCreateInfo viewInfo{};
|
|
||||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
||||||
viewInfo.image = resource.image;
|
|
||||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
viewInfo.format = format;
|
|
||||||
viewInfo.subresourceRange.aspectMask = aspect;
|
|
||||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
|
||||||
viewInfo.subresourceRange.levelCount = mipLevels;
|
|
||||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
|
||||||
viewInfo.subresourceRange.layerCount = 1;
|
|
||||||
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &resource.view), "vkCreateImageView(texture)");
|
|
||||||
|
|
||||||
resource.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
resource.extent = {static_cast<Uint32>(texelSize.x()), static_cast<Uint32>(texelSize.y())};
|
|
||||||
resource.mipLevels = mipLevels;
|
|
||||||
resource.format = format;
|
|
||||||
resource.aspect = viewInfo.subresourceRange.aspectMask;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool VkTextureManager::UploadDirtyMipLevels(MG_State::GLState::TextureObjectMipmap &mipmapTexture,
|
|
||||||
TextureUploadTarget uploadTarget,
|
|
||||||
TextureResource &outResource) {
|
|
||||||
struct UploadItem {
|
|
||||||
Uint32 level = 0;
|
|
||||||
SizeT byteSize = 0;
|
|
||||||
IntVec3 texelSize = {0, 0, 0};
|
|
||||||
const void* source = nullptr;
|
|
||||||
VkDeviceSize offset = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
Vector<UploadItem> uploadItems;
|
|
||||||
uploadItems.reserve(outResource.mipLevels);
|
|
||||||
|
|
||||||
VkDeviceSize stagingSize = 0;
|
|
||||||
for (Uint32 level = 0; level < outResource.mipLevels; ++level) {
|
|
||||||
if (!mipmapTexture.IsStorageDirty(uploadTarget, level)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto texelSize = mipmapTexture.GetMipmapTexelSize(uploadTarget, level);
|
|
||||||
const auto byteSize = mipmapTexture.GetMipmapByteSize(uploadTarget, level);
|
|
||||||
if (texelSize.x() <= 0 || texelSize.y() <= 0 || byteSize == 0) {
|
|
||||||
mipmapTexture.MarkStorageDirty(uploadTarget, level, false);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const void* source = mipmapTexture.MapMipmapData(uploadTarget, level);
|
|
||||||
if (source == nullptr) {
|
|
||||||
MGLOG_D("%s: MapmipmapData failed at level %d", __func__, level);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadItems.push_back({level, byteSize, texelSize, source, stagingSize});
|
|
||||||
stagingSize += static_cast<VkDeviceSize>(byteSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uploadItems.empty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkBuffer stagingBuffer = VK_NULL_HANDLE;
|
|
||||||
VmaAllocation stagingAllocation = nullptr;
|
|
||||||
|
|
||||||
VkBufferCreateInfo bufferInfo{};
|
|
||||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
||||||
bufferInfo.size = stagingSize;
|
|
||||||
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
|
||||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
VmaAllocationCreateInfo stagingAllocationInfo{};
|
|
||||||
stagingAllocationInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
|
|
||||||
stagingAllocationInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
|
||||||
stagingAllocationInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
|
||||||
VK_VERIFY(vmaCreateBuffer(m_allocator, &bufferInfo, &stagingAllocationInfo, &stagingBuffer, &stagingAllocation, nullptr),
|
|
||||||
"vmaCreateBuffer(staging texture)");
|
|
||||||
|
|
||||||
void* mapped = nullptr;
|
|
||||||
VK_VERIFY(vmaMapMemory(m_allocator, stagingAllocation, &mapped), "vmaMapMemory(staging texture)");
|
|
||||||
for (const auto& item : uploadItems) {
|
|
||||||
std::memcpy(static_cast<Uint8*>(mapped) + item.offset, item.source, item.byteSize);
|
|
||||||
}
|
|
||||||
vmaUnmapMemory(m_allocator, stagingAllocation);
|
|
||||||
|
|
||||||
VkCommandBufferAllocateInfo allocInfo{};
|
|
||||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
||||||
allocInfo.commandPool = m_commandPool;
|
|
||||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
||||||
allocInfo.commandBufferCount = 1;
|
|
||||||
|
|
||||||
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
|
||||||
VK_VERIFY(vkAllocateCommandBuffers(m_device, &allocInfo, &commandBuffer), "vkAllocateCommandBuffers(texture)");
|
|
||||||
|
|
||||||
VkCommandBufferBeginInfo beginInfo{};
|
|
||||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
||||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
||||||
VK_VERIFY(vkBeginCommandBuffer(commandBuffer, &beginInfo), "vkBeginCommandBuffer(texture)");
|
|
||||||
|
|
||||||
const VkImageAspectFlags aspectMask = GetAspectMaskForFormat(outResource.format);
|
|
||||||
Bool ok = TransitionImageLayout(commandBuffer, outResource.image,
|
|
||||||
outResource.layout,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
||||||
outResource.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ?
|
|
||||||
kGraphicsSampledReadStages :
|
|
||||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
||||||
outResource.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ? VK_ACCESS_SHADER_READ_BIT : 0,
|
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
||||||
aspectMask);
|
|
||||||
MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL failed");
|
|
||||||
|
|
||||||
for (const auto& item : uploadItems) {
|
|
||||||
VkBufferImageCopy copy{};
|
|
||||||
copy.bufferOffset = item.offset;
|
|
||||||
copy.bufferRowLength = 0;
|
|
||||||
copy.bufferImageHeight = 0;
|
|
||||||
copy.imageSubresource.aspectMask = aspectMask;
|
|
||||||
copy.imageSubresource.mipLevel = item.level;
|
|
||||||
copy.imageSubresource.baseArrayLayer = 0;
|
|
||||||
copy.imageSubresource.layerCount = 1;
|
|
||||||
copy.imageOffset = {0, 0, 0};
|
|
||||||
copy.imageExtent = {static_cast<Uint32>(item.texelSize.x()), static_cast<Uint32>(item.texelSize.y()), 1};
|
|
||||||
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, outResource.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
||||||
1, ©);
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = TransitionImageLayout(commandBuffer, outResource.image,
|
|
||||||
outResource.layout,
|
|
||||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
||||||
kGraphicsSampledReadStages,
|
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
||||||
VK_ACCESS_SHADER_READ_BIT,
|
|
||||||
aspectMask);
|
|
||||||
MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL failed");
|
|
||||||
outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
||||||
|
|
||||||
VK_VERIFY(vkEndCommandBuffer(commandBuffer), "vkEndCommandBuffer(texture)");
|
|
||||||
|
|
||||||
VkSubmitInfo submitInfo{};
|
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
||||||
submitInfo.commandBufferCount = 1;
|
|
||||||
submitInfo.pCommandBuffers = &commandBuffer;
|
|
||||||
|
|
||||||
VkFenceCreateInfo fenceInfo{};
|
|
||||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
|
||||||
VkFence uploadFence = VK_NULL_HANDLE;
|
|
||||||
VK_VERIFY(vkCreateFence(m_device, &fenceInfo, nullptr, &uploadFence), "vkCreateFence(texture upload)");
|
|
||||||
|
|
||||||
VK_VERIFY(vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, uploadFence), "vkQueueSubmit(texture)");
|
|
||||||
VK_VERIFY(vkWaitForFences(m_device, 1, &uploadFence, VK_TRUE, UINT64_MAX), "vkWaitForFences(texture upload)");
|
|
||||||
vkDestroyFence(m_device, uploadFence, nullptr);
|
|
||||||
vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer);
|
|
||||||
|
|
||||||
vmaDestroyBuffer(m_allocator, stagingBuffer, stagingAllocation);
|
|
||||||
|
|
||||||
if (!ok) {
|
|
||||||
MGLOG_D("%s: texture upload cmd failed", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (const auto& item : uploadItems) {
|
|
||||||
mipmapTexture.MarkStorageDirty(uploadTarget, item.level, false);
|
|
||||||
}
|
|
||||||
outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool VkTextureManager::CheckMipmapCompleteness(const MG_State::GLState::ITextureObject& texture,
|
|
||||||
TextureUploadTarget& outTarget,
|
|
||||||
IntVec3& outTexelSize,
|
|
||||||
SizeT& outByteSize,
|
|
||||||
Uint32& outMipLevelCount) {
|
|
||||||
const auto* mipTexture = dynamic_cast<const MG_State::GLState::TextureObjectMipmap*>(&texture);
|
|
||||||
if (!mipTexture) {
|
|
||||||
MGLOG_D("%s: not TextureObjectMipmap", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto& targets = texture.GetUploadTargets();
|
|
||||||
if (targets.empty()) {
|
|
||||||
MGLOG_D("%s: upload target empty", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto target : targets) {
|
|
||||||
const Uint32 mipLevelCount = GetUploadMipLevelCount(*mipTexture, target);
|
|
||||||
if (mipLevelCount == 0) {
|
|
||||||
MGLOG_D("%s: mipLevelCount == 0", __func__);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto level0TexelSize = mipTexture->GetMipmapTexelSize(target, 0);
|
|
||||||
const auto level0ByteSize = mipTexture->GetMipmapByteSize(target, 0);
|
|
||||||
if (level0TexelSize.x() <= 0 || level0TexelSize.y() <= 0 /*|| level0ByteSize == 0*/) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
outTarget = target;
|
|
||||||
outTexelSize = level0TexelSize;
|
|
||||||
outByteSize = level0ByteSize;
|
|
||||||
outMipLevelCount = mipLevelCount;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MGLOG_D("%s: no valid target or mipmap", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint32 VkTextureManager::GetUploadMipLevelCount(const MG_State::GLState::TextureObjectMipmap& texture,
|
|
||||||
TextureUploadTarget target) {
|
|
||||||
const Uint totalLevelCount = texture.GetMipmapLevelCount();
|
|
||||||
if (totalLevelCount == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint32 validLevelCount = 0;
|
|
||||||
for (Uint level = 0; level < totalLevelCount; ++level) {
|
|
||||||
const auto size = texture.GetMipmapTexelSize(target, level);
|
|
||||||
const auto byteSize = texture.GetMipmapByteSize(target, level);
|
|
||||||
if (size.x() <= 0 || size.y() <= 0 /*|| byteSize == 0*/) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++validLevelCount;
|
|
||||||
}
|
|
||||||
return validLevelCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageAspectFlags VkTextureManager::GetAspectMaskForFormat(VkFormat format) {
|
|
||||||
switch (format) {
|
|
||||||
case VK_FORMAT_D16_UNORM:
|
|
||||||
case VK_FORMAT_X8_D24_UNORM_PACK32:
|
|
||||||
case VK_FORMAT_D32_SFLOAT:
|
|
||||||
return VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
||||||
case VK_FORMAT_S8_UINT:
|
|
||||||
return VK_IMAGE_ASPECT_STENCIL_BIT;
|
|
||||||
case VK_FORMAT_D16_UNORM_S8_UINT:
|
|
||||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
|
||||||
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
|
||||||
return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
|
||||||
default:
|
|
||||||
return VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
@@ -1,122 +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;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TextureResource {
|
|
||||||
VkImage image = VK_NULL_HANDLE;
|
|
||||||
VmaAllocation allocation = nullptr;
|
|
||||||
VkImageView view = VK_NULL_HANDLE;
|
|
||||||
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
VkExtent2D extent = {0, 0};
|
|
||||||
Uint32 mipLevels = 1;
|
|
||||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
|
||||||
VkImageAspectFlags aspect = VK_IMAGE_ASPECT_NONE;
|
|
||||||
|
|
||||||
TextureResource() = default;
|
|
||||||
TextureResource(const TextureResource&) = delete;
|
|
||||||
TextureResource(TextureResource&& that) noexcept {
|
|
||||||
std::swap(this->image, that.image);
|
|
||||||
std::swap(this->allocation, that.allocation);
|
|
||||||
std::swap(this->view, that.view);
|
|
||||||
std::swap(this->layout, that.layout);
|
|
||||||
std::swap(this->extent, that.extent);
|
|
||||||
std::swap(this->mipLevels, that.mipLevels);
|
|
||||||
std::swap(this->format, that.format);
|
|
||||||
std::swap(this->aspect, that.aspect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
if (view != VK_NULL_HANDLE) {
|
|
||||||
vkDestroyImageView(s_device, view, nullptr);
|
|
||||||
}
|
|
||||||
if (image != VK_NULL_HANDLE && allocation != nullptr) {
|
|
||||||
vmaDestroyImage(s_allocator, image, allocation);
|
|
||||||
}
|
|
||||||
view = VK_NULL_HANDLE;
|
|
||||||
image = VK_NULL_HANDLE;
|
|
||||||
allocation = nullptr;
|
|
||||||
layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
extent = {0, 0};
|
|
||||||
mipLevels = 1;
|
|
||||||
format = VK_FORMAT_UNDEFINED;
|
|
||||||
aspect = VK_IMAGE_ASPECT_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
~TextureResource() {
|
|
||||||
Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline VkDevice s_device = VK_NULL_HANDLE;
|
|
||||||
static inline VmaAllocator s_allocator = VK_NULL_HANDLE;
|
|
||||||
};
|
|
||||||
|
|
||||||
Bool Initialize(const InitInfo& initInfo);
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
TextureResource* SyncTextureAndGetDescriptor(
|
|
||||||
MG_State::GLState::ITextureObject& texture);
|
|
||||||
void UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout);
|
|
||||||
Bool TransitionTextureForSampling(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture);
|
|
||||||
|
|
||||||
static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout,
|
|
||||||
VkImageLayout newLayout, VkPipelineStageFlags srcStageMask,
|
|
||||||
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
|
|
||||||
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask);
|
|
||||||
|
|
||||||
SizeT CollectGarbage();
|
|
||||||
private:
|
|
||||||
|
|
||||||
Bool SyncTexture(MG_State::GLState::ITextureObject &texture,
|
|
||||||
TextureResource &outResource);
|
|
||||||
Bool SyncTextureResource(const MG_State::GLState::ITextureObject &texture,
|
|
||||||
TextureUploadTarget uploadTarget,
|
|
||||||
const IntVec3 &texelSize, SizeT byteSize, Uint32 mipLevels,
|
|
||||||
TextureResource &resource);
|
|
||||||
Bool UploadDirtyMipLevels(MG_State::GLState::TextureObjectMipmap &mipmapTexture,
|
|
||||||
TextureUploadTarget uploadTarget,
|
|
||||||
TextureResource &outResource);
|
|
||||||
static Bool CheckMipmapCompleteness(const MG_State::GLState::ITextureObject& texture,
|
|
||||||
TextureUploadTarget& outTarget,
|
|
||||||
IntVec3& outTexelSize,
|
|
||||||
SizeT& outByteSize,
|
|
||||||
Uint32& outMipLevelCount);
|
|
||||||
static Uint32 GetUploadMipLevelCount(const MG_State::GLState::TextureObjectMipmap& texture, TextureUploadTarget target);
|
|
||||||
static VkImageAspectFlags GetAspectMaskForFormat(VkFormat format);
|
|
||||||
|
|
||||||
VkDevice m_device = VK_NULL_HANDLE;
|
|
||||||
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
|
||||||
VmaAllocator m_allocator = nullptr;
|
|
||||||
VkCommandPool m_commandPool = VK_NULL_HANDLE;
|
|
||||||
VkQueue m_graphicsQueue = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
Uint8 m_gcCounter = 0;
|
|
||||||
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
|
|
||||||
UnorderedMap<MG_State::GLState::ITextureObject*, TextureResource> m_textureResources;
|
|
||||||
};
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,230 +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 "UniformDescriptorBinder.h"
|
|
||||||
#include "VertexInputStateFactory.h"
|
|
||||||
#include "VkBufferObject.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,
|
|
||||||
Viewport = 1 << 5,
|
|
||||||
Scissor = 1 << 6,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DrawArrayCmd {
|
|
||||||
GLenum mode = GL_TRIANGLES;
|
|
||||||
GLint first = 0;
|
|
||||||
GLsizei count = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DrawElementCmd: public DrawArrayCmd {
|
|
||||||
GLenum indexType = GL_UNSIGNED_SHORT;
|
|
||||||
SizeT indexByteOffset = 0;
|
|
||||||
GLint baseVertex = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
void SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags<DrawSetupAspect> aspects);
|
|
||||||
void ClearAttachmentsOnActiveRenderPass(VkCommandBuffer commandBuffer,
|
|
||||||
const RenderPassEntry& compatibleRenderPassEntry);
|
|
||||||
|
|
||||||
void Clear(GLbitfield mask);
|
|
||||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
|
||||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
|
||||||
GLbitfield mask, GLenum filter);
|
|
||||||
void DrawArrays(const DrawArrayCmd& payload);
|
|
||||||
void DrawElements(const DrawElementCmd& payload);
|
|
||||||
void MultiDrawElements(const Vector<DrawElementCmd>& payloads);
|
|
||||||
void Present();
|
|
||||||
|
|
||||||
const PhysicalDevice& GetPhysicalDevice() 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
NativeWindowType m_window = 0;
|
|
||||||
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;
|
|
||||||
using PFNDrawIndexedIndirectCountFunc = void(VKAPI_PTR*)(VkCommandBuffer commandBuffer, VkBuffer buffer,
|
|
||||||
VkDeviceSize offset, VkBuffer countBuffer,
|
|
||||||
VkDeviceSize countBufferOffset, Uint32 maxDrawCount,
|
|
||||||
Uint32 stride);
|
|
||||||
PFNDrawIndexedIndirectCountFunc m_cmdDrawIndexedIndirectCount = nullptr;
|
|
||||||
|
|
||||||
VkCommandPool m_commandPool = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
Vector<VkBufferObject> m_frameVertexUploadBuffers;
|
|
||||||
Vector<VkDeviceSize> m_frameVertexUploadHeads;
|
|
||||||
Vector<VkBufferObject> m_frameIndexUploadBuffers;
|
|
||||||
Vector<VkDeviceSize> m_frameIndexUploadHeads;
|
|
||||||
Vector<Vector<VkBufferObject>> m_deferredBufferReleases;
|
|
||||||
|
|
||||||
Uint m_imageIndexAcquired = 0;
|
|
||||||
FrameContext m_frameContext;
|
|
||||||
|
|
||||||
UniquePtr<PipelineFactory> m_pipelineFactory;
|
|
||||||
UniquePtr<ProgramFactory> m_programFactory;
|
|
||||||
UniquePtr<UniformDescriptorBinder> m_uniformDescriptorBinder;
|
|
||||||
UniquePtr<VertexInputStateFactory> m_vertexInputStateFactory;
|
|
||||||
UniquePtr<VkClearManager> m_clearManager;
|
|
||||||
UniquePtr<VkRenderPassManager> m_renderPassManager;
|
|
||||||
UniquePtr<VkTextureManager> m_textureManager;
|
|
||||||
UniquePtr<VkSamplerManager> m_samplerManager;
|
|
||||||
BlitResources m_blitResources;
|
|
||||||
|
|
||||||
void CreateInstance();
|
|
||||||
VkResult SetupDebugMessenger();
|
|
||||||
VkResult DestroyDebugMessenger();
|
|
||||||
VkDebugUtilsMessengerCreateInfoEXT PopulateDebugMessengerCreateInfo();
|
|
||||||
void CreateSurface();
|
|
||||||
void PickPhysicalDevice();
|
|
||||||
void CreateLogicalDeviceAndQueues();
|
|
||||||
void CreateAllocator();
|
|
||||||
void DestroyAllocator();
|
|
||||||
void CreateSwapchain();
|
|
||||||
void CreateCommandPool();
|
|
||||||
void CreateFrameContexts();
|
|
||||||
|
|
||||||
VkPipeline GetOrCreatePipeline(
|
|
||||||
GLenum mode,
|
|
||||||
const MG_State::GLState::ProgramObject& program,
|
|
||||||
const MG_State::GLState::VertexArrayObject& vao,
|
|
||||||
const RenderPassEntry& renderPassEntry);
|
|
||||||
|
|
||||||
void DeferDestroyBuffer(VkBufferObject& buffer);
|
|
||||||
void CollectDeferredBufferReleases(Uint32 frameIndex);
|
|
||||||
Bool EnsureFrameUploadBufferCapacity(Uint32 frameIndex, Bool isIndexBuffer, VkDeviceSize requiredEndOffset,
|
|
||||||
VkDeviceSize minCapacity, VkBufferUsageFlags usage);
|
|
||||||
Bool UploadAndBindVertexStreams(VkCommandBuffer commandBuffer, const MG_State::GLState::VertexArrayObject& vao);
|
|
||||||
Bool InitializeBlitResources();
|
|
||||||
void ShutdownBlitResources();
|
|
||||||
Bool TryBlitToDefaultFramebufferWithShader(FrameContext::FrameData& frame,
|
|
||||||
MG_State::GLState::FramebufferObject& readFbo,
|
|
||||||
MG_State::GLState::FramebufferObject& drawFbo,
|
|
||||||
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
|
||||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
|
||||||
GLenum filter);
|
|
||||||
Bool MaterializePendingClearForTexture(VkCommandBuffer commandBuffer,
|
|
||||||
MG_State::GLState::ITextureObject& texture);
|
|
||||||
VkPipeline GetOrCreateBlitPipeline(const RenderPassEntry& renderPassEntry);
|
|
||||||
|
|
||||||
void ShutdownSwapchain();
|
|
||||||
|
|
||||||
// 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 Uint64 BuildPendingClearKey(Uint drawFboExternalIndex, Bool targetsDefaultFramebuffer);
|
|
||||||
static constexpr VkDynamicState s_dynamicStates[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
|
|
||||||
static constexpr const char* s_validationLayerNames[] = {"VK_LAYER_KHRONOS_validation"};
|
|
||||||
static constexpr const char* s_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,20 +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";
|
|
||||||
Version Version = MG_Config::CoreVersion;
|
|
||||||
Uint64 CacheVersion = MG_Config::CacheVersion;
|
|
||||||
Bool EnableValidationLayers = true;
|
|
||||||
};
|
|
||||||
} // 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
|
||||||
+7
-11
@@ -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,18 +11,14 @@
|
|||||||
#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() override;
|
~BackendObject_DirectVulkanTMP() 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;
|
|
||||||
|
|
||||||
const RendererInfo& GetRendererInfo() const override;
|
const RendererInfo& GetRendererInfo() const override;
|
||||||
String GetBackendAPIVersionString() const override;
|
String GetBackendAPIVersionString() const override;
|
||||||
@@ -37,4 +33,4 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
DynamicBackendParameters m_dynamicParameters;
|
DynamicBackendParameters m_dynamicParameters;
|
||||||
MG_External::VulkanCapabilities m_vulkanCaps;
|
MG_External::VulkanCapabilities m_vulkanCaps;
|
||||||
};
|
};
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
} // namespace MobileGL::MG_Backend::DirectVulkanTMP
|
||||||
+28
-74
@@ -1,4 +1,4 @@
|
|||||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp
|
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/DirectVulkanTMP.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,22 +6,28 @@
|
|||||||
// SPDX-License-Identifier: LGPL-3.0-only
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
#include "DirectVulkan.h"
|
#include "DirectVulkanTMP.h"
|
||||||
#include "MG_State/GLState/Core.h"
|
#include "TmpImpl.h"
|
||||||
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
namespace MobileGL::MG_Backend::DirectVulkanTMP {
|
||||||
UniquePtr<VulkanRenderer> pVulkanRenderer = nullptr;
|
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 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 DrawArrays(GLenum mode, GLint first, GLsizei count) {}
|
||||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) {}
|
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) {}
|
||||||
|
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,
|
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 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,
|
||||||
@@ -39,6 +45,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
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 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,
|
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,
|
||||||
@@ -47,74 +55,20 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {}
|
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {}
|
||||||
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 MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
Bool InitWindowSurface(NativeWindowType window) {
|
||||||
GLsizei drawcount) {
|
if (!window) {
|
||||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer");
|
MGLOG_E("Cannot initialize Vulkan window surface: invalid window handle");
|
||||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElements called with null GL context");
|
return false;
|
||||||
|
|
||||||
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.first = 0;
|
|
||||||
payload.count = count[i];
|
|
||||||
payload.indexType = type;
|
|
||||||
payload.indexByteOffset = reinterpret_cast<SizeT>(indices[i]);
|
|
||||||
cmds.push_back(payload);
|
|
||||||
}
|
}
|
||||||
|
TmpImpl::InitVulkan(window);
|
||||||
if (cmds.empty()) {
|
return true;
|
||||||
return;
|
|
||||||
}
|
|
||||||
pVulkanRenderer->MultiDrawElements(cmds);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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");
|
|
||||||
|
|
||||||
DrawElementCmd payload{};
|
|
||||||
payload.mode = mode;
|
|
||||||
payload.first = 0;
|
|
||||||
payload.count = count;
|
|
||||||
payload.indexType = type;
|
|
||||||
payload.indexByteOffset = reinterpret_cast<SizeT>(indices);
|
|
||||||
|
|
||||||
pVulkanRenderer->DrawElements(payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
DrawArrayCmd payload{};
|
|
||||||
payload.mode = mode;
|
|
||||||
payload.first = first;
|
|
||||||
payload.count = count;
|
|
||||||
|
|
||||||
pVulkanRenderer->DrawArrays(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 Present() {
|
void Present() {
|
||||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Present called with null VulkanRenderer");
|
TmpImpl::Present();
|
||||||
pVulkanRenderer->Present();
|
|
||||||
}
|
}
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
|
||||||
|
const TmpImpl::VulkanState& GetVulkanState() {
|
||||||
|
return TmpImpl::GetVulkanState();
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkanTMP
|
||||||
+8
-5
@@ -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,10 +8,11 @@
|
|||||||
|
|
||||||
#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);
|
||||||
@@ -51,5 +52,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
void GenerateMipmap(GLenum target);
|
void GenerateMipmap(GLenum target);
|
||||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
void 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);
|
||||||
|
Bool InitWindowSurface(NativeWindowType window);
|
||||||
void Present();
|
void Present();
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
const TmpImpl::VulkanState& GetVulkanState();
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkanTMP
|
||||||
+169
-127
@@ -1,4 +1,4 @@
|
|||||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp
|
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Managers/ProgramManager.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,37 +6,41 @@
|
|||||||
// SPDX-License-Identifier: LGPL-3.0-only
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
#include "ProgramFactory.h"
|
#include "ProgramManager.h"
|
||||||
|
|
||||||
#include <spirv-tools/libspirv.h>
|
#include "MG_Util/Debug/Log.h"
|
||||||
#include <spirv-tools/optimizer.hpp>
|
#include "spirv-tools/libspirv.h"
|
||||||
#include <source/opt/constants.h>
|
#include "spirv-tools/optimizer.hpp"
|
||||||
#include <source/opt/instruction.h>
|
#include "source/opt/constants.h"
|
||||||
#include <source/opt/ir_builder.h>
|
#include "source/opt/instruction.h"
|
||||||
#include <source/opt/ir_context.h>
|
#include "source/opt/ir_builder.h"
|
||||||
#include <source/opt/module.h>
|
#include "source/opt/ir_context.h"
|
||||||
#include <source/opt/pass.h>
|
#include "source/opt/module.h"
|
||||||
#include <source/opt/type_manager.h>
|
#include "source/opt/pass.h"
|
||||||
|
#include "source/opt/type_manager.h"
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
#include <bit>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager {
|
||||||
namespace {
|
namespace {
|
||||||
|
using ProgramObject = MG_State::GLState::ProgramObject;
|
||||||
using ShaderObject = MG_State::GLState::ShaderObject;
|
using ShaderObject = MG_State::GLState::ShaderObject;
|
||||||
|
|
||||||
struct PositionTargetInfo {
|
struct PositionTargetInfo {
|
||||||
Uint32 variableId = 0;
|
uint32_t variableId = 0;
|
||||||
Uint32 vectorTypeId = 0;
|
uint32_t vectorTypeId = 0;
|
||||||
Uint32 floatTypeId = 0;
|
uint32_t floatTypeId = 0;
|
||||||
Uint32 vectorPtrTypeId = 0;
|
uint32_t vectorPtrTypeId = 0;
|
||||||
Uint32 memberIndex = 0;
|
uint32_t memberIndex = 0;
|
||||||
Bool isMember = false;
|
bool isMember = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Bool IsVec4Float32(spvtools::opt::IRContext* context, Uint32 typeId, Uint32* outFloatTypeId) {
|
bool IsVec4Float32(spvtools::opt::IRContext* context, uint32_t typeId, uint32_t* outFloatTypeId) {
|
||||||
auto* vecInst = context->get_def_use_mgr()->GetDef(typeId);
|
auto* vecInst = context->get_def_use_mgr()->GetDef(typeId);
|
||||||
if (!vecInst || vecInst->opcode() != spv::Op::OpTypeVector) return false;
|
if (!vecInst || vecInst->opcode() != spv::Op::OpTypeVector) return false;
|
||||||
if (vecInst->GetSingleWordInOperand(1) != 4) return false;
|
if (vecInst->GetSingleWordInOperand(1) != 4) return false;
|
||||||
|
|
||||||
const Uint32 floatTypeId = vecInst->GetSingleWordInOperand(0);
|
const uint32_t floatTypeId = vecInst->GetSingleWordInOperand(0);
|
||||||
auto* floatInst = context->get_def_use_mgr()->GetDef(floatTypeId);
|
auto* floatInst = context->get_def_use_mgr()->GetDef(floatTypeId);
|
||||||
if (!floatInst || floatInst->opcode() != spv::Op::OpTypeFloat) return false;
|
if (!floatInst || floatInst->opcode() != spv::Op::OpTypeFloat) return false;
|
||||||
if (floatInst->GetSingleWordInOperand(0) != 32) return false;
|
if (floatInst->GetSingleWordInOperand(0) != 32) return false;
|
||||||
@@ -45,15 +49,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool ResolveDirectPositionTarget(spvtools::opt::IRContext* context, Uint32 variableId,
|
bool ResolveDirectPositionTarget(spvtools::opt::IRContext* context, uint32_t variableId,
|
||||||
PositionTargetInfo* outTarget) {
|
PositionTargetInfo* outTarget) {
|
||||||
auto* varInst = context->get_def_use_mgr()->GetDef(variableId);
|
auto* varInst = context->get_def_use_mgr()->GetDef(variableId);
|
||||||
if (!varInst || varInst->opcode() != spv::Op::OpVariable) return false;
|
if (!varInst || varInst->opcode() != spv::Op::OpVariable) return false;
|
||||||
if (varInst->GetSingleWordInOperand(0) != static_cast<Uint32>(spv::StorageClass::Output)) 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());
|
auto* ptrTypeInst = context->get_def_use_mgr()->GetDef(varInst->type_id());
|
||||||
if (!ptrTypeInst || ptrTypeInst->opcode() != spv::Op::OpTypePointer) return false;
|
if (!ptrTypeInst || ptrTypeInst->opcode() != spv::Op::OpTypePointer) return false;
|
||||||
if (ptrTypeInst->GetSingleWordInOperand(0) != static_cast<Uint32>(spv::StorageClass::Output)) return false;
|
if (ptrTypeInst->GetSingleWordInOperand(0) != static_cast<uint32_t>(spv::StorageClass::Output))
|
||||||
|
return false;
|
||||||
|
|
||||||
PositionTargetInfo target{};
|
PositionTargetInfo target{};
|
||||||
target.variableId = variableId;
|
target.variableId = variableId;
|
||||||
@@ -66,33 +71,34 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint32 FindOutputVectorPointerTypeId(spvtools::opt::IRContext* context, Uint32 vectorTypeId) {
|
uint32_t FindOutputVectorPointerTypeId(spvtools::opt::IRContext* context, uint32_t vectorTypeId) {
|
||||||
auto* vectorType = context->get_type_mgr()->GetType(vectorTypeId);
|
auto* vectorType = context->get_type_mgr()->GetType(vectorTypeId);
|
||||||
if (!vectorType) return 0;
|
if (!vectorType) return 0;
|
||||||
spvtools::opt::analysis::Pointer ptrType(vectorType, spv::StorageClass::Output);
|
spvtools::opt::analysis::Pointer ptrType(vectorType, spv::StorageClass::Output);
|
||||||
return context->get_type_mgr()->GetTypeInstruction(&ptrType);
|
return context->get_type_mgr()->GetTypeInstruction(&ptrType);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool ResolveMemberPositionTarget(spvtools::opt::IRContext* context, Uint32 structTypeId, Uint32 memberIndex,
|
bool ResolveMemberPositionTarget(spvtools::opt::IRContext* context, uint32_t structTypeId, uint32_t memberIndex,
|
||||||
PositionTargetInfo* outTarget) {
|
PositionTargetInfo* outTarget) {
|
||||||
auto* structInst = context->get_def_use_mgr()->GetDef(structTypeId);
|
auto* structInst = context->get_def_use_mgr()->GetDef(structTypeId);
|
||||||
if (!structInst || structInst->opcode() != spv::Op::OpTypeStruct) return false;
|
if (!structInst || structInst->opcode() != spv::Op::OpTypeStruct) return false;
|
||||||
if (memberIndex >= structInst->NumInOperands()) return false;
|
if (memberIndex >= structInst->NumInOperands()) return false;
|
||||||
|
|
||||||
const Uint32 vectorTypeId = structInst->GetSingleWordInOperand(memberIndex);
|
const uint32_t vectorTypeId = structInst->GetSingleWordInOperand(memberIndex);
|
||||||
Uint32 floatTypeId = 0;
|
uint32_t floatTypeId = 0;
|
||||||
if (!IsVec4Float32(context, vectorTypeId, &floatTypeId)) return false;
|
if (!IsVec4Float32(context, vectorTypeId, &floatTypeId)) return false;
|
||||||
|
|
||||||
const Uint32 vectorPtrTypeId = FindOutputVectorPointerTypeId(context, vectorTypeId);
|
const uint32_t vectorPtrTypeId = FindOutputVectorPointerTypeId(context, vectorTypeId);
|
||||||
if (vectorPtrTypeId == 0) return false;
|
if (vectorPtrTypeId == 0) return false;
|
||||||
|
|
||||||
for (auto& inst : context->module()->types_values()) {
|
for (auto& inst : context->module()->types_values()) {
|
||||||
if (inst.opcode() != spv::Op::OpVariable) continue;
|
if (inst.opcode() != spv::Op::OpVariable) continue;
|
||||||
if (inst.GetSingleWordInOperand(0) != static_cast<Uint32>(spv::StorageClass::Output)) continue;
|
if (inst.GetSingleWordInOperand(0) != static_cast<uint32_t>(spv::StorageClass::Output)) continue;
|
||||||
|
|
||||||
auto* ptrTypeInst = context->get_def_use_mgr()->GetDef(inst.type_id());
|
auto* ptrTypeInst = context->get_def_use_mgr()->GetDef(inst.type_id());
|
||||||
if (!ptrTypeInst || ptrTypeInst->opcode() != spv::Op::OpTypePointer) continue;
|
if (!ptrTypeInst || ptrTypeInst->opcode() != spv::Op::OpTypePointer) continue;
|
||||||
if (ptrTypeInst->GetSingleWordInOperand(0) != static_cast<Uint32>(spv::StorageClass::Output)) continue;
|
if (ptrTypeInst->GetSingleWordInOperand(0) != static_cast<uint32_t>(spv::StorageClass::Output))
|
||||||
|
continue;
|
||||||
if (ptrTypeInst->GetSingleWordInOperand(1) != structTypeId) continue;
|
if (ptrTypeInst->GetSingleWordInOperand(1) != structTypeId) continue;
|
||||||
|
|
||||||
PositionTargetInfo target{};
|
PositionTargetInfo target{};
|
||||||
@@ -109,10 +115,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool FindPositionTarget(spvtools::opt::IRContext* context, PositionTargetInfo* outTarget) {
|
bool FindPositionTarget(spvtools::opt::IRContext* context, PositionTargetInfo* outTarget) {
|
||||||
Vector<Pair<Uint32, Uint32>> memberCandidates;
|
Vector<Pair<uint32_t, uint32_t>> memberCandidates;
|
||||||
constexpr auto kDecorationBuiltIn = static_cast<Uint32>(spv::Decoration::BuiltIn);
|
constexpr uint32_t kDecorationBuiltIn = static_cast<uint32_t>(spv::Decoration::BuiltIn);
|
||||||
constexpr auto kBuiltInPosition = static_cast<Uint32>(spv::BuiltIn::Position);
|
constexpr uint32_t kBuiltInPosition = static_cast<uint32_t>(spv::BuiltIn::Position);
|
||||||
|
|
||||||
for (auto& inst : context->module()->annotations()) {
|
for (auto& inst : context->module()->annotations()) {
|
||||||
if (inst.opcode() == spv::Op::OpDecorate) {
|
if (inst.opcode() == spv::Op::OpDecorate) {
|
||||||
@@ -134,16 +140,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool InsertPositionFixup(spvtools::opt::IRContext* context, spvtools::opt::Instruction* insertBefore,
|
bool InsertPositionFixup(spvtools::opt::IRContext* context, spvtools::opt::Instruction* insertBefore,
|
||||||
const PositionTargetInfo& target, Uint32 halfConstId, Bool doYFlip, Bool doZRemap,
|
const PositionTargetInfo& target, uint32_t halfConstId, bool doYFlip, bool doZRemap) {
|
||||||
Bool doSurfaceRotate90, Bool doSurfaceRotate180, Bool doSurfaceRotate270) {
|
|
||||||
using namespace spvtools::opt;
|
using namespace spvtools::opt;
|
||||||
InstructionBuilder builder(context, insertBefore,
|
InstructionBuilder builder(context, insertBefore,
|
||||||
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
|
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
|
||||||
|
|
||||||
Uint32 positionPtrId = target.variableId;
|
uint32_t positionPtrId = target.variableId;
|
||||||
if (target.isMember) {
|
if (target.isMember) {
|
||||||
const Uint32 memberIndexId = builder.GetUintConstantId(target.memberIndex);
|
const uint32_t memberIndexId = builder.GetUintConstantId(target.memberIndex);
|
||||||
if (memberIndexId == 0) return false;
|
if (memberIndexId == 0) return false;
|
||||||
auto* access = builder.AddAccessChain(target.vectorPtrTypeId, target.variableId, {memberIndexId});
|
auto* access = builder.AddAccessChain(target.vectorPtrTypeId, target.variableId, {memberIndexId});
|
||||||
if (!access) return false;
|
if (!access) return false;
|
||||||
@@ -158,37 +163,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
auto* w = builder.AddCompositeExtract(target.floatTypeId, position->result_id(), {3});
|
auto* w = builder.AddCompositeExtract(target.floatTypeId, position->result_id(), {3});
|
||||||
if (!x || !y || !z || !w) return false;
|
if (!x || !y || !z || !w) return false;
|
||||||
|
|
||||||
if (!doYFlip && !doZRemap && !doSurfaceRotate90 && !doSurfaceRotate180 && !doSurfaceRotate270) {
|
if (!doYFlip && !doZRemap) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint32 xValueId = x->result_id();
|
uint32_t yValueId = y->result_id();
|
||||||
Uint32 yValueId = y->result_id();
|
|
||||||
if (doYFlip) {
|
if (doYFlip) {
|
||||||
auto* negY = builder.AddUnaryOp(target.floatTypeId, spv::Op::OpFNegate, y->result_id());
|
auto* negY = builder.AddUnaryOp(target.floatTypeId, spv::Op::OpFNegate, y->result_id());
|
||||||
if (!negY) return false;
|
if (!negY) return false;
|
||||||
yValueId = negY->result_id();
|
yValueId = negY->result_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doSurfaceRotate90) {
|
uint32_t zValueId = z->result_id();
|
||||||
auto* negY = builder.AddUnaryOp(target.floatTypeId, spv::Op::OpFNegate, yValueId);
|
|
||||||
if (!negY) return false;
|
|
||||||
xValueId = negY->result_id();
|
|
||||||
yValueId = x->result_id();
|
|
||||||
} else if (doSurfaceRotate180) {
|
|
||||||
auto* negX = builder.AddUnaryOp(target.floatTypeId, spv::Op::OpFNegate, xValueId);
|
|
||||||
auto* negY = builder.AddUnaryOp(target.floatTypeId, spv::Op::OpFNegate, yValueId);
|
|
||||||
if (!negX || !negY) return false;
|
|
||||||
xValueId = negX->result_id();
|
|
||||||
yValueId = negY->result_id();
|
|
||||||
} else if (doSurfaceRotate270) {
|
|
||||||
auto* negX = builder.AddUnaryOp(target.floatTypeId, spv::Op::OpFNegate, xValueId);
|
|
||||||
if (!negX) return false;
|
|
||||||
xValueId = yValueId;
|
|
||||||
yValueId = negX->result_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint32 zValueId = z->result_id();
|
|
||||||
if (doZRemap) {
|
if (doZRemap) {
|
||||||
auto* zPlusW = builder.AddBinaryOp(target.floatTypeId, spv::Op::OpFAdd, z->result_id(), w->result_id());
|
auto* zPlusW = builder.AddBinaryOp(target.floatTypeId, spv::Op::OpFAdd, z->result_id(), w->result_id());
|
||||||
if (!zPlusW) return false;
|
if (!zPlusW) return false;
|
||||||
@@ -199,7 +183,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto* fixedPosition = builder.AddCompositeConstruct(target.vectorTypeId,
|
auto* fixedPosition = builder.AddCompositeConstruct(target.vectorTypeId,
|
||||||
{xValueId, yValueId, zValueId, w->result_id()});
|
{x->result_id(), yValueId, zValueId, w->result_id()});
|
||||||
if (!fixedPosition) return false;
|
if (!fixedPosition) return false;
|
||||||
|
|
||||||
return builder.AddStore(positionPtrId, fixedPosition->result_id()) != nullptr;
|
return builder.AddStore(positionPtrId, fixedPosition->result_id()) != nullptr;
|
||||||
@@ -208,7 +192,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
class GlToVulkanPositionFixPass final : public spvtools::opt::Pass {
|
class GlToVulkanPositionFixPass final : public spvtools::opt::Pass {
|
||||||
public:
|
public:
|
||||||
const char* name() const override { return "gl-to-vulkan-position-fix"; }
|
const char* name() const override { return "gl-to-vulkan-position-fix"; }
|
||||||
explicit GlToVulkanPositionFixPass(ProgramFactory::CompileOptionFlags transformFlags)
|
explicit GlToVulkanPositionFixPass(ShaderTransformFlags transformFlags)
|
||||||
: m_transformFlags(transformFlags) {}
|
: m_transformFlags(transformFlags) {}
|
||||||
|
|
||||||
Status Process() override {
|
Status Process() override {
|
||||||
@@ -219,21 +203,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
auto* floatType = context()->get_type_mgr()->GetType(target.floatTypeId);
|
auto* floatType = context()->get_type_mgr()->GetType(target.floatTypeId);
|
||||||
if (!floatType) return Status::SuccessWithoutChange;
|
if (!floatType) return Status::SuccessWithoutChange;
|
||||||
|
|
||||||
const auto halfBits = std::bit_cast<Uint32>(0.5f);
|
const uint32_t halfBits = std::bit_cast<uint32_t>(0.5f);
|
||||||
const auto* halfConst = context()->get_constant_mgr()->GetConstant(floatType, {halfBits});
|
const auto* halfConst = context()->get_constant_mgr()->GetConstant(floatType, {halfBits});
|
||||||
auto* halfInst = context()->get_constant_mgr()->GetDefiningInstruction(halfConst);
|
auto* halfInst = context()->get_constant_mgr()->GetDefiningInstruction(halfConst);
|
||||||
if (!halfInst) return Status::SuccessWithoutChange;
|
if (!halfInst) return Status::SuccessWithoutChange;
|
||||||
const Uint32 halfConstId = halfInst->result_id();
|
const uint32_t halfConstId = halfInst->result_id();
|
||||||
|
|
||||||
const Bool doYFlip = (m_transformFlags & ProgramFactory::CompileOptionBit::PositionYFlip);
|
const bool doYFlip = (m_transformFlags & ShaderTransformBit::PositionYFlip);
|
||||||
const Bool doZRemap = (m_transformFlags & ProgramFactory::CompileOptionBit::PositionZRemap);
|
const bool doZRemap = (m_transformFlags & ShaderTransformBit::PositionZRemap);
|
||||||
const Bool doSurfaceRotate90 = (m_transformFlags & ProgramFactory::CompileOptionBit::SurfaceRotate90);
|
|
||||||
const Bool doSurfaceRotate180 =
|
|
||||||
(m_transformFlags & ProgramFactory::CompileOptionBit::SurfaceRotate180);
|
|
||||||
const Bool doSurfaceRotate270 =
|
|
||||||
(m_transformFlags & ProgramFactory::CompileOptionBit::SurfaceRotate270);
|
|
||||||
|
|
||||||
Bool modified = false;
|
bool modified = false;
|
||||||
for (auto& entryPoint : get_module()->entry_points()) {
|
for (auto& entryPoint : get_module()->entry_points()) {
|
||||||
if (entryPoint.opcode() != spv::Op::OpEntryPoint) continue;
|
if (entryPoint.opcode() != spv::Op::OpEntryPoint) continue;
|
||||||
if (entryPoint.NumInOperands() < 2) continue;
|
if (entryPoint.NumInOperands() < 2) continue;
|
||||||
@@ -250,13 +229,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
for (auto& bb : *function) {
|
for (auto& bb : *function) {
|
||||||
for (auto instIter = bb.begin(); instIter != bb.end(); ++instIter) {
|
for (auto instIter = bb.begin(); instIter != bb.end(); ++instIter) {
|
||||||
auto* inst = &*instIter;
|
auto* inst = &*instIter;
|
||||||
const Bool needsFixup =
|
const bool needsFixup =
|
||||||
(model == spv::ExecutionModel::Geometry && inst->opcode() == spv::Op::OpEmitVertex) ||
|
(model == spv::ExecutionModel::Geometry && inst->opcode() == spv::Op::OpEmitVertex) ||
|
||||||
(model != spv::ExecutionModel::Geometry && inst->opcode() == spv::Op::OpReturn);
|
(model != spv::ExecutionModel::Geometry && inst->opcode() == spv::Op::OpReturn);
|
||||||
if (!needsFixup) continue;
|
if (!needsFixup) continue;
|
||||||
|
|
||||||
modified |= InsertPositionFixup(context(), inst, target, halfConstId, doYFlip, doZRemap,
|
modified |= InsertPositionFixup(context(), inst, target, halfConstId, doYFlip, doZRemap);
|
||||||
doSurfaceRotate90, doSurfaceRotate180, doSurfaceRotate270);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,16 +246,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProgramFactory::CompileOptionFlags m_transformFlags;
|
ShaderTransformFlags m_transformFlags;
|
||||||
};
|
};
|
||||||
|
|
||||||
spvtools::Optimizer::PassToken CreateGlToVulkanPositionFixPass(
|
spvtools::Optimizer::PassToken CreateGlToVulkanPositionFixPass(ShaderTransformFlags transformFlags) {
|
||||||
ProgramFactory::CompileOptionFlags transformFlags) {
|
|
||||||
return spvtools::Optimizer::PassToken(MakeUnique<GlToVulkanPositionFixPass>(transformFlags));
|
return spvtools::Optimizer::PassToken(MakeUnique<GlToVulkanPositionFixPass>(transformFlags));
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool TransformSpirvForVulkanPositionFix(const Vector<Uint>& input, Vector<Uint>& output,
|
bool TransformSpirvForVulkanPositionFix(const Vector<Uint32>& input, Vector<Uint32>& output,
|
||||||
ProgramFactory::CompileOptionFlags transformFlags) {
|
ShaderTransformFlags transformFlags) {
|
||||||
if (input.empty()) {
|
if (input.empty()) {
|
||||||
output.clear();
|
output.clear();
|
||||||
return true;
|
return true;
|
||||||
@@ -293,7 +270,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
options.set_run_validator(false);
|
options.set_run_validator(false);
|
||||||
optimizer.RegisterPass(CreateGlToVulkanPositionFixPass(transformFlags));
|
optimizer.RegisterPass(CreateGlToVulkanPositionFixPass(transformFlags));
|
||||||
|
|
||||||
const Bool success = optimizer.Run(input.data(), input.size(), &output, options);
|
const bool success = optimizer.Run(input.data(), input.size(), &output, options);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
MGLOG_E("Vulkan: failed to run GL->Vulkan position fix pass");
|
MGLOG_E("Vulkan: failed to run GL->Vulkan position fix pass");
|
||||||
output = input;
|
output = input;
|
||||||
@@ -302,9 +279,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ShaderStage PickClipFixupStage(const Vector<SharedPtr<ShaderObject>>& shaders) {
|
ShaderStage PickClipFixupStage(const Vector<SharedPtr<ShaderObject>>& shaders) {
|
||||||
Bool hasGeometry = false;
|
bool hasGeometry = false;
|
||||||
Bool hasTessEval = false;
|
bool hasTessEval = false;
|
||||||
Bool hasVertex = false;
|
bool hasVertex = false;
|
||||||
|
|
||||||
for (const auto& shader : shaders) {
|
for (const auto& shader : shaders) {
|
||||||
if (!shader) continue;
|
if (!shader) continue;
|
||||||
@@ -321,9 +298,82 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ProgramFactory::~ProgramFactory() = default;
|
ProgramManager::~ProgramManager() {
|
||||||
|
for (auto& [_, stages] : m_cache) {
|
||||||
|
DestroyStages(stages);
|
||||||
|
}
|
||||||
|
m_cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
VkShaderStageFlagBits ProgramFactory::ToVkStage(ShaderStage stage) {
|
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) {
|
switch (stage) {
|
||||||
case ShaderStage::Vertex:
|
case ShaderStage::Vertex:
|
||||||
return VK_SHADER_STAGE_VERTEX_BIT;
|
return VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
@@ -342,56 +392,48 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramFactory::HashType ProgramFactory::ComputeHash(const MG_State::GLState::ProgramObject& program,
|
void ProgramManager::DestroyStages(ProgramStages& stages) {
|
||||||
CompileOptionFlags flags) const {
|
for (auto module : stages.modules) {
|
||||||
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion));
|
if (module != VK_NULL_HANDLE) {
|
||||||
// We expect shader stages in program object are sorted
|
vkDestroyShaderModule(m_ctx.GetDevice(), module, nullptr);
|
||||||
const auto& spirvs = program.GetGeneratedSpirv();
|
}
|
||||||
for (const auto& spv : spirvs) {
|
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, spv.data(), spv.size() * sizeof(Uint)));
|
|
||||||
}
|
}
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &flags, sizeof(CompileOptionFlags)));
|
stages.modules.clear();
|
||||||
HashType hash = XXH64_digest(m_hashState);
|
stages.stages.clear();
|
||||||
return hash;
|
stages.sourceHash = 0;
|
||||||
|
stages.hash = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<VkPipelineShaderStageCreateInfo>& ProgramFactory::GetOrCreatePipelineShaderStages(
|
Vector<VkPipelineShaderStageCreateInfo>& ProgramManager::CreatePipelineShaderStages(
|
||||||
const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags) {
|
MG_State::GLState::ProgramObject* program, ShaderTransformFlags transformFlags) {
|
||||||
auto hash = ComputeHash(program, flags);
|
auto& entry = m_cache[program];
|
||||||
auto it = m_cache.find(hash);
|
HashType sourceHash = ComputeSourceSpvHash(program);
|
||||||
if (it != m_cache.end()) {
|
if (!entry.stages.empty() && entry.sourceHash == sourceHash) return entry.stages;
|
||||||
return it->second.stages;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& entry = m_cache[hash];
|
DestroyStages(entry);
|
||||||
entry.hash = hash;
|
entry.sourceHash = sourceHash;
|
||||||
auto& shaders = program.GetAttachedShaders();
|
|
||||||
auto& spirv = program.GetGeneratedSpirv();
|
|
||||||
|
|
||||||
const ShaderStage fixupStage = PickClipFixupStage(shaders);
|
if (!program) return entry.stages;
|
||||||
|
|
||||||
for (SizeT i = 0; i < shaders.size(); ++i) {
|
Vector<Vector<Uint32>> spirvs;
|
||||||
auto& spv = spirv[i];
|
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;
|
if (spv.empty()) continue;
|
||||||
|
|
||||||
Vector<Uint> moduleSpv;
|
|
||||||
|
|
||||||
// Apply position fixup if needed
|
|
||||||
if (fixupStage != ShaderStage::Unknown && shaders[i] && shaders[i]->GetShaderStage() == fixupStage) {
|
|
||||||
TransformSpirvForVulkanPositionFix(spv, moduleSpv, flags);
|
|
||||||
} else {
|
|
||||||
moduleSpv = spv;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkShaderModuleCreateInfo smci{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
|
VkShaderModuleCreateInfo smci{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
|
||||||
smci.codeSize = moduleSpv.size() * sizeof(Uint);
|
smci.codeSize = spv.size() * sizeof(Uint);
|
||||||
smci.pCode = moduleSpv.data();
|
smci.pCode = spv.data();
|
||||||
|
|
||||||
VkShaderModule module = VK_NULL_HANDLE;
|
VkShaderModule module = VK_NULL_HANDLE;
|
||||||
VK_VERIFY(vkCreateShaderModule(m_device, &smci, nullptr, &module), "vkCreateShaderModule");
|
VK_VERIFY(vkCreateShaderModule(m_ctx.GetDevice(), &smci, nullptr, &module), "vkCreateShaderModule");
|
||||||
|
|
||||||
VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
|
VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
|
||||||
ShaderStage shaderStage = shaders[i]->GetShaderStage();
|
ShaderStage shaderStage = ShaderStage::Unknown;
|
||||||
|
if (i < shaders.size() && shaders[i]) shaderStage = shaders[i]->GetShaderStage();
|
||||||
stage.stage = ToVkStage(shaderStage);
|
stage.stage = ToVkStage(shaderStage);
|
||||||
stage.module = module;
|
stage.module = module;
|
||||||
stage.pName = "main";
|
stage.pName = "main";
|
||||||
@@ -402,4 +444,4 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
return entry.stages;
|
return entry.stages;
|
||||||
}
|
}
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
} // 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
|
||||||
+4
-3
@@ -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
|
||||||
@@ -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:
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -9,451 +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;
|
|
||||||
#else
|
|
||||||
return MG_Backend::WindowBackend::Unknown;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
return EGL_TRUE;
|
||||||
if (!state) {
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
return state->TerminateDisplay(dpy) ? EGL_TRUE : EGL_FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
return EGL_TRUE;
|
||||||
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;
|
|
||||||
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();
|
return "";
|
||||||
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 "";
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
return state->CreatePbufferSurface(dpy, config, attrib_list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
return EGL_OPENGL_API;
|
||||||
if (!state) {
|
|
||||||
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;
|
return EGL_TRUE;
|
||||||
|
|
||||||
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;
|
|
||||||
default:
|
|
||||||
state->SetError(EGL_BAD_ATTRIBUTE);
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean WaitClient() {
|
EGLBoolean WaitClient() {
|
||||||
@@ -465,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;
|
||||||
|
|||||||
@@ -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
@@ -9,22 +9,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl {
|
namespace MobileGL {
|
||||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
namespace MG_Impl::GLImpl {
|
||||||
void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||||
GLboolean IsBuffer(GLuint buffer);
|
void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
||||||
void DeleteBuffers(GLsizei n, const GLuint* buffers);
|
GLboolean IsBuffer(GLuint buffer);
|
||||||
void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
|
void DeleteBuffers(GLsizei n, const GLuint* buffers);
|
||||||
GLboolean UnmapBuffer(GLenum target);
|
void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
|
||||||
void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
|
GLboolean UnmapBuffer(GLenum target);
|
||||||
void* MapBuffer(GLenum target, GLenum access);
|
void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
|
||||||
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset,
|
void* MapBuffer(GLenum target, GLenum access);
|
||||||
GLsizeiptr size);
|
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset,
|
||||||
void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
|
GLsizeiptr size);
|
||||||
void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
|
void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
|
||||||
void BindBuffer(GLenum target, GLuint buffer);
|
void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
|
||||||
void GenBuffers(GLsizei n, GLuint* buffers);
|
void BindBuffer(GLenum target, GLuint buffer);
|
||||||
void BindBufferBase(GLenum target, GLuint index, GLuint buffer);
|
void GenBuffers(GLsizei n, GLuint* buffers);
|
||||||
void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
|
void BindBufferBase(GLenum target, GLuint index, GLuint buffer);
|
||||||
|
void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
|
||||||
|
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
} // namespace MG_Impl::GLImpl
|
||||||
|
} // namespace MobileGL
|
||||||
|
|||||||
@@ -13,100 +13,105 @@
|
|||||||
#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 {
|
||||||
Bool ValidateBufferTarget(BufferTarget target) {
|
namespace BufferImpl {
|
||||||
if (target == BufferTarget::Unknown) {
|
Bool ValidateBufferTarget(BufferTarget target) {
|
||||||
using namespace MG_Util;
|
if (target == BufferTarget::Unknown) {
|
||||||
String bufferTargetStr = ConvertBufferTargetToString(target);
|
using namespace MG_Util;
|
||||||
String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target));
|
String bufferTargetStr = ConvertBufferTargetToString(target);
|
||||||
MG_State::pGLContext->RecordError(
|
String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target));
|
||||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>(
|
MG_State::pGLContext->RecordError(
|
||||||
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget",
|
ErrorCode::InvalidEnum,
|
||||||
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
MakeShared<GenericErrorInfo>(
|
||||||
return false;
|
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget",
|
||||||
}
|
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateBufferBindingPointTarget(BufferTarget target) {
|
|
||||||
if (target != BufferTarget::Uniform && target != BufferTarget::AtomicCounter &&
|
|
||||||
target != BufferTarget::TransformFeedback && target != BufferTarget::ShaderStorage) {
|
|
||||||
using namespace MG_Util;
|
|
||||||
String bufferTargetStr = ConvertBufferTargetToString(target);
|
|
||||||
String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target));
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>(
|
|
||||||
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget",
|
|
||||||
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateBufferName(Uint index, Bool allowZero) {
|
|
||||||
if (index == 0) {
|
|
||||||
if (allowZero) return true;
|
|
||||||
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName",
|
|
||||||
"Buffer name 0 is not valid."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Bool isValid = MG_State::pGLContext->ValidateBufferName(index);
|
|
||||||
if (isValid) return true;
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidOperation,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName",
|
|
||||||
std::format("Buffer name {} is not valid.", index)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateBufferUsage(BufferUsage usage) {
|
|
||||||
if (usage != BufferUsage::Unknown) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
using namespace MG_Util;
|
|
||||||
String bufferUsageStr = ConvertBufferUsageToString(usage);
|
|
||||||
String glUsageStr = ConvertGLEnumToString(ConvertBufferUsageToGLEnum(usage));
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>(
|
|
||||||
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferUsage",
|
|
||||||
std::format("Usage {} ({}) is not one of the allowable values.", bufferUsageStr, glUsageStr)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits) {
|
Bool ValidateBufferBindingPointTarget(BufferTarget target) {
|
||||||
if (accessBits == BufferMappingAccessBit::Null) {
|
if (target != BufferTarget::Uniform && target != BufferTarget::AtomicCounter &&
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
target != BufferTarget::TransformFeedback && target != BufferTarget::ShaderStorage) {
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
|
using namespace MG_Util;
|
||||||
"ValidateBufferMappingAccess",
|
String bufferTargetStr = ConvertBufferTargetToString(target);
|
||||||
"Access bits cannot be null."));
|
String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target));
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeShared<GenericErrorInfo>(
|
||||||
|
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget",
|
||||||
|
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ValidateBufferName(Uint index, Bool allowZero) {
|
||||||
|
if (index == 0) {
|
||||||
|
if (allowZero) return true;
|
||||||
|
|
||||||
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
|
||||||
|
"ValidateBufferName",
|
||||||
|
"Buffer name 0 is not valid."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Bool isValid = MG_State::pGLContext->ValidateBufferName(index);
|
||||||
|
if (isValid) return true;
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName",
|
||||||
|
std::format("Buffer name {} is not valid.", index)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto validBits = BufferMappingAccessBit::Read | BufferMappingAccessBit::Write |
|
Bool ValidateBufferUsage(BufferUsage usage) {
|
||||||
BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer |
|
if (usage != BufferUsage::Unknown) {
|
||||||
BufferMappingAccessBit::FlushExplicit | BufferMappingAccessBit::Unsynchronized |
|
return true;
|
||||||
BufferMappingAccessBit::Persistent | BufferMappingAccessBit::Coherent;
|
}
|
||||||
|
using namespace MG_Util;
|
||||||
if ((accessBits & validBits) != accessBits) {
|
String bufferUsageStr = ConvertBufferUsageToString(usage);
|
||||||
|
String glUsageStr = ConvertGLEnumToString(ConvertBufferUsageToGLEnum(usage));
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidEnum,
|
ErrorCode::InvalidEnum,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferMappingAccess",
|
MakeShared<GenericErrorInfo>(
|
||||||
"Access bits cannot contain invalid flags."));
|
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferUsage",
|
||||||
|
std::format("Usage {} ({}) is not one of the allowable values.", bufferUsageStr, glUsageStr)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits) {
|
||||||
}
|
if (accessBits == BufferMappingAccessBit::Null) {
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl::BufferImpl
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
|
||||||
|
"ValidateBufferMappingAccess",
|
||||||
|
"Access bits cannot be null."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto validBits = BufferMappingAccessBit::Read | BufferMappingAccessBit::Write |
|
||||||
|
BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer |
|
||||||
|
BufferMappingAccessBit::FlushExplicit | BufferMappingAccessBit::Unsynchronized |
|
||||||
|
BufferMappingAccessBit::Persistent | BufferMappingAccessBit::Coherent;
|
||||||
|
|
||||||
|
if ((accessBits & validBits) != accessBits) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferMappingAccess",
|
||||||
|
"Access bits cannot contain invalid flags."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace BufferImpl
|
||||||
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
@@ -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 {
|
||||||
Bool ValidateBufferTarget(BufferTarget target);
|
namespace BufferImpl {
|
||||||
Bool ValidateBufferName(Uint index, Bool allowZero = false);
|
Bool ValidateBufferTarget(BufferTarget target);
|
||||||
Bool ValidateBufferUsage(BufferUsage usage);
|
Bool ValidateBufferName(Uint index, Bool allowZero = false);
|
||||||
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits);
|
Bool ValidateBufferUsage(BufferUsage usage);
|
||||||
Bool ValidateBufferBindingPointTarget(BufferTarget target);
|
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits);
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl::BufferImpl
|
Bool ValidateBufferBindingPointTarget(BufferTarget target);
|
||||||
|
} // namespace BufferImpl
|
||||||
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
@@ -9,31 +9,34 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl {
|
namespace MobileGL {
|
||||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
namespace MG_Impl::GLImpl {
|
||||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride);
|
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount,
|
||||||
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
GLsizei stride);
|
||||||
const void* indices, GLint basevertex);
|
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||||
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
|
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||||
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
const void* indices, GLint basevertex);
|
||||||
GLsizei instancecount, GLint basevertex, GLuint baseinstance);
|
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
|
||||||
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||||
GLsizei instancecount, GLint basevertex);
|
GLsizei instancecount, GLint basevertex, GLuint baseinstance);
|
||||||
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||||
GLsizei instancecount, GLuint baseinstance);
|
GLsizei instancecount, GLint basevertex);
|
||||||
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount);
|
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||||
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect);
|
GLsizei instancecount, GLuint baseinstance);
|
||||||
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount);
|
||||||
GLuint baseinstance);
|
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect);
|
||||||
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
||||||
void DrawArraysIndirect(GLenum mode, const void* indirect);
|
GLuint baseinstance);
|
||||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex);
|
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
||||||
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
void DrawArraysIndirect(GLenum mode, const void* indirect);
|
||||||
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex);
|
||||||
GLsizei drawcount);
|
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
||||||
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
||||||
GLsizei drawcount, const GLint* basevertex);
|
GLsizei drawcount);
|
||||||
void Clear(GLbitfield mask);
|
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
||||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
GLsizei drawcount, const GLint* basevertex);
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
void Clear(GLbitfield mask);
|
||||||
|
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
||||||
|
} // namespace MG_Impl::GLImpl
|
||||||
|
} // namespace MobileGL
|
||||||
|
|||||||
@@ -38,11 +38,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
RenderbufferTarget rbTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
|
RenderbufferTarget rbTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
|
||||||
if (!FramebufferImpl::ValidateRenderbufferTarget(rbTarget)) return;
|
if (!FramebufferImpl::ValidateRenderbufferTarget(rbTarget)) return;
|
||||||
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(rbTarget);
|
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(rbTarget);
|
||||||
auto& renderbufferObject = bindingSlot.GetBoundObject();
|
auto renderbufferObject = bindingSlot.GetBoundObject();
|
||||||
if (!renderbufferObject) {
|
if (!renderbufferObject) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State",
|
||||||
"Renderbuffer target is bound to no renderbuffer object."));
|
"Renderbuffer target is bound to no renderbuffer object."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (!TextureImpl::ValidateTextureInternalFormat(format)) return;
|
if (!TextureImpl::ValidateTextureInternalFormat(format)) return;
|
||||||
if (width < 0 || height < 0) {
|
if (width < 0 || height < 0) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State",
|
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State",
|
||||||
"Width and height must be non-negative."));
|
"Width and height must be non-negative."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -74,11 +74,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidValue,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenRenderbuffers_State", "n must be non-negative"));
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GenRenderbuffers_State", "n must be non-negative"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
static thread_local Vector<GLuint> renderbufferNames;
|
auto renderbufferNames = MG_State::pGLContext->GenRenderbufferNames(n);
|
||||||
MG_State::pGLContext->GenRenderbufferNames(n, renderbufferNames);
|
|
||||||
Memcpy(renderbuffers, renderbufferNames.data(), sizeof(GLuint) * static_cast<SizeT>(n));
|
Memcpy(renderbuffers, renderbufferNames.data(), sizeof(GLuint) * static_cast<SizeT>(n));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,11 +85,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidValue,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenFramebuffers_State", "n must be non-negative"));
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GenFramebuffers_State", "n must be non-negative"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
static thread_local Vector<GLuint> framebuffersNames;
|
auto framebuffersNames = MG_State::pGLContext->GenFramebufferNames(n);
|
||||||
MG_State::pGLContext->GenFramebufferNames(n, framebuffersNames);
|
|
||||||
Memcpy(framebuffers, framebuffersNames.data(), sizeof(GLuint) * static_cast<SizeT>(n));
|
Memcpy(framebuffers, framebuffersNames.data(), sizeof(GLuint) * static_cast<SizeT>(n));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,11 +119,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (!TextureImpl::ValidateTextureName(texture, true)) return;
|
if (!TextureImpl::ValidateTextureName(texture, true)) return;
|
||||||
|
|
||||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
||||||
auto& framebufferObject = bindingSlot.GetBoundObject();
|
auto framebufferObject = bindingSlot.GetBoundObject();
|
||||||
if (!framebufferObject) {
|
if (!framebufferObject) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferTexture2D_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferTexture2D_State",
|
||||||
"Framebuffer target is bound to no framebuffer object."));
|
"Framebuffer target is bound to no framebuffer object."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -135,11 +133,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
auto textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||||
if (!textureObject) {
|
if (!textureObject) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferTexture2D_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferTexture2D_State",
|
||||||
std::format("Texture object {} is not valid.", texture)));
|
std::format("Texture object {} is not valid.", texture)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -168,11 +166,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
|
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
|
||||||
if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer)) return;
|
if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer)) return;
|
||||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
||||||
auto& framebufferObject = bindingSlot.GetBoundObject();
|
auto framebufferObject = bindingSlot.GetBoundObject();
|
||||||
if (!framebufferObject) {
|
if (!framebufferObject) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferRenderbuffer_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferRenderbuffer_State",
|
||||||
"Framebuffer target is bound to no framebuffer object."));
|
"Framebuffer target is bound to no framebuffer object."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -182,11 +180,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
|
auto renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
|
||||||
if (!renderbufferObject) {
|
if (!renderbufferObject) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferRenderbuffer_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferRenderbuffer_State",
|
||||||
std::format("Renderbuffer object {} is not valid.", renderbuffer)));
|
std::format("Renderbuffer object {} is not valid.", renderbuffer)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -198,18 +196,18 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidValue,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`n` is less than 0."));
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`n` is less than 0."));
|
||||||
return;
|
return;
|
||||||
} else if (n > MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
} else if (n > MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidValue,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`n` is greater than `GL_MAX_DRAW_BUFFERS`."));
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`n` is greater than `GL_MAX_DRAW_BUFFERS`."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get bound framebuffer
|
// Get bound framebuffer
|
||||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
|
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
|
||||||
auto& fbo = bindingSlot.GetBoundObject();
|
auto fbo = bindingSlot.GetBoundObject();
|
||||||
bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
|
bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
|
||||||
|
|
||||||
static int existenceMap[(SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount] = {-1};
|
static int existenceMap[(SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount] = {-1};
|
||||||
@@ -222,7 +220,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (attType == FramebufferAttachmentType::Unknown) {
|
if (attType == FramebufferAttachmentType::Unknown) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidEnum,
|
ErrorCode::InvalidEnum,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||||
std::format("bufs[{}] = {} is not an accepted value.", i,
|
std::format("bufs[{}] = {} is not an accepted value.", i,
|
||||||
MG_Util::ConvertGLEnumToString(bufs[i]))));
|
MG_Util::ConvertGLEnumToString(bufs[i]))));
|
||||||
return;
|
return;
|
||||||
@@ -232,7 +230,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
attType <= FramebufferAttachmentType::Color31) {
|
attType <= FramebufferAttachmentType::Color31) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidEnum,
|
ErrorCode::InvalidEnum,
|
||||||
MakeUnique<GenericErrorInfo>(
|
MakeShared<GenericErrorInfo>(
|
||||||
"MG_Impl/GLImpl", __func__,
|
"MG_Impl/GLImpl", __func__,
|
||||||
std::format(
|
std::format(
|
||||||
"FBO is default FBO, but bufs[{}] = {} is one of the `GL_COLOR_ATTACHMENTn` tokens.", i,
|
"FBO is default FBO, but bufs[{}] = {} is one of the `GL_COLOR_ATTACHMENTn` tokens.", i,
|
||||||
@@ -244,7 +242,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
attType <= FramebufferAttachmentType::BackRight) {
|
attType <= FramebufferAttachmentType::BackRight) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidEnum,
|
ErrorCode::InvalidEnum,
|
||||||
MakeUnique<GenericErrorInfo>(
|
MakeShared<GenericErrorInfo>(
|
||||||
"MG_Impl/GLImpl", __func__,
|
"MG_Impl/GLImpl", __func__,
|
||||||
std::format("FBO is not default FBO, but bufs[{}] = {} is anything other than `GL_NONE` or "
|
std::format("FBO is not default FBO, but bufs[{}] = {} is anything other than `GL_NONE` or "
|
||||||
"one of the `GL_COLOR_ATTACHMENTn` tokens.",
|
"one of the `GL_COLOR_ATTACHMENTn` tokens.",
|
||||||
@@ -255,7 +253,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (attType != FramebufferAttachmentType::None && existenceMap[(SizeT)attType] >= 0) {
|
if (attType != FramebufferAttachmentType::None && existenceMap[(SizeT)attType] >= 0) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||||
std::format("a symbolic constant other than `GL_NONE` appears "
|
std::format("a symbolic constant other than `GL_NONE` appears "
|
||||||
"more than once in bufs. bufs[{}] == bufs[{}] == {}.",
|
"more than once in bufs. bufs[{}] == bufs[{}] == {}.",
|
||||||
i, existenceMap[(SizeT)attType],
|
i, existenceMap[(SizeT)attType],
|
||||||
@@ -269,7 +267,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
(SizeT)FramebufferAttachmentType::Color0 + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
(SizeT)FramebufferAttachmentType::Color0 + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||||
std::format("bufs[{}] == {} indicates a color buffer that does "
|
std::format("bufs[{}] == {} indicates a color buffer that does "
|
||||||
"not exist in the current GL context.",
|
"not exist in the current GL context.",
|
||||||
i, MG_Util::ConvertGLEnumToString(bufs[i]))));
|
i, MG_Util::ConvertGLEnumToString(bufs[i]))));
|
||||||
@@ -299,7 +297,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (attType == FramebufferAttachmentType::Unknown) {
|
if (attType == FramebufferAttachmentType::Unknown) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidEnum,
|
ErrorCode::InvalidEnum,
|
||||||
MakeUnique<GenericErrorInfo>(
|
MakeShared<GenericErrorInfo>(
|
||||||
"MG_Impl/GLImpl", __func__,
|
"MG_Impl/GLImpl", __func__,
|
||||||
std::format("`mode` = {} is not an accepted value.", MG_Util::ConvertGLEnumToString(mode))));
|
std::format("`mode` = {} is not an accepted value.", MG_Util::ConvertGLEnumToString(mode))));
|
||||||
return;
|
return;
|
||||||
@@ -307,7 +305,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
|
|
||||||
// Get bound framebuffer
|
// Get bound framebuffer
|
||||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
|
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
|
||||||
auto& fbo = bindingSlot.GetBoundObject();
|
auto fbo = bindingSlot.GetBoundObject();
|
||||||
fbo->SetReadBuffer(attType);
|
fbo->SetReadBuffer(attType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,13 +313,13 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidValue,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteRenderbuffers_State", "n must be non-negative."));
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteRenderbuffers_State", "n must be non-negative."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!renderbuffers) {
|
if (!renderbuffers) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteRenderbuffers_State",
|
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteRenderbuffers_State",
|
||||||
"Renderbuffer names array cannot be null."));
|
"Renderbuffer names array cannot be null."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -338,13 +336,13 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidValue,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteFramebuffers_State", "n must be non-negative."));
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteFramebuffers_State", "n must be non-negative."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!framebuffers) {
|
if (!framebuffers) {
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteFramebuffers_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteFramebuffers_State",
|
||||||
"Framebuffer names array cannot be null."));
|
"Framebuffer names array cannot be null."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -362,11 +360,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return GL_FRAMEBUFFER_UNDEFINED;
|
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return GL_FRAMEBUFFER_UNDEFINED;
|
||||||
|
|
||||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
||||||
auto& framebufferObject = bindingSlot.GetBoundObject();
|
auto framebufferObject = bindingSlot.GetBoundObject();
|
||||||
if (!framebufferObject) {
|
if (!framebufferObject) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CheckFramebufferStatus_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "CheckFramebufferStatus_State",
|
||||||
"Framebuffer target is bound to no framebuffer object."));
|
"Framebuffer target is bound to no framebuffer object."));
|
||||||
return GL_FRAMEBUFFER_UNDEFINED;
|
return GL_FRAMEBUFFER_UNDEFINED;
|
||||||
}
|
}
|
||||||
@@ -384,11 +382,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
|
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
|
||||||
if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return;
|
if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return;
|
||||||
|
|
||||||
Bool doesRenderbufferCreated = MG_State::pGLContext->ValidateRenderbufferObject(renderbuffer);
|
auto renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
|
||||||
if (!doesRenderbufferCreated) {
|
if (!renderbufferObject) {
|
||||||
MG_State::pGLContext->CreateRenderbufferObject(renderbuffer);
|
MG_State::pGLContext->CreateRenderbufferObject(renderbuffer);
|
||||||
|
renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
|
||||||
}
|
}
|
||||||
auto& renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
|
|
||||||
|
|
||||||
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
|
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
|
||||||
bindingSlot.Bind(renderbufferObject);
|
bindingSlot.Bind(renderbufferObject);
|
||||||
@@ -405,11 +403,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
FramebufferTarget framebufferTarget = MG_Util::ConvertGLEnumToFramebufferTarget(target);
|
FramebufferTarget framebufferTarget = MG_Util::ConvertGLEnumToFramebufferTarget(target);
|
||||||
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
|
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
|
||||||
|
|
||||||
Bool doesFramebufferCreated = MG_State::pGLContext->ValidateFramebufferObject(framebuffer);
|
auto framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
|
||||||
if (!doesFramebufferCreated) {
|
if (!framebufferObject) {
|
||||||
MG_State::pGLContext->CreateFramebufferObject(framebuffer);
|
MG_State::pGLContext->CreateFramebufferObject(framebuffer);
|
||||||
|
framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
|
||||||
}
|
}
|
||||||
auto& framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
|
|
||||||
|
|
||||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
||||||
bindingSlot.Bind(framebufferObject);
|
bindingSlot.Bind(framebufferObject);
|
||||||
@@ -421,11 +419,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
|
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
|
||||||
if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return;
|
if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return;
|
||||||
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
|
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
|
||||||
auto& renderbufferObject = bindingSlot.GetBoundObject();
|
auto renderbufferObject = bindingSlot.GetBoundObject();
|
||||||
if (!renderbufferObject) {
|
if (!renderbufferObject) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetRenderbufferParameteriv_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetRenderbufferParameteriv_State",
|
||||||
"Renderbuffer target is bound to no renderbuffer object."));
|
"Renderbuffer target is bound to no renderbuffer object."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -464,7 +462,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
default:
|
default:
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidEnum,
|
ErrorCode::InvalidEnum,
|
||||||
MakeUnique<GenericErrorInfo>(
|
MakeShared<GenericErrorInfo>(
|
||||||
"MG_Impl/GLImpl", "GetRenderbufferParameteriv_State",
|
"MG_Impl/GLImpl", "GetRenderbufferParameteriv_State",
|
||||||
std::format("pname {} is not an accepted value.", MG_Util::ConvertGLEnumToString(pname))));
|
std::format("pname {} is not an accepted value.", MG_Util::ConvertGLEnumToString(pname))));
|
||||||
return;
|
return;
|
||||||
@@ -494,7 +492,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// Check width/height
|
// Check width/height
|
||||||
if (width < 0 || height < 0) {
|
if (width < 0 || height < 0) {
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||||
"Width and height must be non-negative"));
|
"Width and height must be non-negative"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -503,7 +501,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) {
|
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidEnum,
|
ErrorCode::InvalidEnum,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid format"));
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid format"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,17 +509,17 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) {
|
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidEnum,
|
ErrorCode::InvalidEnum,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid pixel data type"));
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid pixel data type"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get bound framebuffer
|
// Get bound framebuffer
|
||||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
|
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
|
||||||
auto& framebufferObject = bindingSlot.GetBoundObject();
|
auto framebufferObject = bindingSlot.GetBoundObject();
|
||||||
|
|
||||||
if (!framebufferObject) {
|
if (!framebufferObject) {
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||||
"No framebuffer bound to read target"));
|
"No framebuffer bound to read target"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -530,7 +528,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (!framebufferObject->CheckCompleteness()) {
|
if (!framebufferObject->CheckCompleteness()) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidFramebufferOperation,
|
ErrorCode::InvalidFramebufferOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Framebuffer is incomplete"));
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Framebuffer is incomplete"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,7 +537,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) {
|
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||||
"No stencil buffer for stencil index format"));
|
"No stencil buffer for stencil index format"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -547,7 +545,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Depth).IsValid()) {
|
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Depth).IsValid()) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||||
"No depth buffer for depth component format"));
|
"No depth buffer for depth component format"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -556,7 +554,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
!framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) {
|
!framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||||
"No depth/stencil buffer for depth-stencil format"));
|
"No depth/stencil buffer for depth-stencil format"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -565,7 +563,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (texturePixelDataType != TexturePixelDataType::UnsignedInt248 &&
|
if (texturePixelDataType != TexturePixelDataType::UnsignedInt248 &&
|
||||||
texturePixelDataType != TexturePixelDataType::Float32UnsignedInt248Rev) {
|
texturePixelDataType != TexturePixelDataType::Float32UnsignedInt248Rev) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||||
"Invalid type for depth-stencil format"));
|
"Invalid type for depth-stencil format"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -579,7 +577,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// Check if PBO is mapped
|
// Check if PBO is mapped
|
||||||
if (pixelPackBufferObject->IsMapped()) {
|
if (pixelPackBufferObject->IsMapped()) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
ErrorCode::InvalidOperation, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||||
"Pixel pack buffer is currently mapped"));
|
"Pixel pack buffer is currently mapped"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -589,7 +587,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (reinterpret_cast<uintptr_t>(pixels) % typeSize != 0) {
|
if (reinterpret_cast<uintptr_t>(pixels) % typeSize != 0) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||||
"Pixel data not aligned for pixel pack buffer"));
|
"Pixel data not aligned for pixel pack buffer"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -597,11 +595,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
|
|
||||||
// Check multisampling
|
// Check multisampling
|
||||||
if (framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).IsRenderbuffer()) {
|
if (framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).IsRenderbuffer()) {
|
||||||
auto& rbo = framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).GetRenderbuffer();
|
auto rbo = framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).GetRenderbuffer();
|
||||||
if (rbo && rbo->GetSamples() > 1) {
|
if (rbo && rbo->GetSamples() > 1) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||||
"ReadPixels not supported for multisampled framebuffers"));
|
"ReadPixels not supported for multisampled framebuffers"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -734,6 +732,6 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace FramebufferImpl {
|
namespace FramebufferImpl {
|
||||||
UniquePtr<DefaultFramebufferInfo> pDefaultFramebufferInfo;
|
DefaultFramebufferInfo* pDefaultFramebufferInfo;
|
||||||
} // namespace FramebufferImpl
|
} // namespace FramebufferImpl
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
|
|||||||
@@ -11,49 +11,51 @@
|
|||||||
#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 {
|
||||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
namespace MG_Impl::GLImpl {
|
||||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||||
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
||||||
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||||
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||||
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
|
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
||||||
void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
|
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
|
||||||
GLsizei height);
|
void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
|
||||||
void RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
|
GLsizei height);
|
||||||
GLboolean IsRenderbuffer(GLuint renderbuffer);
|
void RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
|
||||||
void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
GLboolean IsRenderbuffer(GLuint renderbuffer);
|
||||||
void GenRenderbuffers(GLsizei n, GLuint* renderbuffers);
|
void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
||||||
void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
|
void GenRenderbuffers(GLsizei n, GLuint* renderbuffers);
|
||||||
void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
|
void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
|
||||||
void BindRenderbuffer(GLenum target, GLuint renderbuffer);
|
void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
|
||||||
void SampleMaski(GLuint maskNumber, GLbitfield mask);
|
void BindRenderbuffer(GLenum target, GLuint renderbuffer);
|
||||||
GLboolean IsFramebuffer(GLuint framebuffer);
|
void SampleMaski(GLuint maskNumber, GLbitfield mask);
|
||||||
void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
|
GLboolean IsFramebuffer(GLuint framebuffer);
|
||||||
void GenFramebuffers(GLsizei n, GLuint* framebuffers);
|
void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
|
||||||
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
|
void GenFramebuffers(GLsizei n, GLuint* framebuffers);
|
||||||
void FramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level,
|
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
|
||||||
GLint zoffset);
|
void FramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level,
|
||||||
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
GLint zoffset);
|
||||||
void FramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||||
void FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level);
|
void FramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||||
void DrawBuffer(GLenum buf);
|
void FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level);
|
||||||
void DrawBuffers(GLsizei n, const GLenum* bufs);
|
void DrawBuffer(GLenum buf);
|
||||||
void ReadBuffer(GLenum src);
|
void DrawBuffers(GLsizei n, const GLenum* bufs);
|
||||||
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
|
void ReadBuffer(GLenum src);
|
||||||
GLenum CheckFramebufferStatus(GLenum target);
|
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
|
||||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
GLenum CheckFramebufferStatus(GLenum target);
|
||||||
GLint dstY1, GLbitfield mask, GLenum filter);
|
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||||
void BindFramebuffer(GLenum target, GLuint framebuffer);
|
GLint dstY1, GLbitfield mask, GLenum filter);
|
||||||
|
void BindFramebuffer(GLenum target, GLuint framebuffer);
|
||||||
|
|
||||||
namespace FramebufferImpl {
|
namespace FramebufferImpl {
|
||||||
struct DefaultFramebufferInfo {
|
struct DefaultFramebufferInfo {
|
||||||
SharedPtr<MG_State::GLState::FramebufferObject> defaultFBO;
|
SharedPtr<MG_State::GLState::FramebufferObject> defaultFBO;
|
||||||
SharedPtr<MG_State::GLState::ITextureObject> colorAttachment;
|
SharedPtr<MG_State::GLState::ITextureObject> colorAttachment;
|
||||||
SharedPtr<MG_State::GLState::ITextureObject> depthAttachment;
|
SharedPtr<MG_State::GLState::ITextureObject> depthAttachment;
|
||||||
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,82 +13,85 @@
|
|||||||
#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 {
|
||||||
Bool ValidateFramebufferTarget(FramebufferTarget target) {
|
namespace FramebufferImpl {
|
||||||
if (target == FramebufferTarget::Unknown) {
|
Bool ValidateFramebufferTarget(FramebufferTarget target) {
|
||||||
using namespace MG_Util;
|
if (target == FramebufferTarget::Unknown) {
|
||||||
String bufferTargetStr = ConvertFramebufferTargetToString(target);
|
using namespace MG_Util;
|
||||||
String glTargetStr = ConvertGLEnumToString(ConvertFramebufferTargetToGLEnum(target));
|
String bufferTargetStr = ConvertFramebufferTargetToString(target);
|
||||||
MG_State::pGLContext->RecordError(
|
String glTargetStr = ConvertGLEnumToString(ConvertFramebufferTargetToGLEnum(target));
|
||||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>(
|
MG_State::pGLContext->RecordError(
|
||||||
"MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferTarget",
|
ErrorCode::InvalidEnum,
|
||||||
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
MakeShared<GenericErrorInfo>(
|
||||||
return false;
|
"MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferTarget",
|
||||||
|
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateFramebufferName(Uint index, Bool allowZero) {
|
Bool ValidateFramebufferName(Uint index, Bool allowZero) {
|
||||||
if (index == 0 && !allowZero) {
|
if (index == 0 && !allowZero) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName",
|
||||||
|
"Framebuffer name 0 is not valid in this situation."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Bool isValid = MG_State::pGLContext->ValidateFramebufferName(index);
|
||||||
|
if (isValid) return true;
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName",
|
||||||
"Framebuffer name 0 is not valid in this situation."));
|
std::format("Framebuffer name {} is not valid.", index)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Bool isValid = MG_State::pGLContext->ValidateFramebufferName(index);
|
|
||||||
if (isValid) return true;
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidOperation,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName",
|
|
||||||
std::format("Framebuffer name {} is not valid.", index)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment) {
|
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment) {
|
||||||
if (attachment == FramebufferAttachmentType::Unknown) {
|
if (attachment == FramebufferAttachmentType::Unknown) {
|
||||||
using namespace MG_Util;
|
using namespace MG_Util;
|
||||||
String attachmentStr = ConvertFramebufferAttachmentTypeToString(attachment);
|
String attachmentStr = ConvertFramebufferAttachmentTypeToString(attachment);
|
||||||
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;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateRenderbufferTarget(RenderbufferTarget target) {
|
Bool ValidateRenderbufferTarget(RenderbufferTarget target) {
|
||||||
if (target == RenderbufferTarget::Unknown) {
|
if (target == RenderbufferTarget::Unknown) {
|
||||||
using namespace MG_Util;
|
using namespace MG_Util;
|
||||||
String renderbufferTargetStr = ConvertRenderbufferTargetToString(target);
|
String renderbufferTargetStr = ConvertRenderbufferTargetToString(target);
|
||||||
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;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateRenderbufferName(Uint index, Bool allowZero) {
|
Bool ValidateRenderbufferName(Uint index, Bool allowZero) {
|
||||||
if (index == 0 && !allowZero) {
|
if (index == 0 && !allowZero) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName",
|
||||||
|
"Renderbuffer name 0 is not valid in this situation."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Bool isValid = MG_State::pGLContext->ValidateRenderbufferName(index);
|
||||||
|
if (isValid) return true;
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName",
|
||||||
"Renderbuffer name 0 is not valid in this situation."));
|
std::format("Renderbuffer name {} is not valid.", index)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Bool isValid = MG_State::pGLContext->ValidateRenderbufferName(index);
|
} // namespace FramebufferImpl
|
||||||
if (isValid) return true;
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidOperation,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName",
|
|
||||||
std::format("Renderbuffer name {} is not valid.", index)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl
|
|
||||||
@@ -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 {
|
||||||
Bool ValidateFramebufferTarget(FramebufferTarget target);
|
namespace FramebufferImpl {
|
||||||
Bool ValidateFramebufferName(Uint index, Bool allowZero = true);
|
Bool ValidateFramebufferTarget(FramebufferTarget target);
|
||||||
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment);
|
Bool ValidateFramebufferName(Uint index, Bool allowZero = true);
|
||||||
Bool ValidateRenderbufferTarget(RenderbufferTarget target);
|
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment);
|
||||||
Bool ValidateRenderbufferName(Uint index, Bool allowZero = true);
|
Bool ValidateRenderbufferTarget(RenderbufferTarget target);
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl
|
Bool ValidateRenderbufferName(Uint index, Bool allowZero = true);
|
||||||
|
} // namespace FramebufferImpl
|
||||||
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
@@ -125,7 +125,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,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;
|
||||||
@@ -254,14 +254,14 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
break;
|
break;
|
||||||
case GL_CURRENT_PROGRAM: {
|
case GL_CURRENT_PROGRAM: {
|
||||||
const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||||
*params = currentProgram ? (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
|
||||||
@@ -286,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: {
|
||||||
@@ -300,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:
|
||||||
@@ -884,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;
|
||||||
@@ -892,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
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -9,59 +9,61 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl {
|
namespace MobileGL {
|
||||||
void AttachShader(GLuint program, GLuint shader);
|
namespace MG_Impl::GLImpl {
|
||||||
void BindAttribLocation(GLuint program, GLuint index, const GLchar* name);
|
void AttachShader(GLuint program, GLuint shader);
|
||||||
void CompileShader(GLuint shader);
|
void BindAttribLocation(GLuint program, GLuint index, const GLchar* name);
|
||||||
GLuint CreateProgram(void);
|
void CompileShader(GLuint shader);
|
||||||
GLuint CreateShader(GLenum type);
|
GLuint CreateProgram(void);
|
||||||
void DeleteProgram(GLuint program);
|
GLuint CreateShader(GLenum type);
|
||||||
void DeleteShader(GLuint shader);
|
void DeleteProgram(GLuint program);
|
||||||
void DetachShader(GLuint program, GLuint shader);
|
void DeleteShader(GLuint shader);
|
||||||
void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type,
|
void DetachShader(GLuint program, GLuint shader);
|
||||||
GLchar* name);
|
void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type,
|
||||||
void GetActiveUniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type,
|
GLchar* name);
|
||||||
GLchar* name);
|
void GetActiveUniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type,
|
||||||
void GetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders);
|
GLchar* name);
|
||||||
GLint GetAttribLocation(GLuint program, const GLchar* name);
|
void GetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders);
|
||||||
void GetProgramiv(GLuint program, GLenum pname, GLint* params);
|
GLint GetAttribLocation(GLuint program, const GLchar* name);
|
||||||
void GetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
|
void GetProgramiv(GLuint program, GLenum pname, GLint* params);
|
||||||
void GetShaderiv(GLuint shader, GLenum pname, GLint* params);
|
void GetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
|
||||||
void GetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
|
void GetShaderiv(GLuint shader, GLenum pname, GLint* params);
|
||||||
void GetShaderSource(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source);
|
void GetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
|
||||||
GLint GetUniformLocation(GLuint program, const GLchar* name);
|
void GetShaderSource(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source);
|
||||||
void GetUniformfv(GLuint program, GLint location, GLfloat* params);
|
GLint GetUniformLocation(GLuint program, const GLchar* name);
|
||||||
void GetUniformiv(GLuint program, GLint location, GLint* params);
|
void GetUniformfv(GLuint program, GLint location, GLfloat* params);
|
||||||
GLboolean IsProgram(GLuint program);
|
void GetUniformiv(GLuint program, GLint location, GLint* params);
|
||||||
GLboolean IsShader(GLuint shader);
|
GLboolean IsProgram(GLuint program);
|
||||||
void LinkProgram(GLuint program);
|
GLboolean IsShader(GLuint shader);
|
||||||
void ShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
|
void LinkProgram(GLuint program);
|
||||||
void UseProgram(GLuint program);
|
void ShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
|
||||||
void Uniform1f(GLint location, GLfloat v0);
|
void UseProgram(GLuint program);
|
||||||
void Uniform2f(GLint location, GLfloat v0, GLfloat v1);
|
void Uniform1f(GLint location, GLfloat v0);
|
||||||
void Uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
void Uniform2f(GLint location, GLfloat v0, GLfloat v1);
|
||||||
void Uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
|
void Uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
||||||
void Uniform1i(GLint location, GLint v0);
|
void Uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
|
||||||
void Uniform2i(GLint location, GLint v0, GLint v1);
|
void Uniform1i(GLint location, GLint v0);
|
||||||
void Uniform3i(GLint location, GLint v0, GLint v1, GLint v2);
|
void Uniform2i(GLint location, GLint v0, GLint v1);
|
||||||
void Uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
|
void Uniform3i(GLint location, GLint v0, GLint v1, GLint v2);
|
||||||
void Uniform1fv(GLint location, GLsizei count, const GLfloat* value);
|
void Uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
|
||||||
void Uniform2fv(GLint location, GLsizei count, const GLfloat* value);
|
void Uniform1fv(GLint location, GLsizei count, const GLfloat* value);
|
||||||
void Uniform3fv(GLint location, GLsizei count, const GLfloat* value);
|
void Uniform2fv(GLint location, GLsizei count, const GLfloat* value);
|
||||||
void Uniform4fv(GLint location, GLsizei count, const GLfloat* value);
|
void Uniform3fv(GLint location, GLsizei count, const GLfloat* value);
|
||||||
void Uniform1iv(GLint location, GLsizei count, const GLint* value);
|
void Uniform4fv(GLint location, GLsizei count, const GLfloat* value);
|
||||||
void Uniform2iv(GLint location, GLsizei count, const GLint* value);
|
void Uniform1iv(GLint location, GLsizei count, const GLint* value);
|
||||||
void Uniform3iv(GLint location, GLsizei count, const GLint* value);
|
void Uniform2iv(GLint location, GLsizei count, const GLint* value);
|
||||||
void Uniform4iv(GLint location, GLsizei count, const GLint* value);
|
void Uniform3iv(GLint location, GLsizei count, const GLint* value);
|
||||||
void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
void Uniform4iv(GLint location, GLsizei count, const GLint* value);
|
||||||
void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||||
void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||||
GLuint GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName);
|
void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||||
void UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
|
GLuint GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName);
|
||||||
void GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params);
|
void UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
|
||||||
void GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length,
|
void GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params);
|
||||||
GLchar* uniformBlockName);
|
void GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length,
|
||||||
void BindFragDataLocation(GLuint program, GLuint colorNumber, const char* name);
|
GLchar* uniformBlockName);
|
||||||
GLint GetFragDataLocation(GLuint program, const char* name);
|
void BindFragDataLocation(GLuint program, GLuint colorNumber, const char* name);
|
||||||
void ValidateProgram(GLuint program);
|
GLint GetFragDataLocation(GLuint program, const char* name);
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
void ValidateProgram(GLuint program);
|
||||||
|
} // namespace MG_Impl::GLImpl
|
||||||
|
} // namespace MobileGL
|
||||||
|
|||||||
@@ -7,467 +7,474 @@
|
|||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
#include "GL_RenderState.h"
|
#include "GL_RenderState.h"
|
||||||
|
#include "MG_State/GLState/RenderState/RenderState.h"
|
||||||
|
#include "MG_Util/Converters/GLToStr/GLEnumConverter.h"
|
||||||
#include <MG_State/GLState/Core.h>
|
#include <MG_State/GLState/Core.h>
|
||||||
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
|
||||||
#include <MG_Util/Converters/GLToMG/RenderStateEnumConverter.h>
|
#include <MG_Util/Converters/GLToMG/RenderStateEnumConverter.h>
|
||||||
#include <MG_Util/Converters/MGToGL/RenderStateEnumConverter.h>
|
#include <MG_Util/Converters/MGToGL/RenderStateEnumConverter.h>
|
||||||
#include <MG_Util/Converters/MGToStr/RenderStateEnumConverter.h>
|
#include <MG_Util/Converters/MGToStr/RenderStateEnumConverter.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl {
|
namespace MobileGL {
|
||||||
void Viewport_State(GLint x, GLint y, GLsizei width, GLsizei height) {
|
namespace MG_Impl::GLImpl {
|
||||||
if (width < 0 || height < 0) {
|
void Viewport_State(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
if (width < 0 || height < 0) {
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Viewport_State",
|
MG_State::pGLContext->RecordError(
|
||||||
"Width abd height must be non-negative."));
|
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Viewport_State",
|
||||||
return;
|
"Width abd height must be non-negative."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_State::pGLContext->SetViewport(IntVec4(x, y, width, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
MG_State::pGLContext->SetViewport(IntVec4(x, y, width, height));
|
void StencilOpSeparate_State(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {
|
||||||
}
|
// TODO: implement
|
||||||
|
|
||||||
void StencilOpSeparate_State(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void StencilOp_State(GLenum fail, GLenum zfail, GLenum zpass) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void StencilMaskSeparate_State(GLenum face, GLuint mask) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void StencilMask_State(GLuint mask) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void StencilFuncSeparate_State(GLenum face, GLenum func, GLint ref, GLuint mask) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void StencilFunc_State(GLenum func, GLint ref, GLuint mask) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scissor_State(GLint x, GLint y, GLsizei width, GLsizei height) {
|
|
||||||
if (width < 0 || height < 0) {
|
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Scissor_State",
|
|
||||||
"Width abd height must be non-negative."));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MG_State::pGLContext->SetScissorBox(IntVec4(x, y, width, height));
|
void StencilOp_State(GLenum fail, GLenum zfail, GLenum zpass) {
|
||||||
}
|
// TODO: implement
|
||||||
|
|
||||||
void SampleCoverage_State(GLfloat value, GLboolean invert) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void PolygonOffset_State(GLfloat factor, GLfloat units) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void PolygonMode_State(GLenum face, GLenum mode) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void PointSize_State(GLfloat size) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void PointParameterf_State(GLenum pname, GLfloat param) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void PointParameteri_State(GLenum pname, GLint param) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelStorei_State(GLenum pname, GLint param) {
|
|
||||||
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), param);
|
|
||||||
PixelStoreParam pixelStoreParam = MG_Util::ConvertGLEnumToPixelStoreParam(pname);
|
|
||||||
if (pixelStoreParam == PixelStoreParam::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "PixelStorei_State",
|
|
||||||
"Pixel store param enum " +
|
|
||||||
MG_Util::ConvertPixelStoreParamToString(pixelStoreParam) + "(" +
|
|
||||||
MG_Util::ConvertGLEnumToString(pname) + ") is not supported."));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MG_State::pGLContext->SetPixelStoreParam(pixelStoreParam, param);
|
void StencilMaskSeparate_State(GLenum face, GLuint mask) {
|
||||||
}
|
// TODO: implement
|
||||||
|
|
||||||
void LogicOp_State(GLenum opcode) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void LineWidth_State(GLfloat width) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
GLboolean IsEnabledi_State(GLenum target, GLuint index) {
|
|
||||||
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
|
|
||||||
if (capInput == CapabilityInput::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "IsEnabledi_State",
|
|
||||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
|
||||||
"(" + MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
|
|
||||||
return GL_FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return MG_State::pGLContext->IsCapabilityEnabledIndexed(capInput, index) ? GL_TRUE : GL_FALSE;
|
void StencilMask_State(GLuint mask) {
|
||||||
}
|
// TODO: implement
|
||||||
|
|
||||||
GLboolean IsEnabled_State(GLenum cap) {
|
|
||||||
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
|
|
||||||
if (capInput == CapabilityInput::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "IsEnabled_State",
|
|
||||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
|
||||||
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
|
|
||||||
return GL_FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return MG_State::pGLContext->IsCapabilityEnabled(capInput) ? GL_TRUE : GL_FALSE;
|
void StencilFuncSeparate_State(GLenum face, GLenum func, GLint ref, GLuint mask) {
|
||||||
}
|
// TODO: implement
|
||||||
|
|
||||||
void Hint_State(GLenum target, GLenum mode) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrontFace_State(GLenum mode) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void Enable_State(GLenum cap) {
|
|
||||||
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
|
|
||||||
if (capInput == CapabilityInput::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Enable_State",
|
|
||||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
|
||||||
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MG_State::pGLContext->SetCapability(capInput, true);
|
void StencilFunc_State(GLenum func, GLint ref, GLuint mask) {
|
||||||
}
|
// TODO: implement
|
||||||
|
|
||||||
void Disable_State(GLenum cap) {
|
|
||||||
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
|
|
||||||
if (capInput == CapabilityInput::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Disable_State",
|
|
||||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
|
||||||
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MG_State::pGLContext->SetCapability(capInput, false);
|
void Scissor_State(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||||
}
|
if (width < 0 || height < 0) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Scissor_State",
|
||||||
|
"Width abd height must be non-negative."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void DepthRange_State(GLclampd near_val, GLclampd far_val) {
|
MG_State::pGLContext->SetScissorBox(IntVec4(x, y, width, height));
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void DepthMask_State(GLboolean flag) {
|
|
||||||
MG_State::pGLContext->SetDepthMask(flag == GL_TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DepthFunc_State(GLenum func) {
|
|
||||||
DepthTestFunc depthFunc = MG_Util::ConvertGLEnumToDepthTestFunc(func);
|
|
||||||
if (depthFunc == DepthTestFunc::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DepthFunc_State",
|
|
||||||
"Depth function enum " + MG_Util::ConvertDepthTestFuncToString(depthFunc) +
|
|
||||||
"(" + MG_Util::ConvertGLEnumToString(func) + ") is not supported."));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MG_State::pGLContext->SetDepthFunc(depthFunc);
|
void SampleCoverage_State(GLfloat value, GLboolean invert) {
|
||||||
}
|
// TODO: implement
|
||||||
|
|
||||||
void CullFace_State(GLenum mode) {
|
|
||||||
CullFaceMode cullFaceMode = MG_Util::ConvertGLEnumToCullFaceMode(mode);
|
|
||||||
if (cullFaceMode == CullFaceMode::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CullFace_State",
|
|
||||||
"Cull face mode enum " +
|
|
||||||
MG_Util::ConvertCullFaceModeToString(cullFaceMode) + "(" +
|
|
||||||
MG_Util::ConvertGLEnumToString(mode) + ") is not supported."));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MG_State::pGLContext->SetCullFaceMode(cullFaceMode);
|
void PolygonOffset_State(GLfloat factor, GLfloat units) {
|
||||||
}
|
// TODO: implement
|
||||||
|
|
||||||
void ColorMask_State(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
|
||||||
MG_State::pGLContext->SetColorMask(
|
|
||||||
BoolVec4(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClampColor_State(GLenum target, GLenum clamp) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void BlendFuncSeparate_State(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {
|
|
||||||
BlendFactor srcRGB = MG_Util::ConvertGLEnumToBlendFactor(sfactorRGB);
|
|
||||||
BlendFactor dstRGB = MG_Util::ConvertGLEnumToBlendFactor(dfactorRGB);
|
|
||||||
BlendFactor srcAlpha = MG_Util::ConvertGLEnumToBlendFactor(sfactorAlpha);
|
|
||||||
BlendFactor dstAlpha = MG_Util::ConvertGLEnumToBlendFactor(dfactorAlpha);
|
|
||||||
|
|
||||||
if (srcRGB == BlendFactor::Unknown || dstRGB == BlendFactor::Unknown || srcAlpha == BlendFactor::Unknown ||
|
|
||||||
dstAlpha == BlendFactor::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BlendFuncSeparate_State",
|
|
||||||
"One of the blend factor enums is not supported: srcRGB " +
|
|
||||||
MG_Util::ConvertBlendFactorToString(srcRGB) + "(" +
|
|
||||||
MG_Util::ConvertGLEnumToString(sfactorRGB) + "), dstRGB " +
|
|
||||||
MG_Util::ConvertBlendFactorToString(dstRGB) + "(" +
|
|
||||||
MG_Util::ConvertGLEnumToString(dfactorRGB) + "), srcAlpha " +
|
|
||||||
MG_Util::ConvertBlendFactorToString(srcAlpha) + "(" +
|
|
||||||
MG_Util::ConvertGLEnumToString(sfactorAlpha) + "), dstAlpha " +
|
|
||||||
MG_Util::ConvertBlendFactorToString(dstAlpha) + "(" +
|
|
||||||
MG_Util::ConvertGLEnumToString(dfactorAlpha) + ")."));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MG_State::pGLContext->SetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
void PolygonMode_State(GLenum face, GLenum mode) {
|
||||||
}
|
// TODO: implement
|
||||||
|
|
||||||
void BlendFunc_State(GLenum sfactor, GLenum dfactor) {
|
|
||||||
BlendFuncSeparate_State(sfactor, dfactor, sfactor, dfactor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BlendEquation_State(GLenum mode) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void BlendColor_State(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearStencil_State(GLint s) {
|
|
||||||
MG_State::pGLContext->SetClearStencil(static_cast<Int>(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearDepth_State(GLclampd depth) {
|
|
||||||
MG_State::pGLContext->SetClearDepth(static_cast<Float>(depth));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearColor_State(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
|
||||||
MG_State::pGLContext->SetClearColor(FloatVec4(red, green, blue, alpha));
|
|
||||||
}
|
|
||||||
|
|
||||||
void BlendFuncSeparatei_State(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
|
|
||||||
if (buf >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidValue,
|
|
||||||
MakeUnique<GenericErrorInfo>(
|
|
||||||
"MG_Impl/GLImpl", "BlendFuncSeparatei_State",
|
|
||||||
"Buffer index " + std::to_string(buf) + " is out of range. Max supported is " +
|
|
||||||
std::to_string(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS - 1) + "."));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BlendFactor srcRGBM = MG_Util::ConvertGLEnumToBlendFactor(srcRGB);
|
void PointSize_State(GLfloat size) {
|
||||||
BlendFactor dstRGBM = MG_Util::ConvertGLEnumToBlendFactor(dstRGB);
|
// TODO: implement
|
||||||
BlendFactor srcAlphaM = MG_Util::ConvertGLEnumToBlendFactor(srcAlpha);
|
|
||||||
BlendFactor dstAlphaM = MG_Util::ConvertGLEnumToBlendFactor(dstAlpha);
|
|
||||||
MG_State::pGLContext->SetBlendFuncIndexed(buf, srcRGBM, dstRGBM, srcAlphaM, dstAlphaM);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Disablei_State(GLenum target, GLuint index) {
|
|
||||||
auto capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
|
|
||||||
if (capInput == CapabilityInput::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Disablei_State",
|
|
||||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
|
||||||
"(" + MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MG_State::pGLContext->SetCapabilityIndexed(capInput, index, false);
|
void PointParameterf_State(GLenum pname, GLfloat param) {
|
||||||
}
|
// TODO: implement
|
||||||
|
|
||||||
void Enablei_State(GLenum target, GLuint index) {
|
|
||||||
auto capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
|
|
||||||
if (capInput == CapabilityInput::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Enablei_State",
|
|
||||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
|
||||||
"(" + MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MG_State::pGLContext->SetCapabilityIndexed(capInput, index, true);
|
void PointParameteri_State(GLenum pname, GLint param) {
|
||||||
}
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
void PixelStorei_State(GLenum pname, GLint param) {
|
||||||
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
|
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), param);
|
||||||
BlendFuncSeparatei_State(buf, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
PixelStoreParam pixelStoreParam = MG_Util::ConvertGLEnumToPixelStoreParam(pname);
|
||||||
}
|
if (pixelStoreParam == PixelStoreParam::Unknown) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "PixelStorei_State",
|
||||||
|
"Pixel store param enum " +
|
||||||
|
MG_Util::ConvertPixelStoreParamToString(pixelStoreParam) + "(" +
|
||||||
|
MG_Util::ConvertGLEnumToString(pname) + ") is not supported."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void Disablei(GLenum target, GLuint index) {
|
MG_State::pGLContext->SetPixelStoreParam(pixelStoreParam, param);
|
||||||
Disablei_State(target, index);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Enablei(GLenum target, GLuint index) {
|
void LogicOp_State(GLenum opcode) {
|
||||||
Enablei_State(target, index);
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlendFunc(GLenum sfactor, GLenum dfactor) {
|
void LineWidth_State(GLfloat width) {
|
||||||
BlendFunc_State(sfactor, dfactor);
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
|
GLboolean IsEnabledi_State(GLenum target, GLuint index) {
|
||||||
Viewport_State(x, y, width, height);
|
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
|
||||||
}
|
if (capInput == CapabilityInput::Unknown) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "IsEnabledi_State",
|
||||||
|
"Capability enum " +
|
||||||
|
MG_Util::ConvertCapabilityInputToString(capInput) + "(" +
|
||||||
|
MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
|
||||||
|
return GL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {
|
return MG_State::pGLContext->IsCapabilityEnabledIndexed(capInput, index) ? GL_TRUE : GL_FALSE;
|
||||||
StencilOpSeparate_State(face, sfail, dpfail, dppass);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
|
GLboolean IsEnabled_State(GLenum cap) {
|
||||||
StencilOp_State(fail, zfail, zpass);
|
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
|
||||||
}
|
if (capInput == CapabilityInput::Unknown) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>(
|
||||||
|
"MG_Impl/GLImpl", "IsEnabled_State",
|
||||||
|
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
||||||
|
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
|
||||||
|
return GL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
void StencilMaskSeparate(GLenum face, GLuint mask) {
|
return MG_State::pGLContext->IsCapabilityEnabled(capInput) ? GL_TRUE : GL_FALSE;
|
||||||
StencilMaskSeparate_State(face, mask);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void StencilMask(GLuint mask) {
|
void Hint_State(GLenum target, GLenum mode) {
|
||||||
StencilMask_State(mask);
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {
|
void FrontFace_State(GLenum mode) {
|
||||||
StencilFuncSeparate_State(face, func, ref, mask);
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
void StencilFunc(GLenum func, GLint ref, GLuint mask) {
|
void Enable_State(GLenum cap) {
|
||||||
StencilFunc_State(func, ref, mask);
|
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
|
||||||
}
|
if (capInput == CapabilityInput::Unknown) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>(
|
||||||
|
"MG_Impl/GLImpl", "Enable_State",
|
||||||
|
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
||||||
|
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) {
|
MG_State::pGLContext->SetCapability(capInput, true);
|
||||||
Scissor_State(x, y, width, height);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void SampleCoverage(GLfloat value, GLboolean invert) {
|
void Disable_State(GLenum cap) {
|
||||||
SampleCoverage_State(value, invert);
|
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
|
||||||
}
|
if (capInput == CapabilityInput::Unknown) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>(
|
||||||
|
"MG_Impl/GLImpl", "Disable_State",
|
||||||
|
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
||||||
|
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void PolygonOffset(GLfloat factor, GLfloat units) {
|
MG_State::pGLContext->SetCapability(capInput, false);
|
||||||
PolygonOffset_State(factor, units);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void PolygonMode(GLenum face, GLenum mode) {
|
void DepthRange_State(GLclampd near_val, GLclampd far_val) {
|
||||||
PolygonMode_State(face, mode);
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointSize(GLfloat size) {
|
void DepthMask_State(GLboolean flag) {
|
||||||
PointSize_State(size);
|
MG_State::pGLContext->SetDepthMask(flag == GL_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointParameterf(GLenum pname, GLfloat param) {
|
void DepthFunc_State(GLenum func) {
|
||||||
PointParameterf_State(pname, param);
|
DepthTestFunc depthFunc = MG_Util::ConvertGLEnumToDepthTestFunc(func);
|
||||||
}
|
if (depthFunc == DepthTestFunc::Unknown) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DepthFunc_State",
|
||||||
|
"Depth function enum " +
|
||||||
|
MG_Util::ConvertDepthTestFuncToString(depthFunc) + "(" +
|
||||||
|
MG_Util::ConvertGLEnumToString(func) + ") is not supported."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void PointParameteri(GLenum pname, GLint param) {
|
MG_State::pGLContext->SetDepthFunc(depthFunc);
|
||||||
PointParameteri_State(pname, param);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void PixelStorei(GLenum pname, GLint param) {
|
void CullFace_State(GLenum mode) {
|
||||||
PixelStorei_State(pname, param);
|
CullFaceMode cullFaceMode = MG_Util::ConvertGLEnumToCullFaceMode(mode);
|
||||||
}
|
if (cullFaceMode == CullFaceMode::Unknown) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "CullFace_State",
|
||||||
|
"Cull face mode enum " +
|
||||||
|
MG_Util::ConvertCullFaceModeToString(cullFaceMode) + "(" +
|
||||||
|
MG_Util::ConvertGLEnumToString(mode) + ") is not supported."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void LogicOp(GLenum opcode) {
|
MG_State::pGLContext->SetCullFaceMode(cullFaceMode);
|
||||||
LogicOp_State(opcode);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void LineWidth(GLfloat width) {
|
void ColorMask_State(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
||||||
LineWidth_State(width);
|
MG_State::pGLContext->SetColorMask(
|
||||||
}
|
BoolVec4(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE));
|
||||||
|
}
|
||||||
|
|
||||||
GLboolean IsEnabledi(GLenum target, GLuint index) {
|
void ClampColor_State(GLenum target, GLenum clamp) {
|
||||||
return IsEnabledi_State(target, index);
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
GLboolean IsEnabled(GLenum cap) {
|
void BlendFuncSeparate_State(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {
|
||||||
return IsEnabled_State(cap);
|
BlendFactor srcRGB = MG_Util::ConvertGLEnumToBlendFactor(sfactorRGB);
|
||||||
}
|
BlendFactor dstRGB = MG_Util::ConvertGLEnumToBlendFactor(dfactorRGB);
|
||||||
|
BlendFactor srcAlpha = MG_Util::ConvertGLEnumToBlendFactor(sfactorAlpha);
|
||||||
|
BlendFactor dstAlpha = MG_Util::ConvertGLEnumToBlendFactor(dfactorAlpha);
|
||||||
|
|
||||||
void Hint(GLenum target, GLenum mode) {
|
if (srcRGB == BlendFactor::Unknown || dstRGB == BlendFactor::Unknown || srcAlpha == BlendFactor::Unknown ||
|
||||||
Hint_State(target, mode);
|
dstAlpha == BlendFactor::Unknown) {
|
||||||
}
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BlendFuncSeparate_State",
|
||||||
|
"One of the blend factor enums is not supported: srcRGB " +
|
||||||
|
MG_Util::ConvertBlendFactorToString(srcRGB) + "(" +
|
||||||
|
MG_Util::ConvertGLEnumToString(sfactorRGB) + "), dstRGB " +
|
||||||
|
MG_Util::ConvertBlendFactorToString(dstRGB) + "(" +
|
||||||
|
MG_Util::ConvertGLEnumToString(dfactorRGB) + "), srcAlpha " +
|
||||||
|
MG_Util::ConvertBlendFactorToString(srcAlpha) + "(" +
|
||||||
|
MG_Util::ConvertGLEnumToString(sfactorAlpha) + "), dstAlpha " +
|
||||||
|
MG_Util::ConvertBlendFactorToString(dstAlpha) + "(" +
|
||||||
|
MG_Util::ConvertGLEnumToString(dfactorAlpha) + ")."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void FrontFace(GLenum mode) {
|
MG_State::pGLContext->SetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||||
FrontFace_State(mode);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Enable(GLenum cap) {
|
void BlendFunc_State(GLenum sfactor, GLenum dfactor) {
|
||||||
Enable_State(cap);
|
BlendFuncSeparate_State(sfactor, dfactor, sfactor, dfactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Disable(GLenum cap) {
|
void BlendEquation_State(GLenum mode) {
|
||||||
Disable_State(cap);
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
void DepthRange(GLclampd near_val, GLclampd far_val) {
|
void BlendColor_State(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||||
DepthRange_State(near_val, far_val);
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
void DepthMask(GLboolean flag) {
|
void ClearStencil_State(GLint s) {
|
||||||
DepthMask_State(flag);
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
void DepthFunc(GLenum func) {
|
void ClearDepth_State(GLclampd depth) {
|
||||||
DepthFunc_State(func);
|
MG_State::pGLContext->SetClearDepth(static_cast<Float>(depth));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CullFace(GLenum mode) {
|
void ClearColor_State(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||||
CullFace_State(mode);
|
MG_State::pGLContext->SetClearColor(FloatVec4(red, green, blue, alpha));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
void BlendFuncSeparatei_State(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
|
||||||
ColorMask_State(red, green, blue, alpha);
|
if (buf >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
||||||
}
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>(
|
||||||
|
"MG_Impl/GLImpl", "BlendFuncSeparatei_State",
|
||||||
|
"Buffer index " + std::to_string(buf) + " is out of range. Max supported is " +
|
||||||
|
std::to_string(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS - 1) + "."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void ClampColor(GLenum target, GLenum clamp) {
|
BlendFactor srcRGBM = MG_Util::ConvertGLEnumToBlendFactor(srcRGB);
|
||||||
ClampColor_State(target, clamp);
|
BlendFactor dstRGBM = MG_Util::ConvertGLEnumToBlendFactor(dstRGB);
|
||||||
}
|
BlendFactor srcAlphaM = MG_Util::ConvertGLEnumToBlendFactor(srcAlpha);
|
||||||
|
BlendFactor dstAlphaM = MG_Util::ConvertGLEnumToBlendFactor(dstAlpha);
|
||||||
|
MG_State::pGLContext->SetBlendFuncIndexed(buf, srcRGBM, dstRGBM, srcAlphaM, dstAlphaM);
|
||||||
|
}
|
||||||
|
|
||||||
void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {
|
void Disablei_State(GLenum target, GLuint index) {
|
||||||
BlendFuncSeparate_State(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
|
auto capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
|
||||||
}
|
if (capInput == CapabilityInput::Unknown) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Disablei_State",
|
||||||
|
"Capability enum " +
|
||||||
|
MG_Util::ConvertCapabilityInputToString(capInput) + "(" +
|
||||||
|
MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void BlendEquation(GLenum mode) {
|
MG_State::pGLContext->SetCapabilityIndexed(capInput, index, false);
|
||||||
BlendEquation_State(mode);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
void Enablei_State(GLenum target, GLuint index) {
|
||||||
BlendColor_State(red, green, blue, alpha);
|
auto capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
|
||||||
}
|
if (capInput == CapabilityInput::Unknown) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Enablei_State",
|
||||||
|
"Capability enum " +
|
||||||
|
MG_Util::ConvertCapabilityInputToString(capInput) + "(" +
|
||||||
|
MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void ClearStencil(GLint s) {
|
MG_State::pGLContext->SetCapabilityIndexed(capInput, index, true);
|
||||||
ClearStencil_State(s);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void ClearDepth(GLclampd depth) {
|
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||||
ClearDepth_State(depth);
|
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
|
||||||
}
|
BlendFuncSeparatei_State(buf, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
void Disablei(GLenum target, GLuint index) {
|
||||||
ClearColor_State(red, green, blue, alpha);
|
Disablei_State(target, index);
|
||||||
}
|
}
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
|
||||||
|
void Enablei(GLenum target, GLuint index) {
|
||||||
|
Enablei_State(target, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlendFunc(GLenum sfactor, GLenum dfactor) {
|
||||||
|
BlendFunc_State(sfactor, dfactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||||
|
Viewport_State(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {
|
||||||
|
StencilOpSeparate_State(face, sfail, dpfail, dppass);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
|
||||||
|
StencilOp_State(fail, zfail, zpass);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StencilMaskSeparate(GLenum face, GLuint mask) {
|
||||||
|
StencilMaskSeparate_State(face, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StencilMask(GLuint mask) {
|
||||||
|
StencilMask_State(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {
|
||||||
|
StencilFuncSeparate_State(face, func, ref, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StencilFunc(GLenum func, GLint ref, GLuint mask) {
|
||||||
|
StencilFunc_State(func, ref, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||||
|
Scissor_State(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleCoverage(GLfloat value, GLboolean invert) {
|
||||||
|
SampleCoverage_State(value, invert);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PolygonOffset(GLfloat factor, GLfloat units) {
|
||||||
|
PolygonOffset_State(factor, units);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PolygonMode(GLenum face, GLenum mode) {
|
||||||
|
PolygonMode_State(face, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PointSize(GLfloat size) {
|
||||||
|
PointSize_State(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PointParameterf(GLenum pname, GLfloat param) {
|
||||||
|
PointParameterf_State(pname, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PointParameteri(GLenum pname, GLint param) {
|
||||||
|
PointParameteri_State(pname, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixelStorei(GLenum pname, GLint param) {
|
||||||
|
PixelStorei_State(pname, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogicOp(GLenum opcode) {
|
||||||
|
LogicOp_State(opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineWidth(GLfloat width) {
|
||||||
|
LineWidth_State(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLboolean IsEnabledi(GLenum target, GLuint index) {
|
||||||
|
return IsEnabledi_State(target, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLboolean IsEnabled(GLenum cap) {
|
||||||
|
return IsEnabled_State(cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hint(GLenum target, GLenum mode) {
|
||||||
|
Hint_State(target, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrontFace(GLenum mode) {
|
||||||
|
FrontFace_State(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Enable(GLenum cap) {
|
||||||
|
Enable_State(cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Disable(GLenum cap) {
|
||||||
|
Disable_State(cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DepthRange(GLclampd near_val, GLclampd far_val) {
|
||||||
|
DepthRange_State(near_val, far_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DepthMask(GLboolean flag) {
|
||||||
|
DepthMask_State(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DepthFunc(GLenum func) {
|
||||||
|
DepthFunc_State(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CullFace(GLenum mode) {
|
||||||
|
CullFace_State(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
||||||
|
ColorMask_State(red, green, blue, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClampColor(GLenum target, GLenum clamp) {
|
||||||
|
ClampColor_State(target, clamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {
|
||||||
|
BlendFuncSeparate_State(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlendEquation(GLenum mode) {
|
||||||
|
BlendEquation_State(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||||
|
BlendColor_State(red, green, blue, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearStencil(GLint s) {
|
||||||
|
ClearStencil_State(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearDepth(GLclampd depth) {
|
||||||
|
ClearDepth_State(depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||||
|
ClearColor_State(red, green, blue, alpha);
|
||||||
|
}
|
||||||
|
} // namespace MG_Impl::GLImpl
|
||||||
|
} // namespace MobileGL
|
||||||
|
|||||||
@@ -9,45 +9,47 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl {
|
namespace MobileGL {
|
||||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
namespace MG_Impl::GLImpl {
|
||||||
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
|
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||||
void Disablei(GLenum target, GLuint index);
|
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
|
||||||
void Enablei(GLenum target, GLuint index);
|
void Disablei(GLenum target, GLuint index);
|
||||||
void BlendFunc(GLenum sfactor, GLenum dfactor);
|
void Enablei(GLenum target, GLuint index);
|
||||||
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
|
void BlendFunc(GLenum sfactor, GLenum dfactor);
|
||||||
void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
|
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||||
void StencilOp(GLenum fail, GLenum zfail, GLenum zpass);
|
void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
|
||||||
void StencilMaskSeparate(GLenum face, GLuint mask);
|
void StencilOp(GLenum fail, GLenum zfail, GLenum zpass);
|
||||||
void StencilMask(GLuint mask);
|
void StencilMaskSeparate(GLenum face, GLuint mask);
|
||||||
void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
|
void StencilMask(GLuint mask);
|
||||||
void StencilFunc(GLenum func, GLint ref, GLuint mask);
|
void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
|
||||||
void Scissor(GLint x, GLint y, GLsizei width, GLsizei height);
|
void StencilFunc(GLenum func, GLint ref, GLuint mask);
|
||||||
void SampleCoverage(GLfloat value, GLboolean invert);
|
void Scissor(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||||
void PolygonOffset(GLfloat factor, GLfloat units);
|
void SampleCoverage(GLfloat value, GLboolean invert);
|
||||||
void PolygonMode(GLenum face, GLenum mode);
|
void PolygonOffset(GLfloat factor, GLfloat units);
|
||||||
void PointSize(GLfloat size);
|
void PolygonMode(GLenum face, GLenum mode);
|
||||||
void PointParameterf(GLenum pname, GLfloat param);
|
void PointSize(GLfloat size);
|
||||||
void PointParameteri(GLenum pname, GLint param);
|
void PointParameterf(GLenum pname, GLfloat param);
|
||||||
void PixelStorei(GLenum pname, GLint param);
|
void PointParameteri(GLenum pname, GLint param);
|
||||||
void LogicOp(GLenum opcode);
|
void PixelStorei(GLenum pname, GLint param);
|
||||||
void LineWidth(GLfloat width);
|
void LogicOp(GLenum opcode);
|
||||||
GLboolean IsEnabledi(GLenum target, GLuint index);
|
void LineWidth(GLfloat width);
|
||||||
GLboolean IsEnabled(GLenum cap);
|
GLboolean IsEnabledi(GLenum target, GLuint index);
|
||||||
void Hint(GLenum target, GLenum mode);
|
GLboolean IsEnabled(GLenum cap);
|
||||||
void FrontFace(GLenum mode);
|
void Hint(GLenum target, GLenum mode);
|
||||||
void Enable(GLenum cap);
|
void FrontFace(GLenum mode);
|
||||||
void Disable(GLenum cap);
|
void Enable(GLenum cap);
|
||||||
void DepthRange(GLclampd near_val, GLclampd far_val);
|
void Disable(GLenum cap);
|
||||||
void DepthMask(GLboolean flag);
|
void DepthRange(GLclampd near_val, GLclampd far_val);
|
||||||
void DepthFunc(GLenum func);
|
void DepthMask(GLboolean flag);
|
||||||
void CullFace(GLenum mode);
|
void DepthFunc(GLenum func);
|
||||||
void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
|
void CullFace(GLenum mode);
|
||||||
void ClampColor(GLenum target, GLenum clamp);
|
void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
|
||||||
void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
|
void ClampColor(GLenum target, GLenum clamp);
|
||||||
void BlendEquation(GLenum mode);
|
void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
|
||||||
void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
void BlendEquation(GLenum mode);
|
||||||
void ClearStencil(GLint s);
|
void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||||
void ClearDepth(GLclampd depth);
|
void ClearStencil(GLint s);
|
||||||
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
void ClearDepth(GLclampd depth);
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||||
|
} // namespace MG_Impl::GLImpl
|
||||||
|
} // namespace MobileGL
|
||||||
|
|||||||
@@ -12,258 +12,254 @@
|
|||||||
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
||||||
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
|
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl {
|
namespace MobileGL {
|
||||||
void SetSamplerParam_State(GLuint sampler, GLenum pname, const void* param, bool isFloat, bool isInteger) {
|
namespace MG_Impl::GLImpl {
|
||||||
if (!SamplerImpl::ValidateSamplerName(sampler)) return;
|
void SetSamplerParam_State(GLuint sampler, GLenum pname, const void* param, bool isFloat, bool isInteger) {
|
||||||
|
|
||||||
Bool doesSamplerObjectCreated = MG_State::pGLContext->ValidateSamplerObject(sampler);
|
|
||||||
if (!doesSamplerObjectCreated) {
|
|
||||||
// Create one for compatibility
|
|
||||||
MG_State::pGLContext->CreateSamplerObject(sampler);
|
|
||||||
}
|
|
||||||
auto& samplerObj = MG_State::pGLContext->GetSamplerObject(sampler);
|
|
||||||
if (!SamplerImpl::ValidateSamplerObject(sampler)) return;
|
|
||||||
|
|
||||||
using namespace MG_Util;
|
|
||||||
switch (pname) {
|
|
||||||
case GL_TEXTURE_WRAP_S:
|
|
||||||
samplerObj->SetWrapS(MG_Util::ConvertGLEnumToSamplerWrapMode(*(const GLint*)param));
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_WRAP_T:
|
|
||||||
samplerObj->SetWrapT(MG_Util::ConvertGLEnumToSamplerWrapMode(*(const GLint*)param));
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_WRAP_R:
|
|
||||||
samplerObj->SetWrapR(MG_Util::ConvertGLEnumToSamplerWrapMode(*(const GLint*)param));
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_MIN_FILTER:
|
|
||||||
samplerObj->SetMinFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(*(const GLint*)param));
|
|
||||||
samplerObj->SetMipmapMode(MG_Util::ConvertGLEnumToSamplerMipmapMode(*(const GLint*)param));
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_MAG_FILTER:
|
|
||||||
samplerObj->SetMagFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(*(const GLint*)param));
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_MIN_LOD:
|
|
||||||
samplerObj->SetLodRange(*(const GLfloat*)param, samplerObj->GetMaxLod());
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_MAX_LOD:
|
|
||||||
samplerObj->SetLodRange(samplerObj->GetMinLod(), *(const GLfloat*)param);
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_LOD_BIAS:
|
|
||||||
samplerObj->SetLodBias(*(const GLfloat*)param);
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_COMPARE_MODE:
|
|
||||||
samplerObj->SetCompareMode(MG_Util::ConvertGLEnumToSamplerCompareMode(*(const GLint*)param));
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_COMPARE_FUNC:
|
|
||||||
samplerObj->SetSamplerCompareFunc(MG_Util::ConvertGLEnumToSamplerCompareFunc(*(const GLint*)param));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "SetSamplerParam_State",
|
|
||||||
"Invalid pname for sampler parameter"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetSamplerParam_State(GLuint sampler, GLenum pname, void* params, bool isFloat, bool isInteger) {
|
|
||||||
if (!SamplerImpl::ValidateSamplerName(sampler)) return;
|
|
||||||
|
|
||||||
Bool doesSamplerObjectCreated = MG_State::pGLContext->ValidateSamplerObject(sampler);
|
|
||||||
if (!doesSamplerObjectCreated) {
|
|
||||||
// Create one for compatibility
|
|
||||||
MG_State::pGLContext->CreateSamplerObject(sampler);
|
|
||||||
}
|
|
||||||
auto& samplerObj = MG_State::pGLContext->GetSamplerObject(sampler);
|
|
||||||
if (!SamplerImpl::ValidateSamplerObject(sampler)) return;
|
|
||||||
|
|
||||||
using namespace MG_Util;
|
|
||||||
switch (pname) {
|
|
||||||
case GL_TEXTURE_WRAP_S:
|
|
||||||
*(GLuint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapS());
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_WRAP_T:
|
|
||||||
*(GLuint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapT());
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_WRAP_R:
|
|
||||||
*(GLuint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapR());
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_MIN_FILTER:
|
|
||||||
*(GLuint*)params =
|
|
||||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObj->GetMinFilter(), samplerObj->GetMipmapMode());
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_MAG_FILTER:
|
|
||||||
*(GLuint*)params =
|
|
||||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObj->GetMagFilter(), SamplerMipmapMode::None);
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_MIN_LOD:
|
|
||||||
*(GLfloat*)params = samplerObj->GetMinLod();
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_MAX_LOD:
|
|
||||||
*(GLfloat*)params = samplerObj->GetMaxLod();
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_LOD_BIAS:
|
|
||||||
*(GLfloat*)params = samplerObj->GetLodBias();
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_COMPARE_MODE:
|
|
||||||
*(GLuint*)params = MG_Util::ConvertSamplerCompareModeToGLEnum(samplerObj->GetCompareMode());
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_COMPARE_FUNC:
|
|
||||||
*(GLuint*)params = MG_Util::ConvertSamplerCompareFuncToGLEnum(samplerObj->GetSamplerCompareFunc());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetSamplerParam_State",
|
|
||||||
"Invalid pname for sampler parameter"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GLboolean IsSampler_State(GLuint sampler) {
|
|
||||||
return MG_State::pGLContext->ValidateSamplerObject(sampler) ? GL_TRUE : GL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// migrate below functions without "_State" into this section
|
|
||||||
void GenSamplers_State(GLsizei count, GLuint* samplers) {
|
|
||||||
if (count < 0) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidValue,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenSamplers", "count must be non-negative"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static thread_local Vector<GLuint> names;
|
|
||||||
MG_State::pGLContext->GenSamplerNames(count, names);
|
|
||||||
Memcpy(samplers, names.data(), count * sizeof(GLuint));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeleteSamplers_State(GLsizei count, const GLuint* samplers) {
|
|
||||||
if (count < 0) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidValue,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteSamplers", "count must be non-negative"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (GLsizei i = 0; i < count; ++i) {
|
|
||||||
if (samplers[i] != 0) {
|
|
||||||
MG_State::pGLContext->MarkSamplerObjectForDeletion(samplers[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateSamplers_State(GLsizei n, GLuint* samplers) {
|
|
||||||
if (n < 0) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidValue,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenSamplers", "count must be non-negative"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static thread_local Vector<GLuint> names;
|
|
||||||
MG_State::pGLContext->GenSamplerNames(n, names);
|
|
||||||
Memcpy(samplers, names.data(), n * sizeof(GLuint));
|
|
||||||
for (GLsizei i = 0; i < n; ++i) {
|
|
||||||
samplers[i] = names[i];
|
|
||||||
MG_State::pGLContext->CreateSamplerObject(names[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BindSampler_State(GLuint unit, GLuint sampler) {
|
|
||||||
if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidValue,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BindSampler", "texture unit out of range"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject((Int)unit);
|
|
||||||
if (sampler == 0) {
|
|
||||||
textureUnit.SetSamplerObject(nullptr);
|
|
||||||
} else {
|
|
||||||
if (!SamplerImpl::ValidateSamplerName(sampler)) return;
|
if (!SamplerImpl::ValidateSamplerName(sampler)) return;
|
||||||
Bool doesSamplerObjectCreated = MG_State::pGLContext->ValidateSamplerObject(sampler);
|
|
||||||
if (!doesSamplerObjectCreated) {
|
auto samplerObj = MG_State::pGLContext->GetSamplerObject(sampler);
|
||||||
MG_State::pGLContext->CreateSamplerObject(sampler);
|
if (!samplerObj) {
|
||||||
|
samplerObj = MG_State::pGLContext->CreateSamplerObject(sampler); // for compatibility
|
||||||
}
|
}
|
||||||
auto& samplerObject = MG_State::pGLContext->GetSamplerObject(sampler);
|
if (!SamplerImpl::ValidateSamplerObject(sampler)) return;
|
||||||
|
|
||||||
textureUnit.SetSamplerObject(MG_State::pGLContext->GetSamplerObject(sampler));
|
using namespace MG_Util;
|
||||||
}
|
switch (pname) {
|
||||||
}
|
case GL_TEXTURE_WRAP_S:
|
||||||
|
samplerObj->SetWrapS(MG_Util::ConvertGLEnumToSamplerWrapMode(*(const GLint*)param));
|
||||||
void BindSamplers_State(GLuint first, GLsizei count, const GLuint* samplers) {
|
break;
|
||||||
if (count < 0) {
|
case GL_TEXTURE_WRAP_T:
|
||||||
MG_State::pGLContext->RecordError(
|
samplerObj->SetWrapT(MG_Util::ConvertGLEnumToSamplerWrapMode(*(const GLint*)param));
|
||||||
ErrorCode::InvalidValue,
|
break;
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BindSamplers", "count must be non-negative"));
|
case GL_TEXTURE_WRAP_R:
|
||||||
return;
|
samplerObj->SetWrapR(MG_Util::ConvertGLEnumToSamplerWrapMode(*(const GLint*)param));
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_MIN_FILTER:
|
||||||
|
samplerObj->SetMinFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(*(const GLint*)param));
|
||||||
|
samplerObj->SetMipmapMode(MG_Util::ConvertGLEnumToSamplerMipmapMode(*(const GLint*)param));
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_MAG_FILTER:
|
||||||
|
samplerObj->SetMagFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(*(const GLint*)param));
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_MIN_LOD:
|
||||||
|
samplerObj->SetLodRange(*(const GLfloat*)param, samplerObj->GetMaxLod());
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_MAX_LOD:
|
||||||
|
samplerObj->SetLodRange(samplerObj->GetMinLod(), *(const GLfloat*)param);
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_LOD_BIAS:
|
||||||
|
samplerObj->SetLodBias(*(const GLfloat*)param);
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_COMPARE_MODE:
|
||||||
|
samplerObj->SetCompareMode(MG_Util::ConvertGLEnumToSamplerCompareMode(*(const GLint*)param));
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_COMPARE_FUNC:
|
||||||
|
samplerObj->SetSamplerCompareFunc(MG_Util::ConvertGLEnumToSamplerCompareFunc(*(const GLint*)param));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "SetSamplerParam_State",
|
||||||
|
"Invalid pname for sampler parameter"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (GLsizei i = 0; i < count; ++i) {
|
void GetSamplerParam_State(GLuint sampler, GLenum pname, void* params, bool isFloat, bool isInteger) {
|
||||||
BindSampler_State(first + i, samplers ? samplers[i] : 0);
|
if (!SamplerImpl::ValidateSamplerName(sampler)) return;
|
||||||
|
|
||||||
|
auto samplerObj = MG_State::pGLContext->GetSamplerObject(sampler);
|
||||||
|
if (!samplerObj) {
|
||||||
|
samplerObj = MG_State::pGLContext->CreateSamplerObject(sampler); // for compatibility
|
||||||
|
}
|
||||||
|
if (!SamplerImpl::ValidateSamplerObject(sampler)) return;
|
||||||
|
|
||||||
|
using namespace MG_Util;
|
||||||
|
switch (pname) {
|
||||||
|
case GL_TEXTURE_WRAP_S:
|
||||||
|
*(GLint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapS());
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_WRAP_T:
|
||||||
|
*(GLint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapT());
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_WRAP_R:
|
||||||
|
*(GLint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapR());
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_MIN_FILTER:
|
||||||
|
*(GLint*)params =
|
||||||
|
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObj->GetMinFilter(), samplerObj->GetMipmapMode());
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_MAG_FILTER:
|
||||||
|
*(GLint*)params =
|
||||||
|
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObj->GetMagFilter(), SamplerMipmapMode::None);
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_MIN_LOD:
|
||||||
|
*(GLfloat*)params = samplerObj->GetMinLod();
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_MAX_LOD:
|
||||||
|
*(GLfloat*)params = samplerObj->GetMaxLod();
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_LOD_BIAS:
|
||||||
|
*(GLfloat*)params = samplerObj->GetLodBias();
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_COMPARE_MODE:
|
||||||
|
*(GLint*)params = MG_Util::ConvertSamplerCompareModeToGLEnum(samplerObj->GetCompareMode());
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_COMPARE_FUNC:
|
||||||
|
*(GLint*)params = MG_Util::ConvertSamplerCompareFuncToGLEnum(samplerObj->GetSamplerCompareFunc());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetSamplerParam_State",
|
||||||
|
"Invalid pname for sampler parameter"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
GLboolean IsSampler_State(GLuint sampler) {
|
||||||
void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) {
|
return MG_State::pGLContext->ValidateSamplerObject(sampler) ? GL_TRUE : GL_FALSE;
|
||||||
GetSamplerParam_State(sampler, pname, params, false, false);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint* param) {
|
// migrate below functions without "_State" into this section
|
||||||
SetSamplerParam_State(sampler, pname, param, false, true);
|
void GenSamplers_State(GLsizei count, GLuint* samplers) {
|
||||||
}
|
if (count < 0) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GenSamplers", "count must be non-negative"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint* param) {
|
auto names = MG_State::pGLContext->GenSamplerNames(count);
|
||||||
SetSamplerParam_State(sampler, pname, param, false, true);
|
for (GLsizei i = 0; i < count; ++i) {
|
||||||
}
|
samplers[i] = names[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param) {
|
void DeleteSamplers_State(GLsizei count, const GLuint* samplers) {
|
||||||
SetSamplerParam_State(sampler, pname, param, false, false);
|
if (count < 0) {
|
||||||
}
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteSamplers", "count must be non-negative"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param) {
|
for (GLsizei i = 0; i < count; ++i) {
|
||||||
SetSamplerParam_State(sampler, pname, param, true, false);
|
if (samplers[i] != 0) {
|
||||||
}
|
MG_State::pGLContext->MarkSamplerObjectForDeletion(samplers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SamplerParameteri(GLuint sampler, GLenum pname, GLint param) {
|
void CreateSamplers_State(GLsizei n, GLuint* samplers) {
|
||||||
SamplerParameteriv(sampler, pname, ¶m);
|
if (n < 0) {
|
||||||
}
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GenSamplers", "count must be non-negative"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) {
|
auto names = MG_State::pGLContext->GenSamplerNames(n);
|
||||||
SamplerParameterfv(sampler, pname, ¶m);
|
for (GLsizei i = 0; i < n; ++i) {
|
||||||
}
|
samplers[i] = names[i];
|
||||||
|
MG_State::pGLContext->CreateSamplerObject(names[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GLboolean IsSampler(GLuint sampler) {
|
void BindSampler_State(GLuint unit, GLuint sampler) {
|
||||||
return IsSampler_State(sampler);
|
if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
|
||||||
}
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BindSampler", "texture unit out of range"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint* params) {
|
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
||||||
GetSamplerParam_State(sampler, pname, params, false, true);
|
if (sampler == 0) {
|
||||||
}
|
textureUnit.SetSamplerObject(nullptr);
|
||||||
|
} else {
|
||||||
|
if (!SamplerImpl::ValidateSamplerName(sampler)) return;
|
||||||
|
auto samplerObject = MG_State::pGLContext->GetSamplerObject(sampler);
|
||||||
|
if (!samplerObject) {
|
||||||
|
samplerObject = MG_State::pGLContext->CreateSamplerObject(sampler);
|
||||||
|
}
|
||||||
|
|
||||||
void GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint* params) {
|
textureUnit.SetSamplerObject(MG_State::pGLContext->GetSamplerObject(sampler));
|
||||||
GetSamplerParam_State(sampler, pname, params, false, true);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) {
|
void BindSamplers_State(GLuint first, GLsizei count, const GLuint* samplers) {
|
||||||
GetSamplerParam_State(sampler, pname, params, true, false);
|
if (count < 0) {
|
||||||
}
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BindSamplers", "count must be non-negative"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void GenSamplers(GLsizei count, GLuint* samplers) {
|
for (GLsizei i = 0; i < count; ++i) {
|
||||||
GenSamplers_State(count, samplers);
|
BindSampler_State(first + i, samplers ? samplers[i] : 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DeleteSamplers(GLsizei count, const GLuint* samplers) {
|
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||||
DeleteSamplers_State(count, samplers);
|
void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) {
|
||||||
}
|
GetSamplerParam_State(sampler, pname, params, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
void CreateSamplers(GLsizei n, GLuint* samplers) {
|
void SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint* param) {
|
||||||
CreateSamplers_State(n, samplers);
|
SetSamplerParam_State(sampler, pname, param, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BindSamplers(GLuint first, GLsizei count, const GLuint* samplers) {
|
void SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint* param) {
|
||||||
BindSamplers_State(first, count, samplers);
|
SetSamplerParam_State(sampler, pname, param, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BindSampler(GLuint unit, GLuint sampler) {
|
void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param) {
|
||||||
BindSampler_State(unit, sampler);
|
SetSamplerParam_State(sampler, pname, param, false, false);
|
||||||
}
|
}
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
|
||||||
|
void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param) {
|
||||||
|
SetSamplerParam_State(sampler, pname, param, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SamplerParameteri(GLuint sampler, GLenum pname, GLint param) {
|
||||||
|
SamplerParameteriv(sampler, pname, ¶m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) {
|
||||||
|
SamplerParameterfv(sampler, pname, ¶m);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLboolean IsSampler(GLuint sampler) {
|
||||||
|
return IsSampler_State(sampler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint* params) {
|
||||||
|
GetSamplerParam_State(sampler, pname, params, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint* params) {
|
||||||
|
GetSamplerParam_State(sampler, pname, params, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) {
|
||||||
|
GetSamplerParam_State(sampler, pname, params, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenSamplers(GLsizei count, GLuint* samplers) {
|
||||||
|
GenSamplers_State(count, samplers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteSamplers(GLsizei count, const GLuint* samplers) {
|
||||||
|
DeleteSamplers_State(count, samplers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateSamplers(GLsizei n, GLuint* samplers) {
|
||||||
|
CreateSamplers_State(n, samplers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindSamplers(GLuint first, GLsizei count, const GLuint* samplers) {
|
||||||
|
BindSamplers_State(first, count, samplers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindSampler(GLuint unit, GLuint sampler) {
|
||||||
|
BindSampler_State(unit, sampler);
|
||||||
|
}
|
||||||
|
} // namespace MG_Impl::GLImpl
|
||||||
|
} // namespace MobileGL
|
||||||
|
|||||||
@@ -9,22 +9,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl {
|
namespace MobileGL {
|
||||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
namespace MG_Impl::GLImpl {
|
||||||
void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params);
|
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||||
void SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint* param);
|
void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params);
|
||||||
void SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint* param);
|
void SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint* param);
|
||||||
void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param);
|
void SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint* param);
|
||||||
void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param);
|
void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param);
|
||||||
void SamplerParameteri(GLuint sampler, GLenum pname, GLint param);
|
void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param);
|
||||||
void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param);
|
void SamplerParameteri(GLuint sampler, GLenum pname, GLint param);
|
||||||
GLboolean IsSampler(GLuint sampler);
|
void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param);
|
||||||
void GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint* params);
|
GLboolean IsSampler(GLuint sampler);
|
||||||
void GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint* params);
|
void GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint* params);
|
||||||
void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params);
|
void GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint* params);
|
||||||
void GenSamplers(GLsizei count, GLuint* samplers);
|
void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params);
|
||||||
void DeleteSamplers(GLsizei count, const GLuint* samplers);
|
void GenSamplers(GLsizei count, GLuint* samplers);
|
||||||
void CreateSamplers(GLsizei n, GLuint* samplers);
|
void DeleteSamplers(GLsizei count, const GLuint* samplers);
|
||||||
void BindSamplers(GLuint first, GLsizei count, const GLuint* samplers);
|
void CreateSamplers(GLsizei n, GLuint* samplers);
|
||||||
void BindSampler(GLuint unit, GLuint sampler);
|
void BindSamplers(GLuint first, GLsizei count, const GLuint* samplers);
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
void BindSampler(GLuint unit, GLuint sampler);
|
||||||
|
} // namespace MG_Impl::GLImpl
|
||||||
|
} // namespace MobileGL
|
||||||
|
|||||||
@@ -11,122 +11,126 @@
|
|||||||
#include <MG_State/GLState/ErrorState/Error.h>
|
#include <MG_State/GLState/ErrorState/Error.h>
|
||||||
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl::SamplerImpl {
|
namespace MobileGL::MG_Impl::GLImpl {
|
||||||
Bool ValidateSamplerName(GLuint sampler) {
|
namespace SamplerImpl {
|
||||||
if (!MG_State::pGLContext->ValidateSamplerName(sampler)) {
|
Bool ValidateSamplerName(GLuint sampler) {
|
||||||
MG_State::pGLContext->RecordError(
|
if (!MG_State::pGLContext->ValidateSamplerName(sampler)) {
|
||||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerName",
|
|
||||||
std::format("Invalid sampler name {}", sampler)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateSamplerObject(GLuint sampler) {
|
|
||||||
if (!MG_State::pGLContext->ValidateSamplerObject(sampler)) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidOperation,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerObject",
|
|
||||||
std::format("Sampler object {} does not exist", sampler)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateSamplerParam(GLenum pname, GLenum param) {
|
|
||||||
using namespace MG_Util;
|
|
||||||
switch (pname) {
|
|
||||||
case GL_TEXTURE_WRAP_S:
|
|
||||||
case GL_TEXTURE_WRAP_T:
|
|
||||||
case GL_TEXTURE_WRAP_R:
|
|
||||||
if (MG_Util::ConvertGLEnumToSamplerWrapMode(param) == SamplerWrapMode::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
|
||||||
"Invalid wrap mode parameter"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GL_TEXTURE_MIN_FILTER:
|
|
||||||
if (MG_Util::ConvertGLEnumToSamplerFilterMode(param) == SamplerFilterMode::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
|
||||||
"Invalid min filter parameter"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GL_TEXTURE_MAG_FILTER:
|
|
||||||
if (param != GL_NEAREST && param != GL_LINEAR) {
|
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
|
||||||
"Invalid mag filter parameter"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GL_TEXTURE_COMPARE_MODE:
|
|
||||||
if (param != GL_NONE && param != GL_COMPARE_REF_TO_TEXTURE) {
|
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
|
||||||
"Invalid compare mode parameter"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GL_TEXTURE_COMPARE_FUNC:
|
|
||||||
if (param < GL_LEQUAL || param > GL_ALWAYS) {
|
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
|
||||||
"Invalid compare function parameter"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
|
||||||
"Invalid pname for sampler parameter"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateSamplerFloatParam(GLenum pname, GLfloat param) {
|
|
||||||
switch (pname) {
|
|
||||||
case GL_TEXTURE_MIN_LOD:
|
|
||||||
case GL_TEXTURE_MAX_LOD:
|
|
||||||
case GL_TEXTURE_LOD_BIAS:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case GL_TEXTURE_BORDER_COLOR:
|
|
||||||
if (param < 0.0f || param > 1.0f) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerFloatParam",
|
|
||||||
"Border color component out of [0,1] range"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return ValidateSamplerParam(pname, static_cast<GLenum>(param));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateSamplerIntParam(GLenum pname, GLint param) {
|
|
||||||
switch (pname) {
|
|
||||||
case GL_TEXTURE_BORDER_COLOR:
|
|
||||||
if (param < 0 || param > 255) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidValue,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerIntParam",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerName",
|
||||||
"Border color component out of [0,255] range"));
|
std::format("Invalid sampler name {}", sampler)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
|
||||||
return ValidateSamplerParam(pname, static_cast<GLenum>(param));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl::SamplerImpl
|
Bool ValidateSamplerObject(GLuint sampler) {
|
||||||
|
if (!MG_State::pGLContext->ValidateSamplerObject(sampler)) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerObject",
|
||||||
|
std::format("Sampler object {} does not exist", sampler)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ValidateSamplerParam(GLenum pname, GLenum param) {
|
||||||
|
using namespace MG_Util;
|
||||||
|
switch (pname) {
|
||||||
|
case GL_TEXTURE_WRAP_S:
|
||||||
|
case GL_TEXTURE_WRAP_T:
|
||||||
|
case GL_TEXTURE_WRAP_R:
|
||||||
|
if (MG_Util::ConvertGLEnumToSamplerWrapMode(param) == SamplerWrapMode::Unknown) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||||
|
"Invalid wrap mode parameter"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_TEXTURE_MIN_FILTER:
|
||||||
|
if (MG_Util::ConvertGLEnumToSamplerFilterMode(param) == SamplerFilterMode::Unknown) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||||
|
"Invalid min filter parameter"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_TEXTURE_MAG_FILTER:
|
||||||
|
if (param != GL_NEAREST && param != GL_LINEAR) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||||
|
"Invalid mag filter parameter"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_TEXTURE_COMPARE_MODE:
|
||||||
|
if (param != GL_NONE && param != GL_COMPARE_REF_TO_TEXTURE) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||||
|
"Invalid compare mode parameter"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_TEXTURE_COMPARE_FUNC:
|
||||||
|
if (param < GL_LEQUAL || param > GL_ALWAYS) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||||
|
"Invalid compare function parameter"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||||
|
"Invalid pname for sampler parameter"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ValidateSamplerFloatParam(GLenum pname, GLfloat param) {
|
||||||
|
switch (pname) {
|
||||||
|
case GL_TEXTURE_MIN_LOD:
|
||||||
|
case GL_TEXTURE_MAX_LOD:
|
||||||
|
case GL_TEXTURE_LOD_BIAS:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GL_TEXTURE_BORDER_COLOR:
|
||||||
|
if (param < 0.0f || param > 1.0f) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerFloatParam",
|
||||||
|
"Border color component out of [0,1] range"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ValidateSamplerParam(pname, static_cast<GLenum>(param));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ValidateSamplerIntParam(GLenum pname, GLint param) {
|
||||||
|
switch (pname) {
|
||||||
|
case GL_TEXTURE_BORDER_COLOR:
|
||||||
|
if (param < 0 || param > 255) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerIntParam",
|
||||||
|
"Border color component out of [0,255] range"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ValidateSamplerParam(pname, static_cast<GLenum>(param));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace SamplerImpl
|
||||||
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
|
|||||||
@@ -10,10 +10,12 @@
|
|||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include <MG_State/GLState/SamplerState/SamplerObject.h>
|
#include <MG_State/GLState/SamplerState/SamplerObject.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl::SamplerImpl {
|
namespace MobileGL::MG_Impl::GLImpl {
|
||||||
Bool ValidateSamplerName(GLuint sampler);
|
namespace SamplerImpl {
|
||||||
Bool ValidateSamplerObject(GLuint sampler);
|
Bool ValidateSamplerName(GLuint sampler);
|
||||||
Bool ValidateSamplerParam(GLenum pname, GLenum param);
|
Bool ValidateSamplerObject(GLuint sampler);
|
||||||
Bool ValidateSamplerFloatParam(GLenum pname, GLfloat param);
|
Bool ValidateSamplerParam(GLenum pname, GLenum param);
|
||||||
Bool ValidateSamplerIntParam(GLenum pname, GLint param);
|
Bool ValidateSamplerFloatParam(GLenum pname, GLfloat param);
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl::SamplerImpl
|
Bool ValidateSamplerIntParam(GLenum pname, GLint param);
|
||||||
|
} // namespace SamplerImpl
|
||||||
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
|
|||||||
@@ -10,34 +10,36 @@
|
|||||||
|
|
||||||
#include "MG_State/GLState/Core.h"
|
#include "MG_State/GLState/Core.h"
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl {
|
namespace MobileGL {
|
||||||
GLsync FenceSync_Backend(GLenum condition, GLbitfield flags) {
|
namespace MG_Impl::GLImpl {
|
||||||
return 0;
|
GLsync FenceSync_Backend(GLenum condition, GLbitfield flags) {
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
GLenum ClientWaitSync_Backend(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
GLenum ClientWaitSync_Backend(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteSync_Backend(GLsync sync) {}
|
void DeleteSync_Backend(GLsync sync) {}
|
||||||
|
|
||||||
GLsync FenceSync_State(GLenum condition, GLbitfield flags) {
|
GLsync FenceSync_State(GLenum condition, GLbitfield flags) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum ClientWaitSync_State(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
GLenum ClientWaitSync_State(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteSync_State(GLsync sync) {}
|
void DeleteSync_State(GLsync sync) {}
|
||||||
|
|
||||||
GLsync FenceSync(GLenum condition, GLbitfield flags) {
|
GLsync FenceSync(GLenum condition, GLbitfield flags) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteSync(GLsync sync) {}
|
void DeleteSync(GLsync sync) {}
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
} // namespace MG_Impl::GLImpl
|
||||||
|
} // namespace MobileGL
|
||||||
@@ -9,8 +9,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl {
|
namespace MobileGL {
|
||||||
GLsync FenceSync(GLenum condition, GLbitfield flags);
|
namespace MG_Impl::GLImpl {
|
||||||
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
|
GLsync FenceSync(GLenum condition, GLbitfield flags);
|
||||||
void DeleteSync(GLsync sync);
|
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
void DeleteSync(GLsync sync);
|
||||||
|
} // namespace MG_Impl::GLImpl
|
||||||
|
} // namespace MobileGL
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,47 +7,48 @@
|
|||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
#include "ProxyTexture.h"
|
#include "ProxyTexture.h"
|
||||||
#include <MG_State/GLState/TextureState/TextureObject2D.h>
|
#include "MG_State/GLState/TextureState/TextureObject2D.h"
|
||||||
|
#include "MG_Util/Types.h"
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
|
namespace MobileGL::MG_Impl::GLImpl {
|
||||||
UniquePtr<ProxyTextureManager> pProxyTextureManager;
|
namespace TextureImpl {
|
||||||
|
ProxyTextureManager* pProxyTextureManager;
|
||||||
|
|
||||||
Bool IsProxyTextureTarget(TextureUploadTarget target) {
|
Bool IsProxyTextureTarget(TextureUploadTarget target) {
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case TextureUploadTarget::ProxyCubeMap:
|
case TextureUploadTarget::ProxyCubeMap:
|
||||||
case TextureUploadTarget::ProxyTexture1DArray:
|
case TextureUploadTarget::ProxyTexture1DArray:
|
||||||
case TextureUploadTarget::ProxyTexture2DArray:
|
case TextureUploadTarget::ProxyTexture2DArray:
|
||||||
case TextureUploadTarget::ProxyTexture1D:
|
case TextureUploadTarget::ProxyTexture1D:
|
||||||
case TextureUploadTarget::ProxyTexture2D:
|
case TextureUploadTarget::ProxyTexture2D:
|
||||||
case TextureUploadTarget::ProxyTexture3D:
|
case TextureUploadTarget::ProxyTexture3D:
|
||||||
case TextureUploadTarget::ProxyTexture2DMultisample:
|
case TextureUploadTarget::ProxyTexture2DMultisample:
|
||||||
case TextureUploadTarget::ProxyTexture2DMultisampleArray:
|
case TextureUploadTarget::ProxyTexture2DMultisampleArray:
|
||||||
case TextureUploadTarget::ProxyTextureRectangle:
|
case TextureUploadTarget::ProxyTextureRectangle:
|
||||||
case TextureUploadTarget::ProxyCubeMapArray:
|
case TextureUploadTarget::ProxyCubeMapArray:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const SharedPtr<MG_State::GLState::ITextureObject>& ProxyTextureManager::CreateOrReplaceProxyTextureObject(
|
SharedPtr<MG_State::GLState::ITextureObject> ProxyTextureManager::CreateOrReplaceProxyTextureObject(
|
||||||
TextureUploadTarget target) {
|
TextureUploadTarget target) {
|
||||||
auto it = m_proxyTexturesMap.find(target);
|
auto it = m_proxyTexturesMap.find(target);
|
||||||
if (it != m_proxyTexturesMap.end()) {
|
if (it != m_proxyTexturesMap.end()) {
|
||||||
m_proxyTexturesMap.erase(it);
|
m_proxyTexturesMap.erase(it);
|
||||||
|
}
|
||||||
|
m_proxyTexturesMap[target] = MakeShared<MG_State::GLState::TextureObject2D>(0);
|
||||||
|
return m_proxyTexturesMap[target];
|
||||||
}
|
}
|
||||||
auto& obj = m_proxyTexturesMap[target];
|
|
||||||
obj = MakeShared<MG_State::GLState::TextureObject2D>(0);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SharedPtr<MG_State::GLState::ITextureObject>& ProxyTextureManager::GetProxyTextureObject(
|
SharedPtr<MG_State::GLState::ITextureObject> ProxyTextureManager::GetProxyTextureObject(
|
||||||
TextureUploadTarget target) {
|
TextureUploadTarget target) {
|
||||||
auto it = m_proxyTexturesMap.find(target);
|
auto it = m_proxyTexturesMap.find(target);
|
||||||
if (it != m_proxyTexturesMap.end()) {
|
if (it != m_proxyTexturesMap.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
static SharedPtr<MG_State::GLState::ITextureObject> nullTextureObject = nullptr;
|
} // namespace TextureImpl
|
||||||
return nullTextureObject;
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl::TextureImpl
|
|
||||||
|
|||||||
@@ -10,18 +10,19 @@
|
|||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include <MG_State/GLState/Core.h>
|
#include <MG_State/GLState/Core.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
|
namespace MobileGL::MG_Impl::GLImpl {
|
||||||
Bool IsProxyTextureTarget(TextureUploadTarget target);
|
namespace TextureImpl {
|
||||||
|
Bool IsProxyTextureTarget(TextureUploadTarget target);
|
||||||
|
|
||||||
class ProxyTextureManager {
|
class ProxyTextureManager {
|
||||||
public:
|
public:
|
||||||
const SharedPtr<MG_State::GLState::ITextureObject>& CreateOrReplaceProxyTextureObject(
|
SharedPtr<MG_State::GLState::ITextureObject> CreateOrReplaceProxyTextureObject(TextureUploadTarget target);
|
||||||
TextureUploadTarget target);
|
SharedPtr<MG_State::GLState::ITextureObject> GetProxyTextureObject(TextureUploadTarget target);
|
||||||
const SharedPtr<MG_State::GLState::ITextureObject>& GetProxyTextureObject(TextureUploadTarget target);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UnorderedMap<TextureUploadTarget, SharedPtr<MG_State::GLState::ITextureObject>> m_proxyTexturesMap;
|
UnorderedMap<TextureUploadTarget, SharedPtr<MG_State::GLState::ITextureObject>> m_proxyTexturesMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern UniquePtr<ProxyTextureManager> pProxyTextureManager;
|
extern ProxyTextureManager* pProxyTextureManager;
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl::TextureImpl
|
} // namespace TextureImpl
|
||||||
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
|
|||||||
@@ -15,295 +15,309 @@
|
|||||||
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
|
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
|
||||||
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
|
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
|
namespace MobileGL::MG_Impl::GLImpl {
|
||||||
Bool ValidateTextureTarget(TextureTarget target) {
|
namespace TextureImpl {
|
||||||
if (target == TextureTarget::Unknown) {
|
Bool ValidateTextureTarget(TextureTarget target) {
|
||||||
MG_State::pGLContext->RecordError(
|
if (target == TextureTarget::Unknown) {
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureTarget", "Invalid texture target"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget) {
|
|
||||||
if (textureUploadTarget == TextureUploadTarget::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureUploadTarget",
|
|
||||||
"Invalid texture upload target"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateTextureName(Uint texture, Bool allowZero) {
|
|
||||||
if (texture == 0) {
|
|
||||||
if (allowZero) return true;
|
|
||||||
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidValue,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureName", "Texture name cannot be zero"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!MG_State::pGLContext->ValidateTextureName(texture)) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidValue,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureName", "Invalid texture name"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateTextureInputFormat(TextureInputFormat format) {
|
|
||||||
if (format == TextureInputFormat::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInputFormat",
|
|
||||||
"Invalid texture input format"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType) {
|
|
||||||
if (texturePixelDataType == TexturePixelDataType::Unknown) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTexturePixelDataType",
|
|
||||||
"Invalid texture pixel data type"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateTextureLevelNumber(GLint level) {
|
|
||||||
if (level < 0) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureLevelNumber",
|
|
||||||
"Texture level must be non-negative"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: GL_INVALID_VALUE may be generated if level is greater than log2(max), where max is the returned
|
|
||||||
// value of GL_MAX_TEXTURE_SIZE.
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateTextureSizeWithTextureUploadTarget(TextureUploadTarget target, GLsizei width, GLsizei height) {
|
|
||||||
if (target == TextureUploadTarget::CubeMapPositiveX || target == TextureUploadTarget::CubeMapNegativeX ||
|
|
||||||
target == TextureUploadTarget::CubeMapPositiveY || target == TextureUploadTarget::CubeMapNegativeY ||
|
|
||||||
target == TextureUploadTarget::CubeMapPositiveZ || target == TextureUploadTarget::CubeMapNegativeZ) {
|
|
||||||
if (width != height) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidEnum,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureTarget", "Invalid texture target"));
|
||||||
"Width and height must be equal for cube map textures"));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(target == TextureUploadTarget::Texture1DArray || target == TextureUploadTarget::ProxyTexture1DArray)) {
|
Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget) {
|
||||||
if (height < 0) {
|
if (textureUploadTarget == TextureUploadTarget::Unknown) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||||
ErrorCode::InvalidValue,
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
|
"ValidateTextureUploadTarget",
|
||||||
"Height must be greater than or equal to zero"));
|
"Invalid texture upload target"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// TODO: GL_INVALID_VALUE is generated if target is not GL_TEXTURE_1D_ARRAY or GL_PROXY_TEXTURE_1D_ARRAY
|
return true;
|
||||||
// and height is greater than GL_MAX_TEXTURE_SIZE.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target == TextureUploadTarget::Texture1DArray || target == TextureUploadTarget::ProxyTexture1DArray) {
|
Bool ValidateTextureName(Uint texture, Bool allowZero) {
|
||||||
if (height < 0) {
|
if (texture == 0) {
|
||||||
MG_State::pGLContext->RecordError(
|
if (allowZero) return true;
|
||||||
ErrorCode::InvalidValue,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||||
"Height must be greater than or equal to zero"));
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureName",
|
||||||
|
"Texture name cannot be zero"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// TODO: GL_INVALID_VALUE is generated if target is GL_TEXTURE_1D_ARRAY or GL_PROXY_TEXTURE_1D_ARRAY and
|
|
||||||
// height is greater than GL_MAX_ARRAY_TEXTURE_LAYERS.
|
if (!MG_State::pGLContext->ValidateTextureName(texture)) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureName", "Invalid texture name"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
Bool ValidateTextureInputFormat(TextureInputFormat format) {
|
||||||
}
|
if (format == TextureInputFormat::Unknown) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
Bool ValidateTextureSizeRange(SizeT width, SizeT height, SizeT depth) {
|
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInputFormat",
|
||||||
if (width < 0 || height < 0 || depth < 0) {
|
"Invalid texture input format"));
|
||||||
MG_State::pGLContext->RecordError(
|
return false;
|
||||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeRange",
|
}
|
||||||
"Width and height must be greater than zero"));
|
return true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: GL_INVALID_VALUE is generated if width is greater than GL_MAX_TEXTURE_SIZE.
|
Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType) {
|
||||||
|
if (texturePixelDataType == TexturePixelDataType::Unknown) {
|
||||||
return true;
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||||
}
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||||
|
"ValidateTexturePixelDataType",
|
||||||
Bool ValidateTextureInternalFormat(TextureInternalFormat format) {
|
"Invalid texture pixel data type"));
|
||||||
if (format == TextureInternalFormat::Unknown) {
|
return false;
|
||||||
MG_State::pGLContext->RecordError(
|
}
|
||||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormat",
|
return true;
|
||||||
"Invalid texture sized internal format"));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateTextureBorderNumber(Int border) {
|
Bool ValidateTextureLevelNumber(GLint level) {
|
||||||
if (border != 0) {
|
if (level < 0) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||||
ErrorCode::InvalidValue,
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureBorderNumber", "Border must be zero"));
|
"ValidateTextureLevelNumber",
|
||||||
return false;
|
"Texture level must be non-negative"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: GL_INVALID_VALUE may be generated if level is greater than log2(max), where max is the returned
|
||||||
|
// value of GL_MAX_TEXTURE_SIZE.
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
|
Bool ValidateTextureSizeWithTextureUploadTarget(TextureUploadTarget target, GLsizei width, GLsizei height) {
|
||||||
TextureInternalFormat internalFormat,
|
if (target == TextureUploadTarget::CubeMapPositiveX || target == TextureUploadTarget::CubeMapNegativeX ||
|
||||||
TexturePixelDataType type) {
|
target == TextureUploadTarget::CubeMapPositiveY || target == TextureUploadTarget::CubeMapNegativeY ||
|
||||||
if (type == TexturePixelDataType::UnsignedByte332 || type == TexturePixelDataType::UnsignedByte233Rev ||
|
target == TextureUploadTarget::CubeMapPositiveZ || target == TextureUploadTarget::CubeMapNegativeZ) {
|
||||||
type == TexturePixelDataType::UnsignedShort565 || type == TexturePixelDataType::UnsignedShort565Rev ||
|
if (width != height) {
|
||||||
type == TexturePixelDataType::UnsignedInt101111Rev) {
|
MG_State::pGLContext->RecordError(
|
||||||
if (format != TextureInputFormat::RGB) {
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
|
||||||
|
"Width and height must be equal for cube map textures"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(target == TextureUploadTarget::Texture1DArray ||
|
||||||
|
target == TextureUploadTarget::ProxyTexture1DArray)) {
|
||||||
|
if (height < 0) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
|
||||||
|
"Height must be greater than or equal to zero"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// TODO: GL_INVALID_VALUE is generated if target is not GL_TEXTURE_1D_ARRAY or GL_PROXY_TEXTURE_1D_ARRAY
|
||||||
|
// and height is greater than GL_MAX_TEXTURE_SIZE.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target == TextureUploadTarget::Texture1DArray || target == TextureUploadTarget::ProxyTexture1DArray) {
|
||||||
|
if (height < 0) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
|
||||||
|
"Height must be greater than or equal to zero"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// TODO: GL_INVALID_VALUE is generated if target is GL_TEXTURE_1D_ARRAY or GL_PROXY_TEXTURE_1D_ARRAY and
|
||||||
|
// height is greater than GL_MAX_ARRAY_TEXTURE_LAYERS.
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ValidateTextureSizeRange(SizeT width, SizeT height, SizeT depth) {
|
||||||
|
if (width < 0 || height < 0 || depth < 0) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeRange",
|
||||||
|
"Width and height must be greater than zero"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: GL_INVALID_VALUE is generated if width is greater than GL_MAX_TEXTURE_SIZE.
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ValidateTextureInternalFormat(TextureInternalFormat format) {
|
||||||
|
if (format == TextureInternalFormat::Unknown) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormat",
|
||||||
|
"Invalid texture sized internal format"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ValidateTextureBorderNumber(Int border) {
|
||||||
|
if (border != 0) {
|
||||||
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||||
|
"ValidateTextureBorderNumber",
|
||||||
|
"Border must be zero"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
|
||||||
|
TextureInternalFormat internalFormat,
|
||||||
|
TexturePixelDataType type) {
|
||||||
|
if (type == TexturePixelDataType::UnsignedByte332 || type == TexturePixelDataType::UnsignedByte233Rev ||
|
||||||
|
type == TexturePixelDataType::UnsignedShort565 || type == TexturePixelDataType::UnsignedShort565Rev ||
|
||||||
|
type == TexturePixelDataType::UnsignedInt101111Rev) {
|
||||||
|
if (format != TextureInputFormat::RGB) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||||
|
"ValidateTextureInternalFormatCompatibleWithInput",
|
||||||
|
"Invalid format for the given type"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == TexturePixelDataType::UnsignedShort4444 || type == TexturePixelDataType::UnsignedShort4444Rev ||
|
||||||
|
type == TexturePixelDataType::UnsignedShort5551 || type == TexturePixelDataType::UnsignedShort1555Rev ||
|
||||||
|
type == TexturePixelDataType::UnsignedInt8888 || type == TexturePixelDataType::UnsignedInt8888Rev ||
|
||||||
|
type == TexturePixelDataType::UnsignedInt1010102 ||
|
||||||
|
type == TexturePixelDataType::UnsignedInt2101010Rev ||
|
||||||
|
type == TexturePixelDataType::UnsignedInt5999Rev) {
|
||||||
|
if (format != TextureInputFormat::RGBA && format != TextureInputFormat::BGRA) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||||
|
"ValidateTextureInternalFormatCompatibleWithInput",
|
||||||
|
"Invalid format for the given type"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (internalFormat == TextureInternalFormat::DepthComponent ||
|
||||||
|
internalFormat == TextureInternalFormat::DepthComponent16 ||
|
||||||
|
internalFormat == TextureInternalFormat::DepthComponent24 ||
|
||||||
|
internalFormat == TextureInternalFormat::DepthComponent32F) {
|
||||||
|
if (format != TextureInputFormat::DepthComponent) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||||
|
"ValidateTextureInternalFormatCompatibleWithInput",
|
||||||
|
"Invalid format for depth component internal format"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format == TextureInputFormat::DepthComponent &&
|
||||||
|
(internalFormat != TextureInternalFormat::DepthComponent &&
|
||||||
|
internalFormat != TextureInternalFormat::DepthComponent16 &&
|
||||||
|
internalFormat != TextureInternalFormat::DepthComponent24 &&
|
||||||
|
internalFormat != TextureInternalFormat::DepthComponent32F &&
|
||||||
|
internalFormat != TextureInternalFormat::DepthComponent32 // workaround for Minecraft 1.21.5+
|
||||||
|
)) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
|
||||||
"Invalid format for the given type"));
|
"Invalid internal format for depth component format"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == TexturePixelDataType::UnsignedShort4444 || type == TexturePixelDataType::UnsignedShort4444Rev ||
|
Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level) {
|
||||||
type == TexturePixelDataType::UnsignedShort5551 || type == TexturePixelDataType::UnsignedShort1555Rev ||
|
if (target == TextureUploadTarget::TextureRectangle ||
|
||||||
type == TexturePixelDataType::UnsignedInt8888 || type == TexturePixelDataType::UnsignedInt8888Rev ||
|
target == TextureUploadTarget::ProxyTextureRectangle) {
|
||||||
type == TexturePixelDataType::UnsignedInt1010102 || type == TexturePixelDataType::UnsignedInt2101010Rev ||
|
if (level != 0) {
|
||||||
type == TexturePixelDataType::UnsignedInt5999Rev) {
|
MG_State::pGLContext->RecordError(
|
||||||
if (format != TextureInputFormat::RGBA && format != TextureInputFormat::BGRA) {
|
ErrorCode::InvalidValue,
|
||||||
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureLevelWithUploadTarget",
|
||||||
|
"Level must be zero for rectangle textures"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ValidateTextureObject(SharedPtr<MG_State::GLState::ITextureObject> textureObject) {
|
||||||
|
if (!textureObject) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureObject", "Texture object is null"));
|
||||||
"Invalid format for the given type"));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (internalFormat == TextureInternalFormat::DepthComponent ||
|
Bool ValidateTextureTargetUniformity(SharedPtr<MG_State::GLState::ITextureObject> textureObject,
|
||||||
internalFormat == TextureInternalFormat::DepthComponent16 ||
|
TextureTarget target) {
|
||||||
internalFormat == TextureInternalFormat::DepthComponent24 ||
|
if (!textureObject) return true; // should be created later
|
||||||
internalFormat == TextureInternalFormat::DepthComponent32F) {
|
TextureTarget prevTarget = textureObject->GetTarget();
|
||||||
if (format != TextureInputFormat::DepthComponent) {
|
if (prevTarget != target) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureTargetUniformity",
|
||||||
"Invalid format for depth component internal format"));
|
"Texture target does not match the previously created texture"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format == TextureInputFormat::DepthComponent &&
|
Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset,
|
||||||
(internalFormat != TextureInternalFormat::DepthComponent &&
|
Int width, Int yoffset, Int height, Int zoffset, Int depth) {
|
||||||
internalFormat != TextureInternalFormat::DepthComponent16 &&
|
auto baseSize = textureObject->GetBaseSize();
|
||||||
internalFormat != TextureInternalFormat::DepthComponent24 &&
|
if (xoffset < 0 || (xoffset + width) > baseSize.x()) {
|
||||||
internalFormat != TextureInternalFormat::DepthComponent32F &&
|
|
||||||
internalFormat != TextureInternalFormat::DepthComponent32 // workaround for Minecraft 1.21.5+
|
|
||||||
)) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidOperation,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
|
|
||||||
"Invalid internal format for depth component format"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level) {
|
|
||||||
if (target == TextureUploadTarget::TextureRectangle || target == TextureUploadTarget::ProxyTextureRectangle) {
|
|
||||||
if (level != 0) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidValue,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureLevelWithUploadTarget",
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
|
||||||
"Level must be zero for rectangle textures"));
|
"xoffset must be non-negative and (xoffset + width) must not exceed "
|
||||||
|
"the texture width."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
if (baseSize.y() == 0) return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateTextureObject(SharedPtr<MG_State::GLState::ITextureObject> textureObject) {
|
if (yoffset < 0 || (yoffset + height) > baseSize.y()) {
|
||||||
if (!textureObject) {
|
MG_State::pGLContext->RecordError(
|
||||||
MG_State::pGLContext->RecordError(
|
ErrorCode::InvalidValue,
|
||||||
ErrorCode::InvalidOperation,
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureObject", "Texture object is null"));
|
"yoffset must be non-negative and (yoffset + height) must not exceed "
|
||||||
return false;
|
"the texture height."));
|
||||||
}
|
return false;
|
||||||
return true;
|
}
|
||||||
}
|
if (baseSize.z() == 0) return true;
|
||||||
|
|
||||||
Bool ValidateTextureTargetUniformity(SharedPtr<MG_State::GLState::ITextureObject> textureObject,
|
if (zoffset < 0 || (zoffset + depth) > baseSize.z()) {
|
||||||
TextureTarget target) {
|
MG_State::pGLContext->RecordError(
|
||||||
if (!textureObject) return true; // should be created later
|
ErrorCode::InvalidValue,
|
||||||
TextureTarget prevTarget = textureObject->GetTarget();
|
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
|
||||||
if (prevTarget != target) {
|
"zoffset must be non-negative and (zoffset + depth) must not exceed "
|
||||||
MG_State::pGLContext->RecordError(
|
"the texture depth."));
|
||||||
ErrorCode::InvalidOperation,
|
return false;
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureTargetUniformity",
|
}
|
||||||
"Texture target does not match the previously created texture"));
|
return true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset,
|
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2) {
|
||||||
Int width, Int yoffset, Int height, Int zoffset, Int depth) {
|
auto unsizedFormat1 = MG_Util::ConvertInternalFormatToUnsized(format1);
|
||||||
auto baseSize = textureObject->GetBaseSize();
|
auto unsizedFormat2 = MG_Util::ConvertInternalFormatToUnsized(format2);
|
||||||
if (xoffset < 0 || (xoffset + width) > baseSize.x()) {
|
if (unsizedFormat1 != unsizedFormat2) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
|
MakeShared<GenericErrorInfo>(
|
||||||
"xoffset must be non-negative and (xoffset + width) must not exceed "
|
std::format("MG_Impl/GLImpl", "ValidateBaseInternalFormatMatch",
|
||||||
"the texture width."));
|
"The base internal format of the two formats do not match ({} vs. {})",
|
||||||
return false;
|
MG_Util::ConvertTextureInternalFormatToString(unsizedFormat1).c_str(),
|
||||||
}
|
MG_Util::ConvertTextureInternalFormatToString(unsizedFormat2).c_str())));
|
||||||
if (baseSize.y() == 0) return true;
|
return false;
|
||||||
|
}
|
||||||
if (yoffset < 0 || (yoffset + height) > baseSize.y()) {
|
return true;
|
||||||
MG_State::pGLContext->RecordError(
|
} // namespace TextureImpl
|
||||||
ErrorCode::InvalidValue,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
|
|
||||||
"yoffset must be non-negative and (yoffset + height) must not exceed "
|
|
||||||
"the texture height."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (baseSize.z() == 0) return true;
|
|
||||||
|
|
||||||
if (zoffset < 0 || (zoffset + depth) > baseSize.z()) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidValue,
|
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
|
|
||||||
"zoffset must be non-negative and (zoffset + depth) must not exceed "
|
|
||||||
"the texture depth."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2) {
|
|
||||||
auto unsizedFormat1 = MG_Util::ConvertInternalFormatToUnsized(format1);
|
|
||||||
auto unsizedFormat2 = MG_Util::ConvertInternalFormatToUnsized(format2);
|
|
||||||
if (unsizedFormat1 != unsizedFormat2) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidOperation,
|
|
||||||
MakeUnique<GenericErrorInfo>(
|
|
||||||
std::format("MG_Impl/GLImpl", "ValidateBaseInternalFormatMatch",
|
|
||||||
"The base internal format of the two formats do not match ({} vs. {})",
|
|
||||||
MG_Util::ConvertTextureInternalFormatToString(unsizedFormat1).c_str(),
|
|
||||||
MG_Util::ConvertTextureInternalFormatToString(unsizedFormat2).c_str())));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} // namespace TextureImpl
|
} // namespace TextureImpl
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl::TextureImpl
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
@@ -12,25 +12,27 @@
|
|||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include <MG_State/GLState/TextureState/TextureObject.h>
|
#include <MG_State/GLState/TextureState/TextureObject.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
|
namespace MobileGL::MG_Impl::GLImpl {
|
||||||
Bool ValidateTextureTarget(TextureTarget target);
|
namespace TextureImpl {
|
||||||
Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget);
|
Bool ValidateTextureTarget(TextureTarget target);
|
||||||
Bool ValidateTextureName(Uint texture, Bool allowZero = false);
|
Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget);
|
||||||
Bool ValidateTextureInputFormat(TextureInputFormat format);
|
Bool ValidateTextureName(Uint texture, Bool allowZero = false);
|
||||||
Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType);
|
Bool ValidateTextureInputFormat(TextureInputFormat format);
|
||||||
Bool ValidateTextureLevelNumber(Int level);
|
Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType);
|
||||||
Bool ValidateTextureSizeWithTextureUploadTarget(TextureUploadTarget target, GLsizei width, GLsizei height);
|
Bool ValidateTextureLevelNumber(Int level);
|
||||||
Bool ValidateTextureSizeRange(SizeT width, SizeT height, SizeT depth);
|
Bool ValidateTextureSizeWithTextureUploadTarget(TextureUploadTarget target, GLsizei width, GLsizei height);
|
||||||
Bool ValidateTextureInternalFormat(TextureInternalFormat format);
|
Bool ValidateTextureSizeRange(SizeT width, SizeT height, SizeT depth);
|
||||||
Bool ValidateTextureBorderNumber(Int border);
|
Bool ValidateTextureInternalFormat(TextureInternalFormat format);
|
||||||
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
|
Bool ValidateTextureBorderNumber(Int border);
|
||||||
TextureInternalFormat internalFormat,
|
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
|
||||||
TexturePixelDataType type);
|
TextureInternalFormat internalFormat,
|
||||||
Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level);
|
TexturePixelDataType type);
|
||||||
Bool ValidateTextureObject(SharedPtr<MG_State::GLState::ITextureObject> textureObject);
|
Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level);
|
||||||
Bool ValidateTextureTargetUniformity(SharedPtr<MG_State::GLState::ITextureObject> textureObject,
|
Bool ValidateTextureObject(SharedPtr<MG_State::GLState::ITextureObject> textureObject);
|
||||||
TextureTarget target);
|
Bool ValidateTextureTargetUniformity(SharedPtr<MG_State::GLState::ITextureObject> textureObject,
|
||||||
Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset,
|
TextureTarget target);
|
||||||
Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0);
|
Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset,
|
||||||
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2);
|
Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0);
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl::TextureImpl
|
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2);
|
||||||
|
} // namespace TextureImpl
|
||||||
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user