Home | History | Annotate | Download | only in draw_buffers_indexed
      1 /*-------------------------------------------------------------------------
      2  * OpenGL Conformance Test Suite
      3  * -----------------------------
      4  *
      5  * Copyright (c) 2015-2016 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
     21  * \brief
     22  */ /*-------------------------------------------------------------------*/
     23 
     24 /*!
     25  * \file  esextcDrawBuffersIndexedBlending.hpp
     26  * \brief Draw Buffers Indexed tests 5. Blending
     27  */ /*-------------------------------------------------------------------*/
     28 
     29 #include "esextcDrawBuffersIndexedBlending.hpp"
     30 #include "gluPixelTransfer.hpp"
     31 #include "gluShaderProgram.hpp"
     32 #include "tcuTestLog.hpp"
     33 #include <cmath>
     34 
     35 namespace glcts
     36 {
     37 
     38 /** Constructor
     39  *
     40  *  @param context     Test context
     41  *  @param name        Test case's name
     42  *  @param description Test case's description
     43  **/
     44 DrawBuffersIndexedBlending::DrawBuffersIndexedBlending(Context& context, const ExtParameters& extParams,
     45 													   const char* name, const char* description)
     46 	: DrawBuffersIndexedBase(context, extParams, name, description)
     47 {
     48 	/* Left blank on purpose */
     49 }
     50 
     51 void DrawBuffersIndexedBlending::prepareFramebuffer()
     52 {
     53 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
     54 
     55 	glw::GLint maxDrawBuffers = 0;
     56 	gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
     57 	if (maxDrawBuffers < 4)
     58 	{
     59 		throw tcu::ResourceError("Minimum number of draw buffers too low");
     60 	}
     61 
     62 	gl.genFramebuffers(1, &m_fbo);
     63 	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
     64 
     65 	std::vector<glw::GLenum> bufs(maxDrawBuffers);
     66 	for (int i = 0; i < maxDrawBuffers; ++i)
     67 	{
     68 		bufs[i] = GL_COLOR_ATTACHMENT0 + i;
     69 	}
     70 	gl.drawBuffers(maxDrawBuffers, &bufs[0]);
     71 }
     72 
     73 void DrawBuffersIndexedBlending::releaseFramebuffer()
     74 {
     75 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
     76 
     77 	glw::GLint maxDrawBuffers = 0;
     78 	gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
     79 	if (maxDrawBuffers < 4)
     80 	{
     81 		throw tcu::ResourceError("Minimum number of draw buffers too low");
     82 	}
     83 
     84 	BlendMaskStateMachine state(m_context, m_testCtx.getLog(), maxDrawBuffers);
     85 	state.SetDefaults();
     86 	gl.deleteFramebuffers(1, &m_fbo);
     87 	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
     88 	glw::GLenum bufs[1] = { GL_BACK };
     89 	gl.drawBuffers(1, bufs);
     90 	gl.readBuffer(GL_BACK);
     91 }
     92 
     93 tcu::TestNode::IterateResult DrawBuffersIndexedBlending::iterate()
     94 {
     95 	static const glw::GLenum BlendFormats[] = {
     96 		GL_R8, GL_RG8, GL_RGB8, GL_RGB565, GL_RGBA4, GL_RGBA8,
     97 	};
     98 	static const int	kSize	= 32;
     99 	static unsigned int formatId = 0;
    100 
    101 	const glw::Functions& gl	 = m_context.getRenderContext().getFunctions();
    102 	glw::GLenum			  format = BlendFormats[formatId];
    103 
    104 	prepareFramebuffer();
    105 
    106 	// Check number of available draw buffers
    107 	glw::GLint maxDrawBuffers = 0;
    108 	gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
    109 	if (maxDrawBuffers < 4)
    110 	{
    111 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Minimum number of draw buffers too low");
    112 		return STOP;
    113 	}
    114 
    115 	// Prepare render targets
    116 	glw::GLuint tex;
    117 	gl.genTextures(1, &tex);
    118 	gl.bindTexture(GL_TEXTURE_2D_ARRAY, tex);
    119 	gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1, format, kSize, kSize, maxDrawBuffers);
    120 	for (int i = 0; i < maxDrawBuffers; ++i)
    121 	{
    122 		gl.framebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, tex, 0, i);
    123 	}
    124 
    125 	// Clear background color
    126 	tcu::Vec4 background(0.5f, 0.5f, 0.5f, 0.5f);
    127 	for (int i = 0; i < maxDrawBuffers; ++i)
    128 	{
    129 		gl.clearBufferfv(GL_COLOR, i, &background[0]);
    130 	}
    131 
    132 	// Prepare expected, blended color values
    133 	tcu::Vec4 colors[] = { tcu::Vec4(0.86f, 0.22f, 0.31f, 0.45f), tcu::Vec4(0.12f, 0.83f, 0.34f, 0.42f),
    134 						   tcu::Vec4(0.56f, 0.63f, 0.76f, 0.99f), tcu::Vec4(0.14f, 0.34f, 0.34f, 0.22f) };
    135 
    136 	int		  numComponents = NumComponents(format);
    137 	tcu::RGBA expected[]	= {
    138 		// GL_MIN
    139 		tcu::RGBA(static_cast<unsigned int>(background.x() * 255),
    140 				  static_cast<unsigned int>((numComponents >= 2 ? colors[0].y() : 0.0f) * 255),
    141 				  static_cast<unsigned int>((numComponents >= 3 ? colors[0].z() : 0.0f) * 255),
    142 				  static_cast<unsigned int>((numComponents == 4 ? background.w() : 1.0f) * 255)),
    143 		// GL_FUNC_ADD
    144 		tcu::RGBA(static_cast<unsigned int>(background.x() * 255),
    145 				  static_cast<unsigned int>((numComponents >= 2 ? background.y() : 0.0f) * 255),
    146 				  static_cast<unsigned int>((numComponents >= 3 ? background.z() : 0.0f) * 255),
    147 				  static_cast<unsigned int>((numComponents == 4 ? colors[1].w() : 1.0f) * 255)),
    148 		// GL_FUNC_SUBTRACT
    149 		tcu::RGBA(
    150 			static_cast<unsigned int>((colors[2].x() * (numComponents == 4 ? colors[2].w() : 1.0f) -
    151 									   background.x() * (numComponents == 4 ? background.w() : 1.0f)) *
    152 									  255),
    153 			static_cast<unsigned int>((numComponents >= 2 ?
    154 										   (colors[2].y() * (numComponents == 4 ? colors[2].w() : 1.0f) -
    155 											background.y() * (numComponents == 4 ? background.w() : 1.0f)) :
    156 										   0.0f) *
    157 									  255),
    158 			static_cast<unsigned int>((numComponents >= 3 ?
    159 										   (colors[2].z() * (numComponents == 4 ? colors[2].w() : 1.0f) -
    160 											background.z() * (numComponents == 4 ? background.w() : 1.0f)) :
    161 										   0.0f) *
    162 									  255),
    163 			static_cast<unsigned int>(
    164 				(numComponents == 4 ? (colors[2].w() * colors[2].w() - background.w() * background.w()) : 1.0f) * 255)),
    165 		// GL_FUNC_REVERSE_SUBTRACT
    166 		tcu::RGBA(static_cast<unsigned int>((background.x() - colors[3].x()) * 255),
    167 				  static_cast<unsigned int>((numComponents >= 2 ? (background.y() - colors[3].y()) : 0.0f) * 255),
    168 				  static_cast<unsigned int>((numComponents >= 3 ? (background.z() - colors[3].z()) : 0.0f) * 255),
    169 				  static_cast<unsigned int>((numComponents == 4 ? (background.w() - colors[3].w()) : 1.0f) * 255))
    170 	};
    171 
    172 	// Setup blending operations
    173 	BlendMaskStateMachine state(m_context, m_testCtx.getLog(), maxDrawBuffers);
    174 	for (int i = 0; i < maxDrawBuffers; ++i)
    175 	{
    176 		switch (i % 4)
    177 		{
    178 		case 0:
    179 			// GL_MIN
    180 			state.SetEnablei(i);
    181 			state.SetBlendEquationSeparatei(i, GL_MIN, GL_MAX);
    182 			state.SetBlendFunci(i, GL_ONE, GL_ONE);
    183 			break;
    184 		case 1:
    185 			// GL_FUNC_ADD
    186 			state.SetEnablei(i);
    187 			state.SetBlendEquationi(i, GL_FUNC_ADD);
    188 			state.SetBlendFuncSeparatei(i, GL_ZERO, GL_ONE, GL_ONE, GL_ZERO);
    189 			break;
    190 		case 2:
    191 			// GL_FUNC_SUBTRACT
    192 			state.SetEnablei(i);
    193 			state.SetBlendEquationi(i, GL_FUNC_SUBTRACT);
    194 			state.SetBlendFunci(i, GL_SRC_ALPHA, GL_DST_ALPHA);
    195 			break;
    196 		case 3:
    197 			// GL_FUNC_REVERSE_SUBTRACT
    198 			state.SetEnablei(i);
    199 			state.SetBlendEquationi(i, GL_FUNC_REVERSE_SUBTRACT);
    200 			state.SetBlendFunci(i, GL_ONE, GL_ONE);
    201 			break;
    202 		}
    203 	}
    204 
    205 	// Prepare shader programs and draw fullscreen quad
    206 	glu::ShaderProgram program(m_context.getRenderContext(),
    207 							   glu::makeVtxFragSources(GenVS().c_str(), GenFS(maxDrawBuffers).c_str()));
    208 	if (!program.isOk())
    209 	{
    210 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Could not create shader program");
    211 		return STOP;
    212 	}
    213 	gl.useProgram(program.getProgram());
    214 
    215 	glw::GLuint positionLocation = gl.getAttribLocation(program.getProgram(), "position");
    216 	tcu::Vec3   vertices[]		 = {
    217 		tcu::Vec3(-1.0f, -1.0f, 0.0f), tcu::Vec3(1.0f, -1.0f, 0.0f), tcu::Vec3(-1.0f, 1.0f, 0.0f),
    218 		tcu::Vec3(1.0f, 1.0f, 0.0f),   tcu::Vec3(-1.0f, 1.0f, 0.0f), tcu::Vec3(1.0f, -1.0f, 0.0f)
    219 	};
    220 
    221 	gl.vertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
    222 	gl.enableVertexAttribArray(positionLocation);
    223 
    224 	for (int i = 0; i < maxDrawBuffers; ++i)
    225 	{
    226 		std::ostringstream os;
    227 		os << "c" << i;
    228 		// i.e.: glUniform4fv(glGetUniformLocation(m_program, "c0"), 1, &colors[i].r);
    229 		gl.uniform4fv(gl.getUniformLocation(program.getProgram(), os.str().c_str()), 1, &colors[i % 4][0]);
    230 	}
    231 
    232 	gl.drawArrays(GL_TRIANGLES, 0, 6);
    233 
    234 	// Read buffer colors and validate proper blending behaviour
    235 	bool	  success = true;
    236 	tcu::RGBA epsilon = GetEpsilon();
    237 	for (int i = 0; i < maxDrawBuffers; ++i)
    238 	{
    239 		gl.readBuffer(GL_COLOR_ATTACHMENT0 + i);
    240 
    241 		tcu::TextureLevel textureLevel(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8),
    242 									   kSize, kSize);
    243 		glu::readPixels(m_context.getRenderContext(), 0, 0, textureLevel.getAccess());
    244 
    245 		if (!VerifyImg(textureLevel, expected[i % 4], epsilon))
    246 		{
    247 			m_testCtx.getLog() << tcu::TestLog::Message << "Blending error in texture format " << format
    248 							   << " occurred for draw buffer #" << i << "\n"
    249 							   << tcu::TestLog::EndMessage;
    250 			m_testCtx.getLog() << tcu::TestLog::Image("Result", "Rendered result image", textureLevel.getAccess());
    251 			success = false;
    252 		}
    253 	}
    254 
    255 	gl.disable(GL_BLEND);
    256 	gl.useProgram(0);
    257 	gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0);
    258 	gl.deleteTextures(1, &tex);
    259 	releaseFramebuffer();
    260 
    261 	// Check for error
    262 	glw::GLenum error_code = gl.getError();
    263 	if (error_code != GL_NO_ERROR)
    264 	{
    265 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Some functions generated error");
    266 		formatId = 0;
    267 		return STOP;
    268 	}
    269 
    270 	if (!success)
    271 	{
    272 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Blending error occurred");
    273 		formatId = 0;
    274 		return STOP;
    275 	}
    276 	else
    277 	{
    278 		++formatId;
    279 		if (formatId < (sizeof(BlendFormats) / sizeof(BlendFormats[0])))
    280 		{
    281 			return CONTINUE;
    282 		}
    283 		else
    284 		{
    285 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    286 			formatId = 0;
    287 			return STOP;
    288 		}
    289 	}
    290 }
    291 
    292 std::string DrawBuffersIndexedBlending::GenVS()
    293 {
    294 	std::ostringstream os;
    295 	os << "#version 300 es                        \n"
    296 		  "precision highp float;                 \n"
    297 		  "precision highp int;                   \n"
    298 		  "layout(location = 0) in vec4 position; \n"
    299 		  "void main() {                          \n"
    300 		  "    gl_Position = position;            \n"
    301 		  "}";
    302 	return os.str();
    303 }
    304 std::string DrawBuffersIndexedBlending::GenFS(int maxDrawBuffers)
    305 {
    306 	std::ostringstream os;
    307 	os << "#version 300 es                        \n"
    308 		  "precision highp float;                 \n"
    309 		  "precision highp int;                   \n";
    310 
    311 	for (int i = 0; i < maxDrawBuffers; ++i)
    312 	{
    313 		os << "\nlayout(location = " << i << ") out vec4 color" << i << ";";
    314 	}
    315 	for (int i = 0; i < maxDrawBuffers; ++i)
    316 	{
    317 		os << "\nuniform vec4 c" << i << ";";
    318 	}
    319 
    320 	os << "\nvoid main() {";
    321 
    322 	for (int i = 0; i < maxDrawBuffers; ++i)
    323 	{
    324 		os << "\n    color" << i << " = c" << i << ";";
    325 	}
    326 
    327 	os << "\n}";
    328 	return os.str();
    329 }
    330 
    331 unsigned int DrawBuffersIndexedBlending::NumComponents(glw::GLenum format)
    332 {
    333 	switch (format)
    334 	{
    335 	case GL_R8:
    336 	case GL_R8I:
    337 	case GL_R8UI:
    338 	case GL_R16I:
    339 	case GL_R16UI:
    340 	case GL_R32I:
    341 	case GL_R32UI:
    342 		return 1;
    343 	case GL_RG8:
    344 	case GL_RG8I:
    345 	case GL_RG8UI:
    346 	case GL_RG16I:
    347 	case GL_RG16UI:
    348 	case GL_RG32I:
    349 	case GL_RG32UI:
    350 		return 2;
    351 	case GL_RGB8:
    352 	case GL_RGB565:
    353 		return 3;
    354 	case GL_RGBA4:
    355 	case GL_RGB5_A1:
    356 	case GL_RGBA8:
    357 	case GL_RGB10_A2:
    358 	case GL_RGBA8I:
    359 	case GL_RGBA8UI:
    360 	case GL_RGBA16I:
    361 	case GL_RGBA16UI:
    362 	case GL_RGBA32I:
    363 	case GL_RGBA32UI:
    364 		return 4;
    365 	default:
    366 		return 0;
    367 	}
    368 }
    369 
    370 tcu::RGBA DrawBuffersIndexedBlending::GetEpsilon()
    371 {
    372 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    373 
    374 	tcu::IVec4 bits;
    375 	tcu::UVec4 epsilon;
    376 
    377 	for (int i = 0; i < 4; ++i)
    378 	{
    379 		gl.getIntegerv(GL_RED_BITS + i, &bits[i]);
    380 		epsilon[i] = de::min(
    381 			255u, static_cast<unsigned int>(ceil(1.0 + 255.0 * (1.0 / pow(2.0, static_cast<double>(bits[i]))))));
    382 	}
    383 
    384 	return tcu::RGBA(epsilon.x(), epsilon.y(), epsilon.z(), epsilon.w());
    385 }
    386 
    387 bool DrawBuffersIndexedBlending::VerifyImg(const tcu::TextureLevel& textureLevel, tcu::RGBA expectedColor,
    388 										   tcu::RGBA epsilon)
    389 {
    390 	for (int y = 0; y < textureLevel.getHeight(); ++y)
    391 	{
    392 		for (int x = 0; x < textureLevel.getWidth(); ++x)
    393 		{
    394 			tcu::RGBA pixel(textureLevel.getAccess().getPixel(x, y));
    395 			if (!tcu::compareThreshold(pixel, expectedColor, epsilon))
    396 			{
    397 				m_testCtx.getLog() << tcu::TestLog::Message << "Expected value: " << expectedColor << "\n"
    398 								   << "Read value:     " << pixel << "\n"
    399 								   << "Epsilon:        " << epsilon << tcu::TestLog::EndMessage;
    400 				return false;
    401 			}
    402 		}
    403 	}
    404 	return true;
    405 }
    406 
    407 } // namespace glcts
    408