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 } // namespace
67
LogGLDebugMessage(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,const void * userParam)68 static void INTERNAL_GL_APIENTRY LogGLDebugMessage(GLenum source,
69 GLenum type,
70 GLuint id,
71 GLenum severity,
72 GLsizei length,
73 const GLchar *message,
74 const void *userParam)
75 {
76 std::string sourceText = gl::GetDebugMessageSourceString(source);
77 std::string typeText = gl::GetDebugMessageTypeString(type);
78 std::string severityText = gl::GetDebugMessageSeverityString(severity);
79
80 #if defined(ANGLE_PLATFORM_ANDROID)
81 if (type == GL_DEBUG_TYPE_ERROR)
82 {
83 for (const char *&err : kIgnoredErrors)
84 {
85 if (strncmp(err, message, length) == 0)
86 {
87 // There is only one ignored message right now and it is quite spammy, around 3MB
88 // for a complete end2end tests run, so don't print it even as a warning.
89 return;
90 }
91 }
92 }
93 #endif // defined(ANGLE_PLATFORM_ANDROID)
94
95 if (type == GL_DEBUG_TYPE_ERROR)
96 {
97 ERR() << std::endl
98 << "\tSource: " << sourceText << std::endl
99 << "\tType: " << typeText << std::endl
100 << "\tID: " << gl::FmtHex(id) << std::endl
101 << "\tSeverity: " << severityText << std::endl
102 << "\tMessage: " << message;
103 }
104 else if (type != GL_DEBUG_TYPE_PERFORMANCE)
105 {
106 // Don't print performance warnings. They tend to be very spammy in the dEQP test suite and
107 // there is very little we can do about them.
108
109 // TODO(ynovikov): filter into WARN and INFO if INFO is ever implemented
110 WARN() << std::endl
111 << "\tSource: " << sourceText << std::endl
112 << "\tType: " << typeText << std::endl
113 << "\tID: " << gl::FmtHex(id) << std::endl
114 << "\tSeverity: " << severityText << std::endl
115 << "\tMessage: " << message;
116 }
117 }
118
119 namespace rx
120 {
121
RendererGL(std::unique_ptr<FunctionsGL> functions,const egl::AttributeMap & attribMap,DisplayGL * display)122 RendererGL::RendererGL(std::unique_ptr<FunctionsGL> functions,
123 const egl::AttributeMap &attribMap,
124 DisplayGL *display)
125 : mMaxSupportedESVersion(0, 0),
126 mFunctions(std::move(functions)),
127 mStateManager(nullptr),
128 mBlitter(nullptr),
129 mMultiviewClearer(nullptr),
130 mUseDebugOutput(false),
131 mCapsInitialized(false),
132 mMultiviewImplementationType(MultiviewImplementationTypeGL::UNSPECIFIED),
133 mNativeParallelCompileEnabled(false),
134 mNeedsFlushBeforeDeleteTextures(false)
135 {
136 ASSERT(mFunctions);
137 if (!display->getState().featuresAllDisabled)
138 {
139 nativegl_gl::InitializeFeatures(mFunctions.get(), &mFeatures);
140 }
141 ApplyFeatureOverrides(&mFeatures, display->getState());
142 mStateManager =
143 new StateManagerGL(mFunctions.get(), getNativeCaps(), getNativeExtensions(), mFeatures);
144 mBlitter = new BlitGL(mFunctions.get(), mFeatures, mStateManager);
145 mMultiviewClearer = new ClearMultiviewGL(mFunctions.get(), mStateManager);
146
147 bool hasDebugOutput = mFunctions->isAtLeastGL(gl::Version(4, 3)) ||
148 mFunctions->hasGLExtension("GL_KHR_debug") ||
149 mFunctions->isAtLeastGLES(gl::Version(3, 2)) ||
150 mFunctions->hasGLESExtension("GL_KHR_debug");
151
152 mUseDebugOutput = hasDebugOutput && ShouldUseDebugLayers(attribMap);
153
154 if (mUseDebugOutput)
155 {
156 mFunctions->enable(GL_DEBUG_OUTPUT);
157 mFunctions->enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
158 mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0,
159 nullptr, GL_TRUE);
160 mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0,
161 nullptr, GL_TRUE);
162 mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0,
163 nullptr, GL_FALSE);
164 mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION,
165 0, nullptr, GL_FALSE);
166 mFunctions->debugMessageCallback(&LogGLDebugMessage, nullptr);
167 }
168
169 if (mFeatures.initializeCurrentVertexAttributes.enabled)
170 {
171 GLint maxVertexAttribs = 0;
172 mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
173
174 for (GLint i = 0; i < maxVertexAttribs; ++i)
175 {
176 mFunctions->vertexAttrib4f(i, 0.0f, 0.0f, 0.0f, 1.0f);
177 }
178 }
179
180 if (hasNativeParallelCompile() && !mNativeParallelCompileEnabled)
181 {
182 SetMaxShaderCompilerThreads(mFunctions.get(), 0xffffffff);
183 mNativeParallelCompileEnabled = true;
184 }
185 }
186
~RendererGL()187 RendererGL::~RendererGL()
188 {
189 SafeDelete(mBlitter);
190 SafeDelete(mMultiviewClearer);
191 SafeDelete(mStateManager);
192
193 std::lock_guard<std::mutex> lock(mWorkerMutex);
194
195 ASSERT(mCurrentWorkerContexts.empty());
196 mWorkerContextPool.clear();
197 }
198
flush()199 angle::Result RendererGL::flush()
200 {
201 mFunctions->flush();
202 mNeedsFlushBeforeDeleteTextures = false;
203 return angle::Result::Continue;
204 }
205
finish()206 angle::Result RendererGL::finish()
207 {
208 if (mFeatures.finishDoesNotCauseQueriesToBeAvailable.enabled && mUseDebugOutput)
209 {
210 mFunctions->enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
211 }
212
213 mFunctions->finish();
214 mNeedsFlushBeforeDeleteTextures = false;
215
216 if (mFeatures.finishDoesNotCauseQueriesToBeAvailable.enabled && mUseDebugOutput)
217 {
218 mFunctions->disable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
219 }
220
221 return angle::Result::Continue;
222 }
223
getResetStatus()224 gl::GraphicsResetStatus RendererGL::getResetStatus()
225 {
226 return gl::FromGLenum<gl::GraphicsResetStatus>(mFunctions->getGraphicsResetStatus());
227 }
228
insertEventMarker(GLsizei length,const char * marker)229 void RendererGL::insertEventMarker(GLsizei length, const char *marker) {}
230
pushGroupMarker(GLsizei length,const char * marker)231 void RendererGL::pushGroupMarker(GLsizei length, const char *marker) {}
232
popGroupMarker()233 void RendererGL::popGroupMarker() {}
234
pushDebugGroup(GLenum source,GLuint id,const std::string & message)235 void RendererGL::pushDebugGroup(GLenum source, GLuint id, const std::string &message) {}
236
popDebugGroup()237 void RendererGL::popDebugGroup() {}
238
getVendorString() const239 std::string RendererGL::getVendorString() const
240 {
241 return std::string(reinterpret_cast<const char *>(mFunctions->getString(GL_VENDOR)));
242 }
243
getRendererDescription() const244 std::string RendererGL::getRendererDescription() const
245 {
246 std::string nativeVendorString(
247 reinterpret_cast<const char *>(mFunctions->getString(GL_VENDOR)));
248 std::string nativeRendererString(
249 reinterpret_cast<const char *>(mFunctions->getString(GL_RENDERER)));
250
251 std::ostringstream rendererString;
252 rendererString << nativeVendorString << ", " << nativeRendererString << ", OpenGL";
253 if (mFunctions->standard == STANDARD_GL_ES)
254 {
255 rendererString << " ES";
256 }
257 rendererString << " " << mFunctions->version.major << "." << mFunctions->version.minor;
258 if (mFunctions->standard == STANDARD_GL_DESKTOP)
259 {
260 // Some drivers (NVIDIA) use a profile mask of 0 when in compatibility profile.
261 if ((mFunctions->profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0 ||
262 (mFunctions->isAtLeastGL(gl::Version(3, 2)) && mFunctions->profile == 0))
263 {
264 rendererString << " compatibility";
265 }
266 else if ((mFunctions->profile & GL_CONTEXT_CORE_PROFILE_BIT) != 0)
267 {
268 rendererString << " core";
269 }
270 }
271
272 return rendererString.str();
273 }
274
getMaxSupportedESVersion() const275 const gl::Version &RendererGL::getMaxSupportedESVersion() const
276 {
277 // Force generation of caps
278 getNativeCaps();
279
280 return mMaxSupportedESVersion;
281 }
282
generateCaps(gl::Caps * outCaps,gl::TextureCapsMap * outTextureCaps,gl::Extensions * outExtensions,gl::Limitations *) const283 void RendererGL::generateCaps(gl::Caps *outCaps,
284 gl::TextureCapsMap *outTextureCaps,
285 gl::Extensions *outExtensions,
286 gl::Limitations * /* outLimitations */) const
287 {
288 nativegl_gl::GenerateCaps(mFunctions.get(), mFeatures, outCaps, outTextureCaps, outExtensions,
289 &mMaxSupportedESVersion, &mMultiviewImplementationType);
290 }
291
getGPUDisjoint()292 GLint RendererGL::getGPUDisjoint()
293 {
294 // TODO(ewell): On GLES backends we should find a way to reliably query disjoint events
295 return 0;
296 }
297
getTimestamp()298 GLint64 RendererGL::getTimestamp()
299 {
300 GLint64 result = 0;
301 mFunctions->getInteger64v(GL_TIMESTAMP, &result);
302 return result;
303 }
304
ensureCapsInitialized() const305 void RendererGL::ensureCapsInitialized() const
306 {
307 if (!mCapsInitialized)
308 {
309 generateCaps(&mNativeCaps, &mNativeTextureCaps, &mNativeExtensions, &mNativeLimitations);
310 mCapsInitialized = true;
311 }
312 }
313
getNativeCaps() const314 const gl::Caps &RendererGL::getNativeCaps() const
315 {
316 ensureCapsInitialized();
317 return mNativeCaps;
318 }
319
getNativeTextureCaps() const320 const gl::TextureCapsMap &RendererGL::getNativeTextureCaps() const
321 {
322 ensureCapsInitialized();
323 return mNativeTextureCaps;
324 }
325
getNativeExtensions() const326 const gl::Extensions &RendererGL::getNativeExtensions() const
327 {
328 ensureCapsInitialized();
329 return mNativeExtensions;
330 }
331
getNativeLimitations() const332 const gl::Limitations &RendererGL::getNativeLimitations() const
333 {
334 ensureCapsInitialized();
335 return mNativeLimitations;
336 }
337
getMultiviewImplementationType() const338 MultiviewImplementationTypeGL RendererGL::getMultiviewImplementationType() const
339 {
340 ensureCapsInitialized();
341 return mMultiviewImplementationType;
342 }
343
initializeFrontendFeatures(angle::FrontendFeatures * features) const344 void RendererGL::initializeFrontendFeatures(angle::FrontendFeatures *features) const
345 {
346 ensureCapsInitialized();
347 nativegl_gl::InitializeFrontendFeatures(mFunctions.get(), features);
348 }
349
dispatchCompute(const gl::Context * context,GLuint numGroupsX,GLuint numGroupsY,GLuint numGroupsZ)350 angle::Result RendererGL::dispatchCompute(const gl::Context *context,
351 GLuint numGroupsX,
352 GLuint numGroupsY,
353 GLuint numGroupsZ)
354 {
355 mFunctions->dispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
356 return angle::Result::Continue;
357 }
358
dispatchComputeIndirect(const gl::Context * context,GLintptr indirect)359 angle::Result RendererGL::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect)
360 {
361 mFunctions->dispatchComputeIndirect(indirect);
362 return angle::Result::Continue;
363 }
364
memoryBarrier(GLbitfield barriers)365 angle::Result RendererGL::memoryBarrier(GLbitfield barriers)
366 {
367 mFunctions->memoryBarrier(barriers);
368 return angle::Result::Continue;
369 }
memoryBarrierByRegion(GLbitfield barriers)370 angle::Result RendererGL::memoryBarrierByRegion(GLbitfield barriers)
371 {
372 mFunctions->memoryBarrierByRegion(barriers);
373 return angle::Result::Continue;
374 }
375
bindWorkerContext(std::string * infoLog)376 bool RendererGL::bindWorkerContext(std::string *infoLog)
377 {
378 if (mFeatures.disableWorkerContexts.enabled)
379 {
380 return false;
381 }
382
383 std::thread::id threadID = std::this_thread::get_id();
384 std::lock_guard<std::mutex> lock(mWorkerMutex);
385 std::unique_ptr<WorkerContext> workerContext;
386 if (!mWorkerContextPool.empty())
387 {
388 auto it = mWorkerContextPool.begin();
389 workerContext = std::move(*it);
390 mWorkerContextPool.erase(it);
391 }
392 else
393 {
394 WorkerContext *newContext = createWorkerContext(infoLog);
395 if (newContext == nullptr)
396 {
397 return false;
398 }
399 workerContext.reset(newContext);
400 }
401
402 if (!workerContext->makeCurrent())
403 {
404 mWorkerContextPool.push_back(std::move(workerContext));
405 return false;
406 }
407 mCurrentWorkerContexts[threadID] = std::move(workerContext);
408 return true;
409 }
410
unbindWorkerContext()411 void RendererGL::unbindWorkerContext()
412 {
413 std::thread::id threadID = std::this_thread::get_id();
414 std::lock_guard<std::mutex> lock(mWorkerMutex);
415
416 auto it = mCurrentWorkerContexts.find(threadID);
417 ASSERT(it != mCurrentWorkerContexts.end());
418 (*it).second->unmakeCurrent();
419 mWorkerContextPool.push_back(std::move((*it).second));
420 mCurrentWorkerContexts.erase(it);
421 }
422
getMaxWorkerContexts()423 unsigned int RendererGL::getMaxWorkerContexts()
424 {
425 // No more than 16 worker contexts.
426 return std::min(16u, std::thread::hardware_concurrency());
427 }
428
hasNativeParallelCompile()429 bool RendererGL::hasNativeParallelCompile()
430 {
431 return mFunctions->maxShaderCompilerThreadsKHR != nullptr ||
432 mFunctions->maxShaderCompilerThreadsARB != nullptr;
433 }
434
setMaxShaderCompilerThreads(GLuint count)435 void RendererGL::setMaxShaderCompilerThreads(GLuint count)
436 {
437 if (hasNativeParallelCompile())
438 {
439 SetMaxShaderCompilerThreads(mFunctions.get(), count);
440 }
441 }
442
setNeedsFlushBeforeDeleteTextures()443 void RendererGL::setNeedsFlushBeforeDeleteTextures()
444 {
445 mNeedsFlushBeforeDeleteTextures = true;
446 }
447
flushIfNecessaryBeforeDeleteTextures()448 void RendererGL::flushIfNecessaryBeforeDeleteTextures()
449 {
450 if (mNeedsFlushBeforeDeleteTextures)
451 {
452 (void)flush();
453 }
454 }
455
ScopedWorkerContextGL(RendererGL * renderer,std::string * infoLog)456 ScopedWorkerContextGL::ScopedWorkerContextGL(RendererGL *renderer, std::string *infoLog)
457 : mRenderer(renderer)
458 {
459 mValid = mRenderer->bindWorkerContext(infoLog);
460 }
461
~ScopedWorkerContextGL()462 ScopedWorkerContextGL::~ScopedWorkerContextGL()
463 {
464 if (mValid)
465 {
466 mRenderer->unbindWorkerContext();
467 }
468 }
469
operator ()() const470 bool ScopedWorkerContextGL::operator()() const
471 {
472 return mValid;
473 }
474
475 } // namespace rx
476