1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.0 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 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 GLSL ES 1.0 gl_FragData[] tests. 22 *//*--------------------------------------------------------------------*/ 23 24#include "es3fShaderFragDataTests.hpp" 25 26#include "glsShaderLibrary.hpp" 27 28#include "gluRenderContext.hpp" 29#include "gluShaderProgram.hpp" 30#include "gluDrawUtil.hpp" 31#include "gluPixelTransfer.hpp" 32#include "gluObjectWrapper.hpp" 33 34#include "tcuRenderTarget.hpp" 35#include "tcuStringTemplate.hpp" 36#include "tcuTestLog.hpp" 37#include "tcuSurface.hpp" 38 39#include "glwFunctions.hpp" 40#include "glwEnums.hpp" 41 42namespace deqp 43{ 44namespace gles3 45{ 46namespace Functional 47{ 48 49using std::string; 50using tcu::TestLog; 51 52namespace 53{ 54 55enum IndexExprType 56{ 57 INDEX_EXPR_STATIC = 0, 58 INDEX_EXPR_UNIFORM, 59 INDEX_EXPR_DYNAMIC, 60 61 INDEX_EXPR_TYPE_LAST 62}; 63 64static bool compareSingleColor (tcu::TestLog& log, const tcu::Surface& surface, tcu::RGBA expectedColor, tcu::RGBA threshold) 65{ 66 const int maxPrints = 10; 67 int numFailedPixels = 0; 68 69 log << TestLog::Message << "Expecting " << expectedColor << " with threshold " << threshold << TestLog::EndMessage; 70 71 for (int y = 0; y < surface.getHeight(); y++) 72 { 73 for (int x = 0; x < surface.getWidth(); x++) 74 { 75 const tcu::RGBA resultColor = surface.getPixel(x, y); 76 const bool isOk = compareThreshold(resultColor, expectedColor, threshold); 77 78 if (!isOk) 79 { 80 if (numFailedPixels < maxPrints) 81 log << TestLog::Message << "ERROR: Got " << resultColor << " at (" << x << ", " << y << ")!" << TestLog::EndMessage; 82 else if (numFailedPixels == maxPrints) 83 log << TestLog::Message << "..." << TestLog::EndMessage; 84 85 numFailedPixels += 1; 86 } 87 } 88 } 89 90 if (numFailedPixels > 0) 91 { 92 log << TestLog::Message << "Found " << numFailedPixels << " invalid pixels, comparison FAILED!" << TestLog::EndMessage; 93 log << TestLog::Image("ResultImage", "Result Image", surface); 94 return false; 95 } 96 else 97 { 98 log << TestLog::Message << "Image comparison passed." << TestLog::EndMessage; 99 return true; 100 } 101} 102 103class FragDataIndexingCase : public TestCase 104{ 105public: 106 FragDataIndexingCase (Context& context, const char* name, const char* description, IndexExprType indexExprType) 107 : TestCase (context, name, description) 108 , m_indexExprType (indexExprType) 109 { 110 } 111 112 static glu::ProgramSources genSources (const IndexExprType indexExprType) 113 { 114 const char* const fragIndexExpr = indexExprType == INDEX_EXPR_STATIC ? "0" : 115 indexExprType == INDEX_EXPR_UNIFORM ? "u_index" : 116 indexExprType == INDEX_EXPR_DYNAMIC ? "int(v_index)" : DE_NULL; 117 glu::ProgramSources sources; 118 119 DE_ASSERT(fragIndexExpr); 120 121 sources << glu::VertexSource( 122 "attribute highp vec4 a_position;\n" 123 "attribute highp float a_index;\n" 124 "attribute highp vec4 a_color;\n" 125 "varying mediump float v_index;\n" 126 "varying mediump vec4 v_color;\n" 127 "void main (void)\n" 128 "{\n" 129 " gl_Position = a_position;\n" 130 " v_color = a_color;\n" 131 " v_index = a_index;\n" 132 "}\n"); 133 134 sources << glu::FragmentSource(string( 135 "varying mediump vec4 v_color;\n" 136 "varying mediump float v_index;\n" 137 "uniform mediump int u_index;\n" 138 "void main (void)\n" 139 "{\n" 140 " gl_FragData[") + fragIndexExpr + "] = v_color;\n" 141 "}\n"); 142 143 return sources; 144 } 145 146 IterateResult iterate (void) 147 { 148 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 149 const glw::Functions& gl = renderCtx.getFunctions(); 150 const glu::ShaderProgram program (renderCtx, genSources(m_indexExprType)); 151 const int viewportW = de::min(renderCtx.getRenderTarget().getWidth(), 128); 152 const int viewportH = de::min(renderCtx.getRenderTarget().getHeight(), 128); 153 154 const float positions[] = 155 { 156 -1.0f, -1.0f, 157 +1.0f, -1.0f, 158 -1.0f, +1.0f, 159 +1.0f, +1.0f 160 }; 161 const float colors[] = 162 { 163 0.0f, 1.0f, 0.0f, 1.0f, 164 0.0f, 1.0f, 0.0f, 1.0f, 165 0.0f, 1.0f, 0.0f, 1.0f, 166 0.0f, 1.0f, 0.0f, 1.0f 167 }; 168 const float indexValues[] = { 0.0f, 0.0f, 0.0f, 0.0f }; 169 const deUint8 indices[] = { 0, 1, 2, 2, 1, 3 }; 170 171 const glu::VertexArrayBinding vertexArrays[] = 172 { 173 glu::va::Float("a_position", 2, 4, 0, &positions[0]), 174 glu::va::Float("a_color", 4, 4, 0, &colors[0]), 175 glu::va::Float("a_index", 1, 4, 0, &indexValues[0]) 176 }; 177 178 m_testCtx.getLog() << program; 179 180 if (!program.isOk()) 181 { 182 if (m_indexExprType == INDEX_EXPR_STATIC) 183 TCU_FAIL("Compile failed"); 184 else 185 throw tcu::NotSupportedError("Dynamic indexing of gl_FragData[] not supported"); 186 } 187 188 gl.clearColor (1.0f, 0.0f, 0.0f, 1.0f); 189 gl.clear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); 190 191 gl.viewport (0, 0, viewportW, viewportH); 192 gl.useProgram (program.getProgram()); 193 gl.uniform1i (gl.getUniformLocation(program.getProgram(), "u_index"), 0); 194 195 glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0], 196 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); 197 GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed"); 198 199 { 200 tcu::Surface result (viewportW, viewportH); 201 const tcu::RGBA threshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1); 202 bool isOk; 203 204 glu::readPixels(renderCtx, 0, 0, result.getAccess()); 205 GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed"); 206 207 isOk = compareSingleColor(m_testCtx.getLog(), result, tcu::RGBA::green(), threshold); 208 209 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 210 isOk ? "Pass" : "Image comparison failed"); 211 } 212 213 return STOP; 214 } 215 216private: 217 const IndexExprType m_indexExprType; 218}; 219 220class FragDataDrawBuffersCase : public TestCase 221{ 222public: 223 FragDataDrawBuffersCase (Context& context) 224 : TestCase(context, "draw_buffers", "gl_FragData[] and glDrawBuffers() interaction") 225 { 226 } 227 228 IterateResult iterate (void) 229 { 230 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 231 const glu::ShaderProgram program (renderCtx, glu::ProgramSources() 232 << glu::VertexSource( 233 "attribute highp vec4 a_position;\n" 234 "attribute highp vec4 a_color;\n" 235 "varying mediump vec4 v_color;\n" 236 "void main (void)\n" 237 "{\n" 238 " gl_Position = a_position;\n" 239 " v_color = a_color;\n" 240 "}\n") 241 << glu::FragmentSource( 242 "varying mediump vec4 v_color;\n" 243 "uniform mediump int u_index;\n" 244 "void main (void)\n" 245 "{\n" 246 " gl_FragData[u_index] = v_color;\n" 247 "}\n")); 248 const glw::Functions& gl = renderCtx.getFunctions(); 249 const int width = 128; 250 const int height = 128; 251 const int indexLoc = program.isOk() ? gl.getUniformLocation(program.getProgram(), "u_index") : -1; 252 const glu::Framebuffer fbo (renderCtx); 253 const glu::Renderbuffer colorBuf0 (renderCtx); 254 const glu::Renderbuffer colorBuf1 (renderCtx); 255 256 const float positions[] = 257 { 258 -1.0f, -1.0f, 259 +1.0f, -1.0f, 260 -1.0f, +1.0f, 261 +1.0f, +1.0f 262 }; 263 const float colors[] = 264 { 265 0.0f, 1.0f, 0.0f, 1.0f, 266 0.0f, 1.0f, 0.0f, 1.0f, 267 0.0f, 1.0f, 0.0f, 1.0f, 268 0.0f, 1.0f, 0.0f, 1.0f 269 }; 270 const deUint8 indices[] = { 0, 1, 2, 2, 1, 3 }; 271 272 const glu::VertexArrayBinding vertexArrays[] = 273 { 274 glu::va::Float("a_position", 2, 4, 0, &positions[0]), 275 glu::va::Float("a_color", 4, 4, 0, &colors[0]) 276 }; 277 278 m_testCtx.getLog() << program; 279 280 if (!program.isOk()) 281 throw tcu::NotSupportedError("Dynamic indexing of gl_FragData[] not supported"); 282 283 gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo); 284 for (int ndx = 0; ndx < 2; ndx++) 285 { 286 const deUint32 rbo = ndx == 0 ? *colorBuf0 : *colorBuf1; 287 288 gl.bindRenderbuffer(GL_RENDERBUFFER, rbo); 289 gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); 290 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+ndx, GL_RENDERBUFFER, rbo); 291 } 292 TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); 293 294 { 295 const deUint32 drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; 296 gl.drawBuffers(DE_LENGTH_OF_ARRAY(drawBuffers), &drawBuffers[0]); 297 } 298 299 gl.clearBufferfv(GL_COLOR, 0, tcu::RGBA::red().toVec().getPtr()); 300 gl.clearBufferfv(GL_COLOR, 1, tcu::RGBA::red().toVec().getPtr()); 301 302 gl.viewport (0, 0, width, height); 303 gl.useProgram (program.getProgram()); 304 305 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed"); 306 307 m_testCtx.getLog() << TestLog::Message << "Drawing to attachments 0 and 1, expecting only attachment 0 to change." << TestLog::EndMessage; 308 309 for (int ndx = 0; ndx < 2; ndx++) 310 { 311 gl.uniform1i(indexLoc, ndx); 312 glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0], 313 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); 314 } 315 GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed"); 316 317 { 318 tcu::Surface result (width, height); 319 const tcu::RGBA threshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1); 320 bool allOk = true; 321 322 for (int ndx = 0; ndx < 2; ndx++) 323 { 324 m_testCtx.getLog() << TestLog::Message << "Verifying attachment " << ndx << "..." << TestLog::EndMessage; 325 326 gl.readBuffer(GL_COLOR_ATTACHMENT0+ndx); 327 glu::readPixels(renderCtx, 0, 0, result.getAccess()); 328 GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed"); 329 330 if (!compareSingleColor(m_testCtx.getLog(), result, ndx == 0 ? tcu::RGBA::green() : tcu::RGBA::red(), threshold)) 331 allOk = false; 332 } 333 334 m_testCtx.setTestResult(allOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 335 allOk ? "Pass" : "Image comparison failed"); 336 } 337 338 return STOP; 339 } 340}; 341 342} // anonymous 343 344ShaderFragDataTests::ShaderFragDataTests (Context& context) 345 : TestCaseGroup(context, "fragdata", "gl_FragData[] Tests") 346{ 347} 348 349ShaderFragDataTests::~ShaderFragDataTests (void) 350{ 351} 352 353void ShaderFragDataTests::init (void) 354{ 355 addChild(new FragDataIndexingCase (m_context, "valid_static_index", "Valid gl_FragData[] assignment using static index", INDEX_EXPR_STATIC)); 356 addChild(new FragDataIndexingCase (m_context, "valid_uniform_index", "Valid gl_FragData[] assignment using uniform index", INDEX_EXPR_UNIFORM)); 357 addChild(new FragDataIndexingCase (m_context, "valid_dynamic_index", "Valid gl_FragData[] assignment using dynamic index", INDEX_EXPR_DYNAMIC)); 358 addChild(new FragDataDrawBuffersCase (m_context)); 359 360 // Negative cases. 361 { 362 gls::ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo()); 363 std::vector<tcu::TestNode*> negativeCases = library.loadShaderFile("shaders/fragdata.test"); 364 365 for (std::vector<tcu::TestNode*>::iterator i = negativeCases.begin(); i != negativeCases.end(); i++) 366 addChild(*i); 367 } 368} 369 370} // Functional 371} // gles3 372} // deqp 373