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 // FunctionsGL.cpp: Implements the FuntionsGL class to contain loaded GL functions
8 
9 #include "libANGLE/renderer/gl/FunctionsGL.h"
10 
11 #include <algorithm>
12 
13 #include "common/string_utils.h"
14 #include "libANGLE/AttributeMap.h"
15 #include "libANGLE/renderer/gl/renderergl_utils.h"
16 
17 namespace rx
18 {
19 
GetGLVersion(PFNGLGETSTRINGPROC getStringFunction,gl::Version * outVersion,StandardGL * outStandard)20 static void GetGLVersion(PFNGLGETSTRINGPROC getStringFunction,
21                          gl::Version *outVersion,
22                          StandardGL *outStandard)
23 {
24     const std::string version = reinterpret_cast<const char *>(getStringFunction(GL_VERSION));
25     if (version.find("OpenGL ES") == std::string::npos)
26     {
27         // OpenGL spec states the GL_VERSION string will be in the following format:
28         // <version number><space><vendor-specific information>
29         // The version number is either of the form major number.minor number or major
30         // number.minor number.release number, where the numbers all have one or more
31         // digits
32         *outStandard = STANDARD_GL_DESKTOP;
33         *outVersion  = gl::Version(version[0] - '0', version[2] - '0');
34     }
35     else
36     {
37         // ES spec states that the GL_VERSION string will be in the following format:
38         // "OpenGL ES N.M vendor-specific information"
39         *outStandard = STANDARD_GL_ES;
40         *outVersion  = gl::Version(version[10] - '0', version[12] - '0');
41     }
42 }
43 
GetIndexedExtensions(PFNGLGETINTEGERVPROC getIntegerFunction,PFNGLGETSTRINGIPROC getStringIFunction)44 static std::vector<std::string> GetIndexedExtensions(PFNGLGETINTEGERVPROC getIntegerFunction,
45                                                      PFNGLGETSTRINGIPROC getStringIFunction)
46 {
47     std::vector<std::string> result;
48 
49     GLint numExtensions;
50     getIntegerFunction(GL_NUM_EXTENSIONS, &numExtensions);
51 
52     result.reserve(numExtensions);
53 
54     for (GLint i = 0; i < numExtensions; i++)
55     {
56         result.push_back(reinterpret_cast<const char *>(getStringIFunction(GL_EXTENSIONS, i)));
57     }
58 
59     return result;
60 }
61 
62 #if defined(ANGLE_ENABLE_OPENGL_NULL)
StubCheckFramebufferStatus(GLenum)63 static GLenum INTERNAL_GL_APIENTRY StubCheckFramebufferStatus(GLenum)
64 {
65     return GL_FRAMEBUFFER_COMPLETE;
66 }
67 
StubGetProgramiv(GLuint program,GLenum pname,GLint * params)68 static void INTERNAL_GL_APIENTRY StubGetProgramiv(GLuint program, GLenum pname, GLint *params)
69 {
70     switch (pname)
71     {
72         case GL_LINK_STATUS:
73             *params = GL_TRUE;
74             break;
75         case GL_VALIDATE_STATUS:
76             *params = GL_TRUE;
77             break;
78         default:
79             break;
80     }
81 }
82 
StubGetShaderiv(GLuint program,GLenum pname,GLint * params)83 static void INTERNAL_GL_APIENTRY StubGetShaderiv(GLuint program, GLenum pname, GLint *params)
84 {
85     switch (pname)
86     {
87         case GL_COMPILE_STATUS:
88             *params = GL_TRUE;
89             break;
90         default:
91             break;
92     }
93 }
94 #endif  // defined(ANGLE_ENABLE_OPENGL_NULL)
95 
96 #define ASSIGN(NAME, FP) FP = reinterpret_cast<decltype(FP)>(loadProcAddress(NAME))
97 
FunctionsGL()98 FunctionsGL::FunctionsGL() : version(), standard(), extensions() {}
99 
~FunctionsGL()100 FunctionsGL::~FunctionsGL() {}
101 
initialize(const egl::AttributeMap & displayAttributes)102 void FunctionsGL::initialize(const egl::AttributeMap &displayAttributes)
103 {
104     // Grab the version number
105     ASSIGN("glGetString", getString);
106     ASSIGN("glGetIntegerv", getIntegerv);
107     GetGLVersion(getString, &version, &standard);
108 
109     // Grab the GL extensions
110     if (isAtLeastGL(gl::Version(3, 0)) || isAtLeastGLES(gl::Version(3, 0)))
111     {
112         ASSIGN("glGetStringi", getStringi);
113         extensions = GetIndexedExtensions(getIntegerv, getStringi);
114     }
115     else
116     {
117         const char *exts = reinterpret_cast<const char *>(getString(GL_EXTENSIONS));
118         angle::SplitStringAlongWhitespace(std::string(exts), &extensions);
119     }
120 
121     std::set<std::string> extensionSet;
122     for (const auto &extension : extensions)
123     {
124         extensionSet.insert(extension);
125     }
126 
127     // Note:
128     // Even though extensions are written against specific versions of GL, many drivers expose the
129     // extensions in even older versions.  Always try loading the extensions regardless of GL
130     // version.
131 
132     // Load the entry points
133 
134 #if defined(ANGLE_ENABLE_OPENGL_NULL)
135     EGLint deviceType =
136         static_cast<EGLint>(displayAttributes.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_NONE));
137 #endif  // defined(ANGLE_ENABLE_GL_NULL)
138 
139     switch (standard)
140     {
141         case STANDARD_GL_DESKTOP:
142         {
143             // Check the context profile
144             profile = 0;
145             if (isAtLeastGL(gl::Version(3, 2)))
146             {
147                 getIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
148             }
149 
150 #if defined(ANGLE_ENABLE_OPENGL_NULL)
151             if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE)
152             {
153                 initProcsDesktopGLNULL(version, extensionSet);
154             }
155             else
156 #endif  // defined(ANGLE_ENABLE_GL_NULL)
157             {
158                 initProcsDesktopGL(version, extensionSet);
159             }
160             break;
161         }
162 
163         case STANDARD_GL_ES:
164         {
165             // No profiles in GLES
166             profile = 0;
167 
168 #if defined(ANGLE_ENABLE_OPENGL_NULL)
169             if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE)
170             {
171                 initProcsGLESNULL(version, extensionSet);
172             }
173             else
174 #endif  // defined(ANGLE_ENABLE_GL_NULL)
175             {
176                 initProcsGLES(version, extensionSet);
177             }
178             break;
179         }
180 
181         default:
182             UNREACHABLE();
183             break;
184     }
185 
186 #if defined(ANGLE_ENABLE_OPENGL_NULL)
187     if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE)
188     {
189         initProcsSharedExtensionsNULL(extensionSet);
190         initializeStubFunctionsForNULLDriver(extensionSet);
191     }
192     else
193 #endif  // defined(ANGLE_ENABLE_OPENGL_NULL)
194     {
195         initProcsSharedExtensions(extensionSet);
196     }
197 }
198 
isAtLeastGL(const gl::Version & glVersion) const199 bool FunctionsGL::isAtLeastGL(const gl::Version &glVersion) const
200 {
201     return standard == STANDARD_GL_DESKTOP && version >= glVersion;
202 }
203 
isAtMostGL(const gl::Version & glVersion) const204 bool FunctionsGL::isAtMostGL(const gl::Version &glVersion) const
205 {
206     return standard == STANDARD_GL_DESKTOP && glVersion >= version;
207 }
208 
isAtLeastGLES(const gl::Version & glesVersion) const209 bool FunctionsGL::isAtLeastGLES(const gl::Version &glesVersion) const
210 {
211     return standard == STANDARD_GL_ES && version >= glesVersion;
212 }
213 
isAtMostGLES(const gl::Version & glesVersion) const214 bool FunctionsGL::isAtMostGLES(const gl::Version &glesVersion) const
215 {
216     return standard == STANDARD_GL_ES && glesVersion >= version;
217 }
218 
hasExtension(const std::string & ext) const219 bool FunctionsGL::hasExtension(const std::string &ext) const
220 {
221     return std::find(extensions.begin(), extensions.end(), ext) != extensions.end();
222 }
223 
hasGLExtension(const std::string & ext) const224 bool FunctionsGL::hasGLExtension(const std::string &ext) const
225 {
226     return standard == STANDARD_GL_DESKTOP && hasExtension(ext);
227 }
228 
hasGLESExtension(const std::string & ext) const229 bool FunctionsGL::hasGLESExtension(const std::string &ext) const
230 {
231     return standard == STANDARD_GL_ES && hasExtension(ext);
232 }
233 
234 #if defined(ANGLE_ENABLE_OPENGL_NULL)
initializeStubFunctionsForNULLDriver(const std::set<std::string> & extensionSet)235 void FunctionsGL::initializeStubFunctionsForNULLDriver(const std::set<std::string> &extensionSet)
236 {
237     // This is a quick hack to get the NULL driver working, but we might want to implement a true
238     // NULL/stub driver that never calls into the OS. See Chromium's implementation in
239     // ui/gl/gl_stub_api.cc. This might be useful for testing things like perf scaling due to
240     // the caps returned by the drivers (i.e. number of texture units) or a true NULL back-end
241     // that could be used in a VM for things like fuzzing.
242     // TODO(jmadill): Implement true no-op/stub back-end.
243     ASSIGN("glGetString", getString);
244     ASSIGN("glGetStringi", getStringi);
245     ASSIGN("glGetIntegerv", getIntegerv);
246     ASSIGN("glGetIntegeri_v", getIntegeri_v);
247 
248     getProgramiv           = &StubGetProgramiv;
249     getShaderiv            = &StubGetShaderiv;
250     checkFramebufferStatus = &StubCheckFramebufferStatus;
251 
252     if (isAtLeastGLES(gl::Version(3, 0)) || isAtLeastGL(gl::Version(4, 2)) ||
253         extensionSet.count("GL_ARB_internalformat_query") > 0)
254     {
255         ASSIGN("glGetInternalformativ", getInternalformativ);
256     }
257 
258     if (isAtLeastGL(gl::Version(4, 3)))
259     {
260         ASSIGN("glGetInternalformati64v", getInternalformati64v);
261     }
262 
263     if (extensionSet.count("GL_NV_internalformat_sample_query") > 0)
264     {
265         ASSIGN("glGetInternalformatSampleivNV", getInternalformatSampleivNV);
266     }
267 }
268 #endif  // defined(ANGLE_ENABLE_OPENGL_NULL)
269 
270 }  // namespace rx
271