/*------------------------------------------------------------------------- * 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)) 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; } } 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 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& filenames) { TCU_CHECK(numLevels == (int)filenames.size()); std::vector 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]); } // 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 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& filenames) { DE_STATIC_ASSERT(tcu::CUBEFACE_LAST == 6); TCU_CHECK(numLevels*tcu::CUBEFACE_LAST == (int)filenames.size()); std::vector 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 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.resize(bufferSize, 0); if (data) deMemcpy(&m_refBuffer[0], data, (int)bufferSize); m_format = internalFormat; m_offset = offset; m_size = size; DE_ASSERT(size != 0 || offset == 0); { const tcu::TextureFormat format = mapGLInternalFormat(internalFormat); deInt32 maxTextureSize = 0; gl.getIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTextureSize); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE) failed"); m_refTexture = tcu::PixelBufferAccess(format, de::min((int)maxTextureSize, (int)((m_size != 0 ? m_size : bufferSize) / format.getPixelSize())), 1, 1, &(m_refBuffer[m_offset])); } { 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(), &(m_refBuffer[0]), 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); } 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[0]), GL_STATIC_DRAW); gl.bindBuffer(GL_TEXTURE_BUFFER, 0); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to upload buffer"); } void TextureBuffer::bufferData (const deUint8* data, size_t size) { const glw::Functions& gl = m_context.getFunctions(); m_refBuffer = vector(data, data+size); { const tcu::TextureFormat format = mapGLInternalFormat(m_format); deInt32 maxTextureSize = 0; gl.getIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTextureSize); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE) failed"); m_refTexture = tcu::PixelBufferAccess(format, de::min((int)maxTextureSize, (int)((m_size != 0 ? m_size : m_refBuffer.size()) / format.getPixelSize())), 1, 1, &(m_refBuffer[m_offset])); } } } // glu