Flutter Impeller
proc_table_gles.cc
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 
6 
7 #include <sstream>
8 
12 
13 namespace impeller {
14 
15 const char* GLErrorToString(GLenum value) {
16  switch (value) {
17  case GL_NO_ERROR:
18  return "GL_NO_ERROR";
19  case GL_INVALID_ENUM:
20  return "GL_INVALID_ENUM";
21  case GL_INVALID_VALUE:
22  return "GL_INVALID_VALUE";
23  case GL_INVALID_OPERATION:
24  return "GL_INVALID_OPERATION";
25  case GL_INVALID_FRAMEBUFFER_OPERATION:
26  return "GL_INVALID_FRAMEBUFFER_OPERATION";
27  case GL_FRAMEBUFFER_COMPLETE:
28  return "GL_FRAMEBUFFER_COMPLETE";
29  case GL_OUT_OF_MEMORY:
30  return "GL_OUT_OF_MEMORY";
31  }
32  return "Unknown.";
33 }
34 
36  const ProcTableGLES::Resolver& resolver) {
37  return [resolver](const char* function_name) -> void* {
38  auto resolved = resolver(function_name);
39  if (resolved) {
40  return resolved;
41  }
42  // If there are certain known suffixes (usually for extensions), strip them
43  // out and try to resolve the same proc addresses again.
44  auto function = std::string{function_name};
45  if (function.find("KHR", function.size() - 3) != std::string::npos) {
46  auto truncated = function.substr(0u, function.size() - 3);
47  return resolver(truncated.c_str());
48  }
49  if (function.find("EXT", function.size() - 3) != std::string::npos) {
50  auto truncated = function.substr(0u, function.size() - 3);
51  return resolver(truncated.c_str());
52  }
53  return nullptr;
54  };
55 }
56 
58  if (!resolver) {
59  return;
60  }
61 
62  resolver = WrappedResolver(resolver);
63 
64  auto error_fn = reinterpret_cast<PFNGLGETERRORPROC>(resolver("glGetError"));
65  if (!error_fn) {
66  VALIDATION_LOG << "Could not resolve "
67  << "glGetError";
68  return;
69  }
70 
71 #define IMPELLER_PROC(proc_ivar) \
72  if (auto fn_ptr = resolver(proc_ivar.name)) { \
73  proc_ivar.function = \
74  reinterpret_cast<decltype(proc_ivar.function)>(fn_ptr); \
75  proc_ivar.error_fn = error_fn; \
76  } else { \
77  VALIDATION_LOG << "Could not resolve " << proc_ivar.name; \
78  return; \
79  }
80 
82 
83 #undef IMPELLER_PROC
84 
85 #define IMPELLER_PROC(proc_ivar) \
86  if (auto fn_ptr = resolver(proc_ivar.name)) { \
87  proc_ivar.function = \
88  reinterpret_cast<decltype(proc_ivar.function)>(fn_ptr); \
89  proc_ivar.error_fn = error_fn; \
90  }
93 
94 #undef IMPELLER_PROC
95 
96  description_ = std::make_unique<DescriptionGLES>(*this);
97 
98  if (!description_->IsValid()) {
99  return;
100  }
101 
102  if (!description_->HasDebugExtension()) {
103  PushDebugGroupKHR.Reset();
104  PopDebugGroupKHR.Reset();
105  ObjectLabelKHR.Reset();
106  } else {
107  GetIntegerv(GL_MAX_LABEL_LENGTH_KHR, &debug_label_max_length_);
108  }
109 
110  if (!description_->HasExtension("GL_EXT_discard_framebuffer")) {
111  DiscardFramebufferEXT.Reset();
112  }
113 
114  capabilities_ = std::make_unique<CapabilitiesGLES>(*this);
115 
116  is_valid_ = true;
117 }
118 
120 
122  return is_valid_;
123 }
124 
126  const fml::Mapping& mapping) const {
127  const GLchar* sources[] = {
128  reinterpret_cast<const GLchar*>(mapping.GetMapping())};
129  const GLint lengths[] = {static_cast<GLint>(mapping.GetSize())};
130  ShaderSource(shader, 1u, sources, lengths);
131 }
132 
134  return description_.get();
135 }
136 
138  return capabilities_.get();
139 }
140 
141 static const char* FramebufferStatusToString(GLenum status) {
142  switch (status) {
143  case GL_FRAMEBUFFER_COMPLETE:
144  return "GL_FRAMEBUFFER_COMPLETE";
145  case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
146  return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
147 #if GL_ES_VERSION_2_0
148  case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
149  return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
150 #endif
151  case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
152  return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
153  case GL_FRAMEBUFFER_UNSUPPORTED:
154  return "GL_FRAMEBUFFER_UNSUPPORTED";
155  case GL_INVALID_ENUM:
156  return "GL_INVALID_ENUM";
157  }
158 
159  return "Unknown FBO Error Status";
160 }
161 
162 static const char* AttachmentTypeString(GLint type) {
163  switch (type) {
164  case GL_RENDERBUFFER:
165  return "GL_RENDERBUFFER";
166  case GL_TEXTURE:
167  return "GL_TEXTURE";
168  case GL_NONE:
169  return "GL_NONE";
170  }
171 
172  return "Unknown Type";
173 }
174 
175 static std::string DescribeFramebufferAttachment(const ProcTableGLES& gl,
176  GLenum attachment) {
177  GLint param = GL_NONE;
178  gl.GetFramebufferAttachmentParameteriv(
179  GL_FRAMEBUFFER, // target
180  attachment, // attachment
181  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, // parameter name
182  &param // parameter
183  );
184 
185  if (param != GL_NONE) {
186  param = GL_NONE;
187  gl.GetFramebufferAttachmentParameteriv(
188  GL_FRAMEBUFFER, // target
189  attachment, // attachment
190  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, // parameter name
191  &param // parameter
192  );
193  std::stringstream stream;
194  stream << AttachmentTypeString(param) << "(" << param << ")";
195  return stream.str();
196  }
197 
198  return "No Attachment";
199 }
200 
202  GLint framebuffer = GL_NONE;
203  GetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer);
204  if (IsFramebuffer(framebuffer) == GL_FALSE) {
205  return "No framebuffer or the default window framebuffer is bound.";
206  }
207 
208  GLenum status = CheckFramebufferStatus(framebuffer);
209  std::stringstream stream;
210  stream << "FBO "
211  << ((framebuffer == GL_NONE) ? "(Default)"
212  : std::to_string(framebuffer))
213  << ": " << FramebufferStatusToString(status) << std::endl;
215  stream << "Framebuffer is complete." << std::endl;
216  } else {
217  stream << "Framebuffer is incomplete." << std::endl;
218  }
219  stream << "Description: " << std::endl;
220  stream << "Color Attachment: "
221  << DescribeFramebufferAttachment(*this, GL_COLOR_ATTACHMENT0)
222  << std::endl;
223  stream << "Color Attachment: "
224  << DescribeFramebufferAttachment(*this, GL_DEPTH_ATTACHMENT)
225  << std::endl;
226  stream << "Color Attachment: "
227  << DescribeFramebufferAttachment(*this, GL_STENCIL_ATTACHMENT)
228  << std::endl;
229  return stream.str();
230 }
231 
233  GLint framebuffer = GL_NONE;
234  GetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer);
235  if (IsFramebuffer(framebuffer) == GL_FALSE) {
236  // The default framebuffer is always complete.
237  return true;
238  }
239  GLenum status = CheckFramebufferStatus(framebuffer);
240  return status == GL_FRAMEBUFFER_COMPLETE;
241 }
242 
243 static std::optional<GLenum> ToDebugIdentifier(DebugResourceType type) {
244  switch (type) {
246  return GL_TEXTURE;
248  return GL_BUFFER_KHR;
250  return GL_PROGRAM_KHR;
252  return GL_SHADER_KHR;
254  return GL_RENDERBUFFER;
256  return GL_FRAMEBUFFER;
257  }
258  FML_UNREACHABLE();
259 }
260 
261 static bool ResourceIsLive(const ProcTableGLES& gl,
262  DebugResourceType type,
263  GLint name) {
264  switch (type) {
266  return gl.IsTexture(name);
268  return gl.IsBuffer(name);
270  return gl.IsProgram(name);
272  return gl.IsShader(name);
274  return gl.IsRenderbuffer(name);
276  return gl.IsFramebuffer(name);
277  }
278  FML_UNREACHABLE();
279 }
280 
282  GLint name,
283  const std::string& label) const {
284  if (debug_label_max_length_ <= 0) {
285  return true;
286  }
287  if (!ObjectLabelKHR.IsAvailable()) {
288  return true;
289  }
290  if (!ResourceIsLive(*this, type, name)) {
291  return false;
292  }
293  const auto identifier = ToDebugIdentifier(type);
294  const auto label_length =
295  std::min<GLsizei>(debug_label_max_length_ - 1, label.size());
296  if (!identifier.has_value()) {
297  return true;
298  }
299  ObjectLabelKHR(identifier.value(), // identifier
300  name, // name
301  label_length, // length
302  label.data() // label
303  );
304  return true;
305 }
306 
307 void ProcTableGLES::PushDebugGroup(const std::string& label) const {
308  if (debug_label_max_length_ <= 0) {
309  return;
310  }
311  UniqueID id;
312  const auto label_length =
313  std::min<GLsizei>(debug_label_max_length_ - 1, label.size());
314  PushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, // source
315  static_cast<GLuint>(id.id), // id
316  label_length, // length
317  label.data() // message
318  );
319 }
320 
322  if (debug_label_max_length_ <= 0) {
323  return;
324  }
325  PopDebugGroupKHR();
326 }
327 
328 std::string ProcTableGLES::GetProgramInfoLogString(GLuint program) const {
329  GLint length = 0;
330  GetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
331  if (length <= 0) {
332  return "";
333  }
334 
335  length = std::min<GLint>(length, 1024);
336  Allocation allocation;
337  if (!allocation.Truncate(length, false)) {
338  return "";
339  }
340  GetProgramInfoLog(program, // program
341  length, // max length
342  &length, // length written (excluding NULL terminator)
343  reinterpret_cast<GLchar*>(allocation.GetBuffer()) // buffer
344  );
345  if (length <= 0) {
346  return "";
347  }
348  return std::string{reinterpret_cast<const char*>(allocation.GetBuffer()),
349  static_cast<size_t>(length)};
350 }
351 
352 } // namespace impeller
impeller::DescribeFramebufferAttachment
static std::string DescribeFramebufferAttachment(const ProcTableGLES &gl, GLenum attachment)
Definition: proc_table_gles.cc:175
impeller::ProcTableGLES::FOR_EACH_IMPELLER_PROC
FOR_EACH_IMPELLER_PROC(IMPELLER_PROC)
impeller::ProcTableGLES::ProcTableGLES
ProcTableGLES(Resolver resolver)
Definition: proc_table_gles.cc:57
allocation.h
impeller::ProcTableGLES::FOR_EACH_IMPELLER_GLES3_PROC
FOR_EACH_IMPELLER_GLES3_PROC(IMPELLER_PROC)
impeller::ProcTableGLES::PushDebugGroup
void PushDebugGroup(const std::string &string) const
Definition: proc_table_gles.cc:307
IMPELLER_PROC
#define IMPELLER_PROC(proc_ivar)
impeller::DebugResourceType::kBuffer
@ kBuffer
impeller::ResourceIsLive
static bool ResourceIsLive(const ProcTableGLES &gl, DebugResourceType type, GLint name)
Definition: proc_table_gles.cc:261
impeller::ProcTableGLES::SetDebugLabel
bool SetDebugLabel(DebugResourceType type, GLint name, const std::string &label) const
Definition: proc_table_gles.cc:281
impeller::WrappedResolver
ProcTableGLES::Resolver WrappedResolver(const ProcTableGLES::Resolver &resolver)
Definition: proc_table_gles.cc:35
impeller::ProcTableGLES::IsValid
bool IsValid() const
Definition: proc_table_gles.cc:121
impeller::DebugResourceType::kProgram
@ kProgram
validation.h
impeller::ProcTableGLES::FOR_EACH_IMPELLER_EXT_PROC
FOR_EACH_IMPELLER_EXT_PROC(IMPELLER_PROC)
impeller::DescriptionGLES
Definition: description_gles.h:17
impeller::ProcTableGLES::Resolver
std::function< void *(const char *function_name)> Resolver
Definition: proc_table_gles.h:190
impeller::DebugResourceType::kTexture
@ kTexture
impeller::Allocation::GetBuffer
uint8_t * GetBuffer() const
Definition: allocation.cc:21
impeller::ProcTableGLES
Definition: proc_table_gles.h:188
impeller::FramebufferStatusToString
static const char * FramebufferStatusToString(GLenum status)
Definition: proc_table_gles.cc:141
impeller::ProcTableGLES::GetProgramInfoLogString
std::string GetProgramInfoLogString(GLuint program) const
Definition: proc_table_gles.cc:328
proc_table_gles.h
impeller::DebugResourceType::kShader
@ kShader
impeller::CapabilitiesGLES
Definition: capabilities_gles.h:17
impeller::Allocation
Definition: allocation.h:15
impeller::DebugResourceType::kRenderBuffer
@ kRenderBuffer
impeller::ProcTableGLES::DescribeCurrentFramebuffer
std::string DescribeCurrentFramebuffer() const
Definition: proc_table_gles.cc:201
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
impeller::DebugResourceType
DebugResourceType
Definition: proc_table_gles.h:179
comparable.h
impeller::ProcTableGLES::IsCurrentFramebufferComplete
bool IsCurrentFramebufferComplete() const
Definition: proc_table_gles.cc:232
impeller::DebugResourceType::kFrameBuffer
@ kFrameBuffer
impeller::GLErrorToString
const char * GLErrorToString(GLenum value)
Definition: proc_table_gles.cc:15
impeller::UniqueID
Definition: comparable.h:19
impeller::AttachmentTypeString
static const char * AttachmentTypeString(GLint type)
Definition: proc_table_gles.cc:162
impeller::ProcTableGLES::GetCapabilities
const CapabilitiesGLES * GetCapabilities() const
Definition: proc_table_gles.cc:137
impeller::ProcTableGLES::ShaderSourceMapping
void ShaderSourceMapping(GLuint shader, const fml::Mapping &mapping) const
Definition: proc_table_gles.cc:125
impeller
Definition: aiks_context.cc:10
impeller::ProcTableGLES::PopDebugGroup
void PopDebugGroup() const
Definition: proc_table_gles.cc:321
impeller::Allocation::Truncate
bool Truncate(size_t length, bool npot=true)
Definition: allocation.cc:33
impeller::ToDebugIdentifier
static std::optional< GLenum > ToDebugIdentifier(DebugResourceType type)
Definition: proc_table_gles.cc:243
impeller::ProcTableGLES::GetDescription
const DescriptionGLES * GetDescription() const
Definition: proc_table_gles.cc:133
impeller::ProcTableGLES::~ProcTableGLES
~ProcTableGLES()