Add testing for sparse D/S/DS images.
[platform/upstream/VK-GL-CTS.git] / modules / glshared / glsTextureBufferCase.cpp
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
84 deUint8 extend2BitsToByte (deUint8 bits)
85 {
86         DE_ASSERT((bits & (~0x03u)) == 0);
87
88         return (deUint8)(bits | (bits << 2) | (bits << 4) | (bits << 6));
89 }
90
91 void 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
154 class CoordVertexShader : public rr::VertexShader
155 {
156 public:
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
179 class TextureVertexShader : public rr::VertexShader
180 {
181 public:
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
207 private:
208         const tcu::ConstPixelBufferAccess m_texture;
209 };
210
211 class CoordFragmentShader : public rr::FragmentShader
212 {
213 public:
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
246 class TextureFragmentShader : public rr::FragmentShader
247 {
248 public:
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
290 private:
291         const tcu::ConstPixelBufferAccess m_texture;
292 };
293
294 string 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
331 string 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
365 string 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
381 glu::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
397 void 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
422 void 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
441 void 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
464 void 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
497 void 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
551 void 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
575 void 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
656 void renderReference (RenderBits                                        renderBits,
657                                           deUint32                                              coordSeed,
658                                           int                                                   triangleCount,
659                                           const glu::TextureBuffer&             texture,
660                                           int                                                   maxTextureBufferSize,
661                                           const tcu::PixelBufferAccess& target)
662 {
663         const tcu::ConstPixelBufferAccess       effectiveAccess                 = glu::getTextureBufferEffectiveRefTexture(texture, maxTextureBufferSize);
664
665         const CoordVertexShader                         coordVertexShader;
666         const TextureVertexShader                       textureVertexShader             (effectiveAccess);
667         const rr::VertexShader* const           vertexShader                    = (renderBits & RENDERBITS_AS_VERTEX_TEXTURE ? static_cast<const rr::VertexShader*>(&textureVertexShader) : &coordVertexShader);
668
669         const CoordFragmentShader                       coordFragmmentShader;
670         const TextureFragmentShader                     textureFragmentShader   (effectiveAccess);
671         const rr::FragmentShader* const         fragmentShader                  = (renderBits & RENDERBITS_AS_FRAGMENT_TEXTURE ? static_cast<const rr::FragmentShader*>(&textureFragmentShader) : &coordFragmmentShader);
672
673         const rr::Renderer                                      renderer;
674         const rr::RenderState                           renderState(rr::ViewportState(rr::WindowRectangle(0, 0, target.getWidth(), target.getHeight())));
675         const rr::RenderTarget                          renderTarget(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(target));
676
677         const rr::Program                                       program(vertexShader, fragmentShader);
678
679         rr::VertexAttrib                                        vertexAttribs[1];
680         vector<deUint8>                                         coords;
681
682         if (renderBits & RENDERBITS_AS_VERTEX_ARRAY)
683         {
684                 vertexAttribs[0].type                   = rr::VERTEXATTRIBTYPE_NONPURE_UNORM8;
685                 vertexAttribs[0].size                   = 2;
686                 vertexAttribs[0].pointer                = texture.getRefBuffer().getPtr();
687         }
688         else
689         {
690                 de::Random rng(coordSeed);
691
692                 genRandomCoords(rng, coords, 0, 256*2);
693
694                 vertexAttribs[0].type                   = rr::VERTEXATTRIBTYPE_NONPURE_UNORM8;
695                 vertexAttribs[0].size                   = 2;
696                 vertexAttribs[0].pointer                = &(coords[0]);
697         }
698
699         if (renderBits & RENDERBITS_AS_INDEX_ARRAY)
700         {
701                 const rr::PrimitiveList primitives(rr::PRIMITIVETYPE_TRIANGLES, triangleCount * 3, rr::DrawIndices(texture.getRefBuffer().getPtr(), rr::INDEXTYPE_UINT8));
702                 const rr::DrawCommand   cmd(renderState, renderTarget, program, 1, vertexAttribs, primitives);
703
704                 renderer.draw(cmd);
705         }
706         else
707         {
708                 const rr::PrimitiveList primitives(rr::PRIMITIVETYPE_TRIANGLES, triangleCount * 3, 0);
709                 const rr::DrawCommand   cmd(renderState, renderTarget, program, 1, vertexAttribs, primitives);
710
711                 renderer.draw(cmd);
712         }
713 }
714
715 void logRendering (TestLog& log, RenderBits renderBits)
716 {
717         const struct
718         {
719                 RenderBits      bit;
720                 const char*     str;
721         } bitInfos[] =
722         {
723                 { RENDERBITS_AS_VERTEX_ARRAY,           "vertex array"          },
724                 { RENDERBITS_AS_INDEX_ARRAY,            "index array"           },
725                 { RENDERBITS_AS_VERTEX_TEXTURE,         "vertex texture"        },
726                 { RENDERBITS_AS_FRAGMENT_TEXTURE,       "fragment texture"      }
727         };
728
729         std::ostringstream      stream;
730         vector<const char*> usedAs;
731
732         DE_ASSERT(renderBits != 0);
733
734         for (int infoNdx = 0; infoNdx < DE_LENGTH_OF_ARRAY(bitInfos); infoNdx++)
735         {
736                 if (renderBits & bitInfos[infoNdx].bit)
737                         usedAs.push_back(bitInfos[infoNdx].str);
738         }
739
740         stream << "Render using texture buffer as ";
741
742         for (int asNdx = 0; asNdx < (int)usedAs.size(); asNdx++)
743         {
744                 if (asNdx+1 == (int)usedAs.size() && (int)usedAs.size() > 1)
745                         stream << " and ";
746                 else if (asNdx > 0)
747                         stream << ", ";
748
749                 stream << usedAs[asNdx];
750         }
751
752         stream << ".";
753
754         log << TestLog::Message << stream.str() << TestLog::EndMessage;
755 }
756
757 void render (TestLog&                                           log,
758                          glu::RenderContext&                    renderContext,
759                          RenderBits                                             renderBits,
760                          de::Random&                                    rng,
761                          glu::ShaderProgram&                    program,
762                          glu::TextureBuffer&                    texture,
763                          const tcu::PixelBufferAccess&  target)
764 {
765         const tcu::ScopedLogSection     renderSection                   (log, "Render Texture buffer", "Render Texture Buffer");
766         const int                                       triangleCount                   = 8;
767         const deUint32                          coordSeed                               = rng.getUint32();
768         int                                                     maxTextureBufferSize    = 0;
769
770         renderContext.getFunctions().getIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTextureBufferSize);
771         GLU_EXPECT_NO_ERROR(renderContext.getFunctions().getError(), "query GL_MAX_TEXTURE_BUFFER_SIZE");
772         DE_ASSERT(maxTextureBufferSize > 0); // checked in init()
773
774         logRendering(log, renderBits);
775
776         renderGL(renderContext, renderBits, coordSeed, triangleCount, program, texture);
777         renderReference(renderBits, coordSeed, triangleCount, texture, maxTextureBufferSize, target);
778 }
779
780 void verifyScreen (TestLog&                                                             log,
781                                    tcu::ResultCollector&                                resultCollector,
782                                    glu::RenderContext&                                  renderContext,
783                                    const tcu::ConstPixelBufferAccess&   referenceTarget)
784 {
785         const tcu::ScopedLogSection     verifySection   (log, "Verify screen contents", "Verify screen contents");
786         tcu::Surface                            screen                  (referenceTarget.getWidth(), referenceTarget.getHeight());
787
788         glu::readPixels(renderContext, 0, 0, screen.getAccess());
789
790         if (!tcu::fuzzyCompare(log, "Result of rendering", "Result of rendering", referenceTarget, screen.getAccess(), 0.05f, tcu::COMPARE_LOG_RESULT))
791                 resultCollector.fail("Rendering failed");
792 }
793
794 void logImplementationInfo (TestLog& log, glu::RenderContext& renderContext)
795 {
796         const tcu::ScopedLogSection             section (log, "Implementation Values", "Implementation Values");
797         de::UniquePtr<glu::ContextInfo> info    (glu::ContextInfo::create(renderContext));
798         const glw::Functions&                   gl              = renderContext.getFunctions();
799
800         if (glu::contextSupports(renderContext.getType(), glu::ApiType(3, 3, glu::PROFILE_CORE)))
801         {
802                 deInt32 maxTextureSize = 0;
803
804                 gl.getIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTextureSize);
805                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE)");
806
807                 log << TestLog::Message << "GL_MAX_TEXTURE_BUFFER_SIZE : " <<  maxTextureSize << TestLog::EndMessage;
808         }
809         else if (glu::contextSupports(renderContext.getType(), glu::ApiType(3, 1, glu::PROFILE_ES)) && info->isExtensionSupported("GL_EXT_texture_buffer"))
810         {
811                 {
812                         deInt32 maxTextureSize = 0;
813
814                         gl.getIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTextureSize);
815                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE_EXT)");
816
817                         log << TestLog::Message << "GL_MAX_TEXTURE_BUFFER_SIZE_EXT : " <<  maxTextureSize << TestLog::EndMessage;
818                 }
819
820                 {
821                         deInt32 textureBufferAlignment = 0;
822
823                         gl.getIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, &textureBufferAlignment);
824                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT)");
825
826                         log << TestLog::Message << "GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT : " <<  textureBufferAlignment << TestLog::EndMessage;
827                 }
828         }
829         else
830                 DE_ASSERT(DE_FALSE);
831 }
832
833 void logTextureInfo (TestLog&   log,
834                                          deUint32       format,
835                                          size_t         bufferSize,
836                                          size_t         offset,
837                                          size_t         size)
838 {
839         const tcu::ScopedLogSection     section(log, "Texture Info", "Texture Info");
840
841         log << TestLog::Message << "Texture format : " << glu::getTextureFormatStr(format) << TestLog::EndMessage;
842         log << TestLog::Message << "Buffer size : " << bufferSize << TestLog::EndMessage;
843
844         if (offset != 0 || size != 0)
845         {
846                 log << TestLog::Message << "Buffer range offset: " << offset << TestLog::EndMessage;
847                 log << TestLog::Message << "Buffer range size: " << size << TestLog::EndMessage;
848         }
849 }
850
851 void runTests (tcu::TestContext&        testCtx,
852                            glu::RenderContext&  renderContext,
853                            de::Random&                  rng,
854                            deUint32                             format,
855                            size_t                               bufferSize,
856                            size_t                               offset,
857                            size_t                               size,
858                            RenderBits                   preRender,
859                            glu::ShaderProgram*  preRenderProgram,
860                            ModifyBits                   modifyType,
861                            RenderBits                   postRender,
862                            glu::ShaderProgram*  postRenderProgram)
863 {
864         const tcu::RenderTarget renderTarget    (renderContext.getRenderTarget());
865         const glw::Functions&   gl                              = renderContext.getFunctions();
866
867         const int                               width                   = de::min<int>(renderTarget.getWidth(), MAX_VIEWPORT_WIDTH);
868         const int                               height                  = de::min<int>(renderTarget.getHeight(), MAX_VIEWPORT_HEIGHT);
869         const tcu::Vec4                 clearColor              (0.25f, 0.5f, 0.75f, 1.0f);
870
871         TestLog&                                log                             = testCtx.getLog();
872         tcu::ResultCollector    resultCollector (log);
873
874         logImplementationInfo(log, renderContext);
875         logTextureInfo(log, format, bufferSize, offset, size);
876
877         {
878                 tcu::Surface                    referenceTarget (width, height);
879                 vector<deUint8>                 bufferData;
880
881                 genRandomCoords(rng, bufferData, 0, bufferSize);
882
883                 for (deUint8 i = 0; i < 4; i++)
884                 {
885                         const deUint8 val = extend2BitsToByte(i);
886
887                         if (val >= offset && val < offset + size)
888                         {
889                                 bufferData[val*2 + 0] = (i / 2 == 0 ? extend2BitsToByte(0x2u) : extend2BitsToByte(0x01u));
890                                 bufferData[val*2 + 1] = (i % 2 == 0 ? extend2BitsToByte(0x2u) : extend2BitsToByte(0x01u));
891                         }
892                 }
893
894                 {
895                         glu::TextureBuffer texture (renderContext, format, bufferSize, offset, size, &(bufferData[0]));
896
897                         TCU_CHECK_MSG(width >= MIN_VIEWPORT_WIDTH || height >= MIN_VIEWPORT_HEIGHT, "Too small viewport");
898
899                         DE_ASSERT(preRender == 0 || preRenderProgram);
900                         DE_ASSERT(postRender == 0 || postRenderProgram);
901
902                         gl.viewport(0, 0, width, height);
903                         gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
904                         gl.clear(GL_COLOR_BUFFER_BIT);
905                         GLU_EXPECT_NO_ERROR(gl.getError(), "Screen setup failed");
906
907                         tcu::clear(referenceTarget.getAccess(), clearColor);
908
909                         texture.upload();
910
911                         if (preRender != 0)
912                                 render(log, renderContext, preRender, rng, *preRenderProgram, texture, referenceTarget.getAccess());
913
914                         if (modifyType != 0)
915                                 modify(log, resultCollector, renderContext, modifyType, rng, texture);
916
917                         if (postRender != 0)
918                                 render(log, renderContext, postRender, rng, *postRenderProgram, texture, referenceTarget.getAccess());
919                 }
920
921                 verifyScreen(log, resultCollector, renderContext, referenceTarget.getAccess());
922
923                 resultCollector.setTestContextResult(testCtx);
924         }
925 }
926
927 } // anonymous
928
929 TextureBufferCase::TextureBufferCase (tcu::TestContext&         testCtx,
930                                                                           glu::RenderContext&   renderCtx,
931                                                                           deUint32                              format,
932                                                                           size_t                                bufferSize,
933                                                                           size_t                                offset,
934                                                                           size_t                                size,
935                                                                           RenderBits                    preRender,
936                                                                           ModifyBits                    modify,
937                                                                           RenderBits                    postRender,
938                                                                           const char*                   name,
939                                                                           const char*                   description)
940         : tcu::TestCase                         (testCtx, name, description)
941         , m_renderCtx                           (renderCtx)
942         , m_format                                      (format)
943         , m_bufferSize                          (bufferSize)
944         , m_offset                                      (offset)
945         , m_size                                        (size)
946
947         , m_preRender                           (preRender)
948         , m_modify                                      (modify)
949         , m_postRender                          (postRender)
950
951         , m_preRenderProgram            (DE_NULL)
952         , m_postRenderProgram           (DE_NULL)
953 {
954 }
955
956 TextureBufferCase::~TextureBufferCase (void)
957 {
958         TextureBufferCase::deinit();
959 }
960
961 void TextureBufferCase::init (void)
962 {
963         de::UniquePtr<glu::ContextInfo> info (glu::ContextInfo::create(m_renderCtx));
964
965         if (!glu::contextSupports(m_renderCtx.getType(), glu::ApiType(3, 3, glu::PROFILE_CORE))
966                 && !(glu::contextSupports(m_renderCtx.getType(), glu::ApiType(3, 1, glu::PROFILE_ES)) && info->isExtensionSupported("GL_EXT_texture_buffer")))
967                 throw tcu::NotSupportedError("Texture buffers not supported", "", __FILE__, __LINE__);
968
969         {
970                 const int maxTextureBufferSize = info->getInt(GL_MAX_TEXTURE_BUFFER_SIZE);
971                 if (maxTextureBufferSize <= 0)
972                         TCU_THROW(NotSupportedError, "GL_MAX_TEXTURE_BUFFER_SIZE > 0 required");
973         }
974
975         if (m_preRender != 0)
976         {
977                 TestLog&                                        log                     = m_testCtx.getLog();
978                 const char* const                       sectionName     = (m_postRender != 0 ? "Primary render program" : "Render program");
979                 const tcu::ScopedLogSection     section         (log, sectionName, sectionName);
980
981                 m_preRenderProgram = createRenderProgram(m_renderCtx, m_preRender);
982                 m_testCtx.getLog() << (*m_preRenderProgram);
983
984                 TCU_CHECK(m_preRenderProgram->isOk());
985         }
986
987         if (m_postRender != 0)
988         {
989                 // Reusing program
990                 if (m_preRender == m_postRender)
991                 {
992                         m_postRenderProgram = m_preRenderProgram;
993                 }
994                 else
995                 {
996                         TestLog&                                        log                     = m_testCtx.getLog();
997                         const char* const                       sectionName     = (m_preRender!= 0 ? "Secondary render program" : "Render program");
998                         const tcu::ScopedLogSection     section         (log, sectionName, sectionName);
999
1000                         m_postRenderProgram = createRenderProgram(m_renderCtx, m_postRender);
1001                         m_testCtx.getLog() << (*m_postRenderProgram);
1002
1003                         TCU_CHECK(m_postRenderProgram->isOk());
1004                 }
1005         }
1006 }
1007
1008 void TextureBufferCase::deinit (void)
1009 {
1010         if (m_preRenderProgram == m_postRenderProgram)
1011                 m_postRenderProgram = DE_NULL;
1012
1013         delete m_preRenderProgram;
1014         m_preRenderProgram = DE_NULL;
1015
1016         delete m_postRenderProgram;
1017         m_postRenderProgram = DE_NULL;
1018 }
1019
1020 tcu::TestCase::IterateResult TextureBufferCase::iterate (void)
1021 {
1022         de::Random      rng             (deInt32Hash(deStringHash(getName())));
1023         size_t          offset;
1024
1025         if (m_offset != 0)
1026         {
1027                 const glw::Functions&   gl                      = m_renderCtx.getFunctions();
1028                 deInt32                                 alignment       = 0;
1029
1030                 gl.getIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, &alignment);
1031                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT)");
1032
1033                 offset = m_offset * alignment;
1034         }
1035         else
1036                 offset = 0;
1037
1038         runTests(m_testCtx, m_renderCtx, rng, m_format, m_bufferSize, offset, m_size, m_preRender, m_preRenderProgram, m_modify, m_postRender, m_postRenderProgram);
1039
1040         return STOP;
1041 }
1042
1043 } // gls
1044 } // deqp