1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL (ES) 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 Shader execution utilities. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "glsShaderExecUtil.hpp" 25 #include "gluRenderContext.hpp" 26 #include "gluDrawUtil.hpp" 27 #include "gluObjectWrapper.hpp" 28 #include "gluShaderProgram.hpp" 29 #include "gluTextureUtil.hpp" 30 #include "gluProgramInterfaceQuery.hpp" 31 #include "gluPixelTransfer.hpp" 32 #include "tcuTestLog.hpp" 33 #include "glwFunctions.hpp" 34 #include "glwEnums.hpp" 35 #include "deSTLUtil.hpp" 36 #include "deStringUtil.hpp" 37 #include "deUniquePtr.hpp" 38 #include "deMemory.h" 39 40 #include <map> 41 42 namespace deqp 43 { 44 namespace gls 45 { 46 47 namespace ShaderExecUtil 48 { 49 50 using std::vector; 51 52 static bool isExtensionSupported (const glu::RenderContext& renderCtx, const std::string& extension) 53 { 54 const glw::Functions& gl = renderCtx.getFunctions(); 55 int numExts = 0; 56 57 gl.getIntegerv(GL_NUM_EXTENSIONS, &numExts); 58 59 for (int ndx = 0; ndx < numExts; ndx++) 60 { 61 const char* curExt = (const char*)gl.getStringi(GL_EXTENSIONS, ndx); 62 63 if (extension == curExt) 64 return true; 65 } 66 67 return false; 68 } 69 70 static void checkExtension (const glu::RenderContext& renderCtx, const std::string& extension) 71 { 72 if (!isExtensionSupported(renderCtx, extension)) 73 throw tcu::NotSupportedError(extension + " is not supported"); 74 } 75 76 // Shader utilities 77 78 static std::string generateVertexShader (const ShaderSpec& shaderSpec) 79 { 80 const bool usesInout = glu::glslVersionUsesInOutQualifiers(shaderSpec.version); 81 const char* in = usesInout ? "in" : "attribute"; 82 const char* out = usesInout ? "out" : "varying"; 83 std::ostringstream src; 84 85 src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n"; 86 87 if (!shaderSpec.globalDeclarations.empty()) 88 src << shaderSpec.globalDeclarations << "\n"; 89 90 for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input) 91 src << in << " " << glu::declare(input->varType, input->name) << ";\n"; 92 93 for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) 94 { 95 DE_ASSERT(output->varType.isBasicType()); 96 97 if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType())) 98 { 99 const int vecSize = glu::getDataTypeScalarSize(output->varType.getBasicType()); 100 const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; 101 const glu::VarType intType (intBaseType, glu::PRECISION_HIGHP); 102 103 src << "flat " << out << " " << glu::declare(intType, "o_" + output->name) << ";\n"; 104 } 105 else 106 src << "flat " << out << " " << glu::declare(output->varType, output->name) << ";\n"; 107 } 108 109 src << "\n" 110 << "void main (void)\n" 111 << "{\n" 112 << " gl_Position = vec4(0.0);\n" 113 << " gl_PointSize = 1.0;\n\n"; 114 115 // Declare necessary output variables (bools). 116 for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) 117 { 118 if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType())) 119 src << "\t" << glu::declare(output->varType, output->name) << ";\n"; 120 } 121 122 // Operation - indented to correct level. 123 { 124 std::istringstream opSrc (shaderSpec.source); 125 std::string line; 126 127 while (std::getline(opSrc, line)) 128 src << "\t" << line << "\n"; 129 } 130 131 // Assignments to outputs. 132 for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) 133 { 134 if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType())) 135 { 136 const int vecSize = glu::getDataTypeScalarSize(output->varType.getBasicType()); 137 const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; 138 139 src << "\to_" << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << output->name << ");\n"; 140 } 141 } 142 143 src << "}\n"; 144 145 return src.str(); 146 } 147 148 static std::string generateGeometryShader (const ShaderSpec& shaderSpec) 149 { 150 DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version)); 151 152 std::ostringstream src; 153 154 src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n"; 155 156 if (glu::glslVersionIsES(shaderSpec.version) && shaderSpec.version <= glu::GLSL_VERSION_310_ES) 157 src << "#extension GL_EXT_geometry_shader : require\n"; 158 159 if (!shaderSpec.globalDeclarations.empty()) 160 src << shaderSpec.globalDeclarations << "\n"; 161 162 src << "layout(points) in;\n" 163 << "layout(points, max_vertices = 1) out;\n"; 164 165 for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input) 166 src << "flat in " << glu::declare(input->varType, "geom_" + input->name) << "[];\n"; 167 168 for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) 169 { 170 DE_ASSERT(output->varType.isBasicType()); 171 172 if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType())) 173 { 174 const int vecSize = glu::getDataTypeScalarSize(output->varType.getBasicType()); 175 const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; 176 const glu::VarType intType (intBaseType, glu::PRECISION_HIGHP); 177 178 src << "flat out " << glu::declare(intType, "o_" + output->name) << ";\n"; 179 } 180 else 181 src << "flat out " << glu::declare(output->varType, output->name) << ";\n"; 182 } 183 184 src << "\n" 185 << "void main (void)\n" 186 << "{\n" 187 << " gl_Position = gl_in[0].gl_Position;\n\n"; 188 189 // Fetch input variables 190 for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input) 191 src << "\t" << glu::declare(input->varType, input->name) << " = geom_" << input->name << "[0];\n"; 192 193 // Declare necessary output variables (bools). 194 for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) 195 { 196 if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType())) 197 src << "\t" << glu::declare(output->varType, output->name) << ";\n"; 198 } 199 200 src << "\n"; 201 202 // Operation - indented to correct level. 203 { 204 std::istringstream opSrc (shaderSpec.source); 205 std::string line; 206 207 while (std::getline(opSrc, line)) 208 src << "\t" << line << "\n"; 209 } 210 211 // Assignments to outputs. 212 for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) 213 { 214 if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType())) 215 { 216 const int vecSize = glu::getDataTypeScalarSize(output->varType.getBasicType()); 217 const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; 218 219 src << "\to_" << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << output->name << ");\n"; 220 } 221 } 222 223 src << " EmitVertex();\n" 224 << " EndPrimitive();\n" 225 << "}\n"; 226 227 return src.str(); 228 } 229 230 static std::string generateEmptyFragmentSource (glu::GLSLVersion version) 231 { 232 const bool customOut = glu::glslVersionUsesInOutQualifiers(version); 233 std::ostringstream src; 234 235 src << glu::getGLSLVersionDeclaration(version) << "\n"; 236 237 // \todo [2013-08-05 pyry] Do we need one dummy output? 238 239 src << "void main (void)\n{\n"; 240 if (!customOut) 241 src << " gl_FragColor = vec4(0.0);\n"; 242 src << "}\n"; 243 244 return src.str(); 245 } 246 247 static std::string generatePassthroughVertexShader (const ShaderSpec& shaderSpec, const char* inputPrefix, const char* outputPrefix) 248 { 249 // flat qualifier is not present in earlier versions? 250 DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version)); 251 252 std::ostringstream src; 253 254 src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n" 255 << "in highp vec4 a_position;\n"; 256 257 for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input) 258 { 259 src << "in " << glu::declare(input->varType, inputPrefix + input->name) << ";\n" 260 << "flat out " << glu::declare(input->varType, outputPrefix + input->name) << ";\n"; 261 } 262 263 src << "\nvoid main (void)\n{\n" 264 << " gl_Position = a_position;\n" 265 << " gl_PointSize = 1.0;\n"; 266 267 for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input) 268 src << "\t" << outputPrefix << input->name << " = " << inputPrefix << input->name << ";\n"; 269 270 src << "}\n"; 271 272 return src.str(); 273 } 274 275 static std::string generateFragmentShader (const ShaderSpec& shaderSpec, bool useIntOutputs, const std::map<std::string, int>& outLocationMap) 276 { 277 DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version)); 278 279 std::ostringstream src; 280 src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n"; 281 282 if (!shaderSpec.globalDeclarations.empty()) 283 src << shaderSpec.globalDeclarations << "\n"; 284 285 for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input) 286 src << "flat in " << glu::declare(input->varType, input->name) << ";\n"; 287 288 for (int outNdx = 0; outNdx < (int)shaderSpec.outputs.size(); ++outNdx) 289 { 290 const Symbol& output = shaderSpec.outputs[outNdx]; 291 const int location = de::lookup(outLocationMap, output.name); 292 const std::string outVarName = "o_" + output.name; 293 glu::VariableDeclaration decl (output.varType, outVarName, glu::STORAGE_OUT, glu::INTERPOLATION_LAST, glu::Layout(location)); 294 295 TCU_CHECK_INTERNAL(output.varType.isBasicType()); 296 297 if (useIntOutputs && glu::isDataTypeFloatOrVec(output.varType.getBasicType())) 298 { 299 const int vecSize = glu::getDataTypeScalarSize(output.varType.getBasicType()); 300 const glu::DataType uintBasicType = vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT; 301 const glu::VarType uintType (uintBasicType, glu::PRECISION_HIGHP); 302 303 decl.varType = uintType; 304 src << decl << ";\n"; 305 } 306 else if (glu::isDataTypeBoolOrBVec(output.varType.getBasicType())) 307 { 308 const int vecSize = glu::getDataTypeScalarSize(output.varType.getBasicType()); 309 const glu::DataType intBasicType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; 310 const glu::VarType intType (intBasicType, glu::PRECISION_HIGHP); 311 312 decl.varType = intType; 313 src << decl << ";\n"; 314 } 315 else if (glu::isDataTypeMatrix(output.varType.getBasicType())) 316 { 317 const int vecSize = glu::getDataTypeMatrixNumRows(output.varType.getBasicType()); 318 const int numVecs = glu::getDataTypeMatrixNumColumns(output.varType.getBasicType()); 319 const glu::DataType uintBasicType = glu::getDataTypeUintVec(vecSize); 320 const glu::VarType uintType (uintBasicType, glu::PRECISION_HIGHP); 321 322 decl.varType = uintType; 323 for (int vecNdx = 0; vecNdx < numVecs; ++vecNdx) 324 { 325 decl.name = outVarName + "_" + de::toString(vecNdx); 326 decl.layout.location = location + vecNdx; 327 src << decl << ";\n"; 328 } 329 } 330 else 331 src << glu::VariableDeclaration(output.varType, output.name, glu::STORAGE_OUT, glu::INTERPOLATION_LAST, location) << ";\n"; 332 } 333 334 src << "\nvoid main (void)\n{\n"; 335 336 for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) 337 { 338 if ((useIntOutputs && glu::isDataTypeFloatOrVec(output->varType.getBasicType())) || 339 glu::isDataTypeBoolOrBVec(output->varType.getBasicType()) || 340 glu::isDataTypeMatrix(output->varType.getBasicType())) 341 src << "\t" << glu::declare(output->varType, output->name) << ";\n"; 342 } 343 344 // Operation - indented to correct level. 345 { 346 std::istringstream opSrc (shaderSpec.source); 347 std::string line; 348 349 while (std::getline(opSrc, line)) 350 src << "\t" << line << "\n"; 351 } 352 353 for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) 354 { 355 if (useIntOutputs && glu::isDataTypeFloatOrVec(output->varType.getBasicType())) 356 src << " o_" << output->name << " = floatBitsToUint(" << output->name << ");\n"; 357 else if (glu::isDataTypeMatrix(output->varType.getBasicType())) 358 { 359 const int numVecs = glu::getDataTypeMatrixNumColumns(output->varType.getBasicType()); 360 361 for (int vecNdx = 0; vecNdx < numVecs; ++vecNdx) 362 if (useIntOutputs) 363 src << "\to_" << output->name << "_" << vecNdx << " = floatBitsToUint(" << output->name << "[" << vecNdx << "]);\n"; 364 else 365 src << "\to_" << output->name << "_" << vecNdx << " = " << output->name << "[" << vecNdx << "];\n"; 366 } 367 else if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType())) 368 { 369 const int vecSize = glu::getDataTypeScalarSize(output->varType.getBasicType()); 370 const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; 371 372 src << "\to_" << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << output->name << ");\n"; 373 } 374 } 375 376 src << "}\n"; 377 378 return src.str(); 379 } 380 381 // ShaderExecutor 382 383 ShaderExecutor::ShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec) 384 : m_renderCtx (renderCtx) 385 , m_inputs (shaderSpec.inputs) 386 , m_outputs (shaderSpec.outputs) 387 { 388 } 389 390 ShaderExecutor::~ShaderExecutor (void) 391 { 392 } 393 394 void ShaderExecutor::useProgram (void) 395 { 396 DE_ASSERT(isOk()); 397 m_renderCtx.getFunctions().useProgram(getProgram()); 398 } 399 400 // VertexProcessorExecutor (base class for vertex and geometry executors) 401 402 class VertexProcessorExecutor : public ShaderExecutor 403 { 404 public: 405 VertexProcessorExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec, const glu::ProgramSources& sources); 406 ~VertexProcessorExecutor(void); 407 408 bool isOk (void) const { return m_program.isOk(); } 409 void log (tcu::TestLog& dst) const { dst << m_program; } 410 deUint32 getProgram (void) const { return m_program.getProgram(); } 411 412 void execute (int numValues, const void* const* inputs, void* const* outputs); 413 414 protected: 415 glu::ShaderProgram m_program; 416 }; 417 418 template<typename Iterator> 419 struct SymbolNameIterator 420 { 421 Iterator symbolIter; 422 423 SymbolNameIterator (Iterator symbolIter_) : symbolIter(symbolIter_) {} 424 425 inline SymbolNameIterator& operator++ (void) { ++symbolIter; return *this; } 426 427 inline bool operator== (const SymbolNameIterator& other) { return symbolIter == other.symbolIter; } 428 inline bool operator!= (const SymbolNameIterator& other) { return symbolIter != other.symbolIter; } 429 430 inline std::string operator* (void) const 431 { 432 if (glu::isDataTypeBoolOrBVec(symbolIter->varType.getBasicType())) 433 return "o_" + symbolIter->name; 434 else 435 return symbolIter->name; 436 } 437 }; 438 439 template<typename Iterator> 440 inline glu::TransformFeedbackVaryings<SymbolNameIterator<Iterator> > getTFVaryings (Iterator begin, Iterator end) 441 { 442 return glu::TransformFeedbackVaryings<SymbolNameIterator<Iterator> >(SymbolNameIterator<Iterator>(begin), SymbolNameIterator<Iterator>(end)); 443 } 444 445 VertexProcessorExecutor::VertexProcessorExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec, const glu::ProgramSources& sources) 446 : ShaderExecutor (renderCtx, shaderSpec) 447 , m_program (renderCtx, 448 glu::ProgramSources(sources) << getTFVaryings(shaderSpec.outputs.begin(), shaderSpec.outputs.end()) 449 << glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS)) 450 { 451 } 452 453 VertexProcessorExecutor::~VertexProcessorExecutor (void) 454 { 455 } 456 457 template<typename Iterator> 458 static int computeTotalScalarSize (Iterator begin, Iterator end) 459 { 460 int size = 0; 461 for (Iterator cur = begin; cur != end; ++cur) 462 size += cur->varType.getScalarSize(); 463 return size; 464 } 465 466 void VertexProcessorExecutor::execute (int numValues, const void* const* inputs, void* const* outputs) 467 { 468 const glw::Functions& gl = m_renderCtx.getFunctions(); 469 const bool useTFObject = isContextTypeES(m_renderCtx.getType()) || (isContextTypeGLCore(m_renderCtx.getType()) && m_renderCtx.getType().getMajorVersion() >= 4); 470 vector<glu::VertexArrayBinding> vertexArrays; 471 de::UniquePtr<glu::TransformFeedback> transformFeedback (useTFObject ? new glu::TransformFeedback(m_renderCtx) : DE_NULL); 472 glu::Buffer outputBuffer (m_renderCtx); 473 const int outputBufferStride = computeTotalScalarSize(m_outputs.begin(), m_outputs.end())*sizeof(deUint32); 474 475 // Setup inputs. 476 for (int inputNdx = 0; inputNdx < (int)m_inputs.size(); inputNdx++) 477 { 478 const Symbol& symbol = m_inputs[inputNdx]; 479 const void* ptr = inputs[inputNdx]; 480 const glu::DataType basicType = symbol.varType.getBasicType(); 481 const int vecSize = glu::getDataTypeScalarSize(basicType); 482 483 if (glu::isDataTypeFloatOrVec(basicType)) 484 vertexArrays.push_back(glu::va::Float(symbol.name, vecSize, numValues, 0, (const float*)ptr)); 485 else if (glu::isDataTypeIntOrIVec(basicType)) 486 vertexArrays.push_back(glu::va::Int32(symbol.name, vecSize, numValues, 0, (const deInt32*)ptr)); 487 else if (glu::isDataTypeUintOrUVec(basicType)) 488 vertexArrays.push_back(glu::va::Uint32(symbol.name, vecSize, numValues, 0, (const deUint32*)ptr)); 489 else if (glu::isDataTypeMatrix(basicType)) 490 { 491 int numRows = glu::getDataTypeMatrixNumRows(basicType); 492 int numCols = glu::getDataTypeMatrixNumColumns(basicType); 493 int stride = numRows * numCols * sizeof(float); 494 495 for (int colNdx = 0; colNdx < numCols; ++colNdx) 496 vertexArrays.push_back(glu::va::Float(symbol.name, colNdx, numRows, numValues, stride, ((const float*)ptr) + colNdx * numRows)); 497 } 498 else 499 DE_ASSERT(false); 500 } 501 502 // Setup TF outputs. 503 if (useTFObject) 504 gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, **transformFeedback); 505 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, *outputBuffer); 506 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, outputBufferStride*numValues, DE_NULL, GL_STREAM_READ); 507 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, *outputBuffer); 508 GLU_EXPECT_NO_ERROR(gl.getError(), "Error in TF setup"); 509 510 // Draw with rasterization disabled. 511 gl.beginTransformFeedback(GL_POINTS); 512 gl.enable(GL_RASTERIZER_DISCARD); 513 glu::draw(m_renderCtx, m_program.getProgram(), (int)vertexArrays.size(), vertexArrays.empty() ? DE_NULL : &vertexArrays[0], 514 glu::pr::Points(numValues)); 515 gl.disable(GL_RASTERIZER_DISCARD); 516 gl.endTransformFeedback(); 517 GLU_EXPECT_NO_ERROR(gl.getError(), "Error in draw"); 518 519 // Read back data. 520 { 521 const void* srcPtr = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, outputBufferStride*numValues, GL_MAP_READ_BIT); 522 int curOffset = 0; // Offset in buffer in bytes. 523 524 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER)"); 525 TCU_CHECK(srcPtr != DE_NULL); 526 527 for (int outputNdx = 0; outputNdx < (int)m_outputs.size(); outputNdx++) 528 { 529 const Symbol& symbol = m_outputs[outputNdx]; 530 void* dstPtr = outputs[outputNdx]; 531 const int scalarSize = symbol.varType.getScalarSize(); 532 533 for (int ndx = 0; ndx < numValues; ndx++) 534 deMemcpy((deUint32*)dstPtr + scalarSize*ndx, (const deUint8*)srcPtr + curOffset + ndx*outputBufferStride, scalarSize*sizeof(deUint32)); 535 536 curOffset += scalarSize*sizeof(deUint32); 537 } 538 539 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); 540 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()"); 541 } 542 543 if (useTFObject) 544 gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); 545 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); 546 GLU_EXPECT_NO_ERROR(gl.getError(), "Restore state"); 547 } 548 549 // VertexShaderExecutor 550 551 class VertexShaderExecutor : public VertexProcessorExecutor 552 { 553 public: 554 VertexShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec); 555 }; 556 557 VertexShaderExecutor::VertexShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec) 558 : VertexProcessorExecutor (renderCtx, shaderSpec, 559 glu::ProgramSources() << glu::VertexSource(generateVertexShader(shaderSpec)) 560 << glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version))) 561 { 562 } 563 564 // GeometryShaderExecutor 565 566 class CheckGeomSupport 567 { 568 public: 569 inline CheckGeomSupport (const glu::RenderContext& renderCtx) 570 { 571 if (renderCtx.getType().getAPI().getProfile() == glu::PROFILE_ES) 572 checkExtension(renderCtx, "GL_EXT_geometry_shader"); 573 } 574 }; 575 576 class GeometryShaderExecutor : private CheckGeomSupport, public VertexProcessorExecutor 577 { 578 public: 579 GeometryShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec); 580 }; 581 582 GeometryShaderExecutor::GeometryShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec) 583 : CheckGeomSupport (renderCtx) 584 , VertexProcessorExecutor (renderCtx, shaderSpec, 585 glu::ProgramSources() << glu::VertexSource(generatePassthroughVertexShader(shaderSpec, "", "geom_")) 586 << glu::GeometrySource(generateGeometryShader(shaderSpec)) 587 << glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version))) 588 { 589 } 590 591 // FragmentShaderExecutor 592 593 class FragmentShaderExecutor : public ShaderExecutor 594 { 595 public: 596 FragmentShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec); 597 ~FragmentShaderExecutor (void); 598 599 bool isOk (void) const { return m_program.isOk(); } 600 void log (tcu::TestLog& dst) const { dst << m_program; } 601 deUint32 getProgram (void) const { return m_program.getProgram(); } 602 603 void execute (int numValues, const void* const* inputs, void* const* outputs); 604 605 protected: 606 std::vector<const Symbol*> m_outLocationSymbols; 607 std::map<std::string, int> m_outLocationMap; 608 glu::ShaderProgram m_program; 609 }; 610 611 static std::map<std::string, int> generateLocationMap (const std::vector<Symbol>& symbols, std::vector<const Symbol*>& locationSymbols) 612 { 613 std::map<std::string, int> ret; 614 int location = 0; 615 616 locationSymbols.clear(); 617 618 for (std::vector<Symbol>::const_iterator it = symbols.begin(); it != symbols.end(); ++it) 619 { 620 const int numLocations = glu::getDataTypeNumLocations(it->varType.getBasicType()); 621 622 TCU_CHECK_INTERNAL(!de::contains(ret, it->name)); 623 de::insert(ret, it->name, location); 624 location += numLocations; 625 626 for (int ndx = 0; ndx < numLocations; ++ndx) 627 locationSymbols.push_back(&*it); 628 } 629 630 return ret; 631 } 632 633 inline bool hasFloatRenderTargets (const glu::RenderContext& renderCtx) 634 { 635 glu::ContextType type = renderCtx.getType(); 636 return glu::isContextTypeGLCore(type); 637 } 638 639 FragmentShaderExecutor::FragmentShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec) 640 : ShaderExecutor (renderCtx, shaderSpec) 641 , m_outLocationSymbols () 642 , m_outLocationMap (generateLocationMap(m_outputs, m_outLocationSymbols)) 643 , m_program (renderCtx, 644 glu::ProgramSources() << glu::VertexSource(generatePassthroughVertexShader(shaderSpec, "a_", "")) 645 << glu::FragmentSource(generateFragmentShader(shaderSpec, !hasFloatRenderTargets(renderCtx), m_outLocationMap))) 646 { 647 } 648 649 FragmentShaderExecutor::~FragmentShaderExecutor (void) 650 { 651 } 652 653 inline int queryInt (const glw::Functions& gl, deUint32 pname) 654 { 655 int value = 0; 656 gl.getIntegerv(pname, &value); 657 return value; 658 } 659 660 static tcu::TextureFormat getRenderbufferFormatForOutput (const glu::VarType& outputType, bool useIntOutputs) 661 { 662 const tcu::TextureFormat::ChannelOrder channelOrderMap[] = 663 { 664 tcu::TextureFormat::R, 665 tcu::TextureFormat::RG, 666 tcu::TextureFormat::RGBA, // No RGB variants available. 667 tcu::TextureFormat::RGBA 668 }; 669 670 const glu::DataType basicType = outputType.getBasicType(); 671 const int numComps = glu::getDataTypeNumComponents(basicType); 672 tcu::TextureFormat::ChannelType channelType; 673 674 switch (glu::getDataTypeScalarType(basicType)) 675 { 676 case glu::TYPE_UINT: channelType = tcu::TextureFormat::UNSIGNED_INT32; break; 677 case glu::TYPE_INT: channelType = tcu::TextureFormat::SIGNED_INT32; break; 678 case glu::TYPE_BOOL: channelType = tcu::TextureFormat::SIGNED_INT32; break; 679 case glu::TYPE_FLOAT: channelType = useIntOutputs ? tcu::TextureFormat::UNSIGNED_INT32 : tcu::TextureFormat::FLOAT; break; 680 default: 681 throw tcu::InternalError("Invalid output type"); 682 } 683 684 DE_ASSERT(de::inRange<int>(numComps, 1, DE_LENGTH_OF_ARRAY(channelOrderMap))); 685 686 return tcu::TextureFormat(channelOrderMap[numComps-1], channelType); 687 } 688 689 void FragmentShaderExecutor::execute (int numValues, const void* const* inputs, void* const* outputs) 690 { 691 const glw::Functions& gl = m_renderCtx.getFunctions(); 692 const bool useIntOutputs = !hasFloatRenderTargets(m_renderCtx); 693 const int maxRenderbufferSize = queryInt(gl, GL_MAX_RENDERBUFFER_SIZE); 694 const int framebufferW = de::min(maxRenderbufferSize, numValues); 695 const int framebufferH = (numValues / framebufferW) + ((numValues % framebufferW != 0) ? 1 : 0); 696 697 glu::Framebuffer framebuffer (m_renderCtx); 698 glu::RenderbufferVector renderbuffers (m_renderCtx, m_outLocationSymbols.size()); 699 700 vector<glu::VertexArrayBinding> vertexArrays; 701 vector<tcu::Vec2> positions (numValues); 702 703 if (framebufferH > maxRenderbufferSize) 704 throw tcu::NotSupportedError("Value count is too high for maximum supported renderbuffer size"); 705 706 // Compute positions - 1px points are used to drive fragment shading. 707 for (int valNdx = 0; valNdx < numValues; valNdx++) 708 { 709 const int ix = valNdx % framebufferW; 710 const int iy = valNdx / framebufferW; 711 const float fx = -1.0f + 2.0f*((float(ix) + 0.5f) / float(framebufferW)); 712 const float fy = -1.0f + 2.0f*((float(iy) + 0.5f) / float(framebufferH)); 713 714 positions[valNdx] = tcu::Vec2(fx, fy); 715 } 716 717 // Vertex inputs. 718 vertexArrays.push_back(glu::va::Float("a_position", 2, numValues, 0, (const float*)&positions[0])); 719 720 for (int inputNdx = 0; inputNdx < (int)m_inputs.size(); inputNdx++) 721 { 722 const Symbol& symbol = m_inputs[inputNdx]; 723 const std::string attribName = "a_" + symbol.name; 724 const void* ptr = inputs[inputNdx]; 725 const glu::DataType basicType = symbol.varType.getBasicType(); 726 const int vecSize = glu::getDataTypeScalarSize(basicType); 727 728 if (glu::isDataTypeFloatOrVec(basicType)) 729 vertexArrays.push_back(glu::va::Float(attribName, vecSize, numValues, 0, (const float*)ptr)); 730 else if (glu::isDataTypeIntOrIVec(basicType)) 731 vertexArrays.push_back(glu::va::Int32(attribName, vecSize, numValues, 0, (const deInt32*)ptr)); 732 else if (glu::isDataTypeUintOrUVec(basicType)) 733 vertexArrays.push_back(glu::va::Uint32(attribName, vecSize, numValues, 0, (const deUint32*)ptr)); 734 else if (glu::isDataTypeMatrix(basicType)) 735 { 736 int numRows = glu::getDataTypeMatrixNumRows(basicType); 737 int numCols = glu::getDataTypeMatrixNumColumns(basicType); 738 int stride = numRows * numCols * sizeof(float); 739 740 for (int colNdx = 0; colNdx < numCols; ++colNdx) 741 vertexArrays.push_back(glu::va::Float(attribName, colNdx, numRows, numValues, stride, ((const float*)ptr) + colNdx * numRows)); 742 } 743 else 744 DE_ASSERT(false); 745 } 746 747 // Construct framebuffer. 748 gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer); 749 750 for (int outNdx = 0; outNdx < (int)m_outLocationSymbols.size(); ++outNdx) 751 { 752 const Symbol& output = *m_outLocationSymbols[outNdx]; 753 const deUint32 renderbuffer = renderbuffers[outNdx]; 754 const deUint32 format = glu::getInternalFormat(getRenderbufferFormatForOutput(output.varType, useIntOutputs)); 755 756 gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer); 757 gl.renderbufferStorage(GL_RENDERBUFFER, format, framebufferW, framebufferH); 758 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+outNdx, GL_RENDERBUFFER, renderbuffer); 759 } 760 gl.bindRenderbuffer(GL_RENDERBUFFER, 0); 761 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set up framebuffer object"); 762 TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); 763 764 { 765 vector<deUint32> drawBuffers(m_outLocationSymbols.size()); 766 for (int ndx = 0; ndx < (int)m_outLocationSymbols.size(); ndx++) 767 drawBuffers[ndx] = GL_COLOR_ATTACHMENT0+ndx; 768 gl.drawBuffers((int)drawBuffers.size(), &drawBuffers[0]); 769 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawBuffers()"); 770 } 771 772 // Render 773 gl.viewport(0, 0, framebufferW, framebufferH); 774 glu::draw(m_renderCtx, m_program.getProgram(), (int)vertexArrays.size(), &vertexArrays[0], 775 glu::pr::Points(numValues)); 776 GLU_EXPECT_NO_ERROR(gl.getError(), "Error in draw"); 777 778 // Read back pixels. 779 { 780 tcu::TextureLevel tmpBuf; 781 782 // \todo [2013-08-07 pyry] Some fast-paths could be added here. 783 784 for (int outNdx = 0; outNdx < (int)m_outputs.size(); ++outNdx) 785 { 786 const Symbol& output = m_outputs[outNdx]; 787 const int outSize = output.varType.getScalarSize(); 788 const int outVecSize = glu::getDataTypeNumComponents(output.varType.getBasicType()); 789 const int outNumLocs = glu::getDataTypeNumLocations(output.varType.getBasicType()); 790 deUint32* dstPtrBase = static_cast<deUint32*>(outputs[outNdx]); 791 const tcu::TextureFormat format = getRenderbufferFormatForOutput(output.varType, useIntOutputs); 792 const tcu::TextureFormat readFormat (tcu::TextureFormat::RGBA, format.type); 793 const int outLocation = de::lookup(m_outLocationMap, output.name); 794 795 tmpBuf.setStorage(readFormat, framebufferW, framebufferH); 796 797 for (int locNdx = 0; locNdx < outNumLocs; ++locNdx) 798 { 799 gl.readBuffer(GL_COLOR_ATTACHMENT0 + outLocation + locNdx); 800 glu::readPixels(m_renderCtx, 0, 0, tmpBuf.getAccess()); 801 GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels"); 802 803 if (outSize == 4 && outNumLocs == 1) 804 deMemcpy(dstPtrBase, tmpBuf.getAccess().getDataPtr(), numValues*outVecSize*sizeof(deUint32)); 805 else 806 { 807 for (int valNdx = 0; valNdx < numValues; valNdx++) 808 { 809 const deUint32* srcPtr = (const deUint32*)tmpBuf.getAccess().getDataPtr() + valNdx*4; 810 deUint32* dstPtr = &dstPtrBase[outSize*valNdx + outVecSize*locNdx]; 811 deMemcpy(dstPtr, srcPtr, outVecSize*sizeof(deUint32)); 812 } 813 } 814 } 815 } 816 } 817 818 // \todo [2013-08-07 pyry] Clear draw buffers & viewport? 819 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 820 } 821 822 // Shared utilities for compute and tess executors 823 824 static deUint32 getVecStd430ByteAlignment (glu::DataType type) 825 { 826 switch (glu::getDataTypeScalarSize(type)) 827 { 828 case 1: return 4u; 829 case 2: return 8u; 830 case 3: return 16u; 831 case 4: return 16u; 832 default: 833 DE_ASSERT(false); 834 return 0u; 835 } 836 } 837 838 class BufferIoExecutor : public ShaderExecutor 839 { 840 public: 841 BufferIoExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec, const glu::ProgramSources& sources); 842 ~BufferIoExecutor (void); 843 844 bool isOk (void) const { return m_program.isOk(); } 845 void log (tcu::TestLog& dst) const { dst << m_program; } 846 deUint32 getProgram (void) const { return m_program.getProgram(); } 847 848 protected: 849 enum 850 { 851 INPUT_BUFFER_BINDING = 0, 852 OUTPUT_BUFFER_BINDING = 1, 853 }; 854 855 void initBuffers (int numValues); 856 deUint32 getInputBuffer (void) const { return *m_inputBuffer; } 857 deUint32 getOutputBuffer (void) const { return *m_outputBuffer; } 858 deUint32 getInputStride (void) const { return getLayoutStride(m_inputLayout); } 859 deUint32 getOutputStride (void) const { return getLayoutStride(m_outputLayout); } 860 861 void uploadInputBuffer (const void* const* inputPtrs, int numValues); 862 void readOutputBuffer (void* const* outputPtrs, int numValues); 863 864 static void declareBufferBlocks (std::ostream& src, const ShaderSpec& spec); 865 static void generateExecBufferIo(std::ostream& src, const ShaderSpec& spec, const char* invocationNdxName); 866 867 glu::ShaderProgram m_program; 868 869 private: 870 struct VarLayout 871 { 872 deUint32 offset; 873 deUint32 stride; 874 deUint32 matrixStride; 875 876 VarLayout (void) : offset(0), stride(0), matrixStride(0) {} 877 }; 878 879 void resizeInputBuffer (int newSize); 880 void resizeOutputBuffer (int newSize); 881 882 static void computeVarLayout (const std::vector<Symbol>& symbols, std::vector<VarLayout>* layout); 883 static deUint32 getLayoutStride (const vector<VarLayout>& layout); 884 885 static void copyToBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr); 886 static void copyFromBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr); 887 888 glu::Buffer m_inputBuffer; 889 glu::Buffer m_outputBuffer; 890 891 vector<VarLayout> m_inputLayout; 892 vector<VarLayout> m_outputLayout; 893 }; 894 895 BufferIoExecutor::BufferIoExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec, const glu::ProgramSources& sources) 896 : ShaderExecutor (renderCtx, shaderSpec) 897 , m_program (renderCtx, sources) 898 , m_inputBuffer (renderCtx) 899 , m_outputBuffer (renderCtx) 900 { 901 computeVarLayout(m_inputs, &m_inputLayout); 902 computeVarLayout(m_outputs, &m_outputLayout); 903 } 904 905 BufferIoExecutor::~BufferIoExecutor (void) 906 { 907 } 908 909 void BufferIoExecutor::resizeInputBuffer (int newSize) 910 { 911 const glw::Functions& gl = m_renderCtx.getFunctions(); 912 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *m_inputBuffer); 913 gl.bufferData(GL_SHADER_STORAGE_BUFFER, newSize, DE_NULL, GL_STATIC_DRAW); 914 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to allocate input buffer"); 915 } 916 917 void BufferIoExecutor::resizeOutputBuffer (int newSize) 918 { 919 const glw::Functions& gl = m_renderCtx.getFunctions(); 920 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *m_outputBuffer); 921 gl.bufferData(GL_SHADER_STORAGE_BUFFER, newSize, DE_NULL, GL_STATIC_DRAW); 922 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to allocate output buffer"); 923 } 924 925 void BufferIoExecutor::initBuffers (int numValues) 926 { 927 const deUint32 inputStride = getLayoutStride(m_inputLayout); 928 const deUint32 outputStride = getLayoutStride(m_outputLayout); 929 const int inputBufferSize = numValues * inputStride; 930 const int outputBufferSize = numValues * outputStride; 931 932 resizeInputBuffer(inputBufferSize); 933 resizeOutputBuffer(outputBufferSize); 934 } 935 936 void BufferIoExecutor::computeVarLayout (const std::vector<Symbol>& symbols, std::vector<VarLayout>* layout) 937 { 938 deUint32 maxAlignment = 0; 939 deUint32 curOffset = 0; 940 941 DE_ASSERT(layout->empty()); 942 layout->resize(symbols.size()); 943 944 for (size_t varNdx = 0; varNdx < symbols.size(); varNdx++) 945 { 946 const Symbol& symbol = symbols[varNdx]; 947 const glu::DataType basicType = symbol.varType.getBasicType(); 948 VarLayout& layoutEntry = (*layout)[varNdx]; 949 950 if (glu::isDataTypeScalarOrVector(basicType)) 951 { 952 const deUint32 alignment = getVecStd430ByteAlignment(basicType); 953 const deUint32 size = (deUint32)glu::getDataTypeScalarSize(basicType)*sizeof(deUint32); 954 955 curOffset = (deUint32)deAlign32((int)curOffset, (int)alignment); 956 maxAlignment = de::max(maxAlignment, alignment); 957 958 layoutEntry.offset = curOffset; 959 layoutEntry.matrixStride = 0; 960 961 curOffset += size; 962 } 963 else if (glu::isDataTypeMatrix(basicType)) 964 { 965 const int numVecs = glu::getDataTypeMatrixNumColumns(basicType); 966 const glu::DataType vecType = glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType)); 967 const deUint32 vecAlignment = getVecStd430ByteAlignment(vecType); 968 969 curOffset = (deUint32)deAlign32((int)curOffset, (int)vecAlignment); 970 maxAlignment = de::max(maxAlignment, vecAlignment); 971 972 layoutEntry.offset = curOffset; 973 layoutEntry.matrixStride = vecAlignment; 974 975 curOffset += vecAlignment*numVecs; 976 } 977 else 978 DE_ASSERT(false); 979 } 980 981 { 982 const deUint32 totalSize = (deUint32)deAlign32(curOffset, maxAlignment); 983 984 for (vector<VarLayout>::iterator varIter = layout->begin(); varIter != layout->end(); ++varIter) 985 varIter->stride = totalSize; 986 } 987 } 988 989 inline deUint32 BufferIoExecutor::getLayoutStride (const vector<VarLayout>& layout) 990 { 991 return layout.empty() ? 0 : layout[0].stride; 992 } 993 994 void BufferIoExecutor::copyToBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr) 995 { 996 if (varType.isBasicType()) 997 { 998 const glu::DataType basicType = varType.getBasicType(); 999 const bool isMatrix = glu::isDataTypeMatrix(basicType); 1000 const int scalarSize = glu::getDataTypeScalarSize(basicType); 1001 const int numVecs = isMatrix ? glu::getDataTypeMatrixNumColumns(basicType) : 1; 1002 const int numComps = scalarSize / numVecs; 1003 1004 for (int elemNdx = 0; elemNdx < numValues; elemNdx++) 1005 { 1006 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++) 1007 { 1008 const int srcOffset = sizeof(deUint32)*(elemNdx*scalarSize + vecNdx*numComps); 1009 const int dstOffset = layout.offset + layout.stride*elemNdx + (isMatrix ? layout.matrixStride*vecNdx : 0); 1010 const deUint8* srcPtr = (const deUint8*)srcBasePtr + srcOffset; 1011 deUint8* dstPtr = (deUint8*)dstBasePtr + dstOffset; 1012 1013 deMemcpy(dstPtr, srcPtr, sizeof(deUint32)*numComps); 1014 } 1015 } 1016 } 1017 else 1018 throw tcu::InternalError("Unsupported type"); 1019 } 1020 1021 void BufferIoExecutor::copyFromBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr) 1022 { 1023 if (varType.isBasicType()) 1024 { 1025 const glu::DataType basicType = varType.getBasicType(); 1026 const bool isMatrix = glu::isDataTypeMatrix(basicType); 1027 const int scalarSize = glu::getDataTypeScalarSize(basicType); 1028 const int numVecs = isMatrix ? glu::getDataTypeMatrixNumColumns(basicType) : 1; 1029 const int numComps = scalarSize / numVecs; 1030 1031 for (int elemNdx = 0; elemNdx < numValues; elemNdx++) 1032 { 1033 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++) 1034 { 1035 const int srcOffset = layout.offset + layout.stride*elemNdx + (isMatrix ? layout.matrixStride*vecNdx : 0); 1036 const int dstOffset = sizeof(deUint32)*(elemNdx*scalarSize + vecNdx*numComps); 1037 const deUint8* srcPtr = (const deUint8*)srcBasePtr + srcOffset; 1038 deUint8* dstPtr = (deUint8*)dstBasePtr + dstOffset; 1039 1040 deMemcpy(dstPtr, srcPtr, sizeof(deUint32)*numComps); 1041 } 1042 } 1043 } 1044 else 1045 throw tcu::InternalError("Unsupported type"); 1046 } 1047 1048 void BufferIoExecutor::uploadInputBuffer (const void* const* inputPtrs, int numValues) 1049 { 1050 const glw::Functions& gl = m_renderCtx.getFunctions(); 1051 const deUint32 buffer = *m_inputBuffer; 1052 const deUint32 inputStride = getLayoutStride(m_inputLayout); 1053 const int inputBufferSize = inputStride*numValues; 1054 1055 if (inputBufferSize == 0) 1056 return; // No inputs 1057 1058 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer); 1059 void* mapPtr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, inputBufferSize, GL_MAP_WRITE_BIT); 1060 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()"); 1061 TCU_CHECK(mapPtr); 1062 1063 try 1064 { 1065 DE_ASSERT(m_inputs.size() == m_inputLayout.size()); 1066 for (size_t inputNdx = 0; inputNdx < m_inputs.size(); ++inputNdx) 1067 { 1068 const glu::VarType& varType = m_inputs[inputNdx].varType; 1069 const VarLayout& layout = m_inputLayout[inputNdx]; 1070 1071 copyToBuffer(varType, layout, numValues, inputPtrs[inputNdx], mapPtr); 1072 } 1073 } 1074 catch (...) 1075 { 1076 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); 1077 throw; 1078 } 1079 1080 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); 1081 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()"); 1082 } 1083 1084 void BufferIoExecutor::readOutputBuffer (void* const* outputPtrs, int numValues) 1085 { 1086 const glw::Functions& gl = m_renderCtx.getFunctions(); 1087 const deUint32 buffer = *m_outputBuffer; 1088 const deUint32 outputStride = getLayoutStride(m_outputLayout); 1089 const int outputBufferSize = numValues*outputStride; 1090 1091 DE_ASSERT(outputBufferSize > 0); // At least some outputs are required. 1092 1093 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer); 1094 void* mapPtr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, outputBufferSize, GL_MAP_READ_BIT); 1095 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()"); 1096 TCU_CHECK(mapPtr); 1097 1098 try 1099 { 1100 DE_ASSERT(m_outputs.size() == m_outputLayout.size()); 1101 for (size_t outputNdx = 0; outputNdx < m_outputs.size(); ++outputNdx) 1102 { 1103 const glu::VarType& varType = m_outputs[outputNdx].varType; 1104 const VarLayout& layout = m_outputLayout[outputNdx]; 1105 1106 copyFromBuffer(varType, layout, numValues, mapPtr, outputPtrs[outputNdx]); 1107 } 1108 } 1109 catch (...) 1110 { 1111 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); 1112 throw; 1113 } 1114 1115 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); 1116 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()"); 1117 } 1118 1119 void BufferIoExecutor::declareBufferBlocks (std::ostream& src, const ShaderSpec& spec) 1120 { 1121 // Input struct 1122 if (!spec.inputs.empty()) 1123 { 1124 glu::StructType inputStruct("Inputs"); 1125 for (vector<Symbol>::const_iterator symIter = spec.inputs.begin(); symIter != spec.inputs.end(); ++symIter) 1126 inputStruct.addMember(symIter->name.c_str(), symIter->varType); 1127 src << glu::declare(&inputStruct) << ";\n"; 1128 } 1129 1130 // Output struct 1131 { 1132 glu::StructType outputStruct("Outputs"); 1133 for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter) 1134 outputStruct.addMember(symIter->name.c_str(), symIter->varType); 1135 src << glu::declare(&outputStruct) << ";\n"; 1136 } 1137 1138 src << "\n"; 1139 1140 if (!spec.inputs.empty()) 1141 { 1142 src << "layout(binding = " << int(INPUT_BUFFER_BINDING) << ", std430) buffer InBuffer\n" 1143 << "{\n" 1144 << " Inputs inputs[];\n" 1145 << "};\n"; 1146 } 1147 1148 src << "layout(binding = " << int(OUTPUT_BUFFER_BINDING) << ", std430) buffer OutBuffer\n" 1149 << "{\n" 1150 << " Outputs outputs[];\n" 1151 << "};\n" 1152 << "\n"; 1153 } 1154 1155 void BufferIoExecutor::generateExecBufferIo (std::ostream& src, const ShaderSpec& spec, const char* invocationNdxName) 1156 { 1157 for (vector<Symbol>::const_iterator symIter = spec.inputs.begin(); symIter != spec.inputs.end(); ++symIter) 1158 src << "\t" << glu::declare(symIter->varType, symIter->name) << " = inputs[" << invocationNdxName << "]." << symIter->name << ";\n"; 1159 1160 for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter) 1161 src << "\t" << glu::declare(symIter->varType, symIter->name) << ";\n"; 1162 1163 src << "\n"; 1164 1165 { 1166 std::istringstream opSrc (spec.source); 1167 std::string line; 1168 1169 while (std::getline(opSrc, line)) 1170 src << "\t" << line << "\n"; 1171 } 1172 1173 src << "\n"; 1174 for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter) 1175 src << "\toutputs[" << invocationNdxName << "]." << symIter->name << " = " << symIter->name << ";\n"; 1176 } 1177 1178 // ComputeShaderExecutor 1179 1180 class ComputeShaderExecutor : public BufferIoExecutor 1181 { 1182 public: 1183 ComputeShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec); 1184 ~ComputeShaderExecutor (void); 1185 1186 void execute (int numValues, const void* const* inputs, void* const* outputs); 1187 1188 protected: 1189 static std::string generateComputeShader (const ShaderSpec& spec); 1190 1191 tcu::IVec3 m_maxWorkSize; 1192 }; 1193 1194 std::string ComputeShaderExecutor::generateComputeShader (const ShaderSpec& spec) 1195 { 1196 std::ostringstream src; 1197 1198 src << glu::getGLSLVersionDeclaration(spec.version) << "\n"; 1199 1200 if (!spec.globalDeclarations.empty()) 1201 src << spec.globalDeclarations << "\n"; 1202 1203 src << "layout(local_size_x = 1) in;\n" 1204 << "\n"; 1205 1206 declareBufferBlocks(src, spec); 1207 1208 src << "void main (void)\n" 1209 << "{\n" 1210 << " uint invocationNdx = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z\n" 1211 << " + gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n"; 1212 1213 generateExecBufferIo(src, spec, "invocationNdx"); 1214 1215 src << "}\n"; 1216 1217 return src.str(); 1218 } 1219 1220 ComputeShaderExecutor::ComputeShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec) 1221 : BufferIoExecutor (renderCtx, shaderSpec, 1222 glu::ProgramSources() << glu::ComputeSource(generateComputeShader(shaderSpec))) 1223 { 1224 m_maxWorkSize = tcu::IVec3(128,128,64); // Minimum in 3plus 1225 } 1226 1227 ComputeShaderExecutor::~ComputeShaderExecutor (void) 1228 { 1229 } 1230 1231 void ComputeShaderExecutor::execute (int numValues, const void* const* inputs, void* const* outputs) 1232 { 1233 const glw::Functions& gl = m_renderCtx.getFunctions(); 1234 const int maxValuesPerInvocation = m_maxWorkSize[0]; 1235 const deUint32 inputStride = getInputStride(); 1236 const deUint32 outputStride = getOutputStride(); 1237 1238 initBuffers(numValues); 1239 1240 // Setup input buffer & copy data 1241 uploadInputBuffer(inputs, numValues); 1242 1243 // Perform compute invocations 1244 { 1245 int curOffset = 0; 1246 while (curOffset < numValues) 1247 { 1248 const int numToExec = de::min(maxValuesPerInvocation, numValues-curOffset); 1249 1250 if (inputStride > 0) 1251 gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, INPUT_BUFFER_BINDING, getInputBuffer(), curOffset*inputStride, numToExec*inputStride); 1252 1253 gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, OUTPUT_BUFFER_BINDING, getOutputBuffer(), curOffset*outputStride, numToExec*outputStride); 1254 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange(GL_SHADER_STORAGE_BUFFER)"); 1255 1256 gl.dispatchCompute(numToExec, 1, 1); 1257 GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); 1258 1259 curOffset += numToExec; 1260 } 1261 } 1262 1263 // Read back data 1264 readOutputBuffer(outputs, numValues); 1265 } 1266 1267 // Tessellation utils 1268 1269 static std::string generateVertexShaderForTess (glu::GLSLVersion version) 1270 { 1271 std::ostringstream src; 1272 1273 src << glu::getGLSLVersionDeclaration(version) << "\n"; 1274 1275 src << "void main (void)\n{\n" 1276 << " gl_Position = vec4(gl_VertexID/2, gl_VertexID%2, 0.0, 1.0);\n" 1277 << "}\n"; 1278 1279 return src.str(); 1280 } 1281 1282 class CheckTessSupport 1283 { 1284 public: 1285 inline CheckTessSupport (const glu::RenderContext& renderCtx) 1286 { 1287 if (renderCtx.getType().getAPI().getProfile() == glu::PROFILE_ES) 1288 checkExtension(renderCtx, "GL_EXT_tessellation_shader"); 1289 } 1290 }; 1291 1292 // TessControlExecutor 1293 1294 class TessControlExecutor : private CheckTessSupport, public BufferIoExecutor 1295 { 1296 public: 1297 TessControlExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec); 1298 ~TessControlExecutor (void); 1299 1300 void execute (int numValues, const void* const* inputs, void* const* outputs); 1301 1302 protected: 1303 static std::string generateTessControlShader (const ShaderSpec& shaderSpec); 1304 }; 1305 1306 std::string TessControlExecutor::generateTessControlShader (const ShaderSpec& shaderSpec) 1307 { 1308 std::ostringstream src; 1309 1310 src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n"; 1311 1312 if (shaderSpec.version == glu::GLSL_VERSION_310_ES) 1313 src << "#extension GL_EXT_tessellation_shader : require\n"; 1314 1315 if (!shaderSpec.globalDeclarations.empty()) 1316 src << shaderSpec.globalDeclarations << "\n"; 1317 1318 src << "\nlayout(vertices = 1) out;\n\n"; 1319 1320 declareBufferBlocks(src, shaderSpec); 1321 1322 src << "void main (void)\n{\n"; 1323 1324 for (int ndx = 0; ndx < 2; ndx++) 1325 src << "\tgl_TessLevelInner[" << ndx << "] = 1.0;\n"; 1326 1327 for (int ndx = 0; ndx < 4; ndx++) 1328 src << "\tgl_TessLevelOuter[" << ndx << "] = 1.0;\n"; 1329 1330 src << "\n" 1331 << "\thighp uint invocationId = uint(gl_PrimitiveID);\n"; 1332 1333 generateExecBufferIo(src, shaderSpec, "invocationId"); 1334 1335 src << "}\n"; 1336 1337 return src.str(); 1338 } 1339 1340 static std::string generateEmptyTessEvalShader (glu::GLSLVersion version) 1341 { 1342 std::ostringstream src; 1343 1344 src << glu::getGLSLVersionDeclaration(version) << "\n"; 1345 1346 if (version == glu::GLSL_VERSION_310_ES) 1347 src << "#extension GL_EXT_tessellation_shader : require\n\n"; 1348 1349 src << "layout(triangles, ccw) in;\n"; 1350 1351 src << "\nvoid main (void)\n{\n" 1352 << "\tgl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n" 1353 << "}\n"; 1354 1355 return src.str(); 1356 } 1357 1358 TessControlExecutor::TessControlExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec) 1359 : CheckTessSupport (renderCtx) 1360 , BufferIoExecutor (renderCtx, shaderSpec, glu::ProgramSources() 1361 << glu::VertexSource(generateVertexShaderForTess(shaderSpec.version)) 1362 << glu::TessellationControlSource(generateTessControlShader(shaderSpec)) 1363 << glu::TessellationEvaluationSource(generateEmptyTessEvalShader(shaderSpec.version)) 1364 << glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version))) 1365 { 1366 } 1367 1368 TessControlExecutor::~TessControlExecutor (void) 1369 { 1370 } 1371 1372 void TessControlExecutor::execute (int numValues, const void* const* inputs, void* const* outputs) 1373 { 1374 const glw::Functions& gl = m_renderCtx.getFunctions(); 1375 1376 initBuffers(numValues); 1377 1378 // Setup input buffer & copy data 1379 uploadInputBuffer(inputs, numValues); 1380 1381 if (!m_inputs.empty()) 1382 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, INPUT_BUFFER_BINDING, getInputBuffer()); 1383 1384 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, OUTPUT_BUFFER_BINDING, getOutputBuffer()); 1385 1386 // Render patches 1387 gl.patchParameteri(GL_PATCH_VERTICES, 3); 1388 gl.drawArrays(GL_PATCHES, 0, 3*numValues); 1389 1390 // Read back data 1391 readOutputBuffer(outputs, numValues); 1392 } 1393 1394 // TessEvaluationExecutor 1395 1396 class TessEvaluationExecutor : private CheckTessSupport, public BufferIoExecutor 1397 { 1398 public: 1399 TessEvaluationExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec); 1400 ~TessEvaluationExecutor (void); 1401 1402 void execute (int numValues, const void* const* inputs, void* const* outputs); 1403 1404 protected: 1405 static std::string generateTessEvalShader (const ShaderSpec& shaderSpec); 1406 }; 1407 1408 static std::string generatePassthroughTessControlShader (glu::GLSLVersion version) 1409 { 1410 std::ostringstream src; 1411 1412 src << glu::getGLSLVersionDeclaration(version) << "\n"; 1413 1414 if (version == glu::GLSL_VERSION_310_ES) 1415 src << "#extension GL_EXT_tessellation_shader : require\n\n"; 1416 1417 src << "layout(vertices = 1) out;\n\n"; 1418 1419 src << "void main (void)\n{\n"; 1420 1421 for (int ndx = 0; ndx < 2; ndx++) 1422 src << "\tgl_TessLevelInner[" << ndx << "] = 1.0;\n"; 1423 1424 for (int ndx = 0; ndx < 4; ndx++) 1425 src << "\tgl_TessLevelOuter[" << ndx << "] = 1.0;\n"; 1426 1427 src << "}\n"; 1428 1429 return src.str(); 1430 } 1431 1432 std::string TessEvaluationExecutor::generateTessEvalShader (const ShaderSpec& shaderSpec) 1433 { 1434 std::ostringstream src; 1435 1436 src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n"; 1437 1438 if (shaderSpec.version == glu::GLSL_VERSION_310_ES) 1439 src << "#extension GL_EXT_tessellation_shader : require\n"; 1440 1441 if (!shaderSpec.globalDeclarations.empty()) 1442 src << shaderSpec.globalDeclarations << "\n"; 1443 1444 src << "\n"; 1445 1446 src << "layout(isolines, equal_spacing) in;\n\n"; 1447 1448 declareBufferBlocks(src, shaderSpec); 1449 1450 src << "void main (void)\n{\n" 1451 << "\tgl_Position = vec4(gl_TessCoord.x, 0.0, 0.0, 1.0);\n" 1452 << "\thighp uint invocationId = uint(gl_PrimitiveID) + (gl_TessCoord.x > 0.5 ? 1u : 0u);\n"; 1453 1454 generateExecBufferIo(src, shaderSpec, "invocationId"); 1455 1456 src << "}\n"; 1457 1458 return src.str(); 1459 } 1460 1461 TessEvaluationExecutor::TessEvaluationExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec) 1462 : CheckTessSupport (renderCtx) 1463 , BufferIoExecutor (renderCtx, shaderSpec, glu::ProgramSources() 1464 << glu::VertexSource(generateVertexShaderForTess(shaderSpec.version)) 1465 << glu::TessellationControlSource(generatePassthroughTessControlShader(shaderSpec.version)) 1466 << glu::TessellationEvaluationSource(generateTessEvalShader(shaderSpec)) 1467 << glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version))) 1468 { 1469 } 1470 1471 TessEvaluationExecutor::~TessEvaluationExecutor (void) 1472 { 1473 } 1474 1475 void TessEvaluationExecutor::execute (int numValues, const void* const* inputs, void* const* outputs) 1476 { 1477 const glw::Functions& gl = m_renderCtx.getFunctions(); 1478 const int alignedValues = deAlign32(numValues, 2); 1479 1480 // Initialize buffers with aligned value count to make room for padding 1481 initBuffers(alignedValues); 1482 1483 // Setup input buffer & copy data 1484 uploadInputBuffer(inputs, numValues); 1485 1486 // \todo [2014-06-26 pyry] Duplicate last value in the buffer to prevent infinite loops for example? 1487 1488 if (!m_inputs.empty()) 1489 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, INPUT_BUFFER_BINDING, getInputBuffer()); 1490 1491 gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, OUTPUT_BUFFER_BINDING, getOutputBuffer()); 1492 1493 // Render patches 1494 gl.patchParameteri(GL_PATCH_VERTICES, 2); 1495 gl.drawArrays(GL_PATCHES, 0, 2*alignedValues); 1496 1497 // Read back data 1498 readOutputBuffer(outputs, numValues); 1499 } 1500 1501 // Utilities 1502 1503 ShaderExecutor* createExecutor (const glu::RenderContext& renderCtx, glu::ShaderType shaderType, const ShaderSpec& shaderSpec) 1504 { 1505 switch (shaderType) 1506 { 1507 case glu::SHADERTYPE_VERTEX: return new VertexShaderExecutor (renderCtx, shaderSpec); 1508 case glu::SHADERTYPE_TESSELLATION_CONTROL: return new TessControlExecutor (renderCtx, shaderSpec); 1509 case glu::SHADERTYPE_TESSELLATION_EVALUATION: return new TessEvaluationExecutor (renderCtx, shaderSpec); 1510 case glu::SHADERTYPE_GEOMETRY: return new GeometryShaderExecutor (renderCtx, shaderSpec); 1511 case glu::SHADERTYPE_FRAGMENT: return new FragmentShaderExecutor (renderCtx, shaderSpec); 1512 case glu::SHADERTYPE_COMPUTE: return new ComputeShaderExecutor (renderCtx, shaderSpec); 1513 default: 1514 throw tcu::InternalError("Unsupported shader type"); 1515 } 1516 } 1517 1518 } // ShaderExecUtil 1519 } // gls 1520 } // deqp 1521