diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 00174c6fc11df..14ffe3d669c09 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1121,6 +1121,7 @@ FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/branching.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/color.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/constants.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/gaussian.glsl +FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/gradient.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/texture.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/transform.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/types.glsl @@ -1291,6 +1292,7 @@ FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.frag FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.vert FILE: ../../../flutter/impeller/entity/shaders/gradient_fill.vert FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_ssbo_fill.frag FILE: ../../../flutter/impeller/entity/shaders/linear_to_srgb_filter.frag FILE: ../../../flutter/impeller/entity/shaders/linear_to_srgb_filter.vert FILE: ../../../flutter/impeller/entity/shaders/morphology_filter.frag @@ -1299,6 +1301,7 @@ FILE: ../../../flutter/impeller/entity/shaders/position.vert FILE: ../../../flutter/impeller/entity/shaders/position_color.vert FILE: ../../../flutter/impeller/entity/shaders/position_uv.vert FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_ssbo_fill.frag FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.frag FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.vert FILE: ../../../flutter/impeller/entity/shaders/runtime_effect.vert @@ -1307,6 +1310,7 @@ FILE: ../../../flutter/impeller/entity/shaders/solid_fill.vert FILE: ../../../flutter/impeller/entity/shaders/srgb_to_linear_filter.frag FILE: ../../../flutter/impeller/entity/shaders/srgb_to_linear_filter.vert FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag FILE: ../../../flutter/impeller/entity/shaders/texture_fill.frag FILE: ../../../flutter/impeller/entity/shaders/texture_fill.vert FILE: ../../../flutter/impeller/entity/shaders/tiled_texture_fill.frag @@ -1490,6 +1494,7 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/texture_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/vertex_descriptor_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/vertex_descriptor_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/vk.h +FILE: ../../../flutter/impeller/renderer/backend_features.h FILE: ../../../flutter/impeller/renderer/blit_command.cc FILE: ../../../flutter/impeller/renderer/blit_command.h FILE: ../../../flutter/impeller/renderer/blit_pass.cc diff --git a/impeller/compiler/code_gen_template.h b/impeller/compiler/code_gen_template.h index 8ce9f4f233b49..d2708052d1838 100644 --- a/impeller/compiler/code_gen_template.h +++ b/impeller/compiler/code_gen_template.h @@ -202,7 +202,6 @@ using Shader = {{camel_case(shader_name)}}{{camel_case(shader_stage)}}Shader; // Sanity checks for {{def.name}} {% if last(def.members).array_elements == 0 %} static_assert(std::is_standard_layout_v>); -static_assert(sizeof(Shader::{{def.name}}<0>) == {{def.byte_length}}); {% for member in def.members %} static_assert(offsetof(Shader::{{def.name}}<0>, {{member.name}}) == {{member.offset}}); {% endfor %} diff --git a/impeller/compiler/compiler.cc b/impeller/compiler/compiler.cc index daf0a6e878fc3..c8fe2f3890404 100644 --- a/impeller/compiler/compiler.cc +++ b/impeller/compiler/compiler.cc @@ -45,10 +45,14 @@ 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) { - sl_options.version = 100; + sl_options.version = source_options.gles_language_version > 0 + ? source_options.gles_language_version + : 100; sl_options.es = true; } else { - sl_options.version = 120; + sl_options.version = source_options.gles_language_version > 0 + ? source_options.gles_language_version + : 120; sl_options.es = false; } gl_compiler->set_common_options(sl_options); diff --git a/impeller/compiler/impellerc_main.cc b/impeller/compiler/impellerc_main.cc index 569b0006c07c0..f25ecd3f86509 100644 --- a/impeller/compiler/impellerc_main.cc +++ b/impeller/compiler/impellerc_main.cc @@ -73,6 +73,7 @@ bool Main(const fml::CommandLine& command_line) { switches.source_file_name, options.type, options.source_language, switches.entry_point); options.json_format = switches.json_format; + options.gles_language_version = switches.gles_language_version; Reflector::Options reflector_options; reflector_options.target_platform = switches.target_platform; diff --git a/impeller/compiler/shader_lib/impeller/BUILD.gn b/impeller/compiler/shader_lib/impeller/BUILD.gn index 5d7e85c6bd009..99ca69f472f7c 100644 --- a/impeller/compiler/shader_lib/impeller/BUILD.gn +++ b/impeller/compiler/shader_lib/impeller/BUILD.gn @@ -9,6 +9,7 @@ copy("impeller") { "color.glsl", "constants.glsl", "gaussian.glsl", + "gradient.glsl", "texture.glsl", "transform.glsl", "types.glsl", diff --git a/impeller/compiler/shader_lib/impeller/gradient.glsl b/impeller/compiler/shader_lib/impeller/gradient.glsl new file mode 100644 index 0000000000000..2c64edd35098b --- /dev/null +++ b/impeller/compiler/shader_lib/impeller/gradient.glsl @@ -0,0 +1,24 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GRADIENT_GLSL_ +#define GRADIENT_GLSL_ + +#include + +/// Compute the indexes and mix coefficient used to mix colors for an +/// arbitrarily sized color gradient. +/// +/// The returned values are the lower index, upper index, and mix +/// coefficient. +vec3 IPComputeFixedGradientValues(float t, float colors_length) { + float rough_index = (colors_length - 1) * t; + float lower_index = floor(rough_index); + float upper_index = ceil(rough_index); + float scale = rough_index - lower_index; + + return vec3(lower_index, upper_index, scale); +} + +#endif diff --git a/impeller/compiler/source_options.h b/impeller/compiler/source_options.h index 921ee5cb5c494..ccd264562a3d0 100644 --- a/impeller/compiler/source_options.h +++ b/impeller/compiler/source_options.h @@ -24,6 +24,7 @@ struct SourceOptions { std::vector include_dirs; std::string file_name = "main.glsl"; std::string entry_point_name = "main"; + uint32_t gles_language_version = 100; std::vector defines; bool json_format = false; diff --git a/impeller/compiler/switches.cc b/impeller/compiler/switches.cc index b816796552675..348b6eac31336 100644 --- a/impeller/compiler/switches.cc +++ b/impeller/compiler/switches.cc @@ -69,6 +69,7 @@ void Switches::PrintHelp(std::ostream& stream) { stream << "[optional,multiple] --include=" << std::endl; stream << "[optional,multiple] --define=" << std::endl; stream << "[optional] --depfile=" << std::endl; + stream << "[optional] --gles-language-verision=" << std::endl; stream << "[optional] --json" << std::endl; } @@ -124,6 +125,9 @@ Switches::Switches(const fml::CommandLine& command_line) command_line.GetOptionValueWithDefault("reflection-cc", "")), depfile_path(command_line.GetOptionValueWithDefault("depfile", "")), json_format(command_line.HasOption("json")), + gles_language_version( + stoi(command_line.GetOptionValueWithDefault("gles-language-version", + "0"))), entry_point( command_line.GetOptionValueWithDefault("entry-point", "main")) { if (!working_directory || !working_directory->is_valid()) { diff --git a/impeller/compiler/switches.h b/impeller/compiler/switches.h index 7a62861fcaf71..01774285e7f27 100644 --- a/impeller/compiler/switches.h +++ b/impeller/compiler/switches.h @@ -33,6 +33,7 @@ struct Switches { std::vector defines; bool json_format; SourceLanguage source_language = SourceLanguage::kUnknown; + uint32_t gles_language_version; std::string entry_point; Switches(); diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 1175f5daef889..ecba665e6617a 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -66,6 +66,20 @@ impeller_shaders("entity_shaders") { ] } +impeller_shaders("modern_entity_shaders") { + name = "modern" + + if (impeller_enable_opengles) { + gles_language_version = "460" + } + + shaders = [ + "shaders/linear_gradient_ssbo_fill.frag", + "shaders/radial_gradient_ssbo_fill.frag", + "shaders/sweep_gradient_ssbo_fill.frag", + ] +} + impeller_component("entity") { sources = [ "contents/atlas_contents.cc", @@ -146,6 +160,7 @@ impeller_component("entity") { public_deps = [ ":entity_shaders", + ":modern_entity_shaders", "../archivist", "../image", "../renderer", diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index dbc6fec50527e..fa6c6782f40cb 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -157,6 +157,14 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); radial_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); + if (context_->GetBackendFeatures().ssbo_support) { + linear_gradient_ssbo_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); + radial_gradient_ssbo_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); + sweep_gradient_ssbo_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); + } sweep_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); rrect_blur_pipelines_[{}] = @@ -303,4 +311,8 @@ std::shared_ptr ContentContext::GetContext() const { return context_; } +const BackendFeatures& ContentContext::GetBackendFeatures() const { + return context_->GetBackendFeatures(); +} + } // namespace impeller diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 07c875bfe5a74..661ac5a58a9d0 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -72,6 +72,10 @@ #include "impeller/typographer/glyph_atlas.h" +#include "impeller/entity/linear_gradient_ssbo_fill.frag.h" +#include "impeller/entity/radial_gradient_ssbo_fill.frag.h" +#include "impeller/entity/sweep_gradient_ssbo_fill.frag.h" + namespace impeller { using LinearGradientFillPipeline = @@ -82,6 +86,15 @@ using RadialGradientFillPipeline = RenderPipelineT; using SweepGradientFillPipeline = RenderPipelineT; +using LinearGradientSSBOFillPipeline = + RenderPipelineT; +using RadialGradientSSBOFillPipeline = + RenderPipelineT; +using SweepGradientSSBOFillPipeline = + RenderPipelineT; using BlendPipeline = RenderPipelineT; using RRectBlurPipeline = RenderPipelineT; @@ -210,6 +223,24 @@ class ContentContext { return GetPipeline(linear_gradient_fill_pipelines_, opts); } + std::shared_ptr> + GetLinearGradientSSBOFillPipeline(ContentContextOptions opts) const { + FML_DCHECK(GetBackendFeatures().ssbo_support); + return GetPipeline(linear_gradient_ssbo_fill_pipelines_, opts); + } + + std::shared_ptr> + GetRadialGradientSSBOFillPipeline(ContentContextOptions opts) const { + FML_DCHECK(GetBackendFeatures().ssbo_support); + return GetPipeline(radial_gradient_ssbo_fill_pipelines_, opts); + } + + std::shared_ptr> + GetSweepGradientSSBOFillPipeline(ContentContextOptions opts) const { + FML_DCHECK(GetBackendFeatures().ssbo_support); + return GetPipeline(sweep_gradient_ssbo_fill_pipelines_, opts); + } + std::shared_ptr> GetRadialGradientFillPipeline( ContentContextOptions opts) const { return GetPipeline(radial_gradient_fill_pipelines_, opts); @@ -391,6 +422,8 @@ class ContentContext { std::shared_ptr GetGlyphAtlasContext() const; + const BackendFeatures& GetBackendFeatures() const; + using SubpassCallback = std::function; @@ -416,6 +449,12 @@ class ContentContext { mutable Variants linear_gradient_fill_pipelines_; mutable Variants radial_gradient_fill_pipelines_; mutable Variants sweep_gradient_fill_pipelines_; + mutable Variants + linear_gradient_ssbo_fill_pipelines_; + mutable Variants + radial_gradient_ssbo_fill_pipelines_; + mutable Variants + sweep_gradient_ssbo_fill_pipelines_; mutable Variants rrect_blur_pipelines_; mutable Variants texture_blend_pipelines_; mutable Variants texture_pipelines_; diff --git a/impeller/entity/contents/gradient_generator.cc b/impeller/entity/contents/gradient_generator.cc index f5fd4c70343fb..6a53719a90594 100644 --- a/impeller/entity/contents/gradient_generator.cc +++ b/impeller/entity/contents/gradient_generator.cc @@ -8,7 +8,6 @@ #include "flutter/fml/logging.h" #include "impeller/entity/contents/content_context.h" -#include "impeller/geometry/gradient.h" #include "impeller/renderer/context.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/texture.h" @@ -16,10 +15,8 @@ namespace impeller { std::shared_ptr CreateGradientTexture( - const std::vector& colors, - const std::vector& stops, + const GradientData& gradient_data, const std::shared_ptr& context) { - auto gradient_data = CreateGradientBuffer(colors, stops); if (gradient_data.texture_size == 0) { FML_DLOG(ERROR) << "Invalid gradient data."; return nullptr; diff --git a/impeller/entity/contents/gradient_generator.h b/impeller/entity/contents/gradient_generator.h index 1110da56837ea..2074d2a3e0440 100644 --- a/impeller/entity/contents/gradient_generator.h +++ b/impeller/entity/contents/gradient_generator.h @@ -11,6 +11,7 @@ #include "flutter/fml/macros.h" #include "flutter/impeller/renderer/texture.h" #include "impeller/geometry/color.h" +#include "impeller/geometry/gradient.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" @@ -20,11 +21,10 @@ class Context; /** * @brief Create a host visible texture that contains the gradient defined - * by the provided colors and stops. + * by the provided gradient data. */ std::shared_ptr CreateGradientTexture( - const std::vector& colors, - const std::vector& stops, + const GradientData& gradient_data, const std::shared_ptr& context); } // namespace impeller diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc index 3b7b927c3e62f..f19d9077abf3c 100644 --- a/impeller/entity/contents/linear_gradient_contents.cc +++ b/impeller/entity/contents/linear_gradient_contents.cc @@ -47,11 +47,21 @@ void LinearGradientContents::SetTileMode(Entity::TileMode tile_mode) { bool LinearGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { + if (renderer.GetBackendFeatures().ssbo_support) { + return RenderSSBO(renderer, entity, pass); + } + return RenderTexture(renderer, entity, pass); +} + +bool LinearGradientContents::RenderTexture(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { using VS = LinearGradientFillPipeline::VertexShader; using FS = LinearGradientFillPipeline::FragmentShader; + auto gradient_data = CreateGradientBuffer(colors_, stops_); auto gradient_texture = - CreateGradientTexture(colors_, stops_, renderer.GetContext()); + CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { return false; } @@ -106,4 +116,58 @@ bool LinearGradientContents::Render(const ContentContext& renderer, return true; } +bool LinearGradientContents::RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = LinearGradientSSBOFillPipeline::VertexShader; + using FS = LinearGradientSSBOFillPipeline::FragmentShader; + + FS::GradientInfo gradient_info; + gradient_info.start_point = start_point_; + gradient_info.end_point = end_point_; + gradient_info.tile_mode = static_cast(tile_mode_); + gradient_info.alpha = GetAlpha(); + + auto& host_buffer = pass.GetTransientsBuffer(); + auto colors = CreateGradientColors(colors_, stops_).value_or(colors_); + + gradient_info.colors_length = colors.size(); + auto color_buffer = host_buffer.Emplace( + colors.data(), colors.size() * sizeof(Color), alignof(Color)); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + frame_info.matrix = GetInverseMatrix(); + + Command cmd; + cmd.label = "LinearGradientSSBOFill"; + cmd.stencil_reference = entity.GetStencilDepth(); + + auto geometry_result = + GetGeometry()->GetPositionBuffer(renderer, entity, pass); + auto options = OptionsFromPassAndEntity(pass, entity); + if (geometry_result.prevent_overdraw) { + options.stencil_compare = CompareFunction::kEqual; + options.stencil_operation = StencilOperation::kIncrementClamp; + } + options.primitive_type = geometry_result.type; + cmd.pipeline = renderer.GetLinearGradientSSBOFillPipeline(options); + + cmd.BindVertices(geometry_result.vertex_buffer); + FS::BindGradientInfo( + cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + FS::BindColorData(cmd, color_buffer); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + + if (!pass.AddCommand(std::move(cmd))) { + return false; + } + + if (geometry_result.prevent_overdraw) { + return ClipRestoreContents().Render(renderer, entity, pass); + } + return true; +} + } // namespace impeller diff --git a/impeller/entity/contents/linear_gradient_contents.h b/impeller/entity/contents/linear_gradient_contents.h index fbc9ec15f545d..2a2fd1c6c6632 100644 --- a/impeller/entity/contents/linear_gradient_contents.h +++ b/impeller/entity/contents/linear_gradient_contents.h @@ -13,6 +13,7 @@ #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" +#include "impeller/geometry/gradient.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" @@ -42,6 +43,14 @@ class LinearGradientContents final : public ColorSourceContents { void SetTileMode(Entity::TileMode tile_mode); private: + bool RenderTexture(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + + bool RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + Point start_point_; Point end_point_; std::vector colors_; diff --git a/impeller/entity/contents/radial_gradient_contents.cc b/impeller/entity/contents/radial_gradient_contents.cc index 920c6255e76d1..ab94c3bde9221 100644 --- a/impeller/entity/contents/radial_gradient_contents.cc +++ b/impeller/entity/contents/radial_gradient_contents.cc @@ -10,6 +10,7 @@ #include "impeller/entity/contents/gradient_generator.h" #include "impeller/entity/entity.h" #include "impeller/entity/geometry.h" +#include "impeller/geometry/gradient.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/sampler_library.h" @@ -47,11 +48,75 @@ const std::vector& RadialGradientContents::GetStops() const { bool RadialGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { + if (renderer.GetBackendFeatures().ssbo_support) { + return RenderSSBO(renderer, entity, pass); + } + return RenderTexture(renderer, entity, pass); +} + +bool RadialGradientContents::RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = RadialGradientSSBOFillPipeline::VertexShader; + using FS = RadialGradientSSBOFillPipeline::FragmentShader; + + FS::GradientInfo gradient_info; + gradient_info.center = center_; + gradient_info.radius = radius_; + gradient_info.tile_mode = static_cast(tile_mode_); + gradient_info.alpha = GetAlpha(); + + auto& host_buffer = pass.GetTransientsBuffer(); + auto colors = CreateGradientColors(colors_, stops_).value_or(colors_); + + gradient_info.colors_length = colors.size(); + auto color_buffer = host_buffer.Emplace( + colors.data(), colors.size() * sizeof(Color), alignof(Color)); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + frame_info.matrix = GetInverseMatrix(); + + Command cmd; + cmd.label = "RadialGradientSSBOFill"; + cmd.stencil_reference = entity.GetStencilDepth(); + + auto geometry_result = + GetGeometry()->GetPositionBuffer(renderer, entity, pass); + auto options = OptionsFromPassAndEntity(pass, entity); + if (geometry_result.prevent_overdraw) { + options.stencil_compare = CompareFunction::kEqual; + options.stencil_operation = StencilOperation::kIncrementClamp; + } + options.primitive_type = geometry_result.type; + cmd.pipeline = renderer.GetRadialGradientSSBOFillPipeline(options); + + cmd.BindVertices(geometry_result.vertex_buffer); + FS::BindGradientInfo( + cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + FS::BindColorData(cmd, color_buffer); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + + if (!pass.AddCommand(std::move(cmd))) { + return false; + } + + if (geometry_result.prevent_overdraw) { + return ClipRestoreContents().Render(renderer, entity, pass); + } + return true; +} + +bool RadialGradientContents::RenderTexture(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { using VS = RadialGradientFillPipeline::VertexShader; using FS = RadialGradientFillPipeline::FragmentShader; + auto gradient_data = CreateGradientBuffer(colors_, stops_); auto gradient_texture = - CreateGradientTexture(colors_, stops_, renderer.GetContext()); + CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { return false; } diff --git a/impeller/entity/contents/radial_gradient_contents.h b/impeller/entity/contents/radial_gradient_contents.h index af659e6b8292f..6cb611d1ee68a 100644 --- a/impeller/entity/contents/radial_gradient_contents.h +++ b/impeller/entity/contents/radial_gradient_contents.h @@ -12,6 +12,7 @@ #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" +#include "impeller/geometry/gradient.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" @@ -41,6 +42,13 @@ class RadialGradientContents final : public ColorSourceContents { void SetTileMode(Entity::TileMode tile_mode); private: + bool RenderTexture(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + + bool RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; Point center_; Scalar radius_; std::vector colors_; diff --git a/impeller/entity/contents/sweep_gradient_contents.cc b/impeller/entity/contents/sweep_gradient_contents.cc index 9b104a7bae2b4..395acc543c0d3 100644 --- a/impeller/entity/contents/sweep_gradient_contents.cc +++ b/impeller/entity/contents/sweep_gradient_contents.cc @@ -9,6 +9,7 @@ #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/gradient_generator.h" #include "impeller/entity/entity.h" +#include "impeller/geometry/gradient.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/sampler_library.h" @@ -52,11 +53,76 @@ const std::vector& SweepGradientContents::GetStops() const { bool SweepGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { + if (renderer.GetBackendFeatures().ssbo_support) { + return RenderSSBO(renderer, entity, pass); + } + return RenderTexture(renderer, entity, pass); +} + +bool SweepGradientContents::RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = SweepGradientSSBOFillPipeline::VertexShader; + using FS = SweepGradientSSBOFillPipeline::FragmentShader; + + FS::GradientInfo gradient_info; + gradient_info.center = center_; + gradient_info.bias = bias_; + gradient_info.scale = scale_; + gradient_info.tile_mode = static_cast(tile_mode_); + gradient_info.alpha = GetAlpha(); + + auto& host_buffer = pass.GetTransientsBuffer(); + auto colors = CreateGradientColors(colors_, stops_).value_or(colors_); + + gradient_info.colors_length = colors.size(); + auto color_buffer = host_buffer.Emplace( + colors.data(), colors.size() * sizeof(Color), alignof(Color)); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + frame_info.matrix = GetInverseMatrix(); + + Command cmd; + cmd.label = "SweepGradientSSBOFill"; + cmd.stencil_reference = entity.GetStencilDepth(); + auto geometry_result = + GetGeometry()->GetPositionBuffer(renderer, entity, pass); + + auto options = OptionsFromPassAndEntity(pass, entity); + if (geometry_result.prevent_overdraw) { + options.stencil_compare = CompareFunction::kEqual; + options.stencil_operation = StencilOperation::kIncrementClamp; + } + options.primitive_type = geometry_result.type; + cmd.pipeline = renderer.GetSweepGradientSSBOFillPipeline(options); + + cmd.BindVertices(geometry_result.vertex_buffer); + FS::BindGradientInfo( + cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + FS::BindColorData(cmd, color_buffer); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + + if (!pass.AddCommand(std::move(cmd))) { + return false; + } + + if (geometry_result.prevent_overdraw) { + return ClipRestoreContents().Render(renderer, entity, pass); + } + return true; +} + +bool SweepGradientContents::RenderTexture(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { using VS = SweepGradientFillPipeline::VertexShader; using FS = SweepGradientFillPipeline::FragmentShader; + auto gradient_data = CreateGradientBuffer(colors_, stops_); auto gradient_texture = - CreateGradientTexture(colors_, stops_, renderer.GetContext()); + CreateGradientTexture(gradient_data, renderer.GetContext()); if (gradient_texture == nullptr) { return false; } diff --git a/impeller/entity/contents/sweep_gradient_contents.h b/impeller/entity/contents/sweep_gradient_contents.h index a25c2f090cb66..94c448cc22961 100644 --- a/impeller/entity/contents/sweep_gradient_contents.h +++ b/impeller/entity/contents/sweep_gradient_contents.h @@ -12,6 +12,7 @@ #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" +#include "impeller/geometry/gradient.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" #include "impeller/geometry/scalar.h" @@ -42,6 +43,14 @@ class SweepGradientContents final : public ColorSourceContents { const std::vector& GetStops() const; private: + bool RenderTexture(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + + bool RenderSSBO(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const; + Point center_; Scalar bias_; Scalar scale_; diff --git a/impeller/entity/shaders/linear_gradient_ssbo_fill.frag b/impeller/entity/shaders/linear_gradient_ssbo_fill.frag new file mode 100644 index 0000000000000..e8cc761c9046b --- /dev/null +++ b/impeller/entity/shaders/linear_gradient_ssbo_fill.frag @@ -0,0 +1,41 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +readonly buffer ColorData { + vec4 colors[]; +} color_data; + +uniform GradientInfo { + vec2 start_point; + vec2 end_point; + float alpha; + float tile_mode; + float colors_length; +} gradient_info; + +in vec2 v_position; + +out vec4 frag_color; + +void main() { + float len = length(gradient_info.end_point - gradient_info.start_point); + float dot = dot( + v_position - gradient_info.start_point, + gradient_info.end_point - gradient_info.start_point + ); + float t = dot / (len * len); + + if ((t < 0.0 || t > 1.0) && gradient_info.tile_mode == kTileModeDecal) { + frag_color = vec4(0); + return; + } + t = IPFloatTile(t, gradient_info.tile_mode); + vec3 values = IPComputeFixedGradientValues(t, gradient_info.colors_length); + + frag_color = mix(color_data.colors[int(values.x)], color_data.colors[int(values.y)], values.z); + frag_color = vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; +} diff --git a/impeller/entity/shaders/radial_gradient_ssbo_fill.frag b/impeller/entity/shaders/radial_gradient_ssbo_fill.frag new file mode 100644 index 0000000000000..b6ce052286102 --- /dev/null +++ b/impeller/entity/shaders/radial_gradient_ssbo_fill.frag @@ -0,0 +1,37 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +readonly buffer ColorData { + vec4 colors[]; +} color_data; + +uniform GradientInfo { + vec2 center; + float radius; + float tile_mode; + float alpha; + float colors_length; +} gradient_info; + +in vec2 v_position; + +out vec4 frag_color; + +void main() { + float len = length(v_position - gradient_info.center); + float t = len / gradient_info.radius; + + if ((t < 0.0 || t > 1.0) && gradient_info.tile_mode == kTileModeDecal) { + frag_color = vec4(0); + return; + } + t = IPFloatTile(t, gradient_info.tile_mode); + vec3 values = IPComputeFixedGradientValues(t, gradient_info.colors_length); + + frag_color = mix(color_data.colors[int(values.x)], color_data.colors[int(values.y)], values.z); + frag_color = vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; +} diff --git a/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag b/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag new file mode 100644 index 0000000000000..129f4aa95c467 --- /dev/null +++ b/impeller/entity/shaders/sweep_gradient_ssbo_fill.frag @@ -0,0 +1,40 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include +#include + +readonly buffer ColorData { + vec4 colors[]; +} color_data; + +uniform GradientInfo { + vec2 center; + float bias; + float scale; + float tile_mode; + float alpha; + float colors_length; +} gradient_info; + +in vec2 v_position; + +out vec4 frag_color; + +void main() { + vec2 coord = v_position - gradient_info.center; + float angle = atan(-coord.y, -coord.x); + float t = (angle * k1Over2Pi + 0.5 + gradient_info.bias) * gradient_info.scale; + + if ((t < 0.0 || t > 1.0) && gradient_info.tile_mode == kTileModeDecal) { + frag_color = vec4(0); + return; + } + t = IPFloatTile(t, gradient_info.tile_mode); + vec3 values = IPComputeFixedGradientValues(t, gradient_info.colors_length); + + frag_color = mix(color_data.colors[int(values.x)], color_data.colors[int(values.y)], values.z); + frag_color = vec4(frag_color.xyz * frag_color.a, frag_color.a) * gradient_info.alpha; +} diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index 9392b12947cbb..0292ffac4f58b 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -1818,6 +1818,75 @@ TEST(GeometryTest, Gradient) { auto gradient = CreateGradientBuffer(colors, stops); ASSERT_EQ(gradient.texture_size, 1024u); + ASSERT_EQ(gradient.color_bytes.size(), 1024u * 4); + } +} + +TEST(GeometryTest, GradientSSBO) { + { + // Simple 2 color gradient produces std::nullopt, as original + // color vector should be used. + std::vector colors = {Color::Red(), Color::Blue()}; + std::vector stops = {0.0, 1.0}; + + auto gradient = CreateGradientColors(colors, stops); + + ASSERT_EQ(gradient, std::nullopt); + } + + { + // Gradient with duplicate stops does not create an empty texture. + std::vector colors = {Color::Red(), Color::Yellow(), Color::Black(), + Color::Blue()}; + std::vector stops = {0.0, 0.25, 0.25, 1.0}; + + auto gradient = CreateGradientColors(colors, stops); + ASSERT_EQ(gradient.value().size(), 5u); + } + + { + // Simple N color gradient produces color buffer containing exactly those + // values. + std::vector colors = {Color::Red(), Color::Blue(), Color::Green(), + Color::White()}; + std::vector stops = {0.0, 0.33, 0.66, 1.0}; + + auto gradient = CreateGradientColors(colors, stops); + + ASSERT_EQ(gradient, std::nullopt); + } + + { + // Gradient with color stops will lerp and scale buffer. + std::vector colors = {Color::Red(), Color::Blue(), Color::Green()}; + std::vector stops = {0.0, 0.25, 1.0}; + + auto gradient = CreateGradientColors(colors, stops); + + std::vector lerped_colors = { + Color::Red(), + Color::Blue(), + Color::lerp(Color::Blue(), Color::Green(), 0.3333), + Color::lerp(Color::Blue(), Color::Green(), 0.6666), + Color::Green(), + }; + + ASSERT_COLORS_NEAR(gradient.value(), lerped_colors); + ASSERT_EQ(gradient.value().size(), 5u); + } + + { + // Gradient size is capped at 1024. + std::vector colors = {}; + std::vector stops = {}; + for (auto i = 0u; i < 1025; i++) { + colors.push_back(Color::Blue()); + stops.push_back(i / 1025.0); + } + + auto gradient = CreateGradientColors(colors, stops); + + ASSERT_EQ(gradient.value().size(), 1024u); } } diff --git a/impeller/geometry/geometry_unittests.h b/impeller/geometry/geometry_unittests.h index 4407ad85479c5..84d960293d379 100644 --- a/impeller/geometry/geometry_unittests.h +++ b/impeller/geometry/geometry_unittests.h @@ -131,6 +131,23 @@ inline ::testing::AssertionResult ColorBufferNear( return ::testing::AssertionSuccess(); } +inline ::testing::AssertionResult ColorsNear(std::vector a, + std::vector b) { + if (a.size() != b.size()) { + return ::testing::AssertionFailure() << "Colors length does not match"; + } + for (auto i = 0u; i < b.size(); i++) { + auto equal = + NumberNear(a[i].red, b[i].red) && NumberNear(a[i].green, b[i].green) && + NumberNear(a[i].blue, b[i].blue) && NumberNear(a[i].alpha, b[i].alpha); + + if (!equal) { + ::testing::AssertionFailure() << "Colors are not equal."; + } + } + return ::testing::AssertionSuccess(); +} + #define ASSERT_MATRIX_NEAR(a, b) ASSERT_PRED2(&::MatrixNear, a, b) #define ASSERT_QUATERNION_NEAR(a, b) ASSERT_PRED2(&::QuaternionNear, a, b) #define ASSERT_RECT_NEAR(a, b) ASSERT_PRED2(&::RectNear, a, b) @@ -141,3 +158,4 @@ inline ::testing::AssertionResult ColorBufferNear( #define ASSERT_SIZE_NEAR(a, b) ASSERT_PRED2(&::SizeNear, a, b) #define ASSERT_ARRAY_4_NEAR(a, b) ASSERT_PRED2(&::Array4Near, a, b) #define ASSERT_COLOR_BUFFER_NEAR(a, b) ASSERT_PRED2(&::ColorBufferNear, a, b) +#define ASSERT_COLORS_NEAR(a, b) ASSERT_PRED2(&::ColorsNear, a, b) diff --git a/impeller/geometry/gradient.cc b/impeller/geometry/gradient.cc index 086d90c2e68b4..e668827e80ea4 100644 --- a/impeller/geometry/gradient.cc +++ b/impeller/geometry/gradient.cc @@ -9,12 +9,12 @@ namespace impeller { -static void AppendColor(const Color& color, std::vector* colors) { +static void AppendColor(const Color& color, GradientData* data) { auto converted = color.ToR8G8B8A8(); - colors->push_back(converted[0]); - colors->push_back(converted[1]); - colors->push_back(converted[2]); - colors->push_back(converted[3]); + data->color_bytes.push_back(converted[0]); + data->color_bytes.push_back(converted[1]); + data->color_bytes.push_back(converted[2]); + data->color_bytes.push_back(converted[3]); } GradientData CreateGradientBuffer(const std::vector& colors, @@ -43,12 +43,15 @@ GradientData CreateGradientBuffer(const std::vector& colors, texture_size = std::min( static_cast(std::round(1.0 / minimum_delta)) + 1, 1024u); } - std::vector color_stop_channels; - color_stop_channels.reserve(texture_size * 4); + GradientData data = { + .color_bytes = {}, + .texture_size = texture_size, + }; + data.color_bytes.reserve(texture_size * 4); if (texture_size == colors.size() && colors.size() <= 1024) { for (auto i = 0u; i < colors.size(); i++) { - AppendColor(colors[i], &color_stop_channels); + AppendColor(colors[i], &data); } } else { Color previous_color = colors[0]; @@ -56,7 +59,7 @@ GradientData CreateGradientBuffer(const std::vector& colors, auto previous_color_index = 0; // The first index is always equal to the first color, exactly. - AppendColor(previous_color, &color_stop_channels); + AppendColor(previous_color, &data); for (auto i = 1u; i < texture_size - 1; i++) { auto scaled_i = i / (texture_size - 1.0); @@ -64,7 +67,7 @@ GradientData CreateGradientBuffer(const std::vector& colors, auto next_stop = stops[previous_color_index + 1]; // We're almost exactly equal to the next stop. if (ScalarNearlyEqual(scaled_i, next_stop)) { - AppendColor(next_color, &color_stop_channels); + AppendColor(next_color, &data); previous_color = next_color; previous_stop = next_stop; @@ -74,7 +77,7 @@ GradientData CreateGradientBuffer(const std::vector& colors, auto t = (scaled_i - previous_stop) / (next_stop - previous_stop); auto mixed_color = Color::lerp(previous_color, next_color, t); - AppendColor(mixed_color, &color_stop_channels); + AppendColor(mixed_color, &data); } else { // We've slightly overshot the previous stop. previous_color = next_color; @@ -86,16 +89,89 @@ GradientData CreateGradientBuffer(const std::vector& colors, auto t = (scaled_i - previous_stop) / (next_stop - previous_stop); auto mixed_color = Color::lerp(previous_color, next_color, t); - AppendColor(mixed_color, &color_stop_channels); + AppendColor(mixed_color, &data); } } // The last index is always equal to the last color, exactly. - AppendColor(colors.back(), &color_stop_channels); + AppendColor(colors.back(), &data); } - return GradientData{ - .color_bytes = std::move(color_stop_channels), - .texture_size = texture_size, - }; + return data; +} + +std::optional> CreateGradientColors( + const std::vector& colors, + const std::vector& stops) { + FML_DCHECK(stops.size() == colors.size()); + + if (stops.size() == 2) { + // Use original buffer. + return std::nullopt; + } + + auto minimum_delta = 1.0; + for (size_t i = 1; i < stops.size(); i++) { + auto value = stops[i] - stops[i - 1]; + // Smaller than kEhCloseEnough + if (value < 0.0001) { + continue; + } + if (value < minimum_delta) { + minimum_delta = value; + } + } + // Avoid creating buffers that are absurdly large due to stops that are + // very close together. + uint32_t color_count = std::min( + static_cast(std::round(1.0 / minimum_delta)) + 1, 1024u); + + if (color_count == colors.size()) { + // Use original buffer. + return std::nullopt; + } + + std::vector data; + data.reserve(color_count); + + Color previous_color = colors[0]; + auto previous_stop = 0.0; + auto previous_color_index = 0; + + // The first index is always equal to the first color, exactly. + data.push_back(colors[0]); + + for (auto i = 1u; i < color_count - 1; i++) { + auto scaled_i = i / (color_count - 1.0); + Color next_color = colors[previous_color_index + 1]; + auto next_stop = stops[previous_color_index + 1]; + // We're almost exactly equal to the next stop. + if (ScalarNearlyEqual(scaled_i, next_stop)) { + data.push_back(next_color); + + previous_color = next_color; + previous_stop = next_stop; + previous_color_index += 1; + } else if (scaled_i < next_stop) { + // We're still between the current stop and the next stop. + auto t = (scaled_i - previous_stop) / (next_stop - previous_stop); + auto mixed_color = Color::lerp(previous_color, next_color, t); + + data.push_back(mixed_color); + } else { + // We've slightly overshot the previous stop. + previous_color = next_color; + previous_stop = next_stop; + previous_color_index += 1; + next_color = colors[previous_color_index + 1]; + auto next_stop = stops[previous_color_index + 1]; + + auto t = (scaled_i - previous_stop) / (next_stop - previous_stop); + auto mixed_color = Color::lerp(previous_color, next_color, t); + data.push_back(mixed_color); + } + } + // The last index is always equal to the last color, exactly. + data.push_back(colors.back()); + return data; } } // namespace impeller diff --git a/impeller/geometry/gradient.h b/impeller/geometry/gradient.h index d9f943de77177..2d8e737adab35 100644 --- a/impeller/geometry/gradient.h +++ b/impeller/geometry/gradient.h @@ -20,8 +20,8 @@ struct GradientData { }; /** - * @brief Populate a vector with the interpolated colors for the linear gradient - * described colors and stops. + * @brief Populate a vector with the interpolated color bytes for the linear + * gradient described by colors and stops. * * @param colors * @param stops @@ -30,4 +30,19 @@ struct GradientData { GradientData CreateGradientBuffer(const std::vector& colors, const std::vector& stops); +/** + * @brief Populate a vector with the interpolated colors for the linear gradient + * described by colors and stops. + * + * If the returned result is std::nullopt, the original color buffer can be used + * instead. + * + * @param colors + * @param stops + * @return GradientData + */ +std::optional> CreateGradientColors( + const std::vector& colors, + const std::vector& stops); + } // namespace impeller diff --git a/impeller/playground/BUILD.gn b/impeller/playground/BUILD.gn index 68ba55aa46045..627160f7def96 100644 --- a/impeller/playground/BUILD.gn +++ b/impeller/playground/BUILD.gn @@ -40,6 +40,7 @@ impeller_component("playground") { public_deps = [ "../entity:entity_shaders", + "../entity:modern_entity_shaders", "../fixtures:shader_fixtures", "../renderer", "imgui:imgui_impeller_backend", diff --git a/impeller/playground/backend/metal/playground_impl_mtl.mm b/impeller/playground/backend/metal/playground_impl_mtl.mm index 1a66beac6c0ab..c400e62a9f7a5 100644 --- a/impeller/playground/backend/metal/playground_impl_mtl.mm +++ b/impeller/playground/backend/metal/playground_impl_mtl.mm @@ -15,6 +15,7 @@ #include "flutter/fml/mapping.h" #include "impeller/entity/mtl/entity_shaders.h" +#include "impeller/entity/mtl/modern_shaders.h" #include "impeller/fixtures/mtl/fixtures_shaders.h" #include "impeller/playground/imgui/mtl/imgui_shaders.h" #include "impeller/renderer/backend/metal/context_mtl.h" @@ -33,6 +34,8 @@ return { std::make_shared(impeller_entity_shaders_data, impeller_entity_shaders_length), + std::make_shared(impeller_modern_shaders_data, + impeller_modern_shaders_length), std::make_shared(impeller_fixtures_shaders_data, impeller_fixtures_shaders_length), std::make_shared(impeller_imgui_shaders_data, diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index e6234c642038e..e539249ed2d7e 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -137,4 +137,9 @@ bool ContextGLES::SupportsOffscreenMSAA() const { return false; } +// |Context| +const BackendFeatures& ContextGLES::GetBackendFeatures() const { + return kLegacyBackendFeatures; +} + } // namespace impeller diff --git a/impeller/renderer/backend/gles/context_gles.h b/impeller/renderer/backend/gles/context_gles.h index 138843a7fb7a3..9e23e1900608c 100644 --- a/impeller/renderer/backend/gles/context_gles.h +++ b/impeller/renderer/backend/gles/context_gles.h @@ -73,6 +73,9 @@ class ContextGLES final : public Context, // |Context| bool SupportsOffscreenMSAA() const override; + // |Context| + const BackendFeatures& GetBackendFeatures() const override; + FML_DISALLOW_COPY_AND_ASSIGN(ContextGLES); }; diff --git a/impeller/renderer/backend/metal/context_mtl.h b/impeller/renderer/backend/metal/context_mtl.h index 1ba4740d09525..df6089f618e3f 100644 --- a/impeller/renderer/backend/metal/context_mtl.h +++ b/impeller/renderer/backend/metal/context_mtl.h @@ -76,6 +76,9 @@ class ContextMTL final : public Context, // |Context| bool SupportsOffscreenMSAA() const override; + // |Context| + const BackendFeatures& GetBackendFeatures() const override; + std::shared_ptr CreateCommandBufferInQueue( id queue) const; diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index 379b7cf52fb5f..faedec8e5bf2b 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -247,4 +247,9 @@ return true; } +// |Context| +const BackendFeatures& ContextMTL::GetBackendFeatures() const { + return kModernBackendFeatures; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index e2002204cd13c..2d4ebbe910ec9 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -25,6 +25,7 @@ #include "impeller/renderer/backend/vulkan/surface_producer_vk.h" #include "impeller/renderer/backend/vulkan/swapchain_details_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" +#include "impeller/renderer/backend_features.h" VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE @@ -596,4 +597,8 @@ PixelFormat ContextVK::GetColorAttachmentPixelFormat() const { return ToPixelFormat(surface_format_); } +const BackendFeatures& ContextVK::GetBackendFeatures() const { + return kModernBackendFeatures; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 44806548cd5af..ef8a5661564ee 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -145,6 +145,9 @@ class ContextVK final : public Context, public BackendCast { // |Context| bool SupportsOffscreenMSAA() const override; + // |Context| + const BackendFeatures& GetBackendFeatures() const override; + FML_DISALLOW_COPY_AND_ASSIGN(ContextVK); }; diff --git a/impeller/renderer/backend_features.h b/impeller/renderer/backend_features.h new file mode 100644 index 0000000000000..f8ea75b134a50 --- /dev/null +++ b/impeller/renderer/backend_features.h @@ -0,0 +1,21 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +namespace impeller { + +/// @brief A struct for describing available backend features for runtime +/// selection. +struct BackendFeatures { + bool ssbo_support; +}; + +/// @brief feature sets available on most but not all modern hardware. +constexpr BackendFeatures kModernBackendFeatures = {.ssbo_support = true}; + +/// @brief Lowest common denominator feature sets. +constexpr BackendFeatures kLegacyBackendFeatures = {.ssbo_support = false}; + +} // namespace impeller diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index 8ba839b8612c0..9d0fd7113a67e 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -8,6 +8,7 @@ #include #include "flutter/fml/macros.h" +#include "impeller/renderer/backend_features.h" #include "impeller/renderer/formats.h" namespace impeller { @@ -52,6 +53,8 @@ class Context : public std::enable_shared_from_this { virtual bool SupportsOffscreenMSAA() const = 0; + virtual const BackendFeatures& GetBackendFeatures() const = 0; + protected: Context(); diff --git a/impeller/tools/impeller.gni b/impeller/tools/impeller.gni index 38495962cdfed..aeb3f162a172d 100644 --- a/impeller/tools/impeller.gni +++ b/impeller/tools/impeller.gni @@ -280,6 +280,11 @@ template("impellerc") { "$shader_target_flag", ] + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + args += [ "--gles-language-version=$gles_language_version" ] + } + if (json) { args += [ "--json" ] } @@ -459,6 +464,9 @@ template("impeller_shaders_gles") { impellerc(impellerc_gles) { shaders = invoker.shaders sl_file_extension = "gles" + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + } # Metal reflectors generate a superset of information. if (impeller_enable_metal || impeller_enable_vulkan) { @@ -571,6 +579,9 @@ template("impeller_shaders") { gles_shaders = "gles_$target_name" impeller_shaders_gles(gles_shaders) { name = invoker.name + if (defined(invoker.gles_language_version)) { + gles_language_version = invoker.gles_language_version + } if (defined(invoker.gles_exclusions)) { shaders = invoker.shaders - invoker.gles_exclusions } else { diff --git a/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm b/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm index a75711c2b4441..1ab7dcd51d3c4 100644 --- a/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm +++ b/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm @@ -10,6 +10,7 @@ #include "flutter/impeller/renderer/backend/metal/context_mtl.h" #include "flutter/shell/common/context_options.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" +#include "impeller/entity/mtl/modern_shaders.h" FLUTTER_ASSERT_ARC @@ -17,6 +18,8 @@ std::vector> shader_mappings = { std::make_shared(impeller_entity_shaders_data, impeller_entity_shaders_length), + std::make_shared(impeller_modern_shaders_data, + impeller_modern_shaders_length), }; auto context = impeller::ContextMTL::Create(shader_mappings, "Impeller Library"); if (!context) {