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