Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
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 <format>
8#include <sstream>
9
10#include "GLES3/gl3.h"
16
17namespace impeller {
18
19std::string_view GLErrorToString(GLenum value) {
20 switch (value) {
21 case GL_NO_ERROR:
22 return "GL_NO_ERROR";
23 case GL_INVALID_ENUM:
24 return "GL_INVALID_ENUM";
25 case GL_INVALID_VALUE:
26 return "GL_INVALID_VALUE";
27 case GL_INVALID_OPERATION:
28 return "GL_INVALID_OPERATION";
29 case GL_INVALID_FRAMEBUFFER_OPERATION:
30 return "GL_INVALID_FRAMEBUFFER_OPERATION";
31 case GL_FRAMEBUFFER_COMPLETE:
32 return "GL_FRAMEBUFFER_COMPLETE";
33 case GL_OUT_OF_MEMORY:
34 return "GL_OUT_OF_MEMORY";
35 }
36 return "Unknown.";
37}
38
39bool GLErrorIsFatal(GLenum value) {
40 switch (value) {
41 case GL_NO_ERROR:
42 return false;
43 case GL_INVALID_ENUM:
44 case GL_INVALID_VALUE:
45 case GL_INVALID_OPERATION:
46 case GL_INVALID_FRAMEBUFFER_OPERATION:
47 case GL_OUT_OF_MEMORY:
48 return true;
49 }
50 return false;
51}
52
54 const ProcTableGLES::Resolver& resolver) {
55 return [resolver](const char* function_name) -> void* {
56 auto resolved = resolver(function_name);
57 if (resolved) {
58 return resolved;
59 }
60 // If there are certain known suffixes (usually for extensions), strip them
61 // out and try to resolve the same proc addresses again.
62 auto function = std::string{function_name};
63 if (function.find("KHR", function.size() - 3) != std::string::npos) {
64 auto truncated = function.substr(0u, function.size() - 3);
65 return resolver(truncated.c_str());
66 }
67 if (function.find("EXT", function.size() - 3) != std::string::npos) {
68 auto truncated = function.substr(0u, function.size() - 3);
69 return resolver(truncated.c_str());
70 }
71 return nullptr;
72 };
73}
74
75ProcTableGLES::ProcTableGLES( // NOLINT(google-readability-function-size)
76 Resolver resolver) {
77 // The reason this constructor has anywhere near enough code to tip off
78 // `google-readability-function-size` is the proc macros, so ignore the lint.
79
80 if (!resolver) {
81 return;
82 }
83
84 resolver = WrappedResolver(resolver);
85
86 auto error_fn = reinterpret_cast<PFNGLGETERRORPROC>(resolver("glGetError"));
87 if (!error_fn) {
88 VALIDATION_LOG << "Could not resolve " << "glGetError";
89 return;
90 }
91
92#define IMPELLER_PROC(proc_ivar) \
93 if (auto fn_ptr = resolver(proc_ivar.name.data())) { \
94 proc_ivar.function = \
95 reinterpret_cast<decltype(proc_ivar.function)>(fn_ptr); \
96 proc_ivar.error_fn = error_fn; \
97 } else { \
98 VALIDATION_LOG << "Could not resolve " << proc_ivar.name; \
99 return; \
100 }
101
103
104 description_ = std::make_unique<DescriptionGLES>(*this);
105
106 if (!description_->IsValid()) {
107 return;
108 }
109
110 if (description_->IsES()) {
112 } else {
114 }
115
116#undef IMPELLER_PROC
117
118#define IMPELLER_PROC(proc_ivar) \
119 if (auto fn_ptr = resolver(proc_ivar.name.data())) { \
120 proc_ivar.function = \
121 reinterpret_cast<decltype(proc_ivar.function)>(fn_ptr); \
122 proc_ivar.error_fn = error_fn; \
123 }
124
125 if (description_->GetGlVersion().IsAtLeast(Version(3))) {
127 }
128
130
131#undef IMPELLER_PROC
132
133 if (!IP_ENABLE_GLES_LABELING || !description_->HasDebugExtension()) {
134 PushDebugGroupKHR.Reset();
135 PopDebugGroupKHR.Reset();
136 ObjectLabelKHR.Reset();
137 } else {
138 GetIntegerv(GL_MAX_LABEL_LENGTH_KHR, &debug_label_max_length_);
139 }
140
141 if (!description_->HasExtension("GL_EXT_discard_framebuffer")) {
142 DiscardFramebufferEXT.Reset();
143 }
144
145 if (!description_->HasExtension("GL_ANGLE_framebuffer_blit")) {
146 BlitFramebufferANGLE.Reset();
147 }
148
149 if (!description_->HasExtension("GL_EXT_instanced_arrays")) {
150 VertexAttribDivisorEXT.Reset();
151 }
152
153 if (!description_->HasExtension("GL_EXT_draw_instanced")) {
154 DrawArraysInstancedEXT.Reset();
155 DrawElementsInstancedEXT.Reset();
156 }
157
158 capabilities_ = std::make_shared<CapabilitiesGLES>(*this);
159
160 is_valid_ = true;
161}
162
164
166 return is_valid_;
167}
168
170 GLuint shader,
171 const fml::Mapping& mapping,
172 const std::vector<Scalar>& defines) const {
173 if (defines.empty()) {
174 const GLchar* sources[] = {
175 reinterpret_cast<const GLchar*>(mapping.GetMapping())};
176 const GLint lengths[] = {static_cast<GLint>(mapping.GetSize())};
177 ShaderSource(shader, 1u, sources, lengths);
178 return;
179 }
180 const auto& shader_source = ComputeShaderWithDefines(mapping, defines);
181 if (!shader_source.has_value()) {
182 VALIDATION_LOG << "Failed to append constant data to shader";
183 return;
184 }
185
186 const GLchar* sources[] = {
187 reinterpret_cast<const GLchar*>(shader_source->c_str())};
188 const GLint lengths[] = {static_cast<GLint>(shader_source->size())};
189 ShaderSource(shader, 1u, sources, lengths);
190}
191
192// Visible For testing.
194 const fml::Mapping& mapping,
195 const std::vector<Scalar>& defines) const {
196 std::string shader_source = std::string{
197 reinterpret_cast<const char*>(mapping.GetMapping()), mapping.GetSize()};
198
199 // Look for the first newline after the '#version' header, which impellerc
200 // will always emit as the first line of a compiled shader.
201 size_t index = shader_source.find('\n');
202 if (index == std::string::npos) {
203 VALIDATION_LOG << "Failed to append constant data to shader";
204 return std::nullopt;
205 }
206
207 std::stringstream ss;
208 ss << std::fixed;
209 for (auto i = 0u; i < defines.size(); i++) {
210 ss << "#define SPIRV_CROSS_CONSTANT_ID_" << i << " " << defines[i] << '\n';
211 }
212 auto define_string = ss.str();
213 shader_source.insert(index + 1, define_string);
214 return shader_source;
215}
216
218 return description_.get();
219}
220
221const std::shared_ptr<const CapabilitiesGLES>& ProcTableGLES::GetCapabilities()
222 const {
223 return capabilities_;
224}
225
226static const char* FramebufferStatusToString(GLenum status) {
227 switch (status) {
228 case GL_FRAMEBUFFER_COMPLETE:
229 return "GL_FRAMEBUFFER_COMPLETE";
230 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
231 return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
232#if GL_ES_VERSION_2_0
233 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
234 return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
235#endif
236 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
237 return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
238 case GL_FRAMEBUFFER_UNSUPPORTED:
239 return "GL_FRAMEBUFFER_UNSUPPORTED";
240 case GL_INVALID_ENUM:
241 return "GL_INVALID_ENUM";
242 }
243
244 return "Unknown FBO Error Status";
245}
246
247static const char* AttachmentTypeString(GLint type) {
248 switch (type) {
249 case GL_RENDERBUFFER:
250 return "GL_RENDERBUFFER";
251 case GL_TEXTURE:
252 return "GL_TEXTURE";
253 case GL_NONE:
254 return "GL_NONE";
255 }
256
257 return "Unknown Type";
258}
259
260static std::string DescribeFramebufferAttachment(const ProcTableGLES& gl,
261 GLenum attachment) {
262 GLint type = GL_NONE;
263 gl.GetFramebufferAttachmentParameteriv(
264 GL_FRAMEBUFFER, // target
265 attachment, // attachment
266 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, // parameter name
267 &type // parameter
268 );
269
270 if (type != GL_NONE) {
271 GLint object = GL_NONE;
272 gl.GetFramebufferAttachmentParameteriv(
273 GL_FRAMEBUFFER, // target
274 attachment, // attachment
275 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, // parameter name
276 &object // parameter
277 );
278 std::stringstream stream;
279 stream << AttachmentTypeString(type) << "(" << object << ")";
280 return stream.str();
281 }
282
283 return "No Attachment";
284}
285
287 GLint framebuffer = GL_NONE;
288 GetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer);
289 if (framebuffer == GL_NONE) {
290 return "The default framebuffer (FBO0) was bound.";
291 }
292 if (IsFramebuffer(framebuffer) == GL_FALSE) {
293 return std::format(
294 "The framebuffer binding ({}) was not a valid framebuffer.",
295 framebuffer);
296 }
297
298 GLenum status = CheckFramebufferStatus(GL_FRAMEBUFFER);
299 std::stringstream stream;
300 stream << "FBO "
301 << ((framebuffer == GL_NONE) ? "(Default)"
302 : std::to_string(framebuffer))
303 << ": " << FramebufferStatusToString(status) << std::endl;
305 stream << "Framebuffer is complete." << std::endl;
306 } else {
307 stream << "Framebuffer is incomplete." << std::endl;
308 }
309 stream << "Description: " << std::endl;
310 stream << "Color Attachment: "
311 << DescribeFramebufferAttachment(*this, GL_COLOR_ATTACHMENT0)
312 << std::endl;
313 stream << "Depth Attachment: "
314 << DescribeFramebufferAttachment(*this, GL_DEPTH_ATTACHMENT)
315 << std::endl;
316 stream << "Stencil Attachment: "
317 << DescribeFramebufferAttachment(*this, GL_STENCIL_ATTACHMENT)
318 << std::endl;
319 return stream.str();
320}
321
323 GLint framebuffer = GL_NONE;
324 GetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer);
325 if (IsFramebuffer(framebuffer) == GL_FALSE) {
326 // The default framebuffer is always complete.
327 return true;
328 }
329 GLenum status = CheckFramebufferStatus(GL_FRAMEBUFFER);
330 return status == GL_FRAMEBUFFER_COMPLETE;
331}
332
333static std::optional<GLenum> ToDebugIdentifier(DebugResourceType type) {
334 switch (type) {
336 return GL_TEXTURE;
338 return GL_BUFFER_KHR;
340 return GL_PROGRAM_KHR;
342 return GL_SHADER_KHR;
344 return GL_RENDERBUFFER;
346 return GL_FRAMEBUFFER;
348 return GL_SYNC_FENCE;
349 }
351}
352
353static bool ResourceIsLive(const ProcTableGLES& gl,
355 GLint name) {
356 switch (type) {
358 return gl.IsTexture(name);
360 return gl.IsBuffer(name);
362 return gl.IsProgram(name);
364 return gl.IsShader(name);
366 return gl.IsRenderbuffer(name);
368 return gl.IsFramebuffer(name);
370 return true;
371 }
373}
374
376 if (debug_label_max_length_ <= 0) {
377 return false;
378 }
379 if (!ObjectLabelKHR.IsAvailable()) {
380 return false;
381 }
382 return true;
383}
384
386 GLint name,
387 std::string_view label) const {
388 if (!SupportsDebugLabels()) {
389 return true;
390 }
391 if (!ResourceIsLive(*this, type, name)) {
392 return false;
393 }
394 const auto identifier = ToDebugIdentifier(type);
395 const auto label_length =
396 std::min<GLsizei>(debug_label_max_length_ - 1, label.size());
397 if (!identifier.has_value()) {
398 return true;
399 }
400 ObjectLabelKHR(identifier.value(), // identifier
401 name, // name
402 label_length, // length
403 label.data() // label
404 );
405 return true;
406}
407
408void ProcTableGLES::PushDebugGroup(const std::string& label) const {
409#ifdef IMPELLER_DEBUG
410 if (debug_label_max_length_ <= 0) {
411 return;
412 }
413
414 UniqueID id;
415 const auto label_length =
416 std::min<GLsizei>(debug_label_max_length_ - 1, label.size());
417 PushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, // source
418 static_cast<GLuint>(id.id), // id
419 label_length, // length
420 label.data() // message
421 );
422#endif // IMPELLER_DEBUG
423}
424
426#ifdef IMPELLER_DEBUG
427 if (debug_label_max_length_ <= 0) {
428 return;
429 }
430
431 PopDebugGroupKHR();
432#endif // IMPELLER_DEBUG
433}
434
435std::string ProcTableGLES::GetProgramInfoLogString(GLuint program) const {
436 GLint length = 0;
437 GetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
438 if (length <= 0) {
439 return "";
440 }
441
442 length = std::min<GLint>(length, 1024);
443 Allocation allocation;
444 if (!allocation.Truncate(Bytes{length}, false)) {
445 return "";
446 }
447 GetProgramInfoLog(program, // program
448 length, // max length
449 &length, // length written (excluding NULL terminator)
450 reinterpret_cast<GLchar*>(allocation.GetBuffer()) // buffer
451 );
452 if (length <= 0) {
453 return "";
454 }
455 return std::string{reinterpret_cast<const char*>(allocation.GetBuffer()),
456 static_cast<size_t>(length)};
457}
458
460#ifdef IMPELLER_DEBUG
461 return CheckFramebufferStatus(target);
462#endif
463 return GL_FRAMEBUFFER_COMPLETE;
464};
465
466} // namespace impeller
virtual const uint8_t * GetMapping() const =0
virtual size_t GetSize() const =0
Describes an allocation on the heap.
Definition allocation.h:22
uint8_t * GetBuffer() const
Gets the pointer to the start of the allocation.
Definition allocation.cc:20
bool Truncate(Bytes length, bool npot=true)
Resize the underlying allocation to at least given number of bytes.
Definition allocation.cc:32
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
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].
std::string GetProgramInfoLogString(GLuint program) const
GLenum CheckFramebufferStatusDebug(GLenum target) const
std::string DescribeCurrentFramebuffer() const
const std::shared_ptr< const CapabilitiesGLES > & GetCapabilities() const
bool IsCurrentFramebufferComplete() const
ProcTableGLES(Resolver resolver)
void PushDebugGroup(const std::string &string) const
const DescriptionGLES * GetDescription() const
int32_t value
uint32_t * target
#define FML_UNREACHABLE()
Definition logging.h:128
Dart_NativeFunction function
Definition fuchsia.cc:51
const char * name
Definition fuchsia.cc:50
size_t length
ProcTableGLES::Resolver WrappedResolver(const ProcTableGLES::Resolver &resolver)
std::string_view GLErrorToString(GLenum value)
bool GLErrorIsFatal(GLenum value)
static std::optional< GLenum > ToDebugIdentifier(DebugResourceType type)
static const char * FramebufferStatusToString(GLenum status)
static const char * AttachmentTypeString(GLint type)
static bool ResourceIsLive(const ProcTableGLES &gl, DebugResourceType type, GLint name)
static std::string DescribeFramebufferAttachment(const ProcTableGLES &gl, GLenum attachment)
#define IMPELLER_PROC(proc_ivar)
#define FOR_EACH_IMPELLER_EXT_PROC(PROC)
#define FOR_EACH_IMPELLER_GLES3_PROC(PROC)
#define FOR_EACH_IMPELLER_DESKTOP_ONLY_PROC(PROC)
#define IP_ENABLE_GLES_LABELING
Enable to allow GLES to push/pop labels for usage in GPU traces.
#define FOR_EACH_IMPELLER_ES_ONLY_PROC(PROC)
#define FOR_EACH_IMPELLER_PROC(PROC)
impeller::ShaderType type
const uintptr_t id
#define VALIDATION_LOG
Definition validation.h:91