/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES 3.0 Module * ------------------------------------------------- * * 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 specification tests. * * \todo [pyry] Following tests are missing: * - Specify mipmap incomplete texture, use without mipmaps, re-specify * as complete and render. * - Randomly re-specify levels to eventually reach mipmap-complete texture. *//*--------------------------------------------------------------------*/ #include "es31fTextureSpecificationTests.hpp" #include "tcuTestLog.hpp" #include "tcuImageCompare.hpp" #include "tcuTextureUtil.hpp" #include "tcuVectorUtil.hpp" #include "gluStrUtil.hpp" #include "gluTexture.hpp" #include "gluTextureUtil.hpp" #include "sglrContextUtil.hpp" #include "sglrContextWrapper.hpp" #include "sglrGLContext.hpp" #include "sglrReferenceContext.hpp" #include "glsTextureTestUtil.hpp" #include "deRandom.hpp" #include "deStringUtil.hpp" // \todo [2012-04-29 pyry] Should be named SglrUtil #include "es31fFboTestUtil.hpp" #include "glwEnums.hpp" namespace deqp { namespace gles31 { namespace Functional { using std::string; using std::vector; using std::pair; using tcu::TestLog; using tcu::Vec4; using tcu::IVec4; using tcu::UVec4; using namespace FboTestUtil; enum { VIEWPORT_WIDTH = 256, VIEWPORT_HEIGHT = 256 }; static inline int maxLevelCount (int size) { return (int)deLog2Floor32(size)+1; } template static tcu::Vector randomVector (de::Random& rnd, const tcu::Vector& minVal = tcu::Vector(0.0f), const tcu::Vector& maxVal = tcu::Vector(1.0f)) { tcu::Vector res; for (int ndx = 0; ndx < Size; ndx++) res[ndx] = rnd.getFloat(minVal[ndx], maxVal[ndx]); return res; } static tcu::CubeFace getCubeFaceFromNdx (int ndx) { switch (ndx) { case 0: return tcu::CUBEFACE_POSITIVE_X; case 1: return tcu::CUBEFACE_NEGATIVE_X; case 2: return tcu::CUBEFACE_POSITIVE_Y; case 3: return tcu::CUBEFACE_NEGATIVE_Y; case 4: return tcu::CUBEFACE_POSITIVE_Z; case 5: return tcu::CUBEFACE_NEGATIVE_Z; default: DE_ASSERT(false); return tcu::CUBEFACE_LAST; } } class TextureSpecCase : public TestCase, public sglr::ContextWrapper { public: TextureSpecCase (Context& context, const char* name, const char* desc); ~TextureSpecCase (void); IterateResult iterate (void); protected: virtual bool checkExtensionSupport (void) { return true; } virtual void createTexture (void) = DE_NULL; virtual void verifyTexture (sglr::GLContext& gles3Context, sglr::ReferenceContext& refContext) = DE_NULL; // Utilities. void renderTex (tcu::Surface& dst, deUint32 program, int width, int height); void readPixels (tcu::Surface& dst, int x, int y, int width, int height); private: TextureSpecCase (const TextureSpecCase& other); TextureSpecCase& operator= (const TextureSpecCase& other); }; TextureSpecCase::TextureSpecCase (Context& context, const char* name, const char* desc) : TestCase(context, name, desc) { } TextureSpecCase::~TextureSpecCase (void) { } TextureSpecCase::IterateResult TextureSpecCase::iterate (void) { glu::RenderContext& renderCtx = TestCase::m_context.getRenderContext(); const tcu::RenderTarget& renderTarget = renderCtx.getRenderTarget(); tcu::TestLog& log = m_testCtx.getLog(); if (renderTarget.getWidth() < VIEWPORT_WIDTH || renderTarget.getHeight() < VIEWPORT_HEIGHT) throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__); if (!checkExtensionSupport()) throw tcu::NotSupportedError("Extension not supported", "", __FILE__, __LINE__); // Context size, and viewport for GLES3.1 de::Random rnd (deStringHash(getName())); int width = deMin32(renderTarget.getWidth(), VIEWPORT_WIDTH); int height = deMin32(renderTarget.getHeight(), VIEWPORT_HEIGHT); int x = rnd.getInt(0, renderTarget.getWidth() - width); int y = rnd.getInt(0, renderTarget.getHeight() - height); // Contexts. sglr::GLContext gles31Context (renderCtx, log, sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(x, y, width, height)); sglr::ReferenceContextBuffers refBuffers (tcu::PixelFormat(8,8,8,renderTarget.getPixelFormat().alphaBits?8:0), 0 /* depth */, 0 /* stencil */, width, height); sglr::ReferenceContext refContext (sglr::ReferenceContextLimits(renderCtx), refBuffers.getColorbuffer(), refBuffers.getDepthbuffer(), refBuffers.getStencilbuffer()); // Clear color buffer. for (int ndx = 0; ndx < 2; ndx++) { setContext(ndx ? (sglr::Context*)&refContext : (sglr::Context*)&gles31Context); glClearColor(0.125f, 0.25f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); } // Construct texture using both GLES3.1 and reference contexts. for (int ndx = 0; ndx < 2; ndx++) { setContext(ndx ? (sglr::Context*)&refContext : (sglr::Context*)&gles31Context); createTexture(); TCU_CHECK(glGetError() == GL_NO_ERROR); } // Initialize case result to pass. m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); // Disable logging. gles31Context.enableLogging(0); // Verify results. verifyTexture(gles31Context, refContext); return STOP; } void TextureSpecCase::renderTex (tcu::Surface& dst, deUint32 program, int width, int height) { int targetW = getWidth(); int targetH = getHeight(); float w = (float)width / (float)targetW; float h = (float)height / (float)targetH; sglr::drawQuad(*getCurrentContext(), program, tcu::Vec3(-1.0f, -1.0f, 0.0f), tcu::Vec3(-1.0f + w*2.0f, -1.0f + h*2.0f, 0.0f)); // Read pixels back. readPixels(dst, 0, 0, width, height); } void TextureSpecCase::readPixels (tcu::Surface& dst, int x, int y, int width, int height) { dst.setSize(width, height); glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, dst.getAccess().getDataPtr()); } class TextureCubeArraySpecCase : public TextureSpecCase { public: TextureCubeArraySpecCase (Context& context, const char* name, const char* desc, const tcu::TextureFormat& format, int size, int depth, int numLevels); ~TextureCubeArraySpecCase (void); protected: virtual bool checkExtensionSupport (void); virtual void verifyTexture (sglr::GLContext& gles3Context, sglr::ReferenceContext& refContext); tcu::TextureFormat m_texFormat; tcu::TextureFormatInfo m_texFormatInfo; int m_size; int m_depth; int m_numLevels; }; TextureCubeArraySpecCase::TextureCubeArraySpecCase (Context& context, const char* name, const char* desc, const tcu::TextureFormat& format, int size, int depth, int numLevels) : TextureSpecCase (context, name, desc) , m_texFormat (format) , m_texFormatInfo (tcu::getTextureFormatInfo(format)) , m_size (size) , m_depth (depth) , m_numLevels (numLevels) { } TextureCubeArraySpecCase::~TextureCubeArraySpecCase (void) { } bool TextureCubeArraySpecCase::checkExtensionSupport (void) { return m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_cube_map_array"); } void TextureCubeArraySpecCase::verifyTexture (sglr::GLContext& gles3Context, sglr::ReferenceContext& refContext) { TextureCubeArrayShader shader (glu::getSamplerCubeArrayType(m_texFormat), glu::TYPE_FLOAT_VEC4); deUint32 shaderIDgles = gles3Context.createProgram(&shader); deUint32 shaderIDRef = refContext.createProgram(&shader); shader.setTexScaleBias(m_texFormatInfo.lookupScale, m_texFormatInfo.lookupBias); // Set state. for (int ndx = 0; ndx < 2; ndx++) { sglr::Context* ctx = ndx ? static_cast(&refContext) : static_cast(&gles3Context); setContext(ctx); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAX_LEVEL, m_numLevels-1); } for (int layerFaceNdx = 0; layerFaceNdx < m_depth; layerFaceNdx++) { const int layerNdx = layerFaceNdx / 6; const tcu::CubeFace face = getCubeFaceFromNdx(layerFaceNdx % 6); bool layerOk = true; shader.setLayer(layerNdx); shader.setFace(face); for (int levelNdx = 0; levelNdx < m_numLevels; levelNdx++) { int levelSize = de::max(1, m_size >> levelNdx); tcu::Surface reference; tcu::Surface result; if (levelSize <= 2) continue; // Fuzzy compare doesn't work for images this small. for (int ndx = 0; ndx < 2; ndx++) { tcu::Surface& dst = ndx ? reference : result; sglr::Context* ctx = ndx ? static_cast(&refContext) : static_cast(&gles3Context); deUint32 shaderID = ndx ? shaderIDRef : shaderIDgles; setContext(ctx); shader.setUniforms(*ctx, shaderID); renderTex(dst, shaderID, levelSize, levelSize); } const float threshold = 0.02f; string levelStr = de::toString(levelNdx); string layerFaceStr = de::toString(layerFaceNdx); string name = string("LayerFace") + layerFaceStr + "Level" + levelStr; string desc = string("Layer-face ") + layerFaceStr + ", Level " + levelStr; bool isFaceOk = tcu::fuzzyCompare(m_testCtx.getLog(), name.c_str(), desc.c_str(), reference, result, threshold, (levelNdx == 0 && layerFaceNdx == 0) == 0 ? tcu::COMPARE_LOG_RESULT : tcu::COMPARE_LOG_ON_ERROR); if (!isFaceOk) { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); layerOk = false; break; } } if (!layerOk) break; } } // Basic TexImage3D() with cube map array texture usage class BasicTexImageCubeArrayCase : public TextureCubeArraySpecCase { public: BasicTexImageCubeArrayCase (Context& context, const char* name, const char* desc, deUint32 internalFormat, int size, int numLayers) : TextureCubeArraySpecCase (context, name, desc, glu::mapGLInternalFormat(internalFormat), size, numLayers, maxLevelCount(size)) , m_internalFormat (internalFormat) { } protected: void createTexture (void) { deUint32 tex = 0; tcu::TextureLevel levelData (m_texFormat); de::Random rnd (deStringHash(getName())); glu::TransferFormat transferFmt = glu::getTransferFormat(m_texFormat); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); for (int ndx = 0; ndx < m_numLevels; ndx++) { int levelW = de::max(1, m_size >> ndx); Vec4 gMin = randomVector<4>(rnd, m_texFormatInfo.valueMin, m_texFormatInfo.valueMax); Vec4 gMax = randomVector<4>(rnd, m_texFormatInfo.valueMin, m_texFormatInfo.valueMax); levelData.setSize(levelW, levelW, m_depth); tcu::fillWithComponentGradients(levelData.getAccess(), gMin, gMax); glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, ndx, m_internalFormat, levelW, levelW, m_depth, 0, transferFmt.format, transferFmt.dataType, levelData.getAccess().getDataPtr()); } } deUint32 m_internalFormat; }; // Basic glTexStorage3D() with cube map array texture usage class BasicTexStorageCubeArrayCase : public TextureCubeArraySpecCase { public: BasicTexStorageCubeArrayCase (Context& context, const char* name, const char* desc, deUint32 internalFormat, int size, int numLayers, int numLevels) : TextureCubeArraySpecCase (context, name, desc, glu::mapGLInternalFormat(internalFormat), size, numLayers, numLevels) , m_internalFormat (internalFormat) { } protected: void createTexture (void) { deUint32 tex = 0; tcu::TextureLevel levelData (m_texFormat); de::Random rnd (deStringHash(getName())); glu::TransferFormat transferFmt = glu::getTransferFormat(m_texFormat); glGenTextures (1, &tex); glBindTexture (GL_TEXTURE_CUBE_MAP_ARRAY, tex); glTexStorage3D (GL_TEXTURE_CUBE_MAP_ARRAY, m_numLevels, m_internalFormat, m_size, m_size, m_depth); glPixelStorei (GL_UNPACK_ALIGNMENT, 1); for (int ndx = 0; ndx < m_numLevels; ndx++) { int levelW = de::max(1, m_size >> ndx); Vec4 gMin = randomVector<4>(rnd, m_texFormatInfo.valueMin, m_texFormatInfo.valueMax); Vec4 gMax = randomVector<4>(rnd, m_texFormatInfo.valueMin, m_texFormatInfo.valueMax); levelData.setSize(levelW, levelW, m_depth); tcu::fillWithComponentGradients(levelData.getAccess(), gMin, gMax); glTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, ndx, 0, 0, 0, levelW, levelW, m_depth, transferFmt.format, transferFmt.dataType, levelData.getAccess().getDataPtr()); } } deUint32 m_internalFormat; }; // Pixel buffer object cases. // TexImage3D() cube map array from pixel buffer object. class TexImageCubeArrayBufferCase : public TextureCubeArraySpecCase { public: TexImageCubeArrayBufferCase (Context& context, const char* name, const char* desc, deUint32 internalFormat, int size, int depth, int imageHeight, int rowLength, int skipImages, int skipRows, int skipPixels, int alignment, int offset) : TextureCubeArraySpecCase (context, name, desc, glu::mapGLInternalFormat(internalFormat), size, depth, 1) , m_internalFormat (internalFormat) , m_imageHeight (imageHeight) , m_rowLength (rowLength) , m_skipImages (skipImages) , m_skipRows (skipRows) , m_skipPixels (skipPixels) , m_alignment (alignment) , m_offset (offset) { } protected: void createTexture (void) { glu::TransferFormat transferFmt = glu::getTransferFormat(m_texFormat); int pixelSize = m_texFormat.getPixelSize(); int rowLength = m_rowLength > 0 ? m_rowLength : m_size; int rowPitch = deAlign32(rowLength*pixelSize, m_alignment); int imageHeight = m_imageHeight > 0 ? m_imageHeight : m_size; int slicePitch = imageHeight*rowPitch; deUint32 tex = 0; deUint32 buf = 0; vector data; DE_ASSERT(m_numLevels == 1); // Fill data with grid. data.resize(slicePitch*(m_depth+m_skipImages) + m_offset); { Vec4 cScale = m_texFormatInfo.valueMax-m_texFormatInfo.valueMin; Vec4 cBias = m_texFormatInfo.valueMin; Vec4 colorA = Vec4(1.0f, 0.0f, 0.0f, 1.0f)*cScale + cBias; Vec4 colorB = Vec4(0.0f, 1.0f, 0.0f, 1.0f)*cScale + cBias; tcu::fillWithGrid(tcu::PixelBufferAccess(m_texFormat, m_size, m_size, m_depth, rowPitch, slicePitch, &data[0] + m_skipImages*slicePitch + m_skipRows*rowPitch + m_skipPixels*pixelSize + m_offset), 4, colorA, colorB); } glGenBuffers(1, &buf); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buf); glBufferData(GL_PIXEL_UNPACK_BUFFER, (int)data.size(), &data[0], GL_STATIC_DRAW); glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, m_imageHeight); glPixelStorei(GL_UNPACK_ROW_LENGTH, m_rowLength); glPixelStorei(GL_UNPACK_SKIP_IMAGES, m_skipImages); glPixelStorei(GL_UNPACK_SKIP_ROWS, m_skipRows); glPixelStorei(GL_UNPACK_SKIP_PIXELS, m_skipPixels); glPixelStorei(GL_UNPACK_ALIGNMENT, m_alignment); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex); glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, m_internalFormat, m_size, m_size, m_depth, 0, transferFmt.format, transferFmt.dataType, (const void*)(deUintptr)m_offset); } deUint32 m_internalFormat; int m_imageHeight; int m_rowLength; int m_skipImages; int m_skipRows; int m_skipPixels; int m_alignment; int m_offset; }; // TexSubImage3D() cube map array PBO case. class TexSubImageCubeArrayBufferCase : public TextureCubeArraySpecCase { public: TexSubImageCubeArrayBufferCase (Context& context, const char* name, const char* desc, deUint32 internalFormat, int size, int depth, int subX, int subY, int subZ, int subW, int subH, int subD, int imageHeight, int rowLength, int skipImages, int skipRows, int skipPixels, int alignment, int offset) : TextureCubeArraySpecCase (context, name, desc, glu::mapGLInternalFormat(internalFormat), size, depth, 1) , m_internalFormat (internalFormat) , m_subX (subX) , m_subY (subY) , m_subZ (subZ) , m_subW (subW) , m_subH (subH) , m_subD (subD) , m_imageHeight (imageHeight) , m_rowLength (rowLength) , m_skipImages (skipImages) , m_skipRows (skipRows) , m_skipPixels (skipPixels) , m_alignment (alignment) , m_offset (offset) { } protected: void createTexture (void) { glu::TransferFormat transferFmt = glu::getTransferFormat(m_texFormat); int pixelSize = m_texFormat.getPixelSize(); deUint32 tex = 0; deUint32 buf = 0; vector data; DE_ASSERT(m_numLevels == 1); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex); // Fill with gradient. { int rowPitch = deAlign32(pixelSize*m_size, 4); int slicePitch = rowPitch*m_size; data.resize(slicePitch*m_depth); tcu::fillWithComponentGradients(tcu::PixelBufferAccess(m_texFormat, m_size, m_size, m_depth, rowPitch, slicePitch, &data[0]), m_texFormatInfo.valueMin, m_texFormatInfo.valueMax); } glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, m_internalFormat, m_size, m_size, m_depth, 0, transferFmt.format, transferFmt.dataType, &data[0]); // Fill data with grid. { int rowLength = m_rowLength > 0 ? m_rowLength : m_subW; int rowPitch = deAlign32(rowLength*pixelSize, m_alignment); int imageHeight = m_imageHeight > 0 ? m_imageHeight : m_subH; int slicePitch = imageHeight*rowPitch; Vec4 cScale = m_texFormatInfo.valueMax-m_texFormatInfo.valueMin; Vec4 cBias = m_texFormatInfo.valueMin; Vec4 colorA = Vec4(1.0f, 0.0f, 0.0f, 1.0f)*cScale + cBias; Vec4 colorB = Vec4(0.0f, 1.0f, 0.0f, 1.0f)*cScale + cBias; data.resize(slicePitch*(m_depth+m_skipImages) + m_offset); tcu::fillWithGrid(tcu::PixelBufferAccess(m_texFormat, m_subW, m_subH, m_subD, rowPitch, slicePitch, &data[0] + m_skipImages*slicePitch + m_skipRows*rowPitch + m_skipPixels*pixelSize + m_offset), 4, colorA, colorB); } glGenBuffers(1, &buf); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buf); glBufferData(GL_PIXEL_UNPACK_BUFFER, (int)data.size(), &data[0], GL_STATIC_DRAW); glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, m_imageHeight); glPixelStorei(GL_UNPACK_ROW_LENGTH, m_rowLength); glPixelStorei(GL_UNPACK_SKIP_IMAGES, m_skipImages); glPixelStorei(GL_UNPACK_SKIP_ROWS, m_skipRows); glPixelStorei(GL_UNPACK_SKIP_PIXELS, m_skipPixels); glPixelStorei(GL_UNPACK_ALIGNMENT, m_alignment); glTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, m_subX, m_subY, m_subZ, m_subW, m_subH, m_subD, transferFmt.format, transferFmt.dataType, (const void*)(deIntptr)m_offset); } deUint32 m_internalFormat; int m_subX; int m_subY; int m_subZ; int m_subW; int m_subH; int m_subD; int m_imageHeight; int m_rowLength; int m_skipImages; int m_skipRows; int m_skipPixels; int m_alignment; int m_offset; }; // TexImage3D() depth case. class TexImageCubeArrayDepthCase : public TextureCubeArraySpecCase { public: TexImageCubeArrayDepthCase (Context& context, const char* name, const char* desc, deUint32 internalFormat, int imageSize, int numLayers) : TextureCubeArraySpecCase(context, name, desc, glu::mapGLInternalFormat(internalFormat), imageSize, numLayers, maxLevelCount(imageSize)) , m_internalFormat (internalFormat) { // we are interested in the behavior near [-2, 2], map it to visible range [0, 1] m_texFormatInfo.lookupBias = Vec4(0.25f, 0.0f, 0.0f, 1.0f); m_texFormatInfo.lookupScale = Vec4(0.5f, 1.0f, 1.0f, 0.0f); } void createTexture (void) { glu::TransferFormat fmt = glu::getTransferFormat(m_texFormat); deUint32 tex = 0; tcu::TextureLevel levelData (m_texFormat); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); GLU_CHECK(); for (int ndx = 0; ndx < m_numLevels; ndx++) { const int levelW = de::max(1, m_size >> ndx); const Vec4 gMin = Vec4(-1.5f, -2.0f, 1.7f, -1.5f); const Vec4 gMax = Vec4(2.0f, 1.5f, -1.0f, 2.0f); levelData.setSize(levelW, levelW, m_depth); tcu::fillWithComponentGradients(levelData.getAccess(), gMin, gMax); glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, ndx, m_internalFormat, levelW, levelW, m_depth, 0, fmt.format, fmt.dataType, levelData.getAccess().getDataPtr()); } } const deUint32 m_internalFormat; }; // TexSubImage3D() depth case. class TexSubImageCubeArrayDepthCase : public TextureCubeArraySpecCase { public: TexSubImageCubeArrayDepthCase (Context& context, const char* name, const char* desc, deUint32 internalFormat, int imageSize, int numLayers) : TextureCubeArraySpecCase(context, name, desc, glu::mapGLInternalFormat(internalFormat), imageSize, numLayers, maxLevelCount(imageSize)) , m_internalFormat (internalFormat) { // we are interested in the behavior near [-2, 2], map it to visible range [0, 1] m_texFormatInfo.lookupBias = Vec4(0.25f, 0.0f, 0.0f, 1.0f); m_texFormatInfo.lookupScale = Vec4(0.5f, 1.0f, 1.0f, 0.0f); } void createTexture (void) { glu::TransferFormat fmt = glu::getTransferFormat(m_texFormat); de::Random rnd (deStringHash(getName())); deUint32 tex = 0; tcu::TextureLevel levelData (m_texFormat); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); GLU_CHECK(); // First specify full texture. for (int ndx = 0; ndx < m_numLevels; ndx++) { const int levelW = de::max(1, m_size >> ndx); const Vec4 gMin = Vec4(-1.5f, -2.0f, 1.7f, -1.5f); const Vec4 gMax = Vec4(2.0f, 1.5f, -1.0f, 2.0f); levelData.setSize(levelW, levelW, m_depth); tcu::fillWithComponentGradients(levelData.getAccess(), gMin, gMax); glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, ndx, m_internalFormat, levelW, levelW, m_depth, 0, fmt.format, fmt.dataType, levelData.getAccess().getDataPtr()); } // Re-specify parts of each level. for (int ndx = 0; ndx < m_numLevels; ndx++) { const int levelW = de::max(1, m_size >> ndx); const int w = rnd.getInt(1, levelW); const int h = rnd.getInt(1, levelW); const int d = rnd.getInt(1, m_depth); const int x = rnd.getInt(0, levelW-w); const int y = rnd.getInt(0, levelW-h); const int z = rnd.getInt(0, m_depth-d); const Vec4 colorA = Vec4(2.0f, 1.5f, -1.0f, 2.0f); const Vec4 colorB = Vec4(-1.5f, -2.0f, 1.7f, -1.5f); const int cellSize = rnd.getInt(2, 16); levelData.setSize(w, h, d); tcu::fillWithGrid(levelData.getAccess(), cellSize, colorA, colorB); glTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, ndx, x, y, z, w, h, d, fmt.format, fmt.dataType, levelData.getAccess().getDataPtr()); } } const deUint32 m_internalFormat; }; // TexImage3D() depth case with pbo. class TexImageCubeArrayDepthBufferCase : public TextureCubeArraySpecCase { public: TexImageCubeArrayDepthBufferCase (Context& context, const char* name, const char* desc, deUint32 internalFormat, int imageSize, int numLayers) : TextureCubeArraySpecCase(context, name, desc, glu::mapGLInternalFormat(internalFormat), imageSize, numLayers, 1) , m_internalFormat (internalFormat) { // we are interested in the behavior near [-2, 2], map it to visible range [0, 1] m_texFormatInfo.lookupBias = Vec4(0.25f, 0.0f, 0.0f, 1.0f); m_texFormatInfo.lookupScale = Vec4(0.5f, 1.0f, 1.0f, 0.0f); } void createTexture (void) { glu::TransferFormat transferFmt = glu::getTransferFormat(m_texFormat); int pixelSize = m_texFormat.getPixelSize(); int rowLength = m_size; int alignment = 4; int rowPitch = deAlign32(rowLength*pixelSize, alignment); int imageHeight = m_size; int slicePitch = imageHeight*rowPitch; deUint32 tex = 0; deUint32 buf = 0; vector data; DE_ASSERT(m_numLevels == 1); // Fill data with grid. data.resize(slicePitch*m_depth); { const Vec4 gMin = Vec4(-1.5f, -2.0f, 1.7f, -1.5f); const Vec4 gMax = Vec4(2.0f, 1.5f, -1.0f, 2.0f); tcu::fillWithComponentGradients(tcu::PixelBufferAccess(m_texFormat, m_size, m_size, m_depth, rowPitch, slicePitch, &data[0]), gMin, gMax); } glGenBuffers(1, &buf); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buf); glBufferData(GL_PIXEL_UNPACK_BUFFER, (int)data.size(), &data[0], GL_STATIC_DRAW); glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, imageHeight); glPixelStorei(GL_UNPACK_ROW_LENGTH, rowLength); glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex); glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, m_internalFormat, m_size, m_size, m_depth, 0, transferFmt.format, transferFmt.dataType, DE_NULL); glDeleteBuffers(1, &buf); } const deUint32 m_internalFormat; }; TextureSpecificationTests::TextureSpecificationTests (Context& context) : TestCaseGroup(context, "specification", "Texture Specification Tests") { } TextureSpecificationTests::~TextureSpecificationTests (void) { } void TextureSpecificationTests::init (void) { struct { const char* name; deUint32 internalFormat; } colorFormats[] = { { "rgba32f", GL_RGBA32F, }, { "rgba32i", GL_RGBA32I, }, { "rgba32ui", GL_RGBA32UI, }, { "rgba16f", GL_RGBA16F, }, { "rgba16i", GL_RGBA16I, }, { "rgba16ui", GL_RGBA16UI, }, { "rgba8", GL_RGBA8, }, { "rgba8i", GL_RGBA8I, }, { "rgba8ui", GL_RGBA8UI, }, { "srgb8_alpha8", GL_SRGB8_ALPHA8, }, { "rgb10_a2", GL_RGB10_A2, }, { "rgb10_a2ui", GL_RGB10_A2UI, }, { "rgba4", GL_RGBA4, }, { "rgb5_a1", GL_RGB5_A1, }, { "rgba8_snorm", GL_RGBA8_SNORM, }, { "rgb8", GL_RGB8, }, { "rgb565", GL_RGB565, }, { "r11f_g11f_b10f", GL_R11F_G11F_B10F, }, { "rgb32f", GL_RGB32F, }, { "rgb32i", GL_RGB32I, }, { "rgb32ui", GL_RGB32UI, }, { "rgb16f", GL_RGB16F, }, { "rgb16i", GL_RGB16I, }, { "rgb16ui", GL_RGB16UI, }, { "rgb8_snorm", GL_RGB8_SNORM, }, { "rgb8i", GL_RGB8I, }, { "rgb8ui", GL_RGB8UI, }, { "srgb8", GL_SRGB8, }, { "rgb9_e5", GL_RGB9_E5, }, { "rg32f", GL_RG32F, }, { "rg32i", GL_RG32I, }, { "rg32ui", GL_RG32UI, }, { "rg16f", GL_RG16F, }, { "rg16i", GL_RG16I, }, { "rg16ui", GL_RG16UI, }, { "rg8", GL_RG8, }, { "rg8i", GL_RG8I, }, { "rg8ui", GL_RG8UI, }, { "rg8_snorm", GL_RG8_SNORM, }, { "r32f", GL_R32F, }, { "r32i", GL_R32I, }, { "r32ui", GL_R32UI, }, { "r16f", GL_R16F, }, { "r16i", GL_R16I, }, { "r16ui", GL_R16UI, }, { "r8", GL_R8, }, { "r8i", GL_R8I, }, { "r8ui", GL_R8UI, }, { "r8_snorm", GL_R8_SNORM, } }; static const struct { const char* name; deUint32 internalFormat; } depthStencilFormats[] = { // Depth and stencil formats { "depth_component32f", GL_DEPTH_COMPONENT32F }, { "depth_component24", GL_DEPTH_COMPONENT24 }, { "depth_component16", GL_DEPTH_COMPONENT16 }, { "depth32f_stencil8", GL_DEPTH32F_STENCIL8 }, { "depth24_stencil8", GL_DEPTH24_STENCIL8 } }; // Basic TexImage3D usage. { tcu::TestCaseGroup* basicTexImageGroup = new tcu::TestCaseGroup(m_testCtx, "basic_teximage3d", "Basic glTexImage3D() usage"); addChild(basicTexImageGroup); for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(colorFormats); formatNdx++) { const char* fmtName = colorFormats[formatNdx].name; deUint32 format = colorFormats[formatNdx].internalFormat; const int texCubeArraySize = 64; const int texCubeArrayLayers = 6; basicTexImageGroup->addChild(new BasicTexImageCubeArrayCase (m_context, (string(fmtName) + "_cube_array").c_str(), "", format, texCubeArraySize, texCubeArrayLayers)); } } // glTexImage3D() pbo cases. { tcu::TestCaseGroup* pboGroup = new tcu::TestCaseGroup(m_testCtx, "teximage3d_pbo", "glTexImage3D() from PBO"); addChild(pboGroup); // Parameter cases static const struct { const char* name; deUint32 format; int size; int depth; int imageHeight; int rowLength; int skipImages; int skipRows; int skipPixels; int alignment; int offset; } parameterCases[] = { { "rgb8_offset", GL_RGB8, 23, 6, 0, 0, 0, 0, 0, 1, 67 }, { "rgb8_alignment", GL_RGB8, 23, 6, 0, 0, 0, 0, 0, 2, 0 }, { "rgb8_image_height", GL_RGB8, 23, 6, 26, 0, 0, 0, 0, 4, 0 }, { "rgb8_row_length", GL_RGB8, 23, 6, 0, 27, 0, 0, 0, 4, 0 }, { "rgb8_skip_images", GL_RGB8, 23, 6, 0, 0, 3, 0, 0, 4, 0 }, { "rgb8_skip_rows", GL_RGB8, 23, 6, 26, 0, 0, 3, 0, 4, 0 }, { "rgb8_skip_pixels", GL_RGB8, 23, 6, 0, 25, 0, 0, 2, 4, 0 } }; for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(colorFormats); formatNdx++) { const string fmtName = colorFormats[formatNdx].name; const deUint32 format = colorFormats[formatNdx].internalFormat; const int texCubeArraySize = 20; const int texCubeDepth = 6; pboGroup->addChild(new TexImageCubeArrayBufferCase (m_context, (fmtName + "_cube_array").c_str(), "", format, texCubeArraySize, texCubeDepth, 0, 0, 0, 0, 0, 4, 0)); } for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(parameterCases); ndx++) { pboGroup->addChild(new TexImageCubeArrayBufferCase(m_context, (string(parameterCases[ndx].name) + "_cube_array").c_str(), "", parameterCases[ndx].format, parameterCases[ndx].size, parameterCases[ndx].depth, parameterCases[ndx].imageHeight, parameterCases[ndx].rowLength, parameterCases[ndx].skipImages, parameterCases[ndx].skipRows, parameterCases[ndx].skipPixels, parameterCases[ndx].alignment, parameterCases[ndx].offset)); } } // glTexImage3D() depth cases. { tcu::TestCaseGroup* shadow3dGroup = new tcu::TestCaseGroup(m_testCtx, "teximage3d_depth", "glTexImage3D() with depth or depth/stencil format"); addChild(shadow3dGroup); for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(depthStencilFormats); ndx++) { const int texCubeArraySize = 64; const int texCubeArrayDepth = 6; shadow3dGroup->addChild(new TexImageCubeArrayDepthCase(m_context, (std::string(depthStencilFormats[ndx].name) + "_cube_array").c_str(), "", depthStencilFormats[ndx].internalFormat, texCubeArraySize, texCubeArrayDepth)); } } // glTexImage3D() depth cases with pbo. { tcu::TestCaseGroup* shadow3dGroup = new tcu::TestCaseGroup(m_testCtx, "teximage3d_depth_pbo", "glTexImage3D() with depth or depth/stencil format with pbo"); addChild(shadow3dGroup); for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(depthStencilFormats); ndx++) { const int texCubeArraySize = 64; const int texCubeArrayDepth = 6; shadow3dGroup->addChild(new TexImageCubeArrayDepthBufferCase(m_context, (std::string(depthStencilFormats[ndx].name) + "_cube_array").c_str(), "", depthStencilFormats[ndx].internalFormat, texCubeArraySize, texCubeArrayDepth)); } } // glTexSubImage3D() PBO cases. { tcu::TestCaseGroup* pboGroup = new tcu::TestCaseGroup(m_testCtx, "texsubimage3d_pbo", "glTexSubImage3D() pixel buffer object tests"); addChild(pboGroup); static const struct { const char* name; deUint32 format; int size; int depth; int subX; int subY; int subZ; int subW; int subH; int subD; int imageHeight; int rowLength; int skipImages; int skipRows; int skipPixels; int alignment; int offset; } paramCases[] = { { "rgb8_offset", GL_RGB8, 26, 12, 1, 2, 1, 23, 19, 8, 0, 0, 0, 0, 0, 4, 67 }, { "rgb8_image_height", GL_RGB8, 26, 12, 1, 2, 1, 23, 19, 8, 26, 0, 0, 0, 0, 4, 0 }, { "rgb8_row_length", GL_RGB8, 26, 12, 1, 2, 1, 23, 19, 8, 0, 27, 0, 0, 0, 4, 0 }, { "rgb8_skip_images", GL_RGB8, 26, 12, 1, 2, 1, 23, 19, 8, 0, 0, 3, 0, 0, 4, 0 }, { "rgb8_skip_rows", GL_RGB8, 26, 12, 1, 2, 1, 23, 19, 8, 22, 0, 0, 3, 0, 4, 0 }, { "rgb8_skip_pixels", GL_RGB8, 26, 12, 1, 2, 1, 23, 19, 8, 0, 25, 0, 0, 2, 4, 0 } }; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(colorFormats); ndx++) { pboGroup->addChild(new TexSubImageCubeArrayBufferCase(m_context, (std::string(colorFormats[ndx].name) + "_cube_array").c_str(), "", colorFormats[ndx].internalFormat, 26, // Size 12, // Depth 1, // Sub X 2, // Sub Y 0, // Sub Z 23, // Sub W 19, // Sub H 8, // Sub D 0, // Image height 0, // Row length 0, // Skip images 0, // Skip rows 0, // Skip pixels 4, // Alignment 0 /* offset */)); } for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(paramCases); ndx++) { pboGroup->addChild(new TexSubImageCubeArrayBufferCase(m_context, (std::string(paramCases[ndx].name) + "_cube_array").c_str(), "", paramCases[ndx].format, paramCases[ndx].size, paramCases[ndx].depth, paramCases[ndx].subX, paramCases[ndx].subY, paramCases[ndx].subZ, paramCases[ndx].subW, paramCases[ndx].subH, paramCases[ndx].subD, paramCases[ndx].imageHeight, paramCases[ndx].rowLength, paramCases[ndx].skipImages, paramCases[ndx].skipRows, paramCases[ndx].skipPixels, paramCases[ndx].alignment, paramCases[ndx].offset)); } } // glTexSubImage3D() depth cases. { tcu::TestCaseGroup* shadow3dGroup = new tcu::TestCaseGroup(m_testCtx, "texsubimage3d_depth", "glTexSubImage3D() with depth or depth/stencil format"); addChild(shadow3dGroup); for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(depthStencilFormats); ndx++) { const int texCubeArraySize = 57; const int texCubeArrayLayers = 6; shadow3dGroup->addChild(new TexSubImageCubeArrayDepthCase(m_context, (std::string(depthStencilFormats[ndx].name) + "_cube_array").c_str(), "", depthStencilFormats[ndx].internalFormat, texCubeArraySize, texCubeArrayLayers)); } } // glTexStorage3D() cases. { tcu::TestCaseGroup* texStorageGroup = new tcu::TestCaseGroup(m_testCtx, "texstorage3d", "Basic glTexStorage3D() usage"); addChild(texStorageGroup); // All formats. tcu::TestCaseGroup* formatGroup = new tcu::TestCaseGroup(m_testCtx, "format", "glTexStorage3D() with all formats"); texStorageGroup->addChild(formatGroup); // Color formats. for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(colorFormats); formatNdx++) { const char* fmtName = colorFormats[formatNdx].name; deUint32 internalFormat = colorFormats[formatNdx].internalFormat; const int texCubeArraySize = 57; const int texCubeArrayLayers = 6; int texCubeArrayLevels = maxLevelCount(texCubeArraySize); formatGroup->addChild(new BasicTexStorageCubeArrayCase (m_context, (string(fmtName) + "_cube_array").c_str(), "", internalFormat, texCubeArraySize, texCubeArrayLayers, texCubeArrayLevels)); } // Depth/stencil formats (only 2D texture array is supported). for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormats); formatNdx++) { const char* fmtName = depthStencilFormats[formatNdx].name; deUint32 internalFormat = depthStencilFormats[formatNdx].internalFormat; const int texCubeArraySize = 57; const int texCubeArrayLayers = 6; int texCubeArrayLevels = maxLevelCount(texCubeArraySize); formatGroup->addChild(new BasicTexStorageCubeArrayCase (m_context, (string(fmtName) + "_cube_array").c_str(), "", internalFormat, texCubeArraySize, texCubeArrayLayers, texCubeArrayLevels)); } // Sizes. static const struct { int size; int layers; int levels; } texCubeArraySizes[] = { // Sz La Le { 1, 6, 1 }, { 2, 6, 2 }, { 32, 6, 3 }, { 64, 6, 4 }, { 57, 12, 1 }, { 57, 12, 2 }, { 57, 12, 6 } }; tcu::TestCaseGroup* sizeGroup = new tcu::TestCaseGroup(m_testCtx, "size", "glTexStorage3D() with various sizes"); texStorageGroup->addChild(sizeGroup); for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(texCubeArraySizes); ndx++) { const deUint32 format = GL_RGBA8; int size = texCubeArraySizes[ndx].size; int layers = texCubeArraySizes[ndx].layers; int levels = texCubeArraySizes[ndx].levels; string name = string("cube_array_") + de::toString(size) + "x" + de::toString(size) + "x" + de::toString(layers) + "_" + de::toString(levels) + "_levels"; sizeGroup->addChild(new BasicTexStorageCubeArrayCase(m_context, name.c_str(), "", format, size, layers, levels)); } } } } // Functional } // gles3 } // deqp