| Flutter Impeller |

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
5 #include "impeller/renderer/backend/gles/pipeline_library_gles.h"
6
7 #include <sstream>
8 #include <string>
9
10 #include "flutter/fml/container.h"
11 #include "flutter/fml/trace_event.h"
12 #include "impeller/base/promise.h"
13 #include "impeller/renderer/backend/gles/pipeline_gles.h"
14 #include "impeller/renderer/backend/gles/shader_function_gles.h"
15
16 namespace impeller {
17
18 PipelineLibraryGLES::PipelineLibraryGLES(ReactorGLES::Ref reactor)
19 : reactor_(std::move(reactor)) {}
20
21 static std::string GetShaderInfoLog(const ProcTableGLES& gl, GLuint shader) {
22 GLint log_length = 0;
23 gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
24 if (log_length == 0) {
25 return "";
26 }
27 auto log_buffer =
28 reinterpret_cast<char*>(std::calloc(log_length, sizeof(char)));
29 gl.GetShaderInfoLog(shader, log_length, &log_length, log_buffer);
30 auto log_string = std::string(log_buffer, log_length);
31 std::free(log_buffer);
32 return log_string;
33 }
34
35 static void LogShaderCompilationFailure(const ProcTableGLES& gl,
36 GLuint shader,
37 const std::string& name,
38 const fml::Mapping& source_mapping,
39 ShaderStage stage) {
40 std::stringstream stream;
41 stream << "Failed to compile ";
42 switch (stage) {
43 case ShaderStage::kUnknown:
44 stream << "unknown";
45 break;
46 case ShaderStage::kVertex:
47 stream << "vertex";
48 break;
49 case ShaderStage::kFragment:
50 stream << "fragment";
51 break;
52 case ShaderStage::kTessellationControl:
53 stream << "tessellation control";
54 break;
55 case ShaderStage::kTessellationEvaluation:
56 stream << "tessellation evaluation";
57 break;
58 case ShaderStage::kCompute:
59 stream << "compute";
60 break;
61 }
62 stream << " shader for '" << name << "' with error:" << std::endl;
63 stream << GetShaderInfoLog(gl, shader) << std::endl;
64 stream << "Shader source was: " << std::endl;
65 stream << std::string{reinterpret_cast<const char*>(
66 source_mapping.GetMapping()),
67 source_mapping.GetSize()}
68 << std::endl;
69 VALIDATION_LOG << stream.str();
70 }
71
72 static bool LinkProgram(
73 const ReactorGLES& reactor,
74 const std::shared_ptr<PipelineGLES>& pipeline,
75 const std::shared_ptr<const ShaderFunction>& vert_function,
76 const std::shared_ptr<const ShaderFunction>& frag_function) {
77 TRACE_EVENT0("impeller", __FUNCTION__);
78
79 const auto& descriptor = pipeline->GetDescriptor();
80
81 auto vert_mapping =
82 ShaderFunctionGLES::Cast(*vert_function).GetSourceMapping();
83 auto frag_mapping =
84 ShaderFunctionGLES::Cast(*frag_function).GetSourceMapping();
85
86 const auto& gl = reactor.GetProcTable();
87
88 auto vert_shader = gl.CreateShader(GL_VERTEX_SHADER);
89 auto frag_shader = gl.CreateShader(GL_FRAGMENT_SHADER);
90
91 if (vert_shader == 0 || frag_shader == 0) {
92 VALIDATION_LOG << "Could not create shader handles.";
93 return false;
94 }
95
96 gl.SetDebugLabel(DebugResourceType::kShader, vert_shader,
97 SPrintF("%s Vertex Shader", descriptor.GetLabel().c_str()));
98 gl.SetDebugLabel(
99 DebugResourceType::kShader, frag_shader,
100 SPrintF("%s Fragment Shader", descriptor.GetLabel().c_str()));
101
102 fml::ScopedCleanupClosure delete_vert_shader(
103 [&gl, vert_shader]() { gl.DeleteShader(vert_shader); });
104 fml::ScopedCleanupClosure delete_frag_shader(
105 [&gl, frag_shader]() { gl.DeleteShader(frag_shader); });
106
107 gl.ShaderSourceMapping(vert_shader, *vert_mapping);
108 gl.ShaderSourceMapping(frag_shader, *frag_mapping);
109
110 gl.CompileShader(vert_shader);
111 gl.CompileShader(frag_shader);
112
113 GLint vert_status = GL_FALSE;
114 GLint frag_status = GL_FALSE;
115
116 gl.GetShaderiv(vert_shader, GL_COMPILE_STATUS, &vert_status);
117 gl.GetShaderiv(frag_shader, GL_COMPILE_STATUS, &frag_status);
118
119 if (vert_status != GL_TRUE) {
120 LogShaderCompilationFailure(gl, vert_shader, descriptor.GetLabel(),
121 *vert_mapping, ShaderStage::kVertex);
122 return false;
123 }
124
125 if (frag_status != GL_TRUE) {
126 LogShaderCompilationFailure(gl, frag_shader, descriptor.GetLabel(),
127 *frag_mapping, ShaderStage::kFragment);
128 return false;
129 }
130
131 auto program = reactor.GetGLHandle(pipeline->GetProgramHandle());
132 if (!program.has_value()) {
133 VALIDATION_LOG << "Could not get program handle from reactor.";
134 return false;
135 }
136
137 gl.AttachShader(*program, vert_shader);
138 gl.AttachShader(*program, frag_shader);
139
140 fml::ScopedCleanupClosure detach_vert_shader(
141 [&gl, program = *program, vert_shader]() {
142 gl.DetachShader(program, vert_shader);
143 });
144 fml::ScopedCleanupClosure detach_frag_shader(
145 [&gl, program = *program, frag_shader]() {
146 gl.DetachShader(program, frag_shader);
147 });
148
149 for (const auto& stage_input :
150 descriptor.GetVertexDescriptor()->GetStageInputs()) {
151 gl.BindAttribLocation(*program, //
152 static_cast<GLuint>(stage_input.location), //
153 stage_input.name //
154 );
155 }
156
157 gl.LinkProgram(*program);
158
159 GLint link_status = GL_FALSE;
160 gl.GetProgramiv(*program, GL_LINK_STATUS, &link_status);
161
162 if (link_status != GL_TRUE) {
163 VALIDATION_LOG << "Could not link shader program: "
164 << gl.GetProgramInfoLogString(*program);
165 return false;
166 }
167 return true;
168 }
169
170 // |PipelineLibrary|
171 bool PipelineLibraryGLES::IsValid() const {
172 return reactor_ != nullptr;
173 }
174
175 // |PipelineLibrary|
176 PipelineFuture<PipelineDescriptor> PipelineLibraryGLES::GetPipeline(
177 PipelineDescriptor descriptor) {
178 if (auto found = pipelines_.find(descriptor); found != pipelines_.end()) {
179 return found->second;
180 }
181
182 if (!reactor_) {
183 return {
184 descriptor,
185 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(nullptr)};
186 }
187
188 auto vert_function = descriptor.GetEntrypointForStage(ShaderStage::kVertex);
189 auto frag_function = descriptor.GetEntrypointForStage(ShaderStage::kFragment);
190
191 if (!vert_function || !frag_function) {
192 VALIDATION_LOG
193 << "Could not find stage entrypoint functions in pipeline descriptor.";
194 return {
195 descriptor,
196 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(nullptr)};
197 }
198
199 auto promise = std::make_shared<
200 std::promise<std::shared_ptr<Pipeline<PipelineDescriptor>>>>();
201 auto pipeline_future =
202 PipelineFuture<PipelineDescriptor>{descriptor, promise->get_future()};
203 pipelines_[descriptor] = pipeline_future;
204 auto weak_this = weak_from_this();
205
206 auto result = reactor_->AddOperation(
207 [promise, weak_this, reactor_ptr = reactor_, descriptor, vert_function,
208 frag_function](const ReactorGLES& reactor) {
209 auto strong_this = weak_this.lock();
210 if (!strong_this) {
211 promise->set_value(nullptr);
212 VALIDATION_LOG << "Library was collected before a pending pipeline "
213 "creation could finish.";
214 return;
215 }
216 auto pipeline = std::shared_ptr<PipelineGLES>(
217 new PipelineGLES(reactor_ptr, strong_this, descriptor));
218 auto program = reactor.GetGLHandle(pipeline->GetProgramHandle());
219 if (!program.has_value()) {
220 promise->set_value(nullptr);
221 VALIDATION_LOG << "Could not obtain program handle.";
222 return;
223 }
224 const auto link_result = LinkProgram(reactor, //
225 pipeline, //
226 vert_function, //
227 frag_function //
228 );
229 if (!link_result) {
230 promise->set_value(nullptr);
231 VALIDATION_LOG << "Could not link pipeline program.";
232 return;
233 }
234 if (!pipeline->BuildVertexDescriptor(reactor.GetProcTable(),
235 program.value())) {
236 promise->set_value(nullptr);
237 VALIDATION_LOG << "Could not build pipeline vertex descriptors.";
238 return;
239 }
240 if (!pipeline->IsValid()) {
241 promise->set_value(nullptr);
242 VALIDATION_LOG << "Pipeline validation checks failed.";
243 return;
244 }
245 promise->set_value(std::move(pipeline));
246 });
247 FML_CHECK(result);
248
249 return pipeline_future;
250 }
251
252 // |PipelineLibrary|
253 PipelineFuture<ComputePipelineDescriptor> PipelineLibraryGLES::GetPipeline(
254 ComputePipelineDescriptor descriptor) {
255 auto promise = std::make_shared<
256 std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
257 // TODO(dnfield): implement compute for GLES.
258 promise->set_value(nullptr);
259 return {descriptor, promise->get_future()};
260 }
261
262 // |PipelineLibrary|
263 void PipelineLibraryGLES::RemovePipelinesWithEntryPoint(
264 std::shared_ptr<const ShaderFunction> function) {
265 fml::erase_if(pipelines_, [&](auto item) {
266 return item->first.GetEntrypointForStage(function->GetStage())
267 ->IsEqual(*function);
268 });
269 }
270
271 // |PipelineLibrary|
272 PipelineLibraryGLES::~PipelineLibraryGLES() = default;
273
274 } // namespace impeller
impeller::ReactorGLES::GetProcTable
const ProcTableGLES & GetProcTable() const
Definition: reactor_gles.cc:47
impeller::ShaderStage::kUnknown
@ kUnknown
impeller::ReactorGLES::Ref
std::shared_ptr< ReactorGLES > Ref
Definition: reactor_gles.h:31
impeller::LinkProgram
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)
Definition: pipeline_library_gles.cc:72
impeller::ShaderStage
ShaderStage
Definition: shader_types.h:20
impeller::LogShaderCompilationFailure
static void LogShaderCompilationFailure(const ProcTableGLES &gl, GLuint shader, const std::string &name, const fml::Mapping &source_mapping, ShaderStage stage)
Definition: pipeline_library_gles.cc:35
impeller::ShaderFunctionGLES::GetSourceMapping
const std::shared_ptr< const fml::Mapping > & GetSourceMapping() const
Definition: shader_function_gles.cc:20
impeller::SPrintF
std::string SPrintF(const char *format,...)
Definition: strings.cc:12
impeller::ShaderStage::kTessellationEvaluation
@ kTessellationEvaluation
impeller::ProcTableGLES
Definition: proc_table_gles.h:188
impeller::ShaderStage::kFragment
@ kFragment
impeller::DebugResourceType::kShader
@ kShader
shader_function_gles.h
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
pipeline_library_gles.h
pipeline_gles.h
promise.h
std
Definition: comparable.h:98
impeller::ShaderStage::kVertex
@ kVertex
impeller::BackendCast< ShaderFunctionGLES, ShaderFunction >::Cast
static ShaderFunctionGLES & Cast(ShaderFunction &base)
Definition: backend_cast.h:14
impeller::ReactorGLES
Definition: reactor_gles.h:19
impeller::ShaderStage::kCompute
@ kCompute
impeller::ShaderStage::kTessellationControl
@ kTessellationControl
impeller::GetShaderInfoLog
static std::string GetShaderInfoLog(const ProcTableGLES &gl, GLuint shader)
Definition: pipeline_library_gles.cc:21
impeller::PipelineLibraryGLES::~PipelineLibraryGLES
~PipelineLibraryGLES() override
impeller
Definition: aiks_context.cc:10
impeller::ReactorGLES::GetGLHandle
std::optional< GLuint > GetGLHandle(const HandleGLES &handle) const
Definition: reactor_gles.cc:52