// // Copyright 2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // ImageIndex.cpp: Implementation for ImageIndex methods. #include "libANGLE/ImageIndex.h" #include "common/utilities.h" #include "libANGLE/Constants.h" #include "libANGLE/angletypes.h" #include namespace gl { namespace { GLint TextureTargetToLayer(TextureTarget target) { switch (target) { case TextureTarget::CubeMapPositiveX: return 0; case TextureTarget::CubeMapNegativeX: return 1; case TextureTarget::CubeMapPositiveY: return 2; case TextureTarget::CubeMapNegativeY: return 3; case TextureTarget::CubeMapPositiveZ: return 4; case TextureTarget::CubeMapNegativeZ: return 5; case TextureTarget::External: return ImageIndex::kEntireLevel; case TextureTarget::Rectangle: return ImageIndex::kEntireLevel; case TextureTarget::_2D: return ImageIndex::kEntireLevel; case TextureTarget::_2DArray: return ImageIndex::kEntireLevel; case TextureTarget::_2DMultisample: return ImageIndex::kEntireLevel; case TextureTarget::_2DMultisampleArray: return ImageIndex::kEntireLevel; case TextureTarget::_3D: return ImageIndex::kEntireLevel; default: UNREACHABLE(); return 0; } } TextureTarget TextureTypeToTarget(TextureType type, GLint layerIndex) { if (type == TextureType::CubeMap) { // As GL_TEXTURE_CUBE_MAP cannot be a texture target in texImage*D APIs, so we don't allow // an entire cube map to have a texture target. ASSERT(layerIndex != ImageIndex::kEntireLevel); return CubeFaceIndexToTextureTarget(layerIndex); } else { return NonCubeTextureTypeToTarget(type); } } bool IsArrayTarget(TextureTarget target) { switch (target) { case TextureTarget::_2DArray: case TextureTarget::_2DMultisampleArray: return true; default: return false; } } } // anonymous namespace ImageIndex::ImageIndex() : mType(TextureType::InvalidEnum), mLevelIndex(0), mLayerIndex(0), mLayerCount(kEntireLevel) {} ImageIndex::ImageIndex(const ImageIndex &other) = default; ImageIndex &ImageIndex::operator=(const ImageIndex &other) = default; bool ImageIndex::hasLayer() const { return mLayerIndex != kEntireLevel; } bool ImageIndex::isLayered() const { switch (mType) { case TextureType::_2DArray: case TextureType::_2DMultisampleArray: case TextureType::CubeMap: case TextureType::_3D: return mLayerIndex == kEntireLevel; default: return false; } } bool ImageIndex::has3DLayer() const { // It's quicker to check != CubeMap than calling usesTex3D, which checks multiple types. This // ASSERT validates the check gives the same result. ASSERT(!hasLayer() || ((mType != TextureType::CubeMap) == usesTex3D())); return (hasLayer() && mType != TextureType::CubeMap); } bool ImageIndex::usesTex3D() const { return mType == TextureType::_3D || mType == TextureType::_2DArray || mType == TextureType::_2DMultisampleArray; } TextureTarget ImageIndex::getTarget() const { return TextureTypeToTarget(mType, mLayerIndex); } GLint ImageIndex::cubeMapFaceIndex() const { ASSERT(mType == TextureType::CubeMap); ASSERT(mLayerIndex == kEntireLevel || mLayerIndex < static_cast(kCubeFaceCount)); return mLayerIndex; } bool ImageIndex::valid() const { return mType != TextureType::InvalidEnum; } bool ImageIndex::isEntireLevelCubeMap() const { return mType == TextureType::CubeMap && mLayerIndex == ImageIndex::kEntireLevel; } ImageIndex ImageIndex::Make2D(GLint levelIndex) { return ImageIndex(TextureType::_2D, levelIndex, kEntireLevel, 1); } ImageIndex ImageIndex::MakeRectangle(GLint levelIndex) { return ImageIndex(TextureType::Rectangle, levelIndex, kEntireLevel, 1); } ImageIndex ImageIndex::MakeCubeMapFace(TextureTarget target, GLint levelIndex) { ASSERT(IsCubeMapFaceTarget(target)); return ImageIndex(TextureType::CubeMap, levelIndex, TextureTargetToLayer(target), 1); } ImageIndex ImageIndex::Make2DArray(GLint levelIndex, GLint layerIndex) { return ImageIndex(TextureType::_2DArray, levelIndex, layerIndex, 1); } ImageIndex ImageIndex::Make2DArrayRange(GLint levelIndex, GLint layerIndex, GLint numLayers) { return ImageIndex(TextureType::_2DArray, levelIndex, layerIndex, numLayers); } ImageIndex ImageIndex::Make3D(GLint levelIndex, GLint layerIndex) { return ImageIndex(TextureType::_3D, levelIndex, layerIndex, 1); } ImageIndex ImageIndex::MakeFromTarget(TextureTarget target, GLint levelIndex, GLint depth) { return ImageIndex(TextureTargetToType(target), levelIndex, TextureTargetToLayer(target), IsArrayTarget(target) ? depth : 1); } ImageIndex ImageIndex::MakeFromType(TextureType type, GLint levelIndex, GLint layerIndex, GLint layerCount) { GLint overrideLayerCount = (type == TextureType::CubeMap && layerIndex == kEntireLevel ? kCubeFaceCount : layerCount); return ImageIndex(type, levelIndex, layerIndex, overrideLayerCount); } ImageIndex ImageIndex::Make2DMultisample() { return ImageIndex(TextureType::_2DMultisample, 0, kEntireLevel, 1); } ImageIndex ImageIndex::Make2DMultisampleArray(GLint layerIndex) { return ImageIndex(TextureType::_2DMultisampleArray, 0, layerIndex, 1); } ImageIndex ImageIndex::Make2DMultisampleArrayRange(GLint layerIndex, GLint numLayers) { return ImageIndex(TextureType::_2DMultisampleArray, 0, layerIndex, numLayers); } bool ImageIndex::operator<(const ImageIndex &b) const { return std::tie(mType, mLevelIndex, mLayerIndex, mLayerCount) < std::tie(b.mType, b.mLevelIndex, b.mLayerIndex, b.mLayerCount); } bool ImageIndex::operator==(const ImageIndex &b) const { return std::tie(mType, mLevelIndex, mLayerIndex, mLayerCount) == std::tie(b.mType, b.mLevelIndex, b.mLayerIndex, b.mLayerCount); } bool ImageIndex::operator!=(const ImageIndex &b) const { return !(*this == b); } ImageIndex::ImageIndex(TextureType type, GLint levelIndex, GLint layerIndex, GLint layerCount) : mType(type), mLevelIndex(levelIndex), mLayerIndex(layerIndex), mLayerCount(layerCount) {} ImageIndexIterator ImageIndex::getLayerIterator(GLint layerCount) const { ASSERT(mType != TextureType::_2D && !hasLayer()); return ImageIndexIterator::MakeGeneric(mType, mLevelIndex, mLevelIndex + 1, 0, layerCount); } ImageIndexIterator::ImageIndexIterator(const ImageIndexIterator &other) = default; ImageIndexIterator ImageIndexIterator::Make2D(GLint minMip, GLint maxMip) { return ImageIndexIterator(TextureType::_2D, Range(minMip, maxMip), Range(ImageIndex::kEntireLevel, ImageIndex::kEntireLevel), nullptr); } ImageIndexIterator ImageIndexIterator::MakeRectangle(GLint minMip, GLint maxMip) { return ImageIndexIterator(TextureType::Rectangle, Range(minMip, maxMip), Range(ImageIndex::kEntireLevel, ImageIndex::kEntireLevel), nullptr); } ImageIndexIterator ImageIndexIterator::MakeCube(GLint minMip, GLint maxMip) { return ImageIndexIterator(TextureType::CubeMap, Range(minMip, maxMip), Range(0, 6), nullptr); } ImageIndexIterator ImageIndexIterator::Make3D(GLint minMip, GLint maxMip, GLint minLayer, GLint maxLayer) { return ImageIndexIterator(TextureType::_3D, Range(minMip, maxMip), Range(minLayer, maxLayer), nullptr); } ImageIndexIterator ImageIndexIterator::Make2DArray(GLint minMip, GLint maxMip, const GLsizei *layerCounts) { return ImageIndexIterator(TextureType::_2DArray, Range(minMip, maxMip), Range(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS), layerCounts); } ImageIndexIterator ImageIndexIterator::Make2DMultisample() { return ImageIndexIterator(TextureType::_2DMultisample, Range(0, 1), Range(ImageIndex::kEntireLevel, ImageIndex::kEntireLevel), nullptr); } ImageIndexIterator ImageIndexIterator::Make2DMultisampleArray(const GLsizei *layerCounts) { return ImageIndexIterator(TextureType::_2DMultisampleArray, Range(0, 1), Range(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS), layerCounts); } ImageIndexIterator ImageIndexIterator::MakeGeneric(TextureType type, GLint minMip, GLint maxMip, GLint minLayer, GLint maxLayer) { if (type == TextureType::CubeMap) { return MakeCube(minMip, maxMip); } return ImageIndexIterator(type, Range(minMip, maxMip), Range(minLayer, maxLayer), nullptr); } ImageIndexIterator::ImageIndexIterator(TextureType type, const Range &mipRange, const Range &layerRange, const GLsizei *layerCounts) : mMipRange(mipRange), mLayerRange(layerRange), mLayerCounts(layerCounts), mCurrentIndex(type, mipRange.low(), layerRange.low(), 1) {} GLint ImageIndexIterator::maxLayer() const { if (mLayerCounts) { ASSERT(mCurrentIndex.hasLayer()); return (mCurrentIndex.getLevelIndex() < mMipRange.high()) ? mLayerCounts[mCurrentIndex.getLevelIndex()] : 0; } return mLayerRange.high(); } ImageIndex ImageIndexIterator::next() { ASSERT(hasNext()); // Make a copy of the current index to return ImageIndex previousIndex = mCurrentIndex; // Iterate layers in the inner loop for now. We can add switchable // layer or mip iteration if we need it. if (mCurrentIndex.hasLayer() && mCurrentIndex.getLayerIndex() < maxLayer() - 1) { mCurrentIndex.mLayerIndex++; } else if (mCurrentIndex.mLevelIndex < mMipRange.high() - 1) { mCurrentIndex.mLayerIndex = mLayerRange.low(); mCurrentIndex.mLevelIndex++; } else { mCurrentIndex = ImageIndex(); } return previousIndex; } ImageIndex ImageIndexIterator::current() const { return mCurrentIndex; } bool ImageIndexIterator::hasNext() const { return mCurrentIndex.valid(); } } // namespace gl