Flutter Engine
The Flutter Engine
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
9#include "fml/closure.h"
15
16namespace impeller {
17
18const char* GLErrorToString(GLenum value) {
19 switch (value) {
20 case GL_NO_ERROR:
21 return "GL_NO_ERROR";
22 case GL_INVALID_ENUM:
23 return "GL_INVALID_ENUM";
24 case GL_INVALID_VALUE:
25 return "GL_INVALID_VALUE";
26 case GL_INVALID_OPERATION:
27 return "GL_INVALID_OPERATION";
28 case GL_INVALID_FRAMEBUFFER_OPERATION:
29 return "GL_INVALID_FRAMEBUFFER_OPERATION";
30 case GL_FRAMEBUFFER_COMPLETE:
31 return "GL_FRAMEBUFFER_COMPLETE";
32 case GL_OUT_OF_MEMORY:
33 return "GL_OUT_OF_MEMORY";
34 }
35 return "Unknown.";
36}
37
38bool GLErrorIsFatal(GLenum value) {
39 switch (value) {
40 case GL_NO_ERROR:
41 return false;
42 case GL_INVALID_ENUM:
43 case GL_INVALID_VALUE:
44 case GL_INVALID_OPERATION:
45 case GL_INVALID_FRAMEBUFFER_OPERATION:
46 case GL_OUT_OF_MEMORY:
47 return true;
48 }
49 return false;
50}
51
53 const ProcTableGLES::Resolver& resolver) {
54 return [resolver](const char* function_name) -> void* {
55 auto resolved = resolver(function_name);
56 if (resolved) {
57 return resolved;
58 }
59 // If there are certain known suffixes (usually for extensions), strip them
60 // out and try to resolve the same proc addresses again.
61 auto function = std::string{function_name};
62 if (function.find("KHR", function.size() - 3) != std::string::npos) {
63 auto truncated = function.substr(0u, function.size() - 3);
64 return resolver(truncated.c_str());
65 }
66 if (function.find("EXT", function.size() - 3) != std::string::npos) {
67 auto truncated = function.substr(0u, function.size() - 3);
68 return resolver(truncated.c_str());
69 }
70 return nullptr;
71 };
72}
73
74ProcTableGLES::ProcTableGLES( // NOLINT(google-readability-function-size)
75 Resolver resolver) {
76 // The reason this constructor has anywhere near enough code to tip off
77 // `google-readability-function-size` is the proc macros, so ignore the lint.
78
79 if (!resolver) {
80 return;
81 }
82
83 resolver = WrappedResolver(resolver);
84
85 auto error_fn = reinterpret_cast<PFNGLGETERRORPROC>(resolver("glGetError"));
86 if (!error_fn) {
87 VALIDATION_LOG << "Could not resolve " << "glGetError";
88 return;
89 }
90
91#define IMPELLER_PROC(proc_ivar) \
92 if (auto fn_ptr = resolver(proc_ivar.name)) { \
93 proc_ivar.function = \
94 reinterpret_cast<decltype(proc_ivar.function)>(fn_ptr); \
95 proc_ivar.error_fn = error_fn; \
96 } else { \
97 VALIDATION_LOG << "Could not resolve " << proc_ivar.name; \
98 return; \
99 }
100
102
103 description_ = std::make_unique<DescriptionGLES>(*this);
104
105 if (!description_->IsValid()) {
106 return;
107 }
108
109 if (description_->IsES()) {
111 } else {
113 }
114
115#undef IMPELLER_PROC
116
117#define IMPELLER_PROC(proc_ivar) \
118 if (auto fn_ptr = resolver(proc_ivar.name)) { \
119 proc_ivar.function = \
120 reinterpret_cast<decltype(proc_ivar.function)>(fn_ptr); \
121 proc_ivar.error_fn = error_fn; \
122 }
125
126#undef IMPELLER_PROC
127
128 if (!description_->HasDebugExtension()) {
129 PushDebugGroupKHR.Reset();
130 PopDebugGroupKHR.Reset();
131 ObjectLabelKHR.Reset();
132 } else {
133 GetIntegerv(GL_MAX_LABEL_LENGTH_KHR, &debug_label_max_length_);
134 }
135
136 if (!description_->HasExtension("GL_EXT_discard_framebuffer")) {
137 DiscardFramebufferEXT.Reset();
138 }
139
140 capabilities_ = std::make_shared<CapabilitiesGLES>(*this);
141
142 is_valid_ = true;
143}
144
146
148 return is_valid_;
149}
150
152 GLuint shader,
153 const fml::Mapping& mapping,
154 const std::vector<Scalar>& defines) const {
155 if (defines.empty()) {
156 const GLchar* sources[] = {
157 reinterpret_cast<const GLchar*>(mapping.GetMapping())};
158 const GLint lengths[] = {static_cast<GLint>(mapping.GetSize())};
159 ShaderSource(shader, 1u, sources, lengths);
160 return;
161 }
162 const auto& shader_source = ComputeShaderWithDefines(mapping, defines);
163 if (!shader_source.has_value()) {
164 VALIDATION_LOG << "Failed to append constant data to shader";
165 return;
166 }
167
168 const GLchar* sources[] = {
169 reinterpret_cast<const GLchar*>(shader_source->c_str())};
170 const GLint lengths[] = {static_cast<GLint>(shader_source->size())};
171 ShaderSource(shader, 1u, sources, lengths);
172}
173
174// Visible For testing.
176 const fml::Mapping& mapping,
177 const std::vector<Scalar>& defines) const {
178 auto shader_source = std::string{
179 reinterpret_cast<const char*>(mapping.GetMapping()), mapping.GetSize()};
180
181 // Look for the first newline after the '#version' header, which impellerc
182 // will always emit as the first line of a compiled shader.
183 auto index = shader_source.find('\n');
184 if (index == std::string::npos) {
185 VALIDATION_LOG << "Failed to append constant data to shader";
186 return std::nullopt;
187 }
188
189 std::stringstream ss;
190 ss << std::fixed;
191 for (auto i = 0u; i < defines.size(); i++) {
192 ss << "#define SPIRV_CROSS_CONSTANT_ID_" << i << " " << defines[i] << '\n';
193 }
194 auto define_string = ss.str();
195 shader_source.insert(index + 1, define_string);
196 return shader_source;
197}
198
200 return description_.get();
201}
202
203const std::shared_ptr<const CapabilitiesGLES>& ProcTableGLES::GetCapabilities()
204 const {
205 return capabilities_;
206}
207
208static const char* FramebufferStatusToString(GLenum status) {
209 switch (status) {
210 case GL_FRAMEBUFFER_COMPLETE:
211 return "GL_FRAMEBUFFER_COMPLETE";
212 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
213 return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
214#if GL_ES_VERSION_2_0
215 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
216 return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
217#endif
218 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
219 return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
220 case GL_FRAMEBUFFER_UNSUPPORTED:
221 return "GL_FRAMEBUFFER_UNSUPPORTED";
222 case GL_INVALID_ENUM:
223 return "GL_INVALID_ENUM";
224 }
225
226 return "Unknown FBO Error Status";
227}
228
229static const char* AttachmentTypeString(GLint type) {
230 switch (type) {
231 case GL_RENDERBUFFER:
232 return "GL_RENDERBUFFER";
233 case GL_TEXTURE:
234 return "GL_TEXTURE";
235 case GL_NONE:
236 return "GL_NONE";
237 }
238
239 return "Unknown Type";
240}
241
243 GLenum attachment) {
244 GLint param = GL_NONE;
245 gl.GetFramebufferAttachmentParameteriv(
246 GL_FRAMEBUFFER, // target
247 attachment, // attachment
248 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, // parameter name
249 &param // parameter
250 );
251
252 if (param != GL_NONE) {
253 param = GL_NONE;
254 gl.GetFramebufferAttachmentParameteriv(
255 GL_FRAMEBUFFER, // target
256 attachment, // attachment
257 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, // parameter name
258 &param // parameter
259 );
260 std::stringstream stream;
261 stream << AttachmentTypeString(param) << "(" << param << ")";
262 return stream.str();
263 }
264
265 return "No Attachment";
266}
267
269 GLint framebuffer = GL_NONE;
270 GetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer);
271 if (IsFramebuffer(framebuffer) == GL_FALSE) {
272 return "No framebuffer or the default window framebuffer is bound.";
273 }
274
275 GLenum status = CheckFramebufferStatus(framebuffer);
276 std::stringstream stream;
277 stream << "FBO "
278 << ((framebuffer == GL_NONE) ? "(Default)"
279 : std::to_string(framebuffer))
280 << ": " << FramebufferStatusToString(status) << std::endl;
282 stream << "Framebuffer is complete." << std::endl;
283 } else {
284 stream << "Framebuffer is incomplete." << std::endl;
285 }
286 stream << "Description: " << std::endl;
287 stream << "Color Attachment: "
288 << DescribeFramebufferAttachment(*this, GL_COLOR_ATTACHMENT0)
289 << std::endl;
290 stream << "Color Attachment: "
291 << DescribeFramebufferAttachment(*this, GL_DEPTH_ATTACHMENT)
292 << std::endl;
293 stream << "Color Attachment: "
294 << DescribeFramebufferAttachment(*this, GL_STENCIL_ATTACHMENT)
295 << std::endl;
296 return stream.str();
297}
298
300 GLint framebuffer = GL_NONE;
301 GetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer);
302 if (IsFramebuffer(framebuffer) == GL_FALSE) {
303 // The default framebuffer is always complete.
304 return true;
305 }
306 GLenum status = CheckFramebufferStatus(framebuffer);
307 return status == GL_FRAMEBUFFER_COMPLETE;
308}
309
310static std::optional<GLenum> ToDebugIdentifier(DebugResourceType type) {
311 switch (type) {
313 return GL_TEXTURE;
315 return GL_BUFFER_KHR;
317 return GL_PROGRAM_KHR;
319 return GL_SHADER_KHR;
321 return GL_RENDERBUFFER;
323 return GL_FRAMEBUFFER;
324 }
326}
327
328static bool ResourceIsLive(const ProcTableGLES& gl,
330 GLint name) {
331 switch (type) {
333 return gl.IsTexture(name);
335 return gl.IsBuffer(name);
337 return gl.IsProgram(name);
339 return gl.IsShader(name);
341 return gl.IsRenderbuffer(name);
343 return gl.IsFramebuffer(name);
344 }
346}
347
349 GLint name,
350 const std::string& label) const {
351 if (debug_label_max_length_ <= 0) {
352 return true;
353 }
354 if (!ObjectLabelKHR.IsAvailable()) {
355 return true;
356 }
357 if (!ResourceIsLive(*this, type, name)) {
358 return false;
359 }
360 const auto identifier = ToDebugIdentifier(type);
361 const auto label_length =
362 std::min<GLsizei>(debug_label_max_length_ - 1, label.size());
363 if (!identifier.has_value()) {
364 return true;
365 }
366 ObjectLabelKHR(identifier.value(), // identifier
367 name, // name
368 label_length, // length
369 label.data() // label
370 );
371 return true;
372}
373
374void ProcTableGLES::PushDebugGroup(const std::string& label) const {
375#ifdef IMPELLER_DEBUG
376 if (debug_label_max_length_ <= 0) {
377 return;
378 }
379
380 UniqueID id;
381 const auto label_length =
382 std::min<GLsizei>(debug_label_max_length_ - 1, label.size());
383 PushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, // source
384 static_cast<GLuint>(id.id), // id
385 label_length, // length
386 label.data() // message
387 );
388#endif // IMPELLER_DEBUG
389}
390
392#ifdef IMPELLER_DEBUG
393 if (debug_label_max_length_ <= 0) {
394 return;
395 }
396
397 PopDebugGroupKHR();
398#endif // IMPELLER_DEBUG
399}
400
401std::string ProcTableGLES::GetProgramInfoLogString(GLuint program) const {
402 GLint length = 0;
403 GetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
404 if (length <= 0) {
405 return "";
406 }
407
408 length = std::min<GLint>(length, 1024);
409 Allocation allocation;
410 if (!allocation.Truncate(length, false)) {
411 return "";
412 }
413 GetProgramInfoLog(program, // program
414 length, // max length
415 &length, // length written (excluding NULL terminator)
416 reinterpret_cast<GLchar*>(allocation.GetBuffer()) // buffer
417 );
418 if (length <= 0) {
419 return "";
420 }
421 return std::string{reinterpret_cast<const char*>(allocation.GetBuffer()),
422 static_cast<size_t>(length)};
423}
424
425} // namespace impeller
GLenum type
virtual const uint8_t * GetMapping() const =0
virtual size_t GetSize() const =0
uint8_t * GetBuffer() const
Definition: allocation.cc:20
bool Truncate(size_t length, bool npot=true)
Definition: allocation.cc:32
FOR_EACH_IMPELLER_ES_ONLY_PROC(IMPELLER_PROC)
std::optional< std::string > ComputeShaderWithDefines(const fml::Mapping &mapping, const std::vector< Scalar > &defines) 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
bool SetDebugLabel(DebugResourceType type, GLint name, const std::string &label) 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
static SkString identifier(const FontFamilyDesc &family, const FontDesc &font)
uint8_t value
#define FML_UNREACHABLE()
Definition: logging.h:109
Dart_NativeFunction function
Definition: fuchsia.cc:51
size_t length
const char *const function_name
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
ProcTableGLES::Resolver WrappedResolver(const ProcTableGLES::Resolver &resolver)
bool GLErrorIsFatal(GLenum value)
static std::optional< GLenum > ToDebugIdentifier(DebugResourceType type)
const char * GLErrorToString(GLenum value)
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)
gl
Definition: malisc.py:41
static SkString to_string(int n)
Definition: nanobench.cpp:119
#define IMPELLER_PROC(proc_ivar)
const uintptr_t id
#define VALIDATION_LOG
Definition: validation.h:73