10 #include "flutter/fml/trace_event.h"
11 #include "fml/closure.h"
20 : reactor_(
std::move(reactor)) {}
24 gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
25 if (log_length == 0) {
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);
40 auto data =
static_cast<char*
>(malloc(10240));
42 gl.GetShaderSource(shader, 10240, &length,
data);
44 auto result = std::string{
data,
static_cast<size_t>(length)};
51 std::string_view name,
52 const fml::Mapping& source_mapping,
54 std::stringstream stream;
55 stream <<
"Failed to compile ";
57 case ShaderStage::kUnknown:
60 case ShaderStage::kVertex:
63 case ShaderStage::kFragment:
66 case ShaderStage::kCompute:
70 stream <<
" shader for '" << name <<
"' with error:" << std::endl;
72 stream <<
"Shader source was: " << std::endl;
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__);
84 const auto& descriptor = pipeline->GetDescriptor();
87 ShaderFunctionGLES::Cast(*vert_function).GetSourceMapping();
89 ShaderFunctionGLES::Cast(*frag_function).GetSourceMapping();
93 auto vert_shader = gl.CreateShader(GL_VERTEX_SHADER);
94 auto frag_shader = gl.CreateShader(GL_FRAGMENT_SHADER);
96 if (vert_shader == 0 || frag_shader == 0) {
101 gl.SetDebugLabel(DebugResourceType::kShader, vert_shader,
102 SPrintF(
"%s Vertex Shader", descriptor.GetLabel().data()));
103 gl.SetDebugLabel(DebugResourceType::kShader, frag_shader,
104 SPrintF(
"%s Fragment Shader", descriptor.GetLabel().data()));
106 fml::ScopedCleanupClosure delete_vert_shader(
107 [&gl, vert_shader]() { gl.DeleteShader(vert_shader); });
108 fml::ScopedCleanupClosure delete_frag_shader(
109 [&gl, frag_shader]() { gl.DeleteShader(frag_shader); });
111 gl.ShaderSourceMapping(vert_shader, *vert_mapping,
112 descriptor.GetSpecializationConstants());
113 gl.ShaderSourceMapping(frag_shader, *frag_mapping,
114 descriptor.GetSpecializationConstants());
116 gl.CompileShader(vert_shader);
117 gl.CompileShader(frag_shader);
119 GLint vert_status = GL_FALSE;
120 GLint frag_status = GL_FALSE;
122 gl.GetShaderiv(vert_shader, GL_COMPILE_STATUS, &vert_status);
123 gl.GetShaderiv(frag_shader, GL_COMPILE_STATUS, &frag_status);
125 if (vert_status != GL_TRUE) {
127 *vert_mapping, ShaderStage::kVertex);
131 if (frag_status != GL_TRUE) {
133 *frag_mapping, ShaderStage::kFragment);
137 auto program = reactor.
GetGLHandle(pipeline->GetProgramHandle());
138 if (!program.has_value()) {
143 gl.AttachShader(*program, vert_shader);
144 gl.AttachShader(*program, frag_shader);
146 fml::ScopedCleanupClosure detach_vert_shader(
147 [&gl, program = *program, vert_shader]() {
148 gl.DetachShader(program, vert_shader);
150 fml::ScopedCleanupClosure detach_frag_shader(
151 [&gl, program = *program, frag_shader]() {
152 gl.DetachShader(program, frag_shader);
155 for (
const auto& stage_input :
156 descriptor.GetVertexDescriptor()->GetStageInputs()) {
157 gl.BindAttribLocation(*program,
158 static_cast<GLuint
>(stage_input.location),
163 gl.LinkProgram(*program);
165 GLint link_status = GL_FALSE;
166 gl.GetProgramiv(*program, GL_LINK_STATUS, &link_status);
168 if (link_status != GL_TRUE) {
170 << gl.GetProgramInfoLogString(*program)
171 <<
"\nVertex Shader:\n"
180 bool PipelineLibraryGLES::IsValid()
const {
181 return reactor_ !=
nullptr;
184 std::shared_ptr<PipelineGLES> PipelineLibraryGLES::CreatePipeline(
185 const std::weak_ptr<PipelineLibrary>& weak_library,
186 const PipelineDescriptor& desc,
187 const std::shared_ptr<const ShaderFunction>& vert_function,
188 const std::shared_ptr<const ShaderFunction>& frag_function) {
189 auto strong_library = weak_library.lock();
191 if (!strong_library) {
192 VALIDATION_LOG <<
"Library was collected before a pending pipeline "
193 "creation could finish.";
197 auto& library = PipelineLibraryGLES::Cast(*strong_library);
199 const auto& reactor = library.GetReactor();
205 auto program_key = ProgramKey{vert_function, frag_function,
206 desc.GetSpecializationConstants()};
208 auto cached_program = library.GetProgramForKey(program_key);
210 const auto has_cached_program = !!cached_program;
212 auto pipeline = std::shared_ptr<PipelineGLES>(
new PipelineGLES(
217 ? std::move(cached_program)
218 : std::make_shared<UniqueHandleGLES>(UniqueHandleGLES::MakeUntracked(
219 reactor, HandleType::kProgram))));
221 auto program = reactor->GetGLHandle(pipeline->GetProgramHandle());
223 if (!program.has_value()) {
228 const auto link_result = !has_cached_program ?
LinkProgram(*reactor,
240 if (!pipeline->BuildVertexDescriptor(reactor->GetProcTable(),
246 if (!pipeline->IsValid()) {
251 if (!has_cached_program) {
252 library.SetProgramForKey(program_key, pipeline->GetSharedHandle());
259 PipelineFuture<PipelineDescriptor> PipelineLibraryGLES::GetPipeline(
260 PipelineDescriptor descriptor,
263 return found->second;
269 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(
nullptr)};
272 auto vert_function = descriptor.GetEntrypointForStage(ShaderStage::kVertex);
273 auto frag_function = descriptor.GetEntrypointForStage(ShaderStage::kFragment);
275 if (!vert_function || !frag_function) {
277 <<
"Could not find stage entrypoint functions in pipeline descriptor.";
280 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(
nullptr)};
283 auto promise = std::make_shared<
284 std::promise<std::shared_ptr<Pipeline<PipelineDescriptor>>>>();
285 auto pipeline_future =
286 PipelineFuture<PipelineDescriptor>{descriptor, promise->get_future()};
289 const auto result = reactor_->AddOperation([promise,
290 weak_this = weak_from_this(),
294 ](
const ReactorGLES& reactor) {
296 CreatePipeline(weak_this, descriptor, vert_function, frag_function));
300 return pipeline_future;
304 PipelineFuture<ComputePipelineDescriptor> PipelineLibraryGLES::GetPipeline(
305 ComputePipelineDescriptor descriptor,
307 auto promise = std::make_shared<
308 std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
309 promise->set_value(
nullptr);
310 return {descriptor, promise->get_future()};
314 bool PipelineLibraryGLES::HasPipeline(
const PipelineDescriptor& descriptor) {
319 void PipelineLibraryGLES::RemovePipelinesWithEntryPoint(
320 std::shared_ptr<const ShaderFunction>
function) {
321 Lock lock(programs_mutex_);
323 PipelineMap::iterator it =
pipelines_.begin();
325 const PipelineDescriptor& desc = it->first;
326 if (desc.GetEntrypointForStage(function->GetStage())->IsEqual(*
function)) {
327 const std::shared_ptr<const ShaderFunction>& vert_function =
328 desc.GetEntrypointForStage(ShaderStage::kVertex);
329 const std::shared_ptr<const ShaderFunction>& frag_function =
330 desc.GetEntrypointForStage(ShaderStage::kFragment);
331 ProgramKey program_key{vert_function, frag_function,
332 desc.GetSpecializationConstants()};
333 programs_.erase(program_key);
342 PipelineLibraryGLES::~PipelineLibraryGLES() =
default;
344 const std::shared_ptr<ReactorGLES>& PipelineLibraryGLES::GetReactor()
const {
348 std::shared_ptr<UniqueHandleGLES> PipelineLibraryGLES::GetProgramForKey(
349 const ProgramKey& key) {
350 Lock lock(programs_mutex_);
351 auto found = programs_.find(key);
352 if (found != programs_.end()) {
353 return found->second;
358 void PipelineLibraryGLES::SetProgramForKey(
359 const ProgramKey& key,
360 std::shared_ptr<UniqueHandleGLES> program) {
361 Lock lock(programs_mutex_);
362 programs_[key] = std::move(program);
PipelineLibraryGLES(const PipelineLibraryGLES &)=delete
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
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...
const ProcTableGLES & GetProcTable() const
Get the OpenGL proc. table the reactor uses to manage handles.
std::vector< std::pair< uint64_t, std::unique_ptr< GenericRenderPipelineHandle > > > pipelines_
static void LogShaderCompilationFailure(const ProcTableGLES &gl, GLuint shader, std::string_view name, const fml::Mapping &source_mapping, ShaderStage stage)
static std::string GetShaderSource(const ProcTableGLES &gl, GLuint shader)
std::string SPrintF(const char *format,...)
static std::string GetShaderInfoLog(const ProcTableGLES &gl, GLuint shader)
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)
std::shared_ptr< const fml::Mapping > data