am c9843818: am 60ce86ed: Merge "Avoid leaking VAO in compute_interop tests." into...
[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 & log.
93         {
94                 int     compileStatus   = 0;
95                 int     infoLogLen              = 0;
96                 int     unusedLen;
97
98                 m_gl.getShaderiv(m_shader, GL_COMPILE_STATUS,           &compileStatus);
99                 m_gl.getShaderiv(m_shader, GL_INFO_LOG_LENGTH,  &infoLogLen);
100                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv()");
101
102                 m_info.compileOk = compileStatus != GL_FALSE;
103
104                 if (infoLogLen > 0)
105                 {
106                         std::vector<char> infoLog(infoLogLen);
107                         m_gl.getShaderInfoLog(m_shader, (int)infoLog.size(), &unusedLen, &infoLog[0]);
108                         m_info.infoLog = std::string(&infoLog[0], infoLogLen);
109                 }
110         }
111 }
112
113 // Program
114
115 static bool getProgramLinkStatus (const glw::Functions& gl, deUint32 program)
116 {
117         int     linkStatus                              = 0;
118
119         gl.getProgramiv(program, GL_LINK_STATUS, &linkStatus);
120         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv()");
121         return (linkStatus != GL_FALSE);
122 }
123
124 static std::string getProgramInfoLog (const glw::Functions& gl, deUint32 program)
125 {
126         int     infoLogLen      = 0;
127         int     unusedLen;
128
129         gl.getProgramiv(program, GL_INFO_LOG_LENGTH,    &infoLogLen);
130         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv()");
131
132         if (infoLogLen > 0)
133         {
134                 std::vector<char> infoLog(infoLogLen);
135                 gl.getProgramInfoLog(program, (int)infoLog.size(), &unusedLen, &infoLog[0]);
136                 return std::string(&infoLog[0], infoLogLen);
137         }
138         return std::string();
139 }
140
141 Program::Program (const RenderContext& renderCtx)
142         : m_gl          (renderCtx.getFunctions())
143         , m_program     (0)
144 {
145         m_program = m_gl.createProgram();
146         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateProgram()");
147 }
148
149 Program::Program (const glw::Functions& gl)
150         : m_gl          (gl)
151         , m_program     (0)
152 {
153         m_program = m_gl.createProgram();
154         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateProgram()");
155 }
156
157 Program::Program (const RenderContext& renderCtx, deUint32 program)
158         : m_gl          (renderCtx.getFunctions())
159         , m_program     (program)
160 {
161         m_info.linkOk   = getProgramLinkStatus(m_gl, program);
162         m_info.infoLog  = getProgramInfoLog(m_gl, program);
163 }
164
165 Program::~Program (void)
166 {
167         m_gl.deleteProgram(m_program);
168 }
169
170 void Program::attachShader (deUint32 shader)
171 {
172         m_gl.attachShader(m_program, shader);
173         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glAttachShader()");
174 }
175
176 void Program::detachShader (deUint32 shader)
177 {
178         m_gl.detachShader(m_program, shader);
179         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDetachShader()");
180 }
181
182 void Program::bindAttribLocation (deUint32 location, const char* name)
183 {
184         m_gl.bindAttribLocation(m_program, location, name);
185         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindAttribLocation()");
186 }
187
188 void Program::transformFeedbackVaryings (int count, const char* const* varyings, deUint32 bufferMode)
189 {
190         m_gl.transformFeedbackVaryings(m_program, count, varyings, bufferMode);
191         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTransformFeedbackVaryings()");
192 }
193
194 void Program::link (void)
195 {
196         m_info.linkOk           = false;
197         m_info.linkTimeUs       = 0;
198         m_info.infoLog.clear();
199
200         {
201                 deUint64 linkStart = deGetMicroseconds();
202                 m_gl.linkProgram(m_program);
203                 m_info.linkTimeUs = deGetMicroseconds() - linkStart;
204         }
205         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glLinkProgram()");
206
207         m_info.linkOk   = getProgramLinkStatus(m_gl, m_program);
208         m_info.infoLog  = getProgramInfoLog(m_gl, m_program);
209 }
210
211 bool Program::isSeparable (void) const
212 {
213         int separable = GL_FALSE;
214
215         m_gl.getProgramiv(m_program, GL_PROGRAM_SEPARABLE, &separable);
216         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetProgramiv()");
217
218         return (separable != GL_FALSE);
219 }
220
221 void Program::setSeparable (bool separable)
222 {
223         m_gl.programParameteri(m_program, GL_PROGRAM_SEPARABLE, separable);
224         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glProgramParameteri()");
225 }
226
227 // ProgramPipeline
228
229 ProgramPipeline::ProgramPipeline (const RenderContext& renderCtx)
230         : m_gl                  (renderCtx.getFunctions())
231         , m_pipeline    (0)
232 {
233         m_gl.genProgramPipelines(1, &m_pipeline);
234         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenProgramPipelines()");
235 }
236
237 ProgramPipeline::ProgramPipeline (const glw::Functions& gl)
238         : m_gl                  (gl)
239         , m_pipeline    (0)
240 {
241         m_gl.genProgramPipelines(1, &m_pipeline);
242         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenProgramPipelines()");
243 }
244
245 ProgramPipeline::~ProgramPipeline (void)
246 {
247         m_gl.deleteProgramPipelines(1, &m_pipeline);
248 }
249
250 void ProgramPipeline::useProgramStages (deUint32 stages, deUint32 program)
251 {
252         m_gl.useProgramStages(m_pipeline, stages, program);
253         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgramStages()");
254 }
255
256 void ProgramPipeline::activeShaderProgram (deUint32 program)
257 {
258         m_gl.activeShaderProgram(m_pipeline, program);
259         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glActiveShaderProgram()");
260 }
261
262 bool ProgramPipeline::isValid (void)
263 {
264         glw::GLint status = GL_FALSE;
265         m_gl.validateProgramPipeline(m_pipeline);
266         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glValidateProgramPipeline()");
267
268         m_gl.getProgramPipelineiv(m_pipeline, GL_VALIDATE_STATUS, &status);
269
270         return (status != GL_FALSE);
271 }
272
273 // ShaderProgram
274
275 ShaderProgram::ShaderProgram (const RenderContext& renderCtx, const ProgramSources& sources)
276         : m_program(renderCtx.getFunctions())
277 {
278         init(renderCtx.getFunctions(), sources);
279 }
280
281 ShaderProgram::ShaderProgram (const glw::Functions& gl, const ProgramSources& sources)
282         : m_program(gl)
283 {
284         init(gl, sources);
285 }
286
287 void ShaderProgram::init (const glw::Functions& gl, const ProgramSources& sources)
288 {
289         try
290         {
291                 bool shadersOk = true;
292
293                 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
294                 {
295                         for (int shaderNdx = 0; shaderNdx < (int)sources.sources[shaderType].size(); ++shaderNdx)
296                         {
297                                 const char* source      = sources.sources[shaderType][shaderNdx].c_str();
298                                 const int       length  = (int)sources.sources[shaderType][shaderNdx].size();
299
300                                 m_shaders[shaderType].reserve(m_shaders[shaderType].size() + 1);
301
302                                 m_shaders[shaderType].push_back(new Shader(gl, ShaderType(shaderType)));
303                                 m_shaders[shaderType].back()->setSources(1, &source, &length);
304                                 m_shaders[shaderType].back()->compile();
305
306                                 shadersOk = shadersOk && m_shaders[shaderType].back()->getCompileStatus();
307                         }
308                 }
309
310                 if (shadersOk)
311                 {
312                         for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
313                                 for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
314                                         m_program.attachShader(m_shaders[shaderType][shaderNdx]->getShader());
315
316                         for (std::vector<AttribLocationBinding>::const_iterator binding = sources.attribLocationBindings.begin(); binding != sources.attribLocationBindings.end(); ++binding)
317                                 m_program.bindAttribLocation(binding->location, binding->name.c_str());
318
319                         DE_ASSERT((sources.transformFeedbackBufferMode == GL_NONE) == sources.transformFeedbackVaryings.empty());
320                         if (sources.transformFeedbackBufferMode != GL_NONE)
321                         {
322                                 std::vector<const char*> tfVaryings(sources.transformFeedbackVaryings.size());
323                                 for (int ndx = 0; ndx < (int)tfVaryings.size(); ndx++)
324                                         tfVaryings[ndx] = sources.transformFeedbackVaryings[ndx].c_str();
325
326                                 m_program.transformFeedbackVaryings((int)tfVaryings.size(), &tfVaryings[0], sources.transformFeedbackBufferMode);
327                         }
328
329                         if (sources.separable)
330                                 m_program.setSeparable(true);
331
332                         m_program.link();
333                 }
334         }
335         catch (...)
336         {
337                 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
338                         for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
339                                 delete m_shaders[shaderType][shaderNdx];
340                 throw;
341         }
342 }
343
344 ShaderProgram::~ShaderProgram (void)
345 {
346         for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
347                 for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
348                         delete m_shaders[shaderType][shaderNdx];
349 }
350
351 // Utilities
352
353 deUint32 getGLShaderType (ShaderType shaderType)
354 {
355         static const deUint32 s_typeMap[] =
356         {
357                 GL_VERTEX_SHADER,
358                 GL_FRAGMENT_SHADER,
359                 GL_GEOMETRY_SHADER,
360                 GL_TESS_CONTROL_SHADER,
361                 GL_TESS_EVALUATION_SHADER,
362                 GL_COMPUTE_SHADER
363         };
364         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST);
365         DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap)));
366         return s_typeMap[shaderType];
367 }
368
369 deUint32 getGLShaderTypeBit (ShaderType shaderType)
370 {
371         static const deUint32 s_typebitMap[] =
372         {
373                 GL_VERTEX_SHADER_BIT,
374                 GL_FRAGMENT_SHADER_BIT,
375                 GL_GEOMETRY_SHADER_BIT,
376                 GL_TESS_CONTROL_SHADER_BIT,
377                 GL_TESS_EVALUATION_SHADER_BIT,
378                 GL_COMPUTE_SHADER_BIT
379         };
380         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typebitMap) == SHADERTYPE_LAST);
381         DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typebitMap)));
382         return s_typebitMap[shaderType];
383 }
384
385 qpShaderType getLogShaderType (ShaderType shaderType)
386 {
387         static const qpShaderType s_typeMap[] =
388         {
389                 QP_SHADER_TYPE_VERTEX,
390                 QP_SHADER_TYPE_FRAGMENT,
391                 QP_SHADER_TYPE_GEOMETRY,
392                 QP_SHADER_TYPE_TESS_CONTROL,
393                 QP_SHADER_TYPE_TESS_EVALUATION,
394                 QP_SHADER_TYPE_COMPUTE
395         };
396         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST);
397         DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap)));
398         return s_typeMap[shaderType];
399 }
400
401 static tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderInfo& shaderInfo)
402 {
403         return log << tcu::TestLog::Shader(getLogShaderType(shaderInfo.type), shaderInfo.source, shaderInfo.compileOk, shaderInfo.infoLog);
404 }
405
406 tcu::TestLog& operator<< (tcu::TestLog& log, const Shader& shader)
407 {
408         return log << tcu::TestLog::ShaderProgram(false, "Plain shader") << shader.getInfo() << tcu::TestLog::EndShaderProgram;
409 }
410
411 tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderProgram& program)
412 {
413         const ProgramInfo& progInfo = program.getProgramInfo();
414
415         log << tcu::TestLog::ShaderProgram(progInfo.linkOk, progInfo.infoLog);
416         try
417         {
418                 for (int shaderTypeNdx = 0; shaderTypeNdx < SHADERTYPE_LAST; shaderTypeNdx++)
419                 {
420                         const glu::ShaderType shaderType = (glu::ShaderType)shaderTypeNdx;
421
422                         for (int shaderNdx = 0; shaderNdx < program.getNumShaders(shaderType); ++shaderNdx)
423                                 log << program.getShaderInfo(shaderType, shaderNdx);
424                 }
425         }
426         catch (...)
427         {
428                 log << tcu::TestLog::EndShaderProgram;
429                 throw;
430         }
431         log << tcu::TestLog::EndShaderProgram;
432
433         // Write statistics.
434         {
435                 static const struct
436                 {
437                         const char*             name;
438                         const char*             description;
439                 } s_compileTimeDesc[] =
440                 {
441                         { "VertexCompileTime",                  "Vertex shader compile time"                                    },
442                         { "FragmentCompileTime",                "Fragment shader compile time"                                  },
443                         { "GeometryCompileTime",                "Geometry shader compile time"                                  },
444                         { "TessControlCompileTime",             "Tesselation control shader compile time"               },
445                         { "TessEvaluationCompileTime",  "Tesselation evaluation shader compile time"    },
446                         { "ComputeCompileTime",                 "Compute shader compile time"                                   },
447                 };
448                 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_compileTimeDesc) == SHADERTYPE_LAST);
449
450                 bool allShadersOk = true;
451
452                 for (int shaderTypeNdx = 0; shaderTypeNdx < SHADERTYPE_LAST; shaderTypeNdx++)
453                 {
454                         const glu::ShaderType shaderType = (glu::ShaderType)shaderTypeNdx;
455
456                         for (int shaderNdx = 0; shaderNdx < program.getNumShaders(shaderType); ++shaderNdx)
457                         {
458                                 const ShaderInfo& shaderInfo = program.getShaderInfo(shaderType, shaderNdx);
459                                 log << tcu::TestLog::Float(s_compileTimeDesc[shaderType].name, s_compileTimeDesc[shaderType].description, "ms", QP_KEY_TAG_TIME, (float)shaderInfo.compileTimeUs / 1000.0f);
460                                 allShadersOk = allShadersOk && shaderInfo.compileOk;
461                         }
462                 }
463
464                 if (allShadersOk)
465                         log << tcu::TestLog::Float("LinkTime", "Link time", "ms", QP_KEY_TAG_TIME, (float)progInfo.linkTimeUs / 1000.0f);
466         }
467
468         return log;
469 }
470
471 } // glu