Home | History | Annotate | Download | only in common
      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 glcRobustnessTests.cpp
     21  * \brief Conformance tests for the Robustness feature functionality.
     22  */ /*-------------------------------------------------------------------*/
     23 
     24 #include "glcRobustnessTests.hpp"
     25 #include "deSharedPtr.hpp"
     26 #include "glcRobustBufferAccessBehaviorTests.hpp"
     27 #include "gluContextInfo.hpp"
     28 #include "gluPlatform.hpp"
     29 #include "gluRenderContext.hpp"
     30 #include "glwEnums.hpp"
     31 #include "glwFunctions.hpp"
     32 #include "tcuCommandLine.hpp"
     33 #include "tcuTestLog.hpp"
     34 #include <cstring>
     35 
     36 using namespace glw;
     37 using namespace deqp::RobustBufferAccessBehavior;
     38 
     39 namespace glcts
     40 {
     41 
     42 namespace ResetNotificationStrategy
     43 {
     44 
     45 class RobustnessBase : public tcu::TestCase
     46 {
     47 public:
     48 	RobustnessBase(tcu::TestContext& testCtx, const char* name, const char* description, glu::ApiType apiType);
     49 
     50 	glu::RenderContext* createRobustContext(glu::ResetNotificationStrategy reset);
     51 
     52 private:
     53 	glu::ApiType m_ApiType;
     54 };
     55 
     56 RobustnessBase::RobustnessBase(tcu::TestContext& testCtx, const char* name, const char* description,
     57 							   glu::ApiType apiType)
     58 	: tcu::TestCase(testCtx, name, description), m_ApiType(apiType)
     59 {
     60 }
     61 
     62 glu::RenderContext* RobustnessBase::createRobustContext(glu::ResetNotificationStrategy reset)
     63 {
     64 	/* Create test context to verify if GL_KHR_robustness extension is available */
     65 	{
     66 		deqp::Context context(m_testCtx, glu::ContextType(m_ApiType));
     67 		if (!context.getContextInfo().isExtensionSupported("GL_KHR_robustness") &&
     68 			!contextSupports(context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
     69 		{
     70 			m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED,
     71 									"GL_KHR_robustness extension not supported");
     72 			return NULL;
     73 		}
     74 	}
     75 
     76 	glu::RenderConfig		renderCfg(glu::ContextType(m_ApiType, glu::CONTEXT_ROBUST));
     77 	const tcu::CommandLine& commandLine = m_testCtx.getCommandLine();
     78 	glu::parseRenderConfig(&renderCfg, commandLine);
     79 
     80 	if (commandLine.getSurfaceType() == tcu::SURFACETYPE_WINDOW)
     81 		renderCfg.resetNotificationStrategy = reset;
     82 	else
     83 		throw tcu::NotSupportedError("Test not supported in non-windowed context");
     84 
     85 	/* Try to create core/es robusness context */
     86 	return createRenderContext(m_testCtx.getPlatform(), commandLine, renderCfg);
     87 }
     88 
     89 class NoResetNotificationCase : public RobustnessBase
     90 {
     91 	typedef glw::GLenum(GLW_APIENTRY* PFNGLGETGRAPHICSRESETSTATUS)();
     92 
     93 public:
     94 	NoResetNotificationCase(tcu::TestContext& testCtx, const char* name, const char* description, glu::ApiType apiType)
     95 		: RobustnessBase(testCtx, name, description, apiType)
     96 	{
     97 	}
     98 
     99 	virtual IterateResult iterate(void)
    100 	{
    101 		glu::ResetNotificationStrategy	strategy = glu::RESET_NOTIFICATION_STRATEGY_NO_RESET_NOTIFICATION;
    102 		de::SharedPtr<glu::RenderContext> robustContext(createRobustContext(strategy));
    103 		if (!robustContext.get())
    104 			return STOP;
    105 
    106 		PFNGLGETGRAPHICSRESETSTATUS pGetGraphicsResetStatus =
    107 			(PFNGLGETGRAPHICSRESETSTATUS)robustContext->getProcAddress("glGetGraphicsResetStatus");
    108 
    109 		if (DE_NULL == pGetGraphicsResetStatus)
    110 		{
    111 			m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR,
    112 									"Pointer to function glGetGraphicsResetStatus is NULL.");
    113 			return STOP;
    114 		}
    115 
    116 		glw::GLint reset = 0;
    117 
    118 		const glw::Functions& gl = robustContext->getFunctions();
    119 		gl.getIntegerv(GL_RESET_NOTIFICATION_STRATEGY, &reset);
    120 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv");
    121 
    122 		if (reset != GL_NO_RESET_NOTIFICATION)
    123 		{
    124 			m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! glGet returned wrong value [" << reset
    125 							   << ", expected " << GL_NO_RESET_NOTIFICATION << "]." << tcu::TestLog::EndMessage;
    126 
    127 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    128 			return STOP;
    129 		}
    130 
    131 		glw::GLint status = pGetGraphicsResetStatus();
    132 		if (status != GL_NO_ERROR)
    133 		{
    134 			m_testCtx.getLog() << tcu::TestLog::Message
    135 							   << "Test failed! glGetGraphicsResetStatus returned wrong value [" << status
    136 							   << ", expected " << GL_NO_ERROR << "]." << tcu::TestLog::EndMessage;
    137 
    138 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    139 			return STOP;
    140 		}
    141 
    142 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    143 		return STOP;
    144 	}
    145 };
    146 
    147 class LoseContextOnResetCase : public RobustnessBase
    148 {
    149 public:
    150 	LoseContextOnResetCase(tcu::TestContext& testCtx, const char* name, const char* description, glu::ApiType apiType)
    151 		: RobustnessBase(testCtx, name, description, apiType)
    152 	{
    153 	}
    154 
    155 	virtual IterateResult iterate(void)
    156 	{
    157 		glu::ResetNotificationStrategy	strategy = glu::RESET_NOTIFICATION_STRATEGY_LOSE_CONTEXT_ON_RESET;
    158 		de::SharedPtr<glu::RenderContext> robustContext(createRobustContext(strategy));
    159 		if (!robustContext.get())
    160 			return STOP;
    161 
    162 		glw::GLint reset = 0;
    163 
    164 		const glw::Functions& gl = robustContext->getFunctions();
    165 		gl.getIntegerv(GL_RESET_NOTIFICATION_STRATEGY, &reset);
    166 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv");
    167 
    168 		if (reset != GL_LOSE_CONTEXT_ON_RESET)
    169 		{
    170 			m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! glGet returned wrong value [" << reset
    171 							   << ", expected " << GL_LOSE_CONTEXT_ON_RESET << "]." << tcu::TestLog::EndMessage;
    172 
    173 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    174 			return STOP;
    175 		}
    176 
    177 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    178 		return STOP;
    179 	}
    180 };
    181 
    182 } // ResetNotificationStrategy namespace
    183 
    184 namespace RobustBufferAccessBehavior
    185 {
    186 
    187 static deqp::Context* createContext(tcu::TestContext& testCtx, glu::ApiType apiType)
    188 {
    189 	deqp::Context* context = new deqp::Context(testCtx, glu::ContextType(apiType));
    190 	if (!context)
    191 	{
    192 		testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Pointer to context is NULL.");
    193 		return DE_NULL;
    194 	}
    195 
    196 	if (!(contextSupports(context->getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
    197 		  (context->getContextInfo().isExtensionSupported("GL_KHR_robustness") &&
    198 		   context->getContextInfo().isExtensionSupported("GL_KHR_robust_buffer_access_behavior"))))
    199 	{
    200 		testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
    201 		delete context;
    202 		return DE_NULL;
    203 	}
    204 
    205 	return context;
    206 }
    207 
    208 /** Implementation of test GetnUniformTest. Description follows:
    209  *
    210  * This test verifies if read uniform variables to the buffer with bufSize less than expected result with GL_INVALID_OPERATION error;
    211  **/
    212 class GetnUniformTest : public tcu::TestCase
    213 {
    214 public:
    215 	/* Public methods */
    216 	GetnUniformTest(tcu::TestContext& testCtx, glu::ApiType apiType);
    217 	virtual ~GetnUniformTest()
    218 	{
    219 	}
    220 
    221 	/* Public methods inherited from TestCase */
    222 	virtual tcu::TestNode::IterateResult iterate(void);
    223 
    224 private:
    225 	/* Private methods */
    226 	std::string getComputeShader(bool glslES320);
    227 
    228 	bool verifyResult(const void* inputData, const void* resultData, int size, const char* method);
    229 	bool verifyError(glw::GLint error, glw::GLint expectedError, const char* method);
    230 
    231 	glu::ApiType m_ApiType;
    232 };
    233 
    234 /** Constructor
    235  *
    236  * @param context Test context
    237  **/
    238 GetnUniformTest::GetnUniformTest(tcu::TestContext& testCtx, glu::ApiType apiType)
    239 	: tcu::TestCase(testCtx, "getnuniform", "Verifies if read uniform variables to the buffer with bufSize less than "
    240 											"expected result with GL_INVALID_OPERATION")
    241 	, m_ApiType(apiType)
    242 {
    243 	/* Nothing to be done here */
    244 }
    245 
    246 /** Execute test
    247  *
    248  * @return tcu::TestNode::STOP
    249  **/
    250 tcu::TestNode::IterateResult GetnUniformTest::iterate()
    251 {
    252 	de::SharedPtr<deqp::Context> context(createContext(m_testCtx, m_ApiType));
    253 	if (!context.get())
    254 		return STOP;
    255 
    256 	/* GL funtion pointers. */
    257 	typedef void(GLW_APIENTRY * PFNGLGETNUNIFORMFV)(glw::GLuint program, glw::GLint location, glw::GLsizei bufSize,
    258 													glw::GLfloat * params);
    259 	typedef void(GLW_APIENTRY * PFNGLGETNUNIFORMIV)(glw::GLuint program, glw::GLint location, glw::GLsizei bufSize,
    260 													glw::GLint * params);
    261 	typedef void(GLW_APIENTRY * PFNGLGETNUNIFORMUIV)(glw::GLuint program, glw::GLint location, glw::GLsizei bufSize,
    262 													 glw::GLuint * params);
    263 
    264 	/* Function pointers need to be grabbed only for GL4.5 but it is done also for ES for consistency */
    265 	glu::RenderContext& renderContext   = context->getRenderContext();
    266 	PFNGLGETNUNIFORMFV  pGetnUniformfv  = (PFNGLGETNUNIFORMFV)renderContext.getProcAddress("glGetnUniformfv");
    267 	PFNGLGETNUNIFORMIV  pGetnUniformiv  = (PFNGLGETNUNIFORMIV)renderContext.getProcAddress("glGetnUniformiv");
    268 	PFNGLGETNUNIFORMUIV pGetnUniformuiv = (PFNGLGETNUNIFORMUIV)renderContext.getProcAddress("glGetnUniformuiv");
    269 
    270 	if ((DE_NULL == pGetnUniformfv) || (DE_NULL == pGetnUniformiv) || (DE_NULL == pGetnUniformuiv))
    271 	{
    272 		m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Pointer to function glGetnUniform* is NULL.");
    273 		return STOP;
    274 	}
    275 
    276 	const Functions& gl = renderContext.getFunctions();
    277 
    278 	const GLfloat input4f[]  = { 1.0f, 5.4f, 3.14159f, 1.28f };
    279 	const GLint   input3i[]  = { 10, -20, -30 };
    280 	const GLuint  input4ui[] = { 10, 20, 30, 40 };
    281 
    282 	/* Test result indicator */
    283 	bool test_result = true;
    284 
    285 	/* Iterate over all cases */
    286 	Program program(*context);
    287 
    288 	/* Compute Shader */
    289 	bool			   glslES320 = contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
    290 	const std::string& cs		 = getComputeShader(glslES320);
    291 
    292 	/* Shaders initialization */
    293 	program.Init(cs /* cs */, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
    294 	program.Use();
    295 
    296 	/* For gl4.5 use shader storage buffer */
    297 	GLuint buf;
    298 	if (!glslES320)
    299 	{
    300 		gl.genBuffers(1, &buf);
    301 		GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
    302 
    303 		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buf);
    304 		GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase");
    305 
    306 		gl.bufferData(GL_SHADER_STORAGE_BUFFER, 16, DE_NULL, GL_STREAM_DRAW);
    307 		GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData");
    308 	}
    309 
    310 	/* passing uniform values */
    311 	gl.programUniform4fv(program.m_id, 11, 1, input4f);
    312 	GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramUniform4fv");
    313 
    314 	gl.programUniform3iv(program.m_id, 12, 1, input3i);
    315 	GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramUniform3iv");
    316 
    317 	gl.programUniform4uiv(program.m_id, 13, 1, input4ui);
    318 	GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramUniform4uiv");
    319 
    320 	gl.dispatchCompute(1, 1, 1);
    321 	GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
    322 
    323 	/* veryfing gfetnUniform error messages */
    324 	GLfloat result4f[4];
    325 	GLint   result3i[3];
    326 	GLuint  result4ui[4];
    327 
    328 	pGetnUniformfv(program.m_id, 11, sizeof(GLfloat) * 4, result4f);
    329 	test_result = test_result &&
    330 				  verifyResult((void*)input4f, (void*)result4f, sizeof(GLfloat) * 4, "getnUniformfv [false negative]");
    331 	test_result = test_result && verifyError(gl.getError(), GL_NO_ERROR, "getnUniformfv [false negative]");
    332 
    333 	pGetnUniformfv(program.m_id, 11, sizeof(GLfloat) * 3, result4f);
    334 	test_result = test_result && verifyError(gl.getError(), GL_INVALID_OPERATION, "getnUniformfv [false positive]");
    335 
    336 	pGetnUniformiv(program.m_id, 12, sizeof(GLint) * 3, result3i);
    337 	test_result = test_result &&
    338 				  verifyResult((void*)input3i, (void*)result3i, sizeof(GLint) * 3, "getnUniformiv [false negative]");
    339 	test_result = test_result && verifyError(gl.getError(), GL_NO_ERROR, "getnUniformiv [false negative]");
    340 
    341 	pGetnUniformiv(program.m_id, 12, sizeof(GLint) * 2, result3i);
    342 	test_result = test_result && verifyError(gl.getError(), GL_INVALID_OPERATION, "getnUniformiv [false positive]");
    343 
    344 	pGetnUniformuiv(program.m_id, 13, sizeof(GLuint) * 4, result4ui);
    345 	test_result = test_result && verifyResult((void*)input4ui, (void*)result4ui, sizeof(GLuint) * 4,
    346 											  "getnUniformuiv [false negative]");
    347 	test_result = test_result && verifyError(gl.getError(), GL_NO_ERROR, "getnUniformuiv [false negative]");
    348 
    349 	pGetnUniformuiv(program.m_id, 13, sizeof(GLuint) * 3, result4ui);
    350 	test_result = test_result && verifyError(gl.getError(), GL_INVALID_OPERATION, "getnUniformuiv [false positive]");
    351 
    352 	/* Set result */
    353 	if (true == test_result)
    354 	{
    355 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    356 	}
    357 	else
    358 	{
    359 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    360 	}
    361 
    362 	if (!glslES320)
    363 	{
    364 		gl.deleteBuffers(1, &buf);
    365 	}
    366 
    367 	/* Done */
    368 	return tcu::TestNode::STOP;
    369 }
    370 
    371 std::string GetnUniformTest::getComputeShader(bool glslES320)
    372 {
    373 	std::stringstream shader;
    374 	shader << "#version " << (glslES320 ? "320 es\n" : "450\n");
    375 	shader << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
    376 			  "layout (location = 11) uniform vec4 inputf;\n"
    377 			  "layout (location = 12) uniform ivec3 inputi;\n"
    378 			  "layout (location = 13) uniform uvec4 inputu;\n";
    379 	if (glslES320)
    380 	{
    381 		shader << "shared float valuef;\n"
    382 				  "shared int valuei;\n"
    383 				  "shared uint valueu;\n";
    384 	}
    385 	else
    386 	{
    387 		shader << "layout (std140, binding = 0) buffer ssbo {"
    388 				  "   float valuef;\n"
    389 				  "   int valuei;\n"
    390 				  "   uint valueu;\n"
    391 				  "};\n";
    392 	}
    393 	shader << "void main()\n"
    394 			  "{\n"
    395 			  "   valuef = inputf.r + inputf.g + inputf.b + inputf.a;\n"
    396 			  "   valuei = inputi.r + inputi.g + inputi.b;\n"
    397 			  "   valueu = inputu.r + inputu.g + inputu.b + inputu.a;\n"
    398 			  "}\n";
    399 
    400 	return shader.str();
    401 }
    402 
    403 bool GetnUniformTest::verifyResult(const void* inputData, const void* resultData, int size, const char* method)
    404 {
    405 	int diff = memcmp(inputData, resultData, size);
    406 	if (diff != 0)
    407 	{
    408 		m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! " << method << " result is not as expected."
    409 						   << tcu::TestLog::EndMessage;
    410 
    411 		return false;
    412 	}
    413 
    414 	return true;
    415 }
    416 
    417 bool GetnUniformTest::verifyError(GLint error, GLint expectedError, const char* method)
    418 {
    419 	if (error != expectedError)
    420 	{
    421 		m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! " << method << " throws unexpected error ["
    422 						   << error << "]." << tcu::TestLog::EndMessage;
    423 
    424 		return false;
    425 	}
    426 
    427 	return true;
    428 }
    429 
    430 /** Implementation of test ReadnPixelsTest. Description follows:
    431  *
    432  * This test verifies if read pixels to the buffer with bufSize less than expected result with GL_INVALID_OPERATION error;
    433  **/
    434 class ReadnPixelsTest : public tcu::TestCase
    435 {
    436 public:
    437 	/* Public methods */
    438 	ReadnPixelsTest(tcu::TestContext& testCtx, glu::ApiType apiType);
    439 	virtual ~ReadnPixelsTest()
    440 	{
    441 	}
    442 
    443 	/* Public methods inherited from TestCase */
    444 	virtual tcu::TestNode::IterateResult iterate(void);
    445 
    446 private:
    447 	/* Private methods */
    448 	void cleanTexture(deqp::Context& context, glw::GLuint texture_id);
    449 	bool verifyResults(deqp::Context& context);
    450 	bool verifyError(glw::GLint error, glw::GLint expectedError, const char* method);
    451 
    452 	glu::ApiType m_ApiType;
    453 };
    454 
    455 /** Constructor
    456  *
    457  * @param context Test context
    458  **/
    459 ReadnPixelsTest::ReadnPixelsTest(tcu::TestContext& testCtx, glu::ApiType apiType)
    460 	: tcu::TestCase(testCtx, "readnpixels",
    461 					"Verifies if read pixels to the buffer with bufSize less than expected result "
    462 					"with GL_INVALID_OPERATION error")
    463 	, m_ApiType(apiType)
    464 {
    465 	/* Nothing to be done here */
    466 }
    467 
    468 /** Execute test
    469  *
    470  * @return tcu::TestNode::STOP
    471  **/
    472 tcu::TestNode::IterateResult ReadnPixelsTest::iterate()
    473 {
    474 	de::SharedPtr<deqp::Context> context(createContext(m_testCtx, m_ApiType));
    475 	if (!context.get())
    476 		return STOP;
    477 
    478 	/* GL funtion pointers. */
    479 	typedef void(GLW_APIENTRY * PFNGLREADNPIXELS)(glw::GLint x, glw::GLint y, glw::GLsizei width, glw::GLsizei height,
    480 												  glw::GLenum format, glw::GLenum type, glw::GLsizei bufSize,
    481 												  glw::GLvoid * data);
    482 
    483 	PFNGLREADNPIXELS pReadnPixels = (PFNGLREADNPIXELS)context->getRenderContext().getProcAddress("glReadnPixels");
    484 
    485 	if (DE_NULL == pReadnPixels)
    486 	{
    487 		m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Pointer to function glReadnPixels is NULL.");
    488 		return STOP;
    489 	}
    490 
    491 	static const GLuint elements[] = {
    492 		0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 1,
    493 	};
    494 
    495 	static const GLfloat vertices[] = {
    496 		0.0f,  0.0f,  0.0f, 1.0f, /* 0 */
    497 		-1.0f, 0.0f,  0.0f, 1.0f, /* 1 */
    498 		-1.0f, 1.0f,  0.0f, 1.0f, /* 2 */
    499 		0.0f,  1.0f,  0.0f, 1.0f, /* 3 */
    500 		1.0f,  1.0f,  0.0f, 1.0f, /* 4 */
    501 		1.0f,  0.0f,  0.0f, 1.0f, /* 5 */
    502 		1.0f,  -1.0f, 0.0f, 1.0f, /* 6 */
    503 		0.0f,  -1.0f, 0.0f, 1.0f, /* 7 */
    504 		-1.0f, -1.0f, 0.0f, 1.0f, /* 8 */
    505 	};
    506 
    507 	bool glslES320 = contextSupports(context->getRenderContext().getType(), glu::ApiType::es(3, 2));
    508 	std::string fs("#version ");
    509 	fs += (glslES320 ? "320 es\n" : "450\n");
    510 	fs += "layout (location = 0) out lowp uvec4 out_fs_color;\n"
    511 		  "\n"
    512 		  "void main()\n"
    513 		  "{\n"
    514 		  "	out_fs_color = uvec4(1, 0, 0, 1);\n"
    515 		  "}\n"
    516 		  "\n";
    517 
    518 	std::string vs("#version ");
    519 	vs += (glslES320 ? "320 es\n" : "450\n");
    520 	vs += "layout (location = 0) in vec4 in_vs_position;\n"
    521 		  "\n"
    522 		  "void main()\n"
    523 		  "{\n"
    524 		  "	gl_Position = in_vs_position;\n"
    525 		  "}\n"
    526 		  "\n";
    527 
    528 	static const GLuint height	 = 8;
    529 	static const GLuint width	  = 8;
    530 	static const GLuint n_vertices = 24;
    531 
    532 	/* GL entry points */
    533 	const Functions& gl = context->getRenderContext().getFunctions();
    534 
    535 	/* Test case objects */
    536 	Program		program(*context);
    537 	Texture		texture(*context);
    538 	Buffer		elements_buffer(*context);
    539 	Buffer		vertices_buffer(*context);
    540 	VertexArray vao(*context);
    541 
    542 	/* Vertex array initialization */
    543 	VertexArray::Generate(gl, vao.m_id);
    544 	VertexArray::Bind(gl, vao.m_id);
    545 
    546 	/* Texture initialization */
    547 	Texture::Generate(gl, texture.m_id);
    548 	Texture::Bind(gl, texture.m_id, GL_TEXTURE_2D);
    549 	Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R8UI, width, height, 0);
    550 	Texture::Bind(gl, 0, GL_TEXTURE_2D);
    551 
    552 	/* Framebuffer initialization */
    553 	GLuint fbo;
    554 	gl.genFramebuffers(1, &fbo);
    555 	GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
    556 	gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
    557 	GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
    558 	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.m_id, 0);
    559 	GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D");
    560 
    561 	/* Buffers initialization */
    562 	elements_buffer.InitData(GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(elements), elements);
    563 	vertices_buffer.InitData(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(vertices), vertices);
    564 
    565 	/* Shaders initialization */
    566 	program.Init("" /* cs */, fs, "" /* gs */, "" /* tcs */, "" /* tes */, vs);
    567 	Program::Use(gl, program.m_id);
    568 
    569 	/* Vertex buffer initialization */
    570 	vertices_buffer.Bind();
    571 	gl.bindVertexBuffer(0 /* bindindex = location */, vertices_buffer.m_id, 0 /* offset */, 16 /* stride */);
    572 	gl.vertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 16, NULL);
    573 	gl.enableVertexAttribArray(0 /* location */);
    574 
    575 	/* Binding elements/indices buffer */
    576 	elements_buffer.Bind();
    577 
    578 	cleanTexture(*context, texture.m_id);
    579 
    580 	gl.drawElements(GL_TRIANGLES, n_vertices, GL_UNSIGNED_INT, 0 /* indices */);
    581 	GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements");
    582 
    583 	/* Set result */
    584 	if (verifyResults(*context))
    585 	{
    586 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    587 	}
    588 	else
    589 	{
    590 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    591 	}
    592 
    593 	/* Done */
    594 	return tcu::TestNode::STOP;
    595 }
    596 
    597 /** Fill texture with value 128
    598  *
    599  * @param texture_id Id of texture
    600  **/
    601 void ReadnPixelsTest::cleanTexture(deqp::Context& context, glw::GLuint texture_id)
    602 {
    603 	static const GLuint height = 8;
    604 	static const GLuint width  = 8;
    605 
    606 	const Functions& gl = context.getRenderContext().getFunctions();
    607 
    608 	GLubyte pixels[width * height];
    609 	for (GLuint i = 0; i < width * height; ++i)
    610 	{
    611 		pixels[i] = 64;
    612 	}
    613 
    614 	Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
    615 
    616 	Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level  */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, 0 /* depth */,
    617 					  GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels);
    618 
    619 	/* Unbind */
    620 	Texture::Bind(gl, 0, GL_TEXTURE_2D);
    621 }
    622 
    623 /** Verifies glReadnPixels results
    624  *
    625  * @return true when glReadnPixels , false otherwise
    626  **/
    627 bool ReadnPixelsTest::verifyResults(deqp::Context& context)
    628 {
    629 	static const GLuint height	 = 8;
    630 	static const GLuint width	  = 8;
    631 	static const GLuint pixel_size = 4 * sizeof(GLuint);
    632 
    633 	const Functions& gl = context.getRenderContext().getFunctions();
    634 
    635 	//Valid buffer size test
    636 	const GLint bufSizeValid = width * height * pixel_size;
    637 	GLubyte		pixelsValid[bufSizeValid];
    638 
    639 	gl.readnPixels(0, 0, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, bufSizeValid, pixelsValid);
    640 	GLU_EXPECT_NO_ERROR(gl.getError(), "ReadnPixels");
    641 
    642 	//Verify glReadnPixels result
    643 	for (unsigned int i = 0; i < width * height; ++i)
    644 	{
    645 		const size_t offset = i * pixel_size;
    646 		const GLuint value  = *(GLuint*)(pixelsValid + offset);
    647 
    648 		if (value != 1)
    649 		{
    650 			context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid pixel value: " << value
    651 											  << ". Offset: " << offset << tcu::TestLog::EndMessage;
    652 			return false;
    653 		}
    654 	}
    655 
    656 	//Invalid buffer size test
    657 	const GLint bufSizeInvalid = width * height * pixel_size - 1;
    658 	GLubyte		pixelsInvalid[bufSizeInvalid];
    659 
    660 	gl.readnPixels(0, 0, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, bufSizeInvalid, pixelsInvalid);
    661 	if (!verifyError(gl.getError(), GL_INVALID_OPERATION, "ReadnPixels [false positive]"))
    662 		return false;
    663 
    664 	return true;
    665 }
    666 
    667 /** Verify operation errors
    668  *
    669  * @param error OpenGL ES error code
    670  * @param expectedError Expected error code
    671  * @param method Method name marker
    672  *
    673  * @return true when error is as expected, false otherwise
    674  **/
    675 bool ReadnPixelsTest::verifyError(GLint error, GLint expectedError, const char* method)
    676 {
    677 	if (error != expectedError)
    678 	{
    679 		m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! " << method << " throws unexpected error ["
    680 						   << error << "]." << tcu::TestLog::EndMessage;
    681 
    682 		return false;
    683 	}
    684 
    685 	return true;
    686 }
    687 
    688 } // RobustBufferAccessBehavior namespace
    689 
    690 RobustnessTests::RobustnessTests(tcu::TestContext& testCtx, glu::ApiType apiType)
    691 	: tcu::TestCaseGroup(testCtx, "robustness",
    692 						 "Verifies API coverage and functionality of GL_KHR_robustness extension.")
    693 	, m_ApiType(apiType)
    694 {
    695 }
    696 
    697 void RobustnessTests::init(void)
    698 {
    699 	tcu::TestCaseGroup::init();
    700 
    701 	try
    702 	{
    703 		addChild(new ResetNotificationStrategy::NoResetNotificationCase(
    704 			m_testCtx, "no_reset_notification", "Verifies if NO_RESET_NOTIFICATION strategy works as expected.",
    705 			m_ApiType));
    706 		addChild(new ResetNotificationStrategy::LoseContextOnResetCase(
    707 			m_testCtx, "lose_context_on_reset", "Verifies if LOSE_CONTEXT_ON_RESET strategy works as expected.",
    708 			m_ApiType));
    709 
    710 		addChild(new RobustBufferAccessBehavior::GetnUniformTest(m_testCtx, m_ApiType));
    711 		addChild(new RobustBufferAccessBehavior::ReadnPixelsTest(m_testCtx, m_ApiType));
    712 	}
    713 	catch (...)
    714 	{
    715 		// Destroy context.
    716 		tcu::TestCaseGroup::deinit();
    717 		throw;
    718 	}
    719 }
    720 
    721 } // glcts namespace
    722