| 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 "impeller/base/allocation.h"
10 #include "impeller/base/comparable.h"
11 #include "impeller/base/validation.h"
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
35 ProcTableGLES::Resolver WrappedResolver(
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
57 ProcTableGLES::ProcTableGLES(Resolver resolver) {
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
81 FOR_EACH_IMPELLER_PROC(IMPELLER_PROC);
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 }
91 FOR_EACH_IMPELLER_GLES3_PROC(IMPELLER_PROC);
92 FOR_EACH_IMPELLER_EXT_PROC(IMPELLER_PROC);
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
119 ProcTableGLES::~ProcTableGLES() = default;
120
121 bool ProcTableGLES::IsValid() const {
122 return is_valid_;
123 }
124
125 void ProcTableGLES::ShaderSourceMapping(GLuint shader,
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
133 const DescriptionGLES* ProcTableGLES::GetDescription() const {
134 return description_.get();
135 }
136
137 const CapabilitiesGLES* ProcTableGLES::GetCapabilities() const {
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
201 std::string ProcTableGLES::DescribeCurrentFramebuffer() const {
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;
214 if (IsCurrentFramebufferComplete()) {
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
232 bool ProcTableGLES::IsCurrentFramebufferComplete() const {
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) {
245 case DebugResourceType::kTexture:
246 return GL_TEXTURE;
247 case DebugResourceType::kBuffer:
248 return GL_BUFFER_KHR;
249 case DebugResourceType::kProgram:
250 return GL_PROGRAM_KHR;
251 case DebugResourceType::kShader:
252 return GL_SHADER_KHR;
253 case DebugResourceType::kRenderBuffer:
254 return GL_RENDERBUFFER;
255 case DebugResourceType::kFrameBuffer:
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) {
265 case DebugResourceType::kTexture:
266 return gl.IsTexture(name);
267 case DebugResourceType::kBuffer:
268 return gl.IsBuffer(name);
269 case DebugResourceType::kProgram:
270 return gl.IsProgram(name);
271 case DebugResourceType::kShader:
272 return gl.IsShader(name);
273 case DebugResourceType::kRenderBuffer:
274 return gl.IsRenderbuffer(name);
275 case DebugResourceType::kFrameBuffer:
276 return gl.IsFramebuffer(name);
277 }
278 FML_UNREACHABLE();
279 }
280
281 bool ProcTableGLES::SetDebugLabel(DebugResourceType type,
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
321 void ProcTableGLES::PopDebugGroup() const {
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()