1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // ShaderGL.cpp: Implements the class methods for ShaderGL.
8
9 #include "libANGLE/renderer/gl/ShaderGL.h"
10
11 #include "common/debug.h"
12 #include "libANGLE/Compiler.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/renderer/gl/FunctionsGL.h"
15 #include "libANGLE/renderer/gl/RendererGL.h"
16 #include "platform/FeaturesGL.h"
17
18 #include <iostream>
19
20 namespace rx
21 {
22
23 using CompileAndCheckShaderInWorkerFunctor = std::function<bool(const char *source)>;
24 class TranslateTaskGL : public angle::Closure
25 {
26 public:
TranslateTaskGL(ShHandle handle,ShCompileOptions options,const std::string & source,CompileAndCheckShaderInWorkerFunctor && compileAndCheckShaderInWorkerFunctor)27 TranslateTaskGL(ShHandle handle,
28 ShCompileOptions options,
29 const std::string &source,
30 CompileAndCheckShaderInWorkerFunctor &&compileAndCheckShaderInWorkerFunctor)
31 : mHandle(handle),
32 mOptions(options),
33 mSource(source),
34 mCompileAndCheckShaderInWorkerFunctor(std::move(compileAndCheckShaderInWorkerFunctor)),
35 mResult(false),
36 mWorkerAvailable(true)
37 {}
38
operator ()()39 void operator()() override
40 {
41 const char *source = mSource.c_str();
42 mResult = sh::Compile(mHandle, &source, 1, mOptions);
43 if (mResult)
44 {
45 mWorkerAvailable =
46 mCompileAndCheckShaderInWorkerFunctor(sh::GetObjectCode(mHandle).c_str());
47 }
48 }
49
getResult()50 bool getResult() { return mResult; }
51
workerAvailable()52 bool workerAvailable() { return mWorkerAvailable; }
53
getHandle()54 ShHandle getHandle() { return mHandle; }
55
56 private:
57 ShHandle mHandle;
58 ShCompileOptions mOptions;
59 std::string mSource;
60 CompileAndCheckShaderInWorkerFunctor mCompileAndCheckShaderInWorkerFunctor;
61 bool mResult;
62 bool mWorkerAvailable;
63 };
64
65 using PostTranslateFunctor = std::function<bool(std::string *infoLog)>;
66 using CompileAndCheckShaderFunctor = std::function<void(const char *source)>;
67 class WaitableCompileEventWorkerContext final : public WaitableCompileEvent
68 {
69 public:
WaitableCompileEventWorkerContext(std::shared_ptr<angle::WaitableEvent> waitableEvent,CompileAndCheckShaderFunctor && compileAndCheckShaderFunctor,PostTranslateFunctor && postTranslateFunctor,std::shared_ptr<TranslateTaskGL> translateTask)70 WaitableCompileEventWorkerContext(std::shared_ptr<angle::WaitableEvent> waitableEvent,
71 CompileAndCheckShaderFunctor &&compileAndCheckShaderFunctor,
72 PostTranslateFunctor &&postTranslateFunctor,
73 std::shared_ptr<TranslateTaskGL> translateTask)
74 : WaitableCompileEvent(waitableEvent),
75 mCompileAndCheckShaderFunctor(std::move(compileAndCheckShaderFunctor)),
76 mPostTranslateFunctor(std::move(postTranslateFunctor)),
77 mTranslateTask(translateTask)
78 {}
79
getResult()80 bool getResult() override { return mTranslateTask->getResult(); }
81
postTranslate(std::string * infoLog)82 bool postTranslate(std::string *infoLog) override
83 {
84 if (!mTranslateTask->workerAvailable())
85 {
86 ShHandle handle = mTranslateTask->getHandle();
87 mCompileAndCheckShaderFunctor(sh::GetObjectCode(handle).c_str());
88 }
89 return mPostTranslateFunctor(infoLog);
90 }
91
92 private:
93 CompileAndCheckShaderFunctor mCompileAndCheckShaderFunctor;
94 PostTranslateFunctor mPostTranslateFunctor;
95 std::shared_ptr<TranslateTaskGL> mTranslateTask;
96 };
97
98 using PeekCompletionFunctor = std::function<bool()>;
99 using CheckShaderFunctor = std::function<void()>;
100
101 class WaitableCompileEventNativeParallel final : public WaitableCompileEvent
102 {
103 public:
WaitableCompileEventNativeParallel(PostTranslateFunctor && postTranslateFunctor,bool result,CheckShaderFunctor && checkShaderFunctor,PeekCompletionFunctor && peekCompletionFunctor)104 WaitableCompileEventNativeParallel(PostTranslateFunctor &&postTranslateFunctor,
105 bool result,
106 CheckShaderFunctor &&checkShaderFunctor,
107 PeekCompletionFunctor &&peekCompletionFunctor)
108 : WaitableCompileEvent(std::shared_ptr<angle::WaitableEventDone>()),
109 mPostTranslateFunctor(std::move(postTranslateFunctor)),
110 mResult(result),
111 mCheckShaderFunctor(std::move(checkShaderFunctor)),
112 mPeekCompletionFunctor(std::move(peekCompletionFunctor))
113 {}
114
wait()115 void wait() override { mCheckShaderFunctor(); }
116
isReady()117 bool isReady() override { return mPeekCompletionFunctor(); }
118
getResult()119 bool getResult() override { return mResult; }
120
postTranslate(std::string * infoLog)121 bool postTranslate(std::string *infoLog) override { return mPostTranslateFunctor(infoLog); }
122
123 private:
124 PostTranslateFunctor mPostTranslateFunctor;
125 bool mResult;
126 CheckShaderFunctor mCheckShaderFunctor;
127 PeekCompletionFunctor mPeekCompletionFunctor;
128 };
129
130 class WaitableCompileEventDone final : public WaitableCompileEvent
131 {
132 public:
WaitableCompileEventDone(PostTranslateFunctor && postTranslateFunctor,bool result)133 WaitableCompileEventDone(PostTranslateFunctor &&postTranslateFunctor, bool result)
134 : WaitableCompileEvent(std::make_shared<angle::WaitableEventDone>()),
135 mPostTranslateFunctor(std::move(postTranslateFunctor)),
136 mResult(result)
137 {}
138
getResult()139 bool getResult() override { return mResult; }
140
postTranslate(std::string * infoLog)141 bool postTranslate(std::string *infoLog) override { return mPostTranslateFunctor(infoLog); }
142
143 private:
144 PostTranslateFunctor mPostTranslateFunctor;
145 bool mResult;
146 };
147
ShaderGL(const gl::ShaderState & data,GLuint shaderID,MultiviewImplementationTypeGL multiviewImplementationType,const std::shared_ptr<RendererGL> & renderer)148 ShaderGL::ShaderGL(const gl::ShaderState &data,
149 GLuint shaderID,
150 MultiviewImplementationTypeGL multiviewImplementationType,
151 const std::shared_ptr<RendererGL> &renderer)
152 : ShaderImpl(data),
153 mShaderID(shaderID),
154 mMultiviewImplementationType(multiviewImplementationType),
155 mRenderer(renderer),
156 mCompileStatus(GL_FALSE)
157 {}
158
~ShaderGL()159 ShaderGL::~ShaderGL()
160 {
161 ASSERT(mShaderID == 0);
162 }
163
destroy()164 void ShaderGL::destroy()
165 {
166 mRenderer->getFunctions()->deleteShader(mShaderID);
167 mShaderID = 0;
168 }
169
compileAndCheckShader(const char * source)170 void ShaderGL::compileAndCheckShader(const char *source)
171 {
172 compileShader(source);
173 checkShader();
174 }
175
compileShader(const char * source)176 void ShaderGL::compileShader(const char *source)
177 {
178 const FunctionsGL *functions = mRenderer->getFunctions();
179 functions->shaderSource(mShaderID, 1, &source, nullptr);
180 functions->compileShader(mShaderID);
181 }
182
checkShader()183 void ShaderGL::checkShader()
184 {
185 const FunctionsGL *functions = mRenderer->getFunctions();
186
187 // Check for compile errors from the native driver
188 mCompileStatus = GL_FALSE;
189 functions->getShaderiv(mShaderID, GL_COMPILE_STATUS, &mCompileStatus);
190 if (mCompileStatus == GL_FALSE)
191 {
192 // Compilation failed, put the error into the info log
193 GLint infoLogLength = 0;
194 functions->getShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
195
196 // Info log length includes the null terminator, so 1 means that the info log is an empty
197 // string.
198 if (infoLogLength > 1)
199 {
200 std::vector<char> buf(infoLogLength);
201 functions->getShaderInfoLog(mShaderID, infoLogLength, nullptr, &buf[0]);
202
203 mInfoLog += &buf[0];
204 WARN() << std::endl << mInfoLog;
205 }
206 else
207 {
208 WARN() << std::endl << "Shader compilation failed with no info log.";
209 }
210 }
211 }
212
peekCompletion()213 bool ShaderGL::peekCompletion()
214 {
215 const FunctionsGL *functions = mRenderer->getFunctions();
216 GLint status = GL_FALSE;
217 functions->getShaderiv(mShaderID, GL_COMPLETION_STATUS, &status);
218 return status == GL_TRUE;
219 }
220
compileAndCheckShaderInWorker(const char * source)221 bool ShaderGL::compileAndCheckShaderInWorker(const char *source)
222 {
223 std::string workerInfoLog;
224 ScopedWorkerContextGL worker(mRenderer.get(), &workerInfoLog);
225 if (worker())
226 {
227 compileAndCheckShader(source);
228 return true;
229 }
230 else
231 {
232 #if !defined(NDEBUG)
233 mInfoLog += "bindWorkerContext failed.\n" + workerInfoLog;
234 #endif
235 return false;
236 }
237 }
238
compile(const gl::Context * context,gl::ShCompilerInstance * compilerInstance,ShCompileOptions options)239 std::shared_ptr<WaitableCompileEvent> ShaderGL::compile(const gl::Context *context,
240 gl::ShCompilerInstance *compilerInstance,
241 ShCompileOptions options)
242 {
243 mInfoLog.clear();
244
245 ShCompileOptions additionalOptions = SH_INIT_GL_POSITION;
246
247 bool isWebGL = context->getExtensions().webglCompatibility;
248 if (isWebGL && (mData.getShaderType() != gl::ShaderType::Compute))
249 {
250 additionalOptions |= SH_INIT_OUTPUT_VARIABLES;
251 }
252
253 if (isWebGL && !context->getState().getEnableFeature(GL_TEXTURE_RECTANGLE_ANGLE))
254 {
255 additionalOptions |= SH_DISABLE_ARB_TEXTURE_RECTANGLE;
256 }
257
258 const angle::FeaturesGL &features = GetFeaturesGL(context);
259
260 if (features.doWhileGLSLCausesGPUHang.enabled)
261 {
262 additionalOptions |= SH_REWRITE_DO_WHILE_LOOPS;
263 }
264
265 if (features.emulateAbsIntFunction.enabled)
266 {
267 additionalOptions |= SH_EMULATE_ABS_INT_FUNCTION;
268 }
269
270 if (features.addAndTrueToLoopCondition.enabled)
271 {
272 additionalOptions |= SH_ADD_AND_TRUE_TO_LOOP_CONDITION;
273 }
274
275 if (features.emulateIsnanFloat.enabled)
276 {
277 additionalOptions |= SH_EMULATE_ISNAN_FLOAT_FUNCTION;
278 }
279
280 if (features.emulateAtan2Float.enabled)
281 {
282 additionalOptions |= SH_EMULATE_ATAN2_FLOAT_FUNCTION;
283 }
284
285 if (features.useUnusedBlocksWithStandardOrSharedLayout.enabled)
286 {
287 additionalOptions |= SH_USE_UNUSED_STANDARD_SHARED_BLOCKS;
288 }
289
290 if (features.removeInvariantAndCentroidForESSL3.enabled)
291 {
292 additionalOptions |= SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3;
293 }
294
295 if (features.rewriteFloatUnaryMinusOperator.enabled)
296 {
297 additionalOptions |= SH_REWRITE_FLOAT_UNARY_MINUS_OPERATOR;
298 }
299
300 if (!features.dontInitializeUninitializedLocals.enabled)
301 {
302 additionalOptions |= SH_INITIALIZE_UNINITIALIZED_LOCALS;
303 }
304
305 if (features.clampPointSize.enabled)
306 {
307 additionalOptions |= SH_CLAMP_POINT_SIZE;
308 }
309
310 if (features.rewriteVectorScalarArithmetic.enabled)
311 {
312 additionalOptions |= SH_REWRITE_VECTOR_SCALAR_ARITHMETIC;
313 }
314
315 if (features.dontUseLoopsToInitializeVariables.enabled)
316 {
317 additionalOptions |= SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES;
318 }
319
320 if (features.clampFragDepth.enabled)
321 {
322 additionalOptions |= SH_CLAMP_FRAG_DEPTH;
323 }
324
325 if (features.rewriteRepeatedAssignToSwizzled.enabled)
326 {
327 additionalOptions |= SH_REWRITE_REPEATED_ASSIGN_TO_SWIZZLED;
328 }
329
330 if (mMultiviewImplementationType == MultiviewImplementationTypeGL::NV_VIEWPORT_ARRAY2)
331 {
332 additionalOptions |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW;
333 additionalOptions |= SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER;
334 }
335
336 if (features.clampArrayAccess.enabled || isWebGL)
337 {
338 additionalOptions |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
339 }
340
341 if (features.addBaseVertexToVertexID.enabled)
342 {
343 additionalOptions |= SH_ADD_BASE_VERTEX_TO_VERTEX_ID;
344 }
345
346 if (features.unfoldShortCircuits.enabled)
347 {
348 additionalOptions |= SH_UNFOLD_SHORT_CIRCUIT;
349 }
350
351 if (features.removeDynamicIndexingOfSwizzledVector.enabled)
352 {
353 additionalOptions |= SH_REMOVE_DYNAMIC_INDEXING_OF_SWIZZLED_VECTOR;
354 }
355
356 if (features.preAddTexelFetchOffsets.enabled)
357 {
358 additionalOptions |= SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH;
359 }
360
361 if (features.regenerateStructNames.enabled)
362 {
363 additionalOptions |= SH_REGENERATE_STRUCT_NAMES;
364 }
365
366 if (features.rewriteRowMajorMatrices.enabled)
367 {
368 additionalOptions |= SH_REWRITE_ROW_MAJOR_MATRICES;
369 }
370
371 options |= additionalOptions;
372
373 auto workerThreadPool = context->getWorkerThreadPool();
374
375 const std::string &source = mData.getSource();
376
377 auto postTranslateFunctor = [this](std::string *infoLog) {
378 if (mCompileStatus == GL_FALSE)
379 {
380 *infoLog = mInfoLog;
381 return false;
382 }
383 return true;
384 };
385
386 if (mRenderer->hasNativeParallelCompile())
387 {
388 ShHandle handle = compilerInstance->getHandle();
389 const char *str = source.c_str();
390 bool result = sh::Compile(handle, &str, 1, options);
391 if (result)
392 {
393 compileShader(sh::GetObjectCode(handle).c_str());
394 auto checkShaderFunctor = [this]() { checkShader(); };
395 auto peekCompletionFunctor = [this]() { return peekCompletion(); };
396 return std::make_shared<WaitableCompileEventNativeParallel>(
397 std::move(postTranslateFunctor), result, std::move(checkShaderFunctor),
398 std::move(peekCompletionFunctor));
399 }
400 else
401 {
402 return std::make_shared<WaitableCompileEventDone>([](std::string *) { return true; },
403 result);
404 }
405 }
406 else if (workerThreadPool->isAsync())
407 {
408 auto compileAndCheckShaderInWorkerFunctor = [this](const char *source) {
409 return compileAndCheckShaderInWorker(source);
410 };
411 auto translateTask =
412 std::make_shared<TranslateTaskGL>(compilerInstance->getHandle(), options, source,
413 std::move(compileAndCheckShaderInWorkerFunctor));
414
415 auto compileAndCheckShaderFunctor = [this](const char *source) {
416 compileAndCheckShader(source);
417 };
418 return std::make_shared<WaitableCompileEventWorkerContext>(
419 angle::WorkerThreadPool::PostWorkerTask(workerThreadPool, translateTask),
420 std::move(compileAndCheckShaderFunctor), std::move(postTranslateFunctor),
421 translateTask);
422 }
423 else
424 {
425 ShHandle handle = compilerInstance->getHandle();
426 const char *str = source.c_str();
427 bool result = sh::Compile(handle, &str, 1, options);
428 if (result)
429 {
430 compileAndCheckShader(sh::GetObjectCode(handle).c_str());
431 }
432 return std::make_shared<WaitableCompileEventDone>(std::move(postTranslateFunctor), result);
433 }
434 }
435
getDebugInfo() const436 std::string ShaderGL::getDebugInfo() const
437 {
438 return mData.getTranslatedSource();
439 }
440
getShaderID() const441 GLuint ShaderGL::getShaderID() const
442 {
443 return mShaderID;
444 }
445
446 } // namespace rx
447