Flutter Engine
The Flutter Engine
pipeline_library_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#include <string>
9
10#include "flutter/fml/container.h"
11#include "flutter/fml/trace_event.h"
12#include "fml/closure.h"
16
17namespace impeller {
18
19PipelineLibraryGLES::PipelineLibraryGLES(ReactorGLES::Ref reactor)
20 : reactor_(std::move(reactor)) {}
21
22static std::string GetShaderInfoLog(const ProcTableGLES& gl, GLuint shader) {
23 GLint log_length = 0;
24 gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
25 if (log_length == 0) {
26 return "";
27 }
28 auto log_buffer =
29 reinterpret_cast<char*>(std::calloc(log_length, sizeof(char)));
30 gl.GetShaderInfoLog(shader, log_length, &log_length, log_buffer);
31 auto log_string = std::string(log_buffer, log_length);
32 std::free(log_buffer);
33 return log_string;
34}
35
36static std::string GetShaderSource(const ProcTableGLES& gl, GLuint shader) {
37 // Arbitrarily chosen size that should be larger than most shaders.
38 // Since this only fires on compilation errors the performance shouldn't
39 // matter.
40 auto data = static_cast<char*>(malloc(10240));
41 GLsizei length;
42 gl.GetShaderSource(shader, 10240, &length, data);
43
44 auto result = std::string{data, static_cast<size_t>(length)};
45 free(data);
46 return result;
47}
48
50 GLuint shader,
51 const std::string& name,
52 const fml::Mapping& source_mapping,
53 ShaderStage stage) {
54 std::stringstream stream;
55 stream << "Failed to compile ";
56 switch (stage) {
58 stream << "unknown";
59 break;
60 case ShaderStage::kVertex:
61 stream << "vertex";
62 break;
63 case ShaderStage::kFragment:
64 stream << "fragment";
65 break;
66 case ShaderStage::kCompute:
67 stream << "compute";
68 break;
69 }
70 stream << " shader for '" << name << "' with error:" << std::endl;
71 stream << GetShaderInfoLog(gl, shader) << std::endl;
72 stream << "Shader source was: " << std::endl;
73 stream << GetShaderSource(gl, shader) << std::endl;
74 VALIDATION_LOG << stream.str();
75}
76
77static bool LinkProgram(
78 const ReactorGLES& reactor,
79 const std::shared_ptr<PipelineGLES>& pipeline,
80 const std::shared_ptr<const ShaderFunction>& vert_function,
81 const std::shared_ptr<const ShaderFunction>& frag_function) {
82 TRACE_EVENT0("impeller", __FUNCTION__);
83
84 const auto& descriptor = pipeline->GetDescriptor();
85
86 auto vert_mapping =
87 ShaderFunctionGLES::Cast(*vert_function).GetSourceMapping();
88 auto frag_mapping =
89 ShaderFunctionGLES::Cast(*frag_function).GetSourceMapping();
90
91 const auto& gl = reactor.GetProcTable();
92
93 auto vert_shader = gl.CreateShader(GL_VERTEX_SHADER);
94 auto frag_shader = gl.CreateShader(GL_FRAGMENT_SHADER);
95
96 if (vert_shader == 0 || frag_shader == 0) {
97 VALIDATION_LOG << "Could not create shader handles.";
98 return false;
99 }
100
101 gl.SetDebugLabel(DebugResourceType::kShader, vert_shader,
102 SPrintF("%s Vertex Shader", descriptor.GetLabel().c_str()));
103 gl.SetDebugLabel(
104 DebugResourceType::kShader, frag_shader,
105 SPrintF("%s Fragment Shader", descriptor.GetLabel().c_str()));
106
107 fml::ScopedCleanupClosure delete_vert_shader(
108 [&gl, vert_shader]() { gl.DeleteShader(vert_shader); });
109 fml::ScopedCleanupClosure delete_frag_shader(
110 [&gl, frag_shader]() { gl.DeleteShader(frag_shader); });
111
112 gl.ShaderSourceMapping(vert_shader, *vert_mapping,
113 descriptor.GetSpecializationConstants());
114 gl.ShaderSourceMapping(frag_shader, *frag_mapping,
115 descriptor.GetSpecializationConstants());
116
117 gl.CompileShader(vert_shader);
118 gl.CompileShader(frag_shader);
119
120 GLint vert_status = GL_FALSE;
121 GLint frag_status = GL_FALSE;
122
123 gl.GetShaderiv(vert_shader, GL_COMPILE_STATUS, &vert_status);
124 gl.GetShaderiv(frag_shader, GL_COMPILE_STATUS, &frag_status);
125
126 if (vert_status != GL_TRUE) {
127 LogShaderCompilationFailure(gl, vert_shader, descriptor.GetLabel(),
128 *vert_mapping, ShaderStage::kVertex);
129 return false;
130 }
131
132 if (frag_status != GL_TRUE) {
133 LogShaderCompilationFailure(gl, frag_shader, descriptor.GetLabel(),
134 *frag_mapping, ShaderStage::kFragment);
135 return false;
136 }
137
138 auto program = reactor.GetGLHandle(pipeline->GetProgramHandle());
139 if (!program.has_value()) {
140 VALIDATION_LOG << "Could not get program handle from reactor.";
141 return false;
142 }
143
144 gl.AttachShader(*program, vert_shader);
145 gl.AttachShader(*program, frag_shader);
146
147 fml::ScopedCleanupClosure detach_vert_shader(
148 [&gl, program = *program, vert_shader]() {
149 gl.DetachShader(program, vert_shader);
150 });
151 fml::ScopedCleanupClosure detach_frag_shader(
152 [&gl, program = *program, frag_shader]() {
153 gl.DetachShader(program, frag_shader);
154 });
155
156 for (const auto& stage_input :
157 descriptor.GetVertexDescriptor()->GetStageInputs()) {
158 gl.BindAttribLocation(*program, //
159 static_cast<GLuint>(stage_input.location), //
160 stage_input.name //
161 );
162 }
163
164 gl.LinkProgram(*program);
165
166 GLint link_status = GL_FALSE;
167 gl.GetProgramiv(*program, GL_LINK_STATUS, &link_status);
168
169 if (link_status != GL_TRUE) {
170 VALIDATION_LOG << "Could not link shader program: "
171 << gl.GetProgramInfoLogString(*program);
172 return false;
173 }
174 return true;
175}
176
177// |PipelineLibrary|
178bool PipelineLibraryGLES::IsValid() const {
179 return reactor_ != nullptr;
180}
181
182// |PipelineLibrary|
183PipelineFuture<PipelineDescriptor> PipelineLibraryGLES::GetPipeline(
184 PipelineDescriptor descriptor,
185 bool async) {
186 if (auto found = pipelines_.find(descriptor); found != pipelines_.end()) {
187 return found->second;
188 }
189
190 if (!reactor_) {
191 return {
192 descriptor,
193 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(nullptr)};
194 }
195
196 auto vert_function = descriptor.GetEntrypointForStage(ShaderStage::kVertex);
197 auto frag_function = descriptor.GetEntrypointForStage(ShaderStage::kFragment);
198
199 if (!vert_function || !frag_function) {
201 << "Could not find stage entrypoint functions in pipeline descriptor.";
202 return {
203 descriptor,
204 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(nullptr)};
205 }
206
207 auto promise = std::make_shared<
208 std::promise<std::shared_ptr<Pipeline<PipelineDescriptor>>>>();
209 auto pipeline_future =
210 PipelineFuture<PipelineDescriptor>{descriptor, promise->get_future()};
211 pipelines_[descriptor] = pipeline_future;
212 auto weak_this = weak_from_this();
213
214 auto result = reactor_->AddOperation(
215 [promise, weak_this, reactor_ptr = reactor_, descriptor, vert_function,
216 frag_function](const ReactorGLES& reactor) {
217 auto strong_this = weak_this.lock();
218 if (!strong_this) {
219 promise->set_value(nullptr);
220 VALIDATION_LOG << "Library was collected before a pending pipeline "
221 "creation could finish.";
222 return;
223 }
224 auto pipeline = std::shared_ptr<PipelineGLES>(
225 new PipelineGLES(reactor_ptr, strong_this, descriptor));
226 auto program = reactor.GetGLHandle(pipeline->GetProgramHandle());
227 if (!program.has_value()) {
228 promise->set_value(nullptr);
229 VALIDATION_LOG << "Could not obtain program handle.";
230 return;
231 }
232 const auto link_result = LinkProgram(reactor, //
233 pipeline, //
234 vert_function, //
235 frag_function //
236 );
237 if (!link_result) {
238 promise->set_value(nullptr);
239 VALIDATION_LOG << "Could not link pipeline program.";
240 return;
241 }
242 if (!pipeline->BuildVertexDescriptor(reactor.GetProcTable(),
243 program.value())) {
244 promise->set_value(nullptr);
245 VALIDATION_LOG << "Could not build pipeline vertex descriptors.";
246 return;
247 }
248 if (!pipeline->IsValid()) {
249 promise->set_value(nullptr);
250 VALIDATION_LOG << "Pipeline validation checks failed.";
251 return;
252 }
253 promise->set_value(std::move(pipeline));
254 });
256
257 return pipeline_future;
258}
259
260// |PipelineLibrary|
261PipelineFuture<ComputePipelineDescriptor> PipelineLibraryGLES::GetPipeline(
262 ComputePipelineDescriptor descriptor,
263 bool async) {
264 auto promise = std::make_shared<
265 std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
266 // TODO(dnfield): implement compute for GLES.
267 promise->set_value(nullptr);
268 return {descriptor, promise->get_future()};
269}
270
271// |PipelineLibrary|
272void PipelineLibraryGLES::RemovePipelinesWithEntryPoint(
273 std::shared_ptr<const ShaderFunction> function) {
274 fml::erase_if(pipelines_, [&](auto item) {
275 return item->first.GetEntrypointForStage(function->GetStage())
276 ->IsEqual(*function);
277 });
278}
279
280// |PipelineLibrary|
281PipelineLibraryGLES::~PipelineLibraryGLES() = default;
282
283} // namespace impeller
Wraps a closure that is invoked in the destructor unless released by the caller.
Definition: closure.h:32
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
Definition: reactor_gles.h:55
std::optional< GLuint > GetGLHandle(const HandleGLES &handle) const
Returns the OpenGL handle for a reactor handle if one is available. This is typically only safe to ca...
Definition: reactor_gles.cc:53
const ProcTableGLES & GetProcTable() const
Get the OpenGL proc. table the reactor uses to manage handles.
Definition: reactor_gles.cc:48
std::shared_ptr< ReactorGLES > Ref
Definition: reactor_gles.h:86
GAsyncResult * result
#define FML_CHECK(condition)
Definition: logging.h:85
Dart_NativeFunction function
Definition: fuchsia.cc:51
size_t length
void * malloc(size_t size)
Definition: allocation.cc:19
void * calloc(size_t n, size_t size)
Definition: allocation.cc:11
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
void erase_if(Collection &container, std::function< bool(typename Collection::iterator)> predicate)
Definition: container.h:16
static std::string GetShaderSource(const ProcTableGLES &gl, GLuint shader)
std::string SPrintF(const char *format,...)
Definition: strings.cc:12
static std::string GetShaderInfoLog(const ProcTableGLES &gl, GLuint shader)
static void LogShaderCompilationFailure(const ProcTableGLES &gl, GLuint shader, const std::string &name, const fml::Mapping &source_mapping, ShaderStage stage)
static bool LinkProgram(const ReactorGLES &reactor, const std::shared_ptr< PipelineGLES > &pipeline, const std::shared_ptr< const ShaderFunction > &vert_function, const std::shared_ptr< const ShaderFunction > &frag_function)
gl
Definition: malisc.py:41
Definition: ref_ptr.h:256
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131
#define VALIDATION_LOG
Definition: validation.h:73