Files
aya/engine/gfx/src/Core/Texture.cpp
2025-12-17 16:47:48 +00:00

173 lines
3.9 KiB
C++

#include "Core/Texture.hpp"
#include "Profiler.hpp"
FASTFLAGVARIABLE(GraphicsTextureCommitChanges, false)
namespace Aya
{
namespace Graphics
{
struct FormatDescription
{
unsigned char bpp;
bool compressed;
bool depth;
};
static const FormatDescription gTextureFormats[Texture::Format_Count] = {
{8, false, false},
{16, false, false},
{16, false, false},
{32, false, false},
{32, false, false},
{64, false, false},
{4, true, false},
{8, true, false},
{8, true, false},
{2, true, false},
{2, true, false},
{4, true, false},
{4, true, false},
{4, true, false},
{16, false, true},
{32, false, true},
};
TextureRegion::TextureRegion()
: x(0)
, y(0)
, z(0)
, width(0)
, height(0)
, depth(0)
{
}
TextureRegion::TextureRegion(unsigned int x, unsigned int y, unsigned int z, unsigned int width, unsigned int height, unsigned int depth)
: x(x)
, y(y)
, z(z)
, width(width)
, height(height)
, depth(depth)
{
}
TextureRegion::TextureRegion(unsigned int x, unsigned int y, unsigned int width, unsigned int height)
: x(x)
, y(y)
, z(0)
, width(width)
, height(height)
, depth(1)
{
}
Texture::Texture(
Device* device, Type type, Format format, unsigned int width, unsigned int height, unsigned int depth, unsigned int mipLevels, Usage usage)
: Resource(device)
, type(type)
, format(format)
, width(width)
, height(height)
, depth(depth)
, mipLevels(mipLevels)
, usage(usage)
{
AYAASSERT(width > 0 && height > 0 && depth > 0);
AYAASSERT(mipLevels > 0 && mipLevels <= getMaxMipCount(width, height, depth));
AYAASSERT(type == Type_3D || depth == 1);
if (usage != Usage_Renderbuffer)
{
AYAPROFILER_COUNTER_ADD("memory/gpu/texture", getTextureSize(type, format, width, height, depth, mipLevels));
}
}
Texture::~Texture()
{
if (usage != Usage_Renderbuffer)
{
AYAPROFILER_COUNTER_SUB("memory/gpu/texture", getTextureSize(type, format, width, height, depth, mipLevels));
}
}
bool Texture::isFormatCompressed(Format format)
{
return gTextureFormats[format].compressed;
}
bool Texture::isFormatDepth(Format format)
{
return gTextureFormats[format].depth;
}
unsigned int Texture::getFormatBits(Format format)
{
return gTextureFormats[format].bpp;
}
unsigned int Texture::getImageSize(Format format, unsigned int width, unsigned int height)
{
const FormatDescription& desc = gTextureFormats[format];
switch (format)
{
case Format_BC1:
case Format_BC2:
case Format_BC3:
case Format_ETC1:
return ((width + 3) / 4) * ((height + 3) / 4) * (desc.bpp * 16 / 8);
case Format_PVRTC_RGB2:
case Format_PVRTC_RGBA2:
return (std::max(width, 16u) * std::max(height, 8u) * 2 + 7) / 8;
case Format_PVRTC_RGB4:
case Format_PVRTC_RGBA4:
return (std::max(width, 8u) * std::max(height, 8u) * 4 + 7) / 8;
default:
AYAASSERT(!desc.compressed);
return width * height * (desc.bpp / 8);
}
}
unsigned int Texture::getTextureSize(Type type, Format format, unsigned int width, unsigned int height, unsigned int depth, unsigned int mipLevels)
{
unsigned int result = 0;
for (unsigned int mip = 0; mip < mipLevels; ++mip)
result += Texture::getImageSize(format, Texture::getMipSide(width, mip), Texture::getMipSide(height, mip)) * Texture::getMipSide(depth, mip);
return result * (type == Texture::Type_Cube ? 6 : 1);
}
unsigned int Texture::getMipSide(unsigned int value, unsigned int mip)
{
unsigned int result = value >> mip;
return result ? result : 1;
}
unsigned int Texture::getMaxMipCount(unsigned int width, unsigned int height, unsigned int depth)
{
unsigned int result = 0;
while (width || height || depth)
{
result++;
width /= 2;
height /= 2;
depth /= 2;
}
return result;
}
} // namespace Graphics
} // namespace Aya