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 Texture buffer test case 22 *//*--------------------------------------------------------------------*/ 23 24#include "glsTextureBufferCase.hpp" 25 26#include "tcuFormatUtil.hpp" 27#include "tcuImageCompare.hpp" 28#include "tcuRenderTarget.hpp" 29#include "tcuStringTemplate.hpp" 30#include "tcuSurface.hpp" 31#include "tcuTestLog.hpp" 32#include "tcuTextureUtil.hpp" 33#include "tcuResultCollector.hpp" 34 35#include "rrRenderer.hpp" 36#include "rrShaders.hpp" 37 38#include "gluObjectWrapper.hpp" 39#include "gluPixelTransfer.hpp" 40#include "gluShaderProgram.hpp" 41#include "gluShaderUtil.hpp" 42#include "gluStrUtil.hpp" 43#include "gluTexture.hpp" 44#include "gluTextureUtil.hpp" 45 46#include "glwEnums.hpp" 47#include "glwFunctions.hpp" 48 49#include "deRandom.hpp" 50#include "deStringUtil.hpp" 51#include "deUniquePtr.hpp" 52 53#include "deMemory.h" 54#include "deString.h" 55#include "deMath.h" 56 57#include <sstream> 58#include <string> 59#include <vector> 60 61using tcu::TestLog; 62 63using std::map; 64using std::string; 65using std::vector; 66 67using namespace deqp::gls::TextureBufferCaseUtil; 68 69namespace deqp 70{ 71namespace gls 72{ 73namespace 74{ 75 76enum 77{ 78 MAX_VIEWPORT_WIDTH = 256, 79 MAX_VIEWPORT_HEIGHT = 256, 80 MIN_VIEWPORT_WIDTH = 64, 81 MIN_VIEWPORT_HEIGHT = 64, 82}; 83 84deUint8 extend2BitsToByte (deUint8 bits) 85{ 86 DE_ASSERT((bits & (~0x03u)) == 0); 87 88 return (deUint8)(bits | (bits << 2) | (bits << 4) | (bits << 6)); 89} 90 91void genRandomCoords (de::Random rng, vector<deUint8>& coords, size_t offset, size_t size) 92{ 93 const deUint8 bits = 2; 94 const deUint8 bitMask = deUint8((0x1u << bits) - 1); 95 96 coords.resize(size); 97 98 for (int i = 0; i < (int)size; i++) 99 { 100 const deUint8 xBits = deUint8(rng.getUint32() & bitMask); 101 coords[i] = extend2BitsToByte(xBits); 102 } 103 104 // Fill indices with nice quad 105 { 106 const deUint8 indices[] = 107 { 108 extend2BitsToByte(0x0u), 109 extend2BitsToByte(0x1u), 110 extend2BitsToByte(0x2u), 111 extend2BitsToByte(0x3u) 112 }; 113 114 for (int i = 0; i < DE_LENGTH_OF_ARRAY(indices); i++) 115 { 116 const deUint8 index = indices[i]; 117 const size_t posX = (size_t(index) * 2) + 0; 118 const size_t posY = (size_t(index) * 2) + 1; 119 120 if (posX >= offset && posX < offset+size) 121 coords[posX - offset] = ((i % 2) == 0 ? extend2BitsToByte(0x0u) : extend2BitsToByte(0x3u)); 122 123 if (posY >= offset && posY < offset+size) 124 coords[posY - offset] = ((i / 2) == 1 ? extend2BitsToByte(0x3u) : extend2BitsToByte(0x0u)); 125 } 126 } 127 128 // Fill beginning of buffer 129 { 130 const deUint8 indices[] = 131 { 132 extend2BitsToByte(0x0u), 133 extend2BitsToByte(0x3u), 134 extend2BitsToByte(0x1u), 135 136 extend2BitsToByte(0x1u), 137 extend2BitsToByte(0x2u), 138 extend2BitsToByte(0x0u), 139 140 extend2BitsToByte(0x0u), 141 extend2BitsToByte(0x2u), 142 extend2BitsToByte(0x1u), 143 144 extend2BitsToByte(0x1u), 145 extend2BitsToByte(0x3u), 146 extend2BitsToByte(0x0u) 147 }; 148 149 for (int i = (int)offset; i < DE_LENGTH_OF_ARRAY(indices) && i < (int)(offset + size); i++) 150 coords[i-offset] = indices[i]; 151 } 152} 153 154class CoordVertexShader : public rr::VertexShader 155{ 156public: 157 CoordVertexShader (void) 158 : rr::VertexShader(1, 1) 159 { 160 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; 161 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; 162 } 163 164 void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const 165 { 166 for (int packetNdx = 0; packetNdx < numPackets; packetNdx++) 167 { 168 rr::VertexPacket* const packet = packets[packetNdx]; 169 tcu::Vec4 position; 170 171 readVertexAttrib(position, inputs[0], packet->instanceNdx, packet->vertexNdx); 172 173 packet->outputs[0] = tcu::Vec4(1.0f); 174 packet->position = tcu::Vec4(2.0f * (position.x() - 0.5f), 2.0f * (position.y() - 0.5f), 0.0f, 1.0f); 175 } 176 } 177}; 178 179class TextureVertexShader : public rr::VertexShader 180{ 181public: 182 TextureVertexShader (const tcu::ConstPixelBufferAccess& texture) 183 : rr::VertexShader (1, 1) 184 , m_texture (texture) 185 { 186 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; 187 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; 188 } 189 190 void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const 191 { 192 for (int packetNdx = 0; packetNdx < numPackets; packetNdx++) 193 { 194 rr::VertexPacket* const packet = packets[packetNdx]; 195 tcu::Vec4 position; 196 tcu::Vec4 texelValue; 197 198 readVertexAttrib(position, inputs[0], packet->instanceNdx, packet->vertexNdx); 199 200 texelValue = tcu::Vec4(m_texture.getPixel(de::clamp<int>((deRoundFloatToInt32(position.x() * 4) + 4) * (deRoundFloatToInt32(position.y() * 4) + 4), 0, m_texture.getWidth()-1), 0)); 201 202 packet->outputs[0] = texelValue; 203 packet->position = tcu::Vec4(2.0f * (position.x() - 0.5f), 2.0f * (position.y() - 0.5f), 0.0f, 1.0f); 204 } 205 } 206 207private: 208 const tcu::ConstPixelBufferAccess m_texture; 209}; 210 211class CoordFragmentShader : public rr::FragmentShader 212{ 213public: 214 CoordFragmentShader (void) 215 : rr::FragmentShader (1, 1) 216 { 217 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; 218 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; 219 } 220 221 222 void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const 223 { 224 for (int packetNdx = 0; packetNdx < numPackets; packetNdx++) 225 { 226 rr::FragmentPacket& packet = packets[packetNdx]; 227 228 const tcu::Vec4 vtxColor0 = rr::readVarying<float>(packet, context, 0, 0); 229 const tcu::Vec4 vtxColor1 = rr::readVarying<float>(packet, context, 0, 1); 230 const tcu::Vec4 vtxColor2 = rr::readVarying<float>(packet, context, 0, 2); 231 const tcu::Vec4 vtxColor3 = rr::readVarying<float>(packet, context, 0, 3); 232 233 const tcu::Vec4 color0 = vtxColor0; 234 const tcu::Vec4 color1 = vtxColor1; 235 const tcu::Vec4 color2 = vtxColor2; 236 const tcu::Vec4 color3 = vtxColor3; 237 238 rr::writeFragmentOutput(context, packetNdx, 0, 0, tcu::Vec4(color0.x() * color0.w(), color0.y() * color0.w(), color0.z() * color0.w(), 1.0f)); 239 rr::writeFragmentOutput(context, packetNdx, 1, 0, tcu::Vec4(color1.x() * color1.w(), color1.y() * color1.w(), color1.z() * color1.w(), 1.0f)); 240 rr::writeFragmentOutput(context, packetNdx, 2, 0, tcu::Vec4(color2.x() * color2.w(), color2.y() * color2.w(), color2.z() * color2.w(), 1.0f)); 241 rr::writeFragmentOutput(context, packetNdx, 3, 0, tcu::Vec4(color3.x() * color3.w(), color3.y() * color3.w(), color3.z() * color3.w(), 1.0f)); 242 } 243 } 244}; 245 246class TextureFragmentShader : public rr::FragmentShader 247{ 248public: 249 TextureFragmentShader (const tcu::ConstPixelBufferAccess& texture) 250 : rr::FragmentShader (1, 1) 251 , m_texture (texture) 252 { 253 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; 254 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; 255 } 256 257 void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const 258 { 259 for (int packetNdx = 0; packetNdx < numPackets; packetNdx++) 260 { 261 rr::FragmentPacket& packet = packets[packetNdx]; 262 263 const tcu::IVec2 position0 = packet.position + tcu::IVec2(0, 0); 264 const tcu::IVec2 position1 = packet.position + tcu::IVec2(1, 0); 265 const tcu::IVec2 position2 = packet.position + tcu::IVec2(0, 1); 266 const tcu::IVec2 position3 = packet.position + tcu::IVec2(1, 1); 267 268 const tcu::Vec4 texColor0 = m_texture.getPixel(de::clamp((position0.x() * position0.y()), 0, m_texture.getWidth()-1), 0); 269 const tcu::Vec4 texColor1 = m_texture.getPixel(de::clamp((position1.x() * position1.y()), 0, m_texture.getWidth()-1), 0); 270 const tcu::Vec4 texColor2 = m_texture.getPixel(de::clamp((position2.x() * position2.y()), 0, m_texture.getWidth()-1), 0); 271 const tcu::Vec4 texColor3 = m_texture.getPixel(de::clamp((position3.x() * position3.y()), 0, m_texture.getWidth()-1), 0); 272 273 const tcu::Vec4 vtxColor0 = rr::readVarying<float>(packet, context, 0, 0); 274 const tcu::Vec4 vtxColor1 = rr::readVarying<float>(packet, context, 0, 1); 275 const tcu::Vec4 vtxColor2 = rr::readVarying<float>(packet, context, 0, 2); 276 const tcu::Vec4 vtxColor3 = rr::readVarying<float>(packet, context, 0, 3); 277 278 const tcu::Vec4 color0 = 0.5f * (vtxColor0 + texColor0); 279 const tcu::Vec4 color1 = 0.5f * (vtxColor1 + texColor1); 280 const tcu::Vec4 color2 = 0.5f * (vtxColor2 + texColor2); 281 const tcu::Vec4 color3 = 0.5f * (vtxColor3 + texColor3); 282 283 rr::writeFragmentOutput(context, packetNdx, 0, 0, tcu::Vec4(color0.x() * color0.w(), color0.y() * color0.w(), color0.z() * color0.w(), 1.0f)); 284 rr::writeFragmentOutput(context, packetNdx, 1, 0, tcu::Vec4(color1.x() * color1.w(), color1.y() * color1.w(), color1.z() * color1.w(), 1.0f)); 285 rr::writeFragmentOutput(context, packetNdx, 2, 0, tcu::Vec4(color2.x() * color2.w(), color2.y() * color2.w(), color2.z() * color2.w(), 1.0f)); 286 rr::writeFragmentOutput(context, packetNdx, 3, 0, tcu::Vec4(color3.x() * color3.w(), color3.y() * color3.w(), color3.z() * color3.w(), 1.0f)); 287 } 288 } 289 290private: 291 const tcu::ConstPixelBufferAccess m_texture; 292}; 293 294string generateVertexShaderTemplate (RenderBits renderBits) 295{ 296 std::ostringstream stream; 297 298 stream << 299 "${VERSION_HEADER}\n"; 300 301 if (renderBits & RENDERBITS_AS_VERTEX_TEXTURE) 302 stream << "${TEXTURE_BUFFER_EXT}"; 303 304 stream << 305 "${VTX_INPUT} layout(location = 0) ${HIGHP} vec2 i_coord;\n" 306 "${VTX_OUTPUT} ${HIGHP} vec4 v_color;\n"; 307 308 if (renderBits & RENDERBITS_AS_VERTEX_TEXTURE) 309 { 310 stream << 311 "uniform ${HIGHP} samplerBuffer u_vtxSampler;\n"; 312 } 313 314 stream << 315 "\n" 316 "void main (void)\n" 317 "{\n"; 318 319 if (renderBits & RENDERBITS_AS_VERTEX_TEXTURE) 320 stream << "\tv_color = texelFetch(u_vtxSampler, clamp((int(round(i_coord.x * 4.0)) + 4) * (int(round(i_coord.y * 4.0)) + 4), 0, textureSize(u_vtxSampler)-1));\n"; 321 else 322 stream << "\tv_color = vec4(1.0);\n"; 323 324 stream << 325 "\tgl_Position = vec4(2.0 * (i_coord - vec2(0.5)), 0.0, 1.0);\n" 326 "}\n"; 327 328 return stream.str(); 329} 330 331string generateFragmentShaderTemplate (RenderBits renderBits) 332{ 333 std::ostringstream stream; 334 335 stream << 336 "${VERSION_HEADER}\n"; 337 338 if (renderBits & RENDERBITS_AS_FRAGMENT_TEXTURE) 339 stream << "${TEXTURE_BUFFER_EXT}"; 340 341 stream << 342 "${FRAG_OUTPUT} layout(location = 0) ${HIGHP} vec4 dEQP_FragColor;\n" 343 "${FRAG_INPUT} ${HIGHP} vec4 v_color;\n"; 344 345 if (renderBits & RENDERBITS_AS_FRAGMENT_TEXTURE) 346 stream << "uniform ${HIGHP} samplerBuffer u_fragSampler;\n"; 347 348 stream << 349 "\n" 350 "void main (void)\n" 351 "{\n"; 352 353 if (renderBits & RENDERBITS_AS_FRAGMENT_TEXTURE) 354 stream << "\t${HIGHP} vec4 color = 0.5 * (v_color + texelFetch(u_fragSampler, clamp(int(gl_FragCoord.x) * int(gl_FragCoord.y), 0, textureSize(u_fragSampler)-1)));\n"; 355 else 356 stream << "\t${HIGHP} vec4 color = v_color;\n"; 357 358 stream << 359 "\tdEQP_FragColor = vec4(color.xyz * color.w, 1.0);\n" 360 "}\n"; 361 362 return stream.str(); 363} 364 365string specializeShader (const string& shaderTemplateString, glu::GLSLVersion glslVersion) 366{ 367 const tcu::StringTemplate shaderTemplate(shaderTemplateString); 368 map<string, string> parameters; 369 370 parameters["VERSION_HEADER"] = glu::getGLSLVersionDeclaration(glslVersion); 371 parameters["VTX_OUTPUT"] = "out"; 372 parameters["VTX_INPUT"] = "in"; 373 parameters["FRAG_INPUT"] = "in"; 374 parameters["FRAG_OUTPUT"] = "out"; 375 parameters["HIGHP"] = (glslVersion == glu::GLSL_VERSION_330 ? "" : "highp"); 376 parameters["TEXTURE_BUFFER_EXT"] = (glslVersion == glu::GLSL_VERSION_330 ? "" : "#extension GL_EXT_texture_buffer : enable\n"); 377 378 return shaderTemplate.specialize(parameters); 379} 380 381glu::ShaderProgram* createRenderProgram (glu::RenderContext& renderContext, 382 RenderBits renderBits) 383{ 384 const string vertexShaderTemplate = generateVertexShaderTemplate(renderBits); 385 const string fragmentShaderTemplate = generateFragmentShaderTemplate(renderBits); 386 387 const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(renderContext.getType()); 388 389 const string vertexShaderSource = specializeShader(vertexShaderTemplate, glslVersion); 390 const string fragmentShaderSource = specializeShader(fragmentShaderTemplate, glslVersion); 391 392 glu::ShaderProgram* const program = new glu::ShaderProgram(renderContext, glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource)); 393 394 return program; 395} 396 397void logModifications (TestLog& log, ModifyBits modifyBits) 398{ 399 tcu::ScopedLogSection section(log, "Modify Operations", "Modify Operations"); 400 401 const struct 402 { 403 ModifyBits bit; 404 const char* str; 405 } bitInfos[] = 406 { 407 { MODIFYBITS_BUFFERDATA, "Recreate buffer data with glBufferData()." }, 408 { MODIFYBITS_BUFFERSUBDATA, "Modify texture buffer with glBufferSubData()." }, 409 { MODIFYBITS_MAPBUFFER_WRITE, "Map buffer write-only and rewrite data." }, 410 { MODIFYBITS_MAPBUFFER_READWRITE, "Map buffer readw-write check and rewrite data." } 411 }; 412 413 DE_ASSERT(modifyBits != 0); 414 415 for (int infoNdx = 0; infoNdx < DE_LENGTH_OF_ARRAY(bitInfos); infoNdx++) 416 { 417 if (modifyBits & bitInfos[infoNdx].bit) 418 log << TestLog::Message << bitInfos[infoNdx].str << TestLog::EndMessage; 419 } 420} 421 422void modifyBufferData (TestLog& log, 423 de::Random& rng, 424 glu::TextureBuffer& texture) 425{ 426 vector<deUint8> data; 427 428 genRandomCoords(rng, data, 0, texture.getBufferSize()); 429 430 log << TestLog::Message << "BufferData, Size: " << data.size() << TestLog::EndMessage; 431 432 { 433 // replace getRefBuffer with a new buffer 434 de::ArrayBuffer<deUint8> buffer(&(data[0]), data.size()); 435 texture.getRefBuffer().swap(buffer); 436 } 437 438 texture.upload(); 439} 440 441void modifyBufferSubData (TestLog& log, 442 de::Random& rng, 443 const glw::Functions& gl, 444 glu::TextureBuffer& texture) 445{ 446 const size_t minSize = 4*16; 447 const size_t size = de::max<size_t>(minSize, size_t((float)(texture.getSize() != 0 ? texture.getSize() : texture.getBufferSize()) * (0.7f + 0.3f * rng.getFloat()))); 448 const size_t minOffset = texture.getOffset(); 449 const size_t offset = minOffset + (rng.getUint32() % (texture.getBufferSize() - (size + minOffset))); 450 vector<deUint8> data; 451 452 genRandomCoords(rng, data, offset, size); 453 454 log << TestLog::Message << "BufferSubData, Offset: " << offset << ", Size: " << size << TestLog::EndMessage; 455 456 gl.bindBuffer(GL_TEXTURE_BUFFER, texture.getGLBuffer()); 457 gl.bufferSubData(GL_TEXTURE_BUFFER, (glw::GLsizei)offset, (glw::GLsizei)data.size(), &(data[0])); 458 gl.bindBuffer(GL_TEXTURE_BUFFER, 0); 459 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to update data with glBufferSubData()"); 460 461 deMemcpy((deUint8*)texture.getRefBuffer().getPtr() + offset, &(data[0]), int(data.size())); 462} 463 464void modifyMapWrite (TestLog& log, 465 de::Random& rng, 466 const glw::Functions& gl, 467 glu::TextureBuffer& texture) 468{ 469 const size_t minSize = 4*16; 470 const size_t size = de::max<size_t>(minSize, size_t((float)(texture.getSize() != 0 ? texture.getSize() : texture.getBufferSize()) * (0.7f + 0.3f * rng.getFloat()))); 471 const size_t minOffset = texture.getOffset(); 472 const size_t offset = minOffset + (rng.getUint32() % (texture.getBufferSize() - (size + minOffset))); 473 vector<deUint8> data; 474 475 genRandomCoords(rng, data, offset, size); 476 477 log << TestLog::Message << "glMapBufferRange, Write Only, Offset: " << offset << ", Size: " << size << TestLog::EndMessage; 478 479 gl.bindBuffer(GL_TEXTURE_BUFFER, texture.getGLBuffer()); 480 { 481 deUint8* ptr = (deUint8*)gl.mapBufferRange(GL_TEXTURE_BUFFER, (glw::GLsizei)offset, (glw::GLsizei)size, GL_MAP_WRITE_BIT); 482 483 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()"); 484 TCU_CHECK(ptr); 485 486 for (int i = 0; i < (int)data.size(); i++) 487 ptr[i] = data[i]; 488 489 TCU_CHECK(gl.unmapBuffer(GL_TEXTURE_BUFFER)); 490 } 491 gl.bindBuffer(GL_TEXTURE_BUFFER, 0); 492 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to update data with glMapBufferRange()"); 493 494 deMemcpy((deUint8*)texture.getRefBuffer().getPtr()+offset, &(data[0]), int(data.size())); 495} 496 497void modifyMapReadWrite (TestLog& log, 498 tcu::ResultCollector& resultCollector, 499 de::Random& rng, 500 const glw::Functions& gl, 501 glu::TextureBuffer& texture) 502{ 503 const size_t minSize = 4*16; 504 const size_t size = de::max<size_t>(minSize, size_t((float)(texture.getSize() != 0 ? texture.getSize() : texture.getBufferSize()) * (0.7f + 0.3f * rng.getFloat()))); 505 const size_t minOffset = texture.getOffset(); 506 const size_t offset = minOffset + (rng.getUint32() % (texture.getBufferSize() - (size + minOffset))); 507 deUint8* const refPtr = (deUint8*)texture.getRefBuffer().getPtr() + offset; 508 vector<deUint8> data; 509 510 genRandomCoords(rng, data, offset, size); 511 512 log << TestLog::Message << "glMapBufferRange, Read Write, Offset: " << offset << ", Size: " << size << TestLog::EndMessage; 513 514 gl.bindBuffer(GL_TEXTURE_BUFFER, texture.getGLBuffer()); 515 { 516 size_t invalidBytes = 0; 517 deUint8* const ptr = (deUint8*)gl.mapBufferRange(GL_TEXTURE_BUFFER, (glw::GLsizei)offset, (glw::GLsizei)size, GL_MAP_WRITE_BIT|GL_MAP_READ_BIT); 518 519 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()"); 520 TCU_CHECK(ptr); 521 522 for (int i = 0; i < (int)data.size(); i++) 523 { 524 if (ptr[i] != refPtr[i]) 525 { 526 if (invalidBytes < 24) 527 log << TestLog::Message << "Invalid byte in mapped buffer. " << tcu::Format::Hex<2>(data[i]).toString() << " at " << i << ", expected " << tcu::Format::Hex<2>(refPtr[i]).toString() << TestLog::EndMessage; 528 529 invalidBytes++; 530 } 531 532 ptr[i] = data[i]; 533 } 534 535 TCU_CHECK(gl.unmapBuffer(GL_TEXTURE_BUFFER)); 536 537 if (invalidBytes > 0) 538 { 539 log << TestLog::Message << "Total of " << invalidBytes << " invalid bytes." << TestLog::EndMessage; 540 resultCollector.fail("Invalid data in mapped buffer"); 541 } 542 } 543 544 gl.bindBuffer(GL_TEXTURE_BUFFER, 0); 545 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to update data with glMapBufferRange()"); 546 547 for (int i = 0; i < (int)data.size(); i++) 548 refPtr[i] = data[i]; 549} 550 551void modify (TestLog& log, 552 tcu::ResultCollector& resultCollector, 553 glu::RenderContext& renderContext, 554 ModifyBits modifyBits, 555 de::Random& rng, 556 glu::TextureBuffer& texture) 557{ 558 const tcu::ScopedLogSection modifySection(log, "Modifying Texture buffer", "Modifying Texture Buffer"); 559 560 logModifications(log, modifyBits); 561 562 if (modifyBits & MODIFYBITS_BUFFERDATA) 563 modifyBufferData(log, rng, texture); 564 565 if (modifyBits & MODIFYBITS_BUFFERSUBDATA) 566 modifyBufferSubData(log, rng, renderContext.getFunctions(), texture); 567 568 if (modifyBits & MODIFYBITS_MAPBUFFER_WRITE) 569 modifyMapWrite(log, rng, renderContext.getFunctions(), texture); 570 571 if (modifyBits & MODIFYBITS_MAPBUFFER_READWRITE) 572 modifyMapReadWrite(log, resultCollector, rng, renderContext.getFunctions(), texture); 573} 574 575void renderGL (glu::RenderContext& renderContext, 576 RenderBits renderBits, 577 deUint32 coordSeed, 578 int triangleCount, 579 glu::ShaderProgram& program, 580 glu::TextureBuffer& texture) 581{ 582 const glw::Functions& gl = renderContext.getFunctions(); 583 const glu::VertexArray vao (renderContext); 584 const glu::Buffer coordBuffer (renderContext); 585 586 gl.useProgram(program.getProgram()); 587 gl.bindVertexArray(*vao); 588 589 gl.enableVertexAttribArray(0); 590 591 if (renderBits & RENDERBITS_AS_VERTEX_ARRAY) 592 { 593 gl.bindBuffer(GL_ARRAY_BUFFER, texture.getGLBuffer()); 594 gl.vertexAttribPointer(0, 2, GL_UNSIGNED_BYTE, true, 0, DE_NULL); 595 } 596 else 597 { 598 de::Random rng(coordSeed); 599 vector<deUint8> coords; 600 601 genRandomCoords(rng, coords, 0, 256*2); 602 603 gl.bindBuffer(GL_ARRAY_BUFFER, *coordBuffer); 604 gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizei)coords.size(), &(coords[0]), GL_STREAM_DRAW); 605 gl.vertexAttribPointer(0, 2, GL_UNSIGNED_BYTE, true, 0, DE_NULL); 606 } 607 608 if (renderBits & RENDERBITS_AS_VERTEX_TEXTURE) 609 { 610 const deInt32 location = gl.getUniformLocation(program.getProgram(), "u_vtxSampler"); 611 612 gl.activeTexture(GL_TEXTURE0); 613 gl.bindTexture(GL_TEXTURE_BUFFER, texture.getGLTexture()); 614 gl.uniform1i(location, 0); 615 } 616 617 if (renderBits & RENDERBITS_AS_FRAGMENT_TEXTURE) 618 { 619 const deInt32 location = gl.getUniformLocation(program.getProgram(), "u_fragSampler"); 620 621 gl.activeTexture(GL_TEXTURE1); 622 gl.bindTexture(GL_TEXTURE_BUFFER, texture.getGLTexture()); 623 gl.uniform1i(location, 1); 624 gl.activeTexture(GL_TEXTURE0); 625 } 626 627 if (renderBits & RENDERBITS_AS_INDEX_ARRAY) 628 { 629 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, texture.getGLBuffer()); 630 gl.drawElements(GL_TRIANGLES, triangleCount * 3, GL_UNSIGNED_BYTE, DE_NULL); 631 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 632 } 633 else 634 gl.drawArrays(GL_TRIANGLES, 0, triangleCount * 3); 635 636 if (renderBits & RENDERBITS_AS_FRAGMENT_TEXTURE) 637 { 638 gl.activeTexture(GL_TEXTURE1); 639 gl.bindTexture(GL_TEXTURE_BUFFER, 0); 640 } 641 642 if (renderBits & RENDERBITS_AS_VERTEX_TEXTURE) 643 { 644 gl.activeTexture(GL_TEXTURE0); 645 gl.bindTexture(GL_TEXTURE_BUFFER, 0); 646 } 647 648 gl.bindBuffer(GL_ARRAY_BUFFER, 0); 649 gl.disableVertexAttribArray(0); 650 651 gl.bindVertexArray(0); 652 gl.useProgram(0); 653 GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed"); 654} 655 656void renderReference (RenderBits renderBits, 657 deUint32 coordSeed, 658 int triangleCount, 659 const glu::TextureBuffer& texture, 660 int maxTextureBufferSize, 661 const tcu::PixelBufferAccess& target, 662 int subpixelBits) 663{ 664 const tcu::ConstPixelBufferAccess effectiveAccess = glu::getTextureBufferEffectiveRefTexture(texture, maxTextureBufferSize); 665 666 const CoordVertexShader coordVertexShader; 667 const TextureVertexShader textureVertexShader (effectiveAccess); 668 const rr::VertexShader* const vertexShader = (renderBits & RENDERBITS_AS_VERTEX_TEXTURE ? static_cast<const rr::VertexShader*>(&textureVertexShader) : &coordVertexShader); 669 670 const CoordFragmentShader coordFragmmentShader; 671 const TextureFragmentShader textureFragmentShader (effectiveAccess); 672 const rr::FragmentShader* const fragmentShader = (renderBits & RENDERBITS_AS_FRAGMENT_TEXTURE ? static_cast<const rr::FragmentShader*>(&textureFragmentShader) : &coordFragmmentShader); 673 674 const rr::Renderer renderer; 675 const rr::RenderState renderState(rr::ViewportState(rr::WindowRectangle(0, 0, target.getWidth(), target.getHeight())), subpixelBits); 676 const rr::RenderTarget renderTarget(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(target)); 677 678 const rr::Program program(vertexShader, fragmentShader); 679 680 rr::VertexAttrib vertexAttribs[1]; 681 vector<deUint8> coords; 682 683 if (renderBits & RENDERBITS_AS_VERTEX_ARRAY) 684 { 685 vertexAttribs[0].type = rr::VERTEXATTRIBTYPE_NONPURE_UNORM8; 686 vertexAttribs[0].size = 2; 687 vertexAttribs[0].pointer = texture.getRefBuffer().getPtr(); 688 } 689 else 690 { 691 de::Random rng(coordSeed); 692 693 genRandomCoords(rng, coords, 0, 256*2); 694 695 vertexAttribs[0].type = rr::VERTEXATTRIBTYPE_NONPURE_UNORM8; 696 vertexAttribs[0].size = 2; 697 vertexAttribs[0].pointer = &(coords[0]); 698 } 699 700 if (renderBits & RENDERBITS_AS_INDEX_ARRAY) 701 { 702 const rr::PrimitiveList primitives(rr::PRIMITIVETYPE_TRIANGLES, triangleCount * 3, rr::DrawIndices(texture.getRefBuffer().getPtr(), rr::INDEXTYPE_UINT8)); 703 const rr::DrawCommand cmd(renderState, renderTarget, program, 1, vertexAttribs, primitives); 704 705 renderer.draw(cmd); 706 } 707 else 708 { 709 const rr::PrimitiveList primitives(rr::PRIMITIVETYPE_TRIANGLES, triangleCount * 3, 0); 710 const rr::DrawCommand cmd(renderState, renderTarget, program, 1, vertexAttribs, primitives); 711 712 renderer.draw(cmd); 713 } 714} 715 716void logRendering (TestLog& log, RenderBits renderBits) 717{ 718 const struct 719 { 720 RenderBits bit; 721 const char* str; 722 } bitInfos[] = 723 { 724 { RENDERBITS_AS_VERTEX_ARRAY, "vertex array" }, 725 { RENDERBITS_AS_INDEX_ARRAY, "index array" }, 726 { RENDERBITS_AS_VERTEX_TEXTURE, "vertex texture" }, 727 { RENDERBITS_AS_FRAGMENT_TEXTURE, "fragment texture" } 728 }; 729 730 std::ostringstream stream; 731 vector<const char*> usedAs; 732 733 DE_ASSERT(renderBits != 0); 734 735 for (int infoNdx = 0; infoNdx < DE_LENGTH_OF_ARRAY(bitInfos); infoNdx++) 736 { 737 if (renderBits & bitInfos[infoNdx].bit) 738 usedAs.push_back(bitInfos[infoNdx].str); 739 } 740 741 stream << "Render using texture buffer as "; 742 743 for (int asNdx = 0; asNdx < (int)usedAs.size(); asNdx++) 744 { 745 if (asNdx+1 == (int)usedAs.size() && (int)usedAs.size() > 1) 746 stream << " and "; 747 else if (asNdx > 0) 748 stream << ", "; 749 750 stream << usedAs[asNdx]; 751 } 752 753 stream << "."; 754 755 log << TestLog::Message << stream.str() << TestLog::EndMessage; 756} 757 758void render (TestLog& log, 759 glu::RenderContext& renderContext, 760 RenderBits renderBits, 761 de::Random& rng, 762 glu::ShaderProgram& program, 763 glu::TextureBuffer& texture, 764 const tcu::PixelBufferAccess& target) 765{ 766 const tcu::ScopedLogSection renderSection (log, "Render Texture buffer", "Render Texture Buffer"); 767 const int triangleCount = 8; 768 const deUint32 coordSeed = rng.getUint32(); 769 int maxTextureBufferSize = 0; 770 771 renderContext.getFunctions().getIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTextureBufferSize); 772 GLU_EXPECT_NO_ERROR(renderContext.getFunctions().getError(), "query GL_MAX_TEXTURE_BUFFER_SIZE"); 773 DE_ASSERT(maxTextureBufferSize > 0); // checked in init() 774 775 logRendering(log, renderBits); 776 777 renderGL(renderContext, renderBits, coordSeed, triangleCount, program, texture); 778 779 int subpixelBits = 0; 780 renderContext.getFunctions().getIntegerv(GL_SUBPIXEL_BITS, &subpixelBits); 781 renderReference(renderBits, coordSeed, triangleCount, texture, maxTextureBufferSize, target, subpixelBits); 782} 783 784void verifyScreen (TestLog& log, 785 tcu::ResultCollector& resultCollector, 786 glu::RenderContext& renderContext, 787 const tcu::ConstPixelBufferAccess& referenceTarget) 788{ 789 const tcu::ScopedLogSection verifySection (log, "Verify screen contents", "Verify screen contents"); 790 tcu::Surface screen (referenceTarget.getWidth(), referenceTarget.getHeight()); 791 792 glu::readPixels(renderContext, 0, 0, screen.getAccess()); 793 794 if (!tcu::fuzzyCompare(log, "Result of rendering", "Result of rendering", referenceTarget, screen.getAccess(), 0.05f, tcu::COMPARE_LOG_RESULT)) 795 resultCollector.fail("Rendering failed"); 796} 797 798void logImplementationInfo (TestLog& log, glu::RenderContext& renderContext) 799{ 800 const tcu::ScopedLogSection section (log, "Implementation Values", "Implementation Values"); 801 de::UniquePtr<glu::ContextInfo> info (glu::ContextInfo::create(renderContext)); 802 const glw::Functions& gl = renderContext.getFunctions(); 803 804 if (glu::contextSupports(renderContext.getType(), glu::ApiType(3, 3, glu::PROFILE_CORE))) 805 { 806 deInt32 maxTextureSize = 0; 807 808 gl.getIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTextureSize); 809 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE)"); 810 811 log << TestLog::Message << "GL_MAX_TEXTURE_BUFFER_SIZE : " << maxTextureSize << TestLog::EndMessage; 812 } 813 else if (glu::contextSupports(renderContext.getType(), glu::ApiType(3, 1, glu::PROFILE_ES)) && info->isExtensionSupported("GL_EXT_texture_buffer")) 814 { 815 { 816 deInt32 maxTextureSize = 0; 817 818 gl.getIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTextureSize); 819 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE_EXT)"); 820 821 log << TestLog::Message << "GL_MAX_TEXTURE_BUFFER_SIZE_EXT : " << maxTextureSize << TestLog::EndMessage; 822 } 823 824 { 825 deInt32 textureBufferAlignment = 0; 826 827 gl.getIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, &textureBufferAlignment); 828 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT)"); 829 830 log << TestLog::Message << "GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT : " << textureBufferAlignment << TestLog::EndMessage; 831 } 832 } 833 else 834 DE_ASSERT(DE_FALSE); 835} 836 837void logTextureInfo (TestLog& log, 838 deUint32 format, 839 size_t bufferSize, 840 size_t offset, 841 size_t size) 842{ 843 const tcu::ScopedLogSection section(log, "Texture Info", "Texture Info"); 844 845 log << TestLog::Message << "Texture format : " << glu::getTextureFormatStr(format) << TestLog::EndMessage; 846 log << TestLog::Message << "Buffer size : " << bufferSize << TestLog::EndMessage; 847 848 if (offset != 0 || size != 0) 849 { 850 log << TestLog::Message << "Buffer range offset: " << offset << TestLog::EndMessage; 851 log << TestLog::Message << "Buffer range size: " << size << TestLog::EndMessage; 852 } 853} 854 855void runTests (tcu::TestContext& testCtx, 856 glu::RenderContext& renderContext, 857 de::Random& rng, 858 deUint32 format, 859 size_t bufferSize, 860 size_t offset, 861 size_t size, 862 RenderBits preRender, 863 glu::ShaderProgram* preRenderProgram, 864 ModifyBits modifyType, 865 RenderBits postRender, 866 glu::ShaderProgram* postRenderProgram) 867{ 868 const tcu::RenderTarget renderTarget (renderContext.getRenderTarget()); 869 const glw::Functions& gl = renderContext.getFunctions(); 870 871 const int width = de::min<int>(renderTarget.getWidth(), MAX_VIEWPORT_WIDTH); 872 const int height = de::min<int>(renderTarget.getHeight(), MAX_VIEWPORT_HEIGHT); 873 const tcu::Vec4 clearColor (0.25f, 0.5f, 0.75f, 1.0f); 874 875 TestLog& log = testCtx.getLog(); 876 tcu::ResultCollector resultCollector (log); 877 878 logImplementationInfo(log, renderContext); 879 logTextureInfo(log, format, bufferSize, offset, size); 880 881 { 882 tcu::Surface referenceTarget (width, height); 883 vector<deUint8> bufferData; 884 885 genRandomCoords(rng, bufferData, 0, bufferSize); 886 887 for (deUint8 i = 0; i < 4; i++) 888 { 889 const deUint8 val = extend2BitsToByte(i); 890 891 if (val >= offset && val < offset + size) 892 { 893 bufferData[val*2 + 0] = (i / 2 == 0 ? extend2BitsToByte(0x2u) : extend2BitsToByte(0x01u)); 894 bufferData[val*2 + 1] = (i % 2 == 0 ? extend2BitsToByte(0x2u) : extend2BitsToByte(0x01u)); 895 } 896 } 897 898 { 899 glu::TextureBuffer texture (renderContext, format, bufferSize, offset, size, &(bufferData[0])); 900 901 TCU_CHECK_MSG(width >= MIN_VIEWPORT_WIDTH || height >= MIN_VIEWPORT_HEIGHT, "Too small viewport"); 902 903 DE_ASSERT(preRender == 0 || preRenderProgram); 904 DE_ASSERT(postRender == 0 || postRenderProgram); 905 906 gl.viewport(0, 0, width, height); 907 gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w()); 908 gl.clear(GL_COLOR_BUFFER_BIT); 909 GLU_EXPECT_NO_ERROR(gl.getError(), "Screen setup failed"); 910 911 tcu::clear(referenceTarget.getAccess(), clearColor); 912 913 texture.upload(); 914 915 if (preRender != 0) 916 render(log, renderContext, preRender, rng, *preRenderProgram, texture, referenceTarget.getAccess()); 917 918 if (modifyType != 0) 919 modify(log, resultCollector, renderContext, modifyType, rng, texture); 920 921 if (postRender != 0) 922 render(log, renderContext, postRender, rng, *postRenderProgram, texture, referenceTarget.getAccess()); 923 } 924 925 verifyScreen(log, resultCollector, renderContext, referenceTarget.getAccess()); 926 927 resultCollector.setTestContextResult(testCtx); 928 } 929} 930 931} // anonymous 932 933TextureBufferCase::TextureBufferCase (tcu::TestContext& testCtx, 934 glu::RenderContext& renderCtx, 935 deUint32 format, 936 size_t bufferSize, 937 size_t offset, 938 size_t size, 939 RenderBits preRender, 940 ModifyBits modify, 941 RenderBits postRender, 942 const char* name, 943 const char* description) 944 : tcu::TestCase (testCtx, name, description) 945 , m_renderCtx (renderCtx) 946 , m_format (format) 947 , m_bufferSize (bufferSize) 948 , m_offset (offset) 949 , m_size (size) 950 951 , m_preRender (preRender) 952 , m_modify (modify) 953 , m_postRender (postRender) 954 955 , m_preRenderProgram (DE_NULL) 956 , m_postRenderProgram (DE_NULL) 957{ 958} 959 960TextureBufferCase::~TextureBufferCase (void) 961{ 962 TextureBufferCase::deinit(); 963} 964 965void TextureBufferCase::init (void) 966{ 967 de::UniquePtr<glu::ContextInfo> info (glu::ContextInfo::create(m_renderCtx)); 968 969 if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType(3, 3, glu::PROFILE_CORE)) 970 && !(glu::contextSupports(m_renderCtx.getType(), glu::ApiType(3, 1, glu::PROFILE_ES)) && info->isExtensionSupported("GL_EXT_texture_buffer"))) 971 throw tcu::NotSupportedError("Texture buffers not supported", "", __FILE__, __LINE__); 972 973 { 974 const int maxTextureBufferSize = info->getInt(GL_MAX_TEXTURE_BUFFER_SIZE); 975 if (maxTextureBufferSize <= 0) 976 TCU_THROW(NotSupportedError, "GL_MAX_TEXTURE_BUFFER_SIZE > 0 required"); 977 } 978 979 if (m_preRender != 0) 980 { 981 TestLog& log = m_testCtx.getLog(); 982 const char* const sectionName = (m_postRender != 0 ? "Primary render program" : "Render program"); 983 const tcu::ScopedLogSection section (log, sectionName, sectionName); 984 985 m_preRenderProgram = createRenderProgram(m_renderCtx, m_preRender); 986 m_testCtx.getLog() << (*m_preRenderProgram); 987 988 TCU_CHECK(m_preRenderProgram->isOk()); 989 } 990 991 if (m_postRender != 0) 992 { 993 // Reusing program 994 if (m_preRender == m_postRender) 995 { 996 m_postRenderProgram = m_preRenderProgram; 997 } 998 else 999 { 1000 TestLog& log = m_testCtx.getLog(); 1001 const char* const sectionName = (m_preRender!= 0 ? "Secondary render program" : "Render program"); 1002 const tcu::ScopedLogSection section (log, sectionName, sectionName); 1003 1004 m_postRenderProgram = createRenderProgram(m_renderCtx, m_postRender); 1005 m_testCtx.getLog() << (*m_postRenderProgram); 1006 1007 TCU_CHECK(m_postRenderProgram->isOk()); 1008 } 1009 } 1010} 1011 1012void TextureBufferCase::deinit (void) 1013{ 1014 if (m_preRenderProgram == m_postRenderProgram) 1015 m_postRenderProgram = DE_NULL; 1016 1017 delete m_preRenderProgram; 1018 m_preRenderProgram = DE_NULL; 1019 1020 delete m_postRenderProgram; 1021 m_postRenderProgram = DE_NULL; 1022} 1023 1024tcu::TestCase::IterateResult TextureBufferCase::iterate (void) 1025{ 1026 de::Random rng (deInt32Hash(deStringHash(getName()))); 1027 size_t offset; 1028 1029 if (m_offset != 0) 1030 { 1031 const glw::Functions& gl = m_renderCtx.getFunctions(); 1032 deInt32 alignment = 0; 1033 1034 gl.getIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, &alignment); 1035 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT)"); 1036 1037 offset = m_offset * alignment; 1038 } 1039 else 1040 offset = 0; 1041 1042 runTests(m_testCtx, m_renderCtx, rng, m_format, m_bufferSize, offset, m_size, m_preRender, m_preRenderProgram, m_modify, m_postRender, m_postRenderProgram); 1043 1044 return STOP; 1045} 1046 1047} // gls 1048} // deqp 1049