1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // ImageIndex.cpp: Implementation for ImageIndex methods.
8 
9 #include "libANGLE/ImageIndex.h"
10 
11 #include "common/utilities.h"
12 #include "libANGLE/Constants.h"
13 #include "libANGLE/angletypes.h"
14 
15 #include <tuple>
16 
17 namespace gl
18 {
19 namespace
20 {
TextureTargetToLayer(TextureTarget target)21 GLint TextureTargetToLayer(TextureTarget target)
22 {
23     switch (target)
24     {
25         case TextureTarget::CubeMapPositiveX:
26             return 0;
27         case TextureTarget::CubeMapNegativeX:
28             return 1;
29         case TextureTarget::CubeMapPositiveY:
30             return 2;
31         case TextureTarget::CubeMapNegativeY:
32             return 3;
33         case TextureTarget::CubeMapPositiveZ:
34             return 4;
35         case TextureTarget::CubeMapNegativeZ:
36             return 5;
37         case TextureTarget::External:
38         case TextureTarget::Rectangle:
39         case TextureTarget::_2D:
40         case TextureTarget::VideoImage:
41         case TextureTarget::_2DArray:
42         case TextureTarget::_2DMultisample:
43         case TextureTarget::_2DMultisampleArray:
44         case TextureTarget::_3D:
45         case TextureTarget::Buffer:
46         case TextureTarget::CubeMapArray:
47             return ImageIndex::kEntireLevel;
48         default:
49             UNREACHABLE();
50             return 0;
51     }
52 }
53 
IsArrayTarget(TextureTarget target)54 bool IsArrayTarget(TextureTarget target)
55 {
56     switch (target)
57     {
58         case TextureTarget::_2DArray:
59         case TextureTarget::_2DMultisampleArray:
60         case TextureTarget::CubeMapArray:
61             return true;
62         default:
63             return false;
64     }
65 }
66 }  // anonymous namespace
67 
TextureTypeToTarget(TextureType type,GLint layerIndex)68 TextureTarget TextureTypeToTarget(TextureType type, GLint layerIndex)
69 {
70     if (type == TextureType::CubeMap)
71     {
72         // As GL_TEXTURE_CUBE_MAP cannot be a texture target in texImage*D APIs, so we don't allow
73         // an entire cube map to have a texture target.
74         ASSERT(layerIndex != ImageIndex::kEntireLevel);
75         return CubeFaceIndexToTextureTarget(layerIndex);
76     }
77     else
78     {
79         return NonCubeTextureTypeToTarget(type);
80     }
81 }
82 
ImageIndex()83 ImageIndex::ImageIndex()
84     : mType(TextureType::InvalidEnum), mLevelIndex(0), mLayerIndex(0), mLayerCount(kEntireLevel)
85 {}
86 
87 ImageIndex::ImageIndex(const ImageIndex &other) = default;
88 
89 ImageIndex &ImageIndex::operator=(const ImageIndex &other) = default;
90 
hasLayer() const91 bool ImageIndex::hasLayer() const
92 {
93     return mLayerIndex != kEntireLevel;
94 }
95 
isLayered() const96 bool ImageIndex::isLayered() const
97 {
98     switch (mType)
99     {
100         case TextureType::_2DArray:
101         case TextureType::_2DMultisampleArray:
102         case TextureType::CubeMap:
103         case TextureType::_3D:
104         case TextureType::CubeMapArray:
105             return mLayerIndex == kEntireLevel;
106         default:
107             return false;
108     }
109 }
110 
has3DLayer() const111 bool ImageIndex::has3DLayer() const
112 {
113     // It's quicker to check != CubeMap than calling usesTex3D, which checks multiple types. This
114     // ASSERT validates the check gives the same result.
115     ASSERT(!hasLayer() || ((mType != TextureType::CubeMap) == usesTex3D()));
116     return (hasLayer() && mType != TextureType::CubeMap);
117 }
118 
usesTex3D() const119 bool ImageIndex::usesTex3D() const
120 {
121     return mType == TextureType::_3D || mType == TextureType::_2DArray ||
122            mType == TextureType::_2DMultisampleArray || mType == TextureType::CubeMapArray;
123 }
124 
getTarget() const125 TextureTarget ImageIndex::getTarget() const
126 {
127     return TextureTypeToTarget(mType, mLayerIndex);
128 }
129 
getTargetOrFirstCubeFace() const130 gl::TextureTarget ImageIndex::getTargetOrFirstCubeFace() const
131 {
132     if (isEntireLevelCubeMap())
133     {
134         return gl::kCubeMapTextureTargetMin;
135     }
136     else
137     {
138         return getTarget();
139     }
140 }
141 
cubeMapFaceIndex() const142 GLint ImageIndex::cubeMapFaceIndex() const
143 {
144     ASSERT(mType == TextureType::CubeMap);
145     ASSERT(mLayerIndex == kEntireLevel || mLayerIndex < static_cast<GLint>(kCubeFaceCount));
146     return mLayerIndex;
147 }
148 
valid() const149 bool ImageIndex::valid() const
150 {
151     return mType != TextureType::InvalidEnum;
152 }
153 
isEntireLevelCubeMap() const154 bool ImageIndex::isEntireLevelCubeMap() const
155 {
156     return mType == TextureType::CubeMap && mLayerIndex == ImageIndex::kEntireLevel;
157 }
158 
Make2D(GLint levelIndex)159 ImageIndex ImageIndex::Make2D(GLint levelIndex)
160 {
161     return ImageIndex(TextureType::_2D, levelIndex, kEntireLevel, 1);
162 }
163 
MakeRectangle(GLint levelIndex)164 ImageIndex ImageIndex::MakeRectangle(GLint levelIndex)
165 {
166     return ImageIndex(TextureType::Rectangle, levelIndex, kEntireLevel, 1);
167 }
168 
MakeCubeMapFace(TextureTarget target,GLint levelIndex)169 ImageIndex ImageIndex::MakeCubeMapFace(TextureTarget target, GLint levelIndex)
170 {
171     ASSERT(IsCubeMapFaceTarget(target));
172     return ImageIndex(TextureType::CubeMap, levelIndex, TextureTargetToLayer(target), 1);
173 }
174 
Make2DArray(GLint levelIndex,GLint layerIndex)175 ImageIndex ImageIndex::Make2DArray(GLint levelIndex, GLint layerIndex)
176 {
177     return ImageIndex(TextureType::_2DArray, levelIndex, layerIndex, 1);
178 }
179 
Make2DArrayRange(GLint levelIndex,GLint layerIndex,GLint numLayers)180 ImageIndex ImageIndex::Make2DArrayRange(GLint levelIndex, GLint layerIndex, GLint numLayers)
181 {
182     return ImageIndex(TextureType::_2DArray, levelIndex, layerIndex, numLayers);
183 }
184 
Make3D(GLint levelIndex,GLint layerIndex)185 ImageIndex ImageIndex::Make3D(GLint levelIndex, GLint layerIndex)
186 {
187     return ImageIndex(TextureType::_3D, levelIndex, layerIndex, 1);
188 }
189 
MakeFromTarget(TextureTarget target,GLint levelIndex,GLint depth)190 ImageIndex ImageIndex::MakeFromTarget(TextureTarget target, GLint levelIndex, GLint depth)
191 {
192     return ImageIndex(TextureTargetToType(target), levelIndex, TextureTargetToLayer(target),
193                       IsArrayTarget(target) ? depth : 1);
194 }
195 
MakeFromType(TextureType type,GLint levelIndex,GLint layerIndex,GLint layerCount)196 ImageIndex ImageIndex::MakeFromType(TextureType type,
197                                     GLint levelIndex,
198                                     GLint layerIndex,
199                                     GLint layerCount)
200 {
201     GLint overrideLayerCount =
202         (type == TextureType::CubeMap && layerIndex == kEntireLevel ? kCubeFaceCount : layerCount);
203     return ImageIndex(type, levelIndex, layerIndex, overrideLayerCount);
204 }
205 
Make2DMultisample()206 ImageIndex ImageIndex::Make2DMultisample()
207 {
208     return ImageIndex(TextureType::_2DMultisample, 0, kEntireLevel, 1);
209 }
210 
Make2DMultisampleArray(GLint layerIndex)211 ImageIndex ImageIndex::Make2DMultisampleArray(GLint layerIndex)
212 {
213     return ImageIndex(TextureType::_2DMultisampleArray, 0, layerIndex, 1);
214 }
215 
Make2DMultisampleArrayRange(GLint layerIndex,GLint numLayers)216 ImageIndex ImageIndex::Make2DMultisampleArrayRange(GLint layerIndex, GLint numLayers)
217 {
218     return ImageIndex(TextureType::_2DMultisampleArray, 0, layerIndex, numLayers);
219 }
220 
operator <(const ImageIndex & b) const221 bool ImageIndex::operator<(const ImageIndex &b) const
222 {
223     return std::tie(mType, mLevelIndex, mLayerIndex, mLayerCount) <
224            std::tie(b.mType, b.mLevelIndex, b.mLayerIndex, b.mLayerCount);
225 }
226 
operator ==(const ImageIndex & b) const227 bool ImageIndex::operator==(const ImageIndex &b) const
228 {
229     return std::tie(mType, mLevelIndex, mLayerIndex, mLayerCount) ==
230            std::tie(b.mType, b.mLevelIndex, b.mLayerIndex, b.mLayerCount);
231 }
232 
operator !=(const ImageIndex & b) const233 bool ImageIndex::operator!=(const ImageIndex &b) const
234 {
235     return !(*this == b);
236 }
237 
ImageIndex(TextureType type,GLint levelIndex,GLint layerIndex,GLint layerCount)238 ImageIndex::ImageIndex(TextureType type, GLint levelIndex, GLint layerIndex, GLint layerCount)
239     : mType(type), mLevelIndex(levelIndex), mLayerIndex(layerIndex), mLayerCount(layerCount)
240 {}
241 
getLayerIterator(GLint layerCount) const242 ImageIndexIterator ImageIndex::getLayerIterator(GLint layerCount) const
243 {
244     ASSERT(mType != TextureType::_2D && !hasLayer());
245     return ImageIndexIterator::MakeGeneric(mType, mLevelIndex, mLevelIndex + 1, 0, layerCount);
246 }
247 
248 ImageIndexIterator::ImageIndexIterator(const ImageIndexIterator &other) = default;
249 
Make2D(GLint minMip,GLint maxMip)250 ImageIndexIterator ImageIndexIterator::Make2D(GLint minMip, GLint maxMip)
251 {
252     return ImageIndexIterator(TextureType::_2D, Range<GLint>(minMip, maxMip),
253                               Range<GLint>(ImageIndex::kEntireLevel, ImageIndex::kEntireLevel),
254                               nullptr);
255 }
256 
MakeRectangle(GLint minMip,GLint maxMip)257 ImageIndexIterator ImageIndexIterator::MakeRectangle(GLint minMip, GLint maxMip)
258 {
259     return ImageIndexIterator(TextureType::Rectangle, Range<GLint>(minMip, maxMip),
260                               Range<GLint>(ImageIndex::kEntireLevel, ImageIndex::kEntireLevel),
261                               nullptr);
262 }
263 
MakeCube(GLint minMip,GLint maxMip)264 ImageIndexIterator ImageIndexIterator::MakeCube(GLint minMip, GLint maxMip)
265 {
266     return ImageIndexIterator(TextureType::CubeMap, Range<GLint>(minMip, maxMip),
267                               Range<GLint>(0, 6), nullptr);
268 }
269 
Make3D(GLint minMip,GLint maxMip,GLint minLayer,GLint maxLayer)270 ImageIndexIterator ImageIndexIterator::Make3D(GLint minMip,
271                                               GLint maxMip,
272                                               GLint minLayer,
273                                               GLint maxLayer)
274 {
275     return ImageIndexIterator(TextureType::_3D, Range<GLint>(minMip, maxMip),
276                               Range<GLint>(minLayer, maxLayer), nullptr);
277 }
278 
Make2DArray(GLint minMip,GLint maxMip,const GLsizei * layerCounts)279 ImageIndexIterator ImageIndexIterator::Make2DArray(GLint minMip,
280                                                    GLint maxMip,
281                                                    const GLsizei *layerCounts)
282 {
283     return ImageIndexIterator(TextureType::_2DArray, Range<GLint>(minMip, maxMip),
284                               Range<GLint>(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS),
285                               layerCounts);
286 }
287 
Make2DMultisample()288 ImageIndexIterator ImageIndexIterator::Make2DMultisample()
289 {
290     return ImageIndexIterator(TextureType::_2DMultisample, Range<GLint>(0, 1),
291                               Range<GLint>(ImageIndex::kEntireLevel, ImageIndex::kEntireLevel),
292                               nullptr);
293 }
294 
Make2DMultisampleArray(const GLsizei * layerCounts)295 ImageIndexIterator ImageIndexIterator::Make2DMultisampleArray(const GLsizei *layerCounts)
296 {
297     return ImageIndexIterator(TextureType::_2DMultisampleArray, Range<GLint>(0, 1),
298                               Range<GLint>(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS),
299                               layerCounts);
300 }
301 
MakeGeneric(TextureType type,GLint minMip,GLint maxMip,GLint minLayer,GLint maxLayer)302 ImageIndexIterator ImageIndexIterator::MakeGeneric(TextureType type,
303                                                    GLint minMip,
304                                                    GLint maxMip,
305                                                    GLint minLayer,
306                                                    GLint maxLayer)
307 {
308     if (type == TextureType::CubeMap)
309     {
310         return MakeCube(minMip, maxMip);
311     }
312 
313     return ImageIndexIterator(type, Range<GLint>(minMip, maxMip), Range<GLint>(minLayer, maxLayer),
314                               nullptr);
315 }
316 
ImageIndexIterator(TextureType type,const Range<GLint> & mipRange,const Range<GLint> & layerRange,const GLsizei * layerCounts)317 ImageIndexIterator::ImageIndexIterator(TextureType type,
318                                        const Range<GLint> &mipRange,
319                                        const Range<GLint> &layerRange,
320                                        const GLsizei *layerCounts)
321     : mMipRange(mipRange),
322       mLayerRange(layerRange),
323       mLayerCounts(layerCounts),
324       mCurrentIndex(type, mipRange.low(), layerRange.low(), 1)
325 {}
326 
maxLayer() const327 GLint ImageIndexIterator::maxLayer() const
328 {
329     if (mLayerCounts)
330     {
331         ASSERT(mCurrentIndex.hasLayer());
332         return (mCurrentIndex.getLevelIndex() < mMipRange.high())
333                    ? mLayerCounts[mCurrentIndex.getLevelIndex()]
334                    : 0;
335     }
336     return mLayerRange.high();
337 }
338 
next()339 ImageIndex ImageIndexIterator::next()
340 {
341     ASSERT(hasNext());
342 
343     // Make a copy of the current index to return
344     ImageIndex previousIndex = mCurrentIndex;
345 
346     // Iterate layers in the inner loop for now. We can add switchable
347     // layer or mip iteration if we need it.
348 
349     if (mCurrentIndex.hasLayer() && mCurrentIndex.getLayerIndex() < maxLayer() - 1)
350     {
351         mCurrentIndex.mLayerIndex++;
352     }
353     else if (mCurrentIndex.mLevelIndex < mMipRange.high() - 1)
354     {
355         mCurrentIndex.mLayerIndex = mLayerRange.low();
356         mCurrentIndex.mLevelIndex++;
357     }
358     else
359     {
360         mCurrentIndex = ImageIndex();
361     }
362 
363     return previousIndex;
364 }
365 
current() const366 ImageIndex ImageIndexIterator::current() const
367 {
368     return mCurrentIndex;
369 }
370 
hasNext() const371 bool ImageIndexIterator::hasNext() const
372 {
373     return mCurrentIndex.valid();
374 }
375 
376 }  // namespace gl
377