1/*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2017 The Khronos Group Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 */ /*! 20 * \file glcLimitTest.cpp 21 * \brief Definition of template class. 22 */ /*-------------------------------------------------------------------*/ 23 24using namespace glw; 25 26template<typename DataType> 27LimitCase<DataType>::LimitCase(deqp::Context& context, 28 const char* caseName, 29 deUint32 limitToken, 30 DataType limitBoundry, 31 bool isBoundryMaximum, 32 const char* glslVersion, 33 const char* glslBuiltin, 34 const char* glslExtension) 35 : deqp::TestCase(context, caseName, "Token limit validation.") 36 , m_limitToken(limitToken) 37 , m_limitBoundry(limitBoundry) 38 , m_isBoundryMaximum(isBoundryMaximum) 39 , m_glslVersion(glslVersion) 40 , m_glslBuiltin(glslBuiltin) 41 , m_glslExtension(glslExtension) 42{ 43} 44 45template<typename DataType> 46LimitCase<DataType>::~LimitCase(void) 47{ 48} 49 50template<typename DataType> 51tcu::TestNode::IterateResult LimitCase<DataType>::iterate(void) 52{ 53 DataType limitValue = DataType(); 54 const Functions& gl = m_context.getRenderContext().getFunctions(); 55 56 // make sure that limit or builtin was specified 57 DE_ASSERT(m_limitToken || !m_glslBuiltin.empty()); 58 59 // check if limit was specified 60 if (m_limitToken) 61 { 62 // check if limit is not smaller or greater then boundry defined in specification 63 limitValue = getLimitValue(gl); 64 if (!isWithinBoundry(limitValue)) 65 { 66 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 67 return STOP; 68 } 69 70 // if glsl builtin wasn't defined then test already passed 71 if (m_glslBuiltin.empty()) 72 { 73 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 74 return STOP; 75 } 76 } 77 78 // create compute shader to check glsl builtin 79 std::string shaderSource = createShader(); 80 const GLchar* source = shaderSource.c_str(); 81 const GLuint program = gl.createProgram(); 82 GLuint shader = gl.createShader(GL_COMPUTE_SHADER); 83 gl.attachShader(program, shader); 84 gl.deleteShader(shader); 85 gl.shaderSource(shader, 1, &source, NULL); 86 gl.compileShader(shader); 87 gl.linkProgram(program); 88 89 GLint status; 90 gl.getProgramiv(program, GL_LINK_STATUS, &status); 91 GLint length; 92 gl.getProgramiv(program, GL_INFO_LOG_LENGTH, &length); 93 if (length > 1) 94 { 95 std::vector<GLchar> log(length); 96 gl.getProgramInfoLog(program, length, NULL, &log[0]); 97 m_testCtx.getLog() << tcu::TestLog::Message 98 << &log[0] 99 << tcu::TestLog::EndMessage; 100 } 101 if (status == GL_FALSE) 102 { 103 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 104 return STOP; 105 } 106 107 gl.useProgram(program); 108 109 GLuint buffer; 110 gl.genBuffers(1, &buffer); 111 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer); 112 gl.bufferData(GL_SHADER_STORAGE_BUFFER, sizeof(DataType), NULL, GL_DYNAMIC_DRAW); 113 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 114 115 gl.dispatchCompute(1, 1, 1); 116 117 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer); 118 gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); 119 DataType* data = static_cast<DataType*>(gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(DataType), GL_MAP_READ_BIT)); 120 DataType builtinValue = data[0]; 121 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); 122 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 123 124 if (m_limitToken) 125 { 126 // limit token was specified - compare builtin to it 127 if (isEqual(limitValue, builtinValue)) 128 { 129 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 130 } 131 else 132 { 133 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 134 m_testCtx.getLog() << tcu::TestLog::Message 135 << "Shader builtin has value: " 136 << builtinValue 137 << " which is different then the value of corresponding limit: " 138 << limitValue 139 << tcu::TestLog::EndMessage; 140 } 141 } 142 else 143 { 144 // limit token was not specified - compare builtin to the boundry 145 if (isWithinBoundry(builtinValue, true)) 146 { 147 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 148 } 149 else 150 { 151 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 152 m_testCtx.getLog() << tcu::TestLog::Message 153 << "Shader builtin value is: " 154 << builtinValue 155 << " which is outside of specified boundry." 156 << tcu::TestLog::EndMessage; 157 } 158 } 159 160 return STOP; 161} 162 163template<typename DataType> 164bool LimitCase<DataType>::isWithinBoundry(DataType value, bool isBuiltin) const 165{ 166 if (m_isBoundryMaximum) 167 { 168 // value should be smaller or euqual to boundry 169 if (isGreater(value, m_limitBoundry)) 170 { 171 m_testCtx.getLog() << tcu::TestLog::Message 172 << (isBuiltin ? "Builtin" : "Limit") 173 << " value is: " 174 << value 175 << " when it should not be greater than " 176 << m_limitBoundry 177 << tcu::TestLog::EndMessage; 178 return false; 179 } 180 } 181 else 182 { 183 // value should be greater or euqual to boundry 184 if (isSmaller(value, m_limitBoundry)) 185 { 186 m_testCtx.getLog() << tcu::TestLog::Message 187 << (isBuiltin ? "Builtin" : "Limit") 188 << " value is: " 189 << value 190 << "when it should not be smaller than " 191 << m_limitBoundry 192 << tcu::TestLog::EndMessage; 193 return false; 194 } 195 } 196 197 return true; 198} 199 200template<typename DataType> 201std::string LimitCase<DataType>::createShader() const 202{ 203 std::stringstream shader; 204 shader << "#version " << m_glslVersion << "\n"; 205 if (!m_glslExtension.empty()) 206 shader << "#extension " + m_glslExtension + " : require\n"; 207 shader << "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 208 "layout(std430) buffer Output {\n" 209 << getGLSLDataType() <<" data; } g_out;" 210 "void main() { " 211 "g_out.data = " << m_glslBuiltin << "; }"; 212 return shader.str(); 213} 214 215template<typename DataType> 216std::string LimitCase<DataType>::getGLSLDataType() const 217{ 218 return "int"; 219} 220 221template<> 222std::string LimitCase<GLfloat>::getGLSLDataType() const 223{ 224 return "float"; 225} 226 227template<> 228std::string LimitCase<tcu::IVec3>::getGLSLDataType() const 229{ 230 return "ivec3"; 231} 232 233template<typename DataType> 234bool LimitCase<DataType>::isEqual(DataType a, DataType b) const 235{ 236 return a == b; 237} 238 239template<> 240bool LimitCase<tcu::IVec3>::isEqual(tcu::IVec3 a, tcu::IVec3 b) const 241{ 242 tcu::BVec3 bVec = tcu::equal(a, b); 243 return tcu::boolAll(bVec); 244} 245 246template<typename DataType> 247bool LimitCase<DataType>::isGreater(DataType a, DataType b) const 248{ 249 return a > b; 250} 251 252template<> 253bool LimitCase<tcu::IVec3>::isGreater(tcu::IVec3 a, tcu::IVec3 b) const 254{ 255 tcu::BVec3 bVec = tcu::greaterThan(a, b); 256 return tcu::boolAll(bVec); 257} 258 259template<typename DataType> 260bool LimitCase<DataType>::isSmaller(DataType a, DataType b) const 261{ 262 return a < b; 263} 264 265template<> 266bool LimitCase<tcu::IVec3>::isSmaller(tcu::IVec3 a, tcu::IVec3 b) const 267{ 268 tcu::BVec3 bVec = tcu::lessThan(a, b); 269 return tcu::boolAll(bVec); 270} 271 272template<typename DataType> 273DataType LimitCase<DataType>::getLimitValue(const Functions&) const 274{ 275 return DataType(); 276} 277 278template<> 279GLint LimitCase<GLint>::getLimitValue(const Functions& gl) const 280{ 281 GLint value = -1; 282 gl.getIntegerv(m_limitToken, &value); 283 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv"); 284 return value; 285} 286 287template<> 288GLint64 LimitCase<GLint64>::getLimitValue(const Functions& gl) const 289{ 290 GLint64 value = -1; 291 gl.getInteger64v(m_limitToken, &value); 292 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInteger64v"); 293 return value; 294} 295 296template<> 297GLuint64 LimitCase<GLuint64>::getLimitValue(const Functions& gl) const 298{ 299 GLint64 value = -1; 300 gl.getInteger64v(m_limitToken, &value); 301 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInteger64v"); 302 return static_cast<GLuint64>(value); 303} 304 305template<> 306GLfloat LimitCase<GLfloat>::getLimitValue(const Functions& gl) const 307{ 308 GLfloat value = -1; 309 gl.getFloatv(m_limitToken, &value); 310 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv"); 311 return value; 312} 313 314template<> 315tcu::IVec3 LimitCase<tcu::IVec3>::getLimitValue(const Functions& gl) const 316{ 317 tcu::IVec3 value(-1); 318 for (int i = 0; i < 3; i++) 319 gl.getIntegeri_v(m_limitToken, (GLuint)i, &value[i]); 320 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegeri_v"); 321 return value; 322} 323 324