20 std::shared_ptr<ReactorGLES>
reactor,
21 std::shared_ptr<fml::BasicTaskRunner> io_task_runner)
24 PipelineCompileQueueGLES::
Create(
std::move(io_task_runner))) {}
28 gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
29 if (log_length == 0) {
33 reinterpret_cast<char*
>(std::calloc(log_length,
sizeof(
char)));
34 gl.GetShaderInfoLog(shader, log_length, &log_length, log_buffer);
35 auto log_string = std::string(log_buffer, log_length);
36 std::free(log_buffer);
44 auto data =
static_cast<char*
>(malloc(10240));
46 gl.GetShaderSource(shader, 10240, &
length, data);
48 auto result = std::string{data,
static_cast<size_t>(
length)};
55 std::string_view
name,
58 std::stringstream stream;
59 stream <<
"Failed to compile ";
61 case ShaderStage::kUnknown:
64 case ShaderStage::kVertex:
67 case ShaderStage::kFragment:
70 case ShaderStage::kCompute:
74 stream <<
" shader for '" <<
name <<
"' with error:" << std::endl;
76 stream <<
"Shader source was: " << std::endl;
83 const std::shared_ptr<PipelineGLES>&
pipeline,
84 const std::shared_ptr<const ShaderFunction>& vert_function,
85 const std::shared_ptr<const ShaderFunction>& frag_function) {
88 const auto& descriptor =
pipeline->GetDescriptor();
91 ShaderFunctionGLES::Cast(*vert_function).GetSourceMapping();
93 ShaderFunctionGLES::Cast(*frag_function).GetSourceMapping();
95 const auto& gl =
reactor.GetProcTable();
97 auto vert_shader = gl.CreateShader(GL_VERTEX_SHADER);
98 auto frag_shader = gl.CreateShader(GL_FRAGMENT_SHADER);
100 if (vert_shader == 0 || frag_shader == 0) {
105 gl.SetDebugLabel(DebugResourceType::kShader, vert_shader,
106 std::format(
"{} Vertex Shader", descriptor.GetLabel()));
107 gl.SetDebugLabel(DebugResourceType::kShader, frag_shader,
108 std::format(
"{} Fragment Shader", descriptor.GetLabel()));
111 [&gl, vert_shader]() { gl.DeleteShader(vert_shader); });
113 [&gl, frag_shader]() { gl.DeleteShader(frag_shader); });
115 gl.ShaderSourceMapping(vert_shader, *vert_mapping,
116 descriptor.GetSpecializationConstants());
117 gl.ShaderSourceMapping(frag_shader, *frag_mapping,
118 descriptor.GetSpecializationConstants());
120 gl.CompileShader(vert_shader);
121 gl.CompileShader(frag_shader);
123 GLint vert_status = GL_FALSE;
124 GLint frag_status = GL_FALSE;
126 gl.GetShaderiv(vert_shader, GL_COMPILE_STATUS, &vert_status);
127 gl.GetShaderiv(frag_shader, GL_COMPILE_STATUS, &frag_status);
129 if (vert_status != GL_TRUE) {
131 *vert_mapping, ShaderStage::kVertex);
135 if (frag_status != GL_TRUE) {
137 *frag_mapping, ShaderStage::kFragment);
142 if (!program.has_value()) {
147 gl.AttachShader(*program, vert_shader);
148 gl.AttachShader(*program, frag_shader);
151 [&gl, program = *program, vert_shader]() {
152 gl.DetachShader(program, vert_shader);
155 [&gl, program = *program, frag_shader]() {
156 gl.DetachShader(program, frag_shader);
159 for (
const auto& stage_input :
160 descriptor.GetVertexDescriptor()->GetStageInputs()) {
161 gl.BindAttribLocation(*program,
162 static_cast<GLuint
>(stage_input.location),
167 gl.LinkProgram(*program);
169 GLint link_status = GL_FALSE;
170 gl.GetProgramiv(*program, GL_LINK_STATUS, &link_status);
172 if (link_status != GL_TRUE) {
174 << gl.GetProgramInfoLogString(*program)
175 <<
"\nVertex Shader:\n"
184bool PipelineLibraryGLES::IsValid()
const {
185 return reactor_ !=
nullptr;
188std::shared_ptr<PipelineGLES> PipelineLibraryGLES::CreatePipeline(
189 const std::weak_ptr<PipelineLibrary>& weak_library,
190 const PipelineDescriptor& desc,
191 const std::shared_ptr<const ShaderFunction>& vert_function,
192 const std::shared_ptr<const ShaderFunction>& frag_function,
194 auto strong_library = weak_library.lock();
196 if (!strong_library) {
197 VALIDATION_LOG <<
"Library was collected before a pending pipeline "
198 "creation could finish.";
202 auto& library = PipelineLibraryGLES::Cast(*strong_library);
204 const auto&
reactor = library.GetReactor();
210 auto program_key = ProgramKey{vert_function, frag_function,
211 desc.GetSpecializationConstants()};
213 auto cached_program = library.GetProgramForKey(program_key);
215 const auto has_cached_program = !!cached_program;
217 std::shared_ptr<UniqueHandleGLES> program_handle =
nullptr;
218 if (has_cached_program) {
219 program_handle = std::move(cached_program);
221 program_handle = threadsafe ? std::make_shared<UniqueHandleGLES>(
223 :
std::make_shared<UniqueHandleGLES>(
224 UniqueHandleGLES::MakeUntracked(
228 auto pipeline = std::shared_ptr<PipelineGLES>(
232 std::move(program_handle)));
236 if (!program.has_value()) {
264 if (!has_cached_program) {
265 library.SetProgramForKey(program_key,
pipeline->GetSharedHandle());
272PipelineFuture<PipelineDescriptor> PipelineLibraryGLES::GetPipeline(
273 PipelineDescriptor descriptor,
277 return found->second;
283 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(
nullptr)};
286 auto vert_function = descriptor.GetEntrypointForStage(ShaderStage::kVertex);
287 auto frag_function = descriptor.GetEntrypointForStage(ShaderStage::kFragment);
289 if (!vert_function || !frag_function) {
291 <<
"Could not find stage entrypoint functions in pipeline descriptor.";
294 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(
nullptr)};
297 auto promise = std::make_shared<
298 std::promise<std::shared_ptr<Pipeline<PipelineDescriptor>>>>();
299 auto pipeline_future =
300 PipelineFuture<PipelineDescriptor>{descriptor, promise->get_future()};
303 std::weak_ptr<PipelineLibrary> weak_this = weak_from_this();
304 std::shared_ptr<ReactorGLES>
reactor = reactor_;
305 auto generation_task = [promise, weak_this, descriptor, vert_function,
306 frag_function, threadsafe,
reactor]() {
307 auto thiz = weak_this.lock();
309 promise->set_value(
nullptr);
312 const bool result =
reactor->AddOperation([promise,
318 ](
const ReactorGLES&
reactor) {
319 promise->set_value(CreatePipeline(weak_this, descriptor, vert_function,
320 frag_function, threadsafe));
325 if (async && compile_queue_) {
326 compile_queue_->PostJobForDescriptor(descriptor,
327 std::move(generation_task));
332 return pipeline_future;
336PipelineFuture<ComputePipelineDescriptor> PipelineLibraryGLES::GetPipeline(
337 ComputePipelineDescriptor descriptor,
339 auto promise = std::make_shared<
340 std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
341 promise->set_value(
nullptr);
342 return {descriptor, promise->get_future()};
346bool PipelineLibraryGLES::HasPipeline(
const PipelineDescriptor& descriptor) {
351void PipelineLibraryGLES::RemovePipelinesWithEntryPoint(
352 std::shared_ptr<const ShaderFunction> function) {
353 Lock lock(programs_mutex_);
355 PipelineMap::iterator it =
pipelines_.begin();
357 const PipelineDescriptor& desc = it->first;
358 if (desc.GetEntrypointForStage(
function->GetStage())->IsEqual(*function)) {
359 const std::shared_ptr<const ShaderFunction>& vert_function =
360 desc.GetEntrypointForStage(ShaderStage::kVertex);
361 const std::shared_ptr<const ShaderFunction>& frag_function =
362 desc.GetEntrypointForStage(ShaderStage::kFragment);
363 ProgramKey program_key{vert_function, frag_function,
364 desc.GetSpecializationConstants()};
365 programs_.erase(program_key);
374PipelineLibraryGLES::~PipelineLibraryGLES() =
default;
376const std::shared_ptr<ReactorGLES>& PipelineLibraryGLES::GetReactor()
const {
380std::shared_ptr<UniqueHandleGLES> PipelineLibraryGLES::GetProgramForKey(
381 const ProgramKey&
key) {
382 Lock lock(programs_mutex_);
383 auto found = programs_.find(
key);
384 if (found != programs_.end()) {
385 return found->second;
390void PipelineLibraryGLES::SetProgramForKey(
391 const ProgramKey&
key,
392 std::shared_ptr<UniqueHandleGLES> program) {
393 Lock lock(programs_mutex_);
394 programs_[
key] = std::move(program);
397PipelineCompileQueue* PipelineLibraryGLES::GetPipelineCompileQueue()
const {
398 return compile_queue_.get();
Wraps a closure that is invoked in the destructor unless released by the caller.
PipelineLibraryGLES(const PipelineLibraryGLES &)=delete
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
std::vector< std::pair< uint64_t, std::unique_ptr< GenericRenderPipelineHandle > > > pipelines_
#define FML_CHECK(condition)
Dart_NativeFunction function
ScopedObject< Object > Create(CtorArgs &&... args)
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)
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< ReactorGLES > reactor
std::shared_ptr< PipelineGLES > pipeline
#define TRACE_EVENT0(category_group, name)