• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     mFunctions->flush();
219     mNeedsFlushBeforeDeleteTextures = false;
220     return angle::Result::Continue;
221 }
222 
finish()223 angle::Result RendererGL::finish()
224 {
225     if (mFeatures.finishDoesNotCauseQueriesToBeAvailable.enabled && mUseDebugOutput)
226     {
227         mFunctions->enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
228     }
229 
230     mFunctions->finish();
231     mNeedsFlushBeforeDeleteTextures = false;
232 
233     if (mFeatures.finishDoesNotCauseQueriesToBeAvailable.enabled && mUseDebugOutput)
234     {
235         mFunctions->disable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
236     }
237 
238     return angle::Result::Continue;
239 }
240 
getResetStatus()241 gl::GraphicsResetStatus RendererGL::getResetStatus()
242 {
243     return gl::FromGLenum<gl::GraphicsResetStatus>(mFunctions->getGraphicsResetStatus());
244 }
245 
insertEventMarker(GLsizei length,const char * marker)246 void RendererGL::insertEventMarker(GLsizei length, const char *marker) {}
247 
pushGroupMarker(GLsizei length,const char * marker)248 void RendererGL::pushGroupMarker(GLsizei length, const char *marker) {}
249 
popGroupMarker()250 void RendererGL::popGroupMarker() {}
251 
pushDebugGroup(GLenum source,GLuint id,const std::string & message)252 void RendererGL::pushDebugGroup(GLenum source, GLuint id, const std::string &message) {}
253 
popDebugGroup()254 void RendererGL::popDebugGroup() {}
255 
getVendorString() const256 std::string RendererGL::getVendorString() const
257 {
258     return std::string(reinterpret_cast<const char *>(mFunctions->getString(GL_VENDOR)));
259 }
260 
getRendererDescription() const261 std::string RendererGL::getRendererDescription() const
262 {
263     std::string nativeVendorString(
264         reinterpret_cast<const char *>(mFunctions->getString(GL_VENDOR)));
265     std::string nativeRendererString(
266         reinterpret_cast<const char *>(mFunctions->getString(GL_RENDERER)));
267 
268     std::ostringstream rendererString;
269     rendererString << nativeVendorString << ", " << nativeRendererString << ", OpenGL";
270     if (mFunctions->standard == STANDARD_GL_ES)
271     {
272         rendererString << " ES";
273     }
274     rendererString << " " << mFunctions->version.major << "." << mFunctions->version.minor;
275     if (mFunctions->standard == STANDARD_GL_DESKTOP)
276     {
277         // Some drivers (NVIDIA) use a profile mask of 0 when in compatibility profile.
278         if ((mFunctions->profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0 ||
279             (mFunctions->isAtLeastGL(gl::Version(3, 2)) && mFunctions->profile == 0))
280         {
281             rendererString << " compatibility";
282         }
283         else if ((mFunctions->profile & GL_CONTEXT_CORE_PROFILE_BIT) != 0)
284         {
285             rendererString << " core";
286         }
287     }
288 
289     return rendererString.str();
290 }
291 
getMaxSupportedESVersion() const292 const gl::Version &RendererGL::getMaxSupportedESVersion() const
293 {
294     // Force generation of caps
295     getNativeCaps();
296 
297     return mMaxSupportedESVersion;
298 }
299 
generateCaps(gl::Caps * outCaps,gl::TextureCapsMap * outTextureCaps,gl::Extensions * outExtensions,gl::Limitations *) const300 void RendererGL::generateCaps(gl::Caps *outCaps,
301                               gl::TextureCapsMap *outTextureCaps,
302                               gl::Extensions *outExtensions,
303                               gl::Limitations * /* outLimitations */) const
304 {
305     nativegl_gl::GenerateCaps(mFunctions.get(), mFeatures, outCaps, outTextureCaps, outExtensions,
306                               &mMaxSupportedESVersion, &mMultiviewImplementationType);
307 }
308 
getGPUDisjoint()309 GLint RendererGL::getGPUDisjoint()
310 {
311     // TODO(ewell): On GLES backends we should find a way to reliably query disjoint events
312     return 0;
313 }
314 
getTimestamp()315 GLint64 RendererGL::getTimestamp()
316 {
317     GLint64 result = 0;
318     mFunctions->getInteger64v(GL_TIMESTAMP, &result);
319     return result;
320 }
321 
ensureCapsInitialized() const322 void RendererGL::ensureCapsInitialized() const
323 {
324     if (!mCapsInitialized)
325     {
326         generateCaps(&mNativeCaps, &mNativeTextureCaps, &mNativeExtensions, &mNativeLimitations);
327         mCapsInitialized = true;
328     }
329 }
330 
getNativeCaps() const331 const gl::Caps &RendererGL::getNativeCaps() const
332 {
333     ensureCapsInitialized();
334     return mNativeCaps;
335 }
336 
getNativeTextureCaps() const337 const gl::TextureCapsMap &RendererGL::getNativeTextureCaps() const
338 {
339     ensureCapsInitialized();
340     return mNativeTextureCaps;
341 }
342 
getNativeExtensions() const343 const gl::Extensions &RendererGL::getNativeExtensions() const
344 {
345     ensureCapsInitialized();
346     return mNativeExtensions;
347 }
348 
getNativeLimitations() const349 const gl::Limitations &RendererGL::getNativeLimitations() const
350 {
351     ensureCapsInitialized();
352     return mNativeLimitations;
353 }
354 
getMultiviewImplementationType() const355 MultiviewImplementationTypeGL RendererGL::getMultiviewImplementationType() const
356 {
357     ensureCapsInitialized();
358     return mMultiviewImplementationType;
359 }
360 
initializeFrontendFeatures(angle::FrontendFeatures * features) const361 void RendererGL::initializeFrontendFeatures(angle::FrontendFeatures *features) const
362 {
363     ensureCapsInitialized();
364     nativegl_gl::InitializeFrontendFeatures(mFunctions.get(), features);
365 }
366 
dispatchCompute(const gl::Context * context,GLuint numGroupsX,GLuint numGroupsY,GLuint numGroupsZ)367 angle::Result RendererGL::dispatchCompute(const gl::Context *context,
368                                           GLuint numGroupsX,
369                                           GLuint numGroupsY,
370                                           GLuint numGroupsZ)
371 {
372     mFunctions->dispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
373     return angle::Result::Continue;
374 }
375 
dispatchComputeIndirect(const gl::Context * context,GLintptr indirect)376 angle::Result RendererGL::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect)
377 {
378     mFunctions->dispatchComputeIndirect(indirect);
379     return angle::Result::Continue;
380 }
381 
memoryBarrier(GLbitfield barriers)382 angle::Result RendererGL::memoryBarrier(GLbitfield barriers)
383 {
384     mFunctions->memoryBarrier(barriers);
385     return angle::Result::Continue;
386 }
memoryBarrierByRegion(GLbitfield barriers)387 angle::Result RendererGL::memoryBarrierByRegion(GLbitfield barriers)
388 {
389     mFunctions->memoryBarrierByRegion(barriers);
390     return angle::Result::Continue;
391 }
392 
bindWorkerContext(std::string * infoLog)393 bool RendererGL::bindWorkerContext(std::string *infoLog)
394 {
395     if (mFeatures.disableWorkerContexts.enabled)
396     {
397         return false;
398     }
399 
400     std::thread::id threadID = std::this_thread::get_id();
401     std::lock_guard<std::mutex> lock(mWorkerMutex);
402     std::unique_ptr<WorkerContext> workerContext;
403     if (!mWorkerContextPool.empty())
404     {
405         auto it       = mWorkerContextPool.begin();
406         workerContext = std::move(*it);
407         mWorkerContextPool.erase(it);
408     }
409     else
410     {
411         WorkerContext *newContext = createWorkerContext(infoLog);
412         if (newContext == nullptr)
413         {
414             return false;
415         }
416         workerContext.reset(newContext);
417     }
418 
419     if (!workerContext->makeCurrent())
420     {
421         mWorkerContextPool.push_back(std::move(workerContext));
422         return false;
423     }
424     mCurrentWorkerContexts[threadID] = std::move(workerContext);
425     return true;
426 }
427 
unbindWorkerContext()428 void RendererGL::unbindWorkerContext()
429 {
430     std::thread::id threadID = std::this_thread::get_id();
431     std::lock_guard<std::mutex> lock(mWorkerMutex);
432 
433     auto it = mCurrentWorkerContexts.find(threadID);
434     ASSERT(it != mCurrentWorkerContexts.end());
435     (*it).second->unmakeCurrent();
436     mWorkerContextPool.push_back(std::move((*it).second));
437     mCurrentWorkerContexts.erase(it);
438 }
439 
getMaxWorkerContexts()440 unsigned int RendererGL::getMaxWorkerContexts()
441 {
442     // No more than 16 worker contexts.
443     return std::min(16u, std::thread::hardware_concurrency());
444 }
445 
hasNativeParallelCompile()446 bool RendererGL::hasNativeParallelCompile()
447 {
448     return mFunctions->maxShaderCompilerThreadsKHR != nullptr ||
449            mFunctions->maxShaderCompilerThreadsARB != nullptr;
450 }
451 
setMaxShaderCompilerThreads(GLuint count)452 void RendererGL::setMaxShaderCompilerThreads(GLuint count)
453 {
454     if (hasNativeParallelCompile())
455     {
456         SetMaxShaderCompilerThreads(mFunctions.get(), count);
457     }
458 }
459 
setNeedsFlushBeforeDeleteTextures()460 void RendererGL::setNeedsFlushBeforeDeleteTextures()
461 {
462     mNeedsFlushBeforeDeleteTextures = true;
463 }
464 
flushIfNecessaryBeforeDeleteTextures()465 void RendererGL::flushIfNecessaryBeforeDeleteTextures()
466 {
467     if (mNeedsFlushBeforeDeleteTextures)
468     {
469         (void)flush();
470     }
471 }
472 
ScopedWorkerContextGL(RendererGL * renderer,std::string * infoLog)473 ScopedWorkerContextGL::ScopedWorkerContextGL(RendererGL *renderer, std::string *infoLog)
474     : mRenderer(renderer)
475 {
476     mValid = mRenderer->bindWorkerContext(infoLog);
477 }
478 
~ScopedWorkerContextGL()479 ScopedWorkerContextGL::~ScopedWorkerContextGL()
480 {
481     if (mValid)
482     {
483         mRenderer->unbindWorkerContext();
484     }
485 }
486 
operator ()() const487 bool ScopedWorkerContextGL::operator()() const
488 {
489     return mValid;
490 }
491 
492 }  // namespace rx
493