#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