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 // Test that ANGLE_ENABLE_GL_DESKTOP_BACKEND has been enabled
160 // See http://anglebug.com/8195
161 ASSERT(getString != nullptr && getError != nullptr);
162 }
163 break;
164 }
165
166 case STANDARD_GL_ES:
167 {
168 // No profiles in GLES
169 profile = 0;
170
171 #if defined(ANGLE_ENABLE_OPENGL_NULL)
172 if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE)
173 {
174 initProcsGLESNULL(version, extensionSet);
175 }
176 else
177 #endif // defined(ANGLE_ENABLE_GL_NULL)
178 {
179 initProcsGLES(version, extensionSet);
180 }
181 break;
182 }
183
184 default:
185 UNREACHABLE();
186 break;
187 }
188
189 #if defined(ANGLE_ENABLE_OPENGL_NULL)
190 if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE)
191 {
192 initProcsSharedExtensionsNULL(extensionSet);
193 initializeStubFunctionsForNULLDriver(extensionSet);
194 }
195 else
196 #endif // defined(ANGLE_ENABLE_OPENGL_NULL)
197 {
198 initProcsSharedExtensions(extensionSet);
199 }
200 }
201
isAtLeastGL(const gl::Version & glVersion) const202 bool FunctionsGL::isAtLeastGL(const gl::Version &glVersion) const
203 {
204 return standard == STANDARD_GL_DESKTOP && version >= glVersion;
205 }
206
isAtMostGL(const gl::Version & glVersion) const207 bool FunctionsGL::isAtMostGL(const gl::Version &glVersion) const
208 {
209 return standard == STANDARD_GL_DESKTOP && glVersion >= version;
210 }
211
isAtLeastGLES(const gl::Version & glesVersion) const212 bool FunctionsGL::isAtLeastGLES(const gl::Version &glesVersion) const
213 {
214 return standard == STANDARD_GL_ES && version >= glesVersion;
215 }
216
isAtMostGLES(const gl::Version & glesVersion) const217 bool FunctionsGL::isAtMostGLES(const gl::Version &glesVersion) const
218 {
219 return standard == STANDARD_GL_ES && glesVersion >= version;
220 }
221
hasExtension(const std::string & ext) const222 bool FunctionsGL::hasExtension(const std::string &ext) const
223 {
224 return std::find(extensions.begin(), extensions.end(), ext) != extensions.end();
225 }
226
hasGLExtension(const std::string & ext) const227 bool FunctionsGL::hasGLExtension(const std::string &ext) const
228 {
229 return standard == STANDARD_GL_DESKTOP && hasExtension(ext);
230 }
231
hasGLESExtension(const std::string & ext) const232 bool FunctionsGL::hasGLESExtension(const std::string &ext) const
233 {
234 return standard == STANDARD_GL_ES && hasExtension(ext);
235 }
236
237 #if defined(ANGLE_ENABLE_OPENGL_NULL)
initializeStubFunctionsForNULLDriver(const std::set<std::string> & extensionSet)238 void FunctionsGL::initializeStubFunctionsForNULLDriver(const std::set<std::string> &extensionSet)
239 {
240 // This is a quick hack to get the NULL driver working, but we might want to implement a true
241 // NULL/stub driver that never calls into the OS. See Chromium's implementation in
242 // ui/gl/gl_stub_api.cc. This might be useful for testing things like perf scaling due to
243 // the caps returned by the drivers (i.e. number of texture units) or a true NULL back-end
244 // that could be used in a VM for things like fuzzing.
245 // TODO(jmadill): Implement true no-op/stub back-end.
246 ASSIGN("glGetString", getString);
247 ASSIGN("glGetStringi", getStringi);
248 ASSIGN("glGetIntegerv", getIntegerv);
249 ASSIGN("glGetIntegeri_v", getIntegeri_v);
250
251 getProgramiv = &StubGetProgramiv;
252 getShaderiv = &StubGetShaderiv;
253 checkFramebufferStatus = &StubCheckFramebufferStatus;
254
255 if (isAtLeastGLES(gl::Version(3, 0)) || isAtLeastGL(gl::Version(4, 2)) ||
256 extensionSet.count("GL_ARB_internalformat_query") > 0)
257 {
258 ASSIGN("glGetInternalformativ", getInternalformativ);
259 }
260
261 if (isAtLeastGL(gl::Version(4, 3)))
262 {
263 ASSIGN("glGetInternalformati64v", getInternalformati64v);
264 }
265
266 if (extensionSet.count("GL_NV_internalformat_sample_query") > 0)
267 {
268 ASSIGN("glGetInternalformatSampleivNV", getInternalformatSampleivNV);
269 }
270 }
271 #endif // defined(ANGLE_ENABLE_OPENGL_NULL)
272
273 } // namespace rx
274