mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[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
This commit is contained in:
@@ -9,3 +9,5 @@
|
||||
CMakeSettings.json
|
||||
MobileGL/MG_Test/out
|
||||
MobileGL/MG_Test/.vs
|
||||
MobileGLCodeManager.*
|
||||
MobileGLCodeManager
|
||||
|
||||
+10
-2
@@ -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
|
||||
)
|
||||
)
|
||||
|
||||
+23
-17
@@ -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 <format>
|
||||
#include <memory>
|
||||
#include <bit>
|
||||
#include <cstdarg>
|
||||
#include <functional>
|
||||
#include <expected>
|
||||
|
||||
@@ -55,6 +56,9 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
#include <GLES3/gl32.h>
|
||||
#include <EGL/egl.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
@@ -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 <EGL/egl.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
#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"
|
||||
|
||||
@@ -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<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteBuffers_State",
|
||||
"n must be non-negative."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!buffers) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteBuffers_State",
|
||||
"Buffer names array cannot be null."));
|
||||
return;
|
||||
}
|
||||
|
||||
for (SizeT i = 0; i < static_cast<SizeT>(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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "FlushMappedBufferRange_State",
|
||||
"Buffer target is bound to no buffer object."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bufferObject->IsMapped()) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<SizeT>(offset), static_cast<SizeT>(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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State",
|
||||
"Offset and length must be non-negative."));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "MapBufferRange_State",
|
||||
"Cannot map a buffer object that is already mapped."));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void* result = bufferObject->AcquireMemoryRange(
|
||||
{ static_cast<SizeT>(offset), static_cast<SizeT>(offset + length) },
|
||||
accessBits
|
||||
);
|
||||
if (!result) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::OutOfMemory,
|
||||
MakeShared<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "CopyBufferSubData_State",
|
||||
"Source and destination buffers overlap in the specified ranges."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto isIllegallyMapped = [](const SharedPtr<MG_State::GLState::BufferObject>& buffer) {
|
||||
return buffer->IsMapped() && !Any(buffer->GetMappingAccess() & BufferMappingAccessBit::Persistent);
|
||||
};
|
||||
if (isIllegallyMapped(readBufferObject) || isIllegallyMapped(writeBufferObject)) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "BufferSubData_State",
|
||||
"Data pointer cannot be null."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (size < 0 || offset < 0) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName",
|
||||
std::format("Buffer name {} is not valid.", index)));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ValidateBufferUsage(BufferUsage usage) {
|
||||
if (usage != BufferUsage::Unknown) {
|
||||
return true;
|
||||
}
|
||||
using namespace MG_Util;
|
||||
String bufferUsageStr = ConvertBufferUsageToString(usage);
|
||||
String glUsageStr = ConvertGLEnumToString(ConvertBufferUsageToGLEnum(usage));
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferMappingAccess",
|
||||
"Access bits cannot contain invalid flags."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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<BufferMappingAccessBit>(static_cast<T>(a) & static_cast<T>(b));
|
||||
}
|
||||
|
||||
inline bool any(BufferMappingAccessBit a) {
|
||||
inline bool Any(BufferMappingAccessBit a) {
|
||||
using T = std::underlying_type_t<BufferMappingAccessBit>;
|
||||
return static_cast<T>(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<BufferObject>& 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;
|
||||
|
||||
@@ -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<BufferObject>& 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<BufferObject>((BufferTarget)i);
|
||||
}
|
||||
}
|
||||
|
||||
SharedPtr<BufferObject> BufferState::GetBufferObject(Uint index) {
|
||||
auto it = m_bufferObjects.find(index);
|
||||
if (it != m_bufferObjects.end()) {
|
||||
@@ -171,6 +186,29 @@ namespace MobileGL {
|
||||
BindingSlot<BufferObject>& 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<BufferObject>((BufferTarget)i);
|
||||
}
|
||||
}
|
||||
BufferState();
|
||||
|
||||
SharedPtr<BufferObject> GetBufferObject(Uint index);
|
||||
Vector<Uint> GenerateNames(Uint number);
|
||||
SharedPtr<BufferObject> CreateBufferObject(Uint index);
|
||||
BindingSlot<BufferObject>& GetBindingSlot(BufferTarget target);
|
||||
void MarkBufferObjectForDeletion(Uint index);
|
||||
bool ValidateName(Uint index) const;
|
||||
bool ValidateBufferObject(Uint index) const;
|
||||
|
||||
private:
|
||||
UnorderedMap<Uint, SharedPtr<BufferObject>> m_bufferObjects;
|
||||
|
||||
@@ -3,20 +3,66 @@
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
// Error
|
||||
void GLContext::RecordError(ErrorCode code, SharedPtr<ErrorInfo> info) {
|
||||
m_errorState.RecordError(code, info);
|
||||
}
|
||||
|
||||
bool GLContext::HasGLError() const {
|
||||
return m_errorState.HasGLError();
|
||||
}
|
||||
|
||||
Optional<const Error> GLContext::PeekGLError() const {
|
||||
return m_errorState.PeekGLError();
|
||||
}
|
||||
|
||||
Optional<Error> GLContext::PopGLError() {
|
||||
return m_errorState.PopGLError();
|
||||
}
|
||||
|
||||
bool GLContext::HasNonGLError() const {
|
||||
return m_errorState.HasNonGLError();
|
||||
}
|
||||
|
||||
Optional<const Error> GLContext::PeekNonGLError() const {
|
||||
return m_errorState.PeekNonGLError();
|
||||
}
|
||||
|
||||
Optional<Error> GLContext::PopNonGLError() {
|
||||
return m_errorState.PopNonGLError();
|
||||
}
|
||||
|
||||
void GLContext::ClearErrors() {
|
||||
m_errorState.Clear();
|
||||
}
|
||||
|
||||
// Buffer
|
||||
Vector<Uint> GLContext::GenBufferNames(Uint number) {
|
||||
return bufferState_.GenerateNames(number);
|
||||
return m_bufferState.GenerateNames(number);
|
||||
}
|
||||
|
||||
SharedPtr<BufferObject> GLContext::GetBufferObject(Uint index) {
|
||||
return bufferState_.GetBufferObject(index);
|
||||
return m_bufferState.GetBufferObject(index);
|
||||
}
|
||||
|
||||
BindingSlot<BufferObject>& GLContext::GetBufferBindingSlot(BufferTarget target) {
|
||||
return bufferState_.GetBindingSlot(target);
|
||||
return m_bufferState.GetBindingSlot(target);
|
||||
}
|
||||
|
||||
SharedPtr<BufferObject> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,15 +7,31 @@ namespace MobileGL {
|
||||
public:
|
||||
GLContext() = default;
|
||||
|
||||
// Error
|
||||
void RecordError(ErrorCode code, SharedPtr<ErrorInfo> info = nullptr);
|
||||
bool HasGLError() const;
|
||||
Optional<const Error> PeekGLError() const;
|
||||
Optional<Error> PopGLError();
|
||||
bool HasNonGLError() const;
|
||||
Optional<const Error> PeekNonGLError() const;
|
||||
Optional<Error> PopNonGLError();
|
||||
void ClearErrors();
|
||||
|
||||
// Buffer
|
||||
Vector<Uint> GenBufferNames(Uint number);
|
||||
SharedPtr<BufferObject> GetBufferObject(Uint index);
|
||||
BindingSlot<BufferObject>& GetBufferBindingSlot(BufferTarget target);
|
||||
SharedPtr<BufferObject> CreateBufferObject(Uint index);
|
||||
SharedPtr<BufferObject> 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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "../../../Includes.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
void ErrorState::RecordError(ErrorCode code, SharedPtr<ErrorInfo> 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<const Error> ErrorState::PeekNonGLError() const {
|
||||
if (m_nonGLErrors.empty()) return Optional<const Error>{ };
|
||||
return Optional<const Error>{m_nonGLErrors.front()};
|
||||
}
|
||||
|
||||
Optional<Error> ErrorState::PopNonGLError() {
|
||||
if (m_nonGLErrors.empty()) return Optional<const Error>{ };
|
||||
auto error = Move(m_nonGLErrors.front());
|
||||
m_nonGLErrors.erase(m_nonGLErrors.begin());
|
||||
return Optional<const Error>{ error };
|
||||
}
|
||||
|
||||
bool ErrorState::HasGLError() const {
|
||||
return !m_errors.empty();
|
||||
}
|
||||
|
||||
Optional<const Error> ErrorState::PeekGLError() const {
|
||||
if (m_errors.empty()) return Optional<const Error>{ };
|
||||
return Optional<const Error>{m_errors.front()};
|
||||
}
|
||||
|
||||
Optional<Error> ErrorState::PopGLError() {
|
||||
if (m_errors.empty()) return Optional<const Error>{ };
|
||||
auto error = Move(m_errors.front());
|
||||
m_errors.erase(m_errors.begin());
|
||||
return Optional<const Error>{ error };
|
||||
}
|
||||
|
||||
void ErrorState::Clear() {
|
||||
m_errors.clear();
|
||||
m_nonGLErrors.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
namespace MobileGL {
|
||||
struct Error {
|
||||
ErrorCode code;
|
||||
SharedPtr<ErrorInfo> info;
|
||||
};
|
||||
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
class ErrorState {
|
||||
public:
|
||||
void RecordError(ErrorCode code, SharedPtr<ErrorInfo> info = nullptr);
|
||||
bool HasNonGLError() const;
|
||||
Optional<const Error> PeekNonGLError() const;
|
||||
Optional<Error> PopNonGLError();
|
||||
bool HasGLError() const;
|
||||
Optional<const Error> PeekGLError() const;
|
||||
Optional<Error> PopGLError();
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
Vector<Error> m_errors;
|
||||
Vector<Error> m_nonGLErrors;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace MobileGL {
|
||||
enum class ErrorCode {
|
||||
NoError = 0,
|
||||
InvalidEnum,
|
||||
InvalidValue,
|
||||
InvalidOperation,
|
||||
InvalidFramebufferOperation,
|
||||
OutOfMemory,
|
||||
StackUnderflow,
|
||||
StackOverflow
|
||||
};
|
||||
}
|
||||
@@ -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<String> m_prefix;
|
||||
Optional<String> m_prefix_2;
|
||||
};
|
||||
}
|
||||
@@ -291,9 +291,8 @@ TEST_F(BufferTest, PartialUpdate) {
|
||||
|
||||
Vector<Int> update{ 999, 888 };
|
||||
bufObj->UploadSubData(
|
||||
sizeof(Int),
|
||||
update.size() * sizeof(Int),
|
||||
update.data()
|
||||
{ (void*)(update.data()), (SizeT)(update.size() * sizeof(Int)) },
|
||||
sizeof(Int)
|
||||
);
|
||||
|
||||
Vector<Int> 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<char> 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<uint16_t*>(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<const float*>(verifyMap);
|
||||
EXPECT_FLOAT_EQ(verts[0], 0.1f);
|
||||
EXPECT_FLOAT_EQ(verts[1], 0.2f);
|
||||
|
||||
const char* partialData = static_cast<const char*>(verifyMap) + 20;
|
||||
EXPECT_STREQ(partialData, "PARTIAL");
|
||||
|
||||
const char* copiedData = static_cast<const char*>(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<const uint16_t*>(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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
//
|
||||
// Created by Swung 0x48 on 2025/7/20.
|
||||
//
|
||||
|
||||
#include "Includes.h"
|
||||
#include "../../../Includes.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Util {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Util {
|
||||
BufferTarget ConvertGLEnumToBufferTarget(GLenum bufferTarget);
|
||||
BufferUsage ConvertGLEnumToBufferUsage(GLenum usage);
|
||||
BufferMappingAccessBit ConvertGLEnumToBufferMappingAccess(GLbitfield access);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Util {
|
||||
GLenum ConvertBufferTargetToGLEnum(BufferTarget bufferTarget);
|
||||
GLenum ConvertBufferUsageToGLEnum(BufferUsage usage);
|
||||
GLbitfield ConvertBufferMappingAccessToGLEnum(BufferMappingAccessBit access);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Util {
|
||||
GLenum ConvertErrorCodeToGLEnum(ErrorCode code);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Util {
|
||||
String ConvertBufferTargetToString(BufferTarget bufferTarget);
|
||||
String ConvertBufferUsageToString(BufferUsage usage);
|
||||
String ConvertBufferMappingAccessToString(BufferMappingAccessBit access);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ namespace MobileGL {
|
||||
template <typename IndexType>
|
||||
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<IndexType> freed_indices_;
|
||||
std::vector<Uint8> is_valid_;
|
||||
IndexType next_index_ = 0;
|
||||
std::vector<IndexType> freed_indices_;
|
||||
std::vector<Uint8> is_valid_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
//
|
||||
// Created by Swung 0x48 on 2025/7/20.
|
||||
//
|
||||
|
||||
#include "Includes.h"
|
||||
#include "../../Includes.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Util {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<T>;
|
||||
template <typename T>
|
||||
using UniquePtr = std::unique_ptr<T>;
|
||||
template<typename T, typename... Args>
|
||||
template <typename T, typename... Args>
|
||||
inline SharedPtr<T> MakeShared(Args&&... args) {
|
||||
return std::make_shared<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
template<typename T, typename... Args>
|
||||
template <typename T, typename... Args>
|
||||
inline UniquePtr<T> MakeUnique(Args&&... args) {
|
||||
return std::make_unique<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
@@ -37,10 +39,14 @@ namespace MobileGL {
|
||||
using Array = std::array<T, N>;
|
||||
template <typename Key, typename Value>
|
||||
using UnorderedMap = std::unordered_map<Key, Value>;
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
inline constexpr std::remove_reference_t<T>&& Move(T&& t) noexcept {
|
||||
return static_cast<std::remove_reference_t<T>&&>(t);
|
||||
}
|
||||
template <typename T>
|
||||
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<typename ObjectType>
|
||||
template <typename ObjectType>
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user