mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 04:38:30 +09:00
Compare commits
299
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85bd0613ca | ||
|
|
dd52f0381a | ||
|
|
cf165c0db5 | ||
|
|
ab9db43599 | ||
|
|
d553e363a7 | ||
|
|
be3c3eb9bb | ||
|
|
357807666d | ||
|
|
d1a5a4e39c | ||
|
|
a701c896f0 | ||
|
|
b0de886f8e | ||
|
|
ad1ca4ea92 | ||
|
|
fbaf5261e2 | ||
|
|
19ada4b8f9 | ||
|
|
ff41e59282 | ||
|
|
a15a13ca46 | ||
|
|
2937043e77 | ||
|
|
24efb0bb17 | ||
|
|
dd2bd267c1 | ||
|
|
5cfe9c8998 | ||
|
|
3bd8a62aa8 | ||
|
|
dcd37f3c38 | ||
|
|
a579fd2342 | ||
|
|
f93ff00642 | ||
|
|
8a628631fb | ||
|
|
59733a2a26 | ||
|
|
c7d385c03d | ||
|
|
27a8aa057c | ||
|
|
e63bfbabf0 | ||
|
|
c107d9edcf | ||
|
|
49e69c1c7d | ||
|
|
482b6d7bbf | ||
|
|
dcfe91bdfc | ||
|
|
6072b5b703 | ||
|
|
9c50ac8a69 | ||
|
|
8b7acad257 | ||
|
|
cb8cb48a60 | ||
|
|
8c00ae1d38 | ||
|
|
633b3d3b0a | ||
|
|
60199c0323 | ||
|
|
9e0e03d4c0 | ||
|
|
4972ebf914 | ||
|
|
4a36d63c1b | ||
|
|
d7e768096e | ||
|
|
e13b5d0618 | ||
|
|
c5bf0dc07d | ||
|
|
9fbd83d602 | ||
|
|
39c5b28dfb | ||
|
|
be533994e5 | ||
|
|
368c089172 | ||
|
|
30c6f55c2d | ||
|
|
407d4344c4 | ||
|
|
76e3950028 | ||
|
|
7337b00ca8 | ||
|
|
22582dea3e | ||
|
|
f600a07404 | ||
|
|
ff790e1ff1 | ||
|
|
a345369269 | ||
|
|
8e4a4359b4 | ||
|
|
0a000d1628 | ||
|
|
5bd8e369c4 | ||
|
|
777d756d1b | ||
|
|
7716a8e05d | ||
|
|
94e93b171c | ||
|
|
1bf12be278 | ||
|
|
99b753be9a | ||
|
|
bc2f2d896b | ||
|
|
659fbf26da | ||
|
|
f61a7bb9c0 | ||
|
|
212309083a | ||
|
|
c1ebd01a70 | ||
|
|
af58e2c7b4 | ||
|
|
b373535d6e | ||
|
|
4a3a44924a | ||
|
|
1b2a7989af | ||
|
|
83d1ce177e | ||
|
|
4321c4a827 | ||
|
|
a039ce0987 | ||
|
|
accfaab720 | ||
|
|
35658eb998 | ||
|
|
ccbde0196e | ||
|
|
0209c5461f | ||
|
|
810b4886c7 | ||
|
|
7dfc2149d8 | ||
|
|
9d1e8bd7cd | ||
|
|
bfa4049ac1 | ||
|
|
87c56ce3d5 | ||
|
|
f2ab50b84e | ||
|
|
b6ac6c182e | ||
|
|
5e9f0f0c70 | ||
|
|
e4455aed9a | ||
|
|
bc018c9513 | ||
|
|
2ecba4d70c | ||
|
|
1e11a5950e | ||
|
|
b324363db0 | ||
|
|
a654b15190 | ||
|
|
75ea7f8c0c | ||
|
|
09aeee4c03 | ||
|
|
87122973be | ||
|
|
8b9adc5121 | ||
|
|
9e42e40705 | ||
|
|
8a91225eb1 | ||
|
|
e82815802e | ||
|
|
67069d4a12 | ||
|
|
4a38e7224e | ||
|
|
645f2f748f | ||
|
|
5652f9ae5f | ||
|
|
f3b0b242dd | ||
|
|
876cb7bcd3 | ||
|
|
ee9a121c6f | ||
|
|
00439c5c4a | ||
|
|
d7286a5832 | ||
|
|
972804fdc7 | ||
|
|
bca7328421 | ||
|
|
8097c0d7b1 | ||
|
|
641f54e1b7 | ||
|
|
c36bfe0843 | ||
|
|
8ae66521e3 | ||
|
|
6e21fd9a35 | ||
|
|
a2e8faafe5 | ||
|
|
668fa3033e | ||
|
|
139f3f978d | ||
|
|
09f96e5ba5 | ||
|
|
592a69b1c4 | ||
|
|
9211341ae7 | ||
|
|
5f9d354adb | ||
|
|
0ae36b71f5 | ||
|
|
20e2768f27 | ||
|
|
00c8b5ae3a | ||
|
|
7687c19b33 | ||
|
|
fc3a7cd5f1 | ||
|
|
0b7f906533 | ||
|
|
c78a94ed09 | ||
|
|
debcb171ce | ||
|
|
282468c9d5 | ||
|
|
34b06da83b | ||
|
|
3d55f38dab | ||
|
|
16426db244 | ||
|
|
6f8c76f06c | ||
|
|
43f2043478 | ||
|
|
f61f068e28 | ||
|
|
e234d471fe | ||
|
|
6ff97a9bb1 | ||
|
|
8adf1d3b8a | ||
|
|
2935279603 | ||
|
|
918b39bb63 | ||
|
|
963e88943c | ||
|
|
1a75bcba5e | ||
|
|
b64309edfc | ||
|
|
e3f1db0a9a | ||
|
|
2c848ab44b | ||
|
|
9b23594415 | ||
|
|
e2e52965df | ||
|
|
6e7907f183 | ||
|
|
b4be1292b8 | ||
|
|
db58f4c214 | ||
|
|
59bad77176 | ||
|
|
3504fca8da | ||
|
|
e61817ff6a | ||
|
|
b9df28838c | ||
|
|
fff00e65c4 | ||
|
|
8320b4f456 | ||
|
|
a757669df5 | ||
|
|
e16c0645c0 | ||
|
|
8d37763fd3 | ||
|
|
e0d0551e7b | ||
|
|
caa814e8f9 | ||
|
|
2502d32a2e | ||
|
|
e57dd3529e | ||
|
|
4b8d809237 | ||
|
|
d42182befc | ||
|
|
5efdb1016e | ||
|
|
15e24cda78 | ||
|
|
d22d2d64f2 | ||
|
|
5013108a7f | ||
|
|
359ba1c572 | ||
|
|
733523011b | ||
|
|
14fc13c34d | ||
|
|
e9fee1358d | ||
|
|
dae3dd9996 | ||
|
|
556db8b02e | ||
|
|
96e993eecf | ||
|
|
fb3e2123cc | ||
|
|
bd8bc1e251 | ||
|
|
22416cf2f0 | ||
|
|
8bdf990810 | ||
|
|
9e90d9508b | ||
|
|
7ccf858181 | ||
|
|
3c66016489 | ||
|
|
b88042bdff | ||
|
|
6540c2eec1 | ||
|
|
d5940f40be | ||
|
|
033ba16aff | ||
|
|
47467ea1ab | ||
|
|
d84b4da766 | ||
|
|
07b7f7eba5 | ||
|
|
7f9953fdee | ||
|
|
ccd51bf2d3 | ||
|
|
f79b7a91d7 | ||
|
|
ea71b3d96f | ||
|
|
f96f4a0a3b | ||
|
|
9f062fbd69 | ||
|
|
56428df5e5 | ||
|
|
25a5fe0757 | ||
|
|
2104d9865d | ||
|
|
dcb8bb1871 | ||
|
|
6b656d3f96 | ||
|
|
c2a0db3d12 | ||
|
|
c810b27a83 | ||
|
|
25f6c67859 | ||
|
|
5f78ff2b51 | ||
|
|
9226ea092c | ||
|
|
12d514229c | ||
|
|
b69b6b2987 | ||
|
|
377b967996 | ||
|
|
e132e9edc1 | ||
|
|
49a18f68e1 | ||
|
|
fe6e7902d3 | ||
|
|
f7ea6cd1d9 | ||
|
|
cf229c4a5b | ||
|
|
058ec6d26e | ||
|
|
098f8d0738 | ||
|
|
5f6a0b5969 | ||
|
|
49b0743422 | ||
|
|
13aa88b5ef | ||
|
|
e055b9a644 | ||
|
|
324498ccac | ||
|
|
206d8ab36a | ||
|
|
53989d1711 | ||
|
|
7b7e00dbb3 | ||
|
|
7d4ebfc305 | ||
|
|
dfe91e96a5 | ||
|
|
4d61f11bb8 | ||
|
|
5412d1c165 | ||
|
|
3ce7a2fd46 | ||
|
|
f8f3d6e657 | ||
|
|
781bda2573 | ||
|
|
d06720f534 | ||
|
|
a3b440e7c5 | ||
|
|
ebdadcecff | ||
|
|
876d5e13af | ||
|
|
2ad1207a31 | ||
|
|
91326025f3 | ||
|
|
3324dbfbf6 | ||
|
|
e1b59bcb46 | ||
|
|
8f57e837b8 | ||
|
|
6b7de70bf3 | ||
|
|
0ac4d8658d | ||
|
|
1a4fde893f | ||
|
|
e01ebc8fc7 | ||
|
|
533e6bd57c | ||
|
|
ad822e1095 | ||
|
|
129091a430 | ||
|
|
1a91e48219 | ||
|
|
4bcedc84b9 | ||
|
|
1357435e94 | ||
|
|
7c67c99717 | ||
|
|
a58016f49d | ||
|
|
8a66b0a542 | ||
|
|
92cdcd952b | ||
|
|
d7156631d1 | ||
|
|
81125dd06d | ||
|
|
7bd4d74b2c | ||
|
|
b25562711a | ||
|
|
927d95fb41 | ||
|
|
843fdcb47a | ||
|
|
ad6ffbe42e | ||
|
|
5f94f72be5 | ||
|
|
0ce95894a3 | ||
|
|
beb9301282 | ||
|
|
0822cb871d | ||
|
|
bfea5dc8ba | ||
|
|
9fb5a38172 | ||
|
|
74ff24e4a4 | ||
|
|
178dbd33ba | ||
|
|
f5e59b1c84 | ||
|
|
ba7bf87ee0 | ||
|
|
99bc2e121b | ||
|
|
341749706d | ||
|
|
a25bfcb0d0 | ||
|
|
b2ea29b91d | ||
|
|
a28f5eeee6 | ||
|
|
2febb10319 | ||
|
|
ae3a27bf06 | ||
|
|
5a751a6745 | ||
|
|
0a7061f375 | ||
|
|
c7db89a200 | ||
|
|
a6784e7714 | ||
|
|
a9b92a756b | ||
|
|
52eb6b3f2a | ||
|
|
43e59d8fce | ||
|
|
ceaa6ff5f8 | ||
|
|
a77088eeb3 | ||
|
|
162dbf8750 | ||
|
|
1c2924eef9 | ||
|
|
acc826ee9f | ||
|
|
8e58875b8f | ||
|
|
51451e8de3 | ||
|
|
b806397ae3 | ||
|
|
358efe4d1b |
@@ -14,7 +14,6 @@ bugprone-forwarding-reference-overload,
|
|||||||
bugprone-inaccurate-erase,
|
bugprone-inaccurate-erase,
|
||||||
bugprone-incorrect-roundings,
|
bugprone-incorrect-roundings,
|
||||||
bugprone-integer-division,
|
bugprone-integer-division,
|
||||||
bugprone-lambda-function-name,
|
|
||||||
bugprone-macro-parentheses,
|
bugprone-macro-parentheses,
|
||||||
bugprone-macro-repeated-side-effects,
|
bugprone-macro-repeated-side-effects,
|
||||||
bugprone-misplaced-operator-in-strlen-in-alloc,
|
bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||||
@@ -63,7 +62,6 @@ cert-str34-c,
|
|||||||
cppcoreguidelines-interfaces-global-init,
|
cppcoreguidelines-interfaces-global-init,
|
||||||
cppcoreguidelines-narrowing-conversions,
|
cppcoreguidelines-narrowing-conversions,
|
||||||
cppcoreguidelines-pro-type-member-init,
|
cppcoreguidelines-pro-type-member-init,
|
||||||
cppcoreguidelines-pro-type-static-cast-downcast,
|
|
||||||
cppcoreguidelines-slicing,
|
cppcoreguidelines-slicing,
|
||||||
google-default-arguments,
|
google-default-arguments,
|
||||||
google-runtime-operator,
|
google-runtime-operator,
|
||||||
|
|||||||
@@ -28,6 +28,13 @@ 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
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
name: MobileGL Plugin APK
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
- Feat/Backend-Direct-GLES
|
||||||
|
- Feat/Backend-Direct-Vulkan
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Set artifact metadata
|
||||||
|
run: |
|
||||||
|
echo "date_today=$(date +'%Y-%m-%d')" >> "$GITHUB_ENV"
|
||||||
|
echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Set up JDK
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: zulu
|
||||||
|
java-version: '17'
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
with:
|
||||||
|
gradle-version: 8.10.2
|
||||||
|
|
||||||
|
- name: Setup Android SDK
|
||||||
|
uses: android-actions/setup-android@v3
|
||||||
|
|
||||||
|
- name: Install Android NDK
|
||||||
|
run: |
|
||||||
|
sdkmanager "ndk;27.3.13750724"
|
||||||
|
echo "ndk.dir=$ANDROID_HOME/ndk/27.3.13750724" >> android-plugin/local.properties
|
||||||
|
|
||||||
|
- name: Update glslang external sources
|
||||||
|
working-directory: 3rdparty/glslang
|
||||||
|
run: python update_glslang_sources.py
|
||||||
|
|
||||||
|
- name: Build plugin APK
|
||||||
|
run: gradle --no-daemon -p android-plugin :app:assembleRelease
|
||||||
|
env:
|
||||||
|
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
|
||||||
|
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
|
||||||
|
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Verify signed APK
|
||||||
|
run: |
|
||||||
|
APKSIGNER="$(find "$ANDROID_HOME/build-tools" -name apksigner -type f | sort -V | tail -n 1)"
|
||||||
|
mapfile -t APKS < <(find android-plugin/app/build/outputs/apk -type f -path '*/release/*.apk' | sort)
|
||||||
|
if [ "${#APKS[@]}" -eq 0 ]; then
|
||||||
|
echo "::error::No release APKs found under android-plugin/app/build/outputs/apk"
|
||||||
|
find android-plugin/app/build/outputs/apk -type f -print || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for APK in "${APKS[@]}"; do
|
||||||
|
if [[ "$APK" == *-unsigned.apk ]]; then
|
||||||
|
echo "::error::Unsigned release APK produced: $APK"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
"$APKSIGNER" verify --verbose "$APK"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Upload plugin APK
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: MobileGL-plugin-${{ env.date_today }}-${{ env.short_sha }}
|
||||||
|
path: |
|
||||||
|
android-plugin/app/build/outputs/apk/release/*.apk
|
||||||
|
android-plugin/app/build/outputs/apk/**/release/*.apk
|
||||||
@@ -28,6 +28,13 @@ 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,3 +15,10 @@ MobileGLCodeManager
|
|||||||
.clangd
|
.clangd
|
||||||
MobileGL/MG_Test/build
|
MobileGL/MG_Test/build
|
||||||
/build_*
|
/build_*
|
||||||
|
/cmake-build*
|
||||||
|
.idea
|
||||||
|
MobileGL/MG*/build*
|
||||||
|
MobileGL/MG*/cmake-build*
|
||||||
|
/android-plugin/.gradle
|
||||||
|
/android-plugin/build
|
||||||
|
/android-plugin/app/build
|
||||||
|
|||||||
+12
@@ -16,3 +16,15 @@
|
|||||||
[submodule "3rdparty/xxHash"]
|
[submodule "3rdparty/xxHash"]
|
||||||
path = 3rdparty/xxHash
|
path = 3rdparty/xxHash
|
||||||
url = https://github.com/Cyan4973/xxHash.git
|
url = https://github.com/Cyan4973/xxHash.git
|
||||||
|
[submodule "3rdparty/VulkanMemoryAllocator"]
|
||||||
|
path = 3rdparty/VulkanMemoryAllocator
|
||||||
|
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
|
||||||
|
[submodule "3rdparty/Vulkan-Utility-Libraries"]
|
||||||
|
path = 3rdparty/Vulkan-Utility-Libraries
|
||||||
|
url = https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git
|
||||||
|
[submodule "3rdparty/Vulkan-Headers"]
|
||||||
|
path = 3rdparty/Vulkan-Headers
|
||||||
|
url = https://github.com/KhronosGroup/Vulkan-Headers.git
|
||||||
|
[submodule "3rdparty/SPIRV-Reflect"]
|
||||||
|
path = 3rdparty/SPIRV-Reflect
|
||||||
|
url = https://github.com/KhronosGroup/SPIRV-Reflect.git
|
||||||
|
|||||||
+1
Submodule 3rdparty/SPIRV-Reflect added at 10b4f09a24
+1
Submodule 3rdparty/Vulkan-Headers added at ad9ce1235e
+1
Submodule 3rdparty/Vulkan-Utility-Libraries added at 738ec97a3f
+1
Submodule 3rdparty/VulkanMemoryAllocator added at e722e57c89
+57
-10
@@ -104,9 +104,20 @@ set(SPIRV_CROSS_ENABLE_CPP OFF CACHE BOOL "Disable C++ API target" FORCE)
|
|||||||
set(SPIRV_CROSS_CLI OFF CACHE BOOL "Disable CLI binary" FORCE)
|
set(SPIRV_CROSS_CLI OFF CACHE BOOL "Disable CLI binary" FORCE)
|
||||||
set(SPIRV_CROSS_STATIC ON CACHE BOOL "Prefer static libs" FORCE)
|
set(SPIRV_CROSS_STATIC ON CACHE BOOL "Prefer static libs" FORCE)
|
||||||
|
|
||||||
|
set(SPIRV_REFLECT_EXECUTABLE OFF CACHE BOOL "Build spirv-reflect executable" FORCE)
|
||||||
|
set(SPIRV_REFLECT_STATIC_LIB ON CACHE BOOL "Build a SPIRV-Reflect static library" FORCE)
|
||||||
|
set(SPIRV_REFLECT_BUILD_TESTS OFF CACHE BOOL "Build the SPIRV-Reflect test suite" FORCE)
|
||||||
|
set(SPIRV_REFLECT_ENABLE_ASSERTS OFF CACHE BOOL "Enable asserts for debugging" FORCE)
|
||||||
|
set(SPIRV_REFLECT_ENABLE_ASAN OFF CACHE BOOL "Use address sanitization" FORCE)
|
||||||
|
set(SPIRV_REFLECT_INSTALL OFF CACHE BOOL "Whether to install" FORCE)
|
||||||
|
|
||||||
# add_subdirectory(3rdparty/DiligentCore)
|
# add_subdirectory(3rdparty/DiligentCore)
|
||||||
add_subdirectory(3rdparty/glslang)
|
add_subdirectory(3rdparty/glslang)
|
||||||
add_subdirectory(3rdparty/SPIRV-Cross)
|
add_subdirectory(3rdparty/SPIRV-Cross)
|
||||||
|
add_subdirectory(3rdparty/VulkanMemoryAllocator)
|
||||||
|
add_subdirectory(3rdparty/Vulkan-Headers)
|
||||||
|
add_subdirectory(3rdparty/Vulkan-Utility-Libraries)
|
||||||
|
add_subdirectory(3rdparty/SPIRV-Reflect)
|
||||||
|
|
||||||
set(XXHASH_BUILD_XXHSUM OFF)
|
set(XXHASH_BUILD_XXHSUM OFF)
|
||||||
option(BUILD_SHARED_LIBS OFF)
|
option(BUILD_SHARED_LIBS OFF)
|
||||||
@@ -127,6 +138,7 @@ 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
|
||||||
|
|
||||||
@@ -158,6 +170,8 @@ set(SOURCE_FILES
|
|||||||
MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.cpp
|
MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.cpp
|
||||||
MobileGL/MG_Util/Converters/GLToMG/ProgramEnumConverter.cpp
|
MobileGL/MG_Util/Converters/GLToMG/ProgramEnumConverter.cpp
|
||||||
MobileGL/MG_Util/Converters/MGToMG/TextureEnumConverter.cpp
|
MobileGL/MG_Util/Converters/MGToMG/TextureEnumConverter.cpp
|
||||||
|
MobileGL/MG_Util/Converters/MGToVk/RenderStateEnumConverter.cpp
|
||||||
|
MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp
|
||||||
|
|
||||||
MobileGL/MG_Util/Classifiers/TextureEnumClassifier.cpp
|
MobileGL/MG_Util/Classifiers/TextureEnumClassifier.cpp
|
||||||
|
|
||||||
@@ -165,6 +179,7 @@ set(SOURCE_FILES
|
|||||||
MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp
|
MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp
|
||||||
MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp
|
MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp
|
||||||
MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.cpp
|
MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.cpp
|
||||||
|
MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/FlattenInterfaceStructPass.cpp
|
||||||
MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.cpp
|
MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.cpp
|
||||||
|
|
||||||
MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp
|
MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp
|
||||||
@@ -209,16 +224,27 @@ 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/DirectVulkanTMP/DirectVulkanTMP.cpp
|
MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp
|
||||||
MobileGL/MG_Backend/DirectVulkanTMP/TmpImpl.cpp
|
MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp
|
||||||
MobileGL/MG_Backend/DirectVulkanTMP/BackendObject_DirectVulkanTMP.cpp
|
MobileGL/MG_Backend/DirectVulkan/VmaImpl.cpp
|
||||||
MobileGL/MG_Backend/DirectVulkanTMP/Renderer/VulkanContext.cpp
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp
|
||||||
MobileGL/MG_Backend/DirectVulkanTMP/Renderer/SwapchainManager.cpp
|
MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.cpp
|
||||||
MobileGL/MG_Backend/DirectVulkanTMP/Renderer/PipelineManager.cpp
|
MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.cpp
|
||||||
MobileGL/MG_Backend/DirectVulkanTMP/Renderer/FrameContext.cpp
|
MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineFactory.cpp
|
||||||
MobileGL/MG_Backend/DirectVulkanTMP/Managers/ProgramManager.cpp
|
MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp
|
||||||
|
MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp
|
||||||
|
MobileGL/MG_Backend/DirectVulkan/Renderer/BufferArena.cpp
|
||||||
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.cpp
|
||||||
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateBuilder.cpp
|
||||||
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp
|
||||||
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp
|
||||||
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp
|
||||||
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VkSamplerManager.cpp
|
||||||
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp
|
||||||
|
MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp
|
||||||
|
|
||||||
MobileGL/MG_State/GLState/Core.cpp
|
MobileGL/MG_State/GLState/Core.cpp
|
||||||
|
MobileGL/MG_State/EGLState/Core.cpp
|
||||||
MobileGL/MG_State/GLState/ErrorState/Error.cpp
|
MobileGL/MG_State/GLState/ErrorState/Error.cpp
|
||||||
MobileGL/MG_State/GLState/BufferState/BufferState.cpp
|
MobileGL/MG_State/GLState/BufferState/BufferState.cpp
|
||||||
MobileGL/MG_State/GLState/BufferState/BufferObject.cpp
|
MobileGL/MG_State/GLState/BufferState/BufferObject.cpp
|
||||||
@@ -251,8 +277,19 @@ set(MOBILEGL_LINK_LIBRARIES
|
|||||||
SPIRV-Tools-opt
|
SPIRV-Tools-opt
|
||||||
SPIRV-Tools
|
SPIRV-Tools
|
||||||
xxHash::xxhash
|
xxHash::xxhash
|
||||||
|
GPUOpen::VulkanMemoryAllocator
|
||||||
|
Vulkan::UtilityHeaders
|
||||||
|
spirv-reflect-static
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(MOBILEGL_COMPILE_DEF
|
||||||
|
-DVMA_STATIC_VULKAN_FUNCTIONS=0
|
||||||
|
-DVMA_DYNAMIC_VULKAN_FUNCTIONS=1
|
||||||
|
-DVMA_VULKAN_VERSION=1001000
|
||||||
|
)
|
||||||
|
|
||||||
|
message(STATUS "MOBILEGL_COMPILE_DEF=${MOBILEGL_COMPILE_DEF}")
|
||||||
|
|
||||||
set(MOBILEGL_INCLUDE_DIR
|
set(MOBILEGL_INCLUDE_DIR
|
||||||
${CMAKE_SOURCE_DIR}/include
|
${CMAKE_SOURCE_DIR}/include
|
||||||
${CMAKE_SOURCE_DIR}/MobileGL
|
${CMAKE_SOURCE_DIR}/MobileGL
|
||||||
@@ -285,10 +322,15 @@ target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${CMAKE_PROJECT_NAME}
|
target_link_libraries(${CMAKE_PROJECT_NAME}
|
||||||
PRIVATE
|
PUBLIC
|
||||||
${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}
|
||||||
@@ -313,9 +355,14 @@ if(NOT ANDROID)
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${CMAKE_PROJECT_NAME}_s
|
target_link_libraries(${CMAKE_PROJECT_NAME}_s
|
||||||
PRIVATE
|
PUBLIC
|
||||||
${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)
|
||||||
|
|||||||
+2
-1
@@ -14,8 +14,9 @@ namespace MobileGL::MG_Config {
|
|||||||
inline const String ProjectName = "MobileGL";
|
inline const String ProjectName = "MobileGL";
|
||||||
inline const String CoreName = "MobileGL Core";
|
inline const String CoreName = "MobileGL Core";
|
||||||
inline const String CoreVendor = "MobileGL-Dev (BZLZHH, Swung0x48, Tungsten)";
|
inline const String CoreVendor = "MobileGL-Dev (BZLZHH, Swung0x48, Tungsten)";
|
||||||
inline const Version CoreVersion = {26, 2, 0, "-dev", VersionType::Development};
|
inline const Version CoreVersion = {26, 6, 0, "-dev", VersionType::Development};
|
||||||
inline const VersionStringFormatAttrib DefaultVersionStringFormatAttrib = {2, 2, 0, true, true};
|
inline const VersionStringFormatAttrib DefaultVersionStringFormatAttrib = {2, 2, 0, true, true};
|
||||||
|
inline const Uint64 CacheVersion = 0;
|
||||||
|
|
||||||
extern BackendType ActiveBackendType;
|
extern BackendType ActiveBackendType;
|
||||||
} // namespace MobileGL::MG_Config
|
} // namespace MobileGL::MG_Config
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
// MobileGL - MobileGL/ConfigLoader.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
extern char** environ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace MobileGL::MG_ConfigLoader {
|
||||||
|
static UniquePtr<UnorderedMap<String, String>> acceptedEnvVariablesMap;
|
||||||
|
|
||||||
|
static Bool IsAcceptedPrefix(const String& key) {
|
||||||
|
return (key.compare(0, 6, "LIBGL_") == 0 || key.compare(0, 9, "MOBILEGL_") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void InitializeAcceptedEnvVariables() {
|
||||||
|
if (!acceptedEnvVariablesMap) {
|
||||||
|
acceptedEnvVariablesMap = MakeUnique<UnorderedMap<String, String>>();
|
||||||
|
} else {
|
||||||
|
acceptedEnvVariablesMap->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
char** envPtr = nullptr;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
envPtr = _environ;
|
||||||
|
#else // POSIX
|
||||||
|
envPtr = ::environ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (envPtr == nullptr) return;
|
||||||
|
|
||||||
|
for (char** env = envPtr; *env != nullptr; ++env) {
|
||||||
|
String entry(*env);
|
||||||
|
SizeT pos = entry.find('=');
|
||||||
|
if (pos != String::npos) {
|
||||||
|
String key = entry.substr(0, pos);
|
||||||
|
String value = entry.substr(pos + 1);
|
||||||
|
|
||||||
|
if (IsAcceptedPrefix(key)) {
|
||||||
|
(*acceptedEnvVariablesMap)[key] = value;
|
||||||
|
MGLOG_D("Config: Accepted env variable: %s=%s", key.c_str(), value.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void QueryEnvVariable(const String& key, String& outValue, const String& defaultValue) {
|
||||||
|
auto it = acceptedEnvVariablesMap->find(key);
|
||||||
|
if (it != acceptedEnvVariablesMap->end()) {
|
||||||
|
outValue = it->second;
|
||||||
|
} else {
|
||||||
|
outValue = defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void InitBackendType() {
|
||||||
|
String backendTypeStr;
|
||||||
|
QueryEnvVariable("MOBILEGL_BACKEND_TYPE", backendTypeStr, "DirectGLES");
|
||||||
|
#define ENTRY(backendType) \
|
||||||
|
if (backendTypeStr == #backendType) { \
|
||||||
|
MG_Config::ActiveBackendType = BackendType::backendType; \
|
||||||
|
MGLOG_I("Config: Active backend type set to " #backendType); \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
ENTRY(DirectGLES)
|
||||||
|
ENTRY(DirectVulkan)
|
||||||
|
ENTRY(Unknown)
|
||||||
|
MG_Config::ActiveBackendType = BackendType::Unknown;
|
||||||
|
#undef ENTRY
|
||||||
|
}
|
||||||
|
|
||||||
|
void Init() {
|
||||||
|
MGLOG_D("Loading configuration from environment variables...");
|
||||||
|
InitializeAcceptedEnvVariables();
|
||||||
|
|
||||||
|
InitBackendType();
|
||||||
|
|
||||||
|
// Destroy the map since we won't need it anymore
|
||||||
|
acceptedEnvVariablesMap.reset();
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_ConfigLoader
|
||||||
+15
-9
@@ -34,7 +34,9 @@
|
|||||||
#define MOBILEGL_EGL_API MOBILEGL_API
|
#define MOBILEGL_EGL_API MOBILEGL_API
|
||||||
|
|
||||||
// ====================== MobileGL configurations ======================= //
|
// ====================== MobileGL configurations ======================= //
|
||||||
#define MOBILEGL_LOG_ACTIVE_LEVEL MOBILEGL_LOG_LEVEL_INFO
|
#ifndef MOBILEGL_LOG_ACTIVE_LEVEL
|
||||||
|
#define MOBILEGL_LOG_ACTIVE_LEVEL MOBILEGL_LOG_LEVEL_DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MOBILEGL_LOG_ENABLE_CONSOLE 0
|
#define MOBILEGL_LOG_ENABLE_CONSOLE 0
|
||||||
#define MOBILEGL_LOG_ENABLE_FILE 1
|
#define MOBILEGL_LOG_ENABLE_FILE 1
|
||||||
@@ -63,11 +65,15 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// =============================== Utils ================================ //
|
// =============================== Utils ================================ //
|
||||||
#define MOBILEGL_ASSERT(condition, ...) \
|
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||||
do { \
|
#define MOBILEGL_ASSERT(condition, ...) \
|
||||||
if (!(condition)) { \
|
do { \
|
||||||
MGLOG_F("Assertion failed" __VA_OPT__(": ") __VA_ARGS__); \
|
if (!(condition)) { \
|
||||||
MGLOG_F(" at %s:%d (%s)", __FILE__, __LINE__, __func__); \
|
MGLOG_F("Assertion failed" __VA_OPT__(": ") __VA_ARGS__); \
|
||||||
TRAP; \
|
MGLOG_F(" at %s:%d (%s)", __FILE__, __LINE__, __func__); \
|
||||||
} \
|
TRAP; \
|
||||||
} while (0)
|
} \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define MOBILEGL_ASSERT(condition, ...)
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
namespace MG_Config {
|
namespace MG_Config {
|
||||||
BackendType ActiveBackendType = BackendType::DirectVulkanTMP;
|
BackendType ActiveBackendType;
|
||||||
} // namespace MG_Config
|
} // namespace MG_Config
|
||||||
|
|
||||||
namespace MG_Backend {
|
namespace MG_Backend {
|
||||||
|
|||||||
+39
-2
@@ -32,13 +32,14 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <climits>
|
||||||
|
#include <cstdlib>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <expected>
|
#include <expected>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <xxhash.h>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -51,6 +52,9 @@
|
|||||||
// 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>
|
||||||
|
|
||||||
@@ -60,7 +64,9 @@
|
|||||||
#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
|
||||||
|
|
||||||
@@ -92,13 +98,44 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
#define VK_USE_PLATFORM_ANDROID_KHR
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
#include <android/native_window.h>
|
#include <android/native_window.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
#define VK_USE_PLATFORM_ANDROID_KHR
|
||||||
|
#elif _WIN32
|
||||||
|
#define VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#define VK_USE_PLATFORM_METAL_EXT
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#define VK_USE_PLATFORM_XLIB_KHR
|
||||||
|
typedef struct _XDisplay Display;
|
||||||
|
typedef unsigned long XID;
|
||||||
|
typedef XID Window;
|
||||||
|
typedef unsigned long VisualID;
|
||||||
|
#else
|
||||||
|
#warning "VK_USE_PLATFORM_*_KHR not defined for this platform!"
|
||||||
|
#endif
|
||||||
|
#if defined(VK_USE_PLATFORM_XLIB_KHR)
|
||||||
|
#pragma push_macro("Bool")
|
||||||
|
#pragma push_macro("None")
|
||||||
|
#pragma push_macro("Always")
|
||||||
|
#pragma push_macro("Status")
|
||||||
|
#pragma push_macro("LSBFirst")
|
||||||
|
#pragma push_macro("DestroyAll")
|
||||||
|
#endif
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
#if defined(VK_USE_PLATFORM_XLIB_KHR)
|
||||||
|
#pragma pop_macro("DestroyAll")
|
||||||
|
#pragma pop_macro("LSBFirst")
|
||||||
|
#pragma pop_macro("Status")
|
||||||
|
#pragma pop_macro("Always")
|
||||||
|
#pragma pop_macro("None")
|
||||||
|
#pragma pop_macro("Bool")
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
#include <tracy/Tracy.hpp>
|
#include <tracy/Tracy.hpp>
|
||||||
|
|||||||
+16
-13
@@ -8,33 +8,36 @@
|
|||||||
|
|
||||||
#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 MG_Initialize() {
|
void 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("MobileGL State initialized");
|
MGLOG_D("MG_State initialized");
|
||||||
MG_Backend::Init();
|
MG_Backend::Init();
|
||||||
MGLOG_D("MobileGL Backend initialized");
|
MGLOG_D("MG_Backend initialized");
|
||||||
MG_Impl::Init();
|
MG_Impl::Init();
|
||||||
MGLOG_D("MobileGL Implementation initialized");
|
MGLOG_D("MG_Impl initialized");
|
||||||
glslang::InitializeProcess();
|
glslang::InitializeProcess();
|
||||||
MGLOG_D("glslang initialized");
|
MGLOG_D("glslang initialized");
|
||||||
MGLOG_I("MobileGL initialized");
|
MGLOG_I("MobileGL initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MG_Destroy() {
|
void Destroy() {
|
||||||
MGLOG_I("MobileGL closing...");
|
MGLOG_I("MobileGL closing...");
|
||||||
glslang::FinalizeProcess();
|
glslang::FinalizeProcess();
|
||||||
delete MG_State::pGLContext;
|
MG_State::pGLContext.reset();
|
||||||
delete MG_Impl::GLImpl::TextureImpl::pProxyTextureManager;
|
MG_State::pEGLContext.reset();
|
||||||
delete MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
MG_Impl::GLImpl::TextureImpl::pProxyTextureManager.reset();
|
||||||
|
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
|
||||||
@@ -42,11 +45,11 @@ namespace MobileGL {
|
|||||||
|
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
__attribute__((constructor)) static void AutoInit() {
|
__attribute__((constructor)) static void AutoInit() {
|
||||||
MG_Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((destructor)) static void AutoDestroy() {
|
__attribute__((destructor)) static void AutoDestroy() {
|
||||||
MG_Destroy();
|
Destroy();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -54,11 +57,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:
|
||||||
MG_Initialize();
|
Initialize();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
MG_Destroy();
|
Destroy();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|||||||
+18
-2
@@ -10,6 +10,22 @@
|
|||||||
#include "Includes.h"
|
#include "Includes.h"
|
||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
void MG_Initialize();
|
void Initialize();
|
||||||
void MG_Destroy();
|
void 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,7 +9,177 @@
|
|||||||
#include "BackendObject.h"
|
#include "BackendObject.h"
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend {
|
namespace MobileGL::MG_Backend {
|
||||||
|
namespace {
|
||||||
|
Bool IsReleaseCurrentRequest(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||||
|
return dpy == EGL_NO_DISPLAY && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::thread::id CurrentThreadKey() {
|
||||||
|
return std::this_thread::get_id();
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Bool BackendObject::InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
if (dpy == EGL_NO_DISPLAY) {
|
||||||
|
MGLOG_E("InitializeEGLDisplay failed: invalid EGLDisplay");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_eglDisplayInitialized && m_eglDisplay != dpy) {
|
||||||
|
MGLOG_E("InitializeEGLDisplay failed: backend already bound to a different EGLDisplay");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_eglDisplay = dpy;
|
||||||
|
m_eglDisplayInitialized = true;
|
||||||
|
if (major) {
|
||||||
|
*major = 1;
|
||||||
|
}
|
||||||
|
if (minor) {
|
||||||
|
*minor = 5;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject::CreateEGLWindowSurface(const WindowHandle& handle) {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
if (!m_eglDisplayInitialized) {
|
||||||
|
MGLOG_E("CreateEGLWindowSurface failed: EGL display is not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (handle.Backend == WindowBackend::Unknown || !handle.Handle) {
|
||||||
|
MGLOG_E("CreateEGLWindowSurface failed: invalid native window handle");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Window &&
|
||||||
|
m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetWindowHandle(handle);
|
||||||
|
if (!InitWindowSurface()) {
|
||||||
|
MGLOG_E("CreateEGLWindowSurface failed: backend InitWindowSurface failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_eglSurfaceInitialized = true;
|
||||||
|
m_eglSurfaceKind = SurfaceKind::Window;
|
||||||
|
m_eglCurrentThreads.clear();
|
||||||
|
m_backendCapabilitiesInitialized = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject::CreateEGLPbufferSurface(EGLint width, EGLint height) {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
if (!m_eglDisplayInitialized) {
|
||||||
|
MGLOG_E("CreateEGLPbufferSurface failed: EGL display is not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (width <= 0 || height <= 0) {
|
||||||
|
MGLOG_E("CreateEGLPbufferSurface failed: invalid size %dx%d", width, height);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Pbuffer) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!InitPbufferSurface(width, height)) {
|
||||||
|
MGLOG_E("CreateEGLPbufferSurface failed: backend InitPbufferSurface failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_eglSurfaceInitialized = true;
|
||||||
|
m_eglSurfaceKind = SurfaceKind::Pbuffer;
|
||||||
|
m_eglCurrentThreads.clear();
|
||||||
|
m_backendCapabilitiesInitialized = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject::MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
const auto threadKey = CurrentThreadKey();
|
||||||
|
if (IsReleaseCurrentRequest(dpy, draw, read, ctx)) {
|
||||||
|
m_eglCurrentThreads.erase(threadKey);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_eglDisplayInitialized || m_eglDisplay != dpy) {
|
||||||
|
MGLOG_E("MakeEGLCurrent failed: EGL display mismatch or not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!m_eglSurfaceInitialized) {
|
||||||
|
MGLOG_E("MakeEGLCurrent failed: EGL surface is not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE || ctx == EGL_NO_CONTEXT) {
|
||||||
|
MGLOG_E("MakeEGLCurrent failed: draw/read/context is invalid");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_backendCapabilitiesInitialized) {
|
||||||
|
if (!InitCapabilities()) {
|
||||||
|
MGLOG_E("MakeEGLCurrent failed: InitCapabilities failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_backendCapabilitiesInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_eglCurrentThreads[threadKey] = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendObject::ResetEGLRuntimeState() {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
m_eglSurfaceInitialized = false;
|
||||||
|
m_backendCapabilitiesInitialized = false;
|
||||||
|
m_eglSurfaceKind = SurfaceKind::None;
|
||||||
|
m_eglCurrentThreads.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject::SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
if (!m_eglDisplayInitialized || m_eglDisplay != dpy) {
|
||||||
|
MGLOG_E("SwapEGLBuffers failed: EGL display mismatch or not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (m_eglCurrentThreads.find(CurrentThreadKey()) == m_eglCurrentThreads.end()) {
|
||||||
|
MGLOG_E("SwapEGLBuffers failed: no current context attached");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!m_eglSurfaceInitialized || draw == EGL_NO_SURFACE) {
|
||||||
|
MGLOG_E("SwapEGLBuffers failed: invalid draw surface");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& backendFunctions = GetBackendFunctions();
|
||||||
|
if (!backendFunctions.Present) {
|
||||||
|
MGLOG_E("SwapEGLBuffers failed: backend Present function is null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
backendFunctions.Present();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendObject::ReleaseEGLResources() {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
ResetEGLRuntimeState();
|
||||||
|
m_eglDisplay = EGL_NO_DISPLAY;
|
||||||
|
m_eglDisplayInitialized = false;
|
||||||
|
m_windowHandle = {};
|
||||||
|
}
|
||||||
|
|
||||||
void BackendObject::SetWindowHandle(const WindowHandle& handle) {
|
void BackendObject::SetWindowHandle(const WindowHandle& handle) {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
m_windowHandle = handle;
|
m_windowHandle = handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bool BackendObject::InitPbufferSurface(EGLint width, EGLint height) {
|
||||||
|
(void)width;
|
||||||
|
(void)height;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} // namespace MobileGL::MG_Backend
|
} // namespace MobileGL::MG_Backend
|
||||||
|
|||||||
@@ -8,11 +8,17 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
#include "MG_State/GLState/TextureState/TextureEnum.h"
|
||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
|
namespace MG_State::GLState {
|
||||||
|
class FramebufferObject;
|
||||||
|
class ITextureObject;
|
||||||
|
}
|
||||||
|
|
||||||
enum class BackendType {
|
enum class BackendType {
|
||||||
DirectGLES,
|
DirectGLES,
|
||||||
DirectVulkanTMP,
|
DirectVulkan,
|
||||||
BackendTypeCount,
|
BackendTypeCount,
|
||||||
Unknown = -1
|
Unknown = -1
|
||||||
};
|
};
|
||||||
@@ -31,6 +37,10 @@ namespace MobileGL {
|
|||||||
void (*MultiDrawElementsIndirect)(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount,
|
void (*MultiDrawElementsIndirect)(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount,
|
||||||
GLsizei stride);
|
GLsizei stride);
|
||||||
void (*MultiDrawArraysIndirect)(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
void (*MultiDrawArraysIndirect)(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||||
|
void (*MultiDrawElementsIndirectCount)(GLenum mode, GLenum type, const void* indirect,
|
||||||
|
GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
|
||||||
|
void (*MultiDrawArraysIndirectCount)(GLenum mode, const void* indirect, GLintptr drawcount,
|
||||||
|
GLsizei maxdrawcount, GLsizei stride);
|
||||||
void (*DrawRangeElementsBaseVertex)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
void (*DrawRangeElementsBaseVertex)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||||
const void* indices, GLint basevertex);
|
const void* indices, GLint basevertex);
|
||||||
void (*DrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
void (*DrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||||
@@ -54,8 +64,17 @@ namespace MobileGL {
|
|||||||
void (*ClearBufferfv)(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
void (*ClearBufferfv)(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||||
void (*ClearBufferuiv)(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
void (*ClearBufferuiv)(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
||||||
void (*ClearBufferiv)(GLenum buffer, GLint drawbuffer, const GLint* value);
|
void (*ClearBufferiv)(GLenum buffer, GLint drawbuffer, const GLint* value);
|
||||||
|
void (*ClearNamedFramebufferfv)(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
||||||
|
GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||||
|
void (*ClearNamedFramebufferfi)(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
||||||
|
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||||
void (*BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
|
void (*BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
|
||||||
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||||
|
void (*BlitNamedFramebuffer)(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
|
||||||
|
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
|
||||||
|
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||||
|
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||||
|
GLbitfield mask, GLenum filter);
|
||||||
void (*CopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
void (*CopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
||||||
GLsizei height, GLint border);
|
GLsizei height, GLint border);
|
||||||
void (*CopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
|
void (*CopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
|
||||||
@@ -64,6 +83,27 @@ namespace MobileGL {
|
|||||||
void (*ReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
|
void (*ReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
|
||||||
void* pixels);
|
void* pixels);
|
||||||
void (*GetTexImage)(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
|
void (*GetTexImage)(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
|
||||||
|
void (*GetTextureImage)(const SharedPtr<MG_State::GLState::ITextureObject>& texture,
|
||||||
|
TextureUploadTarget uploadTarget, GLint level, GLenum format, GLenum type,
|
||||||
|
GLsizei bufSize, GLvoid* pixels);
|
||||||
|
void (*DispatchCompute)(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
|
||||||
|
void (*DispatchComputeIndirect)(GLintptr indirect);
|
||||||
|
void (*MemoryBarrier)(GLbitfield barriers);
|
||||||
|
void (*MemoryBarrierByRegion)(GLbitfield barriers);
|
||||||
|
void (*BindImageTexture)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer,
|
||||||
|
GLenum access, GLenum format);
|
||||||
|
void (*GetIntegeri_v)(GLenum target, GLuint index, GLint* data);
|
||||||
|
void (*GetInteger64i_v)(GLenum target, GLuint index, GLint64* data);
|
||||||
|
void (*GetProgramiv)(GLuint program, GLenum pname, GLint* params);
|
||||||
|
void (*GetProgramInterfaceiv)(GLuint program, GLenum programInterface, GLenum pname, GLint* params);
|
||||||
|
GLuint (*GetProgramResourceIndex)(GLuint program, GLenum programInterface, const GLchar* name);
|
||||||
|
void (*GetProgramResourceName)(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize,
|
||||||
|
GLsizei* length, GLchar* name);
|
||||||
|
void (*GetProgramResourceiv)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount,
|
||||||
|
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params);
|
||||||
|
GLint (*GetProgramResourceLocation)(GLuint program, GLenum programInterface, const GLchar* name);
|
||||||
|
GLint (*GetProgramResourceLocationIndex)(GLuint program, GLenum programInterface, const GLchar* name);
|
||||||
|
void (*ShaderStorageBlockBinding)(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
|
||||||
};
|
};
|
||||||
struct GlobalBackendFunctionsTable {
|
struct GlobalBackendFunctionsTable {
|
||||||
GLFunctionsTable GL;
|
GLFunctionsTable GL;
|
||||||
@@ -72,10 +112,16 @@ namespace MobileGL {
|
|||||||
|
|
||||||
struct DynamicBackendParameters {
|
struct DynamicBackendParameters {
|
||||||
SizeT UniformBufferOffsetAlignment = 256;
|
SizeT UniformBufferOffsetAlignment = 256;
|
||||||
|
SizeT MaxShaderStorageBlockSize = 128 * 1024 * 1024;
|
||||||
|
Uint32 SubgroupSize = 0;
|
||||||
|
Uint32 SubgroupSupportedStages = 0;
|
||||||
|
Uint32 SubgroupSupportedFeatures = 0;
|
||||||
|
Bool SubgroupQuadOperationsInAllStages = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class WindowBackend {
|
enum class WindowBackend {
|
||||||
Android,
|
Android,
|
||||||
|
X11,
|
||||||
// TODO: X11, Wayland, Windows, macOS, etc.
|
// TODO: X11, Wayland, Windows, macOS, etc.
|
||||||
WindowBackendCount,
|
WindowBackendCount,
|
||||||
Unknown = -1
|
Unknown = -1
|
||||||
@@ -91,8 +137,15 @@ namespace MobileGL {
|
|||||||
virtual ~BackendObject() = default;
|
virtual ~BackendObject() = default;
|
||||||
|
|
||||||
virtual void Initialize() = 0;
|
virtual void Initialize() = 0;
|
||||||
virtual void InitCapabilities() = 0;
|
virtual Bool InitCapabilities() = 0;
|
||||||
virtual void InitWindowSurface() = 0;
|
virtual Bool InitWindowSurface() = 0;
|
||||||
|
|
||||||
|
virtual Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor);
|
||||||
|
virtual Bool CreateEGLWindowSurface(const WindowHandle& handle);
|
||||||
|
virtual Bool CreateEGLPbufferSurface(EGLint width, EGLint height);
|
||||||
|
virtual Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
|
||||||
|
virtual Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw);
|
||||||
|
virtual void ReleaseEGLResources();
|
||||||
|
|
||||||
void SetWindowHandle(const WindowHandle& handle);
|
void SetWindowHandle(const WindowHandle& handle);
|
||||||
|
|
||||||
@@ -103,7 +156,23 @@ namespace MobileGL {
|
|||||||
virtual BackendType GetBackendType() const = 0;
|
virtual BackendType GetBackendType() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
enum class SurfaceKind {
|
||||||
|
None,
|
||||||
|
Window,
|
||||||
|
Pbuffer
|
||||||
|
};
|
||||||
|
|
||||||
|
void ResetEGLRuntimeState();
|
||||||
|
virtual Bool InitPbufferSurface(EGLint width, EGLint height);
|
||||||
|
|
||||||
|
mutable std::recursive_mutex m_eglStateMutex;
|
||||||
WindowHandle m_windowHandle;
|
WindowHandle m_windowHandle;
|
||||||
|
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
|
||||||
|
Bool m_eglDisplayInitialized = false;
|
||||||
|
Bool m_eglSurfaceInitialized = false;
|
||||||
|
Bool m_backendCapabilitiesInitialized = false;
|
||||||
|
SurfaceKind m_eglSurfaceKind = SurfaceKind::None;
|
||||||
|
UnorderedMap<std::thread::id, Bool> m_eglCurrentThreads;
|
||||||
};
|
};
|
||||||
} // namespace MG_Backend
|
} // namespace MG_Backend
|
||||||
} // namespace MobileGL
|
} // namespace MobileGL
|
||||||
|
|||||||
@@ -10,11 +10,9 @@
|
|||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include "BackendObject.h"
|
#include "BackendObject.h"
|
||||||
#include "DirectGLES/BackendObject_DirectGLES.h"
|
#include "DirectGLES/BackendObject_DirectGLES.h"
|
||||||
#include "DirectVulkanTMP/BackendObject_DirectVulkanTMP.h"
|
#include "DirectVulkan/BackendObject_DirectVulkan.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,16 +13,24 @@
|
|||||||
#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();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendObject_DirectGLES::InitWindowSurface() {
|
Bool 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() {
|
||||||
@@ -40,18 +48,75 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
DirectGLES::SetGLESFuncsTable(m_GLESFunctions);
|
DirectGLES::SetGLESFuncsTable(m_GLESFunctions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendObject_DirectGLES::InitCapabilities() {
|
Bool BackendObject_DirectGLES::InitCapabilities() {
|
||||||
if (!m_initialized) {
|
if (!m_initialized) {
|
||||||
MGLOG_E("DirectGLES backend not initialized");
|
MGLOG_E("DirectGLES backend not initialized");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
DirectGLES::SetGLESCapabilities(m_GLESCapabilities);
|
DirectGLES::SetGLESCapabilities(m_GLESCapabilities);
|
||||||
UpdateDynamicBackendParameters();
|
UpdateDynamicBackendParameters();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject_DirectGLES::InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) {
|
||||||
|
if (!m_initialized) {
|
||||||
|
MGLOG_E("DirectGLES backend not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return BackendObject::InitializeEGLDisplay(dpy, major, minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject_DirectGLES::CreateEGLWindowSurface(const WindowHandle& handle) {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
if (!m_initialized) {
|
||||||
|
MGLOG_E("DirectGLES backend not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((handle.Backend != WindowBackend::Android && handle.Backend != WindowBackend::X11) || !handle.Handle) {
|
||||||
|
MGLOG_E("DirectGLES backend only supports Android and X11 native windows");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Bool sameHandle = m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Window &&
|
||||||
|
m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
|
||||||
|
if (sameHandle) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_eglSurfaceInitialized) {
|
||||||
|
DestroyEGLContext();
|
||||||
|
ResetEGLRuntimeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
return BackendObject::CreateEGLWindowSurface(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject_DirectGLES::InitPbufferSurface(EGLint width, EGLint height) {
|
||||||
|
return DirectGLES::InitPbufferSurface(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject_DirectGLES::MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||||
|
if (IsReleaseCurrentRequest(dpy, draw, read, ctx)) {
|
||||||
|
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject_DirectGLES::SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) {
|
||||||
|
return BackendObject::SwapEGLBuffers(dpy, draw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendObject_DirectGLES::ReleaseEGLResources() {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
DestroyEGLContext();
|
||||||
|
BackendObject::ReleaseEGLResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
const RendererInfo& BackendObject_DirectGLES::GetRendererInfo() const {
|
const RendererInfo& BackendObject_DirectGLES::GetRendererInfo() const {
|
||||||
@@ -64,7 +129,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
.TargetGLVersion = {3, 3, 0}, // Target OpenGL Version
|
.TargetGLVersion = {3, 3, 0}, // Target OpenGL Version
|
||||||
.TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version
|
.TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version
|
||||||
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
|
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
|
||||||
V_OpenGL33, E_GL_ARB_draw_buffers_blend},
|
V_OpenGL33, E_GL_ARB_draw_buffers_blend, E_GL_ARB_compute_shader,
|
||||||
|
E_GL_ARB_shader_storage_buffer_object, E_GL_ARB_shader_image_load_store,
|
||||||
|
E_GL_ARB_program_interface_query, E_GL_ARB_framebuffer_object,
|
||||||
|
E_GL_EXT_framebuffer_object, E_GL_ARB_depth_texture, E_GL_ARB_buffer_storage,
|
||||||
|
E_GL_ARB_texture_storage, E_GL_ARB_direct_state_access,
|
||||||
|
E_GL_ARB_multi_draw_indirect, E_GL_ARB_indirect_parameters,
|
||||||
|
E_GL_ARB_shader_draw_parameters},
|
||||||
.IsCompatibilityProfile = false // Is Compatibility Profile
|
.IsCompatibilityProfile = false // Is Compatibility Profile
|
||||||
},
|
},
|
||||||
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
|
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
|
||||||
@@ -98,6 +169,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
funcsTable.GL.MultiDrawElements = MultiDrawElements;
|
funcsTable.GL.MultiDrawElements = MultiDrawElements;
|
||||||
funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex;
|
funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex;
|
||||||
funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect;
|
funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect;
|
||||||
|
funcsTable.GL.MultiDrawElementsIndirectCount = MultiDrawElementsIndirectCount;
|
||||||
funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect;
|
funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect;
|
||||||
funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex;
|
funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex;
|
||||||
funcsTable.GL.DrawRangeElements = DrawRangeElements;
|
funcsTable.GL.DrawRangeElements = DrawRangeElements;
|
||||||
@@ -109,12 +181,30 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
funcsTable.GL.DrawArraysInstanced = DrawArraysInstanced;
|
funcsTable.GL.DrawArraysInstanced = DrawArraysInstanced;
|
||||||
funcsTable.GL.DrawElementsIndirect = DrawElementsIndirect;
|
funcsTable.GL.DrawElementsIndirect = DrawElementsIndirect;
|
||||||
funcsTable.GL.DrawArraysIndirect = DrawArraysIndirect;
|
funcsTable.GL.DrawArraysIndirect = DrawArraysIndirect;
|
||||||
|
funcsTable.GL.DispatchCompute = DispatchCompute;
|
||||||
|
funcsTable.GL.DispatchComputeIndirect = DispatchComputeIndirect;
|
||||||
|
funcsTable.GL.MemoryBarrier = MemoryBarrier;
|
||||||
|
funcsTable.GL.MemoryBarrierByRegion = MemoryBarrierByRegion;
|
||||||
|
funcsTable.GL.BindImageTexture = BindImageTexture;
|
||||||
|
funcsTable.GL.GetIntegeri_v = GetIntegeri_v;
|
||||||
|
funcsTable.GL.GetInteger64i_v = GetInteger64i_v;
|
||||||
|
funcsTable.GL.GetProgramiv = GetProgramiv;
|
||||||
|
funcsTable.GL.GetProgramInterfaceiv = GetProgramInterfaceiv;
|
||||||
|
funcsTable.GL.GetProgramResourceIndex = GetProgramResourceIndex;
|
||||||
|
funcsTable.GL.GetProgramResourceName = GetProgramResourceName;
|
||||||
|
funcsTable.GL.GetProgramResourceiv = GetProgramResourceiv;
|
||||||
|
funcsTable.GL.GetProgramResourceLocation = GetProgramResourceLocation;
|
||||||
|
funcsTable.GL.GetProgramResourceLocationIndex = GetProgramResourceLocationIndex;
|
||||||
|
funcsTable.GL.ShaderStorageBlockBinding = ShaderStorageBlockBinding;
|
||||||
funcsTable.GL.Clear = Clear;
|
funcsTable.GL.Clear = Clear;
|
||||||
funcsTable.GL.ClearBufferfi = ClearBufferfi;
|
funcsTable.GL.ClearBufferfi = ClearBufferfi;
|
||||||
funcsTable.GL.ClearBufferfv = ClearBufferfv;
|
funcsTable.GL.ClearBufferfv = ClearBufferfv;
|
||||||
funcsTable.GL.ClearBufferuiv = ClearBufferuiv;
|
funcsTable.GL.ClearBufferuiv = ClearBufferuiv;
|
||||||
funcsTable.GL.ClearBufferiv = ClearBufferiv;
|
funcsTable.GL.ClearBufferiv = ClearBufferiv;
|
||||||
|
funcsTable.GL.ClearNamedFramebufferfv = ClearNamedFramebufferfv;
|
||||||
|
funcsTable.GL.ClearNamedFramebufferfi = ClearNamedFramebufferfi;
|
||||||
funcsTable.GL.BlitFramebuffer = BlitFramebuffer;
|
funcsTable.GL.BlitFramebuffer = BlitFramebuffer;
|
||||||
|
funcsTable.GL.BlitNamedFramebuffer = BlitNamedFramebuffer;
|
||||||
funcsTable.GL.CopyTexImage2D = CopyTexImage2D;
|
funcsTable.GL.CopyTexImage2D = CopyTexImage2D;
|
||||||
funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D;
|
funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D;
|
||||||
funcsTable.GL.GenerateMipmap = GenerateMipmap;
|
funcsTable.GL.GenerateMipmap = GenerateMipmap;
|
||||||
|
|||||||
@@ -17,8 +17,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
~BackendObject_DirectGLES() override;
|
~BackendObject_DirectGLES() override;
|
||||||
|
|
||||||
void Initialize() override;
|
void Initialize() override;
|
||||||
void InitCapabilities() override;
|
Bool InitCapabilities() override;
|
||||||
void InitWindowSurface() override;
|
Bool InitWindowSurface() override;
|
||||||
|
Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) override;
|
||||||
|
Bool CreateEGLWindowSurface(const WindowHandle& handle) override;
|
||||||
|
Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) override;
|
||||||
|
Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) override;
|
||||||
|
void ReleaseEGLResources() override;
|
||||||
|
|
||||||
const RendererInfo& GetRendererInfo() const override;
|
const RendererInfo& GetRendererInfo() const override;
|
||||||
String GetBackendAPIVersionString() const override;
|
String GetBackendAPIVersionString() const override;
|
||||||
@@ -31,6 +36,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateDynamicBackendParameters();
|
void UpdateDynamicBackendParameters();
|
||||||
|
Bool InitPbufferSurface(EGLint width, EGLint height) override;
|
||||||
|
|
||||||
Bool m_initialized = false;
|
Bool m_initialized = false;
|
||||||
MG_External::EGLFunctionsTable m_EGLFunctions;
|
MG_External::EGLFunctionsTable m_EGLFunctions;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
||||||
#include <MG_State/GLState/TextureState/TextureState.h>
|
#include <MG_State/GLState/TextureState/TextureState.h>
|
||||||
#include <MG_State/GLState/SamplerState/SamplerObject.h>
|
#include <MG_State/GLState/SamplerState/SamplerObject.h>
|
||||||
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
|
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
|
||||||
@@ -30,6 +31,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
||||||
GLsizei drawcount, const GLint* basevertex);
|
GLsizei drawcount, const GLint* basevertex);
|
||||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride);
|
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||||
|
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
|
||||||
|
GLsizei maxdrawcount, GLsizei stride);
|
||||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||||
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||||
const void* indices, GLint basevertex);
|
const void* indices, GLint basevertex);
|
||||||
@@ -46,8 +49,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
GLuint baseinstance);
|
GLuint baseinstance);
|
||||||
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
||||||
void DrawArraysIndirect(GLenum mode, const void* indirect);
|
void DrawArraysIndirect(GLenum mode, const void* indirect);
|
||||||
|
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
||||||
|
GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||||
|
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
||||||
|
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||||
GLint dstY1, GLbitfield mask, GLenum filter);
|
GLint dstY1, GLbitfield mask, GLenum filter);
|
||||||
|
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
|
||||||
|
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
|
||||||
|
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||||
|
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||||
|
GLbitfield mask, GLenum filter);
|
||||||
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
||||||
GLsizei height, GLint border);
|
GLsizei height, GLint border);
|
||||||
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
||||||
@@ -56,7 +68,26 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
const GLubyte* GetString(GLenum name);
|
const GLubyte* GetString(GLenum name);
|
||||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
||||||
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
|
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
|
||||||
|
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
|
||||||
|
void DispatchComputeIndirect(GLintptr indirect);
|
||||||
|
void MemoryBarrier(GLbitfield barriers);
|
||||||
|
void MemoryBarrierByRegion(GLbitfield barriers);
|
||||||
|
void BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access,
|
||||||
|
GLenum format);
|
||||||
|
void GetIntegeri_v(GLenum target, GLuint index, GLint* data);
|
||||||
|
void GetInteger64i_v(GLenum target, GLuint index, GLint64* data);
|
||||||
|
void GetProgramiv(GLuint program, GLenum pname, GLint* params);
|
||||||
|
void GetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint* params);
|
||||||
|
GLuint GetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar* name);
|
||||||
|
void GetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length,
|
||||||
|
GLchar* name);
|
||||||
|
void GetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount,
|
||||||
|
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params);
|
||||||
|
GLint GetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar* name);
|
||||||
|
GLint GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, const GLchar* name);
|
||||||
|
void ShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
|
||||||
Bool InitWindowSurface(NativeWindowType window);
|
Bool InitWindowSurface(NativeWindowType window);
|
||||||
|
Bool InitPbufferSurface(EGLint width, EGLint height);
|
||||||
void Present();
|
void Present();
|
||||||
void SetEGLFuncsTable(const MG_External::EGLFunctionsTable& eglFuncs);
|
void SetEGLFuncsTable(const MG_External::EGLFunctionsTable& eglFuncs);
|
||||||
void SetGLESFuncsTable(const MG_External::GLESFunctionsTable& glesFuncs);
|
void SetGLESFuncsTable(const MG_External::GLESFunctionsTable& glesFuncs);
|
||||||
|
|||||||
@@ -7,10 +7,6 @@
|
|||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
#include "Managers.h"
|
#include "Managers.h"
|
||||||
#include "MG_State/GLState/TextureState/TextureEnum.h"
|
|
||||||
#include "MG_State/GLState/TextureState/TextureObject.h"
|
|
||||||
#include "MG_State/GLState/TextureState/TextureState.h"
|
|
||||||
#include "MG_Util/Converters/GLToMG/TextureEnumConverter.h"
|
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "DirectGLES.h"
|
#include "DirectGLES.h"
|
||||||
|
|
||||||
@@ -18,6 +14,7 @@
|
|||||||
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
||||||
#include <MG_Util/Converters/MGToGL/DataTypeConverter.h>
|
#include <MG_Util/Converters/MGToGL/DataTypeConverter.h>
|
||||||
#include <MG_Util/Converters/MGToGL/BufferEnumConverter.h>
|
#include <MG_Util/Converters/MGToGL/BufferEnumConverter.h>
|
||||||
|
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
||||||
#include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h>
|
#include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h>
|
||||||
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
|
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
|
||||||
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
|
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
|
||||||
@@ -26,9 +23,63 @@
|
|||||||
#include <MG_Util/Converters/GLToMG/FramebufferEnumConverter.h>
|
#include <MG_Util/Converters/GLToMG/FramebufferEnumConverter.h>
|
||||||
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
|
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
|
||||||
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectGLES {
|
namespace MobileGL::MG_Backend::DirectGLES {
|
||||||
constexpr Bool PREFER_MAP_BUFFER_RANGE_FOR_BUFFER_SYNC = true;
|
constexpr Bool PREFER_MAP_BUFFER_RANGE_FOR_BUFFER_SYNC = true;
|
||||||
|
constexpr const char* BASE_INSTANCE_UNIFORM_NAME = "mg_BaseInstance";
|
||||||
|
|
||||||
|
static Uint ResolveBackendEsslVersion() {
|
||||||
|
const auto& version = g_GLESCapabilities.GLESVersion;
|
||||||
|
if (version.Major > 3 || (version.Major == 3 && version.Minor >= 2)) {
|
||||||
|
return 320;
|
||||||
|
}
|
||||||
|
if (version.Major == 3 && version.Minor >= 1) {
|
||||||
|
return 310;
|
||||||
|
}
|
||||||
|
return 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ReplaceIdentifier(String source, const String& from, const String& to) {
|
||||||
|
SizeT pos = 0;
|
||||||
|
while ((pos = source.find(from, pos)) != String::npos) {
|
||||||
|
const Bool leftIsIdent = pos > 0 &&
|
||||||
|
(std::isalnum(static_cast<unsigned char>(source[pos - 1])) || source[pos - 1] == '_');
|
||||||
|
const SizeT end = pos + from.size();
|
||||||
|
const Bool rightIsIdent = end < source.size() &&
|
||||||
|
(std::isalnum(static_cast<unsigned char>(source[end])) || source[end] == '_');
|
||||||
|
if (!leftIsIdent && !rightIsIdent) {
|
||||||
|
source.replace(pos, from.size(), to);
|
||||||
|
pos += to.size();
|
||||||
|
} else {
|
||||||
|
pos = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
String InjectUniformAfterVersion(String source, const String& declaration) {
|
||||||
|
const SizeT versionPos = source.find("#version");
|
||||||
|
if (versionPos == String::npos) {
|
||||||
|
return declaration + "\n" + source;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SizeT lineEnd = source.find('\n', versionPos);
|
||||||
|
if (lineEnd == String::npos) {
|
||||||
|
return source + "\n" + declaration + "\n";
|
||||||
|
}
|
||||||
|
source.insert(lineEnd + 1, declaration + "\n");
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
String EmulateBaseInstanceInVertexShader(String source, GLenum shaderType) {
|
||||||
|
if (shaderType != GL_VERTEX_SHADER || source.find("gl_BaseInstance") == String::npos) {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
source = ReplaceIdentifier(std::move(source), "gl_BaseInstance", BASE_INSTANCE_UNIFORM_NAME);
|
||||||
|
return InjectUniformAfterVersion(std::move(source),
|
||||||
|
String("uniform highp int ") + BASE_INSTANCE_UNIFORM_NAME + ";");
|
||||||
|
}
|
||||||
|
|
||||||
namespace BufferImpl {
|
namespace BufferImpl {
|
||||||
BackendBufferObject::BackendBufferObject() {
|
BackendBufferObject::BackendBufferObject() {
|
||||||
@@ -44,7 +95,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendBufferObject::SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
|
void BackendBufferObject::SyncToBackend(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
@@ -105,7 +156,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BackendBufferObject::SyncToBackend_glBufferData(
|
void BackendBufferObject::SyncToBackend_glBufferData(
|
||||||
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
|
const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
@@ -117,11 +168,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
GLenum usage = MG_Util::ConvertBufferUsageToGLEnum(stateBufferObject->GetUsage());
|
GLenum usage = MG_Util::ConvertBufferUsageToGLEnum(stateBufferObject->GetUsage());
|
||||||
|
|
||||||
Bind();
|
Bind();
|
||||||
g_GLESFuncs.glBufferData(TempBufferTarget, size, data, usage);
|
g_GLESFuncs.glBufferData(TempBufferTarget, (GLsizeiptr)size, data, usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendBufferObject::SyncToBackend_glBufferSubData(
|
void BackendBufferObject::SyncToBackend_glBufferSubData(
|
||||||
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
|
const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
@@ -130,7 +181,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
const void* data = stateBufferObject->GetDataReadOnly()->data();
|
const void* data = stateBufferObject->GetDataReadOnly()->data();
|
||||||
// dirty range: [range.start, range.end)
|
// dirty range: [range.start, range.end)
|
||||||
auto ranges = stateBufferObject->GetDirtyRanges();
|
auto& ranges = stateBufferObject->GetDirtyRanges();
|
||||||
if (ranges.empty()) {
|
if (ranges.empty()) {
|
||||||
MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId);
|
MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId);
|
||||||
return;
|
return;
|
||||||
@@ -138,20 +189,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
for (const auto& range : ranges) {
|
for (const auto& range : ranges) {
|
||||||
Bind();
|
Bind();
|
||||||
g_GLESFuncs.glBufferSubData(TempBufferTarget, range.start, range.end - range.start,
|
g_GLESFuncs.glBufferSubData(TempBufferTarget, (GLintptr)range.start,
|
||||||
|
(GLintptr)(range.end - range.start),
|
||||||
reinterpret_cast<const char*>(data) + range.start);
|
reinterpret_cast<const char*>(data) + range.start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendBufferObject::SyncToBackend_glMapBufferRange(
|
void BackendBufferObject::SyncToBackend_glMapBufferRange(
|
||||||
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, Bool invalidate, Bool unsynchronized) {
|
const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, Bool invalidate, Bool unsynchronized) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MGLOG_D("Syncing buffer map (glMapBuffer) for object with ID : %u", m_backendBufferId);
|
MGLOG_D("Syncing buffer map (glMapBuffer) for object with ID : %u", m_backendBufferId);
|
||||||
MGLOG_D("Mapping buffer with ID: %u", m_backendBufferId);
|
MGLOG_D("Mapping buffer with ID: %u", m_backendBufferId);
|
||||||
auto ranges = stateBufferObject->GetDirtyRanges();
|
auto& ranges = stateBufferObject->GetDirtyRanges();
|
||||||
if (ranges.empty()) {
|
if (ranges.empty()) {
|
||||||
MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId);
|
MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId);
|
||||||
return;
|
return;
|
||||||
@@ -159,18 +211,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(TempBufferTarget, minStart, maxEnd - minStart,
|
void* mappedData = g_GLESFuncs.glMapBufferRange(
|
||||||
(invalidate ? GL_MAP_INVALIDATE_RANGE_BIT : 0) |
|
TempBufferTarget, (GLintptr)minStart, (GLintptr)(maxEnd - minStart),
|
||||||
(unsynchronized ? GL_MAP_UNSYNCHRONIZED_BIT : 0) |
|
(invalidate ? GL_MAP_INVALIDATE_RANGE_BIT : 0) | (unsynchronized ? GL_MAP_UNSYNCHRONIZED_BIT : 0) |
|
||||||
GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
|
GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
|
||||||
const void* data = stateBufferObject->GetDataReadOnly()->data();
|
const void* data = stateBufferObject->GetDataReadOnly()->data();
|
||||||
if (mappedData) {
|
if (mappedData) {
|
||||||
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, range.start - minStart,
|
g_GLESFuncs.glFlushMappedBufferRange(TempBufferTarget, (GLintptr)(range.start - minStart),
|
||||||
range.end - range.start);
|
(GLintptr)(range.end - range.start));
|
||||||
}
|
}
|
||||||
g_GLESFuncs.glUnmapBuffer(TempBufferTarget);
|
g_GLESFuncs.glUnmapBuffer(TempBufferTarget);
|
||||||
} else {
|
} else {
|
||||||
@@ -191,15 +243,39 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_GLESFuncs.glBindBuffer(target, m_backendBufferId);
|
g_GLESFuncs.glBindBuffer(target, m_backendBufferId);
|
||||||
}
|
}
|
||||||
|
|
||||||
UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>> g_backendBufferObjects;
|
StateBackendObjectRegistry<MG_State::GLState::BufferObject, BackendBufferObject> g_backendBufferObjects;
|
||||||
BackendBufferObject* g_boundVertexBufferObject = nullptr;
|
BackendBufferObject* g_boundVertexBufferObject = nullptr;
|
||||||
} // namespace BufferImpl
|
} // namespace BufferImpl
|
||||||
|
|
||||||
namespace VertexArrayImpl {
|
namespace VertexArrayImpl {
|
||||||
|
namespace {
|
||||||
|
SizeT GetDataTypeSize(DataType type) {
|
||||||
|
switch (type) {
|
||||||
|
case DataType::Int8:
|
||||||
|
case DataType::Uint8:
|
||||||
|
return 1;
|
||||||
|
case DataType::Int16:
|
||||||
|
case DataType::Uint16:
|
||||||
|
case DataType::Float16:
|
||||||
|
return 2;
|
||||||
|
case DataType::Int32:
|
||||||
|
case DataType::Uint32:
|
||||||
|
case DataType::Float32:
|
||||||
|
case DataType::Fixed32:
|
||||||
|
return 4;
|
||||||
|
case DataType::Float64:
|
||||||
|
return 8;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
BackendVertexArrayObject::BackendVertexArrayObject() {
|
BackendVertexArrayObject::BackendVertexArrayObject() {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
|
m_clientAttributeBufferIds.fill(0);
|
||||||
g_GLESFuncs.glGenVertexArrays(1, &m_backendVAOId);
|
g_GLESFuncs.glGenVertexArrays(1, &m_backendVAOId);
|
||||||
if (m_backendVAOId == 0) {
|
if (m_backendVAOId == 0) {
|
||||||
MGLOG_E("Failed to generate vertex array object.");
|
MGLOG_E("Failed to generate vertex array object.");
|
||||||
@@ -209,32 +285,46 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendVertexArrayObject::Bind() {
|
BackendVertexArrayObject::~BackendVertexArrayObject() {
|
||||||
|
if (m_backendVAOId != 0) {
|
||||||
|
g_GLESFuncs.glDeleteVertexArrays(1, &m_backendVAOId);
|
||||||
|
m_backendVAOId = 0;
|
||||||
|
}
|
||||||
|
for (auto& bufferId : m_clientAttributeBufferIds) {
|
||||||
|
if (bufferId != 0) {
|
||||||
|
g_GLESFuncs.glDeleteBuffers(1, &bufferId);
|
||||||
|
bufferId = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendVertexArrayObject::Bind() const {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
g_GLESFuncs.glBindVertexArray(m_backendVAOId);
|
g_GLESFuncs.glBindVertexArray(m_backendVAOId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendVertexArrayObject::BindAttributeBuffer(Uint index,
|
inline Bool BindAttributeBuffer(const MG_State::GLState::VertexAttribute& attrib) {
|
||||||
const MG_State::GLState::VertexAttribute& attrib) {
|
|
||||||
const auto& bufferObject = attrib.Buffer;
|
const auto& bufferObject = attrib.Buffer;
|
||||||
if (!bufferObject) {
|
if (!bufferObject) {
|
||||||
MGLOG_W("Attribute has no bound buffer, skipping.");
|
MGLOG_W("Attribute has no bound buffer, skipping.");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObject);
|
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObject.get());
|
||||||
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
|
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
|
||||||
MGLOG_E("No backend buffer found for attribute's buffer, cannot bind attribute.");
|
MGLOG_E("No backend buffer found for attribute's buffer, cannot bind attribute.");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
const auto& backendBufferObject = backendBufferIt->second;
|
const auto& backendBufferObject = backendBufferIt->second;
|
||||||
|
|
||||||
backendBufferObject->Bind(GL_ARRAY_BUFFER);
|
backendBufferObject->Bind(GL_ARRAY_BUFFER);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendVertexArrayObject::SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject) {
|
void BackendVertexArrayObject::SyncToBackend(
|
||||||
|
const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
@@ -268,7 +358,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
m_syncedAttributeVersions[attribIndex].BufferVersion;
|
m_syncedAttributeVersions[attribIndex].BufferVersion;
|
||||||
if (!needsSyncFormat && !needsSyncBuffer) continue;
|
if (!needsSyncFormat && !needsSyncBuffer) continue;
|
||||||
|
|
||||||
BindAttributeBuffer(attribIndex, attrib);
|
if (!BindAttributeBuffer(attrib)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!attrib.IsInteger) {
|
if (!attrib.IsInteger) {
|
||||||
g_GLESFuncs.glVertexAttribPointer(
|
g_GLESFuncs.glVertexAttribPointer(
|
||||||
@@ -288,22 +380,82 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
Uint16 currentIndexBufferVersion = stateVAOObject->GetIndexBufferBindingSlot().GetVersion();
|
Uint16 currentIndexBufferVersion = stateVAOObject->GetIndexBufferBindingSlot().GetVersion();
|
||||||
if (currentIndexBufferVersion != m_syncedIndexBufferVersion) {
|
if (currentIndexBufferVersion != m_syncedIndexBufferVersion) {
|
||||||
const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
|
const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
|
||||||
|
Bool indexBufferSynced = false;
|
||||||
if (indexBufferBinding) {
|
if (indexBufferBinding) {
|
||||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding);
|
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding.get());
|
||||||
if (backendBufferIt != BufferImpl::g_backendBufferObjects.end()) {
|
if (backendBufferIt != BufferImpl::g_backendBufferObjects.end()) {
|
||||||
const auto& backendBufferObject = backendBufferIt->second;
|
const auto& backendBufferObject = backendBufferIt->second;
|
||||||
backendBufferObject->Bind(GL_ELEMENT_ARRAY_BUFFER);
|
backendBufferObject->Bind(GL_ELEMENT_ARRAY_BUFFER);
|
||||||
|
indexBufferSynced = true;
|
||||||
} else {
|
} else {
|
||||||
MGLOG_W("No backend buffer found for index buffer binding, cannot bind index buffer.");
|
MGLOG_W("No backend buffer found for index buffer binding, cannot bind index buffer.");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
g_GLESFuncs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
indexBufferSynced = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indexBufferSynced) {
|
||||||
|
m_syncedIndexBufferVersion = currentIndexBufferVersion;
|
||||||
}
|
}
|
||||||
m_syncedIndexBufferVersion = currentIndexBufferVersion;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_syncedAttributeVersions = allAttributeVersions;
|
m_syncedAttributeVersions = allAttributeVersions;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>>
|
void BackendVertexArrayObject::SyncClientSideAttributesForDrawArrays(
|
||||||
|
const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject, GLint first, GLsizei count) {
|
||||||
|
if (!stateVAOObject || count <= 0 || first < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bind();
|
||||||
|
|
||||||
|
const auto& allAttributes = stateVAOObject->GetAllAttributes();
|
||||||
|
for (Uint attribIndex = 0; attribIndex < allAttributes.size(); ++attribIndex) {
|
||||||
|
const auto& attrib = allAttributes[attribIndex];
|
||||||
|
if (!attrib.Enabled || attrib.Buffer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* clientData = reinterpret_cast<const Uint8*>(attrib.Offset);
|
||||||
|
const SizeT componentSize = GetDataTypeSize(attrib.Type);
|
||||||
|
if (!clientData || componentSize == 0 || attrib.Size <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SizeT elementSize = componentSize * static_cast<SizeT>(attrib.Size);
|
||||||
|
const SizeT stride = attrib.Stride > 0 ? static_cast<SizeT>(attrib.Stride) : elementSize;
|
||||||
|
const SizeT uploadSize = static_cast<SizeT>(first + count - 1) * stride + elementSize;
|
||||||
|
|
||||||
|
auto& bufferId = m_clientAttributeBufferIds[attribIndex];
|
||||||
|
if (bufferId == 0) {
|
||||||
|
g_GLESFuncs.glGenBuffers(1, &bufferId);
|
||||||
|
if (bufferId == 0) {
|
||||||
|
MGLOG_E("Failed to create client-side vertex attribute upload buffer.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_GLESFuncs.glBindBuffer(GL_ARRAY_BUFFER, bufferId);
|
||||||
|
g_GLESFuncs.glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(uploadSize), clientData,
|
||||||
|
GL_STREAM_DRAW);
|
||||||
|
|
||||||
|
if (!attrib.IsInteger) {
|
||||||
|
g_GLESFuncs.glVertexAttribPointer(
|
||||||
|
attribIndex, attrib.Size, MG_Util::ConvertDataTypeToGLEnum(attrib.Type),
|
||||||
|
attrib.Normalized ? GL_TRUE : GL_FALSE, static_cast<GLsizei>(stride), nullptr);
|
||||||
|
} else {
|
||||||
|
g_GLESFuncs.glVertexAttribIPointer(attribIndex, attrib.Size,
|
||||||
|
MG_Util::ConvertDataTypeToGLEnum(attrib.Type),
|
||||||
|
static_cast<GLsizei>(stride), nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferImpl::g_boundVertexBufferObject = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
StateBackendObjectRegistry<MG_State::GLState::VertexArrayObject, BackendVertexArrayObject>
|
||||||
g_backendVertexArrayObjects;
|
g_backendVertexArrayObjects;
|
||||||
} // namespace VertexArrayImpl
|
} // namespace VertexArrayImpl
|
||||||
|
|
||||||
@@ -336,7 +488,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_boundTexturesCache[unit][targetN] = this;
|
g_boundTexturesCache[unit][targetN] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint BackendTextureObject::GetBackendTextureId() {
|
Uint BackendTextureObject::GetBackendTextureId() const {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
@@ -344,7 +496,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BackendTextureObject::SyncMipmapsToBackend(
|
void BackendTextureObject::SyncMipmapsToBackend(
|
||||||
SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
|
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
|
||||||
if (!stateTextureObject) {
|
if (!stateTextureObject) {
|
||||||
MGLOG_E("State texture object is null, cannot sync to backend.");
|
MGLOG_E("State texture object is null, cannot sync to backend.");
|
||||||
return;
|
return;
|
||||||
@@ -353,7 +505,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
DebugImpl::ErrorLopper errorLopper;
|
|
||||||
|
|
||||||
MGLOG_D("Syncing texture mipmaps with backend ID %u to backend for state ID %u", m_backendTextureId,
|
MGLOG_D("Syncing texture mipmaps with backend ID %u to backend for state ID %u", m_backendTextureId,
|
||||||
stateTextureObject->GetExternalIndex());
|
stateTextureObject->GetExternalIndex());
|
||||||
@@ -381,7 +532,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Bind(target);
|
Bind(target);
|
||||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||||
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
const auto baseSize = stateTextureObject->GetBaseSize();
|
const auto baseSize = stateTextureObject->GetBaseSize();
|
||||||
@@ -414,7 +565,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
&glFormat, &glType);
|
&glFormat, &glType);
|
||||||
|
|
||||||
const auto& uploadTargets = textureMipmapObject->GetUploadTargets();
|
const auto& uploadTargets = textureMipmapObject->GetUploadTargets();
|
||||||
for (auto uploadTarget : uploadTargets) {
|
for (auto& uploadTarget : uploadTargets) {
|
||||||
for (SizeT level = 0; level < mipmapCount; ++level) {
|
for (SizeT level = 0; level < mipmapCount; ++level) {
|
||||||
auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
|
auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
|
||||||
auto levelByteSize = textureMipmapObject->GetMipmapByteSize(uploadTarget, level);
|
auto levelByteSize = textureMipmapObject->GetMipmapByteSize(uploadTarget, level);
|
||||||
@@ -429,22 +580,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData,
|
levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData,
|
||||||
levelDirty ? "true" : "false");
|
levelDirty ? "true" : "false");
|
||||||
|
|
||||||
errorLopper.Clear();
|
DebugImpl::ErrorLopper::Clear();
|
||||||
g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
auto textureTarget = stateTextureObject->GetTarget();
|
auto textureTarget = stateTextureObject->GetTarget();
|
||||||
// TODO: handle more texture types
|
// TODO: handle more texture types
|
||||||
switch (textureTarget) {
|
switch (textureTarget) {
|
||||||
case TextureTarget::Texture2D:
|
case TextureTarget::Texture2D:
|
||||||
case TextureTarget::TextureCubeMap: {
|
case TextureTarget::TextureCubeMap: {
|
||||||
g_GLESFuncs.glTexImage2D(glUploadTarget, static_cast<GLint>(level), glInternalFormat,
|
g_GLESFuncs.glTexImage2D(
|
||||||
static_cast<GLsizei>(levelTexelSize.x()),
|
glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat,
|
||||||
static_cast<GLsizei>(levelTexelSize.y()), 0, glFormat, glType,
|
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
|
||||||
pData);
|
0, glFormat, glType, pData);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TextureTarget::Texture3D: {
|
case TextureTarget::Texture3D: {
|
||||||
g_GLESFuncs.glTexImage3D(
|
g_GLESFuncs.glTexImage3D(
|
||||||
glUploadTarget, static_cast<GLint>(level), glInternalFormat,
|
glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat,
|
||||||
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
|
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
|
||||||
static_cast<GLsizei>(levelTexelSize.z()), 0, glFormat, glType, pData);
|
static_cast<GLsizei>(levelTexelSize.z()), 0, glFormat, glType, pData);
|
||||||
break;
|
break;
|
||||||
@@ -454,8 +605,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MG_Util::ConvertTextureTargetToString(textureTarget).c_str());
|
MG_Util::ConvertTextureTargetToString(textureTarget).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, glUploadTarget,
|
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__,
|
||||||
glInternalFormat, glFormat, glType, pData](GLenum err) {
|
glUploadTarget, glInternalFormat, glFormat, glType,
|
||||||
|
pData](GLenum err) {
|
||||||
MGLOG_D("%s(%s:%d) ES error: %s. glTexImage*: target=%s, internalformat=%s, format=%s, "
|
MGLOG_D("%s(%s:%d) ES error: %s. glTexImage*: target=%s, internalformat=%s, format=%s, "
|
||||||
"type=%s, pixels=%p",
|
"type=%s, pixels=%p",
|
||||||
func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(),
|
func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(),
|
||||||
@@ -478,7 +630,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat,
|
TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat,
|
||||||
&glFormat, &glType);
|
&glFormat, &glType);
|
||||||
const auto& uploadTargets = textureMipmapObject->GetUploadTargets();
|
const auto& uploadTargets = textureMipmapObject->GetUploadTargets();
|
||||||
for (auto uploadTarget : uploadTargets) {
|
for (auto& uploadTarget : uploadTargets) {
|
||||||
for (SizeT level = 0; level < mipmapCount; ++level) {
|
for (SizeT level = 0; level < mipmapCount; ++level) {
|
||||||
if (!textureMipmapObject->IsStorageDirty(uploadTarget, level)) {
|
if (!textureMipmapObject->IsStorageDirty(uploadTarget, level)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -499,10 +651,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
auto glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget);
|
auto glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget);
|
||||||
g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
DebugImpl::ErrorLopper::Loop(
|
||||||
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line,
|
[file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||||
MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line,
|
||||||
});
|
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()),
|
||||||
@@ -518,22 +671,27 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
auto* textureBufferObject =
|
auto* textureBufferObject =
|
||||||
static_cast<MG_State::GLState::TextureObjectBuffer*>(stateTextureObject.get());
|
static_cast<MG_State::GLState::TextureObjectBuffer*>(stateTextureObject.get());
|
||||||
auto& slot = textureBufferObject->GetBufferBindingSlot();
|
auto& slot = textureBufferObject->GetBufferBindingSlot();
|
||||||
auto buffer = slot.GetBoundObject();
|
auto& buffer = slot.GetBoundObject();
|
||||||
|
if (!buffer) {
|
||||||
|
MGLOG_D("Texture buffer object with ID: %u has no bound buffer, skipping sync.",
|
||||||
|
stateTextureObject->GetExternalIndex());
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto bufferIndex = buffer->GetExternalIndex();
|
auto bufferIndex = buffer->GetExternalIndex();
|
||||||
currentTextureInfo.bufferExternalIndex = bufferIndex;
|
currentTextureInfo.bufferExternalIndex = bufferIndex;
|
||||||
|
|
||||||
Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo);
|
Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo);
|
||||||
MGLOG_D("Texture state changed significantly or not initialized, regenerating texture (tex buffer) "
|
|
||||||
"with ID: %u",
|
|
||||||
m_backendTextureId);
|
|
||||||
|
|
||||||
// Need to sync texture buffer if not synced yet
|
// Need to sync texture buffer if not synced yet
|
||||||
auto& backendBuffers = BufferImpl::g_backendBufferObjects;
|
auto& backendBuffers = BufferImpl::g_backendBufferObjects;
|
||||||
SharedPtr<BufferImpl::BackendBufferObject> backendBufferObject;
|
SharedPtr<BufferImpl::BackendBufferObject> backendBufferObject;
|
||||||
const auto& backendBufferIt = backendBuffers.find(buffer);
|
const auto& backendBufferIt = backendBuffers.find(buffer.get());
|
||||||
if (backendBufferIt == backendBuffers.end()) {
|
if (backendBufferIt == backendBuffers.end()) {
|
||||||
backendBufferObject = MakeShared<BufferImpl::BackendBufferObject>();
|
auto& backendBufferSlot = backendBuffers.GetOrCreate(buffer);
|
||||||
backendBuffers[buffer] = backendBufferObject;
|
if (!backendBufferSlot) {
|
||||||
|
backendBufferSlot = MakeShared<BufferImpl::BackendBufferObject>();
|
||||||
|
}
|
||||||
|
backendBufferObject = backendBufferSlot;
|
||||||
} else {
|
} else {
|
||||||
backendBufferObject = backendBufferIt->second;
|
backendBufferObject = backendBufferIt->second;
|
||||||
}
|
}
|
||||||
@@ -546,14 +704,26 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
TextureImpl::GenerateTextureFormatInfo(textureBufferObject->GetFormat(), &glInternalFormat, &glFormat,
|
TextureImpl::GenerateTextureFormatInfo(textureBufferObject->GetFormat(), &glInternalFormat, &glFormat,
|
||||||
&glType);
|
&glType);
|
||||||
|
|
||||||
g_GLESFuncs.glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId);
|
if (needsRegeneration) {
|
||||||
|
MGLOG_D("Texture state changed significantly or not initialized, regenerating texture buffer with "
|
||||||
|
"ID: %u, buffer ID: %u, buffer size: %zu, format: %s",
|
||||||
|
m_backendTextureId, backendId, buffer->GetSize(),
|
||||||
|
MG_Util::ConvertGLEnumToString(glInternalFormat).c_str());
|
||||||
|
g_GLESFuncs.glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId);
|
||||||
|
DebugImpl::ErrorLopper::Loop(
|
||||||
|
[file = __FILE__, line = __LINE__, func = __func__, glInternalFormat, backendId](GLenum err) {
|
||||||
|
MGLOG_D("%s(%s:%d) glTexBuffer(format=%s, buffer=%u) ES error: %s",
|
||||||
|
func, file, line, MG_Util::ConvertGLEnumToString(glInternalFormat).c_str(),
|
||||||
|
backendId, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
|
});
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
THROW_UNIMPL_EXCEPTION;
|
THROW_UNIMPL_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||||
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -561,11 +731,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BackendTextureObject::SyncBuiltinSamplerToBackend(
|
void BackendTextureObject::SyncBuiltinSamplerToBackend(
|
||||||
SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
|
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
DebugImpl::ErrorLopper errorLopper;
|
|
||||||
if (!stateTextureObject) {
|
if (!stateTextureObject) {
|
||||||
MGLOG_E("State texture object is null, cannot sync to backend.");
|
MGLOG_E("State texture object is null, cannot sync to backend.");
|
||||||
return;
|
return;
|
||||||
@@ -594,7 +764,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Bind(target);
|
Bind(target);
|
||||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||||
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -607,34 +777,39 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_GLESFuncs.glTexParameteri(target, glName, \
|
g_GLESFuncs.glTexParameteri(target, glName, \
|
||||||
MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)); \
|
MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)); \
|
||||||
m_cacheSamplerParameters.internalName = samplerParams.internalName; \
|
m_cacheSamplerParameters.internalName = samplerParams.internalName; \
|
||||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, \
|
DebugImpl::ErrorLopper::Loop( \
|
||||||
t = MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)](GLenum err) { \
|
[file = __FILE__, line = __LINE__, func = __func__, \
|
||||||
MGLOG_D("%s(%s:%d) ES error %s, GL_TEXTURE_MIN_FILTER = %s", func, file, line, \
|
t = MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)](GLenum err) { \
|
||||||
MG_Util::ConvertGLEnumToString(err).c_str(), MG_Util::ConvertGLEnumToString(t).c_str()); \
|
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()); \
|
||||||
|
}); \
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_cacheSamplerParameters.minFilter != samplerParams.minFilter ||
|
if (m_cacheSamplerParameters.minFilter != samplerParams.minFilter ||
|
||||||
m_cacheSamplerParameters.mipmapMode != samplerParams.mipmapMode) {
|
m_cacheSamplerParameters.mipmapMode != samplerParams.mipmapMode) {
|
||||||
g_GLESFuncs.glTexParameteri(
|
g_GLESFuncs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER,
|
||||||
target, GL_TEXTURE_MIN_FILTER,
|
(GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.minFilter,
|
||||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.minFilter, samplerParams.mipmapMode));
|
samplerParams.mipmapMode));
|
||||||
m_cacheSamplerParameters.minFilter = samplerParams.minFilter;
|
m_cacheSamplerParameters.minFilter = samplerParams.minFilter;
|
||||||
m_cacheSamplerParameters.mipmapMode = samplerParams.mipmapMode;
|
m_cacheSamplerParameters.mipmapMode = samplerParams.mipmapMode;
|
||||||
}
|
}
|
||||||
if (m_cacheSamplerParameters.magFilter != samplerParams.magFilter) {
|
if (m_cacheSamplerParameters.magFilter != samplerParams.magFilter) {
|
||||||
g_GLESFuncs.glTexParameteri(
|
g_GLESFuncs.glTexParameteri(
|
||||||
target, GL_TEXTURE_MAG_FILTER,
|
target, GL_TEXTURE_MAG_FILTER,
|
||||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None));
|
(GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None));
|
||||||
m_cacheSamplerParameters.magFilter = samplerParams.magFilter;
|
m_cacheSamplerParameters.magFilter = samplerParams.magFilter;
|
||||||
}
|
}
|
||||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||||
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
|
|
||||||
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapS, GL_TEXTURE_WRAP_S, WrapMode)
|
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapS, GL_TEXTURE_WRAP_S, WrapMode)
|
||||||
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapT, GL_TEXTURE_WRAP_T, WrapMode)
|
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapT, GL_TEXTURE_WRAP_T, WrapMode)
|
||||||
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapR, GL_TEXTURE_WRAP_R, WrapMode)
|
if (SupportsWrapR(targetInternal)) {
|
||||||
|
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapR, GL_TEXTURE_WRAP_R, WrapMode)
|
||||||
|
} else {
|
||||||
|
m_cacheSamplerParameters.wrapR = samplerParams.wrapR;
|
||||||
|
}
|
||||||
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareFunc, GL_TEXTURE_COMPARE_FUNC, CompareFunc)
|
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareFunc, GL_TEXTURE_COMPARE_FUNC, CompareFunc)
|
||||||
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareMode, GL_TEXTURE_COMPARE_MODE, CompareMode)
|
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareMode, GL_TEXTURE_COMPARE_MODE, CompareMode)
|
||||||
if (m_cacheSamplerParameters.minLod != samplerParams.minLod) {
|
if (m_cacheSamplerParameters.minLod != samplerParams.minLod) {
|
||||||
@@ -645,18 +820,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_GLESFuncs.glTexParameterf(target, GL_TEXTURE_MAX_LOD, samplerParams.maxLod);
|
g_GLESFuncs.glTexParameterf(target, GL_TEXTURE_MAX_LOD, samplerParams.maxLod);
|
||||||
m_cacheSamplerParameters.maxLod = samplerParams.maxLod;
|
m_cacheSamplerParameters.maxLod = samplerParams.maxLod;
|
||||||
}
|
}
|
||||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||||
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
#undef SYNC_TEX_SAMPLER_PARAM_IF_CHANGED
|
#undef SYNC_TEX_SAMPLER_PARAM_IF_CHANGED
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendTextureObject::SyncTextureParamsToBackend(
|
void BackendTextureObject::SyncTextureParamsToBackend(
|
||||||
SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
|
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
DebugImpl::ErrorLopper errorLopper;
|
|
||||||
if (!stateTextureObject) {
|
if (!stateTextureObject) {
|
||||||
MGLOG_E("State texture object is null, cannot sync to backend.");
|
MGLOG_E("State texture object is null, cannot sync to backend.");
|
||||||
return;
|
return;
|
||||||
@@ -683,7 +858,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Bind(target);
|
Bind(target);
|
||||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||||
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -696,14 +871,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_GLESFuncs.glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, static_cast<GLint>(levelRange.x()));
|
g_GLESFuncs.glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, static_cast<GLint>(levelRange.x()));
|
||||||
m_cacheLodRange.x() = levelRange.x();
|
m_cacheLodRange.x() = levelRange.x();
|
||||||
}
|
}
|
||||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||||
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
if (m_cacheLodRange.y() != levelRange.y()) {
|
if (m_cacheLodRange.y() != levelRange.y()) {
|
||||||
g_GLESFuncs.glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(levelRange.y()));
|
g_GLESFuncs.glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(levelRange.y()));
|
||||||
m_cacheLodRange.y() = levelRange.y();
|
m_cacheLodRange.y() = levelRange.y();
|
||||||
}
|
}
|
||||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||||
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -720,7 +895,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
SYNC_TEX_SWIZZLE_PARAM_IF_CHANGED(a(), GL_TEXTURE_SWIZZLE_A);
|
SYNC_TEX_SWIZZLE_PARAM_IF_CHANGED(a(), GL_TEXTURE_SWIZZLE_A);
|
||||||
#undef SYNC_TEX_SWIZZLE_PARAM_IF_CHANGED
|
#undef SYNC_TEX_SWIZZLE_PARAM_IF_CHANGED
|
||||||
m_cacheSwizzleParams = swizzleParams;
|
m_cacheSwizzleParams = swizzleParams;
|
||||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||||
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -730,7 +905,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
GLfloat borderColorArray[4] = {borderColor.x(), borderColor.y(), borderColor.z(), borderColor.w()};
|
GLfloat borderColorArray[4] = {borderColor.x(), borderColor.y(), borderColor.z(), borderColor.w()};
|
||||||
g_GLESFuncs.glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, borderColorArray);
|
g_GLESFuncs.glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, borderColorArray);
|
||||||
m_cacheBorderColor = borderColor;
|
m_cacheBorderColor = borderColor;
|
||||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||||
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -760,8 +935,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
|
Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
|
||||||
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
|
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
|
||||||
g_boundTexturesCache;
|
g_boundTexturesCache;
|
||||||
UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>>
|
StateBackendObjectRegistry<MG_State::GLState::ITextureObject, BackendTextureObject> g_backendTextureObjects;
|
||||||
g_backendTextureObjects;
|
|
||||||
} // namespace TextureImpl
|
} // namespace TextureImpl
|
||||||
|
|
||||||
namespace FramebufferImpl {
|
namespace FramebufferImpl {
|
||||||
@@ -778,7 +952,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendFramebufferObject::Bind(FramebufferTarget target) {
|
void BackendFramebufferObject::Bind(FramebufferTarget target) const {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
@@ -788,17 +962,37 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId);
|
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool BackendFramebufferObject::SyncAttachmentObject(
|
void BackendFramebufferObject::InvalidateSyncedState() {
|
||||||
GLenum glFBOTarget, const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
|
std::fill(std::begin(m_frontendDrawBuffers), std::end(m_frontendDrawBuffers),
|
||||||
GLenum glBackendAttachment) {
|
FramebufferAttachmentType::Unknown);
|
||||||
|
std::fill(std::begin(m_backendDrawBuffers), std::end(m_backendDrawBuffers), GL_NONE);
|
||||||
|
m_frontendReadBuffer = FramebufferAttachmentType::Unknown;
|
||||||
|
m_backendReadBuffer = GL_NONE;
|
||||||
|
std::fill(m_syncedFrontendAttachmentVersions.begin(), m_syncedFrontendAttachmentVersions.end(),
|
||||||
|
static_cast<Uint16>(~0u));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool SyncAttachmentObject(GLenum glFBOTarget,
|
||||||
|
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
|
||||||
|
GLenum glBackendAttachment) {
|
||||||
if (attachmentObject.IsTexture()) {
|
if (attachmentObject.IsTexture()) {
|
||||||
const auto& textureObject = attachmentObject.GetTexture();
|
const auto& textureObject = attachmentObject.GetTexture();
|
||||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
SharedPtr<TextureImpl::BackendTextureObject> backendTextureObject;
|
||||||
|
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
||||||
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
||||||
|
auto& backendTextureSlot = TextureImpl::g_backendTextureObjects.GetOrCreate(textureObject);
|
||||||
|
if (!backendTextureSlot) {
|
||||||
|
backendTextureSlot = MakeShared<TextureImpl::BackendTextureObject>();
|
||||||
|
}
|
||||||
|
backendTextureObject = backendTextureSlot;
|
||||||
|
} else {
|
||||||
|
backendTextureObject = backendTextureIt->second;
|
||||||
|
}
|
||||||
|
if (!backendTextureObject) {
|
||||||
MGLOG_E("%s: No backend texture found for FBO attachment, cannot bind texture.", __func__);
|
MGLOG_E("%s: No backend texture found for FBO attachment, cannot bind texture.", __func__);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto& backendTextureObject = backendTextureIt->second;
|
backendTextureObject->SyncMipmapsToBackend(textureObject);
|
||||||
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
|
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
|
||||||
backendTextureObject->Bind(glTextureTarget);
|
backendTextureObject->Bind(glTextureTarget);
|
||||||
g_GLESFuncs.glFramebufferTexture2D(glFBOTarget, glBackendAttachment, glTextureTarget,
|
g_GLESFuncs.glFramebufferTexture2D(glFBOTarget, glBackendAttachment, glTextureTarget,
|
||||||
@@ -807,11 +1001,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
} else if (attachmentObject.IsRenderbuffer()) {
|
} else if (attachmentObject.IsRenderbuffer()) {
|
||||||
const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
|
const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
|
||||||
const auto& backendRenderbufferIt =
|
const auto& backendRenderbufferIt =
|
||||||
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
|
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject.get());
|
||||||
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
|
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
|
||||||
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
|
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
|
||||||
backendRenderbufferObject = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
|
auto& backendRenderbufferSlot =
|
||||||
RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject;
|
RenderbufferImpl::g_backendRenderbufferObjects.GetOrCreate(renderbufferObject);
|
||||||
|
if (!backendRenderbufferSlot) {
|
||||||
|
backendRenderbufferSlot = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
|
||||||
|
}
|
||||||
|
backendRenderbufferObject = backendRenderbufferSlot;
|
||||||
} else {
|
} else {
|
||||||
backendRenderbufferObject = backendRenderbufferIt->second;
|
backendRenderbufferObject = backendRenderbufferIt->second;
|
||||||
}
|
}
|
||||||
@@ -824,8 +1022,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendFramebufferObject::SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
|
void BackendFramebufferObject::SyncToBackend(
|
||||||
FramebufferTarget asTarget) {
|
const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, FramebufferTarget asTarget) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
@@ -853,7 +1051,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
std::fill(m_backendDrawBuffers, m_backendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE);
|
std::fill(m_backendDrawBuffers, m_backendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE);
|
||||||
int nEffectiveBuffers = 0;
|
int nEffectiveBuffers = 0;
|
||||||
for (GLint i = 0; i < FramebufferObject::MAX_DRAW_BUFFERS; ++i) {
|
for (GLint i = 0; i < FramebufferObject::MAX_DRAW_BUFFERS; ++i) {
|
||||||
auto frontendBuf = stateDrawBuffers[i];
|
auto& frontendBuf = stateDrawBuffers[i];
|
||||||
if (frontendBuf == FramebufferAttachmentType::None) {
|
if (frontendBuf == FramebufferAttachmentType::None) {
|
||||||
m_backendDrawBuffers[i] = GL_NONE;
|
m_backendDrawBuffers[i] = GL_NONE;
|
||||||
continue;
|
continue;
|
||||||
@@ -892,7 +1090,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
const auto& attachmentVersions = stateFBOObject->GetAllFramebufferAttachmentVersions();
|
const auto& attachmentVersions = stateFBOObject->GetAllFramebufferAttachmentVersions();
|
||||||
for (SizeT i = 0; i < attachments.size(); ++i) {
|
for (SizeT i = 0; i < attachments.size(); ++i) {
|
||||||
const auto& attachmentObject = attachments[i];
|
const auto& attachmentObject = attachments[i];
|
||||||
FramebufferAttachmentType frontendType = static_cast<FramebufferAttachmentType>(i);
|
auto frontendType = static_cast<FramebufferAttachmentType>(i);
|
||||||
GLenum glBackendAttachment = GL_NONE;
|
GLenum glBackendAttachment = GL_NONE;
|
||||||
if (frontendType >= FramebufferAttachmentType::Color0 &&
|
if (frontendType >= FramebufferAttachmentType::Color0 &&
|
||||||
frontendType <= FramebufferAttachmentType::Color31)
|
frontendType <= FramebufferAttachmentType::Color31)
|
||||||
@@ -902,8 +1100,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// relevant FRONTEND!!! version should be checked and updated
|
// relevant FRONTEND!!! version should be checked and updated
|
||||||
if (m_syncedFrontendAttachmentVersions[i] != attachmentVersions[i]) {
|
if (m_syncedFrontendAttachmentVersions[i] != attachmentVersions[i]) {
|
||||||
SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment);
|
if (SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment)) {
|
||||||
m_syncedFrontendAttachmentVersions[i] = attachmentVersions[i];
|
m_syncedFrontendAttachmentVersions[i] = attachmentVersions[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||||
else {
|
else {
|
||||||
@@ -915,6 +1114,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MG_Util::ConvertFramebufferAttachmentTypeToString(frontendType).c_str(),
|
MG_Util::ConvertFramebufferAttachmentTypeToString(frontendType).c_str(),
|
||||||
MG_Util::ConvertGLEnumToString(glBackendAttachment).c_str(),
|
MG_Util::ConvertGLEnumToString(glBackendAttachment).c_str(),
|
||||||
m_syncedFrontendAttachmentVersions[i]);
|
m_syncedFrontendAttachmentVersions[i]);
|
||||||
|
if (!attachmentObject.IsTexture() && !attachmentObject.IsRenderbuffer()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
GLint objectType = GL_NONE;
|
GLint objectType = GL_NONE;
|
||||||
g_GLESFuncs.glGetFramebufferAttachmentParameteriv(
|
g_GLESFuncs.glGetFramebufferAttachmentParameteriv(
|
||||||
glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &objectType);
|
glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &objectType);
|
||||||
@@ -928,7 +1130,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// Verify that the backend object's name and parameters match the frontend attachment state
|
// Verify that the backend object's name and parameters match the frontend attachment state
|
||||||
if (attachmentObject.IsTexture()) {
|
if (attachmentObject.IsTexture()) {
|
||||||
const auto& textureObject = attachmentObject.GetTexture();
|
const auto& textureObject = attachmentObject.GetTexture();
|
||||||
auto backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
auto backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
||||||
MOBILEGL_ASSERT(backendTextureIt != TextureImpl::g_backendTextureObjects.end(),
|
MOBILEGL_ASSERT(backendTextureIt != TextureImpl::g_backendTextureObjects.end(),
|
||||||
"No backend texture found while framebuffer reports texture attachment.");
|
"No backend texture found while framebuffer reports texture attachment.");
|
||||||
GLuint backendTexId = backendTextureIt->second->GetBackendTextureId();
|
GLuint backendTexId = backendTextureIt->second->GetBackendTextureId();
|
||||||
@@ -944,7 +1146,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
"Attachment texture level mismatch between GLES and state object.");
|
"Attachment texture level mismatch between GLES and state object.");
|
||||||
} else if (attachmentObject.IsRenderbuffer()) {
|
} else if (attachmentObject.IsRenderbuffer()) {
|
||||||
const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
|
const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
|
||||||
auto backendRboIt = RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
|
auto backendRboIt =
|
||||||
|
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject.get());
|
||||||
MOBILEGL_ASSERT(
|
MOBILEGL_ASSERT(
|
||||||
backendRboIt != RenderbufferImpl::g_backendRenderbufferObjects.end(),
|
backendRboIt != RenderbufferImpl::g_backendRenderbufferObjects.end(),
|
||||||
"No backend renderbuffer found while framebuffer reports renderbuffer attachment.");
|
"No backend renderbuffer found while framebuffer reports renderbuffer attachment.");
|
||||||
@@ -975,14 +1178,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return glBackendReadBuffer;
|
return glBackendReadBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>>
|
StateBackendObjectRegistry<MG_State::GLState::FramebufferObject, BackendFramebufferObject>
|
||||||
g_backendFramebufferObjects;
|
g_backendFramebufferObjects;
|
||||||
Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions = {0};
|
Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions = {0};
|
||||||
} // namespace FramebufferImpl
|
} // namespace FramebufferImpl
|
||||||
|
|
||||||
namespace PrgramImpl {
|
namespace PrgramImpl {
|
||||||
UnorderedMap<SharedPtr<MG_State::GLState::ProgramObject>, SharedPtr<BackendProgramObjectImpl>>
|
StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl> g_backendProgramObjects;
|
||||||
g_backendProgramObjects;
|
|
||||||
|
|
||||||
BackendProgramObjectImpl::BackendProgramObjectImpl() {
|
BackendProgramObjectImpl::BackendProgramObjectImpl() {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
@@ -1008,7 +1210,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendProgramObjectImpl::SyncToBackend(SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject) {
|
void BackendProgramObjectImpl::SyncToBackend(
|
||||||
|
const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
@@ -1068,13 +1271,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
String source;
|
String source;
|
||||||
auto& spirvCode = shaderSpirvs[index];
|
auto& spirvCode = shaderSpirvs[index];
|
||||||
|
|
||||||
MG_Util::ShaderTranspiler::SpvcSession spvcSession(spirvCode);
|
MG_Util::ShaderTranspiler::SpvcSession spvcSession(spirvCode,
|
||||||
|
MG_Util::ShaderTranspiler::SessionUsageBit::Transpile);
|
||||||
|
|
||||||
spvc_compiler_options options;
|
spvc_compiler_options options;
|
||||||
spvcSession.CreateOptions(&options);
|
spvcSession.CreateOptions(&options);
|
||||||
|
|
||||||
// TODO: check ESSL version supported by backend driver
|
spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION,
|
||||||
spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, 320);
|
ResolveBackendEsslVersion());
|
||||||
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_TRUE);
|
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_TRUE);
|
||||||
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, SPVC_FALSE);
|
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, SPVC_FALSE);
|
||||||
|
|
||||||
@@ -1096,6 +1300,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
source = RemoveLayoutBinding(source);
|
source = RemoveLayoutBinding(source);
|
||||||
source = ProcessOutColorLocations(source);
|
source = ProcessOutColorLocations(source);
|
||||||
|
source = ForceFlatIntegerVaryings(source, glShaderType);
|
||||||
|
source = EmulateBaseInstanceInVertexShader(std::move(source), glShaderType);
|
||||||
source = ForceSupporterOutput(source);
|
source = ForceSupporterOutput(source);
|
||||||
|
|
||||||
// Patch for Photon compiler precision issue
|
// Patch for Photon compiler precision issue
|
||||||
@@ -1146,6 +1352,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
} else {
|
} else {
|
||||||
MGLOG_D("Program linked successfully. ID: %u", m_backendProgramId);
|
MGLOG_D("Program linked successfully. ID: %u", m_backendProgramId);
|
||||||
}
|
}
|
||||||
|
m_baseInstanceUniformLocation = g_GLESFuncs.glGetUniformLocation(m_backendProgramId,
|
||||||
|
BASE_INSTANCE_UNIFORM_NAME);
|
||||||
|
|
||||||
// Create global UBO
|
// Create global UBO
|
||||||
if (stateProgramObject->GetUBOSize() > 0) {
|
if (stateProgramObject->GetUBOSize() > 0) {
|
||||||
@@ -1161,13 +1369,20 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MGLOG_D("Program sync completed. backend ID %u", m_backendProgramId);
|
MGLOG_D("Program sync completed. backend ID %u", m_backendProgramId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendProgramObjectImpl::Use() {
|
void BackendProgramObjectImpl::Use() const {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
MGLOG_D("Using program %u", m_backendProgramId);
|
MGLOG_D("Using program %u", m_backendProgramId);
|
||||||
g_GLESFuncs.glUseProgram(m_backendProgramId);
|
g_GLESFuncs.glUseProgram(m_backendProgramId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BackendProgramObjectImpl::SetBaseInstance(Uint32 baseInstance) const {
|
||||||
|
if (m_baseInstanceUniformLocation < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g_GLESFuncs.glUniform1i(m_baseInstanceUniformLocation, static_cast<GLint>(baseInstance));
|
||||||
|
}
|
||||||
} // namespace PrgramImpl
|
} // namespace PrgramImpl
|
||||||
|
|
||||||
namespace SamplerImpl {
|
namespace SamplerImpl {
|
||||||
@@ -1184,7 +1399,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendSamplerObject::SyncToBackend(SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject) {
|
void BackendSamplerObject::SyncToBackend(
|
||||||
|
const SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
@@ -1210,22 +1426,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
#define SYNC_SAMPLER_PARAM_IF_CHANGED(internalName, glName, type) \
|
#define SYNC_SAMPLER_PARAM_IF_CHANGED(internalName, glName, type) \
|
||||||
if (m_cacheSamplerParameters.internalName != samplerParams.internalName) { \
|
if (m_cacheSamplerParameters.internalName != samplerParams.internalName) { \
|
||||||
g_GLESFuncs.glSamplerParameteri(m_backendSamplerId, glName, \
|
g_GLESFuncs.glSamplerParameteri(m_backendSamplerId, glName, \
|
||||||
MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)); \
|
(GLint)MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)); \
|
||||||
m_cacheSamplerParameters.internalName = samplerParams.internalName; \
|
m_cacheSamplerParameters.internalName = samplerParams.internalName; \
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_cacheSamplerParameters.minFilter != samplerParams.minFilter ||
|
if (m_cacheSamplerParameters.minFilter != samplerParams.minFilter ||
|
||||||
m_cacheSamplerParameters.mipmapMode != samplerParams.mipmapMode) {
|
m_cacheSamplerParameters.mipmapMode != samplerParams.mipmapMode) {
|
||||||
g_GLESFuncs.glSamplerParameteri(
|
g_GLESFuncs.glSamplerParameteri(m_backendSamplerId, GL_TEXTURE_MIN_FILTER,
|
||||||
m_backendSamplerId, GL_TEXTURE_MIN_FILTER,
|
(GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(
|
||||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.minFilter, samplerParams.mipmapMode));
|
samplerParams.minFilter, samplerParams.mipmapMode));
|
||||||
m_cacheSamplerParameters.minFilter = samplerParams.minFilter;
|
m_cacheSamplerParameters.minFilter = samplerParams.minFilter;
|
||||||
m_cacheSamplerParameters.mipmapMode = samplerParams.mipmapMode;
|
m_cacheSamplerParameters.mipmapMode = samplerParams.mipmapMode;
|
||||||
}
|
}
|
||||||
if (m_cacheSamplerParameters.magFilter != samplerParams.magFilter) {
|
if (m_cacheSamplerParameters.magFilter != samplerParams.magFilter) {
|
||||||
g_GLESFuncs.glSamplerParameteri(
|
g_GLESFuncs.glSamplerParameteri(
|
||||||
m_backendSamplerId, GL_TEXTURE_MAG_FILTER,
|
m_backendSamplerId, GL_TEXTURE_MAG_FILTER,
|
||||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None));
|
(GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None));
|
||||||
m_cacheSamplerParameters.magFilter = samplerParams.magFilter;
|
m_cacheSamplerParameters.magFilter = samplerParams.magFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1256,7 +1472,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_boundSamplersCache[unit] = this;
|
g_boundSamplersCache[unit] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint BackendSamplerObject::GetBackendSamplerId() {
|
Uint BackendSamplerObject::GetBackendSamplerId() const {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
@@ -1271,8 +1487,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS> g_boundSamplersCache;
|
Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS> g_boundSamplersCache;
|
||||||
UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>>
|
StateBackendObjectRegistry<MG_State::GLState::SamplerObject, BackendSamplerObject> g_backendSamplerObjects;
|
||||||
g_backendSamplerObjects;
|
|
||||||
} // namespace SamplerImpl
|
} // namespace SamplerImpl
|
||||||
|
|
||||||
namespace RenderbufferImpl {
|
namespace RenderbufferImpl {
|
||||||
@@ -1287,7 +1502,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendRenderbufferObject::Bind() {
|
void BackendRenderbufferObject::Bind() const {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
@@ -1334,9 +1549,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MGLOG_D("RBO %u sync completed. backend ID %u", stateRBOObject->GetExternalIndex(), m_backendRBOId);
|
MGLOG_D("RBO %u sync completed. backend ID %u", stateRBOObject->GetExternalIndex(), m_backendRBOId);
|
||||||
}
|
}
|
||||||
|
|
||||||
UnorderedMap<SharedPtr<MG_State::GLState::RenderbufferObject>, SharedPtr<BackendRenderbufferObject>>
|
StateBackendObjectRegistry<MG_State::GLState::RenderbufferObject, BackendRenderbufferObject>
|
||||||
g_backendRenderbufferObjects;
|
g_backendRenderbufferObjects;
|
||||||
} // namespace RenderbufferImpl
|
} // namespace RenderbufferImpl
|
||||||
|
|
||||||
namespace Utils {} // namespace Utils
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectGLES
|
} // namespace MobileGL::MG_Backend::DirectGLES
|
||||||
|
|||||||
@@ -15,19 +15,115 @@
|
|||||||
#include <MG_State/GLState/Core.h>
|
#include <MG_State/GLState/Core.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectGLES {
|
namespace MobileGL::MG_Backend::DirectGLES {
|
||||||
|
String EmulateBaseInstanceInVertexShader(String source, GLenum shaderType);
|
||||||
|
|
||||||
|
template <typename StateObject, typename BackendObject>
|
||||||
|
class StateBackendObjectRegistry {
|
||||||
|
public:
|
||||||
|
using StatePtr = SharedPtr<StateObject>;
|
||||||
|
using StateWeakPtr = std::weak_ptr<StateObject>;
|
||||||
|
using BackendPtr = SharedPtr<BackendObject>;
|
||||||
|
using BackendMap = UnorderedMap<StateObject*, BackendPtr>;
|
||||||
|
using StateRefMap = UnorderedMap<StateObject*, StateWeakPtr>;
|
||||||
|
using iterator = typename BackendMap::iterator;
|
||||||
|
using const_iterator = typename BackendMap::const_iterator;
|
||||||
|
|
||||||
|
BackendPtr& GetOrCreate(const StatePtr& stateObj) {
|
||||||
|
MOBILEGL_ASSERT(stateObj != nullptr, "State object must not be null");
|
||||||
|
|
||||||
|
auto* key = stateObj.get();
|
||||||
|
auto trackedStateIt = m_stateRefs.find(key);
|
||||||
|
if (trackedStateIt != m_stateRefs.end() && trackedStateIt->second.expired()) {
|
||||||
|
EraseByKey(key);
|
||||||
|
}
|
||||||
|
m_stateRefs[key] = stateObj;
|
||||||
|
return m_backendObjects[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator find(StateObject* stateObj) {
|
||||||
|
if (!IsAlive(stateObj)) {
|
||||||
|
EraseByKey(stateObj);
|
||||||
|
return m_backendObjects.end();
|
||||||
|
}
|
||||||
|
return m_backendObjects.find(stateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator find(StateObject* stateObj) const {
|
||||||
|
return const_cast<StateBackendObjectRegistry*>(this)->find(stateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end() { return m_backendObjects.end(); }
|
||||||
|
const_iterator end() const { return m_backendObjects.end(); }
|
||||||
|
|
||||||
|
void CollectGarbageIfNeeded() {
|
||||||
|
++m_gcTick;
|
||||||
|
if (m_gcTick < kGCInterval) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CollectGarbage();
|
||||||
|
m_gcTick = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectGarbageNow() { CollectGarbage(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool IsAlive(StateObject* stateObj) const {
|
||||||
|
const auto trackedStateIt = m_stateRefs.find(stateObj);
|
||||||
|
if (trackedStateIt == m_stateRefs.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !trackedStateIt->second.expired();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EraseByKey(StateObject* stateObj) {
|
||||||
|
m_stateRefs.erase(stateObj);
|
||||||
|
m_backendObjects.erase(stateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectGarbage() {
|
||||||
|
if (m_isCollecting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_isCollecting = true;
|
||||||
|
|
||||||
|
Vector<StateObject*> staleKeys;
|
||||||
|
staleKeys.reserve(m_stateRefs.size());
|
||||||
|
for (const auto& [stateKey, stateWeakRef] : m_stateRefs) {
|
||||||
|
if (stateWeakRef.expired()) {
|
||||||
|
staleKeys.push_back(stateKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto* stateKey : staleKeys) {
|
||||||
|
m_stateRefs.erase(stateKey);
|
||||||
|
m_backendObjects.erase(stateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_isCollecting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr Uint32 kGCInterval = 1024;
|
||||||
|
StateRefMap m_stateRefs;
|
||||||
|
BackendMap m_backendObjects;
|
||||||
|
Uint32 m_gcTick = 0;
|
||||||
|
Bool m_isCollecting = false;
|
||||||
|
};
|
||||||
|
|
||||||
namespace BufferImpl {
|
namespace BufferImpl {
|
||||||
const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
|
const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
|
||||||
class BackendBufferObject {
|
class BackendBufferObject {
|
||||||
public:
|
public:
|
||||||
BackendBufferObject();
|
BackendBufferObject();
|
||||||
void SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
void SyncToBackend(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||||
Uint GetBackendBufferId() { return m_backendBufferId; }
|
Uint GetBackendBufferId() const { return m_backendBufferId; }
|
||||||
void Bind(GLenum target = TempBufferTarget);
|
void Bind(GLenum target = TempBufferTarget);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SyncToBackend_glBufferData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
void SyncToBackend_glBufferData(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||||
void SyncToBackend_glBufferSubData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
void SyncToBackend_glBufferSubData(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||||
void SyncToBackend_glMapBufferRange(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject,
|
void SyncToBackend_glMapBufferRange(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject,
|
||||||
Bool invalidate = true, Bool unsynchronized = true);
|
Bool invalidate = true, Bool unsynchronized = true);
|
||||||
|
|
||||||
Uint m_backendBufferId = 0;
|
Uint m_backendBufferId = 0;
|
||||||
@@ -36,29 +132,30 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern BackendBufferObject* g_boundVertexBufferObject;
|
extern BackendBufferObject* g_boundVertexBufferObject;
|
||||||
extern UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>>
|
extern StateBackendObjectRegistry<MG_State::GLState::BufferObject, BackendBufferObject> g_backendBufferObjects;
|
||||||
g_backendBufferObjects;
|
|
||||||
} // namespace BufferImpl
|
} // namespace BufferImpl
|
||||||
|
|
||||||
namespace VertexArrayImpl {
|
namespace VertexArrayImpl {
|
||||||
class BackendVertexArrayObject {
|
class BackendVertexArrayObject {
|
||||||
public:
|
public:
|
||||||
BackendVertexArrayObject();
|
BackendVertexArrayObject();
|
||||||
void SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
|
~BackendVertexArrayObject();
|
||||||
Uint GetBackendVertexArrayId() { return m_backendVAOId; }
|
void SyncToBackend(const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
|
||||||
void Bind();
|
void SyncClientSideAttributesForDrawArrays(
|
||||||
|
const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject, GLint first, GLsizei count);
|
||||||
|
Uint GetBackendVertexArrayId() const { return m_backendVAOId; }
|
||||||
|
void Bind() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void BindAttributeBuffer(Uint index, const MG_State::GLState::VertexAttribute& attrib);
|
|
||||||
|
|
||||||
Uint m_backendVAOId = 0;
|
Uint m_backendVAOId = 0;
|
||||||
|
Array<Uint, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS> m_clientAttributeBufferIds;
|
||||||
Bool m_isInitialized = false;
|
Bool m_isInitialized = false;
|
||||||
Uint16 m_syncedIndexBufferVersion = 0;
|
Uint16 m_syncedIndexBufferVersion = 0;
|
||||||
Array<MG_State::GLState::VertexAttributeVersion, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS>
|
Array<MG_State::GLState::VertexAttributeVersion, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS>
|
||||||
m_syncedAttributeVersions;
|
m_syncedAttributeVersions;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>>
|
extern StateBackendObjectRegistry<MG_State::GLState::VertexArrayObject, BackendVertexArrayObject>
|
||||||
g_backendVertexArrayObjects;
|
g_backendVertexArrayObjects;
|
||||||
} // namespace VertexArrayImpl
|
} // namespace VertexArrayImpl
|
||||||
|
|
||||||
@@ -71,6 +168,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Bool SupportsWrapR(TextureTarget target) {
|
||||||
|
return target == TextureTarget::Texture3D || target == TextureTarget::TextureCubeMap;
|
||||||
|
}
|
||||||
|
|
||||||
struct StateTextureBasicInfo { // Used for tracking texture state changes
|
struct StateTextureBasicInfo { // Used for tracking texture state changes
|
||||||
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
|
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
|
||||||
SizeT width = 0;
|
SizeT width = 0;
|
||||||
@@ -92,11 +193,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
class BackendTextureObject {
|
class BackendTextureObject {
|
||||||
public:
|
public:
|
||||||
BackendTextureObject();
|
BackendTextureObject();
|
||||||
void SyncMipmapsToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
void SyncMipmapsToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||||
void SyncBuiltinSamplerToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
void SyncBuiltinSamplerToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||||
void SyncTextureParamsToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
void SyncTextureParamsToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||||
void Bind(GLenum target, Uint unit = TempTextureUnit);
|
void Bind(GLenum target, Uint unit = TempTextureUnit);
|
||||||
Uint GetBackendTextureId();
|
Uint GetBackendTextureId() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Uint m_backendTextureId = 0;
|
Uint m_backendTextureId = 0;
|
||||||
@@ -113,7 +214,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
void ActivateTextureUnit(Uint unit);
|
void ActivateTextureUnit(Uint unit);
|
||||||
void UnbindTexture(Uint unit, GLenum target);
|
void UnbindTexture(Uint unit, GLenum target);
|
||||||
extern UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>>
|
extern StateBackendObjectRegistry<MG_State::GLState::ITextureObject, BackendTextureObject>
|
||||||
g_backendTextureObjects;
|
g_backendTextureObjects;
|
||||||
extern Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
|
extern Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
|
||||||
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
|
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
|
||||||
@@ -125,13 +226,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
class BackendFramebufferObject {
|
class BackendFramebufferObject {
|
||||||
public:
|
public:
|
||||||
BackendFramebufferObject();
|
BackendFramebufferObject();
|
||||||
void SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
|
void SyncToBackend(const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
|
||||||
FramebufferTarget asTarget);
|
FramebufferTarget asTarget);
|
||||||
Uint GetBackendFramebufferId() { return m_backendFBOId; }
|
void InvalidateSyncedState();
|
||||||
void Bind(FramebufferTarget target);
|
Uint GetBackendFramebufferId() const { return m_backendFBOId; }
|
||||||
bool SyncAttachmentObject(GLenum glFBOTarget,
|
void Bind(FramebufferTarget target) const;
|
||||||
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
|
|
||||||
GLenum glBackendAttachment);
|
|
||||||
// FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index);
|
// FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index);
|
||||||
GLenum GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const;
|
GLenum GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const;
|
||||||
|
|
||||||
@@ -159,7 +258,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
FramebufferObject::FramebufferAttachmentVersionArray m_syncedFrontendAttachmentVersions = {0};
|
FramebufferObject::FramebufferAttachmentVersionArray m_syncedFrontendAttachmentVersions = {0};
|
||||||
};
|
};
|
||||||
|
|
||||||
extern UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>>
|
extern StateBackendObjectRegistry<MG_State::GLState::FramebufferObject, BackendFramebufferObject>
|
||||||
g_backendFramebufferObjects;
|
g_backendFramebufferObjects;
|
||||||
extern Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions;
|
extern Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions;
|
||||||
} // namespace FramebufferImpl
|
} // namespace FramebufferImpl
|
||||||
@@ -169,18 +268,20 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
public:
|
public:
|
||||||
BackendProgramObjectImpl();
|
BackendProgramObjectImpl();
|
||||||
~BackendProgramObjectImpl();
|
~BackendProgramObjectImpl();
|
||||||
void SyncToBackend(SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject);
|
void SyncToBackend(const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject);
|
||||||
void Use();
|
void Use() const;
|
||||||
|
void SetBaseInstance(Uint32 baseInstance) const;
|
||||||
Uint GetBackendProgramId() const { return m_backendProgramId; }
|
Uint GetBackendProgramId() const { return m_backendProgramId; }
|
||||||
Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; }
|
Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Uint m_backendProgramId = 0;
|
Uint m_backendProgramId = 0;
|
||||||
Uint m_backendGlobalUBOId = 0;
|
Uint m_backendGlobalUBOId = 0;
|
||||||
|
Int m_baseInstanceUniformLocation = -1;
|
||||||
Bool m_isInitialized = false;
|
Bool m_isInitialized = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern UnorderedMap<SharedPtr<MG_State::GLState::ProgramObject>, SharedPtr<BackendProgramObjectImpl>>
|
extern StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl>
|
||||||
g_backendProgramObjects;
|
g_backendProgramObjects;
|
||||||
} // namespace PrgramImpl
|
} // namespace PrgramImpl
|
||||||
|
|
||||||
@@ -188,9 +289,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
class BackendSamplerObject {
|
class BackendSamplerObject {
|
||||||
public:
|
public:
|
||||||
BackendSamplerObject();
|
BackendSamplerObject();
|
||||||
void SyncToBackend(SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject);
|
void SyncToBackend(const SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject);
|
||||||
void Bind(Uint unit);
|
void Bind(Uint unit);
|
||||||
Uint GetBackendSamplerId();
|
Uint GetBackendSamplerId() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Uint m_backendSamplerId = 0;
|
Uint m_backendSamplerId = 0;
|
||||||
@@ -203,7 +304,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
extern Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
|
extern Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
|
||||||
g_boundSamplersCache;
|
g_boundSamplersCache;
|
||||||
extern UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>>
|
extern StateBackendObjectRegistry<MG_State::GLState::SamplerObject, BackendSamplerObject>
|
||||||
g_backendSamplerObjects;
|
g_backendSamplerObjects;
|
||||||
} // namespace SamplerImpl
|
} // namespace SamplerImpl
|
||||||
|
|
||||||
@@ -212,8 +313,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
public:
|
public:
|
||||||
BackendRenderbufferObject();
|
BackendRenderbufferObject();
|
||||||
void SyncToBackend(const SharedPtr<MG_State::GLState::RenderbufferObject>& stateRBOObject);
|
void SyncToBackend(const SharedPtr<MG_State::GLState::RenderbufferObject>& stateRBOObject);
|
||||||
Uint GetBackendRenderbufferId() { return m_backendRBOId; }
|
Uint GetBackendRenderbufferId() const { return m_backendRBOId; }
|
||||||
void Bind();
|
void Bind() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Uint m_backendRBOId = 0;
|
Uint m_backendRBOId = 0;
|
||||||
@@ -223,7 +324,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
Int m_cacheHeight = 0;
|
Int m_cacheHeight = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern UnorderedMap<SharedPtr<MG_State::GLState::RenderbufferObject>, SharedPtr<BackendRenderbufferObject>>
|
extern StateBackendObjectRegistry<MG_State::GLState::RenderbufferObject, BackendRenderbufferObject>
|
||||||
g_backendRenderbufferObjects;
|
g_backendRenderbufferObjects;
|
||||||
} // namespace RenderbufferImpl
|
} // namespace RenderbufferImpl
|
||||||
} // namespace MobileGL::MG_Backend::DirectGLES
|
} // namespace MobileGL::MG_Backend::DirectGLES
|
||||||
|
|||||||
@@ -19,10 +19,6 @@
|
|||||||
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
|
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectGLES {
|
namespace MobileGL::MG_Backend::DirectGLES {
|
||||||
namespace BufferImpl {} // namespace BufferImpl
|
|
||||||
|
|
||||||
namespace VertexArrayImpl {} // namespace VertexArrayImpl
|
|
||||||
|
|
||||||
namespace TextureImpl {
|
namespace TextureImpl {
|
||||||
void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat,
|
void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat,
|
||||||
GLenum* outFormat, GLenum* outType) {
|
GLenum* outFormat, GLenum* outType) {
|
||||||
@@ -36,9 +32,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
outInternalFormat, outFormat, outType);
|
outInternalFormat, outFormat, outType);
|
||||||
}
|
}
|
||||||
} // namespace TextureImpl
|
} // namespace TextureImpl
|
||||||
|
|
||||||
namespace FramebufferImpl {} // namespace FramebufferImpl
|
|
||||||
|
|
||||||
namespace PrgramImpl {
|
namespace PrgramImpl {
|
||||||
String ProcessOutColorLocations(const String& glslCode) {
|
String ProcessOutColorLocations(const String& glslCode) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
@@ -108,6 +101,37 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ForceFlatIntegerVaryings(const String& glslCode, GLenum shaderType) {
|
||||||
|
#ifdef TRACY_ENABLE
|
||||||
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
|
#endif
|
||||||
|
String result = glslCode;
|
||||||
|
const String integerType = R"((?:(?:lowp|mediump|highp)\s+)?(?:u?int|[iu]vec[234])\b)";
|
||||||
|
|
||||||
|
auto addFlatQualifier = [&result, &integerType](const String& qualifier) {
|
||||||
|
const std::regex pattern("(layout\\s*\\([^)]*\\)\\s*)(?!(?:flat|smooth|noperspective)\\s)(" +
|
||||||
|
qualifier + "\\s+" + integerType + ")");
|
||||||
|
result = std::regex_replace(result, pattern, "$1flat $2");
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (shaderType) {
|
||||||
|
case GL_VERTEX_SHADER:
|
||||||
|
addFlatQualifier("out");
|
||||||
|
break;
|
||||||
|
case GL_GEOMETRY_SHADER:
|
||||||
|
addFlatQualifier("in");
|
||||||
|
addFlatQualifier("out");
|
||||||
|
break;
|
||||||
|
case GL_FRAGMENT_SHADER:
|
||||||
|
addFlatQualifier("in");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
String RemoveLayoutBinding(const String& glslCode) {
|
String RemoveLayoutBinding(const String& glslCode) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
@@ -166,7 +190,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return GL_UNIFORM_BUFFER_BINDING;
|
return GL_UNIFORM_BUFFER_BINDING;
|
||||||
|
|
||||||
case GL_FRAMEBUFFER:
|
case GL_FRAMEBUFFER:
|
||||||
return GL_FRAMEBUFFER_BINDING;
|
|
||||||
case GL_DRAW_FRAMEBUFFER:
|
case GL_DRAW_FRAMEBUFFER:
|
||||||
return GL_DRAW_FRAMEBUFFER_BINDING;
|
return GL_DRAW_FRAMEBUFFER_BINDING;
|
||||||
case GL_READ_FRAMEBUFFER:
|
case GL_READ_FRAMEBUFFER:
|
||||||
@@ -176,7 +199,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return GL_RENDERBUFFER_BINDING;
|
return GL_RENDERBUFFER_BINDING;
|
||||||
|
|
||||||
case GL_VERTEX_ARRAY:
|
case GL_VERTEX_ARRAY:
|
||||||
return GL_VERTEX_ARRAY_BINDING;
|
|
||||||
case GL_VERTEX_ARRAY_BINDING:
|
case GL_VERTEX_ARRAY_BINDING:
|
||||||
return GL_VERTEX_ARRAY_BINDING;
|
return GL_VERTEX_ARRAY_BINDING;
|
||||||
|
|
||||||
|
|||||||
@@ -14,15 +14,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
namespace DebugImpl {
|
namespace DebugImpl {
|
||||||
class ErrorLopper {
|
class ErrorLopper {
|
||||||
public:
|
public:
|
||||||
void Loop(std::function<void(GLenum)>);
|
static void Loop(const std::function<void(GLenum)>&);
|
||||||
void Clear();
|
static void Clear();
|
||||||
ErrorLopper();
|
ErrorLopper();
|
||||||
~ErrorLopper();
|
~ErrorLopper();
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpenGLScopeMarker {
|
class OpenGLScopeMarker {
|
||||||
public:
|
public:
|
||||||
explicit OpenGLScopeMarker(String scopeName);
|
explicit OpenGLScopeMarker(const String& scopeName);
|
||||||
~OpenGLScopeMarker();
|
~OpenGLScopeMarker();
|
||||||
};
|
};
|
||||||
} // namespace DebugImpl
|
} // namespace DebugImpl
|
||||||
@@ -43,6 +43,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
namespace PrgramImpl {
|
namespace PrgramImpl {
|
||||||
String ProcessOutColorLocations(const String& glslCode);
|
String ProcessOutColorLocations(const String& glslCode);
|
||||||
String ForceSupporterOutput(const String& glslCode);
|
String ForceSupporterOutput(const String& glslCode);
|
||||||
|
String ForceFlatIntegerVaryings(const String& glslCode, GLenum shaderType);
|
||||||
String RemoveLayoutBinding(const String& glslCode);
|
String RemoveLayoutBinding(const String& glslCode);
|
||||||
} // namespace PrgramImpl
|
} // namespace PrgramImpl
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,305 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "BackendObject_DirectVulkan.h"
|
||||||
|
#include "MG_Backend/BackendObject.h"
|
||||||
|
#include "DirectVulkan.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
namespace {
|
||||||
|
Bool IsReleaseCurrentRequest(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||||
|
return dpy == EGL_NO_DISPLAY && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
BackendObject_DirectVulkan::~BackendObject_DirectVulkan() = default;
|
||||||
|
|
||||||
|
BackendObject_DirectVulkan::BackendObject_DirectVulkan():
|
||||||
|
m_rendererInfo{
|
||||||
|
.RendererName = "Magma",
|
||||||
|
.BackendName = "Direct (Vulkan)",
|
||||||
|
.ExtraVendor = Nullopt,
|
||||||
|
.RendererGLInfo =
|
||||||
|
{
|
||||||
|
.TargetGLVersion = {3, 3, 0},
|
||||||
|
.TargetGLSLVersion = {4, 6, 0},
|
||||||
|
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32,
|
||||||
|
V_OpenGL33, E_GL_ARB_draw_buffers_blend, E_GL_ARB_compute_shader,
|
||||||
|
E_GL_ARB_shader_storage_buffer_object, E_GL_ARB_shader_image_load_store,
|
||||||
|
E_GL_ARB_program_interface_query, E_GL_ARB_framebuffer_object,
|
||||||
|
E_GL_ARB_multi_draw_indirect, E_GL_ARB_indirect_parameters,
|
||||||
|
E_GL_EXT_framebuffer_object, E_GL_ARB_depth_texture, E_GL_ARB_buffer_storage,
|
||||||
|
E_GL_ARB_texture_storage, E_GL_ARB_direct_state_access,
|
||||||
|
E_GL_ARB_shader_draw_parameters, E_GL_ARB_gpu_shader_int64},
|
||||||
|
.IsCompatibilityProfile = false
|
||||||
|
},
|
||||||
|
.StaticBackendCapability = {.AllowVSOnlyPrograms = false}} {}
|
||||||
|
|
||||||
|
Bool BackendObject_DirectVulkan::InitWindowSurface() {
|
||||||
|
if (!m_windowHandle.Handle) {
|
||||||
|
MGLOG_E("Cannot initialize DirectVulkan window surface: native window handle is null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto nativeWindow = reinterpret_cast<NativeWindowType>(m_windowHandle.Handle);
|
||||||
|
|
||||||
|
pVulkanRenderer = MakeUnique<MG_Backend::DirectVulkan::VulkanRenderer>(nativeWindow);
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer != nullptr, "InitWindowSurface: VulkanRenderer creation failed");
|
||||||
|
pVulkanRenderer->Initialize();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendObject_DirectVulkan::Initialize() {
|
||||||
|
m_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject_DirectVulkan::InitCapabilities() {
|
||||||
|
if (!m_initialized) {
|
||||||
|
MGLOG_E("Cannot initialize capabilities before backend is initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!pVulkanRenderer) {
|
||||||
|
MGLOG_E("Cannot initialize capabilities: Vulkan renderer has not been created");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& physicalDevice = pVulkanRenderer->GetPhysicalDevice();
|
||||||
|
if (!MG_Util::BackendLoader::QueryVulkanCapabilities(m_vulkanCaps, pVulkanRenderer->GetInstance(),
|
||||||
|
physicalDevice.handle)) {
|
||||||
|
MGLOG_W("DirectVulkan: failed to query extended Vulkan capabilities, using basic properties");
|
||||||
|
MG_Util::BackendLoader::FillInVulkanCapabilities(m_vulkanCaps, physicalDevice.properties);
|
||||||
|
}
|
||||||
|
UpdateDynamicBackendParameters();
|
||||||
|
UpdateAdvertisedExtensions();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject_DirectVulkan::InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) {
|
||||||
|
if (!m_initialized) {
|
||||||
|
MGLOG_E("DirectVulkan backend not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return BackendObject::InitializeEGLDisplay(dpy, major, minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject_DirectVulkan::CreateEGLWindowSurface(const WindowHandle& handle) {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
if (!m_initialized) {
|
||||||
|
MGLOG_E("DirectVulkan backend not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!handle.Handle || (handle.Backend != WindowBackend::Android && handle.Backend != WindowBackend::X11)) {
|
||||||
|
MGLOG_E("DirectVulkan backend only supports Android and X11 native windows");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Bool sameHandle = m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Window &&
|
||||||
|
m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
|
||||||
|
if (sameHandle) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_eglSurfaceInitialized || pVulkanRenderer) {
|
||||||
|
pVulkanRenderer.reset();
|
||||||
|
ResetEGLRuntimeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
return BackendObject::CreateEGLWindowSurface(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject_DirectVulkan::MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
if (IsReleaseCurrentRequest(dpy, draw, read, ctx)) {
|
||||||
|
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
|
||||||
|
}
|
||||||
|
if (!pVulkanRenderer) {
|
||||||
|
MGLOG_E("DirectVulkan renderer is not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return BackendObject::MakeEGLCurrent(dpy, draw, read, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BackendObject_DirectVulkan::SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
if (!pVulkanRenderer) {
|
||||||
|
MGLOG_E("DirectVulkan renderer is not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return BackendObject::SwapEGLBuffers(dpy, draw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendObject_DirectVulkan::ReleaseEGLResources() {
|
||||||
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
|
pVulkanRenderer.reset();
|
||||||
|
BackendObject::ReleaseEGLResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
const RendererInfo& BackendObject_DirectVulkan::GetRendererInfo() const {
|
||||||
|
return m_rendererInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
String BackendObject_DirectVulkan::GetBackendAPIVersionString() const {
|
||||||
|
if (!m_initialized) {
|
||||||
|
return "<uninitialized DirectVulkan backend>";
|
||||||
|
}
|
||||||
|
// Format:
|
||||||
|
// <GPU Name>, Vulkan <Vulkan Version>, Driver <Driver Version>
|
||||||
|
String str = m_vulkanCaps.DeviceName + ", Vulkan " + m_vulkanCaps.VulkanAPIVersion.toString() + ", Driver " +
|
||||||
|
m_vulkanCaps.DriverVersionString;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
BackendType BackendObject_DirectVulkan::GetBackendType() const {
|
||||||
|
return BackendType::DirectVulkan;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GlobalBackendFunctionsTable& BackendObject_DirectVulkan::GetBackendFunctions() const {
|
||||||
|
static GlobalBackendFunctionsTable funcsTable;
|
||||||
|
static Bool funcsTableInitialized = false;
|
||||||
|
if (!funcsTableInitialized) {
|
||||||
|
funcsTable.Present = Present;
|
||||||
|
funcsTable.GL.DrawArrays = DrawArrays;
|
||||||
|
funcsTable.GL.DrawElements = DrawElements;
|
||||||
|
funcsTable.GL.DrawElementsBaseVertex = DrawElementsBaseVertex;
|
||||||
|
funcsTable.GL.MultiDrawElements = MultiDrawElements;
|
||||||
|
funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex;
|
||||||
|
funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect;
|
||||||
|
funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect;
|
||||||
|
funcsTable.GL.MultiDrawElementsIndirectCount = MultiDrawElementsIndirectCount;
|
||||||
|
funcsTable.GL.MultiDrawArraysIndirectCount = MultiDrawArraysIndirectCount;
|
||||||
|
funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex;
|
||||||
|
funcsTable.GL.DrawRangeElements = DrawRangeElements;
|
||||||
|
funcsTable.GL.DrawElementsInstancedBaseVertexBaseInstance = DrawElementsInstancedBaseVertexBaseInstance;
|
||||||
|
funcsTable.GL.DrawElementsInstancedBaseVertex = DrawElementsInstancedBaseVertex;
|
||||||
|
funcsTable.GL.DrawElementsInstancedBaseInstance = DrawElementsInstancedBaseInstance;
|
||||||
|
funcsTable.GL.DrawElementsInstanced = DrawElementsInstanced;
|
||||||
|
funcsTable.GL.DrawArraysInstancedBaseInstance = DrawArraysInstancedBaseInstance;
|
||||||
|
funcsTable.GL.DrawArraysInstanced = DrawArraysInstanced;
|
||||||
|
funcsTable.GL.DrawElementsIndirect = DrawElementsIndirect;
|
||||||
|
funcsTable.GL.DrawArraysIndirect = DrawArraysIndirect;
|
||||||
|
funcsTable.GL.Clear = Clear;
|
||||||
|
funcsTable.GL.ClearBufferfi = ClearBufferfi;
|
||||||
|
funcsTable.GL.ClearBufferfv = ClearBufferfv;
|
||||||
|
funcsTable.GL.ClearBufferuiv = ClearBufferuiv;
|
||||||
|
funcsTable.GL.ClearBufferiv = ClearBufferiv;
|
||||||
|
funcsTable.GL.ClearNamedFramebufferfv = ClearNamedFramebufferfv;
|
||||||
|
funcsTable.GL.ClearNamedFramebufferfi = ClearNamedFramebufferfi;
|
||||||
|
funcsTable.GL.BlitFramebuffer = BlitFramebuffer;
|
||||||
|
funcsTable.GL.BlitNamedFramebuffer = BlitNamedFramebuffer;
|
||||||
|
funcsTable.GL.CopyTexImage2D = CopyTexImage2D;
|
||||||
|
funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D;
|
||||||
|
funcsTable.GL.GenerateMipmap = GenerateMipmap;
|
||||||
|
funcsTable.GL.ReadPixels = ReadPixels;
|
||||||
|
funcsTable.GL.GetTexImage = GetTexImage;
|
||||||
|
funcsTable.GL.GetTextureImage = GetTextureImage;
|
||||||
|
funcsTable.GL.DispatchCompute = DispatchCompute;
|
||||||
|
funcsTable.GL.DispatchComputeIndirect = DispatchComputeIndirect;
|
||||||
|
funcsTable.GL.MemoryBarrier = MemoryBarrier;
|
||||||
|
funcsTable.GL.MemoryBarrierByRegion = MemoryBarrierByRegion;
|
||||||
|
funcsTable.GL.BindImageTexture = BindImageTexture;
|
||||||
|
funcsTable.GL.GetIntegeri_v = GetIntegeri_v;
|
||||||
|
funcsTable.GL.GetInteger64i_v = GetInteger64i_v;
|
||||||
|
funcsTable.GL.GetProgramiv = GetProgramiv;
|
||||||
|
funcsTable.GL.GetProgramInterfaceiv = GetProgramInterfaceiv;
|
||||||
|
funcsTable.GL.GetProgramResourceIndex = GetProgramResourceIndex;
|
||||||
|
funcsTable.GL.GetProgramResourceName = GetProgramResourceName;
|
||||||
|
funcsTable.GL.GetProgramResourceiv = GetProgramResourceiv;
|
||||||
|
funcsTable.GL.GetProgramResourceLocation = GetProgramResourceLocation;
|
||||||
|
funcsTable.GL.GetProgramResourceLocationIndex = GetProgramResourceLocationIndex;
|
||||||
|
funcsTable.GL.ShaderStorageBlockBinding = ShaderStorageBlockBinding;
|
||||||
|
funcsTableInitialized = true;
|
||||||
|
}
|
||||||
|
return funcsTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DynamicBackendParameters& BackendObject_DirectVulkan::GetDynamicParameters() const {
|
||||||
|
return m_dynamicParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendObject_DirectVulkan::ApplyVulkanCapabilitiesForTesting(
|
||||||
|
const MG_External::VulkanCapabilities& capabilities) {
|
||||||
|
m_vulkanCaps = capabilities;
|
||||||
|
UpdateDynamicBackendParameters();
|
||||||
|
UpdateAdvertisedExtensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendObject_DirectVulkan::UpdateAdvertisedExtensions() {
|
||||||
|
auto& extensions = m_rendererInfo.RendererGLInfo.Extensions;
|
||||||
|
extensions.erase(std::remove(extensions.begin(), extensions.end(), E_GL_KHR_shader_subgroup),
|
||||||
|
extensions.end());
|
||||||
|
|
||||||
|
if (m_vulkanCaps.SupportsShaderSubgroup) {
|
||||||
|
extensions.push_back(E_GL_KHR_shader_subgroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendObject_DirectVulkan::UpdateDynamicBackendParameters() {
|
||||||
|
const auto mapShaderStages = [](Uint32 vkStages) {
|
||||||
|
Uint32 glStages = 0;
|
||||||
|
if ((vkStages & VK_SHADER_STAGE_VERTEX_BIT) != 0) glStages |= GL_VERTEX_SHADER_BIT;
|
||||||
|
if ((vkStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) glStages |= GL_TESS_CONTROL_SHADER_BIT;
|
||||||
|
if ((vkStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0) {
|
||||||
|
glStages |= GL_TESS_EVALUATION_SHADER_BIT;
|
||||||
|
}
|
||||||
|
if ((vkStages & VK_SHADER_STAGE_GEOMETRY_BIT) != 0) glStages |= GL_GEOMETRY_SHADER_BIT;
|
||||||
|
if ((vkStages & VK_SHADER_STAGE_FRAGMENT_BIT) != 0) glStages |= GL_FRAGMENT_SHADER_BIT;
|
||||||
|
if ((vkStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0) glStages |= GL_COMPUTE_SHADER_BIT;
|
||||||
|
return glStages;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto mapSubgroupFeatures = [](Uint32 vkFeatures) {
|
||||||
|
Uint32 glFeatures = 0;
|
||||||
|
if ((vkFeatures & VK_SUBGROUP_FEATURE_BASIC_BIT) != 0) {
|
||||||
|
glFeatures |= GL_SUBGROUP_FEATURE_BASIC_BIT_KHR;
|
||||||
|
}
|
||||||
|
if ((vkFeatures & VK_SUBGROUP_FEATURE_VOTE_BIT) != 0) {
|
||||||
|
glFeatures |= GL_SUBGROUP_FEATURE_VOTE_BIT_KHR;
|
||||||
|
}
|
||||||
|
if ((vkFeatures & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) != 0) {
|
||||||
|
glFeatures |= GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR;
|
||||||
|
}
|
||||||
|
if ((vkFeatures & VK_SUBGROUP_FEATURE_BALLOT_BIT) != 0) {
|
||||||
|
glFeatures |= GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR;
|
||||||
|
}
|
||||||
|
if ((vkFeatures & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) != 0) {
|
||||||
|
glFeatures |= GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR;
|
||||||
|
}
|
||||||
|
if ((vkFeatures & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) != 0) {
|
||||||
|
glFeatures |= GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR;
|
||||||
|
}
|
||||||
|
if ((vkFeatures & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) != 0) {
|
||||||
|
glFeatures |= GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR;
|
||||||
|
}
|
||||||
|
if ((vkFeatures & VK_SUBGROUP_FEATURE_QUAD_BIT) != 0) {
|
||||||
|
glFeatures |= GL_SUBGROUP_FEATURE_QUAD_BIT_KHR;
|
||||||
|
}
|
||||||
|
return glFeatures;
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr SizeT kMaxAdvertisedShaderStorageBlockSize = 512ull * 1024ull * 1024ull;
|
||||||
|
m_dynamicParameters.UniformBufferOffsetAlignment = m_vulkanCaps.UniformBufferOffsetAlignment;
|
||||||
|
m_dynamicParameters.MaxShaderStorageBlockSize =
|
||||||
|
std::min(m_vulkanCaps.MaxShaderStorageBlockSize, kMaxAdvertisedShaderStorageBlockSize);
|
||||||
|
if (m_vulkanCaps.SupportsShaderSubgroup) {
|
||||||
|
m_dynamicParameters.SubgroupSize = m_vulkanCaps.SubgroupSize;
|
||||||
|
m_dynamicParameters.SubgroupSupportedStages = mapShaderStages(m_vulkanCaps.SubgroupSupportedStages);
|
||||||
|
m_dynamicParameters.SubgroupSupportedFeatures = mapSubgroupFeatures(m_vulkanCaps.SubgroupSupportedOperations);
|
||||||
|
m_dynamicParameters.SubgroupQuadOperationsInAllStages = m_vulkanCaps.SubgroupQuadOperationsInAllStages;
|
||||||
|
} else {
|
||||||
|
m_dynamicParameters.SubgroupSize = 0;
|
||||||
|
m_dynamicParameters.SubgroupSupportedStages = 0;
|
||||||
|
m_dynamicParameters.SubgroupSupportedFeatures = 0;
|
||||||
|
m_dynamicParameters.SubgroupQuadOperationsInAllStages = false;
|
||||||
|
}
|
||||||
|
if (m_dynamicParameters.MaxShaderStorageBlockSize != m_vulkanCaps.MaxShaderStorageBlockSize) {
|
||||||
|
MGLOG_I("DirectVulkan: clamped GL_MAX_SHADER_STORAGE_BLOCK_SIZE from %zu to %zu",
|
||||||
|
m_vulkanCaps.MaxShaderStorageBlockSize,
|
||||||
|
m_dynamicParameters.MaxShaderStorageBlockSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
+16
-7
@@ -1,4 +1,4 @@
|
|||||||
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/BackendObject_DirectVulkanTMP.h
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.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,26 +11,35 @@
|
|||||||
#include "../BackendObject.h"
|
#include "../BackendObject.h"
|
||||||
#include <MG_Util/BackendLoaders/Vulkan/Loader.h>
|
#include <MG_Util/BackendLoaders/Vulkan/Loader.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkanTMP {
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
class BackendObject_DirectVulkanTMP : public BackendObject {
|
class BackendObject_DirectVulkan : public BackendObject {
|
||||||
public:
|
public:
|
||||||
~BackendObject_DirectVulkanTMP() override;
|
BackendObject_DirectVulkan();
|
||||||
|
~BackendObject_DirectVulkan() override;
|
||||||
|
|
||||||
void Initialize() override;
|
void Initialize() override;
|
||||||
void InitWindowSurface() override;
|
Bool InitWindowSurface() override;
|
||||||
void InitCapabilities() override;
|
Bool InitCapabilities() override;
|
||||||
|
Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) override;
|
||||||
|
Bool CreateEGLWindowSurface(const WindowHandle& handle) override;
|
||||||
|
Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) override;
|
||||||
|
Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) override;
|
||||||
|
void ReleaseEGLResources() override;
|
||||||
|
|
||||||
const RendererInfo& GetRendererInfo() const override;
|
const RendererInfo& GetRendererInfo() const override;
|
||||||
String GetBackendAPIVersionString() const override;
|
String GetBackendAPIVersionString() const override;
|
||||||
const GlobalBackendFunctionsTable& GetBackendFunctions() const override;
|
const GlobalBackendFunctionsTable& GetBackendFunctions() const override;
|
||||||
const DynamicBackendParameters& GetDynamicParameters() const override;
|
const DynamicBackendParameters& GetDynamicParameters() const override;
|
||||||
BackendType GetBackendType() const override;
|
BackendType GetBackendType() const override;
|
||||||
|
void ApplyVulkanCapabilitiesForTesting(const MG_External::VulkanCapabilities& capabilities);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void UpdateAdvertisedExtensions();
|
||||||
void UpdateDynamicBackendParameters();
|
void UpdateDynamicBackendParameters();
|
||||||
|
|
||||||
Bool m_initialized = false;
|
Bool m_initialized = false;
|
||||||
DynamicBackendParameters m_dynamicParameters;
|
DynamicBackendParameters m_dynamicParameters;
|
||||||
MG_External::VulkanCapabilities m_vulkanCaps;
|
MG_External::VulkanCapabilities m_vulkanCaps;
|
||||||
|
RendererInfo m_rendererInfo;
|
||||||
};
|
};
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkanTMP
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,775 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "DirectVulkan.h"
|
||||||
|
#include "DirectVulkanResourceState.h"
|
||||||
|
#include "MG_State/GLState/Core.h"
|
||||||
|
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
||||||
|
#include "MG_Util/Miscellany/IndexGenerator.h"
|
||||||
|
#include <cstring>
|
||||||
|
#include <spirv_reflect.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
UniquePtr<VulkanRenderer> pVulkanRenderer = nullptr;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct BufferVariableResource {
|
||||||
|
String name;
|
||||||
|
GLuint blockIndex = 0;
|
||||||
|
GLint offset = 0;
|
||||||
|
GLint size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StorageBlockResource {
|
||||||
|
String name;
|
||||||
|
GLuint binding = 0;
|
||||||
|
GLint dataSize = 0;
|
||||||
|
Vector<GLuint> activeVariables;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProgramResourceCache {
|
||||||
|
Uint32 backendStateVersion = 0;
|
||||||
|
Vector<StorageBlockResource> storageBlocks;
|
||||||
|
Vector<BufferVariableResource> bufferVariables;
|
||||||
|
GLint computeWorkGroupSize[3] = {1, 1, 1};
|
||||||
|
};
|
||||||
|
|
||||||
|
UnorderedMap<GLuint, ProgramResourceCache> g_programResourceCaches;
|
||||||
|
|
||||||
|
String NormalizeDescriptorName(const SpvReflectDescriptorBinding& binding) {
|
||||||
|
const char* rawName = binding.name;
|
||||||
|
if (binding.type_description != nullptr && binding.type_description->type_name != nullptr) {
|
||||||
|
rawName = binding.type_description->type_name;
|
||||||
|
}
|
||||||
|
if (rawName == nullptr) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
String name = rawName;
|
||||||
|
const auto arraySuffix = name.find("[0]");
|
||||||
|
if (arraySuffix != String::npos) {
|
||||||
|
name = name.substr(0, arraySuffix);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddBufferVariablesRecursive(const SpvReflectBlockVariable& variable, const String& prefix,
|
||||||
|
GLuint blockIndex, Vector<BufferVariableResource>& variables,
|
||||||
|
Vector<GLuint>& activeVariables) {
|
||||||
|
for (Uint32 memberIndex = 0; memberIndex < variable.member_count; ++memberIndex) {
|
||||||
|
const auto& member = variable.members[memberIndex];
|
||||||
|
String name = prefix;
|
||||||
|
if (!name.empty()) {
|
||||||
|
name += ".";
|
||||||
|
}
|
||||||
|
name += member.name ? member.name : "";
|
||||||
|
|
||||||
|
if (member.member_count > 0) {
|
||||||
|
AddBufferVariablesRecursive(member, name, blockIndex, variables, activeVariables);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferVariableResource resource{};
|
||||||
|
resource.name = name;
|
||||||
|
resource.blockIndex = blockIndex;
|
||||||
|
resource.offset = static_cast<GLint>(member.offset);
|
||||||
|
resource.size = static_cast<GLint>(member.size);
|
||||||
|
const GLuint variableIndex = static_cast<GLuint>(variables.size());
|
||||||
|
variables.push_back(resource);
|
||||||
|
activeVariables.push_back(variableIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgramResourceCache& GetProgramResourceCache(const MG_State::GLState::ProgramObject& program) {
|
||||||
|
auto& cache = g_programResourceCaches[program.GetExternalIndex()];
|
||||||
|
const Uint32 backendStateVersion = program.GetBackendStateVersion();
|
||||||
|
if (cache.backendStateVersion == backendStateVersion &&
|
||||||
|
(!cache.storageBlocks.empty() || !cache.bufferVariables.empty())) {
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache = {};
|
||||||
|
cache.backendStateVersion = backendStateVersion;
|
||||||
|
|
||||||
|
Vector<SpvReflectShaderModule> modules;
|
||||||
|
Vector<Bool> validModules;
|
||||||
|
const auto& spirvs = program.GetGeneratedSpirv();
|
||||||
|
for (const auto& spirv : spirvs) {
|
||||||
|
if (spirv.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SpvReflectShaderModule module{};
|
||||||
|
const SpvReflectResult result =
|
||||||
|
spvReflectCreateShaderModule(spirv.size() * sizeof(Uint), spirv.data(), &module);
|
||||||
|
if (result != SPV_REFLECT_RESULT_SUCCESS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
modules.push_back(module);
|
||||||
|
validModules.push_back(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& module : modules) {
|
||||||
|
for (Uint32 entryIndex = 0; entryIndex < module.entry_point_count; ++entryIndex) {
|
||||||
|
const auto& entryPoint = module.entry_points[entryIndex];
|
||||||
|
if ((entryPoint.shader_stage & SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cache.computeWorkGroupSize[0] = static_cast<GLint>(std::max<Uint32>(entryPoint.local_size.x, 1));
|
||||||
|
cache.computeWorkGroupSize[1] = static_cast<GLint>(std::max<Uint32>(entryPoint.local_size.y, 1));
|
||||||
|
cache.computeWorkGroupSize[2] = static_cast<GLint>(std::max<Uint32>(entryPoint.local_size.z, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bindingCount = 0;
|
||||||
|
SpvReflectResult result = spvReflectEnumerateDescriptorBindings(&module, &bindingCount, nullptr);
|
||||||
|
if (result != SPV_REFLECT_RESULT_SUCCESS || bindingCount == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Vector<SpvReflectDescriptorBinding*> bindings(bindingCount);
|
||||||
|
result = spvReflectEnumerateDescriptorBindings(&module, &bindingCount, bindings.data());
|
||||||
|
if (result != SPV_REFLECT_RESULT_SUCCESS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::sort(bindings.begin(), bindings.end(), [](const auto* lhs, const auto* rhs) {
|
||||||
|
const String lhsName = lhs ? NormalizeDescriptorName(*lhs) : String();
|
||||||
|
const String rhsName = rhs ? NormalizeDescriptorName(*rhs) : String();
|
||||||
|
if (lhsName != rhsName) return lhsName < rhsName;
|
||||||
|
return lhs->binding < rhs->binding;
|
||||||
|
});
|
||||||
|
for (const auto* binding : bindings) {
|
||||||
|
if (binding == nullptr ||
|
||||||
|
binding->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const String blockName = NormalizeDescriptorName(*binding);
|
||||||
|
if (blockName.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto existing = std::find_if(
|
||||||
|
cache.storageBlocks.begin(), cache.storageBlocks.end(),
|
||||||
|
[&](const StorageBlockResource& block) { return block.name == blockName; });
|
||||||
|
if (existing != cache.storageBlocks.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageBlockResource block{};
|
||||||
|
block.name = blockName;
|
||||||
|
block.binding = binding->binding;
|
||||||
|
block.dataSize = static_cast<GLint>(binding->block.size);
|
||||||
|
const GLuint blockIndex = static_cast<GLuint>(cache.storageBlocks.size());
|
||||||
|
AddBufferVariablesRecursive(binding->block, blockName, blockIndex, cache.bufferVariables,
|
||||||
|
block.activeVariables);
|
||||||
|
cache.storageBlocks.push_back(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SizeT i = 0; i < modules.size(); ++i) {
|
||||||
|
if (validModules[i]) {
|
||||||
|
spvReflectDestroyShaderModule(&modules[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_State::GLState::ProgramObject* TryGetDirectVulkanProgram(GLuint program) {
|
||||||
|
if (!MG_State::pGLContext || !MG_State::pGLContext->ValidateProgramName(program)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto& programObject = MG_State::pGLContext->GetProgramObject(program);
|
||||||
|
return programObject.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyResourceName(const String& source, GLsizei bufSize, GLsizei* length, GLchar* name) {
|
||||||
|
const GLsizei writtenLength = static_cast<GLsizei>(source.size());
|
||||||
|
if (length) {
|
||||||
|
*length = writtenLength;
|
||||||
|
}
|
||||||
|
if (name && bufSize > 0) {
|
||||||
|
const GLsizei copyLength = std::min<GLsizei>(bufSize - 1, writtenLength);
|
||||||
|
std::memcpy(name, source.data(), static_cast<SizeT>(copyLength));
|
||||||
|
name[copyLength] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
GLuint GetShaderStorageBlockIndex(const MG_State::GLState::ProgramObject& program, const String& name) {
|
||||||
|
auto& cache = GetProgramResourceCache(program);
|
||||||
|
const auto it = std::find_if(cache.storageBlocks.begin(), cache.storageBlocks.end(),
|
||||||
|
[&](const StorageBlockResource& block) { return block.name == name; });
|
||||||
|
return it == cache.storageBlocks.end()
|
||||||
|
? GL_INVALID_INDEX
|
||||||
|
: static_cast<GLuint>(std::distance(cache.storageBlocks.begin(), it));
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint GetShaderStorageBlockBinding(const MG_State::GLState::ProgramObject& program, GLuint blockIndex) {
|
||||||
|
auto& cache = GetProgramResourceCache(program);
|
||||||
|
if (blockIndex >= cache.storageBlocks.size()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return cache.storageBlocks[blockIndex].binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferfi called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferfi called with null GL context");
|
||||||
|
pVulkanRenderer->ClearBufferfi(buffer, drawbuffer, depth, stencil);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferfv called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferfv called with null GL context");
|
||||||
|
pVulkanRenderer->ClearBufferfv(buffer, drawbuffer, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferuiv called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferuiv called with null GL context");
|
||||||
|
pVulkanRenderer->ClearBufferuiv(buffer, drawbuffer, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferiv called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferiv called with null GL context");
|
||||||
|
pVulkanRenderer->ClearBufferiv(buffer, drawbuffer, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
|
||||||
|
GLint drawbuffer, const GLfloat* value) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferfv called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearNamedFramebufferfv called with null GL context");
|
||||||
|
pVulkanRenderer->ClearNamedFramebufferfv(framebuffer, buffer, drawbuffer, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
|
||||||
|
GLint drawbuffer, GLfloat depth, GLint stencil) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferfi called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearNamedFramebufferfi called with null GL context");
|
||||||
|
pVulkanRenderer->ClearNamedFramebufferfi(framebuffer, buffer, drawbuffer, depth, stencil);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsIndirect called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElementsIndirect called with null GL context");
|
||||||
|
pVulkanRenderer->MultiDrawElementsIndirectCount(mode, type, indirect, 0, drawcount, stride);
|
||||||
|
}
|
||||||
|
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {
|
||||||
|
MGLOG_W("DirectVulkan::MultiDrawArraysIndirect is not implemented yet (drawcount=%d)", drawcount);
|
||||||
|
}
|
||||||
|
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
|
||||||
|
GLsizei maxdrawcount, GLsizei stride) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsIndirectCount called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElementsIndirectCount called with null GL context");
|
||||||
|
pVulkanRenderer->MultiDrawElementsIndirectCount(mode, type, indirect, drawcount, maxdrawcount, stride);
|
||||||
|
}
|
||||||
|
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
|
||||||
|
GLsizei maxdrawcount, GLsizei stride) {
|
||||||
|
MGLOG_W("DirectVulkan::MultiDrawArraysIndirectCount is not implemented yet (maxdrawcount=%d)", maxdrawcount);
|
||||||
|
}
|
||||||
|
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||||
|
const void* indices, GLint basevertex) {}
|
||||||
|
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices) {}
|
||||||
|
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||||
|
GLsizei instancecount, GLint basevertex, GLuint baseinstance) {}
|
||||||
|
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||||
|
GLsizei instancecount, GLint basevertex) {}
|
||||||
|
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||||
|
GLsizei instancecount, GLuint baseinstance) {}
|
||||||
|
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) {}
|
||||||
|
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect) {}
|
||||||
|
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
||||||
|
GLuint baseinstance) {}
|
||||||
|
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) {}
|
||||||
|
void DrawArraysIndirect(GLenum mode, const void* indirect) {}
|
||||||
|
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
||||||
|
GLsizei height, GLint border) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyTexImage2D called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::CopyTexImage2D called with null GL context");
|
||||||
|
pVulkanRenderer->CopyTexSubImage2D(target, level, 0, 0, x, y, width, height);
|
||||||
|
}
|
||||||
|
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
||||||
|
GLsizei height) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyTexSubImage2D called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::CopyTexSubImage2D called with null GL context");
|
||||||
|
pVulkanRenderer->CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
|
||||||
|
}
|
||||||
|
void GenerateMipmap(GLenum target) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GenerateMipmap called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::GenerateMipmap called with null GL context");
|
||||||
|
pVulkanRenderer->GenerateMipmap(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DispatchCompute called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DispatchCompute called with null GL context");
|
||||||
|
pVulkanRenderer->DispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DispatchComputeIndirect(GLintptr indirect) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DispatchComputeIndirect called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DispatchComputeIndirect called with null GL context");
|
||||||
|
pVulkanRenderer->DispatchComputeIndirect(indirect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBarrier(GLbitfield barriers) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MemoryBarrier called with null VulkanRenderer");
|
||||||
|
pVulkanRenderer->MemoryBarrier(barriers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBarrierByRegion(GLbitfield barriers) {
|
||||||
|
MemoryBarrier(barriers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access,
|
||||||
|
GLenum format) {
|
||||||
|
(void)unit;
|
||||||
|
(void)texture;
|
||||||
|
(void)level;
|
||||||
|
(void)layered;
|
||||||
|
(void)layer;
|
||||||
|
(void)access;
|
||||||
|
(void)format;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetIntegeri_v(GLenum target, GLuint index, GLint* data) {
|
||||||
|
if (!data) return;
|
||||||
|
switch (target) {
|
||||||
|
case GL_MAX_COMPUTE_WORK_GROUP_COUNT:
|
||||||
|
if (!pVulkanRenderer || index >= 3) {
|
||||||
|
*data = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*data = static_cast<GLint>(
|
||||||
|
pVulkanRenderer->GetPhysicalDevice().properties.limits.maxComputeWorkGroupCount[index]);
|
||||||
|
return;
|
||||||
|
case GL_MAX_COMPUTE_WORK_GROUP_SIZE:
|
||||||
|
if (!pVulkanRenderer || index >= 3) {
|
||||||
|
*data = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*data = static_cast<GLint>(
|
||||||
|
pVulkanRenderer->GetPhysicalDevice().properties.limits.maxComputeWorkGroupSize[index]);
|
||||||
|
return;
|
||||||
|
case GL_SHADER_STORAGE_BUFFER_BINDING: {
|
||||||
|
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, index);
|
||||||
|
auto& obj = point.GetBoundObject();
|
||||||
|
*data = obj ? static_cast<GLint>(obj->GetExternalIndex()) : 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case GL_SHADER_STORAGE_BUFFER_START: {
|
||||||
|
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, index);
|
||||||
|
*data = static_cast<GLint>(point.GetRange().start);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case GL_SHADER_STORAGE_BUFFER_SIZE: {
|
||||||
|
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, index);
|
||||||
|
auto& obj = point.GetBoundObject();
|
||||||
|
if (!obj) {
|
||||||
|
*data = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& range = point.GetRange();
|
||||||
|
const auto start = std::min(range.start, obj->GetSize());
|
||||||
|
const auto end = std::min(range.end, obj->GetSize());
|
||||||
|
*data = static_cast<GLint>(end - start);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case GL_IMAGE_BINDING_NAME:
|
||||||
|
case GL_IMAGE_BINDING_LEVEL:
|
||||||
|
case GL_IMAGE_BINDING_LAYERED:
|
||||||
|
case GL_IMAGE_BINDING_LAYER:
|
||||||
|
case GL_IMAGE_BINDING_ACCESS:
|
||||||
|
case GL_IMAGE_BINDING_FORMAT: {
|
||||||
|
if (index >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
|
||||||
|
*data = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto& imageBinding = MG_State::pGLContext->GetImageTextureBinding(static_cast<Int>(index));
|
||||||
|
if (target == GL_IMAGE_BINDING_NAME) {
|
||||||
|
*data = imageBinding.Texture ? static_cast<GLint>(imageBinding.Texture->GetExternalIndex()) : 0;
|
||||||
|
} else if (target == GL_IMAGE_BINDING_LEVEL) {
|
||||||
|
*data = imageBinding.Level;
|
||||||
|
} else if (target == GL_IMAGE_BINDING_LAYERED) {
|
||||||
|
*data = imageBinding.Layered;
|
||||||
|
} else if (target == GL_IMAGE_BINDING_LAYER) {
|
||||||
|
*data = imageBinding.Layer;
|
||||||
|
} else if (target == GL_IMAGE_BINDING_ACCESS) {
|
||||||
|
*data = static_cast<GLint>(imageBinding.Access);
|
||||||
|
} else {
|
||||||
|
*data = static_cast<GLint>(imageBinding.Format);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
*data = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetInteger64i_v(GLenum target, GLuint index, GLint64* data) {
|
||||||
|
if (!data) return;
|
||||||
|
switch (target) {
|
||||||
|
case GL_SHADER_STORAGE_BUFFER_START: {
|
||||||
|
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, index);
|
||||||
|
*data = static_cast<GLint64>(point.GetRange().start);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case GL_SHADER_STORAGE_BUFFER_SIZE: {
|
||||||
|
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, index);
|
||||||
|
auto& obj = point.GetBoundObject();
|
||||||
|
if (!obj) {
|
||||||
|
*data = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& range = point.GetRange();
|
||||||
|
const auto start = std::min(range.start, obj->GetSize());
|
||||||
|
const auto end = std::min(range.end, obj->GetSize());
|
||||||
|
*data = static_cast<GLint64>(end - start);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
*data = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetProgramiv(GLuint program, GLenum pname, GLint* params) {
|
||||||
|
if (!params) return;
|
||||||
|
auto* programObject = TryGetDirectVulkanProgram(program);
|
||||||
|
if (!programObject) {
|
||||||
|
params[0] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (pname) {
|
||||||
|
case GL_COMPUTE_WORK_GROUP_SIZE: {
|
||||||
|
auto& cache = GetProgramResourceCache(*programObject);
|
||||||
|
params[0] = cache.computeWorkGroupSize[0];
|
||||||
|
params[1] = cache.computeWorkGroupSize[1];
|
||||||
|
params[2] = cache.computeWorkGroupSize[2];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
params[0] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint* params) {
|
||||||
|
if (!params) return;
|
||||||
|
auto* programObject = TryGetDirectVulkanProgram(program);
|
||||||
|
if (!programObject) return;
|
||||||
|
auto& cache = GetProgramResourceCache(*programObject);
|
||||||
|
if (programInterface == GL_SHADER_STORAGE_BLOCK) {
|
||||||
|
if (pname == GL_ACTIVE_RESOURCES) {
|
||||||
|
*params = static_cast<GLint>(cache.storageBlocks.size());
|
||||||
|
} else if (pname == GL_MAX_NAME_LENGTH) {
|
||||||
|
SizeT maxLength = 0;
|
||||||
|
for (const auto& block : cache.storageBlocks) maxLength = std::max(maxLength, block.name.size() + 1);
|
||||||
|
*params = static_cast<GLint>(maxLength);
|
||||||
|
} else {
|
||||||
|
*params = 0;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (programInterface == GL_BUFFER_VARIABLE) {
|
||||||
|
if (pname == GL_ACTIVE_RESOURCES) {
|
||||||
|
*params = static_cast<GLint>(cache.bufferVariables.size());
|
||||||
|
} else if (pname == GL_MAX_NAME_LENGTH) {
|
||||||
|
SizeT maxLength = 0;
|
||||||
|
for (const auto& var : cache.bufferVariables) maxLength = std::max(maxLength, var.name.size() + 1);
|
||||||
|
*params = static_cast<GLint>(maxLength);
|
||||||
|
} else {
|
||||||
|
*params = 0;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*params = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint GetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar* name) {
|
||||||
|
if (!name) return GL_INVALID_INDEX;
|
||||||
|
auto* programObject = TryGetDirectVulkanProgram(program);
|
||||||
|
if (!programObject) return GL_INVALID_INDEX;
|
||||||
|
auto& cache = GetProgramResourceCache(*programObject);
|
||||||
|
if (programInterface == GL_SHADER_STORAGE_BLOCK) {
|
||||||
|
return GetShaderStorageBlockIndex(*programObject, name);
|
||||||
|
}
|
||||||
|
if (programInterface == GL_BUFFER_VARIABLE) {
|
||||||
|
const String resourceName = name;
|
||||||
|
const auto it = std::find_if(cache.bufferVariables.begin(), cache.bufferVariables.end(),
|
||||||
|
[&](const BufferVariableResource& var) { return var.name == resourceName; });
|
||||||
|
return it == cache.bufferVariables.end()
|
||||||
|
? GL_INVALID_INDEX
|
||||||
|
: static_cast<GLuint>(std::distance(cache.bufferVariables.begin(), it));
|
||||||
|
}
|
||||||
|
return GL_INVALID_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize,
|
||||||
|
GLsizei* length, GLchar* name) {
|
||||||
|
auto* programObject = TryGetDirectVulkanProgram(program);
|
||||||
|
if (!programObject) return;
|
||||||
|
auto& cache = GetProgramResourceCache(*programObject);
|
||||||
|
if (programInterface == GL_SHADER_STORAGE_BLOCK && index < cache.storageBlocks.size()) {
|
||||||
|
CopyResourceName(cache.storageBlocks[index].name, bufSize, length, name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (programInterface == GL_BUFFER_VARIABLE && index < cache.bufferVariables.size()) {
|
||||||
|
CopyResourceName(cache.bufferVariables[index].name, bufSize, length, name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (length) *length = 0;
|
||||||
|
if (name && bufSize > 0) name[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount,
|
||||||
|
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params) {
|
||||||
|
auto* programObject = TryGetDirectVulkanProgram(program);
|
||||||
|
if (!programObject || !props || !params || bufSize <= 0) return;
|
||||||
|
auto& cache = GetProgramResourceCache(*programObject);
|
||||||
|
GLsizei written = 0;
|
||||||
|
auto writeValue = [&](GLint value) {
|
||||||
|
if (written < bufSize) {
|
||||||
|
params[written++] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (GLsizei propIndex = 0; propIndex < propCount; ++propIndex) {
|
||||||
|
const GLenum prop = props[propIndex];
|
||||||
|
if (programInterface == GL_SHADER_STORAGE_BLOCK && index < cache.storageBlocks.size()) {
|
||||||
|
const auto& block = cache.storageBlocks[index];
|
||||||
|
switch (prop) {
|
||||||
|
case GL_NAME_LENGTH:
|
||||||
|
writeValue(static_cast<GLint>(block.name.size() + 1));
|
||||||
|
break;
|
||||||
|
case GL_BUFFER_BINDING:
|
||||||
|
writeValue(static_cast<GLint>(block.binding));
|
||||||
|
break;
|
||||||
|
case GL_BUFFER_DATA_SIZE:
|
||||||
|
writeValue(block.dataSize);
|
||||||
|
break;
|
||||||
|
case GL_NUM_ACTIVE_VARIABLES:
|
||||||
|
writeValue(static_cast<GLint>(block.activeVariables.size()));
|
||||||
|
break;
|
||||||
|
case GL_ACTIVE_VARIABLES:
|
||||||
|
for (const auto variable : block.activeVariables) writeValue(static_cast<GLint>(variable));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
writeValue(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (programInterface == GL_BUFFER_VARIABLE && index < cache.bufferVariables.size()) {
|
||||||
|
const auto& var = cache.bufferVariables[index];
|
||||||
|
switch (prop) {
|
||||||
|
case GL_NAME_LENGTH:
|
||||||
|
writeValue(static_cast<GLint>(var.name.size() + 1));
|
||||||
|
break;
|
||||||
|
case GL_TYPE:
|
||||||
|
writeValue(GL_FLOAT);
|
||||||
|
break;
|
||||||
|
case GL_ARRAY_SIZE:
|
||||||
|
writeValue(1);
|
||||||
|
break;
|
||||||
|
case GL_OFFSET:
|
||||||
|
writeValue(var.offset);
|
||||||
|
break;
|
||||||
|
case GL_BLOCK_INDEX:
|
||||||
|
writeValue(static_cast<GLint>(var.blockIndex));
|
||||||
|
break;
|
||||||
|
case GL_ARRAY_STRIDE:
|
||||||
|
case GL_MATRIX_STRIDE:
|
||||||
|
case GL_TOP_LEVEL_ARRAY_SIZE:
|
||||||
|
case GL_TOP_LEVEL_ARRAY_STRIDE:
|
||||||
|
case GL_IS_ROW_MAJOR:
|
||||||
|
writeValue(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
writeValue(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
writeValue(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (length) *length = written;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint GetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar* name) {
|
||||||
|
auto* programObject = TryGetDirectVulkanProgram(program);
|
||||||
|
if (!programObject || !name) return -1;
|
||||||
|
if (programInterface == GL_UNIFORM) {
|
||||||
|
return programObject->GetUniformLocation(name);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, const GLchar* name) {
|
||||||
|
(void)program;
|
||||||
|
(void)programInterface;
|
||||||
|
(void)name;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding) {
|
||||||
|
auto* programObject = TryGetDirectVulkanProgram(program);
|
||||||
|
if (!programObject) return;
|
||||||
|
auto& cache = GetProgramResourceCache(*programObject);
|
||||||
|
if (storageBlockIndex >= cache.storageBlocks.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cache.storageBlocks[storageBlockIndex].binding = storageBlockBinding;
|
||||||
|
}
|
||||||
|
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ReadPixels called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ReadPixels called with null GL context");
|
||||||
|
pVulkanRenderer->ReadPixels(x, y, width, height, format, type, pixels);
|
||||||
|
}
|
||||||
|
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GetTexImage called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::GetTexImage called with null GL context");
|
||||||
|
pVulkanRenderer->GetTexImage(target, level, format, type, pixels);
|
||||||
|
}
|
||||||
|
void GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget uploadTarget,
|
||||||
|
GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid* pixels) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GetTextureImage called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::GetTextureImage called with null GL context");
|
||||||
|
pVulkanRenderer->GetTextureImage(texture, uploadTarget, level, format, type, bufSize, pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear(GLbitfield mask) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Clear called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::Clear called with null GL context");
|
||||||
|
pVulkanRenderer->Clear(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawArrays(GLenum mode, GLint first, GLsizei count) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArrays called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawArrays called with null GL context");
|
||||||
|
|
||||||
|
DrawCmd payload{};
|
||||||
|
payload.mode = mode;
|
||||||
|
payload.params.firstVertex = first;
|
||||||
|
payload.params.vertexCount = count;
|
||||||
|
|
||||||
|
pVulkanRenderer->DrawArrays(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElements called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElements called with null GL context");
|
||||||
|
|
||||||
|
DrawIndexedCmd payload{};
|
||||||
|
payload.mode = mode;
|
||||||
|
payload.indexBufferView.indexType = type;
|
||||||
|
payload.indexBufferView.indexByteOffset = reinterpret_cast<SizeT>(indices);
|
||||||
|
payload.indexBufferView.indexByteSize = count * MG_Util::GetGLTypeSize(type);
|
||||||
|
payload.params.indexCount = count;
|
||||||
|
payload.params.instanceCount = 1;
|
||||||
|
|
||||||
|
pVulkanRenderer->DrawElements(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
||||||
|
GLsizei drawcount) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElements called with null GL context");
|
||||||
|
|
||||||
|
// Vector<DrawElementCmd> cmds;
|
||||||
|
// cmds.reserve(static_cast<SizeT>(drawcount));
|
||||||
|
// for (GLsizei i = 0; i < drawcount; ++i) {
|
||||||
|
// if (count[i] == 0) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// DrawElementCmd payload{};
|
||||||
|
// payload.mode = mode;
|
||||||
|
// payload.firstVertex = 0;
|
||||||
|
// payload.indexCount = count[i];
|
||||||
|
// payload.indexType = type;
|
||||||
|
// payload.indexByteOffset = reinterpret_cast<SizeT>(indices[i]);
|
||||||
|
// cmds.push_back(payload);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (cmds.empty()) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// pVulkanRenderer->MultiDrawElements(cmds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsBaseVertex called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElementsBaseVertex called with null GL context");
|
||||||
|
DrawIndexedCmd payload{};
|
||||||
|
payload.mode = mode;
|
||||||
|
payload.indexBufferView.indexType = type;
|
||||||
|
payload.indexBufferView.indexByteOffset = reinterpret_cast<SizeT>(indices);
|
||||||
|
payload.indexBufferView.indexByteSize = count * MG_Util::GetGLTypeSize(type);
|
||||||
|
payload.params.indexCount = count;
|
||||||
|
payload.params.instanceCount = 1;
|
||||||
|
payload.params.firstIndex = 0;
|
||||||
|
payload.params.vertexOffset = basevertex;
|
||||||
|
payload.params.firstInstance = 0;
|
||||||
|
pVulkanRenderer->DrawElements(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
||||||
|
GLsizei drawcount, const GLint* basevertex) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElements called with null GL context");
|
||||||
|
MultiDrawIndexedCmd payload{};
|
||||||
|
payload.mode = mode;
|
||||||
|
payload.indexBufferView.indexType = type;
|
||||||
|
|
||||||
|
// TODO: allocate draw cmd buf elsewhere
|
||||||
|
static Vector<DrawIndexedCmdParam> params;
|
||||||
|
params.clear();
|
||||||
|
params.resize(drawcount);
|
||||||
|
|
||||||
|
for (GLsizei i = 0; i < drawcount; ++i) {
|
||||||
|
if (count[i] == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this index view needs a redesign, now there's a lotta redundant uploads
|
||||||
|
|
||||||
|
payload.indexBufferView.indexByteOffset = 0;
|
||||||
|
payload.indexBufferView.indexByteSize =
|
||||||
|
std::max(reinterpret_cast<SizeT>(indices[i]) + count[i] * MG_Util::GetGLTypeSize(type),
|
||||||
|
payload.indexBufferView.indexByteSize);
|
||||||
|
|
||||||
|
auto& param = params[i];
|
||||||
|
|
||||||
|
param.indexCount = count[i];
|
||||||
|
param.instanceCount = 1;
|
||||||
|
param.firstIndex = reinterpret_cast<SizeT>(indices[i]) / MG_Util::GetGLTypeSize(type);
|
||||||
|
param.vertexOffset = basevertex[i];
|
||||||
|
param.firstInstance = 0;
|
||||||
|
}
|
||||||
|
payload.drawCount = drawcount;
|
||||||
|
payload.pParams = params.data();
|
||||||
|
pVulkanRenderer->MultiDrawElements(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||||
|
GLint dstY1, GLbitfield mask, GLenum filter) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitFramebuffer called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::BlitFramebuffer called with null GL context");
|
||||||
|
pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
|
||||||
|
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
|
||||||
|
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
|
||||||
|
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitNamedFramebuffer called with null VulkanRenderer");
|
||||||
|
pVulkanRenderer->BlitNamedFramebuffer(readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0,
|
||||||
|
dstY0, dstX1, dstY1, mask, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Present() {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Present called with null VulkanRenderer");
|
||||||
|
pVulkanRenderer->Present();
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
+38
-8
@@ -1,4 +1,4 @@
|
|||||||
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/DirectVulkanTMP.h
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/DirectVulkan.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,16 +8,19 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
#include "Renderer/VulkanRenderer.h"
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkanTMP {
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
namespace TmpImpl {
|
extern UniquePtr<VulkanRenderer> pVulkanRenderer;
|
||||||
class VulkanState;
|
|
||||||
} // namespace TmpImpl
|
|
||||||
|
|
||||||
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||||
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||||
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
||||||
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
|
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
|
||||||
|
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
|
||||||
|
GLint drawbuffer, const GLfloat* value);
|
||||||
|
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
|
||||||
|
GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||||
void Clear(GLbitfield mask);
|
void Clear(GLbitfield mask);
|
||||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
||||||
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
||||||
@@ -28,6 +31,10 @@ namespace MobileGL::MG_Backend::DirectVulkanTMP {
|
|||||||
GLsizei drawcount, const GLint* basevertex);
|
GLsizei drawcount, const GLint* basevertex);
|
||||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride);
|
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||||
|
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
|
||||||
|
GLsizei maxdrawcount, GLsizei stride);
|
||||||
|
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
|
||||||
|
GLsizei maxdrawcount, GLsizei stride);
|
||||||
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||||
const void* indices, GLint basevertex);
|
const void* indices, GLint basevertex);
|
||||||
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
|
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
|
||||||
@@ -45,14 +52,37 @@ namespace MobileGL::MG_Backend::DirectVulkanTMP {
|
|||||||
void DrawArraysIndirect(GLenum mode, const void* indirect);
|
void DrawArraysIndirect(GLenum mode, const void* indirect);
|
||||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||||
GLint dstY1, GLbitfield mask, GLenum filter);
|
GLint dstY1, GLbitfield mask, GLenum filter);
|
||||||
|
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
|
||||||
|
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
|
||||||
|
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||||
|
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||||
|
GLbitfield mask, GLenum filter);
|
||||||
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
||||||
GLsizei height, GLint border);
|
GLsizei height, GLint border);
|
||||||
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
||||||
GLsizei height);
|
GLsizei height);
|
||||||
void GenerateMipmap(GLenum target);
|
void GenerateMipmap(GLenum target);
|
||||||
|
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
|
||||||
|
void DispatchComputeIndirect(GLintptr indirect);
|
||||||
|
void MemoryBarrier(GLbitfield barriers);
|
||||||
|
void MemoryBarrierByRegion(GLbitfield barriers);
|
||||||
|
void BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access,
|
||||||
|
GLenum format);
|
||||||
|
void GetIntegeri_v(GLenum target, GLuint index, GLint* data);
|
||||||
|
void GetInteger64i_v(GLenum target, GLuint index, GLint64* data);
|
||||||
|
void GetProgramiv(GLuint program, GLenum pname, GLint* params);
|
||||||
|
void GetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint* params);
|
||||||
|
GLuint GetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar* name);
|
||||||
|
void GetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize,
|
||||||
|
GLsizei* length, GLchar* name);
|
||||||
|
void GetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount,
|
||||||
|
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params);
|
||||||
|
GLint GetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar* name);
|
||||||
|
GLint GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, const GLchar* name);
|
||||||
|
void ShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
|
||||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
||||||
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
|
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
|
||||||
Bool InitWindowSurface(NativeWindowType window);
|
void GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget uploadTarget,
|
||||||
|
GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid* pixels);
|
||||||
void Present();
|
void Present();
|
||||||
const TmpImpl::VulkanState& GetVulkanState();
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkanTMP
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/DirectVulkanResourceState.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Includes.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_State::GLState {
|
||||||
|
class ProgramObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
GLuint GetShaderStorageBlockIndex(const MG_State::GLState::ProgramObject& program, const String& name);
|
||||||
|
GLuint GetShaderStorageBlockBinding(const MG_State::GLState::ProgramObject& program, GLuint blockIndex);
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/BufferArena.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "BufferArena.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
Bool BufferArena::Initialize(const BufferArenaDesc& desc) {
|
||||||
|
Shutdown();
|
||||||
|
|
||||||
|
MOBILEGL_ASSERT(desc.allocator != nullptr, "BufferArena::Initialize requires valid allocator");
|
||||||
|
MOBILEGL_ASSERT(desc.frameCount > 0, "BufferArena::Initialize requires non-zero frame count");
|
||||||
|
MOBILEGL_ASSERT(desc.usage != 0, "BufferArena::Initialize requires non-zero buffer usage");
|
||||||
|
|
||||||
|
m_desc = desc;
|
||||||
|
m_frames.clear();
|
||||||
|
m_frames.resize(desc.frameCount);
|
||||||
|
m_deferredReleases.resize(desc.frameCount);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferArena::Shutdown() {
|
||||||
|
for (auto& frame : m_frames) {
|
||||||
|
frame.buffer.Destroy();
|
||||||
|
frame.writeCursor = 0;
|
||||||
|
}
|
||||||
|
m_frames.clear();
|
||||||
|
m_deferredReleases.clear();
|
||||||
|
m_desc = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferArena::BeginFrame(Uint32 frameIndex) {
|
||||||
|
CollectDeferredReleases(frameIndex);
|
||||||
|
ResetFrame(frameIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferArena::ResetFrame(Uint32 frameIndex) {
|
||||||
|
AssertValidFrameIndex(frameIndex);
|
||||||
|
m_frames[frameIndex].writeCursor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferArena::CollectDeferredReleases(Uint32 frameIndex) {
|
||||||
|
AssertValidFrameIndex(frameIndex);
|
||||||
|
m_deferredReleases[frameIndex].clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BufferArena::Allocate(Uint32 frameIndex, VkDeviceSize size, VkDeviceSize alignment, BufferSlice& outSlice) {
|
||||||
|
AssertValidFrameIndex(frameIndex);
|
||||||
|
MOBILEGL_ASSERT(size > 0, "BufferArena::Allocate requires non-zero size");
|
||||||
|
|
||||||
|
auto& frame = m_frames[frameIndex];
|
||||||
|
const VkDeviceSize resolvedAlignment = alignment > 0 ? alignment : 1;
|
||||||
|
const VkDeviceSize offset = (frame.writeCursor + resolvedAlignment - 1) & ~(resolvedAlignment - 1);
|
||||||
|
const VkDeviceSize endOffset = offset + size;
|
||||||
|
|
||||||
|
if (!EnsureCapacity(frameIndex, endOffset)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.writeCursor = endOffset;
|
||||||
|
outSlice = frame.buffer.GetSlice(offset, size);
|
||||||
|
return outSlice.IsValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BufferArena::Upload(Uint32 frameIndex, const void* data, VkDeviceSize size, VkDeviceSize alignment,
|
||||||
|
BufferSlice& outSlice) {
|
||||||
|
MOBILEGL_ASSERT(data != nullptr || size == 0, "BufferArena::Upload data pointer is null");
|
||||||
|
if (!Allocate(frameIndex, size, alignment, outSlice)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outSlice.mapped != nullptr) {
|
||||||
|
Memcpy(outSlice.mapped, data, static_cast<SizeT>(size));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_frames[frameIndex].buffer.Upload(data, size, outSlice.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceSize BufferArena::GetWriteCursor(Uint32 frameIndex) const {
|
||||||
|
AssertValidFrameIndex(frameIndex);
|
||||||
|
return m_frames[frameIndex].writeCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint32 BufferArena::GetFrameCount() const {
|
||||||
|
return static_cast<Uint32>(m_frames.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool BufferArena::EnsureCapacity(Uint32 frameIndex, VkDeviceSize requiredEndOffset) {
|
||||||
|
AssertValidFrameIndex(frameIndex);
|
||||||
|
auto& frame = m_frames[frameIndex];
|
||||||
|
auto& buffer = frame.buffer;
|
||||||
|
|
||||||
|
if (buffer.IsValid() && buffer.GetSize() >= requiredEndOffset) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceSize newCapacity = buffer.IsValid() ? buffer.GetSize() : 0;
|
||||||
|
if (newCapacity < m_desc.minBufferSize) {
|
||||||
|
newCapacity = m_desc.minBufferSize;
|
||||||
|
}
|
||||||
|
if (newCapacity == 0) {
|
||||||
|
newCapacity = requiredEndOffset;
|
||||||
|
}
|
||||||
|
while (newCapacity < requiredEndOffset) {
|
||||||
|
newCapacity *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer.IsValid()) {
|
||||||
|
m_deferredReleases[frameIndex].push_back(std::move(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBufferObjectDesc bufferDesc{};
|
||||||
|
bufferDesc.allocator = m_desc.allocator;
|
||||||
|
bufferDesc.size = newCapacity;
|
||||||
|
bufferDesc.usage = m_desc.usage;
|
||||||
|
bufferDesc.memoryUsage = m_desc.memoryUsage;
|
||||||
|
bufferDesc.allocationFlags = m_desc.allocationFlags;
|
||||||
|
if (!buffer.Create(bufferDesc)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (m_desc.persistentlyMapped && buffer.Map() == nullptr) {
|
||||||
|
buffer.Destroy();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.writeCursor = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferArena::AssertValidFrameIndex(Uint32 frameIndex) const {
|
||||||
|
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "BufferArena frame index out of range");
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/BufferArena.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BufferSlice.h"
|
||||||
|
#include "VkBufferObject.h"
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include <Includes.h>
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
struct BufferArenaDesc {
|
||||||
|
VmaAllocator allocator = nullptr;
|
||||||
|
Uint32 frameCount = 0;
|
||||||
|
VkBufferUsageFlags usage = 0;
|
||||||
|
VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
|
||||||
|
VmaAllocationCreateFlags allocationFlags = 0;
|
||||||
|
VkDeviceSize minBufferSize = 0;
|
||||||
|
Bool persistentlyMapped = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BufferArena {
|
||||||
|
public:
|
||||||
|
Bool Initialize(const BufferArenaDesc& desc);
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void BeginFrame(Uint32 frameIndex);
|
||||||
|
void ResetFrame(Uint32 frameIndex);
|
||||||
|
void CollectDeferredReleases(Uint32 frameIndex);
|
||||||
|
|
||||||
|
Bool Allocate(Uint32 frameIndex, VkDeviceSize size, VkDeviceSize alignment, BufferSlice& outSlice);
|
||||||
|
Bool Upload(Uint32 frameIndex, const void* data, VkDeviceSize size, VkDeviceSize alignment, BufferSlice& outSlice);
|
||||||
|
|
||||||
|
VkDeviceSize GetWriteCursor(Uint32 frameIndex) const;
|
||||||
|
Uint32 GetFrameCount() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct FrameResources {
|
||||||
|
VkBufferObject buffer;
|
||||||
|
VkDeviceSize writeCursor = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Bool EnsureCapacity(Uint32 frameIndex, VkDeviceSize requiredEndOffset);
|
||||||
|
void AssertValidFrameIndex(Uint32 frameIndex) const;
|
||||||
|
|
||||||
|
BufferArenaDesc m_desc{};
|
||||||
|
Vector<FrameResources> m_frames;
|
||||||
|
Vector<Vector<VkBufferObject>> m_deferredReleases;
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/BufferSlice.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include <Includes.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
struct BufferSlice {
|
||||||
|
VkBuffer buffer = VK_NULL_HANDLE;
|
||||||
|
VkDeviceSize offset = 0;
|
||||||
|
VkDeviceSize size = 0;
|
||||||
|
void* mapped = nullptr;
|
||||||
|
|
||||||
|
Bool IsValid() const { return buffer != VK_NULL_HANDLE; }
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,284 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "FrameContext.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
VkResult FrameContext::Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount) {
|
||||||
|
Destroy(device, commandPool);
|
||||||
|
m_frames.assign(frameCount, {});
|
||||||
|
currentFrameIndex = 0;
|
||||||
|
|
||||||
|
Vector<VkCommandBuffer> commandBuffers(frameCount, VK_NULL_HANDLE);
|
||||||
|
VkCommandBufferAllocateInfo allocInfo{};
|
||||||
|
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
allocInfo.commandPool = commandPool;
|
||||||
|
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
allocInfo.commandBufferCount = frameCount;
|
||||||
|
VkResult result = vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data());
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (Uint32 i = 0; i < frameCount; ++i) {
|
||||||
|
m_frames[i].commandBuffer = commandBuffers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSemaphoreCreateInfo semaphoreInfo{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
|
||||||
|
VkFenceCreateInfo fenceInfo{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
|
||||||
|
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
|
|
||||||
|
for (Uint32 i = 0; i < frameCount; ++i) {
|
||||||
|
result = CreateSyncObjectsForFrame(device, i, semaphoreInfo, fenceInfo);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
Destroy(device, commandPool);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::Destroy(VkDevice device, VkCommandPool commandPool) {
|
||||||
|
const Uint32 frameCount = static_cast<Uint32>(m_frames.size());
|
||||||
|
Vector<VkCommandBuffer> commandBuffers(frameCount, VK_NULL_HANDLE);
|
||||||
|
for (Uint32 i = 0; i < frameCount; ++i) {
|
||||||
|
commandBuffers[i] = m_frames[i].commandBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Uint32 i = 0; i < frameCount; ++i) {
|
||||||
|
DestroySyncObjectsForFrame(device, i);
|
||||||
|
}
|
||||||
|
DestroySwapchainSemaphores(device);
|
||||||
|
if (device != VK_NULL_HANDLE && commandPool != VK_NULL_HANDLE && !m_frames.empty()) {
|
||||||
|
vkFreeCommandBuffers(device, commandPool, frameCount, commandBuffers.data());
|
||||||
|
}
|
||||||
|
m_frames.clear();
|
||||||
|
currentFrameIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameContext::FrameData& FrameContext::GetCurrent() {
|
||||||
|
MOBILEGL_ASSERT(!m_frames.empty(), "FrameContext is not initialized");
|
||||||
|
return m_frames[currentFrameIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
const FrameContext::FrameData& FrameContext::GetCurrent() const {
|
||||||
|
MOBILEGL_ASSERT(!m_frames.empty(), "FrameContext is not initialized");
|
||||||
|
return m_frames[currentFrameIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool FrameContext::IsCommandRecording() const {
|
||||||
|
return GetCurrent().isCommandRecording;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::AdvanceToNext() {
|
||||||
|
MOBILEGL_ASSERT(!m_frames.empty(), "FrameContext is not initialized");
|
||||||
|
currentFrameIndex = (currentFrameIndex + 1) % static_cast<Uint32>(m_frames.size());
|
||||||
|
GetCurrent().isCommandRecording = false;
|
||||||
|
GetCurrent().hasCommandBufferRecorded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkCommandBuffer& FrameContext::BeginCommandRecording(VkCommandBufferUsageFlags flags,
|
||||||
|
const VkCommandBufferInheritanceInfo* pInheritanceInfo) {
|
||||||
|
auto& frame = GetCurrent();
|
||||||
|
MOBILEGL_ASSERT(!frame.isCommandRecording, "BeginCommandRecording called while command buffer is already recording");
|
||||||
|
|
||||||
|
frame.hasCommandBufferRecorded = false;
|
||||||
|
VK_VERIFY(vkResetCommandBuffer(frame.commandBuffer, 0), "BeginCommandRecording, vkResetCommandBuffer");
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo beginInfo{};
|
||||||
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
beginInfo.flags = flags;
|
||||||
|
beginInfo.pInheritanceInfo = pInheritanceInfo;
|
||||||
|
VK_VERIFY(vkBeginCommandBuffer(frame.commandBuffer, &beginInfo), "BeginCommandRecording, vkBeginCommandBuffer");
|
||||||
|
|
||||||
|
frame.isCommandRecording = true;
|
||||||
|
return frame.commandBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::EndCommandRecording() {
|
||||||
|
auto& frame = GetCurrent();
|
||||||
|
MOBILEGL_ASSERT(frame.isCommandRecording, "EndCommandRecording called without active command buffer recording");
|
||||||
|
VK_VERIFY(vkEndCommandBuffer(frame.commandBuffer), "EndCommandRecording, vkEndCommandBuffer");
|
||||||
|
frame.isCommandRecording = false;
|
||||||
|
frame.hasCommandBufferRecorded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult FrameContext::InitializeSwapchainSemaphores(VkDevice device, Uint32 swapchainImageCount) {
|
||||||
|
DestroySwapchainSemaphores(device);
|
||||||
|
if (swapchainImageCount == 0) {
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_swapchainImageRenderFinishedSemaphores.assign(swapchainImageCount, VK_NULL_HANDLE);
|
||||||
|
VkSemaphoreCreateInfo semaphoreInfo{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
|
||||||
|
for (Uint32 imageIndex = 0; imageIndex < swapchainImageCount; ++imageIndex) {
|
||||||
|
VkResult result =
|
||||||
|
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &m_swapchainImageRenderFinishedSemaphores[imageIndex]);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
DestroySwapchainSemaphores(device);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::DestroySwapchainSemaphores(VkDevice device) {
|
||||||
|
if (device != VK_NULL_HANDLE) {
|
||||||
|
for (auto semaphore : m_swapchainImageRenderFinishedSemaphores) {
|
||||||
|
if (semaphore != VK_NULL_HANDLE) {
|
||||||
|
vkDestroySemaphore(device, semaphore, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_swapchainImageRenderFinishedSemaphores.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool FrameContext::TransitionToPresent(VkImage image, VkImageLayout oldLayout, VkImageLayout presentLayout) {
|
||||||
|
auto& frame = GetCurrent();
|
||||||
|
if (frame.hasCommandBufferRecorded || frame.isCommandRecording || oldLayout == presentLayout ||
|
||||||
|
oldLayout == VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& commandBuffer = BeginCommandRecording();
|
||||||
|
|
||||||
|
VkImageMemoryBarrier presentBarrier{};
|
||||||
|
presentBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
presentBarrier.srcAccessMask = 0;
|
||||||
|
presentBarrier.dstAccessMask = 0;
|
||||||
|
presentBarrier.oldLayout = oldLayout;
|
||||||
|
presentBarrier.newLayout = presentLayout;
|
||||||
|
presentBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
presentBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
presentBarrier.image = image;
|
||||||
|
presentBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
presentBarrier.subresourceRange.baseMipLevel = 0;
|
||||||
|
presentBarrier.subresourceRange.levelCount = 1;
|
||||||
|
presentBarrier.subresourceRange.baseArrayLayer = 0;
|
||||||
|
presentBarrier.subresourceRange.layerCount = 1;
|
||||||
|
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0,
|
||||||
|
nullptr, 0, nullptr, 1, &presentBarrier);
|
||||||
|
|
||||||
|
EndCommandRecording();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameContext::SubmitInfoPacket FrameContext::GetSubmitInfo(Bool shouldSubmitCommandBuffer,
|
||||||
|
Uint32 swapchainImageIndex) const {
|
||||||
|
const auto& frame = GetCurrent();
|
||||||
|
MOBILEGL_ASSERT(!frame.isCommandRecording, "GetSubmitInfo called while command buffer recording is still active");
|
||||||
|
AssertValidSwapchainImageIndex(swapchainImageIndex);
|
||||||
|
SubmitInfoPacket packet{};
|
||||||
|
packet.waitSemaphore = frame.imageAvailableSemaphore;
|
||||||
|
packet.signalSemaphore = m_swapchainImageRenderFinishedSemaphores[swapchainImageIndex];
|
||||||
|
packet.commandBuffer = frame.commandBuffer;
|
||||||
|
|
||||||
|
packet.submitInfo.waitSemaphoreCount = frame.imageAvailableSemaphoreConsumed ? 0U : 1U;
|
||||||
|
packet.submitInfo.pWaitSemaphores = frame.imageAvailableSemaphoreConsumed ? nullptr : &packet.waitSemaphore;
|
||||||
|
packet.submitInfo.pWaitDstStageMask = frame.imageAvailableSemaphoreConsumed ? nullptr : &packet.waitDstStageMask;
|
||||||
|
packet.submitInfo.commandBufferCount = shouldSubmitCommandBuffer ? 1U : 0U;
|
||||||
|
packet.submitInfo.pCommandBuffers = shouldSubmitCommandBuffer ? &packet.commandBuffer : nullptr;
|
||||||
|
packet.submitInfo.signalSemaphoreCount = 1;
|
||||||
|
packet.submitInfo.pSignalSemaphores = &packet.signalSemaphore;
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameContext::PresentInfoPacket FrameContext::GetPresentInfo(VkSwapchainKHR swapchain, const Uint32& imageIndex) const {
|
||||||
|
AssertValidSwapchainImageIndex(imageIndex);
|
||||||
|
PresentInfoPacket packet{};
|
||||||
|
packet.waitSemaphore = m_swapchainImageRenderFinishedSemaphores[imageIndex];
|
||||||
|
packet.swapchain = swapchain;
|
||||||
|
packet.imageIndex = &imageIndex;
|
||||||
|
|
||||||
|
packet.presentInfo.waitSemaphoreCount = 1;
|
||||||
|
packet.presentInfo.pWaitSemaphores = &packet.waitSemaphore;
|
||||||
|
packet.presentInfo.swapchainCount = 1;
|
||||||
|
packet.presentInfo.pSwapchains = &packet.swapchain;
|
||||||
|
packet.presentInfo.pImageIndices = packet.imageIndex;
|
||||||
|
packet.presentInfo.pResults = nullptr;
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult FrameContext::WaitAndAcquireNextImage(VkDevice device, VkSwapchainKHR swapchain, Uint32& outImageIndex,
|
||||||
|
Uint64 timeout, VkFence acquireFence) {
|
||||||
|
auto& frame = GetCurrent();
|
||||||
|
VkResult result = vkWaitForFences(device, 1, &frame.imageInFlightFence, VK_TRUE, timeout);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = vkResetFences(device, 1, &frame.imageInFlightFence);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.imageAvailableSemaphoreConsumed = false;
|
||||||
|
return vkAcquireNextImageKHR(device, swapchain, timeout, frame.imageAvailableSemaphore, acquireFence,
|
||||||
|
&outImageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint32 FrameContext::GetCurrentFrameIndex() const {
|
||||||
|
return currentFrameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint32 FrameContext::GetFrameCount() const {
|
||||||
|
return static_cast<Uint32>(m_frames.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::AssertValidFrameIndex(Uint32 frameIndex) const {
|
||||||
|
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "FrameContext index out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::AssertValidSwapchainImageIndex(Uint32 imageIndex) const {
|
||||||
|
MOBILEGL_ASSERT(imageIndex < m_swapchainImageRenderFinishedSemaphores.size(),
|
||||||
|
"FrameContext swapchain image index out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult FrameContext::CreateSyncObjectsForFrame(VkDevice device, Uint32 frameIndex,
|
||||||
|
const VkSemaphoreCreateInfo& semaphoreInfo,
|
||||||
|
const VkFenceCreateInfo& fenceInfo) {
|
||||||
|
AssertValidFrameIndex(frameIndex);
|
||||||
|
DestroySyncObjectsForFrame(device, frameIndex);
|
||||||
|
|
||||||
|
auto& frame = m_frames[frameIndex];
|
||||||
|
VkResult result =
|
||||||
|
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &frame.imageAvailableSemaphore);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = vkCreateFence(device, &fenceInfo, nullptr, &frame.imageInFlightFence);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
vkDestroySemaphore(device, frame.imageAvailableSemaphore, nullptr);
|
||||||
|
frame.imageAvailableSemaphore = VK_NULL_HANDLE;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.hasCommandBufferRecorded = false;
|
||||||
|
frame.isCommandRecording = false;
|
||||||
|
frame.imageAvailableSemaphoreConsumed = false;
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameContext::DestroySyncObjectsForFrame(VkDevice device, Uint32 frameIndex) {
|
||||||
|
AssertValidFrameIndex(frameIndex);
|
||||||
|
auto& frame = m_frames[frameIndex];
|
||||||
|
if (device != VK_NULL_HANDLE && frame.imageInFlightFence != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyFence(device, frame.imageInFlightFence, nullptr);
|
||||||
|
}
|
||||||
|
frame.imageInFlightFence = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
if (device != VK_NULL_HANDLE && frame.imageAvailableSemaphore != VK_NULL_HANDLE) {
|
||||||
|
vkDestroySemaphore(device, frame.imageAvailableSemaphore, nullptr);
|
||||||
|
}
|
||||||
|
frame.imageAvailableSemaphore = VK_NULL_HANDLE;
|
||||||
|
frame.isCommandRecording = false;
|
||||||
|
frame.hasCommandBufferRecorded = false;
|
||||||
|
frame.imageAvailableSemaphoreConsumed = false;
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include <Includes.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
class FrameContext {
|
||||||
|
public:
|
||||||
|
struct SubmitInfoPacket {
|
||||||
|
VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
VkSemaphore waitSemaphore = VK_NULL_HANDLE;
|
||||||
|
VkSemaphore signalSemaphore = VK_NULL_HANDLE;
|
||||||
|
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
||||||
|
VkSubmitInfo submitInfo{VK_STRUCTURE_TYPE_SUBMIT_INFO};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PresentInfoPacket {
|
||||||
|
VkSemaphore waitSemaphore = VK_NULL_HANDLE;
|
||||||
|
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
||||||
|
const Uint32* imageIndex = nullptr;
|
||||||
|
VkPresentInfoKHR presentInfo{VK_STRUCTURE_TYPE_PRESENT_INFO_KHR};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FrameData {
|
||||||
|
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
||||||
|
VkSemaphore imageAvailableSemaphore = VK_NULL_HANDLE;
|
||||||
|
VkFence imageInFlightFence = VK_NULL_HANDLE;
|
||||||
|
Bool isCommandRecording = false;
|
||||||
|
Bool hasCommandBufferRecorded = false;
|
||||||
|
Bool imageAvailableSemaphoreConsumed = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
VkResult Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount);
|
||||||
|
void Destroy(VkDevice device, VkCommandPool commandPool);
|
||||||
|
|
||||||
|
// Lifecycle functions
|
||||||
|
FrameData& GetCurrent();
|
||||||
|
const FrameData& GetCurrent() const;
|
||||||
|
Bool IsCommandRecording() const;
|
||||||
|
void AdvanceToNext();
|
||||||
|
VkCommandBuffer& BeginCommandRecording(VkCommandBufferUsageFlags flags = 0,
|
||||||
|
const VkCommandBufferInheritanceInfo* pInheritanceInfo = nullptr);
|
||||||
|
void EndCommandRecording();
|
||||||
|
VkResult InitializeSwapchainSemaphores(VkDevice device, Uint32 swapchainImageCount);
|
||||||
|
void DestroySwapchainSemaphores(VkDevice device);
|
||||||
|
Bool TransitionToPresent(VkImage image, VkImageLayout oldLayout,
|
||||||
|
VkImageLayout presentLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||||
|
SubmitInfoPacket GetSubmitInfo(Bool shouldSubmitCommandBuffer, Uint32 swapchainImageIndex) const;
|
||||||
|
PresentInfoPacket GetPresentInfo(VkSwapchainKHR swapchain, const Uint32& imageIndex) const;
|
||||||
|
VkResult WaitAndAcquireNextImage(VkDevice device, VkSwapchainKHR swapchain, Uint32& outImageIndex,
|
||||||
|
Uint64 timeout = UINT64_MAX, VkFence acquireFence = VK_NULL_HANDLE);
|
||||||
|
|
||||||
|
Uint32 GetCurrentFrameIndex() const;
|
||||||
|
Uint32 GetFrameCount() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void AssertValidFrameIndex(Uint32 frameIndex) const;
|
||||||
|
void AssertValidSwapchainImageIndex(Uint32 imageIndex) const;
|
||||||
|
|
||||||
|
VkResult CreateSyncObjectsForFrame(VkDevice device, Uint32 frameIndex,
|
||||||
|
const VkSemaphoreCreateInfo& semaphoreInfo,
|
||||||
|
const VkFenceCreateInfo& fenceInfo);
|
||||||
|
void DestroySyncObjectsForFrame(VkDevice device, Uint32 frameIndex);
|
||||||
|
|
||||||
|
Vector<FrameData> m_frames;
|
||||||
|
Vector<VkSemaphore> m_swapchainImageRenderFinishedSemaphores;
|
||||||
|
Uint32 currentFrameIndex = 0;
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineFactory.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "PipelineFactory.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
PipelineFactory::PipelineFactory(VkDevice device, const VulkanRendererConfig& config):
|
||||||
|
m_device(device), m_config(config) {
|
||||||
|
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "PipelineFactory: device is null");
|
||||||
|
|
||||||
|
VkPipelineCacheCreateInfo pipelineCacheInfo{VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO};
|
||||||
|
VK_VERIFY(vkCreatePipelineCache(m_device, &pipelineCacheInfo, nullptr, &m_pipelineCache),
|
||||||
|
"vkCreatePipelineCache");
|
||||||
|
}
|
||||||
|
|
||||||
|
PipelineFactory::~PipelineFactory() {
|
||||||
|
DestroyAll();
|
||||||
|
if (m_pipelineCache != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyPipelineCache(m_device, m_pipelineCache, nullptr);
|
||||||
|
m_pipelineCache = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PipelineFactory::HashType PipelineFactory::ComputeHash(const PipelineCreatePayload& payload) const {
|
||||||
|
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.programHash, sizeof(payload.programHash)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.vertexInputHash, sizeof(payload.vertexInputHash)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.pipelineLayout, sizeof(payload.pipelineLayout)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.renderPass, sizeof(payload.renderPass)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.colorAttachmentCount, sizeof(payload.colorAttachmentCount)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.subpass, sizeof(payload.subpass)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.topology, sizeof(payload.topology)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.cullMode, sizeof(payload.cullMode)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.frontFace, sizeof(payload.frontFace)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthTestEnable, sizeof(payload.depthTestEnable)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthWriteEnable, sizeof(payload.depthWriteEnable)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthCompareOp, sizeof(payload.depthCompareOp)));
|
||||||
|
if (payload.colorAttachmentCount > 0) {
|
||||||
|
XXHASH_VERIFY(XXH64_update(
|
||||||
|
m_hashState,
|
||||||
|
payload.colorBlendAttachments.data(),
|
||||||
|
sizeof(payload.colorBlendAttachments[0]) * payload.colorAttachmentCount));
|
||||||
|
}
|
||||||
|
return XXH64_digest(m_hashState);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipeline PipelineFactory::GetOrCreatePipeline(const PipelineCreatePayload& payload) {
|
||||||
|
const HashType hash = ComputeHash(payload);
|
||||||
|
auto it = m_cache.find(hash);
|
||||||
|
if (it != m_cache.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipeline pipeline = CreatePipeline(payload);
|
||||||
|
m_cache.emplace(hash, pipeline);
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PipelineFactory::DestroyAll() {
|
||||||
|
for (auto& pair : m_cache) {
|
||||||
|
if (pair.second != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyPipeline(m_device, pair.second, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipeline PipelineFactory::CreatePipeline(const PipelineCreatePayload& payload) const {
|
||||||
|
MOBILEGL_ASSERT(payload.stages != nullptr && !payload.stages->empty(), "PipelineFactory: stages are empty");
|
||||||
|
MOBILEGL_ASSERT(payload.vertexInputState != nullptr, "PipelineFactory: vertexInputState is null");
|
||||||
|
MOBILEGL_ASSERT(payload.pipelineLayout != VK_NULL_HANDLE, "PipelineFactory: pipelineLayout is null");
|
||||||
|
MOBILEGL_ASSERT(payload.renderPass != VK_NULL_HANDLE, "PipelineFactory: renderPass is null");
|
||||||
|
MOBILEGL_ASSERT(payload.colorAttachmentCount <= PipelineCreatePayload::kMaxColorAttachments,
|
||||||
|
"PipelineFactory: colorAttachmentCount=%u is unexpectedly large",
|
||||||
|
payload.colorAttachmentCount);
|
||||||
|
MGLOG_D("PipelineFactory::CreatePipeline: programHash=0x%llx vertexInputHash=0x%llx colorAttachmentCount=%u subpass=%u",
|
||||||
|
static_cast<unsigned long long>(payload.programHash),
|
||||||
|
static_cast<unsigned long long>(payload.vertexInputHash),
|
||||||
|
payload.colorAttachmentCount,
|
||||||
|
payload.subpass);
|
||||||
|
|
||||||
|
static constexpr VkDynamicState kDynamicStates[] = {
|
||||||
|
VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
|
VK_DYNAMIC_STATE_SCISSOR
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineDynamicStateCreateInfo dynamicState{};
|
||||||
|
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||||
|
dynamicState.dynamicStateCount = static_cast<uint32_t>(std::size(kDynamicStates));
|
||||||
|
dynamicState.pDynamicStates = kDynamicStates;
|
||||||
|
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo ia{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO};
|
||||||
|
ia.topology = payload.topology;
|
||||||
|
|
||||||
|
VkPipelineViewportStateCreateInfo vpci{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO};
|
||||||
|
vpci.viewportCount = 1;
|
||||||
|
vpci.scissorCount = 1;
|
||||||
|
|
||||||
|
VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO};
|
||||||
|
raster.polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
raster.cullMode = payload.cullMode;
|
||||||
|
raster.frontFace = payload.frontFace;
|
||||||
|
raster.lineWidth = 1.0f;
|
||||||
|
|
||||||
|
VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO};
|
||||||
|
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
|
||||||
|
VkPipelineDepthStencilStateCreateInfo depthStencil{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO};
|
||||||
|
depthStencil.depthTestEnable = payload.depthTestEnable ? VK_TRUE : VK_FALSE;
|
||||||
|
depthStencil.depthWriteEnable = payload.depthWriteEnable ? VK_TRUE : VK_FALSE;
|
||||||
|
depthStencil.depthCompareOp = payload.depthCompareOp;
|
||||||
|
depthStencil.depthBoundsTestEnable = VK_FALSE;
|
||||||
|
depthStencil.stencilTestEnable = VK_FALSE;
|
||||||
|
|
||||||
|
Vector<VkPipelineColorBlendAttachmentState> colorAttachments(payload.colorAttachmentCount);
|
||||||
|
for (Uint32 i = 0; i < payload.colorAttachmentCount; ++i) {
|
||||||
|
colorAttachments[i] = payload.colorBlendAttachments[i];
|
||||||
|
}
|
||||||
|
VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
|
||||||
|
blend.attachmentCount = payload.colorAttachmentCount;
|
||||||
|
blend.pAttachments = colorAttachments.empty() ? nullptr : colorAttachments.data();
|
||||||
|
|
||||||
|
VkGraphicsPipelineCreateInfo gpi{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};
|
||||||
|
gpi.stageCount = static_cast<Uint32>(payload.stages->size());
|
||||||
|
gpi.pStages = payload.stages->data();
|
||||||
|
gpi.pVertexInputState = payload.vertexInputState;
|
||||||
|
gpi.pInputAssemblyState = &ia;
|
||||||
|
gpi.pViewportState = &vpci;
|
||||||
|
gpi.pRasterizationState = &raster;
|
||||||
|
gpi.pMultisampleState = &ms;
|
||||||
|
gpi.pDepthStencilState = &depthStencil;
|
||||||
|
gpi.pColorBlendState = &blend;
|
||||||
|
gpi.pDynamicState = &dynamicState;
|
||||||
|
gpi.layout = payload.pipelineLayout;
|
||||||
|
gpi.renderPass = payload.renderPass;
|
||||||
|
gpi.subpass = payload.subpass;
|
||||||
|
|
||||||
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
|
VK_VERIFY(vkCreateGraphicsPipelines(m_device, m_pipelineCache, 1, &gpi, nullptr, &pipeline),
|
||||||
|
"vkCreateGraphicsPipelines");
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineFactory.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include "MG_State/GLState/FramebufferState/FramebufferObject.h"
|
||||||
|
#include <Includes.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
class PipelineFactory {
|
||||||
|
public:
|
||||||
|
using HashType = Uint64;
|
||||||
|
|
||||||
|
struct PipelineCreatePayload {
|
||||||
|
static constexpr Uint32 kMaxColorAttachments = MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS;
|
||||||
|
|
||||||
|
HashType programHash = 0;
|
||||||
|
HashType vertexInputHash = 0;
|
||||||
|
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||||
|
Uint32 colorAttachmentCount = 1;
|
||||||
|
Uint32 subpass = 0;
|
||||||
|
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
|
||||||
|
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||||
|
Bool depthTestEnable = false;
|
||||||
|
Bool depthWriteEnable = false;
|
||||||
|
VkCompareOp depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
|
Array<VkPipelineColorBlendAttachmentState, kMaxColorAttachments> colorBlendAttachments{};
|
||||||
|
const Vector<VkPipelineShaderStageCreateInfo>* stages = nullptr;
|
||||||
|
const VkPipelineVertexInputStateCreateInfo* vertexInputState = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit PipelineFactory(VkDevice device, const VulkanRendererConfig& config);
|
||||||
|
~PipelineFactory();
|
||||||
|
PipelineFactory(const PipelineFactory&) = delete;
|
||||||
|
|
||||||
|
HashType ComputeHash(const PipelineCreatePayload& payload) const;
|
||||||
|
VkPipeline GetOrCreatePipeline(const PipelineCreatePayload& payload);
|
||||||
|
void DestroyAll();
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkPipeline CreatePipeline(const PipelineCreatePayload& payload) const;
|
||||||
|
|
||||||
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
const VulkanRendererConfig& m_config;
|
||||||
|
VkPipelineCache m_pipelineCache = VK_NULL_HANDLE;
|
||||||
|
UnorderedMap<HashType, VkPipeline> m_cache;
|
||||||
|
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,207 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
||||||
|
#include "MG_State/GLState/ProgramState/ShaderObject.h"
|
||||||
|
#include "MG_State/GLState/TextureState/TextureEnum.h"
|
||||||
|
|
||||||
|
#include <Includes.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
class ProgramFactory {
|
||||||
|
public:
|
||||||
|
enum class DescriptorBindingKind : Uint8 {
|
||||||
|
None = 0,
|
||||||
|
UniformBufferDynamic,
|
||||||
|
CombinedImageSampler,
|
||||||
|
UniformTexelBuffer,
|
||||||
|
StorageBuffer,
|
||||||
|
StorageImage
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CompileOptionBit : Uint {
|
||||||
|
None = 0,
|
||||||
|
PositionYFlip = 1 << 0,
|
||||||
|
PositionZRemap = 1 << 1,
|
||||||
|
SurfaceRotate90 = 1 << 2,
|
||||||
|
SurfaceRotate180 = 1 << 3,
|
||||||
|
SurfaceRotate270 = 1 << 4,
|
||||||
|
};
|
||||||
|
using CompileOptionFlags = Flags<CompileOptionBit>;
|
||||||
|
using HashType = Uint64;
|
||||||
|
|
||||||
|
struct VkProgramObject {
|
||||||
|
static constexpr Uint32 kMaxVertexInputLocations = 32;
|
||||||
|
|
||||||
|
HashType hash = 0;
|
||||||
|
Vector<VkPipelineShaderStageCreateInfo> stages;
|
||||||
|
Vector<VkShaderModule> modules;
|
||||||
|
|
||||||
|
// Layout data (previously in separate VkProgramLayout)
|
||||||
|
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
|
||||||
|
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
Vector<DescriptorBindingKind> bindingKinds;
|
||||||
|
Vector<Uint32> dynamicBindings;
|
||||||
|
Vector<Int> uniformBlockIndexByBinding;
|
||||||
|
Vector<String> samplerNameByBinding;
|
||||||
|
Vector<Int> samplerUniformLocationByBinding;
|
||||||
|
Vector<TextureTarget> samplerTextureTargetByBinding;
|
||||||
|
Vector<String> storageBlockNameByBinding;
|
||||||
|
Vector<Int> storageBlockIndexByBinding;
|
||||||
|
Int globalUboBinding = -1;
|
||||||
|
Uint32 activeVertexInputLocationMask = 0;
|
||||||
|
Array<GLenum, kMaxVertexInputLocations> vertexInputTypes{};
|
||||||
|
Uint32 activeFragmentOutputLocationMask = 0;
|
||||||
|
Array<GLenum, kMaxVertexInputLocations> fragmentOutputTypes{};
|
||||||
|
ShaderStage rasterizationProducerStage = ShaderStage::Unknown;
|
||||||
|
Uint32 producerOutputComponentCount = 0;
|
||||||
|
Uint32 fragmentInputComponentCount = 0;
|
||||||
|
|
||||||
|
static inline VkDevice s_device = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
VkProgramObject() = default;
|
||||||
|
VkProgramObject(const VkProgramObject&) = delete;
|
||||||
|
VkProgramObject& operator=(const VkProgramObject&) = delete;
|
||||||
|
VkProgramObject(VkProgramObject&& other) noexcept {
|
||||||
|
hash = other.hash;
|
||||||
|
stages = std::move(other.stages);
|
||||||
|
modules = std::move(other.modules);
|
||||||
|
descriptorSetLayout = other.descriptorSetLayout;
|
||||||
|
pipelineLayout = other.pipelineLayout;
|
||||||
|
bindingKinds = std::move(other.bindingKinds);
|
||||||
|
dynamicBindings = std::move(other.dynamicBindings);
|
||||||
|
uniformBlockIndexByBinding = std::move(other.uniformBlockIndexByBinding);
|
||||||
|
samplerNameByBinding = std::move(other.samplerNameByBinding);
|
||||||
|
samplerUniformLocationByBinding = std::move(other.samplerUniformLocationByBinding);
|
||||||
|
samplerTextureTargetByBinding = std::move(other.samplerTextureTargetByBinding);
|
||||||
|
storageBlockNameByBinding = std::move(other.storageBlockNameByBinding);
|
||||||
|
storageBlockIndexByBinding = std::move(other.storageBlockIndexByBinding);
|
||||||
|
globalUboBinding = other.globalUboBinding;
|
||||||
|
activeVertexInputLocationMask = other.activeVertexInputLocationMask;
|
||||||
|
vertexInputTypes = other.vertexInputTypes;
|
||||||
|
activeFragmentOutputLocationMask = other.activeFragmentOutputLocationMask;
|
||||||
|
fragmentOutputTypes = other.fragmentOutputTypes;
|
||||||
|
rasterizationProducerStage = other.rasterizationProducerStage;
|
||||||
|
producerOutputComponentCount = other.producerOutputComponentCount;
|
||||||
|
fragmentInputComponentCount = other.fragmentInputComponentCount;
|
||||||
|
other.hash = 0;
|
||||||
|
other.descriptorSetLayout = VK_NULL_HANDLE;
|
||||||
|
other.pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
other.globalUboBinding = -1;
|
||||||
|
other.activeVertexInputLocationMask = 0;
|
||||||
|
other.activeFragmentOutputLocationMask = 0;
|
||||||
|
other.rasterizationProducerStage = ShaderStage::Unknown;
|
||||||
|
other.producerOutputComponentCount = 0;
|
||||||
|
other.fragmentInputComponentCount = 0;
|
||||||
|
}
|
||||||
|
VkProgramObject& operator=(VkProgramObject&& other) noexcept {
|
||||||
|
if (this == &other) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Destroy();
|
||||||
|
hash = other.hash;
|
||||||
|
stages = std::move(other.stages);
|
||||||
|
modules = std::move(other.modules);
|
||||||
|
descriptorSetLayout = other.descriptorSetLayout;
|
||||||
|
pipelineLayout = other.pipelineLayout;
|
||||||
|
bindingKinds = std::move(other.bindingKinds);
|
||||||
|
dynamicBindings = std::move(other.dynamicBindings);
|
||||||
|
uniformBlockIndexByBinding = std::move(other.uniformBlockIndexByBinding);
|
||||||
|
samplerNameByBinding = std::move(other.samplerNameByBinding);
|
||||||
|
samplerUniformLocationByBinding = std::move(other.samplerUniformLocationByBinding);
|
||||||
|
samplerTextureTargetByBinding = std::move(other.samplerTextureTargetByBinding);
|
||||||
|
storageBlockNameByBinding = std::move(other.storageBlockNameByBinding);
|
||||||
|
storageBlockIndexByBinding = std::move(other.storageBlockIndexByBinding);
|
||||||
|
globalUboBinding = other.globalUboBinding;
|
||||||
|
activeVertexInputLocationMask = other.activeVertexInputLocationMask;
|
||||||
|
vertexInputTypes = other.vertexInputTypes;
|
||||||
|
activeFragmentOutputLocationMask = other.activeFragmentOutputLocationMask;
|
||||||
|
fragmentOutputTypes = other.fragmentOutputTypes;
|
||||||
|
rasterizationProducerStage = other.rasterizationProducerStage;
|
||||||
|
producerOutputComponentCount = other.producerOutputComponentCount;
|
||||||
|
fragmentInputComponentCount = other.fragmentInputComponentCount;
|
||||||
|
other.hash = 0;
|
||||||
|
other.descriptorSetLayout = VK_NULL_HANDLE;
|
||||||
|
other.pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
other.globalUboBinding = -1;
|
||||||
|
other.activeVertexInputLocationMask = 0;
|
||||||
|
other.activeFragmentOutputLocationMask = 0;
|
||||||
|
other.rasterizationProducerStage = ShaderStage::Unknown;
|
||||||
|
other.producerOutputComponentCount = 0;
|
||||||
|
other.fragmentInputComponentCount = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~VkProgramObject() {
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Destroy() {
|
||||||
|
if (s_device != VK_NULL_HANDLE) {
|
||||||
|
if (pipelineLayout != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyPipelineLayout(s_device, pipelineLayout, nullptr);
|
||||||
|
pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
if (descriptorSetLayout != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyDescriptorSetLayout(s_device, descriptorSetLayout, nullptr);
|
||||||
|
descriptorSetLayout = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
for (auto module : modules) {
|
||||||
|
if (module != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyShaderModule(s_device, module, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modules.clear();
|
||||||
|
stages.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit ProgramFactory(VkDevice device, const VulkanRendererConfig& config, Uint32 maxBindings = 16)
|
||||||
|
: m_device(device), m_config(config), m_maxBindings(maxBindings) {
|
||||||
|
VkProgramObject::s_device = device;
|
||||||
|
}
|
||||||
|
~ProgramFactory() = default;
|
||||||
|
ProgramFactory(const ProgramFactory&) = delete;
|
||||||
|
|
||||||
|
HashType ComputeHash(const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags) const;
|
||||||
|
const VkProgramObject& GetOrCreateProgram(
|
||||||
|
const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags);
|
||||||
|
|
||||||
|
static VkShaderStageFlagBits ToVkStage(ShaderStage stage);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ProgramLookupCache {
|
||||||
|
const MG_State::GLState::ProgramObject* program = nullptr;
|
||||||
|
Uint32 backendStateVersion = 0;
|
||||||
|
CompileOptionFlags flags{};
|
||||||
|
HashType hash = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static TextureTarget UniformTypeToTextureTarget(GLenum glType);
|
||||||
|
void ReflectVertexInputs(const Vector<SharedPtr<MG_State::GLState::ShaderObject>>& shaders,
|
||||||
|
const Vector<Vector<Uint>>& spirv,
|
||||||
|
VkProgramObject& entry) const;
|
||||||
|
void ReflectFragmentOutputs(const Vector<SharedPtr<MG_State::GLState::ShaderObject>>& shaders,
|
||||||
|
const Vector<Vector<Uint>>& spirv,
|
||||||
|
VkProgramObject& entry) const;
|
||||||
|
void ReflectLayout(const MG_State::GLState::ProgramObject& program, const Vector<Vector<Uint>>& spirv,
|
||||||
|
VkProgramObject& entry) const;
|
||||||
|
|
||||||
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
Uint32 m_maxBindings = 0;
|
||||||
|
UnorderedMap<HashType, VkProgramObject> m_cache;
|
||||||
|
const VulkanRendererConfig& m_config;
|
||||||
|
mutable ProgramLookupCache m_lastLookup;
|
||||||
|
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,433 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "SwapchainObject.h"
|
||||||
|
|
||||||
|
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
||||||
|
#include "MG_State/GLState/TextureState/TextureObject2D.h"
|
||||||
|
|
||||||
|
#if defined(__has_include)
|
||||||
|
#if __has_include(<vulkan/vk_enum_string_helper.h>)
|
||||||
|
#include <vulkan/vk_enum_string_helper.h>
|
||||||
|
#define MOBILEGL_HAS_VK_ENUM_STRING_HELPER 1
|
||||||
|
#else
|
||||||
|
#define MOBILEGL_HAS_VK_ENUM_STRING_HELPER 0
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define MOBILEGL_HAS_VK_ENUM_STRING_HELPER 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !MOBILEGL_HAS_VK_ENUM_STRING_HELPER
|
||||||
|
static const char* string_VkFormat(VkFormat) {
|
||||||
|
return "VkFormat(unknown)";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* string_VkColorSpaceKHR(VkColorSpaceKHR) {
|
||||||
|
return "VkColorSpaceKHR(unknown)";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* string_VkPresentModeKHR(VkPresentModeKHR) {
|
||||||
|
return "VkPresentModeKHR(unknown)";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* string_VkSurfaceTransformFlagBitsKHR(VkSurfaceTransformFlagBitsKHR) {
|
||||||
|
return "VkSurfaceTransformFlagBitsKHR(unknown)";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
namespace {
|
||||||
|
Bool HasStencilComponent(VkFormat format) {
|
||||||
|
return format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkFormat FindSupportedDepthStencilFormat(VkPhysicalDevice physicalDevice) {
|
||||||
|
const VkFormat candidates[] = {VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT,
|
||||||
|
VK_FORMAT_D32_SFLOAT};
|
||||||
|
for (VkFormat format : candidates) {
|
||||||
|
VkFormatProperties props{};
|
||||||
|
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props);
|
||||||
|
if ((props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return VK_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint32 FindMemoryType(VkPhysicalDevice physicalDevice, Uint32 typeFilter, VkMemoryPropertyFlags properties) {
|
||||||
|
VkPhysicalDeviceMemoryProperties memProperties{};
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
|
||||||
|
|
||||||
|
for (Uint32 i = 0; i < memProperties.memoryTypeCount; i++) {
|
||||||
|
if ((typeFilter & (1 << i)) &&
|
||||||
|
(memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_ASSERT(false, "Failed to find suitable memory type.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
SwapchainObject::SwapchainCapabilities SwapchainObject::GetSwapchainCapabilities(VkPhysicalDevice physicalDevice,
|
||||||
|
VkSurfaceKHR surface) {
|
||||||
|
SwapchainCapabilities swapchainCapabilities{};
|
||||||
|
|
||||||
|
VK_VERIFY(
|
||||||
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &swapchainCapabilities.capabilities));
|
||||||
|
|
||||||
|
Uint32 formatCount = 0;
|
||||||
|
VK_VERIFY(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr));
|
||||||
|
if (formatCount != 0) {
|
||||||
|
swapchainCapabilities.surfaceFormats.resize(formatCount);
|
||||||
|
VK_VERIFY(vkGetPhysicalDeviceSurfaceFormatsKHR(
|
||||||
|
physicalDevice, surface, &formatCount, swapchainCapabilities.surfaceFormats.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint32 presentModeCount = 0;
|
||||||
|
VK_VERIFY(
|
||||||
|
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr));
|
||||||
|
if (presentModeCount != 0) {
|
||||||
|
swapchainCapabilities.presentModes.resize(presentModeCount);
|
||||||
|
VK_VERIFY(vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||||
|
physicalDevice, surface, &presentModeCount, swapchainCapabilities.presentModes.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return swapchainCapabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR SwapchainObject::ChooseSwapchainSurfaceFormat(
|
||||||
|
const Vector<VkSurfaceFormatKHR>& availableFormats) {
|
||||||
|
for (const auto& availableFormat : availableFormats) {
|
||||||
|
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB &&
|
||||||
|
availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
||||||
|
return availableFormat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Properly rank other formats
|
||||||
|
return availableFormats[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPresentModeKHR SwapchainObject::ChooseSwapchainPresentMode(
|
||||||
|
const Vector<VkPresentModeKHR>& availablePresentModes) {
|
||||||
|
for (auto desiredPresentMode : s_desiredPresentModes) {
|
||||||
|
for (const auto& presentMode : availablePresentModes) {
|
||||||
|
if (presentMode == desiredPresentMode) {
|
||||||
|
return presentMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Properly rank other modes
|
||||||
|
return availablePresentModes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapchainObject::Create(VkDevice device, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
|
||||||
|
Uint32 graphicsQueueFamily, Uint32 presentQueueFamily, Uint32 minImageCountHint) {
|
||||||
|
const auto swapchainCapabilities = GetSwapchainCapabilities(physicalDevice, surface);
|
||||||
|
MOBILEGL_ASSERT(swapchainCapabilities.IsComplete(),
|
||||||
|
"SwapchainObject::Create failed: incomplete swapchain capabilities");
|
||||||
|
|
||||||
|
MGLOG_I("Got %d surface formats:", swapchainCapabilities.surfaceFormats.size());
|
||||||
|
for (const auto& sf : swapchainCapabilities.surfaceFormats) {
|
||||||
|
MGLOG_I(" [%s, %s]", string_VkFormat(sf.format), string_VkColorSpaceKHR(sf.colorSpace));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto pickedSurfaceFormat = ChooseSwapchainSurfaceFormat(swapchainCapabilities.surfaceFormats);
|
||||||
|
MGLOG_I("Picked surface format: [%s, %s]", string_VkFormat(pickedSurfaceFormat.format),
|
||||||
|
string_VkColorSpaceKHR(pickedSurfaceFormat.colorSpace));
|
||||||
|
|
||||||
|
MGLOG_I("Got %d present modes:", swapchainCapabilities.presentModes.size());
|
||||||
|
for (const auto& pm : swapchainCapabilities.presentModes) {
|
||||||
|
MGLOG_I(" %s", string_VkPresentModeKHR(pm));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto presentMode = ChooseSwapchainPresentMode(swapchainCapabilities.presentModes);
|
||||||
|
MGLOG_I("Picked present mode: %s", string_VkPresentModeKHR(presentMode));
|
||||||
|
|
||||||
|
const auto& swapchainCaps = swapchainCapabilities.capabilities;
|
||||||
|
const auto targetImageCount = std::max<Uint32>(minImageCountHint, swapchainCaps.minImageCount);
|
||||||
|
MGLOG_I("Set minImageCount = %u", targetImageCount);
|
||||||
|
MGLOG_I("Swapchain currentTransform = %s",
|
||||||
|
string_VkSurfaceTransformFlagBitsKHR(swapchainCaps.currentTransform));
|
||||||
|
|
||||||
|
VkSwapchainCreateInfoKHR createInfo{VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};
|
||||||
|
createInfo.surface = surface;
|
||||||
|
createInfo.minImageCount = targetImageCount;
|
||||||
|
createInfo.imageFormat = pickedSurfaceFormat.format;
|
||||||
|
createInfo.imageColorSpace = pickedSurfaceFormat.colorSpace;
|
||||||
|
createInfo.imageExtent = swapchainCaps.currentExtent;
|
||||||
|
if (swapchainCaps.currentTransform == VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR ||
|
||||||
|
swapchainCaps.currentTransform == VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
|
||||||
|
std::swap(createInfo.imageExtent.width, createInfo.imageExtent.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
createInfo.imageArrayLayers = 1;
|
||||||
|
const VkImageUsageFlags requiredImageUsage =
|
||||||
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
|
MOBILEGL_ASSERT((swapchainCaps.supportedUsageFlags & requiredImageUsage) == requiredImageUsage,
|
||||||
|
"Swapchain does not support required usage flags (COLOR_ATTACHMENT | TRANSFER_DST). "
|
||||||
|
"supportedUsageFlags=0x%x",
|
||||||
|
static_cast<Uint32>(swapchainCaps.supportedUsageFlags));
|
||||||
|
|
||||||
|
VkImageUsageFlags imageUsage = requiredImageUsage;
|
||||||
|
if ((swapchainCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) != 0) {
|
||||||
|
imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
}
|
||||||
|
createInfo.imageUsage = imageUsage;
|
||||||
|
MGLOG_I("Swapchain imageUsage = 0x%x (supportedUsageFlags = 0x%x)", static_cast<Uint32>(createInfo.imageUsage),
|
||||||
|
static_cast<Uint32>(swapchainCaps.supportedUsageFlags));
|
||||||
|
Uint32 queueFamilyIndices[] = {graphicsQueueFamily, presentQueueFamily};
|
||||||
|
if (graphicsQueueFamily != presentQueueFamily) {
|
||||||
|
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
|
createInfo.queueFamilyIndexCount = 2;
|
||||||
|
createInfo.pQueueFamilyIndices = queueFamilyIndices;
|
||||||
|
} else {
|
||||||
|
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
createInfo.queueFamilyIndexCount = 0;
|
||||||
|
createInfo.pQueueFamilyIndices = nullptr;
|
||||||
|
}
|
||||||
|
createInfo.preTransform = swapchainCaps.currentTransform;
|
||||||
|
MGLOG_I("Set swapchain preTransform = %s", string_VkSurfaceTransformFlagBitsKHR(createInfo.preTransform));
|
||||||
|
const VkCompositeAlphaFlagBitsKHR compositeAlphaCandidates[] = {
|
||||||
|
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||||
|
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
|
||||||
|
VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
|
||||||
|
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
|
||||||
|
};
|
||||||
|
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
|
for (auto candidate : compositeAlphaCandidates) {
|
||||||
|
if ((swapchainCaps.supportedCompositeAlpha & candidate) != 0) {
|
||||||
|
createInfo.compositeAlpha = candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createInfo.presentMode = presentMode;
|
||||||
|
createInfo.clipped = VK_TRUE;
|
||||||
|
createInfo.oldSwapchain = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
m_surfaceFormat = {createInfo.imageFormat, createInfo.imageColorSpace};
|
||||||
|
m_extent = createInfo.imageExtent;
|
||||||
|
m_preTransform = createInfo.preTransform;
|
||||||
|
|
||||||
|
VK_VERIFY(vkCreateSwapchainKHR(device, &createInfo, nullptr, &m_swapchain));
|
||||||
|
|
||||||
|
Uint32 imageCount = 0;
|
||||||
|
VK_VERIFY(vkGetSwapchainImagesKHR(device, m_swapchain, &imageCount, nullptr));
|
||||||
|
|
||||||
|
m_images.resize(imageCount, VK_NULL_HANDLE);
|
||||||
|
VK_VERIFY(vkGetSwapchainImagesKHR(device, m_swapchain, &imageCount, m_images.data()));
|
||||||
|
m_imageLayouts.assign(imageCount, VK_IMAGE_LAYOUT_UNDEFINED);
|
||||||
|
|
||||||
|
CreateImageViews(device);
|
||||||
|
CreateDepthStencilResources(device, physicalDevice);
|
||||||
|
|
||||||
|
MGLOG_I("Swapchain created, extent = %dx%d, swapchain imageCount = %d", m_extent.width, m_extent.height,
|
||||||
|
imageCount);
|
||||||
|
|
||||||
|
// Properly initialize Default FBO here
|
||||||
|
auto& defaultFBOInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||||
|
auto* colorTex = static_cast<MG_State::GLState::TextureObject2D*>(defaultFBOInfo->colorAttachment.get());
|
||||||
|
colorTex->AllocateStorage(
|
||||||
|
TextureUploadTarget::Texture2D, 0, {
|
||||||
|
{(Int)createInfo.imageExtent.width, (Int)createInfo.imageExtent.height, 1},
|
||||||
|
createInfo.imageExtent.width * (Int)createInfo.imageExtent.height * 4}); // TODO: 4 is format size
|
||||||
|
TextureInternalFormat depthFormat = TextureInternalFormat::Depth24Stencil8;
|
||||||
|
switch (m_depthStencilFormat) {
|
||||||
|
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||||
|
depthFormat = TextureInternalFormat::Depth24Stencil8;
|
||||||
|
break;
|
||||||
|
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||||
|
depthFormat = TextureInternalFormat::Depth32FStencil8;
|
||||||
|
break;
|
||||||
|
case VK_FORMAT_D32_SFLOAT:
|
||||||
|
depthFormat = TextureInternalFormat::DepthComponent32F;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
depthFormat = TextureInternalFormat::Depth24Stencil8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto* depthTex = static_cast<MG_State::GLState::TextureObject2D*>(defaultFBOInfo->depthAttachment.get());
|
||||||
|
depthTex->SetInternalFormat(depthFormat);
|
||||||
|
depthTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, {
|
||||||
|
{(Int)createInfo.imageExtent.width, (Int)createInfo.imageExtent.height, 1},
|
||||||
|
createInfo.imageExtent.width * createInfo.imageExtent.width * 4}); // TODO: 4 is format size
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapchainObject::CreateDepthStencilResources(VkDevice device, VkPhysicalDevice physicalDevice) {
|
||||||
|
DestroyDepthStencilResources(device);
|
||||||
|
|
||||||
|
const auto imageCount = static_cast<Uint32>(m_images.size());
|
||||||
|
if (imageCount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_depthStencilFormat = FindSupportedDepthStencilFormat(physicalDevice);
|
||||||
|
MOBILEGL_ASSERT(m_depthStencilFormat != VK_FORMAT_UNDEFINED, "No supported depth/stencil format found.");
|
||||||
|
|
||||||
|
m_depthStencilImages.assign(imageCount, VK_NULL_HANDLE);
|
||||||
|
m_depthStencilImageMemories.assign(imageCount, VK_NULL_HANDLE);
|
||||||
|
m_depthStencilImageViews.assign(imageCount, VK_NULL_HANDLE);
|
||||||
|
m_depthStencilImageLayouts.assign(imageCount, VK_IMAGE_LAYOUT_UNDEFINED);
|
||||||
|
|
||||||
|
for (Uint32 i = 0; i < imageCount; ++i) {
|
||||||
|
VkImageCreateInfo imageInfo{};
|
||||||
|
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
|
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
imageInfo.extent.width = m_extent.width;
|
||||||
|
imageInfo.extent.height = m_extent.height;
|
||||||
|
imageInfo.extent.depth = 1;
|
||||||
|
imageInfo.mipLevels = 1;
|
||||||
|
imageInfo.arrayLayers = 1;
|
||||||
|
imageInfo.format = m_depthStencilFormat;
|
||||||
|
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
|
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
VK_VERIFY(vkCreateImage(device, &imageInfo, nullptr, &m_depthStencilImages[i]), "vkCreateImage(depth)");
|
||||||
|
|
||||||
|
VkMemoryRequirements memRequirements{};
|
||||||
|
vkGetImageMemoryRequirements(device, m_depthStencilImages[i], &memRequirements);
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo allocInfo{};
|
||||||
|
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
|
allocInfo.allocationSize = memRequirements.size;
|
||||||
|
allocInfo.memoryTypeIndex =
|
||||||
|
FindMemoryType(physicalDevice, memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
VK_VERIFY(vkAllocateMemory(device, &allocInfo, nullptr, &m_depthStencilImageMemories[i]),
|
||||||
|
"vkAllocateMemory(depth)");
|
||||||
|
VK_VERIFY(vkBindImageMemory(device, m_depthStencilImages[i], m_depthStencilImageMemories[i], 0),
|
||||||
|
"vkBindImageMemory(depth)");
|
||||||
|
|
||||||
|
VkImageViewCreateInfo viewInfo{};
|
||||||
|
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
viewInfo.image = m_depthStencilImages[i];
|
||||||
|
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
viewInfo.format = m_depthStencilFormat;
|
||||||
|
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
if (HasStencilComponent(m_depthStencilFormat)) {
|
||||||
|
viewInfo.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
}
|
||||||
|
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||||
|
viewInfo.subresourceRange.levelCount = 1;
|
||||||
|
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
|
viewInfo.subresourceRange.layerCount = 1;
|
||||||
|
VK_VERIFY(vkCreateImageView(device, &viewInfo, nullptr, &m_depthStencilImageViews[i]),
|
||||||
|
"vkCreateImageView(depth)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapchainObject::DestroyDepthStencilResources(VkDevice device) {
|
||||||
|
for (auto view : m_depthStencilImageViews) {
|
||||||
|
if (view != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyImageView(device, view, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_depthStencilImageViews.clear();
|
||||||
|
|
||||||
|
for (auto image : m_depthStencilImages) {
|
||||||
|
if (image != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyImage(device, image, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_depthStencilImages.clear();
|
||||||
|
|
||||||
|
for (auto memory : m_depthStencilImageMemories) {
|
||||||
|
if (memory != VK_NULL_HANDLE) {
|
||||||
|
vkFreeMemory(device, memory, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_depthStencilImageMemories.clear();
|
||||||
|
m_depthStencilImageLayouts.clear();
|
||||||
|
m_depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapchainObject::Shutdown(VkDevice device) {
|
||||||
|
DestroyDepthStencilResources(device);
|
||||||
|
|
||||||
|
for (auto imageView : m_imageViews) {
|
||||||
|
vkDestroyImageView(device, imageView, nullptr);
|
||||||
|
}
|
||||||
|
m_imageViews.clear();
|
||||||
|
|
||||||
|
if (m_swapchain != VK_NULL_HANDLE) {
|
||||||
|
vkDestroySwapchainKHR(device, m_swapchain, nullptr);
|
||||||
|
m_swapchain = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_images.clear();
|
||||||
|
m_imageLayouts.clear();
|
||||||
|
m_preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImage SwapchainObject::GetImage(Uint32 index) const {
|
||||||
|
MOBILEGL_ASSERT(index < m_images.size(), "Swapchain image index out of range");
|
||||||
|
return m_images[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageLayout SwapchainObject::GetImageLayout(Uint32 index) const {
|
||||||
|
MOBILEGL_ASSERT(index < m_imageLayouts.size(), "Swapchain image layout index out of range");
|
||||||
|
return m_imageLayouts[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapchainObject::SetImageLayout(Uint32 index, VkImageLayout layout) {
|
||||||
|
MOBILEGL_ASSERT(index < m_imageLayouts.size(), "Swapchain image layout index out of range");
|
||||||
|
m_imageLayouts[index] = layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImage SwapchainObject::GetDepthStencilImage(Uint32 index) const {
|
||||||
|
MOBILEGL_ASSERT(index < m_depthStencilImages.size(), "Swapchain depth/stencil image index out of range");
|
||||||
|
return m_depthStencilImages[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageView SwapchainObject::GetDepthStencilImageView(Uint32 index) const {
|
||||||
|
MOBILEGL_ASSERT(index < m_depthStencilImageViews.size(),
|
||||||
|
"Swapchain depth/stencil image view index out of range");
|
||||||
|
return m_depthStencilImageViews[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageLayout SwapchainObject::GetDepthStencilImageLayout(Uint32 index) const {
|
||||||
|
MOBILEGL_ASSERT(index < m_depthStencilImageLayouts.size(),
|
||||||
|
"Swapchain depth/stencil image layout index out of range");
|
||||||
|
return m_depthStencilImageLayouts[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapchainObject::SetDepthStencilImageLayout(Uint32 index, VkImageLayout layout) {
|
||||||
|
MOBILEGL_ASSERT(index < m_depthStencilImageLayouts.size(),
|
||||||
|
"Swapchain depth/stencil image layout index out of range");
|
||||||
|
m_depthStencilImageLayouts[index] = layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapchainObject::CreateImageViews(VkDevice device) {
|
||||||
|
m_imageViews.resize(m_images.size(), VK_NULL_HANDLE);
|
||||||
|
for (SizeT i = 0; i < m_imageViews.size(); i++) {
|
||||||
|
VkImageViewCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
createInfo.image = m_images[i];
|
||||||
|
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
createInfo.format = m_surfaceFormat.format;
|
||||||
|
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
createInfo.subresourceRange.baseMipLevel = 0;
|
||||||
|
createInfo.subresourceRange.levelCount = 1;
|
||||||
|
createInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
|
createInfo.subresourceRange.layerCount = 1;
|
||||||
|
VK_VERIFY(vkCreateImageView(device, &createInfo, nullptr, &m_imageViews[i]));
|
||||||
|
}
|
||||||
|
MGLOG_I("Swapchain image views created");
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef VK_VERIFY
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
// 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
|
||||||
@@ -0,0 +1,953 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "UniformManager.h"
|
||||||
|
|
||||||
|
#include "MG_Backend/DirectVulkan/DirectVulkanResourceState.h"
|
||||||
|
#include "MG_State/GLState/Core.h"
|
||||||
|
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
||||||
|
#include "MG_State/GLState/TextureState/TextureObject2D.h"
|
||||||
|
#include "MG_State/GLState/TextureState/TextureObjectBuffer.h"
|
||||||
|
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
|
||||||
|
#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
|
||||||
|
#include "MG_Util/Metrics/TextureMetrics.h"
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
namespace {
|
||||||
|
constexpr Uint kFallbackTexture2DExternalIndex = 0xFFFFFF00u;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool FindFramebufferAttachmentForTexture(const MG_State::GLState::FramebufferObject& framebuffer,
|
||||||
|
const MG_State::GLState::ITextureObject& texture,
|
||||||
|
FramebufferAttachmentType& outAttachment, Int& outLevel) {
|
||||||
|
const auto& attachments = framebuffer.GetAllAttachmentObjects();
|
||||||
|
for (SizeT i = 0; i < attachments.size(); ++i) {
|
||||||
|
const auto attachmentType = static_cast<FramebufferAttachmentType>(i);
|
||||||
|
if (attachmentType == FramebufferAttachmentType::None) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& attachment = attachments[i];
|
||||||
|
if (!attachment.IsTexture()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto attachedTexture = attachment.GetTexture();
|
||||||
|
if (attachedTexture && attachedTexture.get() == &texture) {
|
||||||
|
outAttachment = attachmentType;
|
||||||
|
outLevel = attachment.GetTextureLevel();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool IsValidSampledImageLayout(VkImageLayout layout) {
|
||||||
|
switch (layout) {
|
||||||
|
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||||
|
case VK_IMAGE_LAYOUT_GENERAL:
|
||||||
|
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
|
||||||
|
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
|
||||||
|
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Int ResolveSamplerUnitIndex(const MG_State::GLState::ProgramObject& program, Int location, Uint32 binding) {
|
||||||
|
MOBILEGL_ASSERT(location >= -1, "ResolveSamplerUnitIndex: invalid sampler location for binding %u", binding);
|
||||||
|
if (location < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const Int uniformUnit = program.GetUniformSamplerOrImageUnitIndex(static_cast<Uint>(location));
|
||||||
|
MOBILEGL_ASSERT(uniformUnit >= -1,
|
||||||
|
"ResolveSamplerUnitIndex: invalid texture unit for binding %u location %d (unit=%d)", binding,
|
||||||
|
location, uniformUnit);
|
||||||
|
return uniformUnit >= 0 ? uniformUnit : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool ShouldDumpDescriptorStats() {
|
||||||
|
static const Bool enabled = [] {
|
||||||
|
const char* value = std::getenv("MOBILEGL_DESCRIPTOR_STATS");
|
||||||
|
return value != nullptr && value[0] != '\0' && std::strcmp(value, "0") != 0;
|
||||||
|
}();
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool UniformManager::Initialize(VkDevice device, VkBufferManager* bufferManager,
|
||||||
|
ProgramFactory* programFactory,
|
||||||
|
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
|
||||||
|
Uint32 maxBindings, Uint32 setsPerFrame,
|
||||||
|
VkTextureManager* textureManager, VkSamplerManager* samplerManager) {
|
||||||
|
Shutdown();
|
||||||
|
|
||||||
|
MOBILEGL_ASSERT(device != VK_NULL_HANDLE, "UniformDescriptorBinder::Initialize requires valid VkDevice");
|
||||||
|
MOBILEGL_ASSERT(bufferManager != nullptr, "UniformDescriptorBinder::Initialize requires valid buffer manager");
|
||||||
|
MOBILEGL_ASSERT(programFactory != nullptr,
|
||||||
|
"UniformDescriptorBinder::Initialize requires valid program factory");
|
||||||
|
MOBILEGL_ASSERT(frameCount > 0, "UniformDescriptorBinder::Initialize requires frameCount > 0");
|
||||||
|
MOBILEGL_ASSERT(maxBindings > 0, "UniformDescriptorBinder::Initialize requires maxBindings > 0");
|
||||||
|
MOBILEGL_ASSERT(setsPerFrame > 0, "UniformDescriptorBinder::Initialize requires setsPerFrame > 0");
|
||||||
|
MOBILEGL_ASSERT(textureManager != nullptr,
|
||||||
|
"UniformDescriptorBinder::Initialize requires valid texture manager");
|
||||||
|
MOBILEGL_ASSERT(samplerManager != nullptr,
|
||||||
|
"UniformDescriptorBinder::Initialize requires valid sampler manager");
|
||||||
|
|
||||||
|
m_device = device;
|
||||||
|
m_bufferManager = bufferManager;
|
||||||
|
m_programFactory = programFactory;
|
||||||
|
m_minDynamicOffsetAlignment = std::max<VkDeviceSize>(1, minUniformBufferOffsetAlignment);
|
||||||
|
m_frameCount = frameCount;
|
||||||
|
m_maxBindings = maxBindings;
|
||||||
|
m_setsPerFrame = setsPerFrame;
|
||||||
|
m_peakDescriptorSetsObserved = 0;
|
||||||
|
m_textureManager = textureManager;
|
||||||
|
m_samplerManager = samplerManager;
|
||||||
|
|
||||||
|
m_frames.resize(m_frameCount);
|
||||||
|
for (Uint32 frameIndex = 0; frameIndex < m_frameCount; ++frameIndex) {
|
||||||
|
auto& frame = m_frames[frameIndex];
|
||||||
|
frame.activeDescriptorPoolIndex = 0;
|
||||||
|
frame.allocatedSetsThisFrame = 0;
|
||||||
|
frame.peakAllocatedSetsThisFrame = 0;
|
||||||
|
frame.descriptorPools.clear();
|
||||||
|
|
||||||
|
VkDescriptorPool initialPool = VK_NULL_HANDLE;
|
||||||
|
if (!CreateDescriptorPool(m_setsPerFrame, initialPool)) {
|
||||||
|
MGLOG_E("UniformDescriptorBinder::Initialize failed: cannot create frame descriptor pool %u",
|
||||||
|
frameIndex);
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
frame.descriptorPools.push_back({initialPool, m_setsPerFrame, 0});
|
||||||
|
MGLOG_D("UniformDescriptorBinder: frame %u descriptor pool created (maxSets=%u)", frameIndex,
|
||||||
|
m_setsPerFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UniformManager::Shutdown() {
|
||||||
|
for (auto& frame : m_frames) {
|
||||||
|
if (m_device != VK_NULL_HANDLE) {
|
||||||
|
for (auto& view : frame.texelBufferViews) {
|
||||||
|
if (view != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyBufferView(m_device, view, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frame.texelBufferViews.clear();
|
||||||
|
frame.descriptorSetCacheByLayout.clear();
|
||||||
|
for (auto& bucket : frame.descriptorPools) {
|
||||||
|
if (bucket.handle != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyDescriptorPool(m_device, bucket.handle, nullptr);
|
||||||
|
bucket.handle = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frame.descriptorPools.clear();
|
||||||
|
frame.activeDescriptorPoolIndex = 0;
|
||||||
|
frame.allocatedSetsThisFrame = 0;
|
||||||
|
frame.peakAllocatedSetsThisFrame = 0;
|
||||||
|
}
|
||||||
|
m_frames.clear();
|
||||||
|
|
||||||
|
m_bufferManager = nullptr;
|
||||||
|
m_programFactory = nullptr;
|
||||||
|
m_device = VK_NULL_HANDLE;
|
||||||
|
m_minDynamicOffsetAlignment = 1;
|
||||||
|
m_frameCount = 0;
|
||||||
|
m_maxBindings = 0;
|
||||||
|
m_setsPerFrame = 0;
|
||||||
|
m_peakDescriptorSetsObserved = 0;
|
||||||
|
m_textureManager = nullptr;
|
||||||
|
m_samplerManager = nullptr;
|
||||||
|
m_fallbackTexture2D.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UniformManager::BeginFrame(Uint32 frameIndex) {
|
||||||
|
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "UniformDescriptorBinder::BeginFrame invalid frame index");
|
||||||
|
auto& frame = m_frames[frameIndex];
|
||||||
|
for (auto& view : frame.texelBufferViews) {
|
||||||
|
if (view != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyBufferView(m_device, view, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frame.texelBufferViews.clear();
|
||||||
|
if (frame.peakAllocatedSetsThisFrame > m_peakDescriptorSetsObserved) {
|
||||||
|
m_peakDescriptorSetsObserved = frame.peakAllocatedSetsThisFrame;
|
||||||
|
MGLOG_D(
|
||||||
|
"UniformDescriptorBinder: new descriptor set peak observed=%u (base setsPerFrame=%u, frame=%u, pools=%zu)",
|
||||||
|
m_peakDescriptorSetsObserved, m_setsPerFrame, frameIndex, frame.descriptorPools.size());
|
||||||
|
}
|
||||||
|
frame.activeDescriptorPoolIndex = 0;
|
||||||
|
frame.allocatedSetsThisFrame = 0;
|
||||||
|
frame.peakAllocatedSetsThisFrame = 0;
|
||||||
|
for (auto& cacheEntryPair : frame.descriptorSetCacheByLayout) {
|
||||||
|
cacheEntryPair.second.cursor = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool UniformManager::ResolveSamplerDescriptor(VkCommandBuffer commandBuffer,
|
||||||
|
const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj,
|
||||||
|
Uint32 binding, VkDescriptorImageInfo& outImageInfo) const {
|
||||||
|
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptor: texture manager is null");
|
||||||
|
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptor: sampler manager is null");
|
||||||
|
MOBILEGL_ASSERT(binding < programObj.samplerNameByBinding.size(),
|
||||||
|
"ResolveSamplerDescriptor: sampler binding %u name lookup out of range", binding);
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject> texture;
|
||||||
|
const Bool resolvedTexture = ResolveSamplerTexture(program, programObj, binding, texture);
|
||||||
|
if (!resolvedTexture) {
|
||||||
|
MGLOG_E("ResolveSamplerDescriptor: failed to resolve sampler texture for binding %u ('%s')", binding,
|
||||||
|
programObj.samplerNameByBinding[binding].c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Int location = programObj.samplerUniformLocationByBinding[binding];
|
||||||
|
const Int unit = ResolveSamplerUnitIndex(program, location, binding);
|
||||||
|
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
||||||
|
const auto samplerOverride = textureUnit.GetSamplerObject();
|
||||||
|
const auto preferredTarget = programObj.samplerTextureTargetByBinding[binding];
|
||||||
|
if (texture == nullptr) {
|
||||||
|
texture = GetFallbackTexture(preferredTarget);
|
||||||
|
MOBILEGL_ASSERT(texture != nullptr,
|
||||||
|
"ResolveSamplerDescriptor: no fallback texture available for binding=%u location=%d unit=%d target=%d",
|
||||||
|
binding, location, unit, static_cast<Int>(preferredTarget));
|
||||||
|
MGLOG_W(
|
||||||
|
"ResolveSamplerDescriptor: using fallback texture for unbound sampler binding=%u ('%s') location=%d unit=%d target=%d",
|
||||||
|
binding, programObj.samplerNameByBinding[binding].c_str(), location, unit,
|
||||||
|
static_cast<Int>(preferredTarget));
|
||||||
|
}
|
||||||
|
|
||||||
|
const MG_State::GLState::SamplerObject* samplerToUse =
|
||||||
|
samplerOverride ? samplerOverride.get() : texture->GetSamplerObject().get();
|
||||||
|
if (samplerToUse == nullptr) {
|
||||||
|
MGLOG_E(
|
||||||
|
"ResolveSamplerDescriptor: sampler binding %u ('%s') has no sampler object (textureId=%d location=%d unit=%d)",
|
||||||
|
binding, programObj.samplerNameByBinding[binding].c_str(), texture->GetExternalIndex(), location,
|
||||||
|
unit);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
VkTextureManager::TextureResource* resource = m_textureManager->SyncTextureAndGetDescriptor(*texture);
|
||||||
|
if (resource == nullptr) {
|
||||||
|
MGLOG_E(
|
||||||
|
"ResolveSamplerDescriptor: sampler binding %u ('%s') failed to create/sync texture resource (textureId=%d target=%d location=%d unit=%d)",
|
||||||
|
binding, programObj.samplerNameByBinding[binding].c_str(), texture->GetExternalIndex(),
|
||||||
|
static_cast<Int>(texture->GetTarget()), location, unit);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!IsValidSampledImageLayout(resource->layout)) {
|
||||||
|
auto drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||||
|
FramebufferAttachmentType attachmentType = FramebufferAttachmentType::None;
|
||||||
|
Int attachmentLevel = 0;
|
||||||
|
if (drawFbo &&
|
||||||
|
FindFramebufferAttachmentForTexture(*drawFbo, *texture, attachmentType, attachmentLevel)) {
|
||||||
|
MGLOG_W("ResolveSamplerDescriptor: framebuffer feedback loop detected: textureId=%d is bound "
|
||||||
|
"for sampling at binding=%u, but is also attached to drawFbo=%u as %s (level=%d, "
|
||||||
|
"trackedLayout=%d)",
|
||||||
|
texture->GetExternalIndex(), binding, drawFbo->GetExternalIndex(),
|
||||||
|
MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(),
|
||||||
|
attachmentLevel, static_cast<Int>(resource->layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Bool readyForSampling = m_textureManager->TransitionTextureForSampling(commandBuffer, *texture);
|
||||||
|
if (!readyForSampling) {
|
||||||
|
MGLOG_E("ResolveSamplerDescriptor: failed to transition textureId=%d for sampler binding=%u",
|
||||||
|
texture->GetExternalIndex(), binding);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
resource = m_textureManager->SyncTextureAndGetDescriptor(*texture);
|
||||||
|
MOBILEGL_ASSERT(resource != nullptr,
|
||||||
|
"ResolveSamplerDescriptor: failed to resync textureId=%d after sampling transition",
|
||||||
|
texture->GetExternalIndex());
|
||||||
|
MOBILEGL_ASSERT(IsValidSampledImageLayout(resource->layout),
|
||||||
|
"ResolveSamplerDescriptor: invalid sampled image layout=%d for textureId=%d, binding=%u",
|
||||||
|
static_cast<Int>(resource->layout), texture->GetExternalIndex(), binding);
|
||||||
|
}
|
||||||
|
outImageInfo = {
|
||||||
|
.sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse, *texture),
|
||||||
|
.imageView = resource->sampledView != VK_NULL_HANDLE ? resource->sampledView : resource->fullView,
|
||||||
|
.imageLayout = resource->layout,
|
||||||
|
};
|
||||||
|
if (ShouldDumpDescriptorStats()) {
|
||||||
|
std::fprintf(stderr,
|
||||||
|
"MOBILEGL_DESCRIPTOR_STATS program=%u binding=%u name=%s location=%d unit=%d "
|
||||||
|
"texture=%u target=%d sampler=%p imageView=%p layout=%d\n",
|
||||||
|
program.GetExternalIndex(),
|
||||||
|
binding,
|
||||||
|
programObj.samplerNameByBinding[binding].c_str(),
|
||||||
|
location,
|
||||||
|
unit,
|
||||||
|
texture->GetExternalIndex(),
|
||||||
|
static_cast<Int>(texture->GetTarget()),
|
||||||
|
reinterpret_cast<void*>(outImageInfo.sampler),
|
||||||
|
reinterpret_cast<void*>(outImageInfo.imageView),
|
||||||
|
static_cast<Int>(outImageInfo.imageLayout));
|
||||||
|
}
|
||||||
|
return outImageInfo.sampler != VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool UniformManager::ResolveSamplerDescriptorOverride(
|
||||||
|
const SamplerBindingOverride& samplerBindingOverride, VkDescriptorImageInfo& outImageInfo) const {
|
||||||
|
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptorOverride: texture manager is null");
|
||||||
|
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptorOverride: sampler manager is null");
|
||||||
|
MOBILEGL_ASSERT(samplerBindingOverride.texture != nullptr,
|
||||||
|
"ResolveSamplerDescriptorOverride: override texture is null for binding %u",
|
||||||
|
samplerBindingOverride.binding);
|
||||||
|
MOBILEGL_ASSERT(samplerBindingOverride.sampler != nullptr,
|
||||||
|
"ResolveSamplerDescriptorOverride: override sampler is null for binding %u",
|
||||||
|
samplerBindingOverride.binding);
|
||||||
|
|
||||||
|
auto* resource = m_textureManager->SyncTextureAndGetDescriptor(*samplerBindingOverride.texture);
|
||||||
|
MOBILEGL_ASSERT(resource != nullptr,
|
||||||
|
"ResolveSamplerDescriptorOverride: failed to sync override texture resource for binding %u textureId=%d",
|
||||||
|
samplerBindingOverride.binding, samplerBindingOverride.texture->GetExternalIndex());
|
||||||
|
MOBILEGL_ASSERT(IsValidSampledImageLayout(resource->layout),
|
||||||
|
"ResolveSamplerDescriptorOverride: invalid layout %d for binding %u textureId=%d",
|
||||||
|
static_cast<Int>(resource->layout), samplerBindingOverride.binding,
|
||||||
|
samplerBindingOverride.texture->GetExternalIndex());
|
||||||
|
|
||||||
|
outImageInfo = {
|
||||||
|
.sampler = m_samplerManager->GetOrCreateSampler(*samplerBindingOverride.sampler,
|
||||||
|
*samplerBindingOverride.texture),
|
||||||
|
.imageView = samplerBindingOverride.imageView != VK_NULL_HANDLE ?
|
||||||
|
samplerBindingOverride.imageView :
|
||||||
|
(resource->sampledView != VK_NULL_HANDLE ? resource->sampledView : resource->fullView),
|
||||||
|
.imageLayout = resource->layout,
|
||||||
|
};
|
||||||
|
return outImageInfo.sampler != VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool UniformManager::ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) {
|
||||||
|
outTexture.reset();
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveSamplerTexture: GL context is null");
|
||||||
|
MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(),
|
||||||
|
"ResolveSamplerTexture: sampler location binding %u out of range", binding);
|
||||||
|
MOBILEGL_ASSERT(binding < programObj.samplerTextureTargetByBinding.size(),
|
||||||
|
"ResolveSamplerTexture: sampler target binding %u out of range", binding);
|
||||||
|
|
||||||
|
const Int location = programObj.samplerUniformLocationByBinding[binding];
|
||||||
|
const Int unit = ResolveSamplerUnitIndex(program, location, binding);
|
||||||
|
|
||||||
|
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
||||||
|
const TextureTarget preferredTarget = programObj.samplerTextureTargetByBinding[binding];
|
||||||
|
outTexture = textureUnit.GetBindingSlot(preferredTarget).GetBoundObject();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool UniformManager::ResolveTexelBufferDescriptor(const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj,
|
||||||
|
Uint32 binding, Uint32 frameIndex,
|
||||||
|
VkBufferView& outBufferView) {
|
||||||
|
outBufferView = VK_NULL_HANDLE;
|
||||||
|
MOBILEGL_ASSERT(m_bufferManager != nullptr, "ResolveTexelBufferDescriptor: buffer manager is null");
|
||||||
|
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "ResolveTexelBufferDescriptor: frame index out of range");
|
||||||
|
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject> texture;
|
||||||
|
if (!ResolveSamplerTexture(program, programObj, binding, texture) || texture == nullptr) {
|
||||||
|
MGLOG_E("ResolveTexelBufferDescriptor: texture buffer binding %u ('%s') is unbound", binding,
|
||||||
|
programObj.samplerNameByBinding[binding].c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture->GetStorageType() != TextureStorageType::Buffer ||
|
||||||
|
texture->GetTarget() != TextureTarget::TextureBuffer) {
|
||||||
|
MGLOG_E(
|
||||||
|
"ResolveTexelBufferDescriptor: binding %u ('%s') expected texture buffer, got textureId=%u target=%d storage=%d",
|
||||||
|
binding, programObj.samplerNameByBinding[binding].c_str(), texture->GetExternalIndex(),
|
||||||
|
static_cast<Int>(texture->GetTarget()), static_cast<Int>(texture->GetStorageType()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* textureBuffer = static_cast<MG_State::GLState::TextureObjectBuffer*>(texture.get());
|
||||||
|
const auto bufferObject = textureBuffer->GetBufferBindingSlot().GetBoundObject();
|
||||||
|
if (bufferObject == nullptr) {
|
||||||
|
MGLOG_E("ResolveTexelBufferDescriptor: texture buffer binding %u ('%s') has no GL buffer bound",
|
||||||
|
binding, programObj.samplerNameByBinding[binding].c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferSlice slice{};
|
||||||
|
if (!m_bufferManager->SyncResidentBuffer(BufferKind::TextureBuffer, bufferObject, slice) || !slice.IsValid()) {
|
||||||
|
MGLOG_E("ResolveTexelBufferDescriptor: failed to sync GL buffer %u for texture buffer %u",
|
||||||
|
bufferObject->GetExternalIndex(), texture->GetExternalIndex());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto internalFormat = textureBuffer->GetFormat();
|
||||||
|
const VkFormat vkFormat = MG_Util::ConvertTextureInternalFormatToVkEnum(internalFormat);
|
||||||
|
if (vkFormat == VK_FORMAT_UNDEFINED) {
|
||||||
|
MGLOG_E("ResolveTexelBufferDescriptor: unsupported texture buffer internal format %d",
|
||||||
|
static_cast<Int>(internalFormat));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VkDeviceSize texelSize =
|
||||||
|
static_cast<VkDeviceSize>(MG_Util::GetSizedInternalFormatSizeInBytes(internalFormat));
|
||||||
|
VkDeviceSize viewRange = slice.size;
|
||||||
|
if (texelSize > 0) {
|
||||||
|
viewRange = (viewRange / texelSize) * texelSize;
|
||||||
|
}
|
||||||
|
if (viewRange == 0) {
|
||||||
|
MGLOG_E("ResolveTexelBufferDescriptor: texture buffer %u has empty view range", texture->GetExternalIndex());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBufferViewCreateInfo viewInfo{};
|
||||||
|
viewInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
|
||||||
|
viewInfo.buffer = slice.buffer;
|
||||||
|
viewInfo.format = vkFormat;
|
||||||
|
viewInfo.offset = slice.offset;
|
||||||
|
viewInfo.range = viewRange;
|
||||||
|
|
||||||
|
VkBufferView bufferView = VK_NULL_HANDLE;
|
||||||
|
const VkResult result = vkCreateBufferView(m_device, &viewInfo, nullptr, &bufferView);
|
||||||
|
if (result != VK_SUCCESS || bufferView == VK_NULL_HANDLE) {
|
||||||
|
MGLOG_E("ResolveTexelBufferDescriptor: vkCreateBufferView failed result=%d format=%d range=%zu",
|
||||||
|
result, static_cast<Int>(vkFormat), static_cast<SizeT>(viewRange));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_frames[frameIndex].texelBufferViews.push_back(bufferView);
|
||||||
|
outBufferView = bufferView;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool UniformManager::ResolveStorageBufferDescriptor(const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj,
|
||||||
|
Uint32 binding,
|
||||||
|
VkDescriptorBufferInfo& outBufferInfo) const {
|
||||||
|
outBufferInfo = {};
|
||||||
|
MOBILEGL_ASSERT(m_bufferManager != nullptr, "ResolveStorageBufferDescriptor: buffer manager is null");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveStorageBufferDescriptor: GL context is null");
|
||||||
|
MOBILEGL_ASSERT(binding < programObj.storageBlockIndexByBinding.size(),
|
||||||
|
"ResolveStorageBufferDescriptor: binding %u out of range", binding);
|
||||||
|
|
||||||
|
const Int blockIndex = programObj.storageBlockIndexByBinding[binding];
|
||||||
|
MOBILEGL_ASSERT(blockIndex >= 0, "ResolveStorageBufferDescriptor: no SSBO block mapped to binding %u",
|
||||||
|
binding);
|
||||||
|
const GLuint frontendBinding =
|
||||||
|
GetShaderStorageBlockBinding(program, static_cast<GLuint>(blockIndex));
|
||||||
|
const Uint32 bindingPointCount =
|
||||||
|
static_cast<Uint32>(MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::ShaderStorage));
|
||||||
|
MOBILEGL_ASSERT(frontendBinding < bindingPointCount,
|
||||||
|
"ResolveStorageBufferDescriptor: frontend SSBO binding %u out of range for block '%s'",
|
||||||
|
frontendBinding, programObj.storageBlockNameByBinding[binding].c_str());
|
||||||
|
|
||||||
|
auto& bindingPoint = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, frontendBinding);
|
||||||
|
const auto bufferObject = bindingPoint.GetBoundObject();
|
||||||
|
if (bufferObject == nullptr) {
|
||||||
|
MGLOG_E("ResolveStorageBufferDescriptor: no SSBO bound at frontend binding %u for block '%s'",
|
||||||
|
frontendBinding, programObj.storageBlockNameByBinding[binding].c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferSlice slice{};
|
||||||
|
if (!m_bufferManager->SyncResidentBuffer(BufferKind::ShaderStorage, bufferObject, slice) || !slice.IsValid()) {
|
||||||
|
MGLOG_E("ResolveStorageBufferDescriptor: failed to sync GL buffer %u for block '%s'",
|
||||||
|
bufferObject->GetExternalIndex(), programObj.storageBlockNameByBinding[binding].c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto range = bindingPoint.GetRange();
|
||||||
|
const VkDeviceSize bufferSize = static_cast<VkDeviceSize>(bufferObject->GetSize());
|
||||||
|
VkDeviceSize rangeStart = static_cast<VkDeviceSize>(std::min(range.start, bufferObject->GetSize()));
|
||||||
|
VkDeviceSize rangeEnd = static_cast<VkDeviceSize>(std::min(range.end, bufferObject->GetSize()));
|
||||||
|
if (rangeEnd <= rangeStart) {
|
||||||
|
rangeStart = 0;
|
||||||
|
rangeEnd = bufferSize;
|
||||||
|
}
|
||||||
|
if (rangeEnd <= rangeStart) {
|
||||||
|
MGLOG_E("ResolveStorageBufferDescriptor: empty SSBO range for block '%s'",
|
||||||
|
programObj.storageBlockNameByBinding[binding].c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outBufferInfo.buffer = slice.buffer;
|
||||||
|
outBufferInfo.offset = slice.offset + rangeStart;
|
||||||
|
outBufferInfo.range = rangeEnd - rangeStart;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool UniformManager::ResolveStorageImageDescriptor(VkCommandBuffer commandBuffer,
|
||||||
|
const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj,
|
||||||
|
Uint32 binding,
|
||||||
|
VkDescriptorImageInfo& outImageInfo) const {
|
||||||
|
outImageInfo = {};
|
||||||
|
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveStorageImageDescriptor: texture manager is null");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveStorageImageDescriptor: GL context is null");
|
||||||
|
MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(),
|
||||||
|
"ResolveStorageImageDescriptor: binding %u out of range", binding);
|
||||||
|
|
||||||
|
const Int location = programObj.samplerUniformLocationByBinding[binding];
|
||||||
|
if (location < 0) {
|
||||||
|
MGLOG_E("ResolveStorageImageDescriptor: storage image binding %u has no uniform location", binding);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const Int imageUnit = program.GetUniformSamplerOrImageUnitIndex(static_cast<Uint>(location));
|
||||||
|
if (imageUnit < 0 || imageUnit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
|
||||||
|
MGLOG_E("ResolveStorageImageDescriptor: image unit %d out of range for binding %u",
|
||||||
|
imageUnit, binding);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& imageBinding = MG_State::pGLContext->GetImageTextureBinding(imageUnit);
|
||||||
|
if (imageBinding.Texture == nullptr) {
|
||||||
|
MGLOG_E("ResolveStorageImageDescriptor: image unit %d is unbound for binding %u", imageUnit, binding);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Bool ready = m_textureManager->TransitionTextureForStorageImage(commandBuffer, *imageBinding.Texture);
|
||||||
|
if (!ready) {
|
||||||
|
MGLOG_E("ResolveStorageImageDescriptor: failed to transition textureId=%d for image unit %d",
|
||||||
|
imageBinding.Texture->GetExternalIndex(), imageUnit);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto* resource = m_textureManager->SyncTextureAndGetDescriptor(*imageBinding.Texture);
|
||||||
|
if (resource == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Uint32 mipLevel = static_cast<Uint32>(std::max<GLint>(0, imageBinding.Level));
|
||||||
|
VkImageView view = m_textureManager->GetOrCreateViewAtMipLevel(*imageBinding.Texture, mipLevel);
|
||||||
|
if (view == VK_NULL_HANDLE) {
|
||||||
|
view = resource->fullView;
|
||||||
|
}
|
||||||
|
outImageInfo.sampler = VK_NULL_HANDLE;
|
||||||
|
outImageInfo.imageView = view;
|
||||||
|
outImageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
return outImageInfo.imageView != VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject> UniformManager::GetFallbackTexture(TextureTarget target) const {
|
||||||
|
MOBILEGL_ASSERT(target == TextureTarget::Texture2D || target == TextureTarget::TextureRectangle,
|
||||||
|
"UniformManager::GetFallbackTexture: unsupported fallback target=%d",
|
||||||
|
static_cast<Int>(target));
|
||||||
|
|
||||||
|
if (m_fallbackTexture2D == nullptr) {
|
||||||
|
auto fallbackTexture = MakeShared<MG_State::GLState::TextureObject2D>(kFallbackTexture2DExternalIndex);
|
||||||
|
fallbackTexture->SetInternalFormat(TextureInternalFormat::RGBA8);
|
||||||
|
fallbackTexture->AllocateStorage(TextureUploadTarget::Texture2D, 0,
|
||||||
|
{.texelSize = {1, 1, 1}, .byteSize = 4});
|
||||||
|
fallbackTexture->MarkStorageDirty(TextureUploadTarget::Texture2D, 0, true);
|
||||||
|
m_fallbackTexture2D = fallbackTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_fallbackTexture2D;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool UniformManager::CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj,
|
||||||
|
Vector<MG_State::GLState::ITextureObject*>& outTextures) {
|
||||||
|
outTextures.clear();
|
||||||
|
|
||||||
|
const Uint32 bindingCount =
|
||||||
|
std::min<Uint32>(m_maxBindings, static_cast<Uint32>(programObj.bindingKinds.size()));
|
||||||
|
for (Uint32 binding = 0; binding < bindingCount; ++binding) {
|
||||||
|
if (programObj.bindingKinds[binding] != ProgramFactory::DescriptorBindingKind::CombinedImageSampler) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject> texture;
|
||||||
|
if (!ResolveSamplerTexture(program, programObj, binding, texture) || !texture) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto found = std::find(outTextures.begin(), outTextures.end(), texture.get());
|
||||||
|
if (found == outTextures.end()) {
|
||||||
|
outTextures.push_back(texture.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool UniformManager::ResolveUniformBufferPayload(const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||||
|
const void*& outData, VkDeviceSize& outSize) const {
|
||||||
|
outData = nullptr;
|
||||||
|
outSize = 0;
|
||||||
|
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveUniformBufferPayload: GL context is null");
|
||||||
|
MOBILEGL_ASSERT(binding < programObj.bindingKinds.size(),
|
||||||
|
"ResolveUniformBufferPayload: binding %u out of range", binding);
|
||||||
|
MOBILEGL_ASSERT(programObj.bindingKinds[binding] == ProgramFactory::DescriptorBindingKind::UniformBufferDynamic,
|
||||||
|
"ResolveUniformBufferPayload: binding %u is not a uniform buffer descriptor", binding);
|
||||||
|
|
||||||
|
if (programObj.globalUboBinding == static_cast<Int>(binding)) {
|
||||||
|
outData = program.GetUBOData();
|
||||||
|
outSize = static_cast<VkDeviceSize>(program.GetUBOSize());
|
||||||
|
static const Array<Uint8, 16> emptyGlobalUbo{};
|
||||||
|
if (outData == nullptr || outSize == 0) {
|
||||||
|
outData = emptyGlobalUbo.data();
|
||||||
|
outSize = static_cast<VkDeviceSize>(emptyGlobalUbo.size());
|
||||||
|
}
|
||||||
|
return outData != nullptr && outSize > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_ASSERT(binding < programObj.uniformBlockIndexByBinding.size(),
|
||||||
|
"ResolveUniformBufferPayload: UBO mapping binding %u out of range", binding);
|
||||||
|
const Int blockIndex = programObj.uniformBlockIndexByBinding[binding];
|
||||||
|
MOBILEGL_ASSERT(blockIndex >= 0,
|
||||||
|
"ResolveUniformBufferPayload: no uniform block mapped to descriptor binding %u", binding);
|
||||||
|
|
||||||
|
const Uint32 activeUniformBlockCount = static_cast<Uint32>(program.GetActiveUniformBlocksCount());
|
||||||
|
MOBILEGL_ASSERT(static_cast<Uint32>(blockIndex) < activeUniformBlockCount,
|
||||||
|
"ResolveUniformBufferPayload: uniform block index %d out of range (count=%u)", blockIndex,
|
||||||
|
activeUniformBlockCount);
|
||||||
|
|
||||||
|
const Uint32 frontendBinding = program.GetUniformBlockBinding(static_cast<Uint32>(blockIndex));
|
||||||
|
const Uint32 uniformBindingPointCount =
|
||||||
|
static_cast<Uint32>(MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform));
|
||||||
|
MOBILEGL_ASSERT(frontendBinding < uniformBindingPointCount,
|
||||||
|
"ResolveUniformBufferPayload: frontend UBO binding %u out of range for block '%s'",
|
||||||
|
frontendBinding, program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
|
||||||
|
|
||||||
|
auto& bindingPoint = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, frontendBinding);
|
||||||
|
const auto bufferObject = bindingPoint.GetBoundObject();
|
||||||
|
MOBILEGL_ASSERT(bufferObject != nullptr,
|
||||||
|
"ResolveUniformBufferPayload: no UBO bound at frontend binding %u for block '%s'",
|
||||||
|
frontendBinding, program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
|
||||||
|
bufferObject->MarkPersistentMappedRangeDirty();
|
||||||
|
|
||||||
|
const auto bufferData = bufferObject->GetDataReadOnly();
|
||||||
|
MOBILEGL_ASSERT(bufferData != nullptr && !bufferData->empty(),
|
||||||
|
"ResolveUniformBufferPayload: bound UBO data is empty for block '%s'",
|
||||||
|
program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
|
||||||
|
|
||||||
|
const auto range = bindingPoint.GetRange();
|
||||||
|
const VkDeviceSize bufferSize = static_cast<VkDeviceSize>(bufferObject->GetSize());
|
||||||
|
const VkDeviceSize rangeStart = static_cast<VkDeviceSize>(range.start);
|
||||||
|
MOBILEGL_ASSERT(rangeStart < bufferSize,
|
||||||
|
"ResolveUniformBufferPayload: UBO range start %zu exceeds buffer size %zu for block '%s'",
|
||||||
|
static_cast<SizeT>(rangeStart), static_cast<SizeT>(bufferSize),
|
||||||
|
program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
|
||||||
|
|
||||||
|
VkDeviceSize rangeEnd = static_cast<VkDeviceSize>(range.end);
|
||||||
|
if (rangeEnd > bufferSize) {
|
||||||
|
rangeEnd = bufferSize;
|
||||||
|
}
|
||||||
|
MOBILEGL_ASSERT(rangeEnd > rangeStart,
|
||||||
|
"ResolveUniformBufferPayload: invalid UBO range [%zu, %zu) for block '%s'",
|
||||||
|
static_cast<SizeT>(rangeStart), static_cast<SizeT>(rangeEnd),
|
||||||
|
program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
|
||||||
|
|
||||||
|
const VkDeviceSize blockSize = static_cast<VkDeviceSize>(program.GetUBOSizeAt(static_cast<Uint32>(blockIndex)));
|
||||||
|
MOBILEGL_ASSERT(blockSize > 0,
|
||||||
|
"ResolveUniformBufferPayload: reflected UBO size is zero for block '%s'",
|
||||||
|
program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
|
||||||
|
|
||||||
|
const VkDeviceSize available = rangeEnd - rangeStart;
|
||||||
|
MOBILEGL_ASSERT(available >= blockSize,
|
||||||
|
"ResolveUniformBufferPayload: bound range %zu is smaller than UBO size %zu for block '%s'",
|
||||||
|
static_cast<SizeT>(available), static_cast<SizeT>(blockSize),
|
||||||
|
program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
|
||||||
|
|
||||||
|
outData = bufferData->data() + static_cast<SizeT>(rangeStart);
|
||||||
|
outSize = blockSize;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool UniformManager::CreateDescriptorPool(Uint32 maxSets, VkDescriptorPool& outPool) const {
|
||||||
|
outPool = VK_NULL_HANDLE;
|
||||||
|
if (m_device == VK_NULL_HANDLE || maxSets == 0 || m_maxBindings == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Uint64 descriptorCount64 = static_cast<Uint64>(maxSets) * static_cast<Uint64>(m_maxBindings);
|
||||||
|
if (descriptorCount64 > static_cast<Uint64>(std::numeric_limits<Uint32>::max())) {
|
||||||
|
MGLOG_E("UniformDescriptorBinder::CreateDescriptorPool failed: descriptorCount overflow");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Uint32 descriptorCount = static_cast<Uint32>(descriptorCount64);
|
||||||
|
VkDescriptorPoolSize poolSizes[5]{};
|
||||||
|
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
||||||
|
poolSizes[0].descriptorCount = descriptorCount;
|
||||||
|
poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
poolSizes[1].descriptorCount = descriptorCount;
|
||||||
|
poolSizes[2].type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
|
||||||
|
poolSizes[2].descriptorCount = descriptorCount;
|
||||||
|
poolSizes[3].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||||
|
poolSizes[3].descriptorCount = descriptorCount;
|
||||||
|
poolSizes[4].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||||
|
poolSizes[4].descriptorCount = descriptorCount;
|
||||||
|
|
||||||
|
VkDescriptorPoolCreateInfo poolInfo{};
|
||||||
|
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
|
poolInfo.maxSets = maxSets;
|
||||||
|
poolInfo.poolSizeCount = static_cast<Uint32>(std::size(poolSizes));
|
||||||
|
poolInfo.pPoolSizes = poolSizes;
|
||||||
|
|
||||||
|
const VkResult result = vkCreateDescriptorPool(m_device, &poolInfo, nullptr, &outPool);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
MGLOG_E("UniformDescriptorBinder::CreateDescriptorPool failed: vkCreateDescriptorPool returned %d",
|
||||||
|
result);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool UniformManager::GrowFrameDescriptorPool(FrameResources& frame, Uint32 frameIndex) {
|
||||||
|
if (frame.descriptorPools.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& currentBucket = frame.descriptorPools[frame.activeDescriptorPoolIndex];
|
||||||
|
const Uint32 currentMaxSets = std::max<Uint32>(1, currentBucket.maxSets);
|
||||||
|
const Uint32 grownMaxSets = currentMaxSets <= (std::numeric_limits<Uint32>::max() / 2) ? (currentMaxSets * 2)
|
||||||
|
: currentMaxSets;
|
||||||
|
|
||||||
|
VkDescriptorPool grownPool = VK_NULL_HANDLE;
|
||||||
|
if (!CreateDescriptorPool(grownMaxSets, grownPool)) {
|
||||||
|
MGLOG_E("UniformDescriptorBinder::GrowFrameDescriptorPool failed: cannot create grown pool (%u -> %u sets)",
|
||||||
|
currentMaxSets, grownMaxSets);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.descriptorPools.push_back({grownPool, grownMaxSets, 0});
|
||||||
|
frame.activeDescriptorPoolIndex = static_cast<Uint32>(frame.descriptorPools.size() - 1);
|
||||||
|
MGLOG_D(
|
||||||
|
"UniformDescriptorBinder: frame %u descriptor pool exhausted, grew pool (%u -> %u sets), poolCount=%zu",
|
||||||
|
frameIndex, currentMaxSets, grownMaxSets, frame.descriptorPools.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult UniformManager::AllocateDescriptorSetsFromActivePool(Uint32 frameIndex, const ProgramFactory::VkProgramObject& programObj, VkDescriptorSet& outDescriptorSet) {
|
||||||
|
auto& frame = m_frames[frameIndex];
|
||||||
|
if (frame.activeDescriptorPoolIndex >= frame.descriptorPools.size()) {
|
||||||
|
frame.activeDescriptorPoolIndex = 0;
|
||||||
|
}
|
||||||
|
if (frame.descriptorPools[frame.activeDescriptorPoolIndex].allocatedSets >=
|
||||||
|
frame.descriptorPools[frame.activeDescriptorPoolIndex].maxSets) {
|
||||||
|
const auto availableBucket = std::find_if(
|
||||||
|
frame.descriptorPools.begin(), frame.descriptorPools.end(),
|
||||||
|
[](const DescriptorPoolBucket& candidate) { return candidate.allocatedSets < candidate.maxSets; });
|
||||||
|
if (availableBucket == frame.descriptorPools.end()) {
|
||||||
|
outDescriptorSet = VK_NULL_HANDLE;
|
||||||
|
return VK_ERROR_OUT_OF_POOL_MEMORY;
|
||||||
|
}
|
||||||
|
frame.activeDescriptorPoolIndex =
|
||||||
|
static_cast<Uint32>(std::distance(frame.descriptorPools.begin(), availableBucket));
|
||||||
|
}
|
||||||
|
auto& bucket = frame.descriptorPools[frame.activeDescriptorPoolIndex];
|
||||||
|
if (bucket.allocatedSets >= bucket.maxSets) {
|
||||||
|
outDescriptorSet = VK_NULL_HANDLE;
|
||||||
|
return VK_ERROR_OUT_OF_POOL_MEMORY;
|
||||||
|
}
|
||||||
|
VkDescriptorSetAllocateInfo allocInfo{};
|
||||||
|
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
|
allocInfo.descriptorSetCount = 1;
|
||||||
|
allocInfo.pSetLayouts = &programObj.descriptorSetLayout;
|
||||||
|
|
||||||
|
allocInfo.descriptorPool = bucket.handle;
|
||||||
|
VkResult result = vkAllocateDescriptorSets(m_device, &allocInfo, &outDescriptorSet);
|
||||||
|
if (result == VK_SUCCESS) {
|
||||||
|
++bucket.allocatedSets;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult UniformManager::AcquireDescriptorSet(Uint32 frameIndex,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj,
|
||||||
|
VkDescriptorSet& outDescriptorSet) {
|
||||||
|
auto& frame = m_frames[frameIndex];
|
||||||
|
auto& cache = frame.descriptorSetCacheByLayout[programObj.descriptorSetLayout];
|
||||||
|
if (cache.cursor < cache.sets.size()) {
|
||||||
|
outDescriptorSet = cache.sets[cache.cursor++];
|
||||||
|
} else {
|
||||||
|
VkResult allocResult = AllocateDescriptorSetsFromActivePool(frameIndex, programObj, outDescriptorSet);
|
||||||
|
if (allocResult == VK_ERROR_OUT_OF_POOL_MEMORY || allocResult == VK_ERROR_FRAGMENTED_POOL) {
|
||||||
|
if (!GrowFrameDescriptorPool(frame, frameIndex)) {
|
||||||
|
MGLOG_E("UniformDescriptorBinder::AcquireDescriptorSet failed: descriptor pool growth failed");
|
||||||
|
return allocResult;
|
||||||
|
}
|
||||||
|
allocResult = AllocateDescriptorSetsFromActivePool(frameIndex, programObj, outDescriptorSet);
|
||||||
|
}
|
||||||
|
if (allocResult != VK_SUCCESS || outDescriptorSet == VK_NULL_HANDLE) {
|
||||||
|
return allocResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.sets.push_back(outDescriptorSet);
|
||||||
|
++cache.cursor;
|
||||||
|
MGLOG_D("UniformDescriptorBinder: cached descriptor set count for frame=%u grew to %zu", frameIndex,
|
||||||
|
cache.sets.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
++frame.allocatedSetsThisFrame;
|
||||||
|
frame.peakAllocatedSetsThisFrame =
|
||||||
|
std::max(frame.peakAllocatedSetsThisFrame, frame.allocatedSetsThisFrame);
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool UniformManager::BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
||||||
|
const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj,
|
||||||
|
Uint32 frameIndex,
|
||||||
|
VkPipelineBindPoint bindPoint,
|
||||||
|
const SamplerBindingOverride* samplerBindingOverride) {
|
||||||
|
auto& frame = m_frames[frameIndex];
|
||||||
|
if (frame.descriptorPools.empty()) {
|
||||||
|
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: frame descriptor pools are invalid");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (frame.activeDescriptorPoolIndex >= frame.descriptorPools.size()) {
|
||||||
|
frame.activeDescriptorPoolIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
|
||||||
|
VkResult allocResult = AcquireDescriptorSet(frameIndex, programObj, descriptorSet);
|
||||||
|
if (allocResult != VK_SUCCESS || descriptorSet == VK_NULL_HANDLE) {
|
||||||
|
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: descriptor set acquire returned %d",
|
||||||
|
allocResult);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_ASSERT(m_textureManager != nullptr, "BindProgramUniformBuffers: texture manager is null");
|
||||||
|
MOBILEGL_ASSERT(m_samplerManager != nullptr, "BindProgramUniformBuffers: sampler manager is null");
|
||||||
|
MOBILEGL_ASSERT(m_bufferManager != nullptr, "BindProgramUniformBuffers: buffer manager is null");
|
||||||
|
|
||||||
|
Vector<VkWriteDescriptorSet> writes;
|
||||||
|
writes.reserve(m_maxBindings);
|
||||||
|
Vector<VkDescriptorBufferInfo> bufferInfos;
|
||||||
|
Vector<VkDescriptorImageInfo> imageInfos;
|
||||||
|
Vector<VkBufferView> texelBufferViews;
|
||||||
|
Vector<Uint32> dynamicOffsets;
|
||||||
|
bufferInfos.reserve(m_maxBindings);
|
||||||
|
imageInfos.reserve(m_maxBindings);
|
||||||
|
texelBufferViews.reserve(m_maxBindings);
|
||||||
|
dynamicOffsets.reserve(programObj.dynamicBindings.size());
|
||||||
|
|
||||||
|
const Uint32 bindingCount =
|
||||||
|
std::min<Uint32>(m_maxBindings, static_cast<Uint32>(programObj.bindingKinds.size()));
|
||||||
|
for (Uint32 binding = 0; binding < bindingCount; ++binding) {
|
||||||
|
const auto kind = programObj.bindingKinds[binding];
|
||||||
|
if (kind == ProgramFactory::DescriptorBindingKind::None) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkWriteDescriptorSet write{};
|
||||||
|
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
write.dstSet = descriptorSet;
|
||||||
|
write.dstBinding = binding;
|
||||||
|
write.dstArrayElement = 0;
|
||||||
|
write.descriptorCount = 1;
|
||||||
|
|
||||||
|
if (kind == ProgramFactory::DescriptorBindingKind::UniformBufferDynamic) {
|
||||||
|
const void* payload = nullptr;
|
||||||
|
VkDeviceSize payloadSize = 0;
|
||||||
|
const Bool hasPayload = ResolveUniformBufferPayload(program, programObj, binding, payload, payloadSize);
|
||||||
|
MOBILEGL_ASSERT(hasPayload && payload != nullptr && payloadSize > 0,
|
||||||
|
"UniformDescriptorBinder::BindProgramUniformBuffers failed: missing UBO payload on binding %u",
|
||||||
|
binding);
|
||||||
|
|
||||||
|
BufferSlice slice{};
|
||||||
|
if (!m_bufferManager->UploadTransient(BufferKind::Uniform, frameIndex, payload, payloadSize,
|
||||||
|
m_minDynamicOffsetAlignment, slice)) {
|
||||||
|
MOBILEGL_ASSERT(false, "UniformDescriptorBinder::BindProgramUniformBuffers failed: UBO upload failed on binding %u",
|
||||||
|
binding);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorBufferInfo bufferInfo{};
|
||||||
|
bufferInfo.buffer = slice.buffer;
|
||||||
|
bufferInfo.offset = 0;
|
||||||
|
bufferInfo.range = payloadSize;
|
||||||
|
bufferInfos.push_back(bufferInfo);
|
||||||
|
|
||||||
|
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
||||||
|
write.pBufferInfo = &bufferInfos.back();
|
||||||
|
writes.push_back(write);
|
||||||
|
dynamicOffsets.push_back(static_cast<Uint32>(slice.offset));
|
||||||
|
} else if (kind == ProgramFactory::DescriptorBindingKind::UniformTexelBuffer) {
|
||||||
|
VkBufferView bufferView = VK_NULL_HANDLE;
|
||||||
|
if (!ResolveTexelBufferDescriptor(program, programObj, binding, frameIndex, bufferView) ||
|
||||||
|
bufferView == VK_NULL_HANDLE) {
|
||||||
|
MGLOG_E(
|
||||||
|
"UniformDescriptorBinder::BindProgramUniformBuffers failed: texture buffer binding %u has no valid descriptor",
|
||||||
|
binding);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
texelBufferViews.push_back(bufferView);
|
||||||
|
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
|
||||||
|
write.pTexelBufferView = &texelBufferViews.back();
|
||||||
|
writes.push_back(write);
|
||||||
|
} else if (kind == ProgramFactory::DescriptorBindingKind::StorageBuffer) {
|
||||||
|
VkDescriptorBufferInfo bufferInfo{};
|
||||||
|
if (!ResolveStorageBufferDescriptor(program, programObj, binding, bufferInfo)) {
|
||||||
|
MGLOG_E(
|
||||||
|
"UniformDescriptorBinder::BindProgramUniformBuffers failed: storage buffer binding %u has no valid descriptor",
|
||||||
|
binding);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferInfos.push_back(bufferInfo);
|
||||||
|
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||||
|
write.pBufferInfo = &bufferInfos.back();
|
||||||
|
writes.push_back(write);
|
||||||
|
} else if (kind == ProgramFactory::DescriptorBindingKind::StorageImage) {
|
||||||
|
VkDescriptorImageInfo imageInfo{};
|
||||||
|
if (!ResolveStorageImageDescriptor(commandBuffer, program, programObj, binding, imageInfo)) {
|
||||||
|
MGLOG_E(
|
||||||
|
"UniformDescriptorBinder::BindProgramUniformBuffers failed: storage image binding %u has no valid descriptor",
|
||||||
|
binding);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
imageInfos.push_back(imageInfo);
|
||||||
|
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||||
|
write.pImageInfo = &imageInfos.back();
|
||||||
|
writes.push_back(write);
|
||||||
|
} else {
|
||||||
|
VkDescriptorImageInfo imageInfo{};
|
||||||
|
Bool hasImage = false;
|
||||||
|
if (samplerBindingOverride != nullptr &&
|
||||||
|
samplerBindingOverride->binding == binding &&
|
||||||
|
samplerBindingOverride->texture != nullptr &&
|
||||||
|
samplerBindingOverride->sampler != nullptr) {
|
||||||
|
hasImage = ResolveSamplerDescriptorOverride(*samplerBindingOverride, imageInfo);
|
||||||
|
} else {
|
||||||
|
hasImage = ResolveSamplerDescriptor(commandBuffer, program, programObj, binding, imageInfo);
|
||||||
|
}
|
||||||
|
if (!hasImage) {
|
||||||
|
MGLOG_E(
|
||||||
|
"UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has no valid texture descriptor",
|
||||||
|
binding);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (imageInfo.sampler == VK_NULL_HANDLE || imageInfo.imageView == VK_NULL_HANDLE) {
|
||||||
|
MGLOG_E(
|
||||||
|
"UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has null sampler or imageView",
|
||||||
|
binding);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
imageInfos.push_back(imageInfo);
|
||||||
|
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
write.pImageInfo = &imageInfos.back();
|
||||||
|
writes.push_back(write);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!writes.empty()) {
|
||||||
|
vkUpdateDescriptorSets(m_device, static_cast<Uint32>(writes.size()), writes.data(), 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCmdBindDescriptorSets(commandBuffer, bindPoint, programObj.pipelineLayout, 0, 1,
|
||||||
|
&descriptorSet, static_cast<Uint32>(dynamicOffsets.size()), dynamicOffsets.data());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ProgramFactory.h"
|
||||||
|
#include "VkBufferManager.h"
|
||||||
|
#include "VkSamplerManager.h"
|
||||||
|
#include "VkTextureManager.h"
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include <Includes.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_State::GLState {
|
||||||
|
class ITextureObject;
|
||||||
|
class ProgramObject;
|
||||||
|
class SamplerObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
class UniformManager {
|
||||||
|
public:
|
||||||
|
struct SamplerBindingOverride {
|
||||||
|
Uint32 binding = 0;
|
||||||
|
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||||
|
const MG_State::GLState::SamplerObject* sampler = nullptr;
|
||||||
|
VkImageView imageView = VK_NULL_HANDLE;
|
||||||
|
};
|
||||||
|
|
||||||
|
Bool Initialize(VkDevice device, VkBufferManager* bufferManager,
|
||||||
|
ProgramFactory* programFactory,
|
||||||
|
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
|
||||||
|
Uint32 maxBindings = 16, Uint32 setsPerFrame = 64,
|
||||||
|
VkTextureManager* textureManager = nullptr, VkSamplerManager* samplerManager = nullptr);
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void BeginFrame(Uint32 frameIndex);
|
||||||
|
Bool CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj,
|
||||||
|
Vector<MG_State::GLState::ITextureObject*>& outTextures);
|
||||||
|
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
||||||
|
const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj,
|
||||||
|
Uint32 frameIndex,
|
||||||
|
VkPipelineBindPoint bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
const SamplerBindingOverride* samplerBindingOverride = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct DescriptorPoolBucket {
|
||||||
|
VkDescriptorPool handle = VK_NULL_HANDLE;
|
||||||
|
Uint32 maxSets = 0;
|
||||||
|
Uint32 allocatedSets = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DescriptorSetCacheEntry {
|
||||||
|
Vector<VkDescriptorSet> sets;
|
||||||
|
Uint32 cursor = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FrameResources {
|
||||||
|
Vector<DescriptorPoolBucket> descriptorPools;
|
||||||
|
UnorderedMap<VkDescriptorSetLayout, DescriptorSetCacheEntry> descriptorSetCacheByLayout;
|
||||||
|
Vector<VkBufferView> texelBufferViews;
|
||||||
|
Uint32 activeDescriptorPoolIndex = 0;
|
||||||
|
Uint32 allocatedSetsThisFrame = 0;
|
||||||
|
Uint32 peakAllocatedSetsThisFrame = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Bool ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject>& outTexture);
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject> GetFallbackTexture(TextureTarget target) const;
|
||||||
|
Bool ResolveSamplerDescriptor(VkCommandBuffer commandBuffer, const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||||
|
VkDescriptorImageInfo& outImageInfo) const;
|
||||||
|
Bool ResolveSamplerDescriptorOverride(const SamplerBindingOverride& samplerBindingOverride,
|
||||||
|
VkDescriptorImageInfo& outImageInfo) const;
|
||||||
|
Bool ResolveTexelBufferDescriptor(const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||||
|
Uint32 frameIndex, VkBufferView& outBufferView);
|
||||||
|
Bool ResolveStorageBufferDescriptor(const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||||
|
VkDescriptorBufferInfo& outBufferInfo) const;
|
||||||
|
Bool ResolveStorageImageDescriptor(VkCommandBuffer commandBuffer,
|
||||||
|
const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||||
|
VkDescriptorImageInfo& outImageInfo) const;
|
||||||
|
Bool ResolveUniformBufferPayload(const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||||
|
const void*& outData, VkDeviceSize& outSize) const;
|
||||||
|
Bool CreateDescriptorPool(Uint32 maxSets, VkDescriptorPool& outPool) const;
|
||||||
|
Bool GrowFrameDescriptorPool(FrameResources& frame, Uint32 frameIndex);
|
||||||
|
VkResult AllocateDescriptorSetsFromActivePool(
|
||||||
|
Uint32 frameIndex, const ProgramFactory::VkProgramObject& programObj, VkDescriptorSet& outDescriptorSet);
|
||||||
|
VkResult AcquireDescriptorSet(Uint32 frameIndex,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj,
|
||||||
|
VkDescriptorSet& outDescriptorSet);
|
||||||
|
|
||||||
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
VkBufferManager* m_bufferManager = nullptr;
|
||||||
|
ProgramFactory* m_programFactory = nullptr;
|
||||||
|
Vector<FrameResources> m_frames;
|
||||||
|
|
||||||
|
VkDeviceSize m_minDynamicOffsetAlignment = 1;
|
||||||
|
Uint32 m_frameCount = 0;
|
||||||
|
Uint32 m_maxBindings = 0;
|
||||||
|
Uint32 m_setsPerFrame = 0;
|
||||||
|
Uint32 m_peakDescriptorSetsObserved = 0;
|
||||||
|
VkTextureManager* m_textureManager = nullptr;
|
||||||
|
VkSamplerManager* m_samplerManager = nullptr;
|
||||||
|
mutable SharedPtr<MG_State::GLState::ITextureObject> m_fallbackTexture2D;
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
// 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
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// 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
|
||||||
@@ -0,0 +1,225 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "VertexInputStateFactory.h"
|
||||||
|
#include "MG_Util/Converters/MGToStr/DataTypeConverter.h"
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
VertexInputStateFactory::HashType VertexInputStateFactory::ComputeHash(
|
||||||
|
const MG_State::GLState::VertexArrayObject& vao) const {
|
||||||
|
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion));
|
||||||
|
|
||||||
|
for (Int i = 0; i < MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS; ++i) {
|
||||||
|
const auto& attr = vao.GetAttribute(i);
|
||||||
|
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Enabled, sizeof(attr.Enabled)));
|
||||||
|
if (!attr.Enabled) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Size, sizeof(attr.Size)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Type, sizeof(attr.Type)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Normalized, sizeof(attr.Normalized)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Stride, sizeof(attr.Stride)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Offset, sizeof(attr.Offset)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.IsInteger, sizeof(attr.IsInteger)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &attr.Divisor, sizeof(attr.Divisor)));
|
||||||
|
|
||||||
|
const SizeT bufferKey = reinterpret_cast<SizeT>(attr.Buffer.get());
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &bufferKey, sizeof(bufferKey)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return XXH64_digest(m_hashState);
|
||||||
|
}
|
||||||
|
|
||||||
|
const VertexInputStateFactory::BackendVertexInputState& VertexInputStateFactory::GetOrCreateVertexInputState(
|
||||||
|
const MG_State::GLState::VertexArrayObject& vao) {
|
||||||
|
const HashType hash = ComputeHash(vao);
|
||||||
|
return GetOrCreateVertexInputState(vao, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
const VertexInputStateFactory::BackendVertexInputState& VertexInputStateFactory::GetOrCreateVertexInputState(
|
||||||
|
const MG_State::GLState::VertexArrayObject& vao, HashType hash) {
|
||||||
|
auto it = m_cache.find(hash);
|
||||||
|
if (it != m_cache.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexInputStateBuilder builder;
|
||||||
|
Vector<SizeT> bindingBufferKeys;
|
||||||
|
Vector<SizeT> bindingBaseOffsets;
|
||||||
|
Vector<Uint32> bindingAttributeLocations;
|
||||||
|
Vector<Bool> bindingUsesClientMemory;
|
||||||
|
|
||||||
|
for (Uint32 location = 0; location < MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS; ++location) {
|
||||||
|
const auto& attr = vao.GetAttribute(location);
|
||||||
|
if (!attr.Enabled) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto vkFormat = ToVkVertexFormat(attr.Type, attr.Size, attr.Normalized, attr.IsInteger);
|
||||||
|
if (vkFormat == VK_FORMAT_UNDEFINED) {
|
||||||
|
MGLOG_D("Skipping unsupported vertex attribute layout (location=%u, type=%s, size=%d)",
|
||||||
|
location, MG_Util::ConvertDataTypeToString(attr.Type).c_str(), attr.Size);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SizeT componentSize = GetComponentSize(attr.Type);
|
||||||
|
if (componentSize == 0) {
|
||||||
|
MGLOG_D("Skipping vertex attribute with unknown component size (location=%u, type=%s)",
|
||||||
|
location, MG_Util::ConvertDataTypeToString(attr.Type).c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Uint32 stride = attr.Stride > 0
|
||||||
|
? static_cast<Uint32>(attr.Stride)
|
||||||
|
: static_cast<Uint32>(componentSize * static_cast<SizeT>(attr.Size));
|
||||||
|
const VkVertexInputRate inputRate =
|
||||||
|
(attr.Divisor == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
|
||||||
|
|
||||||
|
const SizeT bufferKey = reinterpret_cast<SizeT>(attr.Buffer.get());
|
||||||
|
const Uint32 binding = static_cast<Uint32>(bindingBufferKeys.size());
|
||||||
|
bindingBufferKeys.push_back(bufferKey);
|
||||||
|
bindingBaseOffsets.push_back(attr.Buffer ? attr.Offset : 0);
|
||||||
|
bindingAttributeLocations.push_back(location);
|
||||||
|
bindingUsesClientMemory.push_back(attr.Buffer == nullptr);
|
||||||
|
builder.AddBinding(binding, stride, inputRate);
|
||||||
|
builder.AddAttribute(location, binding, vkFormat, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& state = builder.Build();
|
||||||
|
|
||||||
|
auto& entry = m_cache[hash];
|
||||||
|
entry.hash = hash;
|
||||||
|
entry.bindings = builder.GetBindings();
|
||||||
|
entry.attributes = builder.GetAttributes();
|
||||||
|
entry.bindingBufferKeys = std::move(bindingBufferKeys);
|
||||||
|
entry.bindingBaseOffsets = std::move(bindingBaseOffsets);
|
||||||
|
entry.bindingAttributeLocations = std::move(bindingAttributeLocations);
|
||||||
|
entry.bindingUsesClientMemory = std::move(bindingUsesClientMemory);
|
||||||
|
entry.state = state;
|
||||||
|
entry.state.pVertexBindingDescriptions = entry.bindings.empty() ? nullptr : entry.bindings.data();
|
||||||
|
entry.state.pVertexAttributeDescriptions = entry.attributes.empty() ? nullptr : entry.attributes.data();
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkFormat VertexInputStateFactory::ToVkVertexFormat(DataType type, Int size, Bool normalized, Bool isInteger) {
|
||||||
|
switch (type) {
|
||||||
|
case DataType::Float32:
|
||||||
|
switch (size) {
|
||||||
|
case 1: return VK_FORMAT_R32_SFLOAT;
|
||||||
|
case 2: return VK_FORMAT_R32G32_SFLOAT;
|
||||||
|
case 3: return VK_FORMAT_R32G32B32_SFLOAT;
|
||||||
|
case 4: return VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||||
|
default: return VK_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
case DataType::Int32:
|
||||||
|
if (!isInteger || normalized) return VK_FORMAT_UNDEFINED;
|
||||||
|
switch (size) {
|
||||||
|
case 1: return VK_FORMAT_R32_SINT;
|
||||||
|
case 2: return VK_FORMAT_R32G32_SINT;
|
||||||
|
case 3: return VK_FORMAT_R32G32B32_SINT;
|
||||||
|
case 4: return VK_FORMAT_R32G32B32A32_SINT;
|
||||||
|
default: return VK_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
case DataType::Uint32:
|
||||||
|
if (!isInteger || normalized) return VK_FORMAT_UNDEFINED;
|
||||||
|
switch (size) {
|
||||||
|
case 1: return VK_FORMAT_R32_UINT;
|
||||||
|
case 2: return VK_FORMAT_R32G32_UINT;
|
||||||
|
case 3: return VK_FORMAT_R32G32B32_UINT;
|
||||||
|
case 4: return VK_FORMAT_R32G32B32A32_UINT;
|
||||||
|
default: return VK_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
case DataType::Int16:
|
||||||
|
switch (size) {
|
||||||
|
case 1:
|
||||||
|
return isInteger ? VK_FORMAT_R16_SINT : (normalized ? VK_FORMAT_R16_SNORM : VK_FORMAT_R16_SSCALED);
|
||||||
|
case 2:
|
||||||
|
return isInteger ? VK_FORMAT_R16G16_SINT
|
||||||
|
: (normalized ? VK_FORMAT_R16G16_SNORM : VK_FORMAT_R16G16_SSCALED);
|
||||||
|
case 3:
|
||||||
|
return isInteger ? VK_FORMAT_R16G16B16_SINT
|
||||||
|
: (normalized ? VK_FORMAT_R16G16B16_SNORM : VK_FORMAT_R16G16B16_SSCALED);
|
||||||
|
case 4:
|
||||||
|
return isInteger ? VK_FORMAT_R16G16B16A16_SINT
|
||||||
|
: (normalized ? VK_FORMAT_R16G16B16A16_SNORM : VK_FORMAT_R16G16B16A16_SSCALED);
|
||||||
|
default: return VK_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
case DataType::Uint16:
|
||||||
|
switch (size) {
|
||||||
|
case 1:
|
||||||
|
return isInteger ? VK_FORMAT_R16_UINT : (normalized ? VK_FORMAT_R16_UNORM : VK_FORMAT_R16_USCALED);
|
||||||
|
case 2:
|
||||||
|
return isInteger ? VK_FORMAT_R16G16_UINT
|
||||||
|
: (normalized ? VK_FORMAT_R16G16_UNORM : VK_FORMAT_R16G16_USCALED);
|
||||||
|
case 3:
|
||||||
|
return isInteger ? VK_FORMAT_R16G16B16_UINT
|
||||||
|
: (normalized ? VK_FORMAT_R16G16B16_UNORM : VK_FORMAT_R16G16B16_USCALED);
|
||||||
|
case 4:
|
||||||
|
return isInteger ? VK_FORMAT_R16G16B16A16_UINT
|
||||||
|
: (normalized ? VK_FORMAT_R16G16B16A16_UNORM : VK_FORMAT_R16G16B16A16_USCALED);
|
||||||
|
default: return VK_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
case DataType::Int8:
|
||||||
|
switch (size) {
|
||||||
|
case 1:
|
||||||
|
return isInteger ? VK_FORMAT_R8_SINT : (normalized ? VK_FORMAT_R8_SNORM : VK_FORMAT_R8_SSCALED);
|
||||||
|
case 2:
|
||||||
|
return isInteger ? VK_FORMAT_R8G8_SINT
|
||||||
|
: (normalized ? VK_FORMAT_R8G8_SNORM : VK_FORMAT_R8G8_SSCALED);
|
||||||
|
case 3:
|
||||||
|
return isInteger ? VK_FORMAT_R8G8B8_SINT
|
||||||
|
: (normalized ? VK_FORMAT_R8G8B8_SNORM : VK_FORMAT_R8G8B8_SSCALED);
|
||||||
|
case 4:
|
||||||
|
return isInteger ? VK_FORMAT_R8G8B8A8_SINT
|
||||||
|
: (normalized ? VK_FORMAT_R8G8B8A8_SNORM : VK_FORMAT_R8G8B8A8_SSCALED);
|
||||||
|
default: return VK_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
case DataType::Uint8:
|
||||||
|
switch (size) {
|
||||||
|
case 1:
|
||||||
|
return isInteger ? VK_FORMAT_R8_UINT : (normalized ? VK_FORMAT_R8_UNORM : VK_FORMAT_R8_USCALED);
|
||||||
|
case 2:
|
||||||
|
return isInteger ? VK_FORMAT_R8G8_UINT
|
||||||
|
: (normalized ? VK_FORMAT_R8G8_UNORM : VK_FORMAT_R8G8_USCALED);
|
||||||
|
case 3:
|
||||||
|
return isInteger ? VK_FORMAT_R8G8B8_UINT
|
||||||
|
: (normalized ? VK_FORMAT_R8G8B8_UNORM : VK_FORMAT_R8G8B8_USCALED);
|
||||||
|
case 4:
|
||||||
|
return isInteger ? VK_FORMAT_R8G8B8A8_UINT
|
||||||
|
: (normalized ? VK_FORMAT_R8G8B8A8_UNORM : VK_FORMAT_R8G8B8A8_USCALED);
|
||||||
|
default: return VK_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return VK_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeT VertexInputStateFactory::GetComponentSize(DataType type) {
|
||||||
|
switch (type) {
|
||||||
|
case DataType::Int8:
|
||||||
|
case DataType::Uint8:
|
||||||
|
return 1;
|
||||||
|
case DataType::Int16:
|
||||||
|
case DataType::Uint16:
|
||||||
|
case DataType::Float16:
|
||||||
|
return 2;
|
||||||
|
case DataType::Int32:
|
||||||
|
case DataType::Uint32:
|
||||||
|
case DataType::Float32:
|
||||||
|
case DataType::Fixed32:
|
||||||
|
return 4;
|
||||||
|
case DataType::Float64:
|
||||||
|
return 8;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "VertexInputStateBuilder.h"
|
||||||
|
#include "MG_State/GLState/VertexArrayState/VertexArrayObject.h"
|
||||||
|
#include <Includes.h>
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
class VertexInputStateFactory {
|
||||||
|
public:
|
||||||
|
using HashType = Uint64;
|
||||||
|
|
||||||
|
struct BackendVertexInputState {
|
||||||
|
HashType hash = 0;
|
||||||
|
Vector<VkVertexInputBindingDescription> bindings;
|
||||||
|
Vector<VkVertexInputAttributeDescription> attributes;
|
||||||
|
Vector<SizeT> bindingBufferKeys;
|
||||||
|
Vector<SizeT> bindingBaseOffsets;
|
||||||
|
Vector<Uint32> bindingAttributeLocations;
|
||||||
|
Vector<Bool> bindingUsesClientMemory;
|
||||||
|
VkPipelineVertexInputStateCreateInfo state{
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit VertexInputStateFactory(const VulkanRendererConfig& config):
|
||||||
|
m_config(config) {}
|
||||||
|
~VertexInputStateFactory() = default;
|
||||||
|
VertexInputStateFactory(const VertexInputStateFactory&) = delete;
|
||||||
|
|
||||||
|
HashType ComputeHash(const MG_State::GLState::VertexArrayObject& vao) const;
|
||||||
|
const BackendVertexInputState& GetOrCreateVertexInputState(
|
||||||
|
const MG_State::GLState::VertexArrayObject& vao, HashType hash);
|
||||||
|
const BackendVertexInputState& GetOrCreateVertexInputState(const MG_State::GLState::VertexArrayObject& vao);
|
||||||
|
static SizeT GetComponentSize(DataType type);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static VkFormat ToVkVertexFormat(DataType type, Int size, Bool normalized, Bool isInteger);
|
||||||
|
|
||||||
|
const VulkanRendererConfig& m_config;
|
||||||
|
UnorderedMap<HashType, BackendVertexInputState> m_cache;
|
||||||
|
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "VkBufferManager.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
namespace {
|
||||||
|
constexpr Uint32 kResidentBufferGCInterval = 60;
|
||||||
|
constexpr VmaAllocationCreateFlags kResidentBufferAllocationFlags =
|
||||||
|
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Bool VkBufferManager::Initialize(const VkBufferManagerInitInfo& initInfo) {
|
||||||
|
Shutdown();
|
||||||
|
|
||||||
|
MOBILEGL_ASSERT(initInfo.allocator != nullptr, "VkBufferManager::Initialize requires valid allocator");
|
||||||
|
MOBILEGL_ASSERT(initInfo.frameCount > 0, "VkBufferManager::Initialize requires non-zero frame count");
|
||||||
|
|
||||||
|
m_initInfo = initInfo;
|
||||||
|
m_deferredResidentReleases.resize(initInfo.frameCount);
|
||||||
|
m_currentFrameIndex = 0;
|
||||||
|
return InitializeTransientArenas();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkBufferManager::Shutdown() {
|
||||||
|
m_transientUploadArena.Shutdown();
|
||||||
|
DestroyResidentBuffers();
|
||||||
|
DestroyDeferredResidentReleases();
|
||||||
|
m_initInfo = {};
|
||||||
|
m_currentFrameIndex = 0;
|
||||||
|
m_residentGcTick = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkBufferManager::RecreateTransientArenas(Uint32 frameCount) {
|
||||||
|
MOBILEGL_ASSERT(m_initInfo.allocator != nullptr, "VkBufferManager::RecreateTransientArenas requires initialized manager");
|
||||||
|
MOBILEGL_ASSERT(frameCount > 0, "VkBufferManager::RecreateTransientArenas requires non-zero frame count");
|
||||||
|
|
||||||
|
m_transientUploadArena.Shutdown();
|
||||||
|
m_initInfo.frameCount = frameCount;
|
||||||
|
DestroyDeferredResidentReleases();
|
||||||
|
m_deferredResidentReleases.resize(frameCount);
|
||||||
|
m_currentFrameIndex = 0;
|
||||||
|
return InitializeTransientArenas();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkBufferManager::BeginFrame(Uint32 frameIndex) {
|
||||||
|
MOBILEGL_ASSERT(frameIndex < m_deferredResidentReleases.size(),
|
||||||
|
"VkBufferManager::BeginFrame frame index out of range");
|
||||||
|
m_currentFrameIndex = frameIndex;
|
||||||
|
CollectDeferredResidentReleases(frameIndex);
|
||||||
|
m_transientUploadArena.BeginFrame(frameIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkBufferManager::UploadTransient(BufferKind kind, Uint32 frameIndex, const void* data,
|
||||||
|
VkDeviceSize size, VkDeviceSize alignment, BufferSlice& outSlice) {
|
||||||
|
(void)kind;
|
||||||
|
return m_transientUploadArena.Upload(frameIndex, data, size, alignment, outSlice);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkBufferManager::InitializeTransientArenas() {
|
||||||
|
return m_transientUploadArena.Initialize({
|
||||||
|
.allocator = m_initInfo.allocator,
|
||||||
|
.frameCount = m_initInfo.frameCount,
|
||||||
|
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
||||||
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||||
|
.memoryUsage = m_initInfo.transientMemoryUsage,
|
||||||
|
.allocationFlags = m_initInfo.transientAllocationFlags,
|
||||||
|
.minBufferSize = m_initInfo.minUploadBytes,
|
||||||
|
.persistentlyMapped = m_initInfo.transientPersistentMapping,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkBufferManager::SyncResidentBuffer(BufferKind kind,
|
||||||
|
const SharedPtr<MG_State::GLState::BufferObject>& bufferObject,
|
||||||
|
BufferSlice& outSlice) {
|
||||||
|
const VkBufferUsageFlags requiredUsage = GetVkBufferUsage(kind);
|
||||||
|
MOBILEGL_ASSERT(requiredUsage != 0,
|
||||||
|
"VkBufferManager::SyncResidentBuffer unsupported resident buffer kind");
|
||||||
|
MOBILEGL_ASSERT(bufferObject != nullptr, "VkBufferManager::SyncResidentBuffer requires valid buffer object");
|
||||||
|
CollectResidentGarbageIfNeeded();
|
||||||
|
|
||||||
|
const auto* bufferData = bufferObject->GetDataReadOnly().get();
|
||||||
|
MOBILEGL_ASSERT(bufferData != nullptr, "VkBufferManager::SyncResidentBuffer requires frontend buffer data");
|
||||||
|
bufferObject->MarkPersistentMappedRangeDirty();
|
||||||
|
|
||||||
|
const VkDeviceSize bufferSize = static_cast<VkDeviceSize>(bufferObject->GetSize());
|
||||||
|
if (bufferSize == 0) {
|
||||||
|
MGLOG_E("VkBufferManager::SyncResidentBuffer failed: buffer size is zero");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& entry = m_residentBuffers[bufferObject.get()];
|
||||||
|
entry.aliveRef = bufferObject;
|
||||||
|
|
||||||
|
const auto changeBits = bufferObject->GetChangeBits();
|
||||||
|
const Bool needsRecreate = !entry.buffer.IsValid() || entry.size != bufferSize ||
|
||||||
|
((entry.usage & requiredUsage) != requiredUsage) ||
|
||||||
|
(changeBits & BufferChangeBits::PreferReallocationBit);
|
||||||
|
if (needsRecreate) {
|
||||||
|
const VkBufferUsageFlags recreatedUsage = entry.usage | requiredUsage;
|
||||||
|
DeferResidentRelease(std::move(entry.buffer));
|
||||||
|
const Bool created = entry.buffer.Create({
|
||||||
|
.allocator = m_initInfo.allocator,
|
||||||
|
.size = bufferSize,
|
||||||
|
.usage = recreatedUsage,
|
||||||
|
.memoryUsage = VMA_MEMORY_USAGE_AUTO,
|
||||||
|
.allocationFlags = kResidentBufferAllocationFlags,
|
||||||
|
});
|
||||||
|
if (!created || entry.buffer.Map() == nullptr) {
|
||||||
|
MGLOG_E("VkBufferManager::SyncResidentBuffer failed: unable to create resident buffer");
|
||||||
|
entry.buffer.Destroy();
|
||||||
|
entry.size = 0;
|
||||||
|
entry.usage = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!entry.buffer.Upload(bufferData->data(), bufferSize, 0)) {
|
||||||
|
MGLOG_E("VkBufferManager::SyncResidentBuffer failed: initial upload failed");
|
||||||
|
entry.buffer.Destroy();
|
||||||
|
entry.size = 0;
|
||||||
|
entry.usage = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
entry.size = bufferSize;
|
||||||
|
entry.usage = recreatedUsage;
|
||||||
|
bufferObject->ClearDirty();
|
||||||
|
outSlice = entry.buffer.GetSlice(0, bufferSize);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changeBits & BufferChangeBits::DirtyBit) {
|
||||||
|
const auto& dirtyRanges = bufferObject->GetDirtyRanges();
|
||||||
|
for (const auto& range : dirtyRanges) {
|
||||||
|
const VkDeviceSize rangeOffset = static_cast<VkDeviceSize>(range.start);
|
||||||
|
const VkDeviceSize rangeSize = static_cast<VkDeviceSize>(range.end - range.start);
|
||||||
|
if (rangeSize == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!entry.buffer.Upload(bufferData->data() + range.start, rangeSize, rangeOffset)) {
|
||||||
|
MGLOG_E("VkBufferManager::SyncResidentBuffer failed: dirty range upload failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bufferObject->ClearDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
outSlice = entry.buffer.GetSlice(0, bufferSize);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkBufferManager::DowngradeResidentBufferToTransient(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject) {
|
||||||
|
if (bufferObject == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = m_residentBuffers.find(bufferObject.get());
|
||||||
|
if (it == m_residentBuffers.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeferResidentRelease(std::move(it->second.buffer));
|
||||||
|
m_residentBuffers.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkBufferManager::DeferResidentRelease(VkBufferObject&& buffer) {
|
||||||
|
if (!buffer.IsValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_deferredResidentReleases.empty()) {
|
||||||
|
buffer.Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_ASSERT(m_currentFrameIndex < m_deferredResidentReleases.size(),
|
||||||
|
"VkBufferManager::DeferResidentRelease current frame index out of range");
|
||||||
|
m_deferredResidentReleases[m_currentFrameIndex].push_back(std::move(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkBufferManager::CollectDeferredResidentReleases(Uint32 frameIndex) {
|
||||||
|
MOBILEGL_ASSERT(frameIndex < m_deferredResidentReleases.size(),
|
||||||
|
"VkBufferManager::CollectDeferredResidentReleases frame index out of range");
|
||||||
|
m_deferredResidentReleases[frameIndex].clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBufferUsageFlags VkBufferManager::GetVkBufferUsage(BufferKind kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case BufferKind::Vertex:
|
||||||
|
case BufferKind::Index:
|
||||||
|
// A GL buffer can be rebound between ARRAY_BUFFER and ELEMENT_ARRAY_BUFFER,
|
||||||
|
// and may even be used as both within the same draw setup. Keep resident
|
||||||
|
// vertex/index buffers compatible with both roles from the start so we
|
||||||
|
// never need to recreate a buffer after it has already been bound.
|
||||||
|
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
||||||
|
case BufferKind::Uniform:
|
||||||
|
return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||||
|
case BufferKind::TextureBuffer:
|
||||||
|
return VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
|
||||||
|
case BufferKind::ShaderStorage:
|
||||||
|
return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
|
||||||
|
case BufferKind::Indirect:
|
||||||
|
return VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkBufferManager::CollectResidentGarbageIfNeeded() {
|
||||||
|
++m_residentGcTick;
|
||||||
|
if (m_residentGcTick < kResidentBufferGCInterval) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CollectResidentGarbageNow();
|
||||||
|
m_residentGcTick = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkBufferManager::CollectResidentGarbageNow() {
|
||||||
|
Vector<MG_State::GLState::BufferObject*> staleBuffers;
|
||||||
|
staleBuffers.reserve(m_residentBuffers.size());
|
||||||
|
|
||||||
|
for (const auto& [rawBuffer, entry] : m_residentBuffers) {
|
||||||
|
if (entry.aliveRef.expired()) {
|
||||||
|
staleBuffers.push_back(rawBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto* rawBuffer : staleBuffers) {
|
||||||
|
auto it = m_residentBuffers.find(const_cast<MG_State::GLState::BufferObject*>(rawBuffer));
|
||||||
|
if (it == m_residentBuffers.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DeferResidentRelease(std::move(it->second.buffer));
|
||||||
|
m_residentBuffers.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkBufferManager::DestroyDeferredResidentReleases() {
|
||||||
|
for (auto& deferredReleases : m_deferredResidentReleases) {
|
||||||
|
deferredReleases.clear();
|
||||||
|
}
|
||||||
|
m_deferredResidentReleases.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkBufferManager::DestroyResidentBuffers() {
|
||||||
|
for (auto& [_, entry] : m_residentBuffers) {
|
||||||
|
entry.buffer.Destroy();
|
||||||
|
}
|
||||||
|
m_residentBuffers.clear();
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferManager.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BufferArena.h"
|
||||||
|
#include "MG_State/GLState/BufferState/BufferObject.h"
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include <Includes.h>
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
enum class BufferKind : Uint8 {
|
||||||
|
Vertex,
|
||||||
|
Index,
|
||||||
|
Uniform,
|
||||||
|
TextureBuffer,
|
||||||
|
ShaderStorage,
|
||||||
|
Indirect,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VkBufferManagerInitInfo {
|
||||||
|
VmaAllocator allocator = nullptr;
|
||||||
|
Uint32 frameCount = 0;
|
||||||
|
VkDeviceSize minUploadBytes = 4 * 1024 * 1024;
|
||||||
|
VmaMemoryUsage transientMemoryUsage = VMA_MEMORY_USAGE_AUTO;
|
||||||
|
VmaAllocationCreateFlags transientAllocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||||
|
Bool transientPersistentMapping = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VkBufferManager {
|
||||||
|
public:
|
||||||
|
Bool Initialize(const VkBufferManagerInitInfo& initInfo);
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
// Recreate all per-frame transient arenas
|
||||||
|
Bool RecreateTransientArenas(Uint32 frameCount);
|
||||||
|
void BeginFrame(Uint32 frameIndex);
|
||||||
|
|
||||||
|
Bool UploadTransient(BufferKind kind, Uint32 frameIndex, const void* data, VkDeviceSize size,
|
||||||
|
VkDeviceSize alignment, BufferSlice& outSlice);
|
||||||
|
Bool SyncResidentBuffer(BufferKind kind, const SharedPtr<MG_State::GLState::BufferObject>& bufferObject,
|
||||||
|
BufferSlice& outSlice);
|
||||||
|
void DowngradeResidentBufferToTransient(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ResidentBufferEntry {
|
||||||
|
WeakPtr<MG_State::GLState::BufferObject> aliveRef;
|
||||||
|
VkBufferObject buffer;
|
||||||
|
VkDeviceSize size = 0;
|
||||||
|
VkBufferUsageFlags usage = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Bool InitializeTransientArenas();
|
||||||
|
static VkBufferUsageFlags GetVkBufferUsage(BufferKind kind);
|
||||||
|
void DeferResidentRelease(VkBufferObject&& buffer);
|
||||||
|
void CollectDeferredResidentReleases(Uint32 frameIndex);
|
||||||
|
void CollectResidentGarbageIfNeeded();
|
||||||
|
void CollectResidentGarbageNow();
|
||||||
|
void DestroyDeferredResidentReleases();
|
||||||
|
void DestroyResidentBuffers();
|
||||||
|
|
||||||
|
VkBufferManagerInitInfo m_initInfo{};
|
||||||
|
BufferArena m_transientUploadArena;
|
||||||
|
UnorderedMap<MG_State::GLState::BufferObject*, ResidentBufferEntry> m_residentBuffers;
|
||||||
|
Vector<Vector<VkBufferObject>> m_deferredResidentReleases;
|
||||||
|
Uint32 m_currentFrameIndex = 0;
|
||||||
|
Uint32 m_residentGcTick = 0;
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "VkBufferObject.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
VkBufferObject::VkBufferObject(VkBufferObject&& other) noexcept {
|
||||||
|
m_allocator = other.m_allocator;
|
||||||
|
m_buffer = other.m_buffer;
|
||||||
|
m_allocation = other.m_allocation;
|
||||||
|
m_mappedData = other.m_mappedData;
|
||||||
|
m_size = other.m_size;
|
||||||
|
|
||||||
|
other.m_allocator = nullptr;
|
||||||
|
other.m_buffer = VK_NULL_HANDLE;
|
||||||
|
other.m_allocation = nullptr;
|
||||||
|
other.m_mappedData = nullptr;
|
||||||
|
other.m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBufferObject& VkBufferObject::operator=(VkBufferObject&& other) noexcept {
|
||||||
|
if (this == &other) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Destroy();
|
||||||
|
|
||||||
|
m_allocator = other.m_allocator;
|
||||||
|
m_buffer = other.m_buffer;
|
||||||
|
m_allocation = other.m_allocation;
|
||||||
|
m_mappedData = other.m_mappedData;
|
||||||
|
m_size = other.m_size;
|
||||||
|
|
||||||
|
other.m_allocator = nullptr;
|
||||||
|
other.m_buffer = VK_NULL_HANDLE;
|
||||||
|
other.m_allocation = nullptr;
|
||||||
|
other.m_mappedData = nullptr;
|
||||||
|
other.m_size = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBufferObject::~VkBufferObject() {
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkBufferObject::Create(const VkBufferObjectDesc& desc) {
|
||||||
|
return Create(desc.allocator, desc.size, desc.usage, desc.memoryUsage, desc.allocationFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkBufferObject::Create(VmaAllocator allocator, VkDeviceSize size, VkBufferUsageFlags usage,
|
||||||
|
VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocationFlags) {
|
||||||
|
MOBILEGL_ASSERT(allocator != nullptr, "VkBufferObject::Create requires valid VMA allocator");
|
||||||
|
MOBILEGL_ASSERT(size > 0, "VkBufferObject::Create requires non-zero size");
|
||||||
|
|
||||||
|
Destroy();
|
||||||
|
m_allocator = allocator;
|
||||||
|
|
||||||
|
VkBufferCreateInfo bufferInfo{};
|
||||||
|
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
|
bufferInfo.size = size;
|
||||||
|
bufferInfo.usage = usage;
|
||||||
|
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
|
VmaAllocationCreateInfo allocationInfo{};
|
||||||
|
allocationInfo.usage = memoryUsage;
|
||||||
|
allocationInfo.flags = allocationFlags;
|
||||||
|
|
||||||
|
const VkResult result =
|
||||||
|
vmaCreateBuffer(m_allocator, &bufferInfo, &allocationInfo, &m_buffer, &m_allocation, nullptr);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
MGLOG_E("VkBufferObject::Create failed: vmaCreateBuffer returned %d", result);
|
||||||
|
m_allocator = nullptr;
|
||||||
|
m_buffer = VK_NULL_HANDLE;
|
||||||
|
m_allocation = nullptr;
|
||||||
|
m_size = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_size = size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkBufferObject::Destroy() {
|
||||||
|
Unmap();
|
||||||
|
if (m_allocator != nullptr && m_buffer != VK_NULL_HANDLE && m_allocation != nullptr) {
|
||||||
|
vmaDestroyBuffer(m_allocator, m_buffer, m_allocation);
|
||||||
|
}
|
||||||
|
m_buffer = VK_NULL_HANDLE;
|
||||||
|
m_allocation = nullptr;
|
||||||
|
m_allocator = nullptr;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* VkBufferObject::Map() {
|
||||||
|
MOBILEGL_ASSERT(IsValid(), "VkBufferObject::Map called on invalid buffer");
|
||||||
|
|
||||||
|
if (m_mappedData != nullptr) {
|
||||||
|
return m_mappedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VkResult mapResult = vmaMapMemory(m_allocator, m_allocation, &m_mappedData);
|
||||||
|
if (mapResult != VK_SUCCESS || m_mappedData == nullptr) {
|
||||||
|
MGLOG_E("VkBufferObject::Map failed: vmaMapMemory returned %d", mapResult);
|
||||||
|
m_mappedData = nullptr;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_mappedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkBufferObject::Unmap() {
|
||||||
|
if (!IsValid() || m_mappedData == nullptr) {
|
||||||
|
m_mappedData = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vmaUnmapMemory(m_allocator, m_allocation);
|
||||||
|
m_mappedData = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkBufferObject::Upload(const void* data, VkDeviceSize size, VkDeviceSize offset) {
|
||||||
|
MOBILEGL_ASSERT(IsValid(), "VkBufferObject::Upload called on invalid buffer");
|
||||||
|
MOBILEGL_ASSERT(data != nullptr || size == 0, "VkBufferObject::Upload data pointer is null");
|
||||||
|
MOBILEGL_ASSERT(offset + size <= m_size, "VkBufferObject::Upload out of range");
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Bool wasMapped = IsMapped();
|
||||||
|
void* mapped = wasMapped ? m_mappedData : Map();
|
||||||
|
if (mapped == nullptr) {
|
||||||
|
MGLOG_E("VkBufferObject::Upload failed: unable to map buffer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Memcpy(static_cast<Uint8*>(mapped) + offset, data, static_cast<SizeT>(size));
|
||||||
|
const VkResult flushResult = vmaFlushAllocation(m_allocator, m_allocation, offset, size);
|
||||||
|
if (flushResult != VK_SUCCESS) {
|
||||||
|
MGLOG_E("VkBufferObject::Upload failed: vmaFlushAllocation returned %d", flushResult);
|
||||||
|
if (!wasMapped) {
|
||||||
|
Unmap();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wasMapped) {
|
||||||
|
Unmap();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferSlice VkBufferObject::GetSlice(VkDeviceSize offset, VkDeviceSize size) const {
|
||||||
|
MOBILEGL_ASSERT(offset <= m_size, "VkBufferObject::GetSlice offset out of range");
|
||||||
|
const VkDeviceSize resolvedSize = (size == VK_WHOLE_SIZE) ? (m_size - offset) : size;
|
||||||
|
MOBILEGL_ASSERT(offset + resolvedSize <= m_size, "VkBufferObject::GetSlice range out of bounds");
|
||||||
|
|
||||||
|
BufferSlice slice{};
|
||||||
|
slice.buffer = m_buffer;
|
||||||
|
slice.offset = offset;
|
||||||
|
slice.size = resolvedSize;
|
||||||
|
slice.mapped = (m_mappedData != nullptr) ? static_cast<Uint8*>(m_mappedData) + offset : nullptr;
|
||||||
|
return slice;
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BufferSlice.h"
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include <Includes.h>
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
struct VkBufferObjectDesc {
|
||||||
|
VmaAllocator allocator = nullptr;
|
||||||
|
VkDeviceSize size = 0;
|
||||||
|
VkBufferUsageFlags usage = 0;
|
||||||
|
VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
|
||||||
|
VmaAllocationCreateFlags allocationFlags = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VkBufferObject {
|
||||||
|
public:
|
||||||
|
VkBufferObject() = default;
|
||||||
|
~VkBufferObject();
|
||||||
|
|
||||||
|
VkBufferObject(const VkBufferObject&) = delete;
|
||||||
|
VkBufferObject& operator=(const VkBufferObject&) = delete;
|
||||||
|
VkBufferObject(VkBufferObject&& other) noexcept;
|
||||||
|
VkBufferObject& operator=(VkBufferObject&& other) noexcept;
|
||||||
|
|
||||||
|
Bool Create(const VkBufferObjectDesc& desc);
|
||||||
|
Bool Create(VmaAllocator allocator, VkDeviceSize size, VkBufferUsageFlags usage,
|
||||||
|
VmaMemoryUsage memoryUsage, VmaAllocationCreateFlags allocationFlags = 0);
|
||||||
|
void Destroy();
|
||||||
|
|
||||||
|
void* Map();
|
||||||
|
void Unmap();
|
||||||
|
Bool Upload(const void* data, VkDeviceSize size, VkDeviceSize offset = 0);
|
||||||
|
|
||||||
|
VkBuffer GetHandle() const { return m_buffer; }
|
||||||
|
VkDeviceSize GetSize() const { return m_size; }
|
||||||
|
BufferSlice GetSlice(VkDeviceSize offset = 0, VkDeviceSize size = VK_WHOLE_SIZE) const;
|
||||||
|
void* GetMappedData() const { return m_mappedData; }
|
||||||
|
Bool IsMapped() const { return m_mappedData != nullptr; }
|
||||||
|
Bool IsValid() const { return m_allocator != nullptr && m_buffer != VK_NULL_HANDLE && m_allocation != nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
VmaAllocator m_allocator = nullptr;
|
||||||
|
VkBuffer m_buffer = VK_NULL_HANDLE;
|
||||||
|
VmaAllocation m_allocation = nullptr;
|
||||||
|
void* m_mappedData = nullptr;
|
||||||
|
VkDeviceSize m_size = 0;
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "VkClearManager.h"
|
||||||
|
|
||||||
|
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
|
||||||
|
#include "MG_Util/Converters/MGToStr/TextureEnumConverter.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
static SharedPtr<MG_State::GLState::ITextureObject> GetClearableAttachmentTexture(
|
||||||
|
const MG_State::GLState::FramebufferObject& drawFbo, FramebufferAttachmentType attachmentType) {
|
||||||
|
if (attachmentType == FramebufferAttachmentType::None) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& attachment = drawFbo.GetAttachment(attachmentType);
|
||||||
|
if (!attachment.IsTexture() || attachment.IsRenderbuffer()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return attachment.GetTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkClearManager::Initialize() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkClearManager::Shutdown() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkClearManager::QueueClear(GLbitfield mask, const ClearFramebufferPayload& clearPayload,
|
||||||
|
const MG_State::GLState::FramebufferObject& drawFbo) {
|
||||||
|
if (mask & GL_COLOR_BUFFER_BIT) {
|
||||||
|
auto& drawbufs = drawFbo.GetDrawBuffers();
|
||||||
|
// This should automatically work on default & offscreen FBO
|
||||||
|
for (auto drawbuf: drawbufs) {
|
||||||
|
auto texture = GetClearableAttachmentTexture(drawFbo, drawbuf);
|
||||||
|
if (!texture) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueueClear({
|
||||||
|
.mask = GL_COLOR_BUFFER_BIT,
|
||||||
|
.color = clearPayload.color
|
||||||
|
}, texture);
|
||||||
|
|
||||||
|
MGLOG_D("%s: %s (texture %d) - color = (%.2f, %.2f, %.2f, %.2f)", __func__,
|
||||||
|
MG_Util::ConvertFramebufferAttachmentTypeToString(drawbuf).c_str(),
|
||||||
|
texture->GetExternalIndex(),
|
||||||
|
clearPayload.color[0], clearPayload.color[1], clearPayload.color[2], clearPayload.color[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask & GL_DEPTH_BUFFER_BIT) {
|
||||||
|
auto texture = GetClearableAttachmentTexture(drawFbo, FramebufferAttachmentType::Depth);
|
||||||
|
if (texture) {
|
||||||
|
QueueClear({
|
||||||
|
.mask = GL_DEPTH_BUFFER_BIT,
|
||||||
|
.depth = clearPayload.depth,
|
||||||
|
}, texture);
|
||||||
|
|
||||||
|
MGLOG_D("%s: Depth (texture %d) - depth = (%.2f)", __func__,
|
||||||
|
texture->GetExternalIndex(), clearPayload.depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask & GL_STENCIL_BUFFER_BIT) {
|
||||||
|
auto texture = GetClearableAttachmentTexture(drawFbo, FramebufferAttachmentType::Stencil);
|
||||||
|
if (texture) {
|
||||||
|
QueueClear({
|
||||||
|
.mask = GL_STENCIL_BUFFER_BIT,
|
||||||
|
.stencil = clearPayload.stencil,
|
||||||
|
}, texture);
|
||||||
|
|
||||||
|
MGLOG_D("%s: Stencil (texture %d) - stencil = (%u)", __func__,
|
||||||
|
texture->GetExternalIndex(), clearPayload.stencil);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
|
||||||
|
const SharedPtr<MG_State::GLState::ITextureObject>& texture) {
|
||||||
|
if (clearPayload.mask == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WeakPtr<MG_State::GLState::ITextureObject> weakTexturePtr = texture;
|
||||||
|
if (weakTexturePtr.expired())
|
||||||
|
return;
|
||||||
|
auto* pTexture = weakTexturePtr.lock().get();
|
||||||
|
m_aliveObjects[pTexture] = weakTexturePtr;
|
||||||
|
auto& pending = m_pendingClears[pTexture];
|
||||||
|
pending.mask |= clearPayload.mask;
|
||||||
|
if (clearPayload.mask & GL_COLOR_BUFFER_BIT) {
|
||||||
|
pending.color = clearPayload.color;
|
||||||
|
}
|
||||||
|
if (clearPayload.mask & GL_DEPTH_BUFFER_BIT) {
|
||||||
|
pending.depth = clearPayload.depth;
|
||||||
|
}
|
||||||
|
if (clearPayload.mask & GL_STENCIL_BUFFER_BIT) {
|
||||||
|
pending.stencil = clearPayload.stencil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) {
|
||||||
|
return m_pendingClears.find(texture) != m_pendingClears.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkClearManager::GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload) {
|
||||||
|
if (m_aliveObjects.find(texture) == m_aliveObjects.end() ||
|
||||||
|
m_pendingClears.find(texture) == m_pendingClears.end()) {
|
||||||
|
MGLOG_D("%s: Failed getting pending clear for texture %d", __func__, texture->GetExternalIndex());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outPayload = m_pendingClears[texture];
|
||||||
|
MGLOG_D("%s: Got pending clear for texture %d (%s), mask=0x%x clear value: color = (%.2f, %.2f, %.2f, %.2f), depth = (%.2f), stencil = (%u)", __func__,
|
||||||
|
texture->GetExternalIndex(),
|
||||||
|
MG_Util::ConvertTextureInternalFormatToString(texture->GetFormat()).c_str(),
|
||||||
|
static_cast<Uint32>(outPayload.mask),
|
||||||
|
outPayload.color[0], outPayload.color[1], outPayload.color[2], outPayload.color[3],
|
||||||
|
outPayload.depth,
|
||||||
|
outPayload.stencil);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkClearManager::PopPendingClear(MG_State::GLState::ITextureObject* texture) {
|
||||||
|
MGLOG_D("%s: Pop pending clear for texture %d", __func__, texture->GetExternalIndex());
|
||||||
|
m_aliveObjects.erase(texture);
|
||||||
|
m_pendingClears.erase(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeT VkClearManager::CollectGarbage() {
|
||||||
|
m_gcCounter++;
|
||||||
|
if (m_gcCounter != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeT count = 0;
|
||||||
|
for (auto it = m_aliveObjects.begin(); it != m_aliveObjects.end();) {
|
||||||
|
auto current = it++;
|
||||||
|
if (current->second.expired()) {
|
||||||
|
m_pendingClears.erase(current->first);
|
||||||
|
m_aliveObjects.erase(current);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include "../VulkanRendererConfig.h"
|
||||||
|
#include "MG_State/GLState/FramebufferState/FramebufferObject.h"
|
||||||
|
#include "MG_Util/Math/VectorTypes.h"
|
||||||
|
|
||||||
|
#include <Includes.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
struct ClearFramebufferPayload {
|
||||||
|
FloatVec4 color;
|
||||||
|
Float depth{};
|
||||||
|
Uint32 stencil{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ClearAttachmentPayload {
|
||||||
|
GLbitfield mask = 0;
|
||||||
|
FloatVec4 color = FloatVec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
Float depth = 1.0f;
|
||||||
|
Uint32 stencil = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VkClearManager {
|
||||||
|
public:
|
||||||
|
Bool Initialize();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void QueueClear(GLbitfield mask, const ClearFramebufferPayload& clearPayload, const MG_State::GLState::FramebufferObject& drawFbo);
|
||||||
|
void QueueClear(
|
||||||
|
const ClearAttachmentPayload& clearPayload,
|
||||||
|
const SharedPtr<MG_State::GLState::ITextureObject>& texture);
|
||||||
|
Bool HasPendingClear(MG_State::GLState::ITextureObject* texture);
|
||||||
|
Bool GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload);
|
||||||
|
void PopPendingClear(MG_State::GLState::ITextureObject* texture);
|
||||||
|
SizeT CollectGarbage();
|
||||||
|
private:
|
||||||
|
Uint8 m_gcCounter = 0;
|
||||||
|
UnorderedMap<MG_State::GLState::ITextureObject*, ClearAttachmentPayload> m_pendingClears;
|
||||||
|
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,606 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "VkRenderPassManager.h"
|
||||||
|
|
||||||
|
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
||||||
|
#include "MG_State/GLState/TextureState/TextureObject2D.h"
|
||||||
|
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
|
||||||
|
#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
|
||||||
|
#include "MG_Util/Metrics/TextureMetrics.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
static Float ResolveColorClearAlpha(const MG_State::GLState::ITextureObject* texture, Float requestedAlpha) {
|
||||||
|
if (texture != nullptr && MG_Util::GetBaseInternalFormatComponentCount(texture->GetFormat()) == 3) {
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
return requestedAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MG_State::GLState::ITextureObject* ResolveCompleteColorAttachmentTexture(
|
||||||
|
const MG_State::GLState::FramebufferObject& fbo,
|
||||||
|
FramebufferAttachmentType attachmentType,
|
||||||
|
Uint32 drawBufferIndex) {
|
||||||
|
if (attachmentType == FramebufferAttachmentType::None) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& attachment = fbo.GetAttachment(attachmentType);
|
||||||
|
if (!attachment.IsTexture()) {
|
||||||
|
if (attachment.IsEmpty()) {
|
||||||
|
MGLOG_D("GetOrCreateRenderPass: draw buffer slot %u (%s) on FBO %u has no bound color attachment; using VK_ATTACHMENT_UNUSED",
|
||||||
|
drawBufferIndex,
|
||||||
|
MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(),
|
||||||
|
fbo.GetExternalIndex());
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!attachment.IsComplete()) {
|
||||||
|
MGLOG_W("GetOrCreateRenderPass: draw buffer slot %u (%s) on FBO %u has an incomplete texture attachment; using VK_ATTACHMENT_UNUSED",
|
||||||
|
drawBufferIndex,
|
||||||
|
MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(),
|
||||||
|
fbo.GetExternalIndex());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* texture = attachment.GetTexture().get();
|
||||||
|
if (texture == nullptr) {
|
||||||
|
MGLOG_W("GetOrCreateRenderPass: draw buffer slot %u (%s) on FBO %u resolved to a null texture; using VK_ATTACHMENT_UNUSED",
|
||||||
|
drawBufferIndex,
|
||||||
|
MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(),
|
||||||
|
fbo.GetExternalIndex());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
DepthStencilAttachmentLoadInfo ResolveDepthStencilAttachmentLoadInfo(
|
||||||
|
VkImageLayout trackedLayout, Bool clearDepth, Bool clearStencil) {
|
||||||
|
DepthStencilAttachmentLoadInfo info{};
|
||||||
|
info.depthLoadOp = clearDepth
|
||||||
|
? VK_ATTACHMENT_LOAD_OP_CLEAR
|
||||||
|
: (trackedLayout == VK_IMAGE_LAYOUT_UNDEFINED ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
|
||||||
|
: VK_ATTACHMENT_LOAD_OP_LOAD);
|
||||||
|
info.stencilLoadOp = clearStencil
|
||||||
|
? VK_ATTACHMENT_LOAD_OP_CLEAR
|
||||||
|
: (trackedLayout == VK_IMAGE_LAYOUT_UNDEFINED ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
|
||||||
|
: VK_ATTACHMENT_LOAD_OP_LOAD);
|
||||||
|
info.initialLayout =
|
||||||
|
(trackedLayout == VK_IMAGE_LAYOUT_UNDEFINED || (clearDepth && clearStencil)) ? VK_IMAGE_LAYOUT_UNDEFINED
|
||||||
|
: trackedLayout;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkRenderPassManager::VkRenderPassManager(VkDevice device,
|
||||||
|
const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager,
|
||||||
|
SwapchainObject& swapchainObject):
|
||||||
|
m_device(device), m_config(config), m_clearManager(clearManager), m_textureManager(textureManager),
|
||||||
|
m_swapchainObject(swapchainObject) {
|
||||||
|
RenderPassEntry::s_device = m_device;
|
||||||
|
s_clearManager = &m_clearManager;
|
||||||
|
s_textureManager = &m_textureManager;
|
||||||
|
s_swapchainObject = &m_swapchainObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkRenderPassManager::~VkRenderPassManager() {}
|
||||||
|
|
||||||
|
Bool VkRenderPassManager::Initialize() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkRenderPassManager::Shutdown() {
|
||||||
|
}
|
||||||
|
|
||||||
|
VkRenderPassManager::HashType VkRenderPassManager::ComputeHash(
|
||||||
|
const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex, Bool includePendingClear) const {
|
||||||
|
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion));
|
||||||
|
const Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
|
||||||
|
if (isDefaultFbo) {
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &swapchainImageIndex, sizeof(swapchainImageIndex)));
|
||||||
|
}
|
||||||
|
auto& drawBuffers = fbo.GetDrawBuffers();
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, drawBuffers.data(), drawBuffers.size() * sizeof(drawBuffers[0])));
|
||||||
|
auto readBuffer = fbo.GetReadBuffer();
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &readBuffer, sizeof(FramebufferAttachmentType)));
|
||||||
|
Int validDrawBufCount = 0;
|
||||||
|
for (Int i = 0; i < drawBuffers.size(); ++i) {
|
||||||
|
auto drawbuf = drawBuffers[i];
|
||||||
|
if (drawbuf != FramebufferAttachmentType::None)
|
||||||
|
validDrawBufCount = std::max(validDrawBufCount, i + 1);
|
||||||
|
}
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &validDrawBufCount, sizeof(validDrawBufCount)));
|
||||||
|
|
||||||
|
auto combineFramebufferAttachmentObjHash = [&](FramebufferAttachmentType attachment) {
|
||||||
|
auto& att = fbo.GetAttachment(attachment);
|
||||||
|
|
||||||
|
Int type = 0;
|
||||||
|
if (att.IsEmpty()) type = 0;
|
||||||
|
else if (att.IsTexture()) type = 1;
|
||||||
|
else if (att.IsRenderbuffer()) type = 2;
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &type, sizeof(type)));
|
||||||
|
void* contentPtr = nullptr;
|
||||||
|
if (att.IsTexture())
|
||||||
|
contentPtr = att.GetTexture().get();
|
||||||
|
else if (att.IsRenderbuffer())
|
||||||
|
contentPtr = att.GetRenderbuffer().get();
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &contentPtr, sizeof(contentPtr)));
|
||||||
|
if (att.IsTexture()) {
|
||||||
|
const Int textureLevel = att.GetTextureLevel();
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &textureLevel, sizeof(textureLevel)));
|
||||||
|
|
||||||
|
Uint64 imageIdentity = 0;
|
||||||
|
auto* texture = att.GetTexture().get();
|
||||||
|
auto* resource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
||||||
|
if (resource != nullptr) {
|
||||||
|
imageIdentity = reinterpret_cast<Uint64>(resource->image);
|
||||||
|
}
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &imageIdentity, sizeof(imageIdentity)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (includePendingClear && att.IsTexture()) {
|
||||||
|
auto* texture = att.GetTexture().get();
|
||||||
|
auto hasClear = m_clearManager.HasPendingClear(texture);
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &hasClear, sizeof(hasClear)));
|
||||||
|
if (hasClear) {
|
||||||
|
ClearAttachmentPayload clearPayload{};
|
||||||
|
Bool hasPayload = m_clearManager.GetPendingClear(texture, clearPayload);
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &hasPayload, sizeof(hasPayload)));
|
||||||
|
if (hasPayload) {
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &clearPayload.mask, sizeof(clearPayload.mask)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageLayout currentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
if (isDefaultFbo) {
|
||||||
|
if (attachment >= FramebufferAttachmentType::Color0 &&
|
||||||
|
attachment <= FramebufferAttachmentType::Color31) {
|
||||||
|
currentLayout = m_swapchainObject.GetImageLayout(swapchainImageIndex);
|
||||||
|
} else if (attachment == FramebufferAttachmentType::Depth ||
|
||||||
|
attachment == FramebufferAttachmentType::Stencil) {
|
||||||
|
currentLayout = m_swapchainObject.GetDepthStencilImageLayout(swapchainImageIndex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto* textureResource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
||||||
|
if (textureResource != nullptr) {
|
||||||
|
currentLayout = textureResource->layout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, ¤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) {
|
||||||
|
auto hasPendingClearOnFramebuffer = [&]() -> Bool {
|
||||||
|
const auto& drawBuffers = fbo.GetDrawBuffers();
|
||||||
|
for (auto attachment : drawBuffers) {
|
||||||
|
if (attachment == FramebufferAttachmentType::None) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& att = fbo.GetAttachment(attachment);
|
||||||
|
if (att.IsTexture() && m_clearManager.HasPendingClear(att.GetTexture().get())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth);
|
||||||
|
if (depthAtt.IsTexture() && m_clearManager.HasPendingClear(depthAtt.GetTexture().get())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& stencilAtt = fbo.GetAttachment(FramebufferAttachmentType::Stencil);
|
||||||
|
if (stencilAtt.IsTexture() && m_clearManager.HasPendingClear(stencilAtt.GetTexture().get())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// retrieve from cache first
|
||||||
|
auto* activeRenderPass = GetActiveRenderPass();
|
||||||
|
auto compatibilityHash = ComputeHash(fbo, swapchainImageIndex, false);
|
||||||
|
if (activeRenderPass != nullptr &&
|
||||||
|
activeRenderPass->CompatibleWith(compatibilityHash) &&
|
||||||
|
!hasPendingClearOnFramebuffer()) {
|
||||||
|
auto activeIt = m_renderPasses.find(activeRenderPass->hash);
|
||||||
|
MOBILEGL_ASSERT(activeIt != m_renderPasses.end(),
|
||||||
|
"GetOrCreateRenderPass: active render pass hash=0x%llx is missing from cache",
|
||||||
|
static_cast<unsigned long long>(activeRenderPass->hash));
|
||||||
|
return activeIt->second;
|
||||||
|
}
|
||||||
|
auto hash = ComputeHash(fbo, swapchainImageIndex, true);
|
||||||
|
auto it = m_renderPasses.find(hash);
|
||||||
|
if (it != m_renderPasses.end())
|
||||||
|
return it->second;
|
||||||
|
|
||||||
|
Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
|
||||||
|
// Color attachment
|
||||||
|
auto& drawbufs = fbo.GetDrawBuffers();
|
||||||
|
const Uint32 colorAttachmentSlotCount = static_cast<Uint32>(drawbufs.size());
|
||||||
|
|
||||||
|
Int width = 0;
|
||||||
|
Int height = 0;
|
||||||
|
Vector<VkAttachmentDescription> attachmentDescriptions;
|
||||||
|
attachmentDescriptions.reserve(colorAttachmentSlotCount + 1);
|
||||||
|
// Keep the full GL draw buffer slot span so fragment outputs targeting GL_NONE map to VK_ATTACHMENT_UNUSED.
|
||||||
|
Vector<VkAttachmentReference> colorAttachmentRefs(colorAttachmentSlotCount);
|
||||||
|
for (auto& attachmentRef : colorAttachmentRefs) {
|
||||||
|
attachmentRef.attachment = VK_ATTACHMENT_UNUSED;
|
||||||
|
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
}
|
||||||
|
Vector<PendingClearAttachmentInfo> pendingClearAttachments;
|
||||||
|
pendingClearAttachments.reserve(colorAttachmentSlotCount + 1);
|
||||||
|
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
||||||
|
trackedAttachmentLayouts.reserve(colorAttachmentSlotCount + 1);
|
||||||
|
auto& textureResources = RenderPassEntry::s_textureResourcesScratch;
|
||||||
|
textureResources.clear();
|
||||||
|
textureResources.reserve(colorAttachmentSlotCount + 1);
|
||||||
|
Vector<VkImageView> attachmentViews;
|
||||||
|
attachmentViews.reserve(colorAttachmentSlotCount + 1);
|
||||||
|
// This should automatically work on default & offscreen FBO
|
||||||
|
// assuming default FBO has the right param
|
||||||
|
for (Uint32 i = 0; i < colorAttachmentSlotCount; ++i) {
|
||||||
|
auto drawbuf = drawbufs[i];
|
||||||
|
auto* texture = ResolveCompleteColorAttachmentTexture(fbo, drawbuf, i);
|
||||||
|
if (texture == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto& att = fbo.GetAttachment(drawbuf);
|
||||||
|
const Uint32 attachmentMipLevel = static_cast<Uint32>(std::max(att.GetTextureLevel(), 0));
|
||||||
|
const auto textureTarget = texture->GetTarget();
|
||||||
|
const Uint32 attachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
|
||||||
|
attachmentDescriptions.emplace_back();
|
||||||
|
|
||||||
|
// Color attachment description
|
||||||
|
VkAttachmentDescription& desc = attachmentDescriptions.back();
|
||||||
|
switch (textureTarget) {
|
||||||
|
case TextureTarget::Texture2D: {
|
||||||
|
auto* texture2d =
|
||||||
|
static_cast<MG_State::GLState::TextureObject2D*>(texture);
|
||||||
|
desc.flags = 0;
|
||||||
|
desc.format = isDefaultFbo ?
|
||||||
|
m_swapchainObject.GetSurfaceFormat().format :
|
||||||
|
MG_Util::ConvertTextureInternalFormatToVkEnum(
|
||||||
|
texture2d->GetFormat());
|
||||||
|
desc.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
ClearAttachmentPayload clearPayload{};
|
||||||
|
Bool hasClear = m_clearManager.GetPendingClear(texture, clearPayload);
|
||||||
|
VkImageLayout trackedColorLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
desc.loadOp = hasClear ?
|
||||||
|
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||||
|
VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||||
|
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
desc.finalLayout = isDefaultFbo ?
|
||||||
|
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR :
|
||||||
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
if (hasClear) {
|
||||||
|
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
||||||
|
.attachmentIndex = attachmentIndex,
|
||||||
|
.texture = texture
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (width == 0)
|
||||||
|
width = att.GetSize().x();
|
||||||
|
if (height == 0)
|
||||||
|
height = att.GetSize().y();
|
||||||
|
|
||||||
|
if (isDefaultFbo) {
|
||||||
|
const auto& swapchainViews = m_swapchainObject.GetImageViews();
|
||||||
|
MOBILEGL_ASSERT(swapchainImageIndex < swapchainViews.size(),
|
||||||
|
"GetOrCreateRenderPass: swapchain image index out of range");
|
||||||
|
trackedColorLayout = m_swapchainObject.GetImageLayout(swapchainImageIndex);
|
||||||
|
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||||
|
.target = TrackedAttachmentTarget::SwapchainColor,
|
||||||
|
.swapchainImageIndex = swapchainImageIndex,
|
||||||
|
.finalLayout = desc.finalLayout,
|
||||||
|
});
|
||||||
|
textureResources.emplace_back(nullptr);
|
||||||
|
attachmentViews.emplace_back(swapchainViews[swapchainImageIndex]);
|
||||||
|
} else {
|
||||||
|
auto* textureResource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
||||||
|
MOBILEGL_ASSERT(textureResource,
|
||||||
|
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i);
|
||||||
|
textureResources.emplace_back(textureResource);
|
||||||
|
desc.format = textureResource->format;
|
||||||
|
trackedColorLayout = textureResource->layout;
|
||||||
|
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||||
|
.target = TrackedAttachmentTarget::Texture,
|
||||||
|
.texture = texture,
|
||||||
|
.textureMipLevel = attachmentMipLevel,
|
||||||
|
.finalLayout = desc.finalLayout,
|
||||||
|
});
|
||||||
|
attachmentViews.emplace_back(m_textureManager.GetOrCreateViewAtMipLevel(*texture, attachmentMipLevel));
|
||||||
|
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
|
||||||
|
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at color attachment %d", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasClear && trackedColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||||
|
MGLOG_W("GetOrCreateRenderPass: color attachment textureId=%d starts with undefined layout and no clear; "
|
||||||
|
"using LOAD_OP_DONT_CARE",
|
||||||
|
texture->GetExternalIndex());
|
||||||
|
desc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
}
|
||||||
|
desc.initialLayout = (hasClear || trackedColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) ?
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED :
|
||||||
|
trackedColorLayout;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
MOBILEGL_ASSERT(false, "Unsupported texture target");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attachment reference
|
||||||
|
VkAttachmentReference& attachmentRef = colorAttachmentRefs[i];
|
||||||
|
attachmentRef.attachment = attachmentIndex;
|
||||||
|
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depth attachment description
|
||||||
|
auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth);
|
||||||
|
VkAttachmentDescription depthAttachmentDescription;
|
||||||
|
VkAttachmentReference depthAttachmentRef;
|
||||||
|
depthAttachmentRef.attachment = VK_ATTACHMENT_UNUSED;
|
||||||
|
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
VkTextureManager::TextureResource* depthTextureResource = nullptr;
|
||||||
|
if (depthAtt.IsComplete() && depthAtt.IsTexture()) {
|
||||||
|
auto& texture = *depthAtt.GetTexture();
|
||||||
|
const Uint32 attachmentMipLevel = static_cast<Uint32>(std::max(depthAtt.GetTextureLevel(), 0));
|
||||||
|
const Uint32 depthAttachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
|
||||||
|
ClearAttachmentPayload clearPayload{};
|
||||||
|
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
|
||||||
|
Bool clearDepth = hasClear && (clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0;
|
||||||
|
Bool clearStencil = hasClear && (clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0;
|
||||||
|
VkImageLayout trackedDepthLayout = isDefaultFbo ?
|
||||||
|
m_swapchainObject.GetDepthStencilImageLayout(swapchainImageIndex) :
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
if (!isDefaultFbo) {
|
||||||
|
depthTextureResource = m_textureManager.SyncTextureAndGetDescriptor(texture);
|
||||||
|
MOBILEGL_ASSERT(depthTextureResource,
|
||||||
|
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment");
|
||||||
|
trackedDepthLayout = depthTextureResource->layout;
|
||||||
|
}
|
||||||
|
depthAttachmentDescription.flags = 0;
|
||||||
|
depthAttachmentDescription.format = isDefaultFbo ?
|
||||||
|
m_swapchainObject.GetDepthStencilFormat() :
|
||||||
|
MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
|
||||||
|
if (!isDefaultFbo) {
|
||||||
|
depthAttachmentDescription.format = depthTextureResource->format;
|
||||||
|
}
|
||||||
|
depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
const auto loadInfo =
|
||||||
|
ResolveDepthStencilAttachmentLoadInfo(trackedDepthLayout, clearDepth, clearStencil);
|
||||||
|
depthAttachmentDescription.loadOp = loadInfo.depthLoadOp;
|
||||||
|
depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
depthAttachmentDescription.stencilLoadOp = loadInfo.stencilLoadOp;
|
||||||
|
depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
depthAttachmentDescription.initialLayout = loadInfo.initialLayout;
|
||||||
|
if (trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED && (!clearDepth || !clearStencil)) {
|
||||||
|
MGLOG_W("GetOrCreateRenderPass: depth/stencil attachment textureId=%d starts with undefined layout "
|
||||||
|
"and partial/no clear; using DONT_CARE for uncleared aspects",
|
||||||
|
texture.GetExternalIndex());
|
||||||
|
}
|
||||||
|
if (hasClear) {
|
||||||
|
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
||||||
|
.attachmentIndex = depthAttachmentIndex,
|
||||||
|
.texture = &texture
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (isDefaultFbo) {
|
||||||
|
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||||
|
.target = TrackedAttachmentTarget::SwapchainDepthStencil,
|
||||||
|
.swapchainImageIndex = swapchainImageIndex,
|
||||||
|
.finalLayout = depthAttachmentDescription.finalLayout,
|
||||||
|
});
|
||||||
|
attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex));
|
||||||
|
} else {
|
||||||
|
MOBILEGL_ASSERT(depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED ||
|
||||||
|
depthAttachmentDescription.loadOp != VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
|
"GetOrCreateRenderPass: depth attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD",
|
||||||
|
texture.GetExternalIndex());
|
||||||
|
MOBILEGL_ASSERT(depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED ||
|
||||||
|
depthAttachmentDescription.stencilLoadOp != VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
|
"GetOrCreateRenderPass: stencil attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD",
|
||||||
|
texture.GetExternalIndex());
|
||||||
|
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||||
|
.target = TrackedAttachmentTarget::Texture,
|
||||||
|
.texture = &texture,
|
||||||
|
.textureMipLevel = attachmentMipLevel,
|
||||||
|
.finalLayout = depthAttachmentDescription.finalLayout,
|
||||||
|
});
|
||||||
|
textureResources.emplace_back(depthTextureResource);
|
||||||
|
attachmentViews.emplace_back(m_textureManager.GetOrCreateViewAtMipLevel(texture, attachmentMipLevel));
|
||||||
|
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
|
||||||
|
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at depth attachment");
|
||||||
|
if (width == 0 || height == 0) {
|
||||||
|
width = depthAtt.GetSize().x();
|
||||||
|
height = depthAtt.GetSize().y();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attachmentDescriptions.emplace_back(depthAttachmentDescription);
|
||||||
|
depthAttachmentRef.attachment = depthAttachmentIndex;
|
||||||
|
}
|
||||||
|
const Bool hasDepthStencilAttachment = depthAttachmentRef.attachment != VK_ATTACHMENT_UNUSED;
|
||||||
|
|
||||||
|
// Subpass
|
||||||
|
VkSubpassDescription subpassDesc;
|
||||||
|
subpassDesc.flags = 0;
|
||||||
|
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||||
|
subpassDesc.inputAttachmentCount = 0;
|
||||||
|
subpassDesc.pInputAttachments = nullptr;
|
||||||
|
subpassDesc.colorAttachmentCount = colorAttachmentRefs.size();
|
||||||
|
subpassDesc.pColorAttachments = colorAttachmentRefs.data();
|
||||||
|
subpassDesc.pResolveAttachments = nullptr;
|
||||||
|
subpassDesc.pDepthStencilAttachment = depthAtt.IsComplete() ? &depthAttachmentRef : VK_NULL_HANDLE;
|
||||||
|
subpassDesc.preserveAttachmentCount = 0;
|
||||||
|
subpassDesc.pPreserveAttachments = nullptr;
|
||||||
|
|
||||||
|
// Render Pass
|
||||||
|
VkRenderPassCreateInfo renderPassCreateInfo;
|
||||||
|
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
|
renderPassCreateInfo.pNext = VK_NULL_HANDLE;
|
||||||
|
renderPassCreateInfo.flags = 0;
|
||||||
|
renderPassCreateInfo.attachmentCount = attachmentDescriptions.size();
|
||||||
|
renderPassCreateInfo.pAttachments = attachmentDescriptions.data();
|
||||||
|
renderPassCreateInfo.subpassCount = 1;
|
||||||
|
renderPassCreateInfo.pSubpasses = &subpassDesc;
|
||||||
|
renderPassCreateInfo.dependencyCount = 0;
|
||||||
|
renderPassCreateInfo.pDependencies = nullptr;
|
||||||
|
|
||||||
|
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||||
|
VK_VERIFY(vkCreateRenderPass(m_device, &renderPassCreateInfo, nullptr, &renderPass));
|
||||||
|
|
||||||
|
// Framebuffer
|
||||||
|
VkFramebufferCreateInfo framebufferCreateInfo;
|
||||||
|
framebufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||||
|
framebufferCreateInfo.pNext = nullptr;
|
||||||
|
framebufferCreateInfo.flags = 0;
|
||||||
|
framebufferCreateInfo.renderPass = renderPass;
|
||||||
|
framebufferCreateInfo.attachmentCount = attachmentViews.size();
|
||||||
|
framebufferCreateInfo.pAttachments = attachmentViews.data();
|
||||||
|
framebufferCreateInfo.width = width;
|
||||||
|
framebufferCreateInfo.height = height;
|
||||||
|
framebufferCreateInfo.layers = 1;
|
||||||
|
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||||
|
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer));
|
||||||
|
IntVec2 extent = {width, height};
|
||||||
|
RenderPassEntry renderPassEntry {
|
||||||
|
hash,
|
||||||
|
renderPass,
|
||||||
|
framebuffer,
|
||||||
|
compatibilityHash,
|
||||||
|
Move(pendingClearAttachments),
|
||||||
|
Move(trackedAttachmentLayouts),
|
||||||
|
static_cast<Uint32>(attachmentViews.size()),
|
||||||
|
static_cast<Uint32>(colorAttachmentRefs.size()),
|
||||||
|
hasDepthStencilAttachment,
|
||||||
|
extent,
|
||||||
|
1 };
|
||||||
|
MGLOG_D("VkRenderPassManager::GetOrCreateRenderPass: hash=0x%llx compatibilityHash=0x%llx attachmentCount=%u colorAttachmentCount=%u extent=%dx%d",
|
||||||
|
static_cast<unsigned long long>(hash),
|
||||||
|
static_cast<unsigned long long>(compatibilityHash),
|
||||||
|
renderPassEntry.attachmentCount,
|
||||||
|
renderPassEntry.colorAttachmentCount,
|
||||||
|
extent.x(),
|
||||||
|
extent.y());
|
||||||
|
auto [insertedIt, _] = m_renderPasses.emplace(hash, Move(renderPassEntry));
|
||||||
|
return insertedIt->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkRenderPassManager::BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry) {
|
||||||
|
// TODO: Transition all the attachments into proper layout before starting the render pass
|
||||||
|
VkRenderPassBeginInfo renderPassBeginInfo;
|
||||||
|
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
|
renderPassBeginInfo.pNext = nullptr;
|
||||||
|
renderPassBeginInfo.renderPass = renderPassEntry.renderPass;
|
||||||
|
renderPassBeginInfo.framebuffer = renderPassEntry.framebuffer;
|
||||||
|
renderPassBeginInfo.renderArea.offset = { 0, 0 };
|
||||||
|
renderPassBeginInfo.renderArea.extent = {
|
||||||
|
(Uint32)renderPassEntry.extent.x(), (Uint32)renderPassEntry.extent.y() };
|
||||||
|
|
||||||
|
Vector<VkClearValue> clearValues(renderPassEntry.attachmentCount);
|
||||||
|
for (auto& clearValue: clearValues) {
|
||||||
|
clearValue.color = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
clearValue.depthStencil = {1.0f, 0};
|
||||||
|
}
|
||||||
|
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
|
||||||
|
if (!pending.texture || pending.attachmentIndex >= clearValues.size()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ClearAttachmentPayload clearPayload{};
|
||||||
|
if (!s_clearManager->GetPendingClear(pending.texture, clearPayload)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((clearPayload.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||||
|
clearValues[pending.attachmentIndex].color = {
|
||||||
|
clearPayload.color.x(),
|
||||||
|
clearPayload.color.y(),
|
||||||
|
clearPayload.color.z(),
|
||||||
|
ResolveColorClearAlpha(pending.texture, clearPayload.color.w())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||||
|
clearValues[pending.attachmentIndex].depthStencil.depth = clearPayload.depth;
|
||||||
|
}
|
||||||
|
if ((clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0) {
|
||||||
|
clearValues[pending.attachmentIndex].depthStencil.stencil = clearPayload.stencil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPassBeginInfo.clearValueCount = static_cast<Uint32>(clearValues.size());
|
||||||
|
renderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
|
|
||||||
|
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
|
||||||
|
s_clearManager->PopPendingClear(pending.texture);
|
||||||
|
}
|
||||||
|
s_activeRenderPass.hash = renderPassEntry.hash;
|
||||||
|
s_activeRenderPass.compatibilityHash = renderPassEntry.compatibilityHash;
|
||||||
|
s_activeRenderPass.trackedAttachmentLayouts = renderPassEntry.trackedAttachmentLayouts;
|
||||||
|
s_activeRenderPass.extent = renderPassEntry.extent;
|
||||||
|
s_hasActiveRenderPass = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) {
|
||||||
|
auto* activeRenderPass = GetActiveRenderPass();
|
||||||
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
|
if (activeRenderPass != nullptr && !activeRenderPass->trackedAttachmentLayouts.empty()) {
|
||||||
|
for (const auto& trackedAttachment : activeRenderPass->trackedAttachmentLayouts) {
|
||||||
|
switch (trackedAttachment.target) {
|
||||||
|
case TrackedAttachmentTarget::Texture:
|
||||||
|
MOBILEGL_ASSERT(s_textureManager != nullptr, "EndRenderPass: texture manager is null");
|
||||||
|
s_textureManager->UpdateTrackedImageLayoutAfterAttachmentWrite(
|
||||||
|
commandBuffer,
|
||||||
|
trackedAttachment.texture,
|
||||||
|
trackedAttachment.textureMipLevel,
|
||||||
|
trackedAttachment.finalLayout);
|
||||||
|
break;
|
||||||
|
case TrackedAttachmentTarget::SwapchainColor:
|
||||||
|
MOBILEGL_ASSERT(s_swapchainObject != nullptr, "EndRenderPass: swapchain object is null");
|
||||||
|
s_swapchainObject->SetImageLayout(trackedAttachment.swapchainImageIndex, trackedAttachment.finalLayout);
|
||||||
|
break;
|
||||||
|
case TrackedAttachmentTarget::SwapchainDepthStencil:
|
||||||
|
MOBILEGL_ASSERT(s_swapchainObject != nullptr, "EndRenderPass: swapchain object is null");
|
||||||
|
s_swapchainObject->SetDepthStencilImageLayout(trackedAttachment.swapchainImageIndex,
|
||||||
|
trackedAttachment.finalLayout);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MOBILEGL_ASSERT(false, "EndRenderPass: unsupported tracked attachment target=%d",
|
||||||
|
static_cast<Int>(trackedAttachment.target));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s_activeRenderPass = {};
|
||||||
|
s_hasActiveRenderPass = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActiveRenderPassInfo* VkRenderPassManager::GetActiveRenderPass() {
|
||||||
|
return s_hasActiveRenderPass ? &s_activeRenderPass : nullptr;
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SwapchainObject.h"
|
||||||
|
#include "VkClearManager.h"
|
||||||
|
#include "VkTextureManager.h"
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include "../VulkanRendererConfig.h"
|
||||||
|
#include "MG_State/GLState/FramebufferState/FramebufferObject.h"
|
||||||
|
|
||||||
|
#include <Includes.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
enum class TrackedAttachmentTarget : Uint8 {
|
||||||
|
Texture,
|
||||||
|
SwapchainColor,
|
||||||
|
SwapchainDepthStencil
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PendingClearAttachmentInfo {
|
||||||
|
Uint32 attachmentIndex = 0;
|
||||||
|
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TrackedAttachmentLayoutInfo {
|
||||||
|
TrackedAttachmentTarget target = TrackedAttachmentTarget::Texture;
|
||||||
|
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||||
|
Uint32 textureMipLevel = 0;
|
||||||
|
Uint32 swapchainImageIndex = 0;
|
||||||
|
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DepthStencilAttachmentLoadInfo {
|
||||||
|
VkAttachmentLoadOp depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||||
|
VkAttachmentLoadOp stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||||
|
VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
};
|
||||||
|
|
||||||
|
DepthStencilAttachmentLoadInfo ResolveDepthStencilAttachmentLoadInfo(
|
||||||
|
VkImageLayout trackedLayout, Bool clearDepth, Bool clearStencil);
|
||||||
|
|
||||||
|
struct RenderPassEntry {
|
||||||
|
static inline VkDevice s_device;
|
||||||
|
static inline Vector<VkTextureManager::TextureResource*> s_textureResourcesScratch;
|
||||||
|
Uint64 hash = 0;
|
||||||
|
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||||
|
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||||
|
Uint64 compatibilityHash = 0;
|
||||||
|
Vector<PendingClearAttachmentInfo> pendingClearAttachments;
|
||||||
|
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
||||||
|
Uint32 attachmentCount = 0;
|
||||||
|
Uint32 colorAttachmentCount = 0;
|
||||||
|
Bool hasDepthStencilAttachment = false;
|
||||||
|
IntVec2 extent = {0, 0};
|
||||||
|
Uint32 subpass = 0;
|
||||||
|
|
||||||
|
RenderPassEntry() = default;
|
||||||
|
RenderPassEntry(const RenderPassEntry&) = delete;
|
||||||
|
RenderPassEntry(RenderPassEntry&& that) noexcept {
|
||||||
|
std::swap(hash, that.hash);
|
||||||
|
std::swap(renderPass, that.renderPass);
|
||||||
|
std::swap(framebuffer, that.framebuffer);
|
||||||
|
std::swap(compatibilityHash, that.compatibilityHash);
|
||||||
|
std::swap(pendingClearAttachments, that.pendingClearAttachments);
|
||||||
|
std::swap(trackedAttachmentLayouts, that.trackedAttachmentLayouts);
|
||||||
|
std::swap(attachmentCount, that.attachmentCount);
|
||||||
|
std::swap(colorAttachmentCount, that.colorAttachmentCount);
|
||||||
|
std::swap(hasDepthStencilAttachment, that.hasDepthStencilAttachment);
|
||||||
|
std::swap(extent, that.extent);
|
||||||
|
std::swap(subpass, that.subpass);
|
||||||
|
}
|
||||||
|
RenderPassEntry(
|
||||||
|
Uint64 hash,
|
||||||
|
VkRenderPass renderpass,
|
||||||
|
VkFramebuffer framebuffer,
|
||||||
|
Uint64 compatibilityHash,
|
||||||
|
const Vector<PendingClearAttachmentInfo>& pendingClearAttachments,
|
||||||
|
const Vector<TrackedAttachmentLayoutInfo>& trackedAttachmentLayouts,
|
||||||
|
Uint32 attachmentCount,
|
||||||
|
Uint32 colorAttachmentCount,
|
||||||
|
Bool hasDepthStencilAttachment,
|
||||||
|
IntVec2 extent, int subpass):
|
||||||
|
hash(hash),
|
||||||
|
renderPass(renderpass),
|
||||||
|
framebuffer(framebuffer),
|
||||||
|
compatibilityHash(compatibilityHash),
|
||||||
|
pendingClearAttachments(Move(pendingClearAttachments)),
|
||||||
|
trackedAttachmentLayouts(Move(trackedAttachmentLayouts)),
|
||||||
|
attachmentCount(attachmentCount),
|
||||||
|
colorAttachmentCount(colorAttachmentCount),
|
||||||
|
hasDepthStencilAttachment(hasDepthStencilAttachment),
|
||||||
|
extent(extent),
|
||||||
|
subpass(subpass)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~RenderPassEntry() {
|
||||||
|
if (renderPass != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyRenderPass(s_device, renderPass, nullptr);
|
||||||
|
}
|
||||||
|
if (framebuffer != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyFramebuffer(s_device, framebuffer, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool CompatibleWith(const RenderPassEntry& that) const {
|
||||||
|
return this->compatibilityHash == that.compatibilityHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool CompatibleWith(Uint64 compatibilityHash) const {
|
||||||
|
return this->compatibilityHash == compatibilityHash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ActiveRenderPassInfo {
|
||||||
|
Uint64 hash = 0;
|
||||||
|
Uint64 compatibilityHash = 0;
|
||||||
|
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
||||||
|
IntVec2 extent = {0, 0};
|
||||||
|
|
||||||
|
Bool CompatibleWith(const RenderPassEntry& that) const {
|
||||||
|
return compatibilityHash == that.compatibilityHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool CompatibleWith(Uint64 thatCompatibilityHash) const {
|
||||||
|
return compatibilityHash == thatCompatibilityHash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class VkRenderPassManager {
|
||||||
|
public:
|
||||||
|
using HashType = Uint64;
|
||||||
|
VkRenderPassManager(VkDevice device,
|
||||||
|
const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager,
|
||||||
|
SwapchainObject& swapchainObject);
|
||||||
|
~VkRenderPassManager();
|
||||||
|
|
||||||
|
Bool Initialize();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
HashType ComputeHash(
|
||||||
|
const MG_State::GLState::FramebufferObject& fbo,
|
||||||
|
Uint32 swapchainImageIndex,
|
||||||
|
Bool includePendingClear = true) const;
|
||||||
|
RenderPassEntry& GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex);
|
||||||
|
static Bool BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry);
|
||||||
|
static Bool EndRenderPass(VkCommandBuffer commandBuffer);
|
||||||
|
static ActiveRenderPassInfo* GetActiveRenderPass();
|
||||||
|
private:
|
||||||
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
const VulkanRendererConfig& m_config;
|
||||||
|
VkClearManager& m_clearManager;
|
||||||
|
VkTextureManager& m_textureManager;
|
||||||
|
SwapchainObject& m_swapchainObject;
|
||||||
|
UnorderedMap<Uint64, RenderPassEntry> m_renderPasses;
|
||||||
|
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||||
|
static inline ActiveRenderPassInfo s_activeRenderPass{};
|
||||||
|
static inline Bool s_hasActiveRenderPass = false;
|
||||||
|
static inline VkClearManager* s_clearManager = nullptr;
|
||||||
|
static inline VkTextureManager* s_textureManager = nullptr;
|
||||||
|
static inline SwapchainObject* s_swapchainObject = nullptr;
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkSamplerManager.cpp
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#include "VkSamplerManager.h"
|
||||||
|
|
||||||
|
#include "MG_State/GLState/Core.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
namespace {
|
||||||
|
Bool UsesBorderColor(const MG_State::GLState::SamplerObject& sampler) {
|
||||||
|
return sampler.GetWrapS() == SamplerWrapMode::ClampToBorder ||
|
||||||
|
sampler.GetWrapT() == SamplerWrapMode::ClampToBorder ||
|
||||||
|
sampler.GetWrapR() == SamplerWrapMode::ClampToBorder;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool IsDepthTextureFormat(TextureInternalFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case TextureInternalFormat::DepthComponent:
|
||||||
|
case TextureInternalFormat::DepthComponent16:
|
||||||
|
case TextureInternalFormat::DepthComponent24:
|
||||||
|
case TextureInternalFormat::DepthComponent32:
|
||||||
|
case TextureInternalFormat::DepthComponent32F:
|
||||||
|
case TextureInternalFormat::Depth24Stencil8:
|
||||||
|
case TextureInternalFormat::Depth32FStencil8:
|
||||||
|
case TextureInternalFormat::DepthStencil:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool NearlyEqual(Float lhs, Float rhs) {
|
||||||
|
return std::fabs(lhs - rhs) <= 1e-6f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Float ResolveEffectiveMaxLod(const MG_State::GLState::SamplerObject& sampler) {
|
||||||
|
if (sampler.GetMipmapMode() == SamplerMipmapMode::None) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
return sampler.GetMaxLod();
|
||||||
|
}
|
||||||
|
|
||||||
|
Float ResolveEffectiveMinLod(const MG_State::GLState::SamplerObject& sampler, Float effectiveMaxLod) {
|
||||||
|
return std::min(sampler.GetMinLod(), effectiveMaxLod);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Bool VkSamplerManager::Initialize(const InitInfo& initInfo) {
|
||||||
|
Shutdown();
|
||||||
|
|
||||||
|
m_device = initInfo.device;
|
||||||
|
m_config = initInfo.config;
|
||||||
|
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE && m_config != nullptr,
|
||||||
|
"VkSamplerManager::Initialize failed: invalid initialization info");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkSamplerManager::Shutdown() {
|
||||||
|
for (auto& [_, sampler] : m_samplers) {
|
||||||
|
if (m_device != VK_NULL_HANDLE && sampler.handle != VK_NULL_HANDLE) {
|
||||||
|
vkDestroySampler(m_device, sampler.handle, nullptr);
|
||||||
|
}
|
||||||
|
sampler.handle = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
m_samplers.clear();
|
||||||
|
|
||||||
|
m_device = VK_NULL_HANDLE;
|
||||||
|
m_config = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint64 VkSamplerManager::BuildSamplerKey(const MG_State::GLState::SamplerObject& sampler,
|
||||||
|
const MG_State::GLState::ITextureObject& texture) const {
|
||||||
|
MOBILEGL_ASSERT(m_config != nullptr, "VkSamplerManager::BuildSamplerKey: m_config is null");
|
||||||
|
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config->CacheVersion));
|
||||||
|
|
||||||
|
const auto minFilter = sampler.GetMinFilter();
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &minFilter, sizeof(minFilter)));
|
||||||
|
const auto magFilter = sampler.GetMagFilter();
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &magFilter, sizeof(magFilter)));
|
||||||
|
const auto mipmapMode = sampler.GetMipmapMode();
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &mipmapMode, sizeof(mipmapMode)));
|
||||||
|
const auto wrapS = sampler.GetWrapS();
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapS, sizeof(wrapS)));
|
||||||
|
const auto wrapT = sampler.GetWrapT();
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapT, sizeof(wrapT)));
|
||||||
|
const auto wrapR = sampler.GetWrapR();
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapR, sizeof(wrapR)));
|
||||||
|
const auto maxLod = ResolveEffectiveMaxLod(sampler);
|
||||||
|
const auto minLod = ResolveEffectiveMinLod(sampler, maxLod);
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &minLod, sizeof(minLod)));
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &maxLod, sizeof(maxLod)));
|
||||||
|
const auto lodBias = sampler.GetLodBias();
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &lodBias, sizeof(lodBias)));
|
||||||
|
const auto compareMode = sampler.GetCompareMode();
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &compareMode, sizeof(compareMode)));
|
||||||
|
const auto compareFunc = ResolveCompareFunc(sampler, texture);
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &compareFunc, sizeof(compareFunc)));
|
||||||
|
const auto borderColor = ResolveVkBorderColor(sampler, texture);
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &borderColor, sizeof(borderColor)));
|
||||||
|
return XXH64_digest(m_hashState);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSampler VkSamplerManager::GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler,
|
||||||
|
const MG_State::GLState::ITextureObject& texture) {
|
||||||
|
const Uint64 key = BuildSamplerKey(sampler, texture);
|
||||||
|
auto it = m_samplers.find(key);
|
||||||
|
if (it != m_samplers.end()) {
|
||||||
|
return it->second.handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSamplerCreateInfo samplerInfo{};
|
||||||
|
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||||
|
samplerInfo.magFilter = ToVkFilter(sampler.GetMagFilter());
|
||||||
|
samplerInfo.minFilter = ToVkFilter(sampler.GetMinFilter());
|
||||||
|
samplerInfo.mipmapMode = ToVkMipmapMode(sampler.GetMipmapMode());
|
||||||
|
samplerInfo.addressModeU = ToVkAddressMode(sampler.GetWrapS());
|
||||||
|
samplerInfo.addressModeV = ToVkAddressMode(sampler.GetWrapT());
|
||||||
|
samplerInfo.addressModeW = ToVkAddressMode(sampler.GetWrapR());
|
||||||
|
samplerInfo.mipLodBias = sampler.GetLodBias();
|
||||||
|
samplerInfo.anisotropyEnable = VK_FALSE;
|
||||||
|
samplerInfo.maxAnisotropy = 1.0f;
|
||||||
|
samplerInfo.compareEnable = sampler.GetCompareMode() == SamplerCompareMode::CompareToTexture ? VK_TRUE : VK_FALSE;
|
||||||
|
samplerInfo.compareOp = ToVkCompareOp(ResolveCompareFunc(sampler, texture));
|
||||||
|
samplerInfo.maxLod = ResolveEffectiveMaxLod(sampler);
|
||||||
|
samplerInfo.minLod = ResolveEffectiveMinLod(sampler, samplerInfo.maxLod);
|
||||||
|
samplerInfo.borderColor = ResolveVkBorderColor(sampler, texture);
|
||||||
|
samplerInfo.unnormalizedCoordinates = VK_FALSE;
|
||||||
|
|
||||||
|
VkSampler vkSampler = VK_NULL_HANDLE;
|
||||||
|
VK_VERIFY(vkCreateSampler(m_device, &samplerInfo, nullptr, &vkSampler), "vkCreateSampler(texture)");
|
||||||
|
|
||||||
|
SamplerCacheEntry entry{};
|
||||||
|
entry.handle = vkSampler;
|
||||||
|
entry.externalIndex = sampler.GetExternalIndex();
|
||||||
|
entry.version = sampler.GetVersion();
|
||||||
|
m_samplers[key] = entry;
|
||||||
|
return vkSampler;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkFilter VkSamplerManager::ToVkFilter(SamplerFilterMode mode) {
|
||||||
|
return mode == SamplerFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSamplerMipmapMode VkSamplerManager::ToVkMipmapMode(SamplerMipmapMode mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case SamplerMipmapMode::Nearest:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
case SamplerMipmapMode::Linear:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
case SamplerMipmapMode::None:
|
||||||
|
default:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSamplerAddressMode VkSamplerManager::ToVkAddressMode(SamplerWrapMode mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case SamplerWrapMode::ClampToEdge:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
case SamplerWrapMode::MirroredRepeat:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
||||||
|
case SamplerWrapMode::Repeat:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
|
case SamplerWrapMode::ClampToBorder:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||||
|
case SamplerWrapMode::MirrorClampToEdge:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||||
|
default:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkCompareOp VkSamplerManager::ToVkCompareOp(SamplerCompareFunc func) {
|
||||||
|
switch (func) {
|
||||||
|
case SamplerCompareFunc::Never:
|
||||||
|
return VK_COMPARE_OP_NEVER;
|
||||||
|
case SamplerCompareFunc::Less:
|
||||||
|
return VK_COMPARE_OP_LESS;
|
||||||
|
case SamplerCompareFunc::Equal:
|
||||||
|
return VK_COMPARE_OP_EQUAL;
|
||||||
|
case SamplerCompareFunc::LessEqual:
|
||||||
|
return VK_COMPARE_OP_LESS_OR_EQUAL;
|
||||||
|
case SamplerCompareFunc::Greater:
|
||||||
|
return VK_COMPARE_OP_GREATER;
|
||||||
|
case SamplerCompareFunc::NotEqual:
|
||||||
|
return VK_COMPARE_OP_NOT_EQUAL;
|
||||||
|
case SamplerCompareFunc::GreaterEqual:
|
||||||
|
return VK_COMPARE_OP_GREATER_OR_EQUAL;
|
||||||
|
case SamplerCompareFunc::Always:
|
||||||
|
default:
|
||||||
|
return VK_COMPARE_OP_ALWAYS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SamplerCompareFunc VkSamplerManager::ResolveCompareFunc(const MG_State::GLState::SamplerObject& sampler,
|
||||||
|
const MG_State::GLState::ITextureObject& texture) {
|
||||||
|
const auto compareFunc = sampler.GetSamplerCompareFunc();
|
||||||
|
if (sampler.GetCompareMode() == SamplerCompareMode::CompareToTexture &&
|
||||||
|
IsDepthTextureFormat(texture.GetFormat()) && compareFunc == SamplerCompareFunc::Always) {
|
||||||
|
return SamplerCompareFunc::LessEqual;
|
||||||
|
}
|
||||||
|
|
||||||
|
return compareFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBorderColor VkSamplerManager::ResolveVkBorderColor(const MG_State::GLState::SamplerObject& sampler,
|
||||||
|
const MG_State::GLState::ITextureObject& texture) {
|
||||||
|
if (!UsesBorderColor(sampler)) {
|
||||||
|
return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& borderColor = texture.GetBorderColor();
|
||||||
|
const Bool isDepthTexture = IsDepthTextureFormat(texture.GetFormat());
|
||||||
|
|
||||||
|
if (isDepthTexture) {
|
||||||
|
if (NearlyEqual(borderColor.x(), 1.0f)) {
|
||||||
|
return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
||||||
|
}
|
||||||
|
if (NearlyEqual(borderColor.x(), 0.0f)) {
|
||||||
|
return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Bool rgbZero = NearlyEqual(borderColor.x(), 0.0f) && NearlyEqual(borderColor.y(), 0.0f) &&
|
||||||
|
NearlyEqual(borderColor.z(), 0.0f);
|
||||||
|
if (rgbZero && NearlyEqual(borderColor.w(), 0.0f)) {
|
||||||
|
return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||||
|
}
|
||||||
|
if (rgbZero && NearlyEqual(borderColor.w(), 1.0f)) {
|
||||||
|
return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
|
||||||
|
}
|
||||||
|
if (NearlyEqual(borderColor.x(), 1.0f) && NearlyEqual(borderColor.y(), 1.0f) &&
|
||||||
|
NearlyEqual(borderColor.z(), 1.0f) && NearlyEqual(borderColor.w(), 1.0f)) {
|
||||||
|
return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkSamplerManager.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include "../VulkanRendererConfig.h"
|
||||||
|
#include <Includes.h>
|
||||||
|
#include <MG_State/GLState/SamplerState/SamplerObject.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_State::GLState {
|
||||||
|
class SamplerObject;
|
||||||
|
class ITextureObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
class VkSamplerManager {
|
||||||
|
public:
|
||||||
|
struct InitInfo {
|
||||||
|
VkDevice device = VK_NULL_HANDLE;
|
||||||
|
const VulkanRendererConfig* config = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
Bool Initialize(const InitInfo& initInfo);
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
VkSampler GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler,
|
||||||
|
const MG_State::GLState::ITextureObject& texture);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct SamplerCacheEntry {
|
||||||
|
VkSampler handle = VK_NULL_HANDLE;
|
||||||
|
Uint externalIndex = 0;
|
||||||
|
Uint16 version = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Uint64 BuildSamplerKey(const MG_State::GLState::SamplerObject& sampler,
|
||||||
|
const MG_State::GLState::ITextureObject& texture) const;
|
||||||
|
static VkFilter ToVkFilter(SamplerFilterMode mode);
|
||||||
|
static VkSamplerMipmapMode ToVkMipmapMode(SamplerMipmapMode mode);
|
||||||
|
static VkSamplerAddressMode ToVkAddressMode(SamplerWrapMode mode);
|
||||||
|
static VkCompareOp ToVkCompareOp(SamplerCompareFunc func);
|
||||||
|
static SamplerCompareFunc ResolveCompareFunc(const MG_State::GLState::SamplerObject& sampler,
|
||||||
|
const MG_State::GLState::ITextureObject& texture);
|
||||||
|
static VkBorderColor ResolveVkBorderColor(const MG_State::GLState::SamplerObject& sampler,
|
||||||
|
const MG_State::GLState::ITextureObject& texture);
|
||||||
|
|
||||||
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
const VulkanRendererConfig* m_config = nullptr;
|
||||||
|
UnorderedMap<Uint64, SamplerCacheEntry> m_samplers;
|
||||||
|
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,189 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
#include <Includes.h>
|
||||||
|
#include <MG_State/GLState/TextureState/TextureObject.h>
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_State::GLState {
|
||||||
|
class ITextureObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
class VkTextureManager {
|
||||||
|
public:
|
||||||
|
struct InitInfo {
|
||||||
|
VkDevice device = VK_NULL_HANDLE;
|
||||||
|
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||||
|
VmaAllocator allocator = nullptr;
|
||||||
|
VkCommandPool commandPool = VK_NULL_HANDLE;
|
||||||
|
VkQueue graphicsQueue = VK_NULL_HANDLE;
|
||||||
|
Uint32 frameCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextureResource {
|
||||||
|
VkImage image = VK_NULL_HANDLE;
|
||||||
|
VmaAllocation allocation = nullptr;
|
||||||
|
VkImageView fullView = VK_NULL_HANDLE;
|
||||||
|
VkImageView sampledView = VK_NULL_HANDLE;
|
||||||
|
Vector<VkImageView> perMipViews;
|
||||||
|
Vector<VkImageView> perMipSampledViews;
|
||||||
|
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
VkExtent2D extent = {0, 0};
|
||||||
|
Uint32 depth = 1;
|
||||||
|
Uint32 arrayLayers = 1;
|
||||||
|
Uint32 mipLevels = 1;
|
||||||
|
Uint32 sampledBaseMipLevel = 0;
|
||||||
|
Uint32 sampledLevelCount = 1;
|
||||||
|
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||||
|
VkImageAspectFlags aspect = VK_IMAGE_ASPECT_NONE;
|
||||||
|
VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
Uint16 syncedTextureParamsVersion = 0;
|
||||||
|
|
||||||
|
TextureResource() = default;
|
||||||
|
TextureResource(const TextureResource&) = delete;
|
||||||
|
TextureResource(TextureResource&& that) noexcept {
|
||||||
|
std::swap(this->image, that.image);
|
||||||
|
std::swap(this->allocation, that.allocation);
|
||||||
|
std::swap(this->fullView, that.fullView);
|
||||||
|
std::swap(this->sampledView, that.sampledView);
|
||||||
|
std::swap(this->perMipViews, that.perMipViews);
|
||||||
|
std::swap(this->perMipSampledViews, that.perMipSampledViews);
|
||||||
|
std::swap(this->layout, that.layout);
|
||||||
|
std::swap(this->extent, that.extent);
|
||||||
|
std::swap(this->depth, that.depth);
|
||||||
|
std::swap(this->arrayLayers, that.arrayLayers);
|
||||||
|
std::swap(this->mipLevels, that.mipLevels);
|
||||||
|
std::swap(this->sampledBaseMipLevel, that.sampledBaseMipLevel);
|
||||||
|
std::swap(this->sampledLevelCount, that.sampledLevelCount);
|
||||||
|
std::swap(this->format, that.format);
|
||||||
|
std::swap(this->aspect, that.aspect);
|
||||||
|
std::swap(this->viewType, that.viewType);
|
||||||
|
std::swap(this->syncedTextureParamsVersion, that.syncedTextureParamsVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() {
|
||||||
|
if (fullView != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyImageView(s_device, fullView, nullptr);
|
||||||
|
}
|
||||||
|
if (sampledView != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyImageView(s_device, sampledView, nullptr);
|
||||||
|
}
|
||||||
|
for (const auto attachmentView : perMipViews) {
|
||||||
|
if (attachmentView != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyImageView(s_device, attachmentView, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto sampledView : perMipSampledViews) {
|
||||||
|
if (sampledView != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyImageView(s_device, sampledView, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (image != VK_NULL_HANDLE && allocation != nullptr) {
|
||||||
|
vmaDestroyImage(s_allocator, image, allocation);
|
||||||
|
}
|
||||||
|
fullView = VK_NULL_HANDLE;
|
||||||
|
sampledView = VK_NULL_HANDLE;
|
||||||
|
perMipViews.clear();
|
||||||
|
perMipSampledViews.clear();
|
||||||
|
image = VK_NULL_HANDLE;
|
||||||
|
allocation = nullptr;
|
||||||
|
layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
extent = {0, 0};
|
||||||
|
depth = 1;
|
||||||
|
arrayLayers = 1;
|
||||||
|
mipLevels = 1;
|
||||||
|
sampledBaseMipLevel = 0;
|
||||||
|
sampledLevelCount = 1;
|
||||||
|
format = VK_FORMAT_UNDEFINED;
|
||||||
|
aspect = VK_IMAGE_ASPECT_NONE;
|
||||||
|
viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
syncedTextureParamsVersion = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~TextureResource() {
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline VkDevice s_device = VK_NULL_HANDLE;
|
||||||
|
static inline VmaAllocator s_allocator = VK_NULL_HANDLE;
|
||||||
|
};
|
||||||
|
|
||||||
|
Bool Initialize(const InitInfo& initInfo);
|
||||||
|
void Shutdown();
|
||||||
|
void BeginFrame(Uint32 frameIndex);
|
||||||
|
|
||||||
|
TextureResource* SyncTextureAndGetDescriptor(
|
||||||
|
MG_State::GLState::ITextureObject& texture);
|
||||||
|
VkImageView GetOrCreateViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel);
|
||||||
|
VkImageView GetOrCreateSampledViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel);
|
||||||
|
void UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout);
|
||||||
|
void UpdateTrackedImageLayoutAfterAttachmentWrite(VkCommandBuffer commandBuffer,
|
||||||
|
MG_State::GLState::ITextureObject* texture,
|
||||||
|
Uint32 writtenMipLevel,
|
||||||
|
VkImageLayout newLayout);
|
||||||
|
Bool TransitionTextureForSampling(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture);
|
||||||
|
Bool TransitionTextureForStorageImage(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture);
|
||||||
|
|
||||||
|
static VkImageAspectFlags ResolveSampledImageViewAspectMask(VkImageAspectFlags imageAspect);
|
||||||
|
|
||||||
|
static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout,
|
||||||
|
VkImageLayout newLayout, VkPipelineStageFlags srcStageMask,
|
||||||
|
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
|
||||||
|
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask,
|
||||||
|
Uint32 baseMipLevel = 0, Uint32 levelCount = 1,
|
||||||
|
Uint32 layerCount = 1);
|
||||||
|
|
||||||
|
SizeT CollectGarbage();
|
||||||
|
private:
|
||||||
|
|
||||||
|
Bool SyncTexture(MG_State::GLState::ITextureObject &texture,
|
||||||
|
TextureResource &outResource);
|
||||||
|
Bool SyncTextureResource(const MG_State::GLState::ITextureObject &texture,
|
||||||
|
TextureUploadTarget uploadTarget,
|
||||||
|
const IntVec3 &texelSize, SizeT byteSize, Uint32 mipLevels,
|
||||||
|
TextureResource &resource);
|
||||||
|
Bool SyncTextureViews(const MG_State::GLState::ITextureObject& texture, TextureResource& resource);
|
||||||
|
VkImageView CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspect,
|
||||||
|
VkImageViewType viewType, Uint32 baseMipLevel, Uint32 levelCount,
|
||||||
|
Uint32 layerCount,
|
||||||
|
const VkComponentMapping* components = nullptr) const;
|
||||||
|
Bool UploadDirtyMipLevels(MG_State::GLState::TextureObjectMipmap &mipmapTexture,
|
||||||
|
TextureUploadTarget uploadTarget,
|
||||||
|
TextureResource &outResource);
|
||||||
|
static Bool CheckMipmapCompleteness(const MG_State::GLState::ITextureObject& texture,
|
||||||
|
TextureUploadTarget& outTarget,
|
||||||
|
IntVec3& outTexelSize,
|
||||||
|
SizeT& outByteSize,
|
||||||
|
Uint32& outMipLevelCount);
|
||||||
|
static Uint32 GetUploadMipLevelCount(const MG_State::GLState::TextureObjectMipmap& texture, TextureUploadTarget target);
|
||||||
|
static void ResolveViewMipRange(const MG_State::GLState::ITextureObject& texture, Uint32 mipLevels,
|
||||||
|
Uint32& outBaseMipLevel, Uint32& outLevelCount);
|
||||||
|
static VkImageAspectFlags GetAspectMaskForFormat(VkFormat format);
|
||||||
|
void DeferResourceRelease(TextureResource&& resource);
|
||||||
|
void DeferViewRelease(VkImageView view);
|
||||||
|
void CollectDeferredReleases(Uint32 frameIndex);
|
||||||
|
void DestroyDeferredReleases();
|
||||||
|
|
||||||
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
||||||
|
VmaAllocator m_allocator = nullptr;
|
||||||
|
VkCommandPool m_commandPool = VK_NULL_HANDLE;
|
||||||
|
VkQueue m_graphicsQueue = VK_NULL_HANDLE;
|
||||||
|
Uint32 m_currentFrameIndex = 0;
|
||||||
|
|
||||||
|
Uint8 m_gcCounter = 0;
|
||||||
|
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
|
||||||
|
UnorderedMap<MG_State::GLState::ITextureObject*, TextureResource> m_textureResources;
|
||||||
|
Vector<Vector<TextureResource>> m_deferredReleases;
|
||||||
|
Vector<Vector<VkImageView>> m_deferredViewReleases;
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,337 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "Config.h"
|
||||||
|
#include "FrameContext.h"
|
||||||
|
#include "PipelineFactory.h"
|
||||||
|
#include "ProgramFactory.h"
|
||||||
|
#include "SwapchainObject.h"
|
||||||
|
#include "UniformManager.h"
|
||||||
|
#include "VertexInputStateFactory.h"
|
||||||
|
#include "VkBufferObject.h"
|
||||||
|
#include "VkBufferManager.h"
|
||||||
|
#include "VkClearManager.h"
|
||||||
|
#include "VkRenderPassManager.h"
|
||||||
|
#include "VkSamplerManager.h"
|
||||||
|
#include "VkTextureManager.h"
|
||||||
|
#include "MG_Util/Math/VectorTypes.h"
|
||||||
|
#include <Includes.h>
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
|
|
||||||
|
#include "../VkIncludes.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_State::GLState {
|
||||||
|
class FramebufferObject;
|
||||||
|
class ProgramObject;
|
||||||
|
class SamplerObject;
|
||||||
|
class VertexArrayObject;
|
||||||
|
} // namespace MobileGL::MG_State::GLState
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
enum class DrawSetupAspect: Uint8 {
|
||||||
|
FramebufferObject = 1 << 0,
|
||||||
|
VertexArrayObject = 1 << 1,
|
||||||
|
UniformBuffer = 1 << 2,
|
||||||
|
VertexBuffer = 1 << 3,
|
||||||
|
IndexBuffer = 1 << 4,
|
||||||
|
IndirectDrawBuffer = 1 << 5,
|
||||||
|
Viewport = 1 << 6,
|
||||||
|
Scissor = 1 << 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DrawCmdParam {
|
||||||
|
Uint32 vertexCount = 0;
|
||||||
|
Uint32 instanceCount = 1;
|
||||||
|
Uint32 firstVertex = 0;
|
||||||
|
Uint32 firstInstance = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DrawIndexedCmdParam {
|
||||||
|
Uint32 indexCount = 0;
|
||||||
|
Uint32 instanceCount = 1;
|
||||||
|
Uint32 firstIndex = 0;
|
||||||
|
Int32 vertexOffset = 0;
|
||||||
|
Int32 firstInstance = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DrawCmd {
|
||||||
|
GLenum mode = GL_TRIANGLES;
|
||||||
|
DrawCmdParam params;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IndexBufferView {
|
||||||
|
GLenum indexType = GL_UNSIGNED_SHORT;
|
||||||
|
SizeT indexByteOffset = 0;
|
||||||
|
SizeT indexByteSize = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DrawIndexedCmd {
|
||||||
|
GLenum mode = GL_TRIANGLES;
|
||||||
|
IndexBufferView indexBufferView;
|
||||||
|
|
||||||
|
DrawIndexedCmdParam params;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MultiDrawIndexedCmd {
|
||||||
|
GLenum mode = GL_TRIANGLES;
|
||||||
|
IndexBufferView indexBufferView;
|
||||||
|
|
||||||
|
Uint32 drawCount = 0;
|
||||||
|
DrawIndexedCmdParam* pParams = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QueueFamilyIndices {
|
||||||
|
Int32 graphicsFamily = -1;
|
||||||
|
Int32 presentFamily = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PhysicalDevice {
|
||||||
|
QueueFamilyIndices queueFamilies;
|
||||||
|
VkPhysicalDeviceProperties properties;
|
||||||
|
VkPhysicalDevice handle = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
Bool IsComplete() const {
|
||||||
|
return handle != VK_NULL_HANDLE && queueFamilies.graphicsFamily != -1 && queueFamilies.presentFamily != -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class VulkanRenderer {
|
||||||
|
public:
|
||||||
|
VulkanRenderer(NativeWindowType window, const VulkanRendererConfig& cfg = {});
|
||||||
|
~VulkanRenderer();
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
Bool SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags<DrawSetupAspect> aspects,
|
||||||
|
const DrawCmdParam& drawParams,
|
||||||
|
const IndexBufferView* pIndexBufferView = nullptr);
|
||||||
|
void ClearAttachmentsOnActiveRenderPass(VkCommandBuffer commandBuffer,
|
||||||
|
const RenderPassEntry& compatibleRenderPassEntry);
|
||||||
|
|
||||||
|
void Clear(GLbitfield mask);
|
||||||
|
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||||
|
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||||
|
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
||||||
|
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
|
||||||
|
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
||||||
|
GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||||
|
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
||||||
|
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||||
|
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||||
|
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||||
|
GLbitfield mask, GLenum filter);
|
||||||
|
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFbo,
|
||||||
|
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFbo,
|
||||||
|
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||||
|
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||||
|
GLbitfield mask, GLenum filter);
|
||||||
|
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||||
|
GLint x, GLint y, GLsizei width, GLsizei height);
|
||||||
|
void GenerateMipmap(GLenum target);
|
||||||
|
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
||||||
|
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
|
||||||
|
void GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& texture,
|
||||||
|
TextureUploadTarget uploadTarget, GLint level, GLenum format, GLenum type,
|
||||||
|
GLsizei bufSize, GLvoid* pixels);
|
||||||
|
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
|
||||||
|
void DispatchComputeIndirect(GLintptr indirect);
|
||||||
|
void MemoryBarrier(GLbitfield barriers);
|
||||||
|
static VkMemoryBarrier BuildMemoryBarrierForGlBarriers(GLbitfield barriers);
|
||||||
|
void DrawArrays(const DrawCmd& payload);
|
||||||
|
void DrawElements(const DrawIndexedCmd& payload);
|
||||||
|
void MultiDrawElements(const MultiDrawIndexedCmd& payloads);
|
||||||
|
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
|
||||||
|
GLsizei maxdrawcount, GLsizei stride);
|
||||||
|
void Present();
|
||||||
|
|
||||||
|
const PhysicalDevice& GetPhysicalDevice() const;
|
||||||
|
VkInstance GetInstance() const;
|
||||||
|
Bool IsDrawIndirectCountExtensionEnabled() const;
|
||||||
|
|
||||||
|
void RecreateSwapchain();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct BlitUniformData {
|
||||||
|
float srcRect[4] = {0.f, 0.f, 1.f, 1.f};
|
||||||
|
float dstRect[4] = {0.f, 0.f, 1.f, 1.f};
|
||||||
|
Int surfaceTransform = 0;
|
||||||
|
Int padding[3] = {0, 0, 0};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BlitResources {
|
||||||
|
SharedPtr<MG_State::GLState::ProgramObject> program;
|
||||||
|
SharedPtr<MG_State::GLState::SamplerObject> nearestSampler;
|
||||||
|
SharedPtr<MG_State::GLState::SamplerObject> linearSampler;
|
||||||
|
Int srcRectLocation = -1;
|
||||||
|
Int dstRectLocation = -1;
|
||||||
|
Int surfaceTransformLocation = -1;
|
||||||
|
Uint32 samplerBinding = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DepthMipmapResources {
|
||||||
|
SharedPtr<MG_State::GLState::ProgramObject> program;
|
||||||
|
Int srcRectLocation = -1;
|
||||||
|
Int dstRectLocation = -1;
|
||||||
|
Int surfaceTransformLocation = -1;
|
||||||
|
Int srcTexelSizeLocation = -1;
|
||||||
|
Uint32 samplerBinding = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DeferredDepthMipmapCleanup {
|
||||||
|
Vector<VkImageView> imageViews;
|
||||||
|
Vector<VkFramebuffer> framebuffers;
|
||||||
|
Vector<VkRenderPass> renderPasses;
|
||||||
|
Vector<VkPipeline> pipelines;
|
||||||
|
};
|
||||||
|
|
||||||
|
void QueueClearBufferPayload(GLenum buffer, GLint drawbuffer, const ClearAttachmentPayload& clearPayload);
|
||||||
|
void QueueClearBufferPayloadForFramebuffer(const MG_State::GLState::FramebufferObject& framebuffer,
|
||||||
|
GLenum buffer, GLint drawbuffer,
|
||||||
|
const ClearAttachmentPayload& clearPayload);
|
||||||
|
|
||||||
|
NativeWindowType m_window = 0;
|
||||||
|
void* m_platformDisplay = nullptr;
|
||||||
|
void* m_platformLibrary = nullptr;
|
||||||
|
void* m_platformCloseDisplay = nullptr;
|
||||||
|
VulkanRendererConfig m_config;
|
||||||
|
|
||||||
|
// Vulkan objects
|
||||||
|
Bool m_validationLayersEnabled = false;
|
||||||
|
Vector<VkExtensionProperties> m_extensions;
|
||||||
|
VkInstance m_instance = VK_NULL_HANDLE;
|
||||||
|
VkDebugUtilsMessengerEXT m_debugMessenger = VK_NULL_HANDLE;
|
||||||
|
PhysicalDevice m_physicalDevice;
|
||||||
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
VmaAllocator m_allocator = nullptr;
|
||||||
|
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
|
||||||
|
SwapchainObject m_swapchainObject;
|
||||||
|
|
||||||
|
VkQueue m_graphicsQueue = VK_NULL_HANDLE;
|
||||||
|
VkQueue m_presentQueue = VK_NULL_HANDLE;
|
||||||
|
Bool m_drawIndirectCountExtensionEnabled = false;
|
||||||
|
Bool m_indexTypeUint8ExtensionEnabled = false;
|
||||||
|
using PFNDrawIndexedIndirectCountFunc = void(VKAPI_PTR*)(VkCommandBuffer commandBuffer, VkBuffer buffer,
|
||||||
|
VkDeviceSize offset, VkBuffer countBuffer,
|
||||||
|
VkDeviceSize countBufferOffset, Uint32 maxDrawCount,
|
||||||
|
Uint32 stride);
|
||||||
|
static inline PFNDrawIndexedIndirectCountFunc s_vkCmdDrawIndexedIndirectCount = nullptr;
|
||||||
|
|
||||||
|
VkCommandPool m_commandPool = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
struct TransientBufferSliceCacheEntry {
|
||||||
|
BufferSlice slice;
|
||||||
|
Uint64 changeSerial = 0;
|
||||||
|
SizeT size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
VkBufferManager m_bufferManager;
|
||||||
|
UnorderedMap<const MG_State::GLState::BufferObject*, TransientBufferSliceCacheEntry>
|
||||||
|
m_transientVertexIndexBufferSlicesThisFrame;
|
||||||
|
|
||||||
|
Uint m_imageIndexAcquired = 0;
|
||||||
|
FrameContext m_frameContext;
|
||||||
|
|
||||||
|
UniquePtr<PipelineFactory> m_pipelineFactory;
|
||||||
|
UnorderedMap<ProgramFactory::HashType, VkPipeline> m_computePipelines;
|
||||||
|
UniquePtr<ProgramFactory> m_programFactory;
|
||||||
|
UniquePtr<UniformManager> m_uniformManager;
|
||||||
|
UniquePtr<VertexInputStateFactory> m_vertexInputStateFactory;
|
||||||
|
UniquePtr<VkClearManager> m_clearManager;
|
||||||
|
UniquePtr<VkRenderPassManager> m_renderPassManager;
|
||||||
|
UniquePtr<VkTextureManager> m_textureManager;
|
||||||
|
UniquePtr<VkSamplerManager> m_samplerManager;
|
||||||
|
BlitResources m_blitResources;
|
||||||
|
DepthMipmapResources m_depthMipmapResources;
|
||||||
|
Vector<DeferredDepthMipmapCleanup> m_deferredDepthMipmapCleanup;
|
||||||
|
|
||||||
|
void CreateInstance();
|
||||||
|
VkResult SetupDebugMessenger();
|
||||||
|
VkResult DestroyDebugMessenger();
|
||||||
|
VkDebugUtilsMessengerCreateInfoEXT PopulateDebugMessengerCreateInfo();
|
||||||
|
void CreateSurface();
|
||||||
|
void PickPhysicalDevice();
|
||||||
|
void CreateLogicalDeviceAndQueues();
|
||||||
|
void CreateAllocator();
|
||||||
|
void DestroyAllocator();
|
||||||
|
void CreateSwapchain();
|
||||||
|
void CreateCommandPool();
|
||||||
|
|
||||||
|
VkPipeline GetOrCreatePipeline(
|
||||||
|
GLenum mode,
|
||||||
|
const MG_State::GLState::ProgramObject& program,
|
||||||
|
const ProgramFactory::VkProgramObject& programObj,
|
||||||
|
ProgramFactory::CompileOptionFlags transformFlags,
|
||||||
|
const MG_State::GLState::VertexArrayObject& vao,
|
||||||
|
const RenderPassEntry& renderPassEntry);
|
||||||
|
VkPipeline GetOrCreateComputePipeline(const ProgramFactory::VkProgramObject& programObj);
|
||||||
|
void DestroyComputePipelines();
|
||||||
|
|
||||||
|
Bool UploadAndBindVertexBuffers(VkCommandBuffer commandBuffer, const MG_State::GLState::VertexArrayObject& vao,
|
||||||
|
const DrawCmdParam& drawParams);
|
||||||
|
Bool UploadAndBindIndexBuffer(FrameContext::FrameData& frame,
|
||||||
|
const MG_State::GLState::VertexArrayObject& vao,
|
||||||
|
const IndexBufferView* pIndexBufferView = nullptr);
|
||||||
|
Bool InitializeBlitResources();
|
||||||
|
Bool InitializeDepthMipmapResources();
|
||||||
|
void ShutdownBlitResources();
|
||||||
|
void ShutdownDepthMipmapResources();
|
||||||
|
void CollectDeferredDepthMipmapCleanup(Uint32 frameIndex);
|
||||||
|
void DestroyDeferredDepthMipmapCleanup();
|
||||||
|
Bool TryBlitToDefaultFramebufferWithShader(FrameContext::FrameData& frame,
|
||||||
|
MG_State::GLState::FramebufferObject& readFbo,
|
||||||
|
MG_State::GLState::FramebufferObject& drawFbo,
|
||||||
|
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||||
|
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||||
|
GLenum filter);
|
||||||
|
Bool MaterializePendingClearForTexture(VkCommandBuffer commandBuffer,
|
||||||
|
MG_State::GLState::ITextureObject& texture);
|
||||||
|
VkPipeline GetOrCreateBlitPipeline(const RenderPassEntry& renderPassEntry);
|
||||||
|
Bool GenerateDepthMipmapWithShader(FrameContext::FrameData& frame,
|
||||||
|
MG_State::GLState::ITextureObject& texture,
|
||||||
|
VkTextureManager::TextureResource& resource,
|
||||||
|
Uint32 baseMipLevel,
|
||||||
|
Uint32 generateMipLevelCount,
|
||||||
|
const IntVec3& storageBaseTexelSize,
|
||||||
|
VkImageLayout originalLayout,
|
||||||
|
VkImageLayout finalLayout);
|
||||||
|
Bool SubmitReadbackCommandsAndWait(FrameContext::FrameData& frame);
|
||||||
|
|
||||||
|
void ShutdownSwapchain();
|
||||||
|
|
||||||
|
// Static functions
|
||||||
|
static Int GetPresentQueueFamilyIndex(const PhysicalDevice& physicalDevice, VkSurfaceKHR surface,
|
||||||
|
const Vector<VkQueueFamilyProperties>& queueFamilies,
|
||||||
|
Int preferredFamilyIndex = -1);
|
||||||
|
static Vector<VkQueueFamilyProperties> GetQueueFamilyFromPhysicalDevice(VkPhysicalDevice device);
|
||||||
|
static Int GetQueueFamilyIndex(const Vector<VkQueueFamilyProperties>& queueFamilies, VkQueueFlagBits flag);
|
||||||
|
static Vector<VkExtensionProperties> EnumerateInstanceExtensions();
|
||||||
|
static Vector<VkExtensionProperties> EnumerateDeviceExtensions(VkPhysicalDevice device);
|
||||||
|
static Bool IsExtensionSupported(const Vector<VkExtensionProperties>& availableExtensions,
|
||||||
|
const char* extensionName);
|
||||||
|
static Bool IsExtensionAlreadyEnabled(const Vector<const char*>& enabledExtensions, const char* extensionName);
|
||||||
|
static Bool EnableOptionalDeviceExtension(const Vector<VkExtensionProperties>& availableExtensions,
|
||||||
|
Vector<const char*>& inOutEnabledExtensions,
|
||||||
|
const char* extensionName);
|
||||||
|
void ResolveOptionalDeviceExtensions(const Vector<VkExtensionProperties>& availableExtensions,
|
||||||
|
Vector<const char*>& inOutEnabledExtensions);
|
||||||
|
static Bool IsNecessaryDeviceExtensionSupported(VkPhysicalDevice device);
|
||||||
|
static Bool GetMoreCapablePhysicalDevice(VkPhysicalDevice newVkDevice, VkSurfaceKHR surface,
|
||||||
|
const PhysicalDevice& compareWithDevice,
|
||||||
|
PhysicalDevice& outBetterDevice);
|
||||||
|
static constexpr const char* s_validationLayerNames[] = {"VK_LAYER_KHRONOS_validation"};
|
||||||
|
static constexpr const char* s_deviceExtensionNames[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
||||||
|
static Bool CheckValidationLayerSupport();
|
||||||
|
|
||||||
|
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
|
void* pUserData);
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// 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)
|
||||||
+3
-4
@@ -1,4 +1,4 @@
|
|||||||
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Renderer/PipelineManager.cpp
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/VmaImpl.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,6 +6,5 @@
|
|||||||
// 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 <Includes.h>
|
#define VMA_IMPLEMENTATION
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager {}
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRendererConfig.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
struct VulkanRendererConfig {
|
||||||
|
Uint32 MaxFramesInFlight = 2;
|
||||||
|
String AppName = "MobileGL-VulkanRenderer";
|
||||||
|
MobileGL::Version Version = MG_Config::CoreVersion;
|
||||||
|
Uint64 CacheVersion = MG_Config::CacheVersion;
|
||||||
|
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||||
|
Bool EnableValidationLayers = true;
|
||||||
|
#else
|
||||||
|
Bool EnableValidationLayers = false;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/BackendObject_DirectVulkanTMP.cpp
|
|
||||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
|
||||||
// Licensed under the GNU Lesser General Public License v3.0:
|
|
||||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
|
||||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
|
||||||
// SPDX-License-Identifier: LGPL-3.0-only
|
|
||||||
// End of Source File Header
|
|
||||||
|
|
||||||
#include "BackendObject_DirectVulkanTMP.h"
|
|
||||||
#include "MG_Backend/BackendObject.h"
|
|
||||||
#include "DirectVulkanTMP.h"
|
|
||||||
#include "TmpImpl.h"
|
|
||||||
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkanTMP {
|
|
||||||
BackendObject_DirectVulkanTMP::~BackendObject_DirectVulkanTMP() = default;
|
|
||||||
|
|
||||||
void BackendObject_DirectVulkanTMP::InitWindowSurface() {
|
|
||||||
auto nativeWindow = reinterpret_cast<NativeWindowType>(m_windowHandle.Handle);
|
|
||||||
if (!DirectVulkanTMP::InitWindowSurface(nativeWindow)) {
|
|
||||||
MGLOG_E("Failed to initialize window surface for DirectVulkanTMP backend");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackendObject_DirectVulkanTMP::Initialize() {
|
|
||||||
m_initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackendObject_DirectVulkanTMP::InitCapabilities() {
|
|
||||||
if (!m_initialized) {
|
|
||||||
MGLOG_E("Cannot initialize capabilities before backend is initialized");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MG_Util::BackendLoader::QueryVulkanCapabilities(m_vulkanCaps,
|
|
||||||
DirectVulkanTMP::GetVulkanState().ctx->GetPhysicalDevice());
|
|
||||||
UpdateDynamicBackendParameters();
|
|
||||||
}
|
|
||||||
|
|
||||||
const RendererInfo& BackendObject_DirectVulkanTMP::GetRendererInfo() const {
|
|
||||||
static RendererInfo RendererInfo = {
|
|
||||||
.RendererName = "Magma-TMP", // Renderer Name
|
|
||||||
.BackendName = "Direct (Vulkan) TMP", // Backend Name
|
|
||||||
.ExtraVendor = Nullopt, // Extra vendor
|
|
||||||
.RendererGLInfo =
|
|
||||||
{
|
|
||||||
.TargetGLVersion = {3, 3, 0}, // Target OpenGL Version
|
|
||||||
.TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version
|
|
||||||
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
|
|
||||||
V_OpenGL33},
|
|
||||||
.IsCompatibilityProfile = false // Is Compatibility Profile
|
|
||||||
},
|
|
||||||
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
|
|
||||||
};
|
|
||||||
return RendererInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
String BackendObject_DirectVulkanTMP::GetBackendAPIVersionString() const {
|
|
||||||
if (!m_initialized) {
|
|
||||||
return "<uninitialized DirectVulkanTMP backend>";
|
|
||||||
}
|
|
||||||
// Format:
|
|
||||||
// <GPU Name>, Vulkan <Vulkan Version>, Driver <Driver Version>
|
|
||||||
// TODO
|
|
||||||
String str = m_vulkanCaps.DeviceName + ", Vulkan " + m_vulkanCaps.VulkanAPIVersion.toString() + ", Driver " +
|
|
||||||
m_vulkanCaps.DriverVersionString;
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
BackendType BackendObject_DirectVulkanTMP::GetBackendType() const {
|
|
||||||
return BackendType::DirectVulkanTMP;
|
|
||||||
}
|
|
||||||
|
|
||||||
const GlobalBackendFunctionsTable& BackendObject_DirectVulkanTMP::GetBackendFunctions() const {
|
|
||||||
static GlobalBackendFunctionsTable funcsTable;
|
|
||||||
static Bool funcsTableInitialized = false;
|
|
||||||
if (!funcsTableInitialized) {
|
|
||||||
funcsTable.Present = DirectVulkanTMP::Present;
|
|
||||||
funcsTable.GL.DrawArrays = DrawArrays;
|
|
||||||
funcsTable.GL.DrawElements = DrawElements;
|
|
||||||
funcsTable.GL.DrawElementsBaseVertex = DrawElementsBaseVertex;
|
|
||||||
funcsTable.GL.MultiDrawElements = MultiDrawElements;
|
|
||||||
funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex;
|
|
||||||
funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect;
|
|
||||||
funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect;
|
|
||||||
funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex;
|
|
||||||
funcsTable.GL.DrawRangeElements = DrawRangeElements;
|
|
||||||
funcsTable.GL.DrawElementsInstancedBaseVertexBaseInstance = DrawElementsInstancedBaseVertexBaseInstance;
|
|
||||||
funcsTable.GL.DrawElementsInstancedBaseVertex = DrawElementsInstancedBaseVertex;
|
|
||||||
funcsTable.GL.DrawElementsInstancedBaseInstance = DrawElementsInstancedBaseInstance;
|
|
||||||
funcsTable.GL.DrawElementsInstanced = DrawElementsInstanced;
|
|
||||||
funcsTable.GL.DrawArraysInstancedBaseInstance = DrawArraysInstancedBaseInstance;
|
|
||||||
funcsTable.GL.DrawArraysInstanced = DrawArraysInstanced;
|
|
||||||
funcsTable.GL.DrawElementsIndirect = DrawElementsIndirect;
|
|
||||||
funcsTable.GL.DrawArraysIndirect = DrawArraysIndirect;
|
|
||||||
funcsTable.GL.Clear = Clear;
|
|
||||||
funcsTable.GL.ClearBufferfi = ClearBufferfi;
|
|
||||||
funcsTable.GL.ClearBufferfv = ClearBufferfv;
|
|
||||||
funcsTable.GL.ClearBufferuiv = ClearBufferuiv;
|
|
||||||
funcsTable.GL.ClearBufferiv = ClearBufferiv;
|
|
||||||
funcsTable.GL.BlitFramebuffer = BlitFramebuffer;
|
|
||||||
funcsTable.GL.CopyTexImage2D = CopyTexImage2D;
|
|
||||||
funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D;
|
|
||||||
funcsTable.GL.GenerateMipmap = GenerateMipmap;
|
|
||||||
funcsTable.GL.ReadPixels = ReadPixels;
|
|
||||||
funcsTable.GL.GetTexImage = GetTexImage;
|
|
||||||
funcsTableInitialized = true;
|
|
||||||
}
|
|
||||||
return funcsTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DynamicBackendParameters& BackendObject_DirectVulkanTMP::GetDynamicParameters() const {
|
|
||||||
return m_dynamicParameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackendObject_DirectVulkanTMP::UpdateDynamicBackendParameters() {
|
|
||||||
m_dynamicParameters.UniformBufferOffsetAlignment = m_vulkanCaps.UniformBufferOffsetAlignment;
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkanTMP
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/DirectVulkanTMP.cpp
|
|
||||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
|
||||||
// Licensed under the GNU Lesser General Public License v3.0:
|
|
||||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
|
||||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
|
||||||
// SPDX-License-Identifier: LGPL-3.0-only
|
|
||||||
// End of Source File Header
|
|
||||||
|
|
||||||
#include "DirectVulkanTMP.h"
|
|
||||||
#include "TmpImpl.h"
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkanTMP {
|
|
||||||
void Clear(GLbitfield mask) {
|
|
||||||
MobileGL::MG_Backend::DirectVulkanTMP::TmpImpl::Clear(mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
|
|
||||||
MobileGL::MG_Backend::DirectVulkanTMP::TmpImpl::DrawElements(mode, count, type, indices);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {}
|
|
||||||
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {}
|
|
||||||
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {}
|
|
||||||
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {}
|
|
||||||
void DrawArrays(GLenum mode, GLint first, GLsizei count) {}
|
|
||||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) {}
|
|
||||||
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
|
||||||
GLsizei drawcount) {}
|
|
||||||
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
|
||||||
GLsizei drawcount, const GLint* basevertex) {}
|
|
||||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {}
|
|
||||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {}
|
|
||||||
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
|
||||||
const void* indices, GLint basevertex) {}
|
|
||||||
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices) {}
|
|
||||||
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
|
||||||
GLsizei instancecount, GLint basevertex, GLuint baseinstance) {}
|
|
||||||
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
|
||||||
GLsizei instancecount, GLint basevertex) {}
|
|
||||||
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
|
||||||
GLsizei instancecount, GLuint baseinstance) {}
|
|
||||||
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) {}
|
|
||||||
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect) {}
|
|
||||||
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
|
||||||
GLuint baseinstance) {}
|
|
||||||
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) {}
|
|
||||||
void DrawArraysIndirect(GLenum mode, const void* indirect) {}
|
|
||||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
|
||||||
GLint dstY1, GLbitfield mask, GLenum filter) {}
|
|
||||||
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
|
||||||
GLsizei height, GLint border) {}
|
|
||||||
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
|
||||||
GLsizei height) {}
|
|
||||||
void GenerateMipmap(GLenum target) {}
|
|
||||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {}
|
|
||||||
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {}
|
|
||||||
|
|
||||||
Bool InitWindowSurface(NativeWindowType window) {
|
|
||||||
if (!window) {
|
|
||||||
MGLOG_E("Cannot initialize Vulkan window surface: invalid window handle");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
TmpImpl::InitVulkan(window);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Present() {
|
|
||||||
TmpImpl::Present();
|
|
||||||
}
|
|
||||||
|
|
||||||
const TmpImpl::VulkanState& GetVulkanState() {
|
|
||||||
return TmpImpl::GetVulkanState();
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkanTMP
|
|
||||||
@@ -1,447 +0,0 @@
|
|||||||
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Managers/ProgramManager.cpp
|
|
||||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
|
||||||
// Licensed under the GNU Lesser General Public License v3.0:
|
|
||||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
|
||||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
|
||||||
// SPDX-License-Identifier: LGPL-3.0-only
|
|
||||||
// End of Source File Header
|
|
||||||
|
|
||||||
#include "ProgramManager.h"
|
|
||||||
|
|
||||||
#include "MG_Util/Debug/Log.h"
|
|
||||||
#include "spirv-tools/libspirv.h"
|
|
||||||
#include "spirv-tools/optimizer.hpp"
|
|
||||||
#include "source/opt/constants.h"
|
|
||||||
#include "source/opt/instruction.h"
|
|
||||||
#include "source/opt/ir_builder.h"
|
|
||||||
#include "source/opt/ir_context.h"
|
|
||||||
#include "source/opt/module.h"
|
|
||||||
#include "source/opt/pass.h"
|
|
||||||
#include "source/opt/type_manager.h"
|
|
||||||
|
|
||||||
#include <bit>
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager {
|
|
||||||
namespace {
|
|
||||||
using ProgramObject = MG_State::GLState::ProgramObject;
|
|
||||||
using ShaderObject = MG_State::GLState::ShaderObject;
|
|
||||||
|
|
||||||
struct PositionTargetInfo {
|
|
||||||
uint32_t variableId = 0;
|
|
||||||
uint32_t vectorTypeId = 0;
|
|
||||||
uint32_t floatTypeId = 0;
|
|
||||||
uint32_t vectorPtrTypeId = 0;
|
|
||||||
uint32_t memberIndex = 0;
|
|
||||||
bool isMember = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool IsVec4Float32(spvtools::opt::IRContext* context, uint32_t typeId, uint32_t* outFloatTypeId) {
|
|
||||||
auto* vecInst = context->get_def_use_mgr()->GetDef(typeId);
|
|
||||||
if (!vecInst || vecInst->opcode() != spv::Op::OpTypeVector) return false;
|
|
||||||
if (vecInst->GetSingleWordInOperand(1) != 4) return false;
|
|
||||||
|
|
||||||
const uint32_t floatTypeId = vecInst->GetSingleWordInOperand(0);
|
|
||||||
auto* floatInst = context->get_def_use_mgr()->GetDef(floatTypeId);
|
|
||||||
if (!floatInst || floatInst->opcode() != spv::Op::OpTypeFloat) return false;
|
|
||||||
if (floatInst->GetSingleWordInOperand(0) != 32) return false;
|
|
||||||
|
|
||||||
if (outFloatTypeId) *outFloatTypeId = floatTypeId;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ResolveDirectPositionTarget(spvtools::opt::IRContext* context, uint32_t variableId,
|
|
||||||
PositionTargetInfo* outTarget) {
|
|
||||||
auto* varInst = context->get_def_use_mgr()->GetDef(variableId);
|
|
||||||
if (!varInst || varInst->opcode() != spv::Op::OpVariable) return false;
|
|
||||||
if (varInst->GetSingleWordInOperand(0) != static_cast<uint32_t>(spv::StorageClass::Output)) return false;
|
|
||||||
|
|
||||||
auto* ptrTypeInst = context->get_def_use_mgr()->GetDef(varInst->type_id());
|
|
||||||
if (!ptrTypeInst || ptrTypeInst->opcode() != spv::Op::OpTypePointer) return false;
|
|
||||||
if (ptrTypeInst->GetSingleWordInOperand(0) != static_cast<uint32_t>(spv::StorageClass::Output))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
PositionTargetInfo target{};
|
|
||||||
target.variableId = variableId;
|
|
||||||
target.vectorTypeId = ptrTypeInst->GetSingleWordInOperand(1);
|
|
||||||
if (!IsVec4Float32(context, target.vectorTypeId, &target.floatTypeId)) return false;
|
|
||||||
target.vectorPtrTypeId = varInst->type_id();
|
|
||||||
target.isMember = false;
|
|
||||||
|
|
||||||
*outTarget = target;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t FindOutputVectorPointerTypeId(spvtools::opt::IRContext* context, uint32_t vectorTypeId) {
|
|
||||||
auto* vectorType = context->get_type_mgr()->GetType(vectorTypeId);
|
|
||||||
if (!vectorType) return 0;
|
|
||||||
spvtools::opt::analysis::Pointer ptrType(vectorType, spv::StorageClass::Output);
|
|
||||||
return context->get_type_mgr()->GetTypeInstruction(&ptrType);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ResolveMemberPositionTarget(spvtools::opt::IRContext* context, uint32_t structTypeId, uint32_t memberIndex,
|
|
||||||
PositionTargetInfo* outTarget) {
|
|
||||||
auto* structInst = context->get_def_use_mgr()->GetDef(structTypeId);
|
|
||||||
if (!structInst || structInst->opcode() != spv::Op::OpTypeStruct) return false;
|
|
||||||
if (memberIndex >= structInst->NumInOperands()) return false;
|
|
||||||
|
|
||||||
const uint32_t vectorTypeId = structInst->GetSingleWordInOperand(memberIndex);
|
|
||||||
uint32_t floatTypeId = 0;
|
|
||||||
if (!IsVec4Float32(context, vectorTypeId, &floatTypeId)) return false;
|
|
||||||
|
|
||||||
const uint32_t vectorPtrTypeId = FindOutputVectorPointerTypeId(context, vectorTypeId);
|
|
||||||
if (vectorPtrTypeId == 0) return false;
|
|
||||||
|
|
||||||
for (auto& inst : context->module()->types_values()) {
|
|
||||||
if (inst.opcode() != spv::Op::OpVariable) continue;
|
|
||||||
if (inst.GetSingleWordInOperand(0) != static_cast<uint32_t>(spv::StorageClass::Output)) continue;
|
|
||||||
|
|
||||||
auto* ptrTypeInst = context->get_def_use_mgr()->GetDef(inst.type_id());
|
|
||||||
if (!ptrTypeInst || ptrTypeInst->opcode() != spv::Op::OpTypePointer) continue;
|
|
||||||
if (ptrTypeInst->GetSingleWordInOperand(0) != static_cast<uint32_t>(spv::StorageClass::Output))
|
|
||||||
continue;
|
|
||||||
if (ptrTypeInst->GetSingleWordInOperand(1) != structTypeId) continue;
|
|
||||||
|
|
||||||
PositionTargetInfo target{};
|
|
||||||
target.variableId = inst.result_id();
|
|
||||||
target.vectorTypeId = vectorTypeId;
|
|
||||||
target.floatTypeId = floatTypeId;
|
|
||||||
target.vectorPtrTypeId = vectorPtrTypeId;
|
|
||||||
target.memberIndex = memberIndex;
|
|
||||||
target.isMember = true;
|
|
||||||
*outTarget = target;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FindPositionTarget(spvtools::opt::IRContext* context, PositionTargetInfo* outTarget) {
|
|
||||||
Vector<Pair<uint32_t, uint32_t>> memberCandidates;
|
|
||||||
constexpr uint32_t kDecorationBuiltIn = static_cast<uint32_t>(spv::Decoration::BuiltIn);
|
|
||||||
constexpr uint32_t kBuiltInPosition = static_cast<uint32_t>(spv::BuiltIn::Position);
|
|
||||||
|
|
||||||
for (auto& inst : context->module()->annotations()) {
|
|
||||||
if (inst.opcode() == spv::Op::OpDecorate) {
|
|
||||||
if (inst.NumInOperands() < 3) continue;
|
|
||||||
if (inst.GetSingleWordInOperand(1) != kDecorationBuiltIn) continue;
|
|
||||||
if (inst.GetSingleWordInOperand(2) != kBuiltInPosition) continue;
|
|
||||||
if (ResolveDirectPositionTarget(context, inst.GetSingleWordInOperand(0), outTarget)) return true;
|
|
||||||
} else if (inst.opcode() == spv::Op::OpMemberDecorate) {
|
|
||||||
if (inst.NumInOperands() < 4) continue;
|
|
||||||
if (inst.GetSingleWordInOperand(2) != kDecorationBuiltIn) continue;
|
|
||||||
if (inst.GetSingleWordInOperand(3) != kBuiltInPosition) continue;
|
|
||||||
memberCandidates.emplace_back(inst.GetSingleWordInOperand(0), inst.GetSingleWordInOperand(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& [structTypeId, memberIndex] : memberCandidates) {
|
|
||||||
if (ResolveMemberPositionTarget(context, structTypeId, memberIndex, outTarget)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InsertPositionFixup(spvtools::opt::IRContext* context, spvtools::opt::Instruction* insertBefore,
|
|
||||||
const PositionTargetInfo& target, uint32_t halfConstId, bool doYFlip, bool doZRemap) {
|
|
||||||
using namespace spvtools::opt;
|
|
||||||
InstructionBuilder builder(context, insertBefore,
|
|
||||||
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
|
|
||||||
|
|
||||||
uint32_t positionPtrId = target.variableId;
|
|
||||||
if (target.isMember) {
|
|
||||||
const uint32_t memberIndexId = builder.GetUintConstantId(target.memberIndex);
|
|
||||||
if (memberIndexId == 0) return false;
|
|
||||||
auto* access = builder.AddAccessChain(target.vectorPtrTypeId, target.variableId, {memberIndexId});
|
|
||||||
if (!access) return false;
|
|
||||||
positionPtrId = access->result_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* position = builder.AddLoad(target.vectorTypeId, positionPtrId);
|
|
||||||
if (!position) return false;
|
|
||||||
auto* x = builder.AddCompositeExtract(target.floatTypeId, position->result_id(), {0});
|
|
||||||
auto* y = builder.AddCompositeExtract(target.floatTypeId, position->result_id(), {1});
|
|
||||||
auto* z = builder.AddCompositeExtract(target.floatTypeId, position->result_id(), {2});
|
|
||||||
auto* w = builder.AddCompositeExtract(target.floatTypeId, position->result_id(), {3});
|
|
||||||
if (!x || !y || !z || !w) return false;
|
|
||||||
|
|
||||||
if (!doYFlip && !doZRemap) return false;
|
|
||||||
|
|
||||||
uint32_t yValueId = y->result_id();
|
|
||||||
if (doYFlip) {
|
|
||||||
auto* negY = builder.AddUnaryOp(target.floatTypeId, spv::Op::OpFNegate, y->result_id());
|
|
||||||
if (!negY) return false;
|
|
||||||
yValueId = negY->result_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t zValueId = z->result_id();
|
|
||||||
if (doZRemap) {
|
|
||||||
auto* zPlusW = builder.AddBinaryOp(target.floatTypeId, spv::Op::OpFAdd, z->result_id(), w->result_id());
|
|
||||||
if (!zPlusW) return false;
|
|
||||||
auto* mappedZ =
|
|
||||||
builder.AddBinaryOp(target.floatTypeId, spv::Op::OpFMul, zPlusW->result_id(), halfConstId);
|
|
||||||
if (!mappedZ) return false;
|
|
||||||
zValueId = mappedZ->result_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* fixedPosition = builder.AddCompositeConstruct(target.vectorTypeId,
|
|
||||||
{x->result_id(), yValueId, zValueId, w->result_id()});
|
|
||||||
if (!fixedPosition) return false;
|
|
||||||
|
|
||||||
return builder.AddStore(positionPtrId, fixedPosition->result_id()) != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
class GlToVulkanPositionFixPass final : public spvtools::opt::Pass {
|
|
||||||
public:
|
|
||||||
const char* name() const override { return "gl-to-vulkan-position-fix"; }
|
|
||||||
explicit GlToVulkanPositionFixPass(ShaderTransformFlags transformFlags)
|
|
||||||
: m_transformFlags(transformFlags) {}
|
|
||||||
|
|
||||||
Status Process() override {
|
|
||||||
if (!m_transformFlags) return Status::SuccessWithoutChange;
|
|
||||||
PositionTargetInfo target{};
|
|
||||||
if (!FindPositionTarget(context(), &target)) return Status::SuccessWithoutChange;
|
|
||||||
|
|
||||||
auto* floatType = context()->get_type_mgr()->GetType(target.floatTypeId);
|
|
||||||
if (!floatType) return Status::SuccessWithoutChange;
|
|
||||||
|
|
||||||
const uint32_t halfBits = std::bit_cast<uint32_t>(0.5f);
|
|
||||||
const auto* halfConst = context()->get_constant_mgr()->GetConstant(floatType, {halfBits});
|
|
||||||
auto* halfInst = context()->get_constant_mgr()->GetDefiningInstruction(halfConst);
|
|
||||||
if (!halfInst) return Status::SuccessWithoutChange;
|
|
||||||
const uint32_t halfConstId = halfInst->result_id();
|
|
||||||
|
|
||||||
const bool doYFlip = (m_transformFlags & ShaderTransformBit::PositionYFlip);
|
|
||||||
const bool doZRemap = (m_transformFlags & ShaderTransformBit::PositionZRemap);
|
|
||||||
|
|
||||||
bool modified = false;
|
|
||||||
for (auto& entryPoint : get_module()->entry_points()) {
|
|
||||||
if (entryPoint.opcode() != spv::Op::OpEntryPoint) continue;
|
|
||||||
if (entryPoint.NumInOperands() < 2) continue;
|
|
||||||
|
|
||||||
const auto model = static_cast<spv::ExecutionModel>(entryPoint.GetSingleWordInOperand(0));
|
|
||||||
if (model != spv::ExecutionModel::Vertex && model != spv::ExecutionModel::TessellationEvaluation &&
|
|
||||||
model != spv::ExecutionModel::Geometry) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* function = context()->GetFunction(entryPoint.GetSingleWordInOperand(1));
|
|
||||||
if (!function) continue;
|
|
||||||
|
|
||||||
for (auto& bb : *function) {
|
|
||||||
for (auto instIter = bb.begin(); instIter != bb.end(); ++instIter) {
|
|
||||||
auto* inst = &*instIter;
|
|
||||||
const bool needsFixup =
|
|
||||||
(model == spv::ExecutionModel::Geometry && inst->opcode() == spv::Op::OpEmitVertex) ||
|
|
||||||
(model != spv::ExecutionModel::Geometry && inst->opcode() == spv::Op::OpReturn);
|
|
||||||
if (!needsFixup) continue;
|
|
||||||
|
|
||||||
modified |= InsertPositionFixup(context(), inst, target, halfConstId, doYFlip, doZRemap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!modified) return Status::SuccessWithoutChange;
|
|
||||||
context()->InvalidateAnalysesExceptFor(spvtools::opt::IRContext::kAnalysisDefUse |
|
|
||||||
spvtools::opt::IRContext::kAnalysisInstrToBlockMapping);
|
|
||||||
return Status::SuccessWithChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ShaderTransformFlags m_transformFlags;
|
|
||||||
};
|
|
||||||
|
|
||||||
spvtools::Optimizer::PassToken CreateGlToVulkanPositionFixPass(ShaderTransformFlags transformFlags) {
|
|
||||||
return spvtools::Optimizer::PassToken(MakeUnique<GlToVulkanPositionFixPass>(transformFlags));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TransformSpirvForVulkanPositionFix(const Vector<Uint32>& input, Vector<Uint32>& output,
|
|
||||||
ShaderTransformFlags transformFlags) {
|
|
||||||
if (input.empty()) {
|
|
||||||
output.clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!transformFlags) {
|
|
||||||
output = input;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_3);
|
|
||||||
spvtools::OptimizerOptions options;
|
|
||||||
options.set_run_validator(false);
|
|
||||||
optimizer.RegisterPass(CreateGlToVulkanPositionFixPass(transformFlags));
|
|
||||||
|
|
||||||
const bool success = optimizer.Run(input.data(), input.size(), &output, options);
|
|
||||||
if (!success) {
|
|
||||||
MGLOG_E("Vulkan: failed to run GL->Vulkan position fix pass");
|
|
||||||
output = input;
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderStage PickClipFixupStage(const Vector<SharedPtr<ShaderObject>>& shaders) {
|
|
||||||
bool hasGeometry = false;
|
|
||||||
bool hasTessEval = false;
|
|
||||||
bool hasVertex = false;
|
|
||||||
|
|
||||||
for (const auto& shader : shaders) {
|
|
||||||
if (!shader) continue;
|
|
||||||
const auto stage = shader->GetShaderStage();
|
|
||||||
hasGeometry |= (stage == ShaderStage::Geometry);
|
|
||||||
hasTessEval |= (stage == ShaderStage::TessEval);
|
|
||||||
hasVertex |= (stage == ShaderStage::Vertex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasGeometry) return ShaderStage::Geometry;
|
|
||||||
if (hasTessEval) return ShaderStage::TessEval;
|
|
||||||
if (hasVertex) return ShaderStage::Vertex;
|
|
||||||
return ShaderStage::Unknown;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
ProgramManager::~ProgramManager() {
|
|
||||||
for (auto& [_, stages] : m_cache) {
|
|
||||||
DestroyStages(stages);
|
|
||||||
}
|
|
||||||
m_cache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgramManager::HashType ProgramManager::ComputeSourceSpvHash(MG_State::GLState::ProgramObject* program) const {
|
|
||||||
if (!program) return 0;
|
|
||||||
XXH64_state_t* state = XXH64_createState();
|
|
||||||
XXH64_reset(state, 0xC0FFEEu);
|
|
||||||
auto& spirvs = program->GetGeneratedSpirv();
|
|
||||||
for (const auto& spv : spirvs) {
|
|
||||||
if (spv.empty()) continue;
|
|
||||||
XXH64_update(state, spv.data(), spv.size() * sizeof(Uint));
|
|
||||||
}
|
|
||||||
HashType hash = XXH64_digest(state);
|
|
||||||
XXH64_freeState(state);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgramManager::HashType ProgramManager::ComputeSpvHash(const Vector<Vector<Uint32>>& spirvs) const {
|
|
||||||
XXH64_state_t* state = XXH64_createState();
|
|
||||||
XXH64_reset(state, 0xC0FFEEu);
|
|
||||||
for (const auto& spv : spirvs) {
|
|
||||||
if (spv.empty()) continue;
|
|
||||||
XXH64_update(state, spv.data(), spv.size() * sizeof(Uint32));
|
|
||||||
}
|
|
||||||
HashType hash = XXH64_digest(state);
|
|
||||||
XXH64_freeState(state);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProgramManager::BuildPipelineSpirvModules(MG_State::GLState::ProgramObject* program,
|
|
||||||
Vector<Vector<Uint32>>& outSpirvs,
|
|
||||||
ShaderTransformFlags transformFlags) const {
|
|
||||||
outSpirvs.clear();
|
|
||||||
if (!program) return;
|
|
||||||
|
|
||||||
auto& spirvs = program->GetGeneratedSpirv();
|
|
||||||
auto& shaders = program->GetAttachedShaders();
|
|
||||||
const ShaderStage fixupStage = PickClipFixupStage(shaders);
|
|
||||||
|
|
||||||
outSpirvs.reserve(spirvs.size());
|
|
||||||
for (SizeT i = 0; i < spirvs.size(); ++i) {
|
|
||||||
Vector<Uint32> module = spirvs[i];
|
|
||||||
|
|
||||||
ShaderStage stage = ShaderStage::Unknown;
|
|
||||||
if (i < shaders.size() && shaders[i]) stage = shaders[i]->GetShaderStage();
|
|
||||||
|
|
||||||
if (!module.empty() && fixupStage != ShaderStage::Unknown && stage == fixupStage) {
|
|
||||||
Vector<Uint32> transformed;
|
|
||||||
TransformSpirvForVulkanPositionFix(module, transformed, transformFlags);
|
|
||||||
module = Move(transformed);
|
|
||||||
}
|
|
||||||
outSpirvs.push_back(Move(module));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgramManager::HashType ProgramManager::ComputeSpvHash(MG_State::GLState::ProgramObject* program,
|
|
||||||
ShaderTransformFlags transformFlags) const {
|
|
||||||
Vector<Vector<Uint32>> spirvs;
|
|
||||||
BuildPipelineSpirvModules(program, spirvs, transformFlags);
|
|
||||||
return ComputeSpvHash(spirvs);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgramManager::HashType ProgramManager::ComputeProgramHash(MG_State::GLState::ProgramObject* program,
|
|
||||||
ShaderTransformFlags transformFlags) const {
|
|
||||||
if (!program) return 0;
|
|
||||||
const HashType sourceHash = ComputeSourceSpvHash(program);
|
|
||||||
auto it = m_cache.find(program);
|
|
||||||
if (it != m_cache.end() && it->second.sourceHash == sourceHash) return it->second.hash;
|
|
||||||
return ComputeSpvHash(program, transformFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkShaderStageFlagBits ProgramManager::ToVkStage(ShaderStage stage) const {
|
|
||||||
switch (stage) {
|
|
||||||
case ShaderStage::Vertex:
|
|
||||||
return VK_SHADER_STAGE_VERTEX_BIT;
|
|
||||||
case ShaderStage::Fragment:
|
|
||||||
return VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
||||||
case ShaderStage::Geometry:
|
|
||||||
return VK_SHADER_STAGE_GEOMETRY_BIT;
|
|
||||||
case ShaderStage::TessControl:
|
|
||||||
return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
|
|
||||||
case ShaderStage::TessEval:
|
|
||||||
return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
|
|
||||||
case ShaderStage::Compute:
|
|
||||||
return VK_SHADER_STAGE_COMPUTE_BIT;
|
|
||||||
default:
|
|
||||||
return VK_SHADER_STAGE_ALL_GRAPHICS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProgramManager::DestroyStages(ProgramStages& stages) {
|
|
||||||
for (auto module : stages.modules) {
|
|
||||||
if (module != VK_NULL_HANDLE) {
|
|
||||||
vkDestroyShaderModule(m_ctx.GetDevice(), module, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stages.modules.clear();
|
|
||||||
stages.stages.clear();
|
|
||||||
stages.sourceHash = 0;
|
|
||||||
stages.hash = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<VkPipelineShaderStageCreateInfo>& ProgramManager::CreatePipelineShaderStages(
|
|
||||||
MG_State::GLState::ProgramObject* program, ShaderTransformFlags transformFlags) {
|
|
||||||
auto& entry = m_cache[program];
|
|
||||||
HashType sourceHash = ComputeSourceSpvHash(program);
|
|
||||||
if (!entry.stages.empty() && entry.sourceHash == sourceHash) return entry.stages;
|
|
||||||
|
|
||||||
DestroyStages(entry);
|
|
||||||
entry.sourceHash = sourceHash;
|
|
||||||
|
|
||||||
if (!program) return entry.stages;
|
|
||||||
|
|
||||||
Vector<Vector<Uint32>> spirvs;
|
|
||||||
BuildPipelineSpirvModules(program, spirvs, transformFlags);
|
|
||||||
entry.hash = ComputeSpvHash(spirvs);
|
|
||||||
auto& shaders = program->GetAttachedShaders();
|
|
||||||
|
|
||||||
for (SizeT i = 0; i < spirvs.size(); ++i) {
|
|
||||||
auto& spv = spirvs[i];
|
|
||||||
if (spv.empty()) continue;
|
|
||||||
|
|
||||||
VkShaderModuleCreateInfo smci{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
|
|
||||||
smci.codeSize = spv.size() * sizeof(Uint);
|
|
||||||
smci.pCode = spv.data();
|
|
||||||
|
|
||||||
VkShaderModule module = VK_NULL_HANDLE;
|
|
||||||
VK_VERIFY(vkCreateShaderModule(m_ctx.GetDevice(), &smci, nullptr, &module), "vkCreateShaderModule");
|
|
||||||
|
|
||||||
VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
|
|
||||||
ShaderStage shaderStage = ShaderStage::Unknown;
|
|
||||||
if (i < shaders.size() && shaders[i]) shaderStage = shaders[i]->GetShaderStage();
|
|
||||||
stage.stage = ToVkStage(shaderStage);
|
|
||||||
stage.module = module;
|
|
||||||
stage.pName = "main";
|
|
||||||
|
|
||||||
entry.modules.push_back(module);
|
|
||||||
entry.stages.push_back(stage);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry.stages;
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkanTMP::VkManager
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
// 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
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
// 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
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
// MobileGL - MobileGL/MG_Backend/DirectVulkanTMP/Renderer/FrameContext.h
|
|
||||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
|
||||||
// Licensed under the GNU Lesser General Public License v3.0:
|
|
||||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
|
||||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
|
||||||
// SPDX-License-Identifier: LGPL-3.0-only
|
|
||||||
// End of Source File Header
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <Includes.h>
|
|
||||||
#include "VulkanContext.h"
|
|
||||||
#include "VkCommon.h"
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkanTMP {
|
|
||||||
struct TrashBuffer {
|
|
||||||
VkBuffer buffer = VK_NULL_HANDLE;
|
|
||||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
|
||||||
Bool mapped = false;
|
|
||||||
};
|
|
||||||
struct TrashImage {
|
|
||||||
VkImage image = VK_NULL_HANDLE;
|
|
||||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
|
||||||
VkImageView view = VK_NULL_HANDLE;
|
|
||||||
Vector<VkImageView> mipViews;
|
|
||||||
};
|
|
||||||
namespace VkManager {
|
|
||||||
struct FrameContext {
|
|
||||||
VkCommandBuffer CommandBuffer = VK_NULL_HANDLE;
|
|
||||||
VkSemaphore ImageAvailable = VK_NULL_HANDLE;
|
|
||||||
VkSemaphore RenderFinished = VK_NULL_HANDLE;
|
|
||||||
VkFence InFlightFence = VK_NULL_HANDLE;
|
|
||||||
Uint32 CurrentImageIndex = 0;
|
|
||||||
VkCommandPool CommandPool = VK_NULL_HANDLE;
|
|
||||||
Vector<TrashBuffer> TrashBuffers;
|
|
||||||
Vector<TrashImage> TrashImages;
|
|
||||||
// VkCommandPool CommandPool = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
void Initialize(VulkanContext& ctx, VkCommandPool pool);
|
|
||||||
void Cleanup(VulkanContext& ctx);
|
|
||||||
};
|
|
||||||
} // namespace VkManager
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkanTMP
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
// 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
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
// 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
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// 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
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
// 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
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
// 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
@@ -1,308 +0,0 @@
|
|||||||
// 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::DirectVulkanTMP:
|
case BackendType::DirectVulkan:
|
||||||
pActiveBackendObject = MakeUnique<DirectVulkanTMP::BackendObject_DirectVulkanTMP>();
|
pActiveBackendObject = MakeUnique<DirectVulkan::BackendObject_DirectVulkan>();
|
||||||
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) {
|
||||||
MG_Initialize();
|
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) {
|
||||||
MG_Initialize();
|
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) {
|
||||||
MG_Initialize();
|
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,178 +9,488 @@
|
|||||||
#include "EGLImpl.h"
|
#include "EGLImpl.h"
|
||||||
#include "../GetProcAddress.h"
|
#include "../GetProcAddress.h"
|
||||||
#include <MG_Backend/BackendObjects.h>
|
#include <MG_Backend/BackendObjects.h>
|
||||||
|
#include <MG_State/EGLState/Core.h>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::EGLImpl {
|
namespace MobileGL::MG_Impl::EGLImpl {
|
||||||
|
namespace {
|
||||||
|
using EGLStateContext = MG_State::EGLState::EGLContext;
|
||||||
|
|
||||||
|
EGLStateContext* GetState() {
|
||||||
|
if (!MG_State::pEGLContext) {
|
||||||
|
MGLOG_E("pEGLContext is null. MG_State may not be initialized.");
|
||||||
|
}
|
||||||
|
return MG_State::pEGLContext.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_Backend::BackendObject* GetBackendObject(EGLStateContext* state) {
|
||||||
|
auto* backendObject = MG_Backend::pActiveBackendObject.get();
|
||||||
|
if (!backendObject && state) {
|
||||||
|
state->SetError(EGL_NOT_INITIALIZED);
|
||||||
|
}
|
||||||
|
return backendObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_Backend::WindowBackend DetectWindowBackend() {
|
||||||
|
#if defined(ANDROID) || defined(__ANDROID__)
|
||||||
|
return MG_Backend::WindowBackend::Android;
|
||||||
|
#elif defined(__linux__)
|
||||||
|
return MG_Backend::WindowBackend::X11;
|
||||||
|
#else
|
||||||
|
return MG_Backend::WindowBackend::Unknown;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLint GetAttribValue(const EGLint* attribList, EGLint attrib, EGLint defaultValue) {
|
||||||
|
if (!attribList) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
for (SizeT i = 0; attribList[i] != EGL_NONE; i += 2) {
|
||||||
|
if (attribList[i] == attrib) {
|
||||||
|
return attribList[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename NativeType>
|
||||||
|
Bool IsNullNativeHandle(NativeType nativeHandle) {
|
||||||
|
if constexpr (std::is_pointer_v<NativeType>) {
|
||||||
|
return nativeHandle == nullptr;
|
||||||
|
} else {
|
||||||
|
return nativeHandle == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename NativeType>
|
||||||
|
void* ToVoidHandle(NativeType nativeHandle) {
|
||||||
|
if constexpr (std::is_pointer_v<NativeType>) {
|
||||||
|
return reinterpret_cast<void*>(nativeHandle);
|
||||||
|
} else {
|
||||||
|
return reinterpret_cast<void*>(static_cast<SizeT>(nativeHandle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window,
|
EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window,
|
||||||
const EGLint* attrib_list) {
|
const EGLint* attrib_list) {
|
||||||
MGLOG_D("EGLImpl::CreateWindowSurface called with window=%p", window);
|
auto* state = GetState();
|
||||||
const auto& activeBackendObject = MG_Backend::pActiveBackendObject;
|
if (!state) {
|
||||||
if (!activeBackendObject) {
|
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;
|
||||||
|
}
|
||||||
|
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)});
|
|
||||||
activeBackendObject->InitWindowSurface();
|
const MG_Backend::WindowHandle windowHandle = {
|
||||||
return (EGLSurface)1;
|
.Backend = DetectWindowBackend(),
|
||||||
|
.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) {
|
||||||
MGLOG_D("EGLImpl::SwapBuffers called with dpy=%p", dpy);
|
auto* state = GetState();
|
||||||
if (!MG_Backend::gBackendFunctionsTable.Present) {
|
if (!state) {
|
||||||
MGLOG_E("MG_Backend::gBackendFunctionsTable.Present not initialized!");
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
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) {
|
||||||
*num_config = 1;
|
auto* state = GetState();
|
||||||
return EGL_TRUE;
|
if (!state) {
|
||||||
|
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) {
|
||||||
return (EGLContext)1;
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
if (major) *major = 1;
|
auto* state = GetState();
|
||||||
if (minor) *minor = 5;
|
if (!state) {
|
||||||
|
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) {
|
||||||
return (EGLDisplay)1;
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_NO_DISPLAY;
|
||||||
|
}
|
||||||
|
return state->GetDisplay(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLint GetError() {
|
EGLint GetError() {
|
||||||
return EGL_SUCCESS;
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
MGLOG_D("EGLImpl::CreateWindowSurface called with window=%p", window);
|
auto* state = GetState();
|
||||||
const auto& activeBackendObject = MG_Backend::pActiveBackendObject;
|
if (!state) {
|
||||||
if (!activeBackendObject) {
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
return EGL_TRUE;
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
return EGL_TRUE;
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
return state->DestroySurface(dpy, surface) ? EGL_TRUE : EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean Terminate(EGLDisplay dpy) {
|
EGLBoolean Terminate(EGLDisplay dpy) {
|
||||||
return EGL_TRUE;
|
auto* state = GetState();
|
||||||
}
|
if (!state) {
|
||||||
|
|
||||||
EGLBoolean ReleaseThread() {
|
|
||||||
return EGL_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
EGLContext GetCurrentContext() {
|
|
||||||
return (EGLContext)1;
|
|
||||||
}
|
|
||||||
|
|
||||||
EGLBoolean GetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value) {
|
|
||||||
if (attribute == EGL_NATIVE_VISUAL_ID) {
|
|
||||||
#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
|
}
|
||||||
|
if (!state->TerminateDisplay(dpy)) {
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
if (auto* backendObject = MG_Backend::pActiveBackendObject.get()) {
|
||||||
|
backendObject->ReleaseEGLResources();
|
||||||
}
|
}
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean BindAPI(EGLenum api) {
|
EGLBoolean ReleaseThread() {
|
||||||
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
state->ReleaseThread();
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EGLContext GetCurrentContext() {
|
||||||
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_NO_CONTEXT;
|
||||||
|
}
|
||||||
|
return state->GetCurrentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLBoolean GetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value) {
|
||||||
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
return state->GetConfigAttrib(dpy, config, attribute, value) ? EGL_TRUE : EGL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLBoolean BindAPI(EGLenum api) {
|
||||||
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
switch (api) {
|
||||||
|
case EGL_OPENGL_API:
|
||||||
|
case EGL_OPENGL_ES_API:
|
||||||
|
case EGL_OPENVG_API:
|
||||||
|
state->SetBoundAPI(api);
|
||||||
|
return EGL_TRUE;
|
||||||
|
default:
|
||||||
|
state->SetError(EGL_BAD_PARAMETER);
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EGLSurface GetCurrentSurface(EGLint readdraw) {
|
EGLSurface GetCurrentSurface(EGLint readdraw) {
|
||||||
return (EGLSurface)1;
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
return EGL_TRUE;
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
return "";
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (display != EGL_NO_DISPLAY && !state->ValidateDisplay(display)) {
|
||||||
|
state->SetError(EGL_BAD_DISPLAY);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (name) {
|
||||||
|
case EGL_VENDOR:
|
||||||
|
return "MobileGL";
|
||||||
|
case EGL_VERSION:
|
||||||
|
return "1.5 MobileGL";
|
||||||
|
case EGL_CLIENT_APIS:
|
||||||
|
return "OpenGL OpenGL_ES";
|
||||||
|
case EGL_EXTENSIONS:
|
||||||
|
return "";
|
||||||
|
default:
|
||||||
|
state->SetError(EGL_BAD_PARAMETER);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean SwapInterval(EGLDisplay dpy, EGLint interval) {
|
EGLBoolean SwapInterval(EGLDisplay dpy, EGLint interval) {
|
||||||
return EGL_TRUE;
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
return (EGLSurface)1;
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
const EGLint width = GetAttribValue(attrib_list, EGL_WIDTH, 1);
|
||||||
|
const EGLint height = GetAttribValue(attrib_list, EGL_HEIGHT, 1);
|
||||||
|
EGLSurface surface = state->CreatePbufferSurface(dpy, config, attrib_list);
|
||||||
|
if (surface == EGL_NO_SURFACE) {
|
||||||
|
return EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* backendObject = GetBackendObject(state);
|
||||||
|
if (!backendObject) {
|
||||||
|
return EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
if (!backendObject->CreateEGLPbufferSurface(width, height)) {
|
||||||
|
state->DestroySurface(dpy, surface);
|
||||||
|
state->SetError(EGL_BAD_ALLOC);
|
||||||
|
return EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
|
EGLBoolean BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
|
||||||
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
if (!state->ValidateSurfaceOnDisplay(dpy, surface)) {
|
||||||
|
state->SetError(EGL_BAD_SURFACE);
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
if (buffer != EGL_BACK_BUFFER) {
|
||||||
|
state->SetError(EGL_BAD_PARAMETER);
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
|
EGLBoolean ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
|
||||||
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
if (!state->ValidateSurfaceOnDisplay(dpy, surface)) {
|
||||||
|
state->SetError(EGL_BAD_SURFACE);
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
if (buffer != EGL_BACK_BUFFER) {
|
||||||
|
state->SetError(EGL_BAD_PARAMETER);
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) {
|
EGLBoolean CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) {
|
||||||
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
if (!state->ValidateSurfaceOnDisplay(dpy, surface)) {
|
||||||
|
state->SetError(EGL_BAD_SURFACE);
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
if (IsNullNativeHandle(target)) {
|
||||||
|
state->SetError(EGL_BAD_NATIVE_PIXMAP);
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config,
|
EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config,
|
||||||
const EGLint* attrib_list) {
|
const EGLint* attrib_list) {
|
||||||
return (EGLSurface)1;
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
return (EGLSurface)1;
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
if (num_config) {
|
auto* state = GetState();
|
||||||
*num_config = 1;
|
if (!state) {
|
||||||
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
if (configs && config_size > 0) {
|
return state->GetConfigs(dpy, configs, config_size, num_config) ? EGL_TRUE : EGL_FALSE;
|
||||||
configs[0] = (EGLConfig)1;
|
|
||||||
}
|
|
||||||
return EGL_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLDisplay GetCurrentDisplay() {
|
EGLDisplay GetCurrentDisplay() {
|
||||||
return (EGLDisplay)1;
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_NO_DISPLAY;
|
||||||
|
}
|
||||||
|
return state->GetCurrentDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLenum QueryAPI() {
|
EGLenum QueryAPI() {
|
||||||
return EGL_OPENGL_API;
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
if (value) {
|
auto* state = GetState();
|
||||||
*value = 1;
|
if (!state) {
|
||||||
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
return EGL_TRUE;
|
return state->QueryContext(dpy, ctx, attribute, value) ? EGL_TRUE : EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) {
|
EGLBoolean SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) {
|
||||||
return EGL_TRUE;
|
(void)value;
|
||||||
|
|
||||||
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
if (!state->ValidateSurfaceOnDisplay(dpy, surface)) {
|
||||||
|
state->SetError(EGL_BAD_SURFACE);
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (attribute) {
|
||||||
|
case EGL_MIPMAP_LEVEL:
|
||||||
|
case EGL_SWAP_BEHAVIOR:
|
||||||
|
case EGL_TEXTURE_FORMAT:
|
||||||
|
case EGL_TEXTURE_TARGET:
|
||||||
|
case EGL_MIPMAP_TEXTURE:
|
||||||
|
return EGL_TRUE;
|
||||||
|
default:
|
||||||
|
state->SetError(EGL_BAD_ATTRIBUTE);
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean WaitClient() {
|
EGLBoolean WaitClient() {
|
||||||
@@ -192,60 +502,132 @@ 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) {
|
||||||
return reinterpret_cast<EGLSync>(0x1);
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_NO_SYNC;
|
||||||
|
}
|
||||||
|
return state->CreateSync(dpy, type, attrib_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean DestroySync(void* dpy, void* sync) {
|
EGLBoolean DestroySync(EGLDisplay dpy, EGLSync sync) {
|
||||||
return EGL_TRUE;
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
return EGL_CONDITION_SATISFIED;
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
if (value) {
|
auto* state = GetState();
|
||||||
*value = 1;
|
if (!state) {
|
||||||
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
return EGL_TRUE;
|
return state->GetSyncAttrib(dpy, sync, attribute, value) ? EGL_TRUE : EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
return reinterpret_cast<EGLImage>(0x1);
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
return EGL_TRUE;
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
return reinterpret_cast<EGLDisplay>(0x1);
|
(void)attrib_list;
|
||||||
|
|
||||||
|
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) {
|
||||||
return reinterpret_cast<EGLSurface>(0x1);
|
auto* state = GetState();
|
||||||
|
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) {
|
||||||
return reinterpret_cast<EGLSurface>(0x1);
|
auto* state = GetState();
|
||||||
|
if (!state) {
|
||||||
|
return EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
return state->CreatePlatformPixmapSurface(dpy, config, native_pixmap, attrib_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean WaitSync(void* dpy, void* sync, int flags) {
|
EGLBoolean WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) {
|
||||||
return EGL_TRUE;
|
auto* state = GetState();
|
||||||
|
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", (const char*)name);
|
MGLOG_W("Failed to get function: %s", 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(void* dpy, void* sync);
|
EGLBoolean DestroySync(EGLDisplay dpy, EGLSync 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(void* dpy, void* sync, int flags);
|
EGLBoolean WaitSync(EGLDisplay dpy, EGLSync sync, EGLint 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,24 +9,41 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL::MG_Impl::GLImpl {
|
||||||
namespace MG_Impl::GLImpl {
|
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
||||||
void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params);
|
||||||
GLboolean IsBuffer(GLuint buffer);
|
void GetBufferPointerv(GLenum target, GLenum pname, void** 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 BufferStorage(GLenum target, GLsizeiptr size, const void* data, GLbitfield flags);
|
||||||
void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
|
void CreateBuffers(GLsizei n, GLuint* buffers);
|
||||||
void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
|
void NamedBufferStorage(GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags);
|
||||||
void BindBuffer(GLenum target, GLuint buffer);
|
void NamedBufferData(GLuint buffer, GLsizeiptr size, const void* data, GLenum usage);
|
||||||
void GenBuffers(GLsizei n, GLuint* buffers);
|
void NamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data);
|
||||||
void BindBufferBase(GLenum target, GLuint index, GLuint buffer);
|
void CopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset,
|
||||||
void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
|
GLsizeiptr size);
|
||||||
|
void ClearNamedBufferData(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data);
|
||||||
|
void ClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format,
|
||||||
|
GLenum type, const void* data);
|
||||||
|
void* MapNamedBuffer(GLuint buffer, GLenum access);
|
||||||
|
void* MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
|
||||||
|
GLboolean UnmapNamedBuffer(GLuint buffer);
|
||||||
|
void FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length);
|
||||||
|
void GetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint* params);
|
||||||
|
void GetNamedBufferParameteri64v(GLuint buffer, GLenum pname, GLint64* params);
|
||||||
|
void GetNamedBufferPointerv(GLuint buffer, GLenum pname, void** params);
|
||||||
|
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset,
|
||||||
|
GLsizeiptr size);
|
||||||
|
void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
|
||||||
|
void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
|
||||||
|
void BindBuffer(GLenum target, GLuint buffer);
|
||||||
|
void GenBuffers(GLsizei n, GLuint* buffers);
|
||||||
|
void BindBufferBase(GLenum target, GLuint index, GLuint buffer);
|
||||||
|
void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
|
||||||
|
|
||||||
} // namespace MG_Impl::GLImpl
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
} // namespace MobileGL
|
|
||||||
|
|||||||
@@ -13,105 +13,100 @@
|
|||||||
#include <MG_Util/Converters/MGToGL/BufferEnumConverter.h>
|
#include <MG_Util/Converters/MGToGL/BufferEnumConverter.h>
|
||||||
#include <MG_Util/Converters/MGToStr/BufferEnumConverter.h>
|
#include <MG_Util/Converters/MGToStr/BufferEnumConverter.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl {
|
namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
|
||||||
namespace BufferImpl {
|
Bool ValidateBufferTarget(BufferTarget target) {
|
||||||
Bool ValidateBufferTarget(BufferTarget target) {
|
if (target == BufferTarget::Unknown) {
|
||||||
if (target == BufferTarget::Unknown) {
|
using namespace MG_Util;
|
||||||
using namespace MG_Util;
|
String bufferTargetStr = ConvertBufferTargetToString(target);
|
||||||
String bufferTargetStr = ConvertBufferTargetToString(target);
|
String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target));
|
||||||
String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target));
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeShared<GenericErrorInfo>(
|
|
||||||
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget",
|
|
||||||
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target == BufferTarget::Index && MG_State::pGLContext->GetBoundVertexArray() == nullptr) {
|
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
|
||||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
|
|
||||||
"ValidateBufferTarget",
|
|
||||||
"No vertex array object is bound."));
|
|
||||||
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,
|
|
||||||
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(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>(
|
||||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName",
|
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget",
|
||||||
std::format("Buffer name {} is not valid.", index)));
|
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool ValidateBufferUsage(BufferUsage usage) {
|
if (target == BufferTarget::Index && MG_State::pGLContext->GetBoundVertexArray() == nullptr) {
|
||||||
if (usage != BufferUsage::Unknown) {
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||||
return true;
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
|
||||||
}
|
"ValidateBufferTarget",
|
||||||
|
"No vertex array object is bound."));
|
||||||
|
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;
|
using namespace MG_Util;
|
||||||
String bufferUsageStr = ConvertBufferUsageToString(usage);
|
String bufferTargetStr = ConvertBufferTargetToString(target);
|
||||||
String glUsageStr = ConvertGLEnumToString(ConvertBufferUsageToGLEnum(usage));
|
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;
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
if (accessBits == BufferMappingAccessBit::Null) {
|
||||||
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||||
|
MakeUnique<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(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidEnum,
|
ErrorCode::InvalidEnum,
|
||||||
MakeShared<GenericErrorInfo>(
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferMappingAccess",
|
||||||
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferUsage",
|
"Access bits cannot contain invalid flags."));
|
||||||
std::format("Usage {} ({}) is not one of the allowable values.", bufferUsageStr, glUsageStr)));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits) {
|
return true;
|
||||||
if (accessBits == BufferMappingAccessBit::Null) {
|
}
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
} // namespace MobileGL::MG_Impl::GLImpl::BufferImpl
|
||||||
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,12 +10,10 @@
|
|||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include <MG_State/GLState/BufferState/BufferObject.h>
|
#include <MG_State/GLState/BufferState/BufferObject.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl {
|
namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
|
||||||
namespace BufferImpl {
|
Bool ValidateBufferTarget(BufferTarget target);
|
||||||
Bool ValidateBufferTarget(BufferTarget target);
|
Bool ValidateBufferName(Uint index, Bool allowZero = false);
|
||||||
Bool ValidateBufferName(Uint index, Bool allowZero = false);
|
Bool ValidateBufferUsage(BufferUsage usage);
|
||||||
Bool ValidateBufferUsage(BufferUsage usage);
|
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits);
|
||||||
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits);
|
Bool ValidateBufferBindingPointTarget(BufferTarget target);
|
||||||
Bool ValidateBufferBindingPointTarget(BufferTarget target);
|
} // namespace MobileGL::MG_Impl::GLImpl::BufferImpl
|
||||||
} // namespace BufferImpl
|
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
|
||||||
|
|||||||
@@ -73,6 +73,24 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirect(mode, indirect, drawcount, stride);
|
MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirect(mode, indirect, drawcount, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MultiDrawElementsIndirectCount_Backend(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
|
||||||
|
GLsizei maxdrawcount, GLsizei stride) {
|
||||||
|
#ifdef TRACY_ENABLE
|
||||||
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
|
#endif
|
||||||
|
MG_Backend::gBackendFunctionsTable.GL.MultiDrawElementsIndirectCount(mode, type, indirect, drawcount,
|
||||||
|
maxdrawcount, stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiDrawArraysIndirectCount_Backend(GLenum mode, const void* indirect, GLintptr drawcount,
|
||||||
|
GLsizei maxdrawcount, GLsizei stride) {
|
||||||
|
#ifdef TRACY_ENABLE
|
||||||
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
|
#endif
|
||||||
|
MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirectCount(mode, indirect, drawcount, maxdrawcount,
|
||||||
|
stride);
|
||||||
|
}
|
||||||
|
|
||||||
void DrawRangeElementsBaseVertex_Backend(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
void DrawRangeElementsBaseVertex_Backend(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||||
const void* indices, GLint basevertex) {
|
const void* indices, GLint basevertex) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
@@ -156,6 +174,52 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||||
|
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ) {
|
||||||
|
auto dispatchCompute = MG_Backend::gBackendFunctionsTable.GL.DispatchCompute;
|
||||||
|
if (!dispatchCompute) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Backend does not support compute dispatch."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DispatchComputeIndirect(GLintptr indirect) {
|
||||||
|
auto dispatchComputeIndirect = MG_Backend::gBackendFunctionsTable.GL.DispatchComputeIndirect;
|
||||||
|
if (!dispatchComputeIndirect) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||||
|
"Backend does not support indirect compute dispatch."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatchComputeIndirect(indirect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBarrier(GLbitfield barriers) {
|
||||||
|
auto memoryBarrier = MG_Backend::gBackendFunctionsTable.GL.MemoryBarrier;
|
||||||
|
if (!memoryBarrier) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Backend does not support memory barriers."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memoryBarrier(barriers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBarrierByRegion(GLbitfield barriers) {
|
||||||
|
auto memoryBarrierByRegion = MG_Backend::gBackendFunctionsTable.GL.MemoryBarrierByRegion;
|
||||||
|
if (!memoryBarrierByRegion) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||||
|
"Backend does not support regional memory barriers."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memoryBarrierByRegion(barriers);
|
||||||
|
}
|
||||||
|
|
||||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {
|
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {
|
||||||
MultiDrawElementsIndirect_Backend(mode, type, indirect, drawcount, stride);
|
MultiDrawElementsIndirect_Backend(mode, type, indirect, drawcount, stride);
|
||||||
}
|
}
|
||||||
@@ -164,6 +228,32 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
MultiDrawArraysIndirect_Backend(mode, indirect, drawcount, stride);
|
MultiDrawArraysIndirect_Backend(mode, indirect, drawcount, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
|
||||||
|
GLsizei maxdrawcount, GLsizei stride) {
|
||||||
|
auto multiDrawElementsIndirectCount = MG_Backend::gBackendFunctionsTable.GL.MultiDrawElementsIndirectCount;
|
||||||
|
if (!multiDrawElementsIndirectCount) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||||
|
"Backend does not support indirect-parameter indexed draws."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MultiDrawElementsIndirectCount_Backend(mode, type, indirect, drawcount, maxdrawcount, stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
|
||||||
|
GLsizei maxdrawcount, GLsizei stride) {
|
||||||
|
auto multiDrawArraysIndirectCount = MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirectCount;
|
||||||
|
if (!multiDrawArraysIndirectCount) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||||
|
"Backend does not support indirect-parameter array draws."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MultiDrawArraysIndirectCount_Backend(mode, indirect, drawcount, maxdrawcount, stride);
|
||||||
|
}
|
||||||
|
|
||||||
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||||
const void* indices, GLint basevertex) {
|
const void* indices, GLint basevertex) {
|
||||||
DrawRangeElementsBaseVertex_Backend(mode, start, end, count, type, indices, basevertex);
|
DrawRangeElementsBaseVertex_Backend(mode, start, end, count, type, indices, basevertex);
|
||||||
|
|||||||
@@ -9,34 +9,39 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL::MG_Impl::GLImpl {
|
||||||
namespace MG_Impl::GLImpl {
|
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
|
||||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount,
|
void DispatchComputeIndirect(GLintptr indirect);
|
||||||
GLsizei stride);
|
void MemoryBarrier(GLbitfield barriers);
|
||||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
void MemoryBarrierByRegion(GLbitfield barriers);
|
||||||
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, 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 MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
|
||||||
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
GLsizei maxdrawcount, GLsizei stride);
|
||||||
GLsizei instancecount, GLint basevertex, GLuint baseinstance);
|
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
|
||||||
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
GLsizei maxdrawcount, GLsizei stride);
|
||||||
GLsizei instancecount, GLint basevertex);
|
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||||
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
const void* indices, GLint basevertex);
|
||||||
GLsizei instancecount, GLuint baseinstance);
|
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
|
||||||
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount);
|
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||||
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect);
|
GLsizei instancecount, GLint basevertex, GLuint baseinstance);
|
||||||
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||||
GLuint baseinstance);
|
GLsizei instancecount, GLint basevertex);
|
||||||
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||||
void DrawArraysIndirect(GLenum mode, const void* indirect);
|
GLsizei instancecount, GLuint baseinstance);
|
||||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex);
|
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount);
|
||||||
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect);
|
||||||
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
||||||
GLsizei drawcount);
|
GLuint baseinstance);
|
||||||
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
||||||
GLsizei drawcount, const GLint* basevertex);
|
void DrawArraysIndirect(GLenum mode, const void* indirect);
|
||||||
void Clear(GLbitfield mask);
|
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex);
|
||||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
||||||
} // namespace MG_Impl::GLImpl
|
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
||||||
} // namespace MobileGL
|
GLsizei drawcount);
|
||||||
|
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
||||||
|
GLsizei drawcount, const GLint* basevertex);
|
||||||
|
void Clear(GLbitfield mask);
|
||||||
|
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
||||||
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "../Buffer/GL_Buffer.h"
|
#include "../Buffer/GL_Buffer.h"
|
||||||
#include "../Getter/GL_Getter.h"
|
#include "../Getter/GL_Getter.h"
|
||||||
#include "../Sampler/GL_Sampler.h"
|
#include "../Sampler/GL_Sampler.h"
|
||||||
|
#include "../Sync/GL_Sync.h"
|
||||||
#include "../Texture/GL_Texture.h"
|
#include "../Texture/GL_Texture.h"
|
||||||
#include "../Drawing/GL_Drawing.h"
|
#include "../Drawing/GL_Drawing.h"
|
||||||
#include "../Program/GL_Program.h"
|
#include "../Program/GL_Program.h"
|
||||||
@@ -17,42 +18,40 @@
|
|||||||
#include "../Framebuffer/GL_Framebuffer.h"
|
#include "../Framebuffer/GL_Framebuffer.h"
|
||||||
#include "../VertexArray/GL_VertexArray.h"
|
#include "../VertexArray/GL_VertexArray.h"
|
||||||
|
|
||||||
#define DECLARE_GL_FUNCTION_STUB_HEAD(type,name,...) \
|
#define DECLARE_GL_FUNCTION_STUB_HEAD(type, name, ...) MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
|
||||||
MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
|
|
||||||
|
|
||||||
#define DECLARE_GL_FUNCTION_STUB_END(type,name,...) \
|
#define DECLARE_GL_FUNCTION_STUB_END(type, name, ...) \
|
||||||
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
|
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
|
||||||
return (type)1; \
|
return (type)1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(type,name,...) \
|
#define DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(type, name, ...) \
|
||||||
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
|
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DECLARE_GL_FUNCTION_HEAD(type,name,...) \
|
#define DECLARE_GL_FUNCTION_HEAD(type, name, ...) MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
|
||||||
MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
|
|
||||||
|
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
#define DECLARE_GL_FUNCTION_END(type,name,...) \
|
#define DECLARE_GL_FUNCTION_END(type, name, ...) \
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_ENTRY); \
|
ZoneScopedC(TRACY_ZONECOLOR_ENTRY); \
|
||||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||||
return MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
return MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DECLARE_GL_FUNCTION_END_NO_RETURN(type,name,...) \
|
#define DECLARE_GL_FUNCTION_END_NO_RETURN(type, name, ...) \
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_ENTRY); \
|
ZoneScopedC(TRACY_ZONECOLOR_ENTRY); \
|
||||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||||
MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define DECLARE_GL_FUNCTION_END(type,name,...) \
|
#define DECLARE_GL_FUNCTION_END(type, name, ...) \
|
||||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||||
return MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
return MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DECLARE_GL_FUNCTION_END_NO_RETURN(type,name,...) \
|
#define DECLARE_GL_FUNCTION_END_NO_RETURN(type, name, ...) \
|
||||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||||
MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -69,7 +68,7 @@ DECLARE_GL_FUNCTION_HEAD(void, BindRenderbuffer, GLenum target, GLuint renderbuf
|
|||||||
DECLARE_GL_FUNCTION_HEAD(void, BindTexture, GLenum target, GLuint texture) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindTexture, target, texture)
|
DECLARE_GL_FUNCTION_HEAD(void, BindTexture, GLenum target, GLuint texture) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindTexture, target, texture)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, BlendColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendColor, red, green, blue, alpha)
|
DECLARE_GL_FUNCTION_HEAD(void, BlendColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendColor, red, green, blue, alpha)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, BlendEquation, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquation, mode)
|
DECLARE_GL_FUNCTION_HEAD(void, BlendEquation, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquation, mode)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationSeparate, modeRGB, modeAlpha)
|
DECLARE_GL_FUNCTION_HEAD(void, BlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquationSeparate, modeRGB, modeAlpha)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, BlendFunc, GLenum sfactor, GLenum dfactor) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFunc, sfactor, dfactor)
|
DECLARE_GL_FUNCTION_HEAD(void, BlendFunc, GLenum sfactor, GLenum dfactor) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFunc, sfactor, dfactor)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, BlendFuncSeparate, GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFuncSeparate, sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha)
|
DECLARE_GL_FUNCTION_HEAD(void, BlendFuncSeparate, GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFuncSeparate, sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, BufferData, GLenum target, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BufferData, target, size, data, usage)
|
DECLARE_GL_FUNCTION_HEAD(void, BufferData, GLenum target, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BufferData, target, size, data, usage)
|
||||||
@@ -104,8 +103,8 @@ DECLARE_GL_FUNCTION_HEAD(void, DrawArrays, GLenum mode, GLint first, GLsizei cou
|
|||||||
DECLARE_GL_FUNCTION_HEAD(void, DrawElements, GLenum mode, GLsizei count, GLenum type, const void* indices) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElements, mode, count, type, indices)
|
DECLARE_GL_FUNCTION_HEAD(void, DrawElements, GLenum mode, GLsizei count, GLenum type, const void* indices) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElements, mode, count, type, indices)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, Enable, GLenum cap) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Enable, cap)
|
DECLARE_GL_FUNCTION_HEAD(void, Enable, GLenum cap) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Enable, cap)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, EnableVertexAttribArray, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexAttribArray, index)
|
DECLARE_GL_FUNCTION_HEAD(void, EnableVertexAttribArray, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexAttribArray, index)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Finish) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Finish)
|
MOBILEGL_GL_API void glFinish() { MGLOG_D("Implementing function: %s(...)", __FUNCTION__); }
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Flush) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Flush)
|
MOBILEGL_GL_API void glFlush() { MGLOG_D("Implementing function: %s(...)", __FUNCTION__); }
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, FramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer)
|
DECLARE_GL_FUNCTION_HEAD(void, FramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, FramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferTexture2D, target, attachment, textarget, texture, level)
|
DECLARE_GL_FUNCTION_HEAD(void, FramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferTexture2D, target, attachment, textarget, texture, level)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, FrontFace, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FrontFace, mode)
|
DECLARE_GL_FUNCTION_HEAD(void, FrontFace, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FrontFace, mode)
|
||||||
@@ -216,7 +215,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, EndQuery, GLenum target) DECLARE_GL_FUNCTION
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryiv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryiv, target, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryiv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryiv, target, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryObjectuiv, GLuint id, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryObjectuiv, id, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryObjectuiv, GLuint id, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryObjectuiv, id, pname, params)
|
||||||
DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapBuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLboolean, UnmapBuffer, target)
|
DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapBuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLboolean, UnmapBuffer, target)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBufferPointerv, GLenum target, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBufferPointerv, target, pname, params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetBufferPointerv, GLenum target, GLenum pname, void** params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetBufferPointerv, target, pname, params)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, DrawBuffers, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawBuffers, n, bufs)
|
DECLARE_GL_FUNCTION_HEAD(void, DrawBuffers, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawBuffers, n, bufs)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix2x3fv, location, count, transpose, value)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix2x3fv, location, count, transpose, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix3x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix3x2fv, location, count, transpose, value)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix3x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix3x2fv, location, count, transpose, value)
|
||||||
@@ -233,7 +232,7 @@ DECLARE_GL_FUNCTION_HEAD(void, BindVertexArray, GLuint array) DECLARE_GL_FUNCTIO
|
|||||||
DECLARE_GL_FUNCTION_HEAD(void, DeleteVertexArrays, GLsizei n, const GLuint* arrays) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteVertexArrays, n, arrays)
|
DECLARE_GL_FUNCTION_HEAD(void, DeleteVertexArrays, GLsizei n, const GLuint* arrays) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteVertexArrays, n, arrays)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, GenVertexArrays, GLsizei n, GLuint* arrays) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GenVertexArrays, n, arrays)
|
DECLARE_GL_FUNCTION_HEAD(void, GenVertexArrays, GLsizei n, GLuint* arrays) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GenVertexArrays, n, arrays)
|
||||||
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsVertexArray, GLuint array) DECLARE_GL_FUNCTION_END(GLboolean, IsVertexArray, array)
|
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsVertexArray, GLuint array) DECLARE_GL_FUNCTION_END(GLboolean, IsVertexArray, array)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetIntegeri_v, GLenum target, GLuint index, GLint* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetIntegeri_v, target, index, data)
|
DECLARE_GL_FUNCTION_HEAD(void, GetIntegeri_v, GLenum target, GLuint index, GLint* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetIntegeri_v, target, index, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BeginTransformFeedback, GLenum primitiveMode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BeginTransformFeedback, primitiveMode)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, BeginTransformFeedback, GLenum primitiveMode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BeginTransformFeedback, primitiveMode)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, EndTransformFeedback) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EndTransformFeedback)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, EndTransformFeedback) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EndTransformFeedback)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, BindBufferRange, GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindBufferRange, target, index, buffer, offset, size)
|
DECLARE_GL_FUNCTION_HEAD(void, BindBufferRange, GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindBufferRange, target, index, buffer, offset, size)
|
||||||
@@ -249,11 +248,11 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribI4iv, GLuint index, const GLint*
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribI4uiv, GLuint index, const GLuint* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribI4uiv, index, v)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribI4uiv, GLuint index, const GLuint* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribI4uiv, index, v)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetUniformuiv, GLuint program, GLint location, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetUniformuiv, program, location, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetUniformuiv, GLuint program, GLint location, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetUniformuiv, program, location, params)
|
||||||
DECLARE_GL_FUNCTION_HEAD(GLint, GetFragDataLocation, GLuint program, const GLchar* name) DECLARE_GL_FUNCTION_END(GLint, GetFragDataLocation, program, name)
|
DECLARE_GL_FUNCTION_HEAD(GLint, GetFragDataLocation, GLuint program, const GLchar* name) DECLARE_GL_FUNCTION_END(GLint, GetFragDataLocation, program, name)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform1ui, GLint location, GLuint v0) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform1ui, location, v0)
|
DECLARE_GL_FUNCTION_HEAD(void, Uniform1ui, GLint location, GLuint v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform1ui, location, v0)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2ui, GLint location, GLuint v0, GLuint v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2ui, location, v0, v1)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2ui, GLint location, GLuint v0, GLuint v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2ui, location, v0, v1)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3ui, GLint location, GLuint v0, GLuint v1, GLuint v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3ui, location, v0, v1, v2)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3ui, GLint location, GLuint v0, GLuint v1, GLuint v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3ui, location, v0, v1, v2)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4ui, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4ui, location, v0, v1, v2, v3)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4ui, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4ui, location, v0, v1, v2, v3)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform1uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform1uiv, location, count, value)
|
DECLARE_GL_FUNCTION_HEAD(void, Uniform1uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform1uiv, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2uiv, location, count, value)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2uiv, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3uiv, location, count, value)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3uiv, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4uiv, location, count, value)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4uiv, location, count, value)
|
||||||
@@ -270,15 +269,15 @@ DECLARE_GL_FUNCTION_HEAD(void, GetActiveUniformBlockName, GLuint program, GLuint
|
|||||||
DECLARE_GL_FUNCTION_HEAD(void, UniformBlockBinding, GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformBlockBinding, program, uniformBlockIndex, uniformBlockBinding)
|
DECLARE_GL_FUNCTION_HEAD(void, UniformBlockBinding, GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformBlockBinding, program, uniformBlockIndex, uniformBlockBinding)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, DrawArraysInstanced, GLenum mode, GLint first, GLsizei count, GLsizei instancecount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawArraysInstanced, mode, first, count, instancecount)
|
DECLARE_GL_FUNCTION_HEAD(void, DrawArraysInstanced, GLenum mode, GLint first, GLsizei count, GLsizei instancecount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawArraysInstanced, mode, first, count, instancecount)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, DrawElementsInstanced, GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsInstanced, mode, count, type, indices, instancecount)
|
DECLARE_GL_FUNCTION_HEAD(void, DrawElementsInstanced, GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsInstanced, mode, count, type, indices, instancecount)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(GLsync, FenceSync, GLenum condition, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END(GLsync, FenceSync, condition, flags)
|
DECLARE_GL_FUNCTION_HEAD(GLsync, FenceSync, GLenum condition, GLbitfield flags) DECLARE_GL_FUNCTION_END(GLsync, FenceSync, condition, flags)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, IsSync, GLsync sync) DECLARE_GL_FUNCTION_STUB_END(GLboolean, IsSync, sync)
|
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsSync, GLsync sync) DECLARE_GL_FUNCTION_END(GLboolean, IsSync, sync)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, DeleteSync, GLsync sync) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DeleteSync, sync)
|
DECLARE_GL_FUNCTION_HEAD(void, DeleteSync, GLsync sync) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteSync, sync)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, ClientWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_STUB_END(GLenum, ClientWaitSync, sync, flags, timeout)
|
DECLARE_GL_FUNCTION_HEAD(GLenum, ClientWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_END(GLenum, ClientWaitSync, sync, flags, timeout)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, WaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, WaitSync, sync, flags, timeout)
|
DECLARE_GL_FUNCTION_HEAD(void, WaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_END_NO_RETURN(void, WaitSync, sync, flags, timeout)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetInteger64v, GLenum pname, GLint64* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetInteger64v, pname, data)
|
DECLARE_GL_FUNCTION_HEAD(void, GetInteger64v, GLenum pname, GLint64* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetInteger64v, pname, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetSynciv, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetSynciv, sync, pname, bufSize, length, values)
|
DECLARE_GL_FUNCTION_HEAD(void, GetSynciv, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetSynciv, sync, pname, bufSize, length, values)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetInteger64i_v, GLenum target, GLuint index, GLint64* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetInteger64i_v, target, index, data)
|
DECLARE_GL_FUNCTION_HEAD(void, GetInteger64i_v, GLenum target, GLuint index, GLint64* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetInteger64i_v, target, index, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBufferParameteri64v, GLenum target, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBufferParameteri64v, target, pname, params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetBufferParameteri64v, GLenum target, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetBufferParameteri64v, target, pname, params)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, GenSamplers, GLsizei count, GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GenSamplers, count, samplers)
|
DECLARE_GL_FUNCTION_HEAD(void, GenSamplers, GLsizei count, GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GenSamplers, count, samplers)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, DeleteSamplers, GLsizei count, const GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteSamplers, count, samplers)
|
DECLARE_GL_FUNCTION_HEAD(void, DeleteSamplers, GLsizei count, const GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteSamplers, count, samplers)
|
||||||
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsSampler, GLuint sampler) DECLARE_GL_FUNCTION_END(GLboolean, IsSampler, sampler)
|
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsSampler, GLuint sampler) DECLARE_GL_FUNCTION_END(GLboolean, IsSampler, sampler)
|
||||||
@@ -304,17 +303,17 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateSubFramebuffer, GLenum target, GLs
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage2D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage2D, target, levels, internalformat, width, height)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage2D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage2D, target, levels, internalformat, width, height)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage3D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage3D, target, levels, internalformat, width, height, depth)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage3D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage3D, target, levels, internalformat, width, height, depth)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetInternalformativ, GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetInternalformativ, target, internalformat, pname, bufSize, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetInternalformativ, GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetInternalformativ, target, internalformat, pname, bufSize, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, DispatchCompute, GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DispatchCompute, num_groups_x, num_groups_y, num_groups_z)
|
DECLARE_GL_FUNCTION_HEAD(void, DispatchCompute, GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DispatchCompute, num_groups_x, num_groups_y, num_groups_z)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, DispatchComputeIndirect, GLintptr indirect) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DispatchComputeIndirect, indirect)
|
DECLARE_GL_FUNCTION_HEAD(void, DispatchComputeIndirect, GLintptr indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DispatchComputeIndirect, indirect)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, DrawArraysIndirect, GLenum mode, const void* indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawArraysIndirect, mode, indirect)
|
DECLARE_GL_FUNCTION_HEAD(void, DrawArraysIndirect, GLenum mode, const void* indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawArraysIndirect, mode, indirect)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, DrawElementsIndirect, GLenum mode, GLenum type, const void* indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsIndirect, mode, type, indirect)
|
DECLARE_GL_FUNCTION_HEAD(void, DrawElementsIndirect, GLenum mode, GLenum type, const void* indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsIndirect, mode, type, indirect)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, FramebufferParameteri, GLenum target, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FramebufferParameteri, target, pname, param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, FramebufferParameteri, GLenum target, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FramebufferParameteri, target, pname, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetFramebufferParameteriv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetFramebufferParameteriv, target, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetFramebufferParameteriv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetFramebufferParameteriv, target, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramInterfaceiv, GLuint program, GLenum programInterface, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramInterfaceiv, program, programInterface, pname, params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetProgramInterfaceiv, GLuint program, GLenum programInterface, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetProgramInterfaceiv, program, programInterface, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(GLuint, GetProgramResourceIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END(GLuint, GetProgramResourceIndex, program, programInterface, name)
|
DECLARE_GL_FUNCTION_HEAD(GLuint, GetProgramResourceIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_END(GLuint, GetProgramResourceIndex, program, programInterface, name)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramResourceName, GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length, GLchar* name) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramResourceName, program, programInterface, index, bufSize, length, name)
|
DECLARE_GL_FUNCTION_HEAD(void, GetProgramResourceName, GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length, GLchar* name) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetProgramResourceName, program, programInterface, index, bufSize, length, name)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramResourceiv, GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramResourceiv, program, programInterface, index, propCount, props, bufSize, length, params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetProgramResourceiv, GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetProgramResourceiv, program, programInterface, index, propCount, props, bufSize, length, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(GLint, GetProgramResourceLocation, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END(GLint, GetProgramResourceLocation, program, programInterface, name)
|
DECLARE_GL_FUNCTION_HEAD(GLint, GetProgramResourceLocation, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_END(GLint, GetProgramResourceLocation, program, programInterface, name)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, UseProgramStages, GLuint pipeline, GLbitfield stages, GLuint program) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UseProgramStages, pipeline, stages, program)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, UseProgramStages, GLuint pipeline, GLbitfield stages, GLuint program) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UseProgramStages, pipeline, stages, program)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ActiveShaderProgram, GLuint pipeline, GLuint program) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ActiveShaderProgram, pipeline, program)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ActiveShaderProgram, GLuint pipeline, GLuint program) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ActiveShaderProgram, pipeline, program)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(GLuint, CreateShaderProgramv, GLenum type, GLsizei count, const GLchar* const* strings) DECLARE_GL_FUNCTION_STUB_END(GLuint, CreateShaderProgramv, type, count, strings)
|
DECLARE_GL_FUNCTION_STUB_HEAD(GLuint, CreateShaderProgramv, GLenum type, GLsizei count, const GLchar* const* strings) DECLARE_GL_FUNCTION_STUB_END(GLuint, CreateShaderProgramv, type, count, strings)
|
||||||
@@ -323,33 +322,33 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, DeleteProgramPipelines, GLsizei n, const GLu
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenProgramPipelines, GLsizei n, GLuint* pipelines) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenProgramPipelines, n, pipelines)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenProgramPipelines, GLsizei n, GLuint* pipelines) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenProgramPipelines, n, pipelines)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, IsProgramPipeline, GLuint pipeline) DECLARE_GL_FUNCTION_STUB_END(GLboolean, IsProgramPipeline, pipeline)
|
DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, IsProgramPipeline, GLuint pipeline) DECLARE_GL_FUNCTION_STUB_END(GLboolean, IsProgramPipeline, pipeline)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramPipelineiv, GLuint pipeline, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramPipelineiv, pipeline, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramPipelineiv, GLuint pipeline, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramPipelineiv, pipeline, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1i, GLuint program, GLint location, GLint v0) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1i, program, location, v0)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform1i, GLuint program, GLint location, GLint v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1i, program, location, v0)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform2i, GLuint program, GLint location, GLint v0, GLint v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform2i, program, location, v0, v1)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2i, GLuint program, GLint location, GLint v0, GLint v1) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2i, program, location, v0, v1)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform3i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform3i, program, location, v0, v1, v2)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform3i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform3i, program, location, v0, v1, v2)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform4i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform4i, program, location, v0, v1, v2, v3)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform4i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform4i, program, location, v0, v1, v2, v3)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1ui, GLuint program, GLint location, GLuint v0) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1ui, program, location, v0)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform1ui, GLuint program, GLint location, GLuint v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1ui, program, location, v0)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform2ui, GLuint program, GLint location, GLuint v0, GLuint v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform2ui, program, location, v0, v1)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2ui, GLuint program, GLint location, GLuint v0, GLuint v1) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2ui, program, location, v0, v1)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform3ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform3ui, program, location, v0, v1, v2)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform3ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform3ui, program, location, v0, v1, v2)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform4ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform4ui, program, location, v0, v1, v2, v3)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform4ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform4ui, program, location, v0, v1, v2, v3)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1f, GLuint program, GLint location, GLfloat v0) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1f, program, location, v0)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform1f, GLuint program, GLint location, GLfloat v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1f, program, location, v0)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform2f, GLuint program, GLint location, GLfloat v0, GLfloat v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform2f, program, location, v0, v1)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2f, GLuint program, GLint location, GLfloat v0, GLfloat v1) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2f, program, location, v0, v1)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform3f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform3f, program, location, v0, v1, v2)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform3f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform3f, program, location, v0, v1, v2)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform4f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform4f, program, location, v0, v1, v2, v3)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform4f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform4f, program, location, v0, v1, v2, v3)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1iv, program, location, count, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform1iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1iv, program, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform2iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform2iv, program, location, count, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2iv, program, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform3iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform3iv, program, location, count, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform3iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform3iv, program, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform4iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform4iv, program, location, count, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform4iv, GLuint program, GLint location, GLsizei count, const GLint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform4iv, program, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1uiv, program, location, count, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform1uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1uiv, program, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform2uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform2uiv, program, location, count, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2uiv, program, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform3uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform3uiv, program, location, count, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform3uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform3uiv, program, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform4uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform4uiv, program, location, count, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform4uiv, GLuint program, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform4uiv, program, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1fv, program, location, count, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform1fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1fv, program, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform2fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform2fv, program, location, count, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2fv, program, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform3fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform3fv, program, location, count, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform3fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform3fv, program, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform4fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform4fv, program, location, count, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform4fv, GLuint program, GLint location, GLsizei count, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform4fv, program, location, count, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix2fv, program, location, count, transpose, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniformMatrix2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniformMatrix2fv, program, location, count, transpose, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix3fv, program, location, count, transpose, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniformMatrix3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniformMatrix3fv, program, location, count, transpose, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix4fv, program, location, count, transpose, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniformMatrix4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniformMatrix4fv, program, location, count, transpose, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix2x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix2x3fv, program, location, count, transpose, value)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix2x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix2x3fv, program, location, count, transpose, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix3x2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix3x2fv, program, location, count, transpose, value)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix3x2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix3x2fv, program, location, count, transpose, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix2x4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix2x4fv, program, location, count, transpose, value)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix2x4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix2x4fv, program, location, count, transpose, value)
|
||||||
@@ -358,10 +357,10 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix3x4fv, GLuint program, G
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix4x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix4x3fv, program, location, count, transpose, value)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix4x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniformMatrix4x3fv, program, location, count, transpose, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ValidateProgramPipeline, GLuint pipeline) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ValidateProgramPipeline, pipeline)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ValidateProgramPipeline, GLuint pipeline) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ValidateProgramPipeline, pipeline)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramPipelineInfoLog, GLuint pipeline, GLsizei bufSize, GLsizei* length, GLchar* infoLog) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramPipelineInfoLog, pipeline, bufSize, length, infoLog)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramPipelineInfoLog, GLuint pipeline, GLsizei bufSize, GLsizei* length, GLchar* infoLog) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramPipelineInfoLog, pipeline, bufSize, length, infoLog)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindImageTexture, GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindImageTexture, unit, texture, level, layered, layer, access, format)
|
DECLARE_GL_FUNCTION_HEAD(void, BindImageTexture, GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindImageTexture, unit, texture, level, layered, layer, access, format)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBooleani_v, GLenum target, GLuint index, GLboolean* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBooleani_v, target, index, data)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBooleani_v, GLenum target, GLuint index, GLboolean* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBooleani_v, target, index, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, MemoryBarrier, GLbitfield barriers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MemoryBarrier, barriers)
|
DECLARE_GL_FUNCTION_HEAD(void, MemoryBarrier, GLbitfield barriers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MemoryBarrier, barriers)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, MemoryBarrierByRegion, GLbitfield barriers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MemoryBarrierByRegion, barriers)
|
DECLARE_GL_FUNCTION_HEAD(void, MemoryBarrierByRegion, GLbitfield barriers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MemoryBarrierByRegion, barriers)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetMultisamplefv, GLenum pname, GLuint index, GLfloat* val) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetMultisamplefv, pname, index, val)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetMultisamplefv, GLenum pname, GLuint index, GLfloat* val) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetMultisamplefv, pname, index, val)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, SampleMaski, GLuint maskNumber, GLbitfield mask) DECLARE_GL_FUNCTION_END_NO_RETURN(void, SampleMaski, maskNumber, mask)
|
DECLARE_GL_FUNCTION_HEAD(void, SampleMaski, GLuint maskNumber, GLbitfield mask) DECLARE_GL_FUNCTION_END_NO_RETURN(void, SampleMaski, maskNumber, mask)
|
||||||
@@ -387,14 +386,14 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetObjectPtrLabel, const void* ptr, GLsizei
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetPointerv, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetPointerv, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetPointerv, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetPointerv, pname, params)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, Enablei, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Enablei, target, index)
|
DECLARE_GL_FUNCTION_HEAD(void, Enablei, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Enablei, target, index)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, Disablei, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Disablei, target, index)
|
DECLARE_GL_FUNCTION_HEAD(void, Disablei, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Disablei, target, index)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationi, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationi, buf, mode)
|
DECLARE_GL_FUNCTION_HEAD(void, BlendEquationi, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquationi, buf, mode)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationiARB, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationi, buf, mode)
|
DECLARE_GL_FUNCTION_HEAD(void, BlendEquationiARB, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquationi, buf, mode)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationSeparatei, GLuint buf, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationSeparatei, buf, modeRGB, modeAlpha)
|
DECLARE_GL_FUNCTION_HEAD(void, BlendEquationSeparatei, GLuint buf, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquationSeparatei, buf, modeRGB, modeAlpha)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationSeparateiARB, GLuint buf, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationSeparatei, buf, modeRGB, modeAlpha)
|
DECLARE_GL_FUNCTION_HEAD(void, BlendEquationSeparateiARB, GLuint buf, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquationSeparatei, buf, modeRGB, modeAlpha)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFunci, GLuint buf, GLenum src, GLenum dst) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFunci, buf, src, dst)
|
DECLARE_GL_FUNCTION_HEAD(void, BlendFunci, GLuint buf, GLenum src, GLenum dst) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFunci, buf, src, dst)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFunciARB, GLuint buf, GLenum src, GLenum dst) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFunci, buf, src, dst)
|
DECLARE_GL_FUNCTION_HEAD(void, BlendFunciARB, GLuint buf, GLenum src, GLenum dst) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFunci, buf, src, dst)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, BlendFuncSeparatei, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha)
|
DECLARE_GL_FUNCTION_HEAD(void, BlendFuncSeparatei, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFuncSeparateiARB, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha)
|
DECLARE_GL_FUNCTION_HEAD(void, BlendFuncSeparateiARB, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ColorMaski, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ColorMaski, index, r, g, b, a)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ColorMaski, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ColorMaski, index, r, g, b, a)
|
||||||
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsEnabledi, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END(GLboolean, IsEnabledi, target, index)
|
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsEnabledi, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END(GLboolean, IsEnabledi, target, index)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, DrawElementsBaseVertex, GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsBaseVertex, mode, count, type, indices, basevertex)
|
DECLARE_GL_FUNCTION_HEAD(void, DrawElementsBaseVertex, GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsBaseVertex, mode, count, type, indices, basevertex)
|
||||||
@@ -847,7 +846,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4usv, GLuint index, const GLusho
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveRestartIndex, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PrimitiveRestartIndex, index)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveRestartIndex, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PrimitiveRestartIndex, index)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetActiveUniformName, GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetActiveUniformName, program, uniformIndex, bufSize, length, uniformName)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetActiveUniformName, GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetActiveUniformName, program, uniformIndex, bufSize, length, uniformName)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsBaseVertex, mode, count, type, indices, drawcount, basevertex)
|
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsBaseVertex, mode, count, type, indices, drawcount, basevertex)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProvokingVertex, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProvokingVertex, mode)
|
DECLARE_GL_FUNCTION_HEAD(void, ProvokingVertex, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProvokingVertex, mode)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, TexImage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations)
|
DECLARE_GL_FUNCTION_HEAD(void, TexImage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, TexImage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage3DMultisample, target, samples, internalformat, width, height, depth, fixedsamplelocations)
|
DECLARE_GL_FUNCTION_HEAD(void, TexImage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage3DMultisample, target, samples, internalformat, width, height, depth, fixedsamplelocations)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindFragDataLocationIndexed, GLuint program, GLuint colorNumber, GLuint index, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindFragDataLocationIndexed, program, colorNumber, index, name)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindFragDataLocationIndexed, GLuint program, GLuint colorNumber, GLuint index, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindFragDataLocationIndexed, program, colorNumber, index, name)
|
||||||
@@ -977,11 +976,11 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateBufferSubData, GLuint buffer, GLin
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateBufferData, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateBufferData, buffer)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateBufferData, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateBufferData, buffer)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawArraysIndirect, GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawArraysIndirect, mode, indirect, drawcount, stride)
|
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawArraysIndirect, GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawArraysIndirect, mode, indirect, drawcount, stride)
|
||||||
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsIndirect, GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsIndirect, mode, type, indirect, drawcount, stride)
|
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsIndirect, GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsIndirect, mode, type, indirect, drawcount, stride)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(GLint, GetProgramResourceLocationIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END(GLint, GetProgramResourceLocationIndex, program, programInterface, name)
|
DECLARE_GL_FUNCTION_HEAD(GLint, GetProgramResourceLocationIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_END(GLint, GetProgramResourceLocationIndex, program, programInterface, name)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ShaderStorageBlockBinding, GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ShaderStorageBlockBinding, program, storageBlockIndex, storageBlockBinding)
|
DECLARE_GL_FUNCTION_HEAD(void, ShaderStorageBlockBinding, GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ShaderStorageBlockBinding, program, storageBlockIndex, storageBlockBinding)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureView, GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureView, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureView, GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureView, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribLFormat, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribLFormat, attribindex, size, type, relativeoffset)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribLFormat, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribLFormat, attribindex, size, type, relativeoffset)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BufferStorage, GLenum target, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BufferStorage, target, size, data, flags)
|
DECLARE_GL_FUNCTION_HEAD(void, BufferStorage, GLenum target, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BufferStorage, target, size, data, flags)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexImage, GLuint texture, GLint level, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexImage, texture, level, format, type, data)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexImage, GLuint texture, GLint level, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexImage, texture, level, format, type, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindBuffersBase, GLenum target, GLuint first, GLsizei count, const GLuint* buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindBuffersBase, target, first, count, buffers)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindBuffersBase, GLenum target, GLuint first, GLsizei count, const GLuint* buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindBuffersBase, target, first, count, buffers)
|
||||||
@@ -997,51 +996,51 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, TransformFeedbackBufferRange, GLuint xfb, GL
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbackiv, GLuint xfb, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbackiv, xfb, pname, param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbackiv, GLuint xfb, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbackiv, xfb, pname, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki_v, GLuint xfb, GLenum pname, GLuint index, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki_v, xfb, pname, index, param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki_v, GLuint xfb, GLenum pname, GLuint index, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki_v, xfb, pname, index, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki64_v, GLuint xfb, GLenum pname, GLuint index, GLint64* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki64_v, xfb, pname, index, param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki64_v, GLuint xfb, GLenum pname, GLuint index, GLint64* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki64_v, xfb, pname, index, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateBuffers, GLsizei n, GLuint* buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateBuffers, n, buffers)
|
DECLARE_GL_FUNCTION_HEAD(void, CreateBuffers, GLsizei n, GLuint* buffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateBuffers, n, buffers)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferStorage, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferStorage, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferData, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferData, buffer, size, data, usage)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferData, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferData, buffer, size, data, usage)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferSubData, buffer, offset, size, data)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferSubData, buffer, offset, size, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyNamedBufferSubData, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyNamedBufferSubData, readBuffer, writeBuffer, readOffset, writeOffset, size)
|
DECLARE_GL_FUNCTION_HEAD(void, CopyNamedBufferSubData, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CopyNamedBufferSubData, readBuffer, writeBuffer, readOffset, writeOffset, size)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferData, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferData, buffer, internalformat, format, type, data)
|
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedBufferData, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedBufferData, buffer, internalformat, format, type, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferSubData, GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferSubData, buffer, internalformat, offset, size, format, type, data)
|
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedBufferSubData, GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedBufferSubData, buffer, internalformat, offset, size, format, type, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, UnmapNamedBuffer, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END(GLboolean, UnmapNamedBuffer, buffer)
|
DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapNamedBuffer, GLuint buffer) DECLARE_GL_FUNCTION_END(GLboolean, UnmapNamedBuffer, buffer)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, FlushMappedNamedBufferRange, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length)
|
DECLARE_GL_FUNCTION_HEAD(void, FlushMappedNamedBufferRange, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferParameteriv, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameteriv, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferParameteri64v, GLuint buffer, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferParameteri64v, buffer, pname, params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameteri64v, GLuint buffer, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteri64v, buffer, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferPointerv, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferPointerv, buffer, pname, *params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferPointerv, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferPointerv, buffer, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubData, buffer, offset, size, data)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubData, buffer, offset, size, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateFramebuffers, GLsizei n, GLuint* framebuffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateFramebuffers, n, framebuffers)
|
DECLARE_GL_FUNCTION_HEAD(void, CreateFramebuffers, GLsizei n, GLuint* framebuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateFramebuffers, n, framebuffers)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferRenderbuffer, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferRenderbuffer, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteri, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteri, framebuffer, pname, param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteri, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteri, framebuffer, pname, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture, framebuffer, attachment, texture, level)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferTexture, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferTexture, framebuffer, attachment, texture, level)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTextureLayer, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTextureLayer, framebuffer, attachment, texture, level, layer)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTextureLayer, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTextureLayer, framebuffer, attachment, texture, level, layer)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferDrawBuffer, GLuint framebuffer, GLenum buf) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferDrawBuffer, framebuffer, buf)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferDrawBuffer, GLuint framebuffer, GLenum buf) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferDrawBuffer, framebuffer, buf)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferDrawBuffers, GLuint framebuffer, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferDrawBuffers, framebuffer, n, bufs)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferDrawBuffers, GLuint framebuffer, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferDrawBuffers, framebuffer, n, bufs)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferReadBuffer, GLuint framebuffer, GLenum src) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferReadBuffer, framebuffer, src)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferReadBuffer, GLuint framebuffer, GLenum src) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferReadBuffer, framebuffer, src)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferData, framebuffer, numAttachments, attachments)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferData, framebuffer, numAttachments, attachments)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferSubData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferSubData, framebuffer, numAttachments, attachments, x, y, width, height)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferSubData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferSubData, framebuffer, numAttachments, attachments, x, y, width, height)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferiv, framebuffer, buffer, drawbuffer, value)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferiv, framebuffer, buffer, drawbuffer, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferuiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferuiv, framebuffer, buffer, drawbuffer, value)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferuiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferuiv, framebuffer, buffer, drawbuffer, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferfv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferfv, framebuffer, buffer, drawbuffer, value)
|
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedFramebufferfv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedFramebufferfv, framebuffer, buffer, drawbuffer, value)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferfi, GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferfi, framebuffer, buffer, drawbuffer, depth, stencil)
|
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedFramebufferfi, GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedFramebufferfi, framebuffer, buffer, drawbuffer, depth, stencil)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlitNamedFramebuffer, GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlitNamedFramebuffer, readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter)
|
DECLARE_GL_FUNCTION_HEAD(void, BlitNamedFramebuffer, GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlitNamedFramebuffer, readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, CheckNamedFramebufferStatus, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_STUB_END(GLenum, CheckNamedFramebufferStatus, framebuffer, target)
|
DECLARE_GL_FUNCTION_HEAD(GLenum, CheckNamedFramebufferStatus, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLenum, CheckNamedFramebufferStatus, framebuffer, target)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferParameteriv, GLuint framebuffer, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferParameteriv, framebuffer, pname, param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferParameteriv, GLuint framebuffer, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferParameteriv, framebuffer, pname, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferAttachmentParameteriv, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameteriv, framebuffer, attachment, pname, params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetNamedFramebufferAttachmentParameteriv, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameteriv, framebuffer, attachment, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateRenderbuffers, GLsizei n, GLuint* renderbuffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateRenderbuffers, n, renderbuffers)
|
DECLARE_GL_FUNCTION_HEAD(void, CreateRenderbuffers, GLsizei n, GLuint* renderbuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateRenderbuffers, n, renderbuffers)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorage, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorage, renderbuffer, internalformat, width, height)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedRenderbufferStorage, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedRenderbufferStorage, renderbuffer, internalformat, width, height)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisample, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisample, renderbuffer, samples, internalformat, width, height)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisample, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisample, renderbuffer, samples, internalformat, width, height)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedRenderbufferParameteriv, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedRenderbufferParameteriv, renderbuffer, pname, params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetNamedRenderbufferParameteriv, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedRenderbufferParameteriv, renderbuffer, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateTextures, GLenum target, GLsizei n, GLuint* textures) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateTextures, target, n, textures)
|
DECLARE_GL_FUNCTION_HEAD(void, CreateTextures, GLenum target, GLsizei n, GLuint* textures) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateTextures, target, n, textures)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBuffer, GLuint texture, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBuffer, texture, internalformat, buffer)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBuffer, GLuint texture, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBuffer, texture, internalformat, buffer)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferRange, GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferRange, texture, internalformat, buffer, offset, size)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferRange, GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferRange, texture, internalformat, buffer, offset, size)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage1D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage1D, texture, levels, internalformat, width)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage1D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage1D, texture, levels, internalformat, width)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage2D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage2D, texture, levels, internalformat, width, height)
|
DECLARE_GL_FUNCTION_HEAD(void, TextureStorage2D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureStorage2D, texture, levels, internalformat, width, height)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage3D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage3D, texture, levels, internalformat, width, height, depth)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage3D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage3D, texture, levels, internalformat, width, height, depth)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage2DMultisample, GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage2DMultisample, texture, samples, internalformat, width, height, fixedsamplelocations)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage2DMultisample, GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage2DMultisample, texture, samples, internalformat, width, height, fixedsamplelocations)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage3DMultisample, GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage3DMultisample, texture, samples, internalformat, width, height, depth, fixedsamplelocations)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage3DMultisample, GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage3DMultisample, texture, samples, internalformat, width, height, depth, fixedsamplelocations)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage1D, texture, level, xoffset, width, format, type, pixels)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage1D, texture, level, xoffset, width, format, type, pixels)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage2D, texture, level, xoffset, yoffset, width, height, format, type, pixels)
|
DECLARE_GL_FUNCTION_HEAD(void, TextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureSubImage2D, texture, level, xoffset, yoffset, width, height, format, type, pixels)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage3D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage3D, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage3D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage3D, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTextureSubImage1D, texture, level, xoffset, width, format, imageSize, data)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTextureSubImage1D, texture, level, xoffset, width, format, imageSize, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTextureSubImage2D, texture, level, xoffset, yoffset, width, height, format, imageSize, data)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTextureSubImage2D, texture, level, xoffset, yoffset, width, height, format, imageSize, data)
|
||||||
@@ -1049,31 +1048,31 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage3D, GLuint texture,
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage1D, texture, level, xoffset, x, y, width)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage1D, texture, level, xoffset, x, y, width)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage2D, texture, level, xoffset, yoffset, x, y, width, height)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage2D, texture, level, xoffset, yoffset, x, y, width, height)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage3D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage3D, texture, level, xoffset, yoffset, zoffset, x, y, width, height)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage3D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage3D, texture, level, xoffset, yoffset, zoffset, x, y, width, height)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterf, GLuint texture, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterf, texture, pname, param)
|
DECLARE_GL_FUNCTION_HEAD(void, TextureParameterf, GLuint texture, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureParameterf, texture, pname, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterfv, GLuint texture, GLenum pname, const GLfloat* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterfv, texture, pname, param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterfv, GLuint texture, GLenum pname, const GLfloat* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterfv, texture, pname, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameteri, GLuint texture, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameteri, texture, pname, param)
|
DECLARE_GL_FUNCTION_HEAD(void, TextureParameteri, GLuint texture, GLenum pname, GLint param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureParameteri, texture, pname, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterIiv, GLuint texture, GLenum pname, const GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterIiv, texture, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterIiv, GLuint texture, GLenum pname, const GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterIiv, texture, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterIuiv, GLuint texture, GLenum pname, const GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterIuiv, texture, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterIuiv, GLuint texture, GLenum pname, const GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterIuiv, texture, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameteriv, GLuint texture, GLenum pname, const GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameteriv, texture, pname, param)
|
DECLARE_GL_FUNCTION_HEAD(void, TextureParameteriv, GLuint texture, GLenum pname, const GLint* param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureParameteriv, texture, pname, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateTextureMipmap, GLuint texture) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateTextureMipmap, texture)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateTextureMipmap, GLuint texture) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateTextureMipmap, texture)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindTextureUnit, GLuint unit, GLuint texture) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindTextureUnit, unit, texture)
|
DECLARE_GL_FUNCTION_HEAD(void, BindTextureUnit, GLuint unit, GLuint texture) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindTextureUnit, unit, texture)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureImage, GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureImage, texture, level, format, type, bufSize, pixels)
|
DECLARE_GL_FUNCTION_HEAD(void, GetTextureImage, GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureImage, texture, level, format, type, bufSize, pixels)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetCompressedTextureImage, GLuint texture, GLint level, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetCompressedTextureImage, texture, level, bufSize, pixels)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetCompressedTextureImage, GLuint texture, GLint level, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetCompressedTextureImage, texture, level, bufSize, pixels)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureLevelParameterfv, GLuint texture, GLint level, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureLevelParameterfv, texture, level, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureLevelParameterfv, GLuint texture, GLint level, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureLevelParameterfv, texture, level, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureLevelParameteriv, GLuint texture, GLint level, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureLevelParameteriv, texture, level, pname, params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetTextureLevelParameteriv, GLuint texture, GLint level, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureLevelParameteriv, texture, level, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterfv, GLuint texture, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterfv, texture, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterfv, GLuint texture, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterfv, texture, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterIiv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterIiv, texture, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterIiv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterIiv, texture, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterIuiv, GLuint texture, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterIuiv, texture, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterIuiv, GLuint texture, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterIuiv, texture, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameteriv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameteriv, texture, pname, params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetTextureParameteriv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureParameteriv, texture, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateVertexArrays, GLsizei n, GLuint* arrays) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateVertexArrays, n, arrays)
|
DECLARE_GL_FUNCTION_HEAD(void, CreateVertexArrays, GLsizei n, GLuint* arrays) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateVertexArrays, n, arrays)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, DisableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DisableVertexArrayAttrib, vaobj, index)
|
DECLARE_GL_FUNCTION_HEAD(void, DisableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DisableVertexArrayAttrib, vaobj, index)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, EnableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableVertexArrayAttrib, vaobj, index)
|
DECLARE_GL_FUNCTION_HEAD(void, EnableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexArrayAttrib, vaobj, index)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayElementBuffer, GLuint vaobj, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayElementBuffer, vaobj, buffer)
|
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayElementBuffer, GLuint vaobj, GLuint buffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayElementBuffer, vaobj, buffer)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexBuffer, GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexBuffer, vaobj, bindingindex, buffer, offset, stride)
|
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayVertexBuffer, GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayVertexBuffer, vaobj, bindingindex, buffer, offset, stride)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexBuffers, GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, const GLsizei* strides) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexBuffers, vaobj, first, count, buffers, offsets, strides)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexBuffers, GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, const GLsizei* strides) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexBuffers, vaobj, first, count, buffers, offsets, strides)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribBinding, GLuint vaobj, GLuint attribindex, GLuint bindingindex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribBinding, vaobj, attribindex, bindingindex)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribBinding, GLuint vaobj, GLuint attribindex, GLuint bindingindex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribBinding, vaobj, attribindex, bindingindex)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribFormat, vaobj, attribindex, size, type, normalized, relativeoffset)
|
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayAttribFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayAttribFormat, vaobj, attribindex, size, type, normalized, relativeoffset)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribIFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribIFormat, vaobj, attribindex, size, type, relativeoffset)
|
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayAttribIFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayAttribIFormat, vaobj, attribindex, size, type, relativeoffset)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribLFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribLFormat, vaobj, attribindex, size, type, relativeoffset)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribLFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribLFormat, vaobj, attribindex, size, type, relativeoffset)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayBindingDivisor, GLuint vaobj, GLuint bindingindex, GLuint divisor) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayBindingDivisor, vaobj, bindingindex, divisor)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayBindingDivisor, GLuint vaobj, GLuint bindingindex, GLuint divisor) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayBindingDivisor, vaobj, bindingindex, divisor)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayiv, GLuint vaobj, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayiv, vaobj, pname, param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayiv, GLuint vaobj, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayiv, vaobj, pname, param)
|
||||||
@@ -1086,7 +1085,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjecti64v, GLuint id, GLuint
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectiv, id, buffer, pname, offset)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectiv, id, buffer, pname, offset)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectui64v, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectui64v, id, buffer, pname, offset)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectui64v, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectui64v, id, buffer, pname, offset)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectuiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectuiv, id, buffer, pname, offset)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectuiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectuiv, id, buffer, pname, offset)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, pixels)
|
DECLARE_GL_FUNCTION_HEAD(void, GetTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, pixels)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetCompressedTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetCompressedTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, bufSize, pixels)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetCompressedTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetCompressedTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, bufSize, pixels)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnCompressedTexImage, GLenum target, GLint lod, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnCompressedTexImage, target, lod, bufSize, pixels)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnCompressedTexImage, GLenum target, GLint lod, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnCompressedTexImage, target, lod, bufSize, pixels)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnTexImage, GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnTexImage, target, level, format, type, bufSize, pixels)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnTexImage, GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnTexImage, target, level, format, type, bufSize, pixels)
|
||||||
@@ -1105,8 +1104,8 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnHistogram, GLenum target, GLboolean rese
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnMinmax, GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void* values) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnMinmax, target, reset, format, type, bufSize, values)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnMinmax, GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void* values) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnMinmax, target, reset, format, type, bufSize, values)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBarrier, void) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBarrier, )
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBarrier, void) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBarrier, )
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, SpecializeShader, GLuint shader, const GLchar* pEntryPoint, GLuint numSpecializationConstants, const GLuint* pConstantIndex, const GLuint* pConstantValue) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SpecializeShader, shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, SpecializeShader, GLuint shader, const GLchar* pEntryPoint, GLuint numSpecializationConstants, const GLuint* pConstantIndex, const GLuint* pConstantValue) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SpecializeShader, shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawArraysIndirectCount, GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawArraysIndirectCount, mode, indirect, drawcount, maxdrawcount, stride)
|
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawArraysIndirectCount, GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawArraysIndirectCount, mode, indirect, drawcount, maxdrawcount, stride)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElementsIndirectCount, GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElementsIndirectCount, mode, type, indirect, drawcount, maxdrawcount, stride)
|
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsIndirectCount, GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsIndirectCount, mode, type, indirect, drawcount, maxdrawcount, stride)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffsetClamp, GLfloat factor, GLfloat units, GLfloat clamp) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffsetClamp, factor, units, clamp)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffsetClamp, GLfloat factor, GLfloat units, GLfloat clamp) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffsetClamp, factor, units, clamp)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveBoundingBoxARB, GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) DECLARE_GL_FUNCTION_STUB_END(void, PrimitiveBoundingBoxARB, minX, minY, minZ, minW, maxX, maxY, maxZ, maxW)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveBoundingBoxARB, GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) DECLARE_GL_FUNCTION_STUB_END(void, PrimitiveBoundingBoxARB, minX, minY, minZ, minW, maxX, maxY, maxZ, maxW)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(GLuint64, GetTextureHandleARB, GLuint texture) DECLARE_GL_FUNCTION_STUB_END(GLuint64, GetTextureHandleARB, texture)
|
DECLARE_GL_FUNCTION_STUB_HEAD(GLuint64, GetTextureHandleARB, GLuint texture) DECLARE_GL_FUNCTION_STUB_END(GLuint64, GetTextureHandleARB, texture)
|
||||||
@@ -1215,8 +1214,8 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, Histogram, GLenum target, GLsizei width, GLe
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Minmax, GLenum target, GLenum internalformat, GLboolean sink) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Minmax, target, internalformat, sink)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, Minmax, GLenum target, GLenum internalformat, GLboolean sink) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Minmax, target, internalformat, sink)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ResetHistogram, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ResetHistogram, target)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ResetHistogram, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ResetHistogram, target)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ResetMinmax, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ResetMinmax, target)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ResetMinmax, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ResetMinmax, target)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawArraysIndirectCountARB, GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawArraysIndirectCountARB, mode, indirect, drawcount, maxdrawcount, stride)
|
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawArraysIndirectCountARB, GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawArraysIndirectCount, mode, indirect, drawcount, maxdrawcount, stride)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElementsIndirectCountARB, GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElementsIndirectCountARB, mode, type, indirect, drawcount, maxdrawcount, stride)
|
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsIndirectCountARB, GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsIndirectCount, mode, type, indirect, drawcount, maxdrawcount, stride)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CurrentPaletteMatrixARB, GLint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CurrentPaletteMatrixARB, index)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, CurrentPaletteMatrixARB, GLint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CurrentPaletteMatrixARB, index)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixIndexubvARB, GLint size, const GLubyte* indices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixIndexubvARB, size, indices)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixIndexubvARB, GLint size, const GLubyte* indices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixIndexubvARB, size, indices)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixIndexusvARB, GLint size, const GLushort* indices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixIndexusvARB, size, indices)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixIndexusvARB, GLint size, const GLushort* indices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixIndexusvARB, size, indices)
|
||||||
@@ -1846,11 +1845,11 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixLoadTransposefEXT, GLenum mode, const
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixLoadTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixLoadTransposedEXT, mode, m)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixLoadTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixLoadTransposedEXT, mode, m)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposefEXT, GLenum mode, const GLfloat* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposefEXT, mode, m)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposefEXT, GLenum mode, const GLfloat* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposefEXT, mode, m)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposedEXT, mode, m)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposedEXT, mode, m)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferDataEXT, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferDataEXT, buffer, size, data, usage)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferDataEXT, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferData, buffer, size, data, usage)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferSubDataEXT, buffer, offset, size, data)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferSubData, buffer, offset, size, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, UnmapNamedBufferEXT, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END(GLboolean, UnmapNamedBufferEXT, buffer)
|
DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapNamedBufferEXT, GLuint buffer) DECLARE_GL_FUNCTION_END(GLboolean, UnmapNamedBuffer, buffer)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferParameterivEXT, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferParameterivEXT, buffer, pname, params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameterivEXT, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferPointervEXT, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferPointervEXT, buffer, pname, *params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferPointervEXT, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferPointerv, buffer, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubDataEXT, buffer, offset, size, data)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubDataEXT, buffer, offset, size, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferEXT, GLuint texture, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferEXT, texture, target, internalformat, buffer)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferEXT, GLuint texture, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferEXT, texture, target, internalformat, buffer)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiTexBufferEXT, GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiTexBufferEXT, texunit, target, internalformat, buffer)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiTexBufferEXT, GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiTexBufferEXT, texunit, target, internalformat, buffer)
|
||||||
@@ -1885,15 +1884,15 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramLocalParameterdvEXT, GLuint p
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramLocalParameterfvEXT, GLuint program, GLenum target, GLuint index, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramLocalParameterfvEXT, program, target, index, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramLocalParameterfvEXT, GLuint program, GLenum target, GLuint index, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramLocalParameterfvEXT, program, target, index, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramivEXT, GLuint program, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramivEXT, program, target, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramivEXT, GLuint program, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramivEXT, program, target, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramStringEXT, GLuint program, GLenum target, GLenum pname, void* string) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramStringEXT, program, target, pname, string)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramStringEXT, GLuint program, GLenum target, GLenum pname, void* string) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramStringEXT, program, target, pname, string)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageEXT, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageEXT, renderbuffer, internalformat, width, height)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedRenderbufferStorageEXT, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedRenderbufferStorage, renderbuffer, internalformat, width, height)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedRenderbufferParameterivEXT, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedRenderbufferParameterivEXT, renderbuffer, pname, params)
|
DECLARE_GL_FUNCTION_HEAD(void, GetNamedRenderbufferParameterivEXT, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedRenderbufferParameteriv, renderbuffer, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisampleEXT, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisampleEXT, renderbuffer, samples, internalformat, width, height)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisampleEXT, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisampleEXT, renderbuffer, samples, internalformat, width, height)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisampleCoverageEXT, GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisampleCoverageEXT, renderbuffer, coverageSamples, colorSamples, internalformat, width, height)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisampleCoverageEXT, GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisampleCoverageEXT, renderbuffer, coverageSamples, colorSamples, internalformat, width, height)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, CheckNamedFramebufferStatusEXT, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_STUB_END(GLenum, CheckNamedFramebufferStatusEXT, framebuffer, target)
|
DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, CheckNamedFramebufferStatusEXT, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_STUB_END(GLenum, CheckNamedFramebufferStatusEXT, framebuffer, target)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture1DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture1DEXT, framebuffer, attachment, textarget, texture, level)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture1DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture1DEXT, framebuffer, attachment, textarget, texture, level)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture2DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture2DEXT, framebuffer, attachment, textarget, texture, level)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture2DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture2DEXT, framebuffer, attachment, textarget, texture, level)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture3DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture3DEXT, framebuffer, attachment, textarget, texture, level, zoffset)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture3DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture3DEXT, framebuffer, attachment, textarget, texture, level, zoffset)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferRenderbufferEXT, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferRenderbufferEXT, framebuffer, attachment, renderbuffertarget, renderbuffer)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferRenderbufferEXT, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferAttachmentParameterivEXT, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameterivEXT, framebuffer, attachment, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferAttachmentParameterivEXT, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameterivEXT, framebuffer, attachment, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateTextureMipmapEXT, GLuint texture, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateTextureMipmapEXT, texture, target)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateTextureMipmapEXT, GLuint texture, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateTextureMipmapEXT, texture, target)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateMultiTexMipmapEXT, GLenum texunit, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateMultiTexMipmapEXT, texunit, target)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateMultiTexMipmapEXT, GLenum texunit, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateMultiTexMipmapEXT, texunit, target)
|
||||||
@@ -1919,16 +1918,16 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexAttribOffsetEXT, GLuint vao
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexAttribIOffsetEXT, GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexAttribIOffsetEXT, vaobj, buffer, index, size, type, stride, offset)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexAttribIOffsetEXT, GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexAttribIOffsetEXT, vaobj, buffer, index, size, type, stride, offset)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, EnableVertexArrayEXT, GLuint vaobj, GLenum array) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableVertexArrayEXT, vaobj, array)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, EnableVertexArrayEXT, GLuint vaobj, GLenum array) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableVertexArrayEXT, vaobj, array)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, DisableVertexArrayEXT, GLuint vaobj, GLenum array) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DisableVertexArrayEXT, vaobj, array)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, DisableVertexArrayEXT, GLuint vaobj, GLenum array) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DisableVertexArrayEXT, vaobj, array)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, EnableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableVertexArrayAttribEXT, vaobj, index)
|
DECLARE_GL_FUNCTION_HEAD(void, EnableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexArrayAttrib, vaobj, index)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, DisableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DisableVertexArrayAttribEXT, vaobj, index)
|
DECLARE_GL_FUNCTION_HEAD(void, DisableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DisableVertexArrayAttrib, vaobj, index)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegervEXT, GLuint vaobj, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIntegervEXT, vaobj, pname, param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegervEXT, GLuint vaobj, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIntegervEXT, vaobj, pname, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointervEXT, GLuint vaobj, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointervEXT, vaobj, pname, *param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointervEXT, GLuint vaobj, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointervEXT, vaobj, pname, *param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIntegeri_vEXT, vaobj, index, pname, param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIntegeri_vEXT, vaobj, index, pname, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointeri_vEXT, vaobj, index, pname, *param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointeri_vEXT, vaobj, index, pname, *param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, FlushMappedNamedBufferRangeEXT, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FlushMappedNamedBufferRangeEXT, buffer, offset, length)
|
DECLARE_GL_FUNCTION_HEAD(void, FlushMappedNamedBufferRangeEXT, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferStorageEXT, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferStorageEXT, buffer, size, data, flags)
|
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferStorageEXT, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferDataEXT, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferDataEXT, buffer, internalformat, format, type, data)
|
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedBufferDataEXT, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedBufferData, buffer, internalformat, format, type, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferSubDataEXT, GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferSubDataEXT, buffer, internalformat, offset, size, format, type, data)
|
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedBufferSubDataEXT, GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedBufferSubData, buffer, internalformat, offset, size, format, type, data)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteriEXT, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteriEXT, framebuffer, pname, param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteriEXT, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteriEXT, framebuffer, pname, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferParameterivEXT, GLuint framebuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferParameterivEXT, framebuffer, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferParameterivEXT, GLuint framebuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferParameterivEXT, framebuffer, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1dEXT, GLuint program, GLint location, GLdouble x) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1dEXT, program, location, x)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1dEXT, GLuint program, GLint location, GLdouble x) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1dEXT, program, location, x)
|
||||||
@@ -2046,7 +2045,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetPixelTransformParameterfvEXT, GLenum targ
|
|||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfEXT, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfEXT, pname, param)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfEXT, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfEXT, pname, param)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfvEXT, GLenum pname, const GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfvEXT, pname, params)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfvEXT, GLenum pname, const GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfvEXT, pname, params)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffsetClampEXT, GLfloat factor, GLfloat units, GLfloat clamp) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffsetClampEXT, factor, units, clamp)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffsetClampEXT, GLfloat factor, GLfloat units, GLfloat clamp) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffsetClampEXT, factor, units, clamp)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProvokingVertexEXT, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProvokingVertexEXT, mode)
|
DECLARE_GL_FUNCTION_HEAD(void, ProvokingVertexEXT, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProvokingVertex, mode)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, RasterSamplesEXT, GLuint samples, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, RasterSamplesEXT, samples, fixedsamplelocations)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, RasterSamplesEXT, GLuint samples, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, RasterSamplesEXT, samples, fixedsamplelocations)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, SecondaryColor3bEXT, GLbyte red, GLbyte green, GLbyte blue) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SecondaryColor3bEXT, red, green, blue)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, SecondaryColor3bEXT, GLbyte red, GLbyte green, GLbyte blue) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SecondaryColor3bEXT, red, green, blue)
|
||||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, SecondaryColor3bvEXT, const GLbyte* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SecondaryColor3bvEXT, v)
|
DECLARE_GL_FUNCTION_STUB_HEAD(void, SecondaryColor3bvEXT, const GLbyte* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SecondaryColor3bvEXT, v)
|
||||||
@@ -2880,6 +2879,69 @@ MOBILEGL_GL_API void glGetFramebufferParameterivEXT(GLenum target, GLenum pname,
|
|||||||
glGetFramebufferParameteriv(target, pname, params);
|
glGetFramebufferParameteriv(target, pname, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glBindFramebufferEXT(GLenum target, GLuint framebuffer) {
|
||||||
|
glBindFramebuffer(target, framebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glBindRenderbufferEXT(GLenum target, GLuint renderbuffer) {
|
||||||
|
glBindRenderbuffer(target, renderbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API GLenum glCheckFramebufferStatusEXT(GLenum target) {
|
||||||
|
return glCheckFramebufferStatus(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glDeleteFramebuffersEXT(GLsizei n, const GLuint* framebuffers) {
|
||||||
|
glDeleteFramebuffers(n, framebuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glDeleteRenderbuffersEXT(GLsizei n, const GLuint* renderbuffers) {
|
||||||
|
glDeleteRenderbuffers(n, renderbuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glFramebufferRenderbufferEXT(GLenum target, GLenum attachment, GLenum renderbuffertarget,
|
||||||
|
GLuint renderbuffer) {
|
||||||
|
glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
|
||||||
|
GLint level) {
|
||||||
|
glFramebufferTexture2D(target, attachment, textarget, texture, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glGenFramebuffersEXT(GLsizei n, GLuint* framebuffers) {
|
||||||
|
glGenFramebuffers(n, framebuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glGenRenderbuffersEXT(GLsizei n, GLuint* renderbuffers) {
|
||||||
|
glGenRenderbuffers(n, renderbuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glGenerateMipmapEXT(GLenum target) {
|
||||||
|
glGenerateMipmap(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, GLenum pname,
|
||||||
|
GLint* params) {
|
||||||
|
glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glGetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint* params) {
|
||||||
|
glGetRenderbufferParameteriv(target, pname, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API GLboolean glIsFramebufferEXT(GLuint framebuffer) {
|
||||||
|
return glIsFramebuffer(framebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API GLboolean glIsRenderbufferEXT(GLuint renderbuffer) {
|
||||||
|
return glIsRenderbuffer(renderbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBILEGL_GL_API void glRenderbufferStorageEXT(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
|
||||||
|
glRenderbufferStorage(target, internalformat, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API GLenum glGetGraphicsResetStatusARB(void) {
|
MOBILEGL_GL_API GLenum glGetGraphicsResetStatusARB(void) {
|
||||||
return glGetGraphicsResetStatus();
|
return glGetGraphicsResetStatus();
|
||||||
}
|
}
|
||||||
@@ -2902,8 +2964,8 @@ MOBILEGL_GL_API void glGetObjectLabelEXT(GLenum identifier, GLuint name, GLsizei
|
|||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void* glMapNamedBuffer(GLuint buffer, GLenum access) {
|
MOBILEGL_GL_API void* glMapNamedBuffer(GLuint buffer, GLenum access) {
|
||||||
MGLOG_W("Stub function: %s(...)", __FUNCTION__);
|
MGLOG_D("Implementing function: %s(...)", __FUNCTION__);
|
||||||
return nullptr;
|
return MobileGL::MG_Impl::GLImpl::MapNamedBuffer(buffer, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void* glMapNamedBufferEXT(GLuint buffer, GLenum access) {
|
MOBILEGL_GL_API void* glMapNamedBufferEXT(GLuint buffer, GLenum access) {
|
||||||
@@ -2911,8 +2973,8 @@ MOBILEGL_GL_API void* glMapNamedBufferEXT(GLuint buffer, GLenum access) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void* glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) {
|
MOBILEGL_GL_API void* glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) {
|
||||||
MGLOG_W("Stub function: %s(...)", __FUNCTION__);
|
MGLOG_D("Implementing function: %s(...)", __FUNCTION__);
|
||||||
return nullptr;
|
return MobileGL::MG_Impl::GLImpl::MapNamedBufferRange(buffer, offset, length, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void* glMapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) {
|
MOBILEGL_GL_API void* glMapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) {
|
||||||
@@ -3025,48 +3087,48 @@ MOBILEGL_GL_API void glProgramUniform4uivEXT(GLuint program, GLint location, GLs
|
|||||||
glProgramUniform4uiv(program, location, count, value);
|
glProgramUniform4uiv(program, location, count, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix2fv(program, location, count, transpose, value);
|
glProgramUniformMatrix2fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix2x3fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix2x3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix2x3fv(program, location, count, transpose, value);
|
glProgramUniformMatrix2x3fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix2x4fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix2x4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix2x4fv(program, location, count, transpose, value);
|
glProgramUniformMatrix2x4fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix3fv(program, location, count, transpose, value);
|
glProgramUniformMatrix3fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix3x2fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix3x2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix3x2fv(program, location, count, transpose, value);
|
glProgramUniformMatrix3x2fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix3x4fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix3x4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix3x4fv(program, location, count, transpose, value);
|
glProgramUniformMatrix3x4fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix4fv(program, location, count, transpose, value);
|
glProgramUniformMatrix4fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix4x2fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix4x2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix4x2fv(program, location, count, transpose, value);
|
glProgramUniformMatrix4x2fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOBILEGL_GL_API void glProgramUniformMatrix4x3fvEXT(GLuint program, GLint location, GLsizei count,
|
MOBILEGL_GL_API void glProgramUniformMatrix4x3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||||
GLboolean transpose, const GLfloat* value) {
|
const GLfloat* value) {
|
||||||
glProgramUniformMatrix4x3fv(program, location, count, transpose, value);
|
glProgramUniformMatrix4x3fv(program, location, count, transpose, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -11,51 +11,66 @@
|
|||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include <MG_State/GLState/Core.h>
|
#include <MG_State/GLState/Core.h>
|
||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL::MG_Impl::GLImpl {
|
||||||
namespace MG_Impl::GLImpl {
|
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
||||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||||
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
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 RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
|
||||||
void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
|
GLsizei height);
|
||||||
GLsizei height);
|
void RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
|
||||||
void RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
|
GLboolean IsRenderbuffer(GLuint renderbuffer);
|
||||||
GLboolean IsRenderbuffer(GLuint renderbuffer);
|
void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
||||||
void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
void GenRenderbuffers(GLsizei n, GLuint* renderbuffers);
|
||||||
void GenRenderbuffers(GLsizei n, GLuint* renderbuffers);
|
void CreateRenderbuffers(GLsizei n, GLuint* renderbuffers);
|
||||||
void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
|
void NamedRenderbufferStorage(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);
|
||||||
void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
|
void GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, GLint* params);
|
||||||
void BindRenderbuffer(GLenum target, GLuint renderbuffer);
|
void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
|
||||||
void SampleMaski(GLuint maskNumber, GLbitfield mask);
|
void NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget,
|
||||||
GLboolean IsFramebuffer(GLuint framebuffer);
|
GLuint renderbuffer);
|
||||||
void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
|
void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
|
||||||
void GenFramebuffers(GLsizei n, GLuint* framebuffers);
|
void BindRenderbuffer(GLenum target, GLuint renderbuffer);
|
||||||
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
|
void SampleMaski(GLuint maskNumber, GLbitfield mask);
|
||||||
void FramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level,
|
GLboolean IsFramebuffer(GLuint framebuffer);
|
||||||
GLint zoffset);
|
void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
|
||||||
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
void GenFramebuffers(GLsizei n, GLuint* framebuffers);
|
||||||
void FramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
void CreateFramebuffers(GLsizei n, GLuint* framebuffers);
|
||||||
void FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level);
|
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
|
||||||
void DrawBuffer(GLenum buf);
|
void FramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level,
|
||||||
void DrawBuffers(GLsizei n, const GLenum* bufs);
|
GLint zoffset);
|
||||||
void ReadBuffer(GLenum src);
|
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||||
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
|
void FramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||||
GLenum CheckFramebufferStatus(GLenum target);
|
void FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level);
|
||||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
void NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);
|
||||||
GLint dstY1, GLbitfield mask, GLenum filter);
|
void NamedFramebufferDrawBuffer(GLuint framebuffer, GLenum buf);
|
||||||
void BindFramebuffer(GLenum target, GLuint framebuffer);
|
void NamedFramebufferDrawBuffers(GLuint framebuffer, GLsizei n, const GLenum* bufs);
|
||||||
|
void NamedFramebufferReadBuffer(GLuint framebuffer, GLenum src);
|
||||||
|
void ClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||||
|
void ClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||||
|
GLenum CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target);
|
||||||
|
void GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params);
|
||||||
|
void BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1,
|
||||||
|
GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
|
||||||
|
GLenum filter);
|
||||||
|
void DrawBuffer(GLenum buf);
|
||||||
|
void DrawBuffers(GLsizei n, const GLenum* bufs);
|
||||||
|
void ReadBuffer(GLenum src);
|
||||||
|
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
|
||||||
|
GLenum CheckFramebufferStatus(GLenum target);
|
||||||
|
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||||
|
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 DefaultFramebufferInfo* pDefaultFramebufferInfo;
|
extern UniquePtr<DefaultFramebufferInfo> pDefaultFramebufferInfo;
|
||||||
} // namespace FramebufferImpl
|
} // namespace FramebufferImpl
|
||||||
} // namespace MG_Impl::GLImpl
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
} // namespace MobileGL
|
|
||||||
|
|||||||
@@ -13,85 +13,82 @@
|
|||||||
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
|
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
|
||||||
#include <MG_Util/Converters/MGToStr/FramebufferEnumConverter.h>
|
#include <MG_Util/Converters/MGToStr/FramebufferEnumConverter.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl {
|
namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
|
||||||
namespace FramebufferImpl {
|
Bool ValidateFramebufferTarget(FramebufferTarget target) {
|
||||||
Bool ValidateFramebufferTarget(FramebufferTarget target) {
|
if (target == FramebufferTarget::Unknown) {
|
||||||
if (target == FramebufferTarget::Unknown) {
|
using namespace MG_Util;
|
||||||
using namespace MG_Util;
|
String bufferTargetStr = ConvertFramebufferTargetToString(target);
|
||||||
String bufferTargetStr = ConvertFramebufferTargetToString(target);
|
String glTargetStr = ConvertGLEnumToString(ConvertFramebufferTargetToGLEnum(target));
|
||||||
String glTargetStr = ConvertGLEnumToString(ConvertFramebufferTargetToGLEnum(target));
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeShared<GenericErrorInfo>(
|
|
||||||
"MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferTarget",
|
|
||||||
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateFramebufferName(Uint index, Bool 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::InvalidOperation,
|
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>(
|
||||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName",
|
"MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferTarget",
|
||||||
std::format("Framebuffer name {} is not valid.", index)));
|
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment) {
|
Bool ValidateFramebufferName(Uint index, Bool allowZero) {
|
||||||
if (attachment == FramebufferAttachmentType::Unknown) {
|
if (index == 0 && !allowZero) {
|
||||||
using namespace MG_Util;
|
|
||||||
String attachmentStr = ConvertFramebufferAttachmentTypeToString(attachment);
|
|
||||||
String glAttachmentStr = ConvertGLEnumToString(ConvertFramebufferAttachmentTypeToGLEnum(attachment));
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeShared<GenericErrorInfo>(
|
|
||||||
"MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferAttachmentType",
|
|
||||||
std::format("Attachment type {} ({}) is not valid.", attachmentStr, glAttachmentStr)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateRenderbufferTarget(RenderbufferTarget target) {
|
|
||||||
if (target == RenderbufferTarget::Unknown) {
|
|
||||||
using namespace MG_Util;
|
|
||||||
String renderbufferTargetStr = ConvertRenderbufferTargetToString(target);
|
|
||||||
String glTargetStr = ConvertGLEnumToString(ConvertRenderbufferTargetToGLEnum(target));
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidEnum,
|
|
||||||
MakeShared<GenericErrorInfo>(
|
|
||||||
"MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferTarget",
|
|
||||||
std::format("Target {} ({}) is not valid.", renderbufferTargetStr, glTargetStr)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool ValidateRenderbufferName(Uint index, Bool 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::InvalidOperation,
|
ErrorCode::InvalidValue,
|
||||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName",
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName",
|
||||||
std::format("Renderbuffer name {} is not valid.", index)));
|
"Framebuffer name 0 is not valid in this situation."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} // namespace FramebufferImpl
|
Bool isValid = MG_State::pGLContext->ValidateFramebufferName(index);
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
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) {
|
||||||
|
if (attachment == FramebufferAttachmentType::Unknown) {
|
||||||
|
using namespace MG_Util;
|
||||||
|
String attachmentStr = ConvertFramebufferAttachmentTypeToString(attachment);
|
||||||
|
String glAttachmentStr = ConvertGLEnumToString(ConvertFramebufferAttachmentTypeToGLEnum(attachment));
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeUnique<GenericErrorInfo>(
|
||||||
|
"MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferAttachmentType",
|
||||||
|
std::format("Attachment type {} ({}) is not valid.", attachmentStr, glAttachmentStr)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ValidateRenderbufferTarget(RenderbufferTarget target) {
|
||||||
|
if (target == RenderbufferTarget::Unknown) {
|
||||||
|
using namespace MG_Util;
|
||||||
|
String renderbufferTargetStr = ConvertRenderbufferTargetToString(target);
|
||||||
|
String glTargetStr = ConvertGLEnumToString(ConvertRenderbufferTargetToGLEnum(target));
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeUnique<GenericErrorInfo>(
|
||||||
|
"MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferTarget",
|
||||||
|
std::format("Target {} ({}) is not valid.", renderbufferTargetStr, glTargetStr)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ValidateRenderbufferName(Uint index, Bool allowZero) {
|
||||||
|
if (index == 0 && !allowZero) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeUnique<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(
|
||||||
|
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,12 +10,10 @@
|
|||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Impl::GLImpl {
|
namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
|
||||||
namespace FramebufferImpl {
|
Bool ValidateFramebufferTarget(FramebufferTarget target);
|
||||||
Bool ValidateFramebufferTarget(FramebufferTarget target);
|
Bool ValidateFramebufferName(Uint index, Bool allowZero = true);
|
||||||
Bool ValidateFramebufferName(Uint index, Bool allowZero = true);
|
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment);
|
||||||
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment);
|
Bool ValidateRenderbufferTarget(RenderbufferTarget target);
|
||||||
Bool ValidateRenderbufferTarget(RenderbufferTarget target);
|
Bool ValidateRenderbufferName(Uint index, Bool allowZero = true);
|
||||||
Bool ValidateRenderbufferName(Uint index, Bool allowZero = true);
|
} // namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl
|
||||||
} // namespace FramebufferImpl
|
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
|
||||||
|
|||||||
@@ -76,12 +76,12 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
MGLOG_D("shadingLanguageVersion: %s", shadingLanguageVersion.c_str());
|
MGLOG_D("shadingLanguageVersion: %s", shadingLanguageVersion.c_str());
|
||||||
return (const GLubyte*)shadingLanguageVersion.c_str();
|
return (const GLubyte*)shadingLanguageVersion.c_str();
|
||||||
case GL_EXTENSIONS:
|
case GL_EXTENSIONS:
|
||||||
if (extensionsString.empty()) {
|
extensionsString.clear();
|
||||||
for (auto& ext : rendererInfo.RendererGLInfo.Extensions) {
|
for (auto& ext : rendererInfo.RendererGLInfo.Extensions) {
|
||||||
extensionsString += MG_Util::ConvertGLExtToString(ext);
|
if (!extensionsString.empty()) {
|
||||||
extensionsString += " ";
|
extensionsString += " ";
|
||||||
}
|
}
|
||||||
extensionsString.pop_back();
|
extensionsString += MG_Util::ConvertGLExtToString(ext);
|
||||||
}
|
}
|
||||||
return (const GLubyte*)extensionsString.c_str();
|
return (const GLubyte*)extensionsString.c_str();
|
||||||
default:
|
default:
|
||||||
@@ -108,24 +108,95 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Vector<String> extStrings;
|
static Vector<String> extStrings;
|
||||||
static Bool initialized = false;
|
extStrings.clear();
|
||||||
if (!initialized) {
|
extStrings.reserve(exts.size());
|
||||||
extStrings.reserve(exts.size());
|
for (const auto& ext : exts) {
|
||||||
for (const auto& ext : exts) {
|
extStrings.emplace_back(MG_Util::ConvertGLExtToString(ext));
|
||||||
extStrings.emplace_back(MG_Util::ConvertGLExtToString(ext));
|
|
||||||
}
|
|
||||||
initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (const GLubyte*)extStrings[index].c_str();
|
return (const GLubyte*)extStrings[index].c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetIntegeri_v(GLenum target, GLuint index, GLint* data) {
|
||||||
|
if (!data) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "data pointer cannot be null"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto getIntegeri = MG_Backend::gBackendFunctionsTable.GL.GetIntegeri_v;
|
||||||
|
if (!getIntegeri) {
|
||||||
|
*data = 0;
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Backend does not support indexed integer queries."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getIntegeri(target, index, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetInteger64i_v(GLenum target, GLuint index, GLint64* data) {
|
||||||
|
if (!data) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "data pointer cannot be null"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto getInteger64i = MG_Backend::gBackendFunctionsTable.GL.GetInteger64i_v;
|
||||||
|
if (!getInteger64i) {
|
||||||
|
*data = 0;
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Backend does not support indexed integer queries."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getInteger64i(target, index, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetInteger64v(GLenum pname, GLint64* data) {
|
||||||
|
MGLOG_D("glGetInteger64v, pname: %s", MG_Util::ConvertGLEnumToString(pname).c_str());
|
||||||
|
if (!data) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "data pointer cannot be null"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (pname) {
|
||||||
|
case GL_MAX_SHADER_STORAGE_BLOCK_SIZE:
|
||||||
|
if (MG_Backend::pActiveBackendObject) {
|
||||||
|
*data = static_cast<GLint64>(
|
||||||
|
MG_Backend::pActiveBackendObject->GetDynamicParameters().MaxShaderStorageBlockSize);
|
||||||
|
} else {
|
||||||
|
*data = static_cast<GLint64>(MG_Backend::DynamicBackendParameters{}.MaxShaderStorageBlockSize);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case GL_SUBGROUP_SIZE_KHR:
|
||||||
|
case GL_SUBGROUP_SUPPORTED_STAGES_KHR:
|
||||||
|
case GL_SUBGROUP_SUPPORTED_FEATURES_KHR:
|
||||||
|
case GL_SUBGROUP_QUAD_ALL_STAGES_KHR: {
|
||||||
|
GLint params = 0;
|
||||||
|
GetIntegerv(pname, ¶ms);
|
||||||
|
*data = static_cast<GLint64>(params);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
*data = 0;
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||||
|
std::format("Unsupported integer64 pname {}.",
|
||||||
|
MG_Util::ConvertGLEnumToString(pname))));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GetIntegerv(GLenum pname, GLint* params) {
|
void GetIntegerv(GLenum pname, GLint* params) {
|
||||||
MGLOG_D("glGetIntegerv, pname: %s", MG_Util::ConvertGLEnumToString(pname).c_str());
|
MGLOG_D("glGetIntegerv, pname: %s", MG_Util::ConvertGLEnumToString(pname).c_str());
|
||||||
if (!params) {
|
if (!params) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidValue,
|
||||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv", "params pointer cannot be null"));
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv", "params pointer cannot be null"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +206,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto& rendererInfo = activeBackendObject->GetRendererInfo();
|
const auto& rendererInfo = activeBackendObject->GetRendererInfo();
|
||||||
|
const auto& dynamicParameters = activeBackendObject->GetDynamicParameters();
|
||||||
|
|
||||||
switch (pname) {
|
switch (pname) {
|
||||||
case GL_ACTIVE_TEXTURE:
|
case GL_ACTIVE_TEXTURE:
|
||||||
@@ -144,9 +216,9 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
*params = 0; // TODO
|
*params = 0; // TODO
|
||||||
break;
|
break;
|
||||||
case GL_ARRAY_BUFFER_BINDING: {
|
case GL_ARRAY_BUFFER_BINDING: {
|
||||||
auto obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex).GetBoundObject();
|
auto& obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex).GetBoundObject();
|
||||||
if (obj)
|
if (obj)
|
||||||
*params = obj->GetExternalIndex();
|
*params = (GLint)obj->GetExternalIndex();
|
||||||
else
|
else
|
||||||
*params = 0;
|
*params = 0;
|
||||||
break;
|
break;
|
||||||
@@ -160,31 +232,39 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
case GL_BLEND_DST_ALPHA: {
|
case GL_BLEND_DST_ALPHA: {
|
||||||
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha;
|
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha;
|
||||||
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||||
*params = static_cast<GLint>(dstAlpha);
|
*params = static_cast<GLint>(MG_Util::ConvertBlendFactorToGLEnum(dstAlpha));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_BLEND_DST_RGB: {
|
case GL_BLEND_DST_RGB: {
|
||||||
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha;
|
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha;
|
||||||
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||||
*params = static_cast<GLint>(dstRGB);
|
*params = static_cast<GLint>(MG_Util::ConvertBlendFactorToGLEnum(dstRGB));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_BLEND_EQUATION_RGB:
|
case GL_BLEND_EQUATION_RGB: {
|
||||||
*params = 0; // TODO
|
BlendEquation colorEquation = BlendEquation::Add;
|
||||||
|
BlendEquation alphaEquation = BlendEquation::Add;
|
||||||
|
MG_State::pGLContext->GetBlendEquation(colorEquation, alphaEquation);
|
||||||
|
*params = static_cast<GLint>(MG_Util::ConvertBlendEquationToGLEnum(colorEquation));
|
||||||
break;
|
break;
|
||||||
case GL_BLEND_EQUATION_ALPHA:
|
}
|
||||||
*params = 0; // TODO
|
case GL_BLEND_EQUATION_ALPHA: {
|
||||||
|
BlendEquation colorEquation = BlendEquation::Add;
|
||||||
|
BlendEquation alphaEquation = BlendEquation::Add;
|
||||||
|
MG_State::pGLContext->GetBlendEquation(colorEquation, alphaEquation);
|
||||||
|
*params = static_cast<GLint>(MG_Util::ConvertBlendEquationToGLEnum(alphaEquation));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GL_BLEND_SRC_ALPHA: {
|
case GL_BLEND_SRC_ALPHA: {
|
||||||
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha;
|
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha;
|
||||||
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||||
*params = static_cast<GLint>(srcAlpha);
|
*params = static_cast<GLint>(MG_Util::ConvertBlendFactorToGLEnum(srcAlpha));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_BLEND_SRC_RGB: {
|
case GL_BLEND_SRC_RGB: {
|
||||||
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha;
|
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha;
|
||||||
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||||
*params = static_cast<GLint>(srcRGB);
|
*params = static_cast<GLint>(MG_Util::ConvertBlendFactorToGLEnum(srcRGB));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_COLOR_CLEAR_VALUE:
|
case GL_COLOR_CLEAR_VALUE:
|
||||||
@@ -204,42 +284,60 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
case GL_COMPRESSED_TEXTURE_FORMATS:
|
case GL_COMPRESSED_TEXTURE_FORMATS:
|
||||||
*params = 0; // TODO
|
*params = 0; // TODO
|
||||||
break;
|
break;
|
||||||
|
case GL_SUBGROUP_SIZE_KHR:
|
||||||
|
*params = static_cast<GLint>(dynamicParameters.SubgroupSize);
|
||||||
|
break;
|
||||||
|
case GL_SUBGROUP_SUPPORTED_STAGES_KHR:
|
||||||
|
*params = static_cast<GLint>(dynamicParameters.SubgroupSupportedStages);
|
||||||
|
break;
|
||||||
|
case GL_SUBGROUP_SUPPORTED_FEATURES_KHR:
|
||||||
|
*params = static_cast<GLint>(dynamicParameters.SubgroupSupportedFeatures);
|
||||||
|
break;
|
||||||
|
case GL_SUBGROUP_QUAD_ALL_STAGES_KHR:
|
||||||
|
*params = dynamicParameters.SubgroupQuadOperationsInAllStages ? GL_TRUE : GL_FALSE;
|
||||||
|
break;
|
||||||
case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS:
|
case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS:
|
||||||
*params = 0; // TODO
|
*params = 16; // TODO: use backend value
|
||||||
break;
|
break;
|
||||||
case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS:
|
case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS:
|
||||||
*params = 0; // TODO
|
*params = 96; // TODO: use backend value
|
||||||
break;
|
break;
|
||||||
case GL_MAX_COMPUTE_UNIFORM_BLOCKS:
|
case GL_MAX_COMPUTE_UNIFORM_BLOCKS:
|
||||||
*params = 0; // TODO
|
*params = 14; // TODO: use backend value
|
||||||
break;
|
break;
|
||||||
case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS:
|
case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS:
|
||||||
*params = 0; // TODO
|
*params = MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; // TODO: use backend value
|
||||||
break;
|
break;
|
||||||
case GL_MAX_COMPUTE_UNIFORM_COMPONENTS:
|
case GL_MAX_COMPUTE_UNIFORM_COMPONENTS:
|
||||||
*params = 0; // TODO
|
*params = 1024 * 4; // TODO: use backend value
|
||||||
break;
|
break;
|
||||||
case GL_MAX_COMPUTE_ATOMIC_COUNTERS:
|
case GL_MAX_COMPUTE_ATOMIC_COUNTERS:
|
||||||
*params = 0; // TODO
|
*params = 8; // TODO: use backend value
|
||||||
break;
|
break;
|
||||||
case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS:
|
case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS:
|
||||||
*params = 0; // TODO
|
*params = 8; // TODO: use backend value
|
||||||
break;
|
break;
|
||||||
case GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS:
|
case GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS:
|
||||||
*params = 0; // TODO
|
*params = 1024 * 228; // TODO: use backend value
|
||||||
break;
|
break;
|
||||||
case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS:
|
case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS:
|
||||||
*params = 0; // TODO
|
*params = 1024; // TODO: use backend value
|
||||||
break;
|
break;
|
||||||
case GL_MAX_COMPUTE_WORK_GROUP_COUNT:
|
case GL_MAX_COMPUTE_WORK_GROUP_COUNT:
|
||||||
*params = 0; // TODO
|
GetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, ¶ms[0]);
|
||||||
|
GetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, ¶ms[1]);
|
||||||
|
GetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, ¶ms[2]);
|
||||||
break;
|
break;
|
||||||
case GL_MAX_COMPUTE_WORK_GROUP_SIZE:
|
case GL_MAX_COMPUTE_WORK_GROUP_SIZE:
|
||||||
*params = 0; // TODO
|
GetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, ¶ms[0]);
|
||||||
|
GetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, ¶ms[1]);
|
||||||
|
GetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, ¶ms[2]);
|
||||||
break;
|
break;
|
||||||
case GL_DISPATCH_INDIRECT_BUFFER_BINDING:
|
case GL_DISPATCH_INDIRECT_BUFFER_BINDING: {
|
||||||
*params = 0; // TODO
|
auto& obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DispatchIndirect).GetBoundObject();
|
||||||
|
*params = obj ? static_cast<GLint>(obj->GetExternalIndex()) : 0;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GL_MAX_DEBUG_GROUP_STACK_DEPTH:
|
case GL_MAX_DEBUG_GROUP_STACK_DEPTH:
|
||||||
*params = 0; // TODO
|
*params = 0; // TODO
|
||||||
break;
|
break;
|
||||||
@@ -252,16 +350,22 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
case GL_CULL_FACE:
|
case GL_CULL_FACE:
|
||||||
*params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace) ? GL_TRUE : GL_FALSE;
|
*params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace) ? GL_TRUE : GL_FALSE;
|
||||||
break;
|
break;
|
||||||
|
case GL_CULL_FACE_MODE:
|
||||||
|
*params = static_cast<GLint>(MG_Util::ConvertCullFaceModeToGLEnum(MG_State::pGLContext->GetCullFaceMode()));
|
||||||
|
break;
|
||||||
|
case GL_FRONT_FACE:
|
||||||
|
*params = static_cast<GLint>(MG_Util::ConvertFrontFaceModeToGLEnum(MG_State::pGLContext->GetFrontFaceMode()));
|
||||||
|
break;
|
||||||
case GL_CURRENT_PROGRAM: {
|
case GL_CURRENT_PROGRAM: {
|
||||||
const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||||
*params = currentProgram ? currentProgram->GetExternalIndex() : 0;
|
*params = currentProgram ? (GLint)currentProgram->GetExternalIndex() : 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_DEPTH_CLEAR_VALUE:
|
case GL_DEPTH_CLEAR_VALUE:
|
||||||
*params = MG_State::pGLContext->GetClearDepth();
|
*params = (GLint)MG_State::pGLContext->GetClearDepth();
|
||||||
break;
|
break;
|
||||||
case GL_DEPTH_FUNC:
|
case GL_DEPTH_FUNC:
|
||||||
*params = MG_Util::ConvertDepthTestFuncToGLEnum(MG_State::pGLContext->GetDepthFunc());
|
*params = (GLint)MG_Util::ConvertDepthTestFuncToGLEnum(MG_State::pGLContext->GetDepthFunc());
|
||||||
break;
|
break;
|
||||||
case GL_DEPTH_RANGE:
|
case GL_DEPTH_RANGE:
|
||||||
*params = 0; // TODO
|
*params = 0; // TODO
|
||||||
@@ -286,12 +390,12 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
break;
|
break;
|
||||||
case GL_DRAW_FRAMEBUFFER_BINDING: {
|
case GL_DRAW_FRAMEBUFFER_BINDING: {
|
||||||
const auto& FBO = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
const auto& FBO = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||||
*params = FBO ? FBO->GetExternalIndex() : 0;
|
*params = FBO ? (GLint)FBO->GetExternalIndex() : 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_READ_FRAMEBUFFER_BINDING: {
|
case GL_READ_FRAMEBUFFER_BINDING: {
|
||||||
const auto& FBO = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
const auto& FBO = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
||||||
*params = FBO ? FBO->GetExternalIndex() : 0;
|
*params = FBO ? (GLint)FBO->GetExternalIndex() : 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_ELEMENT_ARRAY_BUFFER_BINDING: {
|
case GL_ELEMENT_ARRAY_BUFFER_BINDING: {
|
||||||
@@ -300,7 +404,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const auto& bufferObject = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Index).GetBoundObject();
|
const auto& bufferObject = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Index).GetBoundObject();
|
||||||
*params = bufferObject ? bufferObject->GetExternalIndex() : 0;
|
*params = bufferObject ? (GLint)bufferObject->GetExternalIndex() : 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
|
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
|
||||||
@@ -426,6 +530,22 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
case GL_MAX_GEOMETRY_UNIFORM_COMPONENTS:
|
case GL_MAX_GEOMETRY_UNIFORM_COMPONENTS:
|
||||||
*params = 1024 * 4; // TODO
|
*params = 1024 * 4; // TODO
|
||||||
break;
|
break;
|
||||||
|
case GL_MAX_IMAGE_UNITS:
|
||||||
|
*params = MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; // TODO: use backend value
|
||||||
|
break;
|
||||||
|
case GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS:
|
||||||
|
*params = MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS +
|
||||||
|
MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS;
|
||||||
|
break;
|
||||||
|
case GL_MAX_COMBINED_IMAGE_UNIFORMS:
|
||||||
|
*params = MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; // TODO: use backend value
|
||||||
|
break;
|
||||||
|
case GL_MAX_IMAGE_SAMPLES:
|
||||||
|
*params = 0; // multisampled image load/store is not exposed by the DirectGLES frontend
|
||||||
|
break;
|
||||||
|
case GL_MAX_COMPUTE_IMAGE_UNIFORMS:
|
||||||
|
*params = MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; // TODO: use backend value
|
||||||
|
break;
|
||||||
case GL_MAX_INTEGER_SAMPLES:
|
case GL_MAX_INTEGER_SAMPLES:
|
||||||
*params = 16; // TODO
|
*params = 16; // TODO
|
||||||
break;
|
break;
|
||||||
@@ -571,6 +691,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
case GL_PIXEL_UNPACK_BUFFER_BINDING:
|
case GL_PIXEL_UNPACK_BUFFER_BINDING:
|
||||||
*params = 0; // TODO
|
*params = 0; // TODO
|
||||||
break;
|
break;
|
||||||
|
case GL_PARAMETER_BUFFER_BINDING_ARB: {
|
||||||
|
auto& obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Parameter).GetBoundObject();
|
||||||
|
*params = obj ? static_cast<GLint>(obj->GetExternalIndex()) : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case GL_POINT_FADE_THRESHOLD_SIZE:
|
case GL_POINT_FADE_THRESHOLD_SIZE:
|
||||||
*params = 0; // TODO
|
*params = 0; // TODO
|
||||||
break;
|
break;
|
||||||
@@ -587,11 +712,16 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
*params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ProgramPointSize) ? GL_TRUE : GL_FALSE;
|
*params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ProgramPointSize) ? GL_TRUE : GL_FALSE;
|
||||||
break;
|
break;
|
||||||
case GL_PROVOKING_VERTEX:
|
case GL_PROVOKING_VERTEX:
|
||||||
*params = 0; // TODO
|
*params = static_cast<GLint>(
|
||||||
|
MG_Util::ConvertProvokingVertexModeToGLEnum(MG_State::pGLContext->GetProvokingVertexMode()));
|
||||||
break;
|
break;
|
||||||
case GL_POINT_SIZE:
|
case GL_POINT_SIZE:
|
||||||
*params = 0; // TODO
|
*params = 0; // TODO
|
||||||
break;
|
break;
|
||||||
|
case GL_POLYGON_MODE:
|
||||||
|
params[0] = GL_FILL;
|
||||||
|
params[1] = GL_FILL;
|
||||||
|
break;
|
||||||
case GL_POINT_SIZE_GRANULARITY:
|
case GL_POINT_SIZE_GRANULARITY:
|
||||||
*params = 0; // TODO
|
*params = 0; // TODO
|
||||||
break;
|
break;
|
||||||
@@ -659,11 +789,13 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
case GL_SHADER_COMPILER:
|
case GL_SHADER_COMPILER:
|
||||||
*params = 0; // TODO
|
*params = 0; // TODO
|
||||||
break;
|
break;
|
||||||
case GL_SHADER_STORAGE_BUFFER_BINDING:
|
case GL_SHADER_STORAGE_BUFFER_BINDING: {
|
||||||
*params = 0; // TODO
|
auto& obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::ShaderStorage).GetBoundObject();
|
||||||
|
*params = obj ? static_cast<GLint>(obj->GetExternalIndex()) : 0;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT:
|
case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT:
|
||||||
*params = 0; // TODO
|
*params = 256; // TODO: use backend value
|
||||||
break;
|
break;
|
||||||
case GL_SHADER_STORAGE_BUFFER_START:
|
case GL_SHADER_STORAGE_BUFFER_START:
|
||||||
*params = 0; // TODO
|
*params = 0; // TODO
|
||||||
@@ -884,7 +1016,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
default:
|
default:
|
||||||
MGLOG_E("glGetIntegerv: Invalid enum %s (0x%X)", MG_Util::ConvertGLEnumToString(pname).c_str(), pname);
|
MGLOG_E("glGetIntegerv: Invalid enum %s (0x%X)", MG_Util::ConvertGLEnumToString(pname).c_str(), pname);
|
||||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv",
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv",
|
||||||
std::format("Invalid enum: 0x{:X}", pname)));
|
std::format("Invalid enum: 0x{:X}", pname)));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -892,7 +1024,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GLenum GetError() {
|
GLenum GetError() {
|
||||||
ErrorCode errorCode = MG_State::pGLContext->PopGLError().value_or(Error{ErrorCode::NoError, nullptr}).code;
|
auto error = MG_State::pGLContext->PopGLError();
|
||||||
return MG_Util::ConvertErrorCodeToGLEnum(errorCode);
|
if (!error || !error->get()) {
|
||||||
|
return GL_NO_ERROR;
|
||||||
|
}
|
||||||
|
return MG_Util::ConvertErrorCodeToGLEnum(error->get()->code);
|
||||||
}
|
}
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
|
|||||||
@@ -14,5 +14,8 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
const GLubyte* GetString(GLenum name);
|
const GLubyte* GetString(GLenum name);
|
||||||
const GLubyte* GetStringi(GLenum name, GLuint index);
|
const GLubyte* GetStringi(GLenum name, GLuint index);
|
||||||
void GetIntegerv(GLenum pname, GLint* params);
|
void GetIntegerv(GLenum pname, GLint* params);
|
||||||
|
void GetInteger64v(GLenum pname, GLint64* data);
|
||||||
|
void GetIntegeri_v(GLenum target, GLuint index, GLint* data);
|
||||||
|
void GetInteger64i_v(GLenum target, GLuint index, GLint64* data);
|
||||||
GLenum GetError();
|
GLenum GetError();
|
||||||
} // namespace MobileGL::MG_Impl::GLImpl
|
} // namespace MobileGL::MG_Impl::GLImpl
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user