diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index daa6e2755f882..368629029cac4 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1598,11 +1598,15 @@ FILE: ../../../flutter/impeller/scene/material.cc FILE: ../../../flutter/impeller/scene/material.h FILE: ../../../flutter/impeller/scene/scene.cc FILE: ../../../flutter/impeller/scene/scene.h +FILE: ../../../flutter/impeller/scene/scene_context.cc +FILE: ../../../flutter/impeller/scene/scene_context.h FILE: ../../../flutter/impeller/scene/scene_encoder.cc FILE: ../../../flutter/impeller/scene/scene_encoder.h FILE: ../../../flutter/impeller/scene/scene_entity.cc FILE: ../../../flutter/impeller/scene/scene_entity.h FILE: ../../../flutter/impeller/scene/scene_unittests.cc +FILE: ../../../flutter/impeller/scene/shaders/geometry.vert +FILE: ../../../flutter/impeller/scene/shaders/unlit.frag FILE: ../../../flutter/impeller/scene/static_mesh_entity.cc FILE: ../../../flutter/impeller/scene/static_mesh_entity.h FILE: ../../../flutter/impeller/tessellator/c/tessellator.cc diff --git a/impeller/playground/BUILD.gn b/impeller/playground/BUILD.gn index 627160f7def96..8940b5baef8f8 100644 --- a/impeller/playground/BUILD.gn +++ b/impeller/playground/BUILD.gn @@ -43,6 +43,7 @@ impeller_component("playground") { "../entity:modern_entity_shaders", "../fixtures:shader_fixtures", "../renderer", + "../scene/shaders", "imgui:imgui_impeller_backend", "//flutter/fml", "//third_party/glfw", diff --git a/impeller/playground/backend/gles/playground_impl_gles.cc b/impeller/playground/backend/gles/playground_impl_gles.cc index 804672f11a0e0..999ccfbae07e5 100644 --- a/impeller/playground/backend/gles/playground_impl_gles.cc +++ b/impeller/playground/backend/gles/playground_impl_gles.cc @@ -13,6 +13,7 @@ #include "impeller/playground/imgui/gles/imgui_shaders_gles.h" #include "impeller/renderer/backend/gles/context_gles.h" #include "impeller/renderer/backend/gles/surface_gles.h" +#include "impeller/scene/shaders/gles/scene_shaders_gles.h" namespace impeller { @@ -94,6 +95,8 @@ ShaderLibraryMappingsForPlayground() { impeller_fixtures_shaders_gles_length), std::make_shared( impeller_imgui_shaders_gles_data, impeller_imgui_shaders_gles_length), + std::make_shared( + impeller_scene_shaders_gles_data, impeller_scene_shaders_gles_length), }; } diff --git a/impeller/playground/backend/metal/playground_impl_mtl.mm b/impeller/playground/backend/metal/playground_impl_mtl.mm index c400e62a9f7a5..c3f9e0c33d8e4 100644 --- a/impeller/playground/backend/metal/playground_impl_mtl.mm +++ b/impeller/playground/backend/metal/playground_impl_mtl.mm @@ -22,6 +22,7 @@ #include "impeller/renderer/backend/metal/formats_mtl.h" #include "impeller/renderer/backend/metal/surface_mtl.h" #include "impeller/renderer/backend/metal/texture_mtl.h" +#include "impeller/scene/shaders/mtl/scene_shaders.h" namespace impeller { @@ -40,6 +41,8 @@ impeller_fixtures_shaders_length), std::make_shared(impeller_imgui_shaders_data, impeller_imgui_shaders_length), + std::make_shared(impeller_scene_shaders_data, + impeller_scene_shaders_length), }; } diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.cc b/impeller/playground/backend/vulkan/playground_impl_vk.cc index ca96a816d6f60..3b045b35d4516 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.cc +++ b/impeller/playground/backend/vulkan/playground_impl_vk.cc @@ -19,6 +19,7 @@ #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/surface_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" +#include "impeller/scene/shaders/vk/scene_shaders_vk.h" namespace impeller { @@ -34,6 +35,8 @@ ShaderLibraryMappingsForPlayground() { impeller_fixtures_shaders_vk_length), std::make_shared(impeller_imgui_shaders_vk_data, impeller_imgui_shaders_vk_length), + std::make_shared(impeller_scene_shaders_vk_data, + impeller_scene_shaders_vk_length), }; } diff --git a/impeller/scene/BUILD.gn b/impeller/scene/BUILD.gn index 3389ad42bde7b..30f45eadee109 100644 --- a/impeller/scene/BUILD.gn +++ b/impeller/scene/BUILD.gn @@ -14,6 +14,8 @@ impeller_component("scene") { "material.h", "scene.cc", "scene.h", + "scene_context.cc", + "scene_context.h", "scene_encoder.cc", "scene_encoder.h", "scene_entity.cc", @@ -22,7 +24,10 @@ impeller_component("scene") { "static_mesh_entity.h", ] - public_deps = [ "../renderer" ] + public_deps = [ + "../renderer", + "shaders", + ] deps = [ "//flutter/fml" ] } diff --git a/impeller/scene/scene.cc b/impeller/scene/scene.cc index 4a4cba16a59fc..6fbd0e6f2571c 100644 --- a/impeller/scene/scene.cc +++ b/impeller/scene/scene.cc @@ -9,12 +9,14 @@ #include "flutter/fml/logging.h" #include "impeller/renderer/render_target.h" +#include "impeller/scene/scene_context.h" #include "impeller/scene/scene_encoder.h" namespace impeller { namespace scene { -Scene::Scene(const std::shared_ptr& context) : context_(context){}; +Scene::Scene(std::shared_ptr context) + : scene_context_(std::make_unique(std::move(context))){}; void Scene::Add(const std::shared_ptr& child) { root_.Add(child); @@ -31,7 +33,8 @@ bool Scene::Render(const RenderTarget& render_target, // Encode the commands. std::shared_ptr command_buffer = - encoder.BuildSceneCommandBuffer(*context_, render_target); + encoder.BuildSceneCommandBuffer(*scene_context_->GetContext(), + render_target); // TODO(bdero): Do post processing. diff --git a/impeller/scene/scene.h b/impeller/scene/scene.h index 6a69e79e2be3f..1e279f6f7fd46 100644 --- a/impeller/scene/scene.h +++ b/impeller/scene/scene.h @@ -11,6 +11,7 @@ #include "impeller/renderer/render_target.h" #include "impeller/scene/camera.h" +#include "impeller/scene/scene_context.h" #include "impeller/scene/scene_entity.h" namespace impeller { @@ -19,13 +20,13 @@ namespace scene { class Scene { public: Scene() = delete; - explicit Scene(const std::shared_ptr& context); + explicit Scene(std::shared_ptr context); void Add(const std::shared_ptr& child); bool Render(const RenderTarget& render_target, const Camera& camera) const; private: - std::shared_ptr context_; + std::unique_ptr scene_context_; SceneEntity root_; FML_DISALLOW_COPY_AND_ASSIGN(Scene); diff --git a/impeller/scene/scene_context.cc b/impeller/scene/scene_context.cc new file mode 100644 index 0000000000000..006b13ccc8c05 --- /dev/null +++ b/impeller/scene/scene_context.cc @@ -0,0 +1,50 @@ +// 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 "impeller/scene/scene_context.h" + +namespace impeller { +namespace scene { + +void SceneContextOptions::ApplyToPipelineDescriptor( + PipelineDescriptor& desc) const { + desc.SetSampleCount(sample_count); + desc.SetPrimitiveType(primitive_type); +} + +template +static std::unique_ptr CreateDefaultPipeline( + const Context& context) { + auto desc = PipelineT::Builder::MakeDefaultPipelineDescriptor(context); + if (!desc.has_value()) { + return nullptr; + } + // Apply default ContentContextOptions to the descriptor. + SceneContextOptions{}.ApplyToPipelineDescriptor(*desc); + return std::make_unique(context, desc); +} + +SceneContext::SceneContext(std::shared_ptr context) + : context_(std::move(context)) { + if (!context_ || !context_->IsValid()) { + return; + } + + unlit_pipeline_[{}] = CreateDefaultPipeline(*context_); + + is_valid_ = true; +} + +SceneContext::~SceneContext() = default; + +bool SceneContext::IsValid() const { + return is_valid_; +} + +std::shared_ptr SceneContext::GetContext() const { + return context_; +} + +} // namespace scene +} // namespace impeller diff --git a/impeller/scene/scene_context.h b/impeller/scene/scene_context.h new file mode 100644 index 0000000000000..0b13e480d0888 --- /dev/null +++ b/impeller/scene/scene_context.h @@ -0,0 +1,100 @@ +// 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 + +#include "impeller/renderer/context.h" +#include "impeller/renderer/pipeline_descriptor.h" +#include "impeller/scene/shaders/geometry.vert.h" +#include "impeller/scene/shaders/unlit.frag.h" + +namespace impeller { +namespace scene { + +using UnlitPipeline = + RenderPipelineT; + +struct SceneContextOptions { + SampleCount sample_count = SampleCount::kCount1; + PrimitiveType primitive_type = PrimitiveType::kTriangle; + + struct Hash { + constexpr std::size_t operator()(const SceneContextOptions& o) const { + return fml::HashCombine(o.sample_count, o.primitive_type); + } + }; + + struct Equal { + constexpr bool operator()(const SceneContextOptions& lhs, + const SceneContextOptions& rhs) const { + return lhs.sample_count == rhs.sample_count && + lhs.primitive_type == rhs.primitive_type; + } + }; + + void ApplyToPipelineDescriptor(PipelineDescriptor& desc) const; +}; + +class SceneContext { + public: + explicit SceneContext(std::shared_ptr context); + + ~SceneContext(); + + bool IsValid() const; + + std::shared_ptr GetContext() const; + + std::shared_ptr> GetUnlitPipeline( + SceneContextOptions opts) const { + return GetPipeline(unlit_pipeline_, opts); + } + + private: + std::shared_ptr context_; + + template + using Variants = std::unordered_map, + SceneContextOptions::Hash, + SceneContextOptions::Equal>; + + mutable Variants unlit_pipeline_; + + template + std::shared_ptr> GetPipeline( + Variants& container, + SceneContextOptions opts) const { + if (!IsValid()) { + return nullptr; + } + + if (auto found = container.find(opts); found != container.end()) { + return found->second->WaitAndGet(); + } + + auto prototype = container.find({}); + + // The prototype must always be initialized in the constructor. + FML_CHECK(prototype != container.end()); + + auto variant_future = prototype->second->WaitAndGet()->CreateVariant( + [&opts, variants_count = container.size()](PipelineDescriptor& desc) { + opts.ApplyToPipelineDescriptor(desc); + desc.SetLabel( + SPrintF("%s V#%zu", desc.GetLabel().c_str(), variants_count)); + }); + auto variant = std::make_unique(std::move(variant_future)); + auto variant_pipeline = variant->WaitAndGet(); + container[opts] = std::move(variant); + return variant_pipeline; + } + + bool is_valid_ = false; + + FML_DISALLOW_COPY_AND_ASSIGN(SceneContext); +}; + +} // namespace scene +} // namespace impeller diff --git a/impeller/scene/scene_unittests.cc b/impeller/scene/scene_unittests.cc index 3388c7062b54f..9f2281cd1245e 100644 --- a/impeller/scene/scene_unittests.cc +++ b/impeller/scene/scene_unittests.cc @@ -25,26 +25,26 @@ namespace testing { using SceneTest = PlaygroundTest; INSTANTIATE_PLAYGROUND_SUITE(SceneTest); -TEST_P(SceneTest, UnlitScene) { - auto allocator = GetContext()->GetResourceAllocator(); - auto scene = Scene(GetContext()); +TEST_P(SceneTest, CuboidUnlit) { + Renderer::RenderCallback callback = [&](RenderTarget& render_target) { + auto allocator = GetContext()->GetResourceAllocator(); + auto scene = Scene(GetContext()); - { - auto mesh = SceneEntity::MakeStaticMesh(); + { + auto mesh = SceneEntity::MakeStaticMesh(); - auto material = Material::MakeUnlit(); - material->SetColor(Color::Red()); - mesh->SetMaterial(std::move(material)); + auto material = Material::MakeUnlit(); + material->SetColor(Color::Red()); + mesh->SetMaterial(std::move(material)); - Vector3 size(1, 2, 3); - mesh->SetGeometry(Geometry::MakeCuboid(size)); + Vector3 size(1, 2, 3); + mesh->SetGeometry(Geometry::MakeCuboid(size)); - mesh->SetLocalTransform(Matrix::MakeTranslation(size / 2)); + mesh->SetLocalTransform(Matrix::MakeTranslation(size / 2)); - scene.Add(mesh); - } + scene.Add(mesh); + } - Renderer::RenderCallback callback = [&](RenderTarget& render_target) { auto camera = Camera::MakePerspective( /* fov */ kPiOver4, /* position */ {50, -30, 50}) diff --git a/impeller/scene/shaders/BUILD.gn b/impeller/scene/shaders/BUILD.gn new file mode 100644 index 0000000000000..a802c63f35390 --- /dev/null +++ b/impeller/scene/shaders/BUILD.gn @@ -0,0 +1,14 @@ +# 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. + +import("//flutter/impeller/tools/impeller.gni") + +impeller_shaders("shaders") { + name = "scene" + + shaders = [ + "geometry.vert", + "unlit.frag", + ] +} diff --git a/impeller/scene/shaders/geometry.vert b/impeller/scene/shaders/geometry.vert new file mode 100644 index 0000000000000..fda66b8a4819a --- /dev/null +++ b/impeller/scene/shaders/geometry.vert @@ -0,0 +1,26 @@ +// 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. + +uniform VertInfo { + mat4 mvp; +} +vert_info; + +in vec3 position; +in vec3 normal; +in vec3 tangent; +in vec2 texture_coords; + +out vec3 v_position; +out mat3 v_tangent_space; +out vec2 v_texture_coords; + +void main() { + gl_Position = vert_info.mvp * vec4(position, 1.0); + v_position = gl_Position.xyz; + + v_tangent_space = + mat3(vert_info.mvp) * mat3(tangent, cross(normal, tangent), normal); + v_texture_coords = texture_coords; +} diff --git a/impeller/scene/shaders/unlit.frag b/impeller/scene/shaders/unlit.frag new file mode 100644 index 0000000000000..8f335913ab0e5 --- /dev/null +++ b/impeller/scene/shaders/unlit.frag @@ -0,0 +1,20 @@ +// 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. + +uniform FragInfo { + vec4 color; +} +frag_info; + +uniform sampler2D base_color_texture; + +in vec3 v_position; +in mat3 v_tangent_space; +in vec2 v_texture_coords; + +out vec4 frag_color; + +void main() { + frag_color = texture(base_color_texture, v_texture_coords) * frag_info.color; +}