Files
MobileGL/MobileGL/MG_State/GLState/TextureState/MipmapStorage.cpp
T

89 lines
3.9 KiB
C++

// MobileGL - MobileGL/MG_State/GLState/TextureState/MipmapStorage.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 "MipmapStorage.h"
namespace MobileGL {
namespace MG_State {
namespace GLState {
SizeT MipmapStorage::GetLevelCount() const {
return m_data.size();
}
void MipmapStorage::AllocateLevel(Uint level, MipmapInput input) {
// Grow only. GL respecifies exactly the level it is handed, so allocating level 0
// must not disturb the levels above it - but resize() shrinks as readily as it
// grows, so this used to truncate the whole chain to a single level. Callers that
// genuinely redefine the complete level set say so with TruncateToLevelCount.
const SizeT requiredLevelCount = static_cast<SizeT>(level) + 1;
if (m_data.size() < requiredLevelCount) {
m_data.reserve(std::bit_ceil(requiredLevelCount));
m_data.resize(requiredLevelCount);
m_texelSizes.reserve(std::bit_ceil(requiredLevelCount));
m_texelSizes.resize(requiredLevelCount);
m_isDirty.resize(requiredLevelCount, false);
}
m_texelSizes[level] = input.texelSize;
auto& data = m_data[level];
data.resize(input.byteSize, 0);
}
void MipmapStorage::TruncateToLevelCount(SizeT levelCount) {
if (levelCount >= m_data.size()) return;
m_data.resize(levelCount);
m_texelSizes.resize(levelCount);
m_isDirty.resize(levelCount);
}
void MipmapStorage::UpdateSubData(Uint level, DataPtr input) {
auto& targetData = m_data;
MOBILEGL_ASSERT(level < targetData.size(), "UpdateSubData: level out of range");
auto& levelData = targetData[level];
MOBILEGL_ASSERT(input.size <= levelData.size(), "UpdateSubData: input data larger than allocated");
if (input.data && input.size > 0) {
const Uint8* src = static_cast<const Uint8*>(input.data);
// Clamp so a size mismatch can never write past the allocation.
Memcpy(levelData.data(), src, std::min(input.size, levelData.size()));
m_isDirty[level] = true;
}
}
void* MipmapStorage::MapData(Uint level) {
auto& targetData = m_data;
MOBILEGL_ASSERT(level < targetData.size(), "UpdateSubData: level out of range");
auto& levelData = targetData[level];
return levelData.data();
}
IntVec3 MipmapStorage::GetTexelSize(Uint level) const {
auto& targetTexelSizes = m_texelSizes;
if (level >= targetTexelSizes.size()) return {0, 0, 0};
return targetTexelSizes[level];
}
SizeT MipmapStorage::GetByteSize(Uint level) const {
if (level >= m_data.size()) return 0;
return m_data[level].size();
}
void MipmapStorage::MarkDirty(Uint level, bool dirty) {
MOBILEGL_ASSERT(level < m_isDirty.size(), "MarkDirty: level out of range");
m_isDirty[level] = dirty;
}
bool MipmapStorage::IsDirty(Uint level) const {
MOBILEGL_ASSERT(level < m_isDirty.size(), "IsDirty: level out of range");
return m_isDirty[level];
}
} // namespace GLState
} // namespace MG_State
} // namespace MobileGL