KRTexture::getMemRequiredForLod and KRTexture::getLodData now interpret the passed lod level as a single mip rather than the mip chain starting at the passed lod level.
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, macos-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Has been cancelled

Added KRTexture::getMemRequiredForLodRange
This commit is contained in:
2026-03-19 00:54:36 -07:00
parent d560ba46c7
commit b205fe2e0d
12 changed files with 77 additions and 187 deletions

View File

@@ -126,7 +126,7 @@ void KRTexture::resize(int lod)
if (m_new_lod != target_lod || m_handles.empty()) {
assert(m_newTextureMemUsed == 0);
m_newTextureMemUsed = getMemRequiredForLod(target_lod);
m_newTextureMemUsed = getMemRequiredForLodRange(target_lod);
getContext().getTextureManager()->memoryChanged(m_newTextureMemUsed);
getContext().getTextureManager()->addMemoryTransferredThisFrame(m_newTextureMemUsed);
@@ -294,6 +294,8 @@ bool KRTexture::allocate(KRDevice& device, int target_lod, VkImageCreateFlags im
#endif
)
{
int min_mip = KRMIN(target_lod, m_lod_count - 1);
int mip_count = m_lod_count - min_mip;
hydra::Vector3i dimensions = getDimensions() / (1 << target_lod);
VkImageCreateInfo imageInfo{};
@@ -302,7 +304,7 @@ bool KRTexture::allocate(KRDevice& device, int target_lod, VkImageCreateFlags im
imageInfo.extent.width = static_cast<uint32_t>(dimensions.x);
imageInfo.extent.height = static_cast<uint32_t>(dimensions.y);
imageInfo.extent.depth = static_cast<uint32_t>(dimensions.z);
imageInfo.mipLevels = KRMAX(m_lod_count - target_lod, 1);
imageInfo.mipLevels = mip_count;
imageInfo.arrayLayers = 1;
imageInfo.format = getFormat();
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
@@ -330,3 +332,16 @@ bool KRTexture::allocate(KRDevice& device, int target_lod, VkImageCreateFlags im
#endif
return true;
}
long KRTexture::getMemRequiredForLodRange(int min_lod, int max_lod /* = 0xff */)
{
int target_max_lod = KRMIN(max_lod, m_lod_count - 1);
int target_min_lod = KRMIN(min_lod, m_lod_count - 1);
long memRequired = 0;
for (int lod = target_min_lod; lod <= target_max_lod; lod++) {
memRequired +=
(lod);
}
return memRequired;
}

View File

@@ -53,6 +53,7 @@ public:
virtual long getReferencedMemSize();
virtual long getMemRequiredForLod(int lod) = 0;
long getMemRequiredForLodRange(int min_lod, int max_lod = 0xff);
virtual void resize(int lod);
long getLastFrameUsed();

View File

@@ -53,7 +53,7 @@ bool KRTexture2D::createGPUTexture(int lod)
}
Vector3i dimensions = getDimensions();
size_t bufferSize = getMemRequiredForLod(lod);
size_t bufferSize = getMemRequiredForLodRange(lod);
void* buffer = malloc(bufferSize);
if (!getLodData(buffer, lod)) {
@@ -85,6 +85,9 @@ bool KRTexture2D::createGPUTexture(int lod)
break;
}
int min_mip = KRMIN(target_lod, m_lod_count - 1);
int mip_count = m_lod_count - min_mip;
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = texture.image;
@@ -92,7 +95,7 @@ bool KRTexture2D::createGPUTexture(int lod)
viewInfo.format = getFormat();
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = KRMAX(m_lod_count - target_lod, 1);
viewInfo.subresourceRange.levelCount = mip_count;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
VkResult res = vkCreateImageView(device.m_logicalDevice, &viewInfo, nullptr, &texture.fullImageView);
@@ -101,24 +104,32 @@ bool KRTexture2D::createGPUTexture(int lod)
break;
}
VkBufferImageCopy region{};
region.bufferOffset = 0;
region.bufferRowLength = 0;
region.bufferImageHeight = 0;
std::vector<VkBufferImageCopy> regions;
regions.resize(mip_count, VkBufferImageCopy{});
int bufferOffset = 0;
for (int mip = min_mip; mip < min_mip + mip_count - 1; mip++) {
VkBufferImageCopy& region = regions[mip];
region.bufferOffset = bufferOffset;
region.bufferRowLength = 0;
region.bufferImageHeight = 0;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = mip - min_mip;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageOffset = { 0, 0, 0 };
region.imageExtent = {
(unsigned int)dimensions.x,
(unsigned int)dimensions.y,
(unsigned int)dimensions.z
};
region.imageOffset = { 0, 0, 0 };
region.imageExtent = {
(unsigned int)dimensions.x,
(unsigned int)dimensions.y,
(unsigned int)dimensions.z
};
regions.push_back(region);
device.streamUpload((void*)buffer, bufferSize, texture.image, &region, 1);
bufferOffset += getMemRequiredForLod(mip);
}
device.streamUpload((void*)buffer, bufferSize, texture.image, regions.data(), regions.size());
}
delete buffer;

