[Feat] (MG_Backend/DirectGLES): Implement basic stuff for DirectGLES backend.

This commit is contained in:
BZLZHH
2025-10-19 11:47:44 +08:00
parent ef2221659a
commit 93a0bbaed8
19 changed files with 1574 additions and 24 deletions
+4
View File
@@ -84,6 +84,10 @@ set(SOURCE_FILES
MobileGL/MG_Backend/Init.cpp
MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp
MobileGL/MG_Backend/DirectGLES/Utils.cpp
MobileGL/MG_Backend/DirectGLES/Managers.cpp
MobileGL/MG_State/GLState/Core.cpp
MobileGL/MG_State/GLState/ErrorState/Error.cpp
MobileGL/MG_State/GLState/BufferState/BufferState.cpp
@@ -0,0 +1,294 @@
#include "DirectGLES.h"
#include "Utils.h"
#include "Managers.h"
#include <MG_State/GLState/Core.h>
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/RenderStateEnumConverter.h>
namespace MobileGL::MG_Backend::DirectGLES {
// TODO: deletion of deleted objects
namespace BufferImpl {
void SyncNeccessaryBuffers() {
// All buffers we need are:
// 1.VBOs 2.IBO 3.UBOs (TODO) 4.SSBOs (TODO)
Vector<SharedPtr<MG_State::GLState::BufferObject>> buffersToSync;
const auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
if (!currentVAOObject) {
MGLOG_E("No VAO is currently bound, cannot sync necessary buffers.");
return;
}
for (const auto& attrib : currentVAOObject->GetAllAttributes()) {
const auto& bufferObject = attrib.Buffer;
if (bufferObject) {
buffersToSync.push_back(bufferObject);
}
}
const auto& possibleIBO = currentVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
if (possibleIBO) {
buffersToSync.push_back(possibleIBO);
}
// Do real sync
for (auto& bufferObject : buffersToSync) {
const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject);
SharedPtr<BackendBufferObject> backendBufferObject;
if (backendBufferIt != g_backendBufferObjects.end()) {
backendBufferObject = MakeShared<BackendBufferObject>();
g_backendBufferObjects[bufferObject] = backendBufferObject;
} else {
backendBufferObject = backendBufferIt->second;
}
backendBufferObject->SyncToBackend(bufferObject);
}
}
} // namespace BufferImpl
namespace VertexArrayImpl {
void SyncCurrentVAO() {
auto currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
if (!currentVAOObject) {
MGLOG_E("No VAO is currently bound, cannot sync current VAO.");
return;
}
const auto& backendVAOIt = g_backendVertexArrayObjects.find(currentVAOObject);
SharedPtr<VertexArrayImpl::BackendVertexArrayObject> backendVAOObject;
if (backendVAOIt == g_backendVertexArrayObjects.end()) {
backendVAOObject = MakeShared<VertexArrayImpl::BackendVertexArrayObject>();
g_backendVertexArrayObjects[currentVAOObject] = backendVAOObject;
} else {
backendVAOObject = backendVAOIt->second;
}
backendVAOObject->SyncToBackend(currentVAOObject);
}
} // namespace VertexArrayImpl
namespace TextureImpl {
void SyncNeccessaryTextures() {
// All textures we need are:
// 1. textures bound to current texture units (TODO: only sync ones that are used in current program)
// 2. textures used in current FBO
// 3. textures bound to image units (TODO)
Vector<SharedPtr<MG_State::GLState::ITextureObject>> texturesToSync;
auto& currentUnit =
MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
for (auto& bindingSlot : currentUnit.GetAllBindingSlots()) {
const auto& textureObject = bindingSlot.GetBoundObject();
if (textureObject) {
texturesToSync.push_back(textureObject);
}
}
const auto& currentFBO =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
if (currentFBO) {
for (auto& attachment : currentFBO->GetAllAttachments()) {
if (!attachment.IsTexture()) continue;
const auto& textureObject = attachment.GetTexture();
if (textureObject) {
texturesToSync.push_back(textureObject);
}
}
}
// Do real sync
for (auto& textureObject : texturesToSync) {
const auto& backendTextureIt = g_backendTextureObjects.find(textureObject);
SharedPtr<BackendTextureObject> backendTextureObject;
if (backendTextureIt == g_backendTextureObjects.end()) {
backendTextureObject = MakeShared<BackendTextureObject>();
g_backendTextureObjects[textureObject] = backendTextureObject;
} else {
backendTextureObject = backendTextureIt->second;
}
backendTextureObject->SyncToBackend(textureObject);
}
}
} // namespace TextureImpl
namespace FramebufferImpl {
void SyncCurrentFBO() {
auto currentFBO = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
if (!currentFBO) {
MGLOG_E("No FBO is currently bound, cannot sync current FBO.");
return;
}
const auto& backendFBOIt = g_backendFramebufferObjects.find(currentFBO);
SharedPtr<BackendFramebufferObject> backendFBOObject;
if (backendFBOIt == g_backendFramebufferObjects.end()) {
backendFBOObject = MakeShared<BackendFramebufferObject>();
g_backendFramebufferObjects[currentFBO] = backendFBOObject;
} else {
backendFBOObject = backendFBOIt->second;
}
backendFBOObject->SyncToBackend(currentFBO);
}
} // namespace FramebufferImpl
namespace RenderStateImpl {
void SyncRenderState() {
/*
void SetViewport(IntVec4 viewport); // x, y, width, height
const IntVec4& GetViewport() const; // x, y, width, height
void SetCapability(CapabilityInput cap, Bool enabled);
Bool IsCapabilityEnabled(CapabilityInput cap) const;
void SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, BlendFactor dstAlpha);
void GetBlendFunc(BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
BlendFactor& dstAlpha) const;
void SetDepthFunc(DepthTestFunc func);
DepthTestFunc GetDepthFunc() const;
void SetDepthMask(Bool flag);
Bool GetDepthMask() const;
void SetColorMask(BoolVec4 mask);
const BoolVec4 GetColorMask() const;
void SetClearColor(FloatVec4 color);
const FloatVec4& GetClearColor() const;
void SetClearDepth(Float depth);
Float GetClearDepth() const;
void SetPixelStoreParam(PixelStoreParam param, Int value);
Int GetPixelStoreParam(PixelStoreParam param) const;
void SetCullFaceMode(CullFaceMode mode);
CullFaceMode GetCullFaceMode() const;*/
MG_External::GLES::glViewport(
MG_State::pGLContext->GetViewport().x(), MG_State::pGLContext->GetViewport().y(),
MG_State::pGLContext->GetViewport().z(), MG_State::pGLContext->GetViewport().w());
if (MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::DepthTest)) {
MG_External::GLES::glEnable(GL_DEPTH_TEST);
} else {
MG_External::GLES::glDisable(GL_DEPTH_TEST);
}
if (MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::Blend)) {
MG_External::GLES::glEnable(GL_BLEND);
} else {
MG_External::GLES::glDisable(GL_BLEND);
}
auto ToGLBoolean = [](Bool b) -> GLboolean { return b ? GL_TRUE : GL_FALSE; };
{
BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha;
MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
MG_External::GLES::glBlendFuncSeparate(
MG_Util::ConvertBlendFactorToGLEnum(srcRGB), MG_Util::ConvertBlendFactorToGLEnum(dstRGB),
MG_Util::ConvertBlendFactorToGLEnum(srcAlpha), MG_Util::ConvertBlendFactorToGLEnum(dstAlpha));
}
{
DepthTestFunc df = MG_State::pGLContext->GetDepthFunc();
MG_External::GLES::glDepthFunc(MG_Util::ConvertDepthTestFuncToGLEnum(df));
MG_External::GLES::glDepthMask(MG_State::pGLContext->GetDepthMask() ? GL_TRUE : GL_FALSE);
}
{
BoolVec4 colorMask = MG_State::pGLContext->GetColorMask();
MG_External::GLES::glColorMask(ToGLBoolean(colorMask.x()), ToGLBoolean(colorMask.y()),
ToGLBoolean(colorMask.z()), ToGLBoolean(colorMask.w()));
}
{
const FloatVec4& clearCol = MG_State::pGLContext->GetClearColor();
MG_External::GLES::glClearColor(clearCol.x(), clearCol.y(), clearCol.z(), clearCol.w());
MG_External::GLES::glClearDepthf(MG_State::pGLContext->GetClearDepth());
}
{
{
PixelStoreParam p = PixelStoreParam::UnpackAlignment;
GLint v = MG_State::pGLContext->GetPixelStoreParam(p);
MG_External::GLES::glPixelStorei(MG_Util::ConvertPixelStoreParamToGLEnum(p), v);
}
{
PixelStoreParam p = PixelStoreParam::PackAlignment;
GLint v = MG_State::pGLContext->GetPixelStoreParam(p);
MG_External::GLES::glPixelStorei(MG_Util::ConvertPixelStoreParamToGLEnum(p), v);
}
}
if (MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace)) {
MG_External::GLES::glEnable(GL_CULL_FACE);
} else {
MG_External::GLES::glDisable(GL_CULL_FACE);
}
{
CullFaceMode cfm = MG_State::pGLContext->GetCullFaceMode();
MG_External::GLES::glCullFace(MG_Util::ConvertCullFaceModeToGLEnum(cfm));
}
}
} // namespace RenderStateImpl
namespace PrgramImpl {
void SyncCurrentProgram() {
auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
if (!currentProgram) {
MG_External::GLES::glUseProgram(0);
return;
}
auto backendProgramIt = g_backendProgramObjects.find(currentProgram);
SharedPtr<BackendProgramObjectImpl> backendProgram;
if (backendProgramIt == g_backendProgramObjects.end()) {
backendProgram = MakeShared<BackendProgramObjectImpl>();
g_backendProgramObjects[currentProgram] = backendProgram;
backendProgram->SyncToBackend(currentProgram);
} else {
backendProgram = backendProgramIt->second;
if (!backendProgram->GetBackendProgramId()) {
backendProgram->SyncToBackend(currentProgram);
}
}
backendProgram->Use();
}
} // namespace PrgramImpl
void PrepareForDraw() {
BufferImpl::SyncNeccessaryBuffers();
VertexArrayImpl::SyncCurrentVAO();
TextureImpl::SyncNeccessaryTextures();
FramebufferImpl::SyncCurrentFBO();
PrgramImpl::SyncCurrentProgram();
RenderStateImpl::SyncRenderState();
}
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
PrepareForDraw();
MG_External::GLES::glDrawElements(mode, count, type, indices);
}
void Clear(GLbitfield mask) {
FramebufferImpl::SyncCurrentFBO();
RenderStateImpl::SyncRenderState();
MG_External::GLES::glClear(mask);
}
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint baseVertex) {
PrepareForDraw();
MG_External::GLES::glDrawElementsBaseVertex(mode, count, type, indices, baseVertex);
}
void MultiDrawElements(GLenum mode, const GLsizei* counts, GLenum type, const void* const* indices,
GLsizei drawcount) {
PrepareForDraw();
for (GLsizei i = 0; i < drawcount; ++i) {
MG_External::GLES::glDrawElements(mode, counts[i], type, indices[i]);
}
}
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* counts, GLenum type, const void* const* indices,
GLsizei drawcount, const GLint* baseVertices) {
PrepareForDraw();
for (GLsizei i = 0; i < drawcount; ++i) {
MG_External::GLES::glDrawElementsBaseVertex(mode, counts[i], type, indices[i], baseVertices[i]);
}
}
} // namespace MobileGL::MG_Backend::DirectGLES
@@ -0,0 +1,17 @@
#pragma once
#include <Includes.h>
#define CallAndCheck(operation) \
MGLOG_D("Call GLES func: %s", #operation); \
operation Utils::CheckGLESError();
namespace MobileGL::MG_Backend::DirectGLES {
void Clear(GLbitfield mask);
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
void DrawArrays(GLenum mode, GLint first, GLsizei count);
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex);
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount);
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount, const GLint* basevertex);
} // namespace MobileGL::MG_Backend::DirectGLES
+479
View File
@@ -0,0 +1,479 @@
#include "Managers.h"
#include "Utils.h"
#include "DirectGLES.h"
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/MGToGL/DataTypeConverter.h>
#include <MG_Util/Converters/MGToGL/BufferEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
namespace MobileGL::MG_Backend::DirectGLES {
namespace BufferImpl {
BackendBufferObject::BackendBufferObject() {
MG_External::GLES::glGenBuffers(1, &m_backendBufferId);
if (m_backendBufferId == 0) {
MGLOG_E("Failed to generate buffer object.");
} else {
MGLOG_D("Generated buffer object with ID: %u.", m_backendBufferId);
}
}
const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
void BackendBufferObject::SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
if (!stateBufferObject) {
MGLOG_E("State buffer object is null, cannot sync to backend.");
return;
}
SizeT bufferSize = stateBufferObject->GetSize();
if (bufferSize == 0) {
MGLOG_W("Buffer size is zero, skipping sync for object with ID: %u", m_backendBufferId);
return;
}
MGLOG_D("Syncing buffer object with ID: %u to backend for state: %s", m_backendBufferId,
stateBufferObject.get());
Bool needsRegeneration =
!m_isInitialized || bufferSize > m_prevBufferSize || bufferSize > m_prevBufferSize * 2;
if (needsRegeneration) {
MGLOG_D("Buffer size changed significantly or not initialized, regenerating buffer with ID: %u",
m_backendBufferId);
SyncToBackend_glBufferData(stateBufferObject);
m_isInitialized = true;
return;
}
switch (stateBufferObject->GetUsage()) {
case BufferUsage::StaticDraw:
SyncToBackend_glBufferSubData(stateBufferObject);
break;
case BufferUsage::DynamicDraw:
case BufferUsage::StreamDraw:
SyncToBackend_glMapBufferRange(stateBufferObject);
break;
default:
SyncToBackend_glBufferSubData(stateBufferObject);
break;
}
m_prevBufferSize = bufferSize;
}
void BackendBufferObject::SyncToBackend_glBufferData(
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
BackendBufferBindingProtector backendBufferBindingProtector(TempBufferTarget);
MGLOG_D("Syncing buffer data (glBufferData) for object with ID : %u", m_backendBufferId);
const void* data = stateBufferObject->GetDataReadOnly().get();
SizeT size = stateBufferObject->GetSize();
GLenum usage = MG_Util::ConvertBufferUsageToGLEnum(stateBufferObject->GetUsage());
MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId);
MG_External::GLES::glBufferData(TempBufferTarget, size, data, usage);
stateBufferObject->ClearDirty();
}
void BackendBufferObject::SyncToBackend_glBufferSubData(
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
BackendBufferBindingProtector backendBufferBindingProtector(TempBufferTarget);
MGLOG_D("Syncing buffer sub-data (glBufferSubData) for object with ID : %u", m_backendBufferId);
const void* data = stateBufferObject->GetDataReadOnly().get();
auto range = stateBufferObject->GetDirtyRange();
// dirty range: [range.start, range.end)
MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId);
MG_External::GLES::glBufferSubData(TempBufferTarget, range.start, range.end - range.start,
reinterpret_cast<const char*>(data) + range.start);
}
void BackendBufferObject::SyncToBackend_glMapBufferRange(
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, Bool invalidate) {
BackendBufferBindingProtector backendBufferBindingProtector(TempBufferTarget);
MGLOG_D("Syncing buffer map (glMapBuffer) for object with ID : %u", m_backendBufferId);
MGLOG_D("Mapping buffer with ID: %u", m_backendBufferId);
MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId);
auto range = stateBufferObject->GetDirtyRange();
void* mappedData = MG_External::GLES::glMapBufferRange(
TempBufferTarget, range.start, range.end - range.start,
(invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : 0) | GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
const void* data = stateBufferObject->GetDataReadOnly().get();
if (mappedData) {
Memcpy(reinterpret_cast<const void*>(reinterpret_cast<const char*>(data) + range.start), mappedData,
range.end - range.start);
MGLOG_D("Mapped buffer data successfully for object with ID: %u", m_backendBufferId);
MG_External::GLES::glUnmapBuffer(TempBufferTarget);
} else {
MGLOG_E("Failed to map buffer with ID: %u", m_backendBufferId);
}
}
void BackendBufferObject::Bind() {
MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId);
}
void BackendBufferObject::Bind(GLenum target) {
MG_External::GLES::glBindBuffer(target, m_backendBufferId);
}
UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>> g_backendBufferObjects;
} // namespace BufferImpl
namespace VertexArrayImpl {
BackendVertexArrayObject::BackendVertexArrayObject() {
MG_External::GLES::glGenVertexArrays(1, &m_backendVAOId);
if (m_backendVAOId == 0) {
MGLOG_E("Failed to generate vertex array object.");
} else {
MGLOG_D("Generated vertex array object with ID: %u.", m_backendVAOId);
}
}
void BackendVertexArrayObject::Bind() {
MG_External::GLES::glBindVertexArray(m_backendVAOId);
}
void BackendVertexArrayObject::SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject) {
if (!stateVAOObject) {
MGLOG_E("State VAO object is null, cannot sync to backend.");
return;
}
MGLOG_D("Syncing VAO object with ID: %u to backend for state: %s", m_backendVAOId, stateVAOObject.get());
BufferImpl::BackendBufferBindingProtector backendBufferBindingProtector(BufferImpl::TempBufferTarget);
BackendVertexArrayBindingProtector backendVAOBindingProtector;
Bind();
for (const auto& attribIndex : stateVAOObject->GetDirtyAttributeIndices()) {
const auto& attrib = stateVAOObject->GetAttribute(attribIndex);
auto bufferObject = attrib.Buffer;
if (!bufferObject) {
MGLOG_W("Attribute has no bound buffer, skipping.");
continue;
}
auto backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObject);
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
MGLOG_E("No backend buffer found for attribute's buffer, cannot bind attribute.");
continue;
}
auto backendBufferObject = backendBufferIt->second;
backendBufferObject->Bind(GL_ARRAY_BUFFER);
MG_External::GLES::glEnableVertexAttribArray(attribIndex);
MG_External::GLES::glVertexAttribPointer(
attribIndex, attrib.Size, MG_Util::ConvertDataTypeToGLEnum(attrib.Type),
attrib.Normalized ? GL_TRUE : GL_FALSE, attrib.Stride,
reinterpret_cast<const void*>(static_cast<SizeT>(attrib.Offset)));
// TODO: divisor
}
auto indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
if (indexBufferBinding) {
auto backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding);
if (backendBufferIt != BufferImpl::g_backendBufferObjects.end()) {
auto backendBufferObject = backendBufferIt->second;
backendBufferObject->Bind(GL_ELEMENT_ARRAY_BUFFER);
} else {
MGLOG_E("No backend buffer found for index buffer binding, cannot bind index buffer.");
}
}
stateVAOObject->ClearDirtyAttributes();
}
UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>>
g_backendVertexArrayObjects;
} // namespace VertexArrayImpl
namespace TextureImpl {
BackendTextureObject::BackendTextureObject() {
MG_External::GLES::glGenTextures(1, &m_backendTextureId);
if (m_backendTextureId == 0) {
MGLOG_E("Failed to generate texture object.");
} else {
MGLOG_D("Generated texture object with ID: %u.", m_backendTextureId);
}
}
void BackendTextureObject::Bind(GLenum target) {
MG_External::GLES::glBindTexture(target, m_backendTextureId);
}
Uint BackendTextureObject::GetBackendTextureId() {
return m_backendTextureId;
}
void BackendTextureObject::SyncToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
if (!stateTextureObject) {
MGLOG_E("State texture object is null, cannot sync to backend.");
return;
}
MGLOG_D("Syncing texture object with ID: %u to backend for state: %s", m_backendTextureId,
stateTextureObject.get());
GLenum target = MG_Util::ConvertTextureTargetToGLEnum(stateTextureObject->GetTarget());
// The texture needs to be regenerated completely with glTexImage* calls if:
// 1. Not initialized
// 2. InternalFormat changed
// 3. Size changed
// 4. Mipmap levels changed
if (!stateTextureObject->IsComplete()) {
MGLOG_E("Texture object with ID: %u is not complete, skipping sync.", m_backendTextureId);
return;
}
BackendTextureBindingProtector backendTextureBindingProtector(target);
Bind(target);
StateTextureBasicInfo currentTextureInfo = {
stateTextureObject->GetFormat(), static_cast<SizeT>(stateTextureObject->GetBaseSize().x()),
static_cast<SizeT>(stateTextureObject->GetBaseSize().y()),
static_cast<SizeT>(stateTextureObject->GetBaseSize().z()), stateTextureObject->GetMipmaps().size()};
Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo);
if (needsRegeneration) {
MGLOG_D("Texture state changed significantly or not initialized, regenerating texture with ID: %u",
m_backendTextureId);
// Regenerate all mipmap levels
const auto& mipmaps = stateTextureObject->GetMipmaps();
GLenum glInternalFormat, glType, glFormat;
TextureImpl::GenerateTextureFormatInfo(stateTextureObject->GetFormat(), &glInternalFormat, &glType,
&glFormat);
for (SizeT level = 0; level < mipmaps.size(); ++level) {
const auto& mipmap = mipmaps[level];
MG_External::GLES::glTexImage2D(GL_TEXTURE_2D, static_cast<GLint>(level), glInternalFormat,
static_cast<GLsizei>(mipmap.size.x()),
static_cast<GLsizei>(mipmap.size.y()), 0, glFormat, glType,
mipmap.data.data());
MGLOG_D("Regenerated mipmap level %d for texture with ID: %u", level, m_backendTextureId);
stateTextureObject->UnmarkMipmapDirty(level);
}
m_isInitialized = true;
}
{ // Update sampler parameters; TODO: always use sampler objects in backend
auto samplerObject = stateTextureObject->GetSamplerObject();
if (samplerObject) {
MG_External::GLES::glTexParameteri(
target, GL_TEXTURE_MIN_FILTER,
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObject->GetMinFilter()));
MG_External::GLES::glTexParameteri(
target, GL_TEXTURE_MAG_FILTER,
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObject->GetMagFilter()));
MG_External::GLES::glTexParameteri(
target, GL_TEXTURE_WRAP_S, MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObject->GetWrapS()));
MG_External::GLES::glTexParameteri(
target, GL_TEXTURE_WRAP_T, MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObject->GetWrapT()));
MG_External::GLES::glTexParameteri(
target, GL_TEXTURE_WRAP_R, MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObject->GetWrapR()));
}
}
{ // Update all dirty mipmap levels
const auto& mipmaps = stateTextureObject->GetMipmaps();
GLenum glInternalFormat, glType, glFormat;
TextureImpl::GenerateTextureFormatInfo(stateTextureObject->GetFormat(), &glInternalFormat, &glType,
&glFormat);
for (const auto& mipmap : stateTextureObject->GetMipmaps()) {
if (!mipmap.dirty) {
continue;
}
if (mipmap.data.empty()) {
MGLOG_W("Mipmap level %d has no data, skipping update.", mipmap.level);
continue;
}
MG_External::GLES::glTexSubImage2D(
GL_TEXTURE_2D, static_cast<GLint>(mipmap.level), 0, 0, static_cast<GLsizei>(mipmap.size.x()),
static_cast<GLsizei>(mipmap.size.y()), glFormat, glType, mipmap.data.data());
stateTextureObject->UnmarkMipmapDirty(mipmap.level);
}
}
m_prevTextureInfo = currentTextureInfo;
}
UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>>
g_backendTextureObjects;
} // namespace TextureImpl
namespace FramebufferImpl {
BackendFramebufferObject::BackendFramebufferObject() {
MG_External::GLES::glGenFramebuffers(1, &m_backendFBOId);
if (m_backendFBOId == 0) {
MGLOG_E("Failed to generate framebuffer object.");
} else {
MGLOG_D("Generated framebuffer object with ID: %u.", m_backendFBOId);
}
}
void BackendFramebufferObject::Bind() {
MG_External::GLES::glBindFramebuffer(GL_FRAMEBUFFER, m_backendFBOId);
}
void BackendFramebufferObject::SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject) {
if (!stateFBOObject) {
MGLOG_E("State FBO object is null, cannot sync to backend.");
return;
}
MGLOG_D("Syncing FBO object with ID: %u to backend for state: %s", m_backendFBOId, stateFBOObject.get());
BackendFramebufferBindingProtector backendFBOBindingProtector(GL_FRAMEBUFFER);
Bind();
// TODO: add dirty check
// Sync all attachments
const auto& attachments = stateFBOObject->GetAllAttachments();
for (SizeT index = 0; index < attachments.size(); ++index) {
FramebufferAttachmentType attachmentType = static_cast<FramebufferAttachmentType>(index);
const auto& attachment = attachments[index];
if (!attachment.IsComplete()) {
MG_External::GLES::glFramebufferRenderbuffer(
GL_FRAMEBUFFER, MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(attachmentType),
GL_RENDERBUFFER, 0);
continue;
}
if (attachment.IsTexture()) {
auto textureObject = attachment.GetTexture();
auto backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
MGLOG_E("No backend texture found for FBO attachment, cannot bind texture.");
continue;
}
auto backendTextureObject = backendTextureIt->second;
backendTextureObject->Bind(MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget()));
MG_External::GLES::glFramebufferTexture2D(
GL_FRAMEBUFFER, MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(attachmentType),
MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget()),
backendTextureObject->GetBackendTextureId(), static_cast<GLint>(attachment.GetTextureLevel()));
} else if (attachment.IsRenderbuffer()) {
// TODO
}
}
}
UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>>
g_backendFramebufferObjects;
} // namespace FramebufferImpl
namespace PrgramImpl {
UnorderedMap<SharedPtr<MG_State::GLState::ShaderObject>, SharedPtr<BackendShaderObjectImpl>>
g_backendShaderObjects;
UnorderedMap<SharedPtr<MG_State::GLState::ProgramObject>, SharedPtr<BackendProgramObjectImpl>>
g_backendProgramObjects;
BackendShaderObjectImpl::BackendShaderObjectImpl() {
m_backendShaderId = MG_External::GLES::glCreateShader(GL_VERTEX_SHADER);
if (m_backendShaderId == 0) {
MGLOG_E("Failed to create shader object in backend.");
}
}
BackendShaderObjectImpl::~BackendShaderObjectImpl() {
if (m_backendShaderId != 0) {
MG_External::GLES::glDeleteShader(m_backendShaderId);
}
}
void BackendShaderObjectImpl::SyncToBackend(SharedPtr<MG_State::GLState::ShaderObject>& stateShaderObject) {
if (!stateShaderObject || !stateShaderObject->GetCompileStatus()) {
MGLOG_E("Shader object is null or not compiled, skipping backend sync.");
return;
}
String source = stateShaderObject->GetShaderSource();
source = removeLayoutBinding(source);
source = ProcessOutColorLocations(source);
source = ForceSupporterOutput(source);
GLenum shaderType = ConvertGLShaderTypeByMGLShaderStage(stateShaderObject->GetShaderStage());
const char* sourceCStr = source.c_str();
MG_External::GLES::glShaderSource(m_backendShaderId, 1, &sourceCStr, nullptr);
MG_External::GLES::glCompileShader(m_backendShaderId);
GLint compileStatus;
MG_External::GLES::glGetShaderiv(m_backendShaderId, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus != GL_TRUE) {
GLint logLength;
MG_External::GLES::glGetShaderiv(m_backendShaderId, GL_INFO_LOG_LENGTH, &logLength);
Vector<GLchar> log(logLength);
MG_External::GLES::glGetShaderInfoLog(m_backendShaderId, logLength, nullptr, log.data());
MGLOG_E("Shader compilation failed: %s", log.data());
}
m_isInitialized = true;
}
BackendProgramObjectImpl::BackendProgramObjectImpl() {
m_backendProgramId = MG_External::GLES::glCreateProgram();
if (m_backendProgramId == 0) {
MGLOG_E("Failed to create program object in backend.");
}
}
BackendProgramObjectImpl::~BackendProgramObjectImpl() {
if (m_backendProgramId != 0) {
MG_External::GLES::glDeleteProgram(m_backendProgramId);
}
}
void BackendProgramObjectImpl::SyncToBackend(SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject) {
if (!stateProgramObject || !stateProgramObject->GetLinkStatus()) {
MGLOG_E("Program object is null or not linked, skipping backend sync.");
return;
}
// Detach all existing shaders
GLint attachedCount = 0;
MG_External::GLES::glGetProgramiv(m_backendProgramId, GL_ATTACHED_SHADERS, &attachedCount);
if (attachedCount > 0) {
Vector<GLuint> attachedShaders(attachedCount);
GLsizei actualCount;
MG_External::GLES::glGetAttachedShaders(m_backendProgramId, attachedCount, &actualCount,
attachedShaders.data());
for (GLsizei i = 0; i < actualCount; ++i) {
MG_External::GLES::glDetachShader(m_backendProgramId, attachedShaders[i]);
}
}
// Attach current shaders
for (auto& shader : stateProgramObject->GetAttachedShaders()) {
auto it = g_backendShaderObjects.find(shader);
if (it != g_backendShaderObjects.end() && it->second) {
MG_External::GLES::glAttachShader(m_backendProgramId, it->second->GetBackendShaderId());
}
}
// Link program
MG_External::GLES::glLinkProgram(m_backendProgramId);
GLint linkStatus;
MG_External::GLES::glGetProgramiv(m_backendProgramId, GL_LINK_STATUS, &linkStatus);
if (linkStatus != GL_TRUE) {
GLint logLength;
MG_External::GLES::glGetProgramiv(m_backendProgramId, GL_INFO_LOG_LENGTH, &logLength);
Vector<GLchar> log(logLength);
MG_External::GLES::glGetProgramInfoLog(m_backendProgramId, logLength, nullptr, log.data());
MGLOG_E("Program linking failed: %s", log.data());
}
m_isInitialized = true;
}
void BackendProgramObjectImpl::Use() {
MG_External::GLES::glUseProgram(m_backendProgramId);
}
} // namespace PrgramImpl
namespace Utils {} // namespace Utils
} // namespace MobileGL::MG_Backend::DirectGLES
+124
View File
@@ -0,0 +1,124 @@
#pragma once
#include <Includes.h>
#include "DirectGLES.h"
#include <MG_State/GLState/TextureState/TextureObject.h>
#include <MG_State/GLState/Core.h>
namespace MobileGL::MG_Backend::DirectGLES {
namespace BufferImpl {
class BackendBufferObject {
public:
BackendBufferObject();
void SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
void Bind();
void Bind(GLenum target);
private:
void SyncToBackend_glBufferData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
void SyncToBackend_glBufferSubData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
void SyncToBackend_glMapBufferRange(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject,
Bool invalidate = false);
Uint m_backendBufferId = 0;
SizeT m_prevBufferSize = 0;
Bool m_isInitialized = false;
};
extern UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>>
g_backendBufferObjects;
} // namespace BufferImpl
namespace VertexArrayImpl {
class BackendVertexArrayObject {
public:
BackendVertexArrayObject();
void SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
void Bind();
private:
Uint m_backendVAOId = 0;
Bool m_isInitialized = false;
};
extern UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>>
g_backendVertexArrayObjects;
} // namespace VertexArrayImpl
namespace TextureImpl {
struct StateTextureBasicInfo { // Used for tracking texture state changes
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
SizeT width = 0;
SizeT height = 0;
SizeT depth = 0;
SizeT mipmapLevels = 0;
bool operator==(const StateTextureBasicInfo& other) const {
return internalFormat == other.internalFormat && width == other.width && height == other.height &&
depth == other.depth && mipmapLevels == other.mipmapLevels;
}
bool operator!=(const StateTextureBasicInfo& other) const { return !(*this == other); }
};
class BackendTextureObject {
public:
BackendTextureObject();
void SyncToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
void Bind(GLenum target);
Uint GetBackendTextureId();
private:
Uint m_backendTextureId = 0;
Bool m_isInitialized = false;
StateTextureBasicInfo m_prevTextureInfo;
};
extern UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>>
g_backendTextureObjects;
} // namespace TextureImpl
namespace FramebufferImpl {
class BackendFramebufferObject {
public:
BackendFramebufferObject();
void SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject);
void Bind();
private:
Uint m_backendFBOId = 0;
};
extern UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>>
g_backendFramebufferObjects;
} // namespace FramebufferImpl
namespace PrgramImpl {
class BackendShaderObjectImpl {
public:
BackendShaderObjectImpl();
~BackendShaderObjectImpl();
void SyncToBackend(SharedPtr<MG_State::GLState::ShaderObject>& stateShaderObject);
Uint GetBackendShaderId() const { return m_backendShaderId; }
private:
Uint m_backendShaderId = 0;
Bool m_isInitialized = false;
};
class BackendProgramObjectImpl {
public:
BackendProgramObjectImpl();
~BackendProgramObjectImpl();
void SyncToBackend(SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject);
void Use();
Uint GetBackendProgramId() const { return m_backendProgramId; }
private:
Uint m_backendProgramId = 0;
Bool m_isInitialized = false;
};
extern UnorderedMap<SharedPtr<MG_State::GLState::ShaderObject>, SharedPtr<BackendShaderObjectImpl>>
g_backendShaderObjects;
extern UnorderedMap<SharedPtr<MG_State::GLState::ProgramObject>, SharedPtr<BackendProgramObjectImpl>>
g_backendProgramObjects;
} // namespace PrgramImpl
} // namespace MobileGL::MG_Backend::DirectGLES
+472
View File
@@ -0,0 +1,472 @@
#include "DirectGLES.h"
#include "Utils.h"
#include "Managers.h"
#include <MG_State/GLState/Core.h>
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
namespace MobileGL::MG_Backend::DirectGLES {
namespace BufferImpl {
BackendBufferBindingProtector::BackendBufferBindingProtector(GLenum target) {
m_target = target;
MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, false), &m_previousBinding);
}
BackendBufferBindingProtector::~BackendBufferBindingProtector() {
MG_External::GLES::glBindBuffer(m_target, m_previousBinding);
}
} // namespace BufferImpl
namespace VertexArrayImpl {
BackendVertexArrayBindingProtector::BackendVertexArrayBindingProtector() {
MG_External::GLES::glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &m_previousBinding);
}
BackendVertexArrayBindingProtector::~BackendVertexArrayBindingProtector() {
MG_External::GLES::glBindVertexArray(m_previousBinding);
}
} // namespace VertexArrayImpl
namespace TextureImpl {
BackendTextureBindingProtector::BackendTextureBindingProtector(GLenum target) {
m_target = target;
MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, true), &m_previousBinding);
}
BackendTextureBindingProtector::~BackendTextureBindingProtector() {
MG_External::GLES::glBindTexture(m_target, m_previousBinding);
}
void NormalizePixelFormat(GLenum internalFormat, GLenum* outInternalFormat, GLenum* outType,
GLenum* outFormat) {
switch (internalFormat) {
case GL_DEPTH_COMPONENT16:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_SHORT;
if (outFormat) *outFormat = GL_DEPTH_COMPONENT;
break;
case GL_DEPTH_COMPONENT24:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_INT;
if (outFormat) *outFormat = GL_DEPTH_COMPONENT;
break;
case GL_DEPTH_COMPONENT32:
if (outInternalFormat) *outInternalFormat = GL_DEPTH_COMPONENT32F;
if (outType) *outType = GL_FLOAT;
if (outFormat) *outFormat = GL_DEPTH_COMPONENT;
break;
case GL_DEPTH_COMPONENT32F:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_FLOAT;
if (outFormat) *outFormat = GL_DEPTH_COMPONENT;
break;
case GL_DEPTH_COMPONENT:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_INT;
if (outFormat) *outFormat = GL_DEPTH_COMPONENT;
break;
case GL_DEPTH_STENCIL:
if (outInternalFormat) *outInternalFormat = GL_DEPTH32F_STENCIL8;
if (outType) *outType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
if (outFormat) *outFormat = GL_DEPTH_STENCIL;
break;
case GL_RGB10_A2:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_INT_2_10_10_10_REV;
if (outFormat) *outFormat = GL_RGBA;
break;
case GL_RGB5_A1:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_SHORT_5_5_5_1;
if (outFormat) *outFormat = GL_RGBA;
break;
case GL_COMPRESSED_RED_RGTC1:
case GL_COMPRESSED_RG_RGTC2:
break;
case GL_SRGB8:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_BYTE;
if (outFormat) *outFormat = GL_RGB;
break;
case GL_RGBA32F:
case GL_RGB32F:
case GL_RG32F:
case GL_R32F:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_FLOAT;
if (outFormat) switch (internalFormat) {
case GL_RGBA32F:
if (outFormat) *outFormat = GL_RGBA;
break;
case GL_RGB32F:
if (outFormat) *outFormat = GL_RGB;
break;
case GL_RG32F:
if (outFormat) *outFormat = GL_RG;
break;
case GL_R32F:
if (outFormat) *outFormat = GL_RED;
break;
}
break;
case GL_RGB9_E5:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_INT_5_9_9_9_REV;
if (outFormat) *outFormat = GL_RGB;
break;
case GL_R11F_G11F_B10F:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_INT_10F_11F_11F_REV;
if (outFormat) *outFormat = GL_RGB;
break;
case GL_RGBA32UI:
case GL_RGB32UI:
case GL_RG32UI:
case GL_R32UI:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_INT;
if (outFormat) switch (internalFormat) {
case GL_RGBA32UI:
if (outFormat) *outFormat = GL_RGBA;
break;
case GL_RGB32UI:
if (outFormat) *outFormat = GL_RGB;
break;
case GL_RG32UI:
if (outFormat) *outFormat = GL_RG;
break;
case GL_R32UI:
if (outFormat) *outFormat = GL_RED;
break;
}
break;
break;
case GL_RGBA32I:
case GL_RGB32I:
case GL_RG32I:
case GL_R32I:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_INT;
if (outFormat) switch (internalFormat) {
case GL_RGBA32I:
if (outFormat) *outFormat = GL_RGBA;
break;
case GL_RGB32I:
if (outFormat) *outFormat = GL_RGB;
break;
case GL_RG32I:
if (outFormat) *outFormat = GL_RG;
break;
case GL_R32I:
if (outFormat) *outFormat = GL_RED;
break;
}
break;
case GL_RGBA16: {
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_FLOAT;
if (outFormat) *outFormat = GL_RGBA;
break;
}
case GL_RGBA8:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_BYTE;
if (outFormat) *outFormat = GL_RGBA;
break;
case GL_RGBA:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_BYTE;
if (outFormat) *outFormat = GL_RGBA;
break;
case GL_RGBA16F:
case GL_R16F:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_HALF_FLOAT;
if (outFormat) {
if (internalFormat == GL_RGBA16F) {
*outFormat = GL_RGBA;
} else {
*outFormat = GL_RED;
}
}
break;
case GL_R16:
if (outInternalFormat) *outInternalFormat = GL_R16F;
if (outType) *outType = GL_FLOAT;
if (outFormat) *outFormat = GL_RED;
break;
case GL_RGB16:
if (outInternalFormat) *outInternalFormat = GL_RGB16F;
if (outType) *outType = GL_HALF_FLOAT;
if (outFormat) *outFormat = GL_RGB;
break;
case GL_RGB16F:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_HALF_FLOAT;
if (outFormat) *outFormat = GL_RGB;
break;
case GL_RG16:
case GL_RG16F:
if (outInternalFormat) *outInternalFormat = GL_RG16F;
if (outType) *outType = GL_HALF_FLOAT;
if (outFormat) *outFormat = GL_RG;
break;
case GL_R8:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_BYTE;
if (outFormat) *outFormat = GL_RED;
break;
case GL_R8UI:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_BYTE;
if (outFormat) *outFormat = GL_RED_INTEGER;
break;
case GL_RGB8_SNORM:
case GL_RGBA8_SNORM:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_BYTE;
if (outFormat) {
if (internalFormat == GL_RGB8_SNORM) {
*outFormat = GL_RGB;
} else {
*outFormat = GL_RGBA;
}
}
break;
case GL_RGB8:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_BYTE;
if (outFormat) *outFormat = GL_RGB;
break;
case GL_RGBA16_SNORM:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_SHORT;
if (outFormat) *outFormat = GL_RGBA;
break;
default:
if (outInternalFormat) *outInternalFormat = internalFormat;
if (outType) *outType = GL_UNSIGNED_INT;
if (outFormat) *outFormat = GL_RGBA;
break;
}
}
void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat, GLenum* outType,
GLenum* outFormat) {
NormalizePixelFormat(MG_Util::ConvertTextureInternalFormatToGLEnum(internalFormat), outInternalFormat,
outType, outFormat);
}
} // namespace TextureImpl
namespace FramebufferImpl {
BackendFramebufferBindingProtector::BackendFramebufferBindingProtector(GLenum target) {
m_target = target;
MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, false), &m_previousBinding);
}
BackendFramebufferBindingProtector::~BackendFramebufferBindingProtector() {
MG_External::GLES::glBindFramebuffer(m_target, m_previousBinding);
}
} // namespace FramebufferImpl
namespace PrgramImpl {
String ProcessOutColorLocations(const String& glslCode) {
const static std::regex pattern(R"(\n(out highp vec4 outColor)(\d+);)");
const String replacement = "\nlayout(location=$2) $1$2;";
return std::regex_replace(glslCode, pattern, replacement);
}
String ForceSupporterOutput(const String& glslCode) {
Bool hasPrecisionFloat =
glslCode.find("precision ") != String::npos && glslCode.find("float;") != String::npos;
Bool hasPrecisionInt = glslCode.find("precision ") != String::npos && glslCode.find("int;") != String::npos;
String result = glslCode;
String precisionFloat;
String precisionInt;
if (hasPrecisionFloat && hasPrecisionInt) {
std::istringstream iss(result);
std::vector<String> lines;
String line;
while (std::getline(iss, line)) {
Bool isPrecisionLine = (line.find("precision ") != String::npos) &&
(line.find("float;") != String::npos || line.find("int;") != String::npos);
if (!isPrecisionLine) {
lines.push_back(line);
}
}
result.clear();
for (SizeT i = 0; i < lines.size(); ++i) {
if (i != 0) result += '\n';
result += lines[i];
}
precisionFloat = "precision highp float;\n";
precisionInt = "precision highp int;\n";
} else {
precisionFloat = hasPrecisionFloat ? "" : "precision highp float;\n";
precisionInt = hasPrecisionInt ? "" : "precision highp int;\n";
}
SizeT lastExtensionPos = result.rfind("#extension");
SizeT insertionPos = 0;
if (lastExtensionPos != String::npos) {
SizeT nextNewline = result.find('\n', lastExtensionPos);
if (nextNewline != String::npos) {
insertionPos = nextNewline + 1;
} else {
insertionPos = result.length();
}
} else {
SizeT firstNewline = result.find('\n');
if (firstNewline != String::npos) {
insertionPos = firstNewline + 1;
} else {
result = precisionFloat + precisionInt + result;
return result;
}
}
result.insert(insertionPos, precisionFloat + precisionInt);
return result;
}
String removeLayoutBinding(const String& glslCode) {
static std::regex bindingRegex(R"(layout\s*\(\s*binding\s*=\s*\d+\s*\)\s*)");
String result = std::regex_replace(glslCode, bindingRegex, "");
static std::regex bindingRegex2(R"(layout\s*\(\s*binding\s*=\s*\d+\s*,)");
result = std::regex_replace(result, bindingRegex2, "layout(");
return result;
}
} // namespace PrgramImpl
namespace Utils {
void CheckGLESError() {
while (GLenum err = MG_External::GLES::glGetError() != GL_NO_ERROR) {
MGLOG_E("-> GLES Error: %s", MG_Util::ConvertGLEnumToString(err).c_str());
}
}
GLenum GetBindingQuery(GLenum target, bool isTexture) {
switch (target) {
case GL_TEXTURE_BUFFER:
return isTexture ? GL_TEXTURE_BINDING_BUFFER : GL_TEXTURE_BUFFER_BINDING;
case GL_ARRAY_BUFFER:
return GL_ARRAY_BUFFER_BINDING;
case GL_ATOMIC_COUNTER_BUFFER:
return GL_ATOMIC_COUNTER_BUFFER_BINDING;
case GL_COPY_READ_BUFFER:
return GL_COPY_READ_BUFFER_BINDING;
case GL_COPY_WRITE_BUFFER:
return GL_COPY_WRITE_BUFFER_BINDING;
case GL_DISPATCH_INDIRECT_BUFFER:
return GL_DISPATCH_INDIRECT_BUFFER_BINDING;
case GL_DRAW_INDIRECT_BUFFER:
return GL_DRAW_INDIRECT_BUFFER_BINDING;
case GL_ELEMENT_ARRAY_BUFFER:
return GL_ELEMENT_ARRAY_BUFFER_BINDING;
case GL_PIXEL_PACK_BUFFER:
return GL_PIXEL_PACK_BUFFER_BINDING;
case GL_PIXEL_UNPACK_BUFFER:
return GL_PIXEL_UNPACK_BUFFER_BINDING;
case GL_QUERY_BUFFER:
return GL_QUERY_BUFFER_BINDING;
case GL_SHADER_STORAGE_BUFFER:
return GL_SHADER_STORAGE_BUFFER_BINDING;
case GL_TRANSFORM_FEEDBACK_BUFFER:
return GL_TRANSFORM_FEEDBACK_BUFFER_BINDING;
case GL_UNIFORM_BUFFER:
return GL_UNIFORM_BUFFER_BINDING;
case GL_FRAMEBUFFER:
return GL_FRAMEBUFFER_BINDING;
case GL_DRAW_FRAMEBUFFER:
return GL_DRAW_FRAMEBUFFER_BINDING;
case GL_READ_FRAMEBUFFER:
return GL_READ_FRAMEBUFFER_BINDING;
case GL_RENDERBUFFER:
return GL_RENDERBUFFER_BINDING;
case GL_VERTEX_ARRAY:
return GL_VERTEX_ARRAY_BINDING;
case GL_VERTEX_ARRAY_BINDING:
return GL_VERTEX_ARRAY_BINDING;
case GL_PROGRAM_PIPELINE:
return GL_PROGRAM_PIPELINE_BINDING;
case GL_PROGRAM:
return GL_CURRENT_PROGRAM;
case GL_SAMPLER:
return GL_SAMPLER_BINDING;
case GL_TEXTURE:
return GL_TEXTURE_BINDING_2D;
case GL_TEXTURE_1D:
return GL_TEXTURE_BINDING_1D;
case GL_TEXTURE_1D_ARRAY:
return GL_TEXTURE_BINDING_1D_ARRAY;
case GL_TEXTURE_2D:
return GL_TEXTURE_BINDING_2D;
case GL_TEXTURE_2D_ARRAY:
return GL_TEXTURE_BINDING_2D_ARRAY;
case GL_TEXTURE_2D_MULTISAMPLE:
return GL_TEXTURE_BINDING_2D_MULTISAMPLE;
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
return GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY;
case GL_TEXTURE_3D:
return GL_TEXTURE_BINDING_3D;
case GL_TEXTURE_CUBE_MAP:
return GL_TEXTURE_BINDING_CUBE_MAP;
case GL_TEXTURE_CUBE_MAP_ARRAY:
return GL_TEXTURE_BINDING_CUBE_MAP_ARRAY;
case GL_TEXTURE_RECTANGLE:
return GL_TEXTURE_BINDING_RECTANGLE;
case GL_TRANSFORM_FEEDBACK:
return GL_TRANSFORM_FEEDBACK_BINDING;
case GL_SAMPLES_PASSED:
return GL_SAMPLES_PASSED;
case GL_PRIMITIVES_GENERATED:
return GL_PRIMITIVES_GENERATED;
case GL_DEBUG_OUTPUT:
return GL_DEBUG_OUTPUT;
case GL_DEBUG_OUTPUT_SYNCHRONOUS:
return GL_DEBUG_OUTPUT_SYNCHRONOUS;
default:
return 0;
}
}
} // namespace Utils
} // namespace MobileGL::MG_Backend::DirectGLES
+73
View File
@@ -0,0 +1,73 @@
#pragma once
#include <Includes.h>
#include <MG_State/GLState/Core.h>
namespace MobileGL::MG_Backend::DirectGLES {
namespace BufferImpl {
class BackendBufferBindingProtector {
public:
BackendBufferBindingProtector(GLenum target);
~BackendBufferBindingProtector();
private:
GLenum m_target;
GLint m_previousBinding = 0;
};
} // namespace BufferImpl
namespace VertexArrayImpl {
GLenum GetBindingQuery(GLenum target, bool isTexture);
class BackendVertexArrayBindingProtector {
public:
BackendVertexArrayBindingProtector();
~BackendVertexArrayBindingProtector();
private:
GLint m_previousBinding = 0;
};
} // namespace VertexArrayImpl
namespace TextureImpl {
class BackendTextureBindingProtector {
public:
BackendTextureBindingProtector(GLenum target);
~BackendTextureBindingProtector();
private:
GLenum m_target;
GLint m_previousBinding = 0;
};
void NormalizePixelFormat(GLenum internalFormat, GLenum* outInternalFormat, GLenum* outType, GLenum* outFormat);
void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat, GLenum* outType,
GLenum* outFormat);
} // namespace TextureImpl
namespace FramebufferImpl {
class BackendFramebufferBindingProtector {
public:
BackendFramebufferBindingProtector(GLenum target);
~BackendFramebufferBindingProtector();
private:
GLenum m_target;
GLint m_previousBinding = 0;
};
} // namespace FramebufferImpl
namespace PrgramImpl {
String ProcessOutColorLocations(const String& glslCode);
String ForceSupporterOutput(const String& glslCode);
String removeLayoutBinding(const String& glslCode);
} // namespace PrgramImpl
namespace Utils {
void CheckGLESError();
GLenum GetBindingQuery(GLenum target, bool isTexture);
} // namespace Utils
} // namespace MobileGL::MG_Backend::DirectGLES
+30 -7
View File
@@ -2,25 +2,48 @@
#include <Config.h>
#include <MG_State/GLState/Core.h>
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
#include <MG_Backend/DirectGLES/DirectGLES.h>
namespace MobileGL {
namespace MG_Impl::GLImpl {
void Clear_Backend(GLbitfield mask) {
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
auto clearColor = MG_State::pGLContext->GetClearColor();
MG_External::GLES::glClearColor(clearColor.r(), clearColor.g(), clearColor.b(), clearColor.a());
auto clearDepth = MG_State::pGLContext->GetClearDepth();
MG_External::GLES::glClearDepthf(clearDepth);
MG_External::GLES::glClear(mask);
MG_Backend::DirectGLES::Clear(mask);
#endif
}
void DrawElements_Backend(GLenum mode, GLsizei count, GLenum type, const void* indices) {
// TODO
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
MG_Backend::DirectGLES::DrawElements(mode, count, type, indices);
#endif
}
void MultiDrawElements_Backend(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
GLsizei drawcount) {
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
MG_Backend::DirectGLES::MultiDrawElements(mode, count, type, indices, drawcount);
#endif
}
void MultiDrawElementsBaseVertex_Backend(GLenum mode, const GLsizei* count, GLenum type,
const void* const* indices, GLsizei drawcount,
const GLint* basevertex) {
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
MG_Backend::DirectGLES::MultiDrawElementsBaseVertex(mode, count, type, indices, drawcount, basevertex);
#endif
}
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
GLsizei drawcount) {
MultiDrawElements_Backend(mode, count, type, indices, drawcount);
}
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
GLsizei drawcount, const GLint* basevertex) {
MultiDrawElementsBaseVertex_Backend(mode, count, type, indices, drawcount, basevertex);
}
void Clear(GLbitfield mask) {
Clear_Backend(mask);
}
@@ -4,6 +4,8 @@
namespace MobileGL {
namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount);
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount, const GLint* basevertex);
void Clear(GLbitfield mask);
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
} // namespace MG_Impl::GLImpl
@@ -743,7 +743,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, LoadTransposeMatrixd, const GLdouble* m) DEC
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultTransposeMatrixf, const GLfloat* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultTransposeMatrixf, m)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultTransposeMatrixd, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultTransposeMatrixd, m)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawArrays, GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawArrays, mode, first, count, drawcount)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElements, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElements, mode, count, type, indices, drawcount)
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElements, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElements, mode, count, type, indices, drawcount)
DECLARE_GL_FUNCTION_HEAD(void, PointParameterf, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, PointParameterf, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfv, GLenum pname, const GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfv, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, PointParameteri, GLenum pname, GLint param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, PointParameteri, pname, param)
@@ -819,7 +819,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4uiv, GLuint index, const GLuint
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4usv, GLuint index, const GLushort* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4usv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveRestartIndex, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PrimitiveRestartIndex, index)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetActiveUniformName, GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetActiveUniformName, program, uniformIndex, bufSize, length, uniformName)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElementsBaseVertex, mode, count, type, indices, drawcount, basevertex)
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsBaseVertex, mode, count, type, indices, drawcount, basevertex)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProvokingVertex, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProvokingVertex, mode)
DECLARE_GL_FUNCTION_HEAD(void, TexImage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations)
DECLARE_GL_FUNCTION_HEAD(void, TexImage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage3DMultisample, target, samples, internalformat, width, height, depth, fixedsamplelocations)
@@ -9,15 +9,15 @@ namespace MobileGL {
void BufferObject::Resize(SizeT size) {
m_size = size;
m_data.reserve(std::bit_ceil(size)); // power-of-2 reserve
m_data.resize(size);
m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve
m_dataPtr->resize(size);
m_dirtyRange = {0, 0};
}
void BufferObject::UploadData(DataPtr data, SizeT atOffset) {
assert(atOffset + data.size <= m_size);
assert(!m_isMapped);
memcpy(m_data.data() + atOffset, data.data, data.size);
memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
m_dirtyRange.UnionUpdate(atOffset, atOffset + data.size);
}
@@ -30,7 +30,7 @@ namespace MobileGL {
if (m_mappingAccess & BufferMappingAccessBit::Write) { // if we wrote to the buffer
if (!(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly
memcpy(m_data.data() + m_mappedRange.start, m_stagingData.data(),
memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(),
m_mappedRange.end - m_mappedRange.start);
m_dirtyRange.UnionUpdate(m_mappedRange.start, m_mappedRange.end);
}
@@ -53,7 +53,7 @@ namespace MobileGL {
SizeT end = start + length;
assert(end <= m_mappedRange.end);
memcpy(m_data.data() + start, m_stagingData.data() + offset, length);
memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length);
m_dirtyRange.UnionUpdate(start, end);
}
@@ -61,7 +61,7 @@ namespace MobileGL {
assert(!m_isMapped);
assert(atOffset + data.size <= m_size);
memcpy(m_data.data() + atOffset, data.data, data.size);
memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
m_dirtyRange.UnionUpdate(atOffset, atOffset + data.size);
}
@@ -72,8 +72,8 @@ namespace MobileGL {
assert(srcOffset + size <= src->GetSize());
assert(dstOffset + size <= m_size);
const Uint8* srcData = src->m_data.data() + srcOffset;
memcpy(m_data.data() + dstOffset, srcData, size);
const Uint8* srcData = src->m_dataPtr->data() + srcOffset;
memcpy(m_dataPtr->data() + dstOffset, srcData, size);
m_dirtyRange.UnionUpdate(dstOffset, dstOffset + size);
}
@@ -91,14 +91,14 @@ namespace MobileGL {
if (!(m_mappingAccess &
(BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) {
memcpy(m_stagingData.data(), m_data.data(), m_size);
memcpy(m_stagingData.data(), m_dataPtr->data(), m_size);
}
return m_stagingData.data();
}
}
return m_data.data();
return m_dataPtr->data();
}
void* BufferObject::AcquireMemoryRange(Range1D range, Flags<BufferMappingAccessBit> access) {
@@ -113,16 +113,20 @@ namespace MobileGL {
if (!(access &
(BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) {
memcpy(m_stagingData.data(), m_data.data() + range.start, m_stagingData.size());
memcpy(m_stagingData.data(), m_dataPtr->data() + range.start, m_stagingData.size());
}
return m_stagingData.data();
} else {
m_ownsStagingData = false;
return m_data.data() + range.start;
return m_dataPtr->data() + range.start;
}
}
SharedPtr<Data> BufferObject::GetDataReadOnly() const {
return m_dataPtr;
}
void BufferObject::ClearDirty() {
m_dirtyRange = {0, 0};
}
@@ -1,4 +1,5 @@
#pragma once
#include "MG_Util/Types.h"
#include <Includes.h>
namespace MobileGL {
@@ -70,18 +71,19 @@ namespace MobileGL {
BufferUsage GetUsage() const;
Range1D GetDirtyRange() const;
Range1D GetMappedRange() const;
SharedPtr<Data> GetDataReadOnly() const;
Flags<BufferMappingAccessBit> GetMappingAccess() const;
private:
Int m_id = 0;
SizeT m_size = 0;
BufferUsage m_usage = BufferUsage::StaticDraw;
Data m_data;
SharedPtr<Data> m_dataPtr;
Bool m_isMapped;
Flags<BufferMappingAccessBit> m_mappingAccess;
Range1D m_dirtyRange;
Range1D m_mappedRange;
std::vector<Uint8> m_stagingData;
Vector<Uint8> m_stagingData;
Bool m_ownsStagingData;
};
} // namespace GLState
@@ -88,6 +88,12 @@ namespace MobileGL {
return m_attachments[static_cast<SizeT>(type)];
}
const Array<FramebufferAttachment,
static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>&
FramebufferObject::GetAllAttachments() const {
return m_attachments;
}
Bool FramebufferObject::CheckCompleteness() const {
if (m_attachments.empty()) {
return false;
@@ -89,6 +89,9 @@ namespace MobileGL {
std::shared_ptr<RenderbufferObjectStub> renderbuffer);
void Detach(FramebufferAttachmentType type);
const FramebufferAttachment& GetAttachment(FramebufferAttachmentType type) const;
const Array<FramebufferAttachment,
static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>&
GetAllAttachments() const;
Bool CheckCompleteness() const;
void SetDrawBuffers(const std::vector<FramebufferAttachmentType>& buffers);
const Vector<FramebufferAttachmentType>& GetDrawBuffers() const;
@@ -68,6 +68,12 @@ namespace MobileGL {
m_internalFormat = format;
}
void TextureObjectBase::UnmarkMipmapDirty(Int index) {
if (index >= 0 && index < static_cast<Int>(m_mipmaps.size())) {
m_mipmaps[index].dirty = false;
}
}
// TextureObject1D
TextureObject1D::TextureObject1D() : TextureObjectBase(TextureTarget::Texture1D) {}
@@ -211,6 +211,7 @@ namespace MobileGL {
virtual MipmapLevelInternal& GetMipmap(Int index) = 0;
virtual void SetInternalFormat(TextureInternalFormat format) = 0;
virtual Bool IsComplete() const = 0;
virtual void UnmarkMipmapDirty(Int index) = 0;
};
class TextureObjectBase : public ITextureObject {
@@ -227,6 +228,7 @@ namespace MobileGL {
MipmapLevelInternal& GetMipmap(Int index) override;
void SetInternalFormat(TextureInternalFormat format) override;
Bool IsComplete() const override;
void UnmarkMipmapDirty(Int index) override;
protected:
virtual void SetMipmapImpl(const MipmapLevelInput& level) = 0;
@@ -4,7 +4,8 @@ namespace MobileGL {
namespace MG_State {
namespace GLState {
VertexArrayObject::VertexArrayObject() {
for (auto& attr : m_attributes) {
for (int index = 0; index < MAX_VERTEX_ATTRIBS; ++index) {
auto& attr = m_attributes[index];
attr.Enabled = false;
attr.Size = 4;
attr.Type = DataType::Float32;
@@ -12,17 +13,21 @@ namespace MobileGL {
attr.Stride = 0;
attr.Offset = 0;
attr.Buffer = nullptr;
MarkAttributeDirty(index);
}
}
void VertexArrayObject::EnableAttribute(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return;
m_attributes[index].Enabled = true;
MarkAttributeDirty(index);
}
void VertexArrayObject::DisableAttribute(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return;
m_attributes[index].Enabled = false;
MarkAttributeDirty(index);
}
Bool VertexArrayObject::IsAttributeEnabled(Uint index) const {
@@ -45,11 +50,14 @@ namespace MobileGL {
attr.Stride = stride;
attr.Offset = offset;
attr.IsInteger = isInteger;
MarkAttributeDirty(index);
}
void VertexArrayObject::BindAttributeBuffer(Uint index, const SharedPtr<BufferObject>& buffer) {
if (index >= MAX_VERTEX_ATTRIBS) return;
m_attributes[index].Buffer = buffer;
MarkAttributeDirty(index);
}
BindingSlot<BufferObject>& VertexArrayObject::GetIndexBufferBindingSlot() {
@@ -61,6 +69,27 @@ namespace MobileGL {
if (index >= MAX_VERTEX_ATTRIBS) return emptyAttr;
return m_attributes[index];
}
const Array<VertexAttribute, VertexArrayObject::MAX_VERTEX_ATTRIBS>& VertexArrayObject::GetAllAttributes()
const {
return m_attributes;
}
void VertexArrayObject::MarkAttributeDirty(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return;
if (std::find(m_dirtyAttributes.begin(), m_dirtyAttributes.end(), index) != m_dirtyAttributes.end()) {
return;
}
m_dirtyAttributes.push_back(index);
}
const Vector<Uint>& VertexArrayObject::GetDirtyAttributeIndices() const {
return m_dirtyAttributes;
}
void VertexArrayObject::ClearDirtyAttributes() {
m_dirtyAttributes.clear();
}
} // namespace GLState
} // namespace MG_State
} // namespace MobileGL
@@ -34,9 +34,16 @@ namespace MobileGL {
BindingSlot<BufferObject>& GetIndexBufferBindingSlot();
const VertexAttribute& GetAttribute(Uint index) const;
const Array<VertexAttribute, MAX_VERTEX_ATTRIBS>& GetAllAttributes() const;
const Vector<Uint>& GetDirtyAttributeIndices() const;
void ClearDirtyAttributes();
private:
void MarkAttributeDirty(Uint index);
Array<VertexAttribute, MAX_VERTEX_ATTRIBS> m_attributes;
Vector<Uint> m_dirtyAttributes;
BindingSlot<BufferObject> m_indexBufferBindingSlot;
};
} // namespace GLState
+3
View File
@@ -56,6 +56,9 @@ namespace MobileGL {
inline constexpr void Copy(const T* src, T* dest, SizeT count) {
std::copy(src, src + count, dest);
}
inline constexpr void Memcpy(const void* src, void* dest, SizeT size) {
std::memcpy(dest, src, size);
}
template <typename... Ts>
constexpr auto ToArray(Ts&&... elems) {
using E = std::common_type_t<Ts...>;