Merge branch 'dev' into Feat/Backend-Direct-Vulkan

This commit is contained in:
BZLZHH
2026-02-07 11:41:11 +08:00
50 changed files with 2525 additions and 1136 deletions
+27 -6
View File
@@ -13,11 +13,33 @@ if (ANDROID)
endif() endif()
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug" OR MOBILEGL_FORCE_RELEASE_OPT) if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug" OR MOBILEGL_FORCE_RELEASE_OPT)
# Check if ThinLTO or LTO is suppported
include(CheckIPOSupported) include(CheckIPOSupported)
include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
check_ipo_supported(RESULT LTOSupported OUTPUT LTOError) check_ipo_supported(RESULT LTOSupported OUTPUT LTOError)
if (LTOSupported)
check_c_compiler_flag("-flto" HAS_LTO_C)
check_cxx_compiler_flag("-flto" HAS_LTO_CXX)
if (LTOSupported OR (HAS_LTO_C AND HAS_LTO_CXX))
# Check ThinLTO
check_c_compiler_flag("-flto=thin" HAS_THINLTO_C)
check_cxx_compiler_flag("-flto=thin" HAS_THINLTO_CXX)
if (HAS_THINLTO_C AND HAS_THINLTO_CXX)
message(STATUS "ThinLTO supported, using -flto=thin")
add_compile_options(-flto=thin)
add_link_options(-flto=thin)
else()
# ThinLTO is not supported
message(STATUS "ThinLTO not available, fallback to CMAKE IPO")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif() endif()
else()
message(STATUS "IPO not supported: ${LTOError}")
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND NOT MATCHES "AppleClang") if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND NOT MATCHES "AppleClang")
add_compile_options(-O3 -ffunction-sections -fdata-sections) add_compile_options(-O3 -ffunction-sections -fdata-sections)
@@ -103,7 +125,9 @@ set(SOURCE_FILES
MobileGL/MG_Util/Debug/Log.cpp MobileGL/MG_Util/Debug/Log.cpp
MobileGL/MG_Util/Math/VectorTypes.cpp
MobileGL/MG_Util/Metrics/TextureMetrics.cpp MobileGL/MG_Util/Metrics/TextureMetrics.cpp
MobileGL/MG_Util/Metrics/BufferMetrics.cpp MobileGL/MG_Util/Metrics/BufferMetrics.cpp
MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp
@@ -256,6 +280,7 @@ target_link_libraries(${CMAKE_PROJECT_NAME}
${MOBILEGL_LINK_LIBRARIES} ${MOBILEGL_LINK_LIBRARIES}
) )
if(NOT ANDROID)
add_library(${CMAKE_PROJECT_NAME}_s STATIC add_library(${CMAKE_PROJECT_NAME}_s STATIC
${SOURCE_FILES} ${SOURCE_FILES}
) )
@@ -282,6 +307,7 @@ target_link_libraries(${CMAKE_PROJECT_NAME}_s
PRIVATE PRIVATE
${MOBILEGL_LINK_LIBRARIES} ${MOBILEGL_LINK_LIBRARIES}
) )
endif()
if (TRACY_ENABLE) if (TRACY_ENABLE)
target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC Tracy::TracyClient) target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC Tracy::TracyClient)
@@ -296,11 +322,6 @@ if (ANDROID)
log log
vulkan vulkan
) )
target_link_libraries(${CMAKE_PROJECT_NAME}_s PUBLIC
android
log
vulkan
)
endif() endif()
if (NOT ANDROID) if (NOT ANDROID)
+1 -1
View File
@@ -15,7 +15,7 @@ namespace MobileGL {
inline const String ProjectName = "MobileGL"; inline const String ProjectName = "MobileGL";
inline const String CoreName = "MobileGL Core"; inline const String CoreName = "MobileGL Core";
inline const String CoreVendor = "MobileGL-Dev (BZLZHH, Swung0x48, Tungsten)"; inline const String CoreVendor = "MobileGL-Dev (BZLZHH, Swung0x48, Tungsten)";
inline const Version CoreVersion = {26, 1, 0, "-dev", VersionType::Development}; inline const Version CoreVersion = {26, 2, 0, "-dev", VersionType::Development};
inline const VersionStringFormatAttrib DefaultVersionStringFormatAttrib = {2, 2, 0, true, true}; inline const VersionStringFormatAttrib DefaultVersionStringFormatAttrib = {2, 2, 0, true, true};
extern UniquePtr<RendererInfo> RendererInfoPtr; extern UniquePtr<RendererInfo> RendererInfoPtr;
File diff suppressed because it is too large Load Diff
@@ -8,6 +8,8 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/TextureState/TextureState.h>
#include <MG_State/GLState/SamplerState/SamplerObject.h>
#define CallAndCheck(operation) \ #define CallAndCheck(operation) \
MGLOG_D("Call GLES func: %s", #operation); \ MGLOG_D("Call GLES func: %s", #operation); \
@@ -51,4 +53,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
GLsizei height); GLsizei height);
void GenerateMipmap(GLenum target); void GenerateMipmap(GLenum target);
const GLubyte* GetString(GLenum name); const GLubyte* GetString(GLenum name);
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
} // namespace MobileGL::MG_Backend::DirectGLES } // namespace MobileGL::MG_Backend::DirectGLES
+410 -220
View File
@@ -7,24 +7,29 @@
// End of Source File Header // End of Source File Header
#include "Managers.h" #include "Managers.h"
#include "MG_Backend/Backends.h" #include "MG_State/GLState/TextureState/TextureEnum.h"
#include "MG_Util/Debug/Log.h" #include "MG_State/GLState/TextureState/TextureObject.h"
#include "MG_State/GLState/TextureState/TextureState.h"
#include "MG_Util/Converters/GLToMG/TextureEnumConverter.h"
#include "Utils.h" #include "Utils.h"
#include "DirectGLES.h" #include "DirectGLES.h"
#include "MG_State/GLState/TextureState/TextureObjectBuffer.h"
#include <MG_Util/BackendLoaders/OpenGL/Loader.h> #include <MG_Util/BackendLoaders/OpenGL/Loader.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h> #include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/DataTypeConverter.h> #include <MG_Util/Converters/MGToGL/DataTypeConverter.h>
#include <MG_Util/Converters/MGToGL/BufferEnumConverter.h> #include <MG_Util/Converters/MGToGL/BufferEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h> #include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToStr/FramebufferEnumConverter.h>
#include <MG_State/GLState/TextureState/TextureObjectBuffer.h>
#include <MG_Util/Converters/GLToMG/FramebufferEnumConverter.h> #include <MG_Util/Converters/GLToMG/FramebufferEnumConverter.h>
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h> #include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
#include <MG_State/GLState/FramebufferState/FramebufferObject.h> #include <MG_State/GLState/FramebufferState/FramebufferObject.h>
namespace MobileGL::MG_Backend::DirectGLES { namespace MobileGL::MG_Backend::DirectGLES {
constexpr Bool PREFER_MAP_BUFFER_RANGE_FOR_BUFFER_SYNC = true;
namespace BufferImpl { namespace BufferImpl {
BackendBufferObject::BackendBufferObject() { BackendBufferObject::BackendBufferObject() {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
@@ -39,7 +44,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
void BackendBufferObject::SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) { void BackendBufferObject::SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
@@ -58,8 +62,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("Syncing buffer object with backend ID %u to backend for state ID %u", m_backendBufferId, MGLOG_D("Syncing buffer object with backend ID %u to backend for state ID %u", m_backendBufferId,
stateBufferObject->GetExternalIndex()); stateBufferObject->GetExternalIndex());
// Decide sync method
// glBufferData
Bool needsRegeneration = Bool needsRegeneration =
!m_isInitialized || bufferSize > m_prevBufferSize || bufferSize < m_prevBufferSize / 2; !m_isInitialized || (stateBufferObject->GetChangeBits() & BufferChangeBits::PreferReallocationBit);
if (needsRegeneration) { if (needsRegeneration) {
MGLOG_D("Buffer size changed significantly or not initialized, regenerating buffer with ID: %u", MGLOG_D("Buffer size changed significantly or not initialized, regenerating buffer with ID: %u",
@@ -67,22 +73,33 @@ namespace MobileGL::MG_Backend::DirectGLES {
SyncToBackend_glBufferData(stateBufferObject); SyncToBackend_glBufferData(stateBufferObject);
m_isInitialized = true; m_isInitialized = true;
m_prevBufferSize = bufferSize; m_prevBufferSize = bufferSize;
stateBufferObject->ClearDirty();
return; return;
} }
switch (stateBufferObject->GetUsage()) { // glMapBufferRange or glBufferSubData
case BufferUsage::StaticDraw: Bool useInvalidationMap = !(stateBufferObject->GetChangeBits() & BufferChangeBits::ForbidInvalidationBit);
SyncToBackend_glBufferSubData(stateBufferObject); Bool useUnsynchronizedMap =
break; !(stateBufferObject->GetChangeBits() & BufferChangeBits::ForbidUnsynchronizationBit);
case BufferUsage::DynamicDraw: Bool useMapBufferRange = useInvalidationMap || useUnsynchronizedMap;
case BufferUsage::StreamDraw:
SyncToBackend_glMapBufferRange(stateBufferObject); if (!useMapBufferRange && PREFER_MAP_BUFFER_RANGE_FOR_BUFFER_SYNC) {
break; auto usage = stateBufferObject->GetUsage();
default: if (usage == BufferUsage::DynamicDraw || usage == BufferUsage::StreamDraw ||
SyncToBackend_glBufferSubData(stateBufferObject); usage == BufferUsage::StreamCopy || usage == BufferUsage::DynamicCopy) {
break; useMapBufferRange = true;
}
} }
if (useMapBufferRange) {
MGLOG_D("Using glMapBufferRange to sync buffer with ID: %u", m_backendBufferId);
SyncToBackend_glMapBufferRange(stateBufferObject, useInvalidationMap, useUnsynchronizedMap);
} else {
MGLOG_D("Using glBufferSubData to sync buffer with ID: %u", m_backendBufferId);
SyncToBackend_glBufferSubData(stateBufferObject);
}
// Clear dirty state
stateBufferObject->ClearDirty(); stateBufferObject->ClearDirty();
m_prevBufferSize = bufferSize; m_prevBufferSize = bufferSize;
} }
@@ -92,7 +109,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
BackendBufferBindingProtector backendBufferBindingProtector(TempBufferTarget);
MGLOG_D("Syncing buffer data (glBufferData) for object with ID : %u", m_backendBufferId); MGLOG_D("Syncing buffer data (glBufferData) for object with ID : %u", m_backendBufferId);
@@ -100,10 +116,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
SizeT size = stateBufferObject->GetSize(); SizeT size = stateBufferObject->GetSize();
GLenum usage = MG_Util::ConvertBufferUsageToGLEnum(stateBufferObject->GetUsage()); GLenum usage = MG_Util::ConvertBufferUsageToGLEnum(stateBufferObject->GetUsage());
MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId); Bind();
MG_External::GLES::glBufferData(TempBufferTarget, size, data, usage); MG_External::GLES::glBufferData(TempBufferTarget, size, data, usage);
stateBufferObject->ClearDirty();
} }
void BackendBufferObject::SyncToBackend_glBufferSubData( void BackendBufferObject::SyncToBackend_glBufferSubData(
@@ -111,66 +125,74 @@ namespace MobileGL::MG_Backend::DirectGLES {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
BackendBufferBindingProtector backendBufferBindingProtector(TempBufferTarget);
MGLOG_D("Syncing buffer sub-data (glBufferSubData) for object with ID : %u", m_backendBufferId); MGLOG_D("Syncing buffer sub-data (glBufferSubData) for object with ID : %u", m_backendBufferId);
const void* data = stateBufferObject->GetDataReadOnly()->data(); const void* data = stateBufferObject->GetDataReadOnly()->data();
// dirty range: [range.start, range.end) // dirty range: [range.start, range.end)
const auto& range = stateBufferObject->GetDirtyRange(); auto ranges = stateBufferObject->GetDirtyRanges();
if (range.end == 0) { if (ranges.empty()) {
MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId); MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId);
return; return;
} }
MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId); for (const auto& range : ranges) {
Bind();
MG_External::GLES::glBufferSubData(TempBufferTarget, range.start, range.end - range.start, MG_External::GLES::glBufferSubData(TempBufferTarget, range.start, range.end - range.start,
reinterpret_cast<const char*>(data) + range.start); reinterpret_cast<const char*>(data) + range.start);
} }
}
void BackendBufferObject::SyncToBackend_glMapBufferRange( void BackendBufferObject::SyncToBackend_glMapBufferRange(
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, Bool invalidate) { SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, Bool invalidate, Bool unsynchronized) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
BackendBufferBindingProtector backendBufferBindingProtector(TempBufferTarget);
MGLOG_D("Syncing buffer map (glMapBuffer) for object with ID : %u", m_backendBufferId); MGLOG_D("Syncing buffer map (glMapBuffer) for object with ID : %u", m_backendBufferId);
MGLOG_D("Mapping buffer with ID: %u", m_backendBufferId); MGLOG_D("Mapping buffer with ID: %u", m_backendBufferId);
const auto& range = stateBufferObject->GetDirtyRange(); auto ranges = stateBufferObject->GetDirtyRanges();
if (range.end == 0) { if (ranges.empty()) {
MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId); MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId);
return; return;
} }
MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId); SizeT minStart = ranges.GetOverallMinStart();
void* mappedData = SizeT maxEnd = ranges.GetOverallMaxEnd();
MG_External::GLES::glMapBufferRange(TempBufferTarget, range.start, range.end - range.start, Bind();
(invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : 0) | GL_MAP_WRITE_BIT); void* mappedData = MG_External::GLES::glMapBufferRange(
TempBufferTarget, minStart, maxEnd - minStart,
(invalidate ? GL_MAP_INVALIDATE_RANGE_BIT : 0) | (unsynchronized ? GL_MAP_UNSYNCHRONIZED_BIT : 0) |
GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
const void* data = stateBufferObject->GetDataReadOnly()->data(); const void* data = stateBufferObject->GetDataReadOnly()->data();
if (mappedData) { if (mappedData) {
Memcpy(mappedData, ((const char*)(data) + range.start), range.end - range.start);
MGLOG_D("Mapped buffer data successfully for object with ID: %u", m_backendBufferId); MGLOG_D("Mapped buffer data successfully for object with ID: %u", m_backendBufferId);
Memcpy(mappedData, reinterpret_cast<const char*>(data) + minStart, maxEnd - minStart);
// Explicitly flush the dirty ranges
for (const auto& range : ranges) {
MG_External::GLES::glFlushMappedBufferRange(TempBufferTarget, range.start - minStart,
range.end - range.start);
}
MG_External::GLES::glUnmapBuffer(TempBufferTarget); MG_External::GLES::glUnmapBuffer(TempBufferTarget);
} else { } else {
MGLOG_E("Failed to map buffer with ID: %u", m_backendBufferId); MGLOG_E("Failed to map buffer with ID: %u", m_backendBufferId);
} }
} }
void BackendBufferObject::Bind() {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_External::GLES::glBindBuffer(TempBufferTarget, m_backendBufferId);
}
void BackendBufferObject::Bind(GLenum target) { void BackendBufferObject::Bind(GLenum target) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
if (target == GL_ARRAY_BUFFER) {
if (g_boundVertexBufferObject == this) {
return;
}
g_boundVertexBufferObject = this;
}
MG_External::GLES::glBindBuffer(target, m_backendBufferId); MG_External::GLES::glBindBuffer(target, m_backendBufferId);
} }
UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>> g_backendBufferObjects; UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>> g_backendBufferObjects;
BackendBufferObject* g_boundVertexBufferObject = nullptr;
} // namespace BufferImpl } // namespace BufferImpl
namespace VertexArrayImpl { namespace VertexArrayImpl {
@@ -194,8 +216,25 @@ namespace MobileGL::MG_Backend::DirectGLES {
MG_External::GLES::glBindVertexArray(m_backendVAOId); MG_External::GLES::glBindVertexArray(m_backendVAOId);
} }
void BackendVertexArrayObject::SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject, void BackendVertexArrayObject::BindAttributeBuffer(Uint index,
Bool needDivisor) { const MG_State::GLState::VertexAttribute& attrib) {
const auto& bufferObject = attrib.Buffer;
if (!bufferObject) {
MGLOG_W("Attribute has no bound buffer, skipping.");
return;
}
const 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.");
return;
}
const auto& backendBufferObject = backendBufferIt->second;
backendBufferObject->Bind(GL_ARRAY_BUFFER);
}
void BackendVertexArrayObject::SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
@@ -207,36 +246,30 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("Syncing VAO with backend ID %u to backend for state ID %u", m_backendVAOId, MGLOG_D("Syncing VAO with backend ID %u to backend for state ID %u", m_backendVAOId,
stateVAOObject->GetExternalIndex()); stateVAOObject->GetExternalIndex());
BufferImpl::BackendBufferBindingProtector backendBufferBindingProtector(BufferImpl::TempBufferTarget);
BackendVertexArrayBindingProtector backendVAOBindingProtector;
Bind(); Bind();
for (const auto& attribIndex : stateVAOObject->GetDirtyAttributeIndices()) { const auto& allAttributeVersions = stateVAOObject->GetAllAttributeVersions();
const auto& attrib = stateVAOObject->GetAttribute(attribIndex); const auto& allAttributes = stateVAOObject->GetAllAttributes();
for (Uint attribIndex = 0; attribIndex < allAttributes.size(); ++attribIndex) {
const auto& attrib = allAttributes[attribIndex];
Bool needsSyncSwitch = allAttributeVersions[attribIndex].SwitchVersion !=
m_syncedAttributeVersions[attribIndex].SwitchVersion;
if (needsSyncSwitch) {
if (attrib.Enabled) { if (attrib.Enabled) {
MGLOG_D("Binding attribute index %u for VAO ID: %u", attribIndex, m_backendVAOId);
MG_External::GLES::glEnableVertexAttribArray(attribIndex); MG_External::GLES::glEnableVertexAttribArray(attribIndex);
} else { } else {
MGLOG_D("Disabling attribute index %u for VAO ID: %u", attribIndex, m_backendVAOId);
MG_External::GLES::glDisableVertexAttribArray(attribIndex); MG_External::GLES::glDisableVertexAttribArray(attribIndex);
continue; }
} }
const auto& bufferObject = attrib.Buffer; Bool needsSyncFormat = allAttributeVersions[attribIndex].FormatVersion !=
if (!bufferObject) { m_syncedAttributeVersions[attribIndex].FormatVersion;
MGLOG_W("Attribute has no bound buffer, skipping."); Bool needsSyncBuffer = allAttributeVersions[attribIndex].BufferVersion !=
continue; m_syncedAttributeVersions[attribIndex].BufferVersion;
} if (!needsSyncFormat && !needsSyncBuffer) continue;
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObject); BindAttributeBuffer(attribIndex, attrib);
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
MGLOG_E("No backend buffer found for attribute's buffer, cannot bind attribute.");
continue;
}
const auto& backendBufferObject = backendBufferIt->second;
backendBufferObject->Bind(GL_ARRAY_BUFFER);
if (!attrib.IsInteger) { if (!attrib.IsInteger) {
MG_External::GLES::glVertexAttribPointer( MG_External::GLES::glVertexAttribPointer(
attribIndex, attrib.Size, MG_Util::ConvertDataTypeToGLEnum(attrib.Type), attribIndex, attrib.Size, MG_Util::ConvertDataTypeToGLEnum(attrib.Type),
@@ -247,11 +280,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
attrib.Stride, (const void*)attrib.Offset); attrib.Stride, (const void*)attrib.Offset);
} }
if (needDivisor) { if (needsSyncFormat) {
MG_External::GLES::glVertexAttribDivisor(attribIndex, attrib.Divisor); MG_External::GLES::glVertexAttribDivisor(attribIndex, attrib.Divisor);
} }
} }
Uint16 currentIndexBufferVersion = stateVAOObject->GetIndexBufferBindingSlot().GetVersion();
if (currentIndexBufferVersion != m_syncedIndexBufferVersion) {
const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject(); const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
if (indexBufferBinding) { if (indexBufferBinding) {
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding); const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding);
@@ -262,8 +297,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_W("No backend buffer found for index buffer binding, cannot bind index buffer."); MGLOG_W("No backend buffer found for index buffer binding, cannot bind index buffer.");
} }
} }
m_syncedIndexBufferVersion = currentIndexBufferVersion;
}
stateVAOObject->ClearDirtyAttributes(); m_syncedAttributeVersions = allAttributeVersions;
} }
UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>> UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>>
@@ -284,11 +321,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void BackendTextureObject::Bind(GLenum target) { void BackendTextureObject::Bind(GLenum target, Uint unit) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
if (g_activeTextureUnit != unit) {
ActivateTextureUnit(unit);
}
auto targetN = static_cast<SizeT>(MG_Util::ConvertGLEnumToTextureTarget(target));
if (this == g_boundTexturesCache[unit][targetN]) return;
MG_External::GLES::glBindTexture(target, m_backendTextureId); MG_External::GLES::glBindTexture(target, m_backendTextureId);
g_boundTexturesCache[unit][targetN] = this;
} }
Uint BackendTextureObject::GetBackendTextureId() { Uint BackendTextureObject::GetBackendTextureId() {
@@ -298,17 +343,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
return m_backendTextureId; return m_backendTextureId;
} }
void BackendTextureObject::SyncToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) { void BackendTextureObject::SyncMipmapsToBackend(
#ifdef TRACY_ENABLE SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
DebugImpl::ErrorLopper errorLopper;
if (!stateTextureObject) { if (!stateTextureObject) {
MGLOG_E("State texture object is null, cannot sync to backend."); MGLOG_E("State texture object is null, cannot sync to backend.");
return; return;
} }
MGLOG_D("Syncing texture with backend ID %u to backend for state ID %u", m_backendTextureId, #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
DebugImpl::ErrorLopper errorLopper;
MGLOG_D("Syncing texture mipmaps with backend ID %u to backend for state ID %u", m_backendTextureId,
stateTextureObject->GetExternalIndex()); stateTextureObject->GetExternalIndex());
GLenum target = MG_Util::ConvertTextureTargetToGLEnum(stateTextureObject->GetTarget()); GLenum target = MG_Util::ConvertTextureTargetToGLEnum(stateTextureObject->GetTarget());
@@ -333,7 +380,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
return; return;
} }
// BackendTextureBindingProtector backendTextureBindingProtector(target);
Bind(target); Bind(target);
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
@@ -507,9 +553,54 @@ namespace MobileGL::MG_Backend::DirectGLES {
THROW_UNIMPL_EXCEPTION; THROW_UNIMPL_EXCEPTION;
} }
{ // Update built-in sampler parameters errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
});
m_prevTextureInfo = currentTextureInfo;
}
void BackendTextureObject::SyncBuiltinSamplerToBackend(
SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
DebugImpl::ErrorLopper errorLopper;
if (!stateTextureObject) {
MGLOG_E("State texture object is null, cannot sync to backend.");
return;
}
auto* samplerObject = stateTextureObject->GetSamplerObject().get();
Uint currentSamplerVersion = samplerObject->GetVersion();
if (m_syncedSamplerVersion == currentSamplerVersion) {
MGLOG_D("Sampler parameters have not changed for texture ID: %u, skipping sync.", m_backendTextureId);
return;
}
m_syncedSamplerVersion = currentSamplerVersion;
MGLOG_D("Syncing texture built-in sampler with backend ID %u to backend for state ID %u",
m_backendTextureId, stateTextureObject->GetExternalIndex());
GLenum target = MG_Util::ConvertTextureTargetToGLEnum(stateTextureObject->GetTarget());
auto targetInternal = stateTextureObject->GetTarget();
MGLOG_D(" Texture target for syncing is %s",
MG_Util::ConvertTextureTargetToString(targetInternal).c_str());
if (!IsSupportedTextureTarget(targetInternal)) {
MGLOG_E(" Texture target %s is not supported, skipping.",
MG_Util::ConvertTextureTargetToString(targetInternal).c_str());
return;
}
Bind(target);
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
});
// Update built-in sampler parameters
MGLOG_D("Updating sampler parameters for texture with ID: %u", m_backendTextureId); MGLOG_D("Updating sampler parameters for texture with ID: %u", m_backendTextureId);
const auto& samplerParams = stateTextureObject->GetSamplerObject()->GetAllSamplerParameters(); const auto& samplerParams = samplerObject->GetAllSamplerParameters();
#define SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(internalName, glName, type) \ #define SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(internalName, glName, type) \
if (m_cacheSamplerParameters.internalName != samplerParams.internalName) { \ if (m_cacheSamplerParameters.internalName != samplerParams.internalName) { \
@@ -560,22 +651,56 @@ namespace MobileGL::MG_Backend::DirectGLES {
#undef SYNC_TEX_SAMPLER_PARAM_IF_CHANGED #undef SYNC_TEX_SAMPLER_PARAM_IF_CHANGED
} }
{ // Update texture parameters void BackendTextureObject::SyncTextureParamsToBackend(
SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
DebugImpl::ErrorLopper errorLopper;
if (!stateTextureObject) {
MGLOG_E("State texture object is null, cannot sync to backend.");
return;
}
Uint16 currentTextureParamsVersion = stateTextureObject->GetTextureParamsVersion();
if (m_syncedTextureParamsVersion == currentTextureParamsVersion) {
MGLOG_D("Texture parameters have not changed for texture ID: %u, skipping sync.", m_backendTextureId);
return;
}
m_syncedTextureParamsVersion = currentTextureParamsVersion;
MGLOG_D("Syncing texture params with backend ID %u to backend for state ID %u", m_backendTextureId,
stateTextureObject->GetExternalIndex());
GLenum target = MG_Util::ConvertTextureTargetToGLEnum(stateTextureObject->GetTarget());
auto targetInternal = stateTextureObject->GetTarget();
MGLOG_D(" Texture target for syncing is %s",
MG_Util::ConvertTextureTargetToString(targetInternal).c_str());
if (!IsSupportedTextureTarget(targetInternal)) {
MGLOG_E(" Texture target %s is not supported, skipping.",
MG_Util::ConvertTextureTargetToString(targetInternal).c_str());
return;
}
Bind(target);
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
});
// Update texture parameters
MGLOG_D("Updating texture parameters for texture with ID: %u", m_backendTextureId); MGLOG_D("Updating texture parameters for texture with ID: %u", m_backendTextureId);
const auto& levelRange = stateTextureObject->GetLevelRange(); const auto& levelRange = stateTextureObject->GetLevelRange();
if (m_cacheLodRange.x() != levelRange.x()) { if (m_cacheLodRange.x() != levelRange.x()) {
MG_External::GLES::glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, MG_External::GLES::glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, static_cast<GLint>(levelRange.x()));
static_cast<GLint>(levelRange.x()));
m_cacheLodRange.x() = levelRange.x(); m_cacheLodRange.x() = levelRange.x();
} }
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
}); });
if (m_cacheLodRange.y() != levelRange.y()) { if (m_cacheLodRange.y() != levelRange.y()) {
MG_External::GLES::glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, MG_External::GLES::glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(levelRange.y()));
static_cast<GLint>(levelRange.y()));
m_cacheLodRange.y() = levelRange.y(); m_cacheLodRange.y() = levelRange.y();
} }
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
@@ -612,13 +737,30 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { void ActivateTextureUnit(Uint unit) {
MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); if (unit == g_activeTextureUnit) {
}); return;
}
m_prevTextureInfo = currentTextureInfo; MG_External::GLES::glActiveTexture(GL_TEXTURE0 + unit);
g_activeTextureUnit = unit;
} }
void UnbindTexture(Uint unit, GLenum target) { // Active unit will be modified
if (unit != g_activeTextureUnit) {
ActivateTextureUnit(unit);
}
auto targetN = static_cast<SizeT>(MG_Util::ConvertGLEnumToTextureTarget(target));
if (g_boundTexturesCache[unit][targetN] == nullptr) return;
MG_External::GLES::glBindTexture(target, 0);
g_boundTexturesCache[unit][targetN] = nullptr;
}
Uint g_activeTextureUnit = 0;
Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
g_boundTexturesCache;
UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>> UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>>
g_backendTextureObjects; g_backendTextureObjects;
} // namespace TextureImpl } // namespace TextureImpl
@@ -647,6 +789,42 @@ namespace MobileGL::MG_Backend::DirectGLES {
MG_External::GLES::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId); MG_External::GLES::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId);
} }
Bool BackendFramebufferObject::SyncAttachmentObject(
GLenum glFBOTarget, const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
GLenum glBackendAttachment) {
if (attachmentObject.IsTexture()) {
const auto& textureObject = attachmentObject.GetTexture();
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
MGLOG_E("%s: No backend texture found for FBO attachment, cannot bind texture.", __func__);
return false;
}
const auto& backendTextureObject = backendTextureIt->second;
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
backendTextureObject->Bind(glTextureTarget);
MG_External::GLES::glFramebufferTexture2D(glFBOTarget, glBackendAttachment, glTextureTarget,
backendTextureObject->GetBackendTextureId(),
static_cast<GLint>(attachmentObject.GetTextureLevel()));
} else if (attachmentObject.IsRenderbuffer()) {
const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
const auto& backendRenderbufferIt =
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
backendRenderbufferObject = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject;
} else {
backendRenderbufferObject = backendRenderbufferIt->second;
}
backendRenderbufferObject->SyncToBackend(renderbufferObject);
backendRenderbufferObject->Bind();
MG_External::GLES::glFramebufferRenderbuffer(glFBOTarget, glBackendAttachment, GL_RENDERBUFFER,
backendRenderbufferObject->GetBackendRenderbufferId());
}
return true;
}
void BackendFramebufferObject::SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, void BackendFramebufferObject::SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
FramebufferTarget asTarget) { FramebufferTarget asTarget) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
@@ -659,129 +837,148 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("Syncing FBO with backend ID %u to backend for state ID %u, as %s FBO", m_backendFBOId, MGLOG_D("Syncing FBO with backend ID %u to backend for state ID %u, as %s FBO", m_backendFBOId,
stateFBOObject->GetExternalIndex(), (asTarget == FramebufferTarget::Draw ? "DRAW" : "READ")); stateFBOObject->GetExternalIndex(), (asTarget == FramebufferTarget::Draw ? "DRAW" : "READ"));
GLenum glFBOTarget = MG_Util::ConvertFramebufferTargetToGLEnum(asTarget); GLenum glFBOTarget = MG_Util::ConvertFramebufferTargetToGLEnum(asTarget);
BackendFramebufferBindingProtector backendFBOBindingProtector(glFBOTarget);
Bind(asTarget); Bind(asTarget);
// Handle all attachments // -------------------- Connect attachments (set buffers) -----------------------
const auto& attachments = stateFBOObject->GetAllAttachments(); // 1. Remap draw buffers
for (SizeT i = 0; i < attachments.size(); ++i) {
const auto& attachment = attachments[i];
if (!attachment.IsValid() || attachment.IsEmpty()) {
continue;
}
FramebufferAttachmentType type = static_cast<FramebufferAttachmentType>(i);
GLenum glAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(type);
if (attachment.IsTexture()) {
const auto& textureObject = attachment.GetTexture();
const 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;
}
const auto& backendTextureObject = backendTextureIt->second;
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
backendTextureObject->Bind(glTextureTarget);
MG_External::GLES::glFramebufferTexture2D(glFBOTarget, glAttachment, glTextureTarget,
backendTextureObject->GetBackendTextureId(),
static_cast<GLint>(attachment.GetTextureLevel()));
} else if (attachment.IsRenderbuffer()) {
const auto& renderbufferObject = attachment.GetRenderbuffer();
const auto& backendRenderbufferIt =
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
backendRenderbufferObject = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject;
} else {
backendRenderbufferObject = backendRenderbufferIt->second;
}
backendRenderbufferObject->SyncToBackend(renderbufferObject);
backendRenderbufferObject->Bind();
MG_External::GLES::glFramebufferRenderbuffer(glFBOTarget, glAttachment, GL_RENDERBUFFER,
backendRenderbufferObject->GetBackendRenderbufferId());
}
}
// Handle draw buffers for DRAW_FRAMEBUFFER
if (asTarget == FramebufferTarget::Draw) {
// Create mappings for draw buffers
int nBuffers = 0;
std::fill(m_frontendDrawBuffers,
m_frontendDrawBuffers + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS,
FramebufferAttachmentType::None);
std::fill(m_compactedFrontendDrawBuffers,
m_compactedFrontendDrawBuffers + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS,
FramebufferAttachmentType::None);
std::fill(m_backendDrawBuffers,
m_backendDrawBuffers + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE);
auto& stateDrawBuffers = stateFBOObject->GetDrawBuffers(); auto& stateDrawBuffers = stateFBOObject->GetDrawBuffers();
for (GLint i = 0; i < MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS; ++i) { Bool drawBufferClean = false;
if (stateDrawBuffers[i] == FramebufferAttachmentType::None) { if (memcmp(m_frontendDrawBuffers, stateDrawBuffers.data(),
m_frontendDrawBuffers[i] = FramebufferAttachmentType::None; FramebufferObject::MAX_DRAW_BUFFERS * sizeof(FramebufferAttachmentType)) == 0) {
continue; drawBufferClean = true;
} }
m_frontendDrawBuffers[i] = stateDrawBuffers[i]; if (!drawBufferClean) {
memcpy(m_frontendDrawBuffers, stateDrawBuffers.data(),
FramebufferObject::MAX_DRAW_BUFFERS * sizeof(FramebufferAttachmentType));
std::fill(m_backendDrawBuffers, m_backendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE);
int nEffectiveBuffers = 0;
for (GLint i = 0; i < FramebufferObject::MAX_DRAW_BUFFERS; ++i) {
auto frontendBuf = stateDrawBuffers[i];
if (frontendBuf == FramebufferAttachmentType::None) {
m_backendDrawBuffers[i] = GL_NONE;
continue;
}
// Create compacted mapping // Create compacted mapping
m_backendDrawBuffers[nBuffers] = GL_COLOR_ATTACHMENT0 + nBuffers; if (frontendBuf == FramebufferAttachmentType::FrontLeft ||
m_compactedFrontendDrawBuffers[nBuffers] = m_frontendDrawBuffers[i]; frontendBuf == FramebufferAttachmentType::FrontRight ||
nBuffers++; frontendBuf == FramebufferAttachmentType::BackLeft ||
} frontendBuf == FramebufferAttachmentType::BackRight) {
MGLOG_D("%s: frontend buf token found for default fbo, shouldn't remap", __func__);
MG_External::GLES::glDrawBuffers(nBuffers, m_backendDrawBuffers); m_backendDrawBuffers[i] = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(frontendBuf);
stateFBOObject->ClearDrawBuffersDirtyState();
}
// Handle read buffer for READ_FRAMEBUFFER
else if (asTarget == FramebufferTarget::Read) {
m_frontendReadBuffer = stateFBOObject->GetReadBuffer();
GLenum frontendAtt = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(m_frontendReadBuffer);
GLenum backendAtt = GL_NONE;
const auto& readAttachment = attachments[(SizeT)m_frontendReadBuffer];
GLenum glAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(m_frontendReadBuffer);
if (!readAttachment.IsValid() || readAttachment.IsEmpty()) {
return;
}
if (readAttachment.IsTexture()) {
const auto& textureObject = readAttachment.GetTexture();
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
MGLOG_E("ReadBuffer: No backend texture found for FBO attachment, cannot bind texture.");
return;
}
const auto& backendTextureObject = backendTextureIt->second;
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
backendTextureObject->Bind(glTextureTarget);
MG_External::GLES::glFramebufferTexture2D(glFBOTarget, glAttachment, glTextureTarget,
backendTextureObject->GetBackendTextureId(),
static_cast<GLint>(readAttachment.GetTextureLevel()));
} else if (readAttachment.IsRenderbuffer()) {
const auto& renderbufferObject = readAttachment.GetRenderbuffer();
const auto& backendRenderbufferIt =
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
backendRenderbufferObject = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject;
} else { } else {
backendRenderbufferObject = backendRenderbufferIt->second; m_backendDrawBuffers[i] = GL_COLOR_ATTACHMENT0 + i;
}
nEffectiveBuffers = i + 1;
}
MG_External::GLES::glDrawBuffers(nEffectiveBuffers, m_backendDrawBuffers);
} }
backendRenderbufferObject->SyncToBackend(renderbufferObject); // 2. Remap read buffer
backendRenderbufferObject->Bind(); auto frontendReadBuf = stateFBOObject->GetReadBuffer();
MG_External::GLES::glFramebufferRenderbuffer(glFBOTarget, glAttachment, GL_RENDERBUFFER, if (frontendReadBuf != m_frontendReadBuffer) {
backendRenderbufferObject->GetBackendRenderbufferId()); m_frontendReadBuffer = frontendReadBuf;
}
MG_External::GLES::glReadBuffer(glAttachment); GLenum glBackendReadBuffer = GetBackendAttachmentType(frontendReadBuf);
if (m_backendReadBuffer != glBackendReadBuffer) {
m_backendReadBuffer = glBackendReadBuffer;
MG_External::GLES::glReadBuffer(glBackendReadBuffer);
} }
} }
FramebufferAttachmentType BackendFramebufferObject::GetCompactedAttachmentTypeAtDrawBufferIndex(Int index) { // -------------------- Attach texture to backend FBO -----------------------
return m_compactedFrontendDrawBuffers[index]; const auto& attachments = stateFBOObject->GetAllAttachmentObjects();
const auto& attachmentVersions = stateFBOObject->GetAllFramebufferAttachmentVersions();
for (SizeT i = 0; i < attachments.size(); ++i) {
const auto& attachmentObject = attachments[i];
FramebufferAttachmentType frontendType = static_cast<FramebufferAttachmentType>(i);
GLenum glBackendAttachment = GL_NONE;
if (frontendType >= FramebufferAttachmentType::Color0 &&
frontendType <= FramebufferAttachmentType::Color31)
glBackendAttachment = GetBackendAttachmentType(frontendType);
else
glBackendAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(frontendType);
// relevant FRONTEND!!! version should be checked and updated
if (m_syncedFrontendAttachmentVersions[i] != attachmentVersions[i]) {
SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment);
m_syncedFrontendAttachmentVersions[i] = attachmentVersions[i];
}
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
else {
MGLOG_D("%s: Skipped SyncAttachmentObject(target=%s, frontendObj=(%dx%dx%d, %s), backendAtt=%s), "
"version = %u",
__func__, MG_Util::ConvertGLEnumToString(glFBOTarget).c_str(),
attachmentObject.GetSize().x(), attachmentObject.GetSize().y(),
attachmentObject.GetSize().z(),
MG_Util::ConvertFramebufferAttachmentTypeToString(frontendType).c_str(),
MG_Util::ConvertGLEnumToString(glBackendAttachment).c_str(),
m_syncedFrontendAttachmentVersions[i]);
GLint objectType = GL_NONE;
MG_External::GLES::glGetFramebufferAttachmentParameteriv(
glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &objectType);
MOBILEGL_ASSERT((objectType == GL_NONE) ||
(attachmentObject.IsTexture() && objectType == GL_TEXTURE) ||
(attachmentObject.IsRenderbuffer() && objectType == GL_RENDERBUFFER),
"Attachment type not match!");
GLint objectName = 0;
MG_External::GLES::glGetFramebufferAttachmentParameteriv(
glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &objectName);
// Verify that the backend object's name and parameters match the frontend attachment state
if (attachmentObject.IsTexture()) {
const auto& textureObject = attachmentObject.GetTexture();
auto backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
MOBILEGL_ASSERT(backendTextureIt != TextureImpl::g_backendTextureObjects.end(),
"No backend texture found while framebuffer reports texture attachment.");
GLuint backendTexId = backendTextureIt->second->GetBackendTextureId();
MOBILEGL_ASSERT(static_cast<GLint>(backendTexId) == objectName,
"Attachment texture name mismatch between GLES (%d) and backend texture object "
"(%d), frontend texture object ID=%d.",
objectName, backendTexId, textureObject->GetExternalIndex());
GLint texLevel = 0;
MG_External::GLES::glGetFramebufferAttachmentParameteriv(
glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, &texLevel);
MOBILEGL_ASSERT(texLevel == static_cast<GLint>(attachmentObject.GetTextureLevel()),
"Attachment texture level mismatch between GLES and state object.");
} else if (attachmentObject.IsRenderbuffer()) {
const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
auto backendRboIt = RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
MOBILEGL_ASSERT(
backendRboIt != RenderbufferImpl::g_backendRenderbufferObjects.end(),
"No backend renderbuffer found while framebuffer reports renderbuffer attachment.");
GLuint backendRboId = backendRboIt->second->GetBackendRenderbufferId();
MOBILEGL_ASSERT(static_cast<GLint>(backendRboId) == objectName,
"Attachment renderbuffer name mismatch between GLES and state object.");
}
}
#endif
}
}
GLenum BackendFramebufferObject::GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const {
GLenum glBackendReadBuffer = GL_NONE;
auto it = std::find(m_frontendDrawBuffers, m_frontendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS,
frontendAtt);
Bool notFound = (it == m_frontendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS);
if (notFound) {
MGLOG_D(
"%s: frontendAtt not found in draw buffer (probably not remapped), just use the same as frontend",
__func__);
glBackendReadBuffer = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(frontendAtt);
} else {
MGLOG_D("%s: frontendAtt found in draw buffer, keep it consistent as in read buffers", __func__);
auto index = std::distance(m_frontendDrawBuffers, it);
glBackendReadBuffer = m_backendDrawBuffers[index];
}
return glBackendReadBuffer;
} }
UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>> UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>>
g_backendFramebufferObjects; g_backendFramebufferObjects;
Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions = {0};
} // namespace FramebufferImpl } // namespace FramebufferImpl
namespace PrgramImpl { namespace PrgramImpl {
@@ -902,16 +1099,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
source = ProcessOutColorLocations(source); source = ProcessOutColorLocations(source);
source = ForceSupporterOutput(source); source = ForceSupporterOutput(source);
// TODO: probably a patch system? // Patch for Photon compiler precision issue
// String findStr = "if (distance_weight_sum == 0.0)";
// String replaceStr = "if (distance_weight_sum <= 0.0001)";
// auto pos = source.find(findStr);
// while (pos != String::npos) {
// MGLOG_D("Applying patch #1 to Photon...");
// source.replace(pos, findStr.length(), replaceStr);
// pos = source.find(findStr, pos);
// }
String findStr = "1000000.0"; String findStr = "1000000.0";
String replaceStr = "65500.0"; String replaceStr = "65500.0";
auto pos = source.find(findStr); auto pos = source.find(findStr);
@@ -921,24 +1109,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
pos = source.find(findStr, pos); pos = source.find(findStr, pos);
} }
// findStr = "if (gtao.w == 0.0)";
// replaceStr = "if (abs(gtao.w) <= 0.00001)";
// pos = source.find(findStr);
// while (pos != String::npos) {
// MGLOG_D("Applying patch #3 to Photon...");
// source.replace(pos, findStr.length(), replaceStr);
// pos = source.find(findStr, pos);
// }
// findStr = "== 0.0";
// replaceStr = "<= 0.00001";
// pos = source.find(findStr);
// while (pos != String::npos) {
// MGLOG_D("Applying patch #4 to Photon...");
// source.replace(pos, findStr.length(), replaceStr);
// pos = source.find(findStr, pos);
// }
const char* sourceCStr = source.c_str(); const char* sourceCStr = source.c_str();
MGLOG_D("Setting shader source for backend shader ID: %u\nsrc:\n%s", backendShaderId, sourceCStr); MGLOG_D("Setting shader source for backend shader ID: %u\nsrc:\n%s", backendShaderId, sourceCStr);
MG_External::GLES::glShaderSource(backendShaderId, 1, &sourceCStr, nullptr); MG_External::GLES::glShaderSource(backendShaderId, 1, &sourceCStr, nullptr);
@@ -1025,6 +1195,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
return; return;
} }
Uint currentSamplerVersion = stateSamplerObject->GetVersion();
if (m_isInitialized && m_syncedSamplerVersion == currentSamplerVersion) {
MGLOG_D("Sampler parameters have not changed for sampler ID: %u, skipping sync.",
stateSamplerObject->GetExternalIndex());
return;
}
m_syncedSamplerVersion = currentSamplerVersion;
MGLOG_D("Syncing sampler with backend ID %u to backend for state ID %u", m_backendSamplerId, MGLOG_D("Syncing sampler with backend ID %u to backend for state ID %u", m_backendSamplerId,
stateSamplerObject->GetExternalIndex()); stateSamplerObject->GetExternalIndex());
@@ -1073,7 +1252,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif #endif
if (g_boundSamplersCache[unit] == this) return;
MG_External::GLES::glBindSampler(static_cast<GLenum>(unit), m_backendSamplerId); MG_External::GLES::glBindSampler(static_cast<GLenum>(unit), m_backendSamplerId);
g_boundSamplersCache[unit] = this;
} }
Uint BackendSamplerObject::GetBackendSamplerId() { Uint BackendSamplerObject::GetBackendSamplerId() {
@@ -1083,6 +1265,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
return m_backendSamplerId; return m_backendSamplerId;
} }
void UnbindSampler(Uint unit) {
if (g_boundSamplersCache[unit] == nullptr) return;
MG_External::GLES::glBindSampler(static_cast<GLenum>(unit), 0);
g_boundSamplersCache[unit] = nullptr;
}
Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS> g_boundSamplersCache;
UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>> UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>>
g_backendSamplerObjects; g_backendSamplerObjects;
} // namespace SamplerImpl } // namespace SamplerImpl
+39 -16
View File
@@ -16,25 +16,26 @@
namespace MobileGL::MG_Backend::DirectGLES { namespace MobileGL::MG_Backend::DirectGLES {
namespace BufferImpl { namespace BufferImpl {
const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
class BackendBufferObject { class BackendBufferObject {
public: public:
BackendBufferObject(); BackendBufferObject();
void SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject); void SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
Uint GetBackendBufferId() { return m_backendBufferId; } Uint GetBackendBufferId() { return m_backendBufferId; }
void Bind(); void Bind(GLenum target = TempBufferTarget);
void Bind(GLenum target);
private: private:
void SyncToBackend_glBufferData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject); void SyncToBackend_glBufferData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
void SyncToBackend_glBufferSubData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject); void SyncToBackend_glBufferSubData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
void SyncToBackend_glMapBufferRange(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, void SyncToBackend_glMapBufferRange(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject,
Bool invalidate = true); Bool invalidate = true, Bool unsynchronized = true);
Uint m_backendBufferId = 0; Uint m_backendBufferId = 0;
SizeT m_prevBufferSize = 0; SizeT m_prevBufferSize = 0;
Bool m_isInitialized = false; Bool m_isInitialized = false;
}; };
extern BackendBufferObject* g_boundVertexBufferObject;
extern UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>> extern UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>>
g_backendBufferObjects; g_backendBufferObjects;
} // namespace BufferImpl } // namespace BufferImpl
@@ -43,13 +44,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
class BackendVertexArrayObject { class BackendVertexArrayObject {
public: public:
BackendVertexArrayObject(); BackendVertexArrayObject();
void SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject, Bool needDivisor); void SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
Uint GetBackendVertexArrayId() { return m_backendVAOId; } Uint GetBackendVertexArrayId() { return m_backendVAOId; }
void Bind(); void Bind();
private: private:
void BindAttributeBuffer(Uint index, const MG_State::GLState::VertexAttribute& attrib);
Uint m_backendVAOId = 0; Uint m_backendVAOId = 0;
Bool m_isInitialized = false; Bool m_isInitialized = false;
Uint16 m_syncedIndexBufferVersion = 0;
Array<MG_State::GLState::VertexAttributeVersion, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS>
m_syncedAttributeVersions;
}; };
extern UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>> extern UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>>
@@ -82,11 +88,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
bool operator!=(const StateTextureBasicInfo& other) const { return !(*this == other); } bool operator!=(const StateTextureBasicInfo& other) const { return !(*this == other); }
}; };
inline const Uint TempTextureUnit = 0;
class BackendTextureObject { class BackendTextureObject {
public: public:
BackendTextureObject(); BackendTextureObject();
void SyncToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject); void SyncMipmapsToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
void Bind(GLenum target); void SyncBuiltinSamplerToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
void SyncTextureParamsToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
void Bind(GLenum target, Uint unit = TempTextureUnit);
Uint GetBackendTextureId(); Uint GetBackendTextureId();
private: private:
@@ -98,10 +107,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
FloatVec4 m_cacheBorderColor = {0.0f, 0.0f, 0.0f, 0.0f}; FloatVec4 m_cacheBorderColor = {0.0f, 0.0f, 0.0f, 0.0f};
Vec4<TextureSwizzleParam> m_cacheSwizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green, Vec4<TextureSwizzleParam> m_cacheSwizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green,
TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha}; TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha};
Uint16 m_syncedSamplerVersion = 0;
Uint16 m_syncedTextureParamsVersion = 0;
}; };
void ActivateTextureUnit(Uint unit);
void UnbindTexture(Uint unit, GLenum target);
extern UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>> extern UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>>
g_backendTextureObjects; g_backendTextureObjects;
extern Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
g_boundTexturesCache;
extern Uint g_activeTextureUnit;
} // namespace TextureImpl } // namespace TextureImpl
namespace FramebufferImpl { namespace FramebufferImpl {
@@ -112,7 +129,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
FramebufferTarget asTarget); FramebufferTarget asTarget);
Uint GetBackendFramebufferId() { return m_backendFBOId; } Uint GetBackendFramebufferId() { return m_backendFBOId; }
void Bind(FramebufferTarget target); void Bind(FramebufferTarget target);
FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index); bool SyncAttachmentObject(GLenum glFBOTarget,
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
GLenum glBackendAttachment);
// FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index);
GLenum GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const;
private: private:
Uint m_backendFBOId = 0; Uint m_backendFBOId = 0;
@@ -125,25 +146,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
*/ */
FramebufferAttachmentType m_frontendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = { FramebufferAttachmentType m_frontendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {
FramebufferAttachmentType::None}; FramebufferAttachmentType::None};
/* this will save buffers in its compacted GL form,
not consecutive is not allowed
i.e. it could be like [COLOR_ATTACHMENT0, COLOR_ATTACHMENT5, COLOR_ATTACHMENT4]
(no GL_NONE among those)
*/
FramebufferAttachmentType
m_compactedFrontendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {
FramebufferAttachmentType::None};
/* this will save buffers in stricter ES rules /* this will save buffers in stricter ES rules
reversion, absence or not consecutive are not allowed, according to ES spec reversion, absence or not consecutive are not allowed, according to ES spec
i.e. it could be like [COLOR_ATTACHMENT0, COLOR_ATTACHMENT1, NONE, NONE, ...] i.e. it could be like [COLOR_ATTACHMENT0, COLOR_ATTACHMENT1, NONE, COLOR_ATTACHMENT3, ...]
this array could be provided as data directly to ES `glDrawBuffers` function this array could be provided as data directly to ES `glDrawBuffers` function
*/ */
GLenum m_backendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {GL_NONE}; GLenum m_backendDrawBuffers[MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS] = {GL_NONE};
FramebufferAttachmentType m_frontendReadBuffer = FramebufferAttachmentType::Color0; FramebufferAttachmentType m_frontendReadBuffer = FramebufferAttachmentType::Color0;
GLenum m_backendReadBuffer = GL_COLOR_ATTACHMENT0;
using FramebufferObject = MG_State::GLState::FramebufferObject;
FramebufferObject::FramebufferAttachmentVersionArray m_syncedFrontendAttachmentVersions = {0};
}; };
extern UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>> extern UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>>
g_backendFramebufferObjects; g_backendFramebufferObjects;
extern Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions;
} // namespace FramebufferImpl } // namespace FramebufferImpl
namespace PrgramImpl { namespace PrgramImpl {
@@ -178,8 +196,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
Uint m_backendSamplerId = 0; Uint m_backendSamplerId = 0;
Bool m_isInitialized = false; Bool m_isInitialized = false;
SamplerParameters m_cacheSamplerParameters; SamplerParameters m_cacheSamplerParameters;
Uint16 m_syncedSamplerVersion = 0;
}; };
void UnbindSampler(Uint unit);
extern Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
g_boundSamplersCache;
extern UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>> extern UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>>
g_backendSamplerObjects; g_backendSamplerObjects;
} // namespace SamplerImpl } // namespace SamplerImpl
+3 -83
View File
@@ -19,55 +19,11 @@
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h> #include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
namespace MobileGL::MG_Backend::DirectGLES { namespace MobileGL::MG_Backend::DirectGLES {
namespace BufferImpl { namespace BufferImpl {} // namespace BufferImpl
BackendBufferBindingProtector::BackendBufferBindingProtector(GLenum target) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
m_target = target;
MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, false), &m_previousBinding);
}
BackendBufferBindingProtector::~BackendBufferBindingProtector() { namespace VertexArrayImpl {} // namespace VertexArrayImpl
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_External::GLES::glBindBuffer(m_target, m_previousBinding);
}
} // namespace BufferImpl
namespace VertexArrayImpl {
BackendVertexArrayBindingProtector::BackendVertexArrayBindingProtector() {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_External::GLES::glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &m_previousBinding);
}
BackendVertexArrayBindingProtector::~BackendVertexArrayBindingProtector() {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_External::GLES::glBindVertexArray(m_previousBinding);
}
} // namespace VertexArrayImpl
namespace TextureImpl { namespace TextureImpl {
BackendTextureBindingProtector::BackendTextureBindingProtector(GLenum target) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
m_target = target;
MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, true), &m_previousBinding);
}
BackendTextureBindingProtector::~BackendTextureBindingProtector() {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_External::GLES::glBindTexture(m_target, m_previousBinding);
}
void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat, void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat,
GLenum* outFormat, GLenum* outType) { GLenum* outFormat, GLenum* outType) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
@@ -81,43 +37,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} // namespace TextureImpl } // namespace TextureImpl
namespace FramebufferImpl { namespace FramebufferImpl {} // namespace FramebufferImpl
BackendFramebufferBindingProtector::BackendFramebufferBindingProtector(GLenum target) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
m_target = target;
MG_External::GLES::glGetIntegerv(Utils::GetBindingQuery(target, false), &m_previousBinding);
}
BackendFramebufferBindingProtector::~BackendFramebufferBindingProtector() {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_External::GLES::glBindFramebuffer(m_target, m_previousBinding);
}
GLuint BackendFramebufferBindingProtector::GetTempFBO(FramebufferTarget target) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
GLenum glTarget = MG_Util::ConvertFramebufferTargetToGLEnum(target);
GLuint& fbo = (glTarget == GL_DRAW_FRAMEBUFFER) ? s_tempDrawFBO : s_tempReadFBO;
if (fbo == 0) {
MG_External::GLES::glGenFramebuffers(1, &fbo);
}
return fbo;
}
void BackendFramebufferBindingProtector::BindTempFBO(MobileGL::FramebufferTarget target) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
GLuint fbo = GetTempFBO(target);
GLenum glTarget = MG_Util::ConvertFramebufferTargetToGLEnum(target);
MG_External::GLES::glBindFramebuffer(glTarget, fbo);
}
} // namespace FramebufferImpl
namespace PrgramImpl { namespace PrgramImpl {
String ProcessOutColorLocations(const String& glslCode) { String ProcessOutColorLocations(const String& glslCode) {
+2 -50
View File
@@ -27,66 +27,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
}; };
} // namespace DebugImpl } // namespace DebugImpl
namespace BufferImpl { namespace BufferImpl {} // namespace BufferImpl
class BackendBufferBindingProtector {
public:
BackendBufferBindingProtector(GLenum target);
~BackendBufferBindingProtector();
private:
GLenum m_target;
GLint m_previousBinding = 0;
};
} // namespace BufferImpl
namespace VertexArrayImpl { namespace VertexArrayImpl {
GLenum GetBindingQuery(GLenum target, bool isTexture); GLenum GetBindingQuery(GLenum target, bool isTexture);
class BackendVertexArrayBindingProtector {
public:
BackendVertexArrayBindingProtector();
~BackendVertexArrayBindingProtector();
private:
GLint m_previousBinding = 0;
};
} // namespace VertexArrayImpl } // namespace VertexArrayImpl
namespace TextureImpl { namespace TextureImpl {
class BackendTextureBindingProtector {
public:
BackendTextureBindingProtector(GLenum target);
~BackendTextureBindingProtector();
private:
GLenum m_target;
GLint m_previousBinding = 0;
};
void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat, void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat,
GLenum* outFormat, GLenum* outType); GLenum* outFormat, GLenum* outType);
} // namespace TextureImpl } // namespace TextureImpl
namespace FramebufferImpl { namespace FramebufferImpl {} // namespace FramebufferImpl
class BackendFramebufferBindingProtector {
public:
BackendFramebufferBindingProtector(GLenum target);
~BackendFramebufferBindingProtector();
static GLuint GetTempFBO(FramebufferTarget target);
static void BindTempFBO(FramebufferTarget target);
private:
GLenum m_target;
GLint m_previousBinding = 0;
inline static GLuint s_tempReadFBO = 0;
inline static GLuint s_tempDrawFBO = 0;
};
} // namespace FramebufferImpl
namespace PrgramImpl { namespace PrgramImpl {
String ProcessOutColorLocations(const String& glslCode); String ProcessOutColorLocations(const String& glslCode);
@@ -574,6 +574,7 @@ namespace MobileGL {
return MapBuffer_State(target, access); return MapBuffer_State(target, access);
} }
// FIXME: this should be a "backend" function
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset,
GLsizeiptr size) { GLsizeiptr size) {
CopyBufferSubData_State(readTarget, writeTarget, readOffset, writeOffset, size); CopyBufferSubData_State(readTarget, writeTarget, readOffset, writeOffset, size);
@@ -151,7 +151,7 @@ DECLARE_GL_FUNCTION_HEAD(void, LineWidth, GLfloat width) DECLARE_GL_FUNCTION_END
DECLARE_GL_FUNCTION_HEAD(void, LinkProgram, GLuint program) DECLARE_GL_FUNCTION_END_NO_RETURN(void, LinkProgram, program) DECLARE_GL_FUNCTION_HEAD(void, LinkProgram, GLuint program) DECLARE_GL_FUNCTION_END_NO_RETURN(void, LinkProgram, program)
DECLARE_GL_FUNCTION_HEAD(void, PixelStorei, GLenum pname, GLint param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, PixelStorei, pname, param) DECLARE_GL_FUNCTION_HEAD(void, PixelStorei, GLenum pname, GLint param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, PixelStorei, pname, param)
DECLARE_GL_FUNCTION_HEAD(void, PolygonOffset, GLfloat factor, GLfloat units) DECLARE_GL_FUNCTION_END_NO_RETURN(void, PolygonOffset, factor, units) DECLARE_GL_FUNCTION_HEAD(void, PolygonOffset, GLfloat factor, GLfloat units) DECLARE_GL_FUNCTION_END_NO_RETURN(void, PolygonOffset, factor, units)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ReadPixels, x, y, width, height, format, type, pixels) DECLARE_GL_FUNCTION_HEAD(void, ReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ReadPixels, x, y, width, height, format, type, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ReleaseShaderCompiler) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ReleaseShaderCompiler) DECLARE_GL_FUNCTION_STUB_HEAD(void, ReleaseShaderCompiler) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ReleaseShaderCompiler)
DECLARE_GL_FUNCTION_HEAD(void, RenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, RenderbufferStorage, target, internalformat, width, height) DECLARE_GL_FUNCTION_HEAD(void, RenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, RenderbufferStorage, target, internalformat, width, height)
DECLARE_GL_FUNCTION_HEAD(void, SampleCoverage, GLfloat value, GLboolean invert) DECLARE_GL_FUNCTION_END_NO_RETURN(void, SampleCoverage, value, invert) DECLARE_GL_FUNCTION_HEAD(void, SampleCoverage, GLfloat value, GLboolean invert) DECLARE_GL_FUNCTION_END_NO_RETURN(void, SampleCoverage, value, invert)
@@ -385,15 +385,15 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetObjectLabel, GLenum identifier, GLuint na
DECLARE_GL_FUNCTION_STUB_HEAD(void, ObjectPtrLabel, const void* ptr, GLsizei length, const GLchar* label) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ObjectPtrLabel, ptr, length, label) DECLARE_GL_FUNCTION_STUB_HEAD(void, ObjectPtrLabel, const void* ptr, GLsizei length, const GLchar* label) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ObjectPtrLabel, ptr, length, label)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetObjectPtrLabel, const void* ptr, GLsizei bufSize, GLsizei* length, GLchar* label) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetObjectPtrLabel, ptr, bufSize, length, label) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetObjectPtrLabel, const void* ptr, GLsizei bufSize, GLsizei* length, GLchar* label) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetObjectPtrLabel, ptr, bufSize, length, label)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetPointerv, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetPointerv, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetPointerv, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetPointerv, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Enablei, GLenum target, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Enablei, target, index) DECLARE_GL_FUNCTION_HEAD(void, Enablei, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Enablei, target, index)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Disablei, GLenum target, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Disablei, target, index) DECLARE_GL_FUNCTION_HEAD(void, Disablei, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Disablei, target, index)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationi, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationi, buf, mode) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationi, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationi, buf, mode)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationiARB, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationi, buf, mode) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationiARB, GLuint buf, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationi, buf, mode)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationSeparatei, GLuint buf, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationSeparatei, buf, modeRGB, modeAlpha) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationSeparatei, GLuint buf, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationSeparatei, buf, modeRGB, modeAlpha)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationSeparateiARB, GLuint buf, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationSeparatei, buf, modeRGB, modeAlpha) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationSeparateiARB, GLuint buf, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationSeparatei, buf, modeRGB, modeAlpha)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFunci, GLuint buf, GLenum src, GLenum dst) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFunci, buf, src, dst) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFunci, GLuint buf, GLenum src, GLenum dst) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFunci, buf, src, dst)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFunciARB, GLuint buf, GLenum src, GLenum dst) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFunci, buf, src, dst) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFunciARB, GLuint buf, GLenum src, GLenum dst) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFunci, buf, src, dst)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFuncSeparatei, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha) DECLARE_GL_FUNCTION_HEAD(void, BlendFuncSeparatei, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFuncSeparateiARB, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendFuncSeparateiARB, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ColorMaski, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ColorMaski, index, r, g, b, a) DECLARE_GL_FUNCTION_STUB_HEAD(void, ColorMaski, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ColorMaski, index, r, g, b, a)
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsEnabledi, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END(GLboolean, IsEnabledi, target, index) DECLARE_GL_FUNCTION_HEAD(GLboolean, IsEnabledi, GLenum target, GLuint index) DECLARE_GL_FUNCTION_END(GLboolean, IsEnabledi, target, index)
@@ -9,6 +9,7 @@
#include "GL_Framebuffer.h" #include "GL_Framebuffer.h"
#include "Validators.h" #include "Validators.h"
#include "Config.h" #include "Config.h"
#include <MG_Util/Metrics/TextureMetrics.h>
#include <MG_Impl/GLImpl/Texture/Validators.h> #include <MG_Impl/GLImpl/Texture/Validators.h>
#include <MG_State/GLState/ErrorState/Error.h> #include <MG_State/GLState/ErrorState/Error.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h> #include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
@@ -304,6 +305,25 @@ namespace MobileGL {
} }
} }
void ReadBuffer_State(GLenum mode) {
auto attType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(mode);
// ------------------- Check validity begin ------------------------
if (attType == FramebufferAttachmentType::Unknown) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__,
std::format("`mode` = {} is not an accepted value.", MG_Util::ConvertGLEnumToString(mode))));
return;
}
// Get bound framebuffer
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
auto fbo = bindingSlot.GetBoundObject();
fbo->SetReadBuffer(attType);
}
void DeleteRenderbuffers_State(GLsizei n, const GLuint* renderbuffers) { void DeleteRenderbuffers_State(GLsizei n, const GLuint* renderbuffers) {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
@@ -488,7 +508,142 @@ namespace MobileGL {
#endif #endif
} }
void ReadPixels_State(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
void* pixels) {
TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format);
TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
// Check width/height
if (width < 0 || height < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Width and height must be non-negative"));
return;
}
// Validate format
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid format"));
return;
}
// Validate type
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid pixel data type"));
return;
}
// Get bound framebuffer
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
auto framebufferObject = bindingSlot.GetBoundObject();
if (!framebufferObject) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No framebuffer bound to read target"));
return;
}
// Check framebuffer completeness
if (!framebufferObject->CheckCompleteness()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidFramebufferOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Framebuffer is incomplete"));
return;
}
// Check for required buffers
if (textureInputFormat == TextureInputFormat::StencilIndex) {
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No stencil buffer for stencil index format"));
return;
}
} else if (textureInputFormat == TextureInputFormat::DepthComponent) {
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Depth).IsValid()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No depth buffer for depth component format"));
return;
}
} else if (textureInputFormat == TextureInputFormat::DepthStencil) {
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Depth).IsValid() ||
!framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No depth/stencil buffer for depth-stencil format"));
return;
}
// Validate type for depth/stencil
if (texturePixelDataType != TexturePixelDataType::UnsignedInt248 &&
texturePixelDataType != TexturePixelDataType::Float32UnsignedInt248Rev) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Invalid type for depth-stencil format"));
return;
}
}
// Check PBO state
const auto& pixelPackBufferObject =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
if (pixelPackBufferObject) {
// Check if PBO is mapped
if (pixelPackBufferObject->IsMapped()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Pixel pack buffer is currently mapped"));
return;
}
// Check alignment
const SizeT typeSize = MG_Util::GetTexturePixelDataTypeSize(texturePixelDataType);
if (reinterpret_cast<uintptr_t>(pixels) % typeSize != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Pixel data not aligned for pixel pack buffer"));
return;
}
}
// Check multisampling
if (framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).IsRenderbuffer()) {
auto rbo = framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).GetRenderbuffer();
if (rbo && rbo->GetSamples() > 1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"ReadPixels not supported for multisampled framebuffers"));
return;
}
}
}
void ReadPixels_Backend(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
void* pixels) {
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
MG_Backend::DirectGLES::ReadPixels(x, y, width, height, format, type, pixels);
#endif
}
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */ /* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
ReadPixels_State(x, y, width, height, format, type, pixels);
ReadPixels_Backend(x, y, width, height, format, type, pixels);
}
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
ClearBufferfi_Backend(buffer, drawbuffer, depth, stencil); ClearBufferfi_Backend(buffer, drawbuffer, depth, stencil);
} }
@@ -575,6 +730,10 @@ namespace MobileGL {
DrawBuffers_State(n, bufs); DrawBuffers_State(n, bufs);
} }
void ReadBuffer(GLenum src) {
ReadBuffer_State(src);
}
void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) { void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) {
DeleteRenderbuffers_State(n, renderbuffers); DeleteRenderbuffers_State(n, renderbuffers);
} }
@@ -14,6 +14,7 @@
namespace MobileGL { namespace MobileGL {
namespace MG_Impl::GLImpl { namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */ /* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value); void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value); void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
@@ -46,6 +47,7 @@ namespace MobileGL {
void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
void DrawBuffer(GLenum buf); void DrawBuffer(GLenum buf);
void DrawBuffers(GLsizei n, const GLenum* bufs); void DrawBuffers(GLsizei n, const GLenum* bufs);
void ReadBuffer(GLenum src);
void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers); void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers); void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
GLenum CheckFramebufferStatus(GLenum target); GLenum CheckFramebufferStatus(GLenum target);
+2 -2
View File
@@ -567,7 +567,7 @@ namespace MobileGL {
*params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::PackImageHeight); *params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::PackImageHeight);
break; break;
case GL_PACK_LSB_FIRST: case GL_PACK_LSB_FIRST:
*params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::PackLsbFirst); *params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::PackLSBFirst);
break; break;
case GL_PACK_ROW_LENGTH: case GL_PACK_ROW_LENGTH:
*params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::PackRowLength); *params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::PackRowLength);
@@ -839,7 +839,7 @@ namespace MobileGL {
*params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackImageHeight); *params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackImageHeight);
break; break;
case GL_UNPACK_LSB_FIRST: case GL_UNPACK_LSB_FIRST:
*params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackLsbFirst); *params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackLSBFirst);
break; break;
case GL_UNPACK_ROW_LENGTH: case GL_UNPACK_ROW_LENGTH:
*params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackRowLength); *params = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackRowLength);
@@ -111,15 +111,34 @@ namespace MobileGL {
} }
GLboolean IsEnabledi_State(GLenum target, GLuint index) { GLboolean IsEnabledi_State(GLenum target, GLuint index) {
// TODO: implement CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
if (capInput == CapabilityInput::Unknown) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "IsEnabledi_State",
"Capability enum " +
MG_Util::ConvertCapabilityInputToString(capInput) + "(" +
MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
return GL_FALSE; return GL_FALSE;
} }
return MG_State::pGLContext->IsCapabilityEnabledIndexed(capInput, index) ? GL_TRUE : GL_FALSE;
}
GLboolean IsEnabled_State(GLenum cap) { GLboolean IsEnabled_State(GLenum cap) {
// TODO: implement CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
if (capInput == CapabilityInput::Unknown) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>(
"MG_Impl/GLImpl", "IsEnabled_State",
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
return GL_FALSE; return GL_FALSE;
} }
return MG_State::pGLContext->IsCapabilityEnabled(capInput) ? GL_TRUE : GL_FALSE;
}
void Hint_State(GLenum target, GLenum mode) { void Hint_State(GLenum target, GLenum mode) {
// TODO: implement // TODO: implement
} }
@@ -241,10 +260,6 @@ namespace MobileGL {
// TODO: implement // TODO: implement
} }
void ReadBuffer_State(GLenum src) {
// TODO: implement
}
void ClearStencil_State(GLint s) { void ClearStencil_State(GLint s) {
// TODO: implement // TODO: implement
} }
@@ -257,7 +272,67 @@ namespace MobileGL {
MG_State::pGLContext->SetClearColor(FloatVec4(red, green, blue, alpha)); MG_State::pGLContext->SetClearColor(FloatVec4(red, green, blue, alpha));
} }
void BlendFuncSeparatei_State(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
if (buf >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>(
"MG_Impl/GLImpl", "BlendFuncSeparatei_State",
"Buffer index " + std::to_string(buf) + " is out of range. Max supported is " +
std::to_string(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS - 1) + "."));
return;
}
BlendFactor srcRGBM = MG_Util::ConvertGLEnumToBlendFactor(srcRGB);
BlendFactor dstRGBM = MG_Util::ConvertGLEnumToBlendFactor(dstRGB);
BlendFactor srcAlphaM = MG_Util::ConvertGLEnumToBlendFactor(srcAlpha);
BlendFactor dstAlphaM = MG_Util::ConvertGLEnumToBlendFactor(dstAlpha);
MG_State::pGLContext->SetBlendFuncIndexed(buf, srcRGBM, dstRGBM, srcAlphaM, dstAlphaM);
}
void Disablei_State(GLenum target, GLuint index) {
auto capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
if (capInput == CapabilityInput::Unknown) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Disablei_State",
"Capability enum " +
MG_Util::ConvertCapabilityInputToString(capInput) + "(" +
MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
return;
}
MG_State::pGLContext->SetCapabilityIndexed(capInput, index, false);
}
void Enablei_State(GLenum target, GLuint index) {
auto capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
if (capInput == CapabilityInput::Unknown) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Enablei_State",
"Capability enum " +
MG_Util::ConvertCapabilityInputToString(capInput) + "(" +
MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
return;
}
MG_State::pGLContext->SetCapabilityIndexed(capInput, index, true);
}
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */ /* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
BlendFuncSeparatei_State(buf, srcRGB, dstRGB, srcAlpha, dstAlpha);
}
void Disablei(GLenum target, GLuint index) {
Disablei_State(target, index);
}
void Enablei(GLenum target, GLuint index) {
Enablei_State(target, index);
}
void BlendFunc(GLenum sfactor, GLenum dfactor) { void BlendFunc(GLenum sfactor, GLenum dfactor) {
BlendFunc_State(sfactor, dfactor); BlendFunc_State(sfactor, dfactor);
} }
@@ -390,10 +465,6 @@ namespace MobileGL {
BlendColor_State(red, green, blue, alpha); BlendColor_State(red, green, blue, alpha);
} }
void ReadBuffer(GLenum src) {
ReadBuffer_State(src);
}
void ClearStencil(GLint s) { void ClearStencil(GLint s) {
ClearStencil_State(s); ClearStencil_State(s);
} }
@@ -12,6 +12,9 @@
namespace MobileGL { namespace MobileGL {
namespace MG_Impl::GLImpl { namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */ /* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
void Disablei(GLenum target, GLuint index);
void Enablei(GLenum target, GLuint index);
void BlendFunc(GLenum sfactor, GLenum dfactor); void BlendFunc(GLenum sfactor, GLenum dfactor);
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height); void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
@@ -45,7 +48,6 @@ namespace MobileGL {
void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
void BlendEquation(GLenum mode); void BlendEquation(GLenum mode);
void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
void ReadBuffer(GLenum src);
void ClearStencil(GLint s); void ClearStencil(GLint s);
void ClearDepth(GLclampd depth); void ClearDepth(GLclampd depth);
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+189 -22
View File
@@ -7,26 +7,27 @@
// End of Source File Header // End of Source File Header
#include "GL_Texture.h" #include "GL_Texture.h"
#include "GL/gl.h"
#include "Config.h" #include "Config.h"
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
#include <MG_Backend/DirectGLES/DirectGLES.h>
#endif
#include "MG_Util/Types.h" #include "MG_Util/Types.h"
#include "Validators.h" #include "Validators.h"
#include "ProxyTexture.h" #include "ProxyTexture.h"
#include "MG_State/GLState/TextureState/TextureObjectBuffer.h"
#include "MG_Util/Converters/GLToStr/GLEnumConverter.h"
#include "MG_Util/Texture/TextureFormatProcessor.h"
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
#include <MG_Util/Metrics/TextureMetrics.h> #include <MG_Util/Metrics/TextureMetrics.h>
#include <MG_State/GLState/ErrorState/Error.h> #include <MG_State/GLState/ErrorState/Error.h>
#include <MG_Util/Texture/PixelStoreProcessor.h> #include <MG_Util/Texture/PixelStoreProcessor.h>
#include <MG_Util/Texture/TextureFormatProcessor.h>
#include <MG_Util/Classifiers/TextureEnumClassifier.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h> #include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h> #include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h> #include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h> #include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
#include <MG_State/GLState/TextureState/TextureObjectBuffer.h>
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
#include <MG_Backend/DirectGLES/DirectGLES.h>
#endif
namespace MobileGL { namespace MobileGL {
namespace MG_Impl::GLImpl { namespace MG_Impl::GLImpl {
@@ -714,9 +715,6 @@ namespace MobileGL {
MGLOG_D("%s: Allocating %d bytes at mip %d", __func__, internalBytes, level); MGLOG_D("%s: Allocating %d bytes at mip %d", __func__, internalBytes, level);
textureMipmapObject->AllocateStorage(textureUploadingTarget, level, {{width, height, 1}, internalBytes}); textureMipmapObject->AllocateStorage(textureUploadingTarget, level, {{width, height, 1}, internalBytes});
MGLOG_D("%s: mark mip %d as dirty", __func__, level);
textureMipmapObject->MarkStorageDirty(textureUploadingTarget, level, true);
if (!originalPixels) { if (!originalPixels) {
MGLOG_D("%s: No input pixel and no PBO bound, no pixel transfer", __func__); MGLOG_D("%s: No input pixel and no PBO bound, no pixel transfer", __func__);
return; return;
@@ -740,6 +738,9 @@ namespace MobileGL {
} }
free(processedPixels); free(processedPixels);
MGLOG_D("%s: mark mip %d as dirty", __func__, level);
textureMipmapObject->MarkStorageDirty(textureUploadingTarget, level, true);
} }
void TexImage1D_State(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, void TexImage1D_State(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border,
@@ -1163,10 +1164,6 @@ namespace MobileGL {
} }
} }
void GetTexImage_State(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
// TODO: implement
}
void GetCompressedTexImage_State(GLenum target, GLint level, void* img) { void GetCompressedTexImage_State(GLenum target, GLint level, void* img) {
// TODO: implement // TODO: implement
} }
@@ -1228,12 +1225,57 @@ namespace MobileGL {
void CopyTexImage2D_State(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, void CopyTexImage2D_State(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
GLsizei height, GLint border) { GLsizei height, GLint border) {
GLenum outInternalFormat, format, type; auto internalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
MG_Util::TextureFormatProcessor::NormalizePixelFormat(internalformat, 0, &outInternalFormat, &format, const auto& currentReadFBO =
&type); MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
if (!currentReadFBO) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>(
"MG_Impl/GLImpl", "CopyTexImage2D_State",
"No framebuffer is currently bound to the GL_READ_FRAMEBUFFER target."));
return;
}
Bool isDepth = MG_Util::IsDepthFormatInternalFormat(internalFormat);
Bool isStencil = MG_Util::IsStencilFormatInternalFormat(internalFormat);
TextureInternalFormat srcInternalFormat = TextureInternalFormat::Unknown;
#define GET_SRC_INTERNAL_FORMAT(AttachmentType) \
const auto& srcAttachment = currentReadFBO->GetAttachment(AttachmentType); \
if (srcAttachment.IsTexture()) { \
const auto& texObj = srcAttachment.GetTexture(); \
srcInternalFormat = texObj->GetFormat(); \
} else if (srcAttachment.IsRenderbuffer()) { \
const auto& rboObj = srcAttachment.GetRenderbuffer(); \
srcInternalFormat = rboObj->GetInternalFormat(); \
} else { \
MG_State::pGLContext->RecordError( \
ErrorCode::InvalidOperation, \
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "CopyTexImage2D_State", \
"The attachment specified by the read buffer is incomplete.")); \
return; \
}
if (isDepth) {
GET_SRC_INTERNAL_FORMAT(FramebufferAttachmentType::Depth);
} else if (isStencil) {
GET_SRC_INTERNAL_FORMAT(FramebufferAttachmentType::Stencil);
} else {
const auto& readBufferType = currentReadFBO->GetReadBuffer();
GET_SRC_INTERNAL_FORMAT(readBufferType);
}
if (!TextureImpl::ValidateBaseInternalFormatMatch(internalFormat, srcInternalFormat))
THROW_UNIMPL_EXCEPTION;
GLenum outInternalFormat = MG_Util::ConvertTextureInternalFormatToGLEnum(srcInternalFormat);
GLenum realInternalFormat = GL_RGBA8;
GLenum format = GL_DEPTH_COMPONENT;
GLenum type = GL_UNSIGNED_INT;
MG_Util::TextureFormatProcessor::NormalizePixelFormat(
outInternalFormat, PixelFormatNormalizeOptionBit::None, &realInternalFormat, &format, &type);
const auto pixelUnpackBufferObject = const auto pixelUnpackBufferObject =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelUnpack).GetBoundObject(); MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelUnpack).GetBoundObject();
TexImage2D_State(target, level, outInternalFormat, width, height, border, format, type, nullptr); TexImage2D_State(target, level, realInternalFormat, width, height, border, format, type, nullptr);
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelUnpack).Bind(pixelUnpackBufferObject); MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelUnpack).Bind(pixelUnpackBufferObject);
} }
@@ -1332,7 +1374,136 @@ namespace MobileGL {
MG_State::pGLContext->SetActiveTextureUnit(texture - GL_TEXTURE0); MG_State::pGLContext->SetActiveTextureUnit(texture - GL_TEXTURE0);
} }
void GetTexImage_Backend(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
MG_Backend::DirectGLES::GetTexImage(target, level, format, type, pixels);
#endif
}
// Add to GL_Texture.cpp
void GetTexImage_State(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
// ======================= Converting ================================
TextureUploadTarget textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format);
TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
// ===================== Error Checking ==============================
// Validate target
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Invalid texture target"));
return;
}
// Validate level
if (level < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Level must be non-negative"));
return;
}
// Validate format
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Invalid format"));
return;
}
// Validate type
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Invalid pixel data type"));
return;
}
// Get texture object
SharedPtr<MG_State::GLState::ITextureObject> textureObject = nullptr;
if (TextureImpl::IsProxyTextureTarget(textureUploadTarget)) {
textureObject = TextureImpl::pProxyTextureManager->GetProxyTextureObject(textureUploadTarget);
} else {
auto activeUnit =
MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
auto& bindingSlot = activeUnit.GetBindingSlot(textureTarget);
textureObject = bindingSlot.GetBoundObject();
}
if (!TextureImpl::ValidateTextureObject(textureObject)) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"No valid texture bound to target"));
return;
}
// Check texture completeness
if (!textureObject->IsComplete()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Texture is incomplete"));
return;
}
// Check PBO state
const auto& pixelPackBufferObject =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
if (pixelPackBufferObject) {
// Check if PBO is mapped
if (pixelPackBufferObject->IsMapped()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"Pixel pack buffer is currently mapped"));
return;
}
// Check alignment
const SizeT typeSize = MG_Util::GetTexturePixelDataTypeSize(texturePixelDataType);
if (reinterpret_cast<uintptr_t>(pixels) % typeSize != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"Pixel data not aligned for pixel pack buffer"));
return;
}
}
// Special case for depth/stencil
if (textureInputFormat == TextureInputFormat::StencilIndex) {
if (textureObject->GetFormat() != TextureInternalFormat::DepthStencil &&
textureObject->GetFormat() != TextureInternalFormat::Depth24Stencil8 &&
textureObject->GetFormat() != TextureInternalFormat::Depth32FStencil8) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"No stencil buffer for stencil index format"));
return;
}
}
// Check for multisampling
if (textureObject->GetStorageType() == TextureStorageType::Mipmap) {
auto mipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
if (mipmapObject->GetMipmapLevelCount() > 1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"Multisampled textures not supported for GetTexImage"));
return;
}
}
}
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */ /* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
GetTexImage_State(target, level, format, type, pixels);
GetTexImage_Backend(target, level, format, type, pixels);
}
void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) { GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) {
TexSubImage3D_State(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); TexSubImage3D_State(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
@@ -1429,10 +1600,6 @@ namespace MobileGL {
GetTexLevelParameterfv_State(target, level, pname, params); GetTexLevelParameterfv_State(target, level, pname, params);
} }
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
GetTexImage_State(target, level, format, type, pixels);
}
void GetCompressedTexImage(GLenum target, GLint level, void* img) { void GetCompressedTexImage(GLenum target, GLint level, void* img) {
GetCompressedTexImage_State(target, level, img); GetCompressedTexImage_State(target, level, img);
} }
+1 -1
View File
@@ -12,6 +12,7 @@
namespace MobileGL { namespace MobileGL {
namespace MG_Impl::GLImpl { namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */ /* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels);
void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
@@ -43,7 +44,6 @@ namespace MobileGL {
void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params); void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params);
void GetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint* params); void GetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint* params);
void GetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat* params); void GetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat* params);
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
void GetCompressedTexImage(GLenum target, GLint level, void* img); void GetCompressedTexImage(GLenum target, GLint level, void* img);
void GenTextures(GLsizei n, GLuint* textures); void GenTextures(GLsizei n, GLuint* textures);
void DeleteTextures(GLsizei n, const GLuint* textures); void DeleteTextures(GLsizei n, const GLuint* textures);
+18 -2
View File
@@ -7,13 +7,12 @@
// End of Source File Header // End of Source File Header
#include "Validators.h" #include "Validators.h"
#include "MG_State/GLState/TextureState/TextureObject.h"
#include "MG_Util/Types.h"
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
#include <MG_State/GLState/ErrorState/Error.h> #include <MG_State/GLState/ErrorState/Error.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h> #include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h> #include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h> #include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h> #include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl {
@@ -170,6 +169,7 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
return true; return true;
} }
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format, Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
TextureInternalFormat internalFormat, TextureInternalFormat internalFormat,
TexturePixelDataType type) { TexturePixelDataType type) {
@@ -303,5 +303,21 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
return true; return true;
} }
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2) {
auto unsizedFormat1 = MG_Util::ConvertInternalFormatToUnsized(format1);
auto unsizedFormat2 = MG_Util::ConvertInternalFormatToUnsized(format2);
if (unsizedFormat1 != unsizedFormat2) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>(
std::format("MG_Impl/GLImpl", "ValidateBaseInternalFormatMatch",
"The base internal format of the two formats do not match ({} vs. {})",
MG_Util::ConvertTextureInternalFormatToString(unsizedFormat1).c_str(),
MG_Util::ConvertTextureInternalFormatToString(unsizedFormat2).c_str())));
return false;
}
return true;
} // namespace TextureImpl
} // namespace TextureImpl } // namespace TextureImpl
} // namespace MobileGL::MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
@@ -7,6 +7,7 @@
// End of Source File Header // End of Source File Header
#pragma once #pragma once
#include "MG_State/GLState/TextureState/TextureEnum.h"
#include "MG_Util/Types.h" #include "MG_Util/Types.h"
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/TextureState/TextureObject.h> #include <MG_State/GLState/TextureState/TextureObject.h>
@@ -32,5 +33,6 @@ namespace MobileGL::MG_Impl::GLImpl {
TextureTarget target); TextureTarget target);
Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset, Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset,
Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0); Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0);
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2);
} // namespace TextureImpl } // namespace TextureImpl
} // namespace MobileGL::MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
@@ -14,14 +14,18 @@ namespace MobileGL {
namespace GLState { namespace GLState {
BufferObject::BufferObject(Uint externalIndex) BufferObject::BufferObject(Uint externalIndex)
: m_externalIndex(externalIndex), m_size(0), m_usage(BufferUsage::StaticDraw), m_isMapped(false), : m_externalIndex(externalIndex), m_size(0), m_usage(BufferUsage::StaticDraw), m_isMapped(false),
m_mappingAccess(BufferMappingAccessBit::Null), m_dirtyRange({0, 0}), m_mappedRange({0, 0}), m_mappingAccess(BufferMappingAccessBit::Null),
m_dataPtr(MakeShared<Data>()) {} m_change(BufferChangeBits::DirtyBit | BufferChangeBits::PreferReallocationBit), m_mappedRange({0, 0}),
m_dataPtr(MakeShared<Data>()) {
m_change.DirtyRanges.reserve(BufferChange::DEFAULT_RESERVED_DIRTY_RANGES_COUNT);
}
void BufferObject::Resize(SizeT size) { void BufferObject::Resize(SizeT size) {
m_size = size; m_size = size;
m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve
m_dataPtr->resize(size); m_dataPtr->resize(size);
m_dirtyRange = {0, 0}; m_change.Bits |= BufferChangeBits::DirtyBit;
m_change.Bits |= BufferChangeBits::PreferReallocationBit;
} }
void BufferObject::UploadData(DataPtr data, SizeT atOffset) { void BufferObject::UploadData(DataPtr data, SizeT atOffset) {
@@ -30,7 +34,14 @@ namespace MobileGL {
data.size, m_size); data.size, m_size);
MOBILEGL_ASSERT(!m_isMapped, "Cannot upload data while buffer is mapped."); MOBILEGL_ASSERT(!m_isMapped, "Cannot upload data while buffer is mapped.");
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size); Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
m_dirtyRange.UnionUpdate(atOffset, atOffset + data.size); m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
m_change.Bits |= BufferChangeBits::DirtyBit;
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
// This function may be called by `glBufferData`, but we still set the forbid bits above,
// because when `PreferReallocationBit` is set, those bits are ignored anyway.
// The bits can fit the `glBufferSubData` semantics
// (though `glBufferSubData` calls `UploadSubData` instead).
} }
void BufferObject::SetUsage(BufferUsage usage) { void BufferObject::SetUsage(BufferUsage usage) {
@@ -44,7 +55,8 @@ namespace MobileGL {
if (!(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly if (!(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly
Memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(), Memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(),
m_mappedRange.end - m_mappedRange.start); m_mappedRange.end - m_mappedRange.start);
m_dirtyRange.UnionUpdate(m_mappedRange.start, m_mappedRange.end); m_change.DirtyRanges.Add({m_mappedRange.start, m_mappedRange.end});
m_change.Bits |= BufferChangeBits::DirtyBit;
} }
m_stagingData.clear(); m_stagingData.clear();
@@ -69,7 +81,8 @@ namespace MobileGL {
"Flush range out of bounds: mappedRange.end (%zu) < end (%zu)", m_mappedRange.end, end); "Flush range out of bounds: mappedRange.end (%zu) < end (%zu)", m_mappedRange.end, end);
Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length); Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length);
m_dirtyRange.UnionUpdate(start, end); m_change.DirtyRanges.Add({start, end});
m_change.Bits |= BufferChangeBits::DirtyBit;
} }
void BufferObject::UploadSubData(DataPtr data, SizeT atOffset) { void BufferObject::UploadSubData(DataPtr data, SizeT atOffset) {
@@ -79,7 +92,10 @@ namespace MobileGL {
atOffset, data.size, m_size); atOffset, data.size, m_size);
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size); Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
m_dirtyRange.UnionUpdate(atOffset, atOffset + data.size); m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
m_change.Bits |= BufferChangeBits::DirtyBit;
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
} }
void BufferObject::CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, void BufferObject::CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset,
@@ -95,7 +111,8 @@ namespace MobileGL {
const Uint8* srcData = src->m_dataPtr->data() + srcOffset; const Uint8* srcData = src->m_dataPtr->data() + srcOffset;
Memcpy(m_dataPtr->data() + dstOffset, srcData, size); Memcpy(m_dataPtr->data() + dstOffset, srcData, size);
m_dirtyRange.UnionUpdate(dstOffset, dstOffset + size); m_change.DirtyRanges.Add({dstOffset, dstOffset + size});
m_change.Bits |= BufferChangeBits::DirtyBit;
} }
void* BufferObject::AcquireMemory(Bool markMapped, Bool read, Bool write) { void* BufferObject::AcquireMemory(Bool markMapped, Bool read, Bool write) {
@@ -144,6 +161,14 @@ namespace MobileGL {
m_ownsStagingData = false; m_ownsStagingData = false;
return m_dataPtr->data() + range.start; return m_dataPtr->data() + range.start;
} }
m_change.Bits |= !(access & BufferMappingAccessBit::InvalidateBuffer ||
access & BufferMappingAccessBit::InvalidateRange)
? BufferChangeBits::ForbidInvalidationBit
: BufferChangeBits::None;
m_change.Bits |= !(access & BufferMappingAccessBit::Unsynchronized)
? BufferChangeBits::ForbidUnsynchronizationBit
: BufferChangeBits::None;
} }
const SharedPtr<Data> BufferObject::GetDataReadOnly() const { const SharedPtr<Data> BufferObject::GetDataReadOnly() const {
@@ -151,7 +176,8 @@ namespace MobileGL {
} }
void BufferObject::ClearDirty() { void BufferObject::ClearDirty() {
m_dirtyRange = {0, 0}; m_change.DirtyRanges.clear();
m_change.Bits = BufferChangeBits::None;
} }
SizeT BufferObject::GetSize() const { SizeT BufferObject::GetSize() const {
@@ -162,8 +188,12 @@ namespace MobileGL {
return m_usage; return m_usage;
} }
Range1D BufferObject::GetDirtyRange() const { const VecRange1D& BufferObject::GetDirtyRanges() const {
return m_dirtyRange; return m_change.DirtyRanges;
}
Flags<BufferChangeBits> BufferObject::GetChangeBits() const {
return m_change.Bits;
} }
Bool BufferObject::IsMapped() const { Bool BufferObject::IsMapped() const {
@@ -9,6 +9,7 @@
#pragma once #pragma once
#include "MG_Util/Types.h" #include "MG_Util/Types.h"
#include <Includes.h> #include <Includes.h>
#include <MG_Util/Math/VectorTypes.h>
namespace MobileGL { namespace MobileGL {
enum class BufferTarget { enum class BufferTarget {
@@ -55,6 +56,23 @@ namespace MobileGL {
Coherent = 0x80 Coherent = 0x80
}; };
enum class BufferChangeBits : Uint8 {
None = 0,
DirtyBit = 1 << 0, // When not set, bits below are ignored and nothing should be synced to backend
PreferReallocationBit =
1 << 1, // <=> `glBufferData`; When set, ForbidInvalidationBit and ForbidUnsynchronizationBit are ignored
ForbidInvalidationBit = 1 << 2, // Indidate that invalidation flags were not used during mapping, else we're
// allowed to act as `GL_MAP_INVALIDATE_*` in backend
ForbidUnsynchronizationBit = 1 << 3, // (the same description as above, but for unsynchronization)
};
struct BufferChange {
static constexpr int DEFAULT_RESERVED_DIRTY_RANGES_COUNT = 50;
Flags<BufferChangeBits> Bits = BufferChangeBits::None;
VecRange1D DirtyRanges;
};
namespace MG_State { namespace MG_State {
namespace GLState { namespace GLState {
class BufferObject { class BufferObject {
@@ -77,11 +95,12 @@ namespace MobileGL {
Bool IsMapped() const; Bool IsMapped() const;
SizeT GetSize() const; SizeT GetSize() const;
BufferUsage GetUsage() const; BufferUsage GetUsage() const;
Range1D GetDirtyRange() const;
Range1D GetMappedRange() const; Range1D GetMappedRange() const;
const SharedPtr<Data> GetDataReadOnly() const; const SharedPtr<Data> GetDataReadOnly() const;
Flags<BufferMappingAccessBit> GetMappingAccess() const; Flags<BufferMappingAccessBit> GetMappingAccess() const;
Uint GetExternalIndex() const; Uint GetExternalIndex() const;
const VecRange1D& GetDirtyRanges() const;
Flags<BufferChangeBits> GetChangeBits() const;
private: private:
const Uint m_externalIndex = 0; const Uint m_externalIndex = 0;
@@ -90,7 +109,7 @@ namespace MobileGL {
SharedPtr<Data> m_dataPtr; SharedPtr<Data> m_dataPtr;
Bool m_isMapped; Bool m_isMapped;
Flags<BufferMappingAccessBit> m_mappingAccess; Flags<BufferMappingAccessBit> m_mappingAccess;
Range1D m_dirtyRange; BufferChange m_change;
Range1D m_mappedRange; Range1D m_mappedRange;
Vector<Uint8> m_stagingData; Vector<Uint8> m_stagingData;
Bool m_ownsStagingData; Bool m_ownsStagingData;
+26
View File
@@ -220,6 +220,14 @@ namespace MobileGL {
} }
// RenderState // RenderState
Uint GLContext::GetRenderStateParametersVersion() const {
return m_renderState.GetVersion();
}
const RenderStateParameters& GLContext::GetRenderStateParameters() const {
return m_renderState.GetAllParameters();
}
void GLContext::SetViewport(IntVec4 viewport) { void GLContext::SetViewport(IntVec4 viewport) {
m_renderState.SetViewport(viewport); m_renderState.SetViewport(viewport);
} }
@@ -236,6 +244,14 @@ namespace MobileGL {
return m_renderState.IsCapabilityEnabled(cap); return m_renderState.IsCapabilityEnabled(cap);
} }
void GLContext::SetCapabilityIndexed(CapabilityInput cap, Uint index, Bool enabled) {
m_renderState.SetCapabilityIndexed(cap, index, enabled);
}
Bool GLContext::IsCapabilityEnabledIndexed(CapabilityInput cap, Uint index) const {
return m_renderState.IsCapabilityEnabledIndexed(cap, index);
}
void GLContext::SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, void GLContext::SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha,
BlendFactor dstAlpha) { BlendFactor dstAlpha) {
m_renderState.SetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); m_renderState.SetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
@@ -246,6 +262,16 @@ namespace MobileGL {
m_renderState.GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); m_renderState.GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
} }
void GLContext::SetBlendFuncIndexed(Uint index, BlendFactor srcRGB, BlendFactor dstRGB,
BlendFactor srcAlpha, BlendFactor dstAlpha) {
m_renderState.SetBlendFuncIndexed(index, srcRGB, dstRGB, srcAlpha, dstAlpha);
}
void GLContext::GetBlendFuncIndexed(Uint index, BlendFactor& srcRGB, BlendFactor& dstRGB,
BlendFactor& srcAlpha, BlendFactor& dstAlpha) const {
m_renderState.GetBlendFuncIndexed(index, srcRGB, dstRGB, srcAlpha, dstAlpha);
}
void GLContext::SetDepthFunc(DepthTestFunc func) { void GLContext::SetDepthFunc(DepthTestFunc func) {
m_renderState.SetDepthFunc(func); m_renderState.SetDepthFunc(func);
} }
+8
View File
@@ -86,13 +86,21 @@ namespace MobileGL {
SharedPtr<ProgramObject> GetCurrentProgram(); SharedPtr<ProgramObject> GetCurrentProgram();
// RenderState // RenderState
Uint GetRenderStateParametersVersion() const;
const RenderStateParameters& GetRenderStateParameters() const;
void SetViewport(IntVec4 viewport); // x, y, width, height void SetViewport(IntVec4 viewport); // x, y, width, height
const IntVec4& GetViewport() const; // x, y, width, height const IntVec4& GetViewport() const; // x, y, width, height
void SetCapability(CapabilityInput cap, Bool enabled); void SetCapability(CapabilityInput cap, Bool enabled);
Bool IsCapabilityEnabled(CapabilityInput cap) const; Bool IsCapabilityEnabled(CapabilityInput cap) const;
void SetCapabilityIndexed(CapabilityInput cap, Uint index, Bool enabled);
Bool IsCapabilityEnabledIndexed(CapabilityInput cap, Uint index) const;
void SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, BlendFactor dstAlpha); void SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, BlendFactor dstAlpha);
void GetBlendFunc(BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha, void GetBlendFunc(BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
BlendFactor& dstAlpha) const; BlendFactor& dstAlpha) const;
void SetBlendFuncIndexed(Uint index, BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha,
BlendFactor dstAlpha);
void GetBlendFuncIndexed(Uint index, BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
BlendFactor& dstAlpha) const;
void SetDepthFunc(DepthTestFunc func); void SetDepthFunc(DepthTestFunc func);
DepthTestFunc GetDepthFunc() const; DepthTestFunc GetDepthFunc() const;
void SetDepthMask(Bool flag); void SetDepthMask(Bool flag);
@@ -12,41 +12,41 @@
namespace MobileGL { namespace MobileGL {
namespace MG_State { namespace MG_State {
namespace GLState { namespace GLState {
// FramebufferAttachment // FramebufferAttachmentObject
FramebufferAttachment::FramebufferAttachment(SharedPtr<MG_State::GLState::ITextureObject> texture, FramebufferAttachmentObject::FramebufferAttachmentObject(SharedPtr<MG_State::GLState::ITextureObject> texture,
Int level) Int level)
: m_texture(texture), m_textureLevel(level) {} : m_texture(texture), m_textureLevel(level) {}
FramebufferAttachment::FramebufferAttachment(SharedPtr<RenderbufferObject> renderbuffer) FramebufferAttachmentObject::FramebufferAttachmentObject(SharedPtr<RenderbufferObject> renderbuffer)
: m_renderbuffer(renderbuffer) {} : m_renderbuffer(renderbuffer) {}
FramebufferAttachment::FramebufferAttachment(Bool IsValid) : m_texture(nullptr), m_renderbuffer(nullptr) { FramebufferAttachmentObject::FramebufferAttachmentObject(Bool IsValid) : m_texture(nullptr), m_renderbuffer(nullptr) {
m_isValid = IsValid; m_isValid = IsValid;
} }
Bool FramebufferAttachment::IsTexture() const { Bool FramebufferAttachmentObject::IsTexture() const {
return m_texture != nullptr; return m_texture != nullptr;
} }
Bool FramebufferAttachment::IsRenderbuffer() const { Bool FramebufferAttachmentObject::IsRenderbuffer() const {
return m_renderbuffer != nullptr; return m_renderbuffer != nullptr;
} }
Bool FramebufferAttachment::IsEmpty() const { Bool FramebufferAttachmentObject::IsEmpty() const {
return m_texture == nullptr && m_renderbuffer == nullptr; return m_texture == nullptr && m_renderbuffer == nullptr;
} }
SharedPtr<MG_State::GLState::ITextureObject> FramebufferAttachment::GetTexture() const { SharedPtr<MG_State::GLState::ITextureObject> FramebufferAttachmentObject::GetTexture() const {
return m_texture; return m_texture;
} }
SharedPtr<RenderbufferObject> FramebufferAttachment::GetRenderbuffer() const { SharedPtr<RenderbufferObject> FramebufferAttachmentObject::GetRenderbuffer() const {
return m_renderbuffer; return m_renderbuffer;
} }
Int FramebufferAttachment::GetTextureLevel() const { Int FramebufferAttachmentObject::GetTextureLevel() const {
return m_textureLevel; return m_textureLevel;
} }
Bool FramebufferAttachment::IsComplete() const { Bool FramebufferAttachmentObject::IsComplete() const {
if (IsTexture()) { if (IsTexture()) {
Bool complete = m_texture->IsComplete(); Bool complete = m_texture->IsComplete();
return complete; return complete;
@@ -58,7 +58,7 @@ namespace MobileGL {
return false; return false;
} }
IntVec3 FramebufferAttachment::GetSize() const { IntVec3 FramebufferAttachmentObject::GetSize() const {
if (IsTexture()) { if (IsTexture()) {
// TODO: get correct upload target // TODO: get correct upload target
MOBILEGL_ASSERT(nullptr != dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(m_texture.get()), MOBILEGL_ASSERT(nullptr != dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(m_texture.get()),
@@ -71,56 +71,55 @@ namespace MobileGL {
return {0, 0, 0}; return {0, 0, 0};
} }
Bool FramebufferAttachment::IsValid() const { Bool FramebufferAttachmentObject::IsValid() const {
return m_isValid; return m_isValid;
} }
// FramebufferObject // FramebufferObject
FramebufferObject::FramebufferObject(Uint externalIndex) : m_externalIndex(externalIndex) { FramebufferObject::FramebufferObject(Uint externalIndex) : m_externalIndex(externalIndex) {
m_attachments.fill(FramebufferAttachment(false)); m_attachmentObjects.fill(FramebufferAttachmentObject(false));
m_drawBuffers.fill(FramebufferAttachmentType::None); m_drawBuffers.fill(FramebufferAttachmentType::None);
m_drawBuffers[0] = FramebufferAttachmentType::Color0; m_drawBuffers[0] = FramebufferAttachmentType::Color0;
m_attachmentVersions.fill(0);
} }
void FramebufferObject::AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture, void FramebufferObject::AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture,
int level) { int level) {
m_attachments[static_cast<SizeT>(type)] = FramebufferAttachment(std::move(texture), level); m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(std::move(texture), level);
m_drawBuffersDirty = true; BumpAttachmentVersion(type);
} }
void FramebufferObject::AttachRenderbuffer(FramebufferAttachmentType type, void FramebufferObject::AttachRenderbuffer(FramebufferAttachmentType type,
std::shared_ptr<RenderbufferObject> renderbuffer) { std::shared_ptr<RenderbufferObject> renderbuffer) {
m_attachments[static_cast<SizeT>(type)] = FramebufferAttachment(renderbuffer); m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(renderbuffer);
m_drawBuffersDirty = true; BumpAttachmentVersion(type);
} }
void FramebufferObject::Detach(FramebufferAttachmentType type) { void FramebufferObject::Detach(FramebufferAttachmentType type) {
m_attachments[static_cast<SizeT>(type)] = FramebufferAttachment(false); m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(false);
m_drawBuffersDirty = true; BumpAttachmentVersion(type);
} }
const FramebufferAttachment& FramebufferObject::GetAttachment(FramebufferAttachmentType type) const { const FramebufferAttachmentObject& FramebufferObject::GetAttachment(FramebufferAttachmentType type) const {
return m_attachments[static_cast<SizeT>(type)]; return m_attachmentObjects[static_cast<SizeT>(type)];
} }
const Array<FramebufferAttachment, const FramebufferObject::FramebufferAttachmentObjectArray& FramebufferObject::GetAllAttachmentObjects() const {
static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>& return m_attachmentObjects;
FramebufferObject::GetAllAttachments() const {
return m_attachments;
} }
Bool FramebufferObject::CheckCompleteness() const { Bool FramebufferObject::CheckCompleteness() const {
if (m_attachments.empty()) { if (m_attachmentObjects.empty()) {
return false; return false;
} }
Int width = -1, height = -1; Int width = -1, height = -1;
Int validAttachmentCount = 0; Int validAttachmentCount = 0;
for (SizeT i = 0; i < m_attachments.size(); ++i) { for (SizeT i = 0; i < m_attachmentObjects.size(); ++i) {
if (!m_attachments[i].IsValid()) continue; if (!m_attachmentObjects[i].IsValid()) continue;
++validAttachmentCount; ++validAttachmentCount;
const auto& attachment = m_attachments[i]; const auto& attachment = m_attachmentObjects[i];
auto attachmentSize = attachment.GetSize(); auto attachmentSize = attachment.GetSize();
Int w = attachmentSize.x(); Int w = attachmentSize.x();
Int h = attachmentSize.y(); Int h = attachmentSize.y();
@@ -143,26 +142,22 @@ namespace MobileGL {
void FramebufferObject::SetDrawBuffer(Uint index, FramebufferAttachmentType buffer) { void FramebufferObject::SetDrawBuffer(Uint index, FramebufferAttachmentType buffer) {
if (m_drawBuffers[index] == buffer) return; if (m_drawBuffers[index] == buffer) return;
m_drawBuffersDirty = true;
m_drawBuffers[index] = buffer; m_drawBuffers[index] = buffer;
BumpAttachmentVersion(buffer);
} }
// void FramebufferObject::SetDrawBuffers(const Vector<FramebufferAttachmentType>& buffers) { const FramebufferObject::FramebufferAttachmentArray& FramebufferObject::GetDrawBuffers() const {
// m_drawBuffers = buffers;
// m_drawBuffersDirty = true;
// }
// void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer) {
//
// }
const Array<FramebufferAttachmentType, FramebufferObject::MAX_DRAW_BUFFERS>& FramebufferObject::
GetDrawBuffers() const {
return m_drawBuffers; return m_drawBuffers;
} }
Uint FramebufferObject::GetExternalIndex() const { Uint FramebufferObject::GetExternalIndex() const {
return m_externalIndex; return m_externalIndex;
} }
void FramebufferObject::BumpAttachmentVersion(FramebufferAttachmentType type) {
++m_attachmentVersions[static_cast<SizeT>(type)];
++m_objectVersion;
}
} // namespace GLState } // namespace GLState
} // namespace MG_State } // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -69,11 +69,12 @@ namespace MobileGL {
namespace MG_State { namespace MG_State {
namespace GLState { namespace GLState {
class FramebufferAttachment { class FramebufferAttachmentObject {
public: public:
explicit FramebufferAttachment(SharedPtr<MG_State::GLState::ITextureObject> texture, Int level = 0); explicit FramebufferAttachmentObject(SharedPtr<MG_State::GLState::ITextureObject> texture,
explicit FramebufferAttachment(SharedPtr<RenderbufferObject> renderbuffer); Int level = 0);
explicit FramebufferAttachment(Bool IsValid = true); explicit FramebufferAttachmentObject(SharedPtr<RenderbufferObject> renderbuffer);
explicit FramebufferAttachmentObject(Bool IsValid = true);
Bool IsTexture() const; Bool IsTexture() const;
Bool IsRenderbuffer() const; Bool IsRenderbuffer() const;
@@ -94,36 +95,51 @@ namespace MobileGL {
class FramebufferObject { class FramebufferObject {
public: public:
using TargetEnum = FramebufferTarget;
static constexpr Uint MAX_DRAW_BUFFERS = 8; static constexpr Uint MAX_DRAW_BUFFERS = 8;
using TargetEnum = FramebufferTarget;
using FramebufferAttachmentObjectArray =
Array<FramebufferAttachmentObject,
static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>;
using FramebufferAttachmentArray = Array<FramebufferAttachmentType, MAX_DRAW_BUFFERS>;
using FramebufferAttachmentVersionArray =
Array<Uint16, static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>;
FramebufferObject(Uint externalIndex); FramebufferObject(Uint externalIndex);
void AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture, int level = 0); void AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture, int level = 0);
void AttachRenderbuffer(FramebufferAttachmentType type, void AttachRenderbuffer(FramebufferAttachmentType type,
std::shared_ptr<RenderbufferObject> renderbuffer); std::shared_ptr<RenderbufferObject> renderbuffer);
void Detach(FramebufferAttachmentType type); void Detach(FramebufferAttachmentType type);
const FramebufferAttachment& GetAttachment(FramebufferAttachmentType type) const; const FramebufferAttachmentObject& GetAttachment(FramebufferAttachmentType type) const;
const Array<FramebufferAttachment, const FramebufferAttachmentObjectArray& GetAllAttachmentObjects() const;
static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>&
GetAllAttachments() const;
Bool CheckCompleteness() const; Bool CheckCompleteness() const;
// aka. `buffer` as in glDrawBuffers/glReadBuffers // aka. `buffer` as in glDrawBuffers/glReadBuffers
void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer); void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer);
bool DrawBuffersIsDirty() const { return m_drawBuffersDirty; } const FramebufferAttachmentArray& GetDrawBuffers() const;
void ClearDrawBuffersDirtyState() { m_drawBuffersDirty = false; } void SetReadBuffer(FramebufferAttachmentType buf) { m_readBuffer = buf; }
const Array<FramebufferAttachmentType, MAX_DRAW_BUFFERS>& GetDrawBuffers() const;
FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; } FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; }
const FramebufferAttachmentVersionArray GetAllFramebufferAttachmentVersions() const {
return m_attachmentVersions;
}
Uint16 GetObjectVersion() const { return m_objectVersion; }
Uint GetExternalIndex() const; Uint GetExternalIndex() const;
private: private:
void BumpAttachmentVersion(FramebufferAttachmentType type);
const Uint m_externalIndex = 0; const Uint m_externalIndex = 0;
Array<FramebufferAttachment, FramebufferAttachmentObjectArray m_attachmentObjects;
static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)> FramebufferAttachmentVersionArray m_attachmentVersions;
m_attachments;
Bool m_drawBuffersDirty = false; FramebufferAttachmentArray m_drawBuffers; // Probably no versioning needed for this, just check equality
Array<FramebufferAttachmentType, MAX_DRAW_BUFFERS> m_drawBuffers; FramebufferAttachmentType m_readBuffer = FramebufferAttachmentType::Color0; // ditto
FramebufferAttachmentType m_readBuffer = FramebufferAttachmentType::Color0;
// This version will bump when draw/read buffer changes (by `glDrawBuffer(s)`/`glReadBuffer`)
Uint16 m_objectVersion = 0;
}; };
} // namespace GLState } // namespace GLState
@@ -7,168 +7,246 @@
// End of Source File Header // End of Source File Header
#include "RenderState.h" #include "RenderState.h"
#include "MG_Util/Types.h"
namespace MobileGL { namespace MobileGL {
namespace MG_State { namespace MG_State {
namespace GLState { namespace GLState {
RenderState::RenderState() {} RenderState::RenderState() {}
Uint RenderState::GetVersion() const {
return m_version;
}
const RenderStateParameters& RenderState::GetAllParameters() const {
return m_parameters;
}
// -------------------- Rasterization -------------------- // -------------------- Rasterization --------------------
void RenderState::SetViewport(IntVec4 viewport) { void RenderState::SetViewport(IntVec4 viewport) {
m_viewport = viewport; if (m_parameters.Viewport == viewport) return;
m_parameters.Viewport = viewport;
++m_version;
} }
const IntVec4& RenderState::GetViewport() const { const IntVec4& RenderState::GetViewport() const {
return m_viewport; return m_parameters.Viewport;
} }
// -------------------- Capabilities -------------------- // -------------------- Capabilities --------------------
void RenderState::SetCapability(CapabilityInput cap, Bool enabled) { void RenderState::SetCapability(CapabilityInput cap, Bool enabled) {
#define SET_CAPABILITY(capability, flag) \
case CapabilityInput::capability: \
if (m_parameters.capability##Enabled == flag) break; \
m_parameters.capability##Enabled = flag; \
++m_version; \
break;
switch (cap) { switch (cap) {
case CapabilityInput::Blend: SET_CAPABILITY(DepthTest, enabled);
m_blendEnabled = enabled; SET_CAPABILITY(CullFace, enabled);
break; SET_CAPABILITY(ScissorTest, enabled);
case CapabilityInput::DepthTest: case CapabilityInput::Blend: {
m_depthTestEnabled = enabled; Bool stateChanged = false;
break; for (auto& blendState : m_parameters.BlendStates) {
case CapabilityInput::CullFace: if (blendState.Enabled == enabled) continue;
m_cullFaceEnabled = enabled; blendState.Enabled = enabled;
break; stateChanged = true;
case CapabilityInput::ScissorTest: }
m_scissorTestEnabled = enabled; if (stateChanged) ++m_version;
break; break;
}
default: // not supported currently default: // not supported currently
break; break;
} }
#undef SET_CAPABILITY
} }
Bool RenderState::IsCapabilityEnabled(CapabilityInput cap) const { Bool RenderState::IsCapabilityEnabled(CapabilityInput cap) const {
#define RETURN_CAPABILITY(capability) \
case CapabilityInput::capability: \
return m_parameters.capability##Enabled;
switch (cap) { switch (cap) {
RETURN_CAPABILITY(DepthTest);
RETURN_CAPABILITY(CullFace);
RETURN_CAPABILITY(ScissorTest);
case CapabilityInput::Blend: case CapabilityInput::Blend:
return m_blendEnabled; return m_parameters.BlendStates[0].Enabled;
case CapabilityInput::DepthTest:
return m_depthTestEnabled;
case CapabilityInput::CullFace:
return m_cullFaceEnabled;
case CapabilityInput::ScissorTest:
return m_scissorTestEnabled;
default: default:
return false; return false;
} }
} }
void RenderState::SetCapabilityIndexed(CapabilityInput cap, Uint index, Bool enabled) {
// Only for BlendState currently
if (cap != CapabilityInput::Blend) {
THROW_UNIMPL_EXCEPTION;
return;
}
if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
MOBILEGL_ASSERT(false, "Blend capability index out of range: %d", index);
return;
}
if (m_parameters.BlendStates[index].Enabled == enabled) return;
m_parameters.BlendStates[index].Enabled = enabled;
++m_version;
}
Bool RenderState::IsCapabilityEnabledIndexed(CapabilityInput cap, Uint index) const {
// Only for BlendState currently
if (cap != CapabilityInput::Blend) {
THROW_UNIMPL_EXCEPTION;
return false;
}
if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
MOBILEGL_ASSERT(false, "Blend capability index out of range: %d", index);
return false;
}
return m_parameters.BlendStates[index].Enabled;
}
// -------------------- Blending -------------------- // -------------------- Blending --------------------
void RenderState::SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, void RenderState::SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha,
BlendFactor dstAlpha) { BlendFactor dstAlpha) {
m_srcFactorRGB = srcRGB; Bool stateChanged = false;
m_dstFactorRGB = dstRGB; for (auto& blendState : m_parameters.BlendStates) {
m_srcFactorAlpha = srcAlpha; if (blendState.SrcFactorRGB == srcRGB && blendState.DstFactorRGB == dstRGB &&
m_dstFactorAlpha = dstAlpha; blendState.SrcFactorAlpha == srcAlpha && blendState.DstFactorAlpha == dstAlpha) {
continue;
}
blendState.SrcFactorRGB = srcRGB;
blendState.DstFactorRGB = dstRGB;
blendState.SrcFactorAlpha = srcAlpha;
blendState.DstFactorAlpha = dstAlpha;
stateChanged = true;
}
if (!stateChanged) return;
++m_version;
} }
void RenderState::GetBlendFunc(BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha, void RenderState::GetBlendFunc(BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
BlendFactor& dstAlpha) const { BlendFactor& dstAlpha) const {
srcRGB = m_srcFactorRGB; srcRGB = m_parameters.BlendStates[0].SrcFactorRGB;
dstRGB = m_dstFactorRGB; dstRGB = m_parameters.BlendStates[0].DstFactorRGB;
srcAlpha = m_srcFactorAlpha; srcAlpha = m_parameters.BlendStates[0].SrcFactorAlpha;
dstAlpha = m_dstFactorAlpha; dstAlpha = m_parameters.BlendStates[0].DstFactorAlpha;
}
void RenderState::SetBlendFuncIndexed(Uint index, BlendFactor srcRGB, BlendFactor dstRGB,
BlendFactor srcAlpha, BlendFactor dstAlpha) {
if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
MOBILEGL_ASSERT(false, "Blend function index out of range: %d", index);
return;
}
PerBufferBlendState& blendState = m_parameters.BlendStates[index];
if (blendState.SrcFactorRGB == srcRGB && blendState.DstFactorRGB == dstRGB &&
blendState.SrcFactorAlpha == srcAlpha && blendState.DstFactorAlpha == dstAlpha) {
return;
}
blendState.SrcFactorRGB = srcRGB;
blendState.DstFactorRGB = dstRGB;
blendState.SrcFactorAlpha = srcAlpha;
blendState.DstFactorAlpha = dstAlpha;
++m_version;
}
void RenderState::GetBlendFuncIndexed(Uint index, BlendFactor& srcRGB, BlendFactor& dstRGB,
BlendFactor& srcAlpha, BlendFactor& dstAlpha) const {
if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
MOBILEGL_ASSERT(false, "Blend function index out of range: %d", index);
return;
}
srcRGB = m_parameters.BlendStates[index].SrcFactorRGB;
dstRGB = m_parameters.BlendStates[index].DstFactorRGB;
srcAlpha = m_parameters.BlendStates[index].SrcFactorAlpha;
dstAlpha = m_parameters.BlendStates[index].DstFactorAlpha;
} }
// -------------------- Depth -------------------- // -------------------- Depth --------------------
void RenderState::SetDepthFunc(DepthTestFunc func) { void RenderState::SetDepthFunc(DepthTestFunc func) {
m_depthFunc = func; if (m_parameters.DepthFunc == func) return;
m_parameters.DepthFunc = func;
++m_version;
} }
DepthTestFunc RenderState::GetDepthFunc() const { DepthTestFunc RenderState::GetDepthFunc() const {
return m_depthFunc; return m_parameters.DepthFunc;
} }
void RenderState::SetDepthMask(Bool flag) { void RenderState::SetDepthMask(Bool flag) {
m_depthMask = flag; if (m_parameters.DepthMask == flag) return;
m_parameters.DepthMask = flag;
++m_version;
} }
Bool RenderState::GetDepthMask() const { Bool RenderState::GetDepthMask() const {
return m_depthMask; return m_parameters.DepthMask;
} }
// -------------------- Color Mask -------------------- // -------------------- Color Mask --------------------
void RenderState::SetColorMask(BoolVec4 mask) { void RenderState::SetColorMask(BoolVec4 mask) {
m_colorMask = mask; if (m_parameters.ColorMask == mask) return;
m_parameters.ColorMask = mask;
++m_version;
} }
const BoolVec4 RenderState::GetColorMask() const { const BoolVec4 RenderState::GetColorMask() const {
return m_colorMask; return m_parameters.ColorMask;
} }
// -------------------- Clear State -------------------- // -------------------- Clear State --------------------
void RenderState::SetClearColor(FloatVec4 color) { void RenderState::SetClearColor(FloatVec4 color) {
m_clearColor = color; if (m_parameters.ClearColor == color) return;
m_parameters.ClearColor = color;
++m_version;
} }
const FloatVec4& RenderState::GetClearColor() const { const FloatVec4& RenderState::GetClearColor() const {
return m_clearColor; return m_parameters.ClearColor;
} }
void RenderState::SetClearDepth(Float depth) { void RenderState::SetClearDepth(Float depth) {
m_clearDepth = depth; if (m_parameters.ClearDepth == depth) return;
m_parameters.ClearDepth = depth;
++m_version;
} }
Float RenderState::GetClearDepth() const { Float RenderState::GetClearDepth() const {
return m_clearDepth; return m_parameters.ClearDepth;
} }
// -------------------- Pixel Store -------------------- // -------------------- Pixel Store --------------------
void RenderState::SetPixelStoreParam(PixelStoreParam param, Int value) { void RenderState::SetPixelStoreParam(PixelStoreParam param, Int value) {
#define SET_PIXEL_STORE_PARAM(paramNameHead, paramNameTail, val) \
case PixelStoreParam::paramNameHead##paramNameTail: \
if (m_pixelStore##paramNameHead##Parameters.paramNameTail == val) break; \
m_pixelStore##paramNameHead##Parameters.paramNameTail = val; \
break;
switch (param) { switch (param) {
case PixelStoreParam::PackAlignment: SET_PIXEL_STORE_PARAM(Pack, Alignment, value);
m_packParameters.Alignment = value; SET_PIXEL_STORE_PARAM(Pack, RowLength, value);
break; SET_PIXEL_STORE_PARAM(Pack, ImageHeight, value);
case PixelStoreParam::PackRowLength: SET_PIXEL_STORE_PARAM(Pack, SkipPixels, value);
m_packParameters.RowLength = value; SET_PIXEL_STORE_PARAM(Pack, SkipRows, value);
break; SET_PIXEL_STORE_PARAM(Pack, SkipImages, value);
case PixelStoreParam::PackImageHeight: SET_PIXEL_STORE_PARAM(Pack, SwapBytes, value != 0);
m_packParameters.ImageHeight = value; SET_PIXEL_STORE_PARAM(Pack, LSBFirst, value != 0);
break; SET_PIXEL_STORE_PARAM(Unpack, Alignment, value);
case PixelStoreParam::PackSkipPixels: SET_PIXEL_STORE_PARAM(Unpack, RowLength, value);
m_packParameters.SkipPixels = value; SET_PIXEL_STORE_PARAM(Unpack, ImageHeight, value);
break; SET_PIXEL_STORE_PARAM(Unpack, SkipPixels, value);
case PixelStoreParam::PackSkipRows: SET_PIXEL_STORE_PARAM(Unpack, SkipRows, value);
m_packParameters.SkipRows = value; SET_PIXEL_STORE_PARAM(Unpack, SkipImages, value);
break; SET_PIXEL_STORE_PARAM(Unpack, SwapBytes, value != 0);
case PixelStoreParam::PackSkipImages: SET_PIXEL_STORE_PARAM(Unpack, LSBFirst, value != 0);
m_packParameters.SkipImages = value;
break;
case PixelStoreParam::PackSwapBytes:
m_packParameters.SwapBytes = value != 0;
break;
case PixelStoreParam::PackLsbFirst:
m_packParameters.LSBFirst = value != 0;
break;
case PixelStoreParam::UnpackAlignment:
m_unpackParameters.Alignment = value;
break;
case PixelStoreParam::UnpackRowLength:
m_unpackParameters.RowLength = value;
break;
case PixelStoreParam::UnpackImageHeight:
m_unpackParameters.ImageHeight = value;
break;
case PixelStoreParam::UnpackSkipPixels:
m_unpackParameters.SkipPixels = value;
break;
case PixelStoreParam::UnpackSkipRows:
m_unpackParameters.SkipRows = value;
break;
case PixelStoreParam::UnpackSkipImages:
m_unpackParameters.SkipImages = value;
break;
case PixelStoreParam::UnpackSwapBytes:
m_unpackParameters.SwapBytes = value != 0;
MGLOG_D("%s: SwapBytes = %s", __func__, value ? "true" : "false");
break;
case PixelStoreParam::UnpackLsbFirst:
m_unpackParameters.LSBFirst = value != 0;
break;
default: default:
MOBILEGL_ASSERT(false, "Invalid PixelStoreParam enum: %d", static_cast<int>(param)); MOBILEGL_ASSERT(false, "Invalid PixelStoreParam enum: %d", static_cast<int>(param));
return; return;
@@ -176,39 +254,26 @@ namespace MobileGL {
} }
Int RenderState::GetPixelStoreParam(PixelStoreParam param) const { Int RenderState::GetPixelStoreParam(PixelStoreParam param) const {
#define RETURN_PIXEL_STORE_PARAM(paramNameHead, paramNameTail) \
case PixelStoreParam::paramNameHead##paramNameTail: \
return m_pixelStore##paramNameHead##Parameters.paramNameTail;
switch (param) { switch (param) {
case PixelStoreParam::PackAlignment: RETURN_PIXEL_STORE_PARAM(Pack, Alignment);
return m_packParameters.Alignment; RETURN_PIXEL_STORE_PARAM(Pack, RowLength);
case PixelStoreParam::PackRowLength: RETURN_PIXEL_STORE_PARAM(Pack, ImageHeight);
return m_packParameters.RowLength; RETURN_PIXEL_STORE_PARAM(Pack, SkipPixels);
case PixelStoreParam::PackImageHeight: RETURN_PIXEL_STORE_PARAM(Pack, SkipRows);
return m_packParameters.ImageHeight; RETURN_PIXEL_STORE_PARAM(Pack, SkipImages);
case PixelStoreParam::PackSkipPixels: RETURN_PIXEL_STORE_PARAM(Pack, SwapBytes);
return m_packParameters.SkipPixels; RETURN_PIXEL_STORE_PARAM(Pack, LSBFirst);
case PixelStoreParam::PackSkipRows: RETURN_PIXEL_STORE_PARAM(Unpack, Alignment);
return m_packParameters.SkipRows; RETURN_PIXEL_STORE_PARAM(Unpack, RowLength);
case PixelStoreParam::PackSkipImages: RETURN_PIXEL_STORE_PARAM(Unpack, ImageHeight);
return m_packParameters.SkipImages; RETURN_PIXEL_STORE_PARAM(Unpack, SkipPixels);
case PixelStoreParam::PackSwapBytes: RETURN_PIXEL_STORE_PARAM(Unpack, SkipRows);
return m_packParameters.SwapBytes ? 1 : 0; RETURN_PIXEL_STORE_PARAM(Unpack, SkipImages);
case PixelStoreParam::PackLsbFirst: RETURN_PIXEL_STORE_PARAM(Unpack, SwapBytes);
return m_packParameters.LSBFirst ? 1 : 0; RETURN_PIXEL_STORE_PARAM(Unpack, LSBFirst);
case PixelStoreParam::UnpackAlignment:
return m_unpackParameters.Alignment;
case PixelStoreParam::UnpackRowLength:
return m_unpackParameters.RowLength;
case PixelStoreParam::UnpackImageHeight:
return m_unpackParameters.ImageHeight;
case PixelStoreParam::UnpackSkipPixels:
return m_unpackParameters.SkipPixels;
case PixelStoreParam::UnpackSkipRows:
return m_unpackParameters.SkipRows;
case PixelStoreParam::UnpackSkipImages:
return m_unpackParameters.SkipImages;
case PixelStoreParam::UnpackSwapBytes:
return m_unpackParameters.SwapBytes ? 1 : 0;
case PixelStoreParam::UnpackLsbFirst:
return m_unpackParameters.LSBFirst ? 1 : 0;
default: default:
MOBILEGL_ASSERT(false, "Invalid PixelStoreParam enum: %d", static_cast<int>(param)); MOBILEGL_ASSERT(false, "Invalid PixelStoreParam enum: %d", static_cast<int>(param));
return 0; return 0;
@@ -216,25 +281,31 @@ namespace MobileGL {
} }
PixelStoreParameters RenderState::GetPixelStoreParameters(Bool isUnpack) const { PixelStoreParameters RenderState::GetPixelStoreParameters(Bool isUnpack) const {
return isUnpack ? m_unpackParameters : m_packParameters; return isUnpack ? m_pixelStoreUnpackParameters : m_pixelStorePackParameters;
} }
// -------------------- Cull Face -------------------- // -------------------- Cull Face --------------------
void RenderState::SetCullFaceMode(CullFaceMode mode) { void RenderState::SetCullFaceMode(CullFaceMode mode) {
m_cullFaceMode = mode; if (m_parameters.CullFaceModeSetting == mode) return;
m_parameters.CullFaceModeSetting = mode;
++m_version;
} }
CullFaceMode RenderState::GetCullFaceMode() const { CullFaceMode RenderState::GetCullFaceMode() const {
return m_cullFaceMode; return m_parameters.CullFaceModeSetting;
} }
// --------------------- Scissor --------------------- // --------------------- Scissor ---------------------
void RenderState::SetScissorBox(IntVec4 box) { void RenderState::SetScissorBox(IntVec4 box) {
m_scissorBox = box; if (m_parameters.ScissorBox == box) return;
m_parameters.ScissorBox = box;
++m_version;
} }
const IntVec4& RenderState::GetScissorBox() const { const IntVec4& RenderState::GetScissorBox() const {
return m_scissorBox; return m_parameters.ScissorBox;
} }
} // namespace GLState } // namespace GLState
} // namespace MG_State } // namespace MG_State
@@ -7,9 +7,9 @@
// End of Source File Header // End of Source File Header
#pragma once #pragma once
#include "MG_Util/Math/VectorTypes.h"
#include "MG_Util/Types.h"
#include <Includes.h> #include <Includes.h>
#include <MG_Util/Math/VectorTypes.h>
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
namespace MobileGL { namespace MobileGL {
enum class BlendFactor { enum class BlendFactor {
@@ -53,7 +53,7 @@ namespace MobileGL {
PackSkipPixels, PackSkipPixels,
PackSkipImages, PackSkipImages,
PackSwapBytes, PackSwapBytes,
PackLsbFirst, PackLSBFirst,
// Unpack Parameters // Unpack Parameters
UnpackAlignment, UnpackAlignment,
@@ -63,7 +63,7 @@ namespace MobileGL {
UnpackSkipPixels, UnpackSkipPixels,
UnpackSkipImages, UnpackSkipImages,
UnpackSwapBytes, UnpackSwapBytes,
UnpackLsbFirst, UnpackLSBFirst,
PixelStoreParamCount, PixelStoreParamCount,
Unknown = -1 Unknown = -1
@@ -128,12 +128,51 @@ namespace MobileGL {
Int Alignment = 4; Int Alignment = 4;
}; };
struct PerBufferBlendState {
Bool Enabled = false;
BlendFactor SrcFactorRGB = BlendFactor::One;
BlendFactor DstFactorRGB = BlendFactor::Zero;
BlendFactor SrcFactorAlpha = BlendFactor::One;
BlendFactor DstFactorAlpha = BlendFactor::Zero;
};
struct RenderStateParameters {
// Rasterization
IntVec4 Viewport = IntVec4(0, 0, 0, 0); // x, y, width, height
// Blending
Array<PerBufferBlendState, MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS> BlendStates;
// Depth
Bool DepthTestEnabled = false;
DepthTestFunc DepthFunc = DepthTestFunc::Less;
Bool DepthMask = true;
// Color Mask
BoolVec4 ColorMask = BoolVec4(true, true, true, true);
// Clear State
FloatVec4 ClearColor = FloatVec4(0.0f, 0.0f, 0.0f, 1.0f);
Float ClearDepth = 1.0f;
// Cull Face
Bool CullFaceEnabled = false;
CullFaceMode CullFaceModeSetting = CullFaceMode::Back;
// Scissor
Bool ScissorTestEnabled = false;
IntVec4 ScissorBox = IntVec4(0, 0, 0, 0); // x, y, width, height
};
namespace MG_State { namespace MG_State {
namespace GLState { namespace GLState {
class RenderState { class RenderState {
public: public:
RenderState(); RenderState();
Uint GetVersion() const;
const RenderStateParameters& GetAllParameters() const;
// Rasterization // Rasterization
void SetViewport(IntVec4 viewport); // x, y, width, height void SetViewport(IntVec4 viewport); // x, y, width, height
const IntVec4& GetViewport() const; // x, y, width, height const IntVec4& GetViewport() const; // x, y, width, height
@@ -141,11 +180,17 @@ namespace MobileGL {
// Capabilities // Capabilities
void SetCapability(CapabilityInput cap, Bool enabled); void SetCapability(CapabilityInput cap, Bool enabled);
Bool IsCapabilityEnabled(CapabilityInput cap) const; Bool IsCapabilityEnabled(CapabilityInput cap) const;
void SetCapabilityIndexed(CapabilityInput cap, Uint index, Bool enabled);
Bool IsCapabilityEnabledIndexed(CapabilityInput cap, Uint index) const;
// Blending // Blending
void SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, BlendFactor dstAlpha); void SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, BlendFactor dstAlpha);
void GetBlendFunc(BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha, void GetBlendFunc(BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
BlendFactor& dstAlpha) const; BlendFactor& dstAlpha) const;
void SetBlendFuncIndexed(Uint index, BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha,
BlendFactor dstAlpha);
void GetBlendFuncIndexed(Uint index, BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
BlendFactor& dstAlpha) const;
// Depth // Depth
void SetDepthFunc(DepthTestFunc func); void SetDepthFunc(DepthTestFunc func);
@@ -177,39 +222,12 @@ namespace MobileGL {
const IntVec4& GetScissorBox() const; // x, y, width, height const IntVec4& GetScissorBox() const; // x, y, width, height
private: private:
// Rasterization Uint16 m_version = 0;
IntVec4 m_viewport = IntVec4(0, 0, 0, 0); // x, y, width, height RenderStateParameters m_parameters;
// Blending
Bool m_blendEnabled = false;
BlendFactor m_srcFactorRGB = BlendFactor::One;
BlendFactor m_dstFactorRGB = BlendFactor::Zero;
BlendFactor m_srcFactorAlpha = BlendFactor::One;
BlendFactor m_dstFactorAlpha = BlendFactor::Zero;
// Depth
Bool m_depthTestEnabled = false;
DepthTestFunc m_depthFunc = DepthTestFunc::Less;
Bool m_depthMask = true;
// Color Mask
BoolVec4 m_colorMask = BoolVec4(true, true, true, true);
// Clear State
FloatVec4 m_clearColor = FloatVec4(0.0f, 0.0f, 0.0f, 1.0f);
Float m_clearDepth = 1.0f;
// Pixel Store // Pixel Store
PixelStoreParameters m_packParameters; PixelStoreParameters m_pixelStorePackParameters;
PixelStoreParameters m_unpackParameters; PixelStoreParameters m_pixelStoreUnpackParameters;
// Cull Face
Bool m_cullFaceEnabled = false;
CullFaceMode m_cullFaceMode = CullFaceMode::Back;
// Scissor
Bool m_scissorTestEnabled = false;
IntVec4 m_scissorBox = IntVec4(0, 0, 0, 0); // x, y, width, height
}; };
} // namespace GLState } // namespace GLState
} // namespace MG_State } // namespace MG_State
@@ -14,47 +14,77 @@ namespace MobileGL {
SamplerObject::SamplerObject(Uint externalIndex) : m_externalIndex(externalIndex) {} SamplerObject::SamplerObject(Uint externalIndex) : m_externalIndex(externalIndex) {}
void SamplerObject::SetWrapS(SamplerWrapMode mode) { void SamplerObject::SetWrapS(SamplerWrapMode mode) {
if (mode == m_samplerParameters.wrapS) return;
m_samplerParameters.wrapS = mode; m_samplerParameters.wrapS = mode;
++m_version;
} }
void SamplerObject::SetWrapT(SamplerWrapMode mode) { void SamplerObject::SetWrapT(SamplerWrapMode mode) {
if (mode == m_samplerParameters.wrapT) return;
m_samplerParameters.wrapT = mode; m_samplerParameters.wrapT = mode;
++m_version;
} }
void SamplerObject::SetWrapR(SamplerWrapMode mode) { void SamplerObject::SetWrapR(SamplerWrapMode mode) {
if (mode == m_samplerParameters.wrapR) return;
m_samplerParameters.wrapR = mode; m_samplerParameters.wrapR = mode;
++m_version;
} }
void SamplerObject::SetMinFilter(SamplerFilterMode mode) { void SamplerObject::SetMinFilter(SamplerFilterMode mode) {
if (mode == m_samplerParameters.minFilter) return;
m_samplerParameters.minFilter = mode; m_samplerParameters.minFilter = mode;
++m_version;
} }
void SamplerObject::SetMagFilter(SamplerFilterMode mode) { void SamplerObject::SetMagFilter(SamplerFilterMode mode) {
if (mode == m_samplerParameters.magFilter) return;
m_samplerParameters.magFilter = mode; m_samplerParameters.magFilter = mode;
++m_version;
} }
void SamplerObject::SetMipmapMode(SamplerMipmapMode mode) { void SamplerObject::SetMipmapMode(SamplerMipmapMode mode) {
if (mode == m_samplerParameters.mipmapMode) return;
m_samplerParameters.mipmapMode = mode; m_samplerParameters.mipmapMode = mode;
++m_version;
} }
void SamplerObject::SetLodRange(Float minLod, Float maxLod) { void SamplerObject::SetLodRange(Float minLod, Float maxLod) {
if (minLod == m_samplerParameters.minLod && maxLod == m_samplerParameters.maxLod) return;
if (minLod > maxLod) { if (minLod > maxLod) {
THROW_EXCEPTION("minLod cannot be greater than maxLod"); THROW_EXCEPTION("minLod cannot be greater than maxLod");
} }
m_samplerParameters.minLod = minLod; m_samplerParameters.minLod = minLod;
m_samplerParameters.maxLod = maxLod; m_samplerParameters.maxLod = maxLod;
++m_version;
} }
void SamplerObject::SetLodBias(Float bias) { void SamplerObject::SetLodBias(Float bias) {
if (bias == m_samplerParameters.lodBias) return;
m_samplerParameters.lodBias = bias; m_samplerParameters.lodBias = bias;
++m_version;
} }
void SamplerObject::SetSamplerCompareFunc(SamplerCompareFunc func) { void SamplerObject::SetSamplerCompareFunc(SamplerCompareFunc func) {
if (func == m_samplerParameters.compareFunc) return;
m_samplerParameters.compareFunc = func; m_samplerParameters.compareFunc = func;
++m_version;
} }
void SamplerObject::SetCompareMode(SamplerCompareMode mode) { void SamplerObject::SetCompareMode(SamplerCompareMode mode) {
if (mode == m_samplerParameters.compareMode) return;
m_samplerParameters.compareMode = mode; m_samplerParameters.compareMode = mode;
++m_version;
} }
SamplerWrapMode SamplerObject::GetWrapS() const { SamplerWrapMode SamplerObject::GetWrapS() const {
@@ -108,6 +138,10 @@ namespace MobileGL {
const SamplerParameters& SamplerObject::GetAllSamplerParameters() const { const SamplerParameters& SamplerObject::GetAllSamplerParameters() const {
return m_samplerParameters; return m_samplerParameters;
} }
Uint16 SamplerObject::GetVersion() const {
return m_version;
}
} // namespace GLState } // namespace GLState
} // namespace MG_State } // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -98,10 +98,12 @@ namespace MobileGL {
SamplerCompareMode GetCompareMode() const; SamplerCompareMode GetCompareMode() const;
SamplerCompareFunc GetSamplerCompareFunc() const; SamplerCompareFunc GetSamplerCompareFunc() const;
Uint GetExternalIndex() const; Uint GetExternalIndex() const;
Uint16 GetVersion() const;
const SamplerParameters& GetAllSamplerParameters() const; const SamplerParameters& GetAllSamplerParameters() const;
private: private:
const Uint m_externalIndex; const Uint m_externalIndex;
Uint16 m_version = 0;
SamplerParameters m_samplerParameters; SamplerParameters m_samplerParameters;
}; };
} // namespace GLState } // namespace GLState
@@ -7,6 +7,7 @@
// End of Source File Header // End of Source File Header
#include "TextureObject.h" #include "TextureObject.h"
#include "MG_Util/Types.h"
#include <MG_Util/Metrics/TextureMetrics.h> #include <MG_Util/Metrics/TextureMetrics.h>
namespace MobileGL { namespace MobileGL {
@@ -43,7 +44,10 @@ namespace MobileGL {
} }
void TextureObjectBase::SetInternalFormat(TextureInternalFormat format) { void TextureObjectBase::SetInternalFormat(TextureInternalFormat format) {
if (format == m_internalFormat) return;
m_internalFormat = format; m_internalFormat = format;
++m_textureParamsVersion;
} }
Uint TextureObjectBase::GetExternalIndex() const { Uint TextureObjectBase::GetExternalIndex() const {
@@ -55,7 +59,10 @@ namespace MobileGL {
} }
void TextureObjectBase::SetBorderColor(const FloatVec4& color) { void TextureObjectBase::SetBorderColor(const FloatVec4& color) {
if (color == m_borderColor) return;
m_borderColor = color; m_borderColor = color;
++m_textureParamsVersion;
} }
TextureSwizzleParam TextureObjectBase::GetSwizzleParam(TextureSwizzleParam param) const { TextureSwizzleParam TextureObjectBase::GetSwizzleParam(TextureSwizzleParam param) const {
@@ -80,6 +87,8 @@ namespace MobileGL {
} }
void TextureObjectBase::SetSwizzleParam(TextureSwizzleParam param, TextureSwizzleParam value) { void TextureObjectBase::SetSwizzleParam(TextureSwizzleParam param, TextureSwizzleParam value) {
if (GetSwizzleParam(param) == value) return;
switch (param) { switch (param) {
case TextureSwizzleParam::Red: case TextureSwizzleParam::Red:
m_swizzleParams.r() = value; m_swizzleParams.r() = value;
@@ -98,9 +107,14 @@ namespace MobileGL {
static_cast<Int>(param)); static_cast<Int>(param));
break; break;
} }
++m_textureParamsVersion;
} }
void TextureObjectBase::SetSwizzleParamRGBA(const Vec4<TextureSwizzleParam>& values) { void TextureObjectBase::SetSwizzleParamRGBA(const Vec4<TextureSwizzleParam>& values) {
if (values == m_swizzleParams) return;
m_swizzleParams = values; m_swizzleParams = values;
++m_textureParamsVersion;
} }
const UintVec2& TextureObjectBase::GetLevelRange() const { const UintVec2& TextureObjectBase::GetLevelRange() const {
@@ -108,11 +122,21 @@ namespace MobileGL {
} }
void TextureObjectBase::SetBaseLevel(Uint baseLevel) { void TextureObjectBase::SetBaseLevel(Uint baseLevel) {
if (baseLevel == m_levelRange.x()) return;
m_levelRange.x() = baseLevel; m_levelRange.x() = baseLevel;
++m_textureParamsVersion;
} }
void TextureObjectBase::SetMaxLevel(Uint maxLevel) { void TextureObjectBase::SetMaxLevel(Uint maxLevel) {
if (maxLevel == m_levelRange.y()) return;
m_levelRange.y() = maxLevel; m_levelRange.y() = maxLevel;
++m_textureParamsVersion;
}
Uint16 TextureObjectBase::GetTextureParamsVersion() const {
return m_textureParamsVersion;
} }
Uint TextureObjectWithOneMipmap::GetMipmapLevelCount() const { Uint TextureObjectWithOneMipmap::GetMipmapLevelCount() const {
@@ -144,11 +168,11 @@ namespace MobileGL {
} }
void TextureObjectWithOneMipmap::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, void TextureObjectWithOneMipmap::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel,
bool dirty) { Bool dirty) {
m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty); m_textureStorage.MarkDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel, dirty);
} }
bool TextureObjectWithOneMipmap::IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const { Bool TextureObjectWithOneMipmap::IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const {
return m_textureStorage.IsDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel); return m_textureStorage.IsDirty(GetIndexOfTextureUploadTarget(uploadTarget), mipmapLevel);
} }
@@ -170,7 +194,7 @@ namespace MobileGL {
// For some reason mojang decided to have 0x0 in last level mipmap // For some reason mojang decided to have 0x0 in last level mipmap
// Relaxing checks for that // Relaxing checks for that
bool hadZero = false; Bool hadZero = false;
for (SizeT i = 0; i < levelCount; ++i) { for (SizeT i = 0; i < levelCount; ++i) {
const auto& levelSize = m_textureStorage.GetTexelSize(0, i); const auto& levelSize = m_textureStorage.GetTexelSize(0, i);
if (levelSize.x() <= 0 || levelSize.y() <= 0 || levelSize.z() <= 0) { if (levelSize.x() <= 0 || levelSize.y() <= 0 || levelSize.z() <= 0) {
@@ -41,6 +41,7 @@ namespace MobileGL {
virtual const UintVec2& GetLevelRange() const = 0; virtual const UintVec2& GetLevelRange() const = 0;
virtual void SetBaseLevel(Uint baseLevel) = 0; virtual void SetBaseLevel(Uint baseLevel) = 0;
virtual void SetMaxLevel(Uint maxLevel) = 0; virtual void SetMaxLevel(Uint maxLevel) = 0;
virtual Uint16 GetTextureParamsVersion() const = 0;
protected: protected:
virtual Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const = 0; virtual Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const = 0;
@@ -67,7 +68,7 @@ namespace MobileGL {
const UintVec2& GetLevelRange() const override; const UintVec2& GetLevelRange() const override;
void SetBaseLevel(Uint baseLevel) override; void SetBaseLevel(Uint baseLevel) override;
void SetMaxLevel(Uint maxLevel) override; void SetMaxLevel(Uint maxLevel) override;
Uint16 GetTextureParamsVersion() const override;
protected: protected:
const Uint m_externalIndex; const Uint m_externalIndex;
const TextureTarget m_target = TextureTarget::Unknown; const TextureTarget m_target = TextureTarget::Unknown;
@@ -77,6 +78,7 @@ namespace MobileGL {
Vec4<TextureSwizzleParam> m_swizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green, Vec4<TextureSwizzleParam> m_swizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green,
TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha}; TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha};
UintVec2 m_levelRange = {0, 1000}; UintVec2 m_levelRange = {0, 1000};
Uint16 m_textureParamsVersion = 0;
}; };
class TextureObjectMipmap : public TextureObjectBase { class TextureObjectMipmap : public TextureObjectBase {
@@ -92,8 +94,9 @@ namespace MobileGL {
virtual void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) = 0; virtual void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) = 0;
virtual void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) = 0; virtual void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) = 0;
virtual void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) = 0; virtual void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) = 0;
virtual void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) = 0; virtual void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel,
virtual bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const = 0; Bool dirty = true) = 0;
virtual Bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const = 0;
}; };
class TextureObjectWithOneMipmap : public TextureObjectMipmap { class TextureObjectWithOneMipmap : public TextureObjectMipmap {
@@ -108,7 +111,7 @@ namespace MobileGL {
void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) override; void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) override;
void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) override; void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) override;
void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) override; void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) override;
void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) override; void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, Bool dirty) override;
bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const override; bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const override;
IntVec3 GetBaseSize() const override; IntVec3 GetBaseSize() const override;
@@ -22,20 +22,26 @@ namespace MobileGL {
attr.Offset = 0; attr.Offset = 0;
attr.Buffer = nullptr; attr.Buffer = nullptr;
MarkAttributeDirty(index); BumpAttributeFormatVersion(index);
} }
} }
void VertexArrayObject::EnableAttribute(Uint index) { void VertexArrayObject::EnableAttribute(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return; if (index >= MAX_VERTEX_ATTRIBS) return;
if (m_attributes[index].Enabled) return;
m_attributes[index].Enabled = true; m_attributes[index].Enabled = true;
MarkAttributeDirty(index); BumpAttributeSwitchVersion(index);
} }
void VertexArrayObject::DisableAttribute(Uint index) { void VertexArrayObject::DisableAttribute(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return; if (index >= MAX_VERTEX_ATTRIBS) return;
if (!m_attributes[index].Enabled) return;
m_attributes[index].Enabled = false; m_attributes[index].Enabled = false;
MarkAttributeDirty(index); BumpAttributeSwitchVersion(index);
} }
Bool VertexArrayObject::IsAttributeEnabled(Uint index) const { Bool VertexArrayObject::IsAttributeEnabled(Uint index) const {
@@ -47,6 +53,12 @@ namespace MobileGL {
SizeT offset, Bool isInteger) { SizeT offset, Bool isInteger) {
if (index >= MAX_VERTEX_ATTRIBS) return; if (index >= MAX_VERTEX_ATTRIBS) return;
if (m_attributes[index].Size == size && m_attributes[index].Type == type &&
m_attributes[index].Normalized == normalized && m_attributes[index].Stride == stride &&
m_attributes[index].Offset == offset && m_attributes[index].IsInteger == isInteger) {
return;
}
if (size < 1 || size > 4) { if (size < 1 || size > 4) {
return; return;
} }
@@ -59,13 +71,16 @@ namespace MobileGL {
attr.Offset = offset; attr.Offset = offset;
attr.IsInteger = isInteger; attr.IsInteger = isInteger;
MarkAttributeDirty(index); BumpAttributeFormatVersion(index);
} }
void VertexArrayObject::BindAttributeBuffer(Uint index, const SharedPtr<BufferObject>& buffer) { void VertexArrayObject::BindAttributeBuffer(Uint index, const SharedPtr<BufferObject>& buffer) {
if (index >= MAX_VERTEX_ATTRIBS) return; if (index >= MAX_VERTEX_ATTRIBS) return;
if (m_attributes[index].Buffer == buffer) return;
m_attributes[index].Buffer = buffer; m_attributes[index].Buffer = buffer;
MarkAttributeDirty(index); BumpAttributeBufferVersion(index);
} }
BindingSlot<BufferObject>& VertexArrayObject::GetIndexBufferBindingSlot() { BindingSlot<BufferObject>& VertexArrayObject::GetIndexBufferBindingSlot() {
@@ -83,22 +98,6 @@ namespace MobileGL {
return m_attributes; 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();
}
Uint VertexArrayObject::GetExternalIndex() const { Uint VertexArrayObject::GetExternalIndex() const {
return m_externalIndex; return m_externalIndex;
} }
@@ -107,13 +106,39 @@ namespace MobileGL {
if (index >= MAX_VERTEX_ATTRIBS) return; if (index >= MAX_VERTEX_ATTRIBS) return;
if (m_attributes[index].Divisor == divisor) return; if (m_attributes[index].Divisor == divisor) return;
m_attributes[index].Divisor = divisor; m_attributes[index].Divisor = divisor;
MarkAttributeDirty(index); BumpAttributeFormatVersion(index);
} }
Uint VertexArrayObject::GetAttributeDivisor(Uint index) const { Uint VertexArrayObject::GetAttributeDivisor(Uint index) const {
if (index >= MAX_VERTEX_ATTRIBS) return 0; if (index >= MAX_VERTEX_ATTRIBS) return 0;
return m_attributes[index].Divisor; return m_attributes[index].Divisor;
} }
void VertexArrayObject::BumpAttributeFormatVersion(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return;
++m_attributeVersions[index].FormatVersion;
}
void VertexArrayObject::BumpAttributeBufferVersion(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return;
++m_attributeVersions[index].BufferVersion;
}
void VertexArrayObject::BumpAttributeSwitchVersion(Uint index) {
if (index >= MAX_VERTEX_ATTRIBS) return;
++m_attributeVersions[index].SwitchVersion;
}
const VertexAttributeVersion& VertexArrayObject::GetAttributeVersion(Uint index) const {
static VertexAttributeVersion emptyVersion;
if (index >= MAX_VERTEX_ATTRIBS) return emptyVersion;
return m_attributeVersions[index];
}
const Array<VertexAttributeVersion, VertexArrayObject::MAX_VERTEX_ATTRIBS>& VertexArrayObject::
GetAllAttributeVersions() const {
return m_attributeVersions;
}
} // namespace GLState } // namespace GLState
} // namespace MG_State } // namespace MG_State
} // namespace MobileGL } // namespace MobileGL
@@ -9,6 +9,7 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
#include "../BufferState/BufferObject.h" #include "../BufferState/BufferObject.h"
#include "MG_Util/Types.h"
namespace MobileGL { namespace MobileGL {
namespace MG_State { namespace MG_State {
@@ -25,6 +26,12 @@ namespace MobileGL {
SharedPtr<BufferObject> Buffer; SharedPtr<BufferObject> Buffer;
}; };
struct VertexAttributeVersion {
Uint16 FormatVersion = 0;
Uint16 BufferVersion = 0;
Uint16 SwitchVersion = 0;
};
class VertexArrayObject { class VertexArrayObject {
public: public:
static constexpr int MAX_VERTEX_ATTRIBS = 16; static constexpr int MAX_VERTEX_ATTRIBS = 16;
@@ -45,19 +52,22 @@ namespace MobileGL {
const VertexAttribute& GetAttribute(Uint index) const; const VertexAttribute& GetAttribute(Uint index) const;
const Array<VertexAttribute, MAX_VERTEX_ATTRIBS>& GetAllAttributes() const; const Array<VertexAttribute, MAX_VERTEX_ATTRIBS>& GetAllAttributes() const;
const Vector<Uint>& GetDirtyAttributeIndices() const;
void ClearDirtyAttributes();
Uint GetExternalIndex() const; Uint GetExternalIndex() const;
void SetAttributeDivisor(Uint index, Uint divisor); void SetAttributeDivisor(Uint index, Uint divisor);
Uint GetAttributeDivisor(Uint index) const; Uint GetAttributeDivisor(Uint index) const;
const VertexAttributeVersion& GetAttributeVersion(Uint index) const;
const Array<VertexAttributeVersion, MAX_VERTEX_ATTRIBS>& GetAllAttributeVersions() const;
private: private:
void MarkAttributeDirty(Uint index); void BumpAttributeFormatVersion(Uint index);
void BumpAttributeBufferVersion(Uint index);
void BumpAttributeSwitchVersion(Uint index);
const Uint m_externalIndex = 0; const Uint m_externalIndex = 0;
Array<VertexAttribute, MAX_VERTEX_ATTRIBS> m_attributes; Array<VertexAttribute, MAX_VERTEX_ATTRIBS> m_attributes;
Vector<Uint> m_dirtyAttributes; Array<VertexAttributeVersion, MAX_VERTEX_ATTRIBS> m_attributeVersions;
BindingSlot<BufferObject> m_indexBufferBindingSlot; BindingSlot<BufferObject> m_indexBufferBindingSlot;
}; };
} // namespace GLState } // namespace GLState
+18 -9
View File
@@ -72,7 +72,8 @@ TEST_F(BufferTest, PingPong) {
Vector<Int> bufdata(data.size()); Vector<Int> bufdata(data.size());
memcpy(bufdata.data(), p, byteSize); memcpy(bufdata.data(), p, byteSize);
ASSERT_EQ(data, bufdata); ASSERT_EQ(data, bufdata);
auto range = bufRead->GetDirtyRange(); ASSERT_EQ(bufRead->GetDirtyRanges().size() >= 1, true);
auto range = bufRead->GetDirtyRanges()[0];
ASSERT_EQ(range.start, 0); ASSERT_EQ(range.start, 0);
ASSERT_EQ(range.end, byteSize); ASSERT_EQ(range.end, byteSize);
} }
@@ -122,7 +123,8 @@ TEST_F(BufferTest, AcquireMemory) {
void* p = bufObj->AcquireMemory(false, true, false); void* p = bufObj->AcquireMemory(false, true, false);
memcpy(actual.data(), p, byteSize); memcpy(actual.data(), p, byteSize);
ASSERT_EQ(actual, expected); ASSERT_EQ(actual, expected);
auto dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
auto dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, 0); ASSERT_EQ(dirty.start, 0);
ASSERT_EQ(dirty.end, sizeof(Int) * 5); ASSERT_EQ(dirty.end, sizeof(Int) * 5);
@@ -150,7 +152,8 @@ TEST_F(BufferTest, AcquireMemoryRangeWithoutExplicit) {
void* p = bufObj->AcquireMemory(false, true, false); void* p = bufObj->AcquireMemory(false, true, false);
memcpy(actual.data(), p, byteSize); memcpy(actual.data(), p, byteSize);
ASSERT_EQ(actual, expected); ASSERT_EQ(actual, expected);
auto dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
auto dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, sizeof(Int)); ASSERT_EQ(dirty.start, sizeof(Int));
ASSERT_EQ(dirty.end, sizeof(Int) * 4); ASSERT_EQ(dirty.end, sizeof(Int) * 4);
} }
@@ -177,13 +180,15 @@ TEST_F(BufferTest, AcquireMemoryRangeWithExplicit) {
mappedPtr[1] = 300; mappedPtr[1] = 300;
bufObj->FlushMemoryRange(0, sizeof(Int)); bufObj->FlushMemoryRange(0, sizeof(Int));
auto dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
auto dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, sizeof(Int)); ASSERT_EQ(dirty.start, sizeof(Int));
ASSERT_EQ(dirty.end, sizeof(Int) * 2); ASSERT_EQ(dirty.end, sizeof(Int) * 2);
bufObj->ReleaseMemory(); bufObj->ReleaseMemory();
dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, sizeof(Int)); ASSERT_EQ(dirty.start, sizeof(Int));
ASSERT_EQ(dirty.end, sizeof(Int) * 2); ASSERT_EQ(dirty.end, sizeof(Int) * 2);
@@ -193,7 +198,8 @@ TEST_F(BufferTest, AcquireMemoryRangeWithExplicit) {
memcpy(actual.data(), p, byteSize); memcpy(actual.data(), p, byteSize);
ASSERT_EQ(actual, expected); ASSERT_EQ(actual, expected);
dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, sizeof(Int)); ASSERT_EQ(dirty.start, sizeof(Int));
ASSERT_EQ(dirty.end, sizeof(Int) * 2); ASSERT_EQ(dirty.end, sizeof(Int) * 2);
} }
@@ -235,7 +241,8 @@ TEST_F(BufferTest, CopyBufferSubData) {
ASSERT_EQ(actual, expected); ASSERT_EQ(actual, expected);
auto dirty = dstObj->GetDirtyRange(); ASSERT_EQ(dstObj->GetDirtyRanges().size() >= 1, true);
auto dirty = dstObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, 5 * sizeof(Int)); ASSERT_EQ(dirty.start, 5 * sizeof(Int));
ASSERT_EQ(dirty.end, 9 * sizeof(Int)); ASSERT_EQ(dirty.end, 9 * sizeof(Int));
} }
@@ -265,7 +272,8 @@ TEST_F(BufferTest, WriteWhileMapped) {
ASSERT_EQ(actual, expected); ASSERT_EQ(actual, expected);
auto dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
auto dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, 0); ASSERT_EQ(dirty.start, 0);
ASSERT_EQ(dirty.end, byteSize); ASSERT_EQ(dirty.end, byteSize);
} }
@@ -293,7 +301,8 @@ TEST_F(BufferTest, PartialUpdate) {
ASSERT_EQ(actual, expected); ASSERT_EQ(actual, expected);
auto dirty = bufObj->GetDirtyRange(); ASSERT_EQ(bufObj->GetDirtyRanges().size() >= 1, true);
auto dirty = bufObj->GetDirtyRanges()[0];
ASSERT_EQ(dirty.start, sizeof(Int)); ASSERT_EQ(dirty.start, sizeof(Int));
ASSERT_EQ(dirty.end, 3 * sizeof(Int)); ASSERT_EQ(dirty.end, 3 * sizeof(Int));
} }
@@ -30,11 +30,20 @@ namespace MobileGL {
} }
switch (attachment) { switch (attachment) {
case GL_NONE:
return FramebufferAttachmentType::None;
case GL_DEPTH_ATTACHMENT: case GL_DEPTH_ATTACHMENT:
return FramebufferAttachmentType::Depth; return FramebufferAttachmentType::Depth;
case GL_STENCIL_ATTACHMENT: case GL_STENCIL_ATTACHMENT:
return FramebufferAttachmentType::Stencil; return FramebufferAttachmentType::Stencil;
case GL_UNKNOWN_MGL: case GL_FRONT_LEFT:
return FramebufferAttachmentType::FrontLeft;
case GL_FRONT_RIGHT:
return FramebufferAttachmentType::FrontRight;
case GL_BACK_LEFT:
return FramebufferAttachmentType::BackLeft;
case GL_BACK_RIGHT:
return FramebufferAttachmentType::BackRight;
default: default:
return FramebufferAttachmentType::Unknown; return FramebufferAttachmentType::Unknown;
} }
@@ -85,7 +85,7 @@ namespace MobileGL {
case GL_PACK_SWAP_BYTES: case GL_PACK_SWAP_BYTES:
return PixelStoreParam::PackSwapBytes; return PixelStoreParam::PackSwapBytes;
case GL_PACK_LSB_FIRST: case GL_PACK_LSB_FIRST:
return PixelStoreParam::PackLsbFirst; return PixelStoreParam::PackLSBFirst;
case GL_UNPACK_ALIGNMENT: case GL_UNPACK_ALIGNMENT:
return PixelStoreParam::UnpackAlignment; return PixelStoreParam::UnpackAlignment;
case GL_UNPACK_ROW_LENGTH: case GL_UNPACK_ROW_LENGTH:
@@ -101,7 +101,7 @@ namespace MobileGL {
case GL_UNPACK_SWAP_BYTES: case GL_UNPACK_SWAP_BYTES:
return PixelStoreParam::UnpackSwapBytes; return PixelStoreParam::UnpackSwapBytes;
case GL_UNPACK_LSB_FIRST: case GL_UNPACK_LSB_FIRST:
return PixelStoreParam::UnpackLsbFirst; return PixelStoreParam::UnpackLSBFirst;
default: default:
return PixelStoreParam::Unknown; return PixelStoreParam::Unknown;
} }
@@ -33,6 +33,14 @@ namespace MobileGL {
return GL_DEPTH_ATTACHMENT; return GL_DEPTH_ATTACHMENT;
case FramebufferAttachmentType::Stencil: case FramebufferAttachmentType::Stencil:
return GL_STENCIL_ATTACHMENT; return GL_STENCIL_ATTACHMENT;
case FramebufferAttachmentType::FrontLeft:
return GL_FRONT_LEFT;
case FramebufferAttachmentType::FrontRight:
return GL_FRONT_RIGHT;
case FramebufferAttachmentType::BackLeft:
return GL_BACK_LEFT;
case FramebufferAttachmentType::BackRight:
return GL_BACK_RIGHT;
default: default:
return GL_NONE; return GL_NONE;
} }
@@ -85,7 +85,7 @@ namespace MobileGL {
return GL_PACK_SKIP_IMAGES; return GL_PACK_SKIP_IMAGES;
case PixelStoreParam::PackSwapBytes: case PixelStoreParam::PackSwapBytes:
return GL_PACK_SWAP_BYTES; return GL_PACK_SWAP_BYTES;
case PixelStoreParam::PackLsbFirst: case PixelStoreParam::PackLSBFirst:
return GL_PACK_LSB_FIRST; return GL_PACK_LSB_FIRST;
case PixelStoreParam::UnpackAlignment: case PixelStoreParam::UnpackAlignment:
return GL_UNPACK_ALIGNMENT; return GL_UNPACK_ALIGNMENT;
@@ -101,7 +101,7 @@ namespace MobileGL {
return GL_UNPACK_SKIP_IMAGES; return GL_UNPACK_SKIP_IMAGES;
case PixelStoreParam::UnpackSwapBytes: case PixelStoreParam::UnpackSwapBytes:
return GL_UNPACK_SWAP_BYTES; return GL_UNPACK_SWAP_BYTES;
case PixelStoreParam::UnpackLsbFirst: case PixelStoreParam::UnpackLSBFirst:
return GL_UNPACK_LSB_FIRST; return GL_UNPACK_LSB_FIRST;
default: default:
return GL_UNKNOWN_MGL; return GL_UNKNOWN_MGL;
@@ -183,6 +183,36 @@ namespace MobileGL {
return internalformat; return internalformat;
} }
} }
case TextureInternalFormat::DepthComponent: {
switch (type) {
case TexturePixelDataType::UnsignedShort:
return TextureInternalFormat::DepthComponent16;
case TexturePixelDataType::UnsignedInt:
return TextureInternalFormat::DepthComponent32;
case TexturePixelDataType::Float:
return TextureInternalFormat::DepthComponent32F;
default:
MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, "
"returning original.",
__func__, MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(),
MG_Util::ConvertTextureInputFormatToString(format).c_str(),
MG_Util::ConvertTexturePixelDataTypeToString(type).c_str());
return internalformat;
}
}
case TextureInternalFormat::DepthStencil: {
switch (type) {
case TexturePixelDataType::UnsignedInt248:
return TextureInternalFormat::Depth24Stencil8;
default:
MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, "
"returning original.",
__func__, MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str(),
MG_Util::ConvertTextureInputFormatToString(format).c_str(),
MG_Util::ConvertTexturePixelDataTypeToString(type).c_str());
return internalformat;
}
}
default: { default: {
MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, returning " MGLOG_W("%s: Can't infer sized internal format from internalformat=%s, format=%s, type=%s, returning "
"original.", "original.",
@@ -193,5 +223,93 @@ namespace MobileGL {
} }
} }
} }
TextureInternalFormat ConvertInternalFormatToUnsized(TextureInternalFormat internalformat) {
switch (internalformat) {
case TextureInternalFormat::R8:
case TextureInternalFormat::R8Snorm:
case TextureInternalFormat::R16:
case TextureInternalFormat::R16Snorm:
case TextureInternalFormat::R16F:
case TextureInternalFormat::R32F:
case TextureInternalFormat::R8I:
case TextureInternalFormat::R8UI:
case TextureInternalFormat::R16I:
case TextureInternalFormat::R16UI:
case TextureInternalFormat::R32I:
case TextureInternalFormat::R32UI:
case TextureInternalFormat::Red:
return TextureInternalFormat::Red;
case TextureInternalFormat::RG8:
case TextureInternalFormat::RG8Snorm:
case TextureInternalFormat::RG16:
case TextureInternalFormat::RG16Snorm:
case TextureInternalFormat::RG16F:
case TextureInternalFormat::RG32F:
case TextureInternalFormat::RG8I:
case TextureInternalFormat::RG8UI:
case TextureInternalFormat::RG16I:
case TextureInternalFormat::RG16UI:
case TextureInternalFormat::RG32I:
case TextureInternalFormat::RG32UI:
case TextureInternalFormat::RG:
return TextureInternalFormat::RG;
case TextureInternalFormat::R3G3B2:
case TextureInternalFormat::RGB4:
case TextureInternalFormat::RGB5:
case TextureInternalFormat::RGB8:
case TextureInternalFormat::RGB8Snorm:
case TextureInternalFormat::RGB10:
case TextureInternalFormat::RGB12:
case TextureInternalFormat::RGB16Snorm:
case TextureInternalFormat::RGB16F:
case TextureInternalFormat::RGB32F:
case TextureInternalFormat::R11FG11FB10F:
case TextureInternalFormat::RGB9E5:
case TextureInternalFormat::SRGB8:
case TextureInternalFormat::RGB8I:
case TextureInternalFormat::RGB8UI:
case TextureInternalFormat::RGB16I:
case TextureInternalFormat::RGB16UI:
case TextureInternalFormat::RGB32I:
case TextureInternalFormat::RGB32UI:
case TextureInternalFormat::RGB:
return TextureInternalFormat::RGB;
case TextureInternalFormat::RGBA2:
case TextureInternalFormat::RGBA4:
case TextureInternalFormat::RGB5A1:
case TextureInternalFormat::RGBA8:
case TextureInternalFormat::RGBA8Snorm:
case TextureInternalFormat::RGB10A2:
case TextureInternalFormat::RGB10A2UI:
case TextureInternalFormat::RGBA12:
case TextureInternalFormat::RGBA16:
case TextureInternalFormat::SRGB8Alpha8:
case TextureInternalFormat::RGBA16F:
case TextureInternalFormat::RGBA32F:
case TextureInternalFormat::RGBA8I:
case TextureInternalFormat::RGBA8UI:
case TextureInternalFormat::RGBA16I:
case TextureInternalFormat::RGBA16UI:
case TextureInternalFormat::RGBA32I:
case TextureInternalFormat::RGBA32UI:
case TextureInternalFormat::RGBA:
return TextureInternalFormat::RGBA;
case TextureInternalFormat::DepthComponent16:
case TextureInternalFormat::DepthComponent24:
case TextureInternalFormat::DepthComponent32:
case TextureInternalFormat::DepthComponent32F:
case TextureInternalFormat::DepthComponent:
return TextureInternalFormat::DepthComponent;
case TextureInternalFormat::Depth24Stencil8:
case TextureInternalFormat::Depth32FStencil8:
case TextureInternalFormat::DepthStencil:
return TextureInternalFormat::DepthStencil;
default:
MGLOG_W("%s: Unknown or unhandled internal format %s, returning original.", __func__,
MG_Util::ConvertTextureInternalFormatToString(internalformat).c_str());
return internalformat;
}
}
} // namespace MG_Util } // namespace MG_Util
} // namespace MobileGL } // namespace MobileGL
@@ -15,5 +15,7 @@ namespace MobileGL {
TextureTarget ConvertTextureUploadTargetToTextureTarget(TextureUploadTarget target); TextureTarget ConvertTextureUploadTargetToTextureTarget(TextureUploadTarget target);
TextureInternalFormat ConvertInternalFormatToSized(TextureInternalFormat internalformat, TextureInternalFormat ConvertInternalFormatToSized(TextureInternalFormat internalformat,
TextureInputFormat format, TexturePixelDataType type); TextureInputFormat format, TexturePixelDataType type);
TextureInternalFormat ConvertInternalFormatToUnsized(TextureInternalFormat internalformat);
} // namespace MG_Util } // namespace MG_Util
} // namespace MobileGL } // namespace MobileGL
@@ -84,8 +84,8 @@ namespace MobileGL {
return "PackSkipImages"; return "PackSkipImages";
case PixelStoreParam::PackSwapBytes: case PixelStoreParam::PackSwapBytes:
return "PackSwapBytes"; return "PackSwapBytes";
case PixelStoreParam::PackLsbFirst: case PixelStoreParam::PackLSBFirst:
return "PackLsbFirst"; return "PackLSBFirst";
case PixelStoreParam::UnpackAlignment: case PixelStoreParam::UnpackAlignment:
return "UnpackAlignment"; return "UnpackAlignment";
case PixelStoreParam::UnpackRowLength: case PixelStoreParam::UnpackRowLength:
@@ -100,8 +100,8 @@ namespace MobileGL {
return "UnpackSkipImages"; return "UnpackSkipImages";
case PixelStoreParam::UnpackSwapBytes: case PixelStoreParam::UnpackSwapBytes:
return "UnpackSwapBytes"; return "UnpackSwapBytes";
case PixelStoreParam::UnpackLsbFirst: case PixelStoreParam::UnpackLSBFirst:
return "UnpackLsbFirst"; return "UnpackLSBFirst";
default: default:
return "Unknown"; return "Unknown";
} }
+134
View File
@@ -0,0 +1,134 @@
// MobileGL - MobileGL/MG_Util/Math/VectorTypes.cpp
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
#include "VectorTypes.h"
namespace MobileGL {
void VecRange1D::Add(const Range1D& newRange, Double ratio, SizeT* outMinStart, SizeT* outMaxEnd) {
if (this->empty()) {
this->push_back(newRange);
m_overallMaxEnd = newRange.end;
if (outMinStart) *outMinStart = this->front().start;
if (outMaxEnd) *outMaxEnd = m_overallMaxEnd;
return;
}
auto it = std::lower_bound(this->begin(), this->end(), newRange.start,
[](const Range1D& a, SizeT valueStart) { return a.start < valueStart; });
size_t pos = static_cast<size_t>(std::distance(this->begin(), it));
auto calc_gap = [](const Range1D& a, const Range1D& b) -> SizeT {
return (b.start > a.end) ? (b.start - a.end) : 0;
};
auto calc_threshold = [ratio](const Range1D& a, const Range1D& b) -> SizeT {
SizeT minStart = (a.start < b.start) ? a.start : b.start;
SizeT maxEnd = (a.end > b.end) ? a.end : b.end;
SizeT span = (maxEnd > minStart) ? (maxEnd - minStart) : 0;
return static_cast<SizeT>(static_cast<Double>(span) * ratio);
};
if (pos >= this->size()) {
Range1D& last = this->back();
SizeT gap = calc_gap(last, newRange);
SizeT threshold = calc_threshold(last, newRange);
if (gap <= threshold) {
last.end = std::max(last.end, newRange.end);
m_overallMaxEnd = std::max(m_overallMaxEnd, last.end);
} else {
this->push_back(newRange);
m_overallMaxEnd = std::max(m_overallMaxEnd, newRange.end);
}
if (outMinStart) *outMinStart = this->front().start;
if (outMaxEnd) *outMaxEnd = m_overallMaxEnd;
return;
}
bool merged = false;
if (pos > 0) {
Range1D& prev = (*this)[pos - 1];
SizeT gapPrev = calc_gap(prev, newRange);
SizeT thresholdPrev = calc_threshold(prev, newRange);
if (gapPrev <= thresholdPrev) {
prev.end = std::max(prev.end, newRange.end);
m_overallMaxEnd = std::max(m_overallMaxEnd, prev.end);
size_t writeIdx = pos - 1;
while (writeIdx + 1 < this->size()) {
Range1D& cur = (*this)[writeIdx];
Range1D& nxt = (*this)[writeIdx + 1];
SizeT gap = calc_gap(cur, nxt);
SizeT threshold = calc_threshold(cur, nxt);
if (gap <= threshold) {
// merge nxt into cur
cur.end = std::max(cur.end, nxt.end);
this->erase(this->begin() + (writeIdx + 1));
m_overallMaxEnd = std::max(m_overallMaxEnd, cur.end);
} else {
break;
}
}
merged = true;
}
}
if (!merged) {
// Try to merge with the current pos interval or insert
Range1D& cur = (*this)[pos];
SizeT gapCur = calc_gap(newRange, cur); // gap between new and cur
SizeT thresholdCur = calc_threshold(newRange, cur);
if (gapCur <= thresholdCur) {
cur.start = std::min(cur.start, newRange.start);
cur.end = std::max(cur.end, newRange.end);
m_overallMaxEnd = std::max(m_overallMaxEnd, cur.end);
size_t writeIdx = pos;
while (writeIdx + 1 < this->size()) {
Range1D& cur2 = (*this)[writeIdx];
Range1D& nxt = (*this)[writeIdx + 1];
SizeT gap = calc_gap(cur2, nxt);
SizeT threshold = calc_threshold(cur2, nxt);
if (gap <= threshold) {
cur2.end = std::max(cur2.end, nxt.end);
this->erase(this->begin() + (writeIdx + 1));
m_overallMaxEnd = std::max(m_overallMaxEnd, cur2.end);
} else {
break;
}
}
merged = true;
} else {
this->insert(this->begin() + pos, newRange);
m_overallMaxEnd = std::max(m_overallMaxEnd, newRange.end);
merged = true;
}
}
if (outMinStart) {
*outMinStart = this->front().start;
}
if (outMaxEnd) {
*outMaxEnd = m_overallMaxEnd;
}
}
SizeT VecRange1D::GetOverallMaxEnd() const {
return m_overallMaxEnd;
}
SizeT VecRange1D::GetOverallMinStart() const {
if (this->empty()) return 0;
return this->front().start;
}
} // namespace MobileGL
+11 -1
View File
@@ -11,7 +11,6 @@
#include <Includes.h> #include <Includes.h>
namespace MobileGL { namespace MobileGL {
template <typename Derived, typename T, SizeT N> template <typename Derived, typename T, SizeT N>
struct VecBase { struct VecBase {
Array<T, N> data; Array<T, N> data;
@@ -247,4 +246,15 @@ namespace MobileGL {
return incident - normal * (2.0f * incident.Dot(normal)); return incident - normal * (2.0f * incident.Dot(normal));
} }
} // namespace MG_Util } // namespace MG_Util
class VecRange1D : public Vector<Range1D> {
public:
void Add(const Range1D& newRange, Double ratio = 0.07, SizeT* outMinStart = nullptr,
SizeT* outMaxEnd = nullptr);
SizeT GetOverallMaxEnd() const;
SizeT GetOverallMinStart() const;
private:
SizeT m_overallMaxEnd;
};
} // namespace MobileGL } // namespace MobileGL
@@ -239,6 +239,12 @@ namespace MobileGL {
} }
} }
SizeT GetTexturePixelDataTypeSize(TexturePixelDataType type) {
SizeT sizedPixelFormatSize = GetSizedTexturePixelDataTypeSize(type);
if (sizedPixelFormatSize > 0) return sizedPixelFormatSize;
return GetBaseTexturePixelDataTypeSize(type);
}
SizeT GetInternalBytesPerPixel(TextureInternalFormat internalformat, TexturePixelDataType type) { SizeT GetInternalBytesPerPixel(TextureInternalFormat internalformat, TexturePixelDataType type) {
SizeT sizedTextureFormatSize = GetSizedInternalFormatSizeInBytes(internalformat); SizeT sizedTextureFormatSize = GetSizedInternalFormatSizeInBytes(internalformat);
if (sizedTextureFormatSize > 0) return sizedTextureFormatSize; if (sizedTextureFormatSize > 0) return sizedTextureFormatSize;
@@ -16,6 +16,7 @@ namespace MobileGL {
SizeT GetBaseInternalFormatComponentCount(TextureInternalFormat format); SizeT GetBaseInternalFormatComponentCount(TextureInternalFormat format);
SizeT GetSizedTexturePixelDataTypeSize(TexturePixelDataType type); SizeT GetSizedTexturePixelDataTypeSize(TexturePixelDataType type);
SizeT GetBaseTexturePixelDataTypeSize(TexturePixelDataType type); SizeT GetBaseTexturePixelDataTypeSize(TexturePixelDataType type);
SizeT GetTexturePixelDataTypeSize(TexturePixelDataType type);
// This should respect internal format more // This should respect internal format more
SizeT GetInternalBytesPerPixel(TextureInternalFormat internalformat, TexturePixelDataType type); SizeT GetInternalBytesPerPixel(TextureInternalFormat internalformat, TexturePixelDataType type);
// This should respect type more, representing data passed in // This should respect type more, representing data passed in
@@ -230,11 +230,14 @@ namespace MobileGL {
bool ShaderCompiler::SanitizeAndOptimizeBinary(const Vector<Uint32>& inputBinary, bool ShaderCompiler::SanitizeAndOptimizeBinary(const Vector<Uint32>& inputBinary,
Vector<uint32_t>& outputBinary) { Vector<uint32_t>& outputBinary) {
using namespace spvtools; using namespace spvtools;
OptimizerOptions options;
options.set_run_validator(false);
Optimizer optimizer(SPV_ENV_UNIVERSAL_1_5); Optimizer optimizer(SPV_ENV_UNIVERSAL_1_5);
optimizer.RegisterPass(EliminateFloatEqualsZeroPass::CreateEliminateFloatEqualsZeroPass()); optimizer.RegisterPass(EliminateFloatEqualsZeroPass::CreateEliminateFloatEqualsZeroPass());
return optimizer.Run(inputBinary.data(), inputBinary.size(), &outputBinary); return optimizer.Run(inputBinary.data(), inputBinary.size(), &outputBinary, options);
} }
Result<String> ShaderCompiler::DecompileShader(SpvcSession& session) { Result<String> ShaderCompiler::DecompileShader(SpvcSession& session) {
@@ -9,11 +9,13 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
namespace MobileGL::MG_Util::TextureFormatProcessor { namespace MobileGL {
enum class PixelFormatNormalizeOptionBit : Uint { enum class PixelFormatNormalizeOptionBit : Uint {
NoNorm16 = 1 << 0, NoNorm16 = 1 << 0,
None = 0, None = 0,
}; };
namespace MG_Util::TextureFormatProcessor {
void NormalizePixelFormat(GLenum internalFormat, Flags<PixelFormatNormalizeOptionBit> options, void NormalizePixelFormat(GLenum internalFormat, Flags<PixelFormatNormalizeOptionBit> options,
GLenum* outInternalFormat, GLenum* outFormat, GLenum* outType); GLenum* outInternalFormat, GLenum* outFormat, GLenum* outType);
} // namespace MobileGL::MG_Util::TextureFormatProcessor }
} // namespace MobileGL
+7 -4
View File
@@ -145,17 +145,20 @@ namespace MobileGL {
using TargetEnum = typename ObjectType::TargetEnum; using TargetEnum = typename ObjectType::TargetEnum;
BindingSlot() : m_target((TargetEnum)0), m_boundObject(nullptr) {} BindingSlot() : m_target((TargetEnum)0), m_boundObject(nullptr) {}
explicit BindingSlot(TargetEnum target) : m_target(target), m_boundObject(nullptr) {} explicit BindingSlot(TargetEnum target) : m_target(target), m_boundObject(nullptr) {}
void Bind(SharedPtr<ObjectType> object) {
if (m_boundObject == object) return;
void Bind(SharedPtr<ObjectType> object) { m_boundObject = object; } m_boundObject = object;
++m_version;
}
SharedPtr<ObjectType> GetBoundObject() const { return m_boundObject; } SharedPtr<ObjectType> GetBoundObject() const { return m_boundObject; }
TargetEnum GetTarget() const { return m_target; } TargetEnum GetTarget() const { return m_target; }
Uint16 GetVersion() const { return m_version; }
private: private:
TargetEnum m_target; TargetEnum m_target;
Uint16 m_version = 0;
SharedPtr<ObjectType> m_boundObject; SharedPtr<ObjectType> m_boundObject;
}; };
+1 -1
View File
@@ -91,7 +91,7 @@ If you want to try the project right now, youll need to build it yourself:
## Build Options ## Build Options
| Option | Description | Default | | Option | Description | Default |
| ---------------------------- | ----------------------------------------------------- | ------- | |------------------------------| ----------------------------------------------------- | ------- |
| `MOBILEGL_BUILD_TEST` | Build MobileGL tests (requires Clang) | ON | | `MOBILEGL_BUILD_TEST` | Build MobileGL tests (requires Clang) | ON |
| `MOBILEGL_BUILD_BENCHMARK` | Build MobileGL benchmarks (requires Clang) | ON | | `MOBILEGL_BUILD_BENCHMARK` | Build MobileGL benchmarks (requires Clang) | ON |
| `MOBILEGL_FORCE_RELEASE_OPT` | Enable O3 and LTO in Debug build | ON | | `MOBILEGL_FORCE_RELEASE_OPT` | Enable O3 and LTO in Debug build | ON |
+1 -1
View File
@@ -11,7 +11,7 @@ android {
// externalNativeBuild { // externalNativeBuild {
// cmake { // cmake {
// arguments "-DTRACY_ENABLE=ON" // arguments "-DMOBILEGL_ENABLE_TRACY=ON"
// } // }
// } // }
} }