Flutter Impeller
proc_table_gles.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_PROC_TABLE_GLES_H_
6 #define FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_PROC_TABLE_GLES_H_
7 
8 #include <functional>
9 #include <string>
10 #include <string_view>
11 
12 #include "GLES3/gl3.h"
13 #include "flutter/fml/logging.h"
14 #include "flutter/fml/mapping.h"
18 
19 /// Enable to allow GLES to push/pop labels for usage in GPU traces
20 #define IP_ENABLE_GLES_LABELING false
21 
22 namespace impeller {
23 
24 std::string_view GLErrorToString(GLenum value);
25 bool GLErrorIsFatal(GLenum value);
26 
28  const PFNGLGETERRORPROC error_fn;
29 
30  /// Name of the GL call being wrapped.
31  /// should not be stored beyond the caller's lifetime.
32  std::string_view name;
33 
34  AutoErrorCheck(PFNGLGETERRORPROC error, std::string_view name)
35  : error_fn(error), name(name) {}
36 
38  if (error_fn) {
39  auto error = error_fn();
40  if (error == GL_NO_ERROR) {
41  return;
42  }
43  if (GLErrorIsFatal(error)) {
44  FML_LOG(FATAL) << "Fatal GL Error " << GLErrorToString(error) << "("
45  << error << ")" << " encountered on call to " << name;
46  } else {
47  FML_LOG(ERROR) << "GL Error " << GLErrorToString(error) << "(" << error
48  << ")" << " encountered on call to " << name;
49  }
50  }
51  }
52 };
53 
54 template <typename Type>
55 struct ArgLogger {
56  static void log(std::stringstream& stream, Type arg) { stream << arg; }
57 };
58 
59 template <typename R, typename... Args>
60 struct ArgLogger<R (*)(Args...)> {
61  static void log(std::stringstream& stream, R (*val)(Args...)) {
62  stream << reinterpret_cast<void*>(val);
63  }
64 };
65 
66 template <class Type>
67 void BuildGLArgumentsStream(std::stringstream& stream, Type arg) {
68  ArgLogger<Type>::log(stream, arg);
69 }
70 
71 constexpr void BuildGLArgumentsStream(std::stringstream& stream) {}
72 
73 template <class Type, class... Rest>
74 void BuildGLArgumentsStream(std::stringstream& stream,
75  Type arg,
76  Rest... other_args) {
77  BuildGLArgumentsStream(stream, arg);
78  stream << ", ";
79  BuildGLArgumentsStream(stream, other_args...);
80 }
81 
82 template <class... Type>
83 [[nodiscard]] std::string BuildGLArguments(Type... args) {
84  std::stringstream stream;
85  stream << "(";
86  BuildGLArgumentsStream(stream, args...);
87  stream << ")";
88  return stream.str();
89 }
90 
91 template <class T>
92 struct GLProc {
93  using GLFunctionType = T;
94 
95  //----------------------------------------------------------------------------
96  /// The name of the GL function.
97  ///
98  std::string_view name = {};
99 
100  //----------------------------------------------------------------------------
101  /// The pointer to the GL function.
102  ///
103  GLFunctionType* function = nullptr;
104 
105  //----------------------------------------------------------------------------
106  /// An optional error function. If present, all calls will be followed by an
107  /// error check.
108  ///
109  PFNGLGETERRORPROC error_fn = nullptr;
110 
111  //----------------------------------------------------------------------------
112  /// Whether the OpenGL call and its arguments should be logged.
113  ///
114  /// Only works in IMPELLER_DEBUG and for environments where traditional
115  /// tracing is hard. Expect log spam and only use during development.
116  ///
117  bool log_calls = false;
118 
119  //----------------------------------------------------------------------------
120  /// @brief Call the GL function with the appropriate parameters. Lookup
121  /// the documentation for the GL function being called to
122  /// understand the arguments and return types. The arguments
123  /// types must match and will be type checked.
124  ///
125  template <class... Args>
126  auto operator()(Args&&... args) const {
127 #if defined(IMPELLER_DEBUG) && !defined(NDEBUG)
128  AutoErrorCheck error(error_fn, name);
129  // We check for the existence of extensions, and reset the function pointer
130  // but it's still called unconditionally below, and will segfault. This
131  // validation log will at least give us a hint as to what's going on.
132  FML_CHECK(IsAvailable()) << "GL function " << name << " is not available. "
133  << "This is likely due to a missing extension.";
134  if (log_calls) {
135  FML_LOG(IMPORTANT) << name << BuildGLArguments(args...);
136  }
137 #endif // defined(IMPELLER_DEBUG) && !defined(NDEBUG)
138  return function(std::forward<Args>(args)...);
139  }
140 
141  constexpr bool IsAvailable() const { return function != nullptr; }
142 
143  void Reset() {
144  function = nullptr;
145  error_fn = nullptr;
146  }
147 };
148 
149 #define FOR_EACH_IMPELLER_PROC(PROC) \
150  PROC(ActiveTexture); \
151  PROC(AttachShader); \
152  PROC(BindAttribLocation); \
153  PROC(BindBuffer); \
154  PROC(BindFramebuffer); \
155  PROC(BindRenderbuffer); \
156  PROC(BindTexture); \
157  PROC(BindVertexArray); \
158  PROC(BlendEquationSeparate); \
159  PROC(BlendFuncSeparate); \
160  PROC(BufferData); \
161  PROC(BufferSubData); \
162  PROC(CheckFramebufferStatus); \
163  PROC(Clear); \
164  PROC(ClearColor); \
165  PROC(ClearStencil); \
166  PROC(ColorMask); \
167  PROC(CompileShader); \
168  PROC(CreateProgram); \
169  PROC(CreateShader); \
170  PROC(CullFace); \
171  PROC(DeleteBuffers); \
172  PROC(DeleteFramebuffers); \
173  PROC(DeleteProgram); \
174  PROC(DeleteRenderbuffers); \
175  PROC(DeleteShader); \
176  PROC(DeleteTextures); \
177  PROC(DeleteVertexArrays); \
178  PROC(DepthFunc); \
179  PROC(DepthMask); \
180  PROC(DetachShader); \
181  PROC(Disable); \
182  PROC(DisableVertexAttribArray); \
183  PROC(DrawArrays); \
184  PROC(DrawElements); \
185  PROC(Enable); \
186  PROC(EnableVertexAttribArray); \
187  PROC(Finish); \
188  PROC(Flush); \
189  PROC(FramebufferRenderbuffer); \
190  PROC(FramebufferTexture2D); \
191  PROC(FrontFace); \
192  PROC(GenBuffers); \
193  PROC(GenerateMipmap); \
194  PROC(GenFramebuffers); \
195  PROC(GenRenderbuffers); \
196  PROC(GenTextures); \
197  PROC(GenVertexArrays); \
198  PROC(GetActiveUniform); \
199  PROC(GetBooleanv); \
200  PROC(GetFloatv); \
201  PROC(GetFramebufferAttachmentParameteriv); \
202  PROC(GetIntegerv); \
203  PROC(GetProgramInfoLog); \
204  PROC(GetProgramiv); \
205  PROC(GetShaderInfoLog); \
206  PROC(GetShaderiv); \
207  PROC(GetString); \
208  PROC(GetStringi); \
209  PROC(GetUniformLocation); \
210  PROC(IsBuffer); \
211  PROC(IsFramebuffer); \
212  PROC(IsProgram); \
213  PROC(IsRenderbuffer); \
214  PROC(IsShader); \
215  PROC(IsTexture); \
216  PROC(LinkProgram); \
217  PROC(PixelStorei); \
218  PROC(RenderbufferStorage); \
219  PROC(Scissor); \
220  PROC(ShaderBinary); \
221  PROC(ShaderSource); \
222  PROC(StencilFuncSeparate); \
223  PROC(StencilMaskSeparate); \
224  PROC(StencilOpSeparate); \
225  PROC(TexImage2D); \
226  PROC(TexSubImage2D); \
227  PROC(TexParameteri); \
228  PROC(TexParameterfv); \
229  PROC(Uniform1fv); \
230  PROC(Uniform1i); \
231  PROC(Uniform2fv); \
232  PROC(Uniform3fv); \
233  PROC(Uniform4fv); \
234  PROC(UniformMatrix4fv); \
235  PROC(UseProgram); \
236  PROC(VertexAttribPointer); \
237  PROC(Viewport); \
238  PROC(GetShaderSource); \
239  PROC(ReadPixels);
240 
241 // Calls specific to OpenGLES.
242 void(glClearDepthf)(GLfloat depth);
243 void(glDepthRangef)(GLfloat n, GLfloat f);
244 
245 #define FOR_EACH_IMPELLER_ES_ONLY_PROC(PROC) \
246  PROC(ClearDepthf); \
247  PROC(DepthRangef);
248 
249 // Calls specific to desktop GL.
250 void(glClearDepth)(GLdouble depth);
251 void(glDepthRange)(GLdouble n, GLdouble f);
252 
253 #define FOR_EACH_IMPELLER_DESKTOP_ONLY_PROC(PROC) \
254  PROC(ClearDepth); \
255  PROC(DepthRange);
256 
257 #define FOR_EACH_IMPELLER_GLES3_PROC(PROC) \
258  PROC(FenceSync); \
259  PROC(DeleteSync); \
260  PROC(GetActiveUniformBlockiv); \
261  PROC(GetActiveUniformBlockName); \
262  PROC(GetUniformBlockIndex); \
263  PROC(UniformBlockBinding); \
264  PROC(BindBufferRange); \
265  PROC(WaitSync); \
266  PROC(RenderbufferStorageMultisample) \
267  PROC(BlitFramebuffer);
268 
269 #define FOR_EACH_IMPELLER_EXT_PROC(PROC) \
270  PROC(DebugMessageControlKHR); \
271  PROC(DebugMessageCallbackKHR); \
272  PROC(DiscardFramebufferEXT); \
273  PROC(FramebufferTexture2DMultisampleEXT); \
274  PROC(PushDebugGroupKHR); \
275  PROC(PopDebugGroupKHR); \
276  PROC(ObjectLabelKHR); \
277  PROC(RenderbufferStorageMultisampleEXT); \
278  PROC(GenQueriesEXT); \
279  PROC(DeleteQueriesEXT); \
280  PROC(GetQueryObjectui64vEXT); \
281  PROC(BeginQueryEXT); \
282  PROC(EndQueryEXT); \
283  PROC(GetQueryObjectuivEXT); \
284  PROC(BlitFramebufferANGLE);
285 
286 enum class DebugResourceType {
287  kTexture,
288  kBuffer,
289  kProgram,
290  kShader,
292  kFrameBuffer,
293  kFence,
294 };
295 
297  public:
298  using Resolver = std::function<void*(const char* function_name)>;
299  explicit ProcTableGLES(Resolver resolver);
300  ProcTableGLES(ProcTableGLES&& other) = default;
301 
303 
304 #define IMPELLER_PROC(name) \
305  GLProc<decltype(gl##name)> name = {"gl" #name, nullptr};
306 
312 
313 #undef IMPELLER_PROC
314 
315  bool IsValid() const;
316 
317  /// @brief Set the source for the attached [shader].
318  ///
319  /// Optionally, [defines] may contain a string value that will be
320  /// append to the shader source after the version marker. This can be used to
321  /// support static specialization. For example, setting "#define Foo 1".
322  void ShaderSourceMapping(GLuint shader,
323  const fml::Mapping& mapping,
324  const std::vector<Scalar>& defines = {}) const;
325 
326  const DescriptionGLES* GetDescription() const;
327 
328  const std::shared_ptr<const CapabilitiesGLES>& GetCapabilities() const;
329 
330  std::string DescribeCurrentFramebuffer() const;
331 
332  std::string GetProgramInfoLogString(GLuint program) const;
333 
334  // Only check framebuffer status in debug builds.
335  // Prefer this if possible to direct calls to CheckFramebufferStatus,
336  // which can cause CPU<->GPU round-trips.
337  GLenum CheckFramebufferStatusDebug(GLenum target) const;
338 
339  bool IsCurrentFramebufferComplete() const;
340 
341  bool SupportsDebugLabels() const;
342 
344  GLint name,
345  std::string_view label) const;
346 
347  void PushDebugGroup(const std::string& string) const;
348 
349  void PopDebugGroup() const;
350 
351  // Visible For testing.
352  std::optional<std::string> ComputeShaderWithDefines(
353  const fml::Mapping& mapping,
354  const std::vector<Scalar>& defines) const;
355 
356  private:
357  bool is_valid_ = false;
358  std::unique_ptr<DescriptionGLES> description_;
359  std::shared_ptr<const CapabilitiesGLES> capabilities_;
360  GLint debug_label_max_length_ = 0;
361 
362  ProcTableGLES(const ProcTableGLES&) = delete;
363 
364  ProcTableGLES& operator=(const ProcTableGLES&) = delete;
365 };
366 
367 } // namespace impeller
368 
369 #endif // FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_PROC_TABLE_GLES_H_
GLenum type
FOR_EACH_IMPELLER_ES_ONLY_PROC(IMPELLER_PROC)
ProcTableGLES(ProcTableGLES &&other)=default
std::optional< std::string > ComputeShaderWithDefines(const fml::Mapping &mapping, const std::vector< Scalar > &defines) const
bool SetDebugLabel(DebugResourceType type, GLint name, std::string_view label) const
FOR_EACH_IMPELLER_GLES3_PROC(IMPELLER_PROC)
std::function< void *(const char *function_name)> Resolver
void ShaderSourceMapping(GLuint shader, const fml::Mapping &mapping, const std::vector< Scalar > &defines={}) const
Set the source for the attached [shader].
FOR_EACH_IMPELLER_DESKTOP_ONLY_PROC(IMPELLER_PROC)
std::string GetProgramInfoLogString(GLuint program) const
GLenum CheckFramebufferStatusDebug(GLenum target) const
bool SupportsDebugLabels() const
std::string DescribeCurrentFramebuffer() const
const std::shared_ptr< const CapabilitiesGLES > & GetCapabilities() const
bool IsCurrentFramebufferComplete() const
ProcTableGLES(Resolver resolver)
FOR_EACH_IMPELLER_PROC(IMPELLER_PROC)
FOR_EACH_IMPELLER_EXT_PROC(IMPELLER_PROC)
void PushDebugGroup(const std::string &string) const
const DescriptionGLES * GetDescription() const
int32_t value
void() glClearDepth(GLdouble depth)
std::string_view GLErrorToString(GLenum value)
bool GLErrorIsFatal(GLenum value)
void() glDepthRangef(GLfloat n, GLfloat f)
void BuildGLArgumentsStream(std::stringstream &stream, Type arg)
void() glDepthRange(GLdouble n, GLdouble f)
void() glClearDepthf(GLfloat depth)
std::string BuildGLArguments(Type... args)
#define IMPELLER_PROC(name)
static void log(std::stringstream &stream, R(*val)(Args...))
static void log(std::stringstream &stream, Type arg)
AutoErrorCheck(PFNGLGETERRORPROC error, std::string_view name)
const PFNGLGETERRORPROC error_fn
auto operator()(Args &&... args) const
Call the GL function with the appropriate parameters. Lookup the documentation for the GL function be...
constexpr bool IsAvailable() const
std::string_view name
PFNGLGETERRORPROC error_fn