Cogs.Core
TextureData.cpp
1#include "TextureData.h"
2
3#include <cmath>
4#include <algorithm>
5
6namespace Cogs
7{
8
9 const char* getResourceDimensionsName(ResourceDimensions target)
10 {
11 static const char* names[] =
12 {
13 "Unknown",
14 "Buffer",
15 "Texture1D",
16 "Texture1DArray",
17 "Texture2D",
18 "Texture2DArray",
19 "Texture2DMS",
20 "Texture2DMSArray",
21 "Texture3D",
22 "Texture3DArray",
23 "TextureCube",
24 "TextureCubeArray",
25 "RenderBuffer",
26 "<illegal>"
27 };
28 static_assert(sizeof(names) == sizeof(names[0]) * (size_t(ResourceDimensions::ResourceDimensions_Size) + 1));
29 return names[size_t(target) < size_t(ResourceDimensions::ResourceDimensions_Size) ? size_t(target) : size_t(ResourceDimensions::ResourceDimensions_Size)];
30 }
31
32 size_t getBlockSize(TextureFormat format)
33 {
34 return getFormatInfo(format)->blockSize;
35 }
36
37 TextureExtent getBlockExtent(TextureFormat format)
38 {
39 return getFormatInfo(format)->blockExtent;
40 }
41
42 size_t getComponents(TextureFormat format)
43 {
44 return getFormatInfo(format)->elements;
45 }
46
47 uint32_t getMipLevels(const uint32_t width, const uint32_t height)
48 {
49 return 1 + static_cast<uint32_t>(std::floor(std::log2((double)std::max(width, height))));
50 }
51
52 uint32_t getMipSize(uint32_t size, uint32_t level)
53 {
54 return std::max(1u, size / static_cast<uint32_t>(std::pow(2, level)));
55 }
56
58 {
59 size_t size = getBlockSize(format) * width * height * depth * faces * layers;
60
61 if (levels > 1) {
62 size += (size / 3); // Roughly. :)
63 }
64 return size;
65 }
66
67 TextureData::TextureData(TextureExtent extent, size_t layers, size_t faces, size_t levels, TextureFormat format, Memory::Allocator * allocator) :
68 format(format),
69 layers(layers),
70 faces(faces),
71 levels(levels),
72 blockSize(getBlockSize(format)),
73 blockExtent(getBlockExtent(format)),
74 blockCount(TextureExtent{ (extent.width + getBlockExtent(format).width - 1) / getBlockExtent(format).width, (extent.height + getBlockExtent(format).height - 1) / getBlockExtent(format).height, extent.depth / getBlockExtent(format).depth }),
75 extent(extent),
76 data(allocator)
77 {
78
79 }
80
81 TextureData::TextureData(const void * data, TextureExtent extent, size_t layers, size_t faces, size_t levels, TextureFormat format) :
82 TextureData(extent, layers, faces, levels, format)
83 {
84 initOffsets(data);
85 }
86
87 void TextureData::init(TextureExtent extent, size_t layers, size_t faces, size_t levels, TextureFormat format, Memory::Allocator * allocator)
88 {
89 this->format = format;
90 this->layers = layers;
91 this->faces = faces;
92 this->levels = levels;
93 blockSize = getBlockSize(format);
94 blockExtent = getBlockExtent(format);
95 blockCount = TextureExtent{ (extent.width + getBlockExtent(format).width -1) / getBlockExtent(format).width, (extent.height + getBlockExtent(format).height - 1) / getBlockExtent(format).height, extent.depth / getBlockExtent(format).depth };
96 this->extent = extent;
97 data.reset(getSize(), allocator);
98
99 initOffsets(data.data());
100 }
101
102 void TextureData::initExternal(intptr_t external)
103 {
104 externalHandle = external;
105 }
106
107 void TextureData::initExternal(const void ** data, size_t layers, size_t faces, size_t levels)
108 {
109 assert(this->layers == layers && "External data not compatible.");
110 assert(this->faces == faces && "External data not compatible.");
111 assert(this->levels == levels && "External data not compatible.");
112
113 size_t numOffsets = layers * faces * levels;
114 for (size_t i = 0; i < numOffsets; ++i) {
115 offsets.push_back(data[i]);
116 }
117 }
118
119 void TextureData::clearData()
120 {
121 format = Cogs::TextureFormat::Unknown;
122
123 layers = 0;
124 faces = 0;
125 levels = 0;
126
127 blockSize = 0;
128 blockExtent = {};
129 blockCount = {};
130 extent = {};
131
132 offsets.clear();
133 data.resize(0, false, true); // forceRealloc to free data
134 externalHandle = 0;
135 }
136
137 void * TextureData::getData(size_t layer, size_t face, size_t level)
138 {
139 assert(data.size() && "Cannot modify external data.");
140
141 return static_cast<uint8_t *>(data.data()) + getOffset(layer, face, level);
142 }
143
144 const void * TextureData::getData(size_t layer, size_t face, size_t level) const
145 {
146 return offsets[layer * (faces * levels) + face * levels + level];
147 }
148
149 size_t TextureData::getPitch(size_t level) const
150 {
151 return blockSize * getBlockCount(level).width;
152 }
153
154 size_t TextureData::getLevelSize(size_t level) const
155 {
156 const auto levelBlocks = getBlockCount(level);
157
158 return blockSize * levelBlocks.width * levelBlocks.height * levelBlocks.depth;
159 }
160
161 size_t TextureData::getFaceSize(size_t baseLevel, size_t maxLevel) const
162 {
163 size_t faceSize = 0;
164 for (size_t i = baseLevel; i <= maxLevel; ++i) {
165 faceSize += getLevelSize(i);
166 }
167 return faceSize;
168 }
169
170 size_t TextureData::getLayerSize(size_t baseFace, size_t maxFace, size_t baseLevel, size_t maxLevel) const
171 {
172 return getFaceSize(baseLevel, maxLevel) * (maxFace - baseFace + 1);
173 }
174
175 size_t TextureData::getSize() const
176 {
177 return layers * getLayerSize(0, faces - 1, 0, levels - 1);
178 }
179
180 TextureExtent TextureData::getExtent(size_t level) const
181 {
182 return TextureExtent{
183 std::max(1u, extent.width >> (uint32_t)level),
184 std::max(1u, extent.height >> (uint32_t)level),
185 std::max(1u, extent.depth >> (uint32_t)level),
186 };
187 }
188
189 TextureExtent TextureData::getBlockCount(size_t level) const
190 {
191 return TextureExtent{
192 std::max(1u, ((blockCount.width + (1 << (uint32_t)level) - 1 )) >> (uint32_t)level),
193 std::max(1u, ((blockCount.height + (1 << (uint32_t)level) - 1 )) >> (uint32_t)level),
194 std::max(1u, ((blockCount.depth + (1 << (uint32_t)level) - 1 )) >> (uint32_t)level),
195 };
196 }
197
198 size_t TextureData::getOffset(size_t layer, size_t face, size_t level) const
199 {
200 auto layerSize = getLayerSize(0, faces - 1, 0, levels - 1);
201 auto faceSize = getFaceSize(0, levels - 1);
202
203 size_t offset = layer * layerSize + face * faceSize;
204
205 for (size_t i = 0; i < level; ++i) {
206 offset += getLevelSize(i);
207 }
208
209 return offset;
210 }
211
212 void TextureData::initOffsets(const void * data)
213 {
214 for (size_t i = 0; i < layers; ++i) {
215 for (size_t j = 0; j < faces; ++j) {
216 for (size_t k = 0; k < levels; ++k) {
217 offsets.push_back(static_cast<const uint8_t *>(data) + getOffset(i, j, k));
218 }
219 }
220 }
221 }
222}
Base allocator implementation.
Definition: Allocator.h:30
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
uint16_t elements
Number of channels in a data item.
Definition: DataFormat.h:259
uint8_t blockSize
Bytesize of one block of data.
Definition: DataFormat.h:257
TextureExtent blockExtent
Number of data items in a block.
Definition: DataFormat.h:258
COGSRENDERING_DLL_API size_t estimateMemorySize() const
Attempts to estimate the amount of memory a texture with these attributes will require.
Definition: TextureData.cpp:57