diff --git a/CMakeLists.txt b/CMakeLists.txt index 5902a732..485bc8d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project("MobileGL") enable_language(CXX) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -118,4 +118,4 @@ if (PROFILING) add_library(perfetto STATIC ${CMAKE_SOURCE_DIR}/3rdparty/perfetto/sdk/perfetto.cc) target_link_libraries(MobileGL perfetto ${CMAKE_THREAD_LIBS_INIT}) target_compile_definitions(MobileGL PUBLIC PROFILING=1) -endif() \ No newline at end of file +endif() diff --git a/MG/Constants.h b/MG/Constants.h index acfec821..5f58509e 100644 --- a/MG/Constants.h +++ b/MG/Constants.h @@ -5,6 +5,12 @@ #ifndef MOBILEGL_CONSTANTS_H #define MOBILEGL_CONSTANTS_H +#include +#include +#include +#include +#include + #ifdef __ANDROID__ #define __ANDROID_API__ 26 #endif @@ -15,10 +21,13 @@ #define MG_EXPORT extern "C" __attribute__((visibility("default"))) #endif -#include -#include -#include -#include +namespace ankerl { + template + using unordered_map = ankerl::unordered_dense::map; + + template + using unordered_set = ankerl::unordered_dense::set; +} namespace MG_Constants { namespace Common { @@ -30,7 +39,7 @@ namespace MG_Constants { } namespace Blend { - static const std::unordered_set VALID_FACTORS = { + static const ankerl::unordered_set VALID_FACTORS = { GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR, @@ -39,51 +48,51 @@ namespace MG_Constants { } namespace Depth { - static const std::unordered_set VALID_FUNCS = { + static const ankerl::unordered_set VALID_FUNCS = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS }; // OpenGL 3 } namespace CommonState { - static const std::unordered_set VALID_CAPS = { + static const ankerl::unordered_set VALID_CAPS = { GL_BLEND, GL_DEPTH_TEST, GL_STENCIL_TEST, GL_SCISSOR_TEST, GL_CULL_FACE, GL_POLYGON_OFFSET_FILL, GL_SAMPLE_ALPHA_TO_COVERAGE, GL_SAMPLE_COVERAGE }; // OpenGL 3 } namespace Framebuffer { - static const std::unordered_set VALID_ATTACHMENTS = { + static const ankerl::unordered_set VALID_ATTACHMENTS = { GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT, GL_DEPTH_STENCIL_ATTACHMENT }; // OpenGL 3 - static const std::unordered_set VALID_TARGETS = { + static const ankerl::unordered_set VALID_TARGETS = { GL_FRAMEBUFFER, GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER }; // OpenGL 3 - static const std::unordered_set VALID_ACCESS = { + static const ankerl::unordered_set VALID_ACCESS = { GL_READ_ONLY, GL_WRITE_ONLY, GL_READ_WRITE }; // OpenGL 3 } namespace Buffer { - static const std::unordered_set VALID_PARAM_NAMES = { + static const ankerl::unordered_set VALID_PARAM_NAMES = { GL_BUFFER_ACCESS, GL_BUFFER_MAPPED, GL_BUFFER_SIZE, GL_BUFFER_USAGE }; // OpenGL 3 - static const std::unordered_set VALID_TARGETS = { + static const ankerl::unordered_set VALID_TARGETS = { GL_ARRAY_BUFFER, GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, GL_TEXTURE_BUFFER, GL_TRANSFORM_FEEDBACK_BUFFER, GL_UNIFORM_BUFFER }; // OpenGL 3 - static const std::unordered_set VALID_ACCESS = { + static const ankerl::unordered_set VALID_ACCESS = { GL_READ_ONLY, GL_WRITE_ONLY, GL_READ_WRITE }; // OpenGL 3 } namespace PixelStore { - static const std::unordered_map DEFAULT_VALUES_MAP = { + static const ankerl::unordered_map DEFAULT_VALUES_MAP = { {GL_PACK_SWAP_BYTES, GL_FALSE}, {GL_PACK_LSB_FIRST, GL_FALSE}, {GL_PACK_ROW_LENGTH, 0}, @@ -102,7 +111,7 @@ namespace MG_Constants { {GL_UNPACK_ALIGNMENT, 4} }; // OpenGL 3 - static const std::unordered_set VALID_PARAM_NAMES = { + static const ankerl::unordered_set VALID_PARAM_NAMES = { GL_PACK_SWAP_BYTES, GL_PACK_LSB_FIRST, GL_PACK_ROW_LENGTH, GL_PACK_IMAGE_HEIGHT, GL_PACK_SKIP_ROWS, GL_PACK_SKIP_PIXELS, GL_PACK_SKIP_IMAGES, GL_PACK_ALIGNMENT, GL_UNPACK_SWAP_BYTES, GL_UNPACK_LSB_FIRST, GL_UNPACK_ROW_LENGTH, @@ -116,18 +125,18 @@ namespace MG_Constants { inline const GLuint MAX_TEXTURE_UNITS = 80; const GLsizei MAX_TEXTURE_SIZE = 32768; const GLsizei MAX_ARRAY_LAYERS = 256; - inline const std::unordered_set VALID_TARGETS = { + inline const ankerl::unordered_set VALID_TARGETS = { GL_TEXTURE_2D, GL_PROXY_TEXTURE_2D, GL_TEXTURE_1D_ARRAY, GL_PROXY_TEXTURE_1D_ARRAY, GL_TEXTURE_RECTANGLE, GL_PROXY_TEXTURE_RECTANGLE, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, GL_PROXY_TEXTURE_CUBE_MAP }; // OpenGL 3 - inline const std::unordered_set VALID_FORMATS = { + inline const ankerl::unordered_set VALID_FORMATS = { GL_RED, GL_RG, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL }; // OpenGL 3 - inline const std::unordered_set VALID_INTERNAL_FORMATS = { + inline const ankerl::unordered_set VALID_INTERNAL_FORMATS = { GL_RED, GL_RG, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL, GL_RGBA32F, GL_RGBA32I, GL_RGBA32UI, GL_RGBA16, GL_RGBA16F, GL_RGBA16I, GL_RGBA16UI, GL_RGBA8, GL_RGBA8UI, GL_SRGB8_ALPHA8, GL_RGB10_A2, GL_RGB10_A2UI, @@ -137,12 +146,12 @@ namespace MG_Constants { GL_RGB32F, GL_RGB32I, GL_RGB32UI, GL_RGB16_SNORM, GL_RGB16F, GL_RGB16I, GL_RGB16UI, GL_RGB16, GL_RGB8_SNORM, GL_RGB8, GL_RGB8I, GL_RGB8UI, GL_SRGB8, GL_RGB9_E5, GL_RG16_SNORM, GL_RG8_SNORM, GL_COMPRESSED_RG_RGTC2, GL_COMPRESSED_SIGNED_RG_RGTC2, - GL_R16_SNORM, GL_R8_SNORM, GL_COMPRESSED_RED_RGTC1, GL_COMPRESSED_SIGNED_RED_RGTC1, - GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT16, GL_DEPTH32F_STENCIL8, - GL_DEPTH24_STENCIL8 + GL_R16_SNORM, GL_R8_SNORM, GL_COMPRESSED_RED_RGTC1, GL_COMPRESSED_SIGNED_RED_RGTC1, + GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT16, + GL_DEPTH32F_STENCIL8, GL_DEPTH24_STENCIL8 }; // OpenGL 3 - inline const std::unordered_set VALID_TYPES = { + inline const ankerl::unordered_set VALID_TYPES = { GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT, GL_FLOAT, GL_UNSIGNED_BYTE_3_3_2, GL_UNSIGNED_BYTE_2_3_3_REV, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_5_6_5_REV, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_4_4_4_4_REV, @@ -150,14 +159,14 @@ namespace MG_Constants { GL_UNSIGNED_INT_8_8_8_8_REV, GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_INT_2_10_10_10_REV }; // OpenGL 3 - inline const std::unordered_set VALID_TEXTURE_PARAM_NAMES = { + inline const ankerl::unordered_set VALID_TEXTURE_PARAM_NAMES = { GL_TEXTURE_BASE_LEVEL, GL_TEXTURE_COMPARE_FUNC, GL_TEXTURE_COMPARE_MODE, GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER, GL_TEXTURE_MAX_LEVEL, GL_TEXTURE_SWIZZLE_R, GL_TEXTURE_SWIZZLE_G, GL_TEXTURE_SWIZZLE_B, GL_TEXTURE_SWIZZLE_A, GL_TEXTURE_SWIZZLE_RGBA, GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, GL_TEXTURE_WRAP_R, GL_TEXTURE_LOD_BIAS, GL_TEXTURE_MIN_LOD, GL_TEXTURE_MAX_LOD, GL_TEXTURE_BORDER_COLOR }; // OpenGL 3 - inline const std::unordered_set VALID_QUERY_LEVEL_PROPERTY_PARAM_NAMES = { + inline const ankerl::unordered_set VALID_QUERY_LEVEL_PROPERTY_PARAM_NAMES = { GL_TEXTURE_WIDTH, GL_TEXTURE_HEIGHT, GL_TEXTURE_DEPTH, GL_TEXTURE_INTERNAL_FORMAT, GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE, GL_TEXTURE_DEPTH_SIZE, GL_TEXTURE_COMPRESSED, GL_TEXTURE_COMPRESSED_IMAGE_SIZE diff --git a/MG/Global.h b/MG/Global.h index 2fb584b4..c4226369 100644 --- a/MG/Global.h +++ b/MG/Global.h @@ -27,7 +27,7 @@ namespace MG_Global { } namespace Common { - inline const int LogLevel = MG_Constants::Common::LOG_LEVEL_DEBUG; + inline constexpr int LogLevel = MG_Constants::Common::LOG_LEVEL_INFO; #ifdef __ANDROID__ inline const char* LOG_FILE_PATH = "/sdcard/MG/latest.log"; diff --git a/MG/Includes.h b/MG/Includes.h index 287a8f6e..6763919c 100644 --- a/MG/Includes.h +++ b/MG/Includes.h @@ -100,6 +100,7 @@ #include #include #include +#include #include #include #include @@ -107,7 +108,8 @@ #include #include #include -#include "GLES3/gl32.h" +#include +#include #include "MG_Include/UncertainBool.hpp" diff --git a/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.cpp b/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.cpp index 8e3da8b5..31273952 100644 --- a/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.cpp +++ b/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.cpp @@ -11,9 +11,9 @@ std::atomic g_nextSurfaceId{1}; EGLenum g_currentAPI = EGL_OPENGL_ES_API; std::mutex g_globalMutex; -std::unordered_map g_displays; -std::unordered_map g_surfaces; -std::unordered_map g_contexts; +ankerl::unordered_map g_displays; +ankerl::unordered_map g_surfaces; +ankerl::unordered_map g_contexts; EGLint g_lastError = EGL_SUCCESS; thread_local EGLContext tls_currentContext = EGL_NO_CONTEXT; diff --git a/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.h b/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.h index 1274fa22..71728b96 100644 --- a/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.h +++ b/MG/MG_GL/Implementations/EGL/VK/EGL_EMU.h @@ -69,9 +69,9 @@ extern std::atomic g_nextSurfaceId; extern EGLenum g_currentAPI; extern std::mutex g_globalMutex; -extern std::unordered_map g_displays; -extern std::unordered_map g_surfaces; -extern std::unordered_map g_contexts; +extern ankerl::unordered_map g_displays; +extern ankerl::unordered_map g_surfaces; +extern ankerl::unordered_map g_contexts; extern EGLint g_lastError; extern thread_local EGLContext tls_currentContext; diff --git a/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.cpp b/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.cpp index f6d567d9..a878e6cc 100644 --- a/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.cpp +++ b/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.cpp @@ -5,41 +5,98 @@ #include "GL_Buffer.h" namespace MG_GL::GL { + void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, + GLbitfield access) { + MG_Util::Debug::LogD("glMapBufferRange, target: %s, offset: %lld, length: %lld, access: 0x%X", + MG_Util::Debug::GLEnumToString(target), + static_cast(offset), + static_cast(length), + access); + void* mappedPointer = nullptr; + GLenum result = MG_State::AcquireBufferMemoryRange(target, offset, length, access, &mappedPointer); + + if (result == GL_NO_ERROR) { + MG_Util::Debug::LogD("Mapped pointer: %p", mappedPointer); + return mappedPointer; + } + MG_State::SetError(result); + MG_Util::Debug::LogE("Error mapping buffer range: %s", MG_Util::Debug::GLEnumToString(result)); + return nullptr; + } + + void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) { + MG_Util::Debug::LogD("glFlushMappedBufferRange, target: %s, offset: %lld, length: %lld", + MG_Util::Debug::GLEnumToString(target), + static_cast(offset), + static_cast(length)); + GLenum result = MG_State::SyncBufferMemory(target, offset, length); + if (result == GL_NO_ERROR) { + return; + } + MG_State::SetError(result); + MG_Util::Debug::LogE("Error flushing mapped buffer range: %s", + MG_Util::Debug::GLEnumToString(result)); + } + + void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size) { + MG_Util::Debug::LogD("glCopyBufferSubData, readTarget: %s, writeTarget: %s, " + "readOffset: %lld, writeOffset: %lld, size: %lld", + MG_Util::Debug::GLEnumToString(readTarget), + MG_Util::Debug::GLEnumToString(writeTarget), + static_cast(readOffset), + static_cast(writeOffset), + static_cast(size)); + GLenum result = MG_State::CopyBufferRange(readTarget, writeTarget, readOffset, writeOffset, size); + if (result == GL_NO_ERROR) { + return; + } + MG_State::SetError(result); + MG_Util::Debug::LogE("Error copying buffer subdata: %s", + MG_Util::Debug::GLEnumToString(result)); + } + void* MapBuffer(GLenum target, GLenum access) { MG_Util::Debug::LogD("glMapBuffer(target=0x%x, access=0x%x)", target, access); - void* mappedPtr = nullptr; GLenum err = MG_State::AcquireBufferMemory(target, access, &mappedPtr); - if (err != GL_NO_ERROR) { MG_State::SetError(err); - MG_Util::Debug::LogE("glMapBuffer failed: %s", - MG_Util::Debug::GLEnumToString(err)); + MG_Util::Debug::LogE("glMapBuffer failed: %s", MG_Util::Debug::GLEnumToString(err)); return nullptr; } - MG_Util::Debug::LogD("glMapBuffer returns %p", mappedPtr); return mappedPtr; } GLboolean UnmapBuffer(GLenum target) { MG_Util::Debug::LogD("glUnmapBuffer(target=0x%x)", target); - GLenum err = MG_State::ReleaseBufferMemory(target); if (err != GL_NO_ERROR) { MG_State::SetError(err); - MG_Util::Debug::LogE("glUnmapBuffer failed: %s", - MG_Util::Debug::GLEnumToString(err)); + MG_Util::Debug::LogE("glUnmapBuffer failed: %s", MG_Util::Debug::GLEnumToString(err)); return GL_FALSE; } - MG_Util::Debug::LogD("glUnmapBuffer succeeded"); return GL_TRUE; } void BindBuffer(GLenum target, GLuint buffer) { - MG_Util::Debug::LogD("glBindBuffer, target: %d, buffer: %d", target, buffer); - if (buffer != 0 && !MG_State::ValidateBufferHandle(buffer)) { + MG_Util::Debug::LogD("glBindBuffer, target: %s, buffer: %d", MG_Util::Debug::GLEnumToString(target), buffer); + if (buffer != 0 && + MG_State::ValidateGeneratedName(buffer) && + !MG_State::ValidateAllocatedBufferHandle(buffer)) { + MG_Util::Debug::LogD("Actually creating buffer: %u", buffer); + GLenum result = MG_State::CreateBuffer(buffer); + if (result != GL_NO_ERROR) { + MG_State::SetError(result); + MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); + return; + } + } + + if (buffer != 0 && !MG_State::ValidateAllocatedBufferHandle(buffer)) { MG_State::SetError(GL_INVALID_VALUE); MG_Util::Debug::LogE("Invalid buffer handle: %u", buffer); return; @@ -52,8 +109,8 @@ namespace MG_GL::GL { } void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) { - MG_Util::Debug::LogD("glBufferData, target: %d, size: %zd, data: %p, usage: %d", - target, size, data, usage); + MG_Util::Debug::LogD("glBufferData, target: %s, size: %zd, data: %p, usage: %s", + MG_Util::Debug::GLEnumToString(target), size, data, MG_Util::Debug::GLEnumToString(usage)); GLenum result = MG_State::CommitBufferStorage(target, size, data, usage); if (result == GL_NO_ERROR) return; @@ -80,9 +137,9 @@ namespace MG_GL::GL { return; } - GLenum result = MG_State::CreateBuffers(n, buffers); + GLenum result = MG_State::GenBufferNames(n, buffers); if (result == GL_NO_ERROR) { - MG_Util::Debug::LogD("Generated buffers:"); + MG_Util::Debug::LogD("Generated buffer names:"); for (GLsizei i = 0; i < n; ++i) { MG_Util::Debug::LogD(" Buffer[%d] = %u", i, buffers[i]); } @@ -100,9 +157,32 @@ namespace MG_GL::GL { return GL_FALSE; } - bool isValid = MG_State::ValidateBufferHandle(buffer); + bool isValid = MG_State::ValidateAllocatedBufferHandle(buffer); // Should we report gl error here or in MG_State? MG_Util::Debug::LogD("Buffer %u is %s", buffer, isValid ? "valid" : "invalid"); return isValid ? GL_TRUE : GL_FALSE; } + + void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) { + MG_Util::Debug::LogD("glBufferSubData, target: %s, offset: %lld, size: %lld, data: %p", + MG_Util::Debug::GLEnumToString(target), + static_cast(offset), + static_cast(size), + data); + GLenum result = MG_State::CommitBufferStorageRegion(target, offset, size, data); + if (result != GL_NO_ERROR) { + MG_State::SetError(result); + MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); + } + } + void DeleteBuffers(GLsizei n, const GLuint *buffers) { + MG_Util::Debug::LogD("glDeleteBuffers, n: %d, buffers: %p", n, buffers); + + GLenum result = MG_State::DeleteBuffers(n, buffers); + if (result == GL_NO_ERROR) + return; + + MG_State::SetError(result); + MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); + } } \ No newline at end of file diff --git a/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.h b/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.h index 4ac655eb..029d820d 100644 --- a/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.h +++ b/MG/MG_GL/Implementations/GL/Buffer/GL_Buffer.h @@ -8,12 +8,17 @@ #include "../../../../Includes.h" namespace MG_GL::GL { + void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); + void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length); + void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); void* MapBuffer(GLenum target, GLenum access); GLboolean UnmapBuffer(GLenum target); void BindBuffer(GLenum target, GLuint buffer); void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage); + void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data); void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params); void GenBuffers(GLsizei n, GLuint* buffers); + void DeleteBuffers(GLsizei n, const GLuint *buffers); GLboolean IsBuffer(GLuint buffer); } diff --git a/MG/MG_GL/Implementations/GL/Common/GL_Common.cpp b/MG/MG_GL/Implementations/GL/Common/GL_Common.cpp index b2389138..6e3f5b0d 100644 --- a/MG/MG_GL/Implementations/GL/Common/GL_Common.cpp +++ b/MG/MG_GL/Implementations/GL/Common/GL_Common.cpp @@ -5,6 +5,16 @@ #include "GL_Common.h" namespace MG_GL::GL { + void Clear(GLbitfield mask) { + MG_Util::Debug::LogD("glClear, mask: 0x%X", mask); + GLenum result = MG_State::glClear(mask); + if (result == GL_NO_ERROR) { + return; + } + MG_State::SetError(result); + MG_Util::Debug::LogE("Error clearing buffers: %s", MG_Util::Debug::GLEnumToString(result)); + } + void Enable(GLenum cap) { MG_Util::Debug::LogD("glEnable, cap: %s", MG_Util::Debug::GLEnumToString(cap)); GLenum result = MG_State::glEnable(cap); @@ -43,14 +53,6 @@ namespace MG_GL::GL { MG_Util::Debug::LogE("Error setting separate blend func: %s", MG_Util::Debug::GLEnumToString(result)); } - void Clear(GLbitfield mask) { - MG_Util::Debug::LogD("glClear, mask: 0x%X", mask); - GLenum result = MG_State::glClear(mask); - if (result == GL_NO_ERROR) return; - MG_State::SetError(result); - MG_Util::Debug::LogE("Error clearing buffers: %s", MG_Util::Debug::GLEnumToString(result)); - } - void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { MG_Util::Debug::LogD("glClearColor, rgba: [%.2f, %.2f, %.2f, %.2f]", red, green, blue, alpha); GLenum result = MG_State::glClearColor(red, green, blue, alpha); diff --git a/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp b/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp index 72ea7cbb..290a8706 100644 --- a/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp +++ b/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.cpp @@ -5,13 +5,27 @@ #include "GL_Drawing.h" namespace MG_GL::GL { - // This is a test function that directly draws textures. void DrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) { - ::GLES::glViewport(0,0,3200,1440); - MG_RHI::GLES::Test::DrawAllTextures(); - }; + // TODO + } + void DrawArrays(GLenum mode, GLint first, GLsizei count) { - ::GLES::glViewport(0,0,3200,1440); - MG_RHI::GLES::Test::DrawAllTextures(); - }; + // TODO + } + + void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex) { + // TODO + } + + void MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount) { + // TODO + } + + void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount, const GLint *basevertex) { + // TODO + } + + void DrawBuffer(GLenum buf) { + // TODO + } } \ No newline at end of file diff --git a/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.h b/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.h index 0eff0fcb..923060cb 100644 --- a/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.h +++ b/MG/MG_GL/Implementations/GL/Drawing/GL_Drawing.h @@ -4,12 +4,15 @@ #ifndef MOBILEGL_GL_DRAWING_H #define MOBILEGL_GL_DRAWING_H - #include "../../../../Includes.h" namespace MG_GL::GL { void DrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices); void DrawArrays(GLenum mode, GLint first, GLsizei count); + void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); + void MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount); + void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const *indices, GLsizei drawcount, const GLint *basevertex); + void DrawBuffer(GLenum buf); } #endif //MOBILEGL_GL_DRAWING_H diff --git a/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.cpp b/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.cpp index 7a4945bc..1f64313d 100644 --- a/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.cpp +++ b/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.cpp @@ -45,6 +45,7 @@ namespace MG_GL::GL { GLenum result = MG_State::AttachTexture2DToFramebuffer( target, attachment, textarget, texture, level ); + if (result == GL_NO_ERROR) return; MG_State::SetError(result); MG_Util::Debug::LogE("Texture attachment failed: %s", MG_Util::Debug::GLEnumToString(result)); @@ -64,4 +65,9 @@ namespace MG_GL::GL { MG_Util::Debug::GLEnumToString(result)); return result; } + + void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { + // TODO + } } \ No newline at end of file diff --git a/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.h b/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.h index 712b3289..1ecf9a43 100644 --- a/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.h +++ b/MG/MG_GL/Implementations/GL/Framebuffer/GL_Framebuffer.h @@ -13,6 +13,7 @@ namespace MG_GL::GL { void BindFramebuffer(GLenum target, GLuint framebuffer); void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLenum CheckFramebufferStatus(GLenum target); + void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); } #endif //MOBILEGL_GL_FRAMEBUFFER_H diff --git a/MG/MG_GL/Implementations/GL/GLFuncsDefinitions/GLFuncsDefinitions.cpp b/MG/MG_GL/Implementations/GL/GLFuncsDefinitions/GLFuncsDefinitions.cpp index 062aefcb..9e747e80 100644 --- a/MG/MG_GL/Implementations/GL/GLFuncsDefinitions/GLFuncsDefinitions.cpp +++ b/MG/MG_GL/Implementations/GL/GLFuncsDefinitions/GLFuncsDefinitions.cpp @@ -46,7 +46,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationSeparate, GLenum modeRGB, GLenu 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) -DECLARE_GL_FUNCTION_STUB_HEAD(void, BufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const void *data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BufferSubData, target,offset,size,data) +DECLARE_GL_FUNCTION_HEAD(void, BufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const void *data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BufferSubData, target,offset,size,data) DECLARE_GL_FUNCTION_HEAD(GLenum, CheckFramebufferStatus, GLenum target) DECLARE_GL_FUNCTION_END(GLenum, CheckFramebufferStatus, target) DECLARE_GL_FUNCTION_HEAD(void, Clear, GLbitfield mask) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Clear, mask) DECLARE_GL_FUNCTION_HEAD(void, ClearColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearColor, red,green,blue,alpha) @@ -61,7 +61,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTexSubImage2D, GLenum target, GLint leve DECLARE_GL_FUNCTION_HEAD(GLuint, CreateProgram) DECLARE_GL_FUNCTION_END(GLuint, CreateProgram) DECLARE_GL_FUNCTION_HEAD(GLuint, CreateShader, GLenum type) DECLARE_GL_FUNCTION_END(GLuint, CreateShader, type) DECLARE_GL_FUNCTION_STUB_HEAD(void, CullFace, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CullFace, mode) -DECLARE_GL_FUNCTION_STUB_HEAD(void, DeleteBuffers, GLsizei n, const GLuint *buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DeleteBuffers, n,buffers) +DECLARE_GL_FUNCTION_HEAD(void, DeleteBuffers, GLsizei n, const GLuint *buffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteBuffers, n,buffers) DECLARE_GL_FUNCTION_HEAD(void, DeleteFramebuffers, GLsizei n, const GLuint *framebuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteFramebuffers, n,framebuffers) DECLARE_GL_FUNCTION_HEAD(void, DeleteProgram, GLuint program) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteProgram, program) DECLARE_GL_FUNCTION_STUB_HEAD(void, DeleteRenderbuffers, GLsizei n, const GLuint *renderbuffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DeleteRenderbuffers, n,renderbuffers) @@ -197,10 +197,11 @@ DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix2x4fv, GLint location, GLsizei count DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix4x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix4x2fv, location,count,transpose,value) DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix3x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix3x4fv, location,count,transpose,value) DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix4x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix4x3fv, location,count,transpose,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, BlitFramebuffer, 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, BlitFramebuffer, srcX0,srcY0,srcX1,srcY1,dstX0,dstY0,dstX1,dstY1,mask,filter) +DECLARE_GL_FUNCTION_HEAD(void, BlitFramebuffer, 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, BlitFramebuffer, srcX0,srcY0,srcX1,srcY1,dstX0,dstY0,dstX1,dstY1,mask,filter) +//DECLARE_GL_FUNCTION_STUB_HEAD(void, BlitFramebuffer, 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, BlitFramebuffer, srcX0,srcY0,srcX1,srcY1,dstX0,dstY0,dstX1,dstY1,mask,filter) DECLARE_GL_FUNCTION_STUB_HEAD(void, RenderbufferStorageMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, RenderbufferStorageMultisample, target,samples,internalformat,width,height) DECLARE_GL_FUNCTION_STUB_HEAD(void, FramebufferTextureLayer, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FramebufferTextureLayer, target,attachment,texture,level,layer) -DECLARE_GL_FUNCTION_STUB_HEAD(void, FlushMappedBufferRange, GLenum target, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FlushMappedBufferRange, target,offset,length) +DECLARE_GL_FUNCTION_HEAD(void, FlushMappedBufferRange, GLenum target, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FlushMappedBufferRange, target,offset,length) DECLARE_GL_FUNCTION_HEAD(void, BindVertexArray, GLuint array) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindVertexArray, array) DECLARE_GL_FUNCTION_STUB_HEAD(void, DeleteVertexArrays, GLsizei n, const GLuint *arrays) DECLARE_GL_FUNCTION_STUB_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) @@ -233,7 +234,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearBufferiv, GLenum buffer, GLint drawbuff DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearBufferuiv, GLenum buffer, GLint drawbuffer, const GLuint *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearBufferuiv, buffer,drawbuffer,value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearBufferfv, GLenum buffer, GLint drawbuffer, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearBufferfv, buffer,drawbuffer,value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearBufferfi, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearBufferfi, buffer,drawbuffer,depth,stencil) -DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyBufferSubData, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyBufferSubData, readTarget,writeTarget,readOffset,writeOffset,size) +DECLARE_GL_FUNCTION_HEAD(void, CopyBufferSubData, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CopyBufferSubData, readTarget,writeTarget,readOffset,writeOffset,size) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetUniformIndices, GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetUniformIndices, program,uniformCount,uniformNames,uniformIndices) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetActiveUniformsiv, GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetActiveUniformsiv, program,uniformCount,uniformIndices,pname,params) DECLARE_GL_FUNCTION_STUB_HEAD(GLuint, GetUniformBlockIndex, GLuint program, const GLchar *uniformBlockName) DECLARE_GL_FUNCTION_STUB_END(GLuint, GetUniformBlockIndex, program,uniformBlockName) @@ -365,7 +366,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFunci, GLuint buf, GLenum src, GLenum d DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFuncSeparatei, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFuncSeparatei, buf,srcRGB,dstRGB,srcAlpha,dstAlpha) DECLARE_GL_FUNCTION_STUB_HEAD(void, ColorMaski, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ColorMaski, index,r,g,b,a) DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, IsEnabledi, GLenum target, GLuint index) DECLARE_GL_FUNCTION_STUB_END(GLboolean, IsEnabledi, target,index) -DECLARE_GL_FUNCTION_STUB_HEAD(void, DrawElementsBaseVertex, GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DrawElementsBaseVertex, mode,count,type,indices,basevertex) +DECLARE_GL_FUNCTION_HEAD(void, DrawElementsBaseVertex, GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsBaseVertex, mode,count,type,indices,basevertex) DECLARE_GL_FUNCTION_STUB_HEAD(void, DrawRangeElementsBaseVertex, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DrawRangeElementsBaseVertex, mode,start,end,count,type,indices,basevertex) DECLARE_GL_FUNCTION_STUB_HEAD(void, DrawElementsInstancedBaseVertex, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DrawElementsInstancedBaseVertex, mode,count,type,indices,instancecount,basevertex) DECLARE_GL_FUNCTION_STUB_HEAD(void, FramebufferTexture, GLenum target, GLenum attachment, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FramebufferTexture, target,attachment,texture,level) @@ -388,7 +389,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetSamplerParameterIuiv, GLuint sampler, GLe DECLARE_GL_FUNCTION_STUB_HEAD(void, TexBuffer, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexBuffer, target,internalformat,buffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, TexBufferRange, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexBufferRange, target,internalformat,buffer,offset,size) DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage3DMultisample, target,samples,internalformat,width,height,depth,fixedsamplelocations) -DECLARE_GL_FUNCTION_STUB_HEAD(void*, MapBufferRange, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) DECLARE_GL_FUNCTION_STUB_END(void*, MapBufferRange, target,offset,length,access) +DECLARE_GL_FUNCTION_HEAD(void*, MapBufferRange, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) DECLARE_GL_FUNCTION_END(void*, MapBufferRange, target,offset,length,access) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearIndex, GLfloat c ) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearIndex,c) DECLARE_GL_FUNCTION_STUB_HEAD(void, IndexMask, GLuint mask ) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, IndexMask,mask) DECLARE_GL_FUNCTION_STUB_HEAD(void, AlphaFunc, GLenum func, GLclampf ref ) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, AlphaFunc,func,ref) @@ -402,7 +403,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, EdgeFlag, GLboolean flag ) DECLARE_GL_FUNCTI DECLARE_GL_FUNCTION_STUB_HEAD(void, EdgeFlagv, const GLboolean *flag ) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EdgeFlagv,flag) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClipPlane, GLenum plane, const GLdouble *equation ) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClipPlane,plane,equation) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetClipPlane, GLenum plane, GLdouble *equation ) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetClipPlane,plane,equation) -DECLARE_GL_FUNCTION_STUB_HEAD(void, DrawBuffer, GLenum mode ) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DrawBuffer,mode) +DECLARE_GL_FUNCTION_HEAD(void, DrawBuffer, GLenum mode ) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawBuffer,mode) DECLARE_GL_FUNCTION_STUB_HEAD(void, EnableClientState, GLenum cap ) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableClientState,cap) DECLARE_GL_FUNCTION_STUB_HEAD(void, DisableClientState, GLenum cap ) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DisableClientState,cap) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetDoublev, GLenum pname, GLdouble *params ) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetDoublev,pname,params) @@ -738,7 +739,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, LoadTransposeMatrixd,const GLdouble* m) DECL DECLARE_GL_FUNCTION_STUB_HEAD(void, MultTransposeMatrixf,const GLfloat* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultTransposeMatrixf,m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MultTransposeMatrixd,const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultTransposeMatrixd,m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawArrays, GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawArrays,mode,first,count,drawcount) -DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElements, GLenum mode, const GLsizei* count, GLenum type, const void* const*indices, GLsizei drawcount) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElements,mode,count,type,indices,drawcount) +DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElements, GLenum mode, const GLsizei* count, GLenum type, const void* const*indices, GLsizei drawcount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElements,mode,count,type,indices,drawcount) DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterf, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterf,pname,param) DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfv, GLenum pname, const GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfv,pname,params) DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameteri, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameteri,pname,param) @@ -814,7 +815,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4uiv, GLuint index, const GLuint DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4usv, GLuint index, const GLushort* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4usv,index,v) DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveRestartIndex, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PrimitiveRestartIndex,index) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetActiveUniformName, GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetActiveUniformName,program,uniformIndex,bufSize,length,uniformName) -DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const*indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElementsBaseVertex,mode,count,type,indices,drawcount,basevertex) +DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const*indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsBaseVertex,mode,count,type,indices,drawcount,basevertex) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProvokingVertex, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProvokingVertex,mode) DECLARE_GL_FUNCTION_STUB_HEAD(void, TexImage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexImage2DMultisample,target,samples,internalformat,width,height,fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_HEAD(void, TexImage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexImage3DMultisample,target,samples,internalformat,width,height,depth,fixedsamplelocations) diff --git a/MG/MG_GL/Implementations/GL/Getter/GL_Getter.cpp b/MG/MG_GL/Implementations/GL/Getter/GL_Getter.cpp index c43ce711..e2b920a7 100644 --- a/MG/MG_GL/Implementations/GL/Getter/GL_Getter.cpp +++ b/MG/MG_GL/Implementations/GL/Getter/GL_Getter.cpp @@ -44,7 +44,7 @@ namespace MG_GL::GL { } return (const GLubyte *)rendererString.c_str(); */ - return (const GLubyte *)(MG_GL::Getter::GetMGName() + "(MobileGL Core) Renderer").c_str(); + return (const GLubyte *)(MG_GL::Getter::GetMGName() + " (MobileGL Core) Renderer").c_str(); } case GL_SHADING_LANGUAGE_VERSION: return (const GLubyte *) "4.50 MobileGL with glslang"; @@ -114,37 +114,181 @@ namespace MG_GL::GL { void GetIntegerv(GLenum pname, GLint *params) { MG_Util::Debug::LogD("glGetIntegerv, pname: %s", MG_Util::Debug::GLEnumToString(pname)); + if (!params) { + MG_State::SetError(GL_INVALID_VALUE); + return; + } + switch (pname) { - case GL_CONTEXT_PROFILE_MASK: - (*params) = GL_CONTEXT_CORE_PROFILE_BIT; + // Viewport and scissor + case GL_VIEWPORT: + memcpy(params, MG_State_T::commonState->viewport, 4 * sizeof(GLint)); break; - case GL_NUM_EXTENSIONS: - static GLint num_extensions = -1; - if (num_extensions == -1) { - const GLubyte* ext_str = MG_GL::GL::GetString(GL_EXTENSIONS); - char *copy = strdup((const char *) ext_str); - char *token = strtok(copy, " "); - num_extensions = 0; - while (token) { - num_extensions++; - token = strtok(nullptr, " "); - } - free(copy); - } - (*params) = num_extensions; + case GL_SCISSOR_BOX: + // TODO: memcpy(params, MG_State_T::commonState->scissorBox, 4 * sizeof(GLint)); break; - case GL_MAJOR_VERSION: - (*params) = MG_Global::GL::GLVersionMajor; + case GL_MAX_VIEWPORT_DIMS: { + static const GLint maxDims[2] = {16384, 16384}; + memcpy(params, maxDims, sizeof(maxDims)); break; - case GL_MINOR_VERSION: - (*params) = MG_Global::GL::GLVersionMinor; + } + + // Buffer bindings + case GL_ARRAY_BUFFER_BINDING: + params[0] = static_cast(MG_State_T::bufferState->GetCurrentBinding(GL_ARRAY_BUFFER)); + break; + + case GL_ELEMENT_ARRAY_BUFFER_BINDING: + params[0] = static_cast(MG_State_T::vertexArrayState->GetBoundElementBuffer()); + break; + case GL_DRAW_FRAMEBUFFER_BINDING: + params[0] = static_cast(MG_State_T::framebufferState->currentBindings_[GL_DRAW_FRAMEBUFFER]); + break; + case GL_READ_FRAMEBUFFER_BINDING: + params[0] = static_cast(MG_State_T::framebufferState->currentBindings_[GL_READ_FRAMEBUFFER]); + break; + case GL_RENDERBUFFER_BINDING: + // TODO: params[0] = static_cast(MG_State_T::framebufferState->currentRenderbuffer_); + break; + + // Program state + case GL_CURRENT_PROGRAM: + params[0] = static_cast(MG_State_T::programState->currentProgram_); + break; + case GL_MAX_VERTEX_ATTRIBS: + // TODO: Check the real value + params[0] = 64; + break; + + // Texture state + case GL_TEXTURE_BINDING_2D: { + GLuint unit = MG_State_T::textureState->activeTextureUnit_; + auto& textures = MG_State_T::textureState->textureUnits_[unit].boundTextures; + params[0] = textures.count(GL_TEXTURE_2D) ? static_cast(textures[GL_TEXTURE_2D]) : 0; + break; + } + case GL_ACTIVE_TEXTURE: + params[0] = GL_TEXTURE0 + MG_State_T::textureState->activeTextureUnit_; break; case GL_MAX_TEXTURE_SIZE: - // TODO: Get real GL_MAX_TEXTURE_SIZE. - (*params) = 32768; + params[0] = 8192; break; + + // Blend state + case GL_BLEND_SRC_RGB: + params[0] = static_cast(MG_State_T::commonState->blendSrcRGB); + break; + case GL_BLEND_DST_RGB: + params[0] = static_cast(MG_State_T::commonState->blendDstRGB); + break; + case GL_BLEND_SRC_ALPHA: + params[0] = static_cast(MG_State_T::commonState->blendSrcAlpha); + break; + case GL_BLEND_DST_ALPHA: + params[0] = static_cast(MG_State_T::commonState->blendDstAlpha); + break; + + // Depth and stencil + case GL_DEPTH_FUNC: + params[0] = static_cast(MG_State_T::commonState->depthFunc); + break; + case GL_DEPTH_WRITEMASK: + params[0] = static_cast(MG_State_T::commonState->depthMask); + break; + case GL_STENCIL_REF: + // TODO: params[0] = MG_State_T::commonState->stencilRef; + break; + + // Capability enables + case GL_BLEND: + params[0] = MG_State_T::commonState->capabilities[GL_BLEND] ? GL_TRUE : GL_FALSE; + break; + case GL_DEPTH_TEST: + params[0] = MG_State_T::commonState->capabilities[GL_DEPTH_TEST] ? GL_TRUE : GL_FALSE; + break; + case GL_SCISSOR_TEST: + params[0] = MG_State_T::commonState->capabilities[GL_SCISSOR_TEST] ? GL_TRUE : GL_FALSE; + break; + + // Pixel operations + case GL_PACK_ALIGNMENT: + params[0] = MG_State_T::commonState->QueryPixelStoreInt(GL_PACK_ALIGNMENT); + break; + case GL_UNPACK_ALIGNMENT: + params[0] = MG_State_T::commonState->QueryPixelStoreInt(GL_UNPACK_ALIGNMENT); + break; + + // Hardware limits, TODO: Check the real values + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: + params[0] = 32; + break; + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: + params[0] = 32; + break; + case GL_MAX_TEXTURE_IMAGE_UNITS: + params[0] = 32; + break; + case GL_MAX_RENDERBUFFER_SIZE: + params[0] = 65537; + break; + case GL_MAX_DRAW_BUFFERS: + params[0] = 32; + break; + case GL_MAX_COLOR_ATTACHMENTS: + params[0] = 32; + break; + + // Color state + case GL_COLOR_CLEAR_VALUE: { + const auto& c = MG_State_T::commonState->clearColor; + params[0] = static_cast(c[0] * 0x7FFF); + params[1] = static_cast(c[1] * 0x7FFF); + params[2] = static_cast(c[2] * 0x7FFF); + params[3] = static_cast(c[3] * 0x7FFF); + break; + } + case GL_COLOR_WRITEMASK: + params[0] = MG_State_T::commonState->colorMask[0]; + params[1] = MG_State_T::commonState->colorMask[1]; + params[2] = MG_State_T::commonState->colorMask[2]; + params[3] = MG_State_T::commonState->colorMask[3]; + break; + + // Stencil operations + case GL_STENCIL_CLEAR_VALUE: + // TODO: params[0] = MG_State_T::commonState->stencilClearValue; + break; + case GL_STENCIL_BITS: + // TODO: Check the real value + params[0] = 8; + break; + + // Implementation limits + case GL_SUBPIXEL_BITS: + // TODO: Check the real value + params[0] = 4; + break; + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: + // TODO: params[0] = static_cast(MG_State_T::textureState->compressedFormats_.size()); + break; + case GL_COMPRESSED_TEXTURE_FORMATS: + // TODO: Implement GL_COMPRESSED_TEXTURE_FORMATS + break; + + // Polygon state + case GL_POLYGON_OFFSET_FACTOR: + // TODO: params[0] = static_cast(MG_State_T::commonState->polygonOffsetFactor); + break; + case GL_POLYGON_OFFSET_UNITS: + // TODO: params[0] = static_cast(MG_State_T::commonState->polygonOffsetUnits); + break; + + // Others... default: + MG_Util::Debug::LogE("glGetIntegerv: Invalid enum %s (0x%X)", MG_Util::Debug::GLEnumToString(pname), pname); + MG_State::SetError(GL_INVALID_ENUM); break; } } + } \ No newline at end of file diff --git a/MG/MG_GL/Implementations/GL/VertexArray/GL_VertexArray.cpp b/MG/MG_GL/Implementations/GL/VertexArray/GL_VertexArray.cpp index 04918d3b..94b8d0b8 100644 --- a/MG/MG_GL/Implementations/GL/VertexArray/GL_VertexArray.cpp +++ b/MG/MG_GL/Implementations/GL/VertexArray/GL_VertexArray.cpp @@ -7,7 +7,7 @@ namespace MG_GL::GL { void GenVertexArrays(GLsizei n, GLuint* arrays) { MG_Util::Debug::LogD("glGenVertexArrays, n: %d, arrays: %p", n, arrays); - GLenum result = MG_State::CreateVertexArrays(n, arrays); + GLenum result = MG_State::GenVertexArraysNames(n, arrays); if (result == GL_NO_ERROR) return; MG_State::SetError(result); MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result)); diff --git a/MG/MG_GL/State/Buffer/BufferState.cpp b/MG/MG_GL/State/Buffer/BufferState.cpp index 4dde0d53..48e83cbf 100644 --- a/MG/MG_GL/State/Buffer/BufferState.cpp +++ b/MG/MG_GL/State/Buffer/BufferState.cpp @@ -6,58 +6,60 @@ #include "BufferState.h" -GLenum BufferState::Create(GLuint* buffer) { - MG_Util::Debug::LogD("MG_State: Buffer: Create called"); - if (!buffer) return GL_INVALID_VALUE; +GLenum BufferState::GenName(GLuint *buffer) { + MG_Util::Debug::LogD("MG_State: Buffer: GenName"); + if (!buffer) + return GL_INVALID_VALUE; GLuint id = 0; - if (!freeIds_.empty()) { - id = *freeIds_.begin(); - freeIds_.erase(freeIds_.begin()); + if (freeId_.empty()) { + id = lastId_++; } else { - id = ++lastId_; + id = freeId_.back(); + freeId_.pop_back(); } + *buffer = id; - BufferObject& obj = buffers_[id]; - MG_Util::Debug::LogD("MG_State: Buffer: Create created buffer %d", id); - obj.generated = true; + MG_Util::Debug::LogD("MG_State: Buffer: Gen new name %d", id); return GL_NO_ERROR; } -GLenum BufferState::CreateN(GLsizei n, GLuint* buffers) { - MG_Util::Debug::LogD("MG_State: Buffer: CreateN called with n=%d", n); +GLenum BufferState::GenNameN(GLsizei n, GLuint* buffers) { + MG_Util::Debug::LogD("MG_State: Buffer: GenNameN called with n=%d", n); if (n < 0) return GL_INVALID_VALUE; for (GLsizei i = 0; i < n; ++i) { - GLenum result = Create(&buffers[i]); + GLenum result = GenName(&buffers[i]); if (result != GL_NO_ERROR) { - MG_Util::Debug::LogE("MG_State: Buffer: CreateN create buffer failed with error 0x%x", result); + MG_Util::Debug::LogE("MG_State: Buffer: GenNameN failed with error 0x%x", result); return result; } } - MG_Util::Debug::LogD("MG_State: Buffer: CreateN created buffers successfully"); + MG_Util::Debug::LogD("MG_State: Buffer: GenNameN created buffers successfully"); + return GL_NO_ERROR; +} + +GLenum BufferState::Create(GLuint buffer) { + MG_Util::Debug::LogD("MG_State: Buffer: Create called"); + if (!buffer) + return GL_INVALID_VALUE; + + if (ValidateAllocatedHandle(buffer)) + return GL_INVALID_VALUE; + + BufferObject& obj = buffers_[buffer]; + MG_Util::Debug::LogD("MG_State: Buffer: Create created buffer %d", buffer); + obj.generated = true; + obj.dirty = true; + return GL_NO_ERROR; } GLenum BufferState::Bind(GLenum target, GLuint buffer) { + // We don't handle unallocated buffer names here, just plain bind if (!IsValidTarget_(target)) return GL_INVALID_ENUM; - MG_Util::Debug::LogD("MG_State: Buffer: Bind called with target=0x%x, buffer=%u", target, buffer); - - if (buffer != 0) { - auto it = buffers_.find(buffer); - if (it == buffers_.end()) { - buffers_[buffer]; - } else { - BufferObject& obj = it->second; - if (obj.target != 0 && obj.target != target) { - MG_Util::Debug::LogE("MG_State: Buffer: Bind can not bind a buffer to different target 0x%x, current bind target is 0x%x", target, obj.target); - return GL_INVALID_OPERATION; - } - } - buffers_[buffer].target = target; - } - + MG_Util::Debug::LogD("MG_State: Buffer: Bind called with target=%s, buffer=%u", MG_Util::Debug::GLEnumToString(target), buffer); currentBindings_[target] = buffer; MG_Util::Debug::LogD("MG_State: Buffer: Bind succeed bind buffer %u to target 0x%x", buffer, target); return GL_NO_ERROR; @@ -73,68 +75,190 @@ GLenum BufferState::CommitStorage(GLenum target, GLsizeiptr size, const void* da MG_Util::Debug::LogD("MG_State: Buffer: CommitStorage get buffer object %u at target 0x%x",it->second,target); obj.usage = usage; obj.data.resize(size); - if (data) memcpy(obj.data.data(), data, size); + if (data) { + memcpy(obj.data.data(), data, size); + obj.dataValid = true; + } + obj.dirty = true; MG_Util::Debug::LogD("MG_State: Buffer: CommitStorage buffer at target 0x%x committed storage, size = %zu, usage=0x%x", target, size, usage); return GL_NO_ERROR; } -GLenum BufferState::AcquireBufferMemory(GLenum target, GLenum access, void** mappedPointer) { +GLenum BufferState::CommitStorageRegion(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) { + MG_Util::Debug::LogD("MG_State: Buffer: BufferSubData called on target 0x%x, offset=%ld, size=%ld", target, offset, size); if (!IsValidTarget_(target)) return GL_INVALID_ENUM; - if (MG_Constants::Buffer::VALID_ACCESS.find(access) == MG_Constants::Buffer::VALID_ACCESS.end()) { - return GL_INVALID_ENUM; - MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemory buffer at target 0x%x acquired mapped memory, access mode = 0x%x", target, access); - } - + if (offset < 0 || size < 0) return GL_INVALID_VALUE; + auto it = currentBindings_.find(target); if (it == currentBindings_.end() || it->second == 0) return GL_INVALID_OPERATION; BufferObject& obj = buffers_[it->second]; - if (obj.isMapped) return GL_INVALID_OPERATION; + MG_Util::Debug::LogD("MG_State: Buffer: BufferSubData get buffer object %u at target 0x%x", it->second, target); - obj.isMapped = true; - *mappedPointer = obj.data.data(); - obj.isMapped = true; - obj.accessMode = access; + if (static_cast(offset + size) > obj.data.size()) return GL_INVALID_VALUE; + if (data) { + memcpy(obj.data.data() + offset, data, size); + obj.dirty = true; + } return GL_NO_ERROR; } +GLenum BufferState::AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer) { + MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange called with target=0x%x, offset=%ld, length=%ld, access=0x%x", target, offset, length, access); + if (!IsValidTarget_(target)) { + MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: invalid target 0x%x", target); + return GL_INVALID_ENUM; + } + if (offset < 0 || length <= 0) { + MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: invalid offset %ld or length %ld", offset, length); + return GL_INVALID_VALUE; + } + + auto it = currentBindings_.find(target); + if (it == currentBindings_.end() || it->second == 0) { + MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: no buffer bound to target 0x%x", target); + return GL_INVALID_OPERATION; + } + + BufferObject& obj = buffers_[it->second]; + MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange operating on buffer %u", it->second); + if (obj.isMapped) { + MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: buffer %u is already mapped", it->second); + return GL_INVALID_OPERATION; + } + + const GLbitfield validFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT ; + if ((access & ~validFlags) != 0) { + MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: invalid access flags 0x%x", access); + return GL_INVALID_VALUE; + } + + if (static_cast(offset + length) > obj.data.size()) { + MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: requested range [%ld, %ld) exceeds buffer size %zu", offset, offset + length, obj.data.size()); + return GL_INVALID_VALUE; + } + + obj.isMapped = true; + obj.mapOffset = offset; + obj.mapLength = length; + obj.mapAccessFlags = access; + obj.dirty = true; + *mappedPointer = obj.data.data() + offset; + MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange succeeded for buffer %u. Mapped pointer: %p", it->second, *mappedPointer); + return GL_NO_ERROR; +} + +GLenum BufferState::SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length) { + if (!IsValidTarget_(target)) return GL_INVALID_ENUM; + if (offset < 0 || length <= 0) return GL_INVALID_VALUE; + + auto it = currentBindings_.find(target); + if (it == currentBindings_.end() || it->second == 0) + return GL_INVALID_OPERATION; + + BufferObject& obj = buffers_[it->second]; + if (!obj.isMapped || !(obj.mapAccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT)) + return GL_INVALID_OPERATION; + + if (offset < obj.mapOffset || offset + length > obj.mapOffset + obj.mapLength) + return GL_INVALID_VALUE; + + // TODO: Add support for flush range. + // Now only mark it as dirty. + obj.dirty = true; + return GL_NO_ERROR; +} + +GLenum BufferState::CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { + if (!IsValidTarget_(readTarget) || !IsValidTarget_(writeTarget)) + return GL_INVALID_ENUM; + if (readOffset < 0 || writeOffset < 0 || size < 0) + return GL_INVALID_VALUE; + + GLuint readBuffer = currentBindings_[readTarget]; + GLuint writeBuffer = currentBindings_[writeTarget]; + if (readBuffer == 0 || writeBuffer == 0 || readBuffer == writeBuffer) + return GL_INVALID_OPERATION; + + BufferObject& src = buffers_[readBuffer]; + BufferObject& dst = buffers_[writeBuffer]; + + if (static_cast(readOffset + size) > src.data.size() || + static_cast(writeOffset + size) > dst.data.size()) + return GL_INVALID_VALUE; + + memcpy(dst.data.data() + writeOffset, src.data.data() + readOffset, size); + dst.dirty = true; + return GL_NO_ERROR; +} + +GLenum BufferState::AcquireBufferMemory(GLenum target, GLenum access, void** mappedPointer) { + return AcquireBufferMemoryRange(target, 0, buffers_[currentBindings_[target]].data.size(), access, mappedPointer); +} + GLenum BufferState::ReleaseBufferMemory(GLenum target) { - MG_Util::Debug::LogD("MG_State: Buffer: ReleaseBufferMemory called on target 0x%x",target); - if (!IsValidTarget_(target)) return GL_INVALID_ENUM; + if (!IsValidTarget_(target)) + return GL_INVALID_ENUM; - auto it = currentBindings_.find(target); if (it == currentBindings_.end() || it->second == 0) return GL_INVALID_OPERATION; BufferObject& obj = buffers_[it->second]; - if (!obj.isMapped) return GL_INVALID_OPERATION; + if (!obj.isMapped) + return GL_INVALID_OPERATION; + + if ((obj.mapAccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { + obj.dirty = true; + } obj.isMapped = false; + obj.mapOffset = 0; + obj.mapLength = 0; + obj.mapAccessFlags = 0; obj.accessMode = GL_READ_WRITE; - MG_Util::Debug::LogD("MG_State: Buffer: ReleaseBufferMemory buffer at target 0x%x released mapped memory", target); + return GL_NO_ERROR; } -bool BufferState::ValidateHandle(GLuint buffer) { - bool isvalid = buffers_.count(buffer) > 0; - MG_Util::Debug::LogD("MG_State: Buffer: ValidateHandle called on buffer %u returns %d", buffer, isvalid); - return isvalid; +bool BufferState::ValidateAllocatedHandle(GLuint buffer) { + bool isValid = buffers_.find(buffer) != buffers_.end(); + MG_Util::Debug::LogD("MG_State: Buffer: ValidateAllocatedHandle called on buffer %u returns %d", buffer, isValid); + return isValid; +} + +bool BufferState::ValidateGeneratedName(GLuint buffer) { + bool inFreeList = std::find(freeId_.begin(), freeId_.end(), buffer) != freeId_.end(); + bool lessThanLast = buffer < lastId_; // lastId_ is not generated yet + MG_Util::Debug::LogD("MG_State: Buffer: ValidateGeneratedName called on buffer %u returns %d", buffer, lessThanLast && !inFreeList); + return lessThanLast && !inFreeList; } void BufferState::Delete(GLuint buffer) { - if (buffers_.erase(buffer)) { - freeIds_.insert(buffer); - for (auto& [target, id] : currentBindings_) { - if (id == buffer) id = 0; - } + buffers_.erase(buffer); + if (ValidateGeneratedName(buffer)) + // TODO: Prevent the object that uses a freeId from conflicting with legacy object in the backend. + //freeId_.emplace_back(buffer); + for (auto& [target, id] : currentBindings_) { + if (id == buffer) id = 0; } MG_Util::Debug::LogD("MG_State: Buffer: Delete buffer %u", buffer); } +GLenum BufferState::DeleteN(GLsizei n, const GLuint* buffers) { + MG_Util::Debug::LogD("MG_State: Buffer: DeleteN called with n=%d", n); + if (n < 0) return GL_INVALID_VALUE; + + for (GLsizei i = 0; i < n; ++i) { + Delete(buffers[i]); + } + MG_Util::Debug::LogD("MG_State: Buffer: DeleteN deleted buffers successfully"); + return GL_NO_ERROR; +} + bool BufferState::IsValidTarget_(GLenum target) { MG_Util::Debug::LogD("MG_State: Buffer: IsValidTarget_ called with target=0x%x,result=%d", target, !(MG_Constants::Buffer::VALID_TARGETS.find(target) == MG_Constants::Buffer::VALID_TARGETS.end())); return !(MG_Constants::Buffer::VALID_TARGETS.find(target) == MG_Constants::Buffer::VALID_TARGETS.end()); @@ -179,7 +303,7 @@ GLenum BufferState::QueryPropertyIntVector(GLenum target, GLenum pname, GLint* p case GL_BUFFER_USAGE: *params = static_cast(buffer.usage); break; - MG_Util::Debug::LogD("MG_State: Buffer: QueryPropertyIntVector Query info about buffer %u succeed",buffer.target); + MG_Util::Debug::LogD("MG_State: Buffer: QueryPropertyIntVector Query info about buffer %u succeed", target); default: return GL_INVALID_ENUM; } diff --git a/MG/MG_GL/State/Buffer/BufferState.h b/MG/MG_GL/State/Buffer/BufferState.h index 28db6c1f..1e49e6f8 100644 --- a/MG/MG_GL/State/Buffer/BufferState.h +++ b/MG/MG_GL/State/Buffer/BufferState.h @@ -9,34 +9,48 @@ #include "../../../Includes.h" class BufferState { + template + using unordered_map = ankerl::unordered_dense::map; + public: struct BufferObject { - GLenum target = 0; GLenum usage = GL_STATIC_DRAW; std::vector data; + bool dataValid = false; + bool dirty = false; // TODO: encapsulate this with an public API to RHI bool isMapped = false; bool generated = false; GLenum accessMode = GL_READ_WRITE; + GLintptr mapOffset = 0; + GLsizeiptr mapLength = 0; + GLbitfield mapAccessFlags = 0; }; // Return: the validity of the operation, according to OpenGL 3 standard - GLenum Create(GLuint* buffer); - GLenum CreateN(GLsizei n, GLuint* buffers); + GLenum GenName(GLuint* buffer); + GLenum GenNameN(GLsizei n, GLuint* buffers); + GLenum Create(GLuint buffer); GLenum Bind(GLenum target, GLuint buffer); GLenum CommitStorage(GLenum target, GLsizeiptr size, const void* data, GLenum usage); + GLenum CommitStorageRegion(GLenum target, GLintptr offset, GLsizeiptr size, const void* data); + GLenum AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer); + GLenum SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length); + GLenum CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); GLenum AcquireBufferMemory(GLenum target, GLenum access, void** mappedPointer); GLenum ReleaseBufferMemory(GLenum target); GLenum QueryPropertyIntVector(GLenum target, GLenum pname, GLint* params) const; + GLenum DeleteN(GLsizei n, const GLuint* buffers); - bool ValidateHandle(GLuint buffer); + bool ValidateAllocatedHandle(GLuint buffer); + bool ValidateGeneratedName(GLuint buffer); void Delete(GLuint buffer); GLuint GetCurrentBinding(GLenum target) const; + unordered_map currentBindings_; + unordered_map buffers_; private: - std::unordered_map buffers_; - std::set freeIds_; - GLuint lastId_ = 0; - std::unordered_map currentBindings_; + std::vector freeId_; + GLuint lastId_ = 1; static bool IsValidTarget_(GLenum target); }; diff --git a/MG/MG_GL/State/Common/CommonState.cpp b/MG/MG_GL/State/Common/CommonState.cpp index ec437424..915d57c0 100644 --- a/MG/MG_GL/State/Common/CommonState.cpp +++ b/MG/MG_GL/State/Common/CommonState.cpp @@ -107,6 +107,7 @@ GLenum CommonState::Clear(GLbitfield mask) { if ((mask & ~validBits) != 0) { return GL_INVALID_VALUE; } + clearMask = mask; return GL_NO_ERROR; } diff --git a/MG/MG_GL/State/Common/CommonState.h b/MG/MG_GL/State/Common/CommonState.h index df77e207..0feccbe3 100644 --- a/MG/MG_GL/State/Common/CommonState.h +++ b/MG/MG_GL/State/Common/CommonState.h @@ -9,9 +9,17 @@ #include "../../../Includes.h" class CommonState { -private: + template + using unordered_map = ankerl::unordered_dense::map; +public: + // Viewport + GLint viewport[4] = {0, 0, 0, 0}; + + // Color mask + GLboolean colorMask[4] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}; + // Pixel storage parameters - std::unordered_map pixelStoreParams; + unordered_map pixelStoreParams; // Blend state GLenum blendSrcRGB = GL_ONE; @@ -22,21 +30,15 @@ private: // Clear state GLfloat clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f}; GLfloat clearDepth = 1.0f; - - // Color mask - GLboolean colorMask[4] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}; - + GLenum clearMask; + // Depth state GLenum depthFunc = GL_LESS; GLboolean depthMask = GL_TRUE; - - // Viewport - GLint viewport[4] = {0, 0, 0, 0}; - + // Capability enables - std::unordered_map capabilities; + unordered_map capabilities; -public: CommonState(); // Return: the validity of the operation, according to OpenGL 3 standard @@ -57,6 +59,7 @@ public: GLenum Viewport(GLint x, GLint y, GLsizei width, GLsizei height); GLint QueryPixelStoreInt(GLenum pname); + }; #endif //MOBILEGL_COMMONSTATE_H diff --git a/MG/MG_GL/State/Core/GLState.cpp b/MG/MG_GL/State/Core/GLState.cpp index f7f5f290..5a902406 100644 --- a/MG/MG_GL/State/Core/GLState.cpp +++ b/MG/MG_GL/State/Core/GLState.cpp @@ -155,17 +155,30 @@ namespace MG_State { GLenum AcquireBufferMemory(GLenum target, GLenum access, void** mappedPtr) { return MG_State_T::bufferState->AcquireBufferMemory(target, access, mappedPtr); } + + GLenum AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer) { + return MG_State_T::bufferState->AcquireBufferMemoryRange(target, offset, length, access, mappedPointer); + } + + GLenum SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length) { + return MG_State_T::bufferState->SyncBufferMemory(target, offset, length); + } + + GLenum CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { + return MG_State_T::bufferState->CopyBufferRange(readTarget, writeTarget, readOffset, + writeOffset, size); + } GLenum ReleaseBufferMemory(GLenum target) { return MG_State_T::bufferState->ReleaseBufferMemory(target); } - GLenum CreateBuffer(GLuint* buffer) { + GLenum CreateBuffer(GLuint buffer) { return MG_State_T::bufferState->Create(buffer); } - GLenum CreateBuffers(GLsizei n, GLuint* buffers) { - return MG_State_T::bufferState->CreateN(n, buffers); + GLenum GenBufferNames(GLsizei n, GLuint* buffers) { + return MG_State_T::bufferState->GenNameN(n, buffers); } GLenum BindBuffer(GLenum target, GLuint buffer) { @@ -173,6 +186,7 @@ namespace MG_State { auto* vao = MG_State_T::vertexArrayState->GetCurrentVAO(); if (!vao) return GL_INVALID_OPERATION; vao->elementBuffer = (GLuint)buffer; + vao->eboDirty = true; } return MG_State_T::bufferState->Bind(target, buffer); } @@ -181,14 +195,26 @@ namespace MG_State { return MG_State_T::bufferState->CommitStorage(target, size, data, usage); } - bool ValidateBufferHandle(GLuint buffer) { - return MG_State_T::bufferState->ValidateHandle(buffer); + GLenum CommitBufferStorageRegion(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) { + return MG_State_T::bufferState->CommitStorageRegion(target, offset, size, data); + } + + bool ValidateAllocatedBufferHandle(GLuint buffer) { + return MG_State_T::bufferState->ValidateAllocatedHandle(buffer); + } + + bool ValidateGeneratedName(GLuint buffer) { + return MG_State_T::bufferState->ValidateGeneratedName(buffer); } void DeleteBuffer(GLuint buffer) { return MG_State_T::bufferState->Delete(buffer); } + GLenum DeleteBuffers(GLsizei n, const GLuint* buffers) { + return MG_State_T::bufferState->DeleteN(n, buffers); + } + GLenum QueryBufferPropertyIntVector(GLenum target, GLenum pname, GLint* params) { return MG_State_T::bufferState->QueryPropertyIntVector(target, pname, params); } @@ -206,6 +232,10 @@ namespace MG_State { return MG_State_T::vertexArrayState->CreateN(n, arrays); } + GLenum GenVertexArraysNames(GLsizei n, GLuint* arrays) { + return MG_State_T::vertexArrayState->GenNameN(n, arrays); + } + GLenum EnableVertexAttribArray(GLuint index) { return MG_State_T::vertexArrayState->EnableAttrib(index); } @@ -367,11 +397,11 @@ void UpdateProgramUniformMatrix##suffix##Vector(GLint location, GLsizei count, G GLenum MG_State::AttachTexture2DToFramebuffer(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { - return MG_State_T::framebufferState->glAttachTexture2D(target, attachment, textarget, - texture, level); + return MG_State_T::framebufferState->AttachTexture2D(target, attachment, textarget, + texture, level); } GLenum MG_State::ValidateFramebufferCompleteness(GLenum target) { - return MG_State_T::framebufferState->glValidateCompleteness(target); + return MG_State_T::framebufferState->ValidateCompleteness(target); } } \ No newline at end of file diff --git a/MG/MG_GL/State/Core/GLState.h b/MG/MG_GL/State/Core/GLState.h index e86b040b..77451308 100644 --- a/MG/MG_GL/State/Core/GLState.h +++ b/MG/MG_GL/State/Core/GLState.h @@ -57,18 +57,25 @@ namespace MG_State { // Buffer GLenum AcquireBufferMemory(GLenum target, GLenum access, void** mappedPtr); + GLenum AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer); + GLenum SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length); + GLenum CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); GLenum ReleaseBufferMemory(GLenum target); - GLenum CreateBuffer(GLuint* buffer); - GLenum CreateBuffers(GLsizei n, GLuint* buffers); + GLenum CreateBuffer(GLuint buffer); + GLenum GenBufferNames(GLsizei n, GLuint* buffers); GLenum BindBuffer(GLenum target, GLuint buffer); GLenum CommitBufferStorage(GLenum target, GLsizeiptr size, const void* data, GLenum usage); - bool ValidateBufferHandle(GLuint buffer); + GLenum CommitBufferStorageRegion(GLenum target, GLintptr offset, GLsizeiptr size, const void* data); + bool ValidateAllocatedBufferHandle(GLuint buffer); + bool ValidateGeneratedName(GLuint buffer); void DeleteBuffer(GLuint buffer); + GLenum DeleteBuffers(GLsizei n, const GLuint* buffers); GLenum QueryBufferPropertyIntVector(GLenum target, GLenum pname, GLint* params); // VertexArray GLenum CreateVertexArray(GLuint* array); GLenum CreateVertexArrays(GLsizei n, GLuint* arrays); + GLenum GenVertexArraysNames(GLsizei n, GLuint* arrays); GLenum BindVertexArray(GLuint array); GLenum EnableVertexAttribArray(GLuint index); GLenum DisableVertexAttribArray(GLuint index); diff --git a/MG/MG_GL/State/Framebuffer/FramebufferState.cpp b/MG/MG_GL/State/Framebuffer/FramebufferState.cpp index 2c899445..c75ac235 100644 --- a/MG/MG_GL/State/Framebuffer/FramebufferState.cpp +++ b/MG/MG_GL/State/Framebuffer/FramebufferState.cpp @@ -32,7 +32,8 @@ GLenum FramebufferState::Delete(GLuint framebuffer) { if (framebuffer == 0) return GL_INVALID_VALUE; if (framebuffers_.erase(framebuffer)) { - freeIds_.insert(framebuffer); + // TODO: Prevent the object that uses a freeId from conflicting with legacy object in the backend. + //freeIds_.insert(framebuffer); for (auto& [target, id] : currentBindings_) { if (id == framebuffer) id = 0; } @@ -48,18 +49,18 @@ GLenum FramebufferState::Bind(GLenum target, GLuint framebuffer) { if (target == GL_FRAMEBUFFER) { currentBindings_[GL_READ_FRAMEBUFFER] = framebuffer; currentBindings_[GL_DRAW_FRAMEBUFFER] = framebuffer; - currentBindings_[GL_FRAMEBUFFER] = framebuffer; } else { currentBindings_[target] = framebuffer; } return GL_NO_ERROR; } -GLenum FramebufferState::glAttachTexture2D(GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, GLint level) { +GLenum FramebufferState::AttachTexture2D(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) { if (MG_Constants::Framebuffer::VALID_ATTACHMENTS.find(attachment) == MG_Constants::Framebuffer::VALID_ATTACHMENTS.end() || MG_Constants::Texture::VALID_TARGETS.find(textarget) == MG_Constants::Texture::VALID_TARGETS.end()) return GL_INVALID_ENUM; + if (target == GL_FRAMEBUFFER) target = GL_DRAW_FRAMEBUFFER; FramebufferObject* fbo = GetCurrentFBO(target); if (!fbo) return GL_INVALID_OPERATION; if (texture != 0 && !MG_State_T::textureState->IsTexture(texture)) @@ -83,7 +84,8 @@ GLenum FramebufferState::glAttachTexture2D(GLenum target, GLenum attachment, return GL_NO_ERROR; } -GLenum FramebufferState::glValidateCompleteness(GLenum target) { +GLenum FramebufferState::ValidateCompleteness(GLenum target) { + if (target == GL_FRAMEBUFFER) target = GL_DRAW_FRAMEBUFFER; FramebufferObject* fbo = GetCurrentFBO(target); if (!fbo) return GL_INVALID_OPERATION; return fbo->status; diff --git a/MG/MG_GL/State/Framebuffer/FramebufferState.h b/MG/MG_GL/State/Framebuffer/FramebufferState.h index 8cf7b3df..8af6e7a4 100644 --- a/MG/MG_GL/State/Framebuffer/FramebufferState.h +++ b/MG/MG_GL/State/Framebuffer/FramebufferState.h @@ -17,7 +17,7 @@ struct FramebufferAttachment { struct FramebufferObject { bool generated = false; - std::unordered_map attachments; + ankerl::unordered_map attachments; GLenum status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; GLsizei width = 0; GLsizei height = 0; @@ -30,14 +30,15 @@ public: GLenum CreateN(GLsizei n, GLuint* framebuffers); GLenum Delete(GLuint framebuffer); GLenum Bind(GLenum target, GLuint framebuffer); - GLenum glAttachTexture2D(GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, GLint level); - GLenum glValidateCompleteness(GLenum target); + GLenum AttachTexture2D(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level); + GLenum ValidateCompleteness(GLenum target); FramebufferObject* GetCurrentFBO(GLenum target); + ankerl::unordered_map currentBindings_; // READ/DRAW + private: - std::unordered_map framebuffers_; - std::unordered_map currentBindings_; // READ/DRAW/FRAMEBUFFER + ankerl::unordered_map framebuffers_; std::set freeIds_; GLuint lastId_ = 0; bool ValidateHandle(GLuint framebuffer); diff --git a/MG/MG_GL/State/Program/ProgramState.cpp b/MG/MG_GL/State/Program/ProgramState.cpp index 9a01da02..fed6fb58 100644 --- a/MG/MG_GL/State/Program/ProgramState.cpp +++ b/MG/MG_GL/State/Program/ProgramState.cpp @@ -48,7 +48,7 @@ GLenum ProgramState::DeleteProgram(GLuint program) { } programs_.erase(program); - freeProgramIds_.insert(program); + //freeProgramIds_.insert(program); if (currentProgram_ == program) currentProgram_ = 0; MG_Util::Debug::LogD("MG_State: Program: DeleteProgram success, id=%u", program); @@ -261,6 +261,7 @@ GLenum ProgramState::SetUniform(GLuint program, GLint location, GLsizei count, c } UniformValue& uniform = prog.uniformValues[uniformName]; + uniform.setData(type, count, value); MG_Util::Debug::LogD("MG_State: Program: SetUniform success: %s set", uniformName.c_str()); return GL_NO_ERROR; @@ -303,7 +304,7 @@ GLenum ProgramState::SetUniformMatrix(GLuint program, GLint location, GLsizei co } UniformValue& uniform = prog.uniformValues[uniformName]; - uniform.setData(matrixType, count * MG_Util::Program::GetMatrixElementCount(matrixType), value); + uniform.setData(matrixType, count, value); MG_Util::Debug::LogD("MG_State: Program: SetUniformMatrix success: %s set", uniformName.c_str()); return GL_NO_ERROR; } @@ -334,15 +335,15 @@ void ProgramState::UpdateUniform##suffix##Vector1(GLint location, GLsizei count, } \ void ProgramState::UpdateUniform##suffix##Vector2(GLint location, GLsizei count, const type* value) { \ MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector2 called, location=%d, count=%d", location, count); \ - SetUniform(currentProgram_, location, count * 2, value, vecType); \ + SetUniform(currentProgram_, location, count, value, vecType); \ } \ void ProgramState::UpdateUniform##suffix##Vector3(GLint location, GLsizei count, const type* value) { \ MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector3 called, location=%d, count=%d", location, count); \ - SetUniform(currentProgram_, location, count * 3, value, vecType); \ + SetUniform(currentProgram_, location, count, value, vecType); \ } \ void ProgramState::UpdateUniform##suffix##Vector4(GLint location, GLsizei count, const type* value) { \ MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector4 called, location=%d, count=%d", location, count); \ - SetUniform(currentProgram_, location, count * 4, value, vecType); \ + SetUniform(currentProgram_, location, count, value, vecType); \ } IMPLEMENT_UNIFORM_FUNCTIONS(GLfloat, Float, GL_FLOAT_VEC4) @@ -462,16 +463,62 @@ void ProgramState::CleanupShaders_() { // UniformValue template -void UniformValue::setData(GLenum uniformType, GLsizei numElements, const T* values) { - MG_Util::Debug::LogD("MG_State: Program: UniformValue::setData called, type=0x%X, count=%d", uniformType, numElements); +void UniformValue::setData(GLenum uniformType, GLsizei count_, const T* values) { + MG_Util::Debug::LogD("MG_State: Program: UniformValue::setData called, type=0x%X, count=%d", uniformType, count_); //type = uniformType; - count = numElements; + count = count_; floatData.clear(); intData.clear(); uintData.clear(); boolData.clear(); + switch (type) { + case GL_FLOAT: numElements = count_ * 1; break; + case GL_FLOAT_VEC2: numElements = count_ * 2; break; + case GL_FLOAT_VEC3: numElements = count_ * 3; break; + case GL_FLOAT_VEC4: numElements = count_ * 4; break; + case GL_INT: numElements = count_ * 1; break; + case GL_INT_VEC2: numElements = count_ * 2; break; + case GL_INT_VEC3: numElements = count_ * 3; break; + case GL_INT_VEC4: numElements = count_ * 4; break; + case GL_UNSIGNED_INT: numElements = count_ * 1; break; + case GL_UNSIGNED_INT_VEC2: numElements = count_ * 2; break; + case GL_UNSIGNED_INT_VEC3: numElements = count_ * 3; break; + case GL_UNSIGNED_INT_VEC4: numElements = count_ * 4; break; + case GL_BOOL: numElements = count_ * 1; break; + case GL_BOOL_VEC2: numElements = count_ * 2; break; + case GL_BOOL_VEC3: numElements = count_ * 3; break; + case GL_BOOL_VEC4: numElements = count_ * 4; break; + case GL_FLOAT_MAT2: numElements = count_ * 4; break; // 2x2 + case GL_FLOAT_MAT3: numElements = count_ * 9; break; // 3x3 + case GL_FLOAT_MAT4: numElements = count_ * 16; break; // 4x4 + case GL_FLOAT_MAT2x3: numElements = count_ * 6; break; // 2x3 + case GL_FLOAT_MAT2x4: numElements = count_ * 8; break; // 2x4 + case GL_FLOAT_MAT3x2: numElements = count_ * 6; break; // 3x2 + case GL_FLOAT_MAT3x4: numElements = count_ * 12; break; // 3x4 + case GL_FLOAT_MAT4x2: numElements = count_ * 8; break; // 4x2 + case GL_FLOAT_MAT4x3: numElements = count_ * 12; break; // 4x3 + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_CUBE_SHADOW: + case GL_SAMPLER_1D_ARRAY: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_1D_ARRAY_SHADOW: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_SAMPLER_BUFFER: + case GL_SAMPLER_2D_MULTISAMPLE: + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: numElements = count_ * 1; break; + default: + MG_Util::Debug::LogW("MG_State: Program: UniformValue::setData warning: unsupported type 0x%X for numElements", uniformType); + numElements = 1; + return; + } + for (GLsizei i = 0; i < numElements; ++i) { switch (uniformType) { case GL_FLOAT: diff --git a/MG/MG_GL/State/Program/ProgramState.h b/MG/MG_GL/State/Program/ProgramState.h index 5ea2ce7c..5abc2c9d 100644 --- a/MG/MG_GL/State/Program/ProgramState.h +++ b/MG/MG_GL/State/Program/ProgramState.h @@ -27,36 +27,37 @@ struct UniformValue { std::vector uintData; std::vector boolData; GLsizei count; + GLsizei numElements; UniformValue() : type(0), count(0) {} template - void setData(GLenum uniformType, GLsizei numElements, const T* values); + void setData(GLenum uniformType, GLsizei count_, const T* values); }; struct ProgramObject { std::vector attachedShaders; UncertainBool linked; + bool dirty; GLint linkStatus; std::string infoLog; - std::unordered_map attribBindings; - std::unordered_map attribLocations; - std::unordered_map uniformLocations; - std::unordered_map uniformValues; + ankerl::unordered_map attribBindings; + ankerl::unordered_map attribLocations; + ankerl::unordered_map uniformLocations; + ankerl::unordered_map uniformValues; bool markedForDeletion; }; class ProgramState { -private: - std::unordered_map shaders_; - std::unordered_map programs_; +public: + ankerl::unordered_map shaders_; + ankerl::unordered_map programs_; std::set freeShaderIds_; std::set freeProgramIds_; GLuint lastShaderId_ = 0; GLuint lastProgramId_ = 0; GLuint currentProgram_ = 0; -public: ProgramState(); ~ProgramState(); diff --git a/MG/MG_GL/State/Program/ShaderObject.cpp b/MG/MG_GL/State/Program/ShaderObject.cpp index 0928a551..a8031905 100644 --- a/MG/MG_GL/State/Program/ShaderObject.cpp +++ b/MG/MG_GL/State/Program/ShaderObject.cpp @@ -60,7 +60,8 @@ GLenum ProgramState::DeleteShader(GLuint shader) { MG_Util::Debug::LogD("MG_State: Program: DeleteShader info: shader %u marked for deferred deletion (in use)", shader); } else { shaders_.erase(shader); - freeShaderIds_.insert(shader); + // TODO: Prevent the object that uses a freeId from conflicting with legacy object in the backend. + //freeShaderIds_.insert(shader); MG_Util::Debug::LogD("MG_State: Program: DeleteShader success: shader %u deleted immediately", shader); } return GL_NO_ERROR; diff --git a/MG/MG_GL/State/Texture/TextureState.cpp b/MG/MG_GL/State/Texture/TextureState.cpp index 3a9c70ab..47e8f6d5 100644 --- a/MG/MG_GL/State/Texture/TextureState.cpp +++ b/MG/MG_GL/State/Texture/TextureState.cpp @@ -11,7 +11,7 @@ // TextureObject bool TextureObject::IsImmutable() const { - bool immutable = params.texPropertiesInt.count(GL_TEXTURE_IMMUTABLE_FORMAT); + bool immutable = params.texPropertiesInt.find(GL_TEXTURE_IMMUTABLE_FORMAT) != params.texPropertiesInt.end(); MG_Util::Debug::LogD("MG_State: Texture: TextureObject::IsImmutable returns %d", immutable); return immutable; } @@ -54,7 +54,7 @@ bool TextureState::IsTextureGenerated(GLuint texture) { if (!isValidTexture) { MG_Util::Debug::LogD("MG_State: Texture: IsTextureGenerated invalid texture %d", texture); } else { - generated = textures.at(texture).generated; + generated = textures[texture].generated; if (!generated) { MG_Util::Debug::LogD("MG_State: Texture: IsTextureGenerated texture %d not generated", texture, generated); } @@ -101,12 +101,12 @@ GLenum TextureState::CreateN(GLsizei n, GLuint* textures) { for (GLsizei i = 0; i < n; ++i) { GLuint id = 0; - if (!freeIDs_.empty()) { - id = *freeIDs_.begin(); - freeIDs_.erase(freeIDs_.begin()); + if (!freeID_.empty()) { + id = freeID_.back(); + freeID_.pop_back(); MG_Util::Debug::LogD("MG_State: Texture: CreateN reusing free id=%u", id); } else { - id = ++lastUsedID_; + id = lastUsedID_++; MG_Util::Debug::LogD("MG_State: Texture: CreateN new id=%u", id); } TextureObject obj; @@ -258,7 +258,7 @@ GLenum TextureState::Upload2D(GLenum target, GLint level, GLint internalFormat, if (isProxyTexture) { MG_Util::Debug::LogD("MG_State: Texture: Upload2D proxy texture detected"); TextureObject& proxyTex = proxyTextures_[target]; - TextureParams::MipmapLevel mip{}; + auto& mip = proxyTex.params.mipmapData[level]; mip.width = width; mip.height = height; mip.internalFormat = internalFormat; @@ -266,19 +266,25 @@ GLenum TextureState::Upload2D(GLenum target, GLint level, GLint internalFormat, mip.type = type; proxyTex.generated = true; proxyTex.target = target; - proxyTex.params.mipmapData[level] = mip; return GL_NO_ERROR; } GLuint boundTex = textureUnits_[activeTextureUnit_].GetBoundTexture(target); TextureObject& tex = textures[boundTex]; - TextureParams::MipmapLevel mip{}; +// TextureParams::MipmapLevel mip{}; + + auto& mip = tex.params.mipmapData[level]; mip.width = width; mip.height = height; mip.internalFormat = internalFormat; mip.format = format; mip.type = type; - if (data != nullptr) { + mip.dirty = true; + + if (data == nullptr) { + mip.hasData = false; + MG_Util::Debug::LogD("MG_State: Texture: Upload2D data pointer is null"); + } else { GLint unpackSwapBytes = GetUnpackParam_(GL_UNPACK_SWAP_BYTES); GLint unpackLSBFirst = GetUnpackParam_(GL_UNPACK_LSB_FIRST); GLint unpackSkipPixels = GetUnpackParam_(GL_UNPACK_SKIP_PIXELS); @@ -288,47 +294,69 @@ GLenum TextureState::Upload2D(GLenum target, GLint level, GLint internalFormat, GLint unpackImageHeight = GetUnpackParam_(GL_UNPACK_IMAGE_HEIGHT); GLint unpackSkipImages = GetUnpackParam_(GL_UNPACK_SKIP_IMAGES); - GLsizei rowLength = (unpackRowLength > 0) ? unpackRowLength : width; + bool isDefaultUnpack = (unpackSwapBytes == 0) && (unpackLSBFirst == 0) && + (unpackSkipPixels == 0) && (unpackSkipRows == 0) && + (unpackRowLength == 0) && (unpackAlignment == 4) && + (unpackImageHeight == 0) && (unpackSkipImages == 0); + size_t bytesPerPixel = CalculateBytesPerPixel_(format, type); size_t componentSize = GetComponentSize_(type); - size_t srcRowSize = rowLength * bytesPerPixel; - size_t srcRowStride = (srcRowSize + unpackAlignment - 1) & ~(unpackAlignment - 1); - size_t srcImageStride = (unpackImageHeight > 0) ? - srcRowStride * unpackImageHeight : - srcRowStride * height; - - const GLubyte* srcData = static_cast(data); - srcData += unpackSkipImages * srcImageStride; - srcData += unpackSkipRows * srcRowStride; - srcData += unpackSkipPixels * bytesPerPixel; - size_t dstRowStride = width * bytesPerPixel; size_t dstSize = dstRowStride * height; mip.pixelData.resize(dstSize); - GLubyte* dstData = mip.pixelData.data(); + GLubyte *dstData = mip.pixelData.data(); - for (GLsizei y = 0; y < height; ++y) { - const GLubyte* srcRow = srcData + y * srcRowStride; - GLubyte* dstRow = dstData + y * dstRowStride; + if (isDefaultUnpack) { + const GLubyte *srcData = static_cast(data); + size_t srcRowSize = width * bytesPerPixel; + size_t srcRowStride = (srcRowSize + unpackAlignment - 1) & ~(unpackAlignment - 1); - if (unpackSwapBytes) { - SwapBytesForTexture_(format, type, srcRow, dstRow, width); + if (srcRowStride == dstRowStride) { + memcpy(dstData, srcData, dstSize); + MG_Util::Debug::LogD( + "MG_State: Texture: Upload2D uploaded %zu bytes with fast path - block memcpy", dstSize); + } else { + for (GLsizei y = 0; y < height; ++y) { + const GLubyte *srcRow = srcData + y * srcRowStride; + GLubyte *dstRow = dstData + y * dstRowStride; + memcpy(dstRow, srcRow, srcRowSize); + } + MG_Util::Debug::LogD( + "MG_State: Texture: Upload2D uploaded %zu bytes with fast path - row memcpy", dstSize); } - else if (unpackLSBFirst && componentSize == 1) { - ReverseBitOrder_(srcRow, dstRow, width * bytesPerPixel); - } - else { - memcpy(dstRow, srcRow, width * bytesPerPixel); + } else { + GLsizei rowLength = (unpackRowLength > 0) ? unpackRowLength : width; + + size_t srcRowSize = rowLength * bytesPerPixel; + size_t srcRowStride = (srcRowSize + unpackAlignment - 1) & ~(unpackAlignment - 1); + size_t srcImageStride = (unpackImageHeight > 0) ? + srcRowStride * unpackImageHeight : + srcRowStride * height; + + const GLubyte *srcData = static_cast(data); + srcData += unpackSkipImages * srcImageStride; + srcData += unpackSkipRows * srcRowStride; + srcData += unpackSkipPixels * bytesPerPixel; + + for (GLsizei y = 0; y < height; ++y) { + const GLubyte *srcRow = srcData + y * srcRowStride; + GLubyte *dstRow = dstData + y * dstRowStride; + + if (unpackSwapBytes) { + SwapBytesForTexture_(format, type, srcRow, dstRow, width); + } else if (unpackLSBFirst && componentSize == 1) { + ReverseBitOrder_(srcRow, dstRow, width * bytesPerPixel); + } else { + memcpy(dstRow, srcRow, width * bytesPerPixel); + } } + mip.hasData = true; + MG_Util::Debug::LogD( + "MG_State: Texture: Upload2D uploaded %zu bytes with unpack params", dstSize); } - mip.hasData = true; - MG_Util::Debug::LogD("MG_State: Texture: Upload2D uploaded %zu bytes with unpack params", dstSize); - } else { - mip.hasData = false; - MG_Util::Debug::LogD("MG_State: Texture: Upload2D data pointer is null"); } - tex.params.mipmapData[level] = mip; +// tex.params.mipmapData[level] = mip; return GL_NO_ERROR; } @@ -364,7 +392,7 @@ GLenum TextureState::UpdateRegion2D(GLenum target, GLint level, GLint xoffset, const size_t bytesPerPixel = CalculateBytesPerPixel_(format, type); const size_t srcSize = CalculatePixelDataSize_(format, type, width, height); - + if (bytesPerPixel == 0) { MG_Util::Debug::LogE("MG_State: Texture: Invalid format/type combination"); return GL_INVALID_ENUM; @@ -402,27 +430,68 @@ GLenum TextureState::UpdateRegion2D(GLenum target, GLint level, GLint xoffset, MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D srcData=%p, dstData=%p", srcData, dstData); MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D bytesPerPixel=%zu", bytesPerPixel); - for (GLsizei y = 0; y < height; ++y) { - const GLubyte* srcRow = srcData + y * srcRowStride; - GLubyte* dstRow = dstData + y * dstRowStride; + // Check if fast path is applicable + const bool isDefaultUnpack = (unpackSwapBytes == 0) && (unpackLSBFirst == 0) && + (unpackRowLength == 0) && (unpackAlignment == 4) && + (unpackSkipPixels == 0) && (unpackSkipRows == 0) && + (unpackImageHeight == 0) && (unpackSkipImages == 0); - if (unpackSwapBytes) { - for (GLsizei x = 0; x < width; ++x) { - const GLubyte* srcPixel = srcRow + x * bytesPerPixel; - GLubyte* dstPixel = dstRow + x * bytesPerPixel; - SwapPixelBytes_(format, type, srcPixel, dstPixel); - } - } else if (unpackLSBFirst && GetComponentSize_(type) == 1) { - for (size_t i = 0; i < width * bytesPerPixel; ++i) { - dstRow[i] = ReverseBits_(srcRow[i]); - } + if (isDefaultUnpack) { + const size_t copySize = width * bytesPerPixel; + + if (srcRowStride == dstRowStride) { + MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D block memcpy(dst=%p, src=%p, size=%zu) called.", dstData, srcData, width * bytesPerPixel); + memcpy(dstData, srcData, copySize * height); } else { - MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D memcpy(dst=%p, src=%p, size=%zu) called.", dstRow, srcRow, width * bytesPerPixel); - memcpy(dstRow, srcRow, width * bytesPerPixel); + for (GLsizei y = 0; y < height; ++y) { + const GLubyte* srcRow = srcData + y * srcRowStride; + GLubyte* dstRow = dstData + y * dstRowStride; + memcpy(dstRow, srcRow, copySize); + MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D row memcpy(dst=%p, src=%p, size=%zu) called.", dstRow, srcRow, width * bytesPerPixel); + } + } + } else { + const size_t componentSize = GetComponentSize_(type); + for (GLsizei y = 0; y < height; ++y) { + const GLubyte* srcRow = srcData + y * srcRowStride; + GLubyte* dstRow = dstData + y * dstRowStride; + + if (unpackSwapBytes) { + for (GLsizei x = 0; x < width; ++x) { + SwapPixelBytes_(format, type, srcRow + x*bytesPerPixel, dstRow + x*bytesPerPixel); + } + } else if (unpackLSBFirst && componentSize == 1) { + for (size_t i = 0; i < width * bytesPerPixel; ++i) { + dstRow[i] = ReverseBits_(srcRow[i]); + } + } else { + memcpy(dstRow, srcRow, width * bytesPerPixel); + } } } +// for (GLsizei y = 0; y < height; ++y) { +// const GLubyte* srcRow = srcData + y * srcRowStride; +// GLubyte* dstRow = dstData + y * dstRowStride; +// +// if (unpackSwapBytes) { +// for (GLsizei x = 0; x < width; ++x) { +// const GLubyte* srcPixel = srcRow + x * bytesPerPixel; +// GLubyte* dstPixel = dstRow + x * bytesPerPixel; +// SwapPixelBytes_(format, type, srcPixel, dstPixel); +// } +// } else if (unpackLSBFirst && GetComponentSize_(type) == 1) { +// for (size_t i = 0; i < width * bytesPerPixel; ++i) { +// dstRow[i] = ReverseBits_(srcRow[i]); +// } +// } else { +// MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D memcpy(dst=%p, src=%p, size=%zu) called.", dstRow, srcRow, width * bytesPerPixel); +// memcpy(dstRow, srcRow, width * bytesPerPixel); +// } +// } + mip.hasData = true; + mip.dirty = true; MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D succeeded"); return GL_NO_ERROR; } @@ -541,7 +610,7 @@ GLenum TextureState::Delete(GLuint texture) { if (it != this->textures.end()) { InvalidateTextureInAllUnits_(texture); this->textures.erase(it); - freeIDs_.insert(texture); + //freeID_.emplace_back(texture); MG_Util::Debug::LogD("MG_State: Texture: Delete succeeded for texture=%u", texture); } else { MG_Util::Debug::LogW("MG_State: Texture: Delete texture %u not found", texture); @@ -563,7 +632,8 @@ GLenum TextureState::DeleteN(GLsizei n, const GLuint* textures) { if (it != this->textures.end()) { InvalidateTextureInAllUnits_(id); this->textures.erase(it); - freeIDs_.insert(id); + // TODO: Prevent the object that uses a freeId from conflicting with legacy object in the backend. + //freeID_.emplace_back(id); MG_Util::Debug::LogD("MG_State: Texture: DeleteN deleted texture=%u", id); } else { MG_Util::Debug::LogW("MG_State: Texture: DeleteN texture %u not found", id); @@ -630,7 +700,7 @@ GLenum TextureState::QueryLevelPropertyIntVector(GLenum target, GLint level, GLe return GL_NO_ERROR; } - std::unordered_map::iterator texIt; + unordered_map::iterator texIt; if (!isProxyTexture) { texIt = textures.find(boundTexture); @@ -803,10 +873,10 @@ GLenum TextureState::CheckUploadingTexture2DValidity_(GLenum target, GLint level return GL_INVALID_OPERATION; } - bool isDepthInternal = (internalFormat == GL_DEPTH_COMPONENT32F || internalFormat == GL_DEPTH_COMPONENT24 - || internalFormat == GL_DEPTH_COMPONENT16 || internalFormat == GL_DEPTH32F_STENCIL8 - || internalFormat == GL_DEPTH24_STENCIL8 || internalFormat == GL_DEPTH_COMPONENT - || internalFormat == GL_DEPTH_STENCIL); + bool isDepthInternal = (internalFormat == GL_DEPTH_COMPONENT32 || internalFormat == GL_DEPTH_COMPONENT32F || + internalFormat == GL_DEPTH_COMPONENT24 || internalFormat == GL_DEPTH_COMPONENT16 || + internalFormat == GL_DEPTH32F_STENCIL8 || internalFormat == GL_DEPTH24_STENCIL8 || + internalFormat == GL_DEPTH_COMPONENT || internalFormat == GL_DEPTH_STENCIL); bool isDepthFormat = (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL); if (isDepthInternal != isDepthFormat) { MG_Util::Debug::LogE("MG_State: Texture: CheckUploadingTexture2DValidity_ depth internal/format mismatch"); @@ -895,7 +965,7 @@ GLenum TextureState::CheckUpdatingTextureRegion2DValidity_(GLenum target, GLint return GL_INVALID_OPERATION; } - auto tex = textures[boundTex]; + const auto& tex = textures[boundTex]; if (tex.IsImmutable()) { MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity_ texture is immutable"); @@ -934,7 +1004,7 @@ GLenum TextureState::CheckUpdatingTextureRegion2DValidity_(GLenum target, GLint return GL_INVALID_OPERATION; } - TextureParams::MipmapLevel& mip = mipIt->second; + const auto& mip = mipIt->second; if (xoffset + width > mip.width || yoffset + height > mip.height) { MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity_ region out of bounds: " "x=%d+%d > %d or y=%d+%d > %d", diff --git a/MG/MG_GL/State/Texture/TextureState.h b/MG/MG_GL/State/Texture/TextureState.h index b192ca76..104525f0 100644 --- a/MG/MG_GL/State/Texture/TextureState.h +++ b/MG/MG_GL/State/Texture/TextureState.h @@ -19,8 +19,10 @@ struct ComponentSizes { }; struct TextureParams { - std::unordered_map texPropertiesFloat; - std::unordered_map texPropertiesInt; + template + using unordered_map = ankerl::unordered_dense::map; + unordered_map texPropertiesFloat; + unordered_map texPropertiesInt; struct MipmapLevel { GLsizei width = 0; GLsizei height = 0; @@ -29,8 +31,9 @@ struct TextureParams { GLenum type = GL_UNSIGNED_BYTE; std::vector pixelData; bool hasData = false; + bool dirty = false; // TODO: encapsulate this with an public API to RHI }; - std::unordered_map mipmapData; + unordered_map mipmapData; }; class TextureObject { @@ -44,24 +47,27 @@ public: }; class TextureUnitState { + template + using unordered_map = ankerl::unordered_dense::map; private: GLenum activeTarget = GL_TEXTURE_2D; public: - std::unordered_map boundTextures; + unordered_map boundTextures; void Bind(GLenum target, GLuint texture); GLuint GetBoundTexture(GLenum target); }; class TextureState { + template + using unordered_map = ankerl::unordered_dense::map; private: - std::vector textureUnits_; - GLuint activeTextureUnit_ = 0; - GLuint lastUsedID_ = 0; - std::set freeIDs_; + GLuint lastUsedID_ = 1; +// ankerl::unordered_set freeIDs_; + std::vector freeID_; - std::unordered_map proxyTextures_; + unordered_map proxyTextures_; static GLint GetUnpackParam_(GLenum pname); public: @@ -69,7 +75,7 @@ public: bool IsTextureGenerated(GLuint texture); bool IsTexture(GLuint texture); - std::unordered_map textures; + unordered_map textures; // Return: the validity of the operation, according to OpenGL 3 standard GLenum BindUnit(GLenum textureUnit); @@ -88,6 +94,8 @@ public: GLenum DeleteN(GLsizei n, const GLuint* textures); GLenum QueryLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params); + std::vector textureUnits_; + GLuint activeTextureUnit_ = 0; private: size_t CalculatePixelDataSize_(GLenum format, GLenum type, GLsizei width, GLsizei height); void InvalidateTextureInAllUnits_(GLuint texture); diff --git a/MG/MG_GL/State/VertexArray/VertexArrayState.cpp b/MG/MG_GL/State/VertexArray/VertexArrayState.cpp index f6626b75..59e9199f 100644 --- a/MG/MG_GL/State/VertexArray/VertexArrayState.cpp +++ b/MG/MG_GL/State/VertexArray/VertexArrayState.cpp @@ -10,6 +10,37 @@ VertexArrayState::VertexArrayState() { vaos_[0]; } +GLenum VertexArrayState::GenName(GLuint *array) { + MG_Util::Debug::LogD("MG_State: VAO: GenName"); + if (!array) + return GL_INVALID_VALUE; + GLuint id; + if (freeIds_.empty()) { + id = ++lastId_; + } else { + id = *freeIds_.begin(); + freeIds_.erase(freeIds_.begin()); + } + *array = id; + MG_Util::Debug::LogD("MG_State: VAO: Generated new name %d", id); + return GL_NO_ERROR; +} + +GLenum VertexArrayState::GenNameN(GLsizei n, GLuint* arrays) { + MG_Util::Debug::LogD("MG_State: VAO: GenNameN called with n=%d", n); + if (n < 0) + return GL_INVALID_VALUE; + for (GLsizei i = 0; i < n; ++i) { + GLenum result = GenName(&arrays[i]); + if (result != GL_NO_ERROR) { + MG_Util::Debug::LogE("MG_State: VAO: GenNameN failed at index %d with error 0x%x", i, result); + return result; + } + } + MG_Util::Debug::LogD("MG_State: VAO: GenNameN created %d names", n); + return GL_NO_ERROR; +} + GLenum VertexArrayState::Create(GLuint* array) { if (array == nullptr) return GL_INVALID_VALUE; @@ -41,24 +72,57 @@ GLenum VertexArrayState::CreateN(GLsizei n, GLuint* arrays) { } GLenum VertexArrayState::Bind(GLuint array) { - if (array != 0 && !vaos_.count(array)) return GL_INVALID_OPERATION; + MG_Util::Debug::LogD("MG_State: VAO: Bind called for %u", array); + if (array != 0) { + if (!ValidateGeneratedName(array)) { + MG_Util::Debug::LogE("MG_State: VAO: Bind invalid name %u", array); + return GL_INVALID_OPERATION; + } + auto& vao = vaos_[array]; + if (!vao.generated) { + MG_Util::Debug::LogD("MG_State: VAO: Creating VAO %u during bind", array); + vao.generated = true; + } + } currentVao_ = array; + MG_Util::Debug::LogD("MG_State: VAO: Bound to %u", array); return GL_NO_ERROR; } +bool VertexArrayState::ValidateGeneratedName(GLuint array) { + if (array == 0) + return true; + bool inFreeList = freeIds_.count(array) > 0; + bool valid = (array <= lastId_) && !inFreeList; + MG_Util::Debug::LogD("MG_State: VAO: ValidateGeneratedName %u: %d", array, valid); + return valid; +} + +bool VertexArrayState::ValidateAllocatedHandle(GLuint array) { + bool exists = vaos_.count(array) && vaos_[array].generated; + MG_Util::Debug::LogD("MG_State: VAO: ValidateAllocatedHandle %u: %d", array, exists); + return exists; +} + GLenum VertexArrayState::EnableAttrib(GLuint index) { - if (currentVao_ == 0) return GL_INVALID_OPERATION; + if (!ValidateAllocatedHandle(currentVao_)) + return GL_INVALID_OPERATION; if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE; GetCurrentVAO()->attribs[index].enabled = true; MG_Util::Debug::LogD("Attrib vaos_[%u].attribs[%u].enabled = %d", currentVao_, index, vaos_[currentVao_].attribs[index].enabled); + + GetCurrentVAO()->attribDirty = true; return GL_NO_ERROR; } GLenum VertexArrayState::DisableAttrib(GLuint index) { - if (currentVao_ == 0) return GL_INVALID_OPERATION; + if (!ValidateAllocatedHandle(currentVao_)) + return GL_INVALID_OPERATION; if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE; GetCurrentVAO()->attribs[index].enabled = false; MG_Util::Debug::LogD("Attrib vaos_[%u].attribs[%u].enabled = %d", currentVao_, index, vaos_[currentVao_].attribs[index].enabled); + + GetCurrentVAO()->attribDirty = true; return GL_NO_ERROR; } @@ -66,7 +130,8 @@ GLenum VertexArrayState::SetAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer, bool isInteger, GLuint currentArrayBuffer) { - if (currentVao_ == 0) return GL_INVALID_OPERATION; + if (!ValidateAllocatedHandle(currentVao_)) + return GL_INVALID_OPERATION; if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE; VertexAttribState state; @@ -81,6 +146,8 @@ GLenum VertexArrayState::SetAttribPointer(GLuint index, GLint size, GLenum type, state.enabled = true; vaos_[currentVao_].attribs[index] = state; + + GetCurrentVAO()->attribDirty = true; return GL_NO_ERROR; } diff --git a/MG/MG_GL/State/VertexArray/VertexArrayState.h b/MG/MG_GL/State/VertexArray/VertexArrayState.h index 8b02e9b9..a3df42aa 100644 --- a/MG/MG_GL/State/VertexArray/VertexArrayState.h +++ b/MG/MG_GL/State/VertexArray/VertexArrayState.h @@ -9,7 +9,7 @@ #include "../../../Includes.h" struct VertexAttribState { - bool enabled = false; + bool enabled; GLint size = 4; GLenum type = GL_FLOAT; GLboolean normalized = GL_FALSE; @@ -21,8 +21,10 @@ struct VertexAttribState { struct VertexArrayObject { bool generated = false; + bool attribDirty = false; + bool eboDirty = false; GLuint elementBuffer = 0; - std::unordered_map attribs; + ankerl::unordered_map attribs; }; class VertexArrayState { @@ -30,6 +32,8 @@ public: VertexArrayState(); // Return: the validity of the operation, according to OpenGL 3 standard + GLenum GenName(GLuint* array); + GLenum GenNameN(GLsizei n, GLuint* arrays); GLenum Create(GLuint* array); GLenum CreateN(GLsizei n, GLuint* arrays); GLenum Bind(GLuint array); @@ -42,12 +46,14 @@ public: GLuint GetBoundElementBuffer(); VertexArrayObject* GetCurrentVAO(); + bool ValidateGeneratedName(GLuint array); + bool ValidateAllocatedHandle(GLuint array); + GLuint currentVao_ = 0; + ankerl::unordered_map vaos_; private: - std::unordered_map vaos_; std::set freeIds_; GLuint lastId_ = 0; - GLuint currentVao_ = 0; }; #endif //MOBILEGL_VERTEXARRAYSTATE_H diff --git a/MG/MG_RHI/GLES/Test/TestDrawing.cpp b/MG/MG_RHI/GLES/Test/TestDrawing.cpp index 1bb9bbd9..93348cb6 100644 --- a/MG/MG_RHI/GLES/Test/TestDrawing.cpp +++ b/MG/MG_RHI/GLES/Test/TestDrawing.cpp @@ -48,8 +48,8 @@ namespace MG_RHI::GLES::Test { GLuint quadVBO = 0; GLint uTexLoc = -1; GLint uMVPLoc = -1; - std::unordered_map textureCache; - std::unordered_map textureDirty; + ankerl::unordered_map textureCache; + ankerl::unordered_map textureDirty; }; static ScreenResources sRes; diff --git a/MG/MG_UTIL/Debug/Debug.cpp b/MG/MG_UTIL/Debug/Debug.cpp index ddaac4e2..5add9b7e 100644 --- a/MG/MG_UTIL/Debug/Debug.cpp +++ b/MG/MG_UTIL/Debug/Debug.cpp @@ -1206,6 +1206,15 @@ void Log##name(const char* format, ...) { \ CASE(GL_DOT3_RGBA) /* texture_border_clamp */ CASE(GL_CLAMP_TO_BORDER) +/* framebuffer_status */ + CASE(GL_FRAMEBUFFER_COMPLETE) + CASE(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) + CASE(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) + CASE(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS) + CASE(GL_FRAMEBUFFER_UNSUPPORTED) + CASE(GL_COLOR_ATTACHMENT0) + CASE(GL_DEPTH_ATTACHMENT) + CASE(GL_STENCIL_ATTACHMENT) /* * Miscellaneous */ diff --git a/MG/MG_UTIL/Program/DebugTool.cpp b/MG/MG_UTIL/Program/DebugTool.cpp index 608b9495..e02e123c 100644 --- a/MG/MG_UTIL/Program/DebugTool.cpp +++ b/MG/MG_UTIL/Program/DebugTool.cpp @@ -54,7 +54,7 @@ namespace MG_Util::Program { std::ostringstream ss; ss << "["; - const size_t elemCount = std::min(value.count, 16); // 限制最大显示元素 + const size_t elemCount = std::min(value.count, 16); switch(value.type) { case GL_FLOAT: diff --git a/MG/MG_UTIL/Program/GLSLTool.cpp b/MG/MG_UTIL/Program/GLSLTool.cpp index 91a77e9d..1cd4323b 100644 --- a/MG/MG_UTIL/Program/GLSLTool.cpp +++ b/MG/MG_UTIL/Program/GLSLTool.cpp @@ -108,7 +108,7 @@ namespace MG_Util::Program { return; } - std::unordered_set used_locations; + ankerl::unordered_set used_locations; GLint auto_location = 0; for (auto spirv: allSpirv) { spvc_parsed_ir ir = nullptr; @@ -395,11 +395,44 @@ namespace MG_Util::Program { prog.uniformLocations[name] = final_location; UniformValue uniformValue; uniformValue.type = gl_type; - uniformValue.count = spvc_type_get_array_dimension(type, 0) > 0 ? - spvc_type_get_array_dimension(type, 0) : 1; prog.uniformValues[name] = uniformValue; } } spvc_context_destroy(context); } + + std::string CompileSPIRVToGLSL(std::vector spirv, uint glslVersion, bool isES) { + spvc_context context = nullptr; + spvc_parsed_ir ir = nullptr; + spvc_compiler compiler_glsl = nullptr; + spvc_compiler_options options = nullptr; + spvc_resources resources = nullptr; + const spvc_reflected_resource *list = nullptr; + const char *result = nullptr; + size_t count; + + const SpvId *p_spirv = spirv.data(); + size_t word_count = spirv.size(); + + spvc_context_create(&context); + spvc_context_parse_spirv(context, p_spirv, word_count, &ir); + spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler_glsl); + spvc_compiler_create_shader_resources(compiler_glsl, &resources); + spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count); + spvc_compiler_create_compiler_options(compiler_glsl, &options); + spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, glslVersion); + spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, isES ? SPVC_TRUE : SPVC_FALSE); + spvc_compiler_install_compiler_options(compiler_glsl, options); + spvc_compiler_compile(compiler_glsl, &result); + + if (!result) { + return{}; + } + + std::string essl = result; + + spvc_context_destroy(context); + + return essl; + } } \ No newline at end of file diff --git a/MG/MG_UTIL/Program/GLSLTool.h b/MG/MG_UTIL/Program/GLSLTool.h index 3d6812e7..2488f79c 100644 --- a/MG/MG_UTIL/Program/GLSLTool.h +++ b/MG/MG_UTIL/Program/GLSLTool.h @@ -177,6 +177,7 @@ namespace MG_Util::Program { std::string CompileGLSLToTShader(GLenum shaderType, const std::string& source, glslang::TShader *&shader); std::vector> CompileMultipleShadersToSPIRV(const ProgramState& state, ProgramObject& prog, std::string& infoLog); void ReflectSPIRVUniforms(const std::vector>& allSpirv, ProgramObject& prog, std::string& infoLog); + std::string CompileSPIRVToGLSL(std::vector spirv, uint glslVersion, bool isES); } #endif //MOBILEGL_GLSLTOOL_H diff --git a/PlannedFunctions.md b/PlannedFunctions.md index 4abe8852..9a359fa3 100644 --- a/PlannedFunctions.md +++ b/PlannedFunctions.md @@ -4,7 +4,7 @@ - [x] glGetAttribLocation - [x] glGetBufferParameteriv - [x] glGetError -- [ ] glGetIntegerv +- [x] glGetIntegerv - [x] glGetProgramiv - [x] glGetShaderiv - [x] glGetString @@ -33,6 +33,8 @@ - [x] glFramebufferTexture2D - [x] glGenFramebuffers +  ~~glBlitFramebuffer~~ + --- ### **4. Shader & Program Management** @@ -60,6 +62,10 @@ - [x] glUnmapBuffer - [x] glVertexAttribIPointer - [x] glVertexAttribPointer +- [x] glBufferSubData +- [x] glMapBufferRange +- [x] glFlushMappedBufferRange +- [x] glCopyBufferSubData --- @@ -90,28 +96,27 @@ --- ### **8. Drawing Commands** -- [ ] glDrawElements -- [ ] glDrawArrays +  ~~glDrawElements~~ ## Abstraction Layer (MG_RHI) ### **1. Initialization & Query Functions** -glGetAttribLocation~~ +  ~~glGetAttribLocation~~ -glGetBufferParameteriv~~ +  ~~glGetBufferParameteriv~~ -glGetError~~ +  ~~glGetError~~ -- [ ] glGetIntegerv +  ~~glGetIntegerv~~ - [ ] glGetProgramiv - [ ] glGetShaderiv - [ ] glGetString - [ ] glGetStringi -glGetTexLevelParameteriv~~ +  ~~glGetTexLevelParameteriv~~ -glGetUniformLocation~~ +  ~~glGetUniformLocation~~ --- @@ -133,6 +138,7 @@ glGetUniformLocation~~ - [ ] glDeleteFramebuffers - [ ] glFramebufferTexture2D - [ ] glGenFramebuffers +- [ ] glBlitFramebuffer --- @@ -161,6 +167,10 @@ glGetUniformLocation~~ - [ ] glUnmapBuffer - [ ] glVertexAttribIPointer - [ ] glVertexAttribPointer +- [ ] glBufferSubData +- [ ] glMapBufferRange +- [ ] glFlushMappedBufferRange +- [ ] glCopyBufferSubData --- @@ -191,5 +201,4 @@ glGetUniformLocation~~ --- ### **8. Drawing Commands** -- [ ] glDrawElements -- [ ] glDrawArrays \ No newline at end of file +- [ ] glDrawElements \ No newline at end of file diff --git a/README.md b/README.md index 00caec3f..bb667131 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,11 @@ **glslang** by **KhronosGroup**: [github](https://github.com/KhronosGroup/glslang) -**GlslOptimizerV2** by **aiekick**: [github](https://github.com/aiekick/GlslOptimizerV2) +*(Unused Currently)* **GlslOptimizerV2** by **aiekick**: [github](https://github.com/aiekick/GlslOptimizerV2) + +**unordered_dense** by **Martin Leitner-Ankerl**: [github](https://github.com/martinus/unordered_dense) + +**OpenGL Mathematics (*GLM*)** by **G-Truc Creation**: [github](https://github.com/g-truc/glm) ## Progress @@ -21,12 +25,12 @@ --- -**Target**: **OpenGL implementation compatible with Minecraft 1.17 to 1.21.1** +**Target**: **OpenGL implementation compatible with Minecraft 1.17 to 1.21.5** | Component | Development Progress\* | |--------------------------------|------------------------| -| **OpenGL State Manager** | **59 / 62** | -| **Abstraction Layer (MG_RHI)** | **0 / 57** | +| **OpenGL State Manager** | **65 / 65** | +| **Abstraction Layer (MG_RHI)** | **0 / 61** | | **OpenGL ES Backend** | **N/A** (of MG_RHI) | | **Vulkan Backend** | **planned** | diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..534b45db --- /dev/null +++ b/build.gradle @@ -0,0 +1,36 @@ +apply plugin: 'com.android.library' + +android { + namespace 'top.mobilegl.mobilegl' + compileSdk 34 + + defaultConfig { + minSdk 26 + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + } + proguard { + minifyEnabled true + initWith debug + } + fordebug { + debuggable true + } + } + externalNativeBuild { + cmake { + path "CMakeLists.txt" + version "3.22.1" + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + ndkVersion '27.2.12479018' +} diff --git a/include/ankerl/unordered_dense.h b/include/ankerl/unordered_dense.h new file mode 100644 index 00000000..13484a98 --- /dev/null +++ b/include/ankerl/unordered_dense.h @@ -0,0 +1,2101 @@ +///////////////////////// ankerl::unordered_dense::{map, set} ///////////////////////// + +// A fast & densely stored hashmap and hashset based on robin-hood backward shift deletion. +// Version 4.5.0 +// https://github.com/martinus/unordered_dense +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2022-2024 Martin Leitner-Ankerl +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef ANKERL_UNORDERED_DENSE_H +#define ANKERL_UNORDERED_DENSE_H + +// see https://semver.org/spec/v2.0.0.html +#define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 4 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes +#define ANKERL_UNORDERED_DENSE_VERSION_MINOR 5 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality +#define ANKERL_UNORDERED_DENSE_VERSION_PATCH 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible bug fixes + +// API versioning with inline namespace, see https://www.foonathan.net/2018/11/inline-namespaces/ + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ANKERL_UNORDERED_DENSE_VERSION_CONCAT1(major, minor, patch) v##major##_##minor##_##patch +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ANKERL_UNORDERED_DENSE_VERSION_CONCAT(major, minor, patch) ANKERL_UNORDERED_DENSE_VERSION_CONCAT1(major, minor, patch) +#define ANKERL_UNORDERED_DENSE_NAMESPACE \ + ANKERL_UNORDERED_DENSE_VERSION_CONCAT( \ + ANKERL_UNORDERED_DENSE_VERSION_MAJOR, ANKERL_UNORDERED_DENSE_VERSION_MINOR, ANKERL_UNORDERED_DENSE_VERSION_PATCH) + +#if defined(_MSVC_LANG) +# define ANKERL_UNORDERED_DENSE_CPP_VERSION _MSVC_LANG +#else +# define ANKERL_UNORDERED_DENSE_CPP_VERSION __cplusplus +#endif + +#if defined(__GNUC__) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +# define ANKERL_UNORDERED_DENSE_PACK(decl) decl __attribute__((__packed__)) +#elif defined(_MSC_VER) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +# define ANKERL_UNORDERED_DENSE_PACK(decl) __pragma(pack(push, 1)) decl __pragma(pack(pop)) +#endif + +// exceptions +#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) +# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 1 // NOLINT(cppcoreguidelines-macro-usage) +#else +# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 0 // NOLINT(cppcoreguidelines-macro-usage) +#endif +#ifdef _MSC_VER +# define ANKERL_UNORDERED_DENSE_NOINLINE __declspec(noinline) +#else +# define ANKERL_UNORDERED_DENSE_NOINLINE __attribute__((noinline)) +#endif + +// defined in unordered_dense.cpp +#if !defined(ANKERL_UNORDERED_DENSE_EXPORT) +# define ANKERL_UNORDERED_DENSE_EXPORT +#endif + +#if ANKERL_UNORDERED_DENSE_CPP_VERSION < 201703L +# error ankerl::unordered_dense requires C++17 or higher +#else +# include // for array +# include // for uint64_t, uint32_t, uint8_t, UINT64_C +# include // for size_t, memcpy, memset +# include // for equal_to, hash +# include // for initializer_list +# include // for pair, distance +# include // for numeric_limits +# include // for allocator, allocator_traits, shared_ptr +# include // for optional +# include // for out_of_range +# include // for basic_string +# include // for basic_string_view, hash +# include // for forward_as_tuple +# include // for enable_if_t, declval, conditional_t, ena... +# include // for forward, exchange, pair, as_const, piece... +# include // for vector +# if ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() == 0 +# include // for abort +# endif + +# if defined(__has_include) && !defined(ANKERL_UNORDERED_DENSE_DISABLE_PMR) +# if __has_include() +# define ANKERL_UNORDERED_DENSE_PMR std::pmr // NOLINT(cppcoreguidelines-macro-usage) +# include // for polymorphic_allocator +# elif __has_include() +# define ANKERL_UNORDERED_DENSE_PMR std::experimental::pmr // NOLINT(cppcoreguidelines-macro-usage) +# include // for polymorphic_allocator +# endif +# endif + +# if defined(_MSC_VER) && defined(_M_X64) +# include +# pragma intrinsic(_umul128) +# endif + +# if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) +# define ANKERL_UNORDERED_DENSE_LIKELY(x) __builtin_expect(x, 1) // NOLINT(cppcoreguidelines-macro-usage) +# define ANKERL_UNORDERED_DENSE_UNLIKELY(x) __builtin_expect(x, 0) // NOLINT(cppcoreguidelines-macro-usage) +# else +# define ANKERL_UNORDERED_DENSE_LIKELY(x) (x) // NOLINT(cppcoreguidelines-macro-usage) +# define ANKERL_UNORDERED_DENSE_UNLIKELY(x) (x) // NOLINT(cppcoreguidelines-macro-usage) +# endif + +namespace ankerl::unordered_dense { +inline namespace ANKERL_UNORDERED_DENSE_NAMESPACE { + +namespace detail { + +# if ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() + +// make sure this is not inlined as it is slow and dramatically enlarges code, thus making other +// inlinings more difficult. Throws are also generally the slow path. +[[noreturn]] inline ANKERL_UNORDERED_DENSE_NOINLINE void on_error_key_not_found() { + throw std::out_of_range("ankerl::unordered_dense::map::at(): key not found"); +} +[[noreturn]] inline ANKERL_UNORDERED_DENSE_NOINLINE void on_error_bucket_overflow() { + throw std::overflow_error("ankerl::unordered_dense: reached max bucket size, cannot increase size"); +} +[[noreturn]] inline ANKERL_UNORDERED_DENSE_NOINLINE void on_error_too_many_elements() { + throw std::out_of_range("ankerl::unordered_dense::map::replace(): too many elements"); +} + +# else + +[[noreturn]] inline void on_error_key_not_found() { + abort(); +} +[[noreturn]] inline void on_error_bucket_overflow() { + abort(); +} +[[noreturn]] inline void on_error_too_many_elements() { + abort(); +} + +# endif + +} // namespace detail + +// hash /////////////////////////////////////////////////////////////////////// + +// This is a stripped-down implementation of wyhash: https://github.com/wangyi-fudan/wyhash +// No big-endian support (because different values on different machines don't matter), +// hardcodes seed and the secret, reformats the code, and clang-tidy fixes. +namespace detail::wyhash { + +inline void mum(uint64_t* a, uint64_t* b) { +# if defined(__SIZEOF_INT128__) + __uint128_t r = *a; + r *= *b; + *a = static_cast(r); + *b = static_cast(r >> 64U); +# elif defined(_MSC_VER) && defined(_M_X64) + *a = _umul128(*a, *b, b); +# else + uint64_t ha = *a >> 32U; + uint64_t hb = *b >> 32U; + uint64_t la = static_cast(*a); + uint64_t lb = static_cast(*b); + uint64_t hi{}; + uint64_t lo{}; + uint64_t rh = ha * hb; + uint64_t rm0 = ha * lb; + uint64_t rm1 = hb * la; + uint64_t rl = la * lb; + uint64_t t = rl + (rm0 << 32U); + auto c = static_cast(t < rl); + lo = t + (rm1 << 32U); + c += static_cast(lo < t); + hi = rh + (rm0 >> 32U) + (rm1 >> 32U) + c; + *a = lo; + *b = hi; +# endif +} + +// multiply and xor mix function, aka MUM +[[nodiscard]] inline auto mix(uint64_t a, uint64_t b) -> uint64_t { + mum(&a, &b); + return a ^ b; +} + +// read functions. WARNING: we don't care about endianness, so results are different on big endian! +[[nodiscard]] inline auto r8(const uint8_t* p) -> uint64_t { + uint64_t v{}; + std::memcpy(&v, p, 8U); + return v; +} + +[[nodiscard]] inline auto r4(const uint8_t* p) -> uint64_t { + uint32_t v{}; + std::memcpy(&v, p, 4); + return v; +} + +// reads 1, 2, or 3 bytes +[[nodiscard]] inline auto r3(const uint8_t* p, size_t k) -> uint64_t { + return (static_cast(p[0]) << 16U) | (static_cast(p[k >> 1U]) << 8U) | p[k - 1]; +} + +[[maybe_unused]] [[nodiscard]] inline auto hash(void const* key, size_t len) -> uint64_t { + static constexpr auto secret = std::array{UINT64_C(0xa0761d6478bd642f), + UINT64_C(0xe7037ed1a0b428db), + UINT64_C(0x8ebc6af09c88c6e3), + UINT64_C(0x589965cc75374cc3)}; + + auto const* p = static_cast(key); + uint64_t seed = secret[0]; + uint64_t a{}; + uint64_t b{}; + if (ANKERL_UNORDERED_DENSE_LIKELY(len <= 16)) { + if (ANKERL_UNORDERED_DENSE_LIKELY(len >= 4)) { + a = (r4(p) << 32U) | r4(p + ((len >> 3U) << 2U)); + b = (r4(p + len - 4) << 32U) | r4(p + len - 4 - ((len >> 3U) << 2U)); + } else if (ANKERL_UNORDERED_DENSE_LIKELY(len > 0)) { + a = r3(p, len); + b = 0; + } else { + a = 0; + b = 0; + } + } else { + size_t i = len; + if (ANKERL_UNORDERED_DENSE_UNLIKELY(i > 48)) { + uint64_t see1 = seed; + uint64_t see2 = seed; + do { + seed = mix(r8(p) ^ secret[1], r8(p + 8) ^ seed); + see1 = mix(r8(p + 16) ^ secret[2], r8(p + 24) ^ see1); + see2 = mix(r8(p + 32) ^ secret[3], r8(p + 40) ^ see2); + p += 48; + i -= 48; + } while (ANKERL_UNORDERED_DENSE_LIKELY(i > 48)); + seed ^= see1 ^ see2; + } + while (ANKERL_UNORDERED_DENSE_UNLIKELY(i > 16)) { + seed = mix(r8(p) ^ secret[1], r8(p + 8) ^ seed); + i -= 16; + p += 16; + } + a = r8(p + i - 16); + b = r8(p + i - 8); + } + + return mix(secret[1] ^ len, mix(a ^ secret[1], b ^ seed)); +} + +[[nodiscard]] inline auto hash(uint64_t x) -> uint64_t { + return detail::wyhash::mix(x, UINT64_C(0x9E3779B97F4A7C15)); +} + +} // namespace detail::wyhash + +ANKERL_UNORDERED_DENSE_EXPORT template +struct hash { + auto operator()(T const& obj) const noexcept(noexcept(std::declval>().operator()(std::declval()))) + -> uint64_t { + return std::hash{}(obj); + } +}; + +template +struct hash::is_avalanching> { + using is_avalanching = void; + auto operator()(T const& obj) const noexcept(noexcept(std::declval>().operator()(std::declval()))) + -> uint64_t { + return std::hash{}(obj); + } +}; + +template +struct hash> { + using is_avalanching = void; + auto operator()(std::basic_string const& str) const noexcept -> uint64_t { + return detail::wyhash::hash(str.data(), sizeof(CharT) * str.size()); + } +}; + +template +struct hash> { + using is_avalanching = void; + auto operator()(std::basic_string_view const& sv) const noexcept -> uint64_t { + return detail::wyhash::hash(sv.data(), sizeof(CharT) * sv.size()); + } +}; + +template +struct hash { + using is_avalanching = void; + auto operator()(T* ptr) const noexcept -> uint64_t { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + return detail::wyhash::hash(reinterpret_cast(ptr)); + } +}; + +template +struct hash> { + using is_avalanching = void; + auto operator()(std::unique_ptr const& ptr) const noexcept -> uint64_t { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + return detail::wyhash::hash(reinterpret_cast(ptr.get())); + } +}; + +template +struct hash> { + using is_avalanching = void; + auto operator()(std::shared_ptr const& ptr) const noexcept -> uint64_t { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + return detail::wyhash::hash(reinterpret_cast(ptr.get())); + } +}; + +template +struct hash::value>::type> { + using is_avalanching = void; + auto operator()(Enum e) const noexcept -> uint64_t { + using underlying = typename std::underlying_type_t; + return detail::wyhash::hash(static_cast(e)); + } +}; + +template +struct tuple_hash_helper { + // Converts the value into 64bit. If it is an integral type, just cast it. Mixing is doing the rest. + // If it isn't an integral we need to hash it. + template + [[nodiscard]] constexpr static auto to64(Arg const& arg) -> uint64_t { + if constexpr (std::is_integral_v || std::is_enum_v) { + return static_cast(arg); + } else { + return hash{}(arg); + } + } + + [[nodiscard]] static auto mix64(uint64_t state, uint64_t v) -> uint64_t { + return detail::wyhash::mix(state + v, uint64_t{0x9ddfea08eb382d69}); + } + + // Creates a buffer that holds all the data from each element of the tuple. If possible we memcpy the data directly. If + // not, we hash the object and use this for the array. Size of the array is known at compile time, and memcpy is optimized + // away, so filling the buffer is highly efficient. Finally, call wyhash with this buffer. + template + [[nodiscard]] static auto calc_hash(T const& t, std::index_sequence) noexcept -> uint64_t { + auto h = uint64_t{}; + ((h = mix64(h, to64(std::get(t)))), ...); + return h; + } +}; + +template +struct hash> : tuple_hash_helper { + using is_avalanching = void; + auto operator()(std::tuple const& t) const noexcept -> uint64_t { + return tuple_hash_helper::calc_hash(t, std::index_sequence_for{}); + } +}; + +template +struct hash> : tuple_hash_helper { + using is_avalanching = void; + auto operator()(std::pair const& t) const noexcept -> uint64_t { + return tuple_hash_helper::calc_hash(t, std::index_sequence_for{}); + } +}; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +# define ANKERL_UNORDERED_DENSE_HASH_STATICCAST(T) \ + template <> \ + struct hash { \ + using is_avalanching = void; \ + auto operator()(T const& obj) const noexcept -> uint64_t { \ + return detail::wyhash::hash(static_cast(obj)); \ + } \ + } + +# if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wuseless-cast" +# endif +// see https://en.cppreference.com/w/cpp/utility/hash +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(bool); +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(char); +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(signed char); +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(unsigned char); +# if ANKERL_UNORDERED_DENSE_CPP_VERSION >= 202002L && defined(__cpp_char8_t) +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(char8_t); +# endif +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(char16_t); +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(char32_t); +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(wchar_t); +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(short); +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(unsigned short); +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(int); +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(unsigned int); +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(long); +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(long long); +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(unsigned long); +ANKERL_UNORDERED_DENSE_HASH_STATICCAST(unsigned long long); + +# if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic pop +# endif + +// bucket_type ////////////////////////////////////////////////////////// + +namespace bucket_type { + +struct standard { + static constexpr uint32_t dist_inc = 1U << 8U; // skip 1 byte fingerprint + static constexpr uint32_t fingerprint_mask = dist_inc - 1; // mask for 1 byte of fingerprint + + uint32_t m_dist_and_fingerprint; // upper 3 byte: distance to original bucket. lower byte: fingerprint from hash + uint32_t m_value_idx; // index into the m_values vector. +}; + +ANKERL_UNORDERED_DENSE_PACK(struct big { + static constexpr uint32_t dist_inc = 1U << 8U; // skip 1 byte fingerprint + static constexpr uint32_t fingerprint_mask = dist_inc - 1; // mask for 1 byte of fingerprint + + uint32_t m_dist_and_fingerprint; // upper 3 byte: distance to original bucket. lower byte: fingerprint from hash + size_t m_value_idx; // index into the m_values vector. +}); + +} // namespace bucket_type + +namespace detail { + +struct nonesuch {}; +struct default_container_t {}; + +template class Op, class... Args> +struct detector { + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> { + using value_t = std::true_type; + using type = Op; +}; + +template