mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
Compare commits
70
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 | ||
|
|
407d4344c4 | ||
|
|
76e3950028 | ||
|
|
7337b00ca8 | ||
|
|
22582dea3e | ||
|
|
f600a07404 | ||
|
|
ff790e1ff1 | ||
|
|
a345369269 | ||
|
|
8e4a4359b4 | ||
|
|
0a000d1628 | ||
|
|
5bd8e369c4 | ||
|
|
777d756d1b | ||
|
|
7716a8e05d | ||
|
|
94e93b171c | ||
|
|
1bf12be278 | ||
|
|
99b753be9a | ||
|
|
bc2f2d896b | ||
|
|
659fbf26da | ||
|
|
f61a7bb9c0 | ||
|
|
212309083a | ||
|
|
c1ebd01a70 | ||
|
|
af58e2c7b4 |
@@ -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
|
||||
+4
-1
@@ -18,4 +18,7 @@ MobileGL/MG_Test/build
|
||||
/cmake-build*
|
||||
.idea
|
||||
MobileGL/MG*/build*
|
||||
MobileGL/MG*/cmake-build*
|
||||
MobileGL/MG*/cmake-build*
|
||||
/android-plugin/.gradle
|
||||
/android-plugin/build
|
||||
/android-plugin/app/build
|
||||
|
||||
@@ -179,6 +179,7 @@ set(SOURCE_FILES
|
||||
MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp
|
||||
MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.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/BackendLoaders/OpenGL/Loader.cpp
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ namespace MobileGL::MG_Config {
|
||||
inline const String ProjectName = "MobileGL";
|
||||
inline const String CoreName = "MobileGL Core";
|
||||
inline const String CoreVendor = "MobileGL-Dev (BZLZHH, Swung0x48, Tungsten)";
|
||||
inline const Version CoreVersion = {26, 3, 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 Uint64 CacheVersion = 0;
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
extern char** environ;
|
||||
#endif
|
||||
|
||||
namespace MobileGL::MG_ConfigLoader {
|
||||
static UniquePtr<UnorderedMap<String, String>> acceptedEnvVariablesMap;
|
||||
|
||||
|
||||
+14
-8
@@ -34,7 +34,9 @@
|
||||
#define MOBILEGL_EGL_API MOBILEGL_API
|
||||
|
||||
// ====================== MobileGL configurations ======================= //
|
||||
#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_FILE 1
|
||||
@@ -63,11 +65,15 @@
|
||||
#endif
|
||||
|
||||
// =============================== Utils ================================ //
|
||||
#define MOBILEGL_ASSERT(condition, ...) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
MGLOG_F("Assertion failed" __VA_OPT__(": ") __VA_ARGS__); \
|
||||
MGLOG_F(" at %s:%d (%s)", __FILE__, __LINE__, __func__); \
|
||||
TRAP; \
|
||||
} \
|
||||
} while (0)
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||
#define MOBILEGL_ASSERT(condition, ...) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
MGLOG_F("Assertion failed" __VA_OPT__(": ") __VA_ARGS__); \
|
||||
MGLOG_F(" at %s:%d (%s)", __FILE__, __LINE__, __func__); \
|
||||
TRAP; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define MOBILEGL_ASSERT(condition, ...)
|
||||
#endif
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <numeric>
|
||||
@@ -108,10 +110,32 @@
|
||||
#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>
|
||||
#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
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
@@ -53,7 +53,8 @@ namespace MobileGL::MG_Backend {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_eglWindowSurfaceInitialized && m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle) {
|
||||
if (m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Window &&
|
||||
m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -63,7 +64,35 @@ namespace MobileGL::MG_Backend {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_eglWindowSurfaceInitialized = true;
|
||||
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;
|
||||
@@ -81,8 +110,8 @@ namespace MobileGL::MG_Backend {
|
||||
MGLOG_E("MakeEGLCurrent failed: EGL display mismatch or not initialized");
|
||||
return false;
|
||||
}
|
||||
if (!m_eglWindowSurfaceInitialized) {
|
||||
MGLOG_E("MakeEGLCurrent failed: EGL window surface is not initialized");
|
||||
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) {
|
||||
@@ -104,8 +133,9 @@ namespace MobileGL::MG_Backend {
|
||||
|
||||
void BackendObject::ResetEGLRuntimeState() {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||
m_eglWindowSurfaceInitialized = false;
|
||||
m_eglSurfaceInitialized = false;
|
||||
m_backendCapabilitiesInitialized = false;
|
||||
m_eglSurfaceKind = SurfaceKind::None;
|
||||
m_eglCurrentThreads.clear();
|
||||
}
|
||||
|
||||
@@ -119,7 +149,7 @@ namespace MobileGL::MG_Backend {
|
||||
MGLOG_E("SwapEGLBuffers failed: no current context attached");
|
||||
return false;
|
||||
}
|
||||
if (!m_eglWindowSurfaceInitialized || draw == EGL_NO_SURFACE) {
|
||||
if (!m_eglSurfaceInitialized || draw == EGL_NO_SURFACE) {
|
||||
MGLOG_E("SwapEGLBuffers failed: invalid draw surface");
|
||||
return false;
|
||||
}
|
||||
@@ -134,8 +164,22 @@ namespace MobileGL::MG_Backend {
|
||||
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) {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||
m_windowHandle = handle;
|
||||
}
|
||||
|
||||
Bool BackendObject::InitPbufferSurface(EGLint width, EGLint height) {
|
||||
(void)width;
|
||||
(void)height;
|
||||
return false;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend
|
||||
|
||||
@@ -8,8 +8,14 @@
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include "MG_State/GLState/TextureState/TextureEnum.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State::GLState {
|
||||
class FramebufferObject;
|
||||
class ITextureObject;
|
||||
}
|
||||
|
||||
enum class BackendType {
|
||||
DirectGLES,
|
||||
DirectVulkan,
|
||||
@@ -31,6 +37,10 @@ namespace MobileGL {
|
||||
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 (*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,
|
||||
const void* indices, GLint basevertex);
|
||||
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 (*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>& 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,
|
||||
GLsizei height, GLint border);
|
||||
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* 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 {
|
||||
GLFunctionsTable GL;
|
||||
@@ -72,10 +112,16 @@ namespace MobileGL {
|
||||
|
||||
struct DynamicBackendParameters {
|
||||
SizeT UniformBufferOffsetAlignment = 256;
|
||||
SizeT MaxShaderStorageBlockSize = 128 * 1024 * 1024;
|
||||
Uint32 SubgroupSize = 0;
|
||||
Uint32 SubgroupSupportedStages = 0;
|
||||
Uint32 SubgroupSupportedFeatures = 0;
|
||||
Bool SubgroupQuadOperationsInAllStages = false;
|
||||
};
|
||||
|
||||
enum class WindowBackend {
|
||||
Android,
|
||||
X11,
|
||||
// TODO: X11, Wayland, Windows, macOS, etc.
|
||||
WindowBackendCount,
|
||||
Unknown = -1
|
||||
@@ -96,8 +142,10 @@ namespace MobileGL {
|
||||
|
||||
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);
|
||||
|
||||
@@ -108,14 +156,22 @@ namespace MobileGL {
|
||||
virtual BackendType GetBackendType() const = 0;
|
||||
|
||||
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;
|
||||
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
|
||||
Bool m_eglDisplayInitialized = false;
|
||||
Bool m_eglWindowSurfaceInitialized = false;
|
||||
Bool m_eglSurfaceInitialized = false;
|
||||
Bool m_backendCapabilitiesInitialized = false;
|
||||
SurfaceKind m_eglSurfaceKind = SurfaceKind::None;
|
||||
UnorderedMap<std::thread::id, Bool> m_eglCurrentThreads;
|
||||
};
|
||||
} // namespace MG_Backend
|
||||
|
||||
@@ -78,18 +78,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (handle.Backend != WindowBackend::Android || !handle.Handle) {
|
||||
MGLOG_E("DirectGLES backend only supports Android native windows");
|
||||
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_eglWindowSurfaceInitialized && m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
|
||||
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_eglWindowSurfaceInitialized) {
|
||||
if (m_eglSurfaceInitialized) {
|
||||
DestroyEGLContext();
|
||||
ResetEGLRuntimeState();
|
||||
}
|
||||
@@ -97,6 +97,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
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);
|
||||
@@ -109,6 +113,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
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 {
|
||||
static RendererInfo RendererInfo = {
|
||||
.RendererName = "Espryt", // Renderer Name
|
||||
@@ -119,7 +129,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
.TargetGLVersion = {3, 3, 0}, // Target OpenGL Version
|
||||
.TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version
|
||||
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
|
||||
V_OpenGL33, E_GL_ARB_draw_buffers_blend},
|
||||
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
|
||||
},
|
||||
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
|
||||
@@ -153,6 +169,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
funcsTable.GL.MultiDrawElements = MultiDrawElements;
|
||||
funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex;
|
||||
funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect;
|
||||
funcsTable.GL.MultiDrawElementsIndirectCount = MultiDrawElementsIndirectCount;
|
||||
funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect;
|
||||
funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex;
|
||||
funcsTable.GL.DrawRangeElements = DrawRangeElements;
|
||||
@@ -164,12 +181,30 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
funcsTable.GL.DrawArraysInstanced = DrawArraysInstanced;
|
||||
funcsTable.GL.DrawElementsIndirect = DrawElementsIndirect;
|
||||
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.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;
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
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;
|
||||
String GetBackendAPIVersionString() const override;
|
||||
@@ -35,6 +36,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
private:
|
||||
void UpdateDynamicBackendParameters();
|
||||
Bool InitPbufferSurface(EGLint width, EGLint height) override;
|
||||
|
||||
Bool m_initialized = false;
|
||||
MG_External::EGLFunctionsTable m_EGLFunctions;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
||||
#include <MG_State/GLState/TextureState/TextureState.h>
|
||||
#include <MG_State/GLState/SamplerState/SamplerObject.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,
|
||||
GLsizei drawcount, const GLint* basevertex);
|
||||
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 DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||
const void* indices, GLint basevertex);
|
||||
@@ -46,8 +49,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
GLuint baseinstance);
|
||||
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
||||
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,
|
||||
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,
|
||||
GLsizei height, GLint border);
|
||||
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);
|
||||
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 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 InitPbufferSurface(EGLint width, EGLint height);
|
||||
void Present();
|
||||
void SetEGLFuncsTable(const MG_External::EGLFunctionsTable& eglFuncs);
|
||||
void SetGLESFuncsTable(const MG_External::GLESFunctionsTable& glesFuncs);
|
||||
|
||||
@@ -23,9 +23,63 @@
|
||||
#include <MG_Util/Converters/GLToMG/FramebufferEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
|
||||
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
||||
#include <cctype>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
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 {
|
||||
BackendBufferObject::BackendBufferObject() {
|
||||
@@ -194,10 +248,34 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
} // namespace BufferImpl
|
||||
|
||||
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() {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
m_clientAttributeBufferIds.fill(0);
|
||||
g_GLESFuncs.glGenVertexArrays(1, &m_backendVAOId);
|
||||
if (m_backendVAOId == 0) {
|
||||
MGLOG_E("Failed to generate vertex array object.");
|
||||
@@ -207,6 +285,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
@@ -214,21 +305,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_GLESFuncs.glBindVertexArray(m_backendVAOId);
|
||||
}
|
||||
|
||||
inline void BindAttributeBuffer(const MG_State::GLState::VertexAttribute& attrib) {
|
||||
inline Bool BindAttributeBuffer(const MG_State::GLState::VertexAttribute& attrib) {
|
||||
const auto& bufferObject = attrib.Buffer;
|
||||
if (!bufferObject) {
|
||||
MGLOG_W("Attribute has no bound buffer, skipping.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObject.get());
|
||||
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
|
||||
MGLOG_E("No backend buffer found for attribute's buffer, cannot bind attribute.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
const auto& backendBufferObject = backendBufferIt->second;
|
||||
|
||||
backendBufferObject->Bind(GL_ARRAY_BUFFER);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BackendVertexArrayObject::SyncToBackend(
|
||||
@@ -266,7 +358,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
m_syncedAttributeVersions[attribIndex].BufferVersion;
|
||||
if (!needsSyncFormat && !needsSyncBuffer) continue;
|
||||
|
||||
BindAttributeBuffer(attrib);
|
||||
if (!BindAttributeBuffer(attrib)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!attrib.IsInteger) {
|
||||
g_GLESFuncs.glVertexAttribPointer(
|
||||
@@ -286,21 +380,81 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Uint16 currentIndexBufferVersion = stateVAOObject->GetIndexBufferBindingSlot().GetVersion();
|
||||
if (currentIndexBufferVersion != m_syncedIndexBufferVersion) {
|
||||
const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
|
||||
Bool indexBufferSynced = false;
|
||||
if (indexBufferBinding) {
|
||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding.get());
|
||||
if (backendBufferIt != BufferImpl::g_backendBufferObjects.end()) {
|
||||
const auto& backendBufferObject = backendBufferIt->second;
|
||||
backendBufferObject->Bind(GL_ELEMENT_ARRAY_BUFFER);
|
||||
indexBufferSynced = true;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
} // namespace VertexArrayImpl
|
||||
@@ -518,13 +672,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
static_cast<MG_State::GLState::TextureObjectBuffer*>(stateTextureObject.get());
|
||||
auto& slot = textureBufferObject->GetBufferBindingSlot();
|
||||
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();
|
||||
currentTextureInfo.bufferExternalIndex = bufferIndex;
|
||||
|
||||
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
|
||||
auto& backendBuffers = BufferImpl::g_backendBufferObjects;
|
||||
@@ -548,7 +704,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
TextureImpl::GenerateTextureFormatInfo(textureBufferObject->GetFormat(), &glInternalFormat, &glFormat,
|
||||
&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;
|
||||
}
|
||||
default:
|
||||
@@ -637,7 +805,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
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(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(compareMode, GL_TEXTURE_COMPARE_MODE, CompareMode)
|
||||
if (m_cacheSamplerParameters.minLod != samplerParams.minLod) {
|
||||
@@ -790,17 +962,37 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId);
|
||||
}
|
||||
|
||||
void BackendFramebufferObject::InvalidateSyncedState() {
|
||||
std::fill(std::begin(m_frontendDrawBuffers), std::end(m_frontendDrawBuffers),
|
||||
FramebufferAttachmentType::Unknown);
|
||||
std::fill(std::begin(m_backendDrawBuffers), std::end(m_backendDrawBuffers), GL_NONE);
|
||||
m_frontendReadBuffer = FramebufferAttachmentType::Unknown;
|
||||
m_backendReadBuffer = GL_NONE;
|
||||
std::fill(m_syncedFrontendAttachmentVersions.begin(), m_syncedFrontendAttachmentVersions.end(),
|
||||
static_cast<Uint16>(~0u));
|
||||
}
|
||||
|
||||
static Bool SyncAttachmentObject(GLenum glFBOTarget,
|
||||
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
|
||||
GLenum glBackendAttachment) {
|
||||
if (attachmentObject.IsTexture()) {
|
||||
const auto& textureObject = attachmentObject.GetTexture();
|
||||
SharedPtr<TextureImpl::BackendTextureObject> backendTextureObject;
|
||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
||||
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__);
|
||||
return false;
|
||||
}
|
||||
const auto& backendTextureObject = backendTextureIt->second;
|
||||
backendTextureObject->SyncMipmapsToBackend(textureObject);
|
||||
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
|
||||
backendTextureObject->Bind(glTextureTarget);
|
||||
g_GLESFuncs.glFramebufferTexture2D(glFBOTarget, glBackendAttachment, glTextureTarget,
|
||||
@@ -908,8 +1100,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
// relevant FRONTEND!!! version should be checked and updated
|
||||
if (m_syncedFrontendAttachmentVersions[i] != attachmentVersions[i]) {
|
||||
SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment);
|
||||
m_syncedFrontendAttachmentVersions[i] = attachmentVersions[i];
|
||||
if (SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment)) {
|
||||
m_syncedFrontendAttachmentVersions[i] = attachmentVersions[i];
|
||||
}
|
||||
}
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||
else {
|
||||
@@ -921,6 +1114,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MG_Util::ConvertFramebufferAttachmentTypeToString(frontendType).c_str(),
|
||||
MG_Util::ConvertGLEnumToString(glBackendAttachment).c_str(),
|
||||
m_syncedFrontendAttachmentVersions[i]);
|
||||
if (!attachmentObject.IsTexture() && !attachmentObject.IsRenderbuffer()) {
|
||||
continue;
|
||||
}
|
||||
GLint objectType = GL_NONE;
|
||||
g_GLESFuncs.glGetFramebufferAttachmentParameteriv(
|
||||
glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &objectType);
|
||||
@@ -1081,8 +1277,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
spvc_compiler_options options;
|
||||
spvcSession.CreateOptions(&options);
|
||||
|
||||
// TODO: check ESSL version supported by backend driver
|
||||
spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, 320);
|
||||
spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION,
|
||||
ResolveBackendEsslVersion());
|
||||
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);
|
||||
|
||||
@@ -1104,6 +1300,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
source = RemoveLayoutBinding(source);
|
||||
source = ProcessOutColorLocations(source);
|
||||
source = ForceFlatIntegerVaryings(source, glShaderType);
|
||||
source = EmulateBaseInstanceInVertexShader(std::move(source), glShaderType);
|
||||
source = ForceSupporterOutput(source);
|
||||
|
||||
// Patch for Photon compiler precision issue
|
||||
@@ -1154,6 +1352,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
} else {
|
||||
MGLOG_D("Program linked successfully. ID: %u", m_backendProgramId);
|
||||
}
|
||||
m_baseInstanceUniformLocation = g_GLESFuncs.glGetUniformLocation(m_backendProgramId,
|
||||
BASE_INSTANCE_UNIFORM_NAME);
|
||||
|
||||
// Create global UBO
|
||||
if (stateProgramObject->GetUBOSize() > 0) {
|
||||
@@ -1176,6 +1376,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MGLOG_D("Using program %u", 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 SamplerImpl {
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <MG_State/GLState/Core.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
String EmulateBaseInstanceInVertexShader(String source, GLenum shaderType);
|
||||
|
||||
template <typename StateObject, typename BackendObject>
|
||||
class StateBackendObjectRegistry {
|
||||
public:
|
||||
@@ -137,12 +139,16 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
class BackendVertexArrayObject {
|
||||
public:
|
||||
BackendVertexArrayObject();
|
||||
~BackendVertexArrayObject();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
|
||||
void SyncClientSideAttributesForDrawArrays(
|
||||
const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject, GLint first, GLsizei count);
|
||||
Uint GetBackendVertexArrayId() const { return m_backendVAOId; }
|
||||
void Bind() const;
|
||||
|
||||
private:
|
||||
Uint m_backendVAOId = 0;
|
||||
Array<Uint, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS> m_clientAttributeBufferIds;
|
||||
Bool m_isInitialized = false;
|
||||
Uint16 m_syncedIndexBufferVersion = 0;
|
||||
Array<MG_State::GLState::VertexAttributeVersion, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS>
|
||||
@@ -162,6 +168,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Bool SupportsWrapR(TextureTarget target) {
|
||||
return target == TextureTarget::Texture3D || target == TextureTarget::TextureCubeMap;
|
||||
}
|
||||
|
||||
struct StateTextureBasicInfo { // Used for tracking texture state changes
|
||||
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
|
||||
SizeT width = 0;
|
||||
@@ -218,6 +228,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
BackendFramebufferObject();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
|
||||
FramebufferTarget asTarget);
|
||||
void InvalidateSyncedState();
|
||||
Uint GetBackendFramebufferId() const { return m_backendFBOId; }
|
||||
void Bind(FramebufferTarget target) const;
|
||||
// FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index);
|
||||
@@ -259,12 +270,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
~BackendProgramObjectImpl();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject);
|
||||
void Use() const;
|
||||
void SetBaseInstance(Uint32 baseInstance) const;
|
||||
Uint GetBackendProgramId() const { return m_backendProgramId; }
|
||||
Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; }
|
||||
|
||||
private:
|
||||
Uint m_backendProgramId = 0;
|
||||
Uint m_backendGlobalUBOId = 0;
|
||||
Int m_baseInstanceUniformLocation = -1;
|
||||
Bool m_isInitialized = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -101,6 +101,37 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
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) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
namespace PrgramImpl {
|
||||
String ProcessOutColorLocations(const String& glslCode);
|
||||
String ForceSupporterOutput(const String& glslCode);
|
||||
String ForceFlatIntegerVaryings(const String& glslCode, GLenum shaderType);
|
||||
String RemoveLayoutBinding(const String& glslCode);
|
||||
} // namespace PrgramImpl
|
||||
|
||||
|
||||
@@ -19,6 +19,27 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
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");
|
||||
@@ -47,8 +68,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return false;
|
||||
}
|
||||
|
||||
MG_Util::BackendLoader::FillInVulkanCapabilities(m_vulkanCaps, pVulkanRenderer->GetPhysicalDevice().properties);
|
||||
const auto& physicalDevice = pVulkanRenderer->GetPhysicalDevice();
|
||||
if (!MG_Util::BackendLoader::QueryVulkanCapabilities(m_vulkanCaps, pVulkanRenderer->GetInstance(),
|
||||
physicalDevice.handle)) {
|
||||
MGLOG_W("DirectVulkan: failed to query extended Vulkan capabilities, using basic properties");
|
||||
MG_Util::BackendLoader::FillInVulkanCapabilities(m_vulkanCaps, physicalDevice.properties);
|
||||
}
|
||||
UpdateDynamicBackendParameters();
|
||||
UpdateAdvertisedExtensions();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -66,18 +93,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
MGLOG_E("DirectVulkan backend not initialized");
|
||||
return false;
|
||||
}
|
||||
if (handle.Backend != WindowBackend::Android || !handle.Handle) {
|
||||
MGLOG_E("DirectVulkan backend only supports Android native windows");
|
||||
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_eglWindowSurfaceInitialized && m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
|
||||
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_eglWindowSurfaceInitialized || pVulkanRenderer) {
|
||||
if (m_eglSurfaceInitialized || pVulkanRenderer) {
|
||||
pVulkanRenderer.reset();
|
||||
ResetEGLRuntimeState();
|
||||
}
|
||||
@@ -106,22 +133,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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 {
|
||||
static RendererInfo RendererInfo = {
|
||||
.RendererName = "Magma", // Renderer Name
|
||||
.BackendName = "Direct (Vulkan)", // Backend Name
|
||||
.ExtraVendor = Nullopt, // Extra vendor
|
||||
.RendererGLInfo =
|
||||
{
|
||||
.TargetGLVersion = {3, 3, 0}, // Target OpenGL Version
|
||||
.TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version
|
||||
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
|
||||
V_OpenGL33},
|
||||
.IsCompatibilityProfile = false // Is Compatibility Profile
|
||||
},
|
||||
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
|
||||
};
|
||||
return RendererInfo;
|
||||
return m_rendererInfo;
|
||||
}
|
||||
|
||||
String BackendObject_DirectVulkan::GetBackendAPIVersionString() const {
|
||||
@@ -151,6 +170,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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;
|
||||
@@ -166,12 +187,31 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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;
|
||||
@@ -181,7 +221,85 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
class BackendObject_DirectVulkan : public BackendObject {
|
||||
public:
|
||||
BackendObject_DirectVulkan();
|
||||
~BackendObject_DirectVulkan() override;
|
||||
|
||||
void Initialize() override;
|
||||
@@ -23,18 +24,22 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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;
|
||||
String GetBackendAPIVersionString() const override;
|
||||
const GlobalBackendFunctionsTable& GetBackendFunctions() const override;
|
||||
const DynamicBackendParameters& GetDynamicParameters() const override;
|
||||
BackendType GetBackendType() const override;
|
||||
void ApplyVulkanCapabilitiesForTesting(const MG_External::VulkanCapabilities& capabilities);
|
||||
|
||||
private:
|
||||
void UpdateAdvertisedExtensions();
|
||||
void UpdateDynamicBackendParameters();
|
||||
|
||||
Bool m_initialized = false;
|
||||
DynamicBackendParameters m_dynamicParameters;
|
||||
MG_External::VulkanCapabilities m_vulkanCaps;
|
||||
RendererInfo m_rendererInfo;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -7,19 +7,267 @@
|
||||
// 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;
|
||||
|
||||
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) {}
|
||||
namespace {
|
||||
struct BufferVariableResource {
|
||||
String name;
|
||||
GLuint blockIndex = 0;
|
||||
GLint offset = 0;
|
||||
GLint size = 0;
|
||||
};
|
||||
|
||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {}
|
||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {}
|
||||
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) {}
|
||||
@@ -36,12 +284,359 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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) {}
|
||||
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) {}
|
||||
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) {}
|
||||
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");
|
||||
@@ -164,6 +759,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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();
|
||||
|
||||
@@ -17,6 +17,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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 Clear(GLbitfield mask);
|
||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
||||
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
||||
@@ -27,6 +31,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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 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,
|
||||
const void* indices, GLint basevertex);
|
||||
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
|
||||
@@ -44,12 +52,37 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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 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,
|
||||
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 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 GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
|
||||
void GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget uploadTarget,
|
||||
GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid* pixels);
|
||||
void Present();
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -178,9 +178,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
packet.signalSemaphore = m_swapchainImageRenderFinishedSemaphores[swapchainImageIndex];
|
||||
packet.commandBuffer = frame.commandBuffer;
|
||||
|
||||
packet.submitInfo.waitSemaphoreCount = 1;
|
||||
packet.submitInfo.pWaitSemaphores = &packet.waitSemaphore;
|
||||
packet.submitInfo.pWaitDstStageMask = &packet.waitDstStageMask;
|
||||
packet.submitInfo.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;
|
||||
@@ -217,6 +217,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return result;
|
||||
}
|
||||
|
||||
frame.imageAvailableSemaphoreConsumed = false;
|
||||
return vkAcquireNextImageKHR(device, swapchain, timeout, frame.imageAvailableSemaphore, acquireFence,
|
||||
&outImageIndex);
|
||||
}
|
||||
@@ -260,6 +261,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
frame.hasCommandBufferRecorded = false;
|
||||
frame.isCommandRecording = false;
|
||||
frame.imageAvailableSemaphoreConsumed = false;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -277,5 +279,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
frame.imageAvailableSemaphore = VK_NULL_HANDLE;
|
||||
frame.isCommandRecording = false;
|
||||
frame.hasCommandBufferRecorded = false;
|
||||
frame.imageAvailableSemaphoreConsumed = false;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkFence imageInFlightFence = VK_NULL_HANDLE;
|
||||
Bool isCommandRecording = false;
|
||||
Bool hasCommandBufferRecorded = false;
|
||||
Bool imageAvailableSemaphoreConsumed = false;
|
||||
};
|
||||
|
||||
VkResult Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount);
|
||||
|
||||
@@ -9,8 +9,21 @@
|
||||
#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 {
|
||||
@@ -19,6 +32,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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)));
|
||||
@@ -26,12 +40,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthTestEnable, sizeof(payload.depthTestEnable)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthWriteEnable, sizeof(payload.depthWriteEnable)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthCompareOp, sizeof(payload.depthCompareOp)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.blendEnable, sizeof(payload.blendEnable)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.srcColorBlendFactor, sizeof(payload.srcColorBlendFactor)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.dstColorBlendFactor, sizeof(payload.dstColorBlendFactor)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.srcAlphaBlendFactor, sizeof(payload.srcAlphaBlendFactor)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.dstAlphaBlendFactor, sizeof(payload.dstAlphaBlendFactor)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.colorWriteMask, sizeof(payload.colorWriteMask)));
|
||||
if (payload.colorAttachmentCount > 0) {
|
||||
XXHASH_VERIFY(XXH64_update(
|
||||
m_hashState,
|
||||
payload.colorBlendAttachments.data(),
|
||||
sizeof(payload.colorBlendAttachments[0]) * payload.colorAttachmentCount));
|
||||
}
|
||||
return XXH64_digest(m_hashState);
|
||||
}
|
||||
|
||||
@@ -61,6 +75,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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,
|
||||
@@ -95,18 +117,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
depthStencil.depthBoundsTestEnable = VK_FALSE;
|
||||
depthStencil.stencilTestEnable = VK_FALSE;
|
||||
|
||||
VkPipelineColorBlendAttachmentState colorAttach{};
|
||||
colorAttach.colorWriteMask = payload.colorWriteMask;
|
||||
colorAttach.blendEnable = payload.blendEnable ? VK_TRUE : VK_FALSE;
|
||||
colorAttach.srcColorBlendFactor = payload.srcColorBlendFactor;
|
||||
colorAttach.dstColorBlendFactor = payload.dstColorBlendFactor;
|
||||
colorAttach.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
colorAttach.srcAlphaBlendFactor = payload.srcAlphaBlendFactor;
|
||||
colorAttach.dstAlphaBlendFactor = payload.dstAlphaBlendFactor;
|
||||
colorAttach.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
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 = 1;
|
||||
blend.pAttachments = &colorAttach;
|
||||
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());
|
||||
@@ -124,7 +141,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
gpi.subpass = payload.subpass;
|
||||
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
VK_VERIFY(vkCreateGraphicsPipelines(m_device, VK_NULL_HANDLE, 1, &gpi, nullptr, &pipeline),
|
||||
VK_VERIFY(vkCreateGraphicsPipelines(m_device, m_pipelineCache, 1, &gpi, nullptr, &pipeline),
|
||||
"vkCreateGraphicsPipelines");
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "Config.h"
|
||||
#include "../VkIncludes.h"
|
||||
#include "MG_State/GLState/FramebufferState/FramebufferObject.h"
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
@@ -18,10 +19,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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;
|
||||
@@ -29,20 +33,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool depthTestEnable = false;
|
||||
Bool depthWriteEnable = false;
|
||||
VkCompareOp depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
Bool blendEnable = false;
|
||||
VkBlendFactor srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
VkBlendFactor dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
VkBlendFactor srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
VkBlendFactor dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
VkColorComponentFlags colorWriteMask =
|
||||
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
Array<VkPipelineColorBlendAttachmentState, kMaxColorAttachments> colorBlendAttachments{};
|
||||
const Vector<VkPipelineShaderStageCreateInfo>* stages = nullptr;
|
||||
const VkPipelineVertexInputStateCreateInfo* vertexInputState = nullptr;
|
||||
};
|
||||
|
||||
explicit PipelineFactory(VkDevice device, const VulkanRendererConfig& config):
|
||||
m_device(device), m_config(config) {}
|
||||
explicit PipelineFactory(VkDevice device, const VulkanRendererConfig& config);
|
||||
~PipelineFactory();
|
||||
PipelineFactory(const PipelineFactory&) = delete;
|
||||
|
||||
@@ -55,6 +51,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
enum class DescriptorBindingKind : Uint8 {
|
||||
None = 0,
|
||||
UniformBufferDynamic,
|
||||
CombinedImageSampler
|
||||
CombinedImageSampler,
|
||||
UniformTexelBuffer,
|
||||
StorageBuffer,
|
||||
StorageImage
|
||||
};
|
||||
|
||||
enum class CompileOptionBit : Uint {
|
||||
@@ -36,6 +39,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
using HashType = Uint64;
|
||||
|
||||
struct VkProgramObject {
|
||||
static constexpr Uint32 kMaxVertexInputLocations = 32;
|
||||
|
||||
HashType hash = 0;
|
||||
Vector<VkPipelineShaderStageCreateInfo> stages;
|
||||
Vector<VkShaderModule> modules;
|
||||
@@ -45,9 +50,20 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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;
|
||||
|
||||
@@ -62,13 +78,29 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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) {
|
||||
@@ -82,13 +114,29 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -132,13 +180,28 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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 ReflectLayout(const MG_State::GLState::ProgramObject& program, VkProgramObject& entry) const;
|
||||
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
|
||||
|
||||
@@ -290,7 +290,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
imageInfo.format = m_depthStencilFormat;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
imageInfo.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)");
|
||||
|
||||
@@ -8,12 +8,24 @@
|
||||
|
||||
#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) {
|
||||
@@ -53,6 +65,26 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -109,6 +141,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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);
|
||||
@@ -133,11 +172,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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(
|
||||
@@ -147,13 +193,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
frame.activeDescriptorPoolIndex = 0;
|
||||
frame.allocatedSetsThisFrame = 0;
|
||||
frame.peakAllocatedSetsThisFrame = 0;
|
||||
for (auto& bucket : frame.descriptorPools) {
|
||||
bucket.allocatedSets = 0;
|
||||
if (bucket.handle == VK_NULL_HANDLE) {
|
||||
continue;
|
||||
}
|
||||
VK_VERIFY(vkResetDescriptorPool(m_device, bucket.handle, 0),
|
||||
"UniformDescriptorBinder::BeginFrame, vkResetDescriptorPool");
|
||||
for (auto& cacheEntryPair : frame.descriptorSetCacheByLayout) {
|
||||
cacheEntryPair.second.cursor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,29 +202,49 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramObject& programObj,
|
||||
Uint32 binding, VkDescriptorImageInfo& outImageInfo) const {
|
||||
(void)commandBuffer;
|
||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptor: texture manager is null");
|
||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptor: sampler manager is null");
|
||||
MOBILEGL_ASSERT(binding < programObj.samplerNameByBinding.size(),
|
||||
"ResolveSamplerDescriptor: sampler binding %u name lookup out of range", binding);
|
||||
SharedPtr<MG_State::GLState::ITextureObject> texture;
|
||||
if (!ResolveSamplerTexture(program, programObj, binding, 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 = program.GetUniformSamplerOrImageUnitIndex(static_cast<Uint>(location));
|
||||
const Int unit = ResolveSamplerUnitIndex(program, location, binding);
|
||||
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
||||
const auto samplerOverride = textureUnit.GetSamplerObject();
|
||||
if (!texture) {
|
||||
return false;
|
||||
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) {
|
||||
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)) {
|
||||
@@ -192,25 +253,48 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Int attachmentLevel = 0;
|
||||
if (drawFbo &&
|
||||
FindFramebufferAttachmentForTexture(*drawFbo, *texture, attachmentType, attachmentLevel)) {
|
||||
MOBILEGL_ASSERT(false,
|
||||
"ResolveSamplerDescriptor: framebuffer feedback loop detected: textureId=%d is bound "
|
||||
"for sampling at binding=%u, but is also attached to drawFbo=%u as %s (level=%d, "
|
||||
"trackedLayout=%d)",
|
||||
texture->GetExternalIndex(), binding, drawFbo->GetExternalIndex(),
|
||||
MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(),
|
||||
attachmentLevel, static_cast<Int>(resource->layout));
|
||||
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));
|
||||
}
|
||||
|
||||
MOBILEGL_ASSERT(false,
|
||||
const Bool readyForSampling = m_textureManager->TransitionTextureForSampling(commandBuffer, *texture);
|
||||
if (!readyForSampling) {
|
||||
MGLOG_E("ResolveSamplerDescriptor: failed to transition textureId=%d for sampler binding=%u",
|
||||
texture->GetExternalIndex(), binding);
|
||||
return false;
|
||||
}
|
||||
resource = m_textureManager->SyncTextureAndGetDescriptor(*texture);
|
||||
MOBILEGL_ASSERT(resource != nullptr,
|
||||
"ResolveSamplerDescriptor: failed to resync textureId=%d after sampling transition",
|
||||
texture->GetExternalIndex());
|
||||
MOBILEGL_ASSERT(IsValidSampledImageLayout(resource->layout),
|
||||
"ResolveSamplerDescriptor: invalid sampled image layout=%d for textureId=%d, binding=%u",
|
||||
static_cast<Int>(resource->layout), texture->GetExternalIndex(), binding);
|
||||
return false;
|
||||
}
|
||||
outImageInfo = {
|
||||
.sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse),
|
||||
.imageView = resource->fullView,
|
||||
.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;
|
||||
}
|
||||
|
||||
@@ -218,18 +302,28 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const SamplerBindingOverride& samplerBindingOverride, VkDescriptorImageInfo& outImageInfo) const {
|
||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptorOverride: texture manager is null");
|
||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptorOverride: sampler manager is null");
|
||||
if (samplerBindingOverride.texture == nullptr || samplerBindingOverride.sampler == nullptr) {
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
if (resource == nullptr || !IsValidSampledImageLayout(resource->layout)) {
|
||||
return false;
|
||||
}
|
||||
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),
|
||||
.imageView = resource->fullView,
|
||||
.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;
|
||||
@@ -237,26 +331,224 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
Bool UniformManager::ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const {
|
||||
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) {
|
||||
outTexture.reset();
|
||||
if (!MG_State::pGLContext || binding >= programObj.samplerUniformLocationByBinding.size()) {
|
||||
return false;
|
||||
}
|
||||
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];
|
||||
if (location < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Int unit = program.GetUniformSamplerOrImageUnitIndex(static_cast<Uint>(location));
|
||||
if (unit < 0) {
|
||||
return false;
|
||||
}
|
||||
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 outTexture != nullptr;
|
||||
|
||||
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,
|
||||
@@ -284,62 +576,89 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool UniformManager::GatherBindingPayloads(const MG_State::GLState::ProgramObject& program,
|
||||
Vector<const void*>& outData,
|
||||
Vector<VkDeviceSize>& outSizes) const {
|
||||
outData.assign(m_maxBindings, nullptr);
|
||||
outSizes.assign(m_maxBindings, 0);
|
||||
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;
|
||||
|
||||
const Uint32 activeUniformBlockCount = static_cast<Uint32>(program.GetActiveUniformBlocksCount());
|
||||
const Uint32 uniformBindingPointCount =
|
||||
static_cast<Uint32>(MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform));
|
||||
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);
|
||||
|
||||
for (Uint32 blockIndex = 0; blockIndex < activeUniformBlockCount; ++blockIndex) {
|
||||
const Uint32 binding = program.GetUniformBlockBinding(blockIndex);
|
||||
if (binding >= m_maxBindings) {
|
||||
continue;
|
||||
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());
|
||||
}
|
||||
|
||||
VkDeviceSize blockSize = static_cast<VkDeviceSize>(program.GetUBOSizeAt(blockIndex));
|
||||
if (blockSize == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (binding >= uniformBindingPointCount) {
|
||||
continue;
|
||||
}
|
||||
auto& bindingPoint = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, binding);
|
||||
const auto bufferObject = bindingPoint.GetBoundObject();
|
||||
if (!bufferObject) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto bufferData = bufferObject->GetDataReadOnly();
|
||||
if (!bufferData || bufferData->empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto range = bindingPoint.GetRange();
|
||||
const VkDeviceSize bufferSize = static_cast<VkDeviceSize>(bufferObject->GetSize());
|
||||
VkDeviceSize rangeStart = static_cast<VkDeviceSize>(range.start);
|
||||
VkDeviceSize rangeEnd = static_cast<VkDeviceSize>(range.end);
|
||||
|
||||
if (rangeStart >= bufferSize) {
|
||||
continue;
|
||||
}
|
||||
if (rangeEnd <= rangeStart || rangeEnd > bufferSize) {
|
||||
rangeEnd = bufferSize;
|
||||
}
|
||||
|
||||
VkDeviceSize available = rangeEnd - rangeStart;
|
||||
if (available == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
outData[binding] = bufferData->data() + static_cast<SizeT>(rangeStart);
|
||||
outSizes[binding] = std::min(blockSize, available);
|
||||
return 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;
|
||||
}
|
||||
|
||||
@@ -356,11 +675,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
const Uint32 descriptorCount = static_cast<Uint32>(descriptorCount64);
|
||||
VkDescriptorPoolSize poolSizes[2]{};
|
||||
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;
|
||||
@@ -404,7 +729,26 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
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;
|
||||
@@ -414,17 +758,47 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkResult result = vkAllocateDescriptorSets(m_device, &allocInfo, &outDescriptorSet);
|
||||
if (result == VK_SUCCESS) {
|
||||
++bucket.allocatedSets;
|
||||
++frame.allocatedSetsThisFrame;
|
||||
frame.peakAllocatedSetsThisFrame =
|
||||
std::max(frame.peakAllocatedSetsThisFrame, frame.allocatedSetsThisFrame);
|
||||
}
|
||||
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()) {
|
||||
@@ -436,27 +810,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
|
||||
VkResult allocResult = AllocateDescriptorSetsFromActivePool(frameIndex, programObj, descriptorSet);
|
||||
if (allocResult == VK_ERROR_OUT_OF_POOL_MEMORY || allocResult == VK_ERROR_FRAGMENTED_POOL) {
|
||||
if (!GrowFrameDescriptorPool(frame, frameIndex)) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: descriptor pool growth failed");
|
||||
return false;
|
||||
}
|
||||
allocResult = AllocateDescriptorSetsFromActivePool(frameIndex, programObj, descriptorSet);
|
||||
}
|
||||
VkResult allocResult = AcquireDescriptorSet(frameIndex, programObj, descriptorSet);
|
||||
if (allocResult != VK_SUCCESS || descriptorSet == VK_NULL_HANDLE) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: vkAllocateDescriptorSets returned %d",
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: descriptor set acquire returned %d",
|
||||
allocResult);
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector<const void*> bindingData;
|
||||
Vector<VkDeviceSize> bindingSizes;
|
||||
if (!GatherBindingPayloads(program, bindingData, bindingSizes)) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: cannot gather UBO payloads");
|
||||
return false;
|
||||
}
|
||||
|
||||
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");
|
||||
@@ -465,9 +825,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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 =
|
||||
@@ -486,18 +848,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
write.descriptorCount = 1;
|
||||
|
||||
if (kind == ProgramFactory::DescriptorBindingKind::UniformBufferDynamic) {
|
||||
const void* payload = bindingData[binding];
|
||||
VkDeviceSize payloadSize = bindingSizes[binding];
|
||||
if (payload == nullptr || payloadSize == 0) {
|
||||
if (programObj.globalUboBinding == static_cast<Int>(binding)) {
|
||||
const void* globalUboData = program.GetUBOData();
|
||||
const VkDeviceSize globalUboSize = static_cast<VkDeviceSize>(program.GetUBOSize());
|
||||
if (globalUboData != nullptr && globalUboSize > 0) {
|
||||
payload = globalUboData;
|
||||
payloadSize = globalUboSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
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,
|
||||
@@ -517,6 +873,45 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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;
|
||||
@@ -529,13 +924,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
hasImage = ResolveSamplerDescriptor(commandBuffer, program, programObj, binding, imageInfo);
|
||||
}
|
||||
if (!hasImage) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has no valid texture descriptor",
|
||||
binding);
|
||||
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);
|
||||
MGLOG_E(
|
||||
"UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has null sampler or imageView",
|
||||
binding);
|
||||
return false;
|
||||
}
|
||||
imageInfos.push_back(imageInfo);
|
||||
@@ -549,7 +946,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
vkUpdateDescriptorSets(m_device, static_cast<Uint32>(writes.size()), writes.data(), 0, nullptr);
|
||||
}
|
||||
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, programObj.pipelineLayout, 0, 1,
|
||||
vkCmdBindDescriptorSets(commandBuffer, bindPoint, programObj.pipelineLayout, 0, 1,
|
||||
&descriptorSet, static_cast<Uint32>(dynamicOffsets.size()), dynamicOffsets.data());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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,
|
||||
@@ -45,6 +46,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramObject& programObj,
|
||||
Uint32 frameIndex,
|
||||
VkPipelineBindPoint bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
const SamplerBindingOverride* samplerBindingOverride = nullptr);
|
||||
|
||||
private:
|
||||
@@ -54,27 +56,49 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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;
|
||||
};
|
||||
|
||||
Bool ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
||||
static Bool ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const;
|
||||
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 GatherBindingPayloads(const MG_State::GLState::ProgramObject& program, Vector<const void*>& outData,
|
||||
Vector<VkDeviceSize>& outSizes) 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;
|
||||
@@ -88,6 +112,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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
|
||||
|
||||
|
||||
@@ -41,20 +41,25 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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;
|
||||
UnorderedMap<SizeT, Uint32> bindingByBufferKey;
|
||||
UnorderedMap<SizeT, Uint32> strideByBufferKey;
|
||||
UnorderedMap<SizeT, VkVertexInputRate> inputRateByBufferKey;
|
||||
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 || !attr.Buffer) {
|
||||
if (!attr.Enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -79,29 +84,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
(attr.Divisor == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
|
||||
|
||||
const SizeT bufferKey = reinterpret_cast<SizeT>(attr.Buffer.get());
|
||||
Uint32 binding = 0;
|
||||
auto itBinding = bindingByBufferKey.find(bufferKey);
|
||||
if (itBinding == bindingByBufferKey.end()) {
|
||||
binding = static_cast<Uint32>(bindingByBufferKey.size());
|
||||
bindingByBufferKey.emplace(bufferKey, binding);
|
||||
strideByBufferKey.emplace(bufferKey, stride);
|
||||
inputRateByBufferKey.emplace(bufferKey, inputRate);
|
||||
bindingBufferKeys.push_back(bufferKey);
|
||||
builder.AddBinding(binding, stride, inputRate);
|
||||
} else {
|
||||
binding = itBinding->second;
|
||||
if (strideByBufferKey[bufferKey] != stride) {
|
||||
MGLOG_D("Skipping vertex attribute at location %u: stride mismatch (%u vs %u) on same buffer",
|
||||
location, stride, strideByBufferKey[bufferKey]);
|
||||
continue;
|
||||
}
|
||||
if (inputRateByBufferKey[bufferKey] != inputRate) {
|
||||
MGLOG_D("Skipping vertex attribute at location %u: input-rate mismatch on same buffer", location);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
builder.AddAttribute(location, binding, vkFormat, static_cast<Uint32>(attr.Offset));
|
||||
const 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();
|
||||
@@ -111,6 +100,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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();
|
||||
@@ -148,8 +140,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
case DataType::Int16:
|
||||
switch (size) {
|
||||
case 1:
|
||||
return isInteger ? VK_FORMAT_R16_SINT
|
||||
: (normalized ? VK_FORMAT_R16_SNORM : VK_FORMAT_R16_SSCALED);
|
||||
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);
|
||||
@@ -164,8 +155,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
case DataType::Uint16:
|
||||
switch (size) {
|
||||
case 1:
|
||||
return isInteger ? VK_FORMAT_R16_UINT
|
||||
: (normalized ? VK_FORMAT_R16_UNORM : VK_FORMAT_R16_USCALED);
|
||||
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);
|
||||
@@ -180,8 +170,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
case DataType::Int8:
|
||||
switch (size) {
|
||||
case 1:
|
||||
return isInteger ? VK_FORMAT_R8_SINT
|
||||
: (normalized ? VK_FORMAT_R8_SNORM : VK_FORMAT_R8_SSCALED);
|
||||
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);
|
||||
@@ -196,8 +185,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
case DataType::Uint8:
|
||||
switch (size) {
|
||||
case 1:
|
||||
return isInteger ? VK_FORMAT_R8_UINT
|
||||
: (normalized ? VK_FORMAT_R8_UNORM : VK_FORMAT_R8_USCALED);
|
||||
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);
|
||||
|
||||
@@ -24,6 +24,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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
|
||||
};
|
||||
@@ -35,11 +38,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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);
|
||||
static SizeT GetComponentSize(DataType type);
|
||||
|
||||
const VulkanRendererConfig& m_config;
|
||||
UnorderedMap<HashType, BackendVertexInputState> m_cache;
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
.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_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||
.memoryUsage = m_initInfo.transientMemoryUsage,
|
||||
.allocationFlags = m_initInfo.transientAllocationFlags,
|
||||
.minBufferSize = m_initInfo.minUploadBytes,
|
||||
@@ -80,12 +80,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
BufferSlice& outSlice) {
|
||||
const VkBufferUsageFlags requiredUsage = GetVkBufferUsage(kind);
|
||||
MOBILEGL_ASSERT(requiredUsage != 0,
|
||||
"VkBufferManager::SyncResidentBuffer only supports resident vertex/index buffers");
|
||||
"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) {
|
||||
@@ -196,6 +197,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Vertex,
|
||||
Index,
|
||||
Uniform,
|
||||
TextureBuffer,
|
||||
ShaderStorage,
|
||||
Indirect,
|
||||
};
|
||||
|
||||
struct VkBufferManagerInitInfo {
|
||||
|
||||
@@ -140,6 +140,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -12,6 +12,20 @@
|
||||
#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;
|
||||
}
|
||||
@@ -26,50 +40,71 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
auto& drawbufs = drawFbo.GetDrawBuffers();
|
||||
// This should automatically work on default & offscreen FBO
|
||||
for (auto drawbuf: drawbufs) {
|
||||
if (drawbuf == FramebufferAttachmentType::None ||
|
||||
drawFbo.GetAttachment(drawbuf).IsRenderbuffer())
|
||||
auto texture = GetClearableAttachmentTexture(drawFbo, drawbuf);
|
||||
if (!texture) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QueueClear({
|
||||
.color = clearPayload.color,
|
||||
.attachmentType = drawbuf
|
||||
}, drawFbo.GetAttachment(drawbuf).GetTexture());
|
||||
.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(),
|
||||
drawFbo.GetAttachment(drawbuf).GetTexture()->GetExternalIndex(),
|
||||
texture->GetExternalIndex(),
|
||||
clearPayload.color[0], clearPayload.color[1], clearPayload.color[2], clearPayload.color[3]);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & GL_DEPTH_BUFFER_BIT &&
|
||||
!drawFbo.GetAttachment(FramebufferAttachmentType::Depth).IsRenderbuffer()) {
|
||||
QueueClear({
|
||||
.depth = clearPayload.depth,
|
||||
.attachmentType = FramebufferAttachmentType::Depth,
|
||||
}, drawFbo.GetAttachment(FramebufferAttachmentType::Depth).GetTexture());
|
||||
MGLOG_D("%s: Depth (texture %d) - depth = (%.2f)", __func__,
|
||||
drawFbo.GetAttachment(FramebufferAttachmentType::Depth).GetTexture()->GetExternalIndex(), clearPayload.depth);
|
||||
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 &&
|
||||
!drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).IsRenderbuffer()) {
|
||||
QueueClear({
|
||||
.stencil = clearPayload.stencil,
|
||||
.attachmentType = FramebufferAttachmentType::Stencil,
|
||||
}, drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).GetTexture());
|
||||
MGLOG_D("%s: Stencil (texture %d) - stencil = (%u)", __func__,
|
||||
drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).GetTexture()->GetExternalIndex(), clearPayload.stencil);
|
||||
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;
|
||||
m_pendingClears[pTexture] = clearPayload;
|
||||
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) {
|
||||
@@ -84,9 +119,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
outPayload = m_pendingClears[texture];
|
||||
MGLOG_D("%s: Got pending clear for texture %d (%s), clear value: color = (%.2f, %.2f, %.2f, %.2f), depth = (%.2f), stencil = (%u)", __func__,
|
||||
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);
|
||||
@@ -106,11 +142,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
SizeT count = 0;
|
||||
for (const auto& [raw, weak]: m_aliveObjects) {
|
||||
if (weak.expired()) {
|
||||
count++;
|
||||
m_pendingClears.erase(raw);
|
||||
m_aliveObjects.erase(raw);
|
||||
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;
|
||||
|
||||
@@ -23,12 +23,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
};
|
||||
|
||||
struct ClearAttachmentPayload {
|
||||
union {
|
||||
FloatVec4 color;
|
||||
Float depth{};
|
||||
Uint32 stencil;
|
||||
};
|
||||
FramebufferAttachmentType attachmentType = FramebufferAttachmentType::Color0;
|
||||
GLbitfield mask = 0;
|
||||
FloatVec4 color = FloatVec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
Float depth = 1.0f;
|
||||
Uint32 stencil = 0;
|
||||
};
|
||||
|
||||
class VkClearManager {
|
||||
|
||||
@@ -10,9 +10,74 @@
|
||||
|
||||
#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):
|
||||
@@ -69,6 +134,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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()) {
|
||||
@@ -80,8 +153,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool hasPayload = m_clearManager.GetPendingClear(texture, clearPayload);
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &hasPayload, sizeof(hasPayload)));
|
||||
if (hasPayload) {
|
||||
XXHASH_VERIFY(XXH64_update(
|
||||
m_hashState, &clearPayload.attachmentType, sizeof(clearPayload.attachmentType)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &clearPayload.mask, sizeof(clearPayload.mask)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,9 +167,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
currentLayout = m_swapchainObject.GetDepthStencilImageLayout(swapchainImageIndex);
|
||||
}
|
||||
} else {
|
||||
auto* resource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
||||
if (resource != nullptr) {
|
||||
currentLayout = resource->layout;
|
||||
auto* textureResource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
||||
if (textureResource != nullptr) {
|
||||
currentLayout = textureResource->layout;
|
||||
}
|
||||
}
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, ¤tLayout, sizeof(currentLayout)));
|
||||
@@ -163,44 +235,50 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
|
||||
// Color attachment
|
||||
auto& drawbufs = fbo.GetDrawBuffers();
|
||||
Int validDrawBufCount = 0;
|
||||
for (Int i = 0; i < drawbufs.size(); ++i) {
|
||||
auto drawbuf = drawbufs[i];
|
||||
if (drawbuf != FramebufferAttachmentType::None)
|
||||
validDrawBufCount = std::max(validDrawBufCount, i + 1);
|
||||
}
|
||||
const Uint32 colorAttachmentSlotCount = static_cast<Uint32>(drawbufs.size());
|
||||
|
||||
Int width = 0;
|
||||
Int height = 0;
|
||||
Vector<VkAttachmentDescription> attachmentDescriptions(validDrawBufCount);
|
||||
Vector<VkAttachmentReference> colorAttachmentRefs(validDrawBufCount);
|
||||
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.resize(validDrawBufCount, nullptr);
|
||||
Vector<VkImageView> attachmentViews(validDrawBufCount, VK_NULL_HANDLE);
|
||||
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 (Int i = 0; i < validDrawBufCount; ++i) {
|
||||
for (Uint32 i = 0; i < colorAttachmentSlotCount; ++i) {
|
||||
auto drawbuf = drawbufs[i];
|
||||
if (drawbuf == FramebufferAttachmentType::None ||
|
||||
fbo.GetAttachment(drawbuf).IsRenderbuffer())
|
||||
auto* texture = ResolveCompleteColorAttachmentTexture(fbo, drawbuf, i);
|
||||
if (texture == nullptr)
|
||||
continue;
|
||||
|
||||
auto& att = fbo.GetAttachment(drawbuf);
|
||||
auto* texture = att.GetTexture().get();
|
||||
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[i];
|
||||
VkAttachmentDescription& desc = attachmentDescriptions.back();
|
||||
switch (textureTarget) {
|
||||
case TextureTarget::Texture2D: {
|
||||
auto* texture2d =
|
||||
static_cast<MG_State::GLState::TextureObject2D*>(texture);
|
||||
desc.flags = 0;
|
||||
desc.format =
|
||||
desc.format = isDefaultFbo ?
|
||||
m_swapchainObject.GetSurfaceFormat().format :
|
||||
MG_Util::ConvertTextureInternalFormatToVkEnum(
|
||||
texture2d->GetFormat());
|
||||
desc.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
@@ -218,7 +296,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
if (hasClear) {
|
||||
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
||||
.attachmentIndex = static_cast<Uint32>(i),
|
||||
.attachmentIndex = attachmentIndex,
|
||||
.texture = texture
|
||||
});
|
||||
}
|
||||
@@ -237,19 +315,23 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
.swapchainImageIndex = swapchainImageIndex,
|
||||
.finalLayout = desc.finalLayout,
|
||||
});
|
||||
attachmentViews[i] = swapchainViews[swapchainImageIndex];
|
||||
textureResources.emplace_back(nullptr);
|
||||
attachmentViews.emplace_back(swapchainViews[swapchainImageIndex]);
|
||||
} else {
|
||||
textureResources[i] = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
||||
MOBILEGL_ASSERT(textureResources[i],
|
||||
auto* textureResource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
||||
MOBILEGL_ASSERT(textureResource,
|
||||
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i);
|
||||
trackedColorLayout = textureResources[i]->layout;
|
||||
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[i] = m_textureManager.GetOrCreateViewAtMipLevel(*texture, attachmentMipLevel);
|
||||
MOBILEGL_ASSERT(attachmentViews[i] != VK_NULL_HANDLE,
|
||||
attachmentViews.emplace_back(m_textureManager.GetOrCreateViewAtMipLevel(*texture, attachmentMipLevel));
|
||||
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
|
||||
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at color attachment %d", i);
|
||||
}
|
||||
|
||||
@@ -271,7 +353,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
// Attachment reference
|
||||
VkAttachmentReference& attachmentRef = colorAttachmentRefs[i];
|
||||
attachmentRef.attachment = i;
|
||||
attachmentRef.attachment = attachmentIndex;
|
||||
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
@@ -288,8 +370,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const Uint32 depthAttachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
|
||||
ClearAttachmentPayload clearPayload{};
|
||||
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
|
||||
Bool clearDepth = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Depth;
|
||||
Bool clearStencil = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Stencil;
|
||||
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;
|
||||
@@ -300,30 +382,26 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
trackedDepthLayout = depthTextureResource->layout;
|
||||
}
|
||||
depthAttachmentDescription.flags = 0;
|
||||
depthAttachmentDescription.format =
|
||||
depthAttachmentDescription.format = isDefaultFbo ?
|
||||
m_swapchainObject.GetDepthStencilFormat() :
|
||||
MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
|
||||
if (!isDefaultFbo) {
|
||||
depthAttachmentDescription.format = depthTextureResource->format;
|
||||
}
|
||||
depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
depthAttachmentDescription.loadOp = clearDepth ?
|
||||
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
const auto loadInfo =
|
||||
ResolveDepthStencilAttachmentLoadInfo(trackedDepthLayout, clearDepth, clearStencil);
|
||||
depthAttachmentDescription.loadOp = loadInfo.depthLoadOp;
|
||||
depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
depthAttachmentDescription.stencilLoadOp = clearStencil ?
|
||||
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
depthAttachmentDescription.stencilLoadOp = loadInfo.stencilLoadOp;
|
||||
depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
if (trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||
if (!clearDepth) {
|
||||
depthAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
}
|
||||
if (!clearStencil) {
|
||||
depthAttachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
}
|
||||
depthAttachmentDescription.initialLayout = 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());
|
||||
}
|
||||
depthAttachmentDescription.initialLayout =
|
||||
(clearDepth && clearStencil) || trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED ?
|
||||
VK_IMAGE_LAYOUT_UNDEFINED :
|
||||
trackedDepthLayout;
|
||||
if (hasClear) {
|
||||
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
||||
.attachmentIndex = depthAttachmentIndex,
|
||||
@@ -338,12 +416,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
});
|
||||
attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex));
|
||||
} else {
|
||||
MOBILEGL_ASSERT(clearDepth || clearStencil || depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
MOBILEGL_ASSERT(depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED ||
|
||||
depthAttachmentDescription.loadOp != VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
"GetOrCreateRenderPass: depth attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD",
|
||||
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);
|
||||
@@ -358,6 +442,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
attachmentDescriptions.emplace_back(depthAttachmentDescription);
|
||||
depthAttachmentRef.attachment = depthAttachmentIndex;
|
||||
}
|
||||
const Bool hasDepthStencilAttachment = depthAttachmentRef.attachment != VK_ATTACHMENT_UNUSED;
|
||||
|
||||
// Subpass
|
||||
VkSubpassDescription subpassDesc;
|
||||
@@ -409,8 +494,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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;
|
||||
}
|
||||
@@ -439,17 +533,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
if (!s_clearManager->GetPendingClear(pending.texture, clearPayload)) {
|
||||
continue;
|
||||
}
|
||||
if (clearPayload.attachmentType >= FramebufferAttachmentType::Color0 &&
|
||||
clearPayload.attachmentType <= FramebufferAttachmentType::Color31) {
|
||||
if ((clearPayload.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||
clearValues[pending.attachmentIndex].color = {
|
||||
clearPayload.color.x(),
|
||||
clearPayload.color.y(),
|
||||
clearPayload.color.z(),
|
||||
clearPayload.color.w()
|
||||
ResolveColorClearAlpha(pending.texture, clearPayload.color.w())
|
||||
};
|
||||
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Depth) {
|
||||
}
|
||||
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||
clearValues[pending.attachmentIndex].depthStencil.depth = clearPayload.depth;
|
||||
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Stencil) {
|
||||
}
|
||||
if ((clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0) {
|
||||
clearValues[pending.attachmentIndex].depthStencil.stencil = clearPayload.stencil;
|
||||
}
|
||||
}
|
||||
@@ -478,7 +573,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
switch (trackedAttachment.target) {
|
||||
case TrackedAttachmentTarget::Texture:
|
||||
MOBILEGL_ASSERT(s_textureManager != nullptr, "EndRenderPass: texture manager is null");
|
||||
s_textureManager->UpdateTrackedImageLayout(trackedAttachment.texture, trackedAttachment.finalLayout);
|
||||
s_textureManager->UpdateTrackedImageLayoutAfterAttachmentWrite(
|
||||
commandBuffer,
|
||||
trackedAttachment.texture,
|
||||
trackedAttachment.textureMipLevel,
|
||||
trackedAttachment.finalLayout);
|
||||
break;
|
||||
case TrackedAttachmentTarget::SwapchainColor:
|
||||
MOBILEGL_ASSERT(s_swapchainObject != nullptr, "EndRenderPass: swapchain object is null");
|
||||
|
||||
@@ -32,10 +32,20 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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;
|
||||
@@ -46,6 +56,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Vector<PendingClearAttachmentInfo> pendingClearAttachments;
|
||||
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
||||
Uint32 attachmentCount = 0;
|
||||
Uint32 colorAttachmentCount = 0;
|
||||
Bool hasDepthStencilAttachment = false;
|
||||
IntVec2 extent = {0, 0};
|
||||
Uint32 subpass = 0;
|
||||
|
||||
@@ -59,6 +71,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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);
|
||||
}
|
||||
@@ -70,6 +84,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const Vector<PendingClearAttachmentInfo>& pendingClearAttachments,
|
||||
const Vector<TrackedAttachmentLayoutInfo>& trackedAttachmentLayouts,
|
||||
Uint32 attachmentCount,
|
||||
Uint32 colorAttachmentCount,
|
||||
Bool hasDepthStencilAttachment,
|
||||
IntVec2 extent, int subpass):
|
||||
hash(hash),
|
||||
renderPass(renderpass),
|
||||
@@ -78,6 +94,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
pendingClearAttachments(Move(pendingClearAttachments)),
|
||||
trackedAttachmentLayouts(Move(trackedAttachmentLayouts)),
|
||||
attachmentCount(attachmentCount),
|
||||
colorAttachmentCount(colorAttachmentCount),
|
||||
hasDepthStencilAttachment(hasDepthStencilAttachment),
|
||||
extent(extent),
|
||||
subpass(subpass)
|
||||
{}
|
||||
|
||||
@@ -10,7 +10,49 @@
|
||||
|
||||
#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();
|
||||
|
||||
@@ -34,7 +76,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_config = nullptr;
|
||||
}
|
||||
|
||||
Uint64 VkSamplerManager::BuildSamplerKey(const MG_State::GLState::SamplerObject& sampler) const {
|
||||
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));
|
||||
|
||||
@@ -50,21 +93,24 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapT, sizeof(wrapT)));
|
||||
const auto wrapR = sampler.GetWrapR();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapR, sizeof(wrapR)));
|
||||
const auto minLod = sampler.GetMinLod();
|
||||
const auto maxLod = ResolveEffectiveMaxLod(sampler);
|
||||
const auto minLod = ResolveEffectiveMinLod(sampler, maxLod);
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &minLod, sizeof(minLod)));
|
||||
const auto maxLod = sampler.GetMaxLod();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &maxLod, sizeof(maxLod)));
|
||||
const auto lodBias = sampler.GetLodBias();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &lodBias, sizeof(lodBias)));
|
||||
const auto compareMode = sampler.GetCompareMode();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &compareMode, sizeof(compareMode)));
|
||||
const auto compareFunc = sampler.GetSamplerCompareFunc();
|
||||
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 Uint64 key = BuildSamplerKey(sampler);
|
||||
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;
|
||||
@@ -82,10 +128,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
samplerInfo.anisotropyEnable = VK_FALSE;
|
||||
samplerInfo.maxAnisotropy = 1.0f;
|
||||
samplerInfo.compareEnable = sampler.GetCompareMode() == SamplerCompareMode::CompareToTexture ? VK_TRUE : VK_FALSE;
|
||||
samplerInfo.compareOp = ToVkCompareOp(sampler.GetSamplerCompareFunc());
|
||||
samplerInfo.minLod = sampler.GetMinLod();
|
||||
samplerInfo.maxLod = sampler.GetMaxLod();
|
||||
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||
samplerInfo.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;
|
||||
@@ -153,4 +199,49 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class SamplerObject;
|
||||
class ITextureObject;
|
||||
}
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
@@ -28,7 +29,8 @@ public:
|
||||
Bool Initialize(const InitInfo& initInfo);
|
||||
void Shutdown();
|
||||
|
||||
VkSampler GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler);
|
||||
VkSampler GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler,
|
||||
const MG_State::GLState::ITextureObject& texture);
|
||||
|
||||
private:
|
||||
struct SamplerCacheEntry {
|
||||
@@ -37,11 +39,16 @@ private:
|
||||
Uint16 version = 0;
|
||||
};
|
||||
|
||||
Uint64 BuildSamplerKey(const MG_State::GLState::SamplerObject& sampler) const;
|
||||
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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,20 +26,26 @@ public:
|
||||
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;
|
||||
@@ -48,14 +54,19 @@ public:
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -63,25 +74,38 @@ public:
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -95,18 +119,28 @@ public:
|
||||
|
||||
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 baseMipLevel = 0, Uint32 levelCount = 1,
|
||||
Uint32 layerCount = 1);
|
||||
|
||||
SizeT CollectGarbage();
|
||||
private:
|
||||
@@ -119,7 +153,9 @@ private:
|
||||
TextureResource &resource);
|
||||
Bool SyncTextureViews(const MG_State::GLState::ITextureObject& texture, TextureResource& resource);
|
||||
VkImageView CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspect,
|
||||
Uint32 baseMipLevel, Uint32 levelCount) const;
|
||||
VkImageViewType viewType, Uint32 baseMipLevel, Uint32 levelCount,
|
||||
Uint32 layerCount,
|
||||
const VkComponentMapping* components = nullptr) const;
|
||||
Bool UploadDirtyMipLevels(MG_State::GLState::TextureObjectMipmap &mipmapTexture,
|
||||
TextureUploadTarget uploadTarget,
|
||||
TextureResource &outResource);
|
||||
@@ -132,15 +168,22 @@ private:
|
||||
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
@@ -110,20 +110,49 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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();
|
||||
@@ -146,7 +175,31 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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
|
||||
@@ -172,13 +225,21 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
VkCommandPool m_commandPool = VK_NULL_HANDLE;
|
||||
|
||||
struct TransientBufferSliceCacheEntry {
|
||||
BufferSlice slice;
|
||||
Uint64 changeSerial = 0;
|
||||
SizeT size = 0;
|
||||
};
|
||||
|
||||
VkBufferManager m_bufferManager;
|
||||
Vector<const MG_State::GLState::BufferObject*> m_transientVertexIndexBuffersThisFrame;
|
||||
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;
|
||||
@@ -187,6 +248,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
UniquePtr<VkTextureManager> m_textureManager;
|
||||
UniquePtr<VkSamplerManager> m_samplerManager;
|
||||
BlitResources m_blitResources;
|
||||
DepthMipmapResources m_depthMipmapResources;
|
||||
Vector<DeferredDepthMipmapCleanup> m_deferredDepthMipmapCleanup;
|
||||
|
||||
void CreateInstance();
|
||||
VkResult SetupDebugMessenger();
|
||||
@@ -203,15 +266,24 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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);
|
||||
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,
|
||||
@@ -221,6 +293,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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();
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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
|
||||
|
||||
@@ -34,11 +34,25 @@ namespace MobileGL::MG_Impl::EGLImpl {
|
||||
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>) {
|
||||
@@ -230,7 +244,13 @@ namespace MobileGL::MG_Impl::EGLImpl {
|
||||
if (!state) {
|
||||
return EGL_FALSE;
|
||||
}
|
||||
return state->TerminateDisplay(dpy) ? EGL_TRUE : EGL_FALSE;
|
||||
if (!state->TerminateDisplay(dpy)) {
|
||||
return EGL_FALSE;
|
||||
}
|
||||
if (auto* backendObject = MG_Backend::pActiveBackendObject.get()) {
|
||||
backendObject->ReleaseEGLResources();
|
||||
}
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
EGLBoolean ReleaseThread() {
|
||||
@@ -330,7 +350,24 @@ namespace MobileGL::MG_Impl::EGLImpl {
|
||||
if (!state) {
|
||||
return EGL_NO_SURFACE;
|
||||
}
|
||||
return state->CreatePbufferSurface(dpy, config, attrib_list);
|
||||
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) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,12 +12,31 @@
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
||||
void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params);
|
||||
void GetBufferPointerv(GLenum target, GLenum pname, void** params);
|
||||
GLboolean IsBuffer(GLuint buffer);
|
||||
void DeleteBuffers(GLsizei n, const GLuint* buffers);
|
||||
void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
|
||||
GLboolean UnmapBuffer(GLenum target);
|
||||
void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
|
||||
void* MapBuffer(GLenum target, GLenum access);
|
||||
void BufferStorage(GLenum target, GLsizeiptr size, const void* data, GLbitfield flags);
|
||||
void CreateBuffers(GLsizei n, GLuint* buffers);
|
||||
void NamedBufferStorage(GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags);
|
||||
void NamedBufferData(GLuint buffer, GLsizeiptr size, const void* data, GLenum usage);
|
||||
void NamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data);
|
||||
void CopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset,
|
||||
GLsizeiptr size);
|
||||
void ClearNamedBufferData(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data);
|
||||
void ClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format,
|
||||
GLenum type, const void* data);
|
||||
void* MapNamedBuffer(GLuint buffer, GLenum access);
|
||||
void* MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
|
||||
GLboolean UnmapNamedBuffer(GLuint buffer);
|
||||
void FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length);
|
||||
void GetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint* params);
|
||||
void GetNamedBufferParameteri64v(GLuint buffer, GLenum pname, GLint64* params);
|
||||
void GetNamedBufferPointerv(GLuint buffer, GLenum pname, void** params);
|
||||
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset,
|
||||
GLsizeiptr size);
|
||||
void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
|
||||
|
||||
@@ -73,6 +73,24 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
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,
|
||||
const void* indices, GLint basevertex) {
|
||||
#ifdef TRACY_ENABLE
|
||||
@@ -156,6 +174,52 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
/* @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) {
|
||||
MultiDrawElementsIndirect_Backend(mode, type, indirect, drawcount, stride);
|
||||
}
|
||||
@@ -164,6 +228,32 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
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,
|
||||
const void* indices, GLint basevertex) {
|
||||
DrawRangeElementsBaseVertex_Backend(mode, start, end, count, type, indices, basevertex);
|
||||
|
||||
@@ -11,8 +11,16 @@
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
|
||||
void DispatchComputeIndirect(GLintptr indirect);
|
||||
void MemoryBarrier(GLbitfield barriers);
|
||||
void MemoryBarrierByRegion(GLbitfield barriers);
|
||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||
void 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,
|
||||
const void* indices, GLint basevertex);
|
||||
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "../Buffer/GL_Buffer.h"
|
||||
#include "../Getter/GL_Getter.h"
|
||||
#include "../Sampler/GL_Sampler.h"
|
||||
#include "../Sync/GL_Sync.h"
|
||||
#include "../Texture/GL_Texture.h"
|
||||
#include "../Drawing/GL_Drawing.h"
|
||||
#include "../Program/GL_Program.h"
|
||||
@@ -17,42 +18,40 @@
|
||||
#include "../Framebuffer/GL_Framebuffer.h"
|
||||
#include "../VertexArray/GL_VertexArray.h"
|
||||
|
||||
#define DECLARE_GL_FUNCTION_STUB_HEAD(type,name,...) \
|
||||
MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
|
||||
#define DECLARE_GL_FUNCTION_STUB_HEAD(type, name, ...) MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
|
||||
|
||||
#define DECLARE_GL_FUNCTION_STUB_END(type,name,...) \
|
||||
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
|
||||
return (type)1; \
|
||||
}
|
||||
#define DECLARE_GL_FUNCTION_STUB_END(type, name, ...) \
|
||||
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
|
||||
return (type)1; \
|
||||
}
|
||||
|
||||
#define DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(type,name,...) \
|
||||
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
|
||||
}
|
||||
#define DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(type, name, ...) \
|
||||
MGLOG_W("Stub function: %s(...)", __FUNCTION__); \
|
||||
}
|
||||
|
||||
#define DECLARE_GL_FUNCTION_HEAD(type,name,...) \
|
||||
MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
|
||||
#define DECLARE_GL_FUNCTION_HEAD(type, name, ...) MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
|
||||
|
||||
#ifdef TRACY_ENABLE
|
||||
#define DECLARE_GL_FUNCTION_END(type,name,...) \
|
||||
ZoneScopedC(TRACY_ZONECOLOR_ENTRY); \
|
||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||
return MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||
#define DECLARE_GL_FUNCTION_END(type, name, ...) \
|
||||
ZoneScopedC(TRACY_ZONECOLOR_ENTRY); \
|
||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||
return MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define DECLARE_GL_FUNCTION_END_NO_RETURN(type,name,...) \
|
||||
ZoneScopedC(TRACY_ZONECOLOR_ENTRY); \
|
||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||
MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||
#define DECLARE_GL_FUNCTION_END_NO_RETURN(type, name, ...) \
|
||||
ZoneScopedC(TRACY_ZONECOLOR_ENTRY); \
|
||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||
MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||
}
|
||||
#else
|
||||
#define DECLARE_GL_FUNCTION_END(type,name,...) \
|
||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||
return MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||
#define DECLARE_GL_FUNCTION_END(type, name, ...) \
|
||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||
return MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define DECLARE_GL_FUNCTION_END_NO_RETURN(type,name,...) \
|
||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||
MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||
#define DECLARE_GL_FUNCTION_END_NO_RETURN(type, name, ...) \
|
||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__); \
|
||||
MobileGL::MG_Impl::GLImpl::name(__VA_ARGS__); \
|
||||
}
|
||||
#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, 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_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, 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)
|
||||
@@ -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, 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_STUB_HEAD(void, Finish) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Finish)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Flush) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Flush)
|
||||
MOBILEGL_GL_API void glFinish() { MGLOG_D("Implementing function: %s(...)", __FUNCTION__); }
|
||||
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, 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)
|
||||
@@ -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, 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_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_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)
|
||||
@@ -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, 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_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, 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)
|
||||
@@ -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, 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_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, 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, 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, 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)
|
||||
@@ -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, 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_STUB_HEAD(GLsync, FenceSync, GLenum condition, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_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_STUB_HEAD(void, DeleteSync, GLsync sync) DECLARE_GL_FUNCTION_STUB_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_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_STUB_HEAD(void, GetInteger64v, GLenum pname, GLint64* data) DECLARE_GL_FUNCTION_STUB_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_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_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(GLsync, FenceSync, GLenum condition, GLbitfield flags) DECLARE_GL_FUNCTION_END(GLsync, FenceSync, condition, flags)
|
||||
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsSync, GLsync sync) DECLARE_GL_FUNCTION_END(GLboolean, IsSync, sync)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, DeleteSync, GLsync sync) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteSync, sync)
|
||||
DECLARE_GL_FUNCTION_HEAD(GLenum, ClientWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_END(GLenum, ClientWaitSync, sync, flags, timeout)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, WaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_END_NO_RETURN(void, WaitSync, sync, flags, timeout)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, GetInteger64v, GLenum pname, GLint64* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetInteger64v, pname, data)
|
||||
DECLARE_GL_FUNCTION_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_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_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, 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)
|
||||
@@ -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, 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, 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_STUB_HEAD(void, DispatchComputeIndirect, GLintptr indirect) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DispatchComputeIndirect, indirect)
|
||||
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_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, 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, 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_STUB_HEAD(GLuint, GetProgramResourceIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_STUB_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_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_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(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_HEAD(GLuint, GetProgramResourceIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_END(GLuint, GetProgramResourceIndex, program, programInterface, name)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, GetProgramResourceName, GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length, GLchar* name) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetProgramResourceName, program, programInterface, index, bufSize, length, name)
|
||||
DECLARE_GL_FUNCTION_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_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, 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)
|
||||
@@ -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(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, ProgramUniform1i, GLuint program, GLint location, GLint v0) DECLARE_GL_FUNCTION_STUB_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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, ProgramUniform1i, GLuint program, GLint location, GLint v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1i, program, location, v0)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2i, GLuint program, GLint location, GLint v0, GLint v1) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2i, program, location, v0, v1)
|
||||
DECLARE_GL_FUNCTION_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_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_HEAD(void, ProgramUniform1ui, GLuint program, GLint location, GLuint v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1ui, program, location, v0)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2ui, GLuint program, GLint location, GLuint v0, GLuint v1) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2ui, program, location, v0, v1)
|
||||
DECLARE_GL_FUNCTION_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_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_HEAD(void, ProgramUniform1f, GLuint program, GLint location, GLfloat v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform1f, program, location, v0)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, ProgramUniform2f, GLuint program, GLint location, GLfloat v0, GLfloat v1) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProgramUniform2f, program, location, v0, v1)
|
||||
DECLARE_GL_FUNCTION_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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, 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)
|
||||
@@ -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, 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, 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, MemoryBarrier, GLbitfield barriers) DECLARE_GL_FUNCTION_STUB_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, MemoryBarrier, GLbitfield barriers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MemoryBarrier, barriers)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, MemoryBarrierByRegion, GLbitfield barriers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MemoryBarrierByRegion, barriers)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, 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_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_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_STUB_HEAD(void, BlendEquationi, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_STUB_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_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_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_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_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, BlendEquationi, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_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_HEAD(void, BlendEquationSeparatei, GLuint buf, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_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_HEAD(void, BlendFunci, GLuint buf, GLenum src, GLenum dst) DECLARE_GL_FUNCTION_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_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_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)
|
||||
@@ -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, 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_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, 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)
|
||||
@@ -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_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_STUB_HEAD(GLint, GetProgramResourceLocationIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_STUB_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(GLint, GetProgramResourceLocationIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_END(GLint, GetProgramResourceLocationIndex, program, programInterface, name)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, ShaderStorageBlockBinding, GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ShaderStorageBlockBinding, program, storageBlockIndex, storageBlockBinding)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, 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, 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, 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)
|
||||
@@ -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, 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, CreateBuffers, GLsizei n, GLuint* buffers) DECLARE_GL_FUNCTION_STUB_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_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_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_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_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_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_STUB_HEAD(GLboolean, UnmapNamedBuffer, GLuint buffer) DECLARE_GL_FUNCTION_STUB_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_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_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_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, CreateBuffers, GLsizei n, GLuint* buffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateBuffers, n, buffers)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferStorage, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags)
|
||||
DECLARE_GL_FUNCTION_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_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_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_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_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_HEAD(GLboolean, UnmapNamedBuffer, GLuint buffer) DECLARE_GL_FUNCTION_END(GLboolean, UnmapNamedBuffer, buffer)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, FlushMappedNamedBufferRange, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameteriv, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameteri64v, GLuint buffer, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteri64v, buffer, pname, params)
|
||||
DECLARE_GL_FUNCTION_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, CreateFramebuffers, GLsizei n, GLuint* framebuffers) DECLARE_GL_FUNCTION_STUB_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, CreateFramebuffers, GLsizei n, GLuint* framebuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateFramebuffers, n, framebuffers)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferRenderbuffer, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, 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, NamedFramebufferDrawBuffer, GLuint framebuffer, GLenum buf) DECLARE_GL_FUNCTION_STUB_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_STUB_HEAD(void, NamedFramebufferReadBuffer, GLuint framebuffer, GLenum src) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferReadBuffer, framebuffer, src)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferDrawBuffer, GLuint framebuffer, GLenum buf) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferDrawBuffer, framebuffer, buf)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferDrawBuffers, GLuint framebuffer, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferDrawBuffers, framebuffer, n, bufs)
|
||||
DECLARE_GL_FUNCTION_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, 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, 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_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_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_STUB_HEAD(GLenum, CheckNamedFramebufferStatus, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_STUB_END(GLenum, CheckNamedFramebufferStatus, framebuffer, target)
|
||||
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_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_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_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, 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_STUB_HEAD(void, CreateRenderbuffers, GLsizei n, GLuint* renderbuffers) DECLARE_GL_FUNCTION_STUB_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, GetNamedFramebufferAttachmentParameteriv, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameteriv, framebuffer, attachment, pname, params)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, CreateRenderbuffers, GLsizei n, GLuint* renderbuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateRenderbuffers, n, renderbuffers)
|
||||
DECLARE_GL_FUNCTION_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, GetNamedRenderbufferParameteriv, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_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, GetNamedRenderbufferParameteriv, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedRenderbufferParameteriv, renderbuffer, pname, params)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, CreateTextures, GLenum target, GLsizei n, GLuint* textures) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateTextures, target, n, textures)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, 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, 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, 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, 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, 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)
|
||||
@@ -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, 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, 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, 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, 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, BindTextureUnit, GLuint unit, GLuint texture) DECLARE_GL_FUNCTION_STUB_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, BindTextureUnit, GLuint unit, GLuint texture) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindTextureUnit, unit, texture)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, GetTextureImage, GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureImage, texture, level, format, type, bufSize, pixels)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, 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, 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, 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, GetTextureParameteriv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_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_STUB_HEAD(void, DisableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_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_STUB_HEAD(void, VertexArrayElementBuffer, GLuint vaobj, GLuint buffer) DECLARE_GL_FUNCTION_STUB_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, GetTextureParameteriv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureParameteriv, texture, pname, params)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, CreateVertexArrays, GLsizei n, GLuint* arrays) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateVertexArrays, n, arrays)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, DisableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DisableVertexArrayAttrib, vaobj, index)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, EnableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexArrayAttrib, vaobj, index)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayElementBuffer, GLuint vaobj, GLuint buffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayElementBuffer, vaobj, buffer)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayVertexBuffer, GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayVertexBuffer, vaobj, bindingindex, buffer, offset, stride)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, 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, 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_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, 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_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, 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)
|
||||
@@ -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, 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, 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, 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)
|
||||
@@ -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, 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, 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_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, 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_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, 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)
|
||||
@@ -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, 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, 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_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, 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_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, 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)
|
||||
@@ -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, 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, 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_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_STUB_HEAD(GLboolean, UnmapNamedBufferEXT, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END(GLboolean, UnmapNamedBufferEXT, 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_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, 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_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_HEAD(GLboolean, UnmapNamedBufferEXT, GLuint buffer) DECLARE_GL_FUNCTION_END(GLboolean, UnmapNamedBuffer, buffer)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameterivEXT, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params)
|
||||
DECLARE_GL_FUNCTION_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, 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)
|
||||
@@ -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, 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, 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_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, NamedRenderbufferStorageEXT, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedRenderbufferStorage, renderbuffer, internalformat, width, height)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, GetNamedRenderbufferParameterivEXT, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedRenderbufferParameteriv, renderbuffer, pname, params)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, 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(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, 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, 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, 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)
|
||||
@@ -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, 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, EnableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableVertexArrayAttribEXT, 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, EnableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexArrayAttrib, 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, 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, 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_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_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_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, FlushMappedNamedBufferRangeEXT, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, NamedBufferStorageEXT, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags)
|
||||
DECLARE_GL_FUNCTION_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_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, 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)
|
||||
@@ -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, 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, 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, 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)
|
||||
@@ -2880,6 +2879,69 @@ MOBILEGL_GL_API void glGetFramebufferParameterivEXT(GLenum target, GLenum pname,
|
||||
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) {
|
||||
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) {
|
||||
MGLOG_W("Stub function: %s(...)", __FUNCTION__);
|
||||
return nullptr;
|
||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__);
|
||||
return MobileGL::MG_Impl::GLImpl::MapNamedBuffer(buffer, 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) {
|
||||
MGLOG_W("Stub function: %s(...)", __FUNCTION__);
|
||||
return nullptr;
|
||||
MGLOG_D("Implementing function: %s(...)", __FUNCTION__);
|
||||
return MobileGL::MG_Impl::GLImpl::MapNamedBufferRange(buffer, offset, length, 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);
|
||||
}
|
||||
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsizei count,
|
||||
GLboolean transpose, const GLfloat* value) {
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
glProgramUniformMatrix2fv(program, location, count, transpose, value);
|
||||
}
|
||||
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix2x3fvEXT(GLuint program, GLint location, GLsizei count,
|
||||
GLboolean transpose, const GLfloat* value) {
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix2x3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
glProgramUniformMatrix2x3fv(program, location, count, transpose, value);
|
||||
}
|
||||
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix2x4fvEXT(GLuint program, GLint location, GLsizei count,
|
||||
GLboolean transpose, const GLfloat* value) {
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix2x4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
glProgramUniformMatrix2x4fv(program, location, count, transpose, value);
|
||||
}
|
||||
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsizei count,
|
||||
GLboolean transpose, const GLfloat* value) {
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
glProgramUniformMatrix3fv(program, location, count, transpose, value);
|
||||
}
|
||||
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix3x2fvEXT(GLuint program, GLint location, GLsizei count,
|
||||
GLboolean transpose, const GLfloat* value) {
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix3x2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
glProgramUniformMatrix3x2fv(program, location, count, transpose, value);
|
||||
}
|
||||
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix3x4fvEXT(GLuint program, GLint location, GLsizei count,
|
||||
GLboolean transpose, const GLfloat* value) {
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix3x4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
glProgramUniformMatrix3x4fv(program, location, count, transpose, value);
|
||||
}
|
||||
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count,
|
||||
GLboolean transpose, const GLfloat* value) {
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
glProgramUniformMatrix4fv(program, location, count, transpose, value);
|
||||
}
|
||||
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix4x2fvEXT(GLuint program, GLint location, GLsizei count,
|
||||
GLboolean transpose, const GLfloat* value) {
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix4x2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
glProgramUniformMatrix4x2fv(program, location, count, transpose, value);
|
||||
}
|
||||
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix4x3fvEXT(GLuint program, GLint location, GLsizei count,
|
||||
GLboolean transpose, const GLfloat* value) {
|
||||
MOBILEGL_GL_API void glProgramUniformMatrix4x3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
glProgramUniformMatrix4x3fv(program, location, count, transpose, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,39 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
mask, filter);
|
||||
}
|
||||
|
||||
void BlitNamedFramebuffer_Backend(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
|
||||
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
|
||||
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
|
||||
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
|
||||
auto blitNamedFramebuffer = MG_Backend::gBackendFunctionsTable.GL.BlitNamedFramebuffer;
|
||||
if (!blitNamedFramebuffer) {
|
||||
MGLOG_E("glBlitNamedFramebuffer skipped: backend does not implement explicit framebuffer blit.");
|
||||
return;
|
||||
}
|
||||
blitNamedFramebuffer(readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
|
||||
dstY1, mask, filter);
|
||||
}
|
||||
|
||||
void ClearNamedFramebufferfv_Backend(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
||||
GLenum buffer, GLint drawbuffer, const GLfloat* value) {
|
||||
auto clearNamedFramebufferfv = MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfv;
|
||||
if (!clearNamedFramebufferfv) {
|
||||
MGLOG_E("glClearNamedFramebufferfv skipped: backend does not implement explicit framebuffer clear.");
|
||||
return;
|
||||
}
|
||||
clearNamedFramebufferfv(framebuffer, buffer, drawbuffer, value);
|
||||
}
|
||||
|
||||
void ClearNamedFramebufferfi_Backend(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
||||
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
|
||||
auto clearNamedFramebufferfi = MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfi;
|
||||
if (!clearNamedFramebufferfi) {
|
||||
MGLOG_E("glClearNamedFramebufferfi skipped: backend does not implement explicit framebuffer clear.");
|
||||
return;
|
||||
}
|
||||
clearNamedFramebufferfi(framebuffer, buffer, drawbuffer, depth, stencil);
|
||||
}
|
||||
|
||||
void SampleMaski_State(GLuint maskNumber, GLbitfield mask) {
|
||||
// TODO: implement
|
||||
}
|
||||
@@ -34,23 +67,19 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void RenderbufferStorage_State(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
|
||||
RenderbufferTarget rbTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
|
||||
if (!FramebufferImpl::ValidateRenderbufferTarget(rbTarget)) return;
|
||||
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(rbTarget);
|
||||
auto& renderbufferObject = bindingSlot.GetBoundObject();
|
||||
void AllocateRenderbufferStorage_State(const SharedPtr<MG_State::GLState::RenderbufferObject>& renderbufferObject,
|
||||
GLenum internalformat, GLsizei width, GLsizei height, const char* caller) {
|
||||
if (!renderbufferObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State",
|
||||
"Renderbuffer target is bound to no renderbuffer object."));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "No renderbuffer object is available."));
|
||||
return;
|
||||
}
|
||||
TextureInternalFormat format = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
|
||||
if (!TextureImpl::ValidateTextureInternalFormat(format)) return;
|
||||
if (width < 0 || height < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State",
|
||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||
"Width and height must be non-negative."));
|
||||
return;
|
||||
}
|
||||
@@ -58,6 +87,14 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
renderbufferObject->SetInternalFormat(format);
|
||||
}
|
||||
|
||||
void RenderbufferStorage_State(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
|
||||
RenderbufferTarget rbTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
|
||||
if (!FramebufferImpl::ValidateRenderbufferTarget(rbTarget)) return;
|
||||
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(rbTarget);
|
||||
auto& renderbufferObject = bindingSlot.GetBoundObject();
|
||||
AllocateRenderbufferStorage_State(renderbufferObject, internalformat, width, height, "RenderbufferStorage_State");
|
||||
}
|
||||
|
||||
GLboolean IsRenderbuffer_State(GLuint renderbuffer) {
|
||||
return MG_State::pGLContext->ValidateRenderbufferName(renderbuffer);
|
||||
}
|
||||
@@ -67,7 +104,86 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
void GetFramebufferAttachmentParameteriv_State(GLenum target, GLenum attachment, GLenum pname, GLint* params) {
|
||||
// TODO: implement
|
||||
if (params == nullptr) return;
|
||||
if (target == GL_FRAMEBUFFER) {
|
||||
target = GL_DRAW_FRAMEBUFFER;
|
||||
}
|
||||
|
||||
FramebufferTarget framebufferTarget = MG_Util::ConvertGLEnumToFramebufferTarget(target);
|
||||
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
|
||||
|
||||
const Bool depthStencilAlias = attachment == GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
FramebufferAttachmentType attachmentType = depthStencilAlias
|
||||
? FramebufferAttachmentType::Depth
|
||||
: MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
|
||||
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
|
||||
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
||||
auto& framebufferObject = bindingSlot.GetBoundObject();
|
||||
if (!framebufferObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetFramebufferAttachmentParameteriv_State",
|
||||
"Framebuffer target is bound to no framebuffer object."));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* attachmentObject = [&]() -> const MG_State::GLState::FramebufferAttachmentObject* {
|
||||
if (!depthStencilAlias) {
|
||||
return &framebufferObject->GetAttachment(attachmentType);
|
||||
}
|
||||
|
||||
const auto& depthAttachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Depth);
|
||||
if (depthAttachment.IsValid() && !depthAttachment.IsEmpty()) return &depthAttachment;
|
||||
|
||||
const auto& stencilAttachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil);
|
||||
if (stencilAttachment.IsValid() && !stencilAttachment.IsEmpty()) return &stencilAttachment;
|
||||
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
switch (pname) {
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
|
||||
if (attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid()) {
|
||||
*params = GL_NONE;
|
||||
} else if (attachmentObject->IsTexture()) {
|
||||
*params = GL_TEXTURE;
|
||||
} else if (attachmentObject->IsRenderbuffer()) {
|
||||
*params = GL_RENDERBUFFER;
|
||||
} else {
|
||||
*params = GL_NONE;
|
||||
}
|
||||
break;
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
|
||||
if (attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid()) {
|
||||
*params = 0;
|
||||
} else if (attachmentObject->IsTexture()) {
|
||||
const auto& textureObject = attachmentObject->GetTexture();
|
||||
*params = textureObject ? static_cast<GLint>(textureObject->GetExternalIndex()) : 0;
|
||||
} else if (attachmentObject->IsRenderbuffer()) {
|
||||
const auto& renderbufferObject = attachmentObject->GetRenderbuffer();
|
||||
*params = renderbufferObject ? static_cast<GLint>(renderbufferObject->GetExternalIndex()) : 0;
|
||||
} else {
|
||||
*params = 0;
|
||||
}
|
||||
break;
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
|
||||
*params = (attachmentObject != nullptr && attachmentObject->IsTexture() && attachmentObject->IsValid())
|
||||
? static_cast<GLint>(attachmentObject->GetTextureLevel())
|
||||
: 0;
|
||||
break;
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
|
||||
*params = 0;
|
||||
break;
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "GetFramebufferAttachmentParameteriv_State",
|
||||
std::format("pname {} is not an accepted value.", MG_Util::ConvertGLEnumToString(pname))));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void GenRenderbuffers_State(GLsizei n, GLuint* renderbuffers) {
|
||||
@@ -77,11 +193,55 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenRenderbuffers_State", "n must be non-negative"));
|
||||
return;
|
||||
}
|
||||
static thread_local Vector<GLuint> renderbufferNames;
|
||||
Vector<GLuint> renderbufferNames;
|
||||
MG_State::pGLContext->GenRenderbufferNames(n, renderbufferNames);
|
||||
Memcpy(renderbuffers, renderbufferNames.data(), sizeof(GLuint) * static_cast<SizeT>(n));
|
||||
}
|
||||
|
||||
void CreateRenderbuffers_State(GLsizei n, GLuint* renderbuffers) {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CreateRenderbuffers_State", "n must be non-negative"));
|
||||
return;
|
||||
}
|
||||
if (n > 0 && !renderbuffers) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CreateRenderbuffers_State",
|
||||
"Renderbuffer output pointer cannot be null."));
|
||||
return;
|
||||
}
|
||||
|
||||
Vector<GLuint> renderbufferNames;
|
||||
MG_State::pGLContext->GenRenderbufferNames(static_cast<Uint>(n), renderbufferNames);
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
renderbuffers[i] = renderbufferNames[i];
|
||||
MG_State::pGLContext->CreateRenderbufferObject(renderbufferNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
SharedPtr<MG_State::GLState::RenderbufferObject> GetNamedRenderbufferObject_State(GLuint renderbuffer,
|
||||
const char* caller) {
|
||||
if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer, false)) return nullptr;
|
||||
|
||||
auto& renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
|
||||
if (!renderbufferObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||
std::format("Renderbuffer object {} does not exist.", renderbuffer)));
|
||||
return nullptr;
|
||||
}
|
||||
return renderbufferObject;
|
||||
}
|
||||
|
||||
void NamedRenderbufferStorage_State(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) {
|
||||
auto renderbufferObject = GetNamedRenderbufferObject_State(renderbuffer, "NamedRenderbufferStorage_State");
|
||||
AllocateRenderbufferStorage_State(renderbufferObject, internalformat, width, height,
|
||||
"NamedRenderbufferStorage_State");
|
||||
}
|
||||
|
||||
void GenFramebuffers_State(GLsizei n, GLuint* framebuffers) {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
@@ -89,11 +249,49 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenFramebuffers_State", "n must be non-negative"));
|
||||
return;
|
||||
}
|
||||
static thread_local Vector<GLuint> framebuffersNames;
|
||||
Vector<GLuint> framebuffersNames;
|
||||
MG_State::pGLContext->GenFramebufferNames(n, framebuffersNames);
|
||||
Memcpy(framebuffers, framebuffersNames.data(), sizeof(GLuint) * static_cast<SizeT>(n));
|
||||
}
|
||||
|
||||
void CreateFramebuffers_State(GLsizei n, GLuint* framebuffers) {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CreateFramebuffers_State", "n must be non-negative"));
|
||||
return;
|
||||
}
|
||||
if (n > 0 && !framebuffers) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CreateFramebuffers_State",
|
||||
"Framebuffer output pointer cannot be null."));
|
||||
return;
|
||||
}
|
||||
|
||||
Vector<GLuint> framebufferNames;
|
||||
MG_State::pGLContext->GenFramebufferNames(static_cast<Uint>(n), framebufferNames);
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
framebuffers[i] = framebufferNames[i];
|
||||
MG_State::pGLContext->CreateFramebufferObject(framebufferNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
SharedPtr<MG_State::GLState::FramebufferObject> GetNamedFramebufferObject_State(GLuint framebuffer,
|
||||
const char* caller) {
|
||||
if (!FramebufferImpl::ValidateFramebufferName(framebuffer, false)) return nullptr;
|
||||
|
||||
auto& framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
|
||||
if (!framebufferObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||
std::format("Framebuffer object {} does not exist.", framebuffer)));
|
||||
return nullptr;
|
||||
}
|
||||
return framebufferObject;
|
||||
}
|
||||
|
||||
void FramebufferTextureLayer_State(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) {
|
||||
// TODO: implement
|
||||
}
|
||||
@@ -111,6 +309,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
FramebufferTexture2D_State(target, GL_DEPTH_ATTACHMENT, textarget, texture, level);
|
||||
FramebufferTexture2D_State(target, GL_STENCIL_ATTACHMENT, textarget, texture, level);
|
||||
return;
|
||||
}
|
||||
|
||||
FramebufferAttachmentType attachmentType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
|
||||
@@ -152,7 +351,38 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
void FramebufferTexture_State(GLenum target, GLenum attachment, GLuint texture, GLint level) {
|
||||
// TODO: implement
|
||||
FramebufferTexture2D_State(target, attachment, GL_TEXTURE_2D, texture, level);
|
||||
}
|
||||
|
||||
void NamedFramebufferTexture_State(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) {
|
||||
if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
NamedFramebufferTexture_State(framebuffer, GL_DEPTH_ATTACHMENT, texture, level);
|
||||
NamedFramebufferTexture_State(framebuffer, GL_STENCIL_ATTACHMENT, texture, level);
|
||||
return;
|
||||
}
|
||||
|
||||
auto framebufferObject = GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferTexture_State");
|
||||
if (!framebufferObject) return;
|
||||
|
||||
FramebufferAttachmentType attachmentType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
|
||||
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
|
||||
if (!TextureImpl::ValidateTextureName(texture, true)) return;
|
||||
|
||||
if (texture == 0) {
|
||||
framebufferObject->Detach(attachmentType);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||
if (!textureObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "NamedFramebufferTexture_State",
|
||||
std::format("Texture object {} is not valid.", texture)));
|
||||
return;
|
||||
}
|
||||
|
||||
framebufferObject->AttachTexture(attachmentType, textureObject, level);
|
||||
}
|
||||
|
||||
void FramebufferRenderbuffer_State(GLenum target, GLenum attachment, GLenum renderbuffertarget,
|
||||
@@ -194,7 +424,37 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
framebufferObject->AttachRenderbuffer(attachmentType, renderbufferObject);
|
||||
}
|
||||
|
||||
void DrawBuffers_State(GLsizei n, const GLenum* bufs) {
|
||||
void NamedFramebufferRenderbuffer_State(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget,
|
||||
GLuint renderbuffer) {
|
||||
if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
NamedFramebufferRenderbuffer_State(framebuffer, GL_DEPTH_ATTACHMENT, renderbuffertarget, renderbuffer);
|
||||
NamedFramebufferRenderbuffer_State(framebuffer, GL_STENCIL_ATTACHMENT, renderbuffertarget, renderbuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
auto framebufferObject = GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferRenderbuffer_State");
|
||||
if (!framebufferObject) return;
|
||||
|
||||
FramebufferAttachmentType attachmentType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
|
||||
RenderbufferTarget rbTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(renderbuffertarget);
|
||||
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
|
||||
if (!FramebufferImpl::ValidateRenderbufferTarget(rbTarget)) return;
|
||||
if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer)) return;
|
||||
|
||||
if (renderbuffer == 0) {
|
||||
framebufferObject->Detach(attachmentType);
|
||||
return;
|
||||
}
|
||||
|
||||
auto renderbufferObject =
|
||||
GetNamedRenderbufferObject_State(renderbuffer, "NamedFramebufferRenderbuffer_State");
|
||||
if (!renderbufferObject) return;
|
||||
|
||||
framebufferObject->AttachRenderbuffer(attachmentType, renderbufferObject);
|
||||
}
|
||||
|
||||
void DrawBuffersForFramebuffer_State(const SharedPtr<MG_State::GLState::FramebufferObject>& fbo, Bool isDefaultFBO,
|
||||
GLsizei n, const GLenum* bufs) {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
@@ -206,11 +466,12 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`n` is greater than `GL_MAX_DRAW_BUFFERS`."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get bound framebuffer
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
|
||||
auto& fbo = bindingSlot.GetBoundObject();
|
||||
bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
|
||||
if (!fbo) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"Framebuffer object is null."));
|
||||
return;
|
||||
}
|
||||
|
||||
static int existenceMap[(SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount] = {-1};
|
||||
std::fill(existenceMap, existenceMap + (SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount, -1);
|
||||
@@ -283,6 +544,13 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
}
|
||||
|
||||
void DrawBuffers_State(GLsizei n, const GLenum* bufs) {
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
|
||||
auto& fbo = bindingSlot.GetBoundObject();
|
||||
const bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
|
||||
DrawBuffersForFramebuffer_State(fbo, isDefaultFBO, n, bufs);
|
||||
}
|
||||
|
||||
void DrawBuffer_State(GLenum buf) {
|
||||
if (buf == GL_NONE) {
|
||||
DrawBuffers_State(0, nullptr);
|
||||
@@ -311,6 +579,114 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
fbo->SetReadBuffer(attType);
|
||||
}
|
||||
|
||||
void NamedFramebufferDrawBuffers_State(GLuint framebuffer, GLsizei n, const GLenum* bufs) {
|
||||
auto framebufferObject = GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferDrawBuffers_State");
|
||||
if (!framebufferObject) return;
|
||||
DrawBuffersForFramebuffer_State(framebufferObject, false, n, bufs);
|
||||
}
|
||||
|
||||
void NamedFramebufferDrawBuffer_State(GLuint framebuffer, GLenum buf) {
|
||||
if (buf == GL_NONE) {
|
||||
NamedFramebufferDrawBuffers_State(framebuffer, 0, nullptr);
|
||||
} else {
|
||||
GLenum bufs[] = {buf};
|
||||
NamedFramebufferDrawBuffers_State(framebuffer, 1, bufs);
|
||||
}
|
||||
}
|
||||
|
||||
void NamedFramebufferReadBuffer_State(GLuint framebuffer, GLenum src) {
|
||||
auto framebufferObject = GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferReadBuffer_State");
|
||||
if (!framebufferObject) return;
|
||||
|
||||
auto attType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(src);
|
||||
if (attType == FramebufferAttachmentType::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "NamedFramebufferReadBuffer_State",
|
||||
std::format("`src` = {} is not an accepted value.", MG_Util::ConvertGLEnumToString(src))));
|
||||
return;
|
||||
}
|
||||
framebufferObject->SetReadBuffer(attType);
|
||||
}
|
||||
|
||||
SharedPtr<MG_State::GLState::FramebufferObject> GetFramebufferObjectForNamedClear(GLuint framebuffer,
|
||||
const char* caller) {
|
||||
return framebuffer == 0 ? FramebufferImpl::pDefaultFramebufferInfo->defaultFBO
|
||||
: GetNamedFramebufferObject_State(framebuffer, caller);
|
||||
}
|
||||
|
||||
Bool ValidateNamedClearfv_State(GLenum buffer, GLint drawbuffer, const GLfloat* value, const char* caller) {
|
||||
if (!value) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "value pointer cannot be null."));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (buffer) {
|
||||
case GL_COLOR:
|
||||
if (drawbuffer < 0 ||
|
||||
drawbuffer >= static_cast<GLint>(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "color drawbuffer index is out of range."));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case GL_DEPTH:
|
||||
if (drawbuffer != 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "depth clear requires drawbuffer 0."));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", caller,
|
||||
std::format("buffer {} is not accepted for glClearNamedFramebufferfv.",
|
||||
MG_Util::ConvertGLEnumToString(buffer))));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Bool ValidateNamedClearfi_State(GLenum buffer, GLint drawbuffer, const char* caller) {
|
||||
if (buffer != GL_DEPTH_STENCIL) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", caller,
|
||||
std::format("buffer {} is not accepted for glClearNamedFramebufferfi.",
|
||||
MG_Util::ConvertGLEnumToString(buffer))));
|
||||
return false;
|
||||
}
|
||||
if (drawbuffer != 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "depth/stencil clear requires drawbuffer 0."));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClearNamedFramebufferfv_State(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value) {
|
||||
auto framebufferObject = GetFramebufferObjectForNamedClear(framebuffer, "ClearNamedFramebufferfv_State");
|
||||
if (!framebufferObject) return;
|
||||
if (!ValidateNamedClearfv_State(buffer, drawbuffer, value, "ClearNamedFramebufferfv_State")) return;
|
||||
ClearNamedFramebufferfv_Backend(framebufferObject, buffer, drawbuffer, value);
|
||||
}
|
||||
|
||||
void ClearNamedFramebufferfi_State(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth,
|
||||
GLint stencil) {
|
||||
auto framebufferObject = GetFramebufferObjectForNamedClear(framebuffer, "ClearNamedFramebufferfi_State");
|
||||
if (!framebufferObject) return;
|
||||
if (!ValidateNamedClearfi_State(buffer, drawbuffer, "ClearNamedFramebufferfi_State")) return;
|
||||
ClearNamedFramebufferfi_Backend(framebufferObject, buffer, drawbuffer, depth, stencil);
|
||||
}
|
||||
|
||||
void DeleteRenderbuffers_State(GLsizei n, const GLuint* renderbuffers) {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
@@ -376,7 +752,117 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
// GL_FRAMEBUFFER_UNSUPPORTED, GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
|
||||
// GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS
|
||||
return framebufferObject->CheckCompleteness() ? GL_FRAMEBUFFER_COMPLETE
|
||||
: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
|
||||
: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
|
||||
}
|
||||
|
||||
GLenum CheckNamedFramebufferStatus_State(GLuint framebuffer, GLenum target) {
|
||||
if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CheckNamedFramebufferStatus_State",
|
||||
std::format("target {} is not accepted.",
|
||||
MG_Util::ConvertGLEnumToString(target))));
|
||||
return GL_FRAMEBUFFER_UNDEFINED;
|
||||
}
|
||||
|
||||
auto framebufferObject = GetNamedFramebufferObject_State(framebuffer, "CheckNamedFramebufferStatus_State");
|
||||
if (!framebufferObject) return GL_FRAMEBUFFER_UNDEFINED;
|
||||
|
||||
return framebufferObject->CheckCompleteness() ? GL_FRAMEBUFFER_COMPLETE
|
||||
: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
|
||||
}
|
||||
|
||||
void GetFramebufferAttachmentParameteriv_Object(
|
||||
const SharedPtr<MG_State::GLState::FramebufferObject>& framebufferObject, GLenum attachment, GLenum pname,
|
||||
GLint* params, const char* caller) {
|
||||
if (params == nullptr) return;
|
||||
|
||||
const Bool depthStencilAlias = attachment == GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
FramebufferAttachmentType attachmentType = depthStencilAlias
|
||||
? FramebufferAttachmentType::Depth
|
||||
: MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
|
||||
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
|
||||
|
||||
const auto* attachmentObject = [&]() -> const MG_State::GLState::FramebufferAttachmentObject* {
|
||||
if (!depthStencilAlias) {
|
||||
return &framebufferObject->GetAttachment(attachmentType);
|
||||
}
|
||||
|
||||
const auto& depthAttachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Depth);
|
||||
if (depthAttachment.IsValid() && !depthAttachment.IsEmpty()) return &depthAttachment;
|
||||
|
||||
const auto& stencilAttachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil);
|
||||
if (stencilAttachment.IsValid() && !stencilAttachment.IsEmpty()) return &stencilAttachment;
|
||||
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
switch (pname) {
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
|
||||
if (attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid()) {
|
||||
*params = GL_NONE;
|
||||
} else if (attachmentObject->IsTexture()) {
|
||||
*params = GL_TEXTURE;
|
||||
} else if (attachmentObject->IsRenderbuffer()) {
|
||||
*params = GL_RENDERBUFFER;
|
||||
} else {
|
||||
*params = GL_NONE;
|
||||
}
|
||||
break;
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
|
||||
if (attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid()) {
|
||||
*params = 0;
|
||||
} else if (attachmentObject->IsTexture()) {
|
||||
const auto& textureObject = attachmentObject->GetTexture();
|
||||
*params = textureObject ? static_cast<GLint>(textureObject->GetExternalIndex()) : 0;
|
||||
} else if (attachmentObject->IsRenderbuffer()) {
|
||||
const auto& renderbufferObject = attachmentObject->GetRenderbuffer();
|
||||
*params = renderbufferObject ? static_cast<GLint>(renderbufferObject->GetExternalIndex()) : 0;
|
||||
} else {
|
||||
*params = 0;
|
||||
}
|
||||
break;
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
|
||||
*params = (attachmentObject != nullptr && attachmentObject->IsTexture() && attachmentObject->IsValid())
|
||||
? static_cast<GLint>(attachmentObject->GetTextureLevel())
|
||||
: 0;
|
||||
break;
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
|
||||
*params = 0;
|
||||
break;
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", caller,
|
||||
std::format("pname {} is not an accepted value.", MG_Util::ConvertGLEnumToString(pname))));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void GetNamedFramebufferAttachmentParameteriv_State(GLuint framebuffer, GLenum attachment, GLenum pname,
|
||||
GLint* params) {
|
||||
auto framebufferObject =
|
||||
GetNamedFramebufferObject_State(framebuffer, "GetNamedFramebufferAttachmentParameteriv_State");
|
||||
if (!framebufferObject) return;
|
||||
GetFramebufferAttachmentParameteriv_Object(framebufferObject, attachment, pname, params,
|
||||
"GetNamedFramebufferAttachmentParameteriv_State");
|
||||
}
|
||||
|
||||
void BlitNamedFramebuffer_State(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0,
|
||||
GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||
GLbitfield mask, GLenum filter) {
|
||||
auto readObject = readFramebuffer == 0
|
||||
? FramebufferImpl::pDefaultFramebufferInfo->defaultFBO
|
||||
: GetNamedFramebufferObject_State(readFramebuffer, "BlitNamedFramebuffer_State");
|
||||
auto drawObject = drawFramebuffer == 0
|
||||
? FramebufferImpl::pDefaultFramebufferInfo->defaultFBO
|
||||
: GetNamedFramebufferObject_State(drawFramebuffer, "BlitNamedFramebuffer_State");
|
||||
if (!readObject || !drawObject) return;
|
||||
|
||||
BlitNamedFramebuffer_Backend(readObject, drawObject, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1,
|
||||
mask, filter);
|
||||
}
|
||||
|
||||
void BindRenderbuffer_State(GLenum target, GLuint renderbuffer) {
|
||||
@@ -415,18 +901,15 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
bindingSlot.Bind(framebufferObject);
|
||||
}
|
||||
|
||||
void GetRenderbufferParameteriv_State(GLenum target, GLenum pname, GLint* params) {
|
||||
void GetRenderbufferParameterivForObject_State(const SharedPtr<MG_State::GLState::RenderbufferObject>&
|
||||
renderbufferObject,
|
||||
GLenum pname, GLint* params, const char* caller) {
|
||||
if (!params) return;
|
||||
|
||||
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
|
||||
if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return;
|
||||
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
|
||||
auto& renderbufferObject = bindingSlot.GetBoundObject();
|
||||
if (!renderbufferObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetRenderbufferParameteriv_State",
|
||||
"Renderbuffer target is bound to no renderbuffer object."));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "No renderbuffer object is available."));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -465,12 +948,27 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "GetRenderbufferParameteriv_State",
|
||||
"MG_Impl/GLImpl", caller,
|
||||
std::format("pname {} is not an accepted value.", MG_Util::ConvertGLEnumToString(pname))));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void GetRenderbufferParameteriv_State(GLenum target, GLenum pname, GLint* params) {
|
||||
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
|
||||
if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return;
|
||||
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
|
||||
auto& renderbufferObject = bindingSlot.GetBoundObject();
|
||||
GetRenderbufferParameterivForObject_State(renderbufferObject, pname, params, "GetRenderbufferParameteriv_State");
|
||||
}
|
||||
|
||||
void GetNamedRenderbufferParameteriv_State(GLuint renderbuffer, GLenum pname, GLint* params) {
|
||||
auto renderbufferObject =
|
||||
GetNamedRenderbufferObject_State(renderbuffer, "GetNamedRenderbufferParameteriv_State");
|
||||
GetRenderbufferParameterivForObject_State(renderbufferObject, pname, params,
|
||||
"GetNamedRenderbufferParameteriv_State");
|
||||
}
|
||||
|
||||
void ClearBufferfi_Backend(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
|
||||
MG_Backend::gBackendFunctionsTable.GL.ClearBufferfi(buffer, drawbuffer, depth, stencil);
|
||||
}
|
||||
@@ -576,8 +1074,9 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||
|
||||
if (pixelPackBufferObject) {
|
||||
// Check if PBO is mapped
|
||||
if (pixelPackBufferObject->IsMapped()) {
|
||||
// Persistent mappings remain legal GPU transfer destinations.
|
||||
if (pixelPackBufferObject->IsMapped() &&
|
||||
!(pixelPackBufferObject->GetMappingAccess() & BufferMappingAccessBit::Persistent)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
"Pixel pack buffer is currently mapped"));
|
||||
@@ -663,10 +1162,26 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
GenRenderbuffers_State(n, renderbuffers);
|
||||
}
|
||||
|
||||
void CreateRenderbuffers(GLsizei n, GLuint* renderbuffers) {
|
||||
CreateRenderbuffers_State(n, renderbuffers);
|
||||
}
|
||||
|
||||
void NamedRenderbufferStorage(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) {
|
||||
NamedRenderbufferStorage_State(renderbuffer, internalformat, width, height);
|
||||
}
|
||||
|
||||
void GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, GLint* params) {
|
||||
GetNamedRenderbufferParameteriv_State(renderbuffer, pname, params);
|
||||
}
|
||||
|
||||
void GenFramebuffers(GLsizei n, GLuint* framebuffers) {
|
||||
GenFramebuffers_State(n, framebuffers);
|
||||
}
|
||||
|
||||
void CreateFramebuffers(GLsizei n, GLuint* framebuffers) {
|
||||
CreateFramebuffers_State(n, framebuffers);
|
||||
}
|
||||
|
||||
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) {
|
||||
FramebufferTextureLayer_State(target, attachment, texture, level, layer);
|
||||
}
|
||||
@@ -688,10 +1203,39 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
FramebufferTexture_State(target, attachment, texture, level);
|
||||
}
|
||||
|
||||
void NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) {
|
||||
NamedFramebufferTexture_State(framebuffer, attachment, texture, level);
|
||||
}
|
||||
|
||||
void NamedFramebufferDrawBuffer(GLuint framebuffer, GLenum buf) {
|
||||
NamedFramebufferDrawBuffer_State(framebuffer, buf);
|
||||
}
|
||||
|
||||
void NamedFramebufferDrawBuffers(GLuint framebuffer, GLsizei n, const GLenum* bufs) {
|
||||
NamedFramebufferDrawBuffers_State(framebuffer, n, bufs);
|
||||
}
|
||||
|
||||
void NamedFramebufferReadBuffer(GLuint framebuffer, GLenum src) {
|
||||
NamedFramebufferReadBuffer_State(framebuffer, src);
|
||||
}
|
||||
|
||||
void ClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value) {
|
||||
ClearNamedFramebufferfv_State(framebuffer, buffer, drawbuffer, value);
|
||||
}
|
||||
|
||||
void ClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
|
||||
ClearNamedFramebufferfi_State(framebuffer, buffer, drawbuffer, depth, stencil);
|
||||
}
|
||||
|
||||
void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {
|
||||
FramebufferRenderbuffer_State(target, attachment, renderbuffertarget, renderbuffer);
|
||||
}
|
||||
|
||||
void NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget,
|
||||
GLuint renderbuffer) {
|
||||
NamedFramebufferRenderbuffer_State(framebuffer, attachment, renderbuffertarget, renderbuffer);
|
||||
}
|
||||
|
||||
void DrawBuffer(GLenum buf) {
|
||||
DrawBuffer_State(buf);
|
||||
}
|
||||
@@ -716,6 +1260,21 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return CheckFramebufferStatus_State(target);
|
||||
}
|
||||
|
||||
GLenum CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target) {
|
||||
return CheckNamedFramebufferStatus_State(framebuffer, target);
|
||||
}
|
||||
|
||||
void GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) {
|
||||
GetNamedFramebufferAttachmentParameteriv_State(framebuffer, attachment, pname, params);
|
||||
}
|
||||
|
||||
void BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1,
|
||||
GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
|
||||
GLenum filter) {
|
||||
BlitNamedFramebuffer_State(readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
|
||||
dstY1, mask, filter);
|
||||
}
|
||||
|
||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||
GLint dstY1, GLbitfield mask, GLenum filter) {
|
||||
BlitFramebuffer_Backend(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
|
||||
@@ -24,19 +24,36 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
GLboolean IsRenderbuffer(GLuint renderbuffer);
|
||||
void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
||||
void GenRenderbuffers(GLsizei n, GLuint* renderbuffers);
|
||||
void CreateRenderbuffers(GLsizei n, GLuint* renderbuffers);
|
||||
void NamedRenderbufferStorage(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
void GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, GLint* params);
|
||||
void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
|
||||
void NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget,
|
||||
GLuint renderbuffer);
|
||||
void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
|
||||
void BindRenderbuffer(GLenum target, GLuint renderbuffer);
|
||||
void SampleMaski(GLuint maskNumber, GLbitfield mask);
|
||||
GLboolean IsFramebuffer(GLuint framebuffer);
|
||||
void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
|
||||
void GenFramebuffers(GLsizei n, GLuint* framebuffers);
|
||||
void CreateFramebuffers(GLsizei n, GLuint* framebuffers);
|
||||
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
|
||||
void FramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level,
|
||||
GLint zoffset);
|
||||
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||
void FramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||
void FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level);
|
||||
void NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);
|
||||
void NamedFramebufferDrawBuffer(GLuint framebuffer, GLenum buf);
|
||||
void NamedFramebufferDrawBuffers(GLuint framebuffer, GLsizei n, const GLenum* bufs);
|
||||
void NamedFramebufferReadBuffer(GLuint framebuffer, GLenum src);
|
||||
void ClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||
void ClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||
GLenum CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target);
|
||||
void GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params);
|
||||
void BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1,
|
||||
GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
|
||||
GLenum filter);
|
||||
void DrawBuffer(GLenum buf);
|
||||
void DrawBuffers(GLsizei n, const GLenum* bufs);
|
||||
void ReadBuffer(GLenum src);
|
||||
|
||||
@@ -76,12 +76,12 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
MGLOG_D("shadingLanguageVersion: %s", shadingLanguageVersion.c_str());
|
||||
return (const GLubyte*)shadingLanguageVersion.c_str();
|
||||
case GL_EXTENSIONS:
|
||||
if (extensionsString.empty()) {
|
||||
for (auto& ext : rendererInfo.RendererGLInfo.Extensions) {
|
||||
extensionsString += MG_Util::ConvertGLExtToString(ext);
|
||||
extensionsString.clear();
|
||||
for (auto& ext : rendererInfo.RendererGLInfo.Extensions) {
|
||||
if (!extensionsString.empty()) {
|
||||
extensionsString += " ";
|
||||
}
|
||||
extensionsString.pop_back();
|
||||
extensionsString += MG_Util::ConvertGLExtToString(ext);
|
||||
}
|
||||
return (const GLubyte*)extensionsString.c_str();
|
||||
default:
|
||||
@@ -108,18 +108,89 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
static Vector<String> extStrings;
|
||||
static Bool initialized = false;
|
||||
if (!initialized) {
|
||||
extStrings.reserve(exts.size());
|
||||
for (const auto& ext : exts) {
|
||||
extStrings.emplace_back(MG_Util::ConvertGLExtToString(ext));
|
||||
}
|
||||
initialized = true;
|
||||
extStrings.clear();
|
||||
extStrings.reserve(exts.size());
|
||||
for (const auto& ext : exts) {
|
||||
extStrings.emplace_back(MG_Util::ConvertGLExtToString(ext));
|
||||
}
|
||||
|
||||
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) {
|
||||
MGLOG_D("glGetIntegerv, pname: %s", MG_Util::ConvertGLEnumToString(pname).c_str());
|
||||
if (!params) {
|
||||
@@ -135,6 +206,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return;
|
||||
}
|
||||
const auto& rendererInfo = activeBackendObject->GetRendererInfo();
|
||||
const auto& dynamicParameters = activeBackendObject->GetDynamicParameters();
|
||||
|
||||
switch (pname) {
|
||||
case GL_ACTIVE_TEXTURE:
|
||||
@@ -160,31 +232,39 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
case GL_BLEND_DST_ALPHA: {
|
||||
BlendFactor 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;
|
||||
}
|
||||
case GL_BLEND_DST_RGB: {
|
||||
BlendFactor 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;
|
||||
}
|
||||
case GL_BLEND_EQUATION_RGB:
|
||||
*params = 0; // TODO
|
||||
case GL_BLEND_EQUATION_RGB: {
|
||||
BlendEquation colorEquation = BlendEquation::Add;
|
||||
BlendEquation alphaEquation = BlendEquation::Add;
|
||||
MG_State::pGLContext->GetBlendEquation(colorEquation, alphaEquation);
|
||||
*params = static_cast<GLint>(MG_Util::ConvertBlendEquationToGLEnum(colorEquation));
|
||||
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;
|
||||
}
|
||||
case GL_BLEND_SRC_ALPHA: {
|
||||
BlendFactor 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;
|
||||
}
|
||||
case GL_BLEND_SRC_RGB: {
|
||||
BlendFactor 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;
|
||||
}
|
||||
case GL_COLOR_CLEAR_VALUE:
|
||||
@@ -204,42 +284,60 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
case GL_COMPRESSED_TEXTURE_FORMATS:
|
||||
*params = 0; // TODO
|
||||
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:
|
||||
*params = 0; // TODO
|
||||
*params = 16; // TODO: use backend value
|
||||
break;
|
||||
case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS:
|
||||
*params = 0; // TODO
|
||||
*params = 96; // TODO: use backend value
|
||||
break;
|
||||
case GL_MAX_COMPUTE_UNIFORM_BLOCKS:
|
||||
*params = 0; // TODO
|
||||
*params = 14; // TODO: use backend value
|
||||
break;
|
||||
case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS:
|
||||
*params = 0; // TODO
|
||||
*params = MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; // TODO: use backend value
|
||||
break;
|
||||
case GL_MAX_COMPUTE_UNIFORM_COMPONENTS:
|
||||
*params = 0; // TODO
|
||||
*params = 1024 * 4; // TODO: use backend value
|
||||
break;
|
||||
case GL_MAX_COMPUTE_ATOMIC_COUNTERS:
|
||||
*params = 0; // TODO
|
||||
*params = 8; // TODO: use backend value
|
||||
break;
|
||||
case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS:
|
||||
*params = 0; // TODO
|
||||
*params = 8; // TODO: use backend value
|
||||
break;
|
||||
case GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS:
|
||||
*params = 0; // TODO
|
||||
*params = 1024 * 228; // TODO: use backend value
|
||||
break;
|
||||
case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS:
|
||||
*params = 0; // TODO
|
||||
*params = 1024; // TODO: use backend value
|
||||
break;
|
||||
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;
|
||||
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;
|
||||
case GL_DISPATCH_INDIRECT_BUFFER_BINDING:
|
||||
*params = 0; // TODO
|
||||
case GL_DISPATCH_INDIRECT_BUFFER_BINDING: {
|
||||
auto& obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DispatchIndirect).GetBoundObject();
|
||||
*params = obj ? static_cast<GLint>(obj->GetExternalIndex()) : 0;
|
||||
break;
|
||||
}
|
||||
case GL_MAX_DEBUG_GROUP_STACK_DEPTH:
|
||||
*params = 0; // TODO
|
||||
break;
|
||||
@@ -252,6 +350,12 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
case GL_CULL_FACE:
|
||||
*params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace) ? GL_TRUE : GL_FALSE;
|
||||
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: {
|
||||
const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||
*params = currentProgram ? (GLint)currentProgram->GetExternalIndex() : 0;
|
||||
@@ -426,6 +530,22 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
case GL_MAX_GEOMETRY_UNIFORM_COMPONENTS:
|
||||
*params = 1024 * 4; // TODO
|
||||
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:
|
||||
*params = 16; // TODO
|
||||
break;
|
||||
@@ -571,6 +691,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
case GL_PIXEL_UNPACK_BUFFER_BINDING:
|
||||
*params = 0; // TODO
|
||||
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:
|
||||
*params = 0; // TODO
|
||||
break;
|
||||
@@ -587,11 +712,16 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
*params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ProgramPointSize) ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GL_PROVOKING_VERTEX:
|
||||
*params = 0; // TODO
|
||||
*params = static_cast<GLint>(
|
||||
MG_Util::ConvertProvokingVertexModeToGLEnum(MG_State::pGLContext->GetProvokingVertexMode()));
|
||||
break;
|
||||
case GL_POINT_SIZE:
|
||||
*params = 0; // TODO
|
||||
break;
|
||||
case GL_POLYGON_MODE:
|
||||
params[0] = GL_FILL;
|
||||
params[1] = GL_FILL;
|
||||
break;
|
||||
case GL_POINT_SIZE_GRANULARITY:
|
||||
*params = 0; // TODO
|
||||
break;
|
||||
@@ -659,11 +789,13 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
case GL_SHADER_COMPILER:
|
||||
*params = 0; // TODO
|
||||
break;
|
||||
case GL_SHADER_STORAGE_BUFFER_BINDING:
|
||||
*params = 0; // TODO
|
||||
case GL_SHADER_STORAGE_BUFFER_BINDING: {
|
||||
auto& obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::ShaderStorage).GetBoundObject();
|
||||
*params = obj ? static_cast<GLint>(obj->GetExternalIndex()) : 0;
|
||||
break;
|
||||
}
|
||||
case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT:
|
||||
*params = 0; // TODO
|
||||
*params = 256; // TODO: use backend value
|
||||
break;
|
||||
case GL_SHADER_STORAGE_BUFFER_START:
|
||||
*params = 0; // TODO
|
||||
|
||||
@@ -14,5 +14,8 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
const GLubyte* GetString(GLenum name);
|
||||
const GLubyte* GetStringi(GLenum name, GLuint index);
|
||||
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();
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <MG_Util/Converters/GLToMG/ProgramEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h>
|
||||
#include <MG_Util/Converters/SPIRVCrossToGL/SpvcTypeConverter.h>
|
||||
#include <MG_Backend/BackendObjects.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
static bool CheckShaderNameValidity(Uint shader) {
|
||||
@@ -68,13 +69,15 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
void CopyStr(GLsizei bufSize, GLsizei* length, GLchar* dst, const char* src, GLsizei srcLength) {
|
||||
if (bufSize <= 0) {
|
||||
if (length) *length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
auto sz = std::min(bufSize - 1, srcLength);
|
||||
if (length) *length = sz;
|
||||
|
||||
if (bufSize == 0) return;
|
||||
|
||||
Memcpy(dst, src, sz);
|
||||
dst[sz] = '\0';
|
||||
if (length) *length = sz;
|
||||
}
|
||||
|
||||
void AttachShader_State(GLuint program, GLuint shader) {
|
||||
@@ -303,7 +306,23 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
*params = programObject->GetActiveUniformBlocksMaxNameLength();
|
||||
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
|
||||
break;
|
||||
case GL_COMPUTE_WORK_GROUP_SIZE: // GL >= 4.3
|
||||
case GL_COMPUTE_WORK_GROUP_SIZE: { // GL >= 4.3
|
||||
auto getProgramiv = MG_Backend::gBackendFunctionsTable.GL.GetProgramiv;
|
||||
if (!getProgramiv) {
|
||||
params[0] = 1;
|
||||
params[1] = 1;
|
||||
params[2] = 1;
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"Backend does not support program integer queries."));
|
||||
return;
|
||||
}
|
||||
getProgramiv(program, pname, params);
|
||||
MGLOG_D("%s: %s = (%d, %d, %d)", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), params[0],
|
||||
params[1], params[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
case GL_PROGRAM_BINARY_LENGTH:
|
||||
|
||||
@@ -346,10 +365,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
*params = shaderObject->GetCompileStatus();
|
||||
break;
|
||||
case GL_INFO_LOG_LENGTH:
|
||||
*params = (GLint)shaderObject->GetInfoLog().length();
|
||||
*params = shaderObject->GetInfoLog().empty() ? 0 : (GLint)shaderObject->GetInfoLog().length() + 1;
|
||||
break;
|
||||
case GL_SHADER_SOURCE_LENGTH:
|
||||
*params = (GLint)shaderObject->GetShaderSource().length();
|
||||
*params = shaderObject->GetShaderSource().empty() ? 0 : (GLint)shaderObject->GetShaderSource().length() + 1;
|
||||
break;
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(
|
||||
@@ -462,7 +481,8 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
* A program object marked for deletion with glDeleteProgram but still in use as part of current
|
||||
* rendering state is still considered a program object and glIsProgram will return GL_TRUE.
|
||||
*/
|
||||
return CheckProgramNameValidity(program);
|
||||
if (program == 0) return GL_FALSE;
|
||||
return MG_State::pGLContext->ValidateProgramName(program) ? GL_TRUE : GL_FALSE;
|
||||
}
|
||||
|
||||
GLboolean IsShader_State(GLuint shader) {
|
||||
@@ -470,7 +490,8 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
* A shader object marked for deletion with glDeleteShader but still attached to a program object is still
|
||||
* considered a shader object and glIsShader will return GL_TRUE.
|
||||
*/
|
||||
return CheckShaderNameValidity(shader);
|
||||
if (shader == 0) return GL_FALSE;
|
||||
return MG_State::pGLContext->ValidateShaderName(shader) ? GL_TRUE : GL_FALSE;
|
||||
}
|
||||
|
||||
void LinkProgram_State(GLuint program) {
|
||||
@@ -506,7 +527,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
|
||||
std::string src;
|
||||
for (GLsizei i = 0; i < count; i++) {
|
||||
src += (length == nullptr || length[i] <= 0) ? string[i] : std::string(string[i], length[i]);
|
||||
if (!string[i]) {
|
||||
continue;
|
||||
}
|
||||
src += (length && length[i] >= 0) ? std::string(string[i], length[i]) : std::string(string[i]);
|
||||
}
|
||||
shaderObject->SetShaderSource(Move(src));
|
||||
}
|
||||
@@ -541,6 +565,9 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
} else {
|
||||
auto* ttype = programObject.GetUniformTType(location);
|
||||
if (ttype->isTexture() || ttype->isImage()) {
|
||||
MGLOG_D("%s: program = %d, opaque uniform location = %d, name = '%s', unit = %d", __func__,
|
||||
programObject.GetExternalIndex(), location, programObject.GetUniformName(location).c_str(),
|
||||
static_cast<Int>(*value));
|
||||
programObject.SetUniformSamplerOrImageUnitIndex(location, *value);
|
||||
}
|
||||
}
|
||||
@@ -574,6 +601,36 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
}
|
||||
|
||||
template <GLsizei ItemCount, typename T>
|
||||
void ProgramUniformv_State(GLuint program, GLint location, GLsizei count, T* value) {
|
||||
if (location == -1) return;
|
||||
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject) return;
|
||||
|
||||
if (!programObject->GetLinkStatus()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"program " + std::to_string(program) + " is not linked."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (location > programObject->GetMaxUniformLocation() || location < -1) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"location " + std::to_string(location) +
|
||||
" is an invalid uniform location for program " +
|
||||
std::to_string(program) + "."));
|
||||
return;
|
||||
}
|
||||
|
||||
for (GLint offset = 0; offset < count; offset++) {
|
||||
Uniform_State<ItemCount>(*programObject, location + offset, value + offset * ItemCount);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to transpose a 2x2 matrix
|
||||
void TransposeMatrix2x2(const GLfloat* input, GLfloat* output) {
|
||||
// Input matrix is in column-major order (OpenGL default)
|
||||
@@ -674,6 +731,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
Uniformv_State<4>(location, count, value);
|
||||
}
|
||||
|
||||
void Uniform1uiv_State(GLint location, GLsizei count, const GLuint* value) {
|
||||
Uniformv_State<1>(location, count, value);
|
||||
}
|
||||
|
||||
void UniformMatrix2fv_State(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
// For 2x2 matrices, we have 4 elements per matrix
|
||||
// If transpose is GL_TRUE, we need to transpose the matrix data
|
||||
@@ -793,6 +854,118 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
}
|
||||
|
||||
void ProgramUniformMatrix2fv_State(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
if (location == -1) return;
|
||||
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject) return;
|
||||
|
||||
if (!programObject->GetLinkStatus()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"program " + std::to_string(program) + " is not linked."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (location > programObject->GetMaxUniformLocation() || location < -1) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"location " + std::to_string(location) +
|
||||
" is an invalid uniform location for program " +
|
||||
std::to_string(program) + "."));
|
||||
return;
|
||||
}
|
||||
|
||||
for (GLint i = 0; i < count; i++) {
|
||||
if (transpose == GL_TRUE) {
|
||||
GLfloat transposedMatrix[4];
|
||||
TransposeMatrix2x2(value + i * 4, transposedMatrix);
|
||||
Uniform_State<4>(*programObject, location + i, transposedMatrix);
|
||||
} else {
|
||||
Uniform_State<4>(*programObject, location + i, value + i * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProgramUniformMatrix3fv_State(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
if (location == -1) return;
|
||||
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject) return;
|
||||
|
||||
if (!programObject->GetLinkStatus()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"program " + std::to_string(program) + " is not linked."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (location > programObject->GetMaxUniformLocation() || location < -1) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"location " + std::to_string(location) +
|
||||
" is an invalid uniform location for program " +
|
||||
std::to_string(program) + "."));
|
||||
return;
|
||||
}
|
||||
|
||||
for (GLint i = 0; i < count; i++) {
|
||||
if (transpose == GL_TRUE) {
|
||||
GLfloat transposedMatrix[9];
|
||||
TransposeMatrix3x3(value + i * 9, transposedMatrix);
|
||||
for (int row = 0; row < 3; ++row) {
|
||||
Uniform_State<3>(*programObject, location + i, transposedMatrix + row * 3, row * 4 * sizeof(float));
|
||||
}
|
||||
} else {
|
||||
for (int row = 0; row < 3; ++row) {
|
||||
Uniform_State<3>(*programObject, location + i, value + i * 9 + row * 3, row * 4 * sizeof(float));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProgramUniformMatrix4fv_State(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
if (location == -1) return;
|
||||
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject) return;
|
||||
|
||||
if (!programObject->GetLinkStatus()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"program " + std::to_string(program) + " is not linked."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (location > programObject->GetMaxUniformLocation() || location < -1) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"location " + std::to_string(location) +
|
||||
" is an invalid uniform location for program " +
|
||||
std::to_string(program) + "."));
|
||||
return;
|
||||
}
|
||||
|
||||
for (GLint i = 0; i < count; i++) {
|
||||
if (transpose == GL_TRUE) {
|
||||
GLfloat transposedMatrix[16];
|
||||
TransposeMatrix4x4(value + i * 16, transposedMatrix);
|
||||
Uniform_State<16>(*programObject, location + i, transposedMatrix);
|
||||
} else {
|
||||
Uniform_State<16>(*programObject, location + i, value + i * 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLuint GetUniformBlockIndex_State(GLuint program, const GLchar* uniformBlockName) {
|
||||
const auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject) return GL_INVALID_INDEX;
|
||||
@@ -1094,6 +1267,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
Uniform4iv(location, 1, v);
|
||||
}
|
||||
|
||||
void Uniform1ui(GLint location, GLuint v0) {
|
||||
Uniform1uiv(location, 1, &v0);
|
||||
}
|
||||
|
||||
void Uniform1fv(GLint location, GLsizei count, const GLfloat* value) {
|
||||
Uniform1fv_State(location, count, value);
|
||||
}
|
||||
@@ -1126,6 +1303,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
Uniform4iv_State(location, count, value);
|
||||
}
|
||||
|
||||
void Uniform1uiv(GLint location, GLsizei count, const GLuint* value) {
|
||||
Uniform1uiv_State(location, count, value);
|
||||
}
|
||||
|
||||
void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
UniformMatrix2fv_State(location, count, transpose, value);
|
||||
}
|
||||
@@ -1138,6 +1319,126 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
UniformMatrix4fv_State(location, count, transpose, value);
|
||||
}
|
||||
|
||||
void ProgramUniform1f(GLuint program, GLint location, GLfloat v0) {
|
||||
ProgramUniform1fv(program, location, 1, &v0);
|
||||
}
|
||||
|
||||
void ProgramUniform2f(GLuint program, GLint location, GLfloat v0, GLfloat v1) {
|
||||
GLfloat v[] = {v0, v1};
|
||||
ProgramUniform2fv(program, location, 1, v);
|
||||
}
|
||||
|
||||
void ProgramUniform3f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {
|
||||
GLfloat v[] = {v0, v1, v2};
|
||||
ProgramUniform3fv(program, location, 1, v);
|
||||
}
|
||||
|
||||
void ProgramUniform4f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {
|
||||
GLfloat v[] = {v0, v1, v2, v3};
|
||||
ProgramUniform4fv(program, location, 1, v);
|
||||
}
|
||||
|
||||
void ProgramUniform1i(GLuint program, GLint location, GLint v0) {
|
||||
ProgramUniform1iv(program, location, 1, &v0);
|
||||
}
|
||||
|
||||
void ProgramUniform2i(GLuint program, GLint location, GLint v0, GLint v1) {
|
||||
GLint v[] = {v0, v1};
|
||||
ProgramUniform2iv(program, location, 1, v);
|
||||
}
|
||||
|
||||
void ProgramUniform3i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2) {
|
||||
GLint v[] = {v0, v1, v2};
|
||||
ProgramUniform3iv(program, location, 1, v);
|
||||
}
|
||||
|
||||
void ProgramUniform4i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {
|
||||
GLint v[] = {v0, v1, v2, v3};
|
||||
ProgramUniform4iv(program, location, 1, v);
|
||||
}
|
||||
|
||||
void ProgramUniform1ui(GLuint program, GLint location, GLuint v0) {
|
||||
ProgramUniform1uiv(program, location, 1, &v0);
|
||||
}
|
||||
|
||||
void ProgramUniform2ui(GLuint program, GLint location, GLuint v0, GLuint v1) {
|
||||
GLuint v[] = {v0, v1};
|
||||
ProgramUniform2uiv(program, location, 1, v);
|
||||
}
|
||||
|
||||
void ProgramUniform3ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) {
|
||||
GLuint v[] = {v0, v1, v2};
|
||||
ProgramUniform3uiv(program, location, 1, v);
|
||||
}
|
||||
|
||||
void ProgramUniform4ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) {
|
||||
GLuint v[] = {v0, v1, v2, v3};
|
||||
ProgramUniform4uiv(program, location, 1, v);
|
||||
}
|
||||
|
||||
void ProgramUniform1fv(GLuint program, GLint location, GLsizei count, const GLfloat* value) {
|
||||
ProgramUniformv_State<1>(program, location, count, value);
|
||||
}
|
||||
|
||||
void ProgramUniform2fv(GLuint program, GLint location, GLsizei count, const GLfloat* value) {
|
||||
ProgramUniformv_State<2>(program, location, count, value);
|
||||
}
|
||||
|
||||
void ProgramUniform3fv(GLuint program, GLint location, GLsizei count, const GLfloat* value) {
|
||||
ProgramUniformv_State<3>(program, location, count, value);
|
||||
}
|
||||
|
||||
void ProgramUniform4fv(GLuint program, GLint location, GLsizei count, const GLfloat* value) {
|
||||
ProgramUniformv_State<4>(program, location, count, value);
|
||||
}
|
||||
|
||||
void ProgramUniform1iv(GLuint program, GLint location, GLsizei count, const GLint* value) {
|
||||
ProgramUniformv_State<1>(program, location, count, value);
|
||||
}
|
||||
|
||||
void ProgramUniform2iv(GLuint program, GLint location, GLsizei count, const GLint* value) {
|
||||
ProgramUniformv_State<2>(program, location, count, value);
|
||||
}
|
||||
|
||||
void ProgramUniform3iv(GLuint program, GLint location, GLsizei count, const GLint* value) {
|
||||
ProgramUniformv_State<3>(program, location, count, value);
|
||||
}
|
||||
|
||||
void ProgramUniform4iv(GLuint program, GLint location, GLsizei count, const GLint* value) {
|
||||
ProgramUniformv_State<4>(program, location, count, value);
|
||||
}
|
||||
|
||||
void ProgramUniform1uiv(GLuint program, GLint location, GLsizei count, const GLuint* value) {
|
||||
ProgramUniformv_State<1>(program, location, count, value);
|
||||
}
|
||||
|
||||
void ProgramUniform2uiv(GLuint program, GLint location, GLsizei count, const GLuint* value) {
|
||||
ProgramUniformv_State<2>(program, location, count, value);
|
||||
}
|
||||
|
||||
void ProgramUniform3uiv(GLuint program, GLint location, GLsizei count, const GLuint* value) {
|
||||
ProgramUniformv_State<3>(program, location, count, value);
|
||||
}
|
||||
|
||||
void ProgramUniform4uiv(GLuint program, GLint location, GLsizei count, const GLuint* value) {
|
||||
ProgramUniformv_State<4>(program, location, count, value);
|
||||
}
|
||||
|
||||
void ProgramUniformMatrix2fv(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
ProgramUniformMatrix2fv_State(program, location, count, transpose, value);
|
||||
}
|
||||
|
||||
void ProgramUniformMatrix3fv(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
ProgramUniformMatrix3fv_State(program, location, count, transpose, value);
|
||||
}
|
||||
|
||||
void ProgramUniformMatrix4fv(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value) {
|
||||
ProgramUniformMatrix4fv_State(program, location, count, transpose, value);
|
||||
}
|
||||
|
||||
GLuint GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName) {
|
||||
return GetUniformBlockIndex_State(program, uniformBlockName);
|
||||
}
|
||||
@@ -1163,6 +1464,112 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return GetFragDataLocation_State(program, name);
|
||||
}
|
||||
|
||||
void GetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint* params) {
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject || !programObject->GetLinkStatus()) return;
|
||||
auto getProgramInterfaceiv = MG_Backend::gBackendFunctionsTable.GL.GetProgramInterfaceiv;
|
||||
if (!getProgramInterfaceiv) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"Backend does not support program interface queries."));
|
||||
return;
|
||||
}
|
||||
getProgramInterfaceiv(program, programInterface, pname, params);
|
||||
}
|
||||
|
||||
GLuint GetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar* name) {
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject || !programObject->GetLinkStatus()) return GL_INVALID_INDEX;
|
||||
auto getProgramResourceIndex = MG_Backend::gBackendFunctionsTable.GL.GetProgramResourceIndex;
|
||||
if (!getProgramResourceIndex) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"Backend does not support program interface queries."));
|
||||
return GL_INVALID_INDEX;
|
||||
}
|
||||
return getProgramResourceIndex(program, programInterface, name);
|
||||
}
|
||||
|
||||
void GetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length,
|
||||
GLchar* name) {
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject || !programObject->GetLinkStatus()) return;
|
||||
if (bufSize < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "bufSize must be non-negative."));
|
||||
return;
|
||||
}
|
||||
auto getProgramResourceName = MG_Backend::gBackendFunctionsTable.GL.GetProgramResourceName;
|
||||
if (!getProgramResourceName) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"Backend does not support program interface queries."));
|
||||
return;
|
||||
}
|
||||
getProgramResourceName(program, programInterface, index, bufSize, length, name);
|
||||
}
|
||||
|
||||
void GetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount,
|
||||
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params) {
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject || !programObject->GetLinkStatus()) return;
|
||||
if (propCount < 0 || bufSize < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"propCount and bufSize must be non-negative."));
|
||||
return;
|
||||
}
|
||||
auto getProgramResourceiv = MG_Backend::gBackendFunctionsTable.GL.GetProgramResourceiv;
|
||||
if (!getProgramResourceiv) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"Backend does not support program interface queries."));
|
||||
return;
|
||||
}
|
||||
getProgramResourceiv(program, programInterface, index, propCount, props, bufSize, length, params);
|
||||
}
|
||||
|
||||
GLint GetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar* name) {
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject || !programObject->GetLinkStatus()) return -1;
|
||||
auto getProgramResourceLocation = MG_Backend::gBackendFunctionsTable.GL.GetProgramResourceLocation;
|
||||
if (!getProgramResourceLocation) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"Backend does not support program interface queries."));
|
||||
return -1;
|
||||
}
|
||||
return getProgramResourceLocation(program, programInterface, name);
|
||||
}
|
||||
|
||||
GLint GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, const GLchar* name) {
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject || !programObject->GetLinkStatus()) return -1;
|
||||
auto getProgramResourceLocationIndex = MG_Backend::gBackendFunctionsTable.GL.GetProgramResourceLocationIndex;
|
||||
if (!getProgramResourceLocationIndex) return -1;
|
||||
return getProgramResourceLocationIndex(program, programInterface, name);
|
||||
}
|
||||
|
||||
void ShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding) {
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject || !programObject->GetLinkStatus()) return;
|
||||
auto shaderStorageBlockBinding = MG_Backend::gBackendFunctionsTable.GL.ShaderStorageBlockBinding;
|
||||
if (!shaderStorageBlockBinding) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"Backend does not support shader storage block binding."));
|
||||
return;
|
||||
}
|
||||
shaderStorageBlockBinding(program, storageBlockIndex, storageBlockBinding);
|
||||
}
|
||||
|
||||
void ValidateProgram(GLuint program) {
|
||||
ValidateProgram_State(program);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
void Uniform2i(GLint location, GLint v0, GLint v1);
|
||||
void Uniform3i(GLint location, GLint v0, GLint v1, GLint v2);
|
||||
void Uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
|
||||
void Uniform1ui(GLint location, GLuint v0);
|
||||
void Uniform1fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform2fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform3fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
@@ -53,9 +54,40 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
void Uniform2iv(GLint location, GLsizei count, const GLint* value);
|
||||
void Uniform3iv(GLint location, GLsizei count, const GLint* value);
|
||||
void Uniform4iv(GLint location, GLsizei count, const GLint* value);
|
||||
void Uniform1uiv(GLint location, GLsizei count, const GLuint* value);
|
||||
void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void ProgramUniform1f(GLuint program, GLint location, GLfloat v0);
|
||||
void ProgramUniform2f(GLuint program, GLint location, GLfloat v0, GLfloat v1);
|
||||
void ProgramUniform3f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
||||
void ProgramUniform4f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
|
||||
void ProgramUniform1i(GLuint program, GLint location, GLint v0);
|
||||
void ProgramUniform2i(GLuint program, GLint location, GLint v0, GLint v1);
|
||||
void ProgramUniform3i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
|
||||
void ProgramUniform4i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
|
||||
void ProgramUniform1ui(GLuint program, GLint location, GLuint v0);
|
||||
void ProgramUniform2ui(GLuint program, GLint location, GLuint v0, GLuint v1);
|
||||
void ProgramUniform3ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
|
||||
void ProgramUniform4ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
|
||||
void ProgramUniform1fv(GLuint program, GLint location, GLsizei count, const GLfloat* value);
|
||||
void ProgramUniform2fv(GLuint program, GLint location, GLsizei count, const GLfloat* value);
|
||||
void ProgramUniform3fv(GLuint program, GLint location, GLsizei count, const GLfloat* value);
|
||||
void ProgramUniform4fv(GLuint program, GLint location, GLsizei count, const GLfloat* value);
|
||||
void ProgramUniform1iv(GLuint program, GLint location, GLsizei count, const GLint* value);
|
||||
void ProgramUniform2iv(GLuint program, GLint location, GLsizei count, const GLint* value);
|
||||
void ProgramUniform3iv(GLuint program, GLint location, GLsizei count, const GLint* value);
|
||||
void ProgramUniform4iv(GLuint program, GLint location, GLsizei count, const GLint* value);
|
||||
void ProgramUniform1uiv(GLuint program, GLint location, GLsizei count, const GLuint* value);
|
||||
void ProgramUniform2uiv(GLuint program, GLint location, GLsizei count, const GLuint* value);
|
||||
void ProgramUniform3uiv(GLuint program, GLint location, GLsizei count, const GLuint* value);
|
||||
void ProgramUniform4uiv(GLuint program, GLint location, GLsizei count, const GLuint* value);
|
||||
void ProgramUniformMatrix2fv(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value);
|
||||
void ProgramUniformMatrix3fv(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value);
|
||||
void ProgramUniformMatrix4fv(GLuint program, GLint location, GLsizei count, GLboolean transpose,
|
||||
const GLfloat* value);
|
||||
GLuint GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName);
|
||||
void UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
|
||||
void GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params);
|
||||
@@ -63,5 +95,14 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
GLchar* uniformBlockName);
|
||||
void BindFragDataLocation(GLuint program, GLuint colorNumber, const char* name);
|
||||
GLint GetFragDataLocation(GLuint program, const char* name);
|
||||
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 ValidateProgram(GLuint program);
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -14,6 +14,19 @@
|
||||
#include <MG_Util/Converters/MGToStr/RenderStateEnumConverter.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
static Bool TryConvertBlendEquation(GLenum mode, const char* functionName,
|
||||
::MobileGL::BlendEquation& outEquation) {
|
||||
outEquation = MG_Util::ConvertGLEnumToBlendEquation(mode);
|
||||
if (outEquation != ::MobileGL::BlendEquation::Unknown) return true;
|
||||
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
|
||||
"Blend equation enum " + MG_Util::ConvertGLEnumToString(mode) +
|
||||
" is not supported."));
|
||||
return false;
|
||||
}
|
||||
|
||||
void Viewport_State(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
if (width < 0 || height < 0) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||
@@ -141,7 +154,33 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
void FrontFace_State(GLenum mode) {
|
||||
// TODO: implement
|
||||
FrontFaceMode frontFaceMode = MG_Util::ConvertGLEnumToFrontFaceMode(mode);
|
||||
if (frontFaceMode == FrontFaceMode::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FrontFace_State",
|
||||
"Front face mode enum " +
|
||||
MG_Util::ConvertFrontFaceModeToString(frontFaceMode) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(mode) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetFrontFaceMode(frontFaceMode);
|
||||
}
|
||||
|
||||
void ProvokingVertex_State(GLenum mode) {
|
||||
ProvokingVertexMode provokingVertexMode = MG_Util::ConvertGLEnumToProvokingVertexMode(mode);
|
||||
if (provokingVertexMode == ProvokingVertexMode::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ProvokingVertex_State",
|
||||
"Provoking vertex mode enum " +
|
||||
MG_Util::ConvertProvokingVertexModeToString(provokingVertexMode) +
|
||||
"(" + MG_Util::ConvertGLEnumToString(mode) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetProvokingVertexMode(provokingVertexMode);
|
||||
}
|
||||
|
||||
void Enable_State(GLenum cap) {
|
||||
@@ -249,7 +288,19 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
void BlendEquation_State(GLenum mode) {
|
||||
// TODO: implement
|
||||
::MobileGL::BlendEquation blendEquation = ::MobileGL::BlendEquation::Unknown;
|
||||
if (!TryConvertBlendEquation(mode, "BlendEquation_State", blendEquation)) return;
|
||||
MG_State::pGLContext->SetBlendEquation(blendEquation, blendEquation);
|
||||
}
|
||||
|
||||
void BlendEquationSeparate_State(GLenum modeRGB, GLenum modeAlpha) {
|
||||
::MobileGL::BlendEquation colorEquation = ::MobileGL::BlendEquation::Unknown;
|
||||
if (!TryConvertBlendEquation(modeRGB, "BlendEquationSeparate_State", colorEquation)) return;
|
||||
|
||||
::MobileGL::BlendEquation alphaEquation = ::MobileGL::BlendEquation::Unknown;
|
||||
if (!TryConvertBlendEquation(modeAlpha, "BlendEquationSeparate_State", alphaEquation)) return;
|
||||
|
||||
MG_State::pGLContext->SetBlendEquation(colorEquation, alphaEquation);
|
||||
}
|
||||
|
||||
void BlendColor_State(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
@@ -283,9 +334,45 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
BlendFactor dstRGBM = MG_Util::ConvertGLEnumToBlendFactor(dstRGB);
|
||||
BlendFactor srcAlphaM = MG_Util::ConvertGLEnumToBlendFactor(srcAlpha);
|
||||
BlendFactor dstAlphaM = MG_Util::ConvertGLEnumToBlendFactor(dstAlpha);
|
||||
if (srcRGBM == BlendFactor::Unknown || dstRGBM == BlendFactor::Unknown ||
|
||||
srcAlphaM == BlendFactor::Unknown || dstAlphaM == BlendFactor::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BlendFuncSeparatei_State",
|
||||
"One of the indexed blend factor enums is not supported."));
|
||||
return;
|
||||
}
|
||||
MG_State::pGLContext->SetBlendFuncIndexed(buf, srcRGBM, dstRGBM, srcAlphaM, dstAlphaM);
|
||||
}
|
||||
|
||||
void BlendFunci_State(GLuint buf, GLenum src, GLenum dst) {
|
||||
BlendFuncSeparatei_State(buf, src, dst, src, dst);
|
||||
}
|
||||
|
||||
void BlendEquationSeparatei_State(GLuint buf, GLenum modeRGB, GLenum modeAlpha) {
|
||||
if (buf >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "BlendEquationSeparatei_State",
|
||||
"Buffer index " + std::to_string(buf) + " is out of range. Max supported is " +
|
||||
std::to_string(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS - 1) + "."));
|
||||
return;
|
||||
}
|
||||
|
||||
::MobileGL::BlendEquation colorEquation = ::MobileGL::BlendEquation::Unknown;
|
||||
if (!TryConvertBlendEquation(modeRGB, "BlendEquationSeparatei_State", colorEquation)) return;
|
||||
|
||||
::MobileGL::BlendEquation alphaEquation = ::MobileGL::BlendEquation::Unknown;
|
||||
if (!TryConvertBlendEquation(modeAlpha, "BlendEquationSeparatei_State", alphaEquation)) return;
|
||||
|
||||
MG_State::pGLContext->SetBlendEquationIndexed(buf, colorEquation, alphaEquation);
|
||||
}
|
||||
|
||||
void BlendEquationi_State(GLuint buf, GLenum mode) {
|
||||
BlendEquationSeparatei_State(buf, mode, mode);
|
||||
}
|
||||
|
||||
void Disablei_State(GLenum target, GLuint index) {
|
||||
auto capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
|
||||
if (capInput == CapabilityInput::Unknown) {
|
||||
@@ -315,6 +402,18 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||
void BlendEquationi(GLuint buf, GLenum mode) {
|
||||
BlendEquationi_State(buf, mode);
|
||||
}
|
||||
|
||||
void BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeAlpha) {
|
||||
BlendEquationSeparatei_State(buf, modeRGB, modeAlpha);
|
||||
}
|
||||
|
||||
void BlendFunci(GLuint buf, GLenum src, GLenum dst) {
|
||||
BlendFunci_State(buf, src, dst);
|
||||
}
|
||||
|
||||
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
|
||||
BlendFuncSeparatei_State(buf, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
@@ -415,6 +514,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
FrontFace_State(mode);
|
||||
}
|
||||
|
||||
void ProvokingVertex(GLenum mode) {
|
||||
ProvokingVertex_State(mode);
|
||||
}
|
||||
|
||||
void Enable(GLenum cap) {
|
||||
Enable_State(cap);
|
||||
}
|
||||
@@ -455,6 +558,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
BlendEquation_State(mode);
|
||||
}
|
||||
|
||||
void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {
|
||||
BlendEquationSeparate_State(modeRGB, modeAlpha);
|
||||
}
|
||||
|
||||
void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
BlendColor_State(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void BlendEquationi(GLuint buf, GLenum mode);
|
||||
void BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeAlpha);
|
||||
void BlendFunci(GLuint buf, GLenum src, GLenum dst);
|
||||
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
|
||||
void Disablei(GLenum target, GLuint index);
|
||||
void Enablei(GLenum target, GLuint index);
|
||||
@@ -36,6 +39,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
GLboolean IsEnabled(GLenum cap);
|
||||
void Hint(GLenum target, GLenum mode);
|
||||
void FrontFace(GLenum mode);
|
||||
void ProvokingVertex(GLenum mode);
|
||||
void Enable(GLenum cap);
|
||||
void Disable(GLenum cap);
|
||||
void DepthRange(GLclampd near_val, GLclampd far_val);
|
||||
@@ -46,6 +50,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
void ClampColor(GLenum target, GLenum clamp);
|
||||
void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
|
||||
void BlendEquation(GLenum mode);
|
||||
void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
|
||||
void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
void ClearStencil(GLint s);
|
||||
void ClearDepth(GLclampd depth);
|
||||
|
||||
@@ -167,6 +167,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
void BindSampler_State(GLuint unit, GLuint sampler) {
|
||||
MGLOG_D("BindSampler_State: unit = %u, sampler = %u", unit, sampler);
|
||||
if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
|
||||
@@ -8,36 +8,121 @@
|
||||
|
||||
#include "GL_Sync.h"
|
||||
|
||||
#include "MG_State/GLState/Core.h"
|
||||
#include <MG_State/GLState/Core.h>
|
||||
#include <MG_State/GLState/ErrorState/Error.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
GLsync FenceSync_Backend(GLenum condition, GLbitfield flags) {
|
||||
return 0;
|
||||
}
|
||||
namespace {
|
||||
struct SyncObject {
|
||||
GLenum Condition = GL_SYNC_GPU_COMMANDS_COMPLETE;
|
||||
GLbitfield Flags = 0;
|
||||
};
|
||||
|
||||
GLenum ClientWaitSync_Backend(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
||||
return 0;
|
||||
}
|
||||
UnorderedMap<GLsync, UniquePtr<SyncObject>> g_syncObjects;
|
||||
|
||||
void DeleteSync_Backend(GLsync sync) {}
|
||||
void RecordSyncError(const char* funcName, ErrorCode code, String message) {
|
||||
MG_State::pGLContext->RecordError(code,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName, Move(message)));
|
||||
}
|
||||
|
||||
GLsync FenceSync_State(GLenum condition, GLbitfield flags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLenum ClientWaitSync_State(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DeleteSync_State(GLsync sync) {}
|
||||
SyncObject* GetSyncObject(GLsync sync, const char* funcName) {
|
||||
auto it = g_syncObjects.find(sync);
|
||||
if (sync == nullptr || it == g_syncObjects.end()) {
|
||||
RecordSyncError(funcName, ErrorCode::InvalidValue, "Sync object is not valid.");
|
||||
return nullptr;
|
||||
}
|
||||
return it->second.get();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
GLsync FenceSync(GLenum condition, GLbitfield flags) {
|
||||
return 0;
|
||||
if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) {
|
||||
RecordSyncError("FenceSync", ErrorCode::InvalidEnum, "Condition must be GL_SYNC_GPU_COMMANDS_COMPLETE.");
|
||||
return nullptr;
|
||||
}
|
||||
if (flags != 0) {
|
||||
RecordSyncError("FenceSync", ErrorCode::InvalidValue, "Flags must be zero.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto syncObject = MakeUnique<SyncObject>();
|
||||
syncObject->Condition = condition;
|
||||
syncObject->Flags = flags;
|
||||
GLsync handle = reinterpret_cast<GLsync>(syncObject.get());
|
||||
g_syncObjects[handle] = Move(syncObject);
|
||||
return handle;
|
||||
}
|
||||
|
||||
GLboolean IsSync(GLsync sync) {
|
||||
return g_syncObjects.find(sync) != g_syncObjects.end() ? GL_TRUE : GL_FALSE;
|
||||
}
|
||||
|
||||
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
||||
return 0;
|
||||
(void)timeout;
|
||||
if ((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) != 0) {
|
||||
RecordSyncError("ClientWaitSync", ErrorCode::InvalidValue,
|
||||
"Flags can only contain GL_SYNC_FLUSH_COMMANDS_BIT.");
|
||||
return GL_WAIT_FAILED;
|
||||
}
|
||||
if (!GetSyncObject(sync, "ClientWaitSync")) return GL_WAIT_FAILED;
|
||||
return GL_ALREADY_SIGNALED;
|
||||
}
|
||||
|
||||
void DeleteSync(GLsync sync) {}
|
||||
void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
||||
if (flags != 0) {
|
||||
RecordSyncError("WaitSync", ErrorCode::InvalidValue, "Flags must be zero.");
|
||||
return;
|
||||
}
|
||||
if (timeout != GL_TIMEOUT_IGNORED) {
|
||||
RecordSyncError("WaitSync", ErrorCode::InvalidValue, "Timeout must be GL_TIMEOUT_IGNORED.");
|
||||
return;
|
||||
}
|
||||
(void)GetSyncObject(sync, "WaitSync");
|
||||
}
|
||||
|
||||
void DeleteSync(GLsync sync) {
|
||||
if (sync == nullptr) return;
|
||||
auto it = g_syncObjects.find(sync);
|
||||
if (it == g_syncObjects.end()) {
|
||||
RecordSyncError("DeleteSync", ErrorCode::InvalidValue, "Sync object is not valid.");
|
||||
return;
|
||||
}
|
||||
g_syncObjects.erase(it);
|
||||
}
|
||||
|
||||
void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) {
|
||||
if (bufSize < 0) {
|
||||
RecordSyncError("GetSynciv", ErrorCode::InvalidValue, "bufSize must be non-negative.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto* syncObject = GetSyncObject(sync, "GetSynciv");
|
||||
if (!syncObject) return;
|
||||
|
||||
GLint value = 0;
|
||||
switch (pname) {
|
||||
case GL_OBJECT_TYPE:
|
||||
value = GL_SYNC_FENCE;
|
||||
break;
|
||||
case GL_SYNC_STATUS:
|
||||
value = GL_SIGNALED;
|
||||
break;
|
||||
case GL_SYNC_CONDITION:
|
||||
value = static_cast<GLint>(syncObject->Condition);
|
||||
break;
|
||||
case GL_SYNC_FLAGS:
|
||||
value = static_cast<GLint>(syncObject->Flags);
|
||||
break;
|
||||
default:
|
||||
RecordSyncError("GetSynciv", ErrorCode::InvalidEnum, std::format("Invalid pname enum: 0x{:X}", pname));
|
||||
return;
|
||||
}
|
||||
|
||||
if (length) {
|
||||
*length = bufSize > 0 && values ? 1 : 0;
|
||||
}
|
||||
if (bufSize > 0 && values) {
|
||||
values[0] = value;
|
||||
}
|
||||
}
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
GLsync FenceSync(GLenum condition, GLbitfield flags);
|
||||
GLboolean IsSync(GLsync sync);
|
||||
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
|
||||
void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
|
||||
void DeleteSync(GLsync sync);
|
||||
void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values);
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -29,6 +29,215 @@
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
static SharedPtr<MG_State::GLState::ITextureObject> nullTextureObject;
|
||||
static UnorderedMap<Uint, Bool> g_autoGenerateMipmapByTextureId;
|
||||
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& GetTextureObjectByName(GLuint texture, const char* caller) {
|
||||
if (texture == 0 || !TextureImpl::ValidateTextureName(texture, true)) return nullTextureObject;
|
||||
|
||||
auto& textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||
if (!TextureImpl::ValidateTextureObject(textureObject)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||
std::format("Texture object {} does not exist.", texture)));
|
||||
return nullTextureObject;
|
||||
}
|
||||
return textureObject;
|
||||
}
|
||||
|
||||
TextureUploadTarget GetPrimaryUploadTarget(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject) {
|
||||
if (!textureObject) return TextureUploadTarget::Unknown;
|
||||
const auto& uploadTargets = textureObject->GetUploadTargets();
|
||||
return uploadTargets.empty() ? TextureUploadTarget::Unknown : uploadTargets[0];
|
||||
}
|
||||
|
||||
void TextureParameterObject_State(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject, GLenum pname,
|
||||
GLint param, const char* caller) {
|
||||
if (!textureObject) return;
|
||||
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_MAG_FILTER:
|
||||
textureObject->GetSamplerObject()->SetMagFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(param));
|
||||
break;
|
||||
case GL_TEXTURE_MIN_FILTER:
|
||||
textureObject->GetSamplerObject()->SetMinFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(param));
|
||||
textureObject->GetSamplerObject()->SetMipmapMode(MG_Util::ConvertGLEnumToSamplerMipmapMode(param));
|
||||
break;
|
||||
case GL_TEXTURE_MIN_LOD: {
|
||||
Float maxLod = textureObject->GetSamplerObject()->GetMaxLod();
|
||||
textureObject->GetSamplerObject()->SetLodRange(param, maxLod);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_MAX_LOD: {
|
||||
Float minLod = textureObject->GetSamplerObject()->GetMinLod();
|
||||
textureObject->GetSamplerObject()->SetLodRange(minLod, param);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_BASE_LEVEL:
|
||||
textureObject->SetBaseLevel(param);
|
||||
break;
|
||||
case GL_TEXTURE_MAX_LEVEL:
|
||||
textureObject->SetMaxLevel(param);
|
||||
break;
|
||||
case GL_TEXTURE_SWIZZLE_R:
|
||||
case GL_TEXTURE_SWIZZLE_G:
|
||||
case GL_TEXTURE_SWIZZLE_B:
|
||||
case GL_TEXTURE_SWIZZLE_A: {
|
||||
auto swizzleParam = MG_Util::ConvertGLEnumPnameToTextureSwizzleParam(pname);
|
||||
auto swizzleValue = MG_Util::ConvertGLEnumToTextureSwizzleParam(param);
|
||||
textureObject->SetSwizzleParam(swizzleParam, swizzleValue);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_WRAP_S:
|
||||
textureObject->GetSamplerObject()->SetWrapS(MG_Util::ConvertGLEnumToSamplerWrapMode(param));
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_T:
|
||||
textureObject->GetSamplerObject()->SetWrapT(MG_Util::ConvertGLEnumToSamplerWrapMode(param));
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_R:
|
||||
textureObject->GetSamplerObject()->SetWrapR(MG_Util::ConvertGLEnumToSamplerWrapMode(param));
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_MODE:
|
||||
textureObject->GetSamplerObject()->SetCompareMode(MG_Util::ConvertGLEnumToSamplerCompareMode(param));
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_FUNC:
|
||||
textureObject->GetSamplerObject()->SetSamplerCompareFunc(MG_Util::ConvertGLEnumToSamplerCompareFunc(param));
|
||||
break;
|
||||
case GL_TEXTURE_LOD_BIAS:
|
||||
textureObject->GetSamplerObject()->SetLodBias((GLfloat)param);
|
||||
break;
|
||||
case GL_GENERATE_MIPMAP:
|
||||
g_autoGenerateMipmapByTextureId[textureObject->GetExternalIndex()] = (param != GL_FALSE);
|
||||
break;
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", caller,
|
||||
std::format("pname {} is not a valid texture parameter.", MG_Util::ConvertGLEnumToString(pname))));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureParameterObjectf_State(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject, GLenum pname,
|
||||
GLfloat param, const char* caller) {
|
||||
if (!textureObject) return;
|
||||
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_MAG_FILTER:
|
||||
textureObject->GetSamplerObject()->SetMagFilter(MG_Util::ConvertGLEnumToSamplerFilterMode((GLenum)param));
|
||||
break;
|
||||
case GL_TEXTURE_MIN_FILTER:
|
||||
textureObject->GetSamplerObject()->SetMinFilter(MG_Util::ConvertGLEnumToSamplerFilterMode((GLenum)param));
|
||||
textureObject->GetSamplerObject()->SetMipmapMode(MG_Util::ConvertGLEnumToSamplerMipmapMode((GLenum)param));
|
||||
break;
|
||||
case GL_TEXTURE_MIN_LOD: {
|
||||
Float maxLod = textureObject->GetSamplerObject()->GetMaxLod();
|
||||
textureObject->GetSamplerObject()->SetLodRange(param, maxLod);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_MAX_LOD: {
|
||||
Float minLod = textureObject->GetSamplerObject()->GetMinLod();
|
||||
textureObject->GetSamplerObject()->SetLodRange(minLod, param);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_BASE_LEVEL:
|
||||
textureObject->SetBaseLevel((Uint)param);
|
||||
break;
|
||||
case GL_TEXTURE_MAX_LEVEL:
|
||||
textureObject->SetMaxLevel((Uint)param);
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_S:
|
||||
textureObject->GetSamplerObject()->SetWrapS(MG_Util::ConvertGLEnumToSamplerWrapMode((GLenum)param));
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_T:
|
||||
textureObject->GetSamplerObject()->SetWrapT(MG_Util::ConvertGLEnumToSamplerWrapMode((GLenum)param));
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_R:
|
||||
textureObject->GetSamplerObject()->SetWrapR(MG_Util::ConvertGLEnumToSamplerWrapMode((GLenum)param));
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_MODE:
|
||||
textureObject->GetSamplerObject()->SetCompareMode(
|
||||
MG_Util::ConvertGLEnumToSamplerCompareMode((GLenum)param));
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_FUNC:
|
||||
textureObject->GetSamplerObject()->SetSamplerCompareFunc(
|
||||
MG_Util::ConvertGLEnumToSamplerCompareFunc((GLenum)param));
|
||||
break;
|
||||
case GL_TEXTURE_LOD_BIAS:
|
||||
textureObject->GetSamplerObject()->SetLodBias(param);
|
||||
break;
|
||||
case GL_GENERATE_MIPMAP:
|
||||
g_autoGenerateMipmapByTextureId[textureObject->GetExternalIndex()] = (param != 0.0f);
|
||||
break;
|
||||
case GL_DEPTH_STENCIL_TEXTURE_MODE:
|
||||
if (param != GL_DEPTH_COMPONENT && param != GL_STENCIL_INDEX) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||
"Invalid GL_DEPTH_STENCIL_TEXTURE_MODE value."));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", caller,
|
||||
std::format("pname {} is not a valid texture parameter.", MG_Util::ConvertGLEnumToString(pname))));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void GetTextureParameterObjectiv_State(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
||||
GLenum pname, GLint* params, const char* caller) {
|
||||
if (!textureObject || !params) return;
|
||||
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_MAG_FILTER:
|
||||
*params = (GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(textureObject->GetSamplerObject()->GetMagFilter(),
|
||||
SamplerMipmapMode::None);
|
||||
break;
|
||||
case GL_TEXTURE_MIN_FILTER:
|
||||
*params = (GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(
|
||||
textureObject->GetSamplerObject()->GetMinFilter(), textureObject->GetSamplerObject()->GetMipmapMode());
|
||||
break;
|
||||
case GL_TEXTURE_MIN_LOD:
|
||||
*params = static_cast<GLint>(textureObject->GetSamplerObject()->GetMinLod());
|
||||
break;
|
||||
case GL_TEXTURE_MAX_LOD:
|
||||
*params = static_cast<GLint>(textureObject->GetSamplerObject()->GetMaxLod());
|
||||
break;
|
||||
case GL_TEXTURE_BASE_LEVEL:
|
||||
*params = static_cast<GLint>(textureObject->GetLevelRange().x());
|
||||
break;
|
||||
case GL_TEXTURE_MAX_LEVEL:
|
||||
*params = static_cast<GLint>(textureObject->GetLevelRange().y());
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_S:
|
||||
*params = (GLint)MG_Util::ConvertSamplerWrapModeToGLEnum(textureObject->GetSamplerObject()->GetWrapS());
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_T:
|
||||
*params = (GLint)MG_Util::ConvertSamplerWrapModeToGLEnum(textureObject->GetSamplerObject()->GetWrapT());
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_R:
|
||||
*params = (GLint)MG_Util::ConvertSamplerWrapModeToGLEnum(textureObject->GetSamplerObject()->GetWrapR());
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_MODE:
|
||||
*params =
|
||||
(GLint)MG_Util::ConvertSamplerCompareModeToGLEnum(textureObject->GetSamplerObject()->GetCompareMode());
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_FUNC:
|
||||
*params = (GLint)MG_Util::ConvertSamplerCompareFuncToGLEnum(
|
||||
textureObject->GetSamplerObject()->GetSamplerCompareFunc());
|
||||
break;
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||
"pname is not a valid texture parameter."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& GetTextureObjectByTarget(
|
||||
TextureUploadTarget textureUploadTarget, TextureTarget textureTarget) {
|
||||
@@ -50,6 +259,18 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
MG_Backend::gBackendFunctionsTable.GL.GenerateMipmap(target);
|
||||
}
|
||||
|
||||
void MaybeAutoGenerateMipmap(GLenum target, const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
||||
Bool isProxy, GLint level) {
|
||||
if (isProxy || level != 0 || !textureObject) {
|
||||
return;
|
||||
}
|
||||
const auto it = g_autoGenerateMipmapByTextureId.find(textureObject->GetExternalIndex());
|
||||
if (it == g_autoGenerateMipmapByTextureId.end() || !it->second) {
|
||||
return;
|
||||
}
|
||||
GenerateMipmap_Backend(target);
|
||||
}
|
||||
|
||||
void TexSubImage3D_State(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
|
||||
GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) {
|
||||
// TODO: implement
|
||||
@@ -144,7 +365,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
const SizeT internalBpp = MG_Util::GetInternalBytesPerPixel(textureInternalFormat, texturePixelDataType);
|
||||
|
||||
const SizeT srcRowSize = static_cast<SizeT>(width) * internalBpp;
|
||||
const SizeT srcStride = (srcRowSize + unpackParams.Alignment - 1) & ~(unpackParams.Alignment - 1);
|
||||
const SizeT srcStride = srcRowSize;
|
||||
const SizeT destRowSize = static_cast<SizeT>(texelSize.x()) * internalBpp;
|
||||
|
||||
if (xoffset + width > static_cast<GLsizei>(texelSize.x()) ||
|
||||
@@ -169,6 +390,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
|
||||
MGLOG_D("%s: mark mip %d as dirty", __func__, level);
|
||||
textureMipmapObject->MarkStorageDirty(textureUploadTarget, level, true);
|
||||
MaybeAutoGenerateMipmap(target, textureObject, false, level);
|
||||
}
|
||||
|
||||
void TexSubImage1D_State(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type,
|
||||
@@ -240,6 +462,9 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
case GL_TEXTURE_LOD_BIAS:
|
||||
textureObject->GetSamplerObject()->SetLodBias(param);
|
||||
break;
|
||||
case GL_GENERATE_MIPMAP:
|
||||
g_autoGenerateMipmapByTextureId[textureObject->GetExternalIndex()] = (param != 0.0f);
|
||||
break;
|
||||
case GL_TEXTURE_SWIZZLE_RGBA:
|
||||
// Not supported in this function
|
||||
case GL_TEXTURE_BORDER_COLOR:
|
||||
@@ -263,69 +488,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
auto& textureObject = GetTextureObjectByTarget(textureUploadTarget, textureTarget);
|
||||
if (!textureObject) return;
|
||||
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_MAG_FILTER:
|
||||
textureObject->GetSamplerObject()->SetMagFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(param));
|
||||
break;
|
||||
case GL_TEXTURE_MIN_FILTER:
|
||||
textureObject->GetSamplerObject()->SetMinFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(param));
|
||||
textureObject->GetSamplerObject()->SetMipmapMode(MG_Util::ConvertGLEnumToSamplerMipmapMode(param));
|
||||
break;
|
||||
case GL_TEXTURE_MIN_LOD: {
|
||||
Float maxLod = textureObject->GetSamplerObject()->GetMaxLod();
|
||||
textureObject->GetSamplerObject()->SetLodRange(param, maxLod);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_MAX_LOD: {
|
||||
Float minLod = textureObject->GetSamplerObject()->GetMinLod();
|
||||
textureObject->GetSamplerObject()->SetLodRange(minLod, param);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_BASE_LEVEL:
|
||||
textureObject->SetBaseLevel(param);
|
||||
break;
|
||||
case GL_TEXTURE_MAX_LEVEL:
|
||||
textureObject->SetMaxLevel(param);
|
||||
break;
|
||||
case GL_TEXTURE_SWIZZLE_R:
|
||||
case GL_TEXTURE_SWIZZLE_G:
|
||||
case GL_TEXTURE_SWIZZLE_B:
|
||||
case GL_TEXTURE_SWIZZLE_A: {
|
||||
auto swizzleParam = MG_Util::ConvertGLEnumPnameToTextureSwizzleParam(pname);
|
||||
auto swizzleValue = MG_Util::ConvertGLEnumToTextureSwizzleParam(param);
|
||||
textureObject->SetSwizzleParam(swizzleParam, swizzleValue);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_WRAP_S:
|
||||
textureObject->GetSamplerObject()->SetWrapS(MG_Util::ConvertGLEnumToSamplerWrapMode(param));
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_T:
|
||||
textureObject->GetSamplerObject()->SetWrapT(MG_Util::ConvertGLEnumToSamplerWrapMode(param));
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_R:
|
||||
textureObject->GetSamplerObject()->SetWrapR(MG_Util::ConvertGLEnumToSamplerWrapMode(param));
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_MODE:
|
||||
textureObject->GetSamplerObject()->SetCompareMode(MG_Util::ConvertGLEnumToSamplerCompareMode(param));
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_FUNC:
|
||||
textureObject->GetSamplerObject()->SetSamplerCompareFunc(MG_Util::ConvertGLEnumToSamplerCompareFunc(param));
|
||||
break;
|
||||
case GL_TEXTURE_LOD_BIAS:
|
||||
textureObject->GetSamplerObject()->SetLodBias((GLfloat)param);
|
||||
break;
|
||||
case GL_TEXTURE_SWIZZLE_RGBA:
|
||||
// Not supported in this function
|
||||
case GL_TEXTURE_BORDER_COLOR:
|
||||
// Not supported in this function
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", __func__,
|
||||
std::format("pname {} is not a valid texture parameter.", MG_Util::ConvertGLEnumToString(pname))));
|
||||
return;
|
||||
}
|
||||
TextureParameterObject_State(textureObject, pname, param, __func__);
|
||||
}
|
||||
|
||||
// Quick and dirty TexParameter*v implementation to make NeoForge happy.
|
||||
@@ -546,6 +709,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!TextureImpl::ValidateTextureObject(textureObject)) return;
|
||||
|
||||
// ======================= Processing ================================
|
||||
if (internalformat == GL_ALPHA || format == GL_ALPHA) {
|
||||
textureObject->SetSwizzleParamRGBA({TextureSwizzleParam::Zero, TextureSwizzleParam::Zero,
|
||||
TextureSwizzleParam::Zero, TextureSwizzleParam::Red});
|
||||
}
|
||||
|
||||
SizeT imageSize = 0;
|
||||
const SizeT inputBpp = MG_Util::GetInputBytesPerPixel(textureInputFormat, texturePixelDataType);
|
||||
@@ -655,6 +822,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!TextureImpl::ValidateTextureObject(textureObject)) return;
|
||||
|
||||
// ======================= Processing ================================
|
||||
if (internalformat == GL_ALPHA || format == GL_ALPHA) {
|
||||
textureObject->SetSwizzleParamRGBA({TextureSwizzleParam::Zero, TextureSwizzleParam::Zero,
|
||||
TextureSwizzleParam::Zero, TextureSwizzleParam::Red});
|
||||
}
|
||||
|
||||
SizeT imageSize = 0;
|
||||
const SizeT inputBpp = MG_Util::GetInputBytesPerPixel(textureInputFormat, texturePixelDataType);
|
||||
@@ -685,8 +856,13 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
auto textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
||||
|
||||
// Allocate in TextureObject
|
||||
MGLOG_D("%s: Allocating %d bytes at mip %d", __func__, internalBytes, level);
|
||||
textureMipmapObject->AllocateStorage(textureUploadTarget, level, {{width, height, 1}, internalBytes});
|
||||
if (isProxy) {
|
||||
MGLOG_D("%s: isProxy = true, not allocating", __func__);
|
||||
} else {
|
||||
MGLOG_D("%s: Allocating %d bytes at mip %d", __func__, internalBytes, level);
|
||||
textureMipmapObject->AllocateStorage(textureUploadTarget, level,
|
||||
{{width, height, 1}, internalBytes});
|
||||
}
|
||||
|
||||
if (!originalPixels) {
|
||||
MGLOG_D("%s: No input pixel and no PBO bound, no pixel transfer", __func__);
|
||||
@@ -714,6 +890,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
|
||||
MGLOG_D("%s: mark mip %d as dirty", __func__, level);
|
||||
textureMipmapObject->MarkStorageDirty(textureUploadTarget, level, true);
|
||||
MaybeAutoGenerateMipmap(target, textureObject, isProxy, level);
|
||||
}
|
||||
|
||||
void TexImage1D_State(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format,
|
||||
@@ -1139,7 +1316,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
// ======================= Processing ================================
|
||||
static thread_local Vector<Uint> textureNames;
|
||||
Vector<Uint> textureNames;
|
||||
MG_State::pGLContext->GenTextureNames(n, textureNames);
|
||||
Memcpy(textures, textureNames.data(), n * sizeof(GLuint));
|
||||
}
|
||||
@@ -1287,15 +1464,31 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
void BindTexture_State(GLenum target, GLuint texture) {
|
||||
// TODO: deal with condition where texture == 0
|
||||
MGLOG_D("BindTexture_State called with target: 0x%X, texture: %u", target, texture);
|
||||
const Int activeUnit = MG_State::pGLContext->GetActiveTextureUnit();
|
||||
MGLOG_D("BindTexture_State called with target: 0x%X, texture: %u, unit: %d", target, texture, activeUnit);
|
||||
// ======================= Converting ================================
|
||||
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||
|
||||
// ===================== Error Checking ==============================
|
||||
if (!TextureImpl::ValidateTextureName(texture, true)) return;
|
||||
if (!TextureImpl::ValidateTextureTarget(textureTarget)) return;
|
||||
|
||||
// Name 0 unbinds the current target from the active texture unit.
|
||||
if (texture == 0) {
|
||||
auto& currentUnit = MG_State::pGLContext->GetTextureUnitObject(activeUnit);
|
||||
auto& bindingSlot = currentUnit.GetBindingSlot(textureTarget);
|
||||
bindingSlot.Bind(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Some desktop-side helper code saves GL_ACTIVE_TEXTURE and later feeds it back into glBindTexture
|
||||
// as if it were a texture name. Treating that as a no-op preserves the previous "invalid bind does not
|
||||
// change texture state" behavior, but avoids poisoning the error state every frame.
|
||||
if (!MG_State::pGLContext->ValidateTextureName(texture) && texture >= GL_TEXTURE0 && texture <= GL_TEXTURE31) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TextureImpl::ValidateTextureName(texture, true)) return;
|
||||
|
||||
// ======================= Processing ================================
|
||||
Bool doesTextureExist = MG_State::pGLContext->ValidateTextureObject(texture);
|
||||
if (!doesTextureExist) {
|
||||
@@ -1326,7 +1519,9 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
// ======================= Processing ================================
|
||||
MG_State::pGLContext->SetActiveTextureUnit((Int)texture - GL_TEXTURE0);
|
||||
const Int unit = (Int)texture - GL_TEXTURE0;
|
||||
MGLOG_D("ActiveTexture_State: unit = %d", unit);
|
||||
MG_State::pGLContext->SetActiveTextureUnit(unit);
|
||||
}
|
||||
|
||||
void GetTexImage_Backend(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
|
||||
@@ -1434,27 +1629,434 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
}
|
||||
|
||||
// Check for multisampling
|
||||
if (textureObject->GetStorageType() == TextureStorageType::Mipmap) {
|
||||
auto mipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
||||
if (mipmapObject->GetMipmapLevelCount() > 1) {
|
||||
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) return;
|
||||
}
|
||||
|
||||
void CopyTextureImageToClientOrPBO_State(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
||||
TextureUploadTarget textureUploadTarget, GLint level, GLenum format,
|
||||
GLenum type, GLsizei bufSize, void* pixels, const char* caller) {
|
||||
if (!textureObject) return;
|
||||
|
||||
TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format);
|
||||
TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
|
||||
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) return;
|
||||
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) return;
|
||||
if (!TextureImpl::ValidateTextureLevelNumber(level)) return;
|
||||
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "Texture storage is not mipmap-backed."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
||||
if (static_cast<Uint>(level) >= textureMipmapObject->GetMipmapLevelCount()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "Texture level is out of range."));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto texelSize = textureMipmapObject->GetMipmapTexelSize(textureUploadTarget, level);
|
||||
const void* src = textureMipmapObject->MapMipmapData(textureUploadTarget, level);
|
||||
if (!src) return;
|
||||
|
||||
SizeT packedSize = 0;
|
||||
void* packedPixels = MG_Util::PixelStoreProcessor::ProcessTexturePixelsDataPack(
|
||||
src, MG_State::pGLContext->GetPixelStoreParameters(false), textureObject->GetFormat(), texturePixelDataType,
|
||||
textureInputFormat, texturePixelDataType, texelSize, false, packedSize);
|
||||
if (!packedPixels || packedSize == 0) {
|
||||
if (packedPixels) free(packedPixels);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bufSize >= 0 && static_cast<SizeT>(bufSize) < packedSize) {
|
||||
free(packedPixels);
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "Destination buffer is too small."));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& pixelPackBufferObject =
|
||||
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||
if (pixelPackBufferObject) {
|
||||
const SizeT offset = reinterpret_cast<SizeT>(pixels);
|
||||
if (offset + packedSize > pixelPackBufferObject->GetSize()) {
|
||||
free(packedPixels);
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
|
||||
"Multisampled textures not supported for GetTexImage"));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "Pixel pack buffer is too small."));
|
||||
return;
|
||||
}
|
||||
pixelPackBufferObject->UploadSubData({packedPixels, packedSize}, offset);
|
||||
} else if (pixels) {
|
||||
Memcpy(pixels, packedPixels, packedSize);
|
||||
}
|
||||
|
||||
free(packedPixels);
|
||||
}
|
||||
|
||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||
void CreateTextures(GLenum target, GLsizei n, GLuint* textures) {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "n must be non-negative."));
|
||||
return;
|
||||
}
|
||||
if (n > 0 && !textures) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture output pointer cannot be null."));
|
||||
return;
|
||||
}
|
||||
|
||||
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||
if (!TextureImpl::ValidateTextureTarget(textureTarget)) return;
|
||||
|
||||
Vector<Uint> textureNames;
|
||||
MG_State::pGLContext->GenTextureNames(n, textureNames);
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
textures[i] = textureNames[i];
|
||||
MG_State::pGLContext->CreateTextureObject(textureNames[i], textureTarget);
|
||||
}
|
||||
}
|
||||
|
||||
void TextureStorage2D(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
if (!textureObject) return;
|
||||
if (levels < 1) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "levels must be positive."));
|
||||
return;
|
||||
}
|
||||
if (!TextureImpl::ValidateTextureSizeRange(width, height, 1)) return;
|
||||
|
||||
TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
|
||||
textureInternalFormat = MG_Util::ConvertInternalFormatToSized(textureInternalFormat, TextureInputFormat::RGBA,
|
||||
TexturePixelDataType::UnsignedByte);
|
||||
if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return;
|
||||
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture storage is not mipmap-backed."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto textureUploadTarget = GetPrimaryUploadTarget(textureObject);
|
||||
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
|
||||
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
||||
|
||||
GLenum realInternalFormat = internalformat;
|
||||
GLenum realFormat = GL_RGBA;
|
||||
GLenum realType = GL_UNSIGNED_BYTE;
|
||||
MG_Util::TextureFormatProcessor::NormalizePixelFormat(
|
||||
MG_Util::ConvertTextureInternalFormatToGLEnum(textureInternalFormat), PixelFormatNormalizeOptionBit::None,
|
||||
&realInternalFormat, &realFormat, &realType);
|
||||
const SizeT bytesPerPixel = MG_Util::GetInternalBytesPerPixel(
|
||||
textureInternalFormat, MG_Util::ConvertGLEnumToTexturePixelDataType(realType));
|
||||
|
||||
textureObject->SetInternalFormat(textureInternalFormat);
|
||||
for (GLsizei level = 0; level < levels; ++level) {
|
||||
const GLsizei levelWidth = std::max<GLsizei>(1, width >> level);
|
||||
const GLsizei levelHeight = std::max<GLsizei>(1, height >> level);
|
||||
const SizeT byteSize = static_cast<SizeT>(levelWidth) * static_cast<SizeT>(levelHeight) * bytesPerPixel;
|
||||
textureMipmapObject->AllocateStorage(textureUploadTarget, level, {{levelWidth, levelHeight, 1}, byteSize});
|
||||
textureMipmapObject->MarkStorageDirty(textureUploadTarget, level, false);
|
||||
}
|
||||
}
|
||||
|
||||
void TextureSubImage2D(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type, const void* pixels) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
if (!textureObject) return;
|
||||
|
||||
TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format);
|
||||
TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
|
||||
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) return;
|
||||
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) return;
|
||||
if (!TextureImpl::ValidateTextureLevelNumber(level)) return;
|
||||
if (!TextureImpl::ValidateTextureSizeRange(width, height, 1)) return;
|
||||
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture storage is not mipmap-backed."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto textureUploadTarget = GetPrimaryUploadTarget(textureObject);
|
||||
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
|
||||
if (!TextureImpl::ValidateTextureInternalFormatCompatibleWithInput(textureInputFormat, textureObject->GetFormat(),
|
||||
texturePixelDataType))
|
||||
return;
|
||||
|
||||
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
||||
if (static_cast<Uint>(level) >= textureMipmapObject->GetMipmapLevelCount()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture level is out of range."));
|
||||
return;
|
||||
}
|
||||
if (!TextureImpl::ValidateTextureSubImageOffsets(textureObject, xoffset, width, yoffset, height)) return;
|
||||
|
||||
const void* originalPixels = pixels;
|
||||
const auto& pixelUnpackBufferObject =
|
||||
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelUnpack).GetBoundObject();
|
||||
if (pixelUnpackBufferObject) {
|
||||
originalPixels = reinterpret_cast<const char*>(pixelUnpackBufferObject->GetDataReadOnly()->data()) +
|
||||
reinterpret_cast<SizeT>(pixels);
|
||||
}
|
||||
if (!originalPixels) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"No data supplied from pixels parameter and no PBO bound."));
|
||||
return;
|
||||
}
|
||||
|
||||
SizeT inputSize = 0;
|
||||
void* processedPixels = MG_Util::PixelStoreProcessor::ProcessTexturePixelsDataUnpack(
|
||||
originalPixels, MG_State::pGLContext->GetPixelStoreParameters(true), textureObject->GetFormat(),
|
||||
textureInputFormat, texturePixelDataType, {width, height, 1}, false, inputSize);
|
||||
if (!processedPixels || inputSize == 0) {
|
||||
if (processedPixels) free(processedPixels);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto texelSize = textureMipmapObject->GetMipmapTexelSize(textureUploadTarget, level);
|
||||
const SizeT internalBpp = MG_Util::GetInternalBytesPerPixel(textureObject->GetFormat(), texturePixelDataType);
|
||||
const SizeT srcRowSize = static_cast<SizeT>(width) * internalBpp;
|
||||
const SizeT destRowSize = static_cast<SizeT>(texelSize.x()) * internalBpp;
|
||||
|
||||
const auto* srcData = static_cast<const Uint8*>(processedPixels);
|
||||
Uint8* destData = static_cast<Uint8*>(textureMipmapObject->MapMipmapData(textureUploadTarget, level));
|
||||
if (destData) {
|
||||
for (GLsizei y = 0; y < height; ++y) {
|
||||
const SizeT destRowOffset = static_cast<SizeT>(yoffset + y) * destRowSize +
|
||||
static_cast<SizeT>(xoffset) * internalBpp;
|
||||
const SizeT srcRowOffset = static_cast<SizeT>(y) * srcRowSize;
|
||||
Memcpy(destData + destRowOffset, srcData + srcRowOffset, srcRowSize);
|
||||
}
|
||||
textureMipmapObject->MarkStorageDirty(textureUploadTarget, level, true);
|
||||
}
|
||||
free(processedPixels);
|
||||
}
|
||||
|
||||
void TextureParameteri(GLuint texture, GLenum pname, GLint param) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
TextureParameterObject_State(textureObject, pname, param, __func__);
|
||||
}
|
||||
|
||||
void TextureParameterf(GLuint texture, GLenum pname, GLfloat param) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
TextureParameterObjectf_State(textureObject, pname, param, __func__);
|
||||
}
|
||||
|
||||
void TextureParameteriv(GLuint texture, GLenum pname, const GLint* params) {
|
||||
if (!params) return;
|
||||
if (pname == GL_TEXTURE_SWIZZLE_RGBA) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
if (!textureObject) return;
|
||||
Vec4<TextureSwizzleParam> swizzleParams;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
swizzleParams[i] = MG_Util::ConvertGLEnumToTextureSwizzleParam(static_cast<GLint>(params[i]));
|
||||
if (TextureSwizzleParam::Unknown == swizzleParams[i]) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`params` is not valid."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
textureObject->SetSwizzleParamRGBA(swizzleParams);
|
||||
return;
|
||||
}
|
||||
TextureParameteri(texture, pname, *params);
|
||||
}
|
||||
|
||||
void BindTextureUnit(GLuint unit, GLuint texture) {
|
||||
if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture unit is out of range."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(static_cast<Int>(unit));
|
||||
if (texture == 0) {
|
||||
for (auto& slot : textureUnit.GetAllBindingSlots()) {
|
||||
slot.Bind(nullptr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
if (!textureObject) return;
|
||||
textureUnit.GetBindingSlot(textureObject->GetTarget()).Bind(textureObject);
|
||||
}
|
||||
|
||||
void GetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
if (!textureObject) return;
|
||||
const auto uploadTarget = GetPrimaryUploadTarget(textureObject);
|
||||
if (MG_Backend::pActiveBackendObject != nullptr &&
|
||||
MG_Backend::pActiveBackendObject->GetBackendType() == BackendType::DirectVulkan &&
|
||||
MG_Backend::gBackendFunctionsTable.GL.GetTextureImage != nullptr) {
|
||||
MG_Backend::gBackendFunctionsTable.GL.GetTextureImage(textureObject, uploadTarget, level, format, type,
|
||||
bufSize, pixels);
|
||||
return;
|
||||
}
|
||||
CopyTextureImageToClientOrPBO_State(textureObject, uploadTarget, level, format, type, bufSize, pixels,
|
||||
__func__);
|
||||
}
|
||||
|
||||
void GetTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
|
||||
GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
if (!textureObject) return;
|
||||
if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0 || depth < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture sub-image range is invalid."));
|
||||
return;
|
||||
}
|
||||
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture storage is not mipmap-backed."));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto uploadTarget = GetPrimaryUploadTarget(textureObject);
|
||||
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
||||
if (static_cast<Uint>(level) >= textureMipmapObject->GetMipmapLevelCount()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture level is out of range."));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto texelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, static_cast<Uint>(level));
|
||||
const Bool isFullLevelRead = xoffset == 0 && yoffset == 0 && zoffset == 0 &&
|
||||
width == texelSize.x() && height == texelSize.y() &&
|
||||
depth == texelSize.z();
|
||||
if (!isFullLevelRead) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"Partial texture sub-image readback is not implemented yet."));
|
||||
return;
|
||||
}
|
||||
|
||||
GetTextureImage(texture, level, format, type, bufSize, pixels);
|
||||
}
|
||||
|
||||
void GetTextureParameteriv(GLuint texture, GLenum pname, GLint* params) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
GetTextureParameterObjectiv_State(textureObject, pname, params, __func__);
|
||||
}
|
||||
|
||||
void GetTextureLevelParameteriv(GLuint texture, GLint level, GLenum pname, GLint* params) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
if (!textureObject || !params) return;
|
||||
if (!TextureImpl::ValidateTextureLevelNumber(level)) return;
|
||||
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) return;
|
||||
|
||||
auto textureUploadTarget = GetPrimaryUploadTarget(textureObject);
|
||||
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_WIDTH:
|
||||
*params = textureMipmapObject->GetMipmapTexelSize(textureUploadTarget, level).x();
|
||||
break;
|
||||
case GL_TEXTURE_HEIGHT:
|
||||
*params = textureMipmapObject->GetMipmapTexelSize(textureUploadTarget, level).y();
|
||||
break;
|
||||
case GL_TEXTURE_DEPTH:
|
||||
*params = textureMipmapObject->GetMipmapTexelSize(textureUploadTarget, level).z();
|
||||
break;
|
||||
case GL_TEXTURE_INTERNAL_FORMAT:
|
||||
*params = (GLint)MG_Util::ConvertTextureInternalFormatToGLEnum(textureObject->GetFormat());
|
||||
break;
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"pname is not a valid texture level parameter."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access,
|
||||
GLenum format) {
|
||||
if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Image texture unit is out of range."));
|
||||
return;
|
||||
}
|
||||
if (level < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture level must be non-negative."));
|
||||
return;
|
||||
}
|
||||
if (layer < 0 && layered == GL_FALSE) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture layer must be non-negative."));
|
||||
return;
|
||||
}
|
||||
if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Invalid image texture access."));
|
||||
return;
|
||||
}
|
||||
|
||||
SharedPtr<MG_State::GLState::ITextureObject> textureObject;
|
||||
if (texture != 0) {
|
||||
if (!MG_State::pGLContext->ValidateTextureObject(texture)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture name is not a texture object."));
|
||||
return;
|
||||
}
|
||||
textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||
}
|
||||
|
||||
MG_State::pGLContext->GetImageTextureBinding(static_cast<Int>(unit))
|
||||
.Bind(textureObject, level, layered, layer, access, format);
|
||||
|
||||
auto bindImageTexture = MG_Backend::gBackendFunctionsTable.GL.BindImageTexture;
|
||||
if (!bindImageTexture) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"Backend does not support image texture binding."));
|
||||
return;
|
||||
}
|
||||
bindImageTexture(unit, texture, level, layered, layer, access, format);
|
||||
}
|
||||
|
||||
void GenerateMipmap(GLenum target) {
|
||||
GenerateMipmap_Backend(target);
|
||||
}
|
||||
|
||||
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
|
||||
GetTexImage_State(target, level, format, type, pixels);
|
||||
GetTexImage_Backend(target, level, format, type, pixels);
|
||||
if (MG_Backend::pActiveBackendObject != nullptr &&
|
||||
MG_Backend::pActiveBackendObject->GetBackendType() == BackendType::DirectVulkan &&
|
||||
MG_Backend::gBackendFunctionsTable.GL.GetTexImage != nullptr) {
|
||||
GetTexImage_Backend(target, level, format, type, pixels);
|
||||
return;
|
||||
}
|
||||
TextureUploadTarget textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
|
||||
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||
auto& activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
|
||||
const auto& textureObject = activeUnit.GetBindingSlot(textureTarget).GetBoundObject();
|
||||
CopyTextureImageToClientOrPBO_State(textureObject, textureUploadTarget, level, format, type, -1, pixels,
|
||||
__func__);
|
||||
}
|
||||
|
||||
void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
|
||||
|
||||
@@ -11,8 +11,23 @@
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access,
|
||||
GLenum format);
|
||||
void GenerateMipmap(GLenum target);
|
||||
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
|
||||
void CreateTextures(GLenum target, GLsizei n, GLuint* textures);
|
||||
void TextureStorage2D(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
void TextureSubImage2D(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type, const void* pixels);
|
||||
void TextureParameterf(GLuint texture, GLenum pname, GLfloat param);
|
||||
void TextureParameteri(GLuint texture, GLenum pname, GLint param);
|
||||
void TextureParameteriv(GLuint texture, GLenum pname, const GLint* params);
|
||||
void BindTextureUnit(GLuint unit, GLuint texture);
|
||||
void GetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels);
|
||||
void GetTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
|
||||
GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels);
|
||||
void GetTextureParameteriv(GLuint texture, GLenum pname, GLint* params);
|
||||
void GetTextureLevelParameteriv(GLuint texture, GLint level, GLenum pname, GLint* params);
|
||||
void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
|
||||
GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels);
|
||||
void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
|
||||
|
||||
@@ -8,11 +8,34 @@
|
||||
|
||||
#include "GL_VertexArray.h"
|
||||
#include "Validators.h"
|
||||
#include <MG_Impl/GLImpl/Buffer/Validators.h>
|
||||
#include <MG_State/GLState/Core.h>
|
||||
#include <MG_State/GLState/ErrorState/Error.h>
|
||||
#include <MG_Util/Converters/GLToMG/DataTypeConverter.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
SharedPtr<MG_State::GLState::VertexArrayObject> GetNamedVertexArrayObject_State(GLuint vaobj,
|
||||
const char* caller) {
|
||||
if (!VertexArrayImpl::ValidateVertexArrayName(vaobj)) return nullptr;
|
||||
if (!VertexArrayImpl::ValidateVertexArrayObject(vaobj)) return nullptr;
|
||||
return MG_State::pGLContext->GetVertexArrayObject(vaobj);
|
||||
}
|
||||
|
||||
SharedPtr<MG_State::GLState::BufferObject> GetVertexArrayBufferObject_State(GLuint buffer, const char* caller) {
|
||||
if (!BufferImpl::ValidateBufferName(buffer, true)) return nullptr;
|
||||
if (buffer == 0) return nullptr;
|
||||
|
||||
auto& bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
|
||||
if (!bufferObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||
std::format("Buffer object {} does not exist.", buffer)));
|
||||
return nullptr;
|
||||
}
|
||||
return bufferObject;
|
||||
}
|
||||
|
||||
void DisableVertexAttribArray_State(GLuint index) {
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
|
||||
|
||||
@@ -60,12 +83,6 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
|
||||
auto& vboSlot = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex);
|
||||
auto& vbo = vboSlot.GetBoundObject();
|
||||
if (!vbo) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
|
||||
"No buffer is bound to GL_ARRAY_BUFFER."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto offset = reinterpret_cast<SizeT>(pointer);
|
||||
|
||||
@@ -91,12 +108,6 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
|
||||
auto& vboSlot = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex);
|
||||
auto& vbo = vboSlot.GetBoundObject();
|
||||
if (!vbo) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
|
||||
"No buffer is bound to GL_ARRAY_BUFFER."));
|
||||
return;
|
||||
}
|
||||
|
||||
SizeT offset = reinterpret_cast<SizeT>(pointer);
|
||||
|
||||
@@ -150,27 +161,99 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return;
|
||||
}
|
||||
|
||||
static thread_local Vector<Uint> vaos;
|
||||
Vector<Uint> vaos;
|
||||
MG_State::pGLContext->GenVertexArrayNames(n, vaos);
|
||||
Memcpy(arrays, vaos.data(), n * sizeof(GLuint));
|
||||
}
|
||||
|
||||
GLboolean IsVertexArray_State(GLuint array) {
|
||||
if (array == 0) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "IsVertexArray_State",
|
||||
"Vertex array name 0 is not supported."));
|
||||
return GL_FALSE;
|
||||
}
|
||||
if (!VertexArrayImpl::ValidateVertexArrayName(array)) return GL_FALSE;
|
||||
if (!MG_State::pGLContext->ValidateVertexArrayObject(array)) {
|
||||
void CreateVertexArrays_State(GLsizei n, GLuint* arrays) {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "IsVertexArray_State",
|
||||
std::format("Vertex array object {} does not exist.", array)));
|
||||
return GL_FALSE;
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CreateVertexArrays_State", "n must be non-negative."));
|
||||
return;
|
||||
}
|
||||
return GL_TRUE;
|
||||
|
||||
Vector<Uint> vaos;
|
||||
MG_State::pGLContext->GenVertexArrayNames(n, vaos);
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
MG_State::pGLContext->CreateVertexArrayObject(vaos[i]);
|
||||
arrays[i] = vaos[i];
|
||||
}
|
||||
}
|
||||
|
||||
void DisableVertexArrayAttrib_State(GLuint vaobj, GLuint index) {
|
||||
auto vao = GetNamedVertexArrayObject_State(vaobj, "DisableVertexArrayAttrib_State");
|
||||
if (!vao) return;
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
|
||||
vao->DisableAttribute(index);
|
||||
}
|
||||
|
||||
void EnableVertexArrayAttrib_State(GLuint vaobj, GLuint index) {
|
||||
auto vao = GetNamedVertexArrayObject_State(vaobj, "EnableVertexArrayAttrib_State");
|
||||
if (!vao) return;
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
|
||||
vao->EnableAttribute(index);
|
||||
}
|
||||
|
||||
void VertexArrayElementBuffer_State(GLuint vaobj, GLuint buffer) {
|
||||
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayElementBuffer_State");
|
||||
if (!vao) return;
|
||||
auto bufferObject = GetVertexArrayBufferObject_State(buffer, "VertexArrayElementBuffer_State");
|
||||
if (buffer != 0 && !bufferObject) return;
|
||||
vao->GetIndexBufferBindingSlot().Bind(bufferObject);
|
||||
}
|
||||
|
||||
void VertexArrayVertexBuffer_State(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset,
|
||||
GLsizei stride) {
|
||||
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayVertexBuffer_State");
|
||||
if (!vao) return;
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(bindingindex)) return;
|
||||
if (offset < 0 || stride < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexArrayVertexBuffer_State",
|
||||
"offset and stride must be non-negative."));
|
||||
return;
|
||||
}
|
||||
auto bufferObject = GetVertexArrayBufferObject_State(buffer, "VertexArrayVertexBuffer_State");
|
||||
if (buffer != 0 && !bufferObject) return;
|
||||
|
||||
const auto& attr = vao->GetAttribute(bindingindex);
|
||||
vao->SetAttributeFormat(bindingindex, attr.Size, attr.Type, attr.Normalized, stride, static_cast<SizeT>(offset),
|
||||
attr.IsInteger);
|
||||
vao->BindAttributeBuffer(bindingindex, bufferObject);
|
||||
}
|
||||
|
||||
void VertexArrayAttribFormat_State(GLuint vaobj, GLuint attribindex, GLint size, GLenum type,
|
||||
GLboolean normalized, GLuint relativeoffset) {
|
||||
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayAttribFormat_State");
|
||||
if (!vao) return;
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(attribindex)) return;
|
||||
|
||||
DataType dataType = MG_Util::ConvertGLEnumToDataType(type);
|
||||
const auto& attr = vao->GetAttribute(attribindex);
|
||||
if (!VertexArrayImpl::ValidateVertexAttribPointerParams(attribindex, size, dataType, attr.Stride)) return;
|
||||
|
||||
vao->SetAttributeFormat(attribindex, size, dataType, normalized, attr.Stride, relativeoffset, false);
|
||||
}
|
||||
|
||||
void VertexArrayAttribIFormat_State(GLuint vaobj, GLuint attribindex, GLint size, GLenum type,
|
||||
GLuint relativeoffset) {
|
||||
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayAttribIFormat_State");
|
||||
if (!vao) return;
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(attribindex)) return;
|
||||
|
||||
DataType dataType = MG_Util::ConvertGLEnumToDataType(type);
|
||||
const auto& attr = vao->GetAttribute(attribindex);
|
||||
if (!VertexArrayImpl::ValidateVertexAttribPointerParams(attribindex, size, dataType, attr.Stride)) return;
|
||||
|
||||
vao->SetAttributeFormat(attribindex, size, dataType, false, attr.Stride, relativeoffset, true);
|
||||
}
|
||||
|
||||
GLboolean IsVertexArray_State(GLuint array) {
|
||||
if (array == 0) return GL_FALSE;
|
||||
return MG_State::pGLContext->ValidateVertexArrayObject(array) ? GL_TRUE : GL_FALSE;
|
||||
}
|
||||
|
||||
void VertexAttribDivisor_State(GLuint index, GLuint divisor) {
|
||||
@@ -188,6 +271,35 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||
void CreateVertexArrays(GLsizei n, GLuint* arrays) {
|
||||
CreateVertexArrays_State(n, arrays);
|
||||
}
|
||||
|
||||
void DisableVertexArrayAttrib(GLuint vaobj, GLuint index) {
|
||||
DisableVertexArrayAttrib_State(vaobj, index);
|
||||
}
|
||||
|
||||
void EnableVertexArrayAttrib(GLuint vaobj, GLuint index) {
|
||||
EnableVertexArrayAttrib_State(vaobj, index);
|
||||
}
|
||||
|
||||
void VertexArrayElementBuffer(GLuint vaobj, GLuint buffer) {
|
||||
VertexArrayElementBuffer_State(vaobj, buffer);
|
||||
}
|
||||
|
||||
void VertexArrayVertexBuffer(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) {
|
||||
VertexArrayVertexBuffer_State(vaobj, bindingindex, buffer, offset, stride);
|
||||
}
|
||||
|
||||
void VertexArrayAttribFormat(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized,
|
||||
GLuint relativeoffset) {
|
||||
VertexArrayAttribFormat_State(vaobj, attribindex, size, type, normalized, relativeoffset);
|
||||
}
|
||||
|
||||
void VertexArrayAttribIFormat(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) {
|
||||
VertexArrayAttribIFormat_State(vaobj, attribindex, size, type, relativeoffset);
|
||||
}
|
||||
|
||||
void VertexAttribDivisor(GLuint index, GLuint divisor) {
|
||||
VertexAttribDivisor_State(index, divisor);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,14 @@
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void CreateVertexArrays(GLsizei n, GLuint* arrays);
|
||||
void DisableVertexArrayAttrib(GLuint vaobj, GLuint index);
|
||||
void EnableVertexArrayAttrib(GLuint vaobj, GLuint index);
|
||||
void VertexArrayElementBuffer(GLuint vaobj, GLuint buffer);
|
||||
void VertexArrayVertexBuffer(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
|
||||
void VertexArrayAttribFormat(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized,
|
||||
GLuint relativeoffset);
|
||||
void VertexArrayAttribIFormat(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
|
||||
void VertexAttribDivisor(GLuint index, GLuint divisor);
|
||||
GLboolean IsVertexArray(GLuint array);
|
||||
void DisableVertexAttribArray(GLuint index);
|
||||
|
||||
@@ -321,22 +321,39 @@ namespace MobileGL::MG_Impl {
|
||||
GETPROC(glClearBufferfi, name);
|
||||
GETPROC(glGetStringi, name);
|
||||
GETPROC(glIsRenderbuffer, name);
|
||||
GETPROC(glIsRenderbufferEXT, name);
|
||||
GETPROC(glBindRenderbuffer, name);
|
||||
GETPROC(glBindRenderbufferEXT, name);
|
||||
GETPROC(glDeleteRenderbuffers, name);
|
||||
GETPROC(glDeleteRenderbuffersEXT, name);
|
||||
GETPROC(glGenRenderbuffers, name);
|
||||
GETPROC(glGenRenderbuffersEXT, name);
|
||||
GETPROC(glRenderbufferStorage, name);
|
||||
GETPROC(glRenderbufferStorageEXT, name);
|
||||
GETPROC(glGetRenderbufferParameteriv, name);
|
||||
GETPROC(glGetRenderbufferParameterivEXT, name);
|
||||
GETPROC(glIsFramebuffer, name);
|
||||
GETPROC(glIsFramebufferEXT, name);
|
||||
GETPROC(glBindFramebuffer, name);
|
||||
GETPROC(glBindFramebufferEXT, name);
|
||||
GETPROC(glDeleteFramebuffers, name);
|
||||
GETPROC(glDeleteFramebuffersEXT, name);
|
||||
GETPROC(glGenFramebuffers, name);
|
||||
GETPROC(glGenFramebuffersEXT, name);
|
||||
GETPROC(glCheckFramebufferStatus, name);
|
||||
GETPROC(glCheckFramebufferStatusEXT, name);
|
||||
GETPROC(glFramebufferTexture1D, name);
|
||||
GETPROC(glFramebufferTexture1DEXT, name);
|
||||
GETPROC(glFramebufferTexture2D, name);
|
||||
GETPROC(glFramebufferTexture2DEXT, name);
|
||||
GETPROC(glFramebufferTexture3D, name);
|
||||
GETPROC(glFramebufferTexture3DEXT, name);
|
||||
GETPROC(glFramebufferRenderbuffer, name);
|
||||
GETPROC(glFramebufferRenderbufferEXT, name);
|
||||
GETPROC(glGetFramebufferAttachmentParameteriv, name);
|
||||
GETPROC(glGetFramebufferAttachmentParameterivEXT, name);
|
||||
GETPROC(glGenerateMipmap, name);
|
||||
GETPROC(glGenerateMipmapEXT, name);
|
||||
GETPROC(glBlitFramebuffer, name);
|
||||
GETPROC(glRenderbufferStorageMultisample, name);
|
||||
GETPROC(glFramebufferTextureLayer, name);
|
||||
|
||||
@@ -14,6 +14,69 @@ namespace MobileGL {
|
||||
namespace {
|
||||
constexpr EGLint EGL_DISPLAY_MAJOR_VERSION = 1;
|
||||
constexpr EGLint EGL_DISPLAY_MINOR_VERSION = 5;
|
||||
constexpr EGLint DEFAULT_MAX_PBUFFER_SIZE = 16384;
|
||||
|
||||
template <typename AttrType>
|
||||
Optional<AttrType> ParseAttribValue(const AttrType* attribList, EGLint attrib) {
|
||||
if (!attribList) {
|
||||
return Nullopt;
|
||||
}
|
||||
for (SizeT i = 0; attribList[i] != EGL_NONE; i += 2) {
|
||||
if (attribList[i] == static_cast<AttrType>(attrib)) {
|
||||
return attribList[i + 1];
|
||||
}
|
||||
}
|
||||
return Nullopt;
|
||||
}
|
||||
|
||||
EGLint QueryDefaultX11VisualId() {
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
const char* displayName = std::getenv("DISPLAY");
|
||||
if (!displayName) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* x11Lib = dlopen("libX11.so.6", RTLD_LOCAL | RTLD_NOW);
|
||||
if (!x11Lib) {
|
||||
x11Lib = dlopen("libX11.so", RTLD_LOCAL | RTLD_NOW);
|
||||
}
|
||||
if (!x11Lib) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
using XOpenDisplayFn = void* (*)(const char*);
|
||||
using XDefaultScreenFn = int (*)(void*);
|
||||
using XDefaultVisualFn = void* (*)(void*, int);
|
||||
using XVisualIDFromVisualFn = unsigned long (*)(void*);
|
||||
using XCloseDisplayFn = int (*)(void*);
|
||||
|
||||
auto* xOpenDisplay = reinterpret_cast<XOpenDisplayFn>(dlsym(x11Lib, "XOpenDisplay"));
|
||||
auto* xDefaultScreen = reinterpret_cast<XDefaultScreenFn>(dlsym(x11Lib, "XDefaultScreen"));
|
||||
auto* xDefaultVisual = reinterpret_cast<XDefaultVisualFn>(dlsym(x11Lib, "XDefaultVisual"));
|
||||
auto* xVisualIDFromVisual =
|
||||
reinterpret_cast<XVisualIDFromVisualFn>(dlsym(x11Lib, "XVisualIDFromVisual"));
|
||||
auto* xCloseDisplay = reinterpret_cast<XCloseDisplayFn>(dlsym(x11Lib, "XCloseDisplay"));
|
||||
if (!xOpenDisplay || !xDefaultScreen || !xDefaultVisual || !xVisualIDFromVisual || !xCloseDisplay) {
|
||||
dlclose(x11Lib);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* display = xOpenDisplay(displayName);
|
||||
if (!display) {
|
||||
dlclose(x11Lib);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int screen = xDefaultScreen(display);
|
||||
void* visual = xDefaultVisual(display, screen);
|
||||
const auto visualId = visual ? static_cast<EGLint>(xVisualIDFromVisual(visual)) : 0;
|
||||
xCloseDisplay(display);
|
||||
dlclose(x11Lib);
|
||||
return visualId;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Bool EGLContext::DisplayLookupKey::operator==(const DisplayLookupKey& rhs) const {
|
||||
@@ -65,30 +128,6 @@ namespace MobileGL {
|
||||
return apiIt->second;
|
||||
}
|
||||
|
||||
Optional<EGLint> EGLContext::ParseAttribValue(const EGLint* attribList, EGLint attrib) {
|
||||
if (!attribList) {
|
||||
return Nullopt;
|
||||
}
|
||||
for (SizeT i = 0; attribList[i] != EGL_NONE; i += 2) {
|
||||
if (attribList[i] == attrib) {
|
||||
return attribList[i + 1];
|
||||
}
|
||||
}
|
||||
return Nullopt;
|
||||
}
|
||||
|
||||
Optional<EGLAttrib> EGLContext::ParseAttribValue(const EGLAttrib* attribList, EGLint attrib) {
|
||||
if (!attribList) {
|
||||
return Nullopt;
|
||||
}
|
||||
for (SizeT i = 0; attribList[i] != EGL_NONE; i += 2) {
|
||||
if (attribList[i] == static_cast<EGLAttrib>(attrib)) {
|
||||
return attribList[i + 1];
|
||||
}
|
||||
}
|
||||
return Nullopt;
|
||||
}
|
||||
|
||||
EGLContext::EGLDisplayHandle EGLContext::GetOrCreateDisplay(Uint64 nativeDisplayKey, EGLenum platform) {
|
||||
const DisplayLookupKey key = {
|
||||
.NativeDisplayKey = nativeDisplayKey,
|
||||
@@ -110,30 +149,31 @@ namespace MobileGL {
|
||||
.SwapInterval = 1,
|
||||
};
|
||||
|
||||
const auto config = CreateDefaultConfig(display);
|
||||
displayObject.Configs.push_back(config);
|
||||
displayObject.Configs.push_back(CreateDefaultConfig(display, 1, 0));
|
||||
displayObject.Configs.push_back(CreateDefaultConfig(display, 2, 8));
|
||||
|
||||
m_displays[display] = displayObject;
|
||||
m_displayLookup[key] = display;
|
||||
return display;
|
||||
}
|
||||
|
||||
EGLContext::EGLConfigHandle EGLContext::CreateDefaultConfig(EGLDisplayHandle display) {
|
||||
EGLContext::EGLConfigHandle EGLContext::CreateDefaultConfig(EGLDisplayHandle display, EGLint configId,
|
||||
EGLint stencilSize) {
|
||||
const auto config = EncodeHandle<EGLConfigHandle>(m_nextConfigHandle++);
|
||||
ConfigObject cfg = {
|
||||
.Display = display,
|
||||
.ConfigId = 1,
|
||||
.ConfigId = configId,
|
||||
.RedSize = 8,
|
||||
.GreenSize = 8,
|
||||
.BlueSize = 8,
|
||||
.AlphaSize = 8,
|
||||
.DepthSize = 24,
|
||||
.StencilSize = 8,
|
||||
.StencilSize = stencilSize,
|
||||
.SurfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT | EGL_PIXMAP_BIT,
|
||||
.RenderableType = EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT,
|
||||
.MinSwapInterval = 0,
|
||||
.MaxSwapInterval = 4,
|
||||
.NativeVisualId = 0,
|
||||
.NativeVisualId = QueryDefaultX11VisualId(),
|
||||
};
|
||||
#if defined(ANDROID) || defined(__ANDROID__)
|
||||
cfg.NativeVisualId = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
|
||||
@@ -305,7 +345,6 @@ namespace MobileGL {
|
||||
Bool EGLContext::ChooseConfig(EGLDisplayHandle display, const EGLint* attribList, EGLConfigHandle* configs,
|
||||
EGLint configSize, EGLint* numConfig) {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||
(void)attribList;
|
||||
auto* displayObject = TryGetDisplay(display);
|
||||
if (!displayObject) {
|
||||
SetError(EGL_BAD_DISPLAY);
|
||||
@@ -320,14 +359,84 @@ namespace MobileGL {
|
||||
return false;
|
||||
}
|
||||
|
||||
*numConfig = static_cast<EGLint>(displayObject->Configs.size());
|
||||
Vector<EGLConfigHandle> matchedConfigs;
|
||||
for (const auto config : displayObject->Configs) {
|
||||
const auto* cfg = TryGetConfig(config);
|
||||
if (!cfg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Bool matches = true;
|
||||
if (attribList) {
|
||||
for (SizeT i = 0; attribList[i] != EGL_NONE; i += 2) {
|
||||
const EGLint attr = attribList[i];
|
||||
const EGLint requested = attribList[i + 1];
|
||||
if (requested == EGL_DONT_CARE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (attr) {
|
||||
case EGL_CONFIG_ID:
|
||||
matches = cfg->ConfigId == requested;
|
||||
break;
|
||||
case EGL_RED_SIZE:
|
||||
matches = cfg->RedSize >= requested;
|
||||
break;
|
||||
case EGL_GREEN_SIZE:
|
||||
matches = cfg->GreenSize >= requested;
|
||||
break;
|
||||
case EGL_BLUE_SIZE:
|
||||
matches = cfg->BlueSize >= requested;
|
||||
break;
|
||||
case EGL_ALPHA_SIZE:
|
||||
matches = cfg->AlphaSize >= requested;
|
||||
break;
|
||||
case EGL_BUFFER_SIZE:
|
||||
matches = (cfg->RedSize + cfg->GreenSize + cfg->BlueSize + cfg->AlphaSize) >= requested;
|
||||
break;
|
||||
case EGL_DEPTH_SIZE:
|
||||
matches = cfg->DepthSize >= requested;
|
||||
break;
|
||||
case EGL_STENCIL_SIZE:
|
||||
matches = cfg->StencilSize >= requested;
|
||||
break;
|
||||
case EGL_SURFACE_TYPE:
|
||||
matches = (cfg->SurfaceType & requested) == requested;
|
||||
break;
|
||||
case EGL_RENDERABLE_TYPE:
|
||||
case EGL_CONFORMANT:
|
||||
matches = (cfg->RenderableType & requested) == requested;
|
||||
break;
|
||||
case EGL_SAMPLE_BUFFERS:
|
||||
case EGL_SAMPLES:
|
||||
matches = requested == 0;
|
||||
break;
|
||||
case EGL_NATIVE_VISUAL_ID:
|
||||
matches = cfg->NativeVisualId == requested;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!matches) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matches) {
|
||||
matchedConfigs.push_back(config);
|
||||
}
|
||||
}
|
||||
|
||||
*numConfig = static_cast<EGLint>(matchedConfigs.size());
|
||||
if (!configs || configSize <= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const SizeT copyCount = std::min(static_cast<SizeT>(configSize), displayObject->Configs.size());
|
||||
const SizeT copyCount = std::min(static_cast<SizeT>(configSize), matchedConfigs.size());
|
||||
for (SizeT i = 0; i < copyCount; ++i) {
|
||||
configs[i] = displayObject->Configs[i];
|
||||
configs[i] = matchedConfigs[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -367,9 +476,38 @@ namespace MobileGL {
|
||||
}
|
||||
|
||||
switch (attribute) {
|
||||
case EGL_BUFFER_SIZE:
|
||||
*value = cfg->RedSize + cfg->GreenSize + cfg->BlueSize + cfg->AlphaSize;
|
||||
return true;
|
||||
case EGL_ALPHA_MASK_SIZE:
|
||||
*value = 0;
|
||||
return true;
|
||||
case EGL_BIND_TO_TEXTURE_RGB:
|
||||
case EGL_BIND_TO_TEXTURE_RGBA:
|
||||
*value = EGL_FALSE;
|
||||
return true;
|
||||
case EGL_COLOR_BUFFER_TYPE:
|
||||
*value = EGL_RGB_BUFFER;
|
||||
return true;
|
||||
case EGL_CONFIG_CAVEAT:
|
||||
*value = EGL_NONE;
|
||||
return true;
|
||||
case EGL_CONFIG_ID:
|
||||
*value = cfg->ConfigId;
|
||||
return true;
|
||||
case EGL_LEVEL:
|
||||
*value = 0;
|
||||
return true;
|
||||
case EGL_LUMINANCE_SIZE:
|
||||
*value = 0;
|
||||
return true;
|
||||
case EGL_MAX_PBUFFER_WIDTH:
|
||||
case EGL_MAX_PBUFFER_HEIGHT:
|
||||
*value = DEFAULT_MAX_PBUFFER_SIZE;
|
||||
return true;
|
||||
case EGL_MAX_PBUFFER_PIXELS:
|
||||
*value = DEFAULT_MAX_PBUFFER_SIZE * DEFAULT_MAX_PBUFFER_SIZE;
|
||||
return true;
|
||||
case EGL_RED_SIZE:
|
||||
*value = cfg->RedSize;
|
||||
return true;
|
||||
@@ -401,9 +539,27 @@ namespace MobileGL {
|
||||
case EGL_MAX_SWAP_INTERVAL:
|
||||
*value = cfg->MaxSwapInterval;
|
||||
return true;
|
||||
case EGL_NATIVE_RENDERABLE:
|
||||
*value = EGL_TRUE;
|
||||
return true;
|
||||
case EGL_NATIVE_VISUAL_ID:
|
||||
*value = cfg->NativeVisualId;
|
||||
return true;
|
||||
case EGL_NATIVE_VISUAL_TYPE:
|
||||
*value = cfg->NativeVisualId;
|
||||
return true;
|
||||
case EGL_SAMPLE_BUFFERS:
|
||||
case EGL_SAMPLES:
|
||||
*value = 0;
|
||||
return true;
|
||||
case EGL_TRANSPARENT_TYPE:
|
||||
*value = EGL_NONE;
|
||||
return true;
|
||||
case EGL_TRANSPARENT_RED_VALUE:
|
||||
case EGL_TRANSPARENT_GREEN_VALUE:
|
||||
case EGL_TRANSPARENT_BLUE_VALUE:
|
||||
*value = 0;
|
||||
return true;
|
||||
default:
|
||||
const_cast<EGLContext*>(this)->SetError(EGL_BAD_ATTRIBUTE);
|
||||
return false;
|
||||
|
||||
@@ -210,12 +210,10 @@ namespace MobileGL {
|
||||
}
|
||||
}
|
||||
|
||||
static Optional<EGLint> ParseAttribValue(const EGLint* attribList, EGLint attrib);
|
||||
static Optional<EGLAttrib> ParseAttribValue(const EGLAttrib* attribList, EGLint attrib);
|
||||
static std::thread::id CurrentThreadKey();
|
||||
|
||||
EGLDisplayHandle GetOrCreateDisplay(Uint64 nativeDisplayKey, EGLenum platform);
|
||||
EGLConfigHandle CreateDefaultConfig(EGLDisplayHandle display);
|
||||
EGLConfigHandle CreateDefaultConfig(EGLDisplayHandle display, EGLint configId, EGLint stencilSize);
|
||||
|
||||
DisplayObject* TryGetDisplay(EGLDisplayHandle display);
|
||||
const DisplayObject* TryGetDisplay(EGLDisplayHandle display) const;
|
||||
|
||||
@@ -18,23 +18,47 @@ namespace MobileGL::MG_State::GLState {
|
||||
}
|
||||
|
||||
void BufferObject::Resize(SizeT size) {
|
||||
ReleaseMemory();
|
||||
m_size = size;
|
||||
m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve
|
||||
m_dataPtr->resize(size);
|
||||
m_isImmutableStorage = false;
|
||||
m_storageFlags = 0;
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::PreferReallocationBit;
|
||||
++m_changeSerial;
|
||||
}
|
||||
|
||||
void BufferObject::AllocateImmutableStorage(SizeT size, const void* data, GLbitfield storageFlags) {
|
||||
ReleaseMemory();
|
||||
m_size = size;
|
||||
m_dataPtr->reserve(std::bit_ceil(size));
|
||||
m_dataPtr->resize(size);
|
||||
if (data) {
|
||||
Memcpy(m_dataPtr->data(), data, size);
|
||||
} else if (size > 0) {
|
||||
Memset(m_dataPtr->data(), 0, size);
|
||||
}
|
||||
m_isImmutableStorage = true;
|
||||
m_storageFlags = storageFlags;
|
||||
m_change.DirtyRanges.clear();
|
||||
m_change.DirtyRanges.Add({0, size});
|
||||
m_change.Bits = BufferChangeBits::DirtyBit | BufferChangeBits::PreferReallocationBit;
|
||||
++m_changeSerial;
|
||||
}
|
||||
|
||||
void BufferObject::UploadData(DataPtr data, SizeT atOffset) {
|
||||
MOBILEGL_ASSERT(atOffset + data.size <= m_size,
|
||||
"UploadData out of bounds: atOffset (%zu) + data.size (%zu) > m_size (%zu)", atOffset,
|
||||
data.size, m_size);
|
||||
MOBILEGL_ASSERT(!m_isMapped, "Cannot upload data while buffer is mapped.");
|
||||
MOBILEGL_ASSERT(!m_isMapped || (m_mappingAccess & BufferMappingAccessBit::Persistent),
|
||||
"Cannot upload data while buffer is non-persistently mapped.");
|
||||
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
|
||||
m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
|
||||
++m_changeSerial;
|
||||
// This function may be called by `glBufferData`, but we still set the forbid bits above,
|
||||
// because when `PreferReallocationBit` is set, those bits are ignored anyway.
|
||||
// The bits can fit the `glBufferSubData` semantics
|
||||
@@ -50,10 +74,13 @@ namespace MobileGL::MG_State::GLState {
|
||||
|
||||
if (m_mappingAccess & BufferMappingAccessBit::Write) { // if we wrote to the buffer
|
||||
if (!(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly
|
||||
Memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(),
|
||||
m_mappedRange.end - m_mappedRange.start);
|
||||
if (!(m_mappingAccess & BufferMappingAccessBit::Persistent)) {
|
||||
Memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(),
|
||||
m_mappedRange.end - m_mappedRange.start);
|
||||
}
|
||||
m_change.DirtyRanges.Add({m_mappedRange.start, m_mappedRange.end});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
++m_changeSerial;
|
||||
}
|
||||
|
||||
m_stagingData.clear();
|
||||
@@ -77,13 +104,29 @@ namespace MobileGL::MG_State::GLState {
|
||||
MOBILEGL_ASSERT(end <= m_mappedRange.end, "Flush range out of bounds: mappedRange.end (%zu) < end (%zu)",
|
||||
m_mappedRange.end, end);
|
||||
|
||||
Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length);
|
||||
if (!(m_mappingAccess & BufferMappingAccessBit::Persistent)) {
|
||||
Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length);
|
||||
}
|
||||
m_change.DirtyRanges.Add({start, end});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
++m_changeSerial;
|
||||
}
|
||||
|
||||
void BufferObject::MarkPersistentMappedRangeDirty() {
|
||||
if (!m_isMapped) return;
|
||||
if (!(m_mappingAccess & BufferMappingAccessBit::Persistent)) return;
|
||||
if (!(m_mappingAccess & BufferMappingAccessBit::Write)) return;
|
||||
if (m_mappingAccess & BufferMappingAccessBit::FlushExplicit) return;
|
||||
if (m_mappedRange.start >= m_mappedRange.end) return;
|
||||
|
||||
m_change.DirtyRanges.Add(m_mappedRange);
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
++m_changeSerial;
|
||||
}
|
||||
|
||||
void BufferObject::UploadSubData(DataPtr data, SizeT atOffset) {
|
||||
MOBILEGL_ASSERT(!m_isMapped, "Cannot upload sub data while buffer is mapped.");
|
||||
MOBILEGL_ASSERT(!m_isMapped || (m_mappingAccess & BufferMappingAccessBit::Persistent),
|
||||
"Cannot upload sub data while buffer is non-persistently mapped.");
|
||||
MOBILEGL_ASSERT(atOffset + data.size <= m_size,
|
||||
"UploadSubData out of bounds: atOffset (%zu) + data.size (%zu) > m_size (%zu)", atOffset,
|
||||
data.size, m_size);
|
||||
@@ -93,11 +136,14 @@ namespace MobileGL::MG_State::GLState {
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
|
||||
++m_changeSerial;
|
||||
}
|
||||
|
||||
void BufferObject::CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, SizeT size) {
|
||||
MOBILEGL_ASSERT(!m_isMapped, "Cannot copy data while buffer is mapped.");
|
||||
MOBILEGL_ASSERT(!src->IsMapped(), "Cannot copy data from a buffer that is mapped.");
|
||||
MOBILEGL_ASSERT(!m_isMapped || (m_mappingAccess & BufferMappingAccessBit::Persistent),
|
||||
"Cannot copy data while destination buffer is non-persistently mapped.");
|
||||
MOBILEGL_ASSERT(!src->IsMapped() || (src->GetMappingAccess() & BufferMappingAccessBit::Persistent),
|
||||
"Cannot copy data from a buffer that is non-persistently mapped.");
|
||||
MOBILEGL_ASSERT(srcOffset + size <= src->GetSize(),
|
||||
"Source buffer copy out of bounds: srcOffset (%zu) + size (%zu) > src->GetSize() (%zu)",
|
||||
srcOffset, size, src->GetSize());
|
||||
@@ -109,6 +155,7 @@ namespace MobileGL::MG_State::GLState {
|
||||
Memcpy(m_dataPtr->data() + dstOffset, srcData, size);
|
||||
m_change.DirtyRanges.Add({dstOffset, dstOffset + size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
++m_changeSerial;
|
||||
}
|
||||
|
||||
void* BufferObject::AcquireMemory(Bool markMapped, Bool read, Bool write) {
|
||||
@@ -143,6 +190,19 @@ namespace MobileGL::MG_State::GLState {
|
||||
m_mappingAccess = access;
|
||||
m_mappedRange = range;
|
||||
|
||||
m_change.Bits |=
|
||||
!(access & BufferMappingAccessBit::InvalidateBuffer || access & BufferMappingAccessBit::InvalidateRange)
|
||||
? BufferChangeBits::ForbidInvalidationBit
|
||||
: BufferChangeBits::None;
|
||||
m_change.Bits |= !(access & BufferMappingAccessBit::Unsynchronized)
|
||||
? BufferChangeBits::ForbidUnsynchronizationBit
|
||||
: BufferChangeBits::None;
|
||||
|
||||
if (access & BufferMappingAccessBit::Persistent) {
|
||||
m_ownsStagingData = false;
|
||||
return m_dataPtr->data() + range.start;
|
||||
}
|
||||
|
||||
if (access & BufferMappingAccessBit::Write) {
|
||||
m_stagingData.resize(range.end - range.start);
|
||||
m_ownsStagingData = true;
|
||||
@@ -156,14 +216,6 @@ namespace MobileGL::MG_State::GLState {
|
||||
m_ownsStagingData = false;
|
||||
return m_dataPtr->data() + range.start;
|
||||
}
|
||||
|
||||
m_change.Bits |=
|
||||
!(access & BufferMappingAccessBit::InvalidateBuffer || access & BufferMappingAccessBit::InvalidateRange)
|
||||
? BufferChangeBits::ForbidInvalidationBit
|
||||
: BufferChangeBits::None;
|
||||
m_change.Bits |= !(access & BufferMappingAccessBit::Unsynchronized)
|
||||
? BufferChangeBits::ForbidUnsynchronizationBit
|
||||
: BufferChangeBits::None;
|
||||
}
|
||||
|
||||
const SharedPtr<Data>& BufferObject::GetDataReadOnly() const {
|
||||
@@ -179,6 +231,10 @@ namespace MobileGL::MG_State::GLState {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
Bool BufferObject::IsImmutableStorage() const {
|
||||
return m_isImmutableStorage;
|
||||
}
|
||||
|
||||
BufferUsage BufferObject::GetUsage() const {
|
||||
return m_usage;
|
||||
}
|
||||
@@ -191,6 +247,10 @@ namespace MobileGL::MG_State::GLState {
|
||||
return m_change.Bits;
|
||||
}
|
||||
|
||||
Uint64 BufferObject::GetChangeSerial() const {
|
||||
return m_changeSerial;
|
||||
}
|
||||
|
||||
Bool BufferObject::IsMapped() const {
|
||||
return m_isMapped;
|
||||
}
|
||||
@@ -199,10 +259,25 @@ namespace MobileGL::MG_State::GLState {
|
||||
return m_isMapped ? m_mappedRange : Range1D{0, 0};
|
||||
}
|
||||
|
||||
void* BufferObject::GetMappedPointer() const {
|
||||
if (!m_isMapped) return nullptr;
|
||||
if (m_mappingAccess & BufferMappingAccessBit::Persistent) {
|
||||
return const_cast<Uint8*>(m_dataPtr->data()) + m_mappedRange.start;
|
||||
}
|
||||
if (m_ownsStagingData) {
|
||||
return const_cast<Uint8*>(m_stagingData.data());
|
||||
}
|
||||
return const_cast<Uint8*>(m_dataPtr->data()) + m_mappedRange.start;
|
||||
}
|
||||
|
||||
Flags<BufferMappingAccessBit> BufferObject::GetMappingAccess() const {
|
||||
return m_isMapped ? m_mappingAccess : BufferMappingAccessBit::Null;
|
||||
}
|
||||
|
||||
GLbitfield BufferObject::GetStorageFlags() const {
|
||||
return m_storageFlags;
|
||||
}
|
||||
|
||||
Uint BufferObject::GetExternalIndex() const {
|
||||
return m_externalIndex;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace MobileGL {
|
||||
AtomicCounter,
|
||||
DispatchIndirect,
|
||||
DrawIndirect,
|
||||
Parameter,
|
||||
ShaderStorage,
|
||||
BufferTargetCount,
|
||||
Unknown = -1
|
||||
@@ -80,25 +81,31 @@ namespace MobileGL {
|
||||
BufferObject(Uint externalIndex);
|
||||
|
||||
void Resize(SizeT size);
|
||||
void AllocateImmutableStorage(SizeT size, const void* data, GLbitfield storageFlags);
|
||||
void UploadData(DataPtr data, SizeT atOffset);
|
||||
void SetUsage(BufferUsage usage);
|
||||
void* AcquireMemory(Bool markMapped, Bool read, Bool write);
|
||||
void* AcquireMemoryRange(Range1D range, Flags<BufferMappingAccessBit> access);
|
||||
void ReleaseMemory();
|
||||
void FlushMemoryRange(SizeT offset, SizeT length);
|
||||
void MarkPersistentMappedRangeDirty();
|
||||
void UploadSubData(DataPtr data, SizeT atOffset);
|
||||
void CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, SizeT size);
|
||||
void ClearDirty();
|
||||
|
||||
Bool IsMapped() const;
|
||||
Bool IsImmutableStorage() const;
|
||||
SizeT GetSize() const;
|
||||
BufferUsage GetUsage() const;
|
||||
Range1D GetMappedRange() const;
|
||||
void* GetMappedPointer() const;
|
||||
const SharedPtr<Data>& GetDataReadOnly() const;
|
||||
Flags<BufferMappingAccessBit> GetMappingAccess() const;
|
||||
GLbitfield GetStorageFlags() const;
|
||||
Uint GetExternalIndex() const;
|
||||
const VecRange1D& GetDirtyRanges() const;
|
||||
Flags<BufferChangeBits> GetChangeBits() const;
|
||||
Uint64 GetChangeSerial() const;
|
||||
|
||||
private:
|
||||
const Uint m_externalIndex = 0;
|
||||
@@ -107,7 +114,10 @@ namespace MobileGL {
|
||||
SharedPtr<Data> m_dataPtr;
|
||||
Bool m_isMapped;
|
||||
Flags<BufferMappingAccessBit> m_mappingAccess;
|
||||
Bool m_isImmutableStorage = false;
|
||||
GLbitfield m_storageFlags = 0;
|
||||
BufferChange m_change;
|
||||
Uint64 m_changeSerial = 0;
|
||||
Range1D m_mappedRange;
|
||||
Vector<Uint8> m_stagingData;
|
||||
Bool m_ownsStagingData;
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace MobileGL::MG_State::GLState {
|
||||
ToArray(BufferTarget::Vertex, BufferTarget::Uniform, BufferTarget::CopyRead, BufferTarget::CopyWrite,
|
||||
BufferTarget::PixelPack, BufferTarget::PixelUnpack, BufferTarget::Query, BufferTarget::Texture,
|
||||
BufferTarget::TransformFeedback, BufferTarget::AtomicCounter, BufferTarget::DispatchIndirect,
|
||||
BufferTarget::DrawIndirect, BufferTarget::ShaderStorage);
|
||||
BufferTarget::DrawIndirect, BufferTarget::Parameter, BufferTarget::ShaderStorage);
|
||||
constexpr const auto BufferBindPointTargets = ToArray(BufferTarget::Uniform, BufferTarget::TransformFeedback,
|
||||
BufferTarget::AtomicCounter, BufferTarget::ShaderStorage);
|
||||
|
||||
|
||||
@@ -140,6 +140,48 @@ namespace MobileGL::MG_State {
|
||||
return m_vertexArrayState.GetBoundVertexArray();
|
||||
}
|
||||
|
||||
void GLContext::SetCurrentVertexAttributeFloat(Uint index, const Array<Float, 4>& value) {
|
||||
MOBILEGL_ASSERT(index < m_currentVertexAttributes.size(),
|
||||
"SetCurrentVertexAttributeFloat: index %u is out of range", index);
|
||||
|
||||
auto& current = m_currentVertexAttributes[index];
|
||||
current.floatValue = value;
|
||||
for (SizeT component = 0; component < value.size(); ++component) {
|
||||
current.intValue[component] = static_cast<Int32>(value[component]);
|
||||
current.uintValue[component] = static_cast<Uint32>(value[component]);
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::SetCurrentVertexAttributeInt(Uint index, const Array<Int32, 4>& value) {
|
||||
MOBILEGL_ASSERT(index < m_currentVertexAttributes.size(),
|
||||
"SetCurrentVertexAttributeInt: index %u is out of range", index);
|
||||
|
||||
auto& current = m_currentVertexAttributes[index];
|
||||
current.intValue = value;
|
||||
for (SizeT component = 0; component < value.size(); ++component) {
|
||||
current.floatValue[component] = static_cast<Float>(value[component]);
|
||||
current.uintValue[component] = static_cast<Uint32>(value[component]);
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::SetCurrentVertexAttributeUint(Uint index, const Array<Uint32, 4>& value) {
|
||||
MOBILEGL_ASSERT(index < m_currentVertexAttributes.size(),
|
||||
"SetCurrentVertexAttributeUint: index %u is out of range", index);
|
||||
|
||||
auto& current = m_currentVertexAttributes[index];
|
||||
current.uintValue = value;
|
||||
for (SizeT component = 0; component < value.size(); ++component) {
|
||||
current.floatValue[component] = static_cast<Float>(value[component]);
|
||||
current.intValue[component] = static_cast<Int32>(value[component]);
|
||||
}
|
||||
}
|
||||
|
||||
const CurrentVertexAttributeValue& GLContext::GetCurrentVertexAttribute(Uint index) const {
|
||||
MOBILEGL_ASSERT(index < m_currentVertexAttributes.size(),
|
||||
"GetCurrentVertexAttribute: index %u is out of range", index);
|
||||
return m_currentVertexAttributes[index];
|
||||
}
|
||||
|
||||
// Texture
|
||||
void GLContext::GenTextureNames(Uint number, Vector<Uint>& textures) {
|
||||
m_textureState.GenerateNames(number, textures);
|
||||
@@ -161,6 +203,14 @@ namespace MobileGL::MG_State {
|
||||
return m_textureState.GetUnitObject(unit);
|
||||
}
|
||||
|
||||
ImageTextureBinding& GLContext::GetImageTextureBinding(Int unit) {
|
||||
return m_textureState.GetImageTextureBinding(unit);
|
||||
}
|
||||
|
||||
const ImageTextureBinding& GLContext::GetImageTextureBinding(Int unit) const {
|
||||
return m_textureState.GetImageTextureBinding(unit);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateTextureName(Uint index) const {
|
||||
return m_textureState.ValidateName(index);
|
||||
}
|
||||
@@ -271,6 +321,22 @@ namespace MobileGL::MG_State {
|
||||
m_renderState.GetBlendFuncIndexed(index, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
|
||||
void GLContext::SetBlendEquation(BlendEquation color, BlendEquation alpha) {
|
||||
m_renderState.SetBlendEquation(color, alpha);
|
||||
}
|
||||
|
||||
void GLContext::GetBlendEquation(BlendEquation& color, BlendEquation& alpha) const {
|
||||
m_renderState.GetBlendEquation(color, alpha);
|
||||
}
|
||||
|
||||
void GLContext::SetBlendEquationIndexed(Uint index, BlendEquation color, BlendEquation alpha) {
|
||||
m_renderState.SetBlendEquationIndexed(index, color, alpha);
|
||||
}
|
||||
|
||||
void GLContext::GetBlendEquationIndexed(Uint index, BlendEquation& color, BlendEquation& alpha) const {
|
||||
m_renderState.GetBlendEquationIndexed(index, color, alpha);
|
||||
}
|
||||
|
||||
void GLContext::SetDepthFunc(DepthTestFunc func) {
|
||||
m_renderState.SetDepthFunc(func);
|
||||
}
|
||||
@@ -339,6 +405,22 @@ namespace MobileGL::MG_State {
|
||||
return m_renderState.GetCullFaceMode();
|
||||
}
|
||||
|
||||
void GLContext::SetFrontFaceMode(FrontFaceMode mode) {
|
||||
m_renderState.SetFrontFaceMode(mode);
|
||||
}
|
||||
|
||||
FrontFaceMode GLContext::GetFrontFaceMode() const {
|
||||
return m_renderState.GetFrontFaceMode();
|
||||
}
|
||||
|
||||
void GLContext::SetProvokingVertexMode(ProvokingVertexMode mode) {
|
||||
m_renderState.SetProvokingVertexMode(mode);
|
||||
}
|
||||
|
||||
ProvokingVertexMode GLContext::GetProvokingVertexMode() const {
|
||||
return m_renderState.GetProvokingVertexMode();
|
||||
}
|
||||
|
||||
void GLContext::SetScissorBox(IntVec4 box) {
|
||||
m_renderState.SetScissorBox(box);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,12 @@ namespace MobileGL {
|
||||
void Init();
|
||||
|
||||
namespace GLState {
|
||||
struct CurrentVertexAttributeValue {
|
||||
Array<Float, 4> floatValue{0.f, 0.f, 0.f, 1.f};
|
||||
Array<Int32, 4> intValue{0, 0, 0, 1};
|
||||
Array<Uint32, 4> uintValue{0u, 0u, 0u, 1u};
|
||||
};
|
||||
|
||||
class GLContext {
|
||||
public:
|
||||
GLContext() = default;
|
||||
@@ -61,6 +67,10 @@ namespace MobileGL {
|
||||
Bool ValidateVertexArrayName(Uint index) const;
|
||||
Bool ValidateVertexArrayObject(Uint index) const;
|
||||
const SharedPtr<VertexArrayObject>& GetBoundVertexArray();
|
||||
void SetCurrentVertexAttributeFloat(Uint index, const Array<Float, 4>& value);
|
||||
void SetCurrentVertexAttributeInt(Uint index, const Array<Int32, 4>& value);
|
||||
void SetCurrentVertexAttributeUint(Uint index, const Array<Uint32, 4>& value);
|
||||
const CurrentVertexAttributeValue& GetCurrentVertexAttribute(Uint index) const;
|
||||
|
||||
// Texture
|
||||
void GenTextureNames(Uint number, Vector<Uint>& textures);
|
||||
@@ -68,6 +78,8 @@ namespace MobileGL {
|
||||
const SharedPtr<ITextureObject>& CreateTextureObject(Uint index, TextureTarget target);
|
||||
void MarkTextureObjectForDeletion(Uint index);
|
||||
TextureUnit& GetTextureUnitObject(Int unit);
|
||||
ImageTextureBinding& GetImageTextureBinding(Int unit);
|
||||
const ImageTextureBinding& GetImageTextureBinding(Int unit) const;
|
||||
Bool ValidateTextureName(Uint index) const;
|
||||
Bool ValidateTextureObject(Uint index) const;
|
||||
Int GetActiveTextureUnit() const;
|
||||
@@ -101,6 +113,10 @@ namespace MobileGL {
|
||||
BlendFactor dstAlpha);
|
||||
void GetBlendFuncIndexed(Uint index, BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
|
||||
BlendFactor& dstAlpha) const;
|
||||
void SetBlendEquation(BlendEquation color, BlendEquation alpha);
|
||||
void GetBlendEquation(BlendEquation& color, BlendEquation& alpha) const;
|
||||
void SetBlendEquationIndexed(Uint index, BlendEquation color, BlendEquation alpha);
|
||||
void GetBlendEquationIndexed(Uint index, BlendEquation& color, BlendEquation& alpha) const;
|
||||
void SetDepthFunc(DepthTestFunc func);
|
||||
DepthTestFunc GetDepthFunc() const;
|
||||
void SetDepthMask(Bool flag);
|
||||
@@ -118,6 +134,10 @@ namespace MobileGL {
|
||||
PixelStoreParameters GetPixelStoreParameters(Bool isUnpack) const;
|
||||
void SetCullFaceMode(CullFaceMode mode);
|
||||
CullFaceMode GetCullFaceMode() const;
|
||||
void SetFrontFaceMode(FrontFaceMode mode);
|
||||
FrontFaceMode GetFrontFaceMode() const;
|
||||
void SetProvokingVertexMode(ProvokingVertexMode mode);
|
||||
ProvokingVertexMode GetProvokingVertexMode() const;
|
||||
void SetScissorBox(IntVec4 box); // x, y, width, height
|
||||
const IntVec4& GetScissorBox() const; // x, y, width, height
|
||||
|
||||
@@ -152,6 +172,7 @@ namespace MobileGL {
|
||||
ErrorState m_errorState;
|
||||
BufferState m_bufferState;
|
||||
VertexArrayState m_vertexArrayState;
|
||||
Array<CurrentVertexAttributeValue, VertexArrayObject::MAX_VERTEX_ATTRIBS> m_currentVertexAttributes{};
|
||||
TextureState m_textureState;
|
||||
ProgramState m_programState;
|
||||
RenderState m_renderState;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
||||
#include <MG_Util/ShaderTranspiler/Types.h>
|
||||
#include <MG_Util/ShaderTranspiler/ShaderCompiler.h>
|
||||
#include <MG_Util/ShaderTranspiler/ShaderSourceProcessor.h>
|
||||
#include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h>
|
||||
#include <MG_Util/Converters/SPIRVCrossToGL/SpvcTypeConverter.h>
|
||||
|
||||
@@ -18,6 +19,46 @@ layout(location = 0) out vec4 FragColor;
|
||||
void main() {}
|
||||
)";
|
||||
|
||||
namespace {
|
||||
static int GetVertexInputLocationSpan(GLenum glType) {
|
||||
switch (glType) {
|
||||
case GL_FLOAT_MAT2:
|
||||
case GL_FLOAT_MAT2x3:
|
||||
case GL_FLOAT_MAT2x4:
|
||||
return 2;
|
||||
case GL_FLOAT_MAT3:
|
||||
case GL_FLOAT_MAT3x2:
|
||||
case GL_FLOAT_MAT3x4:
|
||||
return 3;
|
||||
case GL_FLOAT_MAT4:
|
||||
case GL_FLOAT_MAT4x2:
|
||||
case GL_FLOAT_MAT4x3:
|
||||
return 4;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static GLenum GetVertexInputLocationType(GLenum glType) {
|
||||
switch (glType) {
|
||||
case GL_FLOAT_MAT2:
|
||||
case GL_FLOAT_MAT3x2:
|
||||
case GL_FLOAT_MAT4x2:
|
||||
return GL_FLOAT_VEC2;
|
||||
case GL_FLOAT_MAT3:
|
||||
case GL_FLOAT_MAT2x3:
|
||||
case GL_FLOAT_MAT4x3:
|
||||
return GL_FLOAT_VEC3;
|
||||
case GL_FLOAT_MAT4:
|
||||
case GL_FLOAT_MAT2x4:
|
||||
case GL_FLOAT_MAT3x4:
|
||||
return GL_FLOAT_VEC4;
|
||||
default:
|
||||
return glType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
bool ProgramObject::ShaderIsAttached(const SharedPtr<ShaderObject>& shader) {
|
||||
MGLOG_D("ProgramObject %u: ShaderIsAttached check for shader %p", m_externalIndex, shader.get());
|
||||
@@ -93,6 +134,7 @@ namespace MobileGL::MG_State::GLState {
|
||||
|
||||
void ProgramObject::Link(Bool addDefaultFSIfMissingForRenderingPipelineProgram) {
|
||||
MGLOG_D("ProgramObject %u: Link start, shaders to link: %zu", m_externalIndex, m_shaders.size());
|
||||
++m_backendStateVersion;
|
||||
// Remove detached shaders first
|
||||
for (const auto& detachedShader : m_detachedShaders) {
|
||||
RemoveShader(detachedShader);
|
||||
@@ -257,6 +299,27 @@ namespace MobileGL::MG_State::GLState {
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_activeUniformCount; i++) {
|
||||
auto& uniform = m_program->getUniform(i);
|
||||
const auto locationIt = m_uniformLocations.find(uniform.name);
|
||||
if (locationIt == m_uniformLocations.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Uint location = locationIt->second;
|
||||
if (location >= m_uniformSamplerOrImageUnitIndex.size() || uniform.getType() == nullptr ||
|
||||
!uniform.getType()->isOpaque() || (!uniform.getType()->isTexture() && !uniform.getType()->isImage())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int binding = uniform.getBinding();
|
||||
if (binding >= 0 && binding != static_cast<int>(glslang::TQualifier::layoutBindingEnd)) {
|
||||
m_uniformSamplerOrImageUnitIndex[location] = binding;
|
||||
MGLOG_D("ProgramObject %u: Reflection - opaque uniform '%s' location=%u initialUnit=%d",
|
||||
m_externalIndex, uniform.name.c_str(), location, binding);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------ attributes (vertex in) ---------------
|
||||
Int inCount = m_program->getNumPipeInputs();
|
||||
MGLOG_D("ProgramObject %u: Reflection - pipe input count (attributes) = %d", m_externalIndex, inCount);
|
||||
@@ -264,7 +327,10 @@ namespace MobileGL::MG_State::GLState {
|
||||
Int maxLoc = -1;
|
||||
for (int i = 0; i < inCount; ++i) {
|
||||
Int loc = (Int)m_program->getPipeInput(i).layoutLocation();
|
||||
if (loc >= 0 && loc != glslang::TQualifier::layoutLocationEnd) maxLoc = std::max(maxLoc, loc);
|
||||
if (loc >= 0 && loc != glslang::TQualifier::layoutLocationEnd) {
|
||||
const Int locationSpan = GetVertexInputLocationSpan(m_program->getPipeInput(i).glDefineType);
|
||||
maxLoc = std::max(maxLoc, loc + locationSpan - 1);
|
||||
}
|
||||
MGLOG_D("ProgramObject %u: Reflection - pipe input[%d] name='%s' layoutLocation=%d glType=%u",
|
||||
m_externalIndex, i, m_program->getPipeInput(i).name.c_str(), loc,
|
||||
m_program->getPipeInput(i).glDefineType);
|
||||
@@ -294,88 +360,27 @@ namespace MobileGL::MG_State::GLState {
|
||||
m_attribInNameMaxLength = std::max(m_attribInNameMaxLength, (Int)inVar.name.length());
|
||||
|
||||
if (location >= 0 && location < (int)m_attribs.size()) {
|
||||
m_attribs[location] = inVar.name;
|
||||
m_attribTypes[location] = inVar.glDefineType;
|
||||
MGLOG_D("ProgramObject %u: Reflection - got attrib '%s' at explicit location %d", m_externalIndex,
|
||||
inVar.name.c_str(), location);
|
||||
}
|
||||
// else if (location >= (int)m_attribs.size()) {
|
||||
// MGLOG_W("ProgramObject %u: ProgramObject::DoReflection - attrib location %d >= attribs.size()
|
||||
// "
|
||||
// "(%zu). Ignoring.",
|
||||
// m_externalIndex, location, m_attribs.size());
|
||||
// continue;
|
||||
// }
|
||||
// else {
|
||||
// bool placed = false;
|
||||
// for (size_t idx = 0; idx < m_attribs.size(); ++idx) {
|
||||
// if (m_attribs[idx].empty()) {
|
||||
// m_attribs[idx] = inVar.name;
|
||||
// m_attribTypes[idx] = inVar.glDefineType;
|
||||
// placed = true;
|
||||
// MGLOG_D("ProgramObject %u: Reflection - placed attrib '%s' into free slot %zu",
|
||||
// m_externalIndex, inVar.name.c_str(), idx);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (!placed && (int)m_attribs.size() < maxAttribs) {
|
||||
// m_attribs.push_back(inVar.name);
|
||||
// m_attribTypes.push_back(inVar.glDefineType);
|
||||
// placed = true;
|
||||
// MGLOG_D("ProgramObject %u: Reflection - pushed attrib '%s' to new slot %zu",
|
||||
// m_externalIndex, inVar.name.c_str(), m_attribs.size() - 1);
|
||||
// }
|
||||
// if (!placed) {
|
||||
// MGLOG_W("ProgramObject %u: ProgramObject::DoReflection - cannot place attrib '%s' (no
|
||||
// free "
|
||||
// "slot and at max capacity). Ignoring.",
|
||||
// m_externalIndex, inVar.name.c_str());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
const Int locationSpan = GetVertexInputLocationSpan(inVar.glDefineType);
|
||||
const GLenum locationType = GetVertexInputLocationType(inVar.glDefineType);
|
||||
for (Int locationOffset = 0; locationOffset < locationSpan; ++locationOffset) {
|
||||
const Int expandedLocation = location + locationOffset;
|
||||
if (expandedLocation < 0 || expandedLocation >= static_cast<Int>(m_attribs.size())) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Implement glBindAttribLocation semantics (explicit locations set by user)
|
||||
// for (auto& [name, location] : m_explicitAttribLocations) {
|
||||
// MGLOG_D("ProgramObject %u: Reflection - explicit attrib location request: name='%s' location=%d",
|
||||
// m_externalIndex, name.c_str(), location);
|
||||
// if (location < 0) continue;
|
||||
// if (location >= (int)m_attribs.size()) {
|
||||
// if (location >= maxAttribs) {
|
||||
// MGLOG_W("ProgramObject %u: SetExplicitVertexInLocation: requested location %d >= "
|
||||
// "GL_MAX_VERTEX_ATTRIBS (%d). Ignored for attribute '%s'.",
|
||||
// m_externalIndex, location, maxAttribs, name.c_str());
|
||||
// continue;
|
||||
// }
|
||||
// m_attribs.resize(location + 1);
|
||||
// m_attribTypes.resize(location + 1);
|
||||
// MGLOG_D("ProgramObject %u: Reflection - resized attrib arrays to %zu to accommodate explicit
|
||||
// "
|
||||
// "location %d",
|
||||
// m_externalIndex, m_attribs.size(), location);
|
||||
// }
|
||||
//
|
||||
// if (m_attribs[location] != name) {
|
||||
// auto it = std::find(m_attribs.begin(), m_attribs.end(), name);
|
||||
// if (it == m_attribs.end()) {
|
||||
// MGLOG_D("ProgramObject %u: Reflection - explicit attrib '%s' not found in current list, "
|
||||
// "skipping swap",
|
||||
// m_externalIndex, name.c_str());
|
||||
// continue;
|
||||
// }
|
||||
// auto idx = std::distance(m_attribs.begin(), it);
|
||||
// std::swap(m_attribs[location], m_attribs[idx]);
|
||||
// std::swap(m_attribTypes[location], m_attribTypes[idx]);
|
||||
// MGLOG_D("ProgramObject %u: Reflection - swapped attrib '%s' from idx %zu to explicit "
|
||||
// "location %d",
|
||||
// m_externalIndex, name.c_str(), idx, location);
|
||||
// }
|
||||
//
|
||||
// for (SizeT idx = 0; idx < m_attribs.size(); ++idx) {
|
||||
// m_attribLocation[m_attribs[idx]] = idx;
|
||||
// MGLOG_D("ProgramObject %u: Reflection - attribLocation['%s'] = %zu", m_externalIndex,
|
||||
// m_attribs[idx].c_str(), idx);
|
||||
// }
|
||||
// }
|
||||
m_attribs[expandedLocation] = inVar.name;
|
||||
m_attribTypes[expandedLocation] = locationType;
|
||||
MGLOG_D(
|
||||
"ProgramObject %u: Reflection - got attrib '%s' at expanded location %d (baseLocation=%d glType=%u expandedType=%u)",
|
||||
m_externalIndex,
|
||||
inVar.name.c_str(),
|
||||
expandedLocation,
|
||||
location,
|
||||
inVar.glDefineType,
|
||||
static_cast<Uint32>(locationType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- UBO ----------
|
||||
Int uboCount = m_program->getNumUniformBlocks();
|
||||
@@ -403,11 +408,16 @@ namespace MobileGL::MG_State::GLState {
|
||||
MGLOG_D("ProgramObject %u: GenerateBinary - start", m_externalIndex);
|
||||
Vector<SharedPtr<glslang::TShader>> shaders(m_shaders.size());
|
||||
Vector<GLenum> shaderTypes(m_shaders.size());
|
||||
|
||||
// 1. Compile shaders
|
||||
for (SizeT i = 0; i < m_shaders.size(); i++) {
|
||||
auto shaderType = MG_Util::ConvertShaderStageToGLEnum(m_shaders[i]->GetShaderStage());
|
||||
auto shaderStage = m_shaders[i]->GetShaderStage();
|
||||
auto shaderType = MG_Util::ConvertShaderStageToGLEnum(shaderStage);
|
||||
String compileSource = m_shaders[i]->GetShaderSource();
|
||||
PreprocessShaderSource(shaderStage, compileSource);
|
||||
shaderTypes[i] = shaderType;
|
||||
ShaderAttrib attrib{.shaderType = shaderType,
|
||||
.sourceStr = m_shaders[i]->GetShaderSource(),
|
||||
.sourceStr = compileSource,
|
||||
.flags = 0}; // Will need patched glslang to work
|
||||
MGLOG_D("ProgramObject %u: GenerateBinary - compiling shader[%zu] type %u", m_externalIndex, i, shaderType);
|
||||
auto res = ShaderCompiler::CompileShader(attrib);
|
||||
@@ -418,7 +428,7 @@ namespace MobileGL::MG_State::GLState {
|
||||
MGLOG_E("ProgramObject %u: GenerateBinary - CompileShader return code %d, log:\n%s", m_externalIndex,
|
||||
res.error().errc, res.error().log.c_str());
|
||||
MGLOG_E("ProgramObject %u: GenerateBinary - last compiled shader src: \n%s", m_externalIndex,
|
||||
m_shaders[i]->GetShaderSource().c_str());
|
||||
compileSource.c_str());
|
||||
}
|
||||
MOBILEGL_ASSERT(res, "CompileShader failed during binary generation");
|
||||
shaders[i] = res.value();
|
||||
@@ -426,6 +436,7 @@ namespace MobileGL::MG_State::GLState {
|
||||
shaders[i].get());
|
||||
}
|
||||
|
||||
// 2. Do actual linking
|
||||
ProgramAttrib attrib{.shaders = Move(shaders),
|
||||
.explicitVertexInLocations = m_explicitAttribLocations,
|
||||
.explicitFragmentOutLocations = m_explicitFragDataLocation};
|
||||
@@ -452,11 +463,16 @@ namespace MobileGL::MG_State::GLState {
|
||||
MGLOG_D("ProgramObject %u: GenerateBinary - generated %zu SPIR-V modules", m_externalIndex,
|
||||
m_generatedSpirv.size());
|
||||
|
||||
// 3. Linked SPIR-V generated, sanitize and optimize it
|
||||
for (auto& spv : m_generatedSpirv) {
|
||||
auto success = ShaderCompiler::SanitizeAndOptimizeBinary(spv, spv);
|
||||
MOBILEGL_ASSERT(success, "SanitizeBinary failed");
|
||||
}
|
||||
|
||||
// 4. Do reflection (find global UBO etc.)
|
||||
m_uniformSizesInBytes.clear();
|
||||
m_uniformOffsets.clear();
|
||||
m_globalUboScratch.clear();
|
||||
for (SizeT i = 0; i < m_generatedSpirv.size(); i++) {
|
||||
auto& spv = m_generatedSpirv[i];
|
||||
|
||||
@@ -471,9 +487,6 @@ namespace MobileGL::MG_State::GLState {
|
||||
"err = %d%s",
|
||||
m_externalIndex, i, result,
|
||||
(result == SPVC_ERROR_INVALID_SPIRV ? ". Probably no global UBO?" : ""));
|
||||
m_uniformSizesInBytes.clear();
|
||||
m_uniformOffsets.clear();
|
||||
m_globalUboScratch.clear();
|
||||
continue;
|
||||
} else {
|
||||
auto& meta = session.GetMetadata();
|
||||
@@ -482,6 +495,9 @@ namespace MobileGL::MG_State::GLState {
|
||||
"plainUniformOffsets=%zu",
|
||||
m_externalIndex, meta.globalUboSize, meta.plainUniformMemberSizesInBytes.size(),
|
||||
meta.plainUniformOffsetsInUBO.size());
|
||||
if (size == 0) {
|
||||
continue;
|
||||
}
|
||||
m_globalUboScratch.resize(size);
|
||||
m_uniformOffsets.resize(m_maxUniformLocation + 1);
|
||||
for (const auto& [name, offset] : meta.plainUniformOffsetsInUBO) {
|
||||
|
||||
@@ -63,11 +63,54 @@ namespace MobileGL::MG_State::GLState {
|
||||
const auto it = std::find(m_attribs.begin(), m_attribs.end(), name);
|
||||
return (it == m_attribs.end()) ? -1 : (Int)std::distance(m_attribs.begin(), it);
|
||||
}
|
||||
Uint32 GetActiveAttributeLocationMask() const {
|
||||
Uint32 mask = 0;
|
||||
const SizeT count = std::min<SizeT>(m_attribs.size(), 32);
|
||||
for (SizeT index = 0; index < count; ++index) {
|
||||
if (!m_attribs[index].empty()) {
|
||||
mask |= (1u << index);
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
Uint32 GetActiveFragmentOutputLocationMask() const {
|
||||
if (!m_program) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Uint32 mask = 0;
|
||||
const Int outputCount = m_program->getNumPipeOutputs();
|
||||
for (Int index = 0; index < outputCount; ++index) {
|
||||
const Int location = static_cast<Int>(m_program->getPipeOutput(index).layoutLocation());
|
||||
if (location >= 0 && location < 32) {
|
||||
mask |= (1u << location);
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
Int GetActiveFragmentOutputCount() const {
|
||||
return m_program ? m_program->getNumPipeOutputs() : 0;
|
||||
}
|
||||
Int GetFragmentOutputLocation(Uint index) const {
|
||||
MOBILEGL_ASSERT(m_program != nullptr, "ProgramObject::GetFragmentOutputLocation: program is null");
|
||||
MOBILEGL_ASSERT(index < static_cast<Uint>(m_program->getNumPipeOutputs()),
|
||||
"ProgramObject::GetFragmentOutputLocation: index=%u out of range",
|
||||
index);
|
||||
return static_cast<Int>(m_program->getPipeOutput(static_cast<Int>(index)).layoutLocation());
|
||||
}
|
||||
GLenum GetFragmentOutputType(Uint index) const {
|
||||
MOBILEGL_ASSERT(m_program != nullptr, "ProgramObject::GetFragmentOutputType: program is null");
|
||||
MOBILEGL_ASSERT(index < static_cast<Uint>(m_program->getNumPipeOutputs()),
|
||||
"ProgramObject::GetFragmentOutputType: index=%u out of range",
|
||||
index);
|
||||
return m_program->getPipeOutput(static_cast<Int>(index)).glDefineType;
|
||||
}
|
||||
GLenum GetAttribType(Uint index) const { return m_attribTypes[index]; }
|
||||
const String& GetAttribName(Uint index) const { return m_attribs[index]; }
|
||||
void* MapUBO() { return m_globalUboScratch.data(); }
|
||||
const void* GetUBOData() const { return m_globalUboScratch.data(); }
|
||||
Uint GetUBOSize() const { return static_cast<Uint>(m_globalUboScratch.size()); }
|
||||
Uint32 GetBackendStateVersion() const { return m_backendStateVersion; }
|
||||
|
||||
void SetUniformSamplerOrImageUnitIndex(Uint location, Int unit) {
|
||||
m_uniformSamplerOrImageUnitIndex[location] = unit;
|
||||
@@ -105,7 +148,13 @@ namespace MobileGL::MG_State::GLState {
|
||||
}
|
||||
|
||||
// Set by glUniformBlockBinding
|
||||
void SetUniformBlockBinding(Uint index, Uint binding) { m_uniformBlockBinding[index] = (Int)binding; }
|
||||
void SetUniformBlockBinding(Uint index, Uint binding) {
|
||||
if (index >= m_uniformBlockBinding.size() || m_uniformBlockBinding[index] == static_cast<Int>(binding)) {
|
||||
return;
|
||||
}
|
||||
m_uniformBlockBinding[index] = static_cast<Int>(binding);
|
||||
++m_backendStateVersion;
|
||||
}
|
||||
|
||||
Uint GetUniformBlockBinding(Uint index) const { return m_uniformBlockBinding[index]; }
|
||||
|
||||
@@ -177,5 +226,6 @@ namespace MobileGL::MG_State::GLState {
|
||||
Bool m_deleteStatus = false;
|
||||
Bool m_linkStatus = false;
|
||||
Bool m_validateStatus = true;
|
||||
Uint32 m_backendStateVersion = 0;
|
||||
};
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -24,13 +24,14 @@ namespace MobileGL::MG_State::GLState {
|
||||
|
||||
void ShaderObject::Compile() {
|
||||
using namespace MG_Util::ShaderTranspiler;
|
||||
MG_Util::ShaderTranspiler::PreprocessShaderSource(m_stage, m_source);
|
||||
String compileSource = m_source;
|
||||
MG_Util::ShaderTranspiler::PreprocessShaderSource(m_stage, compileSource);
|
||||
|
||||
// Compile for OpenGL here, so that we can do validation and link
|
||||
// like a real OpenGL driver at linking stage
|
||||
// Will compile for other backends later.
|
||||
ShaderAttrib attrib{.shaderType = MG_Util::ConvertShaderStageToGLEnum(m_stage),
|
||||
.sourceStr = m_source,
|
||||
.sourceStr = compileSource,
|
||||
.flags = ShaderCompileBits::CompileForOpenGL};
|
||||
|
||||
auto result = ShaderCompiler::CompileShader(attrib);
|
||||
@@ -42,7 +43,7 @@ namespace MobileGL::MG_State::GLState {
|
||||
m_infoLog = result.error().log;
|
||||
MGLOG_D("ShaderObject::Compile: Shader %d compilation failed.\nSource:\n%s\nInfoLog:\n%s\nSetting "
|
||||
"m_compileStatus = false as a result.",
|
||||
m_externalIndex, m_source.c_str(), m_infoLog.c_str());
|
||||
m_externalIndex, compileSource.c_str(), m_infoLog.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -164,6 +164,48 @@ namespace MobileGL {
|
||||
dstAlpha = m_parameters.BlendStates[index].DstFactorAlpha;
|
||||
}
|
||||
|
||||
void RenderState::SetBlendEquation(BlendEquation color, BlendEquation alpha) {
|
||||
Bool stateChanged = false;
|
||||
for (auto& blendState : m_parameters.BlendStates) {
|
||||
if (blendState.ColorEquation == color && blendState.AlphaEquation == alpha) {
|
||||
continue;
|
||||
}
|
||||
blendState.ColorEquation = color;
|
||||
blendState.AlphaEquation = alpha;
|
||||
stateChanged = true;
|
||||
}
|
||||
if (!stateChanged) return;
|
||||
++m_version;
|
||||
}
|
||||
|
||||
void RenderState::GetBlendEquation(BlendEquation& color, BlendEquation& alpha) const {
|
||||
color = m_parameters.BlendStates[0].ColorEquation;
|
||||
alpha = m_parameters.BlendStates[0].AlphaEquation;
|
||||
}
|
||||
|
||||
void RenderState::SetBlendEquationIndexed(Uint index, BlendEquation color, BlendEquation alpha) {
|
||||
if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
||||
MOBILEGL_ASSERT(false, "Blend equation index out of range: %d", index);
|
||||
return;
|
||||
}
|
||||
PerBufferBlendState& blendState = m_parameters.BlendStates[index];
|
||||
if (blendState.ColorEquation == color && blendState.AlphaEquation == alpha) {
|
||||
return;
|
||||
}
|
||||
blendState.ColorEquation = color;
|
||||
blendState.AlphaEquation = alpha;
|
||||
++m_version;
|
||||
}
|
||||
|
||||
void RenderState::GetBlendEquationIndexed(Uint index, BlendEquation& color, BlendEquation& alpha) const {
|
||||
if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
||||
MOBILEGL_ASSERT(false, "Blend equation index out of range: %d", index);
|
||||
return;
|
||||
}
|
||||
color = m_parameters.BlendStates[index].ColorEquation;
|
||||
alpha = m_parameters.BlendStates[index].AlphaEquation;
|
||||
}
|
||||
|
||||
// -------------------- Depth --------------------
|
||||
void RenderState::SetDepthFunc(DepthTestFunc func) {
|
||||
if (m_parameters.DepthFunc == func) return;
|
||||
@@ -307,6 +349,28 @@ namespace MobileGL {
|
||||
return m_parameters.CullFaceModeSetting;
|
||||
}
|
||||
|
||||
void RenderState::SetFrontFaceMode(FrontFaceMode mode) {
|
||||
if (m_parameters.FrontFaceModeSetting == mode) return;
|
||||
|
||||
m_parameters.FrontFaceModeSetting = mode;
|
||||
++m_version;
|
||||
}
|
||||
|
||||
FrontFaceMode RenderState::GetFrontFaceMode() const {
|
||||
return m_parameters.FrontFaceModeSetting;
|
||||
}
|
||||
|
||||
void RenderState::SetProvokingVertexMode(ProvokingVertexMode mode) {
|
||||
if (m_parameters.ProvokingVertexModeSetting == mode) return;
|
||||
|
||||
m_parameters.ProvokingVertexModeSetting = mode;
|
||||
++m_version;
|
||||
}
|
||||
|
||||
ProvokingVertexMode RenderState::GetProvokingVertexMode() const {
|
||||
return m_parameters.ProvokingVertexModeSetting;
|
||||
}
|
||||
|
||||
// --------------------- Scissor ---------------------
|
||||
void RenderState::SetScissorBox(IntVec4 box) {
|
||||
if (m_parameters.ScissorBox == box) return;
|
||||
|
||||
@@ -31,6 +31,16 @@ namespace MobileGL {
|
||||
Unknown = -1
|
||||
};
|
||||
|
||||
enum class BlendEquation {
|
||||
Add,
|
||||
Subtract,
|
||||
ReverseSubtract,
|
||||
Min,
|
||||
Max,
|
||||
BlendEquationCount,
|
||||
Unknown = -1
|
||||
};
|
||||
|
||||
enum class DepthTestFunc {
|
||||
Never,
|
||||
Less,
|
||||
@@ -77,6 +87,20 @@ namespace MobileGL {
|
||||
Unknown = -1
|
||||
};
|
||||
|
||||
enum class FrontFaceMode {
|
||||
CounterClockwise,
|
||||
Clockwise,
|
||||
FrontFaceModeCount,
|
||||
Unknown = -1
|
||||
};
|
||||
|
||||
enum class ProvokingVertexMode {
|
||||
FirstVertex,
|
||||
LastVertex,
|
||||
ProvokingVertexModeCount,
|
||||
Unknown = -1
|
||||
};
|
||||
|
||||
enum class CapabilityInput {
|
||||
Blend,
|
||||
ClipDistance0,
|
||||
@@ -134,6 +158,8 @@ namespace MobileGL {
|
||||
BlendFactor DstFactorRGB = BlendFactor::Zero;
|
||||
BlendFactor SrcFactorAlpha = BlendFactor::One;
|
||||
BlendFactor DstFactorAlpha = BlendFactor::Zero;
|
||||
BlendEquation ColorEquation = BlendEquation::Add;
|
||||
BlendEquation AlphaEquation = BlendEquation::Add;
|
||||
};
|
||||
|
||||
struct RenderStateParameters {
|
||||
@@ -159,6 +185,8 @@ namespace MobileGL {
|
||||
// Cull Face
|
||||
Bool CullFaceEnabled = false;
|
||||
CullFaceMode CullFaceModeSetting = CullFaceMode::Back;
|
||||
FrontFaceMode FrontFaceModeSetting = FrontFaceMode::CounterClockwise;
|
||||
ProvokingVertexMode ProvokingVertexModeSetting = ProvokingVertexMode::LastVertex;
|
||||
|
||||
// Scissor
|
||||
Bool ScissorTestEnabled = false;
|
||||
@@ -192,6 +220,10 @@ namespace MobileGL {
|
||||
BlendFactor dstAlpha);
|
||||
void GetBlendFuncIndexed(Uint index, BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
|
||||
BlendFactor& dstAlpha) const;
|
||||
void SetBlendEquation(BlendEquation color, BlendEquation alpha);
|
||||
void GetBlendEquation(BlendEquation& color, BlendEquation& alpha) const;
|
||||
void SetBlendEquationIndexed(Uint index, BlendEquation color, BlendEquation alpha);
|
||||
void GetBlendEquationIndexed(Uint index, BlendEquation& color, BlendEquation& alpha) const;
|
||||
|
||||
// Depth
|
||||
void SetDepthFunc(DepthTestFunc func);
|
||||
@@ -219,6 +251,10 @@ namespace MobileGL {
|
||||
// Cull Face
|
||||
void SetCullFaceMode(CullFaceMode mode);
|
||||
CullFaceMode GetCullFaceMode() const;
|
||||
void SetFrontFaceMode(FrontFaceMode mode);
|
||||
FrontFaceMode GetFrontFaceMode() const;
|
||||
void SetProvokingVertexMode(ProvokingVertexMode mode);
|
||||
ProvokingVertexMode GetProvokingVertexMode() const;
|
||||
|
||||
// Scissor
|
||||
void SetScissorBox(IntVec4 box); // x, y, width, height
|
||||
|
||||
@@ -97,6 +97,11 @@ namespace MobileGL::MG_State::GLState {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto& imageBinding : m_imageTextureBindings) {
|
||||
if (imageBinding.Texture == it->second) {
|
||||
imageBinding.Bind(nullptr, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
|
||||
}
|
||||
}
|
||||
m_textureObjects.erase(it);
|
||||
}
|
||||
m_indexGenerator.Delete(index);
|
||||
@@ -109,6 +114,18 @@ namespace MobileGL::MG_State::GLState {
|
||||
return m_textureUnits[unit];
|
||||
}
|
||||
|
||||
ImageTextureBinding& TextureState::GetImageTextureBinding(Int unit) {
|
||||
MOBILEGL_ASSERT(unit >= 0 && unit < MAX_TEXTURE_IMAGE_UNITS, "Image unit is out of range: %d > %d", unit,
|
||||
MAX_TEXTURE_IMAGE_UNITS - 1);
|
||||
return m_imageTextureBindings[unit];
|
||||
}
|
||||
|
||||
const ImageTextureBinding& TextureState::GetImageTextureBinding(Int unit) const {
|
||||
MOBILEGL_ASSERT(unit >= 0 && unit < MAX_TEXTURE_IMAGE_UNITS, "Image unit is out of range: %d > %d", unit,
|
||||
MAX_TEXTURE_IMAGE_UNITS - 1);
|
||||
return m_imageTextureBindings[unit];
|
||||
}
|
||||
|
||||
Int TextureState::GetActiveTextureUnit() const {
|
||||
return m_activeTextureUnit;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,27 @@
|
||||
#include "TextureUnit.h"
|
||||
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
struct ImageTextureBinding {
|
||||
SharedPtr<ITextureObject> Texture;
|
||||
GLint Level = 0;
|
||||
GLboolean Layered = GL_FALSE;
|
||||
GLint Layer = 0;
|
||||
GLenum Access = GL_READ_ONLY;
|
||||
GLenum Format = GL_RGBA8;
|
||||
Uint16 Version = 0;
|
||||
|
||||
void Bind(SharedPtr<ITextureObject> texture, GLint level, GLboolean layered, GLint layer, GLenum access,
|
||||
GLenum format) {
|
||||
Texture = Move(texture);
|
||||
Level = level;
|
||||
Layered = layered;
|
||||
Layer = layer;
|
||||
Access = access;
|
||||
Format = format;
|
||||
++Version;
|
||||
}
|
||||
};
|
||||
|
||||
class TextureState {
|
||||
public:
|
||||
static constexpr int MAX_TEXTURE_IMAGE_UNITS = 32;
|
||||
@@ -23,6 +44,8 @@ namespace MobileGL::MG_State::GLState {
|
||||
const SharedPtr<ITextureObject>& CreateTextureObject(Uint index, TextureTarget target);
|
||||
const SharedPtr<ITextureObject>& GetTextureObject(Uint index);
|
||||
TextureUnit& GetUnitObject(Int unit);
|
||||
ImageTextureBinding& GetImageTextureBinding(Int unit);
|
||||
const ImageTextureBinding& GetImageTextureBinding(Int unit) const;
|
||||
Int GetActiveTextureUnit() const;
|
||||
void SetActiveTextureUnit(Int unit);
|
||||
void MarkTextureObjectForDeletion(Uint index);
|
||||
@@ -32,6 +55,7 @@ namespace MobileGL::MG_State::GLState {
|
||||
private:
|
||||
Int m_activeTextureUnit = 0;
|
||||
Array<TextureUnit, MAX_TEXTURE_IMAGE_UNITS> m_textureUnits;
|
||||
Array<ImageTextureBinding, MAX_TEXTURE_IMAGE_UNITS> m_imageTextureBindings;
|
||||
IndexGenerator<Uint> m_indexGenerator;
|
||||
UnorderedMap<GLuint, SharedPtr<ITextureObject>> m_textureObjects;
|
||||
};
|
||||
|
||||
@@ -330,6 +330,127 @@ TEST_F(BufferTest, DeleteBufferObject) {
|
||||
ASSERT_FALSE(MobileGL::MG_State::pGLContext->GetBufferObject(bufferNames[0]));
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, ParameterBufferBindingAndQuery) {
|
||||
Vector<Uint> bufferNames;
|
||||
MobileGL::MG_State::pGLContext->GenBufferNames(1, bufferNames);
|
||||
auto bufObj = MobileGL::MG_State::pGLContext->CreateBufferObject(bufferNames[0]);
|
||||
|
||||
auto& slot = MobileGL::MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Parameter);
|
||||
slot.Bind(bufObj);
|
||||
|
||||
GLint binding = 0;
|
||||
MobileGL::MG_Impl::GLImpl::GetIntegerv(GL_PARAMETER_BUFFER_BINDING_ARB, &binding);
|
||||
EXPECT_EQ(binding, static_cast<GLint>(bufferNames[0]));
|
||||
|
||||
slot.Bind(nullptr);
|
||||
MobileGL::MG_Impl::GLImpl::GetIntegerv(GL_PARAMETER_BUFFER_BINDING_ARB, &binding);
|
||||
EXPECT_EQ(binding, 0);
|
||||
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, BindBufferBaseZeroUnbindsBindingPoint) {
|
||||
GLuint buffer = 0;
|
||||
MobileGL::MG_Impl::GLImpl::GenBuffers(1, &buffer);
|
||||
MobileGL::MG_Impl::GLImpl::BindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
|
||||
MobileGL::MG_Impl::GLImpl::BufferData(GL_SHADER_STORAGE_BUFFER, 16, nullptr, GL_DYNAMIC_DRAW);
|
||||
|
||||
MobileGL::MG_Impl::GLImpl::BindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, buffer);
|
||||
auto& point = MobileGL::MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, 2);
|
||||
ASSERT_NE(point.GetBoundObject(), nullptr);
|
||||
EXPECT_EQ(point.GetBoundObject()->GetExternalIndex(), buffer);
|
||||
|
||||
MobileGL::MG_Impl::GLImpl::BindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, 0);
|
||||
EXPECT_EQ(point.GetBoundObject(), nullptr);
|
||||
EXPECT_FALSE(MobileGL::MG_State::pGLContext->ValidateBufferObject(0));
|
||||
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, BindBufferRangeZeroUnbindsBindingPoint) {
|
||||
GLuint buffer = 0;
|
||||
MobileGL::MG_Impl::GLImpl::GenBuffers(1, &buffer);
|
||||
MobileGL::MG_Impl::GLImpl::BindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
|
||||
MobileGL::MG_Impl::GLImpl::BufferData(GL_SHADER_STORAGE_BUFFER, 16, nullptr, GL_DYNAMIC_DRAW);
|
||||
|
||||
MobileGL::MG_Impl::GLImpl::BindBufferRange(GL_SHADER_STORAGE_BUFFER, 3, buffer, 4, 8);
|
||||
auto& point = MobileGL::MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, 3);
|
||||
ASSERT_NE(point.GetBoundObject(), nullptr);
|
||||
EXPECT_EQ(point.GetRange().start, 4);
|
||||
EXPECT_EQ(point.GetRange().end, 12);
|
||||
|
||||
MobileGL::MG_Impl::GLImpl::BindBufferRange(GL_SHADER_STORAGE_BUFFER, 3, 0, 0, 0);
|
||||
EXPECT_EQ(point.GetBoundObject(), nullptr);
|
||||
EXPECT_FALSE(MobileGL::MG_State::pGLContext->ValidateBufferObject(0));
|
||||
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, GetInteger64vMaxShaderStorageBlockSize) {
|
||||
GLint64 maxSsboBlockSize = 0;
|
||||
MobileGL::MG_Impl::GLImpl::GetInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &maxSsboBlockSize);
|
||||
|
||||
EXPECT_GT(maxSsboBlockSize, 0);
|
||||
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, CreateBuffersCreatesObjectsImmediately) {
|
||||
GLuint buffers[2] = {};
|
||||
MobileGL::MG_Impl::GLImpl::CreateBuffers(2, buffers);
|
||||
|
||||
EXPECT_NE(buffers[0], 0u);
|
||||
EXPECT_NE(buffers[1], 0u);
|
||||
EXPECT_TRUE(MobileGL::MG_State::pGLContext->ValidateBufferObject(buffers[0]));
|
||||
EXPECT_TRUE(MobileGL::MG_State::pGLContext->ValidateBufferObject(buffers[1]));
|
||||
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, CopyNamedBufferSubDataCopiesBetweenDSABuffers) {
|
||||
GLuint buffers[2] = {};
|
||||
MobileGL::MG_Impl::GLImpl::CreateBuffers(2, buffers);
|
||||
|
||||
Vector<Uint8> src{1, 2, 3, 4, 5, 6};
|
||||
Vector<Uint8> dst(src.size(), 0);
|
||||
MobileGL::MG_Impl::GLImpl::NamedBufferData(buffers[0], src.size(), src.data(), GL_STATIC_DRAW);
|
||||
MobileGL::MG_Impl::GLImpl::NamedBufferData(buffers[1], dst.size(), dst.data(), GL_STATIC_DRAW);
|
||||
MobileGL::MG_Impl::GLImpl::CopyNamedBufferSubData(buffers[0], buffers[1], 1, 2, 3);
|
||||
|
||||
Vector<Uint8> actual(dst.size());
|
||||
auto dstObject = MobileGL::MG_State::pGLContext->GetBufferObject(buffers[1]);
|
||||
Memcpy(actual.data(), dstObject->AcquireMemory(false, true, false), actual.size());
|
||||
EXPECT_EQ(actual, (Vector<Uint8>{0, 0, 2, 3, 4, 0}));
|
||||
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, ClearNamedBufferDataZeroesStorage) {
|
||||
GLuint buffer = 0;
|
||||
MobileGL::MG_Impl::GLImpl::CreateBuffers(1, &buffer);
|
||||
|
||||
Vector<Uint8> initial(8, 0x7F);
|
||||
MobileGL::MG_Impl::GLImpl::NamedBufferData(buffer, initial.size(), initial.data(), GL_STATIC_DRAW);
|
||||
MobileGL::MG_Impl::GLImpl::ClearNamedBufferData(buffer, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
Vector<Uint8> actual(initial.size(), 0xFF);
|
||||
auto bufferObject = MobileGL::MG_State::pGLContext->GetBufferObject(buffer);
|
||||
Memcpy(actual.data(), bufferObject->AcquireMemory(false, true, false), actual.size());
|
||||
EXPECT_EQ(actual, Vector<Uint8>(initial.size(), 0));
|
||||
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, ClearNamedBufferSubDataRepeatsPattern) {
|
||||
GLuint buffer = 0;
|
||||
MobileGL::MG_Impl::GLImpl::CreateBuffers(1, &buffer);
|
||||
|
||||
Vector<Uint32> initial{0, 0, 0, 0, 0};
|
||||
MobileGL::MG_Impl::GLImpl::NamedBufferData(buffer, initial.size() * sizeof(Uint32), initial.data(), GL_STATIC_DRAW);
|
||||
const Uint32 pattern = 0xAABBCCDDu;
|
||||
MobileGL::MG_Impl::GLImpl::ClearNamedBufferSubData(buffer, GL_R32UI, sizeof(Uint32), sizeof(Uint32) * 3,
|
||||
GL_RED_INTEGER, GL_UNSIGNED_INT, &pattern);
|
||||
|
||||
Vector<Uint32> actual(initial.size(), 0);
|
||||
auto bufferObject = MobileGL::MG_State::pGLContext->GetBufferObject(buffer);
|
||||
Memcpy(actual.data(), bufferObject->AcquireMemory(false, true, false), actual.size() * sizeof(Uint32));
|
||||
EXPECT_EQ(actual, (Vector<Uint32>{0, pattern, pattern, pattern, 0}));
|
||||
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
using namespace MobileGL::MG_Impl::GLImpl;
|
||||
|
||||
class GeneralBufferTest : public ::testing::Test {
|
||||
@@ -477,6 +598,157 @@ TEST_F(GeneralBufferTest, General_MapFlags) {
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralBufferTest, General_BufferStorageQueriesImmutable) {
|
||||
GLuint buffer = 0;
|
||||
GenBuffers(1, &buffer);
|
||||
BindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
|
||||
const GLint initial[] = {1, 2, 3, 4};
|
||||
constexpr GLbitfield storageFlags = GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT;
|
||||
BufferStorage(GL_ARRAY_BUFFER, sizeof(initial), initial, storageFlags);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
|
||||
GLint immutable = GL_FALSE;
|
||||
GLint reportedFlags = 0;
|
||||
GetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_IMMUTABLE_STORAGE, &immutable);
|
||||
GetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_STORAGE_FLAGS, &reportedFlags);
|
||||
EXPECT_EQ(immutable, GL_TRUE);
|
||||
EXPECT_EQ(reportedFlags, static_cast<GLint>(storageFlags));
|
||||
|
||||
const GLint update = 42;
|
||||
BufferSubData(GL_ARRAY_BUFFER, sizeof(GLint), sizeof(update), &update);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
|
||||
BufferData(GL_ARRAY_BUFFER, sizeof(initial), initial, GL_DYNAMIC_DRAW);
|
||||
EXPECT_EQ(GetError(), GL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
TEST_F(GeneralBufferTest, General_PersistentMapRequiresStorageFlags) {
|
||||
GLuint mutableBuffer = CreateBoundBuffer(GL_ARRAY_BUFFER, 64, GL_DYNAMIC_DRAW);
|
||||
(void)mutableBuffer;
|
||||
void* mapped = MapBufferRange(GL_ARRAY_BUFFER, 0, 16, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
|
||||
EXPECT_EQ(mapped, nullptr);
|
||||
EXPECT_EQ(GetError(), GL_INVALID_OPERATION);
|
||||
|
||||
GLuint storageBuffer = 0;
|
||||
GenBuffers(1, &storageBuffer);
|
||||
BindBuffer(GL_ARRAY_BUFFER, storageBuffer);
|
||||
BufferStorage(GL_ARRAY_BUFFER, 64, nullptr, GL_MAP_WRITE_BIT);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
mapped = MapBufferRange(GL_ARRAY_BUFFER, 0, 16, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
|
||||
EXPECT_EQ(mapped, nullptr);
|
||||
EXPECT_EQ(GetError(), GL_INVALID_OPERATION);
|
||||
|
||||
GLuint persistentBuffer = 0;
|
||||
GenBuffers(1, &persistentBuffer);
|
||||
BindBuffer(GL_ARRAY_BUFFER, persistentBuffer);
|
||||
BufferStorage(GL_ARRAY_BUFFER, 64, nullptr, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_CLIENT_STORAGE_BIT);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
mapped = MapBufferRange(GL_ARRAY_BUFFER, 0, 16, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
|
||||
ASSERT_NE(mapped, nullptr);
|
||||
EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER));
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralBufferTest, General_PersistentCoherentWriteDirtyWithoutUnmap) {
|
||||
GLuint buffer = 0;
|
||||
GenBuffers(1, &buffer);
|
||||
BindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
|
||||
GLint initial[] = {10, 20, 30, 40};
|
||||
BufferStorage(GL_ARRAY_BUFFER, sizeof(initial), initial,
|
||||
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
|
||||
auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
|
||||
ASSERT_NE(bufferObject, nullptr);
|
||||
bufferObject->ClearDirty();
|
||||
|
||||
auto* mapped = static_cast<GLint*>(
|
||||
MapBufferRange(GL_ARRAY_BUFFER, 0, sizeof(initial),
|
||||
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT));
|
||||
ASSERT_NE(mapped, nullptr);
|
||||
mapped[2] = 1234;
|
||||
|
||||
bufferObject->MarkPersistentMappedRangeDirty();
|
||||
ASSERT_FALSE(bufferObject->GetDirtyRanges().empty());
|
||||
EXPECT_EQ(bufferObject->GetDirtyRanges()[0].start, 0);
|
||||
EXPECT_EQ(bufferObject->GetDirtyRanges()[0].end, sizeof(initial));
|
||||
|
||||
const auto data = bufferObject->GetDataReadOnly();
|
||||
EXPECT_EQ(reinterpret_cast<const GLint*>(data->data())[2], 1234);
|
||||
EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER));
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralBufferTest, General_PersistentExplicitFlushOnlyDirtiesFlushedRange) {
|
||||
GLuint buffer = 0;
|
||||
GenBuffers(1, &buffer);
|
||||
BindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
|
||||
GLint initial[] = {10, 20, 30, 40};
|
||||
BufferStorage(GL_ARRAY_BUFFER, sizeof(initial), initial, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
|
||||
auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
|
||||
ASSERT_NE(bufferObject, nullptr);
|
||||
bufferObject->ClearDirty();
|
||||
|
||||
auto* mapped = static_cast<GLint*>(
|
||||
MapBufferRange(GL_ARRAY_BUFFER, 0, sizeof(initial),
|
||||
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
|
||||
ASSERT_NE(mapped, nullptr);
|
||||
mapped[1] = 200;
|
||||
mapped[3] = 400;
|
||||
|
||||
bufferObject->MarkPersistentMappedRangeDirty();
|
||||
EXPECT_TRUE(bufferObject->GetDirtyRanges().empty());
|
||||
|
||||
FlushMappedBufferRange(GL_ARRAY_BUFFER, sizeof(GLint), sizeof(GLint));
|
||||
ASSERT_FALSE(bufferObject->GetDirtyRanges().empty());
|
||||
EXPECT_EQ(bufferObject->GetDirtyRanges()[0].start, sizeof(GLint));
|
||||
EXPECT_EQ(bufferObject->GetDirtyRanges()[0].end, sizeof(GLint) * 2);
|
||||
|
||||
EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER));
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralBufferTest, General_NamedBufferStorageMappingWrappers) {
|
||||
GLuint buffer = 0;
|
||||
GenBuffers(1, &buffer);
|
||||
|
||||
GLint initial[] = {1, 2, 3, 4};
|
||||
NamedBufferStorage(buffer, sizeof(initial), initial,
|
||||
GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
|
||||
GLint immutable = GL_FALSE;
|
||||
GetNamedBufferParameteriv(buffer, GL_BUFFER_IMMUTABLE_STORAGE, &immutable);
|
||||
EXPECT_EQ(immutable, GL_TRUE);
|
||||
|
||||
auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
|
||||
ASSERT_NE(bufferObject, nullptr);
|
||||
bufferObject->ClearDirty();
|
||||
|
||||
auto* mapped = static_cast<GLint*>(
|
||||
MapNamedBufferRange(buffer, 0, sizeof(initial),
|
||||
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
|
||||
ASSERT_NE(mapped, nullptr);
|
||||
mapped[0] = 99;
|
||||
|
||||
void* mapPointer = nullptr;
|
||||
GetNamedBufferPointerv(buffer, GL_BUFFER_MAP_POINTER, &mapPointer);
|
||||
EXPECT_EQ(mapPointer, mapped);
|
||||
|
||||
FlushMappedNamedBufferRange(buffer, 0, sizeof(GLint));
|
||||
ASSERT_FALSE(bufferObject->GetDirtyRanges().empty());
|
||||
EXPECT_EQ(bufferObject->GetDirtyRanges()[0].start, 0);
|
||||
EXPECT_EQ(bufferObject->GetDirtyRanges()[0].end, sizeof(GLint));
|
||||
|
||||
EXPECT_TRUE(UnmapNamedBuffer(buffer));
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralBufferTest, General_GeneralTest_1) {
|
||||
GLuint buffers[3];
|
||||
GenBuffers(3, buffers);
|
||||
|
||||
@@ -8,6 +8,9 @@ add_executable(
|
||||
target_include_directories(BufferTest PRIVATE
|
||||
${MGL_ROOT}/include
|
||||
${MGL_ROOT}/MobileGL
|
||||
${MGL_ROOT}/3rdparty/xxHash
|
||||
${MGL_ROOT}/3rdparty/Vulkan-Headers/include
|
||||
${MGL_ROOT}/3rdparty/SPIRV-Reflect
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
@@ -16,5 +19,9 @@ target_link_libraries(
|
||||
${LINK_LIBRARIES}
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
target_compile_options(BufferTest PRIVATE /Zc:preprocessor)
|
||||
endif()
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(BufferTest)
|
||||
|
||||
@@ -35,6 +35,12 @@ add_executable(
|
||||
target_link_libraries(
|
||||
SanityTest
|
||||
GTest::gtest_main
|
||||
MobileGL_s
|
||||
)
|
||||
|
||||
target_include_directories(SanityTest PRIVATE
|
||||
${MGL_ROOT}/include
|
||||
${MGL_ROOT}/MobileGL
|
||||
)
|
||||
|
||||
# message(STATUS "glslang_LIBRARIES: ${glslang_LIBRARIES}")
|
||||
@@ -59,8 +65,10 @@ include(GoogleTest)
|
||||
gtest_discover_tests(SanityTest)
|
||||
|
||||
add_subdirectory(Buffer)
|
||||
add_subdirectory(Framebuffer)
|
||||
add_subdirectory(Texture)
|
||||
add_subdirectory(VertexArray)
|
||||
add_subdirectory(Program)
|
||||
if (ENABLE_INTEGRATION_TESTS)
|
||||
add_subdirectory(Backend/DirectVulkan)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
add_executable(
|
||||
FramebufferTest
|
||||
FramebufferTest.cpp
|
||||
)
|
||||
|
||||
target_include_directories(FramebufferTest PRIVATE
|
||||
${MGL_ROOT}/include
|
||||
${MGL_ROOT}/MobileGL
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
FramebufferTest PRIVATE
|
||||
GTest::gtest_main
|
||||
${LINK_LIBRARIES}
|
||||
)
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(FramebufferTest)
|
||||
@@ -0,0 +1,333 @@
|
||||
// MobileGL - MobileGL/MG_Test/Framebuffer/FramebufferTest.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "Includes.h"
|
||||
#include "Init.h"
|
||||
#include <MG_Backend/BackendObjects.h>
|
||||
#include <MG_Impl/GLImpl/Buffer/GL_Buffer.h>
|
||||
#include <MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h>
|
||||
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
|
||||
#include <MG_Impl/GLImpl/Texture/GL_Texture.h>
|
||||
#include <MG_State/GLState/Core.h>
|
||||
|
||||
using namespace MobileGL;
|
||||
|
||||
namespace {
|
||||
SharedPtr<MG_State::GLState::FramebufferObject> g_lastBlitReadFramebuffer;
|
||||
SharedPtr<MG_State::GLState::FramebufferObject> g_lastBlitDrawFramebuffer;
|
||||
Int g_blitNamedFramebufferCallCount = 0;
|
||||
SharedPtr<MG_State::GLState::FramebufferObject> g_lastClearFramebuffer;
|
||||
GLenum g_lastClearBuffer = GL_NONE;
|
||||
GLint g_lastClearDrawbuffer = -1;
|
||||
GLfloat g_lastClearDepth = -1.0f;
|
||||
GLint g_lastClearStencil = -1;
|
||||
FloatVec4 g_lastClearColor = {};
|
||||
Int g_clearNamedFramebufferfvCallCount = 0;
|
||||
Int g_clearNamedFramebufferfiCallCount = 0;
|
||||
Int g_readPixelsCallCount = 0;
|
||||
|
||||
void RecordBlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
|
||||
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
|
||||
GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum) {
|
||||
g_lastBlitReadFramebuffer = readFramebuffer;
|
||||
g_lastBlitDrawFramebuffer = drawFramebuffer;
|
||||
++g_blitNamedFramebufferCallCount;
|
||||
}
|
||||
|
||||
void RecordClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
||||
GLenum buffer, GLint drawbuffer, const GLfloat* value) {
|
||||
g_lastClearFramebuffer = framebuffer;
|
||||
g_lastClearBuffer = buffer;
|
||||
g_lastClearDrawbuffer = drawbuffer;
|
||||
if (value) {
|
||||
if (buffer == GL_COLOR) {
|
||||
g_lastClearColor = FloatVec4(value[0], value[1], value[2], value[3]);
|
||||
} else if (buffer == GL_DEPTH) {
|
||||
g_lastClearDepth = value[0];
|
||||
}
|
||||
}
|
||||
++g_clearNamedFramebufferfvCallCount;
|
||||
}
|
||||
|
||||
void RecordClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
||||
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
|
||||
g_lastClearFramebuffer = framebuffer;
|
||||
g_lastClearBuffer = buffer;
|
||||
g_lastClearDrawbuffer = drawbuffer;
|
||||
g_lastClearDepth = depth;
|
||||
g_lastClearStencil = stencil;
|
||||
++g_clearNamedFramebufferfiCallCount;
|
||||
}
|
||||
|
||||
void RecordReadPixels(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, void*) {
|
||||
++g_readPixelsCallCount;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class FramebufferTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
MobileGL::Initialize();
|
||||
g_lastBlitReadFramebuffer = nullptr;
|
||||
g_lastBlitDrawFramebuffer = nullptr;
|
||||
g_blitNamedFramebufferCallCount = 0;
|
||||
g_lastClearFramebuffer = nullptr;
|
||||
g_lastClearBuffer = GL_NONE;
|
||||
g_lastClearDrawbuffer = -1;
|
||||
g_lastClearDepth = -1.0f;
|
||||
g_lastClearStencil = -1;
|
||||
g_lastClearColor = {};
|
||||
g_clearNamedFramebufferfvCallCount = 0;
|
||||
g_clearNamedFramebufferfiCallCount = 0;
|
||||
g_readPixelsCallCount = 0;
|
||||
MG_Backend::gBackendFunctionsTable.GL.BlitNamedFramebuffer = nullptr;
|
||||
MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfv = nullptr;
|
||||
MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfi = nullptr;
|
||||
MG_Backend::gBackendFunctionsTable.GL.ReadPixels = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(FramebufferTest, CreateFramebuffersCreatesObjectsImmediately) {
|
||||
GLuint framebuffers[2] = {};
|
||||
MG_Impl::GLImpl::CreateFramebuffers(2, framebuffers);
|
||||
|
||||
EXPECT_NE(framebuffers[0], 0u);
|
||||
EXPECT_NE(framebuffers[1], 0u);
|
||||
EXPECT_TRUE(MG_State::pGLContext->ValidateFramebufferObject(framebuffers[0]));
|
||||
EXPECT_TRUE(MG_State::pGLContext->ValidateFramebufferObject(framebuffers[1]));
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(FramebufferTest, NamedFramebufferTextureAttachesWithoutChangingBindings) {
|
||||
GLuint framebuffer = 0;
|
||||
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
||||
|
||||
Vector<Uint> textureNames;
|
||||
MG_State::pGLContext->GenTextureNames(1, textureNames);
|
||||
MG_State::pGLContext->CreateTextureObject(textureNames[0], TextureTarget::Texture2D);
|
||||
|
||||
const auto originalDraw =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
const auto originalRead =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
||||
|
||||
MG_Impl::GLImpl::NamedFramebufferTexture(framebuffer, GL_COLOR_ATTACHMENT0, textureNames[0], 3);
|
||||
|
||||
const auto framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
|
||||
const auto& attachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Color0);
|
||||
EXPECT_TRUE(attachment.IsTexture());
|
||||
EXPECT_EQ(attachment.GetTexture()->GetExternalIndex(), textureNames[0]);
|
||||
EXPECT_EQ(attachment.GetTextureLevel(), 3);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), originalDraw);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), originalRead);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(FramebufferTest, NamedDepthFramebufferTextureStorageIsCompleteWithoutBinding) {
|
||||
GLuint framebuffer = 0;
|
||||
GLuint texture = 0;
|
||||
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
|
||||
|
||||
const auto originalDraw =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
const auto originalRead =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
||||
|
||||
MG_Impl::GLImpl::TextureStorage2D(texture, 1, GL_DEPTH_COMPONENT24, 64, 32);
|
||||
MG_Impl::GLImpl::NamedFramebufferTexture(framebuffer, GL_DEPTH_ATTACHMENT, texture, 0);
|
||||
|
||||
EXPECT_EQ(MG_Impl::GLImpl::CheckNamedFramebufferStatus(framebuffer, GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), originalDraw);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), originalRead);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(FramebufferTest, ReadPixelsAllowsPersistentMappedPixelPackBuffer) {
|
||||
GLuint framebuffer = 0;
|
||||
GLuint texture = 0;
|
||||
GLuint pixelPackBuffer = 0;
|
||||
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
|
||||
MG_Impl::GLImpl::CreateBuffers(1, &pixelPackBuffer);
|
||||
|
||||
MG_Impl::GLImpl::TextureStorage2D(texture, 1, GL_RGBA8, 4, 4);
|
||||
MG_Impl::GLImpl::NamedFramebufferTexture(framebuffer, GL_COLOR_ATTACHMENT0, texture, 0);
|
||||
MG_Impl::GLImpl::BindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
|
||||
|
||||
MG_Impl::GLImpl::BindBuffer(GL_PIXEL_PACK_BUFFER, pixelPackBuffer);
|
||||
MG_Impl::GLImpl::BufferStorage(GL_PIXEL_PACK_BUFFER, 4 * 4 * 4, nullptr,
|
||||
GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT);
|
||||
ASSERT_NE(MG_Impl::GLImpl::MapBufferRange(GL_PIXEL_PACK_BUFFER, 0, 4 * 4 * 4,
|
||||
GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT),
|
||||
nullptr);
|
||||
|
||||
MG_Backend::gBackendFunctionsTable.GL.ReadPixels = RecordReadPixels;
|
||||
MG_Impl::GLImpl::ReadPixels(0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
EXPECT_EQ(g_readPixelsCallCount, 1);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(FramebufferTest, NamedRenderbufferStorageAndFramebufferAttachDoNotChangeBindings) {
|
||||
GLuint framebuffer = 0;
|
||||
GLuint renderbuffer = 0;
|
||||
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
||||
MG_Impl::GLImpl::CreateRenderbuffers(1, &renderbuffer);
|
||||
|
||||
const auto originalDraw =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
const auto originalRead =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
||||
const auto originalRenderbuffer =
|
||||
MG_State::pGLContext->GetRenderbufferBindingSlot(RenderbufferTarget::Renderbuffer).GetBoundObject();
|
||||
|
||||
MG_Impl::GLImpl::NamedRenderbufferStorage(renderbuffer, GL_RGBA8, 64, 32);
|
||||
|
||||
GLint width = 0;
|
||||
GLint height = 0;
|
||||
GLint format = 0;
|
||||
MG_Impl::GLImpl::GetNamedRenderbufferParameteriv(renderbuffer, GL_RENDERBUFFER_WIDTH, &width);
|
||||
MG_Impl::GLImpl::GetNamedRenderbufferParameteriv(renderbuffer, GL_RENDERBUFFER_HEIGHT, &height);
|
||||
MG_Impl::GLImpl::GetNamedRenderbufferParameteriv(renderbuffer, GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
|
||||
|
||||
EXPECT_EQ(width, 64);
|
||||
EXPECT_EQ(height, 32);
|
||||
EXPECT_EQ(format, GL_RGBA8);
|
||||
|
||||
MG_Impl::GLImpl::NamedFramebufferRenderbuffer(framebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
|
||||
|
||||
const auto framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
|
||||
const auto& attachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Color0);
|
||||
EXPECT_TRUE(attachment.IsRenderbuffer());
|
||||
EXPECT_EQ(attachment.GetRenderbuffer()->GetExternalIndex(), renderbuffer);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), originalDraw);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), originalRead);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetRenderbufferBindingSlot(RenderbufferTarget::Renderbuffer).GetBoundObject(),
|
||||
originalRenderbuffer);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(FramebufferTest, NamedFramebufferDrawBuffersDoNotModifyDefaultFramebuffer) {
|
||||
GLuint framebuffer = 0;
|
||||
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
||||
|
||||
const auto defaultDraw =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
const auto defaultRead =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
||||
|
||||
GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
|
||||
MG_Impl::GLImpl::NamedFramebufferDrawBuffers(framebuffer, 2, bufs);
|
||||
MG_Impl::GLImpl::NamedFramebufferReadBuffer(framebuffer, GL_COLOR_ATTACHMENT1);
|
||||
|
||||
const auto framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
|
||||
EXPECT_EQ(framebufferObject->GetDrawBuffers()[0], FramebufferAttachmentType::Color0);
|
||||
EXPECT_EQ(framebufferObject->GetDrawBuffers()[1], FramebufferAttachmentType::Color1);
|
||||
EXPECT_EQ(framebufferObject->GetReadBuffer(), FramebufferAttachmentType::Color1);
|
||||
EXPECT_EQ(defaultDraw->GetDrawBuffers()[0], FramebufferAttachmentType::Color0);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), defaultDraw);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), defaultRead);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(FramebufferTest, ClearNamedFramebufferfvUsesNamedObjectWithoutChangingBindings) {
|
||||
GLuint framebuffer = 0;
|
||||
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
||||
|
||||
const auto defaultDraw =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
const auto defaultRead =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
||||
|
||||
const GLfloat depth[] = {0.25f};
|
||||
MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfv = RecordClearNamedFramebufferfv;
|
||||
MG_Impl::GLImpl::ClearNamedFramebufferfv(framebuffer, GL_DEPTH, 0, depth);
|
||||
|
||||
const auto framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
|
||||
EXPECT_EQ(g_clearNamedFramebufferfvCallCount, 1);
|
||||
EXPECT_EQ(g_lastClearFramebuffer, framebufferObject);
|
||||
EXPECT_EQ(g_lastClearBuffer, GL_DEPTH);
|
||||
EXPECT_EQ(g_lastClearDrawbuffer, 0);
|
||||
EXPECT_EQ(g_lastClearDepth, 0.25f);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), defaultDraw);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), defaultRead);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(FramebufferTest, ClearNamedFramebufferfiAllowsDefaultFramebufferZero) {
|
||||
GLuint framebuffer = 0;
|
||||
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
||||
|
||||
const auto defaultDraw =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
const auto defaultRead =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
||||
|
||||
MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfi = RecordClearNamedFramebufferfi;
|
||||
MG_Impl::GLImpl::ClearNamedFramebufferfi(0, GL_DEPTH_STENCIL, 0, 0.5f, 7);
|
||||
|
||||
EXPECT_EQ(g_clearNamedFramebufferfiCallCount, 1);
|
||||
EXPECT_EQ(g_lastClearFramebuffer, defaultDraw);
|
||||
EXPECT_EQ(g_lastClearBuffer, GL_DEPTH_STENCIL);
|
||||
EXPECT_EQ(g_lastClearDrawbuffer, 0);
|
||||
EXPECT_EQ(g_lastClearDepth, 0.5f);
|
||||
EXPECT_EQ(g_lastClearStencil, 7);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), defaultDraw);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), defaultRead);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(FramebufferTest, GetNamedFramebufferAttachmentParameterivReadsTargetObjectDirectly) {
|
||||
GLuint framebuffer = 0;
|
||||
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
||||
|
||||
Vector<Uint> textureNames;
|
||||
MG_State::pGLContext->GenTextureNames(1, textureNames);
|
||||
MG_State::pGLContext->CreateTextureObject(textureNames[0], TextureTarget::Texture2D);
|
||||
MG_Impl::GLImpl::NamedFramebufferTexture(framebuffer, GL_COLOR_ATTACHMENT0, textureNames[0], 2);
|
||||
|
||||
GLint objectType = 0;
|
||||
GLint objectName = 0;
|
||||
GLint textureLevel = 0;
|
||||
MG_Impl::GLImpl::GetNamedFramebufferAttachmentParameteriv(
|
||||
framebuffer, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &objectType);
|
||||
MG_Impl::GLImpl::GetNamedFramebufferAttachmentParameteriv(
|
||||
framebuffer, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &objectName);
|
||||
MG_Impl::GLImpl::GetNamedFramebufferAttachmentParameteriv(
|
||||
framebuffer, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, &textureLevel);
|
||||
|
||||
EXPECT_EQ(objectType, GL_TEXTURE);
|
||||
EXPECT_EQ(objectName, static_cast<GLint>(textureNames[0]));
|
||||
EXPECT_EQ(textureLevel, 2);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(FramebufferTest, BlitNamedFramebufferAllowsDefaultFramebufferZero) {
|
||||
GLuint framebuffer = 0;
|
||||
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
|
||||
|
||||
const auto defaultDraw =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
const auto defaultRead =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
||||
|
||||
MG_Backend::gBackendFunctionsTable.GL.BlitNamedFramebuffer = RecordBlitNamedFramebuffer;
|
||||
MG_Impl::GLImpl::BlitNamedFramebuffer(framebuffer, 0, 0, 0, 16, 16, 0, 0, 16, 16, GL_COLOR_BUFFER_BIT,
|
||||
GL_NEAREST);
|
||||
|
||||
const auto framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
|
||||
EXPECT_EQ(g_blitNamedFramebufferCallCount, 1);
|
||||
EXPECT_EQ(g_lastBlitReadFramebuffer, framebufferObject);
|
||||
EXPECT_EQ(g_lastBlitDrawFramebuffer, defaultDraw);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), defaultDraw);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), defaultRead);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
@@ -7,8 +7,15 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "Includes.h"
|
||||
#include "Init.h"
|
||||
#include "MG_Backend/DirectVulkan/DirectVulkanResourceState.h"
|
||||
#include "MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h"
|
||||
#include "MG_Backend/BackendObjects.h"
|
||||
#include "MG_Impl/GLImpl/Getter/GL_Getter.h"
|
||||
#include "MG_Impl/GLImpl/Program/GL_Program.h"
|
||||
#include "MG_State/GLState/Core.h"
|
||||
#include "MG_Util/ShaderTranspiler/ShaderCompiler.h"
|
||||
@@ -113,6 +120,240 @@ TEST_F(ProgramTest, CompileFragment) {
|
||||
CompileShader(fs);
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, CompileVoxySubgroupProbeShader) {
|
||||
char infoLog[1024] = "";
|
||||
const char* csSrc = R"(#version 430
|
||||
#extension GL_KHR_shader_subgroup_basic : require
|
||||
#extension GL_KHR_shader_subgroup_arithmetic : require
|
||||
layout(local_size_x=32) in;
|
||||
void main() {
|
||||
uint a = subgroupExclusiveAdd(gl_LocalInvocationIndex);
|
||||
}
|
||||
)";
|
||||
|
||||
GLuint cs = CreateShader(GL_COMPUTE_SHADER);
|
||||
ShaderSource(cs, 1, &csSrc, nullptr);
|
||||
CompileShader(cs);
|
||||
|
||||
GLint compileStatus = GL_FALSE;
|
||||
GetShaderiv(cs, GL_COMPILE_STATUS, &compileStatus);
|
||||
GetShaderInfoLog(cs, sizeof(infoLog), nullptr, infoLog);
|
||||
EXPECT_EQ(compileStatus, GL_TRUE) << infoLog;
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, CompileVoxyGpuShaderInt64QuadDecode) {
|
||||
auto previousBackend = Move(MG_Backend::pActiveBackendObject);
|
||||
MG_Backend::pActiveBackendObject = MakeUnique<MG_Backend::DirectVulkan::BackendObject_DirectVulkan>();
|
||||
|
||||
char infoLog[2048] = "";
|
||||
const char* vsSrc = R"(#version 460 core
|
||||
#extension GL_ARB_gpu_shader_int64 : enable
|
||||
|
||||
#ifdef GL_ARB_gpu_shader_int64
|
||||
#define Quad uint64_t
|
||||
#define Eu32(data, amountBits, shift) (uint((data)>>(shift))&((1u<<(amountBits))-1))
|
||||
|
||||
vec3 extractPos(uint64_t quad) {
|
||||
return vec3(Eu32(quad, 5, 21), Eu32(quad, 5, 16), Eu32(quad, 5, 11));
|
||||
}
|
||||
|
||||
uint extractStateId(uint64_t quad) {
|
||||
return Eu32(quad, 16, 26);
|
||||
}
|
||||
|
||||
uint extractBiomeId(uint64_t quad) {
|
||||
return Eu32(quad, 9, 46);
|
||||
}
|
||||
#else
|
||||
#error GL_ARB_gpu_shader_int64 should select Voxy native quad decode path
|
||||
#endif
|
||||
|
||||
layout(std430, binding = 1) readonly buffer QuadBuffer {
|
||||
Quad quadData[];
|
||||
};
|
||||
|
||||
layout(location = 0) flat out uvec4 interData;
|
||||
|
||||
void main() {
|
||||
uint64_t quad = quadData[uint(gl_VertexID) >> 2];
|
||||
vec3 pos = extractPos(quad);
|
||||
interData = uvec4(extractStateId(quad), extractBiomeId(quad), uint(pos.x), uint(pos.y));
|
||||
gl_Position = vec4(pos * (1.0 / 32.0), 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
GLuint vs = CreateShader(GL_VERTEX_SHADER);
|
||||
ShaderSource(vs, 1, &vsSrc, nullptr);
|
||||
CompileShader(vs);
|
||||
|
||||
GLint compileStatus = GL_FALSE;
|
||||
GetShaderiv(vs, GL_COMPILE_STATUS, &compileStatus);
|
||||
GetShaderInfoLog(vs, sizeof(infoLog), nullptr, infoLog);
|
||||
EXPECT_EQ(compileStatus, GL_TRUE) << infoLog;
|
||||
|
||||
MG_Backend::pActiveBackendObject = Move(previousBackend);
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, ShaderSourceKeepsOriginalTextAfterCompile) {
|
||||
const char* part0 = R"(#define HIGHP_OR_DEFAULT highp
|
||||
attribute vec4 Position;
|
||||
varying vec2 uv;
|
||||
)";
|
||||
const char* ignored = "this segment should be ignored";
|
||||
const char* part2 = R"(void main() {
|
||||
uv = Position.xy;
|
||||
gl_Position = Position;
|
||||
}
|
||||
)";
|
||||
const GLchar* parts[] = {part0, ignored, part2};
|
||||
const GLint lengths[] = {static_cast<GLint>(std::strlen(part0)), 0, static_cast<GLint>(std::strlen(part2))};
|
||||
const String expectedSource = String(part0) + part2;
|
||||
|
||||
GLuint vs = CreateShader(GL_VERTEX_SHADER);
|
||||
ShaderSource(vs, 3, parts, lengths);
|
||||
|
||||
GLint sourceLength = 0;
|
||||
GetShaderiv(vs, GL_SHADER_SOURCE_LENGTH, &sourceLength);
|
||||
ASSERT_EQ(sourceLength, static_cast<GLint>(expectedSource.size() + 1));
|
||||
|
||||
std::vector<GLchar> sourceBuffer(static_cast<size_t>(sourceLength));
|
||||
GLsizei written = 0;
|
||||
GetShaderSource(vs, sourceLength, &written, sourceBuffer.data());
|
||||
EXPECT_EQ(written, static_cast<GLsizei>(expectedSource.size()));
|
||||
EXPECT_EQ(String(sourceBuffer.data(), static_cast<size_t>(written)), expectedSource);
|
||||
|
||||
CompileShader(vs);
|
||||
GLint compileStatus = GL_FALSE;
|
||||
GetShaderiv(vs, GL_COMPILE_STATUS, &compileStatus);
|
||||
ASSERT_EQ(compileStatus, GL_TRUE);
|
||||
|
||||
std::fill(sourceBuffer.begin(), sourceBuffer.end(), '\0');
|
||||
written = 0;
|
||||
GetShaderSource(vs, sourceLength, &written, sourceBuffer.data());
|
||||
EXPECT_EQ(written, static_cast<GLsizei>(expectedSource.size()));
|
||||
EXPECT_EQ(String(sourceBuffer.data(), static_cast<size_t>(written)), expectedSource);
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, LinkProgramWithLegacyGlmarkStyleShaders) {
|
||||
char infoLog[1024] = "";
|
||||
|
||||
const char* legacyVs = R"(attribute vec4 Position;
|
||||
attribute vec2 TexCoord;
|
||||
varying vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
vTexCoord = TexCoord;
|
||||
gl_Position = Position;
|
||||
}
|
||||
)";
|
||||
const char* legacyFs = R"(varying vec2 vTexCoord;
|
||||
uniform sampler2D Texture;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = texture2D(Texture, vTexCoord);
|
||||
}
|
||||
)";
|
||||
|
||||
GLuint vs = CreateShader(GL_VERTEX_SHADER);
|
||||
ShaderSource(vs, 1, &legacyVs, NULL);
|
||||
CompileShader(vs);
|
||||
GLint vsStatus = GL_FALSE;
|
||||
GetShaderiv(vs, GL_COMPILE_STATUS, &vsStatus);
|
||||
GetShaderInfoLog(vs, sizeof(infoLog), nullptr, infoLog);
|
||||
ASSERT_EQ(vsStatus, GL_TRUE) << infoLog;
|
||||
|
||||
GLuint fs = CreateShader(GL_FRAGMENT_SHADER);
|
||||
ShaderSource(fs, 1, &legacyFs, NULL);
|
||||
CompileShader(fs);
|
||||
GLint fsStatus = GL_FALSE;
|
||||
GetShaderiv(fs, GL_COMPILE_STATUS, &fsStatus);
|
||||
GetShaderInfoLog(fs, sizeof(infoLog), nullptr, infoLog);
|
||||
ASSERT_EQ(fsStatus, GL_TRUE) << infoLog;
|
||||
|
||||
GLuint program = CreateProgram();
|
||||
AttachShader(program, vs);
|
||||
AttachShader(program, fs);
|
||||
LinkProgram(program);
|
||||
|
||||
GLint linkStatus = GL_FALSE;
|
||||
GetProgramiv(program, GL_LINK_STATUS, &linkStatus);
|
||||
GetProgramInfoLog(program, sizeof(infoLog), nullptr, infoLog);
|
||||
ASSERT_EQ(linkStatus, GL_TRUE) << infoLog;
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, ImageUniformLayoutBindingInitializesImageUnit) {
|
||||
char infoLog[1024] = "";
|
||||
const char* csSrc = R"(#version 460 core
|
||||
layout(local_size_x = 1) in;
|
||||
layout(binding = 4, rgba8) uniform writeonly image2D colourTexOut;
|
||||
|
||||
void main() {
|
||||
imageStore(colourTexOut, ivec2(0), vec4(1.0));
|
||||
}
|
||||
)";
|
||||
|
||||
GLuint cs = CreateShader(GL_COMPUTE_SHADER);
|
||||
ShaderSource(cs, 1, &csSrc, nullptr);
|
||||
CompileShader(cs);
|
||||
GLint csStatus = GL_FALSE;
|
||||
GetShaderiv(cs, GL_COMPILE_STATUS, &csStatus);
|
||||
GetShaderInfoLog(cs, sizeof(infoLog), nullptr, infoLog);
|
||||
ASSERT_EQ(csStatus, GL_TRUE) << infoLog;
|
||||
|
||||
GLuint program = CreateProgram();
|
||||
AttachShader(program, cs);
|
||||
LinkProgram(program);
|
||||
GLint linkStatus = GL_FALSE;
|
||||
GetProgramiv(program, GL_LINK_STATUS, &linkStatus);
|
||||
GetProgramInfoLog(program, sizeof(infoLog), nullptr, infoLog);
|
||||
ASSERT_EQ(linkStatus, GL_TRUE) << infoLog;
|
||||
|
||||
const GLint location = GetUniformLocation(program, "colourTexOut");
|
||||
ASSERT_GE(location, 0);
|
||||
auto programObject = MobileGL::MG_State::pGLContext->GetProgramObject(program);
|
||||
ASSERT_NE(programObject, nullptr);
|
||||
EXPECT_EQ(programObject->GetUniformSamplerOrImageUnitIndex(static_cast<Uint>(location)), 4);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, DirectVulkanStorageBlockUsesShaderLayoutBinding) {
|
||||
char infoLog[1024] = "";
|
||||
const char* csSrc = R"(#version 460 core
|
||||
layout(local_size_x = 1) in;
|
||||
layout(std430, binding = 2) buffer requestQueueStruct {
|
||||
uint value;
|
||||
} requestQueue;
|
||||
|
||||
void main() {
|
||||
requestQueue.value = 1u;
|
||||
}
|
||||
)";
|
||||
|
||||
GLuint cs = CreateShader(GL_COMPUTE_SHADER);
|
||||
ShaderSource(cs, 1, &csSrc, nullptr);
|
||||
CompileShader(cs);
|
||||
GLint csStatus = GL_FALSE;
|
||||
GetShaderiv(cs, GL_COMPILE_STATUS, &csStatus);
|
||||
GetShaderInfoLog(cs, sizeof(infoLog), nullptr, infoLog);
|
||||
ASSERT_EQ(csStatus, GL_TRUE) << infoLog;
|
||||
|
||||
GLuint program = CreateProgram();
|
||||
AttachShader(program, cs);
|
||||
LinkProgram(program);
|
||||
GLint linkStatus = GL_FALSE;
|
||||
GetProgramiv(program, GL_LINK_STATUS, &linkStatus);
|
||||
GetProgramInfoLog(program, sizeof(infoLog), nullptr, infoLog);
|
||||
ASSERT_EQ(linkStatus, GL_TRUE) << infoLog;
|
||||
|
||||
auto programObject = MobileGL::MG_State::pGLContext->GetProgramObject(program);
|
||||
ASSERT_NE(programObject, nullptr);
|
||||
const GLuint blockIndex =
|
||||
MG_Backend::DirectVulkan::GetShaderStorageBlockIndex(*programObject, "requestQueueStruct");
|
||||
ASSERT_NE(blockIndex, GL_INVALID_INDEX);
|
||||
EXPECT_EQ(MG_Backend::DirectVulkan::GetShaderStorageBlockBinding(*programObject, blockIndex), 2u);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, CompileAndLink) {
|
||||
char infoLog[1024] = "";
|
||||
|
||||
@@ -216,6 +457,63 @@ TEST_F(ProgramTest, CompileAndLink) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, Uniform1uiStoresUnsignedValue) {
|
||||
char infoLog[1024] = "";
|
||||
|
||||
const char* simpleVs = R"(#version 460
|
||||
layout(location = 0) in vec4 Position;
|
||||
|
||||
void main() {
|
||||
gl_Position = Position;
|
||||
}
|
||||
)";
|
||||
|
||||
const char* uintFs = R"(#version 460
|
||||
uniform uint NodeQueueIndex;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragColor = vec4(float(NodeQueueIndex & 255u));
|
||||
}
|
||||
)";
|
||||
|
||||
GLuint vs = CreateShader(GL_VERTEX_SHADER);
|
||||
ShaderSource(vs, 1, &simpleVs, NULL);
|
||||
CompileShader(vs);
|
||||
GLint vsStatus = GL_FALSE;
|
||||
GetShaderiv(vs, GL_COMPILE_STATUS, &vsStatus);
|
||||
GetShaderInfoLog(vs, 1024, nullptr, infoLog);
|
||||
ASSERT_EQ(vsStatus, GL_TRUE) << infoLog;
|
||||
|
||||
GLuint fs = CreateShader(GL_FRAGMENT_SHADER);
|
||||
ShaderSource(fs, 1, &uintFs, NULL);
|
||||
CompileShader(fs);
|
||||
GLint fsStatus = GL_FALSE;
|
||||
GetShaderiv(fs, GL_COMPILE_STATUS, &fsStatus);
|
||||
GetShaderInfoLog(fs, 1024, nullptr, infoLog);
|
||||
ASSERT_EQ(fsStatus, GL_TRUE) << infoLog;
|
||||
|
||||
GLuint program = CreateProgram();
|
||||
AttachShader(program, vs);
|
||||
AttachShader(program, fs);
|
||||
LinkProgram(program);
|
||||
GLint linkStatus = GL_FALSE;
|
||||
GetProgramiv(program, GL_LINK_STATUS, &linkStatus);
|
||||
ASSERT_EQ(linkStatus, GL_TRUE);
|
||||
|
||||
UseProgram(program);
|
||||
GLint loc = GetUniformLocation(program, "NodeQueueIndex");
|
||||
ASSERT_GE(loc, 0);
|
||||
|
||||
const GLuint expected = 0xF1234567u;
|
||||
Uniform1ui(loc, expected);
|
||||
|
||||
GLint actual = 0;
|
||||
GetUniformiv(program, loc, &actual);
|
||||
EXPECT_EQ(static_cast<GLuint>(actual), expected);
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, UniformMatrixFunctions) {
|
||||
char infoLog[1024] = "";
|
||||
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Includes.h"
|
||||
#include "Init.h"
|
||||
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
||||
#include <MG_Util/ShaderTranspiler/ShaderCompiler.h>
|
||||
#include <MG_Util/ShaderTranspiler/ShaderSourceProcessor.h>
|
||||
#include <MG_Util/ShaderTranspiler/Types.h>
|
||||
#include <MG_Util/ShaderTranspiler/glslang/UniformTraverser.h>
|
||||
|
||||
@@ -28,6 +31,78 @@ TEST_F(ProgramUtilTest, Sanity) {
|
||||
ASSERT_TRUE(true);
|
||||
}
|
||||
|
||||
TEST_F(ProgramUtilTest, PreprocessLegacyVertexShaderModernizesGlmarkStyleSource) {
|
||||
using namespace MG_Util::ShaderTranspiler;
|
||||
|
||||
String source = R"(#define HIGHP_OR_DEFAULT highp
|
||||
attribute vec3 position;
|
||||
varying vec2 uv;
|
||||
uniform HIGHP_OR_DEFAULT mat4 modelViewProjection;
|
||||
|
||||
void main() {
|
||||
uv = position.xy;
|
||||
gl_Position = modelViewProjection * vec4(position, 1.0);
|
||||
})";
|
||||
|
||||
PreprocessShaderSource(ShaderStage::Vertex, source);
|
||||
|
||||
EXPECT_EQ(source.find("#version 460 core\n"), 0);
|
||||
EXPECT_NE(source.find("in vec3 position;"), String::npos);
|
||||
EXPECT_NE(source.find("out vec2 uv;"), String::npos);
|
||||
EXPECT_EQ(source.find("attribute"), String::npos);
|
||||
EXPECT_EQ(source.find("varying"), String::npos);
|
||||
EXPECT_EQ(source.find("HIGHP_OR_DEFAULT"), String::npos);
|
||||
EXPECT_EQ(source.find("#define"), String::npos);
|
||||
}
|
||||
|
||||
TEST_F(ProgramUtilTest, PreprocessLegacyFragmentShaderModernizesGlmarkStyleSource) {
|
||||
using namespace MG_Util::ShaderTranspiler;
|
||||
|
||||
String source = R"(#define MEDIUMP_OR_DEFAULT mediump
|
||||
varying vec2 uv;
|
||||
uniform sampler2D texture0;
|
||||
|
||||
void main() {
|
||||
MEDIUMP_OR_DEFAULT vec4 color = texture2D(texture0, uv);
|
||||
gl_FragColor = color;
|
||||
})";
|
||||
|
||||
PreprocessShaderSource(ShaderStage::Fragment, source);
|
||||
|
||||
EXPECT_EQ(source.find("#version 460 core\n"), 0);
|
||||
EXPECT_NE(source.find("out vec4 mg_FragColor;\n"), String::npos);
|
||||
EXPECT_NE(source.find("in vec2 uv;"), String::npos);
|
||||
EXPECT_NE(source.find("texture(texture0, uv)"), String::npos);
|
||||
EXPECT_NE(source.find("mg_FragColor = color;"), String::npos);
|
||||
EXPECT_EQ(source.find("gl_FragColor"), String::npos);
|
||||
EXPECT_EQ(source.find("texture2D"), String::npos);
|
||||
EXPECT_EQ(source.find("MEDIUMP_OR_DEFAULT"), String::npos);
|
||||
EXPECT_EQ(source.find("mediump"), String::npos);
|
||||
EXPECT_EQ(source.find("#define"), String::npos);
|
||||
}
|
||||
|
||||
TEST_F(ProgramUtilTest, PreprocessFragmentShaderInjectsDepthRangeShim) {
|
||||
using namespace MG_Util::ShaderTranspiler;
|
||||
|
||||
String source = R"(#version 460 core
|
||||
out float depth;
|
||||
|
||||
void main() {
|
||||
depth = gl_DepthRange.diff * 0.5 + gl_DepthRange.near;
|
||||
})";
|
||||
|
||||
PreprocessShaderSource(ShaderStage::Fragment, source);
|
||||
|
||||
EXPECT_NE(source.find("struct mg_DepthRangeParameters"), String::npos);
|
||||
EXPECT_NE(source.find("#define gl_DepthRange mg_DepthRange"), String::npos);
|
||||
|
||||
ShaderAttrib attrib{.shaderType = GL_FRAGMENT_SHADER, .sourceStr = source};
|
||||
auto res = ShaderCompiler::CompileShader(attrib);
|
||||
if (!res) {
|
||||
FAIL() << "errc: " << res.error().errc << "\nlog: " << res.error().log << "\nsource:\n" << source;
|
||||
}
|
||||
}
|
||||
|
||||
const char* vs = R"(#version 150
|
||||
|
||||
in vec4 Position;
|
||||
@@ -97,6 +172,66 @@ void main() {
|
||||
fragColor = vec4(OutColor, 1.0);
|
||||
})";
|
||||
|
||||
const char* daily_weather_variation_vs = R"(#version 150
|
||||
|
||||
struct DailyWeatherVariation {
|
||||
vec2 clouds_cumulus_coverage;
|
||||
vec2 clouds_altocumulus_coverage;
|
||||
vec2 clouds_cirrus_coverage;
|
||||
float clouds_cumulus_congestus_amount;
|
||||
float clouds_stratus_amount;
|
||||
float fogginess;
|
||||
float aurora_amount;
|
||||
float nlc_amount;
|
||||
mat2x3 aurora_colors;
|
||||
};
|
||||
|
||||
in vec4 Position;
|
||||
out DailyWeatherVariation daily_weather_variation;
|
||||
|
||||
DailyWeatherVariation get_daily_weather_variation() {
|
||||
DailyWeatherVariation daily_weather_variation;
|
||||
daily_weather_variation.clouds_cumulus_coverage = vec2(1.0, 2.0);
|
||||
daily_weather_variation.clouds_altocumulus_coverage = vec2(3.0, 4.0);
|
||||
daily_weather_variation.clouds_cirrus_coverage = vec2(5.0, 6.0);
|
||||
daily_weather_variation.clouds_cumulus_congestus_amount = 7.0;
|
||||
daily_weather_variation.clouds_stratus_amount = 8.0;
|
||||
daily_weather_variation.fogginess = 9.0;
|
||||
daily_weather_variation.aurora_amount = 10.0;
|
||||
daily_weather_variation.nlc_amount = 11.0;
|
||||
daily_weather_variation.aurora_colors = mat2x3(vec3(12.0, 13.0, 14.0), vec3(15.0, 16.0, 17.0));
|
||||
return daily_weather_variation;
|
||||
}
|
||||
|
||||
void main() {
|
||||
gl_Position = Position;
|
||||
daily_weather_variation = get_daily_weather_variation();
|
||||
})";
|
||||
|
||||
const char* daily_weather_variation_fs = R"(#version 150
|
||||
|
||||
struct DailyWeatherVariation {
|
||||
vec2 clouds_cumulus_coverage;
|
||||
vec2 clouds_altocumulus_coverage;
|
||||
vec2 clouds_cirrus_coverage;
|
||||
float clouds_cumulus_congestus_amount;
|
||||
float clouds_stratus_amount;
|
||||
float fogginess;
|
||||
float aurora_amount;
|
||||
float nlc_amount;
|
||||
mat2x3 aurora_colors;
|
||||
};
|
||||
|
||||
in DailyWeatherVariation daily_weather_variation;
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
vec3 aurora = daily_weather_variation.aurora_colors[1];
|
||||
DailyWeatherVariation variation = daily_weather_variation;
|
||||
vec2 coverage = variation.clouds_cumulus_coverage + daily_weather_variation.clouds_altocumulus_coverage;
|
||||
fragColor = vec4(coverage, aurora.x + variation.aurora_amount, 1.0);
|
||||
})";
|
||||
|
||||
TEST_F(ProgramUtilTest, CompileSimpleFragmentShader) {
|
||||
using namespace MG_Util::ShaderTranspiler;
|
||||
ShaderAttrib attrib{.shaderType = GL_FRAGMENT_SHADER, .sourceStr = fs};
|
||||
@@ -351,6 +486,110 @@ TEST_F(ProgramUtilTest, DecompProgram) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ProgramUtilTest, FlattenDailyWeatherVariationInterfaceInSpirvPass) {
|
||||
using namespace MG_Util::ShaderTranspiler;
|
||||
|
||||
String vsSource = daily_weather_variation_vs;
|
||||
String fsSource = daily_weather_variation_fs;
|
||||
PreprocessShaderSource(ShaderStage::Vertex, vsSource);
|
||||
PreprocessShaderSource(ShaderStage::Fragment, fsSource);
|
||||
|
||||
ShaderAttrib vsAttrib{.shaderType = GL_VERTEX_SHADER, .sourceStr = vsSource};
|
||||
auto vsRes = ShaderCompiler::CompileShader(vsAttrib);
|
||||
if (!vsRes) {
|
||||
ASSERT_NE(vsRes.error().errc, 0);
|
||||
FAIL() << "errc: " << vsRes.error().errc << "\nlog: " << vsRes.error().log;
|
||||
}
|
||||
|
||||
ShaderAttrib fsAttrib{.shaderType = GL_FRAGMENT_SHADER, .sourceStr = fsSource};
|
||||
auto fsRes = ShaderCompiler::CompileShader(fsAttrib);
|
||||
if (!fsRes) {
|
||||
ASSERT_NE(fsRes.error().errc, 0);
|
||||
FAIL() << "errc: " << fsRes.error().errc << "\nlog: " << fsRes.error().log;
|
||||
}
|
||||
|
||||
ProgramAttrib programAttrib{.shaders = {vsRes.value(), fsRes.value()}};
|
||||
auto programRes = ShaderCompiler::LinkProgram(programAttrib);
|
||||
if (!programRes) {
|
||||
ASSERT_NE(programRes.error().errc, 0);
|
||||
FAIL() << "errc: " << programRes.error().errc << "\nlog: " << programRes.error().log;
|
||||
}
|
||||
|
||||
ProgramBinaryAttrib binaryAttrib{
|
||||
.shaderTypes = {GL_VERTEX_SHADER, GL_FRAGMENT_SHADER},
|
||||
.program = *programRes.value(),
|
||||
};
|
||||
auto binRes = ShaderCompiler::GetSpirvBinaryFromProgram(binaryAttrib);
|
||||
ASSERT_TRUE(binRes.has_value());
|
||||
|
||||
Vector<Vector<uint32_t>> optimizedSpirvs;
|
||||
optimizedSpirvs.reserve(binRes->size());
|
||||
for (const auto& spirv : binRes.value()) {
|
||||
Vector<uint32_t> optimized;
|
||||
ASSERT_TRUE(ShaderCompiler::SanitizeAndOptimizeBinary(spirv, optimized));
|
||||
optimizedSpirvs.push_back(std::move(optimized));
|
||||
}
|
||||
|
||||
Vector<SpvcSession> sessions(optimizedSpirvs.size());
|
||||
for (SizeT i = 0; i < optimizedSpirvs.size(); ++i) {
|
||||
sessions[i] = SpvcSession(optimizedSpirvs[i], SessionUsageBit::Transpile);
|
||||
}
|
||||
|
||||
auto vertexSource = ShaderCompiler::DecompileShader(sessions[0]);
|
||||
auto fragmentSource = ShaderCompiler::DecompileShader(sessions[1]);
|
||||
ASSERT_TRUE(vertexSource.has_value());
|
||||
ASSERT_TRUE(fragmentSource.has_value());
|
||||
|
||||
EXPECT_EQ(vertexSource->find("out DailyWeatherVariation "), std::string::npos);
|
||||
EXPECT_EQ(fragmentSource->find("in DailyWeatherVariation "), std::string::npos);
|
||||
EXPECT_NE(vertexSource->find("daily_weather_variation_clouds_cumulus_coverage"), std::string::npos);
|
||||
EXPECT_NE(vertexSource->find("daily_weather_variation_aurora_colors"), std::string::npos);
|
||||
EXPECT_NE(fragmentSource->find("daily_weather_variation_clouds_altocumulus_coverage"), std::string::npos);
|
||||
EXPECT_NE(fragmentSource->find("daily_weather_variation_aurora_colors"), std::string::npos);
|
||||
|
||||
const struct ExpectedInterface {
|
||||
const char* name;
|
||||
uint32_t location;
|
||||
} expectedInterfaces[] = {
|
||||
{"daily_weather_variation_clouds_cumulus_coverage", 0},
|
||||
{"daily_weather_variation_clouds_altocumulus_coverage", 1},
|
||||
{"daily_weather_variation_clouds_cirrus_coverage", 2},
|
||||
{"daily_weather_variation_clouds_cumulus_congestus_amount", 3},
|
||||
{"daily_weather_variation_clouds_stratus_amount", 4},
|
||||
{"daily_weather_variation_fogginess", 5},
|
||||
{"daily_weather_variation_aurora_amount", 6},
|
||||
{"daily_weather_variation_nlc_amount", 7},
|
||||
{"daily_weather_variation_aurora_colors", 8},
|
||||
};
|
||||
|
||||
const auto vsOutputs = sessions[0].GetShaderInterface(SPVC_RESOURCE_TYPE_STAGE_OUTPUT);
|
||||
const auto fsInputs = sessions[1].GetShaderInterface(SPVC_RESOURCE_TYPE_STAGE_INPUT);
|
||||
ASSERT_EQ(vsOutputs.size(), std::size(expectedInterfaces));
|
||||
ASSERT_EQ(fsInputs.size(), std::size(expectedInterfaces));
|
||||
|
||||
for (const auto& expected : expectedInterfaces) {
|
||||
bool foundVertex = false;
|
||||
for (const auto& output : vsOutputs) {
|
||||
if (output.name == expected.name) {
|
||||
foundVertex = true;
|
||||
EXPECT_EQ(output.location, expected.location);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(foundVertex) << "missing vertex output: " << expected.name;
|
||||
|
||||
bool foundFragment = false;
|
||||
for (const auto& input : fsInputs) {
|
||||
if (input.name == expected.name) {
|
||||
foundFragment = true;
|
||||
EXPECT_EQ(input.location, expected.location);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(foundFragment) << "missing fragment input: " << expected.name;
|
||||
}
|
||||
}
|
||||
|
||||
const char* blit_vs = R"(#version 460 core
|
||||
|
||||
in vec3 Position;
|
||||
|
||||
@@ -7,10 +7,403 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#include <MG_Backend/DirectGLES/BackendObject_DirectGLES.h>
|
||||
#include <MG_Backend/DirectGLES/Managers.h>
|
||||
#include <MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h>
|
||||
#include <MG_Backend/BackendObjects.h>
|
||||
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
|
||||
#include <MG_Impl/GLImpl/RenderState/GL_RenderState.h>
|
||||
#include <MG_State/GLState/Core.h>
|
||||
#include <MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h>
|
||||
#include <MG_Backend/DirectVulkan/Renderer/VkTextureManager.h>
|
||||
#include <MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h>
|
||||
#include <MG_Util/ShaderTranspiler/ShaderCompiler.h>
|
||||
#include <MG_Util/ShaderTranspiler/ShaderSourceProcessor.h>
|
||||
#include <MG_Util/Debug/Log.h>
|
||||
|
||||
namespace {
|
||||
class DynamicParameterBackend final : public MobileGL::MG_Backend::BackendObject {
|
||||
public:
|
||||
explicit DynamicParameterBackend(MobileGL::MG_Backend::DynamicBackendParameters params):
|
||||
m_params(params) {}
|
||||
|
||||
void Initialize() override {}
|
||||
MobileGL::Bool InitCapabilities() override { return true; }
|
||||
MobileGL::Bool InitWindowSurface() override { return true; }
|
||||
const MobileGL::RendererInfo& GetRendererInfo() const override { return m_info; }
|
||||
MobileGL::String GetBackendAPIVersionString() const override { return "test"; }
|
||||
const MobileGL::MG_Backend::GlobalBackendFunctionsTable& GetBackendFunctions() const override {
|
||||
return m_functions;
|
||||
}
|
||||
const MobileGL::MG_Backend::DynamicBackendParameters& GetDynamicParameters() const override {
|
||||
return m_params;
|
||||
}
|
||||
MobileGL::BackendType GetBackendType() const override { return MobileGL::BackendType::Unknown; }
|
||||
|
||||
private:
|
||||
MobileGL::MG_Backend::DynamicBackendParameters m_params;
|
||||
MobileGL::MG_Backend::GlobalBackendFunctionsTable m_functions{};
|
||||
MobileGL::RendererInfo m_info{
|
||||
.RendererName = "Test",
|
||||
.BackendName = "DynamicParameterBackend",
|
||||
.ExtraVendor = MobileGL::Nullopt,
|
||||
.RendererGLInfo = {.TargetGLVersion = {3, 3, 0},
|
||||
.TargetGLSLVersion = {4, 6, 0},
|
||||
.Extensions = {},
|
||||
.IsCompatibilityProfile = false},
|
||||
.StaticBackendCapability = {.AllowVSOnlyPrograms = false}};
|
||||
};
|
||||
|
||||
void SetEnvVar(const char* name, const char* value) {
|
||||
#if defined(_WIN32)
|
||||
_putenv_s(name, value);
|
||||
#else
|
||||
setenv(name, value, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UnsetEnvVar(const char* name) {
|
||||
#if defined(_WIN32)
|
||||
_putenv_s(name, "");
|
||||
#else
|
||||
unsetenv(name);
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(Sanity, BasicAssertions) {
|
||||
// Expect two strings not to be equal.
|
||||
EXPECT_STRNE("hello", "world");
|
||||
// Expect equality.
|
||||
EXPECT_EQ(7 * 6, 42);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DirectGLESSanity, AdvertisesDepthTextureForGlmarkShadowScenes) {
|
||||
MobileGL::MG_Backend::DirectGLES::BackendObject_DirectGLES backend;
|
||||
const auto& extensions = backend.GetRendererInfo().RendererGLInfo.Extensions;
|
||||
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_depth_texture), extensions.end());
|
||||
}
|
||||
|
||||
TEST(DirectGLESSanity, AdvertisesVoxyRequiredRenderingExtensionsWithoutRaisingGLVersion) {
|
||||
MobileGL::MG_Backend::DirectGLES::BackendObject_DirectGLES backend;
|
||||
const auto& rendererInfo = backend.GetRendererInfo().RendererGLInfo;
|
||||
const auto& extensions = rendererInfo.Extensions;
|
||||
|
||||
EXPECT_EQ(rendererInfo.TargetGLVersion.Major, 3);
|
||||
EXPECT_EQ(rendererInfo.TargetGLVersion.Minor, 3);
|
||||
EXPECT_EQ(rendererInfo.TargetGLVersion.Patch, 0);
|
||||
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_compute_shader),
|
||||
extensions.end());
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_shader_storage_buffer_object),
|
||||
extensions.end());
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_texture_storage),
|
||||
extensions.end());
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_direct_state_access),
|
||||
extensions.end());
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_multi_draw_indirect),
|
||||
extensions.end());
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_indirect_parameters),
|
||||
extensions.end());
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_shader_draw_parameters),
|
||||
extensions.end());
|
||||
EXPECT_EQ(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_gpu_shader_int64),
|
||||
extensions.end());
|
||||
EXPECT_EQ(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_KHR_shader_subgroup),
|
||||
extensions.end());
|
||||
}
|
||||
|
||||
TEST(DirectGLESSanity, ProvidesNamedFramebufferBlitForDirectStateAccess) {
|
||||
MobileGL::MG_Backend::DirectGLES::BackendObject_DirectGLES backend;
|
||||
const auto& funcs = backend.GetBackendFunctions().GL;
|
||||
|
||||
EXPECT_NE(funcs.ClearNamedFramebufferfv, nullptr);
|
||||
EXPECT_NE(funcs.ClearNamedFramebufferfi, nullptr);
|
||||
EXPECT_NE(funcs.BlitFramebuffer, nullptr);
|
||||
EXPECT_NE(funcs.BlitNamedFramebuffer, nullptr);
|
||||
}
|
||||
|
||||
TEST(DirectGLESSanity, RewritesBaseInstanceBuiltinForEsslVertexShaders) {
|
||||
const MobileGL::String source = R"(#version 320 es
|
||||
void main() {
|
||||
uint drawId = gl_BaseInstance;
|
||||
uint untouched = my_gl_BaseInstance_value;
|
||||
}
|
||||
)";
|
||||
|
||||
const auto rewritten = MobileGL::MG_Backend::DirectGLES::EmulateBaseInstanceInVertexShader(
|
||||
source, GL_VERTEX_SHADER);
|
||||
|
||||
EXPECT_NE(rewritten.find("uniform highp int mg_BaseInstance;"), MobileGL::String::npos);
|
||||
EXPECT_NE(rewritten.find("uint drawId = mg_BaseInstance;"), MobileGL::String::npos);
|
||||
EXPECT_NE(rewritten.find("my_gl_BaseInstance_value"), MobileGL::String::npos);
|
||||
EXPECT_EQ(rewritten.find("uint drawId = gl_BaseInstance;"), MobileGL::String::npos);
|
||||
}
|
||||
|
||||
TEST(DirectGLESSanity, LeavesBaseInstanceBuiltinAloneOutsideVertexShaders) {
|
||||
const MobileGL::String source = "#version 320 es\nuint value = gl_BaseInstance;\n";
|
||||
|
||||
const auto rewritten = MobileGL::MG_Backend::DirectGLES::EmulateBaseInstanceInVertexShader(
|
||||
source, GL_FRAGMENT_SHADER);
|
||||
|
||||
EXPECT_EQ(rewritten, source);
|
||||
}
|
||||
|
||||
TEST(DirectVulkanSanity, AdvertisesTextureStorageForDirectStateAccess) {
|
||||
MobileGL::MG_Backend::DirectVulkan::BackendObject_DirectVulkan backend;
|
||||
const auto& extensions = backend.GetRendererInfo().RendererGLInfo.Extensions;
|
||||
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_direct_state_access),
|
||||
extensions.end());
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_texture_storage), extensions.end());
|
||||
}
|
||||
|
||||
TEST(DirectVulkanSanity, AdvertisesVoxyRequiredRenderingExtensionsWithoutRaisingGLVersion) {
|
||||
MobileGL::MG_Backend::DirectVulkan::BackendObject_DirectVulkan backend;
|
||||
const auto& rendererInfo = backend.GetRendererInfo().RendererGLInfo;
|
||||
const auto& extensions = rendererInfo.Extensions;
|
||||
|
||||
EXPECT_EQ(rendererInfo.TargetGLVersion.Major, 3);
|
||||
EXPECT_EQ(rendererInfo.TargetGLVersion.Minor, 3);
|
||||
EXPECT_EQ(rendererInfo.TargetGLVersion.Patch, 0);
|
||||
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_compute_shader),
|
||||
extensions.end());
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_shader_storage_buffer_object),
|
||||
extensions.end());
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_multi_draw_indirect),
|
||||
extensions.end());
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_indirect_parameters),
|
||||
extensions.end());
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_shader_draw_parameters),
|
||||
extensions.end());
|
||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_gpu_shader_int64),
|
||||
extensions.end());
|
||||
}
|
||||
|
||||
TEST(DirectVulkanSanity, AdvertisesSubgroupOnlyWhenVulkanReportsUsableSupport) {
|
||||
using namespace MobileGL;
|
||||
|
||||
MG_Backend::DirectVulkan::BackendObject_DirectVulkan backend;
|
||||
|
||||
MG_External::VulkanCapabilities unsupportedCaps;
|
||||
unsupportedCaps.SupportsShaderSubgroup = false;
|
||||
unsupportedCaps.SubgroupSize = 32;
|
||||
unsupportedCaps.SubgroupSupportedStages = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
unsupportedCaps.SubgroupSupportedOperations = VK_SUBGROUP_FEATURE_BASIC_BIT;
|
||||
backend.ApplyVulkanCapabilitiesForTesting(unsupportedCaps);
|
||||
|
||||
const auto& unsupportedExtensions = backend.GetRendererInfo().RendererGLInfo.Extensions;
|
||||
EXPECT_EQ(std::find(unsupportedExtensions.begin(), unsupportedExtensions.end(), E_GL_KHR_shader_subgroup),
|
||||
unsupportedExtensions.end());
|
||||
EXPECT_EQ(backend.GetDynamicParameters().SubgroupSize, 0u);
|
||||
EXPECT_EQ(backend.GetDynamicParameters().SubgroupSupportedStages, 0u);
|
||||
EXPECT_EQ(backend.GetDynamicParameters().SubgroupSupportedFeatures, 0u);
|
||||
|
||||
MG_External::VulkanCapabilities supportedCaps;
|
||||
supportedCaps.SupportsShaderSubgroup = true;
|
||||
supportedCaps.SubgroupSize = 32;
|
||||
supportedCaps.SubgroupSupportedStages = VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
supportedCaps.SubgroupSupportedOperations =
|
||||
VK_SUBGROUP_FEATURE_BASIC_BIT | VK_SUBGROUP_FEATURE_ARITHMETIC_BIT | VK_SUBGROUP_FEATURE_QUAD_BIT;
|
||||
supportedCaps.SubgroupQuadOperationsInAllStages = true;
|
||||
backend.ApplyVulkanCapabilitiesForTesting(supportedCaps);
|
||||
|
||||
const auto& supportedExtensions = backend.GetRendererInfo().RendererGLInfo.Extensions;
|
||||
EXPECT_NE(std::find(supportedExtensions.begin(), supportedExtensions.end(), E_GL_KHR_shader_subgroup),
|
||||
supportedExtensions.end());
|
||||
EXPECT_EQ(backend.GetDynamicParameters().SubgroupSize, 32u);
|
||||
EXPECT_EQ(backend.GetDynamicParameters().SubgroupSupportedStages,
|
||||
static_cast<Uint32>(GL_FRAGMENT_SHADER_BIT | GL_COMPUTE_SHADER_BIT));
|
||||
EXPECT_EQ(backend.GetDynamicParameters().SubgroupSupportedFeatures,
|
||||
static_cast<Uint32>(GL_SUBGROUP_FEATURE_BASIC_BIT_KHR |
|
||||
GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR |
|
||||
GL_SUBGROUP_FEATURE_QUAD_BIT_KHR));
|
||||
EXPECT_TRUE(backend.GetDynamicParameters().SubgroupQuadOperationsInAllStages);
|
||||
}
|
||||
|
||||
TEST(DirectVulkanSanity, KeepsOptionalGpuShaderInt64BranchForVoxyQuadDecode) {
|
||||
using namespace MobileGL;
|
||||
|
||||
MG_Backend::pActiveBackendObject = MakeUnique<MG_Backend::DirectVulkan::BackendObject_DirectVulkan>();
|
||||
String source = R"(#version 460 core
|
||||
#extension GL_ARB_gpu_shader_int64 : enable
|
||||
#ifdef GL_ARB_gpu_shader_int64
|
||||
uint getLowBits(uint64_t v) {
|
||||
return uint(v & uint64_t(0xffu));
|
||||
}
|
||||
#else
|
||||
#error int64 branch should be enabled for DirectVulkan
|
||||
#endif
|
||||
void main() {
|
||||
gl_Position = vec4(float(getLowBits(uint64_t(0x2au))));
|
||||
}
|
||||
)";
|
||||
|
||||
MG_Util::ShaderTranspiler::PreprocessShaderSource(ShaderStage::Vertex, source);
|
||||
EXPECT_NE(source.find("#extension GL_ARB_gpu_shader_int64"), String::npos);
|
||||
EXPECT_NE(source.find("GL_ARB_gpu_shader_int64"), String::npos);
|
||||
|
||||
auto shaderResult = MG_Util::ShaderTranspiler::ShaderCompiler::CompileShader({
|
||||
.shaderType = GL_VERTEX_SHADER,
|
||||
.sourceStr = source,
|
||||
.flags = MG_Util::ShaderTranspiler::ShaderCompileBits::CompileForOpenGL,
|
||||
});
|
||||
EXPECT_TRUE(shaderResult) << (shaderResult ? "" : shaderResult.error().log);
|
||||
|
||||
MG_Backend::pActiveBackendObject.reset();
|
||||
}
|
||||
|
||||
TEST(GetterSanity, ReportsKhrSubgroupDynamicParameters) {
|
||||
using namespace MobileGL;
|
||||
|
||||
MG_State::pGLContext = MakeUnique<MG_State::GLState::GLContext>();
|
||||
|
||||
MG_Backend::DynamicBackendParameters params;
|
||||
params.SubgroupSize = 32;
|
||||
params.SubgroupSupportedStages = GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT | GL_COMPUTE_SHADER_BIT;
|
||||
params.SubgroupSupportedFeatures = GL_SUBGROUP_FEATURE_BASIC_BIT_KHR |
|
||||
GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR |
|
||||
GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR |
|
||||
GL_SUBGROUP_FEATURE_QUAD_BIT_KHR;
|
||||
params.SubgroupQuadOperationsInAllStages = true;
|
||||
MG_Backend::pActiveBackendObject = MakeUnique<DynamicParameterBackend>(params);
|
||||
|
||||
GLint intValue = 0;
|
||||
MG_Impl::GLImpl::GetIntegerv(GL_SUBGROUP_SIZE_KHR, &intValue);
|
||||
EXPECT_EQ(intValue, 32);
|
||||
MG_Impl::GLImpl::GetIntegerv(GL_SUBGROUP_SUPPORTED_STAGES_KHR, &intValue);
|
||||
EXPECT_EQ(intValue, static_cast<GLint>(params.SubgroupSupportedStages));
|
||||
MG_Impl::GLImpl::GetIntegerv(GL_SUBGROUP_SUPPORTED_FEATURES_KHR, &intValue);
|
||||
EXPECT_EQ(intValue, static_cast<GLint>(params.SubgroupSupportedFeatures));
|
||||
MG_Impl::GLImpl::GetIntegerv(GL_SUBGROUP_QUAD_ALL_STAGES_KHR, &intValue);
|
||||
EXPECT_EQ(intValue, GL_TRUE);
|
||||
|
||||
GLint64 int64Value = 0;
|
||||
MG_Impl::GLImpl::GetInteger64v(GL_SUBGROUP_SUPPORTED_FEATURES_KHR, &int64Value);
|
||||
EXPECT_EQ(int64Value, static_cast<GLint64>(params.SubgroupSupportedFeatures));
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
|
||||
MG_Backend::pActiveBackendObject.reset();
|
||||
MG_State::pGLContext.reset();
|
||||
}
|
||||
|
||||
TEST(DirectVulkanSanity, CommandMemoryBarrierMakesIndirectDrawCommandsVisible) {
|
||||
using namespace MobileGL;
|
||||
using namespace MobileGL::MG_Backend::DirectVulkan;
|
||||
|
||||
const VkMemoryBarrier commandBarrier =
|
||||
VulkanRenderer::BuildMemoryBarrierForGlBarriers(GL_COMMAND_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
EXPECT_NE(commandBarrier.dstAccessMask & VK_ACCESS_INDIRECT_COMMAND_READ_BIT, 0u);
|
||||
|
||||
const VkMemoryBarrier storageOnlyBarrier =
|
||||
VulkanRenderer::BuildMemoryBarrierForGlBarriers(GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
EXPECT_EQ(storageOnlyBarrier.dstAccessMask & VK_ACCESS_INDIRECT_COMMAND_READ_BIT, 0u);
|
||||
}
|
||||
|
||||
TEST(DirectVulkanSanity, DrawIndexedIndirectCommandMatchesGlAndVulkanLayout) {
|
||||
using namespace MobileGL::MG_Backend::DirectVulkan;
|
||||
|
||||
EXPECT_EQ(sizeof(DrawIndexedCmdParam), 20u);
|
||||
EXPECT_EQ(offsetof(DrawIndexedCmdParam, indexCount), 0u);
|
||||
EXPECT_EQ(offsetof(DrawIndexedCmdParam, instanceCount), 4u);
|
||||
EXPECT_EQ(offsetof(DrawIndexedCmdParam, firstIndex), 8u);
|
||||
EXPECT_EQ(offsetof(DrawIndexedCmdParam, vertexOffset), 12u);
|
||||
EXPECT_EQ(offsetof(DrawIndexedCmdParam, firstInstance), 16u);
|
||||
}
|
||||
|
||||
TEST(DirectVulkanSanity, UndefinedDepthStencilLayoutUsesDontCareForUnclearedAspects) {
|
||||
using namespace MobileGL;
|
||||
using namespace MobileGL::MG_Backend::DirectVulkan;
|
||||
|
||||
auto noClear = ResolveDepthStencilAttachmentLoadInfo(VK_IMAGE_LAYOUT_UNDEFINED, false, false);
|
||||
EXPECT_EQ(noClear.depthLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
|
||||
EXPECT_EQ(noClear.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
|
||||
EXPECT_EQ(noClear.initialLayout, VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
|
||||
auto depthOnlyClear = ResolveDepthStencilAttachmentLoadInfo(VK_IMAGE_LAYOUT_UNDEFINED, true, false);
|
||||
EXPECT_EQ(depthOnlyClear.depthLoadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
|
||||
EXPECT_EQ(depthOnlyClear.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
|
||||
EXPECT_EQ(depthOnlyClear.initialLayout, VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
|
||||
auto knownLayout = ResolveDepthStencilAttachmentLoadInfo(
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, false);
|
||||
EXPECT_EQ(knownLayout.depthLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD);
|
||||
EXPECT_EQ(knownLayout.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD);
|
||||
EXPECT_EQ(knownLayout.initialLayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
}
|
||||
|
||||
TEST(DirectVulkanSanity, SampledDepthStencilViewUsesSingleDepthAspect) {
|
||||
using namespace MobileGL::MG_Backend::DirectVulkan;
|
||||
|
||||
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(VK_IMAGE_ASPECT_COLOR_BIT),
|
||||
VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(VK_IMAGE_ASPECT_DEPTH_BIT),
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(VK_IMAGE_ASPECT_STENCIL_BIT),
|
||||
VK_IMAGE_ASPECT_STENCIL_BIT);
|
||||
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT),
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
}
|
||||
|
||||
TEST(RenderStateSanity, ProvokingVertexUpdatesStateAndValidatesEnum) {
|
||||
using namespace MobileGL;
|
||||
|
||||
MG_State::pGLContext = MakeUnique<MG_State::GLState::GLContext>();
|
||||
MG_Backend::pActiveBackendObject = MakeUnique<MG_Backend::DirectGLES::BackendObject_DirectGLES>();
|
||||
|
||||
GLint mode = 0;
|
||||
MG_Impl::GLImpl::GetIntegerv(GL_PROVOKING_VERTEX, &mode);
|
||||
EXPECT_EQ(mode, GL_LAST_VERTEX_CONVENTION);
|
||||
|
||||
const Uint initialVersion = MG_State::pGLContext->GetRenderStateParametersVersion();
|
||||
MG_Impl::GLImpl::ProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
|
||||
MG_Impl::GLImpl::GetIntegerv(GL_PROVOKING_VERTEX, &mode);
|
||||
EXPECT_EQ(mode, GL_FIRST_VERTEX_CONVENTION);
|
||||
EXPECT_GT(MG_State::pGLContext->GetRenderStateParametersVersion(), initialVersion);
|
||||
|
||||
const Uint updatedVersion = MG_State::pGLContext->GetRenderStateParametersVersion();
|
||||
MG_Impl::GLImpl::ProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetRenderStateParametersVersion(), updatedVersion);
|
||||
|
||||
MG_Impl::GLImpl::ProvokingVertex(GL_TRIANGLES);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_ENUM);
|
||||
MG_Impl::GLImpl::GetIntegerv(GL_PROVOKING_VERTEX, &mode);
|
||||
EXPECT_EQ(mode, GL_FIRST_VERTEX_CONVENTION);
|
||||
|
||||
MG_Backend::pActiveBackendObject.reset();
|
||||
MG_State::pGLContext.reset();
|
||||
}
|
||||
|
||||
TEST(LogSanity, UsesEnvOverrideForFilePath) {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
MobileGL::MG_Util::Debug::Close();
|
||||
|
||||
const fs::path logPath = fs::temp_directory_path() / "mobilegl-log-env-override-test.log";
|
||||
const std::string message = "mobilegl-log-env-override-regression";
|
||||
fs::remove(logPath);
|
||||
|
||||
SetEnvVar("MOBILEGL_LOG_FILE_PATH", logPath.string().c_str());
|
||||
MobileGL::MG_Util::Debug::Log("INFO", ANDROID_LOG_INFO, "%s", message.c_str());
|
||||
MobileGL::MG_Util::Debug::Close();
|
||||
UnsetEnvVar("MOBILEGL_LOG_FILE_PATH");
|
||||
|
||||
{
|
||||
std::ifstream logFile(logPath);
|
||||
ASSERT_TRUE(logFile.good());
|
||||
|
||||
const std::string contents((std::istreambuf_iterator<char>(logFile)), std::istreambuf_iterator<char>());
|
||||
EXPECT_NE(contents.find(message), std::string::npos);
|
||||
}
|
||||
|
||||
fs::remove(logPath);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
add_executable(
|
||||
TextureTest
|
||||
TextureTest.cpp
|
||||
)
|
||||
|
||||
target_include_directories(TextureTest PRIVATE
|
||||
${MGL_ROOT}/include
|
||||
${MGL_ROOT}/MobileGL
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
TextureTest PRIVATE
|
||||
GTest::gtest_main
|
||||
${LINK_LIBRARIES}
|
||||
)
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(TextureTest)
|
||||
@@ -0,0 +1,222 @@
|
||||
// MobileGL - MobileGL/MG_Test/Texture/TextureTest.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "Includes.h"
|
||||
#include "Init.h"
|
||||
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
|
||||
#include <MG_Impl/GLImpl/RenderState/GL_RenderState.h>
|
||||
#include <MG_Impl/GLImpl/Texture/GL_Texture.h>
|
||||
#include <MG_State/GLState/Core.h>
|
||||
#include <MG_State/GLState/TextureState/TextureObject.h>
|
||||
#include <MG_Util/Texture/TextureFormatProcessor.h>
|
||||
|
||||
using namespace MobileGL;
|
||||
|
||||
class TextureTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override { MobileGL::Initialize(); }
|
||||
};
|
||||
|
||||
TEST_F(TextureTest, CreateTexturesCreatesObjectsWithoutBinding) {
|
||||
GLuint texture = 0;
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
|
||||
|
||||
EXPECT_NE(texture, 0u);
|
||||
EXPECT_TRUE(MG_State::pGLContext->ValidateTextureObject(texture));
|
||||
|
||||
auto& unit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
|
||||
EXPECT_EQ(unit.GetBindingSlot(TextureTarget::Texture2D).GetBoundObject(), nullptr);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(TextureTest, TextureStorageAndSubImageModifyNamedObjectOnly) {
|
||||
GLuint namedTexture = 0;
|
||||
GLuint boundTexture = 0;
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &namedTexture);
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &boundTexture);
|
||||
MG_Impl::GLImpl::BindTextureUnit(0, boundTexture);
|
||||
|
||||
const auto boundObjectBefore =
|
||||
MG_State::pGLContext->GetTextureUnitObject(0).GetBindingSlot(TextureTarget::Texture2D).GetBoundObject();
|
||||
|
||||
MG_Impl::GLImpl::TextureStorage2D(namedTexture, 2, GL_RGBA8, 2, 2);
|
||||
const Uint8 pixels[] = {
|
||||
1, 2, 3, 4,
|
||||
5, 6, 7, 8,
|
||||
9, 10, 11, 12,
|
||||
13, 14, 15, 16,
|
||||
};
|
||||
MG_Impl::GLImpl::TextureSubImage2D(namedTexture, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
const auto namedObject = MG_State::pGLContext->GetTextureObject(namedTexture);
|
||||
auto* mipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(namedObject.get());
|
||||
EXPECT_EQ(mipmapObject->GetMipmapTexelSize(TextureUploadTarget::Texture2D, 0), IntVec3(2, 2, 1));
|
||||
EXPECT_EQ(mipmapObject->GetMipmapTexelSize(TextureUploadTarget::Texture2D, 1), IntVec3(1, 1, 1));
|
||||
EXPECT_TRUE(mipmapObject->IsStorageDirty(TextureUploadTarget::Texture2D, 0));
|
||||
EXPECT_FALSE(mipmapObject->IsStorageDirty(TextureUploadTarget::Texture2D, 1));
|
||||
|
||||
EXPECT_EQ(MG_State::pGLContext->GetTextureUnitObject(0).GetBindingSlot(TextureTarget::Texture2D).GetBoundObject(),
|
||||
boundObjectBefore);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(TextureTest, BoundTexSubImage2DUsesCompactRowsAfterUnpackProcessing) {
|
||||
GLuint texture = 0;
|
||||
MG_Impl::GLImpl::GenTextures(1, &texture);
|
||||
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
const Uint8 initialPixels[2 * 16] = {};
|
||||
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 5, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, initialPixels);
|
||||
|
||||
const Uint8 subImageWithGuard[] = {
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
101, 102, 103,
|
||||
10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
201, 202, 203, 204, 205, 206,
|
||||
};
|
||||
MG_Impl::GLImpl::PixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
MG_Impl::GLImpl::TexSubImage2D(GL_TEXTURE_2D, 0, 1, 0, 3, 2, GL_RGB, GL_UNSIGNED_BYTE, subImageWithGuard);
|
||||
|
||||
const auto textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||
auto* mipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
||||
const auto* stored = static_cast<const Uint8*>(
|
||||
mipmapObject->MapMipmapData(TextureUploadTarget::Texture2D, 0));
|
||||
|
||||
const Uint8 expected[] = {
|
||||
0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0,
|
||||
0, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0, 0, 0,
|
||||
};
|
||||
for (SizeT i = 0; i < sizeof(expected); ++i) {
|
||||
EXPECT_EQ(stored[i], expected[i]) << "byte " << i;
|
||||
}
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(TextureTest, GetTextureImageReadsNamedObjectWithoutBinding) {
|
||||
GLuint texture = 0;
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
|
||||
MG_Impl::GLImpl::TextureStorage2D(texture, 1, GL_RGBA8, 2, 1);
|
||||
|
||||
const Uint8 pixels[] = {
|
||||
21, 22, 23, 24,
|
||||
31, 32, 33, 34,
|
||||
};
|
||||
MG_Impl::GLImpl::TextureSubImage2D(texture, 0, 0, 0, 2, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
Uint8 output[sizeof(pixels)] = {};
|
||||
MG_Impl::GLImpl::GetTextureImage(texture, 0, GL_RGBA, GL_UNSIGNED_BYTE, sizeof(output), output);
|
||||
|
||||
EXPECT_EQ(std::memcmp(output, pixels, sizeof(pixels)), 0);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(TextureTest, GetTextureSubImageReadsFullNamedLevelWithoutBinding) {
|
||||
GLuint texture = 0;
|
||||
GLuint boundTexture = 0;
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &boundTexture);
|
||||
MG_Impl::GLImpl::BindTextureUnit(0, boundTexture);
|
||||
|
||||
const auto boundObjectBefore =
|
||||
MG_State::pGLContext->GetTextureUnitObject(0).GetBindingSlot(TextureTarget::Texture2D).GetBoundObject();
|
||||
|
||||
MG_Impl::GLImpl::TextureStorage2D(texture, 1, GL_RGBA8, 2, 1);
|
||||
const Uint8 pixels[] = {
|
||||
41, 42, 43, 44,
|
||||
51, 52, 53, 54,
|
||||
};
|
||||
MG_Impl::GLImpl::TextureSubImage2D(texture, 0, 0, 0, 2, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
Uint8 output[sizeof(pixels)] = {};
|
||||
MG_Impl::GLImpl::GetTextureSubImage(texture, 0, 0, 0, 0, 2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
sizeof(output), output);
|
||||
|
||||
EXPECT_EQ(std::memcmp(output, pixels, sizeof(pixels)), 0);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetTextureUnitObject(0).GetBindingSlot(TextureTarget::Texture2D).GetBoundObject(),
|
||||
boundObjectBefore);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(TextureTest, GetTextureSubImageRejectsPartialReadbackForNow) {
|
||||
GLuint texture = 0;
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
|
||||
MG_Impl::GLImpl::TextureStorage2D(texture, 1, GL_RGBA8, 2, 2);
|
||||
|
||||
Uint8 output[4] = {};
|
||||
MG_Impl::GLImpl::GetTextureSubImage(texture, 0, 0, 0, 0, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
sizeof(output), output);
|
||||
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
TEST_F(TextureTest, TextureParameteriAndBindTextureUnitAreDirectStateAccess) {
|
||||
GLuint texture = 0;
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
|
||||
|
||||
MG_Impl::GLImpl::TextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
GLint minFilter = 0;
|
||||
MG_Impl::GLImpl::GetTextureParameteriv(texture, GL_TEXTURE_MIN_FILTER, &minFilter);
|
||||
EXPECT_EQ(minFilter, GL_NEAREST);
|
||||
|
||||
MG_Impl::GLImpl::BindTextureUnit(3, texture);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetActiveTextureUnit(), 0);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetTextureUnitObject(3)
|
||||
.GetBindingSlot(TextureTarget::Texture2D)
|
||||
.GetBoundObject()
|
||||
->GetExternalIndex(),
|
||||
texture);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(TextureTest, TextureParameterfModifiesNamedObjectWithoutBinding) {
|
||||
GLuint namedTexture = 0;
|
||||
GLuint boundTexture = 0;
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &namedTexture);
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &boundTexture);
|
||||
MG_Impl::GLImpl::BindTextureUnit(0, boundTexture);
|
||||
|
||||
const auto boundObjectBefore =
|
||||
MG_State::pGLContext->GetTextureUnitObject(0).GetBindingSlot(TextureTarget::Texture2D).GetBoundObject();
|
||||
|
||||
MG_Impl::GLImpl::TextureParameterf(namedTexture, GL_TEXTURE_MIN_FILTER, static_cast<GLfloat>(GL_LINEAR));
|
||||
MG_Impl::GLImpl::TextureParameterf(namedTexture, GL_TEXTURE_MAG_FILTER, static_cast<GLfloat>(GL_NEAREST));
|
||||
MG_Impl::GLImpl::TextureParameterf(namedTexture, GL_DEPTH_STENCIL_TEXTURE_MODE,
|
||||
static_cast<GLfloat>(GL_DEPTH_COMPONENT));
|
||||
|
||||
GLint namedMinFilter = 0;
|
||||
GLint namedMagFilter = 0;
|
||||
GLint boundMinFilter = 0;
|
||||
GLint boundMagFilter = 0;
|
||||
MG_Impl::GLImpl::GetTextureParameteriv(namedTexture, GL_TEXTURE_MIN_FILTER, &namedMinFilter);
|
||||
MG_Impl::GLImpl::GetTextureParameteriv(namedTexture, GL_TEXTURE_MAG_FILTER, &namedMagFilter);
|
||||
MG_Impl::GLImpl::GetTextureParameteriv(boundTexture, GL_TEXTURE_MIN_FILTER, &boundMinFilter);
|
||||
MG_Impl::GLImpl::GetTextureParameteriv(boundTexture, GL_TEXTURE_MAG_FILTER, &boundMagFilter);
|
||||
|
||||
EXPECT_EQ(namedMinFilter, GL_LINEAR);
|
||||
EXPECT_EQ(namedMagFilter, GL_NEAREST);
|
||||
EXPECT_EQ(boundMinFilter, GL_NEAREST_MIPMAP_LINEAR);
|
||||
EXPECT_EQ(boundMagFilter, GL_LINEAR);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetTextureUnitObject(0).GetBindingSlot(TextureTarget::Texture2D).GetBoundObject(),
|
||||
boundObjectBefore);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(TextureTest, NormalizeDepth24Stencil8UsesPackedDepthStencilType) {
|
||||
GLenum internalFormat = 0;
|
||||
GLenum format = 0;
|
||||
GLenum type = 0;
|
||||
MG_Util::TextureFormatProcessor::NormalizePixelFormat(GL_DEPTH24_STENCIL8,
|
||||
PixelFormatNormalizeOptionBit::None,
|
||||
&internalFormat, &format, &type);
|
||||
|
||||
EXPECT_EQ(internalFormat, GL_DEPTH24_STENCIL8);
|
||||
EXPECT_EQ(format, GL_DEPTH_STENCIL);
|
||||
EXPECT_EQ(type, GL_UNSIGNED_INT_24_8);
|
||||
}
|
||||
@@ -272,6 +272,102 @@ TEST_F(GeneralVertexArrayTest, General_VAOLifecycle) {
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralVertexArrayTest, General_CreateVertexArraysCreatesObjectsWithoutChangingBinding) {
|
||||
GLuint bound = CreateVAO();
|
||||
auto boundObj = MG_State::pGLContext->GetBoundVertexArray();
|
||||
ASSERT_NE(boundObj, nullptr);
|
||||
|
||||
GLuint vaos[2] = {};
|
||||
CreateVertexArrays(2, vaos);
|
||||
|
||||
EXPECT_NE(vaos[0], 0u);
|
||||
EXPECT_NE(vaos[1], 0u);
|
||||
EXPECT_NE(vaos[0], vaos[1]);
|
||||
EXPECT_EQ(IsVertexArray(vaos[0]), GL_TRUE);
|
||||
EXPECT_EQ(IsVertexArray(vaos[1]), GL_TRUE);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetBoundVertexArray(), boundObj);
|
||||
|
||||
DeleteVertexArrays(2, vaos);
|
||||
DeleteVertexArrays(1, &bound);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralVertexArrayTest, General_CreateVertexArraysRejectsNegativeCount) {
|
||||
GLuint vao = 0;
|
||||
CreateVertexArrays(-1, &vao);
|
||||
EXPECT_EQ(GetError(), GL_INVALID_VALUE);
|
||||
}
|
||||
|
||||
TEST_F(GeneralVertexArrayTest, General_DirectStateAccessConfiguresNamedVAOWithoutChangingBinding) {
|
||||
GLuint bound = CreateVAO();
|
||||
auto boundObj = MG_State::pGLContext->GetBoundVertexArray();
|
||||
ASSERT_NE(boundObj, nullptr);
|
||||
|
||||
GLuint vao = 0;
|
||||
CreateVertexArrays(1, &vao);
|
||||
|
||||
GLuint vertexBuffer = 0;
|
||||
GLuint indexBuffer = 0;
|
||||
CreateBuffers(1, &vertexBuffer);
|
||||
CreateBuffers(1, &indexBuffer);
|
||||
NamedBufferData(vertexBuffer, 256, nullptr, GL_STATIC_DRAW);
|
||||
NamedBufferData(indexBuffer, 128, nullptr, GL_STATIC_DRAW);
|
||||
|
||||
VertexArrayVertexBuffer(vao, 2, vertexBuffer, 16, 24);
|
||||
VertexArrayAttribFormat(vao, 2, 3, GL_FLOAT, GL_TRUE, 12);
|
||||
EnableVertexArrayAttrib(vao, 2);
|
||||
VertexArrayElementBuffer(vao, indexBuffer);
|
||||
|
||||
auto vaoObj = MG_State::pGLContext->GetVertexArrayObject(vao);
|
||||
ASSERT_NE(vaoObj, nullptr);
|
||||
|
||||
const auto& attr = vaoObj->GetAttribute(2);
|
||||
EXPECT_TRUE(attr.Enabled);
|
||||
EXPECT_EQ(attr.Size, 3);
|
||||
EXPECT_EQ(attr.Type, DataType::Float32);
|
||||
EXPECT_TRUE(attr.Normalized);
|
||||
EXPECT_FALSE(attr.IsInteger);
|
||||
EXPECT_EQ(attr.Stride, 24);
|
||||
EXPECT_EQ(attr.Offset, 12);
|
||||
EXPECT_EQ(attr.Buffer, MG_State::pGLContext->GetBufferObject(vertexBuffer));
|
||||
EXPECT_EQ(vaoObj->GetIndexBufferBindingSlot().GetBoundObject(), MG_State::pGLContext->GetBufferObject(indexBuffer));
|
||||
EXPECT_EQ(MG_State::pGLContext->GetBoundVertexArray(), boundObj);
|
||||
|
||||
DeleteVertexArrays(1, &vao);
|
||||
DeleteVertexArrays(1, &bound);
|
||||
GLuint buffers[] = {vertexBuffer, indexBuffer};
|
||||
DeleteBuffers(2, buffers);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralVertexArrayTest, General_DirectStateAccessIntegerAttribAndUnbindElementBuffer) {
|
||||
GLuint vao = 0;
|
||||
GLuint indexBuffer = 0;
|
||||
CreateVertexArrays(1, &vao);
|
||||
CreateBuffers(1, &indexBuffer);
|
||||
|
||||
VertexArrayAttribIFormat(vao, 1, 4, GL_UNSIGNED_INT, 8);
|
||||
EnableVertexArrayAttrib(vao, 1);
|
||||
VertexArrayElementBuffer(vao, indexBuffer);
|
||||
VertexArrayElementBuffer(vao, 0);
|
||||
|
||||
auto vaoObj = MG_State::pGLContext->GetVertexArrayObject(vao);
|
||||
ASSERT_NE(vaoObj, nullptr);
|
||||
|
||||
const auto& attr = vaoObj->GetAttribute(1);
|
||||
EXPECT_TRUE(attr.Enabled);
|
||||
EXPECT_EQ(attr.Size, 4);
|
||||
EXPECT_EQ(attr.Type, DataType::Uint32);
|
||||
EXPECT_TRUE(attr.IsInteger);
|
||||
EXPECT_FALSE(attr.Normalized);
|
||||
EXPECT_EQ(attr.Offset, 8);
|
||||
EXPECT_EQ(vaoObj->GetIndexBufferBindingSlot().GetBoundObject(), nullptr);
|
||||
|
||||
DeleteVertexArrays(1, &vao);
|
||||
DeleteBuffers(1, &indexBuffer);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralVertexArrayTest, General_VertexAttributeConfiguration) {
|
||||
GLuint vao = CreateVAO();
|
||||
GLuint vbo = CreateVBO(GL_ARRAY_BUFFER, 128);
|
||||
@@ -318,6 +414,69 @@ TEST_F(GeneralVertexArrayTest, General_IndexBufferBinding) {
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralVertexArrayTest, General_ElementArrayBufferBindingIsVaoLocalAndZeroUnbinds) {
|
||||
GLuint vao1 = CreateVAO();
|
||||
|
||||
GLuint ebo1;
|
||||
GenBuffers(1, &ebo1);
|
||||
BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo1);
|
||||
|
||||
GLint binding = -1;
|
||||
GetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &binding);
|
||||
EXPECT_EQ(binding, static_cast<GLint>(ebo1));
|
||||
|
||||
auto vaoObj1 = MG_State::pGLContext->GetVertexArrayObject(vao1);
|
||||
ASSERT_NE(vaoObj1, nullptr);
|
||||
EXPECT_EQ(vaoObj1->GetIndexBufferBindingSlot().GetBoundObject(), MG_State::pGLContext->GetBufferObject(ebo1));
|
||||
|
||||
GLuint vao2 = CreateVAO();
|
||||
auto vaoObj2 = MG_State::pGLContext->GetVertexArrayObject(vao2);
|
||||
ASSERT_NE(vaoObj2, nullptr);
|
||||
GetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &binding);
|
||||
EXPECT_EQ(binding, 0);
|
||||
EXPECT_EQ(vaoObj2->GetIndexBufferBindingSlot().GetBoundObject(), nullptr);
|
||||
|
||||
BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetBufferObject(0), nullptr);
|
||||
EXPECT_EQ(IsBuffer(0), GL_FALSE);
|
||||
|
||||
BindVertexArray(vao1);
|
||||
GetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &binding);
|
||||
EXPECT_EQ(binding, static_cast<GLint>(ebo1));
|
||||
|
||||
BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
GetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &binding);
|
||||
EXPECT_EQ(binding, 0);
|
||||
EXPECT_EQ(vaoObj1->GetIndexBufferBindingSlot().GetBoundObject(), nullptr);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetBufferObject(0), nullptr);
|
||||
EXPECT_EQ(IsBuffer(0), GL_FALSE);
|
||||
|
||||
DeleteVertexArrays(1, &vao1);
|
||||
DeleteVertexArrays(1, &vao2);
|
||||
DeleteBuffers(1, &ebo1);
|
||||
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralVertexArrayTest, General_ClientSideVertexAttribPointerIsAccepted) {
|
||||
GLuint vao = CreateVAO();
|
||||
BindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
float vertices[] = {0.0f, 0.0f, 1.0f, 1.0f};
|
||||
VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices);
|
||||
EnableVertexAttribArray(0);
|
||||
|
||||
auto vaoObj = MG_State::pGLContext->GetVertexArrayObject(vao);
|
||||
ASSERT_NE(vaoObj, nullptr);
|
||||
|
||||
const auto& attr = vaoObj->GetAttribute(0);
|
||||
EXPECT_TRUE(attr.Enabled);
|
||||
EXPECT_EQ(attr.Buffer, nullptr);
|
||||
EXPECT_EQ(attr.Offset, reinterpret_cast<SizeT>(vertices));
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralVertexArrayTest, General_IntegerAttributes) {
|
||||
GLuint vao = CreateVAO();
|
||||
GLuint vbo = CreateVBO(GL_ARRAY_BUFFER, 128);
|
||||
@@ -365,15 +524,18 @@ TEST_F(GeneralVertexArrayTest, General_StatePreservation) {
|
||||
}
|
||||
|
||||
TEST_F(GeneralVertexArrayTest, General_ErrorConditions) {
|
||||
ASSERT_NE(MG_State::pGLContext->GetBoundVertexArray(), nullptr);
|
||||
BindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
VertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
|
||||
EXPECT_EQ(GetError(), GL_INVALID_OPERATION);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
|
||||
GLuint vao = CreateVAO();
|
||||
EnableVertexAttribArray(MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS);
|
||||
EXPECT_EQ(GetError(), GL_INVALID_VALUE);
|
||||
|
||||
BindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
VertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
|
||||
EXPECT_EQ(GetError(), GL_INVALID_OPERATION);
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
|
||||
GLuint vbo = CreateVBO(GL_ARRAY_BUFFER, 64);
|
||||
VertexAttribPointer(0, 3, 0xFFFFFFFF, GL_FALSE, 0, nullptr);
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
#if !defined(__WIN32) && !defined(_WIN32) && !defined(__APPLE__)
|
||||
static const String LibPathPrefixes[] = {
|
||||
"/opt/vc/lib/", "/usr/local/lib/", "/usr/lib/", "/usr/lib/x86_64-linux-gnu/",
|
||||
"/usr/lib64/", "/lib64/",
|
||||
"" // We should put this to the end of the list to avoid breaking `LD_LIBRARY_PATH` usage
|
||||
};
|
||||
|
||||
@@ -311,6 +312,7 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
INIT_GLES_FUNC(glFramebufferParameteri)
|
||||
INIT_GLES_FUNC(glGetFramebufferParameteriv)
|
||||
INIT_GLES_FUNC(glGetProgramInterfaceiv)
|
||||
INIT_GLES_FUNC(glShaderStorageBlockBinding)
|
||||
INIT_GLES_FUNC(glGetProgramResourceIndex)
|
||||
INIT_GLES_FUNC(glGetProgramResourceName)
|
||||
INIT_GLES_FUNC(glGetProgramResourceiv)
|
||||
|
||||
@@ -447,6 +447,8 @@ namespace MobileGL {
|
||||
GL_FUNC_TYPEDEF(void, glGetFramebufferParameteriv, GLenum target, GLenum pname, GLint* params)
|
||||
GL_FUNC_TYPEDEF(void, glGetProgramInterfaceiv, GLuint program, GLenum programInterface, GLenum pname,
|
||||
GLint* params)
|
||||
GL_FUNC_TYPEDEF(void, glShaderStorageBlockBinding, GLuint program, GLuint storageBlockIndex,
|
||||
GLuint storageBlockBinding)
|
||||
GL_FUNC_TYPEDEF(GLuint, glGetProgramResourceIndex, GLuint program, GLenum programInterface,
|
||||
const GLchar* name)
|
||||
GL_FUNC_TYPEDEF(void, glGetProgramResourceName, GLuint program, GLenum programInterface, GLuint index,
|
||||
@@ -884,6 +886,7 @@ namespace MobileGL {
|
||||
GL_FUNC_DECL(glFramebufferParameteri)
|
||||
GL_FUNC_DECL(glGetFramebufferParameteriv)
|
||||
GL_FUNC_DECL(glGetProgramInterfaceiv)
|
||||
GL_FUNC_DECL(glShaderStorageBlockBinding)
|
||||
GL_FUNC_DECL(glGetProgramResourceIndex)
|
||||
GL_FUNC_DECL(glGetProgramResourceName)
|
||||
GL_FUNC_DECL(glGetProgramResourceiv)
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
#include "Loader.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace MobileGL::MG_Util::BackendLoader {
|
||||
namespace {
|
||||
struct VulkanDynamicFunctions {
|
||||
@@ -33,6 +36,14 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
Bool IsShaderSubgroupForcedDisabled() {
|
||||
const char* value = std::getenv("MOBILEGL_DISABLE_SUBGROUP");
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
return std::strcmp(value, "true") == 0 || std::strcmp(value, "TRUE") == 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
inline Version DecodeApiVersion(uint32_t version) {
|
||||
@@ -46,6 +57,12 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline Bool HasUsableShaderSubgroupSupport(const VkPhysicalDeviceSubgroupProperties& subgroupProps) {
|
||||
return subgroupProps.subgroupSize > 0 &&
|
||||
(subgroupProps.supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0 &&
|
||||
(subgroupProps.supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) != 0;
|
||||
}
|
||||
|
||||
Bool QueryVulkanCapabilities(MobileGL::MG_External::VulkanCapabilities& caps, VkInstance instance,
|
||||
VkPhysicalDevice physicalDevice) {
|
||||
if (!physicalDevice) {
|
||||
@@ -69,8 +86,12 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
return false;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceSubgroupProperties subgroupProps{};
|
||||
subgroupProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
|
||||
|
||||
VkPhysicalDeviceProperties2 props2{};
|
||||
props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||
props2.pNext = &subgroupProps;
|
||||
if (vk.vkGetPhysicalDeviceProperties2) {
|
||||
vk.vkGetPhysicalDeviceProperties2(physicalDevice, &props2);
|
||||
} else {
|
||||
@@ -83,6 +104,29 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
caps.DeviceName = p.deviceName;
|
||||
caps.DriverVersionString = DecodeDriverVersion(p.driverVersion);
|
||||
caps.UniformBufferOffsetAlignment = static_cast<int>(p.limits.minUniformBufferOffsetAlignment);
|
||||
caps.MaxShaderStorageBlockSize = static_cast<SizeT>(p.limits.maxStorageBufferRange);
|
||||
const Bool supportsShaderSubgroup = vk.vkGetPhysicalDeviceProperties2 &&
|
||||
HasUsableShaderSubgroupSupport(subgroupProps);
|
||||
const Bool forceDisableShaderSubgroup = IsShaderSubgroupForcedDisabled();
|
||||
caps.SupportsShaderSubgroup = supportsShaderSubgroup && !forceDisableShaderSubgroup;
|
||||
if (caps.SupportsShaderSubgroup) {
|
||||
caps.SubgroupSize = subgroupProps.subgroupSize;
|
||||
caps.SubgroupSupportedStages = subgroupProps.supportedStages;
|
||||
caps.SubgroupSupportedOperations = subgroupProps.supportedOperations;
|
||||
caps.SubgroupQuadOperationsInAllStages = subgroupProps.quadOperationsInAllStages == VK_TRUE;
|
||||
} else {
|
||||
caps.SubgroupSize = 0;
|
||||
caps.SubgroupSupportedStages = 0;
|
||||
caps.SubgroupSupportedOperations = 0;
|
||||
caps.SubgroupQuadOperationsInAllStages = false;
|
||||
}
|
||||
|
||||
MGLOG_I("Vulkan shader subgroup support: detected=%s advertised=%s size=%u stages=0x%x operations=0x%x",
|
||||
supportsShaderSubgroup ? "true" : "false", caps.SupportsShaderSubgroup ? "true" : "false",
|
||||
subgroupProps.subgroupSize, subgroupProps.supportedStages, subgroupProps.supportedOperations);
|
||||
if (supportsShaderSubgroup && forceDisableShaderSubgroup) {
|
||||
MGLOG_W("Vulkan shader subgroup support forced off by MOBILEGL_DISABLE_SUBGROUP");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -93,5 +137,11 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
caps.DeviceName = properties.deviceName;
|
||||
caps.DriverVersionString = DecodeDriverVersion(properties.driverVersion);
|
||||
caps.UniformBufferOffsetAlignment = static_cast<int>(properties.limits.minUniformBufferOffsetAlignment);
|
||||
caps.MaxShaderStorageBlockSize = static_cast<SizeT>(properties.limits.maxStorageBufferRange);
|
||||
caps.SupportsShaderSubgroup = false;
|
||||
caps.SubgroupSize = 0;
|
||||
caps.SubgroupSupportedStages = 0;
|
||||
caps.SubgroupSupportedOperations = 0;
|
||||
caps.SubgroupQuadOperationsInAllStages = false;
|
||||
}
|
||||
} // namespace MobileGL::MG_Util::BackendLoader
|
||||
|
||||
@@ -16,6 +16,12 @@ namespace MobileGL {
|
||||
String DeviceName;
|
||||
String DriverVersionString;
|
||||
Int UniformBufferOffsetAlignment = 256;
|
||||
SizeT MaxShaderStorageBlockSize = 128 * 1024 * 1024;
|
||||
Bool SupportsShaderSubgroup = false;
|
||||
Uint32 SubgroupSize = 0;
|
||||
Uint32 SubgroupSupportedStages = 0;
|
||||
Uint32 SubgroupSupportedOperations = 0;
|
||||
Bool SubgroupQuadOperationsInAllStages = false;
|
||||
};
|
||||
} // namespace MG_External
|
||||
namespace MG_Util::BackendLoader {
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace MobileGL {
|
||||
return BufferTarget::DispatchIndirect;
|
||||
case GL_DRAW_INDIRECT_BUFFER:
|
||||
return BufferTarget::DrawIndirect;
|
||||
case GL_PARAMETER_BUFFER_ARB:
|
||||
return BufferTarget::Parameter;
|
||||
case GL_SHADER_STORAGE_BUFFER:
|
||||
return BufferTarget::ShaderStorage;
|
||||
case GL_UNKNOWN_MGL:
|
||||
@@ -84,4 +86,4 @@ namespace MobileGL {
|
||||
return result;
|
||||
}
|
||||
} // namespace MG_Util
|
||||
} // namespace MobileGL
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -45,6 +45,23 @@ namespace MobileGL {
|
||||
}
|
||||
}
|
||||
|
||||
BlendEquation ConvertGLEnumToBlendEquation(GLenum v) {
|
||||
switch (v) {
|
||||
case GL_FUNC_ADD:
|
||||
return BlendEquation::Add;
|
||||
case GL_FUNC_SUBTRACT:
|
||||
return BlendEquation::Subtract;
|
||||
case GL_FUNC_REVERSE_SUBTRACT:
|
||||
return BlendEquation::ReverseSubtract;
|
||||
case GL_MIN:
|
||||
return BlendEquation::Min;
|
||||
case GL_MAX:
|
||||
return BlendEquation::Max;
|
||||
default:
|
||||
return BlendEquation::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
DepthTestFunc ConvertGLEnumToDepthTestFunc(GLenum v) {
|
||||
switch (v) {
|
||||
case GL_NEVER:
|
||||
@@ -120,6 +137,28 @@ namespace MobileGL {
|
||||
}
|
||||
}
|
||||
|
||||
FrontFaceMode ConvertGLEnumToFrontFaceMode(GLenum v) {
|
||||
switch (v) {
|
||||
case GL_CCW:
|
||||
return FrontFaceMode::CounterClockwise;
|
||||
case GL_CW:
|
||||
return FrontFaceMode::Clockwise;
|
||||
default:
|
||||
return FrontFaceMode::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
ProvokingVertexMode ConvertGLEnumToProvokingVertexMode(GLenum v) {
|
||||
switch (v) {
|
||||
case GL_FIRST_VERTEX_CONVENTION:
|
||||
return ProvokingVertexMode::FirstVertex;
|
||||
case GL_LAST_VERTEX_CONVENTION:
|
||||
return ProvokingVertexMode::LastVertex;
|
||||
default:
|
||||
return ProvokingVertexMode::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
CapabilityInput ConvertGLEnumToCapabilityInput(GLenum v) {
|
||||
switch (v) {
|
||||
case GL_BLEND:
|
||||
@@ -197,4 +236,4 @@ namespace MobileGL {
|
||||
}
|
||||
}
|
||||
} // namespace MG_Util
|
||||
} // namespace MobileGL
|
||||
} // namespace MobileGL
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user