From e79a2fa8094b956f0e5944d2d05707cf39a0375d Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Wed, 23 Jul 2025 22:57:51 +0800 Subject: [PATCH] [Feat|Fix|Improvement] (All): Continue building the basic structure. Feat: implement MG_Impl/Buffer Feat: implement MG_State/ErrorState and integrate it into MG_State/GLContext Feat: add buffer deletion management Feat: introduce `INSERTION_POINT` (https://github.com/MobileGL-Dev/MobileGLCodeManager) Feat: add tests about MG_Impl/Buffer and buffer deletion feature Feat: add several converters Fix: fix some compiling errors Fix: fix some incorrect behaviors in MG_State/Buffer Improvement: remove some current statements at the beginning of the source file, which will be added uniformly soon Improvement: optimize some naming --- .gitignore | 2 + CMakeLists.txt | 12 +- MobileGL/Includes.h | 40 +- MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp | 440 ++++++++++++++++++ MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h | 17 + MobileGL/MG_Impl/GLImpl/Buffer/Validators.cpp | 71 +++ MobileGL/MG_Impl/GLImpl/Buffer/Validators.h | 10 + .../MG_Impl/GLImpl/Exporting/Definitions.cpp | 20 +- MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp | 16 +- MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.h | 2 + .../GLState/BufferState/BufferObject.h | 17 +- .../GLState/BufferState/BufferState.cpp | 62 ++- .../GLState/BufferState/BufferState.h | 9 +- MobileGL/MG_State/GLState/Core.cpp | 54 ++- MobileGL/MG_State/GLState/Core.h | 20 +- .../MG_State/GLState/ErrorState/Error.cpp | 58 +++ MobileGL/MG_State/GLState/ErrorState/Error.h | 28 ++ .../MG_State/GLState/ErrorState/ErrorCode.h | 14 + .../MG_State/GLState/ErrorState/ErrorInfo.h | 32 ++ MobileGL/MG_Test/Buffer/BufferTest.cpp | 252 +++++++++- MobileGL/MG_Test/Buffer/CMakeLists.txt | 13 + .../GLToGlslang/GLShaderLangConverter.cpp | 6 +- .../GLToGlslang/GLShaderLangConverter.h | 12 +- .../Converters/GLToMG/BufferEnumConverter.cpp | 54 +++ .../Converters/GLToMG/BufferEnumConverter.h | 9 + .../Converters/MGToGL/BufferEnumConverter.cpp | 54 +++ .../Converters/MGToGL/BufferEnumConverter.h | 9 + .../Converters/MGToGL/ErrorCodeConverter.cpp | 28 ++ .../Converters/MGToGL/ErrorCodeConverter.h | 7 + .../MGToStr/BufferEnumConverter.cpp | 57 +++ .../Converters/MGToStr/BufferEnumConverter.h | 9 + MobileGL/MG_Util/Debug/Log.cpp | 10 +- MobileGL/MG_Util/Miscellany/IndexGenerator.h | 10 +- .../ShaderTranspiler/ShaderCompiler.cpp | 6 +- .../MG_Util/ShaderTranspiler/ShaderCompiler.h | 10 +- MobileGL/MG_Util/ShaderTranspiler/Types.h | 9 +- MobileGL/MG_Util/Types.h | 16 +- 37 files changed, 1377 insertions(+), 118 deletions(-) create mode 100644 MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp create mode 100644 MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h create mode 100644 MobileGL/MG_Impl/GLImpl/Buffer/Validators.cpp create mode 100644 MobileGL/MG_Impl/GLImpl/Buffer/Validators.h create mode 100644 MobileGL/MG_State/GLState/ErrorState/Error.cpp create mode 100644 MobileGL/MG_State/GLState/ErrorState/Error.h create mode 100644 MobileGL/MG_State/GLState/ErrorState/ErrorCode.h create mode 100644 MobileGL/MG_State/GLState/ErrorState/ErrorInfo.h create mode 100644 MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.cpp create mode 100644 MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.h create mode 100644 MobileGL/MG_Util/Converters/MGToGL/BufferEnumConverter.cpp create mode 100644 MobileGL/MG_Util/Converters/MGToGL/BufferEnumConverter.h create mode 100644 MobileGL/MG_Util/Converters/MGToGL/ErrorCodeConverter.cpp create mode 100644 MobileGL/MG_Util/Converters/MGToGL/ErrorCodeConverter.h create mode 100644 MobileGL/MG_Util/Converters/MGToStr/BufferEnumConverter.cpp create mode 100644 MobileGL/MG_Util/Converters/MGToStr/BufferEnumConverter.h diff --git a/.gitignore b/.gitignore index 55420895..9086b56b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ CMakeSettings.json MobileGL/MG_Test/out MobileGL/MG_Test/.vs +MobileGLCodeManager.* +MobileGLCodeManager diff --git a/CMakeLists.txt b/CMakeLists.txt index ad457fc1..abe986af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,11 @@ add_library(${CMAKE_PROJECT_NAME} SHARED MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp MobileGL/MG_Util/Converters/MGToStr/GLExtensionConverter.cpp + MobileGL/MG_Util/Converters/MGToStr/BufferEnumConverter.cpp MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp + MobileGL/MG_Util/Converters/MGToGL/ErrorCodeConverter.cpp + MobileGL/MG_Util/Converters/MGToGL/BufferEnumConverter.cpp + MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.cpp MobileGL/MG_Impl/GLXImpl/Exporting/Definitions.cpp MobileGL/MG_Impl/GLXImpl/LookUp/LookUp.cpp @@ -29,16 +33,20 @@ add_library(${CMAKE_PROJECT_NAME} SHARED MobileGL/MG_Impl/EGLImpl/Exporting/Definitions.cpp MobileGL/MG_Impl/EGLImpl/Temporary/TemporaryEGLImpl.cpp + # @INSERTION_POINT:SOURCE_FILE_GLIMPL@ # MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp + MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp + MobileGL/MG_Impl/GLImpl/Buffer/Validators.cpp MobileGL/MG_Backend/Init.cpp MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp MobileGL/MG_State/GLState/Core.cpp + MobileGL/MG_State/GLState/ErrorState/Error.cpp MobileGL/MG_State/GLState/BufferState/BufferState.cpp -) + ) target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/library/arm64-v8a/libglslang.a @@ -72,4 +80,4 @@ target_link_libraries(MobileGL # Diligent-Common # Diligent-GraphicsEngineOpenGL-shared # Diligent-GraphicsEngineVk-shared -) \ No newline at end of file +) diff --git a/MobileGL/Includes.h b/MobileGL/Includes.h index 458afa00..d3d997f0 100644 --- a/MobileGL/Includes.h +++ b/MobileGL/Includes.h @@ -1,7 +1,7 @@ #pragma once #ifdef __ANDROID__ -#define __ANDROID_API__ 26 // fix pthread_getname_np not defined +#define __ANDROID_API__ 26 // force Android API level to 26 for compatibility #endif #ifdef _WIN32 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,9 @@ #include #include #include +#include +#include +#include #ifdef __ANDROID__ #include @@ -85,20 +89,16 @@ typedef int android_LogPriority; -int __android_log_print(int prio, const char *tag, const char *fmt, ...); +inline int __android_log_print(int prio, const char* tag, const char* fmt, ...) { } #endif -#include -#include -#include - #include "MG_Util/GLExtensions.h" #include "MG_Util/Types.h" #include "MG_Util/Miscellany/IndexGenerator.h" #include "MG_Util/Debug/Log.h" -#include "MG_Util/Converters/GLToStr/GLEnumConverter.h" -#include "MG_Util/Converters/MGToStr/GLExtensionConverter.h" -#include "MG_Util/Converters/GLToGlslang/GLShaderLangConverter.h" +#include "MG_State/GLState/ErrorState/ErrorCode.h" +#include "MG_State/GLState/ErrorState/ErrorInfo.h" +#include "MG_State/GLState/ErrorState/Error.h" #include "MG_Backend/Backends.h" @@ -107,14 +107,20 @@ int __android_log_print(int prio, const char *tag, const char *fmt, ...); #include "MG_Impl/GLXImpl/LookUp/LookUp.h" #include "MG_Impl/EGLImpl/Temporary/TemporaryEGLImpl.h" -#include "MG_Impl/GLImpl/Getter/GL_Getter.h" - -//#include "MG_Util/Pipelines/PipelineExecutor.hpp" - -//#include "MG_Util/Pipelines/ShaderCompilationPipeline.h" - -// #include "MG_Util/ShaderTranspiler/glslang/UniformTraverser.h" - #include "MG_State/GLState/BufferState/BufferObject.h" #include "MG_State/GLState/BufferState/BufferState.h" + +/* @INSERTION_POINT:HEADER_FILE_GLIMPL@ */ +#include "MG_Impl/GLImpl/Getter/GL_Getter.h" +#include "MG_Impl/GLImpl/Buffer/GL_Buffer.h" +#include "MG_Impl/GLImpl/Buffer/Validators.h" + #include "MG_State/GLState/Core.h" + +#include "MG_Util/Converters/GLToMG/BufferEnumConverter.h" +#include "MG_Util/Converters/MGToGL/BufferEnumConverter.h" +#include "MG_Util/Converters/MGToGL/ErrorCodeConverter.h" +#include "MG_Util/Converters/GLToStr/GLEnumConverter.h" +#include "MG_Util/Converters/MGToStr/BufferEnumConverter.h" +#include "MG_Util/Converters/MGToStr/GLExtensionConverter.h" +#include "MG_Util/Converters/GLToGlslang/GLShaderLangConverter.h" diff --git a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp new file mode 100644 index 00000000..66e4aa58 --- /dev/null +++ b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp @@ -0,0 +1,440 @@ +#include "../../../Includes.h" + +namespace MobileGL { + namespace MG_Impl::GLImpl { + void DeleteBuffers_State(GLsizei n, const GLuint* buffers) { + if (n < 0) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "DeleteBuffers_State", + "n must be non-negative.")); + return; + } + + if (!buffers) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "DeleteBuffers_State", + "Buffer names array cannot be null.")); + return; + } + + for (SizeT i = 0; i < static_cast(n); ++i) { + Uint bufferName = buffers[i]; + if (bufferName == 0) continue; + if (!BufferImpl::ValidateBufferName(bufferName)) continue; + MG_State::pGLContext->MarkBufferObjectForDeletion(bufferName); + } + + } + + void FlushMappedBufferRange_State(GLenum target, GLintptr offset, GLsizeiptr length) { + if (length < 0 || offset < 0) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "FlushMappedBufferRange_State", + "Offset and length must be non-negative.")); + return; + } + + BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); + if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return; + + auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); + + auto bufferObject = bindingSlot.GetBoundObject(); + if (!bufferObject) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "FlushMappedBufferRange_State", + "Buffer target is bound to no buffer object.")); + return; + } + + if (!bufferObject->IsMapped()) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "FlushMappedBufferRange_State", + "Cannot flush a buffer object that is not mapped.")); + return; + } + + if (offset + length > bufferObject->GetSize()) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "FlushMappedBufferRange_State", + "Offset and length exceed buffer size.")); + return; + } + + BufferMappingAccessBit mappingAccess = bufferObject->GetMappingAccess(); + if(!Any(mappingAccess & BufferMappingAccessBit::FlushExplicit)) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "FlushMappedBufferRange_State", + "Cannot flush a buffer object that is not mapped with GL_MAP_FLUSH_EXPLICIT_BIT.")); + return; + } + + bufferObject->FlushMemoryRange(static_cast(offset), static_cast(length)); + } + + GLboolean UnmapBuffer_State(GLenum target) { + BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); + if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return GL_FALSE; + + auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); + + auto bufferObject = bindingSlot.GetBoundObject(); + if (!bufferObject) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "UnmapBuffer_State", + "Buffer target is bound to no buffer object.")); + return GL_FALSE; + } + + if (!bufferObject->IsMapped()) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "UnmapBuffer_State", + "Cannot unmap a buffer object that is not mapped.")); + return GL_FALSE; + } + + bufferObject->ReleaseMemory(); + return GL_TRUE; + } + + void* MapBufferRange_State(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { + if (length < 0 || offset < 0) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "MapBufferRange_State", + "Offset and length must be non-negative.")); + return nullptr; + } + + if (length == 0) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "MapBufferRange_State", + "Length must be greater than zero.")); + return nullptr; + } + + BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); + if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return nullptr; + + auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); + auto bufferObject = bindingSlot.GetBoundObject(); + if (!bufferObject) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "MapBufferRange_State", + "Buffer target is bound to no buffer object.")); + return nullptr; + } + + if (offset + length > bufferObject->GetSize()) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "MapBufferRange_State", + "Offset and length exceed buffer size.")); + return nullptr; + } + + auto accessBits = MG_Util::ConvertGLEnumToBufferMappingAccess(access); + if (!BufferImpl::ValidateBufferMappingAccess(accessBits)) return nullptr; + + if (!Any(accessBits & (BufferMappingAccessBit::Read | BufferMappingAccessBit::Write))) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "MapBufferRange_State", + "At least one of GL_MAP_READ_BIT or GL_MAP_WRITE_BIT must be set.")); + return nullptr; + } + + if (Any(accessBits & BufferMappingAccessBit::Read)) { + const auto invalidFlags = BufferMappingAccessBit::InvalidateRange | + BufferMappingAccessBit::InvalidateBuffer | + BufferMappingAccessBit::Unsynchronized; + + if (Any(accessBits & invalidFlags)) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "MapBufferRange_State", + "GL_MAP_READ_BIT cannot be combined with invalidation or unsynchronized flags.")); + return nullptr; + } + } + + if (Any(accessBits & BufferMappingAccessBit::FlushExplicit)) { + if (!(Any(accessBits & BufferMappingAccessBit::Write))) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "MapBufferRange_State", + "GL_MAP_FLUSH_EXPLICIT_BIT requires GL_MAP_WRITE_BIT.")); + return nullptr; + } + } + + const BufferMappingAccessBit storageFlags = + BufferMappingAccessBit::Persistent | BufferMappingAccessBit::Coherent; + BufferMappingAccessBit requiredFlags = accessBits & storageFlags; + if (Any(requiredFlags)) { + // TODO: check if the buffer data is created by BufferStorage and its flags after its implementation + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "MapBufferRange_State", + "Access flags require matching storage flags in buffer.")); + return nullptr; + } + + if (bufferObject->IsMapped()) { + const auto invalidateFlags = BufferMappingAccessBit::InvalidateRange | + BufferMappingAccessBit::InvalidateBuffer; + + if (!Any(accessBits & invalidateFlags)) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "MapBufferRange_State", + "Cannot map a buffer object that is already mapped.")); + return nullptr; + } + } + + void* result = bufferObject->AcquireMemoryRange( + { static_cast(offset), static_cast(offset + length) }, + accessBits + ); + if (!result) { + MG_State::pGLContext->RecordError(ErrorCode::OutOfMemory, + MakeShared("MG_Impl/GLImpl", "MapBufferRange_State", + "Failed to map buffer due to insufficient memory.")); + return nullptr; + } + return result; + } + + void* MapBuffer_State(GLenum target, GLenum access) { + bool readable = access == GL_READ_ONLY || access == GL_READ_WRITE; + bool writable = access == GL_WRITE_ONLY || access == GL_READ_WRITE; + if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum, + MakeShared("MG_Impl/GLImpl", "MapBuffer_State", + "Access must be one of GL_READ_ONLY, GL_WRITE_ONLY, or GL_READ_WRITE.")); + return nullptr; + } + + BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); + if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return nullptr; + auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); + + auto bufferObject = bindingSlot.GetBoundObject(); + if (!bufferObject) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "MapBuffer_State", + "Buffer target is bound to no buffer object.")); + return nullptr; + } + + if (bufferObject->IsMapped()) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "MapBuffer_State", + "Cannot map a buffer object that is already mapped.")); + return nullptr; + } + + void* result = bufferObject->AcquireMemory(true, readable, writable); + if (!result) { + MG_State::pGLContext->RecordError(ErrorCode::OutOfMemory, + MakeShared("MG_Impl/GLImpl", "MapBuffer_State", + "Failed to map buffer due to insufficient memory.")); + return nullptr; + } + return result; + } + + void CopyBufferSubData_State(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { + if (size < 0 || readOffset < 0 || writeOffset < 0) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "CopyBufferSubData_State", + "Offset and size must be non-negative.")); + return; + } + + BufferTarget readBufferTarget = MG_Util::ConvertGLEnumToBufferTarget(readTarget); + BufferTarget writeBufferTarget = MG_Util::ConvertGLEnumToBufferTarget(writeTarget); + if (!BufferImpl::ValidateBufferTarget(readBufferTarget) || !BufferImpl::ValidateBufferTarget(writeBufferTarget)) return; + + auto& readBindingSlot = MG_State::pGLContext->GetBufferBindingSlot(readBufferTarget); + auto& writeBindingSlot = MG_State::pGLContext->GetBufferBindingSlot(writeBufferTarget); + auto readBufferObject = readBindingSlot.GetBoundObject(); + auto writeBufferObject = writeBindingSlot.GetBoundObject(); + + if (!readBufferObject || !writeBufferObject) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "CopyBufferSubData_State", + "One of the buffer targets is bound to no buffer object.")); + return; + } + + if (readOffset + size > readBufferObject->GetSize() || writeOffset + size > writeBufferObject->GetSize()) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "CopyBufferSubData_State", + "Offset and size must be within the bounds of the buffer objects.")); + return; + } + + if (readBufferObject == writeBufferObject) { + if ((readOffset <= writeOffset && readOffset + size > writeOffset) || + (writeOffset <= readOffset && writeOffset + size > readOffset)) + MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "CopyBufferSubData_State", + "Source and destination buffers overlap in the specified ranges.")); + return; + } + + auto isIllegallyMapped = [](const SharedPtr& buffer) { + return buffer->IsMapped() && !Any(buffer->GetMappingAccess() & BufferMappingAccessBit::Persistent); + }; + if (isIllegallyMapped(readBufferObject) || isIllegallyMapped(writeBufferObject)) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "CopyBufferSubData_State", + "Cannot copy data from/to a mapped buffer object unless it was mapped with GL_MAP_PERSISTENT_BIT.")); + return; + } + + writeBufferObject->CopyDataFrom(readBufferObject, readOffset, writeOffset, size); + } + + void BufferSubData_State(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) { + if (!data) { + MG_State::pGLContext->RecordError(ErrorCode::NoError, // somehow OpenGL does not generate an error for this + MakeShared("MG_Impl/GLImpl", "BufferSubData_State", + "Data pointer cannot be null.")); + return; + } + + if (size < 0 || offset < 0) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "BufferSubData_State", + "Offset and size must be non-negative.")); + return; + } + + BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); + if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return; + auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); + + auto bufferObject = bindingSlot.GetBoundObject(); + if (!bufferObject) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "BufferSubData_State", + "Buffer target is bound to no buffer object.")); + return; + } + + SizeT bufferSize = bufferObject->GetSize(); + Range1D mappedRange = bufferObject->GetMappedRange(); + if ((offset < mappedRange.end) && (offset + size > mappedRange.start)) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "BufferSubData_State", + "Offset and size must not overlap with the mapped range of the buffer object.")); + return; + } + + BufferMappingAccessBit mappingAccess = bufferObject->GetMappingAccess(); + if (bufferObject->IsMapped() && !Any(mappingAccess & BufferMappingAccessBit::Persistent)) { + Range1D mappedRange = bufferObject->GetMappedRange(); + if (offset + size >= mappedRange.start) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "BufferSubData_State", + "Cannot modify a mapped buffer object unless it was mapped with GL_MAP_PERSISTENT_BIT.")); + return; + } + } + + bufferObject->UploadSubData({ (void*)data, (SizeT)size }, offset); + } + + void BufferData_State(GLenum target, GLsizeiptr size, const void* data, GLenum usage) { + if (size < 0) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "BufferData_State", + "Size must be non-negative.")); + return; + } + + BufferUsage bufferUsage = MG_Util::ConvertGLEnumToBufferUsage(usage); + if (!BufferImpl::ValidateBufferUsage(bufferUsage)) return; + + BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); + if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return; + auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); + + auto bufferObject = bindingSlot.GetBoundObject(); + if (!bufferObject) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", "BufferData_State", + "Buffer target is bound to no buffer object.")); + return; + } + + bufferObject->SetUsage(bufferUsage); + bufferObject->Resize(size); + if (data) { + bufferObject->UploadData({ (void*)data, (SizeT)size }, 0); + } + } + + void BindBuffer_State(GLenum target, GLuint buffer) { + if (buffer != 0 && !BufferImpl::ValidateBufferName(buffer)) return; + BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target); + if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return; + + auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer); + if (!bufferObject) { + MG_State::pGLContext->CreateBufferObject(buffer); + bufferObject = MG_State::pGLContext->GetBufferObject(buffer); + } + + auto& bindingSlot = MG_State::pGLContext->GetBufferBindingSlot(bufferTarget); + bindingSlot.Bind(bufferObject); + } + + void GenBuffers_State(GLsizei n, GLuint* buffers) { + if (n < 0) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", "GenBuffers_State", "n must be non-negative")); + return; + } + auto bufferNames = MG_State::pGLContext->GenBufferNames(n); + Copy(bufferNames.data(), buffers, bufferNames.size()); + } + + /* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */ + void DeleteBuffers(GLsizei n, const GLuint* buffers) { + DeleteBuffers_State(n, buffers); + } + + void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) { + FlushMappedBufferRange_State(target, offset, length); + } + + GLboolean UnmapBuffer(GLenum target) { + return UnmapBuffer_State(target); + } + + void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { + return MapBufferRange_State(target, offset, length, access); + } + + void* MapBuffer(GLenum target, GLenum access) { + return MapBuffer_State(target, access); + } + + void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { + CopyBufferSubData_State(readTarget, writeTarget, readOffset, writeOffset, size); + } + + void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) { + BufferSubData_State(target, offset, size, data); + } + + void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) { + BufferData_State(target, size, data, usage); + } + + void BindBuffer(GLenum target, GLuint buffer) { + BindBuffer_State(target, buffer); + } + + void GenBuffers(GLsizei n, GLuint* buffers) { + GenBuffers_State(n, buffers); + } + } +} diff --git a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h new file mode 100644 index 00000000..e01adaa5 --- /dev/null +++ b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h @@ -0,0 +1,17 @@ +#pragma once + +namespace MobileGL { + namespace MG_Impl::GLImpl { + /* @INSERTION_POINT:FUNCTION_DECLARATION@ */ + void DeleteBuffers(GLsizei n, const GLuint* buffers); + void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length); + GLboolean UnmapBuffer(GLenum target); + void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); + void* MapBuffer(GLenum target, GLenum access); + void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); + void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data); + void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage); + void BindBuffer(GLenum target, GLuint buffer); + void GenBuffers(GLsizei n, GLuint* buffers); + } +} diff --git a/MobileGL/MG_Impl/GLImpl/Buffer/Validators.cpp b/MobileGL/MG_Impl/GLImpl/Buffer/Validators.cpp new file mode 100644 index 00000000..7ff17337 --- /dev/null +++ b/MobileGL/MG_Impl/GLImpl/Buffer/Validators.cpp @@ -0,0 +1,71 @@ +#include "../../../Includes.h" + +namespace MobileGL::MG_Impl::GLImpl { + namespace BufferImpl { + bool ValidateBufferTarget(BufferTarget target) { + if (target != BufferTarget::Unknown) + return true; + + using namespace MG_Util; + String bufferTargetStr = ConvertBufferTargetToString(target); + String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target)); + MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum, + MakeShared("MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget", + std::format("Target {} ({}) is not valid.", + bufferTargetStr, glTargetStr))); + return false; + } + + bool ValidateBufferName(Uint index) { + bool isValid = MG_State::pGLContext->ValidateBufferName(index); + if (isValid) + return true; + MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName", + std::format("Buffer name {} is not valid.", index))); + return false; + } + + bool ValidateBufferUsage(BufferUsage usage) { + if (usage != BufferUsage::Unknown) { + return true; + } + using namespace MG_Util; + String bufferUsageStr = ConvertBufferUsageToString(usage); + String glUsageStr = ConvertGLEnumToString(ConvertBufferUsageToGLEnum(usage)); + MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum, + MakeShared("MG_Impl/GLImpl/BufferImpl", "ValidateBufferUsage", + std::format("Usage {} ({}) is not one of the allowable values.", + bufferUsageStr, glUsageStr))); + return false; + } + + bool ValidateBufferMappingAccess(BufferMappingAccessBit accessBits) { + if (accessBits == BufferMappingAccessBit::Null) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum, + MakeShared("MG_Impl/GLImpl/BufferImpl", "ValidateBufferMappingAccess", + "Access bits cannot be null.")); + return false; + } + + const BufferMappingAccessBit validBits = + BufferMappingAccessBit::Read | + BufferMappingAccessBit::Write | + BufferMappingAccessBit::InvalidateRange | + BufferMappingAccessBit::InvalidateBuffer | + BufferMappingAccessBit::FlushExplicit | + BufferMappingAccessBit::Unsynchronized | + BufferMappingAccessBit::Persistent | + BufferMappingAccessBit::Coherent; + + if ((accessBits & validBits) != accessBits) { + MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum, + MakeShared("MG_Impl/GLImpl/BufferImpl", "ValidateBufferMappingAccess", + "Access bits cannot contain invalid flags.")); + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/MobileGL/MG_Impl/GLImpl/Buffer/Validators.h b/MobileGL/MG_Impl/GLImpl/Buffer/Validators.h new file mode 100644 index 00000000..16df8c3d --- /dev/null +++ b/MobileGL/MG_Impl/GLImpl/Buffer/Validators.h @@ -0,0 +1,10 @@ +#pragma once + +namespace MobileGL::MG_Impl::GLImpl { + namespace BufferImpl { + bool ValidateBufferTarget(BufferTarget target); + bool ValidateBufferName(Uint index); + bool ValidateBufferUsage(BufferUsage usage); + bool ValidateBufferMappingAccess(BufferMappingAccessBit accessBits); + } +} \ No newline at end of file diff --git a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp index 9b6afc22..40de21fa 100644 --- a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp +++ b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp @@ -27,12 +27,12 @@ MOBILEGL_GL_API type gl##name(__VA_ARGS__) { DECLARE_GL_FUNCTION_HEAD(const GLubyte*, GetStringi, GLenum name, GLuint index) DECLARE_GL_FUNCTION_END(const GLubyte*, GetStringi, name, index) DECLARE_GL_FUNCTION_HEAD(const GLubyte*, GetString, GLenum name) DECLARE_GL_FUNCTION_END(const GLubyte*, GetString, name) -DECLARE_GL_FUNCTION_STUB_HEAD(void*, MapBuffer, GLenum target, GLenum access) DECLARE_GL_FUNCTION_STUB_END(void*, MapBuffer, target, access) +DECLARE_GL_FUNCTION_HEAD(void*, MapBuffer, GLenum target, GLenum access) DECLARE_GL_FUNCTION_END(void*, MapBuffer, target, access) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearDepth, GLclampd depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearDepth, depth) DECLARE_GL_FUNCTION_STUB_HEAD(void, ActiveTexture, GLenum texture) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ActiveTexture, texture) DECLARE_GL_FUNCTION_STUB_HEAD(void, AttachShader, GLuint program, GLuint shader) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, AttachShader, program, shader) DECLARE_GL_FUNCTION_STUB_HEAD(void, BindAttribLocation, GLuint program, GLuint index, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindAttribLocation, program, index, name) -DECLARE_GL_FUNCTION_STUB_HEAD(void, BindBuffer, GLenum target, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindBuffer, target, buffer) +DECLARE_GL_FUNCTION_HEAD(void, BindBuffer, GLenum target, GLuint buffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindBuffer, target, buffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, BindFramebuffer, GLenum target, GLuint framebuffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindFramebuffer, target, framebuffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, BindRenderbuffer, GLenum target, GLuint renderbuffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindRenderbuffer, target, renderbuffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, BindTexture, GLenum target, GLuint texture) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindTexture, target, texture) @@ -41,8 +41,8 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquation, GLenum mode) DECLARE_GL_FUNCT DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationSeparate, modeRGB, modeAlpha) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFunc, GLenum sfactor, GLenum dfactor) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFunc, sfactor, dfactor) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFuncSeparate, GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFuncSeparate, sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha) -DECLARE_GL_FUNCTION_STUB_HEAD(void, BufferData, GLenum target, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_STUB_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, BufferData, GLenum target, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BufferData, target, size, data, usage) +DECLARE_GL_FUNCTION_HEAD(void, 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_STUB_HEAD(GLenum, CheckFramebufferStatus, GLenum target) DECLARE_GL_FUNCTION_STUB_END(GLenum, CheckFramebufferStatus, target) DECLARE_GL_FUNCTION_STUB_HEAD(void, Clear, GLbitfield mask) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Clear, mask) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearColor, red, green, blue, alpha) @@ -57,7 +57,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTexSubImage2D, GLenum target, GLint leve DECLARE_GL_FUNCTION_STUB_HEAD(GLuint, CreateProgram) DECLARE_GL_FUNCTION_STUB_END(GLuint, CreateProgram) DECLARE_GL_FUNCTION_STUB_HEAD(GLuint, CreateShader, GLenum type) DECLARE_GL_FUNCTION_STUB_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_STUB_HEAD(void, DeleteFramebuffers, GLsizei n, const GLuint* framebuffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DeleteFramebuffers, n, framebuffers) DECLARE_GL_FUNCTION_STUB_HEAD(void, DeleteProgram, GLuint program) DECLARE_GL_FUNCTION_STUB_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) @@ -89,7 +89,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetAttachedShaders, GLuint program, GLsizei DECLARE_GL_FUNCTION_STUB_HEAD(GLint, GetAttribLocation, GLuint program, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END(GLint, GetAttribLocation, program, name) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBooleanv, GLenum pname, GLboolean* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBooleanv, pname, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBufferParameteriv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBufferParameteriv, target, pname, params) -DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, GetError) DECLARE_GL_FUNCTION_STUB_END(GLenum, GetError) +DECLARE_GL_FUNCTION_HEAD(GLenum, GetError) DECLARE_GL_FUNCTION_END(GLenum, GetError) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetFloatv, GLenum pname, GLfloat* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetFloatv, pname, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetFramebufferAttachmentParameteriv, target, attachment, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetIntegerv, GLenum pname, GLint* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetIntegerv, pname, data) @@ -184,7 +184,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, BeginQuery, GLenum target, GLuint id) DECLAR DECLARE_GL_FUNCTION_STUB_HEAD(void, EndQuery, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EndQuery, target) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryiv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryiv, target, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryObjectuiv, GLuint id, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryObjectuiv, id, pname, params) -DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, UnmapBuffer, GLenum target) DECLARE_GL_FUNCTION_STUB_END(GLboolean, UnmapBuffer, target) +DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapBuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLboolean, UnmapBuffer, target) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBufferPointerv, GLenum target, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBufferPointerv, target, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, DrawBuffers, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DrawBuffers, n, bufs) DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix2x3fv, location, count, transpose, value) @@ -197,7 +197,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, BlitFramebuffer, GLint srcX0, GLint srcY0, G //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_STUB_HEAD(void, BindVertexArray, GLuint array) DECLARE_GL_FUNCTION_STUB_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_STUB_HEAD(void, GenVertexArrays, GLsizei n, GLuint* arrays) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenVertexArrays, n, arrays) @@ -230,7 +230,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) @@ -2792,4 +2792,4 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, ReplacementCodeuiTexCoord2fVertex3fvSUN, con DECLARE_GL_FUNCTION_STUB_HEAD(void, ReplacementCodeuiTexCoord2fNormal3fVertex3fSUN, GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ReplacementCodeuiTexCoord2fNormal3fVertex3fSUN, rc, s, t, nx, ny, nz, x, y, z) DECLARE_GL_FUNCTION_STUB_HEAD(void, ReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN, const GLuint* rc, const GLfloat* tc, const GLfloat* n, const GLfloat* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN, rc, tc, n, v) DECLARE_GL_FUNCTION_STUB_HEAD(void, ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN, GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN, rc, s, t, r, g, b, a, nx, ny, nz, x, y, z) -DECLARE_GL_FUNCTION_STUB_HEAD(void, ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN, const GLuint* rc, const GLfloat* tc, const GLfloat* c, const GLfloat* n, const GLfloat* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN, rc, tc, c, n, v) \ No newline at end of file +DECLARE_GL_FUNCTION_STUB_HEAD(void, ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN, const GLuint* rc, const GLfloat* tc, const GLfloat* c, const GLfloat* n, const GLfloat* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN, rc, tc, c, n, v) diff --git a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp index aa41466d..8ccb8fee 100644 --- a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp +++ b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp @@ -2,11 +2,16 @@ namespace MobileGL { namespace MG_Impl::GLImpl { + /* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */ const GLubyte* GetString(GLenum name) { + static String vendorString; + static String versionStr; + static String rendererString; + static String shadingLanguageVersion; + static String extensionsString; MGLOG_D("glGetString, name: %s", MG_Util::ConvertGLEnumToString(name).c_str()); switch (name) { case GL_VENDOR: - static String vendorString; if (vendorString.empty()) { if (MG_Config::RendererInfoPtr->ExtraVendor.has_value()) { vendorString = std::format("{}{}", @@ -17,7 +22,6 @@ namespace MobileGL { } return (const GLubyte*)vendorString.c_str(); case GL_VERSION: { - static String versionStr; if (versionStr.empty()) { versionStr = std::format("{} {}, {} Backend, Version {}", MG_Config::RendererInfoPtr->RendererGLInfo.TargetGLVersion.toString().c_str(), @@ -30,7 +34,6 @@ namespace MobileGL { case GL_RENDERER: { - static String rendererString; if (rendererString.empty()) { String deviceInfo; rendererString = std::format("{} ({}) ({})", @@ -41,7 +44,6 @@ namespace MobileGL { return (const GLubyte*)rendererString.c_str(); } case GL_SHADING_LANGUAGE_VERSION: - static String shadingLanguageVersion; if (shadingLanguageVersion.empty()) { shadingLanguageVersion = std::format("{} MobileGL", MG_Config::RendererInfoPtr->RendererGLInfo.TargetGLSLVersion.toString( @@ -49,7 +51,6 @@ namespace MobileGL { } return (const GLubyte*)shadingLanguageVersion.c_str(); case GL_EXTENSIONS: - static String extensionsString; if (extensionsString.empty()) { for (auto& ext : MG_Config::RendererInfoPtr->RendererGLInfo.Extensions) { extensionsString += MG_Util::ConvertetGLExtToString(ext); @@ -124,5 +125,10 @@ namespace MobileGL { break; } } + + GLenum GetError() { + ErrorCode errorCode = MG_State::pGLContext->PopGLError().value_or(Error{ ErrorCode::NoError, nullptr }).code; + return MG_Util::ConvertErrorCodeToGLEnum(errorCode); + } } } \ No newline at end of file diff --git a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.h b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.h index 2ffb3fe6..272f8b90 100644 --- a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.h +++ b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.h @@ -2,8 +2,10 @@ namespace MobileGL { namespace MG_Impl::GLImpl { + /* @INSERTION_POINT:FUNCTION_DECLARATION@ */ const GLubyte* GetString(GLenum name); const GLubyte* GetStringi(GLenum name, GLuint index); void GetIntegerv(GLenum pname, GLint* params); + GLenum GetError(); } } \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/BufferState/BufferObject.h b/MobileGL/MG_State/GLState/BufferState/BufferObject.h index 4e366c9e..7f46ed6f 100644 --- a/MobileGL/MG_State/GLState/BufferState/BufferObject.h +++ b/MobileGL/MG_State/GLState/BufferState/BufferObject.h @@ -16,7 +16,8 @@ namespace MobileGL { DispatchIndirect, DrawIndirect, ShaderStorage, - BufferTargetCount + BufferTargetCount, + Unknown = -1 }; enum class BufferUsage { @@ -28,7 +29,8 @@ namespace MobileGL { StaticCopy, DynamicDraw, DynamicRead, - DynamicCopy + DynamicCopy, + Unknown = -1 }; enum class BufferMappingAccessBit : Uint { @@ -38,7 +40,9 @@ namespace MobileGL { InvalidateRange = 0x04, InvalidateBuffer = 0x08, FlushExplicit = 0x10, - Unsynchronized = 0x20 + Unsynchronized = 0x20, + Persistent = 0x40, + Coherent = 0x80 }; inline BufferMappingAccessBit operator|(BufferMappingAccessBit a, BufferMappingAccessBit b) { @@ -56,7 +60,7 @@ namespace MobileGL { return static_cast(static_cast(a) & static_cast(b)); } - inline bool any(BufferMappingAccessBit a) { + inline bool Any(BufferMappingAccessBit a) { using T = std::underlying_type_t; return static_cast(a) != 0; } @@ -76,7 +80,7 @@ namespace MobileGL { void* AcquireMemoryRange(Range1D range, BufferMappingAccessBit access); void ReleaseMemory(); void FlushMemoryRange(SizeT offset, SizeT length); - void UploadSubData(SizeT offset, SizeT size, const void* data); + void UploadSubData(DataPtr data, SizeT atOffset); void CopyDataFrom(const SharedPtr& src, SizeT srcOffset, SizeT dstOffset, SizeT size); void ClearDirty(); @@ -84,7 +88,8 @@ namespace MobileGL { SizeT GetSize() const; BufferUsage GetUsage() const; Range1D GetDirtyRange() const; - + Range1D GetMappedRange() const; + BufferMappingAccessBit GetMappingAccess() const; private: Int m_id = 0; SizeT m_size = 0; diff --git a/MobileGL/MG_State/GLState/BufferState/BufferState.cpp b/MobileGL/MG_State/GLState/BufferState/BufferState.cpp index 60fc399c..56548ddc 100644 --- a/MobileGL/MG_State/GLState/BufferState/BufferState.cpp +++ b/MobileGL/MG_State/GLState/BufferState/BufferState.cpp @@ -31,8 +31,8 @@ namespace MobileGL { void BufferObject::ReleaseMemory() { if (!m_isMapped) return; - if (any(m_mappingAccess & BufferMappingAccessBit::Write)) { // if we wrote to the buffer - if (!any(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly + if (Any(m_mappingAccess & BufferMappingAccessBit::Write)) { // if we wrote to the buffer + if (!Any(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly memcpy(m_data.data() + m_mappedRange.start, m_stagingData.data(), m_mappedRange.end - m_mappedRange.start); @@ -50,8 +50,8 @@ namespace MobileGL { void BufferObject::FlushMemoryRange(SizeT offset, SizeT length) { assert(m_isMapped); - assert(any(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)); - assert(any(m_mappingAccess & BufferMappingAccessBit::Write)); + assert(Any(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)); + assert(Any(m_mappingAccess & BufferMappingAccessBit::Write)); SizeT start = m_mappedRange.start + offset; SizeT end = start + length; @@ -61,12 +61,12 @@ namespace MobileGL { m_dirtyRange.UnionUpdate(start, end); } - void BufferObject::UploadSubData(SizeT offset, SizeT size, const void* data) { + void BufferObject::UploadSubData(DataPtr data, SizeT atOffset) { assert(!m_isMapped); - assert(offset + size <= m_size); + assert(atOffset + data.size <= m_size); - memcpy(m_data.data() + offset, data, size); - m_dirtyRange.UnionUpdate(offset, offset + size); + memcpy(m_data.data() + atOffset, data.data, data.size); + m_dirtyRange.UnionUpdate(atOffset, atOffset + data.size); } void BufferObject::CopyDataFrom(const SharedPtr& src, SizeT srcOffset, SizeT dstOffset, SizeT size) { @@ -88,11 +88,11 @@ namespace MobileGL { (write ? BufferMappingAccessBit::Write : BufferMappingAccessBit::Null); m_mappedRange = { 0, m_size }; - if (any(m_mappingAccess & BufferMappingAccessBit::Write)) { + if (Any(m_mappingAccess & BufferMappingAccessBit::Write)) { m_stagingData.resize(m_size); m_ownsStagingData = true; - if (!any(m_mappingAccess & (BufferMappingAccessBit::InvalidateRange | + if (!Any(m_mappingAccess & (BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) { memcpy(m_stagingData.data(), m_data.data(), m_size); } @@ -110,11 +110,11 @@ namespace MobileGL { m_mappingAccess = access; m_mappedRange = range; - if (any(access & BufferMappingAccessBit::Write)) { + if (Any(access & BufferMappingAccessBit::Write)) { m_stagingData.resize(range.end - range.start); m_ownsStagingData = true; - if (!any(access & (BufferMappingAccessBit::InvalidateRange | + if (!Any(access & (BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) { memcpy(m_stagingData.data(), m_data.data() + range.start, m_stagingData.size()); } @@ -147,7 +147,22 @@ namespace MobileGL { return m_isMapped; } + Range1D BufferObject::GetMappedRange() const { + return m_isMapped ? m_mappedRange : Range1D{ 0, 0 }; + } + + BufferMappingAccessBit BufferObject::GetMappingAccess() const { + return m_isMapped ? m_mappingAccess : BufferMappingAccessBit::Null; + } + // BufferState + BufferState::BufferState() + : m_indexGenerator(1024, 1) { + for (SizeT i = 0; i < (SizeT)BufferTarget::BufferTargetCount; ++i) { + m_bindingSlots[i] = BindingSlot((BufferTarget)i); + } + } + SharedPtr BufferState::GetBufferObject(Uint index) { auto it = m_bufferObjects.find(index); if (it != m_bufferObjects.end()) { @@ -171,6 +186,29 @@ namespace MobileGL { BindingSlot& BufferState::GetBindingSlot(BufferTarget target) { return m_bindingSlots[(SizeT)target]; } + + void BufferState::MarkBufferObjectForDeletion(Uint index) { + if (m_indexGenerator.IsValid(index)) { + auto it = m_bufferObjects.find(index); + if (it != m_bufferObjects.end()) { + for (SizeT i = 0; i < (SizeT)BufferTarget::BufferTargetCount; ++i) { + if (m_bindingSlots[i].GetBoundObject() == it->second) { + m_bindingSlots[i].Bind(nullptr); + } + } + m_bufferObjects.erase(it); + } + m_indexGenerator.Delete(index); + } + } + + bool BufferState::ValidateName(Uint index) const { + return m_indexGenerator.IsValid(index); + } + + bool BufferState::ValidateBufferObject(Uint index) const { + return m_bufferObjects.find(index) != m_bufferObjects.end(); + } } } } \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/BufferState/BufferState.h b/MobileGL/MG_State/GLState/BufferState/BufferState.h index cc9eb28f..d12f6347 100644 --- a/MobileGL/MG_State/GLState/BufferState/BufferState.h +++ b/MobileGL/MG_State/GLState/BufferState/BufferState.h @@ -5,16 +5,15 @@ namespace MobileGL { namespace GLState { class BufferState { public: - BufferState() { - for (SizeT i = 0; i < (SizeT)BufferTarget::BufferTargetCount; ++i) { - m_bindingSlots[i] = BindingSlot((BufferTarget)i); - } - } + BufferState(); SharedPtr GetBufferObject(Uint index); Vector GenerateNames(Uint number); SharedPtr CreateBufferObject(Uint index); BindingSlot& GetBindingSlot(BufferTarget target); + void MarkBufferObjectForDeletion(Uint index); + bool ValidateName(Uint index) const; + bool ValidateBufferObject(Uint index) const; private: UnorderedMap> m_bufferObjects; diff --git a/MobileGL/MG_State/GLState/Core.cpp b/MobileGL/MG_State/GLState/Core.cpp index 13ceb62d..05bf018f 100644 --- a/MobileGL/MG_State/GLState/Core.cpp +++ b/MobileGL/MG_State/GLState/Core.cpp @@ -3,20 +3,66 @@ namespace MobileGL { namespace MG_State { namespace GLState { + // Error + void GLContext::RecordError(ErrorCode code, SharedPtr info) { + m_errorState.RecordError(code, info); + } + + bool GLContext::HasGLError() const { + return m_errorState.HasGLError(); + } + + Optional GLContext::PeekGLError() const { + return m_errorState.PeekGLError(); + } + + Optional GLContext::PopGLError() { + return m_errorState.PopGLError(); + } + + bool GLContext::HasNonGLError() const { + return m_errorState.HasNonGLError(); + } + + Optional GLContext::PeekNonGLError() const { + return m_errorState.PeekNonGLError(); + } + + Optional GLContext::PopNonGLError() { + return m_errorState.PopNonGLError(); + } + + void GLContext::ClearErrors() { + m_errorState.Clear(); + } + + // Buffer Vector GLContext::GenBufferNames(Uint number) { - return bufferState_.GenerateNames(number); + return m_bufferState.GenerateNames(number); } SharedPtr GLContext::GetBufferObject(Uint index) { - return bufferState_.GetBufferObject(index); + return m_bufferState.GetBufferObject(index); } BindingSlot& GLContext::GetBufferBindingSlot(BufferTarget target) { - return bufferState_.GetBindingSlot(target); + return m_bufferState.GetBindingSlot(target); } SharedPtr GLContext::CreateBufferObject(Uint index) { - return bufferState_.CreateBufferObject(index); + return m_bufferState.CreateBufferObject(index); + } + + void GLContext::MarkBufferObjectForDeletion(Uint index) { + m_bufferState.MarkBufferObjectForDeletion(index); + } + + bool GLContext::ValidateBufferName(Uint index) const { + return m_bufferState.ValidateName(index); + } + + bool GLContext::ValidateBufferObject(Uint index) const { + return m_bufferState.ValidateBufferObject(index); } } diff --git a/MobileGL/MG_State/GLState/Core.h b/MobileGL/MG_State/GLState/Core.h index e0711c09..81e36551 100644 --- a/MobileGL/MG_State/GLState/Core.h +++ b/MobileGL/MG_State/GLState/Core.h @@ -7,15 +7,31 @@ namespace MobileGL { public: GLContext() = default; + // Error + void RecordError(ErrorCode code, SharedPtr info = nullptr); + bool HasGLError() const; + Optional PeekGLError() const; + Optional PopGLError(); + bool HasNonGLError() const; + Optional PeekNonGLError() const; + Optional PopNonGLError(); + void ClearErrors(); + // Buffer Vector GenBufferNames(Uint number); SharedPtr GetBufferObject(Uint index); BindingSlot& GetBufferBindingSlot(BufferTarget target); - SharedPtr CreateBufferObject(Uint index); + SharedPtr CreateBufferObject(Uint index); + void MarkBufferObjectForDeletion(Uint index); + bool ValidateBufferName(Uint index) const; + bool ValidateBufferObject(Uint index) const; private: + // Error + ErrorState m_errorState; + // Buffer - BufferState bufferState_; + BufferState m_bufferState; }; } diff --git a/MobileGL/MG_State/GLState/ErrorState/Error.cpp b/MobileGL/MG_State/GLState/ErrorState/Error.cpp new file mode 100644 index 00000000..26e3538f --- /dev/null +++ b/MobileGL/MG_State/GLState/ErrorState/Error.cpp @@ -0,0 +1,58 @@ +#include "../../../Includes.h" + +namespace MobileGL { + namespace MG_State { + namespace GLState { + void ErrorState::RecordError(ErrorCode code, SharedPtr info) { + if (code == ErrorCode::NoError) { + MGLOG_E("Recording Non-OpenGL error:\n%s", + info->ToString().c_str()); + m_nonGLErrors.push_back(Error{ code, info }); + } + else { + MGLOG_E("Recording OpenGL error (%s):\n%s", + MG_Util::ConvertGLEnumToString(MG_Util::ConvertErrorCodeToGLEnum(code)).c_str(), + info->ToString().c_str()); + m_errors.push_back(Error{ code, info }); + } + } + + bool ErrorState::HasNonGLError() const { + return !m_nonGLErrors.empty(); + } + + Optional ErrorState::PeekNonGLError() const { + if (m_nonGLErrors.empty()) return Optional{ }; + return Optional{m_nonGLErrors.front()}; + } + + Optional ErrorState::PopNonGLError() { + if (m_nonGLErrors.empty()) return Optional{ }; + auto error = Move(m_nonGLErrors.front()); + m_nonGLErrors.erase(m_nonGLErrors.begin()); + return Optional{ error }; + } + + bool ErrorState::HasGLError() const { + return !m_errors.empty(); + } + + Optional ErrorState::PeekGLError() const { + if (m_errors.empty()) return Optional{ }; + return Optional{m_errors.front()}; + } + + Optional ErrorState::PopGLError() { + if (m_errors.empty()) return Optional{ }; + auto error = Move(m_errors.front()); + m_errors.erase(m_errors.begin()); + return Optional{ error }; + } + + void ErrorState::Clear() { + m_errors.clear(); + m_nonGLErrors.clear(); + } + } + } +} \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/ErrorState/Error.h b/MobileGL/MG_State/GLState/ErrorState/Error.h new file mode 100644 index 00000000..d5a12229 --- /dev/null +++ b/MobileGL/MG_State/GLState/ErrorState/Error.h @@ -0,0 +1,28 @@ +#pragma once + +namespace MobileGL { + struct Error { + ErrorCode code; + SharedPtr info; + }; + + namespace MG_State { + namespace GLState { + class ErrorState { + public: + void RecordError(ErrorCode code, SharedPtr info = nullptr); + bool HasNonGLError() const; + Optional PeekNonGLError() const; + Optional PopNonGLError(); + bool HasGLError() const; + Optional PeekGLError() const; + Optional PopGLError(); + void Clear(); + + private: + Vector m_errors; + Vector m_nonGLErrors; + }; + } + } +} \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/ErrorState/ErrorCode.h b/MobileGL/MG_State/GLState/ErrorState/ErrorCode.h new file mode 100644 index 00000000..daa0d87b --- /dev/null +++ b/MobileGL/MG_State/GLState/ErrorState/ErrorCode.h @@ -0,0 +1,14 @@ +#pragma once + +namespace MobileGL { + enum class ErrorCode { + NoError = 0, + InvalidEnum, + InvalidValue, + InvalidOperation, + InvalidFramebufferOperation, + OutOfMemory, + StackUnderflow, + StackOverflow + }; +} diff --git a/MobileGL/MG_State/GLState/ErrorState/ErrorInfo.h b/MobileGL/MG_State/GLState/ErrorState/ErrorInfo.h new file mode 100644 index 00000000..b2d6d524 --- /dev/null +++ b/MobileGL/MG_State/GLState/ErrorState/ErrorInfo.h @@ -0,0 +1,32 @@ +#pragma once + +namespace MobileGL { + class ErrorInfo { + public: + virtual ~ErrorInfo() = default; + virtual String ToString() const = 0; + }; + + class GenericErrorInfo : public ErrorInfo { + public: + explicit GenericErrorInfo(String message) : m_message(Move(message)) {} + explicit GenericErrorInfo(String m_prefix, String message) : m_message(Move(message)), m_prefix(Move(m_prefix)) {} + explicit GenericErrorInfo(String m_prefix, String m_prefix_2, String message) : m_message(Move(message)), m_prefix(Move(m_prefix)), m_prefix_2(Move(m_prefix_2)) {} + + String ToString() const override { + StringStream ss; + if (m_prefix.has_value()) { + ss << "[" << m_prefix.value() << "] "; + } + if (m_prefix_2.has_value()) { + ss << "[" << m_prefix_2.value() << "] "; + } + ss << m_message; + return ss.str(); + } + private: + String m_message; + Optional m_prefix; + Optional m_prefix_2; + }; +} diff --git a/MobileGL/MG_Test/Buffer/BufferTest.cpp b/MobileGL/MG_Test/Buffer/BufferTest.cpp index cd682c8f..288ced90 100644 --- a/MobileGL/MG_Test/Buffer/BufferTest.cpp +++ b/MobileGL/MG_Test/Buffer/BufferTest.cpp @@ -291,9 +291,8 @@ TEST_F(BufferTest, PartialUpdate) { Vector update{ 999, 888 }; bufObj->UploadSubData( - sizeof(Int), - update.size() * sizeof(Int), - update.data() + { (void*)(update.data()), (SizeT)(update.size() * sizeof(Int)) }, + sizeof(Int) ); Vector expected{ 100, 999, 888, 400, 500 }; @@ -307,3 +306,250 @@ TEST_F(BufferTest, PartialUpdate) { ASSERT_EQ(dirty.start, sizeof(Int)); ASSERT_EQ(dirty.end, 3 * sizeof(Int)); } + +TEST_F(BufferTest, DeleteBufferObject) { + auto bufferNames = glContext.GenBufferNames(1); + auto& slot = glContext.GetBufferBindingSlot(BufferTarget::Vertex); + auto bufObj = glContext.CreateBufferObject(bufferNames[0]); + slot.Bind(bufObj); + ASSERT_TRUE(slot.GetBoundObject() == bufObj); + glContext.MarkBufferObjectForDeletion(bufferNames[0]); + ASSERT_TRUE(slot.GetBoundObject() == nullptr); + ASSERT_FALSE(glContext.GetBufferObject(bufferNames[0])); +} + +using namespace MobileGL::MG_Impl::GLImpl; + +class GeneralBufferTest : public ::testing::Test { +protected: + void SetUp() override { + MG_State::pGLContext = new MG_State::GLState::GLContext(); + } + + GLuint CreateBoundBuffer(GLenum target, GLsizeiptr size, GLenum usage) { + GLuint buffer; + GenBuffers(1, &buffer); + BindBuffer(target, buffer); + BufferData(target, size, nullptr, usage); + EXPECT_EQ(GetError(), GL_NO_ERROR); + return buffer; + } +}; + +TEST_F(GeneralBufferTest, General_BufferLifecycle) { + GLuint buffers[3]; + + GenBuffers(3, buffers); + EXPECT_NE(buffers[0], 0); + EXPECT_NE(buffers[1], 0); + EXPECT_NE(buffers[2], 0); + EXPECT_NE(buffers[0], buffers[1]); + + GLuint deleteBuf = buffers[1]; + DeleteBuffers(1, &deleteBuf); + + BindBuffer(GL_ARRAY_BUFFER, deleteBuf); + EXPECT_EQ(GetError(), GL_INVALID_OPERATION); + + EXPECT_EQ(GetError(), GL_NO_ERROR); +} + +TEST_F(GeneralBufferTest, General_BufferDataOperations) { + GLuint buffer = CreateBoundBuffer(GL_ARRAY_BUFFER, 100, GL_STATIC_DRAW); + + const char initData[100] = { 0 }; + char readBack[100]; + void* mapped = MapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); + ASSERT_NE(mapped, nullptr); + memcpy(readBack, mapped, 100); + EXPECT_EQ(memcmp(initData, readBack, 100), 0); + UnmapBuffer(GL_ARRAY_BUFFER); + + const char subData[] = "TEST"; + BufferSubData(GL_ARRAY_BUFFER, 10, sizeof(subData), subData); + mapped = MapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); + memcpy(readBack, (char*)mapped + 10, sizeof(subData)); + EXPECT_STREQ(readBack, "TEST"); + UnmapBuffer(GL_ARRAY_BUFFER); + + EXPECT_EQ(GetError(), GL_NO_ERROR); +} + +TEST_F(GeneralBufferTest, General_BufferCopy) { + GLuint src = CreateBoundBuffer(GL_COPY_READ_BUFFER, 50, GL_STATIC_READ); + GLuint dst = CreateBoundBuffer(GL_COPY_WRITE_BUFFER, 50, GL_STATIC_DRAW); + + const char srcData[] = "SOURCE_BUFFER_DATA"; + BufferSubData(GL_COPY_READ_BUFFER, 0, sizeof(srcData), srcData); + + void* srcMappedData = MapBuffer(GL_COPY_READ_BUFFER, GL_READ_ONLY); + EXPECT_STREQ((char*)srcMappedData, "SOURCE_BUFFER_DATA"); + UnmapBuffer(GL_COPY_READ_BUFFER); + + CopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 10, sizeof(srcData)); + + char result[50]; + void* mapped = MapBuffer(GL_COPY_WRITE_BUFFER, GL_READ_ONLY); + memcpy(result, (char*)mapped + 10, sizeof(srcData)); + EXPECT_STREQ(result, "SOURCE_BUFFER_DATA"); + UnmapBuffer(GL_COPY_WRITE_BUFFER); + + EXPECT_EQ(GetError(), GL_NO_ERROR); +} + +TEST_F(GeneralBufferTest, General_BufferMapping) { + GLuint buffer = 0; + GenBuffers(1, &buffer); + BindBuffer(GL_ARRAY_BUFFER, buffer); + Vector data; + data.resize(100, '\0'); + BufferData(GL_ARRAY_BUFFER, data.size(), data.data(), GL_DYNAMIC_DRAW); + + void* fullMap = MapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); + ASSERT_NE(fullMap, nullptr); + strcpy((char*)fullMap, " Full mapping test"); + EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER)); + + void* partialMap = MapBufferRange(GL_ARRAY_BUFFER, 0, 30, + GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); + ASSERT_NE(partialMap, nullptr); + strcpy((char*)partialMap, "Partial (not valid value)"); + + FlushMappedBufferRange(GL_ARRAY_BUFFER, 0, 7); + EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER)); + + partialMap = MapBufferRange(GL_ARRAY_BUFFER, 20, 40, + GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); + ASSERT_NE(partialMap, nullptr); + strcpy((char*)partialMap, ": modified data (not valid value)"); + + FlushMappedBufferRange(GL_ARRAY_BUFFER, 0, 15); + EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER)); + + char verify[40]; + void* verifyMap = MapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); + memcpy(verify, (char*)verifyMap, 40); + EXPECT_STREQ(verify, "Partial mapping test: modified data"); + UnmapBuffer(GL_ARRAY_BUFFER); + + EXPECT_EQ(GetError(), GL_NO_ERROR); +} + +TEST_F(GeneralBufferTest, General_InvalidOperations) { + EXPECT_EQ(MapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY), nullptr); // GL_INVALID_OPERATION + EXPECT_EQ(GetError(), GL_INVALID_OPERATION); + + GLuint buffer = CreateBoundBuffer(GL_ARRAY_BUFFER, 50, GL_STREAM_READ); + + EXPECT_EQ(MapBuffer(0xFFFFFFFF, GL_READ_ONLY), nullptr); // GL_INVALID_ENUM + + void* mapped = MapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); + EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER)); + EXPECT_FALSE(UnmapBuffer(GL_ARRAY_BUFFER)); // GL_INVALID_OPERATION + + EXPECT_EQ(GetError(), GL_INVALID_ENUM); + EXPECT_EQ(GetError(), GL_INVALID_OPERATION); + + EXPECT_EQ(GetError(), GL_NO_ERROR); +} + +TEST_F(GeneralBufferTest, General_MapFlags) { + GLuint buffer = CreateBoundBuffer(GL_ARRAY_BUFFER, 100, GL_DYNAMIC_COPY); + + void* roMap = MapBufferRange(GL_ARRAY_BUFFER, 0, 100, GL_MAP_READ_BIT); + ASSERT_NE(roMap, nullptr); + + EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER)); + + void* nosyncMap = MapBufferRange(GL_ARRAY_BUFFER, 0, 100, + GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + ASSERT_NE(nosyncMap, nullptr); + memset(nosyncMap, 0xAA, 100); + EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER)); + + EXPECT_EQ(GetError(), GL_NO_ERROR); +} + +TEST_F(GeneralBufferTest, General_GeneralTest_1) { + GLuint buffers[3]; + GenBuffers(3, buffers); + const GLuint vbo = buffers[0]; + const GLuint ibo = buffers[1]; + const GLuint staging = buffers[2]; + + BindBuffer(GL_ARRAY_BUFFER, vbo); + BufferData(GL_ARRAY_BUFFER, 64, nullptr, GL_STATIC_DRAW); + + const float vertexData[] = { 0.1f, 0.2f, 0.3f, 1.0f }; + BufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertexData), vertexData); + + BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + const uint16_t indexData[] = { 0, 1, 2, 3, 0 }; + BufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexData), indexData, GL_STATIC_DRAW); + + const uint16_t newIndices[] = { 4, 5 }; + BufferSubData(GL_ELEMENT_ARRAY_BUFFER, 2 * sizeof(uint16_t), + sizeof(newIndices), newIndices); + + BindBuffer(GL_COPY_READ_BUFFER, staging); + const char stagingData[] = "StagingBufferData"; + BufferData(GL_COPY_READ_BUFFER, sizeof(stagingData), stagingData, GL_STREAM_COPY); + + CopyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, + 0, 40, sizeof(stagingData)); + + BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + void* fullMap = MapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_WRITE); + ASSERT_NE(fullMap, nullptr); + + uint16_t* indices = static_cast(fullMap); + indices[0] = 10; + + EXPECT_TRUE(UnmapBuffer(GL_ELEMENT_ARRAY_BUFFER)); + + BindBuffer(GL_ARRAY_BUFFER, vbo); + void* partialMap = MapBufferRange(GL_ARRAY_BUFFER, 20, 8, + GL_MAP_WRITE_BIT | + GL_MAP_FLUSH_EXPLICIT_BIT); + ASSERT_NE(partialMap, nullptr); + + const char partialWriteData[] = "PARTIAL"; // 7 chars + '\0' = 8 bytes + memcpy(partialMap, partialWriteData, sizeof(partialWriteData)); + FlushMappedBufferRange(GL_ARRAY_BUFFER, 0, sizeof(partialWriteData)); + + EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER)); + + BindBuffer(GL_ARRAY_BUFFER, vbo); + void* verifyMap = MapBufferRange(GL_ARRAY_BUFFER, 0, 64, GL_MAP_READ_BIT); + ASSERT_NE(verifyMap, nullptr); + + const float* verts = static_cast(verifyMap); + EXPECT_FLOAT_EQ(verts[0], 0.1f); + EXPECT_FLOAT_EQ(verts[1], 0.2f); + + const char* partialData = static_cast(verifyMap) + 20; + EXPECT_STREQ(partialData, "PARTIAL"); + + const char* copiedData = static_cast(verifyMap) + 40; + EXPECT_STREQ(copiedData, "StagingBufferData"); + + EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER)); + + BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + void* iboMap = MapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY); + const uint16_t* finalIndices = static_cast(iboMap); + EXPECT_EQ(finalIndices[0], 10); + EXPECT_EQ(finalIndices[2], 4); + EXPECT_TRUE(UnmapBuffer(GL_ELEMENT_ARRAY_BUFFER)); + + DeleteBuffers(1, &staging); + + BindBuffer(GL_COPY_READ_BUFFER, staging); + GLenum err = GetError(); + EXPECT_EQ(err, GL_INVALID_OPERATION); + + GLuint toDelete[] = { vbo, ibo }; + DeleteBuffers(2, toDelete); + + EXPECT_EQ(GetError(), GL_NO_ERROR); +} \ No newline at end of file diff --git a/MobileGL/MG_Test/Buffer/CMakeLists.txt b/MobileGL/MG_Test/Buffer/CMakeLists.txt index b631e06f..b948b68a 100644 --- a/MobileGL/MG_Test/Buffer/CMakeLists.txt +++ b/MobileGL/MG_Test/Buffer/CMakeLists.txt @@ -6,6 +6,19 @@ add_executable( ${MGL_ROOT}/MobileGL/MG_State/GLState/Core.cpp ${MGL_ROOT}/MobileGL/MG_State/GLState/BufferState/BufferState.cpp + ${MGL_ROOT}/MobileGL/MG_State/GLState/ErrorState/Error.cpp + ${MGL_ROOT}/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp + ${MGL_ROOT}/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp + ${MGL_ROOT}/MobileGL/MG_Impl/GLImpl/Buffer/Validators.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/MGToStr/GLExtensionConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/MGToStr/BufferEnumConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/MGToGL/ErrorCodeConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/MGToGL/BufferEnumConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Backend/Init.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Debug/Log.cpp ) target_include_directories(BufferTest PRIVATE diff --git a/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp b/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp index 77c5d54e..8fdd6090 100644 --- a/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp +++ b/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp @@ -1,8 +1,4 @@ -// -// Created by Swung 0x48 on 2025/7/20. -// - -#include "Includes.h" +#include "../../../Includes.h" namespace MobileGL { namespace MG_Util { diff --git a/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.h b/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.h index 03cc400f..078254e6 100644 --- a/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.h +++ b/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.h @@ -1,15 +1,7 @@ -// -// Created by Swung 0x48 on 2025/7/20. -// - -#ifndef MOBILEGL_GLSHADERLANGCONVERTER_H -#define MOBILEGL_GLSHADERLANGCONVERTER_H +#pragma once namespace MobileGL { namespace MG_Util { EShLanguage ConvertGLEnumToEShLanguage(GLenum shaderType); } -} - - -#endif //MOBILEGL_GLSHADERLANGCONVERTER_H +} \ No newline at end of file diff --git a/MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.cpp b/MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.cpp new file mode 100644 index 00000000..10ee459b --- /dev/null +++ b/MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.cpp @@ -0,0 +1,54 @@ +#include "../../../Includes.h" + +namespace MobileGL { + namespace MG_Util { + BufferTarget ConvertGLEnumToBufferTarget(GLenum bufferTarget) { + switch (bufferTarget) { + case GL_ARRAY_BUFFER: return BufferTarget::Vertex; + case GL_ELEMENT_ARRAY_BUFFER: return BufferTarget::Index; + case GL_UNIFORM_BUFFER: return BufferTarget::Uniform; + case GL_COPY_READ_BUFFER: return BufferTarget::CopyRead; + case GL_COPY_WRITE_BUFFER: return BufferTarget::CopyWrite; + case GL_PIXEL_PACK_BUFFER: return BufferTarget::PixelPack; + case GL_PIXEL_UNPACK_BUFFER: return BufferTarget::PixelUnpack; + case GL_QUERY_BUFFER: return BufferTarget::Query; + case GL_TEXTURE_BUFFER: return BufferTarget::Texture; + case GL_TRANSFORM_FEEDBACK_BUFFER: return BufferTarget::TransformFeedback; + case GL_ATOMIC_COUNTER_BUFFER: return BufferTarget::AtomicCounter; + case GL_DISPATCH_INDIRECT_BUFFER: return BufferTarget::DispatchIndirect; + case GL_DRAW_INDIRECT_BUFFER: return BufferTarget::DrawIndirect; + case GL_SHADER_STORAGE_BUFFER: return BufferTarget::ShaderStorage; + case GL_UNKNOWN_MGL: + default: return BufferTarget::Unknown; + } + } + + BufferUsage ConvertGLEnumToBufferUsage(GLenum usage) { + switch (usage) { + case GL_STREAM_DRAW: return BufferUsage::StreamDraw; + case GL_STREAM_READ: return BufferUsage::StreamRead; + case GL_STREAM_COPY: return BufferUsage::StreamCopy; + case GL_STATIC_DRAW: return BufferUsage::StaticDraw; + case GL_STATIC_READ: return BufferUsage::StaticRead; + case GL_STATIC_COPY: return BufferUsage::StaticCopy; + case GL_DYNAMIC_DRAW: return BufferUsage::DynamicDraw; + case GL_DYNAMIC_READ: return BufferUsage::DynamicRead; + case GL_DYNAMIC_COPY: return BufferUsage::DynamicCopy; + default: return BufferUsage::Unknown; + } + } + + BufferMappingAccessBit ConvertGLEnumToBufferMappingAccess(GLbitfield access) { + BufferMappingAccessBit result = BufferMappingAccessBit::Null; + if (access & GL_MAP_READ_BIT) result |= BufferMappingAccessBit::Read; + if (access & GL_MAP_WRITE_BIT) result |= BufferMappingAccessBit::Write; + if (access & GL_MAP_INVALIDATE_RANGE_BIT) result |= BufferMappingAccessBit::InvalidateRange; + if (access & GL_MAP_INVALIDATE_BUFFER_BIT) result |= BufferMappingAccessBit::InvalidateBuffer; + if (access & GL_MAP_FLUSH_EXPLICIT_BIT) result |= BufferMappingAccessBit::FlushExplicit; + if (access & GL_MAP_UNSYNCHRONIZED_BIT) result |= BufferMappingAccessBit::Unsynchronized; + if (access & GL_MAP_PERSISTENT_BIT) result |= BufferMappingAccessBit::Persistent; + if (access & GL_MAP_COHERENT_BIT) result |= BufferMappingAccessBit::Coherent; + return result; + } + } +} \ No newline at end of file diff --git a/MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.h b/MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.h new file mode 100644 index 00000000..5ee97dc7 --- /dev/null +++ b/MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.h @@ -0,0 +1,9 @@ +#pragma once + +namespace MobileGL { + namespace MG_Util { + BufferTarget ConvertGLEnumToBufferTarget(GLenum bufferTarget); + BufferUsage ConvertGLEnumToBufferUsage(GLenum usage); + BufferMappingAccessBit ConvertGLEnumToBufferMappingAccess(GLbitfield access); + } +} \ No newline at end of file diff --git a/MobileGL/MG_Util/Converters/MGToGL/BufferEnumConverter.cpp b/MobileGL/MG_Util/Converters/MGToGL/BufferEnumConverter.cpp new file mode 100644 index 00000000..2563e582 --- /dev/null +++ b/MobileGL/MG_Util/Converters/MGToGL/BufferEnumConverter.cpp @@ -0,0 +1,54 @@ +#include "../../../Includes.h" + +namespace MobileGL { + namespace MG_Util { + GLenum ConvertBufferTargetToGLEnum(BufferTarget bufferTarget) { + switch (bufferTarget) { + case BufferTarget::Vertex: return GL_ARRAY_BUFFER; + case BufferTarget::Index: return GL_ELEMENT_ARRAY_BUFFER; + case BufferTarget::Uniform: return GL_UNIFORM_BUFFER; + case BufferTarget::CopyRead: return GL_COPY_READ_BUFFER; + case BufferTarget::CopyWrite: return GL_COPY_WRITE_BUFFER; + case BufferTarget::PixelPack: return GL_PIXEL_PACK_BUFFER; + case BufferTarget::PixelUnpack: return GL_PIXEL_UNPACK_BUFFER; + case BufferTarget::Query: return GL_QUERY_BUFFER; + case BufferTarget::Texture: return GL_TEXTURE_BUFFER; + case BufferTarget::TransformFeedback: return GL_TRANSFORM_FEEDBACK_BUFFER; + case BufferTarget::AtomicCounter: return GL_ATOMIC_COUNTER_BUFFER; + case BufferTarget::DispatchIndirect: return GL_DISPATCH_INDIRECT_BUFFER; + case BufferTarget::DrawIndirect: return GL_DRAW_INDIRECT_BUFFER; + case BufferTarget::ShaderStorage: return GL_SHADER_STORAGE_BUFFER; + case BufferTarget::Unknown: + default: return GL_UNKNOWN_MGL; + } + } + + GLenum ConvertBufferUsageToGLEnum(BufferUsage usage) { + switch (usage) { + case BufferUsage::StreamDraw: return GL_STREAM_DRAW; + case BufferUsage::StreamRead: return GL_STREAM_READ; + case BufferUsage::StreamCopy: return GL_STREAM_COPY; + case BufferUsage::StaticDraw: return GL_STATIC_DRAW; + case BufferUsage::StaticRead: return GL_STATIC_READ; + case BufferUsage::StaticCopy: return GL_STATIC_COPY; + case BufferUsage::DynamicDraw: return GL_DYNAMIC_DRAW; + case BufferUsage::DynamicRead: return GL_DYNAMIC_READ; + case BufferUsage::DynamicCopy: return GL_DYNAMIC_COPY; + default: return GL_UNKNOWN_MGL; + } + } + + GLbitfield ConvertBufferMappingAccessToGLEnum(BufferMappingAccessBit access) { + GLbitfield result = 0; + if (Any(access & BufferMappingAccessBit::Read)) result |= GL_MAP_READ_BIT; + if (Any(access & BufferMappingAccessBit::Write)) result |= GL_MAP_WRITE_BIT; + if (Any(access & BufferMappingAccessBit::InvalidateRange)) result |= GL_MAP_INVALIDATE_RANGE_BIT; + if (Any(access & BufferMappingAccessBit::InvalidateBuffer)) result |= GL_MAP_INVALIDATE_BUFFER_BIT; + if (Any(access & BufferMappingAccessBit::FlushExplicit)) result |= GL_MAP_FLUSH_EXPLICIT_BIT; + if (Any(access & BufferMappingAccessBit::Unsynchronized)) result |= GL_MAP_UNSYNCHRONIZED_BIT; + if (Any(access & BufferMappingAccessBit::Persistent)) result |= GL_MAP_PERSISTENT_BIT; + if (Any(access & BufferMappingAccessBit::Coherent)) result |= GL_MAP_COHERENT_BIT; + return result; + } + } +} \ No newline at end of file diff --git a/MobileGL/MG_Util/Converters/MGToGL/BufferEnumConverter.h b/MobileGL/MG_Util/Converters/MGToGL/BufferEnumConverter.h new file mode 100644 index 00000000..949de48b --- /dev/null +++ b/MobileGL/MG_Util/Converters/MGToGL/BufferEnumConverter.h @@ -0,0 +1,9 @@ +#pragma once + +namespace MobileGL { + namespace MG_Util { + GLenum ConvertBufferTargetToGLEnum(BufferTarget bufferTarget); + GLenum ConvertBufferUsageToGLEnum(BufferUsage usage); + GLbitfield ConvertBufferMappingAccessToGLEnum(BufferMappingAccessBit access); + } +} \ No newline at end of file diff --git a/MobileGL/MG_Util/Converters/MGToGL/ErrorCodeConverter.cpp b/MobileGL/MG_Util/Converters/MGToGL/ErrorCodeConverter.cpp new file mode 100644 index 00000000..19cfed3d --- /dev/null +++ b/MobileGL/MG_Util/Converters/MGToGL/ErrorCodeConverter.cpp @@ -0,0 +1,28 @@ +#include "../../../Includes.h" + +namespace MobileGL { + namespace MG_Util { + GLenum ConvertErrorCodeToGLEnum(ErrorCode code) { + switch (code) { + case ErrorCode::NoError: + return GL_NO_ERROR; + case ErrorCode::InvalidEnum: + return GL_INVALID_ENUM; + case ErrorCode::InvalidValue: + return GL_INVALID_VALUE; + case ErrorCode::InvalidOperation: + return GL_INVALID_OPERATION; + case ErrorCode::InvalidFramebufferOperation: + return GL_INVALID_FRAMEBUFFER_OPERATION; + case ErrorCode::OutOfMemory: + return GL_OUT_OF_MEMORY; + case ErrorCode::StackUnderflow: + return GL_STACK_UNDERFLOW; + case ErrorCode::StackOverflow: + return GL_STACK_OVERFLOW; + default: + return GL_NO_ERROR; + } + } + } +} \ No newline at end of file diff --git a/MobileGL/MG_Util/Converters/MGToGL/ErrorCodeConverter.h b/MobileGL/MG_Util/Converters/MGToGL/ErrorCodeConverter.h new file mode 100644 index 00000000..59aee290 --- /dev/null +++ b/MobileGL/MG_Util/Converters/MGToGL/ErrorCodeConverter.h @@ -0,0 +1,7 @@ +#pragma once + +namespace MobileGL { + namespace MG_Util { + GLenum ConvertErrorCodeToGLEnum(ErrorCode code); + } +} \ No newline at end of file diff --git a/MobileGL/MG_Util/Converters/MGToStr/BufferEnumConverter.cpp b/MobileGL/MG_Util/Converters/MGToStr/BufferEnumConverter.cpp new file mode 100644 index 00000000..9fe73797 --- /dev/null +++ b/MobileGL/MG_Util/Converters/MGToStr/BufferEnumConverter.cpp @@ -0,0 +1,57 @@ +#include "../../../Includes.h" + +namespace MobileGL { + namespace MG_Util { + String ConvertBufferTargetToString(BufferTarget bufferTarget) { + switch (bufferTarget) { + case BufferTarget::Vertex: return "Vertex"; + case BufferTarget::Index: return "Index"; + case BufferTarget::Uniform: return "Uniform"; + case BufferTarget::CopyRead: return "CopyRead"; + case BufferTarget::CopyWrite: return "CopyWrite"; + case BufferTarget::PixelPack: return "PixelPack"; + case BufferTarget::PixelUnpack: return "PixelUnpack"; + case BufferTarget::Query: return "Query"; + case BufferTarget::Texture: return "Texture"; + case BufferTarget::TransformFeedback: return "TransformFeedback"; + case BufferTarget::AtomicCounter: return "AtomicCounter"; + case BufferTarget::DispatchIndirect: return "DispatchIndirect"; + case BufferTarget::DrawIndirect: return "DrawIndirect"; + case BufferTarget::ShaderStorage: return "ShaderStorage"; + case BufferTarget::Unknown: + default: return "Unknown"; + } + } + + String ConvertBufferUsageToString(BufferUsage usage) { + switch (usage) { + case BufferUsage::StreamDraw: return "StreamDraw"; + case BufferUsage::StreamRead: return "StreamRead"; + case BufferUsage::StreamCopy: return "StreamCopy"; + case BufferUsage::StaticDraw: return "StaticDraw"; + case BufferUsage::StaticRead: return "StaticRead"; + case BufferUsage::StaticCopy: return "StaticCopy"; + case BufferUsage::DynamicDraw: return "DynamicDraw"; + case BufferUsage::DynamicRead: return "DynamicRead"; + case BufferUsage::DynamicCopy: return "DynamicCopy"; + default: return "Unknown"; + } + } + + String ConvertBufferMappingAccessToString(BufferMappingAccessBit access) { + String result = "["; + if (Any(access & BufferMappingAccessBit::Read)) result += "Read, "; + if (Any(access & BufferMappingAccessBit::Write)) result += "Write, "; + if (Any(access & BufferMappingAccessBit::InvalidateRange)) result += "InvalidateRange, "; + if (Any(access & BufferMappingAccessBit::InvalidateBuffer)) result += "InvalidateBuffer, "; + if (Any(access & BufferMappingAccessBit::FlushExplicit)) result += "FlushExplicit, "; + if (Any(access & BufferMappingAccessBit::Unsynchronized)) result += "Unsynchronized, "; + if (Any(access & BufferMappingAccessBit::Persistent)) result += "Persistent, "; + if (Any(access & BufferMappingAccessBit::Coherent)) result += "Coherent, "; + result.pop_back(); + result.pop_back(); + result += "]"; + return result.empty() ? "[]" : result; + } + } +} \ No newline at end of file diff --git a/MobileGL/MG_Util/Converters/MGToStr/BufferEnumConverter.h b/MobileGL/MG_Util/Converters/MGToStr/BufferEnumConverter.h new file mode 100644 index 00000000..720bab15 --- /dev/null +++ b/MobileGL/MG_Util/Converters/MGToStr/BufferEnumConverter.h @@ -0,0 +1,9 @@ +#pragma once + +namespace MobileGL { + namespace MG_Util { + String ConvertBufferTargetToString(BufferTarget bufferTarget); + String ConvertBufferUsageToString(BufferUsage usage); + String ConvertBufferMappingAccessToString(BufferMappingAccessBit access); + } +} \ No newline at end of file diff --git a/MobileGL/MG_Util/Debug/Log.cpp b/MobileGL/MG_Util/Debug/Log.cpp index 41fd7583..5f0304e9 100644 --- a/MobileGL/MG_Util/Debug/Log.cpp +++ b/MobileGL/MG_Util/Debug/Log.cpp @@ -7,15 +7,15 @@ namespace MobileGL { constexpr char* GetOSName() { #if defined(_WIN32) - return "Windows"; + return (char*)"Windows"; #elif defined(__ANDROID__) - return "Android"; + return (char*)"Android"; #elif defined(__APPLE__) - return "macOS"; + return (char*)"macOS"; #elif defined(__linux__) - return "Linux"; + return (char*)"Linux"; #else - return "UnknownOS"; + return (char*)"UnknownOS"; #endif } diff --git a/MobileGL/MG_Util/Miscellany/IndexGenerator.h b/MobileGL/MG_Util/Miscellany/IndexGenerator.h index 01b1a976..83a19ef5 100644 --- a/MobileGL/MG_Util/Miscellany/IndexGenerator.h +++ b/MobileGL/MG_Util/Miscellany/IndexGenerator.h @@ -7,8 +7,8 @@ namespace MobileGL { template class IndexGenerator { public: - explicit IndexGenerator(size_t initial_capacity = 1024) - : next_index_(0) + explicit IndexGenerator(size_t initial_capacity = 1024, IndexType first_index = 0) + : next_index_(first_index) { is_valid_.reserve(initial_capacity); } @@ -50,9 +50,9 @@ namespace MobileGL { } private: - IndexType next_index_ = 0; - std::vector freed_indices_; - std::vector is_valid_; + IndexType next_index_ = 0; + std::vector freed_indices_; + std::vector is_valid_; }; } diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp index f99425a1..433c5358 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp @@ -1,8 +1,4 @@ -// -// Created by Swung 0x48 on 2025/7/20. -// - -#include "Includes.h" +#include "../../Includes.h" namespace MobileGL { namespace MG_Util { diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h index 9023c67b..56bde616 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h @@ -1,9 +1,4 @@ -// -// Created by Swung 0x48 on 2025/7/20. -// - -#ifndef MOBILEGLTEST_SHADERCOMPILER_H -#define MOBILEGLTEST_SHADERCOMPILER_H +#pragma once namespace MobileGL { namespace MG_Util { @@ -17,6 +12,3 @@ namespace ShaderTranspiler { } } } - - -#endif //MOBILEGLTEST_SHADERCOMPILER_H diff --git a/MobileGL/MG_Util/ShaderTranspiler/Types.h b/MobileGL/MG_Util/ShaderTranspiler/Types.h index 8dfe9675..a16019bf 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/Types.h +++ b/MobileGL/MG_Util/ShaderTranspiler/Types.h @@ -1,9 +1,4 @@ -// -// Created by Swung 0x48 on 2025/7/20. -// - -#ifndef MG_UTIL_SHADERTRANSPILER_TYPES_H -#define MG_UTIL_SHADERTRANSPILER_TYPES_H +#pragma once namespace MobileGL { namespace MG_Util { @@ -145,5 +140,3 @@ namespace MobileGL { } #include "ShaderCompiler.h" - -#endif //MG_UTIL_SHADERTRANSPILER_TYPES_H diff --git a/MobileGL/MG_Util/Types.h b/MobileGL/MG_Util/Types.h index 9080bbd7..05c41e31 100644 --- a/MobileGL/MG_Util/Types.h +++ b/MobileGL/MG_Util/Types.h @@ -1,5 +1,7 @@ #pragma once +#define GL_UNKNOWN_MGL 0 + namespace MobileGL { using String = std::string; using StringStream = std::stringstream; @@ -24,11 +26,11 @@ namespace MobileGL { using SharedPtr = std::shared_ptr; template using UniquePtr = std::unique_ptr; - template + template inline SharedPtr MakeShared(Args&&... args) { return std::make_shared(std::forward(args)...); } - template + template inline UniquePtr MakeUnique(Args&&... args) { return std::make_unique(std::forward(args)...); } @@ -37,10 +39,14 @@ namespace MobileGL { using Array = std::array; template using UnorderedMap = std::unordered_map; - template + template inline constexpr std::remove_reference_t&& Move(T&& t) noexcept { return static_cast&&>(t); } + template + inline constexpr void Copy(const T* src, T* dest, SizeT count) { + std::copy(src, src + count, dest); + } class RuntimeError : public std::runtime_error { public: using std::runtime_error::runtime_error; @@ -100,7 +106,7 @@ namespace MobileGL { } }; - template + template class BindingSlot { public: using TargetEnum = typename ObjectType::TargetEnum; @@ -162,4 +168,4 @@ namespace MobileGL { }; } -#include "MG_Util/ShaderTranspiler/Types.h" +#include "../MG_Util/ShaderTranspiler/Types.h"