am 1ec5f90c: (-s ours) am 2985717d: Remove negative linking tests from mustpass....
[platform/upstream/VK-GL-CTS.git] / framework / opengl / gluShaderProgram.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES Utilities
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 Wrapper for GL program object.
22  *//*--------------------------------------------------------------------*/
23
24 #include "gluShaderProgram.hpp"
25 #include "gluRenderContext.hpp"
26 #include "glwFunctions.hpp"
27 #include "glwEnums.hpp"
28 #include "tcuTestLog.hpp"
29 #include "deClock.h"
30
31 #include <cstring>
32
33 using std::string;
34
35 namespace glu
36 {
37
38 // Shader
39
40 Shader::Shader (const RenderContext& renderCtx, ShaderType shaderType)
41         : m_gl          (renderCtx.getFunctions())
42         , m_shader      (0)
43 {
44         m_info.type     = shaderType;
45         m_shader        = m_gl.createShader(getGLShaderType(shaderType));
46         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateShader()");
47         TCU_CHECK(m_shader);
48 }
49
50 Shader::Shader (const glw::Functions& gl, ShaderType shaderType)
51         : m_gl          (gl)
52         , m_shader      (0)
53 {
54         m_info.type     = shaderType;
55         m_shader        = m_gl.createShader(getGLShaderType(shaderType));
56         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateShader()");
57         TCU_CHECK(m_shader);
58 }
59
60 Shader::~Shader (void)
61 {
62         m_gl.deleteShader(m_shader);
63 }
64
65 void Shader::setSources (int numSourceStrings, const char* const* sourceStrings, const int* lengths)
66 {
67         m_gl.shaderSource(m_shader, numSourceStrings, sourceStrings, lengths);
68         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glShaderSource()");
69
70         m_info.source.clear();
71         for (int ndx = 0; ndx < numSourceStrings; ndx++)
72         {
73                 const size_t length = lengths && lengths[ndx] >= 0 ? lengths[ndx] : strlen(sourceStrings[ndx]);
74                 m_info.source += std::string(sourceStrings[ndx], length);
75         }
76 }
77
78 void Shader::compile (void)
79 {
80         m_info.compileOk                = false;
81         m_info.compileTimeUs    = 0;
82         m_info.infoLog.clear();
83
84         {
85                 deUint64 compileStart = deGetMicroseconds();
86                 m_gl.compileShader(m_shader);
87                 m_info.compileTimeUs = deGetMicroseconds() - compileStart;
88         }
89
90         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCompileShader()");
91
92         // Query status
93         {
94                 int compileStatus = 0;
95
96                 m_gl.getShaderiv(m_shader, GL_COMPILE_STATUS, &compileStatus);
97                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv()");
98
99                 m_info.compileOk = compileStatus != GL_FALSE;
100         }
101
102         // Query log
103         {
104                 int infoLogLen = 0;
105                 int unusedLen;
106
107                 m_gl.getShaderiv(m_shader, GL_INFO_LOG_LENGTH, &infoLogLen);
108                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv()");
109
110                 if (infoLogLen > 0)
111                 {
112                         // The INFO_LOG_LENGTH query and the buffer query implementations have
113                         // very commonly off-by-one errors. Try to work around these issues.
114
115                         // add tolerance for off-by-one in log length, buffer write, and for terminator
116                         std::vector<char> infoLog(infoLogLen + 3, '\0');
117
118                         // claim buf size is one smaller to protect from off-by-one writing over buffer bounds
119                         m_gl.getShaderInfoLog(m_shader, (int)infoLog.size() - 1, &unusedLen, &infoLog[0]);
120
121                         if (infoLog[(int)(infoLog.size()) - 1] != '\0')
122                         {
123                                 // return whole buffer if null terminator was overwritten
124                                 m_info.infoLog = std::string(&infoLog[0], infoLog.size());
125                         }
126                         else
127                         {
128                                 // read as C string. infoLog is guaranteed to be 0-terminated
129                                 m_info.infoLog = std::string(&infoLog[0]);
130                         }
131                 }
132         }
133 }
134
135 // Program
136
137 static bool getProgramLinkStatus (const glw::Functions& gl, deUint32 program)
138 {
139         int     linkStatus                              = 0;
140
141         gl.getProgramiv(program, GL_LINK_STATUS, &linkStatus);
142         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv()");
143         return (linkStatus != GL_FALSE);
144 }
145
146 static std::string getProgramInfoLog (const glw::Functions& gl, deUint32 program)
147 {
148         int infoLogLen = 0;
149         int unusedLen;
150
151         gl.getProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLen);
152         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv()");
153
154         if (infoLogLen > 0)
155         {
156                 // The INFO_LOG_LENGTH query and the buffer query implementations have
157                 // very commonly off-by-one errors. Try to work around these issues.
158
159                 // add tolerance for off-by-one in log length, buffer write, and for terminator
160                 std::vector<char> infoLog(infoLogLen + 3, '\0');
161
162                 // claim buf size is one smaller to protect from off-by-one writing over buffer bounds
163                 gl.getProgramInfoLog(program, (int)infoLog.size() - 1, &unusedLen, &infoLog[0]);
164
165                 // return whole buffer if null terminator was overwritten
166                 if (infoLog[(int)(infoLog.size()) - 1] != '\0')
167                         return std::string(&infoLog[0], infoLog.size());
168
169                 // read as C string. infoLog is guaranteed to be 0-terminated
170                 return std::string(&infoLog[0]);
171         }
172         return std::string();
173 }
174
175 Program::Program (const RenderContext& renderCtx)
176         : m_gl          (renderCtx.getFunctions())
177         , m_program     (0)
178 {
179         m_program = m_gl.createProgram();
180         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateProgram()");
181 }
182
183 Program::Program (const glw::Functions& gl)
184         : m_gl          (gl)
185         , m_program     (0)
186 {
187         m_program = m_gl.createProgram();
188         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateProgram()");
189 }
190
191 Program::Program (const RenderContext& renderCtx, deUint32 program)
192         : m_gl          (renderCtx.getFunctions())
193         , m_program     (program)
194 {
195         m_info.linkOk   = getProgramLinkStatus(m_gl, program);
196         m_info.infoLog  = getProgramInfoLog(m_gl, program);
197 }
198
199 Program::~Program (void)
200 {
201         m_gl.deleteProgram(m_program);
202 }
203
204 void Program::attachShader (deUint32 shader)
205 {
206         m_gl.attachShader(m_program, shader);
207         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glAttachShader()");
208 }
209
210 void Program::detachShader (deUint32 shader)
211 {
212         m_gl.detachShader(m_program, shader);
213         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDetachShader()");
214 }
215
216 void Program::bindAttribLocation (deUint32 location, const char* name)
217 {
218         m_gl.bindAttribLocation(m_program, location, name);
219         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindAttribLocation()");
220 }
221
222 void Program::transformFeedbackVaryings (int count, const char* const* varyings, deUint32 bufferMode)
223 {
224         m_gl.transformFeedbackVaryings(m_program, count, varyings, bufferMode);
225         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTransformFeedbackVaryings()");
226 }
227
228 void Program::link (void)
229 {
230         m_info.linkOk           = false;
231         m_info.linkTimeUs       = 0;
232         m_info.infoLog.clear();
233
234         {
235                 deUint64 linkStart = deGetMicroseconds();
236                 m_gl.linkProgram(m_program);
237                 m_info.linkTimeUs = deGetMicroseconds() - linkStart;
238         }
239         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glLinkProgram()");
240
241         m_info.linkOk   = getProgramLinkStatus(m_gl, m_program);
242         m_info.infoLog  = getProgramInfoLog(m_gl, m_program);
243 }
244
245 bool Program::isSeparable (void) const
246 {
247         int separable = GL_FALSE;
248
249         m_gl.getProgramiv(m_program, GL_PROGRAM_SEPARABLE, &separable);
250         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetProgramiv()");
251
252         return (separable != GL_FALSE);
253 }
254
255 void Program::setSeparable (bool separable)
256 {
257         m_gl.programParameteri(m_program, GL_PROGRAM_SEPARABLE, separable);
258         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glProgramParameteri()");
259 }
260
261 // ProgramPipeline
262
263 ProgramPipeline::ProgramPipeline (const RenderContext& renderCtx)
264         : m_gl                  (renderCtx.getFunctions())
265         , m_pipeline    (0)
266 {
267         m_gl.genProgramPipelines(1, &m_pipeline);
268         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenProgramPipelines()");
269 }
270
271 ProgramPipeline::ProgramPipeline (const glw::Functions& gl)
272         : m_gl                  (gl)
273         , m_pipeline    (0)
274 {
275         m_gl.genProgramPipelines(1, &m_pipeline);
276         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenProgramPipelines()");
277 }
278
279 ProgramPipeline::~ProgramPipeline (void)
280 {
281         m_gl.deleteProgramPipelines(1, &m_pipeline);
282 }
283
284 void ProgramPipeline::useProgramStages (deUint32 stages, deUint32 program)
285 {
286         m_gl.useProgramStages(m_pipeline, stages, program);
287         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgramStages()");
288 }
289
290 void ProgramPipeline::activeShaderProgram (deUint32 program)
291 {
292         m_gl.activeShaderProgram(m_pipeline, program);
293         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glActiveShaderProgram()");
294 }
295
296 bool ProgramPipeline::isValid (void)
297 {
298         glw::GLint status = GL_FALSE;
299         m_gl.validateProgramPipeline(m_pipeline);
300         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glValidateProgramPipeline()");
301
302         m_gl.getProgramPipelineiv(m_pipeline, GL_VALIDATE_STATUS, &status);
303
304         return (status != GL_FALSE);
305 }
306
307 // ShaderProgram
308
309 ShaderProgram::ShaderProgram (const RenderContext& renderCtx, const ProgramSources& sources)
310         : m_program(renderCtx.getFunctions())
311 {
312         init(renderCtx.getFunctions(), sources);
313 }
314
315 ShaderProgram::ShaderProgram (const glw::Functions& gl, const ProgramSources& sources)
316         : m_program(gl)
317 {
318         init(gl, sources);
319 }
320
321 void ShaderProgram::init (const glw::Functions& gl, const ProgramSources& sources)
322 {
323         try
324         {
325                 bool shadersOk = true;
326
327                 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
328                 {
329                         for (int shaderNdx = 0; shaderNdx < (int)sources.sources[shaderType].size(); ++shaderNdx)
330                         {
331                                 const char* source      = sources.sources[shaderType][shaderNdx].c_str();
332                                 const int       length  = (int)sources.sources[shaderType][shaderNdx].size();
333
334                                 m_shaders[shaderType].reserve(m_shaders[shaderType].size() + 1);
335
336                                 m_shaders[shaderType].push_back(new Shader(gl, ShaderType(shaderType)));
337                                 m_shaders[shaderType].back()->setSources(1, &source, &length);
338                                 m_shaders[shaderType].back()->compile();
339
340                                 shadersOk = shadersOk && m_shaders[shaderType].back()->getCompileStatus();
341                         }
342                 }
343
344                 if (shadersOk)
345                 {
346                         for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
347                                 for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
348                                         m_program.attachShader(m_shaders[shaderType][shaderNdx]->getShader());
349
350                         for (std::vector<AttribLocationBinding>::const_iterator binding = sources.attribLocationBindings.begin(); binding != sources.attribLocationBindings.end(); ++binding)
351                                 m_program.bindAttribLocation(binding->location, binding->name.c_str());
352
353                         DE_ASSERT((sources.transformFeedbackBufferMode == GL_NONE) == sources.transformFeedbackVaryings.empty());
354                         if (sources.transformFeedbackBufferMode != GL_NONE)
355                         {
356                                 std::vector<const char*> tfVaryings(sources.transformFeedbackVaryings.size());
357                                 for (int ndx = 0; ndx < (int)tfVaryings.size(); ndx++)
358                                         tfVaryings[ndx] = sources.transformFeedbackVaryings[ndx].c_str();
359
360                                 m_program.transformFeedbackVaryings((int)tfVaryings.size(), &tfVaryings[0], sources.transformFeedbackBufferMode);
361                         }
362
363                         if (sources.separable)
364                                 m_program.setSeparable(true);
365
366                         m_program.link();
367                 }
368         }
369         catch (...)
370         {
371                 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
372                         for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
373                                 delete m_shaders[shaderType][shaderNdx];
374                 throw;
375         }
376 }
377
378 ShaderProgram::~ShaderProgram (void)
379 {
380         for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
381                 for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
382                         delete m_shaders[shaderType][shaderNdx];
383 }
384
385 // Utilities
386
387 deUint32 getGLShaderType (ShaderType shaderType)
388 {
389         static const deUint32 s_typeMap[] =
390         {
391                 GL_VERTEX_SHADER,
392                 GL_FRAGMENT_SHADER,
393                 GL_GEOMETRY_SHADER,
394                 GL_TESS_CONTROL_SHADER,
395                 GL_TESS_EVALUATION_SHADER,
396                 GL_COMPUTE_SHADER
397         };
398         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST);
399         DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap)));
400         return s_typeMap[shaderType];
401 }
402
403 deUint32 getGLShaderTypeBit (ShaderType shaderType)
404 {
405         static const deUint32 s_typebitMap[] =
406         {
407                 GL_VERTEX_SHADER_BIT,
408                 GL_FRAGMENT_SHADER_BIT,
409                 GL_GEOMETRY_SHADER_BIT,
410                 GL_TESS_CONTROL_SHADER_BIT,
411                 GL_TESS_EVALUATION_SHADER_BIT,
412                 GL_COMPUTE_SHADER_BIT
413         };
414         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typebitMap) == SHADERTYPE_LAST);
415         DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typebitMap)));
416         return s_typebitMap[shaderType];
417 }
418
419 qpShaderType getLogShaderType (ShaderType shaderType)
420 {
421         static const qpShaderType s_typeMap[] =
422         {
423                 QP_SHADER_TYPE_VERTEX,
424                 QP_SHADER_TYPE_FRAGMENT,
425                 QP_SHADER_TYPE_GEOMETRY,
426                 QP_SHADER_TYPE_TESS_CONTROL,
427                 QP_SHADER_TYPE_TESS_EVALUATION,
428                 QP_SHADER_TYPE_COMPUTE
429         };
430         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST);
431         DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap)));
432         return s_typeMap[shaderType];
433 }
434
435 tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderInfo& shaderInfo)
436 {
437         return log << tcu::TestLog::Shader(getLogShaderType(shaderInfo.type), shaderInfo.source, shaderInfo.compileOk, shaderInfo.infoLog);
438 }
439
440 tcu::TestLog& operator<< (tcu::TestLog& log, const Shader& shader)
441 {
442         return log << tcu::TestLog::ShaderProgram(false, "Plain shader") << shader.getInfo() << tcu::TestLog::EndShaderProgram;
443 }
444
445 static void logShaderProgram (tcu::TestLog& log, const ProgramInfo& programInfo, size_t numShaders, const ShaderInfo* const* shaderInfos)
446 {
447         log << tcu::TestLog::ShaderProgram(programInfo.linkOk, programInfo.infoLog);
448         try
449         {
450                 for (size_t shaderNdx = 0; shaderNdx < numShaders; ++shaderNdx)
451                         log << *shaderInfos[shaderNdx];
452         }
453         catch (...)
454         {
455                 log << tcu::TestLog::EndShaderProgram;
456                 throw;
457         }
458         log << tcu::TestLog::EndShaderProgram;
459
460         // Write statistics.
461         {
462                 static const struct
463                 {
464                         const char*             name;
465                         const char*             description;
466                 } s_compileTimeDesc[] =
467                 {
468                         { "VertexCompileTime",                  "Vertex shader compile time"                                    },
469                         { "FragmentCompileTime",                "Fragment shader compile time"                                  },
470                         { "GeometryCompileTime",                "Geometry shader compile time"                                  },
471                         { "TessControlCompileTime",             "Tesselation control shader compile time"               },
472                         { "TessEvaluationCompileTime",  "Tesselation evaluation shader compile time"    },
473                         { "ComputeCompileTime",                 "Compute shader compile time"                                   },
474                 };
475                 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_compileTimeDesc) == SHADERTYPE_LAST);
476
477                 bool allShadersOk = true;
478
479                 for (size_t shaderNdx = 0; shaderNdx < numShaders; ++shaderNdx)
480                 {
481                         const ShaderInfo&       shaderInfo      = *shaderInfos[shaderNdx];
482
483                         log << tcu::TestLog::Float(s_compileTimeDesc[shaderInfo.type].name,
484                                                                            s_compileTimeDesc[shaderInfo.type].description,
485                                                                            "ms", QP_KEY_TAG_TIME, (float)shaderInfo.compileTimeUs / 1000.0f);
486
487                         allShadersOk = allShadersOk && shaderInfo.compileOk;
488                 }
489
490                 if (allShadersOk)
491                         log << tcu::TestLog::Float("LinkTime", "Link time", "ms", QP_KEY_TAG_TIME, (float)programInfo.linkTimeUs / 1000.0f);
492         }
493 }
494
495 tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderProgramInfo& shaderProgramInfo)
496 {
497         std::vector<const ShaderInfo*>  shaderPtrs      (shaderProgramInfo.shaders.size());
498
499         for (size_t ndx = 0; ndx < shaderPtrs.size(); ndx++)
500                 shaderPtrs[ndx] = &shaderProgramInfo.shaders[ndx];
501
502         logShaderProgram(log, shaderProgramInfo.program, shaderPtrs.size(), shaderPtrs.empty() ? DE_NULL : &shaderPtrs[0]);
503
504         return log;
505 }
506
507 tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderProgram& shaderProgram)
508 {
509         std::vector<const ShaderInfo*>  shaderPtrs;
510
511         for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
512         {
513                 for (int shaderNdx = 0; shaderNdx < shaderProgram.getNumShaders((ShaderType)shaderType); shaderNdx++)
514                         shaderPtrs.push_back(&shaderProgram.getShaderInfo((ShaderType)shaderType, shaderNdx));
515         }
516
517         logShaderProgram(log, shaderProgram.getProgramInfo(), shaderPtrs.size(), shaderPtrs.empty() ? DE_NULL : &shaderPtrs[0]);
518
519         return log;
520 }
521
522 tcu::TestLog& operator<< (tcu::TestLog& log, const ProgramSources& sources)
523 {
524         log << tcu::TestLog::ShaderProgram(false, "(Source only)");
525
526         try
527         {
528                 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
529                 {
530                         for (size_t shaderNdx = 0; shaderNdx < sources.sources[shaderType].size(); shaderNdx++)
531                         {
532                                 log << tcu::TestLog::Shader(getLogShaderType((ShaderType)shaderType),
533                                                                                         sources.sources[shaderType][shaderNdx],
534                                                                                         false, "");
535                         }
536                 }
537         }
538         catch (...)
539         {
540                 log << tcu::TestLog::EndShaderProgram;
541                 throw;
542         }
543
544         log << tcu::TestLog::EndShaderProgram;
545
546         return log;
547 }
548
549 } // glu