/*------------------------------------------------------------------------- * 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 format performance tests. *//*--------------------------------------------------------------------*/ #include "es3pTextureCases.hpp" #include "glsShaderPerformanceCase.hpp" #include "tcuTextureUtil.hpp" #include "tcuRenderTarget.hpp" #include "gluTexture.hpp" #include "gluTextureUtil.hpp" #include "gluStrUtil.hpp" #include "deStringUtil.hpp" #include "glwEnums.hpp" #include "glwFunctions.hpp" namespace deqp { namespace gles3 { namespace Performance { using namespace gls; using namespace glw; // GL types using tcu::Vec2; using tcu::Vec3; using tcu::Vec4; using tcu::IVec4; using std::string; using std::vector; using tcu::TestLog; Texture2DRenderCase::Texture2DRenderCase (Context& context, const char* name, const char* description, deUint32 internalFormat, deUint32 wrapS, deUint32 wrapT, deUint32 minFilter, deUint32 magFilter, const tcu::Mat3& coordTransform, int numTextures, bool powerOfTwo) : ShaderPerformanceCase (context.getTestContext(), context.getRenderContext(), name, description, CASETYPE_FRAGMENT) , m_internalFormat (internalFormat) , m_wrapS (wrapS) , m_wrapT (wrapT) , m_minFilter (minFilter) , m_magFilter (magFilter) , m_coordTransform (coordTransform) , m_numTextures (numTextures) , m_powerOfTwo (powerOfTwo) { } Texture2DRenderCase::~Texture2DRenderCase (void) { for (vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++) delete *i; m_textures.clear(); } static inline int roundDownToPowerOfTwo (int val) { DE_ASSERT(val >= 0); int l0 = deClz32(val); return val & ~((1<<(31-l0))-1); } void Texture2DRenderCase::init (void) { TestLog& log = m_testCtx.getLog(); const tcu::TextureFormat texFormat = glu::mapGLInternalFormat(m_internalFormat); const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFormat); const glu::Precision samplerPrec = (texFormat.type == tcu::TextureFormat::FLOAT || texFormat.type == tcu::TextureFormat::UNSIGNED_INT32 || texFormat.type == tcu::TextureFormat::SIGNED_INT32) ? glu::PRECISION_HIGHP : glu::PRECISION_MEDIUMP; const glu::DataType samplerType = glu::getSampler2DType(texFormat); const bool isIntUint = samplerType == glu::TYPE_INT_SAMPLER_2D || samplerType == glu::TYPE_UINT_SAMPLER_2D; int width = m_renderCtx.getRenderTarget().getWidth(); int height = m_renderCtx.getRenderTarget().getHeight(); if (m_powerOfTwo) { width = roundDownToPowerOfTwo(width); height = roundDownToPowerOfTwo(height); } bool mipmaps = m_minFilter == GL_NEAREST_MIPMAP_NEAREST || m_minFilter == GL_NEAREST_MIPMAP_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_NEAREST || m_minFilter == GL_LINEAR_MIPMAP_LINEAR; DE_ASSERT(m_powerOfTwo || (!mipmaps && m_wrapS == GL_CLAMP_TO_EDGE && m_wrapT == GL_CLAMP_TO_EDGE)); Vec2 p00 = (m_coordTransform * Vec3(0.0f, 0.0f, 1.0f)).swizzle(0,1); Vec2 p10 = (m_coordTransform * Vec3(1.0f, 0.0f, 1.0f)).swizzle(0,1); Vec2 p01 = (m_coordTransform * Vec3(0.0f, 1.0f, 1.0f)).swizzle(0,1); Vec2 p11 = (m_coordTransform * Vec3(1.0f, 1.0f, 1.0f)).swizzle(0,1); m_attributes.push_back(AttribSpec("a_coords", Vec4(p00.x(), p00.y(), 0.0f, 0.0f), Vec4(p10.x(), p10.y(), 0.0f, 0.0f), Vec4(p01.x(), p01.y(), 0.0f, 0.0f), Vec4(p11.x(), p11.y(), 0.0f, 0.0f))); log << TestLog::Message << "Size: " << width << "x" << height << TestLog::EndMessage; log << TestLog::Message << "Format: " <<glu::getPixelFormatName(m_internalFormat) << TestLog::EndMessage; log << TestLog::Message << "Coords: " << p00 << ", " << p10 << ", " << p01 << ", " << p11 << TestLog::EndMessage; log << TestLog::Message << "Wrap: " << glu::getTextureWrapModeStr(m_wrapS) << " / " << glu::getTextureWrapModeStr(m_wrapT) << TestLog::EndMessage; log << TestLog::Message << "Filter: " << glu::getTextureFilterStr(m_minFilter) << " / " << glu::getTextureFilterStr(m_magFilter) << TestLog::EndMessage; log << TestLog::Message << "Mipmaps: " << (mipmaps ? "true" : "false") << TestLog::EndMessage; log << TestLog::Message << "Using additive blending." << TestLog::EndMessage; // Use same viewport size as texture size. setViewportSize(width, height); m_vertShaderSource = "#version 300 es\n" "in highp vec4 a_position;\n" "in mediump vec2 a_coords;\n" "out mediump vec2 v_coords;\n" "void main (void)\n" "{\n" " gl_Position = a_position;\n" " v_coords = a_coords;\n" "}\n"; std::ostringstream fragSrc; fragSrc << "#version 300 es\n"; fragSrc << "layout(location = 0) out mediump vec4 o_color;\n"; fragSrc << "in mediump vec2 v_coords;\n"; for (int texNdx = 0; texNdx < m_numTextures; texNdx++) fragSrc << "uniform " << glu::getPrecisionName(samplerPrec) << " " << glu::getDataTypeName(samplerType) << " u_sampler" << texNdx << ";\n"; fragSrc << "void main (void)\n" << "{\n"; for (int texNdx = 0; texNdx < m_numTextures; texNdx++) { if (texNdx == 0) fragSrc << "\t" << glu::getPrecisionName(samplerPrec) << " vec4 r = "; else fragSrc << "\tr += "; if (isIntUint) fragSrc << "vec4("; fragSrc << "texture(u_sampler" << texNdx << ", v_coords)"; if (isIntUint) fragSrc << ")"; fragSrc << ";\n"; } fragSrc << " o_color = r;\n" << "}\n"; m_fragShaderSource = fragSrc.str(); m_textures.reserve(m_numTextures); for (int texNdx = 0; texNdx < m_numTextures; texNdx++) { static const IVec4 swizzles[] = { IVec4(0,1,2,3), IVec4(1,2,3,0), IVec4(2,3,0,1), IVec4(3,0,1,2), IVec4(3,2,1,0), IVec4(2,1,0,3), IVec4(1,0,3,2), IVec4(0,3,2,1) }; const IVec4& sw = swizzles[texNdx % DE_LENGTH_OF_ARRAY(swizzles)]; glu::Texture2D* texture = new glu::Texture2D(m_renderCtx, m_internalFormat, width, height); m_textures.push_back(texture); // Fill levels. int numLevels = mipmaps ? texture->getRefTexture().getNumLevels() : 1; for (int levelNdx = 0; levelNdx < numLevels; levelNdx++) { // \todo [2013-06-02 pyry] Values are not scaled back to 0..1 range in shaders. texture->getRefTexture().allocLevel(levelNdx); tcu::fillWithComponentGradients(texture->getRefTexture().getLevel(levelNdx), fmtInfo.valueMin.swizzle(sw[0], sw[1], sw[2], sw[3]), fmtInfo.valueMax.swizzle(sw[0], sw[1], sw[2], sw[3])); } texture->upload(); } ShaderPerformanceCase::init(); } void Texture2DRenderCase::deinit (void) { for (vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++) delete *i; m_textures.clear(); ShaderPerformanceCase::deinit(); } void Texture2DRenderCase::setupProgram (deUint32 program) { const glw::Functions& gl = m_renderCtx.getFunctions(); for (int texNdx = 0; texNdx < m_numTextures; texNdx++) { int samplerLoc = gl.getUniformLocation(program, (string("u_sampler") + de::toString(texNdx)).c_str()); gl.uniform1i(samplerLoc, texNdx); } } void Texture2DRenderCase::setupRenderState (void) { const glw::Functions& gl = m_renderCtx.getFunctions(); // Setup additive blending. gl.enable(GL_BLEND); gl.blendFunc(GL_ONE, GL_ONE); gl.blendEquation(GL_FUNC_ADD); // Setup textures. for (int texNdx = 0; texNdx < m_numTextures; texNdx++) { gl.activeTexture(GL_TEXTURE0 + texNdx); gl.bindTexture(GL_TEXTURE_2D, m_textures[texNdx]->getGLTexture()); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT); } } } // Performance } // gles3 } // deqp