| /*------------------------------------------------------------------------- |
| * drawElements Quality Program OpenGL (ES) 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 Random shader test case. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "glsRandomShaderCase.hpp" |
| |
| #include "gluShaderProgram.hpp" |
| #include "gluPixelTransfer.hpp" |
| #include "gluTextureUtil.hpp" |
| #include "gluStrUtil.hpp" |
| |
| #include "tcuImageCompare.hpp" |
| #include "tcuTestLog.hpp" |
| |
| #include "deRandom.hpp" |
| #include "deStringUtil.hpp" |
| |
| #include "rsgProgramGenerator.hpp" |
| #include "rsgProgramExecutor.hpp" |
| #include "rsgUtils.hpp" |
| |
| #include "tcuTextureUtil.hpp" |
| #include "tcuRenderTarget.hpp" |
| |
| #include "glw.h" |
| #include "glwFunctions.hpp" |
| |
| using std::vector; |
| using std::string; |
| using std::pair; |
| using std::map; |
| |
| namespace deqp |
| { |
| namespace gls |
| { |
| |
| enum |
| { |
| VIEWPORT_WIDTH = 64, |
| VIEWPORT_HEIGHT = 64, |
| |
| TEXTURE_2D_WIDTH = 64, |
| TEXTURE_2D_HEIGHT = 64, |
| TEXTURE_2D_FORMAT = GL_RGBA, |
| TEXTURE_2D_DATA_TYPE = GL_UNSIGNED_BYTE, |
| |
| TEXTURE_CUBE_SIZE = 16, |
| TEXTURE_CUBE_FORMAT = GL_RGBA, |
| TEXTURE_CUBE_DATA_TYPE = GL_UNSIGNED_BYTE, |
| |
| TEXTURE_WRAP_S = GL_CLAMP_TO_EDGE, |
| TEXTURE_WRAP_T = GL_CLAMP_TO_EDGE, |
| |
| TEXTURE_MIN_FILTER = GL_LINEAR, |
| TEXTURE_MAG_FILTER = GL_LINEAR |
| }; |
| |
| VertexArray::VertexArray (const rsg::ShaderInput* input, int numVertices) |
| : m_input (input) |
| , m_vertices (input->getVariable()->getType().getNumElements() * numVertices) |
| { |
| } |
| |
| TextureManager::TextureManager (void) |
| { |
| } |
| |
| TextureManager::~TextureManager (void) |
| { |
| } |
| |
| void TextureManager::bindTexture (int unit, const glu::Texture2D* tex2D) |
| { |
| m_tex2D[unit] = tex2D; |
| } |
| |
| void TextureManager::bindTexture (int unit, const glu::TextureCube* texCube) |
| { |
| m_texCube[unit] = texCube; |
| } |
| |
| inline vector<pair<int, const glu::Texture2D*> > TextureManager::getBindings2D (void) const |
| { |
| vector<pair<int, const glu::Texture2D*> > bindings; |
| for (map<int, const glu::Texture2D*>::const_iterator i = m_tex2D.begin(); i != m_tex2D.end(); i++) |
| bindings.push_back(*i); |
| return bindings; |
| } |
| |
| inline vector<pair<int, const glu::TextureCube*> > TextureManager::getBindingsCube (void) const |
| { |
| vector<pair<int, const glu::TextureCube*> > bindings; |
| for (map<int, const glu::TextureCube*>::const_iterator i = m_texCube.begin(); i != m_texCube.end(); i++) |
| bindings.push_back(*i); |
| return bindings; |
| } |
| |
| RandomShaderCase::RandomShaderCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, const rsg::ProgramParameters& params) |
| : tcu::TestCase (testCtx, name, description) |
| , m_renderCtx (renderCtx) |
| , m_parameters (params) |
| , m_gridWidth (1) |
| , m_gridHeight (1) |
| , m_vertexShader (rsg::Shader::TYPE_VERTEX) |
| , m_fragmentShader (rsg::Shader::TYPE_FRAGMENT) |
| , m_tex2D (DE_NULL) |
| , m_texCube (DE_NULL) |
| { |
| } |
| |
| RandomShaderCase::~RandomShaderCase (void) |
| { |
| delete m_tex2D; |
| delete m_texCube; |
| } |
| |
| void RandomShaderCase::init (void) |
| { |
| // Generate shaders |
| rsg::ProgramGenerator programGenerator; |
| programGenerator.generate(m_parameters, m_vertexShader, m_fragmentShader); |
| |
| checkShaderLimits(m_vertexShader); |
| checkShaderLimits(m_fragmentShader); |
| checkProgramLimits(m_vertexShader, m_fragmentShader); |
| |
| // Compute uniform values |
| std::vector<const rsg::ShaderInput*> unifiedUniforms; |
| de::Random rnd(m_parameters.seed); |
| rsg::computeUnifiedUniforms(m_vertexShader, m_fragmentShader, unifiedUniforms); |
| rsg::computeUniformValues(rnd, m_uniforms, unifiedUniforms); |
| |
| // Generate vertices |
| const vector<rsg::ShaderInput*>& inputs = m_vertexShader.getInputs(); |
| int numVertices = (m_gridWidth+1)*(m_gridHeight+1); |
| |
| for (vector<rsg::ShaderInput*>::const_iterator i = inputs.begin(); i != inputs.end(); i++) |
| { |
| const rsg::ShaderInput* input = *i; |
| rsg::ConstValueRangeAccess valueRange = input->getValueRange(); |
| int numComponents = input->getVariable()->getType().getNumElements(); |
| VertexArray vtxArray(input, numVertices); |
| bool isPosition = string(input->getVariable()->getName()) == "dEQP_Position"; |
| |
| TCU_CHECK(input->getVariable()->getType().getBaseType() == rsg::VariableType::TYPE_FLOAT); |
| |
| for (int vtxNdx = 0; vtxNdx < numVertices; vtxNdx++) |
| { |
| int y = vtxNdx / (m_gridWidth+1); |
| int x = vtxNdx - y*(m_gridWidth+1); |
| float xf = (float)x / (float)m_gridWidth; |
| float yf = (float)y / (float)m_gridHeight; |
| float* dst = &vtxArray.getVertices()[vtxNdx*numComponents]; |
| |
| if (isPosition) |
| { |
| // Position attribute gets special interpolation handling. |
| DE_ASSERT(numComponents == 4); |
| dst[0] = -1.0f + xf * 2.0f; |
| dst[1] = 1.0f + yf * -2.0f; |
| dst[2] = 0.0f; |
| dst[3] = 1.0f; |
| } |
| else |
| { |
| for (int compNdx = 0; compNdx < numComponents; compNdx++) |
| { |
| float minVal = valueRange.getMin().component(compNdx).asFloat(); |
| float maxVal = valueRange.getMax().component(compNdx).asFloat(); |
| float xd, yd; |
| |
| rsg::getVertexInterpolationCoords(xd, yd, xf, yf, compNdx); |
| |
| float f = (xd+yd) / 2.0f; |
| |
| dst[compNdx] = minVal + f * (maxVal-minVal); |
| } |
| } |
| } |
| |
| m_vertexArrays.push_back(vtxArray); |
| } |
| |
| // Generate indices |
| int numQuads = m_gridWidth*m_gridHeight; |
| int numIndices = numQuads*6; |
| m_indices.resize(numIndices); |
| for (int quadNdx = 0; quadNdx < numQuads; quadNdx++) |
| { |
| int quadY = quadNdx / (m_gridWidth); |
| int quadX = quadNdx - quadY*m_gridWidth; |
| |
| m_indices[quadNdx*6+0] = (deUint16)(quadX + quadY*(m_gridWidth+1)); |
| m_indices[quadNdx*6+1] = (deUint16)(quadX + (quadY+1)*(m_gridWidth+1)); |
| m_indices[quadNdx*6+2] = (deUint16)(quadX + quadY*(m_gridWidth+1) + 1); |
| m_indices[quadNdx*6+3] = (deUint16)(m_indices[quadNdx*6+2]); |
| m_indices[quadNdx*6+4] = (deUint16)(m_indices[quadNdx*6+1]); |
| m_indices[quadNdx*6+5] = (deUint16)(quadX + (quadY+1)*(m_gridWidth+1) + 1); |
| } |
| |
| // Create textures. |
| for (vector<rsg::VariableValue>::const_iterator uniformIter = m_uniforms.begin(); uniformIter != m_uniforms.end(); uniformIter++) |
| { |
| const rsg::VariableType& type = uniformIter->getVariable()->getType(); |
| |
| if (!type.isSampler()) |
| continue; |
| |
| int unitNdx = uniformIter->getValue().asInt(0); |
| |
| if (type == rsg::VariableType(rsg::VariableType::TYPE_SAMPLER_2D, 1)) |
| m_texManager.bindTexture(unitNdx, getTex2D()); |
| else if (type == rsg::VariableType(rsg::VariableType::TYPE_SAMPLER_CUBE, 1)) |
| m_texManager.bindTexture(unitNdx, getTexCube()); |
| else |
| DE_ASSERT(DE_FALSE); |
| } |
| } |
| |
| static int getNumSamplerUniforms (const std::vector<rsg::ShaderInput*>& uniforms) |
| { |
| int numSamplers = 0; |
| |
| for (std::vector<rsg::ShaderInput*>::const_iterator it = uniforms.begin(); it != uniforms.end(); ++it) |
| { |
| if ((*it)->getVariable()->getType().isSampler()) |
| ++numSamplers; |
| } |
| |
| return numSamplers; |
| } |
| |
| void RandomShaderCase::checkShaderLimits (const rsg::Shader& shader) const |
| { |
| const int numRequiredSamplers = getNumSamplerUniforms(shader.getUniforms()); |
| |
| if (numRequiredSamplers > 0) |
| { |
| const GLenum pname = (shader.getType() == rsg::Shader::TYPE_VERTEX) ? (GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS) : (GL_MAX_TEXTURE_IMAGE_UNITS); |
| int numSupported = -1; |
| GLenum error; |
| |
| m_renderCtx.getFunctions().getIntegerv(pname, &numSupported); |
| error = m_renderCtx.getFunctions().getError(); |
| |
| if (error != GL_NO_ERROR) |
| throw tcu::TestError("Limit query failed: " + de::toString(glu::getErrorStr(error))); |
| |
| if (numSupported < numRequiredSamplers) |
| throw tcu::NotSupportedError("Shader requires " + de::toString(numRequiredSamplers) + " sampler(s). Implementation supports " + de::toString(numSupported)); |
| } |
| } |
| |
| void RandomShaderCase::checkProgramLimits (const rsg::Shader& vtxShader, const rsg::Shader& frgShader) const |
| { |
| const int numRequiredCombinedSamplers = getNumSamplerUniforms(vtxShader.getUniforms()) + getNumSamplerUniforms(frgShader.getUniforms()); |
| |
| if (numRequiredCombinedSamplers > 0) |
| { |
| int numSupported = -1; |
| GLenum error; |
| |
| m_renderCtx.getFunctions().getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numSupported); |
| error = m_renderCtx.getFunctions().getError(); |
| |
| if (error != GL_NO_ERROR) |
| throw tcu::TestError("Limit query failed: " + de::toString(glu::getErrorStr(error))); |
| |
| if (numSupported < numRequiredCombinedSamplers) |
| throw tcu::NotSupportedError("Program requires " + de::toString(numRequiredCombinedSamplers) + " sampler(s). Implementation supports " + de::toString(numSupported)); |
| } |
| } |
| |
| const glu::Texture2D* RandomShaderCase::getTex2D (void) |
| { |
| if (!m_tex2D) |
| { |
| m_tex2D = new glu::Texture2D(m_renderCtx, TEXTURE_2D_FORMAT, TEXTURE_2D_DATA_TYPE, TEXTURE_2D_WIDTH, TEXTURE_2D_HEIGHT); |
| |
| m_tex2D->getRefTexture().allocLevel(0); |
| tcu::fillWithComponentGradients(m_tex2D->getRefTexture().getLevel(0), tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)); |
| m_tex2D->upload(); |
| |
| // Setup parameters. |
| glBindTexture(GL_TEXTURE_2D, m_tex2D->getGLTexture()); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, TEXTURE_WRAP_S); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, TEXTURE_WRAP_T); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TEXTURE_MIN_FILTER); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TEXTURE_MAG_FILTER); |
| |
| GLU_CHECK(); |
| } |
| |
| return m_tex2D; |
| } |
| |
| const glu::TextureCube* RandomShaderCase::getTexCube (void) |
| { |
| if (!m_texCube) |
| { |
| m_texCube = new glu::TextureCube(m_renderCtx, TEXTURE_CUBE_FORMAT, TEXTURE_CUBE_DATA_TYPE, TEXTURE_CUBE_SIZE); |
| |
| static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] = |
| { |
| { tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x |
| { tcu::Vec4( 0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x |
| { tcu::Vec4(-1.0f, 0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y |
| { tcu::Vec4(-1.0f, -1.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y |
| { tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z |
| { tcu::Vec4( 0.0f, 0.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) } // positive z |
| }; |
| |
| // Fill level 0. |
| for (int face = 0; face < tcu::CUBEFACE_LAST; face++) |
| { |
| m_texCube->getRefTexture().allocLevel((tcu::CubeFace)face, 0); |
| tcu::fillWithComponentGradients(m_texCube->getRefTexture().getLevelFace(0, (tcu::CubeFace)face), gradients[face][0], gradients[face][1]); |
| } |
| |
| m_texCube->upload(); |
| |
| // Setup parameters. |
| glBindTexture(GL_TEXTURE_CUBE_MAP, m_texCube->getGLTexture()); |
| glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, TEXTURE_WRAP_S); |
| glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, TEXTURE_WRAP_T); |
| glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, TEXTURE_MIN_FILTER); |
| glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, TEXTURE_MAG_FILTER); |
| |
| GLU_CHECK(); |
| } |
| |
| return m_texCube; |
| } |
| |
| void RandomShaderCase::deinit (void) |
| { |
| delete m_tex2D; |
| delete m_texCube; |
| |
| m_tex2D = DE_NULL; |
| m_texCube = DE_NULL; |
| |
| // Free up memory |
| m_vertexArrays.clear(); |
| m_indices.clear(); |
| } |
| |
| namespace |
| { |
| |
| void setUniformValue (int location, rsg::ConstValueAccess value) |
| { |
| DE_STATIC_ASSERT(sizeof(rsg::Scalar) == sizeof(float)); |
| DE_STATIC_ASSERT(sizeof(rsg::Scalar) == sizeof(int)); |
| |
| switch (value.getType().getBaseType()) |
| { |
| case rsg::VariableType::TYPE_FLOAT: |
| switch (value.getType().getNumElements()) |
| { |
| case 1: glUniform1fv(location, 1, (float*)value.value().getValuePtr()); break; |
| case 2: glUniform2fv(location, 1, (float*)value.value().getValuePtr()); break; |
| case 3: glUniform3fv(location, 1, (float*)value.value().getValuePtr()); break; |
| case 4: glUniform4fv(location, 1, (float*)value.value().getValuePtr()); break; |
| default: TCU_FAIL("Unsupported type"); |
| } |
| break; |
| |
| case rsg::VariableType::TYPE_INT: |
| case rsg::VariableType::TYPE_BOOL: |
| case rsg::VariableType::TYPE_SAMPLER_2D: |
| case rsg::VariableType::TYPE_SAMPLER_CUBE: |
| switch (value.getType().getNumElements()) |
| { |
| case 1: glUniform1iv(location, 1, (int*)value.value().getValuePtr()); break; |
| case 2: glUniform2iv(location, 1, (int*)value.value().getValuePtr()); break; |
| case 3: glUniform3iv(location, 1, (int*)value.value().getValuePtr()); break; |
| case 4: glUniform4iv(location, 1, (int*)value.value().getValuePtr()); break; |
| default: TCU_FAIL("Unsupported type"); |
| } |
| break; |
| |
| default: |
| TCU_FAIL("Unsupported type"); |
| } |
| } |
| |
| tcu::MessageBuilder& operator<< (tcu::MessageBuilder& message, rsg::ConstValueAccess value) |
| { |
| const char* scalarType = DE_NULL; |
| const char* vecType = DE_NULL; |
| |
| switch (value.getType().getBaseType()) |
| { |
| case rsg::VariableType::TYPE_FLOAT: scalarType = "float"; vecType = "vec"; break; |
| case rsg::VariableType::TYPE_INT: scalarType = "int"; vecType = "ivec"; break; |
| case rsg::VariableType::TYPE_BOOL: scalarType = "bool"; vecType = "bvec"; break; |
| case rsg::VariableType::TYPE_SAMPLER_2D: scalarType = "sampler2D"; break; |
| case rsg::VariableType::TYPE_SAMPLER_CUBE: scalarType = "samplerCube"; break; |
| default: |
| TCU_FAIL("Unsupported type."); |
| } |
| |
| int numElements = value.getType().getNumElements(); |
| if (numElements == 1) |
| message << scalarType << "("; |
| else |
| message << vecType << numElements << "("; |
| |
| for (int elementNdx = 0; elementNdx < numElements; elementNdx++) |
| { |
| if (elementNdx > 0) |
| message << ", "; |
| |
| switch (value.getType().getBaseType()) |
| { |
| case rsg::VariableType::TYPE_FLOAT: message << value.component(elementNdx).asFloat(); break; |
| case rsg::VariableType::TYPE_INT: message << value.component(elementNdx).asInt(); break; |
| case rsg::VariableType::TYPE_BOOL: message << (value.component(elementNdx).asBool() ? "true" : "false"); break; |
| case rsg::VariableType::TYPE_SAMPLER_2D: message << value.component(elementNdx).asInt(); break; |
| case rsg::VariableType::TYPE_SAMPLER_CUBE: message << value.component(elementNdx).asInt(); break; |
| default: |
| DE_ASSERT(DE_FALSE); |
| } |
| } |
| |
| message << ")"; |
| |
| return message; |
| } |
| |
| tcu::MessageBuilder& operator<< (tcu::MessageBuilder& message, rsg::ConstValueRangeAccess valueRange) |
| { |
| return message << valueRange.getMin() << " -> " << valueRange.getMax(); |
| } |
| |
| } // anonymous |
| |
| RandomShaderCase::IterateResult RandomShaderCase::iterate (void) |
| { |
| tcu::TestLog& log = m_testCtx.getLog(); |
| |
| // Compile program |
| glu::ShaderProgram program(m_renderCtx, glu::makeVtxFragSources(m_vertexShader.getSource(), m_fragmentShader.getSource())); |
| log << program; |
| |
| if (!program.isOk()) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Failed to compile shader"); |
| return STOP; |
| } |
| |
| // Compute random viewport |
| de::Random rnd (m_parameters.seed); |
| int viewportWidth = de::min<int>(VIEWPORT_WIDTH, m_renderCtx.getRenderTarget().getWidth()); |
| int viewportHeight = de::min<int>(VIEWPORT_HEIGHT, m_renderCtx.getRenderTarget().getHeight()); |
| int viewportX = rnd.getInt(0, m_renderCtx.getRenderTarget().getWidth() - viewportWidth); |
| int viewportY = rnd.getInt(0, m_renderCtx.getRenderTarget().getHeight() - viewportHeight); |
| bool hasAlpha = m_renderCtx.getRenderTarget().getPixelFormat().alphaBits > 0; |
| tcu::TextureLevel rendered (tcu::TextureFormat(hasAlpha ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), viewportWidth, viewportHeight); |
| tcu::TextureLevel reference (tcu::TextureFormat(hasAlpha ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), viewportWidth, viewportHeight); |
| |
| // Reference program executor. |
| rsg::ProgramExecutor executor (reference.getAccess(), m_gridWidth, m_gridHeight); |
| |
| GLU_CHECK_CALL(glUseProgram(program.getProgram())); |
| |
| // Set up attributes |
| for (vector<VertexArray>::const_iterator attribIter = m_vertexArrays.begin(); attribIter != m_vertexArrays.end(); attribIter++) |
| { |
| GLint location = glGetAttribLocation(program.getProgram(), attribIter->getName()); |
| |
| // Print to log. |
| log << tcu::TestLog::Message << "attribute[" << location << "]: " << attribIter->getName() << " = " << attribIter->getValueRange() << tcu::TestLog::EndMessage; |
| |
| if (location >= 0) |
| { |
| glVertexAttribPointer(location, attribIter->getNumComponents(), GL_FLOAT, GL_FALSE, 0, &attribIter->getVertices()[0]); |
| glEnableVertexAttribArray(location); |
| } |
| } |
| GLU_CHECK_MSG("After attribute setup"); |
| |
| // Uniforms |
| for (vector<rsg::VariableValue>::const_iterator uniformIter = m_uniforms.begin(); uniformIter != m_uniforms.end(); uniformIter++) |
| { |
| GLint location = glGetUniformLocation(program.getProgram(), uniformIter->getVariable()->getName()); |
| |
| log << tcu::TestLog::Message << "uniform[" << location << "]: " << uniformIter->getVariable()->getName() << " = " << uniformIter->getValue() << tcu::TestLog::EndMessage; |
| |
| if (location >= 0) |
| setUniformValue(location, uniformIter->getValue()); |
| } |
| GLU_CHECK_MSG("After uniform setup"); |
| |
| // Textures |
| vector<pair<int, const glu::Texture2D*> > tex2DBindings = m_texManager.getBindings2D(); |
| vector<pair<int, const glu::TextureCube*> > texCubeBindings = m_texManager.getBindingsCube(); |
| |
| for (vector<pair<int, const glu::Texture2D*> >::const_iterator i = tex2DBindings.begin(); i != tex2DBindings.end(); i++) |
| { |
| int unitNdx = i->first; |
| const glu::Texture2D* texture = i->second; |
| |
| glActiveTexture(GL_TEXTURE0 + unitNdx); |
| glBindTexture(GL_TEXTURE_2D, texture->getGLTexture()); |
| |
| executor.setTexture(unitNdx, &texture->getRefTexture(), glu::mapGLSampler(TEXTURE_WRAP_S, TEXTURE_WRAP_T, TEXTURE_MIN_FILTER, TEXTURE_MAG_FILTER)); |
| } |
| GLU_CHECK_MSG("After 2D texture setup"); |
| |
| for (vector<pair<int, const glu::TextureCube*> >::const_iterator i = texCubeBindings.begin(); i != texCubeBindings.end(); i++) |
| { |
| int unitNdx = i->first; |
| const glu::TextureCube* texture = i->second; |
| |
| glActiveTexture(GL_TEXTURE0 + unitNdx); |
| glBindTexture(GL_TEXTURE_CUBE_MAP, texture->getGLTexture()); |
| |
| executor.setTexture(unitNdx, &texture->getRefTexture(), glu::mapGLSampler(TEXTURE_WRAP_S, TEXTURE_WRAP_T, TEXTURE_MIN_FILTER, TEXTURE_MAG_FILTER)); |
| } |
| GLU_CHECK_MSG("After cubemap setup"); |
| |
| // Draw and read |
| glViewport(viewportX, viewportY, viewportWidth, viewportHeight); |
| glDrawElements(GL_TRIANGLES, (GLsizei)m_indices.size(), GL_UNSIGNED_SHORT, &m_indices[0]); |
| glFlush(); |
| GLU_CHECK_MSG("Draw"); |
| |
| // Render reference while GPU is doing work |
| executor.execute(m_vertexShader, m_fragmentShader, m_uniforms); |
| |
| if (rendered.getFormat().order != tcu::TextureFormat::RGBA || rendered.getFormat().type != tcu::TextureFormat::UNORM_INT8) |
| { |
| // Read as GL_RGBA8 |
| tcu::TextureLevel readBuf(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), rendered.getWidth(), rendered.getHeight()); |
| glu::readPixels(m_renderCtx, viewportX, viewportY, readBuf.getAccess()); |
| GLU_CHECK_MSG("Read pixels"); |
| tcu::copy(rendered, readBuf); |
| } |
| else |
| glu::readPixels(m_renderCtx, viewportX, viewportY, rendered.getAccess()); |
| |
| // Compare |
| { |
| float threshold = 0.02f; |
| bool imagesOk = tcu::fuzzyCompare(log, "Result", "Result images", reference.getAccess(), rendered.getAccess(), threshold, tcu::COMPARE_LOG_RESULT); |
| |
| if (imagesOk) |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| else |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); |
| } |
| |
| return STOP; |
| } |
| |
| } // gls |
| } // deqp |