/*------------------------------------------------------------------------- * 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 FBO colorbuffer tests. *//*--------------------------------------------------------------------*/ #include "es3fFboColorbufferTests.hpp" #include "es3fFboTestCase.hpp" #include "es3fFboTestUtil.hpp" #include "gluTextureUtil.hpp" #include "gluContextInfo.hpp" #include "tcuImageCompare.hpp" #include "tcuRGBA.hpp" #include "tcuTestLog.hpp" #include "tcuTextureUtil.hpp" #include "sglrContextUtil.hpp" #include "deRandom.hpp" #include "deString.h" #include "glwEnums.hpp" namespace deqp { namespace gles3 { namespace Functional { using std::string; using tcu::Vec2; using tcu::Vec3; using tcu::Vec4; using tcu::IVec2; using tcu::IVec3; using tcu::IVec4; using tcu::UVec4; using tcu::TestLog; using namespace FboTestUtil; const tcu::RGBA MIN_THRESHOLD(12, 12, 12, 12); 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::Vec4 generateRandomColor (de::Random& random) { tcu::Vec4 retVal; for (int i = 0; i < 3; ++i) retVal[i] = random.getFloat(); retVal[3] = 1.0f; return retVal; } class FboColorbufferCase : public FboTestCase { public: FboColorbufferCase (Context& context, const char* name, const char* desc, const deUint32 format) : FboTestCase (context, name, desc) , m_format (format) { } bool compare (const tcu::Surface& reference, const tcu::Surface& result) { const tcu::RGBA threshold (tcu::max(getFormatThreshold(m_format), MIN_THRESHOLD)); m_testCtx.getLog() << TestLog::Message << "Comparing images, threshold: " << threshold << TestLog::EndMessage; return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(), result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT); } protected: const deUint32 m_format; }; class FboColorClearCase : public FboColorbufferCase { public: FboColorClearCase (Context& context, const char* name, const char* desc, deUint32 format, int width, int height) : FboColorbufferCase (context, name, desc, format) , m_width (width) , m_height (height) { } protected: void preCheck (void) { checkFormatSupport(m_format); } void render (tcu::Surface& dst) { tcu::TextureFormat fboFormat = glu::mapGLInternalFormat(m_format); tcu::TextureChannelClass fmtClass = tcu::getTextureChannelClass(fboFormat.type); tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(fboFormat); de::Random rnd (17); const int numClears = 16; deUint32 fbo = 0; deUint32 rbo = 0; glGenFramebuffers(1, &fbo); glGenRenderbuffers(1, &rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo); glRenderbufferStorage(GL_RENDERBUFFER, m_format, m_width, m_height); checkError(); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); checkError(); checkFramebufferStatus(GL_FRAMEBUFFER); glViewport(0, 0, m_width, m_height); // Initialize to transparent black. switch (fmtClass) { case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: glClearBufferfv(GL_COLOR, 0, Vec4(0.0f).getPtr()); break; case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: glClearBufferuiv(GL_COLOR, 0, UVec4(0).getPtr()); break; case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: glClearBufferiv(GL_COLOR, 0, IVec4(0).getPtr()); break; default: DE_ASSERT(DE_FALSE); } // Do random scissored clears. glEnable(GL_SCISSOR_TEST); for (int ndx = 0; ndx < numClears; ndx++) { int x = rnd.getInt(0, m_width - 1); int y = rnd.getInt(0, m_height - 1); int w = rnd.getInt(1, m_width - x); int h = rnd.getInt(1, m_height - y); Vec4 color = randomVector<4>(rnd, fmtInfo.valueMin, fmtInfo.valueMax); glScissor(x, y, w, h); switch (fmtClass) { case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: glClearBufferfv(GL_COLOR, 0, color.getPtr()); break; case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: glClearBufferuiv(GL_COLOR, 0, color.cast().getPtr()); break; case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: glClearBufferiv(GL_COLOR, 0, color.cast().getPtr()); break; default: DE_ASSERT(DE_FALSE); } } // Read results from renderbuffer. readPixels(dst, 0, 0, m_width, m_height, fboFormat, fmtInfo.lookupScale, fmtInfo.lookupBias); checkError(); } private: const int m_width; const int m_height; }; class FboColorMultiTex2DCase : public FboColorbufferCase { public: FboColorMultiTex2DCase (Context& context, const char* name, const char* description, deUint32 tex0Fmt, const IVec2& tex0Size, deUint32 tex1Fmt, const IVec2& tex1Size) : FboColorbufferCase (context, name, description, tex0Fmt) , m_tex0Fmt (tex0Fmt) , m_tex1Fmt (tex1Fmt) , m_tex0Size (tex0Size) , m_tex1Size (tex1Size) { } protected: void preCheck (void) { checkFormatSupport(m_tex0Fmt); checkFormatSupport(m_tex1Fmt); } void render (tcu::Surface& dst) { tcu::TextureFormat texFmt0 = glu::mapGLInternalFormat(m_tex0Fmt); tcu::TextureFormat texFmt1 = glu::mapGLInternalFormat(m_tex1Fmt); tcu::TextureFormatInfo fmtInfo0 = tcu::getTextureFormatInfo(texFmt0); tcu::TextureFormatInfo fmtInfo1 = tcu::getTextureFormatInfo(texFmt1); Texture2DShader texToFbo0Shader (DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt0), fmtInfo0.valueMax-fmtInfo0.valueMin, fmtInfo0.valueMin); Texture2DShader texToFbo1Shader (DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt1), fmtInfo1.valueMax-fmtInfo1.valueMin, fmtInfo1.valueMin); Texture2DShader multiTexShader (DataTypes() << glu::getSampler2DType(texFmt0) << glu::getSampler2DType(texFmt1), glu::TYPE_FLOAT_VEC4); deUint32 texToFbo0ShaderID = getCurrentContext()->createProgram(&texToFbo0Shader); deUint32 texToFbo1ShaderID = getCurrentContext()->createProgram(&texToFbo1Shader); deUint32 multiTexShaderID = getCurrentContext()->createProgram(&multiTexShader); // Setup shaders multiTexShader.setTexScaleBias(0, fmtInfo0.lookupScale * 0.5f, fmtInfo0.lookupBias * 0.5f); multiTexShader.setTexScaleBias(1, fmtInfo1.lookupScale * 0.5f, fmtInfo1.lookupBias * 0.5f); texToFbo0Shader.setUniforms(*getCurrentContext(), texToFbo0ShaderID); texToFbo1Shader.setUniforms(*getCurrentContext(), texToFbo1ShaderID); multiTexShader.setUniforms (*getCurrentContext(), multiTexShaderID); // Framebuffers. deUint32 fbo0, fbo1; deUint32 tex0, tex1; for (int ndx = 0; ndx < 2; ndx++) { glu::TransferFormat transferFmt = glu::getTransferFormat(ndx ? texFmt1 : texFmt0); deUint32 format = ndx ? m_tex1Fmt : m_tex0Fmt; bool isFilterable = glu::isGLInternalColorFormatFilterable(format); const IVec2& size = ndx ? m_tex1Size : m_tex0Size; deUint32& fbo = ndx ? fbo1 : fbo0; deUint32& tex = ndx ? tex1 : tex0; glGenFramebuffers(1, &fbo); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, isFilterable ? GL_LINEAR : GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, isFilterable ? GL_LINEAR : GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, format, size.x(), size.y(), 0, transferFmt.format, transferFmt.dataType, DE_NULL); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); checkError(); checkFramebufferStatus(GL_FRAMEBUFFER); } // Render textures to both framebuffers. for (int ndx = 0; ndx < 2; ndx++) { const deUint32 format = GL_RGBA; const deUint32 dataType = GL_UNSIGNED_BYTE; const int texW = 128; const int texH = 128; deUint32 tmpTex = 0; deUint32 fbo = ndx ? fbo1 : fbo0; const IVec2& viewport = ndx ? m_tex1Size : m_tex0Size; tcu::TextureLevel data (glu::mapGLTransferFormat(format, dataType), texW, texH, 1); if (ndx == 0) tcu::fillWithComponentGradients(data.getAccess(), Vec4(0.0f), Vec4(1.0f)); else tcu::fillWithGrid(data.getAccess(), 8, Vec4(0.2f, 0.7f, 0.1f, 1.0f), Vec4(0.7f, 0.1f, 0.5f, 0.8f)); glGenTextures(1, &tmpTex); glBindTexture(GL_TEXTURE_2D, tmpTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr()); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glViewport(0, 0, viewport.x(), viewport.y()); sglr::drawQuad(*getCurrentContext(), ndx ? texToFbo1ShaderID : texToFbo0ShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); } // Render to framebuffer. glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, getWidth(), getHeight()); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, tex1); sglr::drawQuad(*getCurrentContext(), multiTexShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); readPixels(dst, 0, 0, getWidth(), getHeight()); } private: deUint32 m_tex0Fmt; deUint32 m_tex1Fmt; IVec2 m_tex0Size; IVec2 m_tex1Size; }; class FboColorTexCubeCase : public FboColorbufferCase { public: FboColorTexCubeCase (Context& context, const char* name, const char* description, deUint32 texFmt, const IVec2& texSize) : FboColorbufferCase (context, name, description, texFmt) , m_texSize (texSize) { } protected: void preCheck (void) { checkFormatSupport(m_format); } void render (tcu::Surface& dst) { static const deUint32 cubeGLFaces[] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; static const tcu::CubeFace cubeTexFaces[] = { tcu::CUBEFACE_POSITIVE_X, tcu::CUBEFACE_POSITIVE_Y, tcu::CUBEFACE_POSITIVE_Z, tcu::CUBEFACE_NEGATIVE_X, tcu::CUBEFACE_NEGATIVE_Y, tcu::CUBEFACE_NEGATIVE_Z }; de::Random rnd (deStringHash(getName()) ^ 0x9eef603d); tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_format); tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); Texture2DShader texToFboShader (DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt), fmtInfo.valueMax-fmtInfo.valueMin, fmtInfo.valueMin); TextureCubeShader cubeTexShader (glu::getSamplerCubeType(texFmt), glu::TYPE_FLOAT_VEC4); deUint32 texToFboShaderID = getCurrentContext()->createProgram(&texToFboShader); deUint32 cubeTexShaderID = getCurrentContext()->createProgram(&cubeTexShader); // Setup shaders texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID); cubeTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias); // Framebuffers. std::vector fbos; deUint32 tex; { glu::TransferFormat transferFmt = glu::getTransferFormat(texFmt); bool isFilterable = glu::isGLInternalColorFormatFilterable(m_format); const IVec2& size = m_texSize; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_CUBE_MAP, tex); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, isFilterable ? GL_LINEAR : GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, isFilterable ? GL_LINEAR : GL_NEAREST); // Generate an image and FBO for each cube face for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cubeGLFaces); ndx++) glTexImage2D(cubeGLFaces[ndx], 0, m_format, size.x(), size.y(), 0, transferFmt.format, transferFmt.dataType, DE_NULL); checkError(); for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cubeGLFaces); ndx++) { deUint32 layerFbo; glGenFramebuffers(1, &layerFbo); glBindFramebuffer(GL_FRAMEBUFFER, layerFbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, cubeGLFaces[ndx], tex, 0); checkError(); checkFramebufferStatus(GL_FRAMEBUFFER); fbos.push_back(layerFbo); } } // Render test images to random cube faces std::vector order; for (size_t n = 0; n < fbos.size(); n++) order.push_back((int)n); rnd.shuffle(order.begin(), order.end()); DE_ASSERT(order.size() >= 4); for (int ndx = 0; ndx < 4; ndx++) { const int face = order[ndx]; const deUint32 format = GL_RGBA; const deUint32 dataType = GL_UNSIGNED_BYTE; const int texW = 128; const int texH = 128; deUint32 tmpTex = 0; const deUint32 fbo = fbos[face]; const IVec2& viewport = m_texSize; tcu::TextureLevel data (glu::mapGLTransferFormat(format, dataType), texW, texH, 1); tcu::fillWithGrid(data.getAccess(), 8, generateRandomColor(rnd), Vec4(0.0f)); glGenTextures(1, &tmpTex); glBindTexture(GL_TEXTURE_2D, tmpTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr()); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glViewport(0, 0, viewport.x(), viewport.y()); sglr::drawQuad(*getCurrentContext(), texToFboShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); checkError(); // Render to framebuffer { const Vec3 p0 = Vec3(float(ndx % 2) - 1.0f, float(ndx / 2) - 1.0f, 0.0f); const Vec3 p1 = p0 + Vec3(1.0f, 1.0f, 0.0f); glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, getWidth(), getHeight()); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, tex); cubeTexShader.setFace(cubeTexFaces[face]); cubeTexShader.setUniforms(*getCurrentContext(), cubeTexShaderID); sglr::drawQuad(*getCurrentContext(), cubeTexShaderID, p0, p1); checkError(); } } readPixels(dst, 0, 0, getWidth(), getHeight()); } private: IVec2 m_texSize; }; class FboColorTex2DArrayCase : public FboColorbufferCase { public: FboColorTex2DArrayCase (Context& context, const char* name, const char* description, deUint32 texFmt, const IVec3& texSize) : FboColorbufferCase (context, name, description, texFmt) , m_texSize (texSize) { } protected: void preCheck (void) { checkFormatSupport(m_format); } void render (tcu::Surface& dst) { de::Random rnd (deStringHash(getName()) ^ 0xed607a89); tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_format); tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); Texture2DShader texToFboShader (DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt), fmtInfo.valueMax-fmtInfo.valueMin, fmtInfo.valueMin); Texture2DArrayShader arrayTexShader (glu::getSampler2DArrayType(texFmt), glu::TYPE_FLOAT_VEC4); deUint32 texToFboShaderID = getCurrentContext()->createProgram(&texToFboShader); deUint32 arrayTexShaderID = getCurrentContext()->createProgram(&arrayTexShader); // Setup textures texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID); arrayTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias); // Framebuffers. std::vector fbos; deUint32 tex; { glu::TransferFormat transferFmt = glu::getTransferFormat(texFmt); bool isFilterable = glu::isGLInternalColorFormatFilterable(m_format); const IVec3& size = m_texSize; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D_ARRAY, tex); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, isFilterable ? GL_LINEAR : GL_NEAREST); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, isFilterable ? GL_LINEAR : GL_NEAREST); glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, m_format, size.x(), size.y(), size.z(), 0, transferFmt.format, transferFmt.dataType, DE_NULL); // Generate an FBO for each layer for (int ndx = 0; ndx < m_texSize.z(); ndx++) { deUint32 layerFbo; glGenFramebuffers(1, &layerFbo); glBindFramebuffer(GL_FRAMEBUFFER, layerFbo); glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, ndx); checkError(); checkFramebufferStatus(GL_FRAMEBUFFER); fbos.push_back(layerFbo); } } // Render test images to random texture layers std::vector order; for (size_t n = 0; n < fbos.size(); n++) order.push_back((int)n); rnd.shuffle(order.begin(), order.end()); for (size_t ndx = 0; ndx < order.size(); ndx++) { const int layer = order[ndx]; const deUint32 format = GL_RGBA; const deUint32 dataType = GL_UNSIGNED_BYTE; const int texW = 128; const int texH = 128; deUint32 tmpTex = 0; const deUint32 fbo = fbos[layer]; const IVec3& viewport = m_texSize; tcu::TextureLevel data (glu::mapGLTransferFormat(format, dataType), texW, texH, 1); tcu::fillWithGrid(data.getAccess(), 8, generateRandomColor(rnd), Vec4(0.0f)); glGenTextures(1, &tmpTex); glBindTexture(GL_TEXTURE_2D, tmpTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr()); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glViewport(0, 0, viewport.x(), viewport.y()); sglr::drawQuad(*getCurrentContext(), texToFboShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); checkError(); // Render to framebuffer { const Vec3 p0 = Vec3(float(ndx % 2) - 1.0f, float(ndx / 2) - 1.0f, 0.0f); const Vec3 p1 = p0 + Vec3(1.0f, 1.0f, 0.0f); glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, getWidth(), getHeight()); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D_ARRAY, tex); arrayTexShader.setLayer(layer); arrayTexShader.setUniforms(*getCurrentContext(), arrayTexShaderID); sglr::drawQuad(*getCurrentContext(), arrayTexShaderID, p0, p1); checkError(); } } readPixels(dst, 0, 0, getWidth(), getHeight()); } private: IVec3 m_texSize; }; class FboColorTex3DCase : public FboColorbufferCase { public: FboColorTex3DCase (Context& context, const char* name, const char* description, deUint32 texFmt, const IVec3& texSize) : FboColorbufferCase (context, name, description, texFmt) , m_texSize (texSize) { } protected: void preCheck (void) { checkFormatSupport(m_format); } void render (tcu::Surface& dst) { de::Random rnd (deStringHash(getName()) ^ 0x74d947b2); tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_format); tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt); Texture2DShader texToFboShader (DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt), fmtInfo.valueMax-fmtInfo.valueMin, fmtInfo.valueMin); Texture3DShader tdTexShader (glu::getSampler3DType(texFmt), glu::TYPE_FLOAT_VEC4); deUint32 texToFboShaderID= getCurrentContext()->createProgram(&texToFboShader); deUint32 tdTexShaderID = getCurrentContext()->createProgram(&tdTexShader); // Setup shaders texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID); tdTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias); // Framebuffers. std::vector fbos; deUint32 tex; { glu::TransferFormat transferFmt = glu::getTransferFormat(texFmt); const IVec3& size = m_texSize; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_3D, tex); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage3D(GL_TEXTURE_3D, 0, m_format, size.x(), size.y(), size.z(), 0, transferFmt.format, transferFmt.dataType, DE_NULL); // Generate an FBO for each layer for (int ndx = 0; ndx < m_texSize.z(); ndx++) { deUint32 layerFbo; glGenFramebuffers(1, &layerFbo); glBindFramebuffer(GL_FRAMEBUFFER, layerFbo); glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, ndx); checkError(); checkFramebufferStatus(GL_FRAMEBUFFER); fbos.push_back(layerFbo); } } // Render test images to random texture layers std::vector order; for (size_t n = 0; n < fbos.size(); n++) order.push_back((int)n); rnd.shuffle(order.begin(), order.end()); for (size_t ndx = 0; ndx < order.size(); ndx++) { const int layer = order[ndx]; const deUint32 format = GL_RGBA; const deUint32 dataType = GL_UNSIGNED_BYTE; const int texW = 128; const int texH = 128; deUint32 tmpTex = 0; const deUint32 fbo = fbos[layer]; const IVec3& viewport = m_texSize; tcu::TextureLevel data (glu::mapGLTransferFormat(format, dataType), texW, texH, 1); tcu::fillWithGrid(data.getAccess(), 8, generateRandomColor(rnd), Vec4(0.0f)); glGenTextures(1, &tmpTex); glBindTexture(GL_TEXTURE_2D, tmpTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr()); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glViewport(0, 0, viewport.x(), viewport.y()); sglr::drawQuad(*getCurrentContext() , texToFboShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); checkError(); // Render to framebuffer { const Vec3 p0 = Vec3(float(ndx % 2) - 1.0f, float(ndx / 2) - 1.0f, 0.0f); const Vec3 p1 = p0 + Vec3(1.0f, 1.0f, 0.0f); glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, getWidth(), getHeight()); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_3D, tex); tdTexShader.setDepth(float(layer) / float(m_texSize.z()-1)); tdTexShader.setUniforms(*getCurrentContext(), tdTexShaderID); sglr::drawQuad(*getCurrentContext(), tdTexShaderID, p0, p1); checkError(); } } readPixels(dst, 0, 0, getWidth(), getHeight()); } private: IVec3 m_texSize; }; class FboBlendCase : public FboColorbufferCase { public: FboBlendCase (Context& context, const char* name, const char* desc, deUint32 format, IVec2 size, deUint32 funcRGB, deUint32 funcAlpha, deUint32 srcRGB, deUint32 dstRGB, deUint32 srcAlpha, deUint32 dstAlpha) : FboColorbufferCase (context, name, desc, format) , m_size (size) , m_funcRGB (funcRGB) , m_funcAlpha (funcAlpha) , m_srcRGB (srcRGB) , m_dstRGB (dstRGB) , m_srcAlpha (srcAlpha) , m_dstAlpha (dstAlpha) { } protected: void preCheck (void) { checkFormatSupport(m_format); } void render (tcu::Surface& dst) { // \note Assumes floating-point or fixed-point format. tcu::TextureFormat fboFmt = glu::mapGLInternalFormat(m_format); Texture2DShader texShader (DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4); GradientShader gradShader (glu::TYPE_FLOAT_VEC4); deUint32 texShaderID = getCurrentContext()->createProgram(&texShader); deUint32 gradShaderID = getCurrentContext()->createProgram(&gradShader); deUint32 fbo = 0; deUint32 rbo = 0; // Setup shaders texShader.setUniforms (*getCurrentContext(), texShaderID); gradShader.setGradient(*getCurrentContext(), gradShaderID, tcu::Vec4(0.0f), tcu::Vec4(1.0f)); glGenFramebuffers(1, &fbo); glGenRenderbuffers(1, &rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo); glRenderbufferStorage(GL_RENDERBUFFER, m_format, m_size.x(), m_size.y()); checkError(); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); checkError(); checkFramebufferStatus(GL_FRAMEBUFFER); glViewport(0, 0, m_size.x(), m_size.y()); // Fill framebuffer with grid pattern. { const deUint32 format = GL_RGBA; const deUint32 dataType = GL_UNSIGNED_BYTE; const int texW = 128; const int texH = 128; deUint32 gridTex = 0; tcu::TextureLevel data (glu::mapGLTransferFormat(format, dataType), texW, texH, 1); tcu::fillWithGrid(data.getAccess(), 8, Vec4(0.2f, 0.7f, 0.1f, 1.0f), Vec4(0.7f, 0.1f, 0.5f, 0.8f)); glGenTextures(1, &gridTex); glBindTexture(GL_TEXTURE_2D, gridTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr()); sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); } // Setup blend. glEnable(GL_BLEND); glBlendEquationSeparate(m_funcRGB, m_funcAlpha); glBlendFuncSeparate(m_srcRGB, m_dstRGB, m_srcAlpha, m_dstAlpha); // Render gradient with blend. sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); readPixels(dst, 0, 0, m_size.x(), m_size.y(), fboFmt, Vec4(1.0f), Vec4(0.0f)); } private: IVec2 m_size; deUint32 m_funcRGB; deUint32 m_funcAlpha; deUint32 m_srcRGB; deUint32 m_dstRGB; deUint32 m_srcAlpha; deUint32 m_dstAlpha; }; class FboRepeatedClearSampleTex2DCase : public FboColorbufferCase { public: FboRepeatedClearSampleTex2DCase (Context& context, const char* name, const char* desc, deUint32 format) : FboColorbufferCase(context, name, desc, format) { } protected: void preCheck (void) { checkFormatSupport(m_format); } void render (tcu::Surface& dst) { const tcu::TextureFormat fboFormat = glu::mapGLInternalFormat(m_format); const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(fboFormat); const int numRowsCols = 4; const int cellSize = 16; const int fboSizes[] = { cellSize, cellSize*numRowsCols }; Texture2DShader fboBlitShader (DataTypes() << glu::getSampler2DType(fboFormat), getFragmentOutputType(fboFormat), Vec4(1.0f), Vec4(0.0f)); const deUint32 fboBlitShaderID = getCurrentContext()->createProgram(&fboBlitShader); de::Random rnd (18169662); deUint32 fbos[] = { 0, 0 }; deUint32 textures[] = { 0, 0 }; glGenFramebuffers(2, &fbos[0]); glGenTextures(2, &textures[0]); for (int fboNdx = 0; fboNdx < DE_LENGTH_OF_ARRAY(fbos); fboNdx++) { glBindTexture(GL_TEXTURE_2D, textures[fboNdx]); glTexStorage2D(GL_TEXTURE_2D, 1, m_format, fboSizes[fboNdx], fboSizes[fboNdx]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); checkError(); glBindFramebuffer(GL_FRAMEBUFFER, fbos[fboNdx]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[fboNdx], 0); checkError(); checkFramebufferStatus(GL_FRAMEBUFFER); } // larger fbo bound -- clear to transparent black clearColorBuffer(fboFormat, Vec4(0.0f)); fboBlitShader.setUniforms(*getCurrentContext(), fboBlitShaderID); glBindTexture(GL_TEXTURE_2D, textures[0]); for (int cellY = 0; cellY < numRowsCols; cellY++) for (int cellX = 0; cellX < numRowsCols; cellX++) { const Vec4 color = randomVector<4>(rnd, fmtInfo.valueMin, fmtInfo.valueMax); glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); clearColorBuffer(fboFormat, color); glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); glViewport(cellX*cellSize, cellY*cellSize, cellSize, cellSize); sglr::drawQuad(*getCurrentContext(), fboBlitShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); } readPixels(dst, 0, 0, fboSizes[1], fboSizes[1], fboFormat, fmtInfo.lookupScale, fmtInfo.lookupBias); checkError(); } }; class FboRepeatedClearBlitTex2DCase : public FboColorbufferCase { public: FboRepeatedClearBlitTex2DCase (Context& context, const char* name, const char* desc, deUint32 format) : FboColorbufferCase(context, name, desc, format) { } protected: void preCheck (void) { checkFormatSupport(m_format); } void render (tcu::Surface& dst) { const tcu::TextureFormat fboFormat = glu::mapGLInternalFormat(m_format); const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(fboFormat); const int numRowsCols = 4; const int cellSize = 16; const int fboSizes[] = { cellSize, cellSize*numRowsCols }; de::Random rnd (18169662); deUint32 fbos[] = { 0, 0 }; deUint32 textures[] = { 0, 0 }; glGenFramebuffers(2, &fbos[0]); glGenTextures(2, &textures[0]); for (int fboNdx = 0; fboNdx < DE_LENGTH_OF_ARRAY(fbos); fboNdx++) { glBindTexture(GL_TEXTURE_2D, textures[fboNdx]); glTexStorage2D(GL_TEXTURE_2D, 1, m_format, fboSizes[fboNdx], fboSizes[fboNdx]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); checkError(); glBindFramebuffer(GL_FRAMEBUFFER, fbos[fboNdx]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[fboNdx], 0); checkError(); checkFramebufferStatus(GL_FRAMEBUFFER); } // larger fbo bound -- clear to transparent black clearColorBuffer(fboFormat, Vec4(0.0f)); for (int cellY = 0; cellY < numRowsCols; cellY++) for (int cellX = 0; cellX < numRowsCols; cellX++) { const Vec4 color = randomVector<4>(rnd, fmtInfo.valueMin, fmtInfo.valueMax); glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); clearColorBuffer(fboFormat, color); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); glBlitFramebuffer(0, 0, cellSize, cellSize, cellX*cellSize, cellY*cellSize, (cellX+1)*cellSize, (cellY+1)*cellSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); } glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); readPixels(dst, 0, 0, fboSizes[1], fboSizes[1], fboFormat, fmtInfo.lookupScale, fmtInfo.lookupBias); checkError(); } }; class FboRepeatedClearBlitRboCase : public FboColorbufferCase { public: FboRepeatedClearBlitRboCase (Context& context, const char* name, const char* desc, deUint32 format) : FboColorbufferCase(context, name, desc, format) { } protected: void preCheck (void) { checkFormatSupport(m_format); } void render (tcu::Surface& dst) { const tcu::TextureFormat fboFormat = glu::mapGLInternalFormat(m_format); const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(fboFormat); const int numRowsCols = 4; const int cellSize = 16; const int fboSizes[] = { cellSize, cellSize*numRowsCols }; de::Random rnd (18169662); deUint32 fbos[] = { 0, 0 }; deUint32 rbos[] = { 0, 0 }; glGenFramebuffers(2, &fbos[0]); glGenRenderbuffers(2, &rbos[0]); for (int fboNdx = 0; fboNdx < DE_LENGTH_OF_ARRAY(fbos); fboNdx++) { glBindRenderbuffer(GL_RENDERBUFFER, rbos[fboNdx]); glRenderbufferStorage(GL_RENDERBUFFER, m_format, fboSizes[fboNdx], fboSizes[fboNdx]); checkError(); glBindFramebuffer(GL_FRAMEBUFFER, fbos[fboNdx]); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbos[fboNdx]); checkError(); checkFramebufferStatus(GL_FRAMEBUFFER); } // larger fbo bound -- clear to transparent black clearColorBuffer(fboFormat, Vec4(0.0f)); for (int cellY = 0; cellY < numRowsCols; cellY++) for (int cellX = 0; cellX < numRowsCols; cellX++) { const Vec4 color = randomVector<4>(rnd, fmtInfo.valueMin, fmtInfo.valueMax); glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); clearColorBuffer(fboFormat, color); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); glBlitFramebuffer(0, 0, cellSize, cellSize, cellX*cellSize, cellY*cellSize, (cellX+1)*cellSize, (cellY+1)*cellSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); } glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); readPixels(dst, 0, 0, fboSizes[1], fboSizes[1], fboFormat, fmtInfo.lookupScale, fmtInfo.lookupBias); checkError(); } }; FboColorTests::FboColorTests (Context& context) : TestCaseGroup(context, "color", "Colorbuffer tests") { } FboColorTests::~FboColorTests (void) { } void FboColorTests::init (void) { static const deUint32 colorFormats[] = { // RGBA formats GL_RGBA32I, GL_RGBA32UI, GL_RGBA16I, GL_RGBA16UI, GL_RGBA8, GL_RGBA8I, GL_RGBA8UI, GL_SRGB8_ALPHA8, GL_RGB10_A2, GL_RGB10_A2UI, GL_RGBA4, GL_RGB5_A1, // RGB formats GL_RGB8, GL_RGB565, // RG formats GL_RG32I, GL_RG32UI, GL_RG16I, GL_RG16UI, GL_RG8, GL_RG8I, GL_RG8UI, // R formats GL_R32I, GL_R32UI, GL_R16I, GL_R16UI, GL_R8, GL_R8I, GL_R8UI, // GL_EXT_color_buffer_float GL_RGBA32F, GL_RGBA16F, GL_R11F_G11F_B10F, GL_RG32F, GL_RG16F, GL_R32F, GL_R16F, // GL_EXT_color_buffer_half_float GL_RGB16F }; // .clear { tcu::TestCaseGroup* clearGroup = new tcu::TestCaseGroup(m_testCtx, "clear", "Color clears"); addChild(clearGroup); for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(colorFormats); ndx++) clearGroup->addChild(new FboColorClearCase(m_context, getFormatName(colorFormats[ndx]), "", colorFormats[ndx], 129, 117)); } // .tex2d { tcu::TestCaseGroup* tex2DGroup = new tcu::TestCaseGroup(m_testCtx, "tex2d", "Texture 2D tests"); addChild(tex2DGroup); for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++) tex2DGroup->addChild(new FboColorMultiTex2DCase(m_context, getFormatName(colorFormats[fmtNdx]), "", colorFormats[fmtNdx], IVec2(129, 117), colorFormats[fmtNdx], IVec2(99, 128))); } // .texcube { tcu::TestCaseGroup* texCubeGroup = new tcu::TestCaseGroup(m_testCtx, "texcube", "Texture cube map tests"); addChild(texCubeGroup); for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++) texCubeGroup->addChild(new FboColorTexCubeCase(m_context, getFormatName(colorFormats[fmtNdx]), "", colorFormats[fmtNdx], IVec2(128, 128))); } // .tex2darray { tcu::TestCaseGroup* tex2DArrayGroup = new tcu::TestCaseGroup(m_testCtx, "tex2darray", "Texture 2D array tests"); addChild(tex2DArrayGroup); for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++) tex2DArrayGroup->addChild(new FboColorTex2DArrayCase(m_context, getFormatName(colorFormats[fmtNdx]), "", colorFormats[fmtNdx], IVec3(128, 128, 5))); } // .tex3d { tcu::TestCaseGroup* tex3DGroup = new tcu::TestCaseGroup(m_testCtx, "tex3d", "Texture 3D tests"); addChild(tex3DGroup); for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++) tex3DGroup->addChild(new FboColorTex3DCase(m_context, getFormatName(colorFormats[fmtNdx]), "", colorFormats[fmtNdx], IVec3(128, 128, 5))); } // .blend { tcu::TestCaseGroup* blendGroup = new tcu::TestCaseGroup(m_testCtx, "blend", "Blending tests"); addChild(blendGroup); for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++) { deUint32 format = colorFormats[fmtNdx]; tcu::TextureFormat texFmt = glu::mapGLInternalFormat(format); tcu::TextureChannelClass fmtClass = tcu::getTextureChannelClass(texFmt.type); string fmtName = getFormatName(format); if (texFmt.type == tcu::TextureFormat::FLOAT || fmtClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER || fmtClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER) continue; // Blending is not supported. blendGroup->addChild(new FboBlendCase(m_context, (fmtName + "_src_over").c_str(), "", format, IVec2(127, 111), GL_FUNC_ADD, GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE)); } } // .repeated_clear { tcu::TestCaseGroup* const repeatedClearGroup = new tcu::TestCaseGroup(m_testCtx, "repeated_clear", "Repeated clears and blits"); addChild(repeatedClearGroup); // .sample.tex2d { tcu::TestCaseGroup* const sampleGroup = new tcu::TestCaseGroup(m_testCtx, "sample", "Read by sampling"); repeatedClearGroup->addChild(sampleGroup); tcu::TestCaseGroup* const tex2DGroup = new tcu::TestCaseGroup(m_testCtx, "tex2d", "2D Texture"); sampleGroup->addChild(tex2DGroup); for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++) tex2DGroup->addChild(new FboRepeatedClearSampleTex2DCase(m_context, getFormatName(colorFormats[fmtNdx]), "", colorFormats[fmtNdx])); } // .blit { tcu::TestCaseGroup* const blitGroup = new tcu::TestCaseGroup(m_testCtx, "blit", "Blitted"); repeatedClearGroup->addChild(blitGroup); // .tex2d { tcu::TestCaseGroup* const tex2DGroup = new tcu::TestCaseGroup(m_testCtx, "tex2d", "2D Texture"); blitGroup->addChild(tex2DGroup); for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++) tex2DGroup->addChild(new FboRepeatedClearBlitTex2DCase(m_context, getFormatName(colorFormats[fmtNdx]), "", colorFormats[fmtNdx])); } // .rbo { tcu::TestCaseGroup* const rboGroup = new tcu::TestCaseGroup(m_testCtx, "rbo", "Renderbuffer"); blitGroup->addChild(rboGroup); for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++) rboGroup->addChild(new FboRepeatedClearBlitRboCase(m_context, getFormatName(colorFormats[fmtNdx]), "", colorFormats[fmtNdx])); } } } } } // Functional } // gles3 } // deqp