View File

@@ -93,7 +93,7 @@ bool KRTextureCube::createGPUTexture(int lod)
size_t bufferSizes[6] = {};
void* buffers[6] = {};
for (int i = 0; i < 6; i++) {
bufferSizes[i] = getMemRequiredForLod(lod);
bufferSizes[i] = getMemRequiredForLodRange(lod);
buffers[i] = malloc(bufferSizes[i]);
m_textures[i]->getLodData(buffers[i], lod);
}
@@ -170,7 +170,6 @@ long KRTextureCube::getMemRequiredForLod(int lod)
return memoryRequired;
}
void KRTextureCube::requestResidency(float lodCoverage, texture_usage_t textureUsage)
{
KRTexture::requestResidency(lodCoverage, textureUsage);

View File

@@ -82,7 +82,7 @@ KRTextureKTX::KRTextureKTX(KRContext& context, Block* data, std::string name) :
}
}
m_lod_count = (int)KRMAX(m_header.numberOfMipmapLevels, 1) - 1;
m_lod_count = (int)KRMAX(m_header.numberOfMipmapLevels, 1);
}
KRTextureKTX::KRTextureKTX(KRContext& context, std::string name, unsigned int internal_format, unsigned int base_internal_format, int width, int height, const std::list<Block*>& blocks) : KRTexture2D(context, new Block(), name)
@@ -119,7 +119,7 @@ KRTextureKTX::KRTextureKTX(KRContext& context, std::string name, unsigned int in
KRTextureKTX::~KRTextureKTX()
{
for (std::list<Block*>::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) {
for (std::vector<Block*>::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) {
Block* block = *itr;
delete block;
}
@@ -362,74 +362,20 @@ VkFormat KRTextureKTX::getFormat() const
long KRTextureKTX::getMemRequiredForLod(int lod)
{
// Determine how much memory will be consumed
long memoryRequired = 0;
int level = 0;
for (std::list<Block*>::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) {
Block* block = *itr;
if (level >= lod) {
memoryRequired += (long)block->getSize();
}
level++;
}
return memoryRequired;
int target_lod = KRMIN(lod, m_lod_count - 1);
return (long)m_blocks[target_lod]->getSize();
}
bool KRTextureKTX::getLodData(void* buffer, int lod)
{
unsigned char* converted_image = (unsigned char*)buffer;
int target_lod = KRMIN(lod, m_lod_count);
if (m_blocks.size() == 0) {
return false;
}
// Determine how much memory will be consumed
long memoryRequired = 0;
long memoryTransferred = 0;
// Upload texture data
int level = 0;
for (std::list<Block*>::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) {
Block* block = *itr;
if (level >= target_lod) {
/*
if (width > current_lod_max_dim) {
current_lod_max_dim = width;
}
if (height > current_lod_max_dim) {
current_lod_max_dim = height;
}
*/
block->lock();
/*
* TODO - Vulkan Refactoring
GLDEBUG(glCompressedTexImage2D(target, destination_level, (unsigned int)m_header.glInternalFormat, width, height, 0, (int)block->getSize(), block->getStart()));
*/
block->unlock();
memoryTransferred += (long)block->getSize(); // memoryTransferred does not include throughput of mipmap levels copied through glCopyTextureLevelsAPPLE
memoryRequired += (long)block->getSize();
//
// err = glGetError();
// if (err != GL_NO_ERROR) {
// assert(false);
// return false;
// }
//
}
level++;
}
int target_lod = KRMIN(lod, m_lod_count - 1);
m_blocks[target_lod]->copy(buffer);
return true;
}
std::string KRTextureKTX::getExtension()

View File

@@ -52,7 +52,7 @@ public:
protected:
std::list<Block*> m_blocks;
std::vector<Block*> m_blocks;
typedef struct _KTXHeader
{

View File

@@ -68,7 +68,7 @@ KRTextureKTX2::KRTextureKTX2(KRContext& context, Block* data, std::string name)
if (height < 1) {
height = 1;
}
m_lod_count = (int)KRMAX(m_header.levelCount, 1) - 1;
m_lod_count = (int)KRMAX(m_header.levelCount, 1);
}
KRTextureKTX2::~KRTextureKTX2()
@@ -82,63 +82,26 @@ Vector3i KRTextureKTX2::getDimensions() const
long KRTextureKTX2::getMemRequiredForLod(int lod)
{
int target_lod = KRMIN(lod, m_lod_count);
int target_lod = KRMIN(lod, m_lod_count - 1);
// Determine how much memory will be consumed
long memoryRequired = 0;
KTX2LevelIndex levelIndex;
m_pData->copy(&levelIndex, sizeof(m_header) + sizeof(KTX2LevelIndex) * target_lod, sizeof(KTX2LevelIndex));
int level = 0;
for (__uint32_t level = 0; level < m_header.levelCount; level++) {
KTX2LevelIndex levelIndex;
m_pData->copy(&levelIndex, sizeof(m_header) + sizeof(KTX2LevelIndex) * level, sizeof(KTX2LevelIndex));
if (level >= target_lod) {
memoryRequired += (long)levelIndex.byteLength;
}
level++;
}
return memoryRequired;
return (long)levelIndex.byteLength;
}
bool KRTextureKTX2::getLodData(void* buffer, int lod)
{
unsigned char* converted_image = (unsigned char*)buffer;
int target_lod = KRMIN(lod, m_lod_count);
int target_lod = KRMIN(lod, m_lod_count - 1);
// Determine how much memory will be consumed
long memoryRequired = 0;
long memoryTransferred = 0;
KTX2LevelIndex levelIndex;
m_pData->copy(&levelIndex, sizeof(m_header) + sizeof(KTX2LevelIndex) * target_lod, sizeof(KTX2LevelIndex));
int level = 0;
for (__uint32_t level = 0; level < m_header.levelCount; level++) {
KTX2LevelIndex levelIndex;
m_pData->copy(&levelIndex, sizeof(m_header) + sizeof(KTX2LevelIndex) * level, sizeof(KTX2LevelIndex));
if (level >= target_lod) {
/*
* TODO - Vulkan Refactoring
GLDEBUG(glCompressedTexImage2D(target, destination_level, (unsigned int)m_header.glInternalFormat, width, height, 0, (int)block->getSize(), block->getStart()));
*/
memoryTransferred += (long)levelIndex.byteLength; // memoryTransferred does not include throughput of mipmap levels copied through glCopyTextureLevelsAPPLE
memoryRequired += (long)levelIndex.byteLength;
//
// err = glGetError();
// if (err != GL_NO_ERROR) {
// assert(false);
// return false;
// }
//
}
level++;
}
// TODO - Implement copy of buffer data
assert(false);
return true;
}
std::string KRTextureKTX2::getExtension()

View File

@@ -303,7 +303,7 @@ void KRTextureManager::balanceTextureMemory(long& memoryRemaining, long& memoryR
for (auto itr = m_activeTextures_streamer.begin(); itr != m_activeTextures_streamer.end(); itr++) {
KRTexture* texture = (*itr).second;
int min_lod_level = KRMIN(getContext().KRENGINE_TEXTURE_LQ_LOD, texture->getLodCount());
long minLodMem = texture->getMemRequiredForLod(min_lod_level);
long minLodMem = texture->getMemRequiredForLodRange(min_lod_level);
memoryRemaining -= minLodMem;
if (memoryRemainingThisFrame > minLodMem && (texture->getNewLod() != -1 || texture->getNewLod() > min_lod_level)) {
@@ -333,8 +333,8 @@ void KRTextureManager::balanceTextureMemory(long& memoryRemaining, long& memoryR
KRTexture* texture = (*itr).second;
int min_lod_level = KRMIN(getContext().KRENGINE_TEXTURE_LQ_LOD, texture->getLodCount());
int target_lod_level = KRMIN(getContext().KRENGINE_TEXTURE_HQ_LOD + mip_drop, texture->getLodCount());
long targetMem = texture->getMemRequiredForLod(target_lod_level);
long additionalMemRequired = targetMem - texture->getMemRequiredForLod(min_lod_level);
long targetMem = texture->getMemRequiredForLodRange(target_lod_level);
long additionalMemRequired = targetMem - texture->getMemRequiredForLodRange(min_lod_level);
memoryRemainingThisMip -= additionalMemRequired;
memoryRemaining -= additionalMemRequired;
if (memoryRemainingThisMip > 0 && memoryRemainingThisFrame > targetMem) {
@@ -347,12 +347,12 @@ void KRTextureManager::balanceTextureMemory(long& memoryRemaining, long& memoryR
} else if (current_lod_level == (target_lod_level + 2)) {
// We are two lod levels away from the target.
// Advance to the lod level inbetween.
memoryRemainingThisFrame -= texture->getMemRequiredForLod(target_lod_level + 1);
memoryRemainingThisFrame -= texture->getMemRequiredForLodRange(target_lod_level + 1);
texture->resize(target_lod_level + 1);
} else if (current_lod_level > (target_lod_level + 2)) {
// We are more than two lod levels away from the target.
// Advance directly to the lod 2 levels away from the target.
memoryRemainingThisFrame -= texture->getMemRequiredForLod(target_lod_level + 2);
memoryRemainingThisFrame -= texture->getMemRequiredForLodRange(target_lod_level + 2);
texture->resize(target_lod_level + 2);
}
}

View File

@@ -77,7 +77,7 @@ KRTexturePNG::KRTexturePNG(KRContext& context, Block* data, std::string name) :
m_dimensions.x = SWAP_4(pHeader->chunk_IHDR.width);
m_dimensions.y = SWAP_4(pHeader->chunk_IHDR.height);
m_lod_count = 0; // Mipmaps not yet supported for PNG images
m_lod_count = 1; // Mipmaps not yet supported for PNG images
switch (pHeader->chunk_IHDR.colorType) {
case 0:
// greyscale

View File

@@ -142,7 +142,7 @@ KRTexturePVR::KRTexturePVR(KRContext& context, Block* data, std::string name) :
KRTexturePVR::~KRTexturePVR()
{
for (std::list<Block*>::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) {
for (std::vector<Block*>::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) {
Block* block = *itr;
delete block;
}
@@ -174,64 +174,19 @@ VkFormat KRTexturePVR::getFormat() const
long KRTexturePVR::getMemRequiredForLod(int lod)
{
// Determine how much memory will be consumed
long memoryRequired = 0;
int level = 0;
for (std::list<Block*>::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) {
Block* block = *itr;
if (level >= lod) {
memoryRequired += (long)block->getSize();
}
level++;
}
return memoryRequired;
int target_lod = KRMIN(lod, m_lod_count - 1);
return m_blocks[target_lod]->getSize();
}
bool KRTexturePVR::getLodData(void* buffer, int lod)
{
int target_lod = KRMIN(lod, m_lod_count);
if (m_blocks.size() == 0) {
return false;
}
// Determine how much memory will be consumed
int width = m_iWidth;
int height = m_iHeight;
long memoryRequired = 0;
long memoryTransferred = 0;
// Upload texture data
int level = 0;
for (std::list<Block*>::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) {
Block* block = *itr;
if (level >= target_lod) {
block->lock();
/*
* TODO - Vulkan Refactoring
GLDEBUG(glCompressedTexImage2D(target, destination_level, m_internalFormat, width, height, 0, (int)block->getSize(), block->getStart()));
*/
block->unlock();
memoryTransferred += (long)block->getSize(); // memoryTransferred does not include throughput of mipmap levels copied through glCopyTextureLevelsAPPLE
memoryRequired += (long)block->getSize();
//
// err = glGetError();
// if (err != GL_NO_ERROR) {
// assert(false);
// return false;
// }
//
}
level++;
}
int target_lod = KRMIN(lod, m_lod_count - 1);
m_blocks[target_lod]->copy(buffer);
return true;
}
std::string KRTexturePVR::getExtension()

View File

@@ -54,5 +54,5 @@ protected:
unsigned int m_internalFormat;
bool m_bHasAlpha;
std::list<mimir::Block*> m_blocks;
std::vector<mimir::Block*> m_blocks;
};

View File

@@ -79,7 +79,7 @@ KRTextureTGA::KRTextureTGA(KRContext& context, Block* data, std::string name) :
m_dimensions.x = pHeader->width;
m_dimensions.y = pHeader->height;
m_lod_count = 0; // Mipmaps not yet supported for TGA images
m_lod_count = 1; // Mipmaps not yet supported for TGA images
switch (pHeader->imagetype) {
case 2: // rgb
case 10: // rgb + rle