| // | |
| // 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 <tuple> | |
| 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); | |
| } | |
| } | |
| } // 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<GLint>(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) | |
| { | |
| return ImageIndex(TextureTargetToType(target), levelIndex, TextureTargetToLayer(target), 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<GLint>(minMip, maxMip), | |
| Range<GLint>(ImageIndex::kEntireLevel, ImageIndex::kEntireLevel), | |
| nullptr); | |
| } | |
| ImageIndexIterator ImageIndexIterator::MakeRectangle(GLint minMip, GLint maxMip) | |
| { | |
| return ImageIndexIterator(TextureType::Rectangle, Range<GLint>(minMip, maxMip), | |
| Range<GLint>(ImageIndex::kEntireLevel, ImageIndex::kEntireLevel), | |
| nullptr); | |
| } | |
| ImageIndexIterator ImageIndexIterator::MakeCube(GLint minMip, GLint maxMip) | |
| { | |
| return ImageIndexIterator(TextureType::CubeMap, Range<GLint>(minMip, maxMip), | |
| Range<GLint>(0, 6), nullptr); | |
| } | |
| ImageIndexIterator ImageIndexIterator::Make3D(GLint minMip, GLint maxMip, | |
| GLint minLayer, GLint maxLayer) | |
| { | |
| return ImageIndexIterator(TextureType::_3D, Range<GLint>(minMip, maxMip), | |
| Range<GLint>(minLayer, maxLayer), nullptr); | |
| } | |
| ImageIndexIterator ImageIndexIterator::Make2DArray(GLint minMip, GLint maxMip, | |
| const GLsizei *layerCounts) | |
| { | |
| return ImageIndexIterator(TextureType::_2DArray, Range<GLint>(minMip, maxMip), | |
| Range<GLint>(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS), | |
| layerCounts); | |
| } | |
| ImageIndexIterator ImageIndexIterator::Make2DMultisample() | |
| { | |
| return ImageIndexIterator(TextureType::_2DMultisample, Range<GLint>(0, 1), | |
| Range<GLint>(ImageIndex::kEntireLevel, ImageIndex::kEntireLevel), | |
| nullptr); | |
| } | |
| ImageIndexIterator ImageIndexIterator::Make2DMultisampleArray(const GLsizei *layerCounts) | |
| { | |
| return ImageIndexIterator(TextureType::_2DMultisampleArray, Range<GLint>(0, 1), | |
| Range<GLint>(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<GLint>(minMip, maxMip), Range<GLint>(minLayer, maxLayer), | |
| nullptr); | |
| } | |
| ImageIndexIterator::ImageIndexIterator(TextureType type, | |
| const Range<GLint> &mipRange, | |
| const Range<GLint> &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 |