diff --git a/engine/src/flutter/impeller/compiler/compiler.cc b/engine/src/flutter/impeller/compiler/compiler.cc index 6123ad3f15..8cef217d9b 100644 --- a/engine/src/flutter/impeller/compiler/compiler.cc +++ b/engine/src/flutter/impeller/compiler/compiler.cc @@ -156,11 +156,15 @@ static CompilerBackend CreateGLSLCompiler(const spirv_cross::ParsedIR& ir, sl_options.force_zero_initialized_variables = true; sl_options.vertex.fixup_clipspace = true; if (source_options.target_platform == TargetPlatform::kOpenGLES || - source_options.target_platform == TargetPlatform::kRuntimeStageGLES) { + source_options.target_platform == TargetPlatform::kRuntimeStageGLES || + source_options.target_platform == TargetPlatform::kRuntimeStageGLES3) { sl_options.version = source_options.gles_language_version > 0 ? source_options.gles_language_version : 100; sl_options.es = true; + if (source_options.target_platform == TargetPlatform::kRuntimeStageGLES3) { + sl_options.version = 300; + } if (source_options.require_framebuffer_fetch && source_options.type == SourceType::kFragmentShader) { gl_compiler->remap_ext_framebuffer_fetch(0, 0, true); @@ -202,6 +206,7 @@ static bool EntryPointMustBeNamedMain(TargetPlatform platform) { case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: return true; } FML_UNREACHABLE(); @@ -224,6 +229,7 @@ static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR& ir, case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: compiler = CreateGLSLCompiler(ir, source_options); break; case TargetPlatform::kSkSL: @@ -317,7 +323,8 @@ Compiler::Compiler(const std::shared_ptr& source_mapping, spirv_options.target = target; } break; case TargetPlatform::kRuntimeStageMetal: - case TargetPlatform::kRuntimeStageGLES: { + case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: { SPIRVCompilerTargetEnv target; target.env = shaderc_target_env::shaderc_target_env_opengl; diff --git a/engine/src/flutter/impeller/compiler/impellerc_main.cc b/engine/src/flutter/impeller/compiler/impellerc_main.cc index a0535a2882..e4b5435037 100644 --- a/engine/src/flutter/impeller/compiler/impellerc_main.cc +++ b/engine/src/flutter/impeller/compiler/impellerc_main.cc @@ -207,6 +207,7 @@ static bool OutputDepfile(const Compiler& compiler, const Switches& switches) { case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageMetal: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: case TargetPlatform::kRuntimeStageVulkan: case TargetPlatform::kSkSL: case TargetPlatform::kVulkan: diff --git a/engine/src/flutter/impeller/compiler/reflector.cc b/engine/src/flutter/impeller/compiler/reflector.cc index 23792ea692..5f9ba45eb1 100644 --- a/engine/src/flutter/impeller/compiler/reflector.cc +++ b/engine/src/flutter/impeller/compiler/reflector.cc @@ -312,6 +312,8 @@ static std::optional GetRuntimeStageBackend( return RuntimeStageBackend::kMetal; case TargetPlatform::kRuntimeStageGLES: return RuntimeStageBackend::kOpenGLES; + case TargetPlatform::kRuntimeStageGLES3: + return RuntimeStageBackend::kOpenGLES3; case TargetPlatform::kRuntimeStageVulkan: return RuntimeStageBackend::kVulkan; case TargetPlatform::kSkSL: diff --git a/engine/src/flutter/impeller/compiler/runtime_stage_data.cc b/engine/src/flutter/impeller/compiler/runtime_stage_data.cc index b45926305f..c7b28a6184 100644 --- a/engine/src/flutter/impeller/compiler/runtime_stage_data.cc +++ b/engine/src/flutter/impeller/compiler/runtime_stage_data.cc @@ -204,6 +204,8 @@ static std::string RuntimeStageBackendToString(RuntimeStageBackend backend) { return "opengles"; case RuntimeStageBackend::kVulkan: return "vulkan"; + case RuntimeStageBackend::kOpenGLES3: + return "opengles3"; } } @@ -384,6 +386,9 @@ RuntimeStageData::CreateMultiStageFlatbuffer() const { case RuntimeStageBackend::kVulkan: runtime_stages->vulkan = std::move(runtime_stage); break; + case RuntimeStageBackend::kOpenGLES3: + runtime_stages->opengles3 = std::move(runtime_stage); + break; } } return runtime_stages; diff --git a/engine/src/flutter/impeller/compiler/switches.cc b/engine/src/flutter/impeller/compiler/switches.cc index 31ae741707..1dba36b211 100644 --- a/engine/src/flutter/impeller/compiler/switches.cc +++ b/engine/src/flutter/impeller/compiler/switches.cc @@ -29,6 +29,7 @@ static const std::map kKnownRuntimeStages = { {"sksl", TargetPlatform::kSkSL}, {"runtime-stage-metal", TargetPlatform::kRuntimeStageMetal}, {"runtime-stage-gles", TargetPlatform::kRuntimeStageGLES}, + {"runtime-stage-gles3", TargetPlatform::kRuntimeStageGLES3}, {"runtime-stage-vulkan", TargetPlatform::kRuntimeStageVulkan}, }; diff --git a/engine/src/flutter/impeller/compiler/types.cc b/engine/src/flutter/impeller/compiler/types.cc index 2368bcd20f..85e197b99d 100644 --- a/engine/src/flutter/impeller/compiler/types.cc +++ b/engine/src/flutter/impeller/compiler/types.cc @@ -89,6 +89,8 @@ std::string TargetPlatformToString(TargetPlatform platform) { return "RuntimeStageMetal"; case TargetPlatform::kRuntimeStageGLES: return "RuntimeStageGLES"; + case TargetPlatform::kRuntimeStageGLES3: + return "RuntimeStageGLES3"; case TargetPlatform::kRuntimeStageVulkan: return "RuntimeStageVulkan"; case TargetPlatform::kSkSL: @@ -146,6 +148,7 @@ bool TargetPlatformNeedsReflection(TargetPlatform platform) { case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageMetal: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: case TargetPlatform::kRuntimeStageVulkan: case TargetPlatform::kVulkan: return true; @@ -221,6 +224,7 @@ spirv_cross::CompilerMSL::Options::Platform TargetPlatformToMSLPlatform( case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: case TargetPlatform::kRuntimeStageVulkan: case TargetPlatform::kVulkan: case TargetPlatform::kUnknown: @@ -255,6 +259,7 @@ std::string TargetPlatformSLExtension(TargetPlatform platform) { case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: return "glsl"; case TargetPlatform::kVulkan: case TargetPlatform::kRuntimeStageVulkan: @@ -268,6 +273,7 @@ bool TargetPlatformIsOpenGL(TargetPlatform platform) { case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: return true; case TargetPlatform::kMetalDesktop: case TargetPlatform::kRuntimeStageMetal: @@ -292,6 +298,7 @@ bool TargetPlatformIsMetal(TargetPlatform platform) { case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: case TargetPlatform::kRuntimeStageVulkan: case TargetPlatform::kVulkan: return false; @@ -312,6 +319,7 @@ bool TargetPlatformIsVulkan(TargetPlatform platform) { case TargetPlatform::kOpenGLES: case TargetPlatform::kOpenGLDesktop: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: return false; } FML_UNREACHABLE(); @@ -322,6 +330,7 @@ bool TargetPlatformBundlesSkSL(TargetPlatform platform) { case TargetPlatform::kSkSL: case TargetPlatform::kRuntimeStageMetal: case TargetPlatform::kRuntimeStageGLES: + case TargetPlatform::kRuntimeStageGLES3: case TargetPlatform::kRuntimeStageVulkan: return true; case TargetPlatform::kMetalDesktop: diff --git a/engine/src/flutter/impeller/compiler/types.h b/engine/src/flutter/impeller/compiler/types.h index 81b631d49e..3878d0cef6 100644 --- a/engine/src/flutter/impeller/compiler/types.h +++ b/engine/src/flutter/impeller/compiler/types.h @@ -34,6 +34,7 @@ enum class TargetPlatform { kVulkan, kRuntimeStageMetal, kRuntimeStageGLES, + kRuntimeStageGLES3, kRuntimeStageVulkan, kSkSL, }; diff --git a/engine/src/flutter/impeller/core/runtime_types.h b/engine/src/flutter/impeller/core/runtime_types.h index 1d8ca60b29..84eb052991 100644 --- a/engine/src/flutter/impeller/core/runtime_types.h +++ b/engine/src/flutter/impeller/core/runtime_types.h @@ -17,6 +17,7 @@ enum class RuntimeStageBackend { kSkSL, kMetal, kOpenGLES, + kOpenGLES3, kVulkan, }; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.cc index 491f9f24d7..3f10bc9b5d 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.cc @@ -8,6 +8,8 @@ #include #include "impeller/base/validation.h" +#include "impeller/core/buffer_view.h" +#include "impeller/core/device_buffer.h" #include "impeller/core/shader_types.h" #include "impeller/renderer/backend/gles/device_buffer_gles.h" #include "impeller/renderer/backend/gles/formats_gles.h" @@ -101,6 +103,38 @@ bool BufferBindingsGLES::ReadUniformsBindings(const ProcTableGLES& gl, if (!gl.IsProgram(program)) { return false; } + program_handle_ = program; + if (gl.GetDescription()->GetGlVersion().IsAtLeast(Version{3, 0, 0})) { + return ReadUniformsBindingsV3(gl, program); + } + return ReadUniformsBindingsV2(gl, program); +} + +bool BufferBindingsGLES::ReadUniformsBindingsV3(const ProcTableGLES& gl, + GLuint program) { + program_handle_ = program; + GLint uniform_blocks = 0; + gl.GetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &uniform_blocks); + for (GLint i = 0; i < uniform_blocks; i++) { + GLint name_length = 0; + gl.GetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_NAME_LENGTH, + &name_length); + + std::vector name; + name.resize(name_length); + GLint length = 0; + gl.GetActiveUniformBlockName(program, i, name_length, &length, name.data()); + + GLuint block_index = gl.GetUniformBlockIndex(program, name.data()); + ubo_locations_[std::string{name.data(), static_cast(length)}] = + std::make_pair(block_index, i); + } + use_ubo_ = true; + return ReadUniformsBindingsV2(gl, program); +} + +bool BufferBindingsGLES::ReadUniformsBindingsV2(const ProcTableGLES& gl, + GLuint program) { GLint max_name_size = 0; gl.GetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_name_size); @@ -139,6 +173,9 @@ bool BufferBindingsGLES::ReadUniformsBindings(const ProcTableGLES& gl, auto location = gl.GetUniformLocation(program, name.data()); if (location == -1) { + if (use_ubo_) { + continue; + } VALIDATION_LOG << "Could not query the location of an active uniform."; return false; } @@ -280,8 +317,47 @@ bool BufferBindingsGLES::BindUniformBuffer(const ProcTableGLES& gl, } const DeviceBufferGLES& device_buffer_gles = DeviceBufferGLES::Cast(*device_buffer); + + if (use_ubo_) { + return BindUniformBufferV3(gl, buffer.resource, metadata, + device_buffer_gles); + } + return BindUniformBufferV2(gl, buffer.resource, metadata, device_buffer_gles); +} + +bool BufferBindingsGLES::BindUniformBufferV3( + const ProcTableGLES& gl, + const BufferView& buffer, + const ShaderMetadata* metadata, + const DeviceBufferGLES& device_buffer_gles) { + absl::flat_hash_map>::iterator it = + ubo_locations_.find(metadata->name); + if (it == ubo_locations_.end()) { + return BindUniformBufferV2(gl, buffer, metadata, device_buffer_gles); + } + const auto& [block_index, binding_point] = it->second; + gl.UniformBlockBinding(program_handle_, block_index, binding_point); + + if (!device_buffer_gles.BindAndUploadDataIfNecessary( + DeviceBufferGLES::BindingType::kUniformBuffer)) { + return false; + } + auto handle = device_buffer_gles.GetHandle(); + if (!handle.has_value()) { + return false; + } + gl.BindBufferRange(GL_UNIFORM_BUFFER, binding_point, handle.value(), + buffer.GetRange().offset, buffer.GetRange().length); + return true; +} + +bool BufferBindingsGLES::BindUniformBufferV2( + const ProcTableGLES& gl, + const BufferView& buffer, + const ShaderMetadata* metadata, + const DeviceBufferGLES& device_buffer_gles) { const uint8_t* buffer_ptr = - device_buffer_gles.GetBufferData() + buffer.resource.GetRange().offset; + device_buffer_gles.GetBufferData() + buffer.GetRange().offset; if (metadata->members.empty()) { VALIDATION_LOG << "Uniform buffer had no members. This is currently " @@ -320,64 +396,46 @@ bool BufferBindingsGLES::BindUniformBuffer(const ProcTableGLES& gl, reinterpret_cast(array_element_buffer.data()); } - switch (member.type) { - case ShaderType::kFloat: - switch (member.size) { - case sizeof(Matrix): - gl.UniformMatrix4fv(location, // location - element_count, // count - GL_FALSE, // normalize - buffer_data // data - ); - continue; - case sizeof(Vector4): - gl.Uniform4fv(location, // location - element_count, // count - buffer_data // data - ); - continue; - case sizeof(Vector3): - gl.Uniform3fv(location, // location - element_count, // count - buffer_data // data - ); - continue; - case sizeof(Vector2): - gl.Uniform2fv(location, // location - element_count, // count - buffer_data // data - ); - continue; - case sizeof(Scalar): - gl.Uniform1fv(location, // location - element_count, // count - buffer_data // data - ); - continue; - } - VALIDATION_LOG << "Size " << member.size - << " could not be mapped ShaderType::kFloat for key: " - << member.name; - case ShaderType::kBoolean: - case ShaderType::kSignedByte: - case ShaderType::kUnsignedByte: - case ShaderType::kSignedShort: - case ShaderType::kUnsignedShort: - case ShaderType::kSignedInt: - case ShaderType::kUnsignedInt: - case ShaderType::kSignedInt64: - case ShaderType::kUnsignedInt64: - case ShaderType::kAtomicCounter: - case ShaderType::kUnknown: - case ShaderType::kVoid: - case ShaderType::kHalfFloat: - case ShaderType::kDouble: - case ShaderType::kStruct: - case ShaderType::kImage: - case ShaderType::kSampledImage: - case ShaderType::kSampler: - VALIDATION_LOG << "Could not bind uniform buffer data for key: " - << member.name << " : " << static_cast(member.type); + if (member.type != ShaderType::kFloat) { + VALIDATION_LOG << "Could not bind uniform buffer data for key: " + << member.name << " : " << static_cast(member.type); + return false; + } + + switch (member.size) { + case sizeof(Matrix): + gl.UniformMatrix4fv(location, // location + element_count, // count + GL_FALSE, // normalize + buffer_data // data + ); + continue; + case sizeof(Vector4): + gl.Uniform4fv(location, // location + element_count, // count + buffer_data // data + ); + continue; + case sizeof(Vector3): + gl.Uniform3fv(location, // location + element_count, // count + buffer_data // data + ); + continue; + case sizeof(Vector2): + gl.Uniform2fv(location, // location + element_count, // count + buffer_data // data + ); + continue; + case sizeof(Scalar): + gl.Uniform1fv(location, // location + element_count, // count + buffer_data // data + ); + continue; + default: + VALIDATION_LOG << "Invalid member size binding: " << member.size; return false; } } diff --git a/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.h index eeaaf43fcd..29f032da76 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.h @@ -10,6 +10,7 @@ #include "flutter/third_party/abseil-cpp/absl/container/flat_hash_map.h" #include "impeller/core/shader_types.h" +#include "impeller/renderer/backend/gles/device_buffer_gles.h" #include "impeller/renderer/backend/gles/gles.h" #include "impeller/renderer/backend/gles/proc_table_gles.h" #include "impeller/renderer/command.h" @@ -65,18 +66,35 @@ class BufferBindingsGLES { std::vector> vertex_attrib_arrays_; absl::flat_hash_map uniform_locations_; + absl::flat_hash_map> ubo_locations_; using BindingMap = absl::flat_hash_map>; BindingMap binding_map_ = {}; GLuint vertex_array_object_ = 0; + GLuint program_handle_ = GL_NONE; + bool use_ubo_ = false; const std::vector& ComputeUniformLocations( const ShaderMetadata* metadata); + bool ReadUniformsBindingsV2(const ProcTableGLES& gl, GLuint program); + + bool ReadUniformsBindingsV3(const ProcTableGLES& gl, GLuint program); + GLint ComputeTextureLocation(const ShaderMetadata* metadata); bool BindUniformBuffer(const ProcTableGLES& gl, const BufferResource& buffer); + bool BindUniformBufferV2(const ProcTableGLES& gl, + const BufferView& buffer, + const ShaderMetadata* metadata, + const DeviceBufferGLES& device_buffer_gles); + + bool BindUniformBufferV3(const ProcTableGLES& gl, + const BufferView& buffer, + const ShaderMetadata* metadata, + const DeviceBufferGLES& device_buffer_gles); + std::optional BindTextures( const ProcTableGLES& gl, const std::vector& bound_textures, diff --git a/engine/src/flutter/impeller/renderer/backend/gles/context_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/context_gles.cc index ba98e78f5c..c0c4c4c045 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/context_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/context_gles.cc @@ -7,6 +7,8 @@ #include "impeller/base/config.h" #include "impeller/base/validation.h" +#include "impeller/base/version.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/backend/gles/command_buffer_gles.h" #include "impeller/renderer/backend/gles/gpu_tracer_gles.h" #include "impeller/renderer/backend/gles/handle_gles.h" @@ -180,4 +182,13 @@ bool ContextGLES::AddTrackingFence( return true; } +// |Context| +RuntimeStageBackend ContextGLES::GetRuntimeStageBackend() const { + if (GetReactor()->GetProcTable().GetDescription()->GetGlVersion().IsAtLeast( + Version{3, 0, 0})) { + return RuntimeStageBackend::kOpenGLES3; + } + return RuntimeStageBackend::kOpenGLES; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/gles/context_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/context_gles.h index 1c2587cc0d..8184830054 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/context_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/context_gles.h @@ -6,6 +6,7 @@ #define FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_CONTEXT_GLES_H_ #include "impeller/base/backend_cast.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/backend/gles/allocator_gles.h" #include "impeller/renderer/backend/gles/capabilities_gles.h" #include "impeller/renderer/backend/gles/gpu_tracer_gles.h" @@ -106,6 +107,9 @@ class ContextGLES final : public Context, // |Context| [[nodiscard]] bool FlushCommandBuffers() override; + // |Context| + RuntimeStageBackend GetRuntimeStageBackend() const override; + ContextGLES(const ContextGLES&) = delete; ContextGLES& operator=(const ContextGLES&) = delete; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.cc index f4caaf5af8..c477b75220 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.cc @@ -56,6 +56,10 @@ bool DeviceBufferGLES::OnCopyHostBuffer(const uint8_t* source, return true; } +std::optional DeviceBufferGLES::GetHandle() const { + return reactor_->GetGLHandle(handle_); +} + void DeviceBufferGLES::Flush(std::optional range) const { if (!range.has_value()) { dirty_range_ = Range{ @@ -75,6 +79,8 @@ static GLenum ToTarget(DeviceBufferGLES::BindingType type) { return GL_ARRAY_BUFFER; case DeviceBufferGLES::BindingType::kElementArrayBuffer: return GL_ELEMENT_ARRAY_BUFFER; + case DeviceBufferGLES::BindingType::kUniformBuffer: + return GL_UNIFORM_BUFFER; } FML_UNREACHABLE(); } diff --git a/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.h index a18e010dc2..8fe5c69425 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/device_buffer_gles.h @@ -34,12 +34,15 @@ class DeviceBufferGLES final enum class BindingType { kArrayBuffer, kElementArrayBuffer, + kUniformBuffer, }; [[nodiscard]] bool BindAndUploadDataIfNecessary(BindingType type) const; void Flush(std::optional range = std::nullopt) const override; + std::optional GetHandle() const; + private: ReactorGLES::Ref reactor_; HandleGLES handle_; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.cc index 3f0d518879..c4450e7b3b 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.cc @@ -6,7 +6,6 @@ #include -#include "fml/closure.h" #include "impeller/base/allocation.h" #include "impeller/base/comparable.h" #include "impeller/base/strings.h" @@ -180,12 +179,12 @@ void ProcTableGLES::ShaderSourceMapping( std::optional ProcTableGLES::ComputeShaderWithDefines( const fml::Mapping& mapping, const std::vector& defines) const { - auto shader_source = std::string{ + std::string shader_source = std::string{ reinterpret_cast(mapping.GetMapping()), mapping.GetSize()}; // Look for the first newline after the '#version' header, which impellerc // will always emit as the first line of a compiled shader. - auto index = shader_source.find('\n'); + size_t index = shader_source.find('\n'); if (index == std::string::npos) { VALIDATION_LOG << "Failed to append constant data to shader"; return std::nullopt; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.h index 746d26c668..ccc499af9d 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.h @@ -241,6 +241,11 @@ void(glDepthRange)(GLdouble n, GLdouble f); #define FOR_EACH_IMPELLER_GLES3_PROC(PROC) \ PROC(FenceSync); \ PROC(DeleteSync); \ + PROC(GetActiveUniformBlockiv); \ + PROC(GetActiveUniformBlockName); \ + PROC(GetUniformBlockIndex); \ + PROC(UniformBlockBinding); \ + PROC(BindBufferRange); \ PROC(WaitSync); \ PROC(BlitFramebuffer); diff --git a/engine/src/flutter/impeller/renderer/backend/gles/shader_library_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/shader_library_gles.cc index 3c8dbbb816..018fc50c6b 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/shader_library_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/shader_library_gles.cc @@ -57,7 +57,6 @@ ShaderLibraryGLES::ShaderLibraryGLES( ) -> bool { const auto stage = ToShaderStage(type); const auto key_name = GLESShaderNameToShaderKeyName(name, stage); - functions[ShaderKey{key_name, stage}] = std::shared_ptr( new ShaderFunctionGLES(library_id, // stage, // diff --git a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h index 15bb2fd46e..a0af10d442 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h @@ -118,6 +118,9 @@ class ContextMTL final : public Context, // |Context| const std::shared_ptr& GetCapabilities() const override; + // |Context| + RuntimeStageBackend GetRuntimeStageBackend() const override; + void SetCapabilities(const std::shared_ptr& capabilities); // |Context| diff --git a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm index 0a66c82146..a4083bfa63 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm @@ -13,6 +13,7 @@ #include "flutter/fml/paths.h" #include "flutter/fml/synchronization/sync_switch.h" #include "impeller/core/formats.h" +#include "impeller/core/runtime_types.h" #include "impeller/core/sampler_descriptor.h" #include "impeller/renderer/backend/metal/gpu_tracer_mtl.h" #include "impeller/renderer/backend/metal/sampler_library_mtl.h" @@ -430,6 +431,11 @@ std::shared_ptr ContextMTL::GetCommandQueue() const { return command_queue_ip_; } +// |Context| +RuntimeStageBackend ContextMTL::GetRuntimeStageBackend() const { + return RuntimeStageBackend::kMetal; +} + #ifdef IMPELLER_DEBUG const std::shared_ptr ContextMTL::GetCaptureManager() const { diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc index 62da661cf7..c72f944f48 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc @@ -8,6 +8,7 @@ #include "fml/concurrent_message_loop.h" #include "impeller/core/formats.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/backend/vulkan/command_queue_vk.h" #include "impeller/renderer/backend/vulkan/descriptor_pool_vk.h" #include "impeller/renderer/backend/vulkan/render_pass_builder_vk.h" @@ -721,4 +722,8 @@ bool ContextVK::GetShouldDisableSurfaceControlSwapchain() const { return should_disable_surface_control_; } +RuntimeStageBackend ContextVK::GetRuntimeStageBackend() const { + return RuntimeStageBackend::kVulkan; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h index 40bddc494d..08ed6569b0 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h @@ -13,6 +13,7 @@ #include "impeller/base/backend_cast.h" #include "impeller/base/strings.h" #include "impeller/core/formats.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/backend/vulkan/command_pool_vk.h" #include "impeller/renderer/backend/vulkan/device_holder_vk.h" #include "impeller/renderer/backend/vulkan/driver_info_vk.h" @@ -229,6 +230,8 @@ class ContextVK final : public Context, // | Context | bool FlushCommandBuffers() override; + RuntimeStageBackend GetRuntimeStageBackend() const override; + std::shared_ptr GetIdleWaiter() const override { return idle_waiter_vk_; } diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc index faaf748df9..0783762666 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc @@ -5,6 +5,7 @@ #include "impeller/renderer/backend/vulkan/surface_context_vk.h" #include "flutter/fml/trace_event.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/backend/vulkan/command_pool_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_vk.h" @@ -128,4 +129,8 @@ bool SurfaceContextVK::FlushCommandBuffers() { return parent_->FlushCommandBuffers(); } +RuntimeStageBackend SurfaceContextVK::GetRuntimeStageBackend() const { + return parent_->GetRuntimeStageBackend(); +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h index f439ff927a..488dc19f90 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h @@ -8,6 +8,7 @@ #include #include "impeller/base/backend_cast.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/command_queue.h" #include "impeller/renderer/context.h" @@ -66,8 +67,12 @@ class SurfaceContextVK : public Context, // |Context| std::shared_ptr GetCommandQueue() const override; + // |Context| std::shared_ptr GetIdleWaiter() const override; + // |Context| + RuntimeStageBackend GetRuntimeStageBackend() const override; + // |Context| void Shutdown() override; diff --git a/engine/src/flutter/impeller/renderer/context.h b/engine/src/flutter/impeller/renderer/context.h index 62254504b9..71bad51128 100644 --- a/engine/src/flutter/impeller/renderer/context.h +++ b/engine/src/flutter/impeller/renderer/context.h @@ -236,6 +236,12 @@ class Context { /// virtual void ResetThreadLocalState() const; + /// @brief Retrieve the runtime stage for this context type. + /// + /// This is used by the engine shell and other subsystems for loading the + /// correct shader types. + virtual RuntimeStageBackend GetRuntimeStageBackend() const = 0; + protected: Context(); diff --git a/engine/src/flutter/impeller/renderer/testing/mocks.h b/engine/src/flutter/impeller/renderer/testing/mocks.h index c020daacfe..d8eca488be 100644 --- a/engine/src/flutter/impeller/renderer/testing/mocks.h +++ b/engine/src/flutter/impeller/renderer/testing/mocks.h @@ -7,6 +7,7 @@ #include "gmock/gmock.h" #include "impeller/core/allocator.h" +#include "impeller/core/runtime_types.h" #include "impeller/core/sampler_descriptor.h" #include "impeller/core/texture.h" #include "impeller/renderer/command_buffer.h" @@ -184,6 +185,11 @@ class MockImpellerContext : public Context { GetCommandQueue, (), (const, override)); + + MOCK_METHOD(RuntimeStageBackend, + GetRuntimeStageBackend, + (), + (const, override)); }; class MockTexture : public Texture { diff --git a/engine/src/flutter/impeller/runtime_stage/runtime_stage.cc b/engine/src/flutter/impeller/runtime_stage/runtime_stage.cc index bf46e805a9..634274ac21 100644 --- a/engine/src/flutter/impeller/runtime_stage/runtime_stage.cc +++ b/engine/src/flutter/impeller/runtime_stage/runtime_stage.cc @@ -75,6 +75,8 @@ RuntimeStage::Map RuntimeStage::DecodeRuntimeStages( RuntimeStageIfPresent(raw_stages->metal(), payload)}, {RuntimeStageBackend::kOpenGLES, RuntimeStageIfPresent(raw_stages->opengles(), payload)}, + {RuntimeStageBackend::kOpenGLES3, + RuntimeStageIfPresent(raw_stages->opengles3(), payload)}, {RuntimeStageBackend::kVulkan, RuntimeStageIfPresent(raw_stages->vulkan(), payload)}, }; diff --git a/engine/src/flutter/impeller/runtime_stage/runtime_stage_types.fbs b/engine/src/flutter/impeller/runtime_stage/runtime_stage_types.fbs index 39c8af71cf..dd9f7f5a66 100644 --- a/engine/src/flutter/impeller/runtime_stage/runtime_stage_types.fbs +++ b/engine/src/flutter/impeller/runtime_stage/runtime_stage_types.fbs @@ -83,5 +83,6 @@ table RuntimeStages { sksl: RuntimeStage; metal: RuntimeStage; opengles: RuntimeStage; + opengles3: RuntimeStage; vulkan: RuntimeStage; } diff --git a/engine/src/flutter/impeller/tools/compiler.gni b/engine/src/flutter/impeller/tools/compiler.gni index 6c2d080865..180600b8ea 100644 --- a/engine/src/flutter/impeller/tools/compiler.gni +++ b/engine/src/flutter/impeller/tools/compiler.gni @@ -36,6 +36,7 @@ template("_impellerc") { # --vulkan # --runtime-stage-metal # --runtime-stage-gles +# --runtime-stage-gles3 # --runtime-stage-vulkan # Not required for --shader_bundle mode. # Required: sl_file_extension The file extension to use for output files. diff --git a/engine/src/flutter/impeller/tools/shaders.gni b/engine/src/flutter/impeller/tools/shaders.gni index e0bd24183d..140b886552 100644 --- a/engine/src/flutter/impeller/tools/shaders.gni +++ b/engine/src/flutter/impeller/tools/shaders.gni @@ -97,6 +97,7 @@ template("impeller_shaders") { analyze = false } gles_shaders = "gles_$target_name" + impeller_shaders_gles(gles_shaders) { name = invoker.name require_framebuffer_fetch = require_framebuffer_fetch @@ -110,6 +111,22 @@ template("impeller_shaders") { } analyze = analyze } + + gles3_shaders = "gles3_$target_name" + + impeller_shaders_gles(gles3_shaders) { + name = invoker.name + require_framebuffer_fetch = require_framebuffer_fetch + gles_language_version = 300 + is_300 = true + analyze = false + if (defined(invoker.gles_exclusions)) { + shaders = invoker.shaders - invoker.gles_exclusions + } else { + shaders = invoker.shaders + } + analyze = analyze + } } if (impeller_enable_vulkan) { @@ -139,7 +156,10 @@ template("impeller_shaders") { } if (enable_opengles) { - public_deps += [ ":$gles_shaders" ] + public_deps += [ + ":$gles3_shaders", + ":$gles_shaders", + ] } if (impeller_enable_vulkan) { diff --git a/engine/src/flutter/impeller/tools/shaders_gles.gni b/engine/src/flutter/impeller/tools/shaders_gles.gni index 903be3fedb..9839227daa 100644 --- a/engine/src/flutter/impeller/tools/shaders_gles.gni +++ b/engine/src/flutter/impeller/tools/shaders_gles.gni @@ -19,6 +19,8 @@ template("impeller_shaders_gles") { require_framebuffer_fetch = invoker.require_framebuffer_fetch } + is_300 = defined(invoker.is_300) && invoker.is_300 + shaders_base_name = string_join("", [ invoker.name, @@ -35,11 +37,18 @@ template("impeller_shaders_gles") { # Metal reflectors generate a superset of information. if (impeller_enable_metal || impeller_enable_vulkan) { - intermediates_subdir = "gles" + if (is_300) { + intermediates_subdir = "gles3" + } else { + intermediates_subdir = "gles" + } } shader_target_flags = [ "--opengl-es" ] defines = [ "IMPELLER_TARGET_OPENGLES" ] + if (is_300) { + defines += [ "IMPELLER_TARGET_OPENGLES3" ] + } } gles_shaders = @@ -68,13 +77,24 @@ template("impeller_shaders_gles") { } embed_gles_lib = "embed_$target_name" - embed_blob(embed_gles_lib) { - gles_library_files = get_target_outputs(":$gles_lib") - symbol_name = shaders_base_name - blob = gles_library_files[0] - hdr = "$target_gen_dir/gles/$shaders_base_name.h" - cc = "$target_gen_dir/gles/$shaders_base_name.cc" - deps = [ ":$gles_lib" ] + if (is_300) { + embed_blob(embed_gles_lib) { + gles_library_files = get_target_outputs(":$gles_lib") + symbol_name = shaders_base_name + "3" + blob = gles_library_files[0] + hdr = "$target_gen_dir/gles3/$shaders_base_name.h" + cc = "$target_gen_dir/gles3/$shaders_base_name.cc" + deps = [ ":$gles_lib" ] + } + } else { + embed_blob(embed_gles_lib) { + gles_library_files = get_target_outputs(":$gles_lib") + symbol_name = shaders_base_name + blob = gles_library_files[0] + hdr = "$target_gen_dir/gles/$shaders_base_name.h" + cc = "$target_gen_dir/gles/$shaders_base_name.cc" + deps = [ ":$gles_lib" ] + } } group(target_name) { diff --git a/engine/src/flutter/lib/ui/painting/fragment_program.cc b/engine/src/flutter/lib/ui/painting/fragment_program.cc index 68a96a1524..54b321609c 100644 --- a/engine/src/flutter/lib/ui/painting/fragment_program.cc +++ b/engine/src/flutter/lib/ui/painting/fragment_program.cc @@ -33,6 +33,8 @@ static std::string RuntimeStageBackendToString( return "OpenGLES"; case impeller::RuntimeStageBackend::kVulkan: return "Vulkan"; + case impeller::RuntimeStageBackend::kOpenGLES3: + return "OpenGLES3"; } } diff --git a/engine/src/flutter/lib/ui/painting/image_decoder_unittests.cc b/engine/src/flutter/lib/ui/painting/image_decoder_unittests.cc index 1e41ab5cc8..968c09d344 100644 --- a/engine/src/flutter/lib/ui/painting/image_decoder_unittests.cc +++ b/engine/src/flutter/lib/ui/painting/image_decoder_unittests.cc @@ -24,6 +24,7 @@ #include "flutter/testing/test_gl_surface.h" #include "flutter/testing/testing.h" #include "fml/logging.h" +#include "impeller/core/runtime_types.h" #include "impeller/renderer/command_queue.h" #include "third_party/skia/include/codec/SkCodecAnimation.h" #include "third_party/skia/include/core/SkData.h" @@ -96,6 +97,10 @@ class TestImpellerContext : public impeller::Context { void Shutdown() override {} + RuntimeStageBackend GetRuntimeStageBackend() const override { + return RuntimeStageBackend::kVulkan; + } + bool DidDisposeResources() const { return did_dispose_; } mutable size_t command_buffer_count_ = 0; diff --git a/engine/src/flutter/shell/common/shell.cc b/engine/src/flutter/shell/common/shell.cc index ba28d8e950..9cc5c13f31 100644 --- a/engine/src/flutter/shell/common/shell.cc +++ b/engine/src/flutter/shell/common/shell.cc @@ -29,7 +29,6 @@ #include "flutter/shell/common/skia_event_tracer_impl.h" #include "flutter/shell/common/switches.h" #include "flutter/shell/common/vsync_waiter.h" -#include "impeller/runtime_stage/runtime_stage.h" #include "rapidjson/stringbuffer.h" #include "rapidjson/writer.h" #include "third_party/dart/runtime/include/dart_tools_api.h" @@ -200,14 +199,7 @@ static impeller::RuntimeStageBackend DetermineRuntimeStageBackend( if (!impeller_context) { return impeller::RuntimeStageBackend::kSkSL; } - switch (impeller_context->GetBackendType()) { - case impeller::Context::BackendType::kMetal: - return impeller::RuntimeStageBackend::kMetal; - case impeller::Context::BackendType::kOpenGLES: - return impeller::RuntimeStageBackend::kOpenGLES; - case impeller::Context::BackendType::kVulkan: - return impeller::RuntimeStageBackend::kVulkan; - } + return impeller_context->GetRuntimeStageBackend(); } std::unique_ptr Shell::CreateShellOnPlatformThread( diff --git a/engine/src/flutter/shell/common/shell_unittests.cc b/engine/src/flutter/shell/common/shell_unittests.cc index 8c6a0c2f47..a38994120c 100644 --- a/engine/src/flutter/shell/common/shell_unittests.cc +++ b/engine/src/flutter/shell/common/shell_unittests.cc @@ -4876,7 +4876,7 @@ TEST_F(ShellTest, RuntimeStageBackendWithImpeller) { EXPECT_EQ(backend, impeller::RuntimeStageBackend::kMetal); break; case impeller::Context::BackendType::kOpenGLES: - EXPECT_EQ(backend, impeller::RuntimeStageBackend::kOpenGLES); + EXPECT_EQ(backend, impeller::RuntimeStageBackend::kOpenGLES3); break; case impeller::Context::BackendType::kVulkan: EXPECT_EQ(backend, impeller::RuntimeStageBackend::kVulkan); diff --git a/engine/src/flutter/shell/platform/android/android_context_gl_impeller.cc b/engine/src/flutter/shell/platform/android/android_context_gl_impeller.cc index 4397976811..31ad0a5551 100644 --- a/engine/src/flutter/shell/platform/android/android_context_gl_impeller.cc +++ b/engine/src/flutter/shell/platform/android/android_context_gl_impeller.cc @@ -11,6 +11,8 @@ #include "flutter/impeller/toolkit/egl/surface.h" #include "impeller/entity/gles/entity_shaders_gles.h" #include "impeller/entity/gles/framebuffer_blend_shaders_gles.h" +#include "impeller/entity/gles3/entity_shaders_gles.h" +#include "impeller/entity/gles3/framebuffer_blend_shaders_gles.h" namespace flutter { @@ -55,8 +57,10 @@ static std::shared_ptr CreateImpellerContext( FML_LOG(ERROR) << "Could not create OpenGL proc table."; return nullptr; } + bool is_gles3 = proc_table->GetDescription()->GetGlVersion().IsAtLeast( + impeller::Version{3, 0, 0}); - std::vector> shader_mappings = { + std::vector> gles2_shader_mappings = { std::make_shared( impeller_entity_shaders_gles_data, impeller_entity_shaders_gles_length), @@ -65,8 +69,19 @@ static std::shared_ptr CreateImpellerContext( impeller_framebuffer_blend_shaders_gles_length), }; + std::vector> gles3_shader_mappings = { + std::make_shared( + impeller_entity_shaders_gles3_data, + impeller_entity_shaders_gles3_length), + std::make_shared( + impeller_framebuffer_blend_shaders_gles3_data, + impeller_framebuffer_blend_shaders_gles3_length), + }; + auto context = impeller::ContextGLES::Create( - std::move(proc_table), shader_mappings, enable_gpu_tracing); + std::move(proc_table), + is_gles3 ? gles3_shader_mappings : gles2_shader_mappings, + enable_gpu_tracing); if (!context) { FML_LOG(ERROR) << "Could not create OpenGLES Impeller Context."; return nullptr; diff --git a/engine/src/flutter/shell/platform/android/android_context_gl_unittests.cc b/engine/src/flutter/shell/platform/android/android_context_gl_unittests.cc index 5173f59d67..33416e0182 100644 --- a/engine/src/flutter/shell/platform/android/android_context_gl_unittests.cc +++ b/engine/src/flutter/shell/platform/android/android_context_gl_unittests.cc @@ -13,6 +13,7 @@ #include "fml/logging.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "impeller/core/runtime_types.h" #include "shell/platform/android/context/android_context.h" namespace flutter { @@ -84,6 +85,10 @@ class TestImpellerContext : public impeller::Context { void Shutdown() override { did_shutdown = true; } + impeller::RuntimeStageBackend GetRuntimeStageBackend() const override { + return impeller::RuntimeStageBackend::kVulkan; + } + bool did_shutdown = false; };