| /*------------------------------------------------------------------------- |
| * drawElements Quality Program OpenGL ES Utilities |
| * ------------------------------------------------ |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Texture classes. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "gluTexture.hpp" |
| #include "gluTextureUtil.hpp" |
| #include "deFilePath.hpp" |
| #include "tcuImageIO.hpp" |
| #include "tcuSurface.hpp" |
| #include "tcuTextureUtil.hpp" |
| |
| #include "glwFunctions.hpp" |
| #include "glwEnums.hpp" |
| |
| #include "deUniquePtr.hpp" |
| |
| using std::vector; |
| |
| namespace glu |
| { |
| |
| static inline int computePixelStore (const tcu::TextureFormat& format) |
| { |
| int pixelSize = format.getPixelSize(); |
| if (deIsPowerOfTwo32(pixelSize)) |
| return de::min(pixelSize, 8); |
| else |
| return 1; |
| } |
| |
| // Texture1D |
| |
| Texture1D::Texture1D (const RenderContext& context, deUint32 format, deUint32 dataType, int width) |
| : m_context (context) |
| , m_format (format) |
| , m_refTexture (mapGLTransferFormat(format, dataType), width) |
| , m_glTexture (0) |
| { |
| const glw::Functions& gl = context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| Texture1D::Texture1D (const RenderContext& context, deUint32 sizedFormat, int width) |
| : m_context (context) |
| , m_format (sizedFormat) |
| , m_refTexture (mapGLInternalFormat(sizedFormat), width) |
| , m_glTexture (0) |
| { |
| const glw::Functions& gl = context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| Texture1D::~Texture1D (void) |
| { |
| if (m_glTexture) |
| m_context.getFunctions().deleteTextures(1, &m_glTexture); |
| } |
| |
| void Texture1D::upload (void) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| |
| TCU_CHECK(m_glTexture); |
| gl.bindTexture(GL_TEXTURE_1D, m_glTexture); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, computePixelStore(m_refTexture.getFormat())); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| |
| TransferFormat transferFormat = getTransferFormat(m_refTexture.getFormat()); |
| |
| for (int levelNdx = 0; levelNdx < m_refTexture.getNumLevels(); levelNdx++) |
| { |
| if (m_refTexture.isLevelEmpty(levelNdx)) |
| continue; // Don't upload. |
| |
| tcu::ConstPixelBufferAccess access = m_refTexture.getLevel(levelNdx); |
| gl.texImage1D(GL_TEXTURE_1D, levelNdx, m_format, access.getWidth(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr()); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| } |
| |
| // Texture2D |
| |
| Texture2D::Texture2D (const RenderContext& context, deUint32 format, deUint32 dataType, int width, int height) |
| : m_context (context) |
| , m_isCompressed (false) |
| , m_format (format) |
| , m_refTexture (mapGLTransferFormat(format, dataType), width, height) |
| , m_glTexture (0) |
| { |
| const glw::Functions& gl = context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| Texture2D::Texture2D (const RenderContext& context, deUint32 sizedFormat, int width, int height) |
| : m_context (context) |
| , m_isCompressed (false) |
| , m_format (sizedFormat) |
| , m_refTexture (mapGLInternalFormat(sizedFormat), width, height) |
| , m_glTexture (0) |
| { |
| const glw::Functions& gl = context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| Texture2D::Texture2D (const RenderContext& context, const ContextInfo& contextInfo, int numLevels, const tcu::CompressedTexture* levels, const tcu::TexDecompressionParams& decompressionParams) |
| : m_context (context) |
| , m_isCompressed (true) |
| , m_format (getGLFormat(levels[0].getFormat())) |
| , m_refTexture (getUncompressedFormat(levels[0].getFormat()), levels[0].getWidth(), levels[0].getHeight()) |
| , m_glTexture (0) |
| { |
| const glw::Functions& gl = context.getFunctions(); |
| |
| if (!contextInfo.isCompressedTextureFormatSupported(m_format)) |
| TCU_THROW(NotSupportedError, "Compressed texture format not supported"); |
| |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| |
| try |
| { |
| loadCompressed(numLevels, levels, decompressionParams); |
| } |
| catch (const std::exception&) |
| { |
| gl.deleteTextures(1, &m_glTexture); |
| throw; |
| } |
| } |
| |
| Texture2D::~Texture2D (void) |
| { |
| if (m_glTexture) |
| m_context.getFunctions().deleteTextures(1, &m_glTexture); |
| } |
| |
| void Texture2D::upload (void) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| |
| DE_ASSERT(!m_isCompressed); |
| |
| TCU_CHECK(m_glTexture); |
| gl.bindTexture(GL_TEXTURE_2D, m_glTexture); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, computePixelStore(m_refTexture.getFormat())); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| |
| TransferFormat transferFormat = getTransferFormat(m_refTexture.getFormat()); |
| |
| for (int levelNdx = 0; levelNdx < m_refTexture.getNumLevels(); levelNdx++) |
| { |
| if (m_refTexture.isLevelEmpty(levelNdx)) |
| continue; // Don't upload. |
| |
| tcu::ConstPixelBufferAccess access = m_refTexture.getLevel(levelNdx); |
| DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize()*access.getWidth()); |
| gl.texImage2D(GL_TEXTURE_2D, levelNdx, m_format, access.getWidth(), access.getHeight(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr()); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| } |
| |
| void Texture2D::loadCompressed (int numLevels, const tcu::CompressedTexture* levels, const tcu::TexDecompressionParams& decompressionParams) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| deUint32 compressedFormat = getGLFormat(levels[0].getFormat()); |
| |
| TCU_CHECK(m_glTexture); |
| gl.bindTexture(GL_TEXTURE_2D, m_glTexture); |
| |
| for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) |
| { |
| const tcu::CompressedTexture& level = levels[levelNdx]; |
| |
| // Decompress to reference texture. |
| m_refTexture.allocLevel(levelNdx); |
| tcu::PixelBufferAccess refLevelAccess = m_refTexture.getLevel(levelNdx); |
| TCU_CHECK(level.getWidth() == refLevelAccess.getWidth() && |
| level.getHeight() == refLevelAccess.getHeight()); |
| level.decompress(refLevelAccess, decompressionParams); |
| |
| // Upload to GL texture in compressed form. |
| gl.compressedTexImage2D(GL_TEXTURE_2D, levelNdx, compressedFormat, |
| level.getWidth(), level.getHeight(), 0 /* border */, level.getDataSize(), level.getData()); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| } |
| |
| Texture2D* Texture2D::create (const RenderContext& context, const ContextInfo& contextInfo, const tcu::Archive& archive, int numLevels, const char* const* levelFileNames) |
| { |
| DE_ASSERT(numLevels > 0); |
| |
| std::string ext = de::FilePath(levelFileNames[0]).getFileExtension(); |
| |
| if (ext == "png") |
| { |
| // Uncompressed texture. |
| |
| tcu::TextureLevel level; |
| |
| // Load level 0. |
| tcu::ImageIO::loadPNG(level, archive, levelFileNames[0]); |
| |
| TCU_CHECK_INTERNAL(level.getFormat() == tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8) || |
| level.getFormat() == tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8)); |
| |
| bool isRGBA = level.getFormat() == tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8); |
| Texture2D* texture = new Texture2D(context, isRGBA ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, level.getWidth(), level.getHeight()); |
| |
| try |
| { |
| // Fill level 0. |
| texture->getRefTexture().allocLevel(0); |
| tcu::copy(texture->getRefTexture().getLevel(0), level.getAccess()); |
| |
| // Fill remaining levels. |
| for (int levelNdx = 1; levelNdx < numLevels; levelNdx++) |
| { |
| tcu::ImageIO::loadPNG(level, archive, levelFileNames[levelNdx]); |
| |
| texture->getRefTexture().allocLevel(levelNdx); |
| tcu::copy(texture->getRefTexture().getLevel(levelNdx), level.getAccess()); |
| } |
| |
| // Upload data. |
| texture->upload(); |
| } |
| catch (const std::exception&) |
| { |
| delete texture; |
| throw; |
| } |
| |
| return texture; |
| } |
| else if (ext == "pkm") |
| { |
| // Compressed texture. |
| vector<tcu::CompressedTexture> levels(numLevels); |
| |
| for (int ndx = 0; ndx < numLevels; ndx++) |
| tcu::ImageIO::loadPKM(levels[ndx], archive, levelFileNames[ndx]); |
| |
| return new Texture2D(context, contextInfo, numLevels, &levels[0]); |
| } |
| else |
| TCU_FAIL("Unsupported file format"); |
| } |
| |
| Texture2D* Texture2D::create (const RenderContext& context, const ContextInfo& contextInfo, const tcu::Archive& archive, int numLevels, const std::vector<std::string>& filenames) |
| { |
| TCU_CHECK(numLevels == (int)filenames.size()); |
| |
| std::vector<const char*> charPtrs(filenames.size()); |
| for (int ndx = 0; ndx < (int)filenames.size(); ndx++) |
| charPtrs[ndx] = filenames[ndx].c_str(); |
| |
| return Texture2D::create(context, contextInfo, archive, numLevels, &charPtrs[0]); |
| } |
| |
| // ImmutableTexture2D |
| |
| ImmutableTexture2D::ImmutableTexture2D (const RenderContext& context, deUint32 sizedFormat, int width, int height) |
| : Texture2D(context, sizedFormat, width, height) |
| { |
| } |
| |
| void ImmutableTexture2D::upload (void) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| |
| DE_ASSERT(!m_isCompressed); |
| |
| TCU_CHECK(m_glTexture); |
| gl.bindTexture(GL_TEXTURE_2D, m_glTexture); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, computePixelStore(m_refTexture.getFormat())); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| |
| TransferFormat transferFormat = getTransferFormat(m_refTexture.getFormat()); |
| |
| gl.texStorage2D(GL_TEXTURE_2D, m_refTexture.getNumLevels(), m_format, m_refTexture.getWidth(), m_refTexture.getHeight()); |
| for (int levelNdx = 0; levelNdx < m_refTexture.getNumLevels(); levelNdx++) |
| { |
| if (m_refTexture.isLevelEmpty(levelNdx)) |
| continue; // Don't upload. |
| |
| tcu::ConstPixelBufferAccess access = m_refTexture.getLevel(levelNdx); |
| DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize()*access.getWidth()); |
| gl.texSubImage2D(GL_TEXTURE_2D, levelNdx, 0, 0, access.getWidth(), access.getHeight(), transferFormat.format, transferFormat.dataType, access.getDataPtr()); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| } |
| |
| // TextureCube |
| |
| TextureCube::TextureCube (const RenderContext& context, const ContextInfo& contextInfo, int numLevels, const tcu::CompressedTexture* levels, const tcu::TexDecompressionParams& decompressionParams) |
| : m_context (context) |
| , m_isCompressed (true) |
| , m_format (getGLFormat(levels[0].getFormat())) |
| , m_refTexture (getUncompressedFormat(levels[0].getFormat()), levels[0].getWidth()) |
| , m_glTexture (0) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| |
| TCU_CHECK_INTERNAL(levels[0].getWidth() == levels[0].getHeight()); |
| |
| if (!contextInfo.isCompressedTextureFormatSupported(m_format)) |
| throw tcu::NotSupportedError("Compressed texture format not supported", "", __FILE__, __LINE__); |
| |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| |
| try |
| { |
| loadCompressed(numLevels, levels, decompressionParams); |
| } |
| catch (const std::exception&) |
| { |
| gl.deleteTextures(1, &m_glTexture); |
| throw; |
| } |
| } |
| |
| TextureCube::TextureCube (const RenderContext& context, deUint32 format, deUint32 dataType, int size) |
| : m_context (context) |
| , m_isCompressed (false) |
| , m_format (format) |
| , m_refTexture (mapGLTransferFormat(format, dataType), size) |
| , m_glTexture (0) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| TextureCube::TextureCube (const RenderContext& context, deUint32 internalFormat, int size) |
| : m_context (context) |
| , m_isCompressed (false) |
| , m_format (internalFormat) |
| , m_refTexture (mapGLInternalFormat(internalFormat), size) |
| , m_glTexture (0) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| TextureCube::~TextureCube (void) |
| { |
| if (m_glTexture) |
| m_context.getFunctions().deleteTextures(1, &m_glTexture); |
| } |
| |
| void TextureCube::upload (void) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| |
| DE_ASSERT(!m_isCompressed); |
| |
| TCU_CHECK(m_glTexture); |
| gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_glTexture); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, computePixelStore(m_refTexture.getFormat())); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| |
| TransferFormat transferFormat = getTransferFormat(m_refTexture.getFormat()); |
| |
| for (int face = 0; face < tcu::CUBEFACE_LAST; face++) |
| { |
| for (int levelNdx = 0; levelNdx < m_refTexture.getNumLevels(); levelNdx++) |
| { |
| if (m_refTexture.isLevelEmpty((tcu::CubeFace)face, levelNdx)) |
| continue; // Don't upload. |
| |
| tcu::ConstPixelBufferAccess access = m_refTexture.getLevelFace(levelNdx, (tcu::CubeFace)face); |
| DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize()*access.getWidth()); |
| gl.texImage2D(getGLCubeFace((tcu::CubeFace)face), levelNdx, m_format, access.getWidth(), access.getHeight(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr()); |
| } |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| } |
| |
| void TextureCube::loadCompressed (int numLevels, const tcu::CompressedTexture* levels, const tcu::TexDecompressionParams& decompressionParams) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| deUint32 compressedFormat = getGLFormat(levels[0].getFormat()); |
| |
| TCU_CHECK(m_glTexture); |
| gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_glTexture); |
| |
| for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) |
| { |
| for (int face = 0; face < tcu::CUBEFACE_LAST; face++) |
| { |
| const tcu::CompressedTexture& level = levels[levelNdx*tcu::CUBEFACE_LAST + face]; |
| |
| // Decompress to reference texture. |
| m_refTexture.allocLevel((tcu::CubeFace)face, levelNdx); |
| tcu::PixelBufferAccess refLevelAccess = m_refTexture.getLevelFace(levelNdx, (tcu::CubeFace)face); |
| TCU_CHECK(level.getWidth() == refLevelAccess.getWidth() && |
| level.getHeight() == refLevelAccess.getHeight()); |
| level.decompress(refLevelAccess, decompressionParams); |
| |
| // Upload to GL texture in compressed form. |
| gl.compressedTexImage2D(getGLCubeFace((tcu::CubeFace)face), levelNdx, compressedFormat, |
| level.getWidth(), level.getHeight(), 0 /* border */, level.getDataSize(), level.getData()); |
| } |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| } |
| |
| TextureCube* TextureCube::create (const RenderContext& context, const ContextInfo& contextInfo, const tcu::Archive& archive, int numLevels, const char* const* filenames) |
| { |
| DE_ASSERT(numLevels > 0); |
| |
| std::string ext = de::FilePath(filenames[0]).getFileExtension(); |
| |
| // \todo [2011-11-21 pyry] Support PNG images. |
| if (ext == "pkm") |
| { |
| // Compressed texture. |
| int numImages = numLevels*tcu::CUBEFACE_LAST; |
| vector<tcu::CompressedTexture> levels (numImages); |
| |
| for (int ndx = 0; ndx < numImages; ndx++) |
| tcu::ImageIO::loadPKM(levels[ndx], archive, filenames[ndx]); |
| |
| return new TextureCube(context, contextInfo, numLevels, &levels[0]); |
| } |
| else |
| TCU_FAIL("Unsupported file format"); |
| } |
| |
| TextureCube* TextureCube::create (const RenderContext& context, const ContextInfo& contextInfo, const tcu::Archive& archive, int numLevels, const std::vector<std::string>& filenames) |
| { |
| DE_STATIC_ASSERT(tcu::CUBEFACE_LAST == 6); |
| TCU_CHECK(numLevels*tcu::CUBEFACE_LAST == (int)filenames.size()); |
| |
| std::vector<const char*> charPtrs(filenames.size()); |
| for (int ndx = 0; ndx < (int)filenames.size(); ndx++) |
| charPtrs[ndx] = filenames[ndx].c_str(); |
| |
| return TextureCube::create(context, contextInfo, archive, numLevels, &charPtrs[0]); |
| } |
| |
| // Texture1DArray |
| |
| Texture1DArray::Texture1DArray (const RenderContext& context, deUint32 format, deUint32 dataType, int width, int numLevels) |
| : m_context (context) |
| , m_format (format) |
| , m_refTexture (mapGLTransferFormat(format, dataType), width, numLevels) |
| , m_glTexture (0) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| Texture1DArray::Texture1DArray (const RenderContext& context, deUint32 sizedFormat, int width, int numLevels) |
| : m_context (context) |
| , m_format (sizedFormat) |
| , m_refTexture (mapGLInternalFormat(sizedFormat), width, numLevels) |
| , m_glTexture (0) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| Texture1DArray::~Texture1DArray (void) |
| { |
| if (m_glTexture) |
| m_context.getFunctions().deleteTextures(1, &m_glTexture); |
| } |
| |
| void Texture1DArray::upload (void) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| |
| TCU_CHECK(m_glTexture); |
| gl.bindTexture(GL_TEXTURE_1D_ARRAY, m_glTexture); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, computePixelStore(m_refTexture.getFormat())); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| |
| TransferFormat transferFormat = getTransferFormat(m_refTexture.getFormat()); |
| |
| for (int levelNdx = 0; levelNdx < m_refTexture.getNumLevels(); levelNdx++) |
| { |
| if (m_refTexture.isLevelEmpty(levelNdx)) |
| continue; // Don't upload. |
| |
| tcu::ConstPixelBufferAccess access = m_refTexture.getLevel(levelNdx); |
| DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize()*access.getWidth()); |
| gl.texImage2D(GL_TEXTURE_1D_ARRAY, levelNdx, m_format, access.getWidth(), access.getHeight(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr()); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| } |
| |
| // Texture2DArray |
| |
| Texture2DArray::Texture2DArray (const RenderContext& context, deUint32 format, deUint32 dataType, int width, int height, int numLevels) |
| : m_context (context) |
| , m_isCompressed (false) |
| , m_format (format) |
| , m_refTexture (mapGLTransferFormat(format, dataType), width, height, numLevels) |
| , m_glTexture (0) |
| { |
| // \todo [2013-04-08 pyry] Check support here. |
| const glw::Functions& gl = m_context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| Texture2DArray::Texture2DArray (const RenderContext& context, deUint32 sizedFormat, int width, int height, int numLevels) |
| : m_context (context) |
| , m_isCompressed (false) |
| , m_format (sizedFormat) |
| , m_refTexture (mapGLInternalFormat(sizedFormat), width, height, numLevels) |
| , m_glTexture (0) |
| { |
| // \todo [2013-04-08 pyry] Check support here. |
| const glw::Functions& gl = m_context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| Texture2DArray::Texture2DArray (const RenderContext& context, const ContextInfo& contextInfo, int numLevels, const tcu::CompressedTexture* levels, const tcu::TexDecompressionParams& decompressionParams) |
| : m_context (context) |
| , m_isCompressed (true) |
| , m_format (getGLFormat(levels[0].getFormat())) |
| , m_refTexture (getUncompressedFormat(levels[0].getFormat()), levels[0].getWidth(), levels[0].getHeight(), levels[0].getDepth()) |
| , m_glTexture (0) |
| { |
| const glw::Functions& gl = context.getFunctions(); |
| |
| if (!contextInfo.isCompressedTextureFormatSupported(m_format)) |
| throw tcu::NotSupportedError("Compressed texture format not supported", "", __FILE__, __LINE__); |
| |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| |
| try |
| { |
| loadCompressed(numLevels, levels, decompressionParams); |
| } |
| catch (const std::exception&) |
| { |
| gl.deleteTextures(1, &m_glTexture); |
| throw; |
| } |
| } |
| |
| Texture2DArray::~Texture2DArray (void) |
| { |
| if (m_glTexture) |
| m_context.getFunctions().deleteTextures(1, &m_glTexture); |
| } |
| |
| void Texture2DArray::upload (void) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| |
| if (!gl.texImage3D) |
| throw tcu::NotSupportedError("glTexImage3D() is not supported"); |
| |
| TCU_CHECK(m_glTexture); |
| gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_glTexture); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, computePixelStore(m_refTexture.getFormat())); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| |
| TransferFormat transferFormat = getTransferFormat(m_refTexture.getFormat()); |
| |
| for (int levelNdx = 0; levelNdx < m_refTexture.getNumLevels(); levelNdx++) |
| { |
| if (m_refTexture.isLevelEmpty(levelNdx)) |
| continue; // Don't upload. |
| |
| tcu::ConstPixelBufferAccess access = m_refTexture.getLevel(levelNdx); |
| DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize()*access.getWidth()); |
| DE_ASSERT(access.getSlicePitch() == access.getFormat().getPixelSize()*access.getWidth()*access.getHeight()); |
| gl.texImage3D(GL_TEXTURE_2D_ARRAY, levelNdx, m_format, access.getWidth(), access.getHeight(), access.getDepth(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr()); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| } |
| |
| void Texture2DArray::loadCompressed (int numLevels, const tcu::CompressedTexture* levels, const tcu::TexDecompressionParams& decompressionParams) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| deUint32 compressedFormat = getGLFormat(levels[0].getFormat()); |
| |
| TCU_CHECK(m_glTexture); |
| gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_glTexture); |
| |
| for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) |
| { |
| const tcu::CompressedTexture& level = levels[levelNdx]; |
| |
| // Decompress to reference texture. |
| m_refTexture.allocLevel(levelNdx); |
| tcu::PixelBufferAccess refLevelAccess = m_refTexture.getLevel(levelNdx); |
| TCU_CHECK(level.getWidth() == refLevelAccess.getWidth() && |
| level.getHeight() == refLevelAccess.getHeight() && |
| level.getDepth() == refLevelAccess.getDepth()); |
| level.decompress(refLevelAccess, decompressionParams); |
| |
| // Upload to GL texture in compressed form. |
| gl.compressedTexImage3D(GL_TEXTURE_2D_ARRAY, levelNdx, compressedFormat, |
| level.getWidth(), level.getHeight(), m_refTexture.getLevel(levelNdx).getDepth(), 0 /* border */, level.getDataSize(), level.getData()); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| } |
| |
| // Texture3D |
| |
| Texture3D::Texture3D (const RenderContext& context, deUint32 format, deUint32 dataType, int width, int height, int depth) |
| : m_context (context) |
| , m_isCompressed (false) |
| , m_format (format) |
| , m_refTexture (mapGLTransferFormat(format, dataType), width, height, depth) |
| , m_glTexture (0) |
| { |
| // \todo [2013-04-08 pyry] Check support here. |
| const glw::Functions& gl = m_context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| Texture3D::Texture3D (const RenderContext& context, deUint32 sizedFormat, int width, int height, int depth) |
| : m_context (context) |
| , m_isCompressed (false) |
| , m_format (sizedFormat) |
| , m_refTexture (mapGLInternalFormat(sizedFormat), width, height, depth) |
| , m_glTexture (0) |
| { |
| // \todo [2013-04-08 pyry] Check support here. |
| const glw::Functions& gl = m_context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| Texture3D::Texture3D (const RenderContext& context, |
| const ContextInfo& contextInfo, |
| int numLevels, |
| const tcu::CompressedTexture* levels, |
| const tcu::TexDecompressionParams& decompressionParams) |
| : m_context (context) |
| , m_isCompressed (true) |
| , m_format (getGLFormat(levels[0].getFormat())) |
| , m_refTexture (getUncompressedFormat(levels[0].getFormat()), levels[0].getWidth(), levels[0].getHeight(), levels[0].getDepth()) |
| , m_glTexture (0) |
| { |
| const glw::Functions& gl = context.getFunctions(); |
| |
| if (!contextInfo.isCompressedTextureFormatSupported(m_format)) |
| throw tcu::NotSupportedError("Compressed texture format not supported", "", __FILE__, __LINE__); |
| |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| |
| try |
| { |
| loadCompressed(numLevels, levels, decompressionParams); |
| } |
| catch (const std::exception&) |
| { |
| gl.deleteTextures(1, &m_glTexture); |
| throw; |
| } |
| } |
| |
| Texture3D::~Texture3D (void) |
| { |
| if (m_glTexture) |
| m_context.getFunctions().deleteTextures(1, &m_glTexture); |
| } |
| |
| void Texture3D::upload (void) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| |
| DE_ASSERT(!m_isCompressed); |
| |
| if (!gl.texImage3D) |
| throw tcu::NotSupportedError("glTexImage3D() is not supported"); |
| |
| TCU_CHECK(m_glTexture); |
| gl.bindTexture(GL_TEXTURE_3D, m_glTexture); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, computePixelStore(m_refTexture.getFormat())); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| |
| TransferFormat transferFormat = getTransferFormat(m_refTexture.getFormat()); |
| |
| for (int levelNdx = 0; levelNdx < m_refTexture.getNumLevels(); levelNdx++) |
| { |
| if (m_refTexture.isLevelEmpty(levelNdx)) |
| continue; // Don't upload. |
| |
| tcu::ConstPixelBufferAccess access = m_refTexture.getLevel(levelNdx); |
| DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize()*access.getWidth()); |
| DE_ASSERT(access.getSlicePitch() == access.getFormat().getPixelSize()*access.getWidth()*access.getHeight()); |
| gl.texImage3D(GL_TEXTURE_3D, levelNdx, m_format, access.getWidth(), access.getHeight(), access.getDepth(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr()); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| } |
| |
| void Texture3D::loadCompressed (int numLevels, const tcu::CompressedTexture* levels, const tcu::TexDecompressionParams& decompressionParams) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| deUint32 compressedFormat = getGLFormat(levels[0].getFormat()); |
| |
| if (!gl.compressedTexImage3D) |
| throw tcu::NotSupportedError("glCompressedTexImage3D() is not supported"); |
| |
| TCU_CHECK(m_glTexture); |
| gl.bindTexture(GL_TEXTURE_3D, m_glTexture); |
| |
| for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) |
| { |
| const tcu::CompressedTexture& level = levels[levelNdx]; |
| |
| // Decompress to reference texture. |
| m_refTexture.allocLevel(levelNdx); |
| tcu::PixelBufferAccess refLevelAccess = m_refTexture.getLevel(levelNdx); |
| TCU_CHECK(level.getWidth() == refLevelAccess.getWidth() && |
| level.getHeight() == refLevelAccess.getHeight() && |
| level.getDepth() == refLevelAccess.getDepth()); |
| level.decompress(refLevelAccess, decompressionParams); |
| |
| // Upload to GL texture in compressed form. |
| gl.compressedTexImage3D(GL_TEXTURE_3D, levelNdx, compressedFormat, |
| level.getWidth(), level.getHeight(), level.getDepth(), 0 /* border */, level.getDataSize(), level.getData()); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| } |
| |
| // TextureCubeArray |
| |
| TextureCubeArray::TextureCubeArray (const RenderContext& context, deUint32 format, deUint32 dataType, int size, int numLayers) |
| : m_context (context) |
| , m_format (format) |
| , m_refTexture (mapGLTransferFormat(format, dataType), size, numLayers) |
| , m_glTexture (0) |
| { |
| // \todo [2013-04-08 pyry] Check support here. |
| const glw::Functions& gl = m_context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| TextureCubeArray::TextureCubeArray (const RenderContext& context, deUint32 sizedFormat, int size, int numLayers) |
| : m_context (context) |
| , m_format (sizedFormat) |
| , m_refTexture (mapGLInternalFormat(sizedFormat), size, numLayers) |
| , m_glTexture (0) |
| { |
| // \todo [2013-04-08 pyry] Check support here. |
| const glw::Functions& gl = m_context.getFunctions(); |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| } |
| |
| TextureCubeArray::~TextureCubeArray (void) |
| { |
| if (m_glTexture) |
| m_context.getFunctions().deleteTextures(1, &m_glTexture); |
| } |
| |
| void TextureCubeArray::upload (void) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| |
| if (!gl.texImage3D) |
| throw tcu::NotSupportedError("glTexImage3D() is not supported"); |
| |
| TCU_CHECK(m_glTexture); |
| gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, m_glTexture); |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, computePixelStore(m_refTexture.getFormat())); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| |
| TransferFormat transferFormat = getTransferFormat(m_refTexture.getFormat()); |
| |
| for (int levelNdx = 0; levelNdx < m_refTexture.getNumLevels(); levelNdx++) |
| { |
| if (m_refTexture.isLevelEmpty(levelNdx)) |
| continue; // Don't upload. |
| |
| tcu::ConstPixelBufferAccess access = m_refTexture.getLevel(levelNdx); |
| DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize()*access.getWidth()); |
| DE_ASSERT(access.getSlicePitch() == access.getFormat().getPixelSize()*access.getWidth()*access.getHeight()); |
| gl.texImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, levelNdx, m_format, access.getWidth(), access.getHeight(), access.getDepth(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr()); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Texture upload failed"); |
| } |
| |
| // TextureBuffer |
| |
| TextureBuffer::TextureBuffer (const RenderContext& context, deUint32 internalFormat, size_t bufferSize) |
| : m_context (context) |
| , m_format (0) |
| , m_offset (0) |
| , m_size (0) |
| , m_glTexture (0) |
| , m_glBuffer (0) |
| { |
| init(internalFormat, bufferSize, 0, 0, DE_NULL); |
| } |
| |
| TextureBuffer::TextureBuffer (const RenderContext& context, deUint32 internalFormat, size_t bufferSize, size_t offset, size_t size, const void* data) |
| : m_context (context) |
| , m_format (0) |
| , m_offset (0) |
| , m_size (0) |
| , m_glTexture (0) |
| , m_glBuffer (0) |
| { |
| init(internalFormat, bufferSize, offset, size, data); |
| } |
| |
| void TextureBuffer::init (deUint32 internalFormat, size_t bufferSize, size_t offset, size_t size, const void* data) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| de::UniquePtr<ContextInfo> info (ContextInfo::create(m_context)); |
| |
| if (offset != 0 || size != 0) |
| { |
| if (!(contextSupports(m_context.getType(), glu::ApiType(3, 3, glu::PROFILE_CORE)) && info->isExtensionSupported("GL_ARB_texture_buffer_range")) |
| && !(contextSupports(m_context.getType(), glu::ApiType(3, 1, glu::PROFILE_ES)) |
| && info->isExtensionSupported("GL_EXT_texture_buffer"))) |
| { |
| throw tcu::NotSupportedError("Ranged texture buffers not supported", "", __FILE__, __LINE__); |
| } |
| } |
| else |
| { |
| if (!contextSupports(m_context.getType(), glu::ApiType(3, 3, glu::PROFILE_CORE)) |
| && !(contextSupports(m_context.getType(), glu::ApiType(3, 1, glu::PROFILE_ES)) |
| && info->isExtensionSupported("GL_EXT_texture_buffer"))) |
| { |
| throw tcu::NotSupportedError("Texture buffers not supported", "", __FILE__, __LINE__); |
| } |
| } |
| |
| m_refBuffer.setStorage(bufferSize); |
| if (data) |
| deMemcpy(m_refBuffer.getPtr(), data, (int)bufferSize); |
| |
| m_format = internalFormat; |
| m_offset = offset; |
| m_size = size; |
| |
| DE_ASSERT(size != 0 || offset == 0); |
| |
| { |
| gl.genTextures(1, &m_glTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed"); |
| |
| gl.genBuffers(1, &m_glBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed"); |
| |
| gl.bindBuffer(GL_TEXTURE_BUFFER, m_glBuffer); |
| gl.bufferData(GL_TEXTURE_BUFFER, (glw::GLsizei)m_refBuffer.size(), data, GL_STATIC_DRAW); |
| gl.bindBuffer(GL_TEXTURE_BUFFER, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create buffer"); |
| |
| gl.bindTexture(GL_TEXTURE_BUFFER, m_glTexture); |
| |
| if (offset != 0 || size != 0) |
| gl.texBufferRange(GL_TEXTURE_BUFFER, m_format, m_glBuffer, (glw::GLintptr)m_offset, (glw::GLsizeiptr)m_size); |
| else |
| gl.texBuffer(GL_TEXTURE_BUFFER, m_format, m_glBuffer); |
| |
| gl.bindTexture(GL_TEXTURE_BUFFER, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to bind buffer to texture"); |
| } |
| } |
| |
| TextureBuffer::~TextureBuffer (void) |
| { |
| if (m_glTexture) |
| m_context.getFunctions().deleteTextures(1, &m_glTexture); |
| |
| if (m_glBuffer) |
| m_context.getFunctions().deleteBuffers(1, &m_glBuffer); |
| } |
| |
| |
| const tcu::PixelBufferAccess TextureBuffer::getFullRefTexture (void) |
| { |
| const tcu::TextureFormat format = mapGLInternalFormat(m_format); |
| const size_t bufferLengthBytes = (m_size != 0) ? (m_size) : (m_refBuffer.size()); |
| const int bufferLengthPixels = (int)bufferLengthBytes / format.getPixelSize(); |
| |
| return tcu::PixelBufferAccess(format, |
| tcu::IVec3(bufferLengthPixels, 1, 1), |
| (deUint8*)m_refBuffer.getPtr() + m_offset); |
| } |
| |
| const tcu::ConstPixelBufferAccess TextureBuffer::getFullRefTexture (void) const |
| { |
| return const_cast<TextureBuffer*>(this)->getFullRefTexture(); |
| } |
| |
| void TextureBuffer::upload (void) |
| { |
| const glw::Functions& gl = m_context.getFunctions(); |
| |
| gl.bindBuffer(GL_TEXTURE_BUFFER, m_glBuffer); |
| gl.bufferData(GL_TEXTURE_BUFFER, (glw::GLsizei)m_refBuffer.size(), m_refBuffer.getPtr(), GL_STATIC_DRAW); |
| gl.bindBuffer(GL_TEXTURE_BUFFER, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to upload buffer"); |
| } |
| |
| } // glu |