• 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 // 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