10#include <spdlog/spdlog.h>
17 uint32_t Texture::_nextId = 0;
20 _device(graphicsDevice), _width(options.
width), _height(options.
height), _depth(options.
depth),
21 _format(options.
format), _id(_nextId++), _minFilter(options.minFilter), _magFilter(options.magFilter),
22 _cubemap(options.cubemap), _volume(options.volume), _arrayLength(options.arrayLength), _numLevelsRequested(options.numLevels),
23 _mipmaps(options.
mipmaps), _storage(options.
storage), _name(options.
name), _profilerHint(options.profilerHint)
25 assert(options.
width > 0 &&
"Texture width must be greater than 0");
26 assert(options.
height > 0 &&
"Texture height must be greater than 0");
27 assert(options.
depth > 0 &&
"Texture depth must be greater than 0");
58 recreateImpl(options.
levels !=
nullptr);
60 spdlog::trace(
"Alloc: Id %u %s: %ux%u [Format:%u]%s%s%s[MipLevels:%u]",
61 _id, _name, _width, _height,
static_cast<uint32_t
>(_format),
62 _cubemap ?
"[Cubemap]" :
"",
63 _volume ?
"[Volume]" :
"",
73 void Texture::updateNumLevels() {
76 if (_numLevelsRequested > 0 && _numLevelsRequested > maxLevels) {
77 spdlog::warn(
"Texture#numLevels: requested mip level count %u is greater than maximum %u, clamping",
78 _numLevelsRequested, maxLevels);
81 _numLevels = std::min(_numLevelsRequested > 0 ? _numLevelsRequested : maxLevels, maxLevels);
82 _mipmaps = _numLevels > 1;
85 void Texture::clearLevels() {
88 _levels[0].resize(6,
nullptr);
89 _levelDataSizes.resize(1);
90 _levelDataSizes[0].resize(6, 0);
91 _levelStorage.resize(1);
92 _levelStorage[0].resize(6);
93 _levelsUpdated.resize(1);
94 _levelsUpdated[0].resize(6,
true);
97 _levels[0].resize(1,
nullptr);
98 _levelDataSizes.resize(1);
99 _levelDataSizes[0].resize(1, 0);
100 _levelStorage.resize(1);
101 _levelStorage[0].resize(1);
102 _levelsUpdated.resize(1);
103 _levelsUpdated[0].resize(1,
true);
107 void Texture::recreateImpl(
bool enableUpload)
113 _impl = _device->createGPUTexture(
this);
121 void Texture::dirtyAll() {
123 _levelsUpdated.resize(1);
124 _levelsUpdated[0].resize(6,
true);
126 _levelsUpdated.resize(1);
127 _levelsUpdated[0].resize(1,
true);
131 _needsMipmapsUpload = _mipmaps;
132 _mipmapsUploaded =
false;
140 _needsMipmapsUpload = _mipmaps;
143 _impl->uploadImmediate(_device);
149 if (_levels.empty() || mipLevel >= _levels[0].size()) {
152 return _levels[0][mipLevel];
157 if (face >= _levelDataSizes.size() || mipLevel >= _levelDataSizes[face].size()) {
160 return _levelDataSizes[face][mipLevel];
165 if (!data || dataSize == 0) {
171 spdlog::warn(
"Texture::setLevelData face index {} out of range for cubemap", face);
178 if (face >= _levels.size()) {
179 _levels.resize(face + 1);
180 _levelDataSizes.resize(face + 1);
181 _levelStorage.resize(face + 1);
182 _levelsUpdated.resize(face + 1);
185 const auto requiredLevels = mipLevel + 1;
186 if (_levels[face].size() < requiredLevels) {
187 _levels[face].resize(requiredLevels,
nullptr);
188 _levelDataSizes[face].resize(requiredLevels, 0);
189 _levelStorage[face].resize(requiredLevels);
190 _levelsUpdated[face].resize(requiredLevels,
true);
193 auto&
storage = _levelStorage[face][mipLevel];
194 storage.assign(data, data + dataSize);
195 _levels[face][mipLevel] =
storage.data();
196 _levelDataSizes[face][mipLevel] = dataSize;
197 _levelsUpdated[face][mipLevel] =
true;
202 if (!_cubemap || face >= 6 || _levels.size() <= face) {
205 if (mipLevel >= _levels[face].size()) {
208 return _levels[face][mipLevel];
212 if (!
isArray() || index >= _arrayLength) {
223 adjustVramSizeTracking(_device->_vram, -
static_cast<int64_t
>(_gpuSize));
238 void Texture::adjustVramSizeTracking(
DeviceVRAM& vram, int64_t size)
240 spdlog::trace(
"%u %s size: %lld vram.tex: %zu => %zu", _id, _name.c_str(), size, vram.
tex, vram.
tex + size);
245 switch (_profilerHint) {
266 _needsMipmapsUpload =
true;
273 if (_minFilter != filter) {
274 if (_integerFormat) {
275 spdlog::warn(
"minFilter property cannot be changed on integer texture, will remain FILTER_NEAREST");
285 if (_magFilter != filter) {
286 if (_integerFormat) {
287 spdlog::warn(
"magFilter property cannot be changed on integer texture, will remain FILTER_NEAREST");
297 if (_addressU != address) {
305 if (_addressV != address) {
314 spdlog::warn(
"Cannot set W addressing mode for a non-3D texture");
317 if (_addressW != address) {
327 _impl->propertyChanged(flag);
329 _renderVersionDirty = _device->renderVersion();
Abstract GPU interface for resource creation, state management, and draw submission.
size_t getLevelDataSize(uint32_t mipLevel, uint32_t face=0) const
Texture(GraphicsDevice *graphicsDevice, const TextureOptions &options=TextureOptions{})
PixelFormat format() const
void setLevelData(uint32_t mipLevel, const uint8_t *data, size_t dataSize, uint32_t face=0)
void * getLevel(uint32_t mipLevel) const
void setMinFilter(FilterMode filter)
void setAddressW(AddressMode address)
const std::string & name() const
virtual void propertyChanged(TextureProperty flag)
void setMipmaps(bool mipmaps)
void resize(uint32_t width, uint32_t height, uint32_t depth=1)
void setAddressU(AddressMode address)
void * getFaceData(uint32_t mipLevel, uint32_t face) const
void setMagFilter(FilterMode filter)
void setAddressV(AddressMode address)
void * getArrayData(uint32_t mipLevel, uint32_t index) const
static uint32_t calcMipLevelsCount(uint32_t width, uint32_t height, uint32_t depth=1)
bool isCompressedPixelFormat(const PixelFormat format)
bool isIntegerPixelFormat(const PixelFormat format)
TextureProjection projection