/*------------------------------------------------------------------------- * 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 swizzle tests. *//*--------------------------------------------------------------------*/ #include "es3fTextureSwizzleTests.hpp" #include "glsTextureTestUtil.hpp" #include "gluPixelTransfer.hpp" #include "gluTexture.hpp" #include "gluRenderContext.hpp" #include "tcuTextureUtil.hpp" #include "tcuRenderTarget.hpp" #include "deString.h" #include "glwEnums.hpp" #include "glwFunctions.hpp" namespace deqp { namespace gles3 { namespace Functional { using std::string; using std::vector; using tcu::TestLog; using namespace deqp::gls; using namespace deqp::gls::TextureTestUtil; static int swizzle (const tcu::RGBA& c, deUint32 swz) { switch (swz) { case GL_RED: return c.getRed(); case GL_GREEN: return c.getGreen(); case GL_BLUE: return c.getBlue(); case GL_ALPHA: return c.getAlpha(); case GL_ZERO: return 0; case GL_ONE: return (1<<8)-1; default: DE_ASSERT(false); return 0; } } static void swizzle (tcu::Surface& surface, deUint32 swzR, deUint32 swzG, deUint32 swzB, deUint32 swzA) { for (int y = 0; y < surface.getHeight(); y++) { for (int x = 0; x < surface.getWidth(); x++) { tcu::RGBA p = surface.getPixel(x, y); surface.setPixel(x, y, tcu::RGBA(swizzle(p, swzR), swizzle(p, swzG), swizzle(p, swzB), swizzle(p, swzA))); } } } class Texture2DSwizzleCase : public TestCase { public: Texture2DSwizzleCase (Context& context, const char* name, const char* description, deUint32 internalFormat, deUint32 format, deUint32 dataType, deUint32 swizzleR, deUint32 swizzleG, deUint32 swizzleB, deUint32 swizzleA); ~Texture2DSwizzleCase (void); void init (void); void deinit (void); IterateResult iterate (void); private: Texture2DSwizzleCase (const Texture2DSwizzleCase& other); Texture2DSwizzleCase& operator= (const Texture2DSwizzleCase& other); deUint32 m_internalFormat; deUint32 m_format; deUint32 m_dataType; deUint32 m_swizzleR; deUint32 m_swizzleG; deUint32 m_swizzleB; deUint32 m_swizzleA; glu::Texture2D* m_texture; TextureRenderer m_renderer; }; Texture2DSwizzleCase::Texture2DSwizzleCase (Context& context, const char* name, const char* description, deUint32 internalFormat, deUint32 format, deUint32 dataType, deUint32 swizzleR, deUint32 swizzleG, deUint32 swizzleB, deUint32 swizzleA) : TestCase (context, name, description) , m_internalFormat (internalFormat) , m_format (format) , m_dataType (dataType) , m_swizzleR (swizzleR) , m_swizzleG (swizzleG) , m_swizzleB (swizzleB) , m_swizzleA (swizzleA) , m_texture (DE_NULL) , m_renderer (context.getRenderContext(), context.getTestContext(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP) { } Texture2DSwizzleCase::~Texture2DSwizzleCase (void) { deinit(); } void Texture2DSwizzleCase::init (void) { int width = de::min(128, m_context.getRenderContext().getRenderTarget().getWidth()); int height = de::min(128, m_context.getRenderContext().getRenderTarget().getHeight()); m_texture = (m_internalFormat == m_format) ? new glu::Texture2D(m_context.getRenderContext(), m_format, m_dataType, width, height) : new glu::Texture2D(m_context.getRenderContext(), m_internalFormat, width, height); tcu::TextureFormatInfo spec = tcu::getTextureFormatInfo(m_texture->getRefTexture().getFormat()); // Fill level 0. m_texture->getRefTexture().allocLevel(0); tcu::fillWithComponentGradients(m_texture->getRefTexture().getLevel(0), spec.valueMin, spec.valueMax); } void Texture2DSwizzleCase::deinit (void) { delete m_texture; m_texture = DE_NULL; m_renderer.clear(); } Texture2DSwizzleCase::IterateResult Texture2DSwizzleCase::iterate (void) { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); TestLog& log = m_testCtx.getLog(); RandomViewport viewport (m_context.getRenderContext().getRenderTarget(), m_texture->getRefTexture().getWidth(), m_texture->getRefTexture().getHeight(), deStringHash(getName())); tcu::Surface renderedFrame (viewport.width, viewport.height); tcu::Surface referenceFrame (viewport.width, viewport.height); tcu::RGBA threshold = m_context.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1); vector<float> texCoord; ReferenceParams renderParams (TEXTURETYPE_2D); tcu::TextureFormatInfo spec = tcu::getTextureFormatInfo(m_texture->getRefTexture().getFormat()); renderParams.samplerType = getSamplerType(m_texture->getRefTexture().getFormat()); renderParams.sampler = tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST); renderParams.colorScale = spec.lookupScale; renderParams.colorBias = spec.lookupBias; computeQuadTexCoord2D(texCoord, tcu::Vec2(0.0f, 0.0f), tcu::Vec2(1.0f, 1.0f)); // Setup base viewport. gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); // Upload texture data to GL. m_texture->upload(); // Bind to unit 0. gl.activeTexture(GL_TEXTURE0); gl.bindTexture(GL_TEXTURE_2D, m_texture->getGLTexture()); // Setup nearest neighbor filtering and clamp-to-edge. gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Setup texture swizzle. gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, m_swizzleR); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, m_swizzleG); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, m_swizzleB); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, m_swizzleA); GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state"); // Draw. m_renderer.renderQuad(0, &texCoord[0], renderParams); glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, renderedFrame.getAccess()); // Compute reference { const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat(); // Do initial rendering to RGBA8 in order to keep alpha sampleTexture(SurfaceAccess(referenceFrame, tcu::PixelFormat(8,8,8,8)), m_texture->getRefTexture(), &texCoord[0], renderParams); // Swizzle channels swizzle(referenceFrame, m_swizzleR, m_swizzleG, m_swizzleB, m_swizzleA); // Convert to destination format if (pixelFormat != tcu::PixelFormat(8,8,8,8)) { for (int y = 0; y < referenceFrame.getHeight(); y++) { for (int x = 0; x < referenceFrame.getWidth(); x++) { tcu::RGBA p = referenceFrame.getPixel(x, y); referenceFrame.setPixel(x, y, pixelFormat.convertColor(p)); } } } } // Compare and log. bool isOk = compareImages(log, referenceFrame, renderedFrame, threshold); m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Image comparison failed"); return STOP; } TextureSwizzleTests::TextureSwizzleTests (Context& context) : TestCaseGroup(context, "swizzle", "Texture Swizzle Tests") { } TextureSwizzleTests::~TextureSwizzleTests (void) { } void TextureSwizzleTests::init (void) { static const struct { const char* name; deUint32 internalFormat; deUint32 format; deUint32 dataType; } formats[] = { { "alpha", GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE }, { "luminance", GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE }, { "luminance_alpha", GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE }, { "red", GL_R8, GL_RED, GL_UNSIGNED_BYTE }, { "rg", GL_RG8, GL_RG, GL_UNSIGNED_BYTE }, { "rgb", GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE }, { "rgba", GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE } }; static const struct { const char* name; deUint32 channel; } channels[] = { { "r", GL_TEXTURE_SWIZZLE_R }, { "g", GL_TEXTURE_SWIZZLE_G }, { "b", GL_TEXTURE_SWIZZLE_B }, { "a", GL_TEXTURE_SWIZZLE_A } }; static const struct { const char* name; deUint32 swizzle; } swizzles[] = { { "red", GL_RED }, { "green", GL_GREEN }, { "blue", GL_BLUE }, { "alpha", GL_ALPHA }, { "zero", GL_ZERO }, { "one", GL_ONE } }; static const struct { const char* name; deUint32 swzR; deUint32 swzG; deUint32 swzB; deUint32 swzA; } swizzleCases[] = { { "all_red", GL_RED, GL_RED, GL_RED, GL_RED }, { "all_green", GL_GREEN, GL_GREEN, GL_GREEN, GL_GREEN }, { "all_blue", GL_BLUE, GL_BLUE, GL_BLUE, GL_BLUE }, { "all_alpha", GL_ALPHA, GL_ALPHA, GL_ALPHA, GL_ALPHA }, { "all_zero", GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO }, { "all_one", GL_ONE, GL_ONE, GL_ONE, GL_ONE }, { "bgra", GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA }, { "abgr", GL_ALPHA, GL_BLUE, GL_GREEN, GL_RED }, { "one_one_red_green", GL_ONE, GL_ONE, GL_RED, GL_GREEN } }; static const deUint32 defaultSwizzles[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; // All swizzles applied to each channel. tcu::TestCaseGroup* singleChannelGroup = new tcu::TestCaseGroup(m_testCtx, "single_channel", "Single-channel swizzle"); addChild(singleChannelGroup); for (int chanNdx = 0; chanNdx < DE_LENGTH_OF_ARRAY(channels); chanNdx++) { for (int swzNdx = 0; swzNdx < DE_LENGTH_OF_ARRAY(swizzles); swzNdx++) { if (swizzles[swzNdx].swizzle == defaultSwizzles[chanNdx]) continue; // No need to test default case. string name = string(channels[chanNdx].name) + "_" + swizzles[swzNdx].name; deUint32 swz = swizzles[swzNdx].swizzle; deUint32 swzR = (chanNdx == 0) ? swz : defaultSwizzles[0]; deUint32 swzG = (chanNdx == 1) ? swz : defaultSwizzles[1]; deUint32 swzB = (chanNdx == 2) ? swz : defaultSwizzles[2]; deUint32 swzA = (chanNdx == 3) ? swz : defaultSwizzles[3]; singleChannelGroup->addChild(new Texture2DSwizzleCase(m_context, name.c_str(), "Single-channel swizzle", GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, swzR, swzG, swzB, swzA)); } } // Swizzles for all formats. tcu::TestCaseGroup* multiChannelGroup = new tcu::TestCaseGroup(m_testCtx, "multi_channel", "Multi-channel swizzle"); addChild(multiChannelGroup); for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(formats); fmtNdx++) { for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(swizzleCases); caseNdx++) { string name = string(formats[fmtNdx].name) + "_" + swizzleCases[caseNdx].name; deUint32 swzR = swizzleCases[caseNdx].swzR; deUint32 swzG = swizzleCases[caseNdx].swzG; deUint32 swzB = swizzleCases[caseNdx].swzB; deUint32 swzA = swizzleCases[caseNdx].swzA; deUint32 intFormat = formats[fmtNdx].internalFormat; deUint32 format = formats[fmtNdx].format; deUint32 dataType = formats[fmtNdx].dataType; multiChannelGroup->addChild(new Texture2DSwizzleCase(m_context, name.c_str(), "Multi-channel swizzle", intFormat, format, dataType, swzR, swzG, swzB, swzA)); } } } } // Functional } // gles3 } // deqp