Merge branch 'Feat/dev-es-shittily-draw' into dev-es without ShittilyDraw

# Conflict:
#	MG/Includes.h

# Changes:
#      Remove ShittilyDraw, ready to implement MG_RHI...
#      Update progress.
This commit is contained in:
BZLZHH
2025-05-17 11:50:47 +08:00
40 changed files with 3163 additions and 321 deletions
+182 -58
View File
@@ -6,58 +6,60 @@
#include "BufferState.h"
GLenum BufferState::Create(GLuint* buffer) {
MG_Util::Debug::LogD("MG_State: Buffer: Create called");
if (!buffer) return GL_INVALID_VALUE;
GLenum BufferState::GenName(GLuint *buffer) {
MG_Util::Debug::LogD("MG_State: Buffer: GenName");
if (!buffer)
return GL_INVALID_VALUE;
GLuint id = 0;
if (!freeIds_.empty()) {
id = *freeIds_.begin();
freeIds_.erase(freeIds_.begin());
if (freeId_.empty()) {
id = lastId_++;
} else {
id = ++lastId_;
id = freeId_.back();
freeId_.pop_back();
}
*buffer = id;
BufferObject& obj = buffers_[id];
MG_Util::Debug::LogD("MG_State: Buffer: Create created buffer %d", id);
obj.generated = true;
MG_Util::Debug::LogD("MG_State: Buffer: Gen new name %d", id);
return GL_NO_ERROR;
}
GLenum BufferState::CreateN(GLsizei n, GLuint* buffers) {
MG_Util::Debug::LogD("MG_State: Buffer: CreateN called with n=%d", n);
GLenum BufferState::GenNameN(GLsizei n, GLuint* buffers) {
MG_Util::Debug::LogD("MG_State: Buffer: GenNameN called with n=%d", n);
if (n < 0) return GL_INVALID_VALUE;
for (GLsizei i = 0; i < n; ++i) {
GLenum result = Create(&buffers[i]);
GLenum result = GenName(&buffers[i]);
if (result != GL_NO_ERROR) {
MG_Util::Debug::LogE("MG_State: Buffer: CreateN create buffer failed with error 0x%x", result);
MG_Util::Debug::LogE("MG_State: Buffer: GenNameN failed with error 0x%x", result);
return result;
}
}
MG_Util::Debug::LogD("MG_State: Buffer: CreateN created buffers successfully");
MG_Util::Debug::LogD("MG_State: Buffer: GenNameN created buffers successfully");
return GL_NO_ERROR;
}
GLenum BufferState::Create(GLuint buffer) {
MG_Util::Debug::LogD("MG_State: Buffer: Create called");
if (!buffer)
return GL_INVALID_VALUE;
if (ValidateAllocatedHandle(buffer))
return GL_INVALID_VALUE;
BufferObject& obj = buffers_[buffer];
MG_Util::Debug::LogD("MG_State: Buffer: Create created buffer %d", buffer);
obj.generated = true;
obj.dirty = true;
return GL_NO_ERROR;
}
GLenum BufferState::Bind(GLenum target, GLuint buffer) {
// We don't handle unallocated buffer names here, just plain bind
if (!IsValidTarget_(target)) return GL_INVALID_ENUM;
MG_Util::Debug::LogD("MG_State: Buffer: Bind called with target=0x%x, buffer=%u", target, buffer);
if (buffer != 0) {
auto it = buffers_.find(buffer);
if (it == buffers_.end()) {
buffers_[buffer];
} else {
BufferObject& obj = it->second;
if (obj.target != 0 && obj.target != target) {
MG_Util::Debug::LogE("MG_State: Buffer: Bind can not bind a buffer to different target 0x%x, current bind target is 0x%x", target, obj.target);
return GL_INVALID_OPERATION;
}
}
buffers_[buffer].target = target;
}
MG_Util::Debug::LogD("MG_State: Buffer: Bind called with target=%s, buffer=%u", MG_Util::Debug::GLEnumToString(target), buffer);
currentBindings_[target] = buffer;
MG_Util::Debug::LogD("MG_State: Buffer: Bind succeed bind buffer %u to target 0x%x", buffer, target);
return GL_NO_ERROR;
@@ -73,68 +75,190 @@ GLenum BufferState::CommitStorage(GLenum target, GLsizeiptr size, const void* da
MG_Util::Debug::LogD("MG_State: Buffer: CommitStorage get buffer object %u at target 0x%x",it->second,target);
obj.usage = usage;
obj.data.resize(size);
if (data) memcpy(obj.data.data(), data, size);
if (data) {
memcpy(obj.data.data(), data, size);
obj.dataValid = true;
}
obj.dirty = true;
MG_Util::Debug::LogD("MG_State: Buffer: CommitStorage buffer at target 0x%x committed storage, size = %zu, usage=0x%x", target, size, usage);
return GL_NO_ERROR;
}
GLenum BufferState::AcquireBufferMemory(GLenum target, GLenum access, void** mappedPointer) {
GLenum BufferState::CommitStorageRegion(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
MG_Util::Debug::LogD("MG_State: Buffer: BufferSubData called on target 0x%x, offset=%ld, size=%ld", target, offset, size);
if (!IsValidTarget_(target)) return GL_INVALID_ENUM;
if (MG_Constants::Buffer::VALID_ACCESS.find(access) == MG_Constants::Buffer::VALID_ACCESS.end()) {
return GL_INVALID_ENUM;
MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemory buffer at target 0x%x acquired mapped memory, access mode = 0x%x", target, access);
}
if (offset < 0 || size < 0) return GL_INVALID_VALUE;
auto it = currentBindings_.find(target);
if (it == currentBindings_.end() || it->second == 0)
return GL_INVALID_OPERATION;
BufferObject& obj = buffers_[it->second];
if (obj.isMapped) return GL_INVALID_OPERATION;
MG_Util::Debug::LogD("MG_State: Buffer: BufferSubData get buffer object %u at target 0x%x", it->second, target);
obj.isMapped = true;
*mappedPointer = obj.data.data();
obj.isMapped = true;
obj.accessMode = access;
if (static_cast<size_t>(offset + size) > obj.data.size()) return GL_INVALID_VALUE;
if (data) {
memcpy(obj.data.data() + offset, data, size);
obj.dirty = true;
}
return GL_NO_ERROR;
}
GLenum BufferState::AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer) {
MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange called with target=0x%x, offset=%ld, length=%ld, access=0x%x", target, offset, length, access);
if (!IsValidTarget_(target)) {
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: invalid target 0x%x", target);
return GL_INVALID_ENUM;
}
if (offset < 0 || length <= 0) {
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: invalid offset %ld or length %ld", offset, length);
return GL_INVALID_VALUE;
}
auto it = currentBindings_.find(target);
if (it == currentBindings_.end() || it->second == 0) {
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: no buffer bound to target 0x%x", target);
return GL_INVALID_OPERATION;
}
BufferObject& obj = buffers_[it->second];
MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange operating on buffer %u", it->second);
if (obj.isMapped) {
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: buffer %u is already mapped", it->second);
return GL_INVALID_OPERATION;
}
const GLbitfield validFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT ;
if ((access & ~validFlags) != 0) {
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: invalid access flags 0x%x", access);
return GL_INVALID_VALUE;
}
if (static_cast<size_t>(offset + length) > obj.data.size()) {
MG_Util::Debug::LogE("MG_State: Buffer: AcquireBufferMemoryRange failed: requested range [%ld, %ld) exceeds buffer size %zu", offset, offset + length, obj.data.size());
return GL_INVALID_VALUE;
}
obj.isMapped = true;
obj.mapOffset = offset;
obj.mapLength = length;
obj.mapAccessFlags = access;
obj.dirty = true;
*mappedPointer = obj.data.data() + offset;
MG_Util::Debug::LogD("MG_State: Buffer: AcquireBufferMemoryRange succeeded for buffer %u. Mapped pointer: %p", it->second, *mappedPointer);
return GL_NO_ERROR;
}
GLenum BufferState::SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length) {
if (!IsValidTarget_(target)) return GL_INVALID_ENUM;
if (offset < 0 || length <= 0) return GL_INVALID_VALUE;
auto it = currentBindings_.find(target);
if (it == currentBindings_.end() || it->second == 0)
return GL_INVALID_OPERATION;
BufferObject& obj = buffers_[it->second];
if (!obj.isMapped || !(obj.mapAccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT))
return GL_INVALID_OPERATION;
if (offset < obj.mapOffset || offset + length > obj.mapOffset + obj.mapLength)
return GL_INVALID_VALUE;
// TODO: Add support for flush range.
// Now only mark it as dirty.
obj.dirty = true;
return GL_NO_ERROR;
}
GLenum BufferState::CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
if (!IsValidTarget_(readTarget) || !IsValidTarget_(writeTarget))
return GL_INVALID_ENUM;
if (readOffset < 0 || writeOffset < 0 || size < 0)
return GL_INVALID_VALUE;
GLuint readBuffer = currentBindings_[readTarget];
GLuint writeBuffer = currentBindings_[writeTarget];
if (readBuffer == 0 || writeBuffer == 0 || readBuffer == writeBuffer)
return GL_INVALID_OPERATION;
BufferObject& src = buffers_[readBuffer];
BufferObject& dst = buffers_[writeBuffer];
if (static_cast<size_t>(readOffset + size) > src.data.size() ||
static_cast<size_t>(writeOffset + size) > dst.data.size())
return GL_INVALID_VALUE;
memcpy(dst.data.data() + writeOffset, src.data.data() + readOffset, size);
dst.dirty = true;
return GL_NO_ERROR;
}
GLenum BufferState::AcquireBufferMemory(GLenum target, GLenum access, void** mappedPointer) {
return AcquireBufferMemoryRange(target, 0, buffers_[currentBindings_[target]].data.size(), access, mappedPointer);
}
GLenum BufferState::ReleaseBufferMemory(GLenum target) {
MG_Util::Debug::LogD("MG_State: Buffer: ReleaseBufferMemory called on target 0x%x",target);
if (!IsValidTarget_(target)) return GL_INVALID_ENUM;
if (!IsValidTarget_(target))
return GL_INVALID_ENUM;
auto it = currentBindings_.find(target);
if (it == currentBindings_.end() || it->second == 0)
return GL_INVALID_OPERATION;
BufferObject& obj = buffers_[it->second];
if (!obj.isMapped) return GL_INVALID_OPERATION;
if (!obj.isMapped)
return GL_INVALID_OPERATION;
if ((obj.mapAccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
obj.dirty = true;
}
obj.isMapped = false;
obj.mapOffset = 0;
obj.mapLength = 0;
obj.mapAccessFlags = 0;
obj.accessMode = GL_READ_WRITE;
MG_Util::Debug::LogD("MG_State: Buffer: ReleaseBufferMemory buffer at target 0x%x released mapped memory", target);
return GL_NO_ERROR;
}
bool BufferState::ValidateHandle(GLuint buffer) {
bool isvalid = buffers_.count(buffer) > 0;
MG_Util::Debug::LogD("MG_State: Buffer: ValidateHandle called on buffer %u returns %d", buffer, isvalid);
return isvalid;
bool BufferState::ValidateAllocatedHandle(GLuint buffer) {
bool isValid = buffers_.find(buffer) != buffers_.end();
MG_Util::Debug::LogD("MG_State: Buffer: ValidateAllocatedHandle called on buffer %u returns %d", buffer, isValid);
return isValid;
}
bool BufferState::ValidateGeneratedName(GLuint buffer) {
bool inFreeList = std::find(freeId_.begin(), freeId_.end(), buffer) != freeId_.end();
bool lessThanLast = buffer < lastId_; // lastId_ is not generated yet
MG_Util::Debug::LogD("MG_State: Buffer: ValidateGeneratedName called on buffer %u returns %d", buffer, lessThanLast && !inFreeList);
return lessThanLast && !inFreeList;
}
void BufferState::Delete(GLuint buffer) {
if (buffers_.erase(buffer)) {
freeIds_.insert(buffer);
for (auto& [target, id] : currentBindings_) {
if (id == buffer) id = 0;
}
buffers_.erase(buffer);
if (ValidateGeneratedName(buffer))
// TODO: Prevent the object that uses a freeId from conflicting with legacy object in the backend.
//freeId_.emplace_back(buffer);
for (auto& [target, id] : currentBindings_) {
if (id == buffer) id = 0;
}
MG_Util::Debug::LogD("MG_State: Buffer: Delete buffer %u", buffer);
}
GLenum BufferState::DeleteN(GLsizei n, const GLuint* buffers) {
MG_Util::Debug::LogD("MG_State: Buffer: DeleteN called with n=%d", n);
if (n < 0) return GL_INVALID_VALUE;
for (GLsizei i = 0; i < n; ++i) {
Delete(buffers[i]);
}
MG_Util::Debug::LogD("MG_State: Buffer: DeleteN deleted buffers successfully");
return GL_NO_ERROR;
}
bool BufferState::IsValidTarget_(GLenum target) {
MG_Util::Debug::LogD("MG_State: Buffer: IsValidTarget_ called with target=0x%x,result=%d", target, !(MG_Constants::Buffer::VALID_TARGETS.find(target) == MG_Constants::Buffer::VALID_TARGETS.end()));
return !(MG_Constants::Buffer::VALID_TARGETS.find(target) == MG_Constants::Buffer::VALID_TARGETS.end());
@@ -179,7 +303,7 @@ GLenum BufferState::QueryPropertyIntVector(GLenum target, GLenum pname, GLint* p
case GL_BUFFER_USAGE:
*params = static_cast<GLint>(buffer.usage);
break;
MG_Util::Debug::LogD("MG_State: Buffer: QueryPropertyIntVector Query info about buffer %u succeed",buffer.target);
MG_Util::Debug::LogD("MG_State: Buffer: QueryPropertyIntVector Query info about buffer %u succeed", target);
default:
return GL_INVALID_ENUM;
}
+22 -8
View File
@@ -9,34 +9,48 @@
#include "../../../Includes.h"
class BufferState {
template <typename K, typename V>
using unordered_map = ankerl::unordered_dense::map<K, V>;
public:
struct BufferObject {
GLenum target = 0;
GLenum usage = GL_STATIC_DRAW;
std::vector<GLubyte> data;
bool dataValid = false;
bool dirty = false; // TODO: encapsulate this with an public API to RHI
bool isMapped = false;
bool generated = false;
GLenum accessMode = GL_READ_WRITE;
GLintptr mapOffset = 0;
GLsizeiptr mapLength = 0;
GLbitfield mapAccessFlags = 0;
};
// Return: the validity of the operation, according to OpenGL 3 standard
GLenum Create(GLuint* buffer);
GLenum CreateN(GLsizei n, GLuint* buffers);
GLenum GenName(GLuint* buffer);
GLenum GenNameN(GLsizei n, GLuint* buffers);
GLenum Create(GLuint buffer);
GLenum Bind(GLenum target, GLuint buffer);
GLenum CommitStorage(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
GLenum CommitStorageRegion(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
GLenum AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer);
GLenum SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length);
GLenum CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
GLenum AcquireBufferMemory(GLenum target, GLenum access, void** mappedPointer);
GLenum ReleaseBufferMemory(GLenum target);
GLenum QueryPropertyIntVector(GLenum target, GLenum pname, GLint* params) const;
GLenum DeleteN(GLsizei n, const GLuint* buffers);
bool ValidateHandle(GLuint buffer);
bool ValidateAllocatedHandle(GLuint buffer);
bool ValidateGeneratedName(GLuint buffer);
void Delete(GLuint buffer);
GLuint GetCurrentBinding(GLenum target) const;
unordered_map<GLenum, GLuint> currentBindings_;
unordered_map<GLuint, BufferObject> buffers_;
private:
std::unordered_map<GLuint, BufferObject> buffers_;
std::set<GLuint> freeIds_;
GLuint lastId_ = 0;
std::unordered_map<GLenum, GLuint> currentBindings_;
std::vector<GLuint> freeId_;
GLuint lastId_ = 1;
static bool IsValidTarget_(GLenum target);
};
+1
View File
@@ -107,6 +107,7 @@ GLenum CommonState::Clear(GLbitfield mask) {
if ((mask & ~validBits) != 0) {
return GL_INVALID_VALUE;
}
clearMask = mask;
return GL_NO_ERROR;
}
+15 -12
View File
@@ -9,9 +9,17 @@
#include "../../../Includes.h"
class CommonState {
private:
template <typename K, typename V>
using unordered_map = ankerl::unordered_dense::map<K, V>;
public:
// Viewport
GLint viewport[4] = {0, 0, 0, 0};
// Color mask
GLboolean colorMask[4] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE};
// Pixel storage parameters
std::unordered_map<GLenum, GLint> pixelStoreParams;
unordered_map<GLenum, GLint> pixelStoreParams;
// Blend state
GLenum blendSrcRGB = GL_ONE;
@@ -22,21 +30,15 @@ private:
// Clear state
GLfloat clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GLfloat clearDepth = 1.0f;
// Color mask
GLboolean colorMask[4] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE};
GLenum clearMask;
// Depth state
GLenum depthFunc = GL_LESS;
GLboolean depthMask = GL_TRUE;
// Viewport
GLint viewport[4] = {0, 0, 0, 0};
// Capability enables
std::unordered_map<GLenum, bool> capabilities;
unordered_map<GLenum, bool> capabilities;
public:
CommonState();
// Return: the validity of the operation, according to OpenGL 3 standard
@@ -57,6 +59,7 @@ public:
GLenum Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
GLint QueryPixelStoreInt(GLenum pname);
};
#endif //MOBILEGL_COMMONSTATE_H
+38 -8
View File
@@ -155,17 +155,30 @@ namespace MG_State {
GLenum AcquireBufferMemory(GLenum target, GLenum access, void** mappedPtr) {
return MG_State_T::bufferState->AcquireBufferMemory(target, access, mappedPtr);
}
GLenum AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer) {
return MG_State_T::bufferState->AcquireBufferMemoryRange(target, offset, length, access, mappedPointer);
}
GLenum SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length) {
return MG_State_T::bufferState->SyncBufferMemory(target, offset, length);
}
GLenum CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
return MG_State_T::bufferState->CopyBufferRange(readTarget, writeTarget, readOffset,
writeOffset, size);
}
GLenum ReleaseBufferMemory(GLenum target) {
return MG_State_T::bufferState->ReleaseBufferMemory(target);
}
GLenum CreateBuffer(GLuint* buffer) {
GLenum CreateBuffer(GLuint buffer) {
return MG_State_T::bufferState->Create(buffer);
}
GLenum CreateBuffers(GLsizei n, GLuint* buffers) {
return MG_State_T::bufferState->CreateN(n, buffers);
GLenum GenBufferNames(GLsizei n, GLuint* buffers) {
return MG_State_T::bufferState->GenNameN(n, buffers);
}
GLenum BindBuffer(GLenum target, GLuint buffer) {
@@ -173,6 +186,7 @@ namespace MG_State {
auto* vao = MG_State_T::vertexArrayState->GetCurrentVAO();
if (!vao) return GL_INVALID_OPERATION;
vao->elementBuffer = (GLuint)buffer;
vao->eboDirty = true;
}
return MG_State_T::bufferState->Bind(target, buffer);
}
@@ -181,14 +195,26 @@ namespace MG_State {
return MG_State_T::bufferState->CommitStorage(target, size, data, usage);
}
bool ValidateBufferHandle(GLuint buffer) {
return MG_State_T::bufferState->ValidateHandle(buffer);
GLenum CommitBufferStorageRegion(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
return MG_State_T::bufferState->CommitStorageRegion(target, offset, size, data);
}
bool ValidateAllocatedBufferHandle(GLuint buffer) {
return MG_State_T::bufferState->ValidateAllocatedHandle(buffer);
}
bool ValidateGeneratedName(GLuint buffer) {
return MG_State_T::bufferState->ValidateGeneratedName(buffer);
}
void DeleteBuffer(GLuint buffer) {
return MG_State_T::bufferState->Delete(buffer);
}
GLenum DeleteBuffers(GLsizei n, const GLuint* buffers) {
return MG_State_T::bufferState->DeleteN(n, buffers);
}
GLenum QueryBufferPropertyIntVector(GLenum target, GLenum pname, GLint* params) {
return MG_State_T::bufferState->QueryPropertyIntVector(target, pname, params);
}
@@ -206,6 +232,10 @@ namespace MG_State {
return MG_State_T::vertexArrayState->CreateN(n, arrays);
}
GLenum GenVertexArraysNames(GLsizei n, GLuint* arrays) {
return MG_State_T::vertexArrayState->GenNameN(n, arrays);
}
GLenum EnableVertexAttribArray(GLuint index) {
return MG_State_T::vertexArrayState->EnableAttrib(index);
}
@@ -367,11 +397,11 @@ void UpdateProgramUniformMatrix##suffix##Vector(GLint location, GLsizei count, G
GLenum MG_State::AttachTexture2DToFramebuffer(GLenum target, GLenum attachment, GLenum textarget,
GLuint texture, GLint level) {
return MG_State_T::framebufferState->glAttachTexture2D(target, attachment, textarget,
texture, level);
return MG_State_T::framebufferState->AttachTexture2D(target, attachment, textarget,
texture, level);
}
GLenum MG_State::ValidateFramebufferCompleteness(GLenum target) {
return MG_State_T::framebufferState->glValidateCompleteness(target);
return MG_State_T::framebufferState->ValidateCompleteness(target);
}
}
+10 -3
View File
@@ -57,18 +57,25 @@ namespace MG_State {
// Buffer
GLenum AcquireBufferMemory(GLenum target, GLenum access, void** mappedPtr);
GLenum AcquireBufferMemoryRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void** mappedPointer);
GLenum SyncBufferMemory(GLenum target, GLintptr offset, GLsizeiptr length);
GLenum CopyBufferRange(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
GLenum ReleaseBufferMemory(GLenum target);
GLenum CreateBuffer(GLuint* buffer);
GLenum CreateBuffers(GLsizei n, GLuint* buffers);
GLenum CreateBuffer(GLuint buffer);
GLenum GenBufferNames(GLsizei n, GLuint* buffers);
GLenum BindBuffer(GLenum target, GLuint buffer);
GLenum CommitBufferStorage(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
bool ValidateBufferHandle(GLuint buffer);
GLenum CommitBufferStorageRegion(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
bool ValidateAllocatedBufferHandle(GLuint buffer);
bool ValidateGeneratedName(GLuint buffer);
void DeleteBuffer(GLuint buffer);
GLenum DeleteBuffers(GLsizei n, const GLuint* buffers);
GLenum QueryBufferPropertyIntVector(GLenum target, GLenum pname, GLint* params);
// VertexArray
GLenum CreateVertexArray(GLuint* array);
GLenum CreateVertexArrays(GLsizei n, GLuint* arrays);
GLenum GenVertexArraysNames(GLsizei n, GLuint* arrays);
GLenum BindVertexArray(GLuint array);
GLenum EnableVertexAttribArray(GLuint index);
GLenum DisableVertexAttribArray(GLuint index);
@@ -32,7 +32,8 @@ GLenum FramebufferState::Delete(GLuint framebuffer) {
if (framebuffer == 0) return GL_INVALID_VALUE;
if (framebuffers_.erase(framebuffer)) {
freeIds_.insert(framebuffer);
// TODO: Prevent the object that uses a freeId from conflicting with legacy object in the backend.
//freeIds_.insert(framebuffer);
for (auto& [target, id] : currentBindings_) {
if (id == framebuffer) id = 0;
}
@@ -48,18 +49,18 @@ GLenum FramebufferState::Bind(GLenum target, GLuint framebuffer) {
if (target == GL_FRAMEBUFFER) {
currentBindings_[GL_READ_FRAMEBUFFER] = framebuffer;
currentBindings_[GL_DRAW_FRAMEBUFFER] = framebuffer;
currentBindings_[GL_FRAMEBUFFER] = framebuffer;
} else {
currentBindings_[target] = framebuffer;
}
return GL_NO_ERROR;
}
GLenum FramebufferState::glAttachTexture2D(GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level) {
GLenum FramebufferState::AttachTexture2D(GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level) {
if (MG_Constants::Framebuffer::VALID_ATTACHMENTS.find(attachment) == MG_Constants::Framebuffer::VALID_ATTACHMENTS.end() ||
MG_Constants::Texture::VALID_TARGETS.find(textarget) == MG_Constants::Texture::VALID_TARGETS.end())
return GL_INVALID_ENUM;
if (target == GL_FRAMEBUFFER) target = GL_DRAW_FRAMEBUFFER;
FramebufferObject* fbo = GetCurrentFBO(target);
if (!fbo) return GL_INVALID_OPERATION;
if (texture != 0 && !MG_State_T::textureState->IsTexture(texture))
@@ -83,7 +84,8 @@ GLenum FramebufferState::glAttachTexture2D(GLenum target, GLenum attachment,
return GL_NO_ERROR;
}
GLenum FramebufferState::glValidateCompleteness(GLenum target) {
GLenum FramebufferState::ValidateCompleteness(GLenum target) {
if (target == GL_FRAMEBUFFER) target = GL_DRAW_FRAMEBUFFER;
FramebufferObject* fbo = GetCurrentFBO(target);
if (!fbo) return GL_INVALID_OPERATION;
return fbo->status;
@@ -17,7 +17,7 @@ struct FramebufferAttachment {
struct FramebufferObject {
bool generated = false;
std::unordered_map<GLenum, FramebufferAttachment> attachments;
ankerl::unordered_map<GLenum, FramebufferAttachment> attachments;
GLenum status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
GLsizei width = 0;
GLsizei height = 0;
@@ -30,14 +30,15 @@ public:
GLenum CreateN(GLsizei n, GLuint* framebuffers);
GLenum Delete(GLuint framebuffer);
GLenum Bind(GLenum target, GLuint framebuffer);
GLenum glAttachTexture2D(GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level);
GLenum glValidateCompleteness(GLenum target);
GLenum AttachTexture2D(GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level);
GLenum ValidateCompleteness(GLenum target);
FramebufferObject* GetCurrentFBO(GLenum target);
ankerl::unordered_map<GLenum, GLuint> currentBindings_; // READ/DRAW
private:
std::unordered_map<GLuint, FramebufferObject> framebuffers_;
std::unordered_map<GLenum, GLuint> currentBindings_; // READ/DRAW/FRAMEBUFFER
ankerl::unordered_map<GLuint, FramebufferObject> framebuffers_;
std::set<GLuint> freeIds_;
GLuint lastId_ = 0;
bool ValidateHandle(GLuint framebuffer);
+55 -8
View File
@@ -48,7 +48,7 @@ GLenum ProgramState::DeleteProgram(GLuint program) {
}
programs_.erase(program);
freeProgramIds_.insert(program);
//freeProgramIds_.insert(program);
if (currentProgram_ == program)
currentProgram_ = 0;
MG_Util::Debug::LogD("MG_State: Program: DeleteProgram success, id=%u", program);
@@ -261,6 +261,7 @@ GLenum ProgramState::SetUniform(GLuint program, GLint location, GLsizei count, c
}
UniformValue& uniform = prog.uniformValues[uniformName];
uniform.setData(type, count, value);
MG_Util::Debug::LogD("MG_State: Program: SetUniform success: %s set", uniformName.c_str());
return GL_NO_ERROR;
@@ -303,7 +304,7 @@ GLenum ProgramState::SetUniformMatrix(GLuint program, GLint location, GLsizei co
}
UniformValue& uniform = prog.uniformValues[uniformName];
uniform.setData(matrixType, count * MG_Util::Program::GetMatrixElementCount(matrixType), value);
uniform.setData(matrixType, count, value);
MG_Util::Debug::LogD("MG_State: Program: SetUniformMatrix success: %s set", uniformName.c_str());
return GL_NO_ERROR;
}
@@ -334,15 +335,15 @@ void ProgramState::UpdateUniform##suffix##Vector1(GLint location, GLsizei count,
} \
void ProgramState::UpdateUniform##suffix##Vector2(GLint location, GLsizei count, const type* value) { \
MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector2 called, location=%d, count=%d", location, count); \
SetUniform<type>(currentProgram_, location, count * 2, value, vecType); \
SetUniform<type>(currentProgram_, location, count, value, vecType); \
} \
void ProgramState::UpdateUniform##suffix##Vector3(GLint location, GLsizei count, const type* value) { \
MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector3 called, location=%d, count=%d", location, count); \
SetUniform<type>(currentProgram_, location, count * 3, value, vecType); \
SetUniform<type>(currentProgram_, location, count, value, vecType); \
} \
void ProgramState::UpdateUniform##suffix##Vector4(GLint location, GLsizei count, const type* value) { \
MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector4 called, location=%d, count=%d", location, count); \
SetUniform<type>(currentProgram_, location, count * 4, value, vecType); \
SetUniform<type>(currentProgram_, location, count, value, vecType); \
}
IMPLEMENT_UNIFORM_FUNCTIONS(GLfloat, Float, GL_FLOAT_VEC4)
@@ -462,16 +463,62 @@ void ProgramState::CleanupShaders_() {
// UniformValue
template<typename T>
void UniformValue::setData(GLenum uniformType, GLsizei numElements, const T* values) {
MG_Util::Debug::LogD("MG_State: Program: UniformValue::setData called, type=0x%X, count=%d", uniformType, numElements);
void UniformValue::setData(GLenum uniformType, GLsizei count_, const T* values) {
MG_Util::Debug::LogD("MG_State: Program: UniformValue::setData called, type=0x%X, count=%d", uniformType, count_);
//type = uniformType;
count = numElements;
count = count_;
floatData.clear();
intData.clear();
uintData.clear();
boolData.clear();
switch (type) {
case GL_FLOAT: numElements = count_ * 1; break;
case GL_FLOAT_VEC2: numElements = count_ * 2; break;
case GL_FLOAT_VEC3: numElements = count_ * 3; break;
case GL_FLOAT_VEC4: numElements = count_ * 4; break;
case GL_INT: numElements = count_ * 1; break;
case GL_INT_VEC2: numElements = count_ * 2; break;
case GL_INT_VEC3: numElements = count_ * 3; break;
case GL_INT_VEC4: numElements = count_ * 4; break;
case GL_UNSIGNED_INT: numElements = count_ * 1; break;
case GL_UNSIGNED_INT_VEC2: numElements = count_ * 2; break;
case GL_UNSIGNED_INT_VEC3: numElements = count_ * 3; break;
case GL_UNSIGNED_INT_VEC4: numElements = count_ * 4; break;
case GL_BOOL: numElements = count_ * 1; break;
case GL_BOOL_VEC2: numElements = count_ * 2; break;
case GL_BOOL_VEC3: numElements = count_ * 3; break;
case GL_BOOL_VEC4: numElements = count_ * 4; break;
case GL_FLOAT_MAT2: numElements = count_ * 4; break; // 2x2
case GL_FLOAT_MAT3: numElements = count_ * 9; break; // 3x3
case GL_FLOAT_MAT4: numElements = count_ * 16; break; // 4x4
case GL_FLOAT_MAT2x3: numElements = count_ * 6; break; // 2x3
case GL_FLOAT_MAT2x4: numElements = count_ * 8; break; // 2x4
case GL_FLOAT_MAT3x2: numElements = count_ * 6; break; // 3x2
case GL_FLOAT_MAT3x4: numElements = count_ * 12; break; // 3x4
case GL_FLOAT_MAT4x2: numElements = count_ * 8; break; // 4x2
case GL_FLOAT_MAT4x3: numElements = count_ * 12; break; // 4x3
case GL_SAMPLER_1D:
case GL_SAMPLER_2D:
case GL_SAMPLER_3D:
case GL_SAMPLER_CUBE:
case GL_SAMPLER_1D_SHADOW:
case GL_SAMPLER_2D_SHADOW:
case GL_SAMPLER_CUBE_SHADOW:
case GL_SAMPLER_1D_ARRAY:
case GL_SAMPLER_2D_ARRAY:
case GL_SAMPLER_1D_ARRAY_SHADOW:
case GL_SAMPLER_2D_ARRAY_SHADOW:
case GL_SAMPLER_BUFFER:
case GL_SAMPLER_2D_MULTISAMPLE:
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: numElements = count_ * 1; break;
default:
MG_Util::Debug::LogW("MG_State: Program: UniformValue::setData warning: unsupported type 0x%X for numElements", uniformType);
numElements = 1;
return;
}
for (GLsizei i = 0; i < numElements; ++i) {
switch (uniformType) {
case GL_FLOAT:
+10 -9
View File
@@ -27,36 +27,37 @@ struct UniformValue {
std::vector<GLuint> uintData;
std::vector<GLboolean> boolData;
GLsizei count;
GLsizei numElements;
UniformValue() : type(0), count(0) {}
template<typename T>
void setData(GLenum uniformType, GLsizei numElements, const T* values);
void setData(GLenum uniformType, GLsizei count_, const T* values);
};
struct ProgramObject {
std::vector<GLuint> attachedShaders;
UncertainBool linked;
bool dirty;
GLint linkStatus;
std::string infoLog;
std::unordered_map<std::string, GLint> attribBindings;
std::unordered_map<std::string, GLint> attribLocations;
std::unordered_map<std::string, GLint> uniformLocations;
std::unordered_map<std::string, UniformValue> uniformValues;
ankerl::unordered_map<std::string, GLint> attribBindings;
ankerl::unordered_map<std::string, GLint> attribLocations;
ankerl::unordered_map<std::string, GLint> uniformLocations;
ankerl::unordered_map<std::string, UniformValue> uniformValues;
bool markedForDeletion;
};
class ProgramState {
private:
std::unordered_map<GLuint, ShaderObject> shaders_;
std::unordered_map<GLuint, ProgramObject> programs_;
public:
ankerl::unordered_map<GLuint, ShaderObject> shaders_;
ankerl::unordered_map<GLuint, ProgramObject> programs_;
std::set<GLuint> freeShaderIds_;
std::set<GLuint> freeProgramIds_;
GLuint lastShaderId_ = 0;
GLuint lastProgramId_ = 0;
GLuint currentProgram_ = 0;
public:
ProgramState();
~ProgramState();
+2 -1
View File
@@ -60,7 +60,8 @@ GLenum ProgramState::DeleteShader(GLuint shader) {
MG_Util::Debug::LogD("MG_State: Program: DeleteShader info: shader %u marked for deferred deletion (in use)", shader);
} else {
shaders_.erase(shader);
freeShaderIds_.insert(shader);
// TODO: Prevent the object that uses a freeId from conflicting with legacy object in the backend.
//freeShaderIds_.insert(shader);
MG_Util::Debug::LogD("MG_State: Program: DeleteShader success: shader %u deleted immediately", shader);
}
return GL_NO_ERROR;
+134 -64
View File
@@ -11,7 +11,7 @@
// TextureObject
bool TextureObject::IsImmutable() const {
bool immutable = params.texPropertiesInt.count(GL_TEXTURE_IMMUTABLE_FORMAT);
bool immutable = params.texPropertiesInt.find(GL_TEXTURE_IMMUTABLE_FORMAT) != params.texPropertiesInt.end();
MG_Util::Debug::LogD("MG_State: Texture: TextureObject::IsImmutable returns %d", immutable);
return immutable;
}
@@ -54,7 +54,7 @@ bool TextureState::IsTextureGenerated(GLuint texture) {
if (!isValidTexture) {
MG_Util::Debug::LogD("MG_State: Texture: IsTextureGenerated invalid texture %d", texture);
} else {
generated = textures.at(texture).generated;
generated = textures[texture].generated;
if (!generated) {
MG_Util::Debug::LogD("MG_State: Texture: IsTextureGenerated texture %d not generated", texture, generated);
}
@@ -101,12 +101,12 @@ GLenum TextureState::CreateN(GLsizei n, GLuint* textures) {
for (GLsizei i = 0; i < n; ++i) {
GLuint id = 0;
if (!freeIDs_.empty()) {
id = *freeIDs_.begin();
freeIDs_.erase(freeIDs_.begin());
if (!freeID_.empty()) {
id = freeID_.back();
freeID_.pop_back();
MG_Util::Debug::LogD("MG_State: Texture: CreateN reusing free id=%u", id);
} else {
id = ++lastUsedID_;
id = lastUsedID_++;
MG_Util::Debug::LogD("MG_State: Texture: CreateN new id=%u", id);
}
TextureObject obj;
@@ -258,7 +258,7 @@ GLenum TextureState::Upload2D(GLenum target, GLint level, GLint internalFormat,
if (isProxyTexture) {
MG_Util::Debug::LogD("MG_State: Texture: Upload2D proxy texture detected");
TextureObject& proxyTex = proxyTextures_[target];
TextureParams::MipmapLevel mip{};
auto& mip = proxyTex.params.mipmapData[level];
mip.width = width;
mip.height = height;
mip.internalFormat = internalFormat;
@@ -266,19 +266,25 @@ GLenum TextureState::Upload2D(GLenum target, GLint level, GLint internalFormat,
mip.type = type;
proxyTex.generated = true;
proxyTex.target = target;
proxyTex.params.mipmapData[level] = mip;
return GL_NO_ERROR;
}
GLuint boundTex = textureUnits_[activeTextureUnit_].GetBoundTexture(target);
TextureObject& tex = textures[boundTex];
TextureParams::MipmapLevel mip{};
// TextureParams::MipmapLevel mip{};
auto& mip = tex.params.mipmapData[level];
mip.width = width;
mip.height = height;
mip.internalFormat = internalFormat;
mip.format = format;
mip.type = type;
if (data != nullptr) {
mip.dirty = true;
if (data == nullptr) {
mip.hasData = false;
MG_Util::Debug::LogD("MG_State: Texture: Upload2D data pointer is null");
} else {
GLint unpackSwapBytes = GetUnpackParam_(GL_UNPACK_SWAP_BYTES);
GLint unpackLSBFirst = GetUnpackParam_(GL_UNPACK_LSB_FIRST);
GLint unpackSkipPixels = GetUnpackParam_(GL_UNPACK_SKIP_PIXELS);
@@ -288,47 +294,69 @@ GLenum TextureState::Upload2D(GLenum target, GLint level, GLint internalFormat,
GLint unpackImageHeight = GetUnpackParam_(GL_UNPACK_IMAGE_HEIGHT);
GLint unpackSkipImages = GetUnpackParam_(GL_UNPACK_SKIP_IMAGES);
GLsizei rowLength = (unpackRowLength > 0) ? unpackRowLength : width;
bool isDefaultUnpack = (unpackSwapBytes == 0) && (unpackLSBFirst == 0) &&
(unpackSkipPixels == 0) && (unpackSkipRows == 0) &&
(unpackRowLength == 0) && (unpackAlignment == 4) &&
(unpackImageHeight == 0) && (unpackSkipImages == 0);
size_t bytesPerPixel = CalculateBytesPerPixel_(format, type);
size_t componentSize = GetComponentSize_(type);
size_t srcRowSize = rowLength * bytesPerPixel;
size_t srcRowStride = (srcRowSize + unpackAlignment - 1) & ~(unpackAlignment - 1);
size_t srcImageStride = (unpackImageHeight > 0) ?
srcRowStride * unpackImageHeight :
srcRowStride * height;
const GLubyte* srcData = static_cast<const GLubyte*>(data);
srcData += unpackSkipImages * srcImageStride;
srcData += unpackSkipRows * srcRowStride;
srcData += unpackSkipPixels * bytesPerPixel;
size_t dstRowStride = width * bytesPerPixel;
size_t dstSize = dstRowStride * height;
mip.pixelData.resize(dstSize);
GLubyte* dstData = mip.pixelData.data();
GLubyte *dstData = mip.pixelData.data();
for (GLsizei y = 0; y < height; ++y) {
const GLubyte* srcRow = srcData + y * srcRowStride;
GLubyte* dstRow = dstData + y * dstRowStride;
if (isDefaultUnpack) {
const GLubyte *srcData = static_cast<const GLubyte *>(data);
size_t srcRowSize = width * bytesPerPixel;
size_t srcRowStride = (srcRowSize + unpackAlignment - 1) & ~(unpackAlignment - 1);
if (unpackSwapBytes) {
SwapBytesForTexture_(format, type, srcRow, dstRow, width);
if (srcRowStride == dstRowStride) {
memcpy(dstData, srcData, dstSize);
MG_Util::Debug::LogD(
"MG_State: Texture: Upload2D uploaded %zu bytes with fast path - block memcpy", dstSize);
} else {
for (GLsizei y = 0; y < height; ++y) {
const GLubyte *srcRow = srcData + y * srcRowStride;
GLubyte *dstRow = dstData + y * dstRowStride;
memcpy(dstRow, srcRow, srcRowSize);
}
MG_Util::Debug::LogD(
"MG_State: Texture: Upload2D uploaded %zu bytes with fast path - row memcpy", dstSize);
}
else if (unpackLSBFirst && componentSize == 1) {
ReverseBitOrder_(srcRow, dstRow, width * bytesPerPixel);
}
else {
memcpy(dstRow, srcRow, width * bytesPerPixel);
} else {
GLsizei rowLength = (unpackRowLength > 0) ? unpackRowLength : width;
size_t srcRowSize = rowLength * bytesPerPixel;
size_t srcRowStride = (srcRowSize + unpackAlignment - 1) & ~(unpackAlignment - 1);
size_t srcImageStride = (unpackImageHeight > 0) ?
srcRowStride * unpackImageHeight :
srcRowStride * height;
const GLubyte *srcData = static_cast<const GLubyte *>(data);
srcData += unpackSkipImages * srcImageStride;
srcData += unpackSkipRows * srcRowStride;
srcData += unpackSkipPixels * bytesPerPixel;
for (GLsizei y = 0; y < height; ++y) {
const GLubyte *srcRow = srcData + y * srcRowStride;
GLubyte *dstRow = dstData + y * dstRowStride;
if (unpackSwapBytes) {
SwapBytesForTexture_(format, type, srcRow, dstRow, width);
} else if (unpackLSBFirst && componentSize == 1) {
ReverseBitOrder_(srcRow, dstRow, width * bytesPerPixel);
} else {
memcpy(dstRow, srcRow, width * bytesPerPixel);
}
}
mip.hasData = true;
MG_Util::Debug::LogD(
"MG_State: Texture: Upload2D uploaded %zu bytes with unpack params", dstSize);
}
mip.hasData = true;
MG_Util::Debug::LogD("MG_State: Texture: Upload2D uploaded %zu bytes with unpack params", dstSize);
} else {
mip.hasData = false;
MG_Util::Debug::LogD("MG_State: Texture: Upload2D data pointer is null");
}
tex.params.mipmapData[level] = mip;
// tex.params.mipmapData[level] = mip;
return GL_NO_ERROR;
}
@@ -364,7 +392,7 @@ GLenum TextureState::UpdateRegion2D(GLenum target, GLint level, GLint xoffset,
const size_t bytesPerPixel = CalculateBytesPerPixel_(format, type);
const size_t srcSize = CalculatePixelDataSize_(format, type, width, height);
if (bytesPerPixel == 0) {
MG_Util::Debug::LogE("MG_State: Texture: Invalid format/type combination");
return GL_INVALID_ENUM;
@@ -402,27 +430,68 @@ GLenum TextureState::UpdateRegion2D(GLenum target, GLint level, GLint xoffset,
MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D srcData=%p, dstData=%p", srcData, dstData);
MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D bytesPerPixel=%zu", bytesPerPixel);
for (GLsizei y = 0; y < height; ++y) {
const GLubyte* srcRow = srcData + y * srcRowStride;
GLubyte* dstRow = dstData + y * dstRowStride;
// Check if fast path is applicable
const bool isDefaultUnpack = (unpackSwapBytes == 0) && (unpackLSBFirst == 0) &&
(unpackRowLength == 0) && (unpackAlignment == 4) &&
(unpackSkipPixels == 0) && (unpackSkipRows == 0) &&
(unpackImageHeight == 0) && (unpackSkipImages == 0);
if (unpackSwapBytes) {
for (GLsizei x = 0; x < width; ++x) {
const GLubyte* srcPixel = srcRow + x * bytesPerPixel;
GLubyte* dstPixel = dstRow + x * bytesPerPixel;
SwapPixelBytes_(format, type, srcPixel, dstPixel);
}
} else if (unpackLSBFirst && GetComponentSize_(type) == 1) {
for (size_t i = 0; i < width * bytesPerPixel; ++i) {
dstRow[i] = ReverseBits_(srcRow[i]);
}
if (isDefaultUnpack) {
const size_t copySize = width * bytesPerPixel;
if (srcRowStride == dstRowStride) {
MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D block memcpy(dst=%p, src=%p, size=%zu) called.", dstData, srcData, width * bytesPerPixel);
memcpy(dstData, srcData, copySize * height);
} else {
MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D memcpy(dst=%p, src=%p, size=%zu) called.", dstRow, srcRow, width * bytesPerPixel);
memcpy(dstRow, srcRow, width * bytesPerPixel);
for (GLsizei y = 0; y < height; ++y) {
const GLubyte* srcRow = srcData + y * srcRowStride;
GLubyte* dstRow = dstData + y * dstRowStride;
memcpy(dstRow, srcRow, copySize);
MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D row memcpy(dst=%p, src=%p, size=%zu) called.", dstRow, srcRow, width * bytesPerPixel);
}
}
} else {
const size_t componentSize = GetComponentSize_(type);
for (GLsizei y = 0; y < height; ++y) {
const GLubyte* srcRow = srcData + y * srcRowStride;
GLubyte* dstRow = dstData + y * dstRowStride;
if (unpackSwapBytes) {
for (GLsizei x = 0; x < width; ++x) {
SwapPixelBytes_(format, type, srcRow + x*bytesPerPixel, dstRow + x*bytesPerPixel);
}
} else if (unpackLSBFirst && componentSize == 1) {
for (size_t i = 0; i < width * bytesPerPixel; ++i) {
dstRow[i] = ReverseBits_(srcRow[i]);
}
} else {
memcpy(dstRow, srcRow, width * bytesPerPixel);
}
}
}
// for (GLsizei y = 0; y < height; ++y) {
// const GLubyte* srcRow = srcData + y * srcRowStride;
// GLubyte* dstRow = dstData + y * dstRowStride;
//
// if (unpackSwapBytes) {
// for (GLsizei x = 0; x < width; ++x) {
// const GLubyte* srcPixel = srcRow + x * bytesPerPixel;
// GLubyte* dstPixel = dstRow + x * bytesPerPixel;
// SwapPixelBytes_(format, type, srcPixel, dstPixel);
// }
// } else if (unpackLSBFirst && GetComponentSize_(type) == 1) {
// for (size_t i = 0; i < width * bytesPerPixel; ++i) {
// dstRow[i] = ReverseBits_(srcRow[i]);
// }
// } else {
// MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D memcpy(dst=%p, src=%p, size=%zu) called.", dstRow, srcRow, width * bytesPerPixel);
// memcpy(dstRow, srcRow, width * bytesPerPixel);
// }
// }
mip.hasData = true;
mip.dirty = true;
MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D succeeded");
return GL_NO_ERROR;
}
@@ -541,7 +610,7 @@ GLenum TextureState::Delete(GLuint texture) {
if (it != this->textures.end()) {
InvalidateTextureInAllUnits_(texture);
this->textures.erase(it);
freeIDs_.insert(texture);
//freeID_.emplace_back(texture);
MG_Util::Debug::LogD("MG_State: Texture: Delete succeeded for texture=%u", texture);
} else {
MG_Util::Debug::LogW("MG_State: Texture: Delete texture %u not found", texture);
@@ -563,7 +632,8 @@ GLenum TextureState::DeleteN(GLsizei n, const GLuint* textures) {
if (it != this->textures.end()) {
InvalidateTextureInAllUnits_(id);
this->textures.erase(it);
freeIDs_.insert(id);
// TODO: Prevent the object that uses a freeId from conflicting with legacy object in the backend.
//freeID_.emplace_back(id);
MG_Util::Debug::LogD("MG_State: Texture: DeleteN deleted texture=%u", id);
} else {
MG_Util::Debug::LogW("MG_State: Texture: DeleteN texture %u not found", id);
@@ -630,7 +700,7 @@ GLenum TextureState::QueryLevelPropertyIntVector(GLenum target, GLint level, GLe
return GL_NO_ERROR;
}
std::unordered_map<GLuint, TextureObject>::iterator texIt;
unordered_map<GLuint, TextureObject>::iterator texIt;
if (!isProxyTexture) {
texIt = textures.find(boundTexture);
@@ -803,10 +873,10 @@ GLenum TextureState::CheckUploadingTexture2DValidity_(GLenum target, GLint level
return GL_INVALID_OPERATION;
}
bool isDepthInternal = (internalFormat == GL_DEPTH_COMPONENT32F || internalFormat == GL_DEPTH_COMPONENT24
|| internalFormat == GL_DEPTH_COMPONENT16 || internalFormat == GL_DEPTH32F_STENCIL8
|| internalFormat == GL_DEPTH24_STENCIL8 || internalFormat == GL_DEPTH_COMPONENT
|| internalFormat == GL_DEPTH_STENCIL);
bool isDepthInternal = (internalFormat == GL_DEPTH_COMPONENT32 || internalFormat == GL_DEPTH_COMPONENT32F ||
internalFormat == GL_DEPTH_COMPONENT24 || internalFormat == GL_DEPTH_COMPONENT16 ||
internalFormat == GL_DEPTH32F_STENCIL8 || internalFormat == GL_DEPTH24_STENCIL8 ||
internalFormat == GL_DEPTH_COMPONENT || internalFormat == GL_DEPTH_STENCIL);
bool isDepthFormat = (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL);
if (isDepthInternal != isDepthFormat) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUploadingTexture2DValidity_ depth internal/format mismatch");
@@ -895,7 +965,7 @@ GLenum TextureState::CheckUpdatingTextureRegion2DValidity_(GLenum target, GLint
return GL_INVALID_OPERATION;
}
auto tex = textures[boundTex];
const auto& tex = textures[boundTex];
if (tex.IsImmutable()) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity_ texture is immutable");
@@ -934,7 +1004,7 @@ GLenum TextureState::CheckUpdatingTextureRegion2DValidity_(GLenum target, GLint
return GL_INVALID_OPERATION;
}
TextureParams::MipmapLevel& mip = mipIt->second;
const auto& mip = mipIt->second;
if (xoffset + width > mip.width || yoffset + height > mip.height) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity_ region out of bounds: "
"x=%d+%d > %d or y=%d+%d > %d",
+18 -10
View File
@@ -19,8 +19,10 @@ struct ComponentSizes {
};
struct TextureParams {
std::unordered_map<GLenum, GLfloat> texPropertiesFloat;
std::unordered_map<GLenum, GLint> texPropertiesInt;
template <typename K, typename V>
using unordered_map = ankerl::unordered_dense::map<K, V>;
unordered_map<GLenum, GLfloat> texPropertiesFloat;
unordered_map<GLenum, GLint> texPropertiesInt;
struct MipmapLevel {
GLsizei width = 0;
GLsizei height = 0;
@@ -29,8 +31,9 @@ struct TextureParams {
GLenum type = GL_UNSIGNED_BYTE;
std::vector<GLubyte> pixelData;
bool hasData = false;
bool dirty = false; // TODO: encapsulate this with an public API to RHI
};
std::unordered_map<GLint, MipmapLevel> mipmapData;
unordered_map<GLint, MipmapLevel> mipmapData;
};
class TextureObject {
@@ -44,24 +47,27 @@ public:
};
class TextureUnitState {
template <typename K, typename V>
using unordered_map = ankerl::unordered_dense::map<K, V>;
private:
GLenum activeTarget = GL_TEXTURE_2D;
public:
std::unordered_map<GLenum, GLuint> boundTextures;
unordered_map<GLenum, GLuint> boundTextures;
void Bind(GLenum target, GLuint texture);
GLuint GetBoundTexture(GLenum target);
};
class TextureState {
template <typename K, typename V>
using unordered_map = ankerl::unordered_dense::map<K, V>;
private:
std::vector<TextureUnitState> textureUnits_;
GLuint activeTextureUnit_ = 0;
GLuint lastUsedID_ = 0;
std::set<GLuint> freeIDs_;
GLuint lastUsedID_ = 1;
// ankerl::unordered_set<GLuint> freeIDs_;
std::vector<GLuint> freeID_;
std::unordered_map<GLenum, TextureObject> proxyTextures_;
unordered_map<GLenum, TextureObject> proxyTextures_;
static GLint GetUnpackParam_(GLenum pname);
public:
@@ -69,7 +75,7 @@ public:
bool IsTextureGenerated(GLuint texture);
bool IsTexture(GLuint texture);
std::unordered_map<GLuint, TextureObject> textures;
unordered_map<GLuint, TextureObject> textures;
// Return: the validity of the operation, according to OpenGL 3 standard
GLenum BindUnit(GLenum textureUnit);
@@ -88,6 +94,8 @@ public:
GLenum DeleteN(GLsizei n, const GLuint* textures);
GLenum QueryLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params);
std::vector<TextureUnitState> textureUnits_;
GLuint activeTextureUnit_ = 0;
private:
size_t CalculatePixelDataSize_(GLenum format, GLenum type, GLsizei width, GLsizei height);
void InvalidateTextureInAllUnits_(GLuint texture);
@@ -10,6 +10,37 @@ VertexArrayState::VertexArrayState() {
vaos_[0];
}
GLenum VertexArrayState::GenName(GLuint *array) {
MG_Util::Debug::LogD("MG_State: VAO: GenName");
if (!array)
return GL_INVALID_VALUE;
GLuint id;
if (freeIds_.empty()) {
id = ++lastId_;
} else {
id = *freeIds_.begin();
freeIds_.erase(freeIds_.begin());
}
*array = id;
MG_Util::Debug::LogD("MG_State: VAO: Generated new name %d", id);
return GL_NO_ERROR;
}
GLenum VertexArrayState::GenNameN(GLsizei n, GLuint* arrays) {
MG_Util::Debug::LogD("MG_State: VAO: GenNameN called with n=%d", n);
if (n < 0)
return GL_INVALID_VALUE;
for (GLsizei i = 0; i < n; ++i) {
GLenum result = GenName(&arrays[i]);
if (result != GL_NO_ERROR) {
MG_Util::Debug::LogE("MG_State: VAO: GenNameN failed at index %d with error 0x%x", i, result);
return result;
}
}
MG_Util::Debug::LogD("MG_State: VAO: GenNameN created %d names", n);
return GL_NO_ERROR;
}
GLenum VertexArrayState::Create(GLuint* array) {
if (array == nullptr) return GL_INVALID_VALUE;
@@ -41,24 +72,57 @@ GLenum VertexArrayState::CreateN(GLsizei n, GLuint* arrays) {
}
GLenum VertexArrayState::Bind(GLuint array) {
if (array != 0 && !vaos_.count(array)) return GL_INVALID_OPERATION;
MG_Util::Debug::LogD("MG_State: VAO: Bind called for %u", array);
if (array != 0) {
if (!ValidateGeneratedName(array)) {
MG_Util::Debug::LogE("MG_State: VAO: Bind invalid name %u", array);
return GL_INVALID_OPERATION;
}
auto& vao = vaos_[array];
if (!vao.generated) {
MG_Util::Debug::LogD("MG_State: VAO: Creating VAO %u during bind", array);
vao.generated = true;
}
}
currentVao_ = array;
MG_Util::Debug::LogD("MG_State: VAO: Bound to %u", array);
return GL_NO_ERROR;
}
bool VertexArrayState::ValidateGeneratedName(GLuint array) {
if (array == 0)
return true;
bool inFreeList = freeIds_.count(array) > 0;
bool valid = (array <= lastId_) && !inFreeList;
MG_Util::Debug::LogD("MG_State: VAO: ValidateGeneratedName %u: %d", array, valid);
return valid;
}
bool VertexArrayState::ValidateAllocatedHandle(GLuint array) {
bool exists = vaos_.count(array) && vaos_[array].generated;
MG_Util::Debug::LogD("MG_State: VAO: ValidateAllocatedHandle %u: %d", array, exists);
return exists;
}
GLenum VertexArrayState::EnableAttrib(GLuint index) {
if (currentVao_ == 0) return GL_INVALID_OPERATION;
if (!ValidateAllocatedHandle(currentVao_))
return GL_INVALID_OPERATION;
if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
GetCurrentVAO()->attribs[index].enabled = true;
MG_Util::Debug::LogD("Attrib vaos_[%u].attribs[%u].enabled = %d", currentVao_, index, vaos_[currentVao_].attribs[index].enabled);
GetCurrentVAO()->attribDirty = true;
return GL_NO_ERROR;
}
GLenum VertexArrayState::DisableAttrib(GLuint index) {
if (currentVao_ == 0) return GL_INVALID_OPERATION;
if (!ValidateAllocatedHandle(currentVao_))
return GL_INVALID_OPERATION;
if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
GetCurrentVAO()->attribs[index].enabled = false;
MG_Util::Debug::LogD("Attrib vaos_[%u].attribs[%u].enabled = %d", currentVao_, index, vaos_[currentVao_].attribs[index].enabled);
GetCurrentVAO()->attribDirty = true;
return GL_NO_ERROR;
}
@@ -66,7 +130,8 @@ GLenum VertexArrayState::SetAttribPointer(GLuint index, GLint size, GLenum type,
GLboolean normalized, GLsizei stride,
const void* pointer, bool isInteger,
GLuint currentArrayBuffer) {
if (currentVao_ == 0) return GL_INVALID_OPERATION;
if (!ValidateAllocatedHandle(currentVao_))
return GL_INVALID_OPERATION;
if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE;
VertexAttribState state;
@@ -81,6 +146,8 @@ GLenum VertexArrayState::SetAttribPointer(GLuint index, GLint size, GLenum type,
state.enabled = true;
vaos_[currentVao_].attribs[index] = state;
GetCurrentVAO()->attribDirty = true;
return GL_NO_ERROR;
}
+10 -4
View File
@@ -9,7 +9,7 @@
#include "../../../Includes.h"
struct VertexAttribState {
bool enabled = false;
bool enabled;
GLint size = 4;
GLenum type = GL_FLOAT;
GLboolean normalized = GL_FALSE;
@@ -21,8 +21,10 @@ struct VertexAttribState {
struct VertexArrayObject {
bool generated = false;
bool attribDirty = false;
bool eboDirty = false;
GLuint elementBuffer = 0;
std::unordered_map<GLuint, VertexAttribState> attribs;
ankerl::unordered_map<GLuint, VertexAttribState> attribs;
};
class VertexArrayState {
@@ -30,6 +32,8 @@ public:
VertexArrayState();
// Return: the validity of the operation, according to OpenGL 3 standard
GLenum GenName(GLuint* array);
GLenum GenNameN(GLsizei n, GLuint* arrays);
GLenum Create(GLuint* array);
GLenum CreateN(GLsizei n, GLuint* arrays);
GLenum Bind(GLuint array);
@@ -42,12 +46,14 @@ public:
GLuint GetBoundElementBuffer();
VertexArrayObject* GetCurrentVAO();
bool ValidateGeneratedName(GLuint array);
bool ValidateAllocatedHandle(GLuint array);
GLuint currentVao_ = 0;
ankerl::unordered_map<GLuint, VertexArrayObject> vaos_;
private:
std::unordered_map<GLuint, VertexArrayObject> vaos_;
std::set<GLuint> freeIds_;
GLuint lastId_ = 0;
GLuint currentVao_ = 0;
};
#endif //MOBILEGL_VERTEXARRAYSTATE_H