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 // RendererGL.cpp: Implements the class methods for RendererGL.
8
9 #include "libANGLE/renderer/gl/RendererGL.h"
10
11 #include <EGL/eglext.h>
12
13 #include "common/debug.h"
14 #include "libANGLE/AttributeMap.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/Display.h"
17 #include "libANGLE/State.h"
18 #include "libANGLE/Surface.h"
19 #include "libANGLE/renderer/gl/BlitGL.h"
20 #include "libANGLE/renderer/gl/BufferGL.h"
21 #include "libANGLE/renderer/gl/ClearMultiviewGL.h"
22 #include "libANGLE/renderer/gl/CompilerGL.h"
23 #include "libANGLE/renderer/gl/ContextGL.h"
24 #include "libANGLE/renderer/gl/DisplayGL.h"
25 #include "libANGLE/renderer/gl/FenceNVGL.h"
26 #include "libANGLE/renderer/gl/FramebufferGL.h"
27 #include "libANGLE/renderer/gl/FunctionsGL.h"
28 #include "libANGLE/renderer/gl/ProgramGL.h"
29 #include "libANGLE/renderer/gl/QueryGL.h"
30 #include "libANGLE/renderer/gl/RenderbufferGL.h"
31 #include "libANGLE/renderer/gl/SamplerGL.h"
32 #include "libANGLE/renderer/gl/ShaderGL.h"
33 #include "libANGLE/renderer/gl/StateManagerGL.h"
34 #include "libANGLE/renderer/gl/SurfaceGL.h"
35 #include "libANGLE/renderer/gl/SyncGL.h"
36 #include "libANGLE/renderer/gl/TextureGL.h"
37 #include "libANGLE/renderer/gl/TransformFeedbackGL.h"
38 #include "libANGLE/renderer/gl/VertexArrayGL.h"
39 #include "libANGLE/renderer/gl/renderergl_utils.h"
40 #include "libANGLE/renderer/renderer_utils.h"
41
42 namespace
43 {
44
SetMaxShaderCompilerThreads(const rx::FunctionsGL * functions,GLuint count)45 void SetMaxShaderCompilerThreads(const rx::FunctionsGL *functions, GLuint count)
46 {
47 if (functions->maxShaderCompilerThreadsKHR != nullptr)
48 {
49 functions->maxShaderCompilerThreadsKHR(count);
50 }
51 else
52 {
53 ASSERT(functions->maxShaderCompilerThreadsARB != nullptr);
54 functions->maxShaderCompilerThreadsARB(count);
55 }
56 }
57
58 #if defined(ANGLE_PLATFORM_ANDROID)
59 const char *kIgnoredErrors[] = {
60 // Wrong error message on Android Q Pixel 2. http://anglebug.com/3491
61 "FreeAllocationOnTimestamp - Reference to buffer created from "
62 "different context without a share list. Application failed to pass "
63 "share_context to eglCreateContext. Results are undefined.",
64 };
65 #endif // defined(ANGLE_PLATFORM_ANDROID)
66
67 const char *kIgnoredWarnings[] = {
68 // We always request GL_ARB_gpu_shader5 and GL_EXT_gpu_shader5 when compiling shaders but some
69 // drivers warn when it is not present. This ends up spamming the console on every shader
70 // compile.
71 "extension `GL_ARB_gpu_shader5' unsupported in",
72 "extension `GL_EXT_gpu_shader5' unsupported in",
73 };
74
75 } // namespace
76
LogGLDebugMessage(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,const void * userParam)77 static void INTERNAL_GL_APIENTRY LogGLDebugMessage(GLenum source,
78 GLenum type,
79 GLuint id,
80 GLenum severity,
81 GLsizei length,
82 const GLchar *message,
83 const void *userParam)
84 {
85 std::string sourceText = gl::GetDebugMessageSourceString(source);
86 std::string typeText = gl::GetDebugMessageTypeString(type);
87 std::string severityText = gl::GetDebugMessageSeverityString(severity);
88
89 #if defined(ANGLE_PLATFORM_ANDROID)
90 if (type == GL_DEBUG_TYPE_ERROR)
91 {
92 for (const char *&err : kIgnoredErrors)
93 {
94 if (strncmp(err, message, length) == 0)
95 {
96 // There is only one ignored message right now and it is quite spammy, around 3MB
97 // for a complete end2end tests run, so don't print it even as a warning.
98 return;
99 }
100 }
101 }
102 #endif // defined(ANGLE_PLATFORM_ANDROID)
103
104 if (type == GL_DEBUG_TYPE_ERROR)
105 {
106 ERR() << std::endl
107 << "\tSource: " << sourceText << std::endl
108 << "\tType: " << typeText << std::endl
109 << "\tID: " << gl::FmtHex(id) << std::endl
110 << "\tSeverity: " << severityText << std::endl
111 << "\tMessage: " << message;
112 }
113 else if (type != GL_DEBUG_TYPE_PERFORMANCE)
114 {
115 // Don't print performance warnings. They tend to be very spammy in the dEQP test suite and
116 // there is very little we can do about them.
117
118 for (const char *&warn : kIgnoredWarnings)
119 {
120 if (strstr(message, warn) != nullptr)
121 {
122 return;
123 }
124 }
125
126 // TODO(ynovikov): filter into WARN and INFO if INFO is ever implemented
127 WARN() << std::endl
128 << "\tSource: " << sourceText << std::endl
129 << "\tType: " << typeText << std::endl
130 << "\tID: " << gl::FmtHex(id) << std::endl
131 << "\tSeverity: " << severityText << std::endl
132 << "\tMessage: " << message;
133 }
134 }
135
136 namespace rx
137 {
138
RendererGL(std::unique_ptr<FunctionsGL> functions,const egl::AttributeMap & attribMap,DisplayGL * display)139 RendererGL::RendererGL(std::unique_ptr<FunctionsGL> functions,
140 const egl::AttributeMap &attribMap,
141 DisplayGL *display)
142 : mMaxSupportedESVersion(0, 0),
143 mFunctions(std::move(functions)),
144 mStateManager(nullptr),
145 mBlitter(nullptr),
146 mMultiviewClearer(nullptr),
147 mUseDebugOutput(false),
148 mCapsInitialized(false),
149 mMultiviewImplementationType(MultiviewImplementationTypeGL::UNSPECIFIED),
150 mNativeParallelCompileEnabled(false),
151 mNeedsFlushBeforeDeleteTextures(false)
152 {
153 ASSERT(mFunctions);
154 if (!display->getState().featuresAllDisabled)
155 {
156 nativegl_gl::InitializeFeatures(mFunctions.get(), &mFeatures);
157 }
158 ApplyFeatureOverrides(&mFeatures, display->getState());
159 mStateManager =
160 new StateManagerGL(mFunctions.get(), getNativeCaps(), getNativeExtensions(), mFeatures);
161 mBlitter = new BlitGL(mFunctions.get(), mFeatures, mStateManager);
162 mMultiviewClearer = new ClearMultiviewGL(mFunctions.get(), mStateManager);
163
164 bool hasDebugOutput = mFunctions->isAtLeastGL(gl::Version(4, 3)) ||
165 mFunctions->hasGLExtension("GL_KHR_debug") ||
166 mFunctions->isAtLeastGLES(gl::Version(3, 2)) ||
167 mFunctions->hasGLESExtension("GL_KHR_debug");
168
169 mUseDebugOutput = hasDebugOutput && ShouldUseDebugLayers(attribMap);
170
171 if (mUseDebugOutput)
172 {
173 mFunctions->enable(GL_DEBUG_OUTPUT);
174 mFunctions->enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
175 mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0,
176 nullptr, GL_TRUE);
177 mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0,
178 nullptr, GL_TRUE);
179 mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0,
180 nullptr, GL_FALSE);
181 mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION,
182 0, nullptr, GL_FALSE);
183 mFunctions->debugMessageCallback(&LogGLDebugMessage, nullptr);
184 }
185
186 if (mFeatures.initializeCurrentVertexAttributes.enabled)
187 {
188 GLint maxVertexAttribs = 0;
189 mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
190
191 for (GLint i = 0; i < maxVertexAttribs; ++i)
192 {
193 mFunctions->vertexAttrib4f(i, 0.0f, 0.0f, 0.0f, 1.0f);
194 }
195 }
196
197 if (hasNativeParallelCompile() && !mNativeParallelCompileEnabled)
198 {
199 SetMaxShaderCompilerThreads(mFunctions.get(), 0xffffffff);
200 mNativeParallelCompileEnabled = true;
201 }
202 }
203
~RendererGL()204 RendererGL::~RendererGL()
205 {
206 SafeDelete(mBlitter);
207 SafeDelete(mMultiviewClearer);
208 SafeDelete(mStateManager);
209
210 std::lock_guard<std::mutex> lock(mWorkerMutex);
211
212 ASSERT(mCurrentWorkerContexts.empty());
213 mWorkerContextPool.clear();
214 }
215
flush()216 angle::Result RendererGL::flush()
217 {
218 if (!mWorkDoneSinceLastFlush && !mNeedsFlushBeforeDeleteTextures)
219 {
220 return angle::Result::Continue;
221 }
222
223 mFunctions->flush();
224 mNeedsFlushBeforeDeleteTextures = false;
225 mWorkDoneSinceLastFlush = false;
226 return angle::Result::Continue;
227 }
228
finish()229 angle::Result RendererGL::finish()
230 {
231 if (mFeatures.finishDoesNotCauseQueriesToBeAvailable.enabled && mUseDebugOutput)
232 {
233 mFunctions->enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
234 }
235
236 mFunctions->finish();
237 mNeedsFlushBeforeDeleteTextures = false;
238 mWorkDoneSinceLastFlush = false;
239
240 if (mFeatures.finishDoesNotCauseQueriesToBeAvailable.enabled && mUseDebugOutput)
241 {
242 mFunctions->disable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
243 }
244
245 return angle::Result::Continue;
246 }
247
getResetStatus()248 gl::GraphicsResetStatus RendererGL::getResetStatus()
249 {
250 return gl::FromGLenum<gl::GraphicsResetStatus>(mFunctions->getGraphicsResetStatus());
251 }
252
insertEventMarker(GLsizei length,const char * marker)253 void RendererGL::insertEventMarker(GLsizei length, const char *marker) {}
254
pushGroupMarker(GLsizei length,const char * marker)255 void RendererGL::pushGroupMarker(GLsizei length, const char *marker) {}
256
popGroupMarker()257 void RendererGL::popGroupMarker() {}
258
pushDebugGroup(GLenum source,GLuint id,const std::string & message)259 void RendererGL::pushDebugGroup(GLenum source, GLuint id, const std::string &message) {}
260
popDebugGroup()261 void RendererGL::popDebugGroup() {}
262
getMaxSupportedESVersion() const263 const gl::Version &RendererGL::getMaxSupportedESVersion() const
264 {
265 // Force generation of caps
266 getNativeCaps();
267
268 return mMaxSupportedESVersion;
269 }
270
generateCaps(gl::Caps * outCaps,gl::TextureCapsMap * outTextureCaps,gl::Extensions * outExtensions,gl::Limitations * outLimitations) const271 void RendererGL::generateCaps(gl::Caps *outCaps,
272 gl::TextureCapsMap *outTextureCaps,
273 gl::Extensions *outExtensions,
274 gl::Limitations *outLimitations) const
275 {
276 nativegl_gl::GenerateCaps(mFunctions.get(), mFeatures, outCaps, outTextureCaps, outExtensions,
277 outLimitations, &mMaxSupportedESVersion,
278 &mMultiviewImplementationType);
279 }
280
getGPUDisjoint()281 GLint RendererGL::getGPUDisjoint()
282 {
283 // TODO(ewell): On GLES backends we should find a way to reliably query disjoint events
284 return 0;
285 }
286
getTimestamp()287 GLint64 RendererGL::getTimestamp()
288 {
289 GLint64 result = 0;
290 mFunctions->getInteger64v(GL_TIMESTAMP, &result);
291 return result;
292 }
293
ensureCapsInitialized() const294 void RendererGL::ensureCapsInitialized() const
295 {
296 if (!mCapsInitialized)
297 {
298 generateCaps(&mNativeCaps, &mNativeTextureCaps, &mNativeExtensions, &mNativeLimitations);
299 mCapsInitialized = true;
300 }
301 }
302
getNativeCaps() const303 const gl::Caps &RendererGL::getNativeCaps() const
304 {
305 ensureCapsInitialized();
306 return mNativeCaps;
307 }
308
getNativeTextureCaps() const309 const gl::TextureCapsMap &RendererGL::getNativeTextureCaps() const
310 {
311 ensureCapsInitialized();
312 return mNativeTextureCaps;
313 }
314
getNativeExtensions() const315 const gl::Extensions &RendererGL::getNativeExtensions() const
316 {
317 ensureCapsInitialized();
318 return mNativeExtensions;
319 }
320
getNativeLimitations() const321 const gl::Limitations &RendererGL::getNativeLimitations() const
322 {
323 ensureCapsInitialized();
324 return mNativeLimitations;
325 }
326
getMultiviewImplementationType() const327 MultiviewImplementationTypeGL RendererGL::getMultiviewImplementationType() const
328 {
329 ensureCapsInitialized();
330 return mMultiviewImplementationType;
331 }
332
initializeFrontendFeatures(angle::FrontendFeatures * features) const333 void RendererGL::initializeFrontendFeatures(angle::FrontendFeatures *features) const
334 {
335 ensureCapsInitialized();
336 nativegl_gl::InitializeFrontendFeatures(mFunctions.get(), features);
337 }
338
dispatchCompute(const gl::Context * context,GLuint numGroupsX,GLuint numGroupsY,GLuint numGroupsZ)339 angle::Result RendererGL::dispatchCompute(const gl::Context *context,
340 GLuint numGroupsX,
341 GLuint numGroupsY,
342 GLuint numGroupsZ)
343 {
344 mFunctions->dispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
345 mWorkDoneSinceLastFlush = true;
346 return angle::Result::Continue;
347 }
348
dispatchComputeIndirect(const gl::Context * context,GLintptr indirect)349 angle::Result RendererGL::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect)
350 {
351 mFunctions->dispatchComputeIndirect(indirect);
352 mWorkDoneSinceLastFlush = true;
353 return angle::Result::Continue;
354 }
355
memoryBarrier(GLbitfield barriers)356 angle::Result RendererGL::memoryBarrier(GLbitfield barriers)
357 {
358 mFunctions->memoryBarrier(barriers);
359 mWorkDoneSinceLastFlush = true;
360 return angle::Result::Continue;
361 }
memoryBarrierByRegion(GLbitfield barriers)362 angle::Result RendererGL::memoryBarrierByRegion(GLbitfield barriers)
363 {
364 mFunctions->memoryBarrierByRegion(barriers);
365 mWorkDoneSinceLastFlush = true;
366 return angle::Result::Continue;
367 }
368
bindWorkerContext(std::string * infoLog)369 bool RendererGL::bindWorkerContext(std::string *infoLog)
370 {
371 if (mFeatures.disableWorkerContexts.enabled)
372 {
373 return false;
374 }
375
376 std::thread::id threadID = std::this_thread::get_id();
377 std::lock_guard<std::mutex> lock(mWorkerMutex);
378 std::unique_ptr<WorkerContext> workerContext;
379 if (!mWorkerContextPool.empty())
380 {
381 auto it = mWorkerContextPool.begin();
382 workerContext = std::move(*it);
383 mWorkerContextPool.erase(it);
384 }
385 else
386 {
387 WorkerContext *newContext = createWorkerContext(infoLog);
388 if (newContext == nullptr)
389 {
390 return false;
391 }
392 workerContext.reset(newContext);
393 }
394
395 if (!workerContext->makeCurrent())
396 {
397 mWorkerContextPool.push_back(std::move(workerContext));
398 return false;
399 }
400 mCurrentWorkerContexts[threadID] = std::move(workerContext);
401 return true;
402 }
403
unbindWorkerContext()404 void RendererGL::unbindWorkerContext()
405 {
406 std::thread::id threadID = std::this_thread::get_id();
407 std::lock_guard<std::mutex> lock(mWorkerMutex);
408
409 auto it = mCurrentWorkerContexts.find(threadID);
410 ASSERT(it != mCurrentWorkerContexts.end());
411 (*it).second->unmakeCurrent();
412 mWorkerContextPool.push_back(std::move((*it).second));
413 mCurrentWorkerContexts.erase(it);
414 }
415
getMaxWorkerContexts()416 unsigned int RendererGL::getMaxWorkerContexts()
417 {
418 // No more than 16 worker contexts.
419 return std::min(16u, std::thread::hardware_concurrency());
420 }
421
hasNativeParallelCompile()422 bool RendererGL::hasNativeParallelCompile()
423 {
424 if (mFeatures.disableNativeParallelCompile.enabled)
425 {
426 return false;
427 }
428 return mFunctions->maxShaderCompilerThreadsKHR != nullptr ||
429 mFunctions->maxShaderCompilerThreadsARB != nullptr;
430 }
431
setMaxShaderCompilerThreads(GLuint count)432 void RendererGL::setMaxShaderCompilerThreads(GLuint count)
433 {
434 if (hasNativeParallelCompile())
435 {
436 SetMaxShaderCompilerThreads(mFunctions.get(), count);
437 }
438 }
439
setNeedsFlushBeforeDeleteTextures()440 void RendererGL::setNeedsFlushBeforeDeleteTextures()
441 {
442 mNeedsFlushBeforeDeleteTextures = true;
443 }
444
markWorkSubmitted()445 void RendererGL::markWorkSubmitted()
446 {
447 mWorkDoneSinceLastFlush = true;
448 }
449
flushIfNecessaryBeforeDeleteTextures()450 void RendererGL::flushIfNecessaryBeforeDeleteTextures()
451 {
452 if (mNeedsFlushBeforeDeleteTextures)
453 {
454 (void)flush();
455 }
456 }
457
ScopedWorkerContextGL(RendererGL * renderer,std::string * infoLog)458 ScopedWorkerContextGL::ScopedWorkerContextGL(RendererGL *renderer, std::string *infoLog)
459 : mRenderer(renderer)
460 {
461 mValid = mRenderer->bindWorkerContext(infoLog);
462 }
463
~ScopedWorkerContextGL()464 ScopedWorkerContextGL::~ScopedWorkerContextGL()
465 {
466 if (mValid)
467 {
468 mRenderer->unbindWorkerContext();
469 }
470 }
471
operator ()() const472 bool ScopedWorkerContextGL::operator()() const
473 {
474 return mValid;
475 }
476
handleGPUSwitch()477 void RendererGL::handleGPUSwitch()
478 {
479 nativegl_gl::ReInitializeFeaturesAtGPUSwitch(mFunctions.get(), &mFeatures);
480 }
481
482 } // namespace rx
483