| 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
5 #include "impeller/renderer/backend/gles/proc_table_gles.h"
6
7 #include <sstream>
8
9 #include "fml/closure.h"
10 #include "impeller/base/allocation.h"
11 #include "impeller/base/comparable.h"
12 #include "impeller/base/validation.h"
13 #include "impeller/renderer/backend/gles/capabilities_gles.h"
14 #include "impeller/renderer/capabilities.h"
15
16 namespace impeller {
17
18 const 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
38 bool 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
52 ProcTableGLES::Resolver WrappedResolver(
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
74 ProcTableGLES::ProcTableGLES(Resolver resolver) {
75 if (!resolver) {
76 return;
77 }
78
79 resolver = WrappedResolver(resolver);
80
81 auto error_fn = reinterpret_cast<PFNGLGETERRORPROC>(resolver("glGetError"));
82 if (!error_fn) {
83 VALIDATION_LOG << "Could not resolve "
84 << "glGetError";
85 return;
86 }
87
88 #define IMPELLER_PROC(proc_ivar) \
89 if (auto fn_ptr = resolver(proc_ivar.name)) { \
90 proc_ivar.function = \
91 reinterpret_cast<decltype(proc_ivar.function)>(fn_ptr); \
92 proc_ivar.error_fn = error_fn; \
93 } else { \
94 VALIDATION_LOG << "Could not resolve " << proc_ivar.name; \
95 return; \
96 }
97
98 FOR_EACH_IMPELLER_PROC(IMPELLER_PROC);
99
100 #undef IMPELLER_PROC
101
102 #define IMPELLER_PROC(proc_ivar) \
103 if (auto fn_ptr = resolver(proc_ivar.name)) { \
104 proc_ivar.function = \
105 reinterpret_cast<decltype(proc_ivar.function)>(fn_ptr); \
106 proc_ivar.error_fn = error_fn; \
107 }
108 FOR_EACH_IMPELLER_GLES3_PROC(IMPELLER_PROC);
109 FOR_EACH_IMPELLER_EXT_PROC(IMPELLER_PROC);
110
111 #undef IMPELLER_PROC
112
113 description_ = std::make_unique<DescriptionGLES>(*this);
114
115 if (!description_->IsValid()) {
116 return;
117 }
118
119 if (!description_->HasDebugExtension()) {
120 PushDebugGroupKHR.Reset();
121 PopDebugGroupKHR.Reset();
122 ObjectLabelKHR.Reset();
123 } else {
124 GetIntegerv(GL_MAX_LABEL_LENGTH_KHR, &debug_label_max_length_);
125 }
126
127 if (!description_->HasExtension("GL_EXT_discard_framebuffer")) {
128 DiscardFramebufferEXT.Reset();
129 }
130
131 capabilities_ = std::make_shared<CapabilitiesGLES>(*this);
132
133 is_valid_ = true;
134 }
135
136 ProcTableGLES::~ProcTableGLES() = default;
137
138 bool ProcTableGLES::IsValid() const {
139 return is_valid_;
140 }
141
142 void ProcTableGLES::ShaderSourceMapping(
143 GLuint shader,
144 const fml::Mapping& mapping,
145 const std::vector<Scalar>& defines) const {
146 if (defines.empty()) {
147 const GLchar* sources[] = {
148 reinterpret_cast<const GLchar*>(mapping.GetMapping())};
149 const GLint lengths[] = {static_cast<GLint>(mapping.GetSize())};
150 ShaderSource(shader, 1u, sources, lengths);
151 return;
152 }
153 const auto& shader_source = ComputeShaderWithDefines(mapping, defines);
154 if (!shader_source.has_value()) {
155 VALIDATION_LOG << "Failed to append constant data to shader";
156 return;
157 }
158
159 const GLchar* sources[] = {
160 reinterpret_cast<const GLchar*>(shader_source->c_str())};
161 const GLint lengths[] = {static_cast<GLint>(shader_source->size())};
162 ShaderSource(shader, 1u, sources, lengths);
163 }
164
165 // Visible For testing.
166 std::optional<std::string> ProcTableGLES::ComputeShaderWithDefines(
167 const fml::Mapping& mapping,
168 const std::vector<Scalar>& defines) const {
169 auto shader_source = std::string{
170 reinterpret_cast<const char*>(mapping.GetMapping()), mapping.GetSize()};
171
172 // Look for the first newline after the '#version' header, which impellerc
173 // will always emit as the first line of a compiled shader.
174 auto index = shader_source.find('\n');
175 if (index == std::string::npos) {
176 VALIDATION_LOG << "Failed to append constant data to shader";
177 return std::nullopt;
178 }
179
180 std::stringstream ss;
181 ss << std::fixed;
182 for (auto i = 0u; i < defines.size(); i++) {
183 ss << "#define SPIRV_CROSS_CONSTANT_ID_" << i << " " << defines[i] << '\n';
184 }
185 auto define_string = ss.str();
186 shader_source.insert(index + 1, define_string);
187 return shader_source;
188 }
189
190 const DescriptionGLES* ProcTableGLES::GetDescription() const {
191 return description_.get();
192 }
193
194 const std::shared_ptr<const CapabilitiesGLES>& ProcTableGLES::GetCapabilities()
195 const {
196 return capabilities_;
197 }
198
199 static const char* FramebufferStatusToString(GLenum status) {
200 switch (status) {
201 case GL_FRAMEBUFFER_COMPLETE:
202 return "GL_FRAMEBUFFER_COMPLETE";
203 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
204 return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
205 #if GL_ES_VERSION_2_0
206 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
207 return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
208 #endif
209 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
210 return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
211 case GL_FRAMEBUFFER_UNSUPPORTED:
212 return "GL_FRAMEBUFFER_UNSUPPORTED";
213 case GL_INVALID_ENUM:
214 return "GL_INVALID_ENUM";
215 }
216
217 return "Unknown FBO Error Status";
218 }
219
220 static const char* AttachmentTypeString(GLint type) {
221 switch (type) {
222 case GL_RENDERBUFFER:
223 return "GL_RENDERBUFFER";
224 case GL_TEXTURE:
225 return "GL_TEXTURE";
226 case GL_NONE:
227 return "GL_NONE";
228 }
229
230 return "Unknown Type";
231 }
232
233 static std::string DescribeFramebufferAttachment(const ProcTableGLES& gl,
234 GLenum attachment) {
235 GLint param = GL_NONE;
236 gl.GetFramebufferAttachmentParameteriv(
237 GL_FRAMEBUFFER, // target
238 attachment, // attachment
239 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, // parameter name
240 &param // parameter
241 );
242
243 if (param != GL_NONE) {
244 param = GL_NONE;
245 gl.GetFramebufferAttachmentParameteriv(
246 GL_FRAMEBUFFER, // target
247 attachment, // attachment
248 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, // parameter name
249 &param // parameter
250 );
251 std::stringstream stream;
252 stream << AttachmentTypeString(param) << "(" << param << ")";
253 return stream.str();
254 }
255
256 return "No Attachment";
257 }
258
259 std::string ProcTableGLES::DescribeCurrentFramebuffer() const {
260 GLint framebuffer = GL_NONE;
261 GetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer);
262 if (IsFramebuffer(framebuffer) == GL_FALSE) {
263 return "No framebuffer or the default window framebuffer is bound.";
264 }
265
266 GLenum status = CheckFramebufferStatus(framebuffer);
267 std::stringstream stream;
268 stream << "FBO "
269 << ((framebuffer == GL_NONE) ? "(Default)"
270 : std::to_string(framebuffer))
271 << ": " << FramebufferStatusToString(status) << std::endl;
272 if (IsCurrentFramebufferComplete()) {
273 stream << "Framebuffer is complete." << std::endl;
274 } else {
275 stream << "Framebuffer is incomplete." << std::endl;
276 }
277 stream << "Description: " << std::endl;
278 stream << "Color Attachment: "
279 << DescribeFramebufferAttachment(*this, GL_COLOR_ATTACHMENT0)
280 << std::endl;
281 stream << "Color Attachment: "
282 << DescribeFramebufferAttachment(*this, GL_DEPTH_ATTACHMENT)
283 << std::endl;
284 stream << "Color Attachment: "
285 << DescribeFramebufferAttachment(*this, GL_STENCIL_ATTACHMENT)
286 << std::endl;
287 return stream.str();
288 }
289
290 bool ProcTableGLES::IsCurrentFramebufferComplete() const {
291 GLint framebuffer = GL_NONE;
292 GetIntegerv(GL_FRAMEBUFFER_BINDING, &framebuffer);
293 if (IsFramebuffer(framebuffer) == GL_FALSE) {
294 // The default framebuffer is always complete.
295 return true;
296 }
297 GLenum status = CheckFramebufferStatus(framebuffer);
298 return status == GL_FRAMEBUFFER_COMPLETE;
299 }
300
301 static std::optional<GLenum> ToDebugIdentifier(DebugResourceType type) {
302 switch (type) {
303 case DebugResourceType::kTexture:
304 return GL_TEXTURE;
305 case DebugResourceType::kBuffer:
306 return GL_BUFFER_KHR;
307 case DebugResourceType::kProgram:
308 return GL_PROGRAM_KHR;
309 case DebugResourceType::kShader:
310 return GL_SHADER_KHR;
311 case DebugResourceType::kRenderBuffer:
312 return GL_RENDERBUFFER;
313 case DebugResourceType::kFrameBuffer:
314 return GL_FRAMEBUFFER;
315 }
316 FML_UNREACHABLE();
317 }
318
319 static bool ResourceIsLive(const ProcTableGLES& gl,
320 DebugResourceType type,
321 GLint name) {
322 switch (type) {
323 case DebugResourceType::kTexture:
324 return gl.IsTexture(name);
325 case DebugResourceType::kBuffer:
326 return gl.IsBuffer(name);
327 case DebugResourceType::kProgram:
328 return gl.IsProgram(name);
329 case DebugResourceType::kShader:
330 return gl.IsShader(name);
331 case DebugResourceType::kRenderBuffer:
332 return gl.IsRenderbuffer(name);
333 case DebugResourceType::kFrameBuffer:
334 return gl.IsFramebuffer(name);
335 }
336 FML_UNREACHABLE();
337 }
338
339 bool ProcTableGLES::SetDebugLabel(DebugResourceType type,
340 GLint name,
341 const std::string& label) const {
342 if (debug_label_max_length_ <= 0) {
343 return true;
344 }
345 if (!ObjectLabelKHR.IsAvailable()) {
346 return true;
347 }
348 if (!ResourceIsLive(*this, type, name)) {
349 return false;
350 }
351 const auto identifier = ToDebugIdentifier(type);
352 const auto label_length =
353 std::min<GLsizei>(debug_label_max_length_ - 1, label.size());
354 if (!identifier.has_value()) {
355 return true;
356 }
357 ObjectLabelKHR(identifier.value(), // identifier
358 name, // name
359 label_length, // length
360 label.data() // label
361 );
362 return true;
363 }
364
365 void ProcTableGLES::PushDebugGroup(const std::string& label) const {
366 #ifdef IMPELLER_DEBUG
367 if (debug_label_max_length_ <= 0) {
368 return;
369 }
370
371 UniqueID id;
372 const auto label_length =
373 std::min<GLsizei>(debug_label_max_length_ - 1, label.size());
374 PushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, // source
375 static_cast<GLuint>(id.id), // id
376 label_length, // length
377 label.data() // message
378 );
379 #endif // IMPELLER_DEBUG
380 }
381
382 void ProcTableGLES::PopDebugGroup() const {
383 #ifdef IMPELLER_DEBUG
384 if (debug_label_max_length_ <= 0) {
385 return;
386 }
387
388 PopDebugGroupKHR();
389 #endif // IMPELLER_DEBUG
390 }
391
392 std::string ProcTableGLES::GetProgramInfoLogString(GLuint program) const {
393 GLint length = 0;
394 GetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
395 if (length <= 0) {
396 return "";
397 }
398
399 length = std::min<GLint>(length, 1024);
400 Allocation allocation;
401 if (!allocation.Truncate(length, false)) {
402 return "";
403 }
404 GetProgramInfoLog(program, // program
405 length, // max length
406 &length, // length written (excluding NULL terminator)
407 reinterpret_cast<GLchar*>(allocation.GetBuffer()) // buffer
408 );
409 if (length <= 0) {
410 return "";
411 }
412 return std::string{reinterpret_cast<const char*>(allocation.GetBuffer()),
413 static_cast<size_t>(length)};
414 }
415
416 } // namespace impeller
impeller::ProcTableGLES::ShaderSourceMapping
void ShaderSourceMapping(GLuint shader, const fml::Mapping &mapping, const std::vector< Scalar > &defines={}) const
Set the source for the attached [shader].
Definition: proc_table_gles.cc:142
impeller::DescribeFramebufferAttachment
static std::string DescribeFramebufferAttachment(const ProcTableGLES &gl, GLenum attachment)
Definition: proc_table_gles.cc:233
impeller::ProcTableGLES::FOR_EACH_IMPELLER_PROC
FOR_EACH_IMPELLER_PROC(IMPELLER_PROC)
impeller::ProcTableGLES::ProcTableGLES
ProcTableGLES(Resolver resolver)
Definition: proc_table_gles.cc:74
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:365
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:319
impeller::ProcTableGLES::SetDebugLabel
bool SetDebugLabel(DebugResourceType type, GLint name, const std::string &label) const
Definition: proc_table_gles.cc:339
impeller::WrappedResolver
ProcTableGLES::Resolver WrappedResolver(const ProcTableGLES::Resolver &resolver)
Definition: proc_table_gles.cc:52
impeller::ProcTableGLES::IsValid
bool IsValid() const
Definition: proc_table_gles.cc:138
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:18
impeller::ProcTableGLES::Resolver
std::function< void *(const char *function_name)> Resolver
Definition: proc_table_gles.h:219
impeller::DebugResourceType::kTexture
@ kTexture
capabilities.h
impeller::ProcTableGLES::GetCapabilities
const std::shared_ptr< const CapabilitiesGLES > & GetCapabilities() const
Definition: proc_table_gles.cc:194
impeller::Allocation::GetBuffer
uint8_t * GetBuffer() const
Definition: allocation.cc:20
impeller::ProcTableGLES
Definition: proc_table_gles.h:217
impeller::FramebufferStatusToString
static const char * FramebufferStatusToString(GLenum status)
Definition: proc_table_gles.cc:199
impeller::ProcTableGLES::ComputeShaderWithDefines
std::optional< std::string > ComputeShaderWithDefines(const fml::Mapping &mapping, const std::vector< Scalar > &defines) const
Definition: proc_table_gles.cc:166
impeller::ProcTableGLES::GetProgramInfoLogString
std::string GetProgramInfoLogString(GLuint program) const
Definition: proc_table_gles.cc:392
proc_table_gles.h
impeller::DebugResourceType::kShader
@ kShader
impeller::Allocation
Definition: allocation.h:16
impeller::DebugResourceType::kRenderBuffer
@ kRenderBuffer
impeller::ProcTableGLES::DescribeCurrentFramebuffer
std::string DescribeCurrentFramebuffer() const
Definition: proc_table_gles.cc:259
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:67
impeller::DebugResourceType
DebugResourceType
Definition: proc_table_gles.h:208
comparable.h
impeller::ProcTableGLES::IsCurrentFramebufferComplete
bool IsCurrentFramebufferComplete() const
Definition: proc_table_gles.cc:290
impeller::DebugResourceType::kFrameBuffer
@ kFrameBuffer
impeller::GLErrorToString
const char * GLErrorToString(GLenum value)
Definition: proc_table_gles.cc:18
impeller::UniqueID
Definition: comparable.h:16
impeller::AttachmentTypeString
static const char * AttachmentTypeString(GLint type)
Definition: proc_table_gles.cc:220
capabilities_gles.h
impeller
Definition: aiks_context.cc:10
impeller::ProcTableGLES::PopDebugGroup
void PopDebugGroup() const
Definition: proc_table_gles.cc:382
impeller::Allocation::Truncate
bool Truncate(size_t length, bool npot=true)
Definition: allocation.cc:32
impeller::GLErrorIsFatal
bool GLErrorIsFatal(GLenum value)
Definition: proc_table_gles.cc:38
impeller::ToDebugIdentifier
static std::optional< GLenum > ToDebugIdentifier(DebugResourceType type)
Definition: proc_table_gles.cc:301
impeller::ProcTableGLES::GetDescription
const DescriptionGLES * GetDescription() const
Definition: proc_table_gles.cc:190
impeller::ProcTableGLES::~ProcTableGLES
~ProcTableGLES()