Merge Vulkan CTS 1.0.2.2 into goog/oc-dev
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fNegativeSSBOBlockTests.cpp
1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2016 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 Negative Shader Storage Buffer Object (SSBO) tests.
22 *//*--------------------------------------------------------------------*/
23 #include "es31fNegativeSSBOBlockTests.hpp"
24 #include "glwDefs.hpp"
25 #include "glwEnums.hpp"
26 #include "tcuStringTemplate.hpp"
27 #include "gluShaderProgram.hpp"
28 #include <map>
29
30 namespace deqp
31 {
32 namespace gles31
33 {
34 namespace Functional
35 {
36 namespace NegativeTestShared
37 {
38 namespace
39 {
40 using tcu::TestLog;
41 using glu::CallLogWrapper;
42 using namespace glw;
43 namespace args
44 {
45 enum ArgMember
46 {
47         ARGMEMBER_FORMAT                        =       0,
48         ARGMEMBER_BINDING_POINT,
49         ARGMEMBER_MATRIX_ORDER,
50         ARGMEMBER_MEMBER_TYPE,
51         ARGMEMBER_NAME,
52         ARGMEMBER_FIXED_ARRAY,
53         ARGMEMBER_VARIABLE_ARRAY,
54         ARGMEMBER_REORDER
55 };
56
57 // key pair ssbo arg data
58 struct SsboArgData
59 {
60         ArgMember       member;
61         std::string     data;
62
63         SsboArgData(const ArgMember& member_, const std::string& data_)
64         {
65                 member  =       member_;
66                 data    =       data_;
67         }
68 };
69
70 // class which manages string based argument used to build varying ssbo interface blocks and members
71 class SsboArgs
72 {
73 public:
74                                         SsboArgs(const std::string version, tcu::TestLog& log);
75
76         void                    setSingleValue                                          (const SsboArgData argData);
77         bool                    setAllValues                                            (const std::vector<SsboArgData> argDataList);
78
79         const std::string&      getContextVersion                               (void) const;
80         const std::string&      getStdFormat                                    (void) const;
81         const std::string&      getBindingPoint                                 (void) const;
82         const std::string&      getMatrixOrder                                  (void) const;
83         const std::string&      getMemberType                                   (void) const;
84         const std::string&      getMemberName                                   (void) const;
85         const std::string&      getMemberFixedArrayName                 (void) const;
86         const std::string&      getMemberVariableArray                  (void) const;
87         bool                            getMemberReorder                                (void) const;
88         int                                     getNumberMembers                                (void) const;
89
90         void                            resetValues                                             (void);
91
92         std::map<std::string, std::string>      populateArgsMap (void) const;
93
94 private:
95         std::string             m_negativeContextVersion;
96         std::string             m_stdFormat;
97         std::string             m_bindingPoint;
98         std::string             m_matrixOrder;
99         std::string             m_memberType;
100         std::string             m_memberName;
101         std::string             m_memberFixedArrayerName;
102         std::string             m_memberVariableArray;
103         bool                    m_memberReorder;
104         int                             m_numberMembers;
105         tcu::TestLog&   m_testLog;
106
107         void                    setDefaultValues                                        (void);
108 };
109
110 //constructor which ensure a proper context is passed into the struct
111 SsboArgs::SsboArgs(const std::string version, tcu::TestLog& log)
112         : m_negativeContextVersion      (version)
113         , m_numberMembers                       (8)
114         , m_testLog                                     (log)
115 {
116         setDefaultValues();
117 }
118
119 void SsboArgs::setSingleValue (const SsboArgData argData)
120 {
121         std::string message;
122
123         switch (argData.member)
124         {
125                 case ARGMEMBER_FORMAT:
126                         m_stdFormat                                     =       argData.data;
127                         return;
128                 case ARGMEMBER_BINDING_POINT:
129                         m_bindingPoint                          =       argData.data;
130                         return;
131                 case ARGMEMBER_MATRIX_ORDER:
132                         m_matrixOrder                           =       argData.data;
133                         return;
134                 case ARGMEMBER_MEMBER_TYPE:
135                         m_memberType                            =       argData.data;
136                         return;
137                 case ARGMEMBER_NAME:
138                         m_memberName                            =       argData.data;
139                         return;
140                 case ARGMEMBER_FIXED_ARRAY:
141                         m_memberFixedArrayerName        =       argData.data;
142                         return;
143                 case ARGMEMBER_VARIABLE_ARRAY:
144                         m_memberVariableArray           =       argData.data;
145                         return;
146                 case ARGMEMBER_REORDER:
147                         if (argData.data == "true")
148                         {
149                                 m_memberReorder                 =       true;
150                         }
151                         return;
152                 default:
153                         message = "auto loop argument data member not recognised.";
154                         m_testLog << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
155         }
156 }
157
158 bool SsboArgs::setAllValues (const std::vector<SsboArgData> argDataList)
159 {
160         std::string     message;
161
162         if ((argDataList.size() == 0) || (argDataList.size() > (size_t)m_numberMembers))
163         {
164                 message = "set of args does not match the number of args struct changeable members.";
165                 m_testLog << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
166
167                 return false;
168         }
169         else
170         {
171                 for (unsigned int idx = 0; idx < argDataList.size(); idx++)
172                 {
173                         setSingleValue(argDataList[idx]);
174                 }
175         }
176
177         return true;
178 }
179
180 const std::string& SsboArgs::getContextVersion (void) const
181 {
182         return m_negativeContextVersion;
183 }
184
185 const std::string& SsboArgs::getStdFormat (void) const
186 {
187         return m_stdFormat;
188 }
189
190 const std::string& SsboArgs::getBindingPoint (void) const
191 {
192         return m_bindingPoint;
193 }
194
195 const std::string& SsboArgs::getMatrixOrder (void) const
196 {
197         return m_matrixOrder;
198 }
199
200 const std::string& SsboArgs::getMemberType (void) const
201 {
202         return m_memberType;
203 }
204
205 const std::string& SsboArgs::getMemberName (void) const
206 {
207         return m_memberName;
208 }
209
210 const std::string& SsboArgs::getMemberFixedArrayName (void) const
211 {
212         return m_memberFixedArrayerName;
213 }
214
215 const std::string& SsboArgs::getMemberVariableArray (void) const
216 {
217         return m_memberVariableArray;
218 }
219
220 bool SsboArgs::getMemberReorder (void) const
221 {
222         return m_memberReorder;
223 }
224
225 int SsboArgs::getNumberMembers (void) const
226 {
227         return m_numberMembers;
228 }
229
230 void SsboArgs::resetValues (void)
231 {
232         setDefaultValues();
233 }
234
235 //converts SsboArgs member variable into a map object to be used by tcu::StringTemplate
236 std::map<std::string, std::string> SsboArgs::populateArgsMap (void) const
237 {
238         std::map<std::string, std::string> argsMap;
239
240         // key placeholders located at specific points in the ssbo block
241         argsMap["NEGATIVE_CONTEXT_VERSION"]     =       m_negativeContextVersion;
242         argsMap["STD_FORMAT"]                           =       m_stdFormat;
243         argsMap["BINDING_POINT"]                        =       m_bindingPoint;
244         argsMap["MATRIX_ORDER"]                         =       m_matrixOrder;
245         argsMap["MEMBER_TYPE"]                          =       m_memberType;
246         argsMap["MEMBER_NAME"]                          =       m_memberName;
247         argsMap["MEMBER_FIXED_ARRAY"]           =       m_memberFixedArrayerName;
248         argsMap["MEMBER_VARIABLE_ARRAY"]        =       m_memberVariableArray;
249
250         return argsMap;
251 }
252
253 // default values i.e. same shader template
254 void SsboArgs::setDefaultValues (void)
255 {
256         m_stdFormat                                     =       "std430";
257         m_bindingPoint                          =       "0";
258         m_matrixOrder                           =       "column_major";
259         m_memberType                            =       "int";
260         m_memberName                            =       "matrix";
261         m_memberFixedArrayerName        =       "10";
262         m_memberVariableArray           =       "";
263         m_memberReorder                         =       false;
264 }
265 } // args
266
267 std::string generateVaryingSSBOShader(const glw::GLenum shaderType, const args::SsboArgs& args, tcu::TestLog& log)
268 {
269         std::map<std::string, std::string>      argsMap;
270         std::ostringstream                                      source;
271         std::string                                                     sourceString;
272         std::stringstream                                       ssboString;
273         std::string                                                     message;
274
275         if (args.getMemberReorder())
276         {
277                 ssboString      << "    mediump vec4 array_1[${MEMBER_FIXED_ARRAY}];\n"
278                                         << "    highp mat4 ${MEMBER_NAME};\n"
279                                         << "    lowp ${MEMBER_TYPE} data;\n"
280                                         << "    mediump float array_2[${MEMBER_VARIABLE_ARRAY}];\n";
281         }
282         else
283         {
284                 ssboString      << "    lowp ${MEMBER_TYPE} data;\n"
285                                         << "    highp mat4 ${MEMBER_NAME};\n"
286                                         << "    mediump vec4 array_1[${MEMBER_FIXED_ARRAY}];\n"
287                                         << "    mediump float array_2[${MEMBER_VARIABLE_ARRAY}];\n";
288         }
289
290         argsMap = args.populateArgsMap();
291
292         switch (shaderType)
293         {
294                 case GL_VERTEX_SHADER:
295                 {
296                         source  << "${NEGATIVE_CONTEXT_VERSION}\n"
297                                         << "layout (location = 0) in highp vec4 position;\n"
298                                         << "layout (location = 1) in mediump vec4 colour;\n"
299                                         << "out mediump vec4 vertex_colour;\n"
300                                         << "layout (${STD_FORMAT}, binding = ${BINDING_POINT}, ${MATRIX_ORDER}) buffer ssbo_block\n"
301                                         << "{\n";
302
303                         source << ssboString.str();
304
305                         source  << "} ssbo;\n"
306                                         << "void main()\n"
307                                         << "{\n"
308                                         << "    mediump vec4 variable;\n"
309                                         << "    gl_Position = ssbo.${MEMBER_NAME} * position;\n"
310                                         << "    for (int idx = 0; idx < ${MEMBER_FIXED_ARRAY}; idx++)\n"
311                                         << "    {\n"
312                                         << "            variable += ssbo.array_1[idx];\n"
313                                         << "    }\n"
314                                         << "    vertex_colour = colour + variable;\n"
315                                         << "}\n";
316
317                         sourceString = source.str();
318                         sourceString = tcu::StringTemplate(sourceString).specialize(argsMap);
319
320                         return sourceString;
321                 }
322
323                 case GL_FRAGMENT_SHADER:
324                 {
325                         source  << "${NEGATIVE_CONTEXT_VERSION}\n"
326                                         << "in mediump vec4 vertex_colour;\n"
327                                         << "layout (location = 0) out mediump vec4 fragment_colour;\n"
328                                         << "layout (${STD_FORMAT}, binding = ${BINDING_POINT}, ${MATRIX_ORDER}) buffer ssbo_block\n"
329                                         << "{\n";
330
331                         source << ssboString.str();
332
333                         source  << "} ssbo;\n"
334                                         << "void main()\n"
335                                         << "{\n"
336                                         << "    mediump vec4 variable;\n"
337                                         << "    variable * ssbo.${MEMBER_NAME};\n"
338                                         << "    for (int idx = 0; idx < ${MEMBER_FIXED_ARRAY}; idx++)\n"
339                                         << "    {\n"
340                                         << "            variable += ssbo.array_1[idx];\n"
341                                         << "    }\n"
342                                         << "    fragment_colour = vertex_colour + variable;\n"
343                                         << "}\n";
344
345                         sourceString = source.str();
346                         sourceString = tcu::StringTemplate(sourceString).specialize(argsMap);
347
348                         return sourceString;
349                 }
350
351                 case GL_GEOMETRY_SHADER:
352                 {
353                         // TODO:
354                         return sourceString;
355                 }
356
357                 case GL_TESS_CONTROL_SHADER:
358                 {
359                         // TODO:
360                         return sourceString;
361                 }
362
363                 case GL_TESS_EVALUATION_SHADER:
364                 {
365                         // TODO:
366                         return sourceString;
367                 }
368
369                 case GL_COMPUTE_SHADER:
370                 {
371                         // TODO:
372                         return sourceString;
373                 }
374
375                 default:
376                 {
377                         message = "shader type not recognised.";
378                         log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
379                 }
380         }
381
382         return std::string();
383 }
384
385 void logProgramInfo(NegativeTestContext& ctx, GLint program)
386 {
387         GLint                   maxLength       =       0;
388         std::string             message;
389         tcu::TestLog&   log                     =       ctx.getLog();
390
391         ctx.glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
392
393         message = "Program log:";
394         log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
395
396         if (maxLength == 0)
397         {
398                 message = "No available info log.";
399                 log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
400                 return;
401         }
402
403         std::vector<GLchar> infoLog(maxLength);
404         ctx.glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
405
406         std::string programLogMessage(&infoLog[0], maxLength);
407         log << tcu::TestLog::Message << programLogMessage << tcu::TestLog::EndMessage;
408 }
409
410 void ssbo_block_matching(NegativeTestContext& ctx)
411 {
412         const bool                              isES32                                                                                                  =       contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
413         const glu::GLSLVersion  version                                                                                                 =       isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
414         tcu::TestLog&                   log                                                                                                             =       ctx.getLog();
415         std::string                             message;
416         std::string                             versionString(glu::getGLSLVersionDeclaration(version));
417         args::SsboArgs                  ssboArgs(versionString, log);
418         GLint                                   shaderVertexGL;
419         std::string                             shaderVertexString;
420         const char*                             shaderVertexCharPtr;
421
422         // List of arguments used to create varying ssbo objects in the fragment shader
423         const args::SsboArgData argDataArrayFrag[] = {  args::SsboArgData(args::ARGMEMBER_FORMAT,                       "std140"),
424                                                                                                         args::SsboArgData(args::ARGMEMBER_BINDING_POINT,        "10"),
425                                                                                                         args::SsboArgData(args::ARGMEMBER_MATRIX_ORDER,         "row_major"),
426                                                                                                         args::SsboArgData(args::ARGMEMBER_MEMBER_TYPE,          "vec2"),
427                                                                                                         args::SsboArgData(args::ARGMEMBER_NAME,                         "name_changed"),
428                                                                                                         args::SsboArgData(args::ARGMEMBER_FIXED_ARRAY,          "20"),
429                                                                                                         args::SsboArgData(args::ARGMEMBER_VARIABLE_ARRAY,       "5"),
430                                                                                                         args::SsboArgData(args::ARGMEMBER_REORDER,                      "true") };
431         std::vector<args::SsboArgData> argDataVectorFrag(argDataArrayFrag, argDataArrayFrag + sizeof(argDataArrayFrag) / sizeof(argDataArrayFrag[0]));
432
433         // create default vertex shader
434         shaderVertexString = generateVaryingSSBOShader(GL_VERTEX_SHADER, ssboArgs, log);
435         shaderVertexCharPtr = shaderVertexString.c_str();
436         shaderVertexGL = ctx.glCreateShader(GL_VERTEX_SHADER);
437
438         // log
439         message = shaderVertexString;
440         log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
441
442         // compile
443         ctx.glShaderSource(shaderVertexGL, 1, &shaderVertexCharPtr, DE_NULL);
444         ctx.glCompileShader(shaderVertexGL);
445
446         for (std::size_t idx = 0; idx < argDataVectorFrag.size(); ++idx)
447         {
448                 GLint                   linkStatus                              =       -1;
449                 GLint                   program;
450                 GLint                   shaderFragmentGL;
451                 std::string             shaderFragmentString;
452                 const char*             shaderFragmentCharPtr;
453
454                 ctx.beginSection("Multiple shaders created using SSBO's sharing the same name but not matching layouts");
455
456                 program = ctx.glCreateProgram();
457
458                 // reset args to default and make a single change
459                 ssboArgs.resetValues();
460                 ssboArgs.setSingleValue(argDataVectorFrag[idx]);
461
462                 // create fragment shader
463                 shaderFragmentString = generateVaryingSSBOShader(GL_FRAGMENT_SHADER, ssboArgs, log);
464                 shaderFragmentCharPtr = shaderFragmentString.c_str();
465                 shaderFragmentGL = ctx.glCreateShader(GL_FRAGMENT_SHADER);
466
467                 // log
468                 message = shaderFragmentString;
469                 log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
470
471                 // compile
472                 ctx.glShaderSource(shaderFragmentGL, 1, &shaderFragmentCharPtr, DE_NULL);
473                 ctx.glCompileShader(shaderFragmentGL);
474
475                 // attach shaders to program and attempt to link
476                 ctx.glAttachShader(program, shaderVertexGL);
477                 ctx.glAttachShader(program, shaderFragmentGL);
478                 ctx.glLinkProgram(program);
479                 ctx.glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
480
481                 logProgramInfo(ctx, program);
482
483                 if (linkStatus == GL_TRUE)
484                 {
485                         ctx.fail("Program should not have linked");
486                 }
487
488                 // clean up resources
489                 ctx.glDeleteShader(shaderFragmentGL);
490                 ctx.glDeleteProgram(program);
491
492                 ctx.endSection();
493         }
494
495         // clean up default resources
496         ctx.glDeleteShader(shaderVertexGL);
497 }
498
499 void ssbo_block_shared_qualifier(NegativeTestContext& ctx)
500 {
501         const bool                              isES32                                                                                                  =       contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
502         const glu::GLSLVersion  version                                                                                                 =       isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
503         tcu::TestLog&                   log                                                                                                             =       ctx.getLog();
504         std::string                             message;
505         std::string                             versionString(glu::getGLSLVersionDeclaration(version));
506         args::SsboArgs                  ssboArgs(versionString, log);
507         bool                                    result;
508         GLint                                   shaderVertexGL;
509         std::string                             shaderVertexString;
510         const char*                             shaderVertexCharPtr;
511
512         // default args used in vertex shader ssbo
513         const args::SsboArgData argDataArrayVert[] = {  args::SsboArgData(args::ARGMEMBER_FORMAT,                       "shared"),
514                                                                                                         args::SsboArgData(args::ARGMEMBER_BINDING_POINT,        "0"),
515                                                                                                         args::SsboArgData(args::ARGMEMBER_MATRIX_ORDER,         "column_major"),
516                                                                                                         args::SsboArgData(args::ARGMEMBER_FIXED_ARRAY,          "10"),
517                                                                                                         args::SsboArgData(args::ARGMEMBER_VARIABLE_ARRAY,       "10"),
518                                                                                                         args::SsboArgData(args::ARGMEMBER_REORDER,                      "false") };
519         std::vector<args::SsboArgData> argDataVectorVert(argDataArrayVert, argDataArrayVert + sizeof(argDataArrayVert) / sizeof(argDataArrayVert[0]));
520
521         // args changed in fragment shader ssbo
522         const args::SsboArgData argDataArrayFrag[] = {  args::SsboArgData(args::ARGMEMBER_MATRIX_ORDER,         "row_major"),
523                                                                                                         args::SsboArgData(args::ARGMEMBER_VARIABLE_ARRAY,       ""),
524                                                                                                         args::SsboArgData(args::ARGMEMBER_FIXED_ARRAY,          "20") };
525         std::vector<args::SsboArgData> argDataVectorFrag(argDataArrayFrag, argDataArrayFrag + sizeof(argDataArrayFrag) / sizeof(argDataArrayFrag[0]));
526
527         // set default vertex ssbo args
528         result = ssboArgs.setAllValues(argDataVectorVert);
529
530         if (result == false)
531         {
532                 message = "Invalid use of args.setAllValues()";
533                 log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
534                 return;
535         }
536
537         // create default vertex shader
538         shaderVertexString = generateVaryingSSBOShader(GL_VERTEX_SHADER, ssboArgs, log);
539         shaderVertexCharPtr = shaderVertexString.c_str();
540         shaderVertexGL = ctx.glCreateShader(GL_VERTEX_SHADER);
541
542         // log
543         message = shaderVertexString;
544         log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
545
546         // compile
547         ctx.glShaderSource(shaderVertexGL, 1, &shaderVertexCharPtr, DE_NULL);
548         ctx.glCompileShader(shaderVertexGL);
549
550         for (std::size_t idx = 0; idx < argDataVectorFrag.size(); idx++)
551         {
552                 GLint           linkStatus                              =       -1;
553                 GLint           program;
554                 GLint           shaderFragmentGL;
555                 std::string     shaderFragmentString;
556                 const char*     shaderFragmentCharPtr;
557
558                 ctx.beginSection("Multiple shaders created using SSBO's sharing the same name but not matching layouts");
559
560                 program = ctx.glCreateProgram();
561
562                 // reset args to default and make a single change
563                 ssboArgs.setAllValues(argDataVectorVert);
564                 ssboArgs.setSingleValue(argDataVectorFrag[idx]);
565
566                 // create fragment shader
567                 shaderFragmentString = generateVaryingSSBOShader(GL_FRAGMENT_SHADER, ssboArgs, log);
568                 shaderFragmentCharPtr = shaderFragmentString.c_str();
569                 shaderFragmentGL = ctx.glCreateShader(GL_FRAGMENT_SHADER);
570
571                 // log
572                 message = shaderFragmentString;
573                 log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
574
575                 // compile
576                 ctx.glShaderSource(shaderFragmentGL, 1, &shaderFragmentCharPtr, DE_NULL);
577                 ctx.glCompileShader(shaderFragmentGL);
578
579                 // attach shaders to the program and attempt to link
580                 ctx.glAttachShader(program, shaderVertexGL);
581                 ctx.glAttachShader(program, shaderFragmentGL);
582                 ctx.glLinkProgram(program);
583                 ctx.glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
584
585                 logProgramInfo(ctx, program);
586
587                 if (linkStatus == GL_TRUE)
588                 {
589                         ctx.fail("Program should not have linked");
590                 }
591
592                 // clean up resources
593                 ctx.glDeleteShader(shaderFragmentGL);
594                 ctx.glDeleteProgram(program);
595
596                 ctx.endSection();
597         }
598
599         // clean up default resources
600         ctx.glDeleteShader(shaderVertexGL);
601 }
602 } // anonymous
603
604 std::vector<FunctionContainer> getNegativeSSBOBlockTestFunctions (void)
605 {
606         const FunctionContainer funcs[] =
607         {
608                 { ssbo_block_matching,                  "ssbo_block_interface_matching_tests",  "Invalid Shader Linkage" },
609                 { ssbo_block_shared_qualifier,  "ssbo_using_shared_qualifier_tests",    "Invalid Shader Linkage" },
610         };
611
612         return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
613 }
614 } // NegativeTestShared
615 } //Functional
616 } //gles31
617 } //deqp