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