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