diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 560e444e869f3..8b437f782eb2b 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -5572,20 +5572,39 @@ ORIGIN: ../../../flutter/impeller/typographer/typeface.cc + ../../../flutter/LIC ORIGIN: ../../../flutter/impeller/typographer/typeface.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/typographer_context.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/typographer/typographer_context.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/command_buffer.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/command_buffer.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/context.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/context.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/device_buffer.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/device_buffer.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/export.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/export.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/fixtures.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/fixtures.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/formats.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/formats.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/host_buffer.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/host_buffer.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/lib/gpu.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/lib/src/buffer.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/lib/src/command_buffer.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/lib/src/context.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/lib/src/formats.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/lib/src/render_pass.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/lib/src/render_pipeline.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/lib/src/shader.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/lib/src/shader_library.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/lib/src/smoketest.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/lib/src/texture.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/render_pass.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/render_pass.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/render_pipeline.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/render_pipeline.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/shader.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/shader.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/shader_library.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/gpu/shader_library.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/smoketest.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/smoketest.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/gpu/texture.cc + ../../../flutter/LICENSE @@ -8348,20 +8367,39 @@ FILE: ../../../flutter/impeller/typographer/typeface.cc FILE: ../../../flutter/impeller/typographer/typeface.h FILE: ../../../flutter/impeller/typographer/typographer_context.cc FILE: ../../../flutter/impeller/typographer/typographer_context.h +FILE: ../../../flutter/lib/gpu/command_buffer.cc +FILE: ../../../flutter/lib/gpu/command_buffer.h FILE: ../../../flutter/lib/gpu/context.cc FILE: ../../../flutter/lib/gpu/context.h FILE: ../../../flutter/lib/gpu/device_buffer.cc FILE: ../../../flutter/lib/gpu/device_buffer.h FILE: ../../../flutter/lib/gpu/export.cc FILE: ../../../flutter/lib/gpu/export.h +FILE: ../../../flutter/lib/gpu/fixtures.cc +FILE: ../../../flutter/lib/gpu/fixtures.h +FILE: ../../../flutter/lib/gpu/formats.cc +FILE: ../../../flutter/lib/gpu/formats.h FILE: ../../../flutter/lib/gpu/host_buffer.cc FILE: ../../../flutter/lib/gpu/host_buffer.h FILE: ../../../flutter/lib/gpu/lib/gpu.dart FILE: ../../../flutter/lib/gpu/lib/src/buffer.dart +FILE: ../../../flutter/lib/gpu/lib/src/command_buffer.dart FILE: ../../../flutter/lib/gpu/lib/src/context.dart FILE: ../../../flutter/lib/gpu/lib/src/formats.dart +FILE: ../../../flutter/lib/gpu/lib/src/render_pass.dart +FILE: ../../../flutter/lib/gpu/lib/src/render_pipeline.dart +FILE: ../../../flutter/lib/gpu/lib/src/shader.dart +FILE: ../../../flutter/lib/gpu/lib/src/shader_library.dart FILE: ../../../flutter/lib/gpu/lib/src/smoketest.dart FILE: ../../../flutter/lib/gpu/lib/src/texture.dart +FILE: ../../../flutter/lib/gpu/render_pass.cc +FILE: ../../../flutter/lib/gpu/render_pass.h +FILE: ../../../flutter/lib/gpu/render_pipeline.cc +FILE: ../../../flutter/lib/gpu/render_pipeline.h +FILE: ../../../flutter/lib/gpu/shader.cc +FILE: ../../../flutter/lib/gpu/shader.h +FILE: ../../../flutter/lib/gpu/shader_library.cc +FILE: ../../../flutter/lib/gpu/shader_library.h FILE: ../../../flutter/lib/gpu/smoketest.cc FILE: ../../../flutter/lib/gpu/smoketest.h FILE: ../../../flutter/lib/gpu/texture.cc diff --git a/impeller/compiler/impellerc_main.cc b/impeller/compiler/impellerc_main.cc index f09f323fae4f7..9c7b58b6d760b 100644 --- a/impeller/compiler/impellerc_main.cc +++ b/impeller/compiler/impellerc_main.cc @@ -8,15 +8,12 @@ #include "flutter/fml/backtrace.h" #include "flutter/fml/command_line.h" #include "flutter/fml/file.h" -#include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" -#include "impeller/base/strings.h" #include "impeller/compiler/compiler.h" #include "impeller/compiler/source_options.h" #include "impeller/compiler/switches.h" #include "impeller/compiler/types.h" #include "impeller/compiler/utilities.h" -#include "third_party/shaderc/libshaderc/include/shaderc/shaderc.hpp" namespace impeller { namespace compiler { @@ -88,7 +85,8 @@ bool Main(const fml::CommandLine& command_line) { // Generate SkSL if needed. std::shared_ptr sksl_mapping; - if (switches.iplr && TargetPlatformBundlesSkSL(switches.target_platform)) { + if (switches.iplr && TargetPlatformBundlesSkSL(switches.target_platform) && + switches.iplr_bundle.empty()) { SourceOptions sksl_options = options; sksl_options.target_platform = TargetPlatform::kSkSL; diff --git a/impeller/compiler/runtime_stage_data.cc b/impeller/compiler/runtime_stage_data.cc index 0a15de1f6f0cb..942a08963a29d 100644 --- a/impeller/compiler/runtime_stage_data.cc +++ b/impeller/compiler/runtime_stage_data.cc @@ -319,7 +319,7 @@ std::shared_ptr RuntimeStageData::CreateMapping() const { shader_->GetMapping() + shader_->GetSize()}; } // It is not an error for the SkSL to be ommitted. - if (sksl_->GetSize() > 0u) { + if (sksl_ && sksl_->GetSize() > 0u) { runtime_stage.sksl = {sksl_->GetMapping(), sksl_->GetMapping() + sksl_->GetSize()}; } diff --git a/impeller/compiler/switches.cc b/impeller/compiler/switches.cc index c539ed423228f..83c1ccaf3fb47 100644 --- a/impeller/compiler/switches.cc +++ b/impeller/compiler/switches.cc @@ -63,6 +63,9 @@ void Switches::PrintHelp(std::ostream& stream) { << std::endl; stream << "[optional] --iplr (causes --sl file to be emitted in iplr format)" << std::endl; + stream << "[optional] --iplr-bundle= (causes --sl file to be " + "emitted in the iplr bundle format)" + << std::endl; stream << "[optional] --reflection-json=" << std::endl; stream << "[optional] --reflection-header=" << std::endl; @@ -121,6 +124,7 @@ Switches::Switches(const fml::CommandLine& command_line) input_type(SourceTypeFromCommandLine(command_line)), sl_file_name(command_line.GetOptionValueWithDefault("sl", "")), iplr(command_line.HasOption("iplr")), + iplr_bundle(command_line.GetOptionValueWithDefault("iplr-bundle", "")), spirv_file_name(command_line.GetOptionValueWithDefault("spirv", "")), reflection_json_name( command_line.GetOptionValueWithDefault("reflection-json", "")), diff --git a/impeller/compiler/switches.h b/impeller/compiler/switches.h index c159f1a9cc545..c02e344fa4a88 100644 --- a/impeller/compiler/switches.h +++ b/impeller/compiler/switches.h @@ -24,6 +24,7 @@ struct Switches { SourceType input_type = SourceType::kUnknown; std::string sl_file_name = ""; bool iplr = false; + std::string iplr_bundle = ""; std::string spirv_file_name = ""; std::string reflection_json_name = ""; std::string reflection_header_name = ""; diff --git a/impeller/entity/contents/runtime_effect_contents.h b/impeller/entity/contents/runtime_effect_contents.h index 61cb4267e9bd2..ada5f582654bf 100644 --- a/impeller/entity/contents/runtime_effect_contents.h +++ b/impeller/entity/contents/runtime_effect_contents.h @@ -4,7 +4,6 @@ #pragma once -#include #include #include diff --git a/impeller/fixtures/BUILD.gn b/impeller/fixtures/BUILD.gn index bcd37254b2327..35bd4134bca43 100644 --- a/impeller/fixtures/BUILD.gn +++ b/impeller/fixtures/BUILD.gn @@ -114,6 +114,27 @@ test_fixtures("file_fixtures") { ] } +impellerc("flutter_gpu_shaders") { + shaders = [ + # Temporarily build Flutter GPU test shaders as runtime stages. + "flutter_gpu_unlit.frag", + "flutter_gpu_unlit.vert", + ] + sl_file_extension = "iplr" + shader_target_flag = "--runtime-stage-metal" + iplr = true + iplr_bundle = "temporary" +} + +test_fixtures("flutter_gpu_fixtures") { + dart_main = "dart_tests.dart" + + fixtures = + filter_include(get_target_outputs(":flutter_gpu_shaders"), [ "*.iplr" ]) + + deps = [ ":flutter_gpu_shaders" ] +} + group("fixtures") { testonly = true diff --git a/impeller/fixtures/dart_tests.dart b/impeller/fixtures/dart_tests.dart index 2413c1b5546ce..8ec5229b37df9 100644 --- a/impeller/fixtures/dart_tests.dart +++ b/impeller/fixtures/dart_tests.dart @@ -159,3 +159,64 @@ void textureAsImageThrowsWhenNotShaderReadable() { assert(exception!.contains( 'Only shader readable Flutter GPU textures can be used as UI Images')); } + +@pragma('vm:entry-point') +void canCreateShaderLibrary() { + final gpu.ShaderLibrary? library = gpu.ShaderLibrary.fromAsset('playground'); + assert(library != null); + final gpu.Shader? shader = library!['UnlitVertex']; + assert(shader != null); +} + +gpu.RenderPipeline createUnlitRenderPipeline() { + final gpu.ShaderLibrary? library = gpu.ShaderLibrary.fromAsset('playground'); + assert(library != null); + final gpu.Shader? vertex = library!['UnlitVertex']; + assert(vertex != null); + final gpu.Shader? fragment = library['UnlitFragment']; + assert(fragment != null); + return gpu.gpuContext.createRenderPipeline(vertex!, fragment!); +} + +ByteData float32(List values) { + return Float32List.fromList(values).buffer.asByteData(); +} + +@pragma('vm:entry-point') +void canCreateRenderPassAndSubmit() { + final gpu.Texture? renderTexture = + gpu.gpuContext.createTexture(gpu.StorageMode.devicePrivate, 100, 100); + assert(renderTexture != null); + + final gpu.CommandBuffer commandBuffer = gpu.gpuContext.createCommandBuffer(); + final gpu.RenderPass encoder = commandBuffer.createRenderPass( + colorAttachment: gpu.ColorAttachment(texture: renderTexture!)); + + final gpu.RenderPipeline pipeline = createUnlitRenderPipeline(); + encoder.bindPipeline(pipeline); + + final gpu.HostBuffer transients = gpu.HostBuffer(); + final gpu.BufferView vertices = transients.emplace(float32([ + -0.5, -0.5, // + 0.5, 0.5, // + 0.5, -0.5, // + ])); + final gpu.BufferView color = + transients.emplace(float32([0, 1, 0, 1])); // rgba + final gpu.BufferView mvp = transients.emplace(float32([ + 1, 0, 0, 0, // + 0, 1, 0, 0, // + 0, 0, 1, 0, // + 0, 0, 0, 1, // + ])); + encoder.bindVertexBuffer(vertices, 3); + + final gpu.UniformSlot? colorSlot = + pipeline.vertexShader.getUniformSlot('color'); + final gpu.UniformSlot? mvpSlot = pipeline.vertexShader.getUniformSlot('mvp'); + encoder.bindUniform(mvpSlot!, mvp); + encoder.bindUniform(colorSlot!, color); + encoder.draw(); + + commandBuffer.submit(); +} diff --git a/impeller/fixtures/flutter_gpu_unlit.frag b/impeller/fixtures/flutter_gpu_unlit.frag new file mode 100644 index 0000000000000..fc61864108b1d --- /dev/null +++ b/impeller/fixtures/flutter_gpu_unlit.frag @@ -0,0 +1,10 @@ +// 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. + +in vec4 v_color; +out vec4 frag_color; + +void main() { + frag_color = v_color; +} diff --git a/impeller/fixtures/flutter_gpu_unlit.vert b/impeller/fixtures/flutter_gpu_unlit.vert new file mode 100644 index 0000000000000..1de82a3294fb7 --- /dev/null +++ b/impeller/fixtures/flutter_gpu_unlit.vert @@ -0,0 +1,16 @@ +// 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. + +#version 320 es + +layout(location = 0) uniform mat4 mvp; +layout(location = 1) uniform vec4 color; + +in vec2 position; +out vec4 v_color; + +void main() { + v_color = color; + gl_Position = mvp * vec4(position, 0.0, 1.0); +} diff --git a/impeller/renderer/BUILD.gn b/impeller/renderer/BUILD.gn index a04ecd5e7ab0e..8d6a2061f9e59 100644 --- a/impeller/renderer/BUILD.gn +++ b/impeller/renderer/BUILD.gn @@ -143,15 +143,6 @@ impeller_component("renderer_unittests") { } } -test_fixtures("renderer_dart_fixtures") { - dart_main = "../fixtures/dart_tests.dart" - - fixtures = [ - "../fixtures/bay_bridge.jpg", - "../fixtures/boston.jpg", - ] -} - impeller_component("renderer_dart_unittests") { testonly = true @@ -159,8 +150,8 @@ impeller_component("renderer_dart_unittests") { deps = [ ":renderer", - ":renderer_dart_fixtures", - "../fixtures:shader_fixtures", + "../fixtures:flutter_gpu_fixtures", + "../fixtures:flutter_gpu_shaders", "../playground:playground_test", "//flutter/lib/gpu", "//flutter/runtime:runtime", diff --git a/impeller/renderer/render_pass.h b/impeller/renderer/render_pass.h index 658eb07163636..512c152d6e0bf 100644 --- a/impeller/renderer/render_pass.h +++ b/impeller/renderer/render_pass.h @@ -29,6 +29,8 @@ class RenderPass { public: virtual ~RenderPass(); + const std::weak_ptr& GetContext() const; + const RenderTarget& GetRenderTarget() const; ISize GetRenderTargetSize() const; @@ -101,8 +103,6 @@ class RenderPass { RenderPass(std::weak_ptr context, const RenderTarget& target); - const std::weak_ptr& GetContext() const; - virtual void OnSetLabel(std::string label) = 0; virtual bool OnEncodeCommands(const Context& context) const = 0; diff --git a/impeller/renderer/renderer_dart_unittests.cc b/impeller/renderer/renderer_dart_unittests.cc index 89faca58540fe..7e413346cc9a0 100644 --- a/impeller/renderer/renderer_dart_unittests.cc +++ b/impeller/renderer/renderer_dart_unittests.cc @@ -8,23 +8,21 @@ #include "flutter/common/settings.h" #include "flutter/common/task_runners.h" -#include "flutter/fml/backtrace.h" -#include "flutter/fml/command_line.h" #include "flutter/lib/gpu/context.h" -#include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/lib/gpu/shader.h" +#include "flutter/lib/gpu/shader_library.h" #include "flutter/runtime/dart_isolate.h" #include "flutter/runtime/dart_vm_lifecycle.h" -#include "flutter/runtime/isolate_configuration.h" #include "flutter/testing/dart_fixture.h" #include "flutter/testing/dart_isolate_runner.h" -#include "flutter/testing/fixture_test.h" #include "flutter/testing/testing.h" -#include "impeller/fixtures/box_fade.frag.h" -#include "impeller/fixtures/box_fade.vert.h" +#include "fml/memory/ref_ptr.h" +#include "impeller/core/shader_types.h" +#include "impeller/fixtures/flutter_gpu_unlit.vert.h" #include "impeller/playground/playground_test.h" -#include "impeller/renderer/pipeline_library.h" #include "impeller/renderer/render_pass.h" -#include "impeller/renderer/sampler_library.h" +#include "impeller/renderer/vertex_descriptor.h" +#include "impeller/runtime_stage/runtime_stage.h" #include "gtest/gtest.h" #include "third_party/imgui/imgui.h" @@ -32,6 +30,40 @@ namespace impeller { namespace testing { +// This helper is for piggybacking on the RuntimeStage infrastructure for +// testing shaders/pipelines before the full shader bundle importer is finished. +static fml::RefPtr OpenRuntimeStageAsShader( + const std::string& fixture_name, + std::shared_ptr vertex_desc) { + auto fixture = flutter::testing::OpenFixtureAsMapping(fixture_name); + assert(fixture); + RuntimeStage stage(std::move(fixture)); + return flutter::gpu::Shader::Make( + stage.GetEntrypoint(), ToShaderStage(stage.GetShaderStage()), + stage.GetCodeMapping(), stage.GetUniforms(), std::move(vertex_desc)); +} + +static void InstantiateTestShaderLibrary() { + flutter::gpu::ShaderLibrary::ShaderMap shaders; + auto vertex_desc = std::make_shared(); + vertex_desc->SetStageInputs( + // TODO(bdero): The stage inputs need to be packed into the flatbuffer. + FlutterGpuUnlitVertexShader::kAllShaderStageInputs, + // TODO(bdero): Make the vertex attribute layout fully configurable. + // When encoding commands, allow for specifying a stride, + // type, and vertex buffer slot for each attribute. + // Provide a way to lookup vertex attribute slot locations by + // name from the shader. + FlutterGpuUnlitVertexShader::kInterleavedBufferLayout); + shaders["UnlitVertex"] = OpenRuntimeStageAsShader( + "flutter_gpu_unlit.vert.iplr", std::move(vertex_desc)); + shaders["UnlitFragment"] = + OpenRuntimeStageAsShader("flutter_gpu_unlit.frag.iplr", nullptr); + auto library = + flutter::gpu::ShaderLibrary::MakeFromShaders(std::move(shaders)); + flutter::gpu::ShaderLibrary::SetOverride(library); +} + class RendererDartTest : public PlaygroundTest, public flutter::testing::DartFixture { public: @@ -52,6 +84,8 @@ class RendererDartTest : public PlaygroundTest, assert(GetContext() != nullptr); flutter::gpu::Context::SetOverrideContext(GetContext()); + InstantiateTestShaderLibrary(); + return isolate_.get(); } @@ -140,5 +174,9 @@ DART_TEST_CASE(textureOverwriteThrowsForWrongBufferSize); DART_TEST_CASE(textureAsImageReturnsAValidUIImageHandle); DART_TEST_CASE(textureAsImageThrowsWhenNotShaderReadable); +DART_TEST_CASE(canCreateShaderLibrary); + +DART_TEST_CASE(canCreateRenderPassAndSubmit); + } // namespace testing } // namespace impeller diff --git a/impeller/runtime_stage/runtime_stage.cc b/impeller/runtime_stage/runtime_stage.cc index 919d374a3f053..786dc7a88fa24 100644 --- a/impeller/runtime_stage/runtime_stage.cc +++ b/impeller/runtime_stage/runtime_stage.cc @@ -96,11 +96,13 @@ RuntimeStage::RuntimeStage(std::shared_ptr payload) [payload = payload_](auto, auto) {} // ); - sksl_mapping_ = std::make_shared( - runtime_stage->sksl()->data(), // - runtime_stage->sksl()->size(), // - [payload = payload_](auto, auto) {} // - ); + if (runtime_stage->sksl()) { + sksl_mapping_ = std::make_shared( + runtime_stage->sksl()->data(), // + runtime_stage->sksl()->size(), // + [payload = payload_](auto, auto) {} // + ); + } is_valid_ = true; } diff --git a/impeller/tools/impeller.gni b/impeller/tools/impeller.gni index 69bd645da1dfd..4d48704493975 100644 --- a/impeller/tools/impeller.gni +++ b/impeller/tools/impeller.gni @@ -282,6 +282,7 @@ template("impellerc") { ]) # Optional: invoker.iplr Causes --sl output to be in iplr format. + # Optional: invoker.iplr_bundle specifies a Flutter GPU shader bundle configuration. # Optional: invoker.defines specifies a list of valueless macro definitions. # Optional: invoker.intermediates_subdir specifies the subdirectory in which # to put intermediates. @@ -375,6 +376,9 @@ template("impellerc") { if (iplr) { args += [ "--iplr" ] } + if (defined(invoker.iplr_bundle)) { + args += [ "--iplr-bundle=${invoker.iplr_bundle}" ] + } outputs = [ sl_intermediate, diff --git a/lib/gpu/BUILD.gn b/lib/gpu/BUILD.gn index d24d75738458e..b26dc419dc864 100644 --- a/lib/gpu/BUILD.gn +++ b/lib/gpu/BUILD.gn @@ -32,14 +32,28 @@ source_set("gpu") { if (!is_fuchsia) { sources = [ + "command_buffer.cc", + "command_buffer.h", "context.cc", "context.h", "device_buffer.cc", "device_buffer.h", "export.cc", "export.h", + "fixtures.cc", + "fixtures.h", + "formats.cc", + "formats.h", "host_buffer.cc", "host_buffer.h", + "render_pass.cc", + "render_pass.h", + "render_pipeline.cc", + "render_pipeline.h", + "shader.cc", + "shader.h", + "shader_library.cc", + "shader_library.h", "smoketest.cc", "smoketest.h", "texture.cc", diff --git a/lib/gpu/command_buffer.cc b/lib/gpu/command_buffer.cc new file mode 100644 index 0000000000000..f0dd7e0234092 --- /dev/null +++ b/lib/gpu/command_buffer.cc @@ -0,0 +1,114 @@ +// 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 "flutter/lib/gpu/command_buffer.h" + +#include "dart_api.h" +#include "fml/make_copyable.h" +#include "impeller/renderer/command_buffer.h" +#include "impeller/renderer/render_pass.h" +#include "lib/ui/ui_dart_state.h" +#include "tonic/converter/dart_converter.h" + +namespace flutter { +namespace gpu { + +IMPLEMENT_WRAPPERTYPEINFO(flutter_gpu, CommandBuffer); + +CommandBuffer::CommandBuffer( + std::shared_ptr command_buffer) + : command_buffer_(std::move(command_buffer)) {} + +CommandBuffer::~CommandBuffer() = default; + +std::shared_ptr CommandBuffer::GetCommandBuffer() { + return command_buffer_; +} + +void CommandBuffer::AddRenderPass( + std::shared_ptr render_pass) { + encodables_.push_back(std::move(render_pass)); +} + +bool CommandBuffer::Submit() { + for (auto& encodable : encodables_) { + encodable->EncodeCommands(); + } + return command_buffer_->SubmitCommands(); +} + +bool CommandBuffer::Submit( + const impeller::CommandBuffer::CompletionCallback& completion_callback) { + for (auto& encodable : encodables_) { + encodable->EncodeCommands(); + } + return command_buffer_->SubmitCommands(completion_callback); +} + +} // namespace gpu +} // namespace flutter + +//---------------------------------------------------------------------------- +/// Exports +/// + +bool InternalFlutterGpu_CommandBuffer_Initialize( + Dart_Handle wrapper, + flutter::gpu::Context* contextWrapper) { + auto res = fml::MakeRefCounted( + contextWrapper->GetContext()->CreateCommandBuffer()); + res->AssociateWithDartWrapper(wrapper); + + return true; +} + +Dart_Handle InternalFlutterGpu_CommandBuffer_Submit( + flutter::gpu::CommandBuffer* wrapper, + Dart_Handle completion_callback) { + if (Dart_IsNull(completion_callback)) { + bool success = wrapper->Submit(); + if (!success) { + return tonic::ToDart("Failed to submit CommandBuffer"); + } + return Dart_Null(); + } + + if (!Dart_IsClosure(completion_callback)) { + return tonic::ToDart("Completion callback must be a function"); + } + + auto dart_state = flutter::UIDartState::Current(); + auto& task_runners = dart_state->GetTaskRunners(); + + auto persistent_completion_callback = + std::make_unique(dart_state, + completion_callback); + + bool success = wrapper->Submit(fml::MakeCopyable( + [callback = std::move(persistent_completion_callback), + task_runners](impeller::CommandBuffer::Status status) mutable { + bool success = status != impeller::CommandBuffer::Status::kError; + + auto ui_completion_task = fml::MakeCopyable( + [callback = std::move(callback), success]() mutable { + auto dart_state = callback->dart_state().lock(); + if (!dart_state) { + // The root isolate could have died in the meantime. + return; + } + tonic::DartState::Scope scope(dart_state); + + tonic::DartInvoke(callback->Get(), {tonic::ToDart(success)}); + + // callback is associated with the Dart isolate and must be + // deleted on the UI thread. + callback.reset(); + }); + task_runners.GetUITaskRunner()->PostTask(ui_completion_task); + })); + if (!success) { + return tonic::ToDart("Failed to submit CommandBuffer"); + } + return Dart_Null(); +} diff --git a/lib/gpu/command_buffer.h b/lib/gpu/command_buffer.h new file mode 100644 index 0000000000000..505471045bdf0 --- /dev/null +++ b/lib/gpu/command_buffer.h @@ -0,0 +1,59 @@ +// 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 "flutter/lib/gpu/context.h" +#include "flutter/lib/gpu/export.h" +#include "flutter/lib/ui/dart_wrapper.h" +#include "impeller/renderer/command_buffer.h" + +namespace flutter { +namespace gpu { + +class CommandBuffer : public RefCountedDartWrappable { + DEFINE_WRAPPERTYPEINFO(); + FML_FRIEND_MAKE_REF_COUNTED(CommandBuffer); + + public: + explicit CommandBuffer( + std::shared_ptr command_buffer); + + std::shared_ptr GetCommandBuffer(); + + void AddRenderPass(std::shared_ptr render_pass); + + bool Submit(); + bool Submit( + const impeller::CommandBuffer::CompletionCallback& completion_callback); + + ~CommandBuffer() override; + + private: + std::shared_ptr command_buffer_; + std::vector> encodables_; + + FML_DISALLOW_COPY_AND_ASSIGN(CommandBuffer); +}; + +} // namespace gpu +} // namespace flutter + +//---------------------------------------------------------------------------- +/// Exports +/// + +extern "C" { + +FLUTTER_GPU_EXPORT +extern bool InternalFlutterGpu_CommandBuffer_Initialize( + Dart_Handle wrapper, + flutter::gpu::Context* contextWrapper); + +FLUTTER_GPU_EXPORT +extern Dart_Handle InternalFlutterGpu_CommandBuffer_Submit( + flutter::gpu::CommandBuffer* wrapper, + Dart_Handle completion_callback); + +} // extern "C" diff --git a/lib/gpu/context.cc b/lib/gpu/context.cc index 25f663a9a4a10..03536ef352d56 100644 --- a/lib/gpu/context.cc +++ b/lib/gpu/context.cc @@ -6,7 +6,7 @@ #include -#include "dart_api.h" +#include "flutter/lib/gpu/formats.h" #include "flutter/lib/ui/ui_dart_state.h" #include "fml/make_copyable.h" #include "tonic/converter/dart_converter.h" @@ -14,7 +14,7 @@ namespace flutter { namespace gpu { -IMPLEMENT_WRAPPERTYPEINFO(gpu, Context); +IMPLEMENT_WRAPPERTYPEINFO(flutter_gpu, Context); std::shared_ptr Context::default_context_; @@ -76,21 +76,22 @@ Dart_Handle InternalFlutterGpu_Context_InitializeDefault(Dart_Handle wrapper) { return Dart_Null(); } -/// extern int InternalFlutterGpu_Context_GetDefaultColorFormat( flutter::gpu::Context* wrapper) { - return static_cast( - wrapper->GetContext()->GetCapabilities()->GetDefaultColorFormat()); + return static_cast(flutter::gpu::FromImpellerPixelFormat( + wrapper->GetContext()->GetCapabilities()->GetDefaultColorFormat())); } extern int InternalFlutterGpu_Context_GetDefaultStencilFormat( flutter::gpu::Context* wrapper) { - return static_cast( - wrapper->GetContext()->GetCapabilities()->GetDefaultStencilFormat()); + return static_cast(flutter::gpu::FromImpellerPixelFormat( + wrapper->GetContext()->GetCapabilities()->GetDefaultStencilFormat())); } extern int InternalFlutterGpu_Context_GetDefaultDepthStencilFormat( flutter::gpu::Context* wrapper) { - return static_cast( - wrapper->GetContext()->GetCapabilities()->GetDefaultDepthStencilFormat()); + return static_cast(flutter::gpu::FromImpellerPixelFormat( + wrapper->GetContext() + ->GetCapabilities() + ->GetDefaultDepthStencilFormat())); } diff --git a/lib/gpu/device_buffer.cc b/lib/gpu/device_buffer.cc index cbe07afb6b6d8..f783f9b8ada74 100644 --- a/lib/gpu/device_buffer.cc +++ b/lib/gpu/device_buffer.cc @@ -5,6 +5,7 @@ #include "flutter/lib/gpu/device_buffer.h" #include "dart_api.h" +#include "flutter/lib/gpu/formats.h" #include "fml/mapping.h" #include "impeller/core/device_buffer.h" #include "impeller/core/device_buffer_descriptor.h" @@ -17,7 +18,7 @@ namespace flutter { namespace gpu { -IMPLEMENT_WRAPPERTYPEINFO(gpu, DeviceBuffer); +IMPLEMENT_WRAPPERTYPEINFO(flutter_gpu, DeviceBuffer); DeviceBuffer::DeviceBuffer( std::shared_ptr device_buffer) @@ -25,6 +26,10 @@ DeviceBuffer::DeviceBuffer( DeviceBuffer::~DeviceBuffer() = default; +std::shared_ptr DeviceBuffer::GetBuffer() { + return device_buffer_; +} + bool DeviceBuffer::Overwrite(const tonic::DartByteData& source_bytes, size_t destination_offset_in_bytes) { if (!device_buffer_->CopyHostBuffer( @@ -49,7 +54,8 @@ bool InternalFlutterGpu_DeviceBuffer_Initialize( int storage_mode, int size_in_bytes) { impeller::DeviceBufferDescriptor desc; - desc.storage_mode = static_cast(storage_mode); + desc.storage_mode = flutter::gpu::ToImpellerStorageMode( + static_cast(storage_mode)); desc.size = size_in_bytes; auto device_buffer = gpu_context->GetContext()->GetResourceAllocator()->CreateBuffer(desc); diff --git a/lib/gpu/device_buffer.h b/lib/gpu/device_buffer.h index df2f73ed82646..44f7ac0c11bef 100644 --- a/lib/gpu/device_buffer.h +++ b/lib/gpu/device_buffer.h @@ -22,6 +22,8 @@ class DeviceBuffer : public RefCountedDartWrappable { ~DeviceBuffer() override; + std::shared_ptr GetBuffer(); + bool Overwrite(const tonic::DartByteData& source_bytes, size_t destination_offset_in_bytes); diff --git a/lib/gpu/fixtures.cc b/lib/gpu/fixtures.cc new file mode 100644 index 0000000000000..c85020b3b7bd3 --- /dev/null +++ b/lib/gpu/fixtures.cc @@ -0,0 +1,132 @@ +// 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 "flutter/lib/gpu/fixtures.h" + +// These blobs are generated using xxd -i [myfile.iplr]. +// This is a temporary hack to provision the shader library before the importer +// is done. + +unsigned char kFlutterGPUUnlitVertIPLR[] = { + 0x18, 0x00, 0x00, 0x00, 0x49, 0x50, 0x4c, 0x52, 0x00, 0x00, 0x0e, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x18, 0x03, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x72, 0x02, 0x00, 0x00, 0x23, 0x69, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x5f, + 0x73, 0x74, 0x64, 0x6c, 0x69, 0x62, 0x3e, 0x0a, 0x23, 0x69, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x73, 0x69, 0x6d, 0x64, 0x2f, 0x73, + 0x69, 0x6d, 0x64, 0x2e, 0x68, 0x3e, 0x0a, 0x0a, 0x75, 0x73, 0x69, 0x6e, + 0x67, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, + 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, + 0x63, 0x74, 0x20, 0x66, 0x6c, 0x75, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x67, + 0x70, 0x75, 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x74, 0x5f, 0x76, 0x65, 0x72, + 0x74, 0x65, 0x78, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x75, 0x74, + 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, + 0x34, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x5b, 0x5b, + 0x75, 0x73, 0x65, 0x72, 0x28, 0x6c, 0x6f, 0x63, 0x6e, 0x30, 0x29, 0x5d, + 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, + 0x34, 0x20, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x5b, 0x5b, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x5d, 0x5d, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, + 0x63, 0x74, 0x20, 0x66, 0x6c, 0x75, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x67, + 0x70, 0x75, 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x74, 0x5f, 0x76, 0x65, 0x72, + 0x74, 0x65, 0x78, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x6e, 0x0a, + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, + 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5b, 0x5b, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x30, 0x29, + 0x5d, 0x5d, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x76, 0x65, 0x72, 0x74, + 0x65, 0x78, 0x20, 0x66, 0x6c, 0x75, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x67, + 0x70, 0x75, 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x74, 0x5f, 0x76, 0x65, 0x72, + 0x74, 0x65, 0x78, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x75, 0x74, + 0x20, 0x66, 0x6c, 0x75, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x67, 0x70, 0x75, + 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x74, 0x65, + 0x78, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x66, 0x6c, 0x75, 0x74, 0x74, + 0x65, 0x72, 0x5f, 0x67, 0x70, 0x75, 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x74, + 0x5f, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5f, 0x6d, 0x61, 0x69, 0x6e, + 0x5f, 0x69, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x5b, 0x73, 0x74, 0x61, + 0x67, 0x65, 0x5f, 0x69, 0x6e, 0x5d, 0x5d, 0x2c, 0x20, 0x63, 0x6f, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, + 0x26, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x5b, 0x5b, 0x62, 0x75, + 0x66, 0x66, 0x65, 0x72, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x2c, 0x20, 0x63, + 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6c, 0x6f, 0x61, + 0x74, 0x34, 0x78, 0x34, 0x26, 0x20, 0x6d, 0x76, 0x70, 0x20, 0x5b, 0x5b, + 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x28, 0x31, 0x29, 0x5d, 0x5d, 0x29, + 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x75, 0x74, 0x74, + 0x65, 0x72, 0x5f, 0x67, 0x70, 0x75, 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x74, + 0x5f, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5f, 0x6d, 0x61, 0x69, 0x6e, + 0x5f, 0x6f, 0x75, 0x74, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x7b, + 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x76, + 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x63, 0x6f, 0x6c, + 0x6f, 0x72, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, + 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x3d, 0x20, 0x6d, 0x76, 0x70, 0x20, 0x2a, 0x20, 0x66, 0x6c, 0x6f, 0x61, + 0x74, 0x34, 0x28, 0x69, 0x6e, 0x2e, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x2c, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x14, 0x00, + 0x1c, 0x00, 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x28, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, + 0x14, 0x00, 0x1c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x6d, 0x76, 0x70, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x66, 0x6c, 0x75, 0x74, + 0x74, 0x65, 0x72, 0x5f, 0x67, 0x70, 0x75, 0x5f, 0x75, 0x6e, 0x6c, 0x69, + 0x74, 0x5f, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5f, 0x6d, 0x61, 0x69, + 0x6e, 0x00, 0x00, 0x00}; + +unsigned char kFlutterGPUUnlitFragIPLR[] = { + 0x18, 0x00, 0x00, 0x00, 0x49, 0x50, 0x4c, 0x52, 0x00, 0x00, 0x0e, 0x00, + 0x10, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe8, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xda, 0x01, 0x00, 0x00, 0x23, 0x69, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x5f, + 0x73, 0x74, 0x64, 0x6c, 0x69, 0x62, 0x3e, 0x0a, 0x23, 0x69, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x73, 0x69, 0x6d, 0x64, 0x2f, 0x73, + 0x69, 0x6d, 0x64, 0x2e, 0x68, 0x3e, 0x0a, 0x0a, 0x75, 0x73, 0x69, 0x6e, + 0x67, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, + 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, + 0x63, 0x74, 0x20, 0x66, 0x6c, 0x75, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x67, + 0x70, 0x75, 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x74, 0x5f, 0x66, 0x72, 0x61, + 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, + 0x75, 0x74, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, + 0x61, 0x74, 0x34, 0x20, 0x66, 0x72, 0x61, 0x67, 0x5f, 0x63, 0x6f, 0x6c, + 0x6f, 0x72, 0x20, 0x5b, 0x5b, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x30, + 0x29, 0x5d, 0x5d, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, + 0x75, 0x63, 0x74, 0x20, 0x66, 0x6c, 0x75, 0x74, 0x74, 0x65, 0x72, 0x5f, + 0x67, 0x70, 0x75, 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x74, 0x5f, 0x66, 0x72, + 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, + 0x69, 0x6e, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, + 0x61, 0x74, 0x34, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, + 0x5b, 0x5b, 0x75, 0x73, 0x65, 0x72, 0x28, 0x6c, 0x6f, 0x63, 0x6e, 0x30, + 0x29, 0x5d, 0x5d, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x66, 0x72, 0x61, + 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6c, 0x75, 0x74, 0x74, 0x65, + 0x72, 0x5f, 0x67, 0x70, 0x75, 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x74, 0x5f, + 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x69, + 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x20, 0x66, 0x6c, 0x75, 0x74, 0x74, 0x65, + 0x72, 0x5f, 0x67, 0x70, 0x75, 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x74, 0x5f, + 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x69, + 0x6e, 0x28, 0x66, 0x6c, 0x75, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x67, 0x70, + 0x75, 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x74, 0x5f, 0x66, 0x72, 0x61, 0x67, + 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x6e, + 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x5b, 0x73, 0x74, 0x61, 0x67, 0x65, 0x5f, + 0x69, 0x6e, 0x5d, 0x5d, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x66, 0x6c, 0x75, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x67, 0x70, 0x75, 0x5f, + 0x75, 0x6e, 0x6c, 0x69, 0x74, 0x5f, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, + 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x20, + 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x66, 0x72, 0x61, 0x67, 0x5f, 0x63, + 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x2e, 0x76, 0x5f, + 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x3b, 0x0a, 0x7d, + 0x0a, 0x0a, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x66, 0x6c, 0x75, 0x74, + 0x74, 0x65, 0x72, 0x5f, 0x67, 0x70, 0x75, 0x5f, 0x75, 0x6e, 0x6c, 0x69, + 0x74, 0x5f, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6d, + 0x61, 0x69, 0x6e, 0x00}; diff --git a/lib/gpu/fixtures.h b/lib/gpu/fixtures.h new file mode 100644 index 0000000000000..13926f2c9b928 --- /dev/null +++ b/lib/gpu/fixtures.h @@ -0,0 +1,42 @@ +// 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/core/shader_types.h" + +struct FlutterGPUUnlitVertexShader { + struct PerVertexData { + impeller::Point position; // (offset 0, size 8) + }; // struct PerVertexData (size 8) + + static constexpr auto kInputPosition = impeller::ShaderStageIOSlot{ + // position + "position", // name + 0u, // attribute location + 0u, // attribute set + 0u, // attribute binding + impeller::ShaderType::kFloat, // type + 32u, // bit width of type + 2u, // vec size + 1u, // number of columns + 0u, // offset for interleaved layout + }; + + static constexpr std::array + kAllShaderStageInputs = { + &kInputPosition, // position + }; + + static constexpr auto kInterleavedLayout = impeller::ShaderStageBufferLayout{ + sizeof(PerVertexData), // stride for interleaved layout + 0u, // attribute binding + }; + static constexpr std::array + kInterleavedBufferLayout = {&kInterleavedLayout}; +}; + +constexpr unsigned int kFlutterGPUUnlitVertIPLRLength = 856; +extern unsigned char kFlutterGPUUnlitVertIPLR[]; + +constexpr unsigned int kFlutterGPUUnlitFragIPLRLength = 556; +extern unsigned char kFlutterGPUUnlitFragIPLR[]; diff --git a/lib/gpu/formats.cc b/lib/gpu/formats.cc new file mode 100644 index 0000000000000..07f1f6b17fbd5 --- /dev/null +++ b/lib/gpu/formats.cc @@ -0,0 +1,13 @@ +// 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 "flutter/lib/gpu/formats.h" + +namespace flutter { +namespace gpu { + +// + +} // namespace gpu +} // namespace flutter diff --git a/lib/gpu/formats.h b/lib/gpu/formats.h new file mode 100644 index 0000000000000..86b2cf44ad395 --- /dev/null +++ b/lib/gpu/formats.h @@ -0,0 +1,288 @@ +// 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 "fml/logging.h" +#include "impeller/core/formats.h" +#include "impeller/core/shader_types.h" + +// ATTENTION! ATTENTION! ATTENTION! +// All enums defined in this file must exactly match the contents and order of +// the corresponding enums defined in `gpu/lib/src/formats.dart`. + +namespace flutter { +namespace gpu { + +enum class FlutterGPUStorageMode { + kHostVisible, + kDevicePrivate, + kDeviceTransient, +}; + +constexpr impeller::StorageMode ToImpellerStorageMode( + FlutterGPUStorageMode value) { + switch (value) { + case FlutterGPUStorageMode::kHostVisible: + return impeller::StorageMode::kHostVisible; + case FlutterGPUStorageMode::kDevicePrivate: + return impeller::StorageMode::kDevicePrivate; + case FlutterGPUStorageMode::kDeviceTransient: + return impeller::StorageMode::kDeviceTransient; + } +} + +enum class FlutterGPUPixelFormat { + kUnknown, + kA8UNormInt, + kR8UNormInt, + kR8G8UNormInt, + kR8G8B8A8UNormInt, + kR8G8B8A8UNormIntSRGB, + kB8G8R8A8UNormInt, + kB8G8R8A8UNormIntSRGB, + kR32G32B32A32Float, + kR16G16B16A16Float, + kB10G10R10XR, + kB10G10R10XRSRGB, + kB10G10R10A10XR, + kS8UInt, + kD24UnormS8Uint, + kD32FloatS8UInt, +}; + +constexpr impeller::PixelFormat ToImpellerPixelFormat( + FlutterGPUPixelFormat value) { + switch (value) { + case FlutterGPUPixelFormat::kUnknown: + return impeller::PixelFormat::kUnknown; + case FlutterGPUPixelFormat::kA8UNormInt: + return impeller::PixelFormat::kA8UNormInt; + case FlutterGPUPixelFormat::kR8UNormInt: + return impeller::PixelFormat::kR8UNormInt; + case FlutterGPUPixelFormat::kR8G8UNormInt: + return impeller::PixelFormat::kR8G8UNormInt; + case FlutterGPUPixelFormat::kR8G8B8A8UNormInt: + return impeller::PixelFormat::kR8G8B8A8UNormInt; + case FlutterGPUPixelFormat::kR8G8B8A8UNormIntSRGB: + return impeller::PixelFormat::kR8G8B8A8UNormIntSRGB; + case FlutterGPUPixelFormat::kB8G8R8A8UNormInt: + return impeller::PixelFormat::kB8G8R8A8UNormInt; + case FlutterGPUPixelFormat::kB8G8R8A8UNormIntSRGB: + return impeller::PixelFormat::kB8G8R8A8UNormIntSRGB; + case FlutterGPUPixelFormat::kR32G32B32A32Float: + return impeller::PixelFormat::kR32G32B32A32Float; + case FlutterGPUPixelFormat::kR16G16B16A16Float: + return impeller::PixelFormat::kR16G16B16A16Float; + case FlutterGPUPixelFormat::kB10G10R10XR: + return impeller::PixelFormat::kB10G10R10XR; + case FlutterGPUPixelFormat::kB10G10R10XRSRGB: + return impeller::PixelFormat::kB10G10R10XRSRGB; + case FlutterGPUPixelFormat::kB10G10R10A10XR: + return impeller::PixelFormat::kB10G10R10A10XR; + case FlutterGPUPixelFormat::kS8UInt: + return impeller::PixelFormat::kS8UInt; + case FlutterGPUPixelFormat::kD24UnormS8Uint: + return impeller::PixelFormat::kD24UnormS8Uint; + case FlutterGPUPixelFormat::kD32FloatS8UInt: + return impeller::PixelFormat::kD32FloatS8UInt; + } +} + +constexpr FlutterGPUPixelFormat FromImpellerPixelFormat( + impeller::PixelFormat value) { + switch (value) { + case impeller::PixelFormat::kUnknown: + return FlutterGPUPixelFormat::kUnknown; + case impeller::PixelFormat::kA8UNormInt: + return FlutterGPUPixelFormat::kA8UNormInt; + case impeller::PixelFormat::kR8UNormInt: + return FlutterGPUPixelFormat::kR8UNormInt; + case impeller::PixelFormat::kR8G8UNormInt: + return FlutterGPUPixelFormat::kR8G8UNormInt; + case impeller::PixelFormat::kR8G8B8A8UNormInt: + return FlutterGPUPixelFormat::kR8G8B8A8UNormInt; + case impeller::PixelFormat::kR8G8B8A8UNormIntSRGB: + return FlutterGPUPixelFormat::kR8G8B8A8UNormIntSRGB; + case impeller::PixelFormat::kB8G8R8A8UNormInt: + return FlutterGPUPixelFormat::kB8G8R8A8UNormInt; + case impeller::PixelFormat::kB8G8R8A8UNormIntSRGB: + return FlutterGPUPixelFormat::kB8G8R8A8UNormIntSRGB; + case impeller::PixelFormat::kR32G32B32A32Float: + return FlutterGPUPixelFormat::kR32G32B32A32Float; + case impeller::PixelFormat::kR16G16B16A16Float: + return FlutterGPUPixelFormat::kR16G16B16A16Float; + case impeller::PixelFormat::kB10G10R10XR: + return FlutterGPUPixelFormat::kB10G10R10XR; + case impeller::PixelFormat::kB10G10R10XRSRGB: + return FlutterGPUPixelFormat::kB10G10R10XRSRGB; + case impeller::PixelFormat::kB10G10R10A10XR: + return FlutterGPUPixelFormat::kB10G10R10A10XR; + case impeller::PixelFormat::kS8UInt: + return FlutterGPUPixelFormat::kS8UInt; + case impeller::PixelFormat::kD24UnormS8Uint: + return FlutterGPUPixelFormat::kD24UnormS8Uint; + case impeller::PixelFormat::kD32FloatS8UInt: + return FlutterGPUPixelFormat::kD32FloatS8UInt; + } +} + +enum class FlutterGPUTextureCoordinateSystem { + kUploadFromHost, + kRenderToTexture, +}; + +constexpr impeller::TextureCoordinateSystem ToImpellerTextureCoordinateSystem( + FlutterGPUTextureCoordinateSystem value) { + switch (value) { + case FlutterGPUTextureCoordinateSystem::kUploadFromHost: + return impeller::TextureCoordinateSystem::kUploadFromHost; + case FlutterGPUTextureCoordinateSystem::kRenderToTexture: + return impeller::TextureCoordinateSystem::kRenderToTexture; + } +} + +enum class FlutterGPUBlendFactor { + kZero, + kOne, + kSourceColor, + kOneMinusSourceColor, + kSourceAlpha, + kOneMinusSourceAlpha, + kDestinationColor, + kOneMinusDestinationColor, + kDestinationAlpha, + kOneMinusDestinationAlpha, + kSourceAlphaSaturated, + kBlendColor, + kOneMinusBlendColor, + kBlendAlpha, + kOneMinusBlendAlpha, +}; + +constexpr impeller::BlendFactor ToImpellerBlendFactor( + FlutterGPUBlendFactor value) { + switch (value) { + case FlutterGPUBlendFactor::kZero: + return impeller::BlendFactor::kZero; + case FlutterGPUBlendFactor::kOne: + return impeller::BlendFactor::kOne; + case FlutterGPUBlendFactor::kSourceColor: + return impeller::BlendFactor::kSourceColor; + case FlutterGPUBlendFactor::kOneMinusSourceColor: + return impeller::BlendFactor::kOneMinusSourceColor; + case FlutterGPUBlendFactor::kSourceAlpha: + return impeller::BlendFactor::kSourceAlpha; + case FlutterGPUBlendFactor::kOneMinusSourceAlpha: + return impeller::BlendFactor::kOneMinusSourceAlpha; + case FlutterGPUBlendFactor::kDestinationColor: + return impeller::BlendFactor::kDestinationColor; + case FlutterGPUBlendFactor::kOneMinusDestinationColor: + return impeller::BlendFactor::kOneMinusDestinationColor; + case FlutterGPUBlendFactor::kDestinationAlpha: + return impeller::BlendFactor::kDestinationAlpha; + case FlutterGPUBlendFactor::kOneMinusDestinationAlpha: + return impeller::BlendFactor::kOneMinusDestinationAlpha; + case FlutterGPUBlendFactor::kSourceAlphaSaturated: + return impeller::BlendFactor::kSourceAlphaSaturated; + case FlutterGPUBlendFactor::kBlendColor: + return impeller::BlendFactor::kBlendColor; + case FlutterGPUBlendFactor::kOneMinusBlendColor: + return impeller::BlendFactor::kOneMinusBlendColor; + case FlutterGPUBlendFactor::kBlendAlpha: + return impeller::BlendFactor::kBlendAlpha; + case FlutterGPUBlendFactor::kOneMinusBlendAlpha: + return impeller::BlendFactor::kOneMinusBlendAlpha; + } +} + +enum class FlutterGPUBlendOperation { + kAdd, + kSubtract, + kReverseSubtract, +}; + +constexpr impeller::BlendOperation ToImpellerBlendOperation( + FlutterGPUBlendOperation value) { + switch (value) { + case FlutterGPUBlendOperation::kAdd: + return impeller::BlendOperation::kAdd; + case FlutterGPUBlendOperation::kSubtract: + return impeller::BlendOperation::kSubtract; + case FlutterGPUBlendOperation::kReverseSubtract: + return impeller::BlendOperation::kReverseSubtract; + } +} + +enum class FlutterGPULoadAction { + kDontCare, + kLoad, + kClear, +}; + +constexpr impeller::LoadAction ToImpellerLoadAction( + FlutterGPULoadAction value) { + switch (value) { + case FlutterGPULoadAction::kDontCare: + return impeller::LoadAction::kDontCare; + case FlutterGPULoadAction::kLoad: + return impeller::LoadAction::kLoad; + case FlutterGPULoadAction::kClear: + return impeller::LoadAction::kClear; + } +} + +enum class FlutterGPUStoreAction { + kDontCare, + kStore, + kMultisampleResolve, + kStoreAndMultisampleResolve, +}; + +constexpr impeller::StoreAction ToImpellerStoreAction( + FlutterGPUStoreAction value) { + switch (value) { + case FlutterGPUStoreAction::kDontCare: + return impeller::StoreAction::kDontCare; + case FlutterGPUStoreAction::kStore: + return impeller::StoreAction::kStore; + case FlutterGPUStoreAction::kMultisampleResolve: + return impeller::StoreAction::kMultisampleResolve; + case FlutterGPUStoreAction::kStoreAndMultisampleResolve: + return impeller::StoreAction::kStoreAndMultisampleResolve; + } +} + +enum class FlutterGPUShaderStage { + kVertex, + kFragment, +}; + +constexpr impeller::ShaderStage ToImpellerShaderStage( + FlutterGPUShaderStage value) { + switch (value) { + case FlutterGPUShaderStage::kVertex: + return impeller::ShaderStage::kVertex; + case FlutterGPUShaderStage::kFragment: + return impeller::ShaderStage::kFragment; + } +} + +constexpr FlutterGPUShaderStage FromImpellerShaderStage( + impeller::ShaderStage value) { + switch (value) { + case impeller::ShaderStage::kVertex: + return FlutterGPUShaderStage::kVertex; + case impeller::ShaderStage::kFragment: + return FlutterGPUShaderStage::kFragment; + case impeller::ShaderStage::kUnknown: + case impeller::ShaderStage::kTessellationControl: + case impeller::ShaderStage::kTessellationEvaluation: + case impeller::ShaderStage::kCompute: + FML_LOG(ERROR) << "Invalid Flutter GPU ShaderStage " + << static_cast(value); + FML_UNREACHABLE(); + } +} + +} // namespace gpu +} // namespace flutter diff --git a/lib/gpu/host_buffer.cc b/lib/gpu/host_buffer.cc index ad79d7aebe717..b7edccf5318d6 100644 --- a/lib/gpu/host_buffer.cc +++ b/lib/gpu/host_buffer.cc @@ -11,12 +11,16 @@ namespace flutter { namespace gpu { -IMPLEMENT_WRAPPERTYPEINFO(gpu, HostBuffer); +IMPLEMENT_WRAPPERTYPEINFO(flutter_gpu, HostBuffer); HostBuffer::HostBuffer() : host_buffer_(impeller::HostBuffer::Create()) {} HostBuffer::~HostBuffer() = default; +std::shared_ptr HostBuffer::GetBuffer() { + return host_buffer_; +} + size_t HostBuffer::EmplaceBytes(const tonic::DartByteData& byte_data) { auto view = host_buffer_->Emplace(byte_data.data(), byte_data.length_in_bytes(), diff --git a/lib/gpu/host_buffer.h b/lib/gpu/host_buffer.h index 0662c1f9fab9d..b386bc962c23b 100644 --- a/lib/gpu/host_buffer.h +++ b/lib/gpu/host_buffer.h @@ -21,6 +21,8 @@ class HostBuffer : public RefCountedDartWrappable { ~HostBuffer() override; + std::shared_ptr GetBuffer(); + size_t EmplaceBytes(const tonic::DartByteData& byte_data); private: diff --git a/lib/gpu/lib/gpu.dart b/lib/gpu/lib/gpu.dart index 0215900cb2b5c..8603811c3fd8b 100644 --- a/lib/gpu/lib/gpu.dart +++ b/lib/gpu/lib/gpu.dart @@ -19,7 +19,12 @@ import 'dart:ui' as ui; export 'src/smoketest.dart'; -part 'src/formats.dart'; -part 'src/context.dart'; part 'src/buffer.dart'; +part 'src/command_buffer.dart'; +part 'src/context.dart'; +part 'src/formats.dart'; part 'src/texture.dart'; +part 'src/render_pass.dart'; +part 'src/render_pipeline.dart'; +part 'src/shader.dart'; +part 'src/shader_library.dart'; diff --git a/lib/gpu/lib/src/buffer.dart b/lib/gpu/lib/src/buffer.dart index 9794e5612b79d..c2b08220f050c 100644 --- a/lib/gpu/lib/src/buffer.dart +++ b/lib/gpu/lib/src/buffer.dart @@ -24,7 +24,13 @@ class BufferView { } /// A buffer that can be referenced by commands on the GPU. -mixin Buffer {} +mixin Buffer { + void _bindAsVertexBuffer(RenderPass renderPass, int offsetInBytes, + int lengthInBytes, int vertexCount); + + bool _bindAsUniform(RenderPass renderPass, UniformSlot slot, + int offsetInBytes, int lengthInBytes); +} /// [DeviceBuffer] is a region of memory allocated on the device heap /// (GPU-resident memory). @@ -52,6 +58,20 @@ base class DeviceBuffer extends NativeFieldWrapperClass1 with Buffer { final StorageMode storageMode; final int sizeInBytes; + @override + void _bindAsVertexBuffer(RenderPass renderPass, int offsetInBytes, + int lengthInBytes, int vertexCount) { + renderPass._bindVertexBufferDevice( + this, offsetInBytes, lengthInBytes, vertexCount); + } + + @override + bool _bindAsUniform(RenderPass renderPass, UniformSlot slot, + int offsetInBytes, int lengthInBytes) { + return renderPass._bindUniformDevice(slot.shaderStage.index, slot.slotId, + this, offsetInBytes, lengthInBytes); + } + /// Wrap with native counterpart. @Native, Int, Int)>( symbol: 'InternalFlutterGpu_DeviceBuffer_Initialize') @@ -109,6 +129,20 @@ base class HostBuffer extends NativeFieldWrapperClass1 with Buffer { _initialize(); } + @override + void _bindAsVertexBuffer(RenderPass renderPass, int offsetInBytes, + int lengthInBytes, int vertexCount) { + renderPass._bindVertexBufferHost( + this, offsetInBytes, lengthInBytes, vertexCount); + } + + @override + bool _bindAsUniform(RenderPass renderPass, UniformSlot slot, + int offsetInBytes, int lengthInBytes) { + return renderPass._bindUniformHost(slot.shaderStage.index, slot.slotId, + this, offsetInBytes, lengthInBytes); + } + /// Wrap with native counterpart. @Native( symbol: 'InternalFlutterGpu_HostBuffer_Initialize') diff --git a/lib/gpu/lib/src/command_buffer.dart b/lib/gpu/lib/src/command_buffer.dart new file mode 100644 index 0000000000000..06ff0d985bea6 --- /dev/null +++ b/lib/gpu/lib/src/command_buffer.dart @@ -0,0 +1,38 @@ +// 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. + +// ignore_for_file: public_member_api_docs + +part of flutter_gpu; + +typedef CompletionCallback = void Function(bool success); + +base class CommandBuffer extends NativeFieldWrapperClass1 { + /// Creates a new CommandBuffer. + CommandBuffer._(GpuContext gpuContext) { + _initialize(gpuContext); + } + + RenderPass createRenderPass( + {required ColorAttachment colorAttachment, + StencilAttachment? stencilAttachment = null}) { + return RenderPass._(this, colorAttachment, stencilAttachment); + } + + void submit({CompletionCallback? completionCallback}) { + String? error = _submit(completionCallback); + if (error != null) { + throw Exception(error); + } + } + + /// Wrap with native counterpart. + @Native)>( + symbol: 'InternalFlutterGpu_CommandBuffer_Initialize') + external bool _initialize(GpuContext gpuContext); + + @Native, Handle)>( + symbol: 'InternalFlutterGpu_CommandBuffer_Submit') + external String? _submit(CompletionCallback? completionCallback); +} diff --git a/lib/gpu/lib/src/context.dart b/lib/gpu/lib/src/context.dart index 3963211a4ebc5..0905acac5a02c 100644 --- a/lib/gpu/lib/src/context.dart +++ b/lib/gpu/lib/src/context.dart @@ -94,6 +94,16 @@ base class GpuContext extends NativeFieldWrapperClass1 { return result.isValid ? result : null; } + /// Create a new command buffer that can be used to submit GPU commands. + CommandBuffer createCommandBuffer() { + return CommandBuffer._(this); + } + + RenderPipeline createRenderPipeline( + Shader vertexShader, Shader fragmentShader) { + return RenderPipeline._(this, vertexShader, fragmentShader); + } + /// Associates the default Impeller context with this Context. @Native( symbol: 'InternalFlutterGpu_Context_InitializeDefault') diff --git a/lib/gpu/lib/src/formats.dart b/lib/gpu/lib/src/formats.dart index 50256ecdc0bd5..3252dd31e0db3 100644 --- a/lib/gpu/lib/src/formats.dart +++ b/lib/gpu/lib/src/formats.dart @@ -6,6 +6,10 @@ part of flutter_gpu; +// ATTENTION! ATTENTION! ATTENTION! +// All enum classes defined in this file must exactly match the contents and +// order of the corresponding enums defined in `gpu/formats.h`. + /// Specifies where an allocation resides and how it may be used. enum StorageMode { /// Allocations can be mapped onto the hosts address space and also be used by @@ -59,3 +63,45 @@ enum TextureCoordinateSystem { /// (0, 0) is the top-left of the image with +Y going down. renderToTexture, } + +enum BlendFactor { + zero, + one, + sourceColor, + oneMinusSourceColor, + sourceAlpha, + oneMinusSourceAlpha, + destinationColor, + oneMinusDestinationColor, + destinationAlpha, + oneMinusDestinationAlpha, + sourceAlphaSaturated, + blendColor, + oneMinusBlendColor, + blendAlpha, + oneMinusBlendAlpha, +} + +enum BlendOperation { + add, + subtract, + reverseSubtract, +} + +enum LoadAction { + dontCare, + load, + clear, +} + +enum StoreAction { + dontCare, + store, + multisampleResolve, + storeAndMultisampleResolve, +} + +enum ShaderStage { + vertex, + fragment, +} diff --git a/lib/gpu/lib/src/render_pass.dart b/lib/gpu/lib/src/render_pass.dart new file mode 100644 index 0000000000000..e8f1ef4157d77 --- /dev/null +++ b/lib/gpu/lib/src/render_pass.dart @@ -0,0 +1,141 @@ +// 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. + +// ignore_for_file: public_member_api_docs + +part of flutter_gpu; + +base class ColorAttachment { + ColorAttachment( + {this.loadAction = LoadAction.clear, + this.storeAction = StoreAction.store, + this.clearColor = const ui.Color(0x00000000), + required this.texture, + this.resolveTexture = null}); + + LoadAction loadAction; + StoreAction storeAction; + ui.Color clearColor; + Texture texture; + Texture? resolveTexture; +} + +base class StencilAttachment { + StencilAttachment( + {this.loadAction = LoadAction.clear, + this.storeAction = StoreAction.dontCare, + this.clearStencil = 0, + required this.texture}); + + LoadAction loadAction; + StoreAction storeAction; + int clearStencil; + Texture texture; +} + +/// A descriptor for RenderPass creation. Defines the output targets for raster +/// pipelines. +base class RenderTarget {} + +base class RenderPass extends NativeFieldWrapperClass1 { + /// Creates a new RenderPass. + RenderPass._(CommandBuffer commandBuffer, ColorAttachment colorAttachment, + StencilAttachment? stencilAttachment) { + _initialize(); + String? error; + error = _setColorAttachment( + colorAttachment.loadAction.index, + colorAttachment.storeAction.index, + colorAttachment.clearColor.value, + colorAttachment.texture, + colorAttachment.resolveTexture); + if (error != null) { + throw Exception(error); + } + if (stencilAttachment != null) { + error = _setStencilAttachment( + stencilAttachment.loadAction.index, + stencilAttachment.storeAction.index, + stencilAttachment.clearStencil, + stencilAttachment.texture); + if (error != null) { + throw Exception(error); + } + } + error = _begin(commandBuffer); + if (error != null) { + throw Exception(error); + } + } + + void bindPipeline(RenderPipeline pipeline) { + _bindPipeline(pipeline); + } + + void bindVertexBuffer(BufferView bufferView, int vertexCount) { + bufferView.buffer._bindAsVertexBuffer( + this, bufferView.offsetInBytes, bufferView.lengthInBytes, vertexCount); + } + + void bindUniform(UniformSlot slot, BufferView bufferView) { + bool success = bufferView.buffer._bindAsUniform( + this, slot, bufferView.offsetInBytes, bufferView.lengthInBytes); + if (!success) { + throw Exception("Failed to bind uniform slot"); + } + } + + void draw() { + if (!_draw()) { + throw Exception("Failed to append draw"); + } + } + + /// Wrap with native counterpart. + @Native( + symbol: 'InternalFlutterGpu_RenderPass_Initialize') + external void _initialize(); + + @Native, Int, Int, Int, Pointer, Handle)>( + symbol: 'InternalFlutterGpu_RenderPass_SetColorAttachment') + external String? _setColorAttachment(int loadAction, int storeAction, + int clearColor, Texture texture, Texture? resolveTexture); + + @Native, Int, Int, Int, Pointer)>( + symbol: 'InternalFlutterGpu_RenderPass_SetStencilAttachment') + external String? _setStencilAttachment( + int loadAction, int storeAction, int clearStencil, Texture texture); + + @Native, Pointer)>( + symbol: 'InternalFlutterGpu_RenderPass_Begin') + external String? _begin(CommandBuffer commandBuffer); + + @Native, Pointer)>( + symbol: 'InternalFlutterGpu_RenderPass_BindPipeline') + external void _bindPipeline(RenderPipeline pipeline); + + @Native, Pointer, Int, Int, Int)>( + symbol: 'InternalFlutterGpu_RenderPass_BindVertexBufferDevice') + external void _bindVertexBufferDevice(DeviceBuffer buffer, int offsetInBytes, + int lengthInBytes, int vertexCount); + + @Native, Pointer, Int, Int, Int)>( + symbol: 'InternalFlutterGpu_RenderPass_BindVertexBufferHost') + external void _bindVertexBufferHost( + HostBuffer buffer, int offsetInBytes, int lengthInBytes, int vertexCount); + + @Native, Int, Int, Pointer, Int, Int)>( + symbol: 'InternalFlutterGpu_RenderPass_BindUniformDevice') + external bool _bindUniformDevice(int stage, int slotId, DeviceBuffer buffer, + int offsetInBytes, int lengthInBytes); + + @Native, Int, Int, Pointer, Int, Int)>( + symbol: 'InternalFlutterGpu_RenderPass_BindUniformHost') + external bool _bindUniformHost(int stage, int slotId, HostBuffer buffer, + int offsetInBytes, int lengthInBytes); + + @Native)>( + symbol: 'InternalFlutterGpu_RenderPass_Draw') + external bool _draw(); +} diff --git a/lib/gpu/lib/src/render_pipeline.dart b/lib/gpu/lib/src/render_pipeline.dart new file mode 100644 index 0000000000000..a8d110e29a2fd --- /dev/null +++ b/lib/gpu/lib/src/render_pipeline.dart @@ -0,0 +1,29 @@ +// 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. + +// ignore_for_file: public_member_api_docs + +part of flutter_gpu; + +base class RenderPipeline extends NativeFieldWrapperClass1 { + /// Creates a new RenderPipeline. + RenderPipeline._( + GpuContext gpuContext, Shader vertexShader, Shader fragmentShader) + : vertexShader = vertexShader, + fragmentShader = fragmentShader { + String? error = _initialize(gpuContext, vertexShader, fragmentShader); + if (error != null) { + throw Exception(error); + } + } + + final Shader vertexShader; + final Shader fragmentShader; + + /// Wrap with native counterpart. + @Native, Pointer, Pointer)>( + symbol: 'InternalFlutterGpu_RenderPipeline_Initialize') + external String? _initialize( + GpuContext gpuContext, Shader vertexShader, Shader fragmentShader); +} diff --git a/lib/gpu/lib/src/shader.dart b/lib/gpu/lib/src/shader.dart new file mode 100644 index 0000000000000..9ebbe9280f176 --- /dev/null +++ b/lib/gpu/lib/src/shader.dart @@ -0,0 +1,35 @@ +// 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. + +// ignore_for_file: public_member_api_docs + +part of flutter_gpu; + +base class UniformSlot { + const UniformSlot(this.slotId, this.shaderStage); + + final int slotId; + final ShaderStage shaderStage; +} + +base class Shader extends NativeFieldWrapperClass1 { + // [Shader] handles are instantiated when interacting with a [ShaderLibrary]. + Shader._(); + + UniformSlot? getUniformSlot(String name) { + int slot = _getUniformSlot(name); + if (slot < 0) { + return null; + } + return UniformSlot(slot, ShaderStage.values[_getShaderStage()]); + } + + @Native)>( + symbol: 'InternalFlutterGpu_Shader_GetShaderStage') + external int _getShaderStage(); + + @Native, Handle)>( + symbol: 'InternalFlutterGpu_Shader_GetUniformSlot') + external int _getUniformSlot(String name); +} diff --git a/lib/gpu/lib/src/shader_library.dart b/lib/gpu/lib/src/shader_library.dart new file mode 100644 index 0000000000000..551c20bc589ee --- /dev/null +++ b/lib/gpu/lib/src/shader_library.dart @@ -0,0 +1,38 @@ +// 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. + +// ignore_for_file: public_member_api_docs + +part of flutter_gpu; + +base class ShaderLibrary extends NativeFieldWrapperClass1 { + static ShaderLibrary? fromAsset(String assetName) { + final lib = ShaderLibrary._(); + final error = lib._initializeWithAsset(assetName); + if (error != null) { + throw Exception("Failed to initialize ShaderLibrary: ${error}"); + } + return lib; + } + + ShaderLibrary._(); + + Shader? operator [](String shaderName) { + // This `flutter_gpu` library isn't always registered as part of the builtin + // DartClassLibrary, and so we can't instantiate the Dart classes on the + // engine side. + // Providing a new wrapper to [_getShader] for wrapping the native + // counterpart (if it hasn't been wrapped already) is a hack to work around + // this. + return _getShader(shaderName, Shader._()); + } + + @Native( + symbol: 'InternalFlutterGpu_ShaderLibrary_InitializeWithAsset') + external String? _initializeWithAsset(String assetName); + + @Native, Handle, Handle)>( + symbol: 'InternalFlutterGpu_ShaderLibrary_GetShader') + external Shader? _getShader(String shaderName, Shader shaderWrapper); +} diff --git a/lib/gpu/render_pass.cc b/lib/gpu/render_pass.cc new file mode 100644 index 0000000000000..08fbae379368d --- /dev/null +++ b/lib/gpu/render_pass.cc @@ -0,0 +1,280 @@ +// 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 "flutter/lib/gpu/render_pass.h" + +#include "flutter/lib/gpu/formats.h" +#include "flutter/lib/gpu/render_pipeline.h" +#include "fml/memory/ref_ptr.h" +#include "impeller/core/buffer_view.h" +#include "impeller/core/formats.h" +#include "impeller/core/shader_types.h" +#include "impeller/core/vertex_buffer.h" +#include "impeller/geometry/color.h" +#include "impeller/renderer/pipeline_library.h" +#include "tonic/converter/dart_converter.h" + +namespace flutter { +namespace gpu { + +IMPLEMENT_WRAPPERTYPEINFO(flutter_gpu, RenderPass); + +RenderPass::RenderPass() + : vertex_buffer_( + impeller::VertexBuffer{.index_type = impeller::IndexType::kNone}){}; + +RenderPass::~RenderPass() = default; + +const std::weak_ptr& RenderPass::GetContext() const { + return render_pass_->GetContext(); +} + +impeller::Command& RenderPass::GetCommand() { + return command_; +} + +const impeller::Command& RenderPass::GetCommand() const { + return command_; +} + +impeller::RenderTarget& RenderPass::GetRenderTarget() { + return render_target_; +} + +const impeller::RenderTarget& RenderPass::GetRenderTarget() const { + return render_target_; +} + +impeller::VertexBuffer& RenderPass::GetVertexBuffer() { + return vertex_buffer_; +} + +bool RenderPass::Begin(flutter::gpu::CommandBuffer& command_buffer) { + render_pass_ = + command_buffer.GetCommandBuffer()->CreateRenderPass(render_target_); + if (!render_pass_) { + return false; + } + command_buffer.AddRenderPass(render_pass_); + return true; +} + +void RenderPass::SetPipeline(fml::RefPtr pipeline) { + render_pipeline_ = std::move(pipeline); +} + +std::shared_ptr> +RenderPass::GetOrCreatePipeline() { + // Infer the pipeline layout based on the shape of the RenderTarget. + auto pipeline_desc = pipeline_descriptor_; + { + FML_DCHECK(render_target_.HasColorAttachment(0)) + << "The render target has no color attachment. This should never " + "happen."; + color_desc_.format = render_target_.GetRenderTargetPixelFormat(); + pipeline_desc.SetColorAttachmentDescriptor(0, color_desc_); + } + + if (auto stencil = render_target_.GetStencilAttachment()) { + pipeline_desc.SetStencilPixelFormat( + stencil->texture->GetTextureDescriptor().format); + pipeline_desc.SetStencilAttachmentDescriptors(stencil_front_desc_, + stencil_back_desc_); + } else { + pipeline_desc.ClearStencilAttachments(); + } + + if (auto depth = render_target_.GetDepthAttachment()) { + pipeline_desc.SetDepthStencilAttachmentDescriptor(depth_desc_); + } else { + pipeline_desc.ClearDepthAttachment(); + } + + auto& context = *GetContext().lock(); + + render_pipeline_->BindToPipelineDescriptor(*context.GetShaderLibrary(), + pipeline_desc); + + auto pipeline = + context.GetPipelineLibrary()->GetPipeline(pipeline_desc).Get(); + FML_DCHECK(pipeline) << "Couldn't resolve render pipeline"; + return pipeline; +} + +impeller::Command RenderPass::ProvisionRasterCommand() { + impeller::Command result = command_; + + result.pipeline = GetOrCreatePipeline(); + result.BindVertices(vertex_buffer_); + + return result; +} + +bool RenderPass::Draw() { + impeller::Command result = ProvisionRasterCommand(); + return render_pass_->AddCommand(std::move(result)); +} + +} // namespace gpu +} // namespace flutter + +static impeller::Color ToImpellerColor(uint32_t argb) { + return impeller::Color::MakeRGBA8((argb >> 16) & 0xFF, // R + (argb >> 8) & 0xFF, // G + argb & 0xFF, // B + argb >> 24); // A +} + +//---------------------------------------------------------------------------- +/// Exports +/// + +void InternalFlutterGpu_RenderPass_Initialize(Dart_Handle wrapper) { + auto res = fml::MakeRefCounted(); + res->AssociateWithDartWrapper(wrapper); +} + +Dart_Handle InternalFlutterGpu_RenderPass_SetColorAttachment( + flutter::gpu::RenderPass* wrapper, + int load_action, + int store_action, + int clear_color, + flutter::gpu::Texture* texture, + Dart_Handle resolve_texture_wrapper) { + impeller::ColorAttachment desc; + desc.load_action = flutter::gpu::ToImpellerLoadAction( + static_cast(load_action)); + desc.store_action = flutter::gpu::ToImpellerStoreAction( + static_cast(store_action)); + desc.clear_color = ToImpellerColor(static_cast(clear_color)); + desc.texture = texture->GetTexture(); + if (!Dart_IsNull(resolve_texture_wrapper)) { + flutter::gpu::Texture* resolve_texture = + tonic::DartConverter::FromDart( + resolve_texture_wrapper); + desc.resolve_texture = resolve_texture->GetTexture(); + } + wrapper->GetRenderTarget().SetColorAttachment(desc, 0); + return Dart_Null(); +} + +Dart_Handle InternalFlutterGpu_RenderPass_SetStencilAttachment( + flutter::gpu::RenderPass* wrapper, + int load_action, + int store_action, + int clear_stencil, + flutter::gpu::Texture* texture) { + impeller::StencilAttachment desc; + desc.load_action = flutter::gpu::ToImpellerLoadAction( + static_cast(load_action)); + desc.store_action = flutter::gpu::ToImpellerStoreAction( + static_cast(store_action)); + desc.clear_stencil = clear_stencil; + desc.texture = texture->GetTexture(); + wrapper->GetRenderTarget().SetStencilAttachment(desc); + return Dart_Null(); +} + +Dart_Handle InternalFlutterGpu_RenderPass_Begin( + flutter::gpu::RenderPass* wrapper, + flutter::gpu::CommandBuffer* command_buffer) { + if (!wrapper->Begin(*command_buffer)) { + return tonic::ToDart("Failed to begin RenderPass"); + } + return Dart_Null(); +} + +void InternalFlutterGpu_RenderPass_BindPipeline( + flutter::gpu::RenderPass* wrapper, + flutter::gpu::RenderPipeline* pipeline) { + auto ref = fml::RefPtr(pipeline); + wrapper->SetPipeline(std::move(ref)); +} + +template +static void BindVertexBuffer(flutter::gpu::RenderPass* wrapper, + TBuffer* buffer, + int offset_in_bytes, + int length_in_bytes, + int vertex_count) { + auto& vertex_buffer = wrapper->GetVertexBuffer(); + vertex_buffer.vertex_buffer = impeller::BufferView{ + .buffer = buffer->GetBuffer(), + .range = impeller::Range(offset_in_bytes, length_in_bytes), + }; + vertex_buffer.vertex_count = vertex_count; +} + +void InternalFlutterGpu_RenderPass_BindVertexBufferDevice( + flutter::gpu::RenderPass* wrapper, + flutter::gpu::DeviceBuffer* device_buffer, + int offset_in_bytes, + int length_in_bytes, + int vertex_count) { + BindVertexBuffer(wrapper, device_buffer, offset_in_bytes, length_in_bytes, + vertex_count); +} + +void InternalFlutterGpu_RenderPass_BindVertexBufferHost( + flutter::gpu::RenderPass* wrapper, + flutter::gpu::HostBuffer* host_buffer, + int offset_in_bytes, + int length_in_bytes, + int vertex_count) { + BindVertexBuffer(wrapper, host_buffer, offset_in_bytes, length_in_bytes, + vertex_count); +} + +template +static bool BindUniform(flutter::gpu::RenderPass* wrapper, + int stage, + int slot_id, + TBuffer* buffer, + int offset_in_bytes, + int length_in_bytes) { + // TODO(113715): Populate this metadata once GLES is able to handle + // non-struct uniform names. + std::shared_ptr metadata = + std::make_shared(); + + auto& command = wrapper->GetCommand(); + impeller::ShaderUniformSlot slot; + // Don't populate the slot name... we don't have it here and Impeller doesn't + // even use it for anything. + slot.ext_res_0 = slot_id; + return command.BindResource( + flutter::gpu::ToImpellerShaderStage( + static_cast(stage)), + slot, metadata, + impeller::BufferView{ + .buffer = buffer->GetBuffer(), + .range = impeller::Range(offset_in_bytes, length_in_bytes), + }); +} + +bool InternalFlutterGpu_RenderPass_BindUniformDevice( + flutter::gpu::RenderPass* wrapper, + int stage, + int slot_id, + flutter::gpu::DeviceBuffer* device_buffer, + int offset_in_bytes, + int length_in_bytes) { + return BindUniform(wrapper, stage, slot_id, device_buffer, offset_in_bytes, + length_in_bytes); +} + +bool InternalFlutterGpu_RenderPass_BindUniformHost( + flutter::gpu::RenderPass* wrapper, + int stage, + int slot_id, + flutter::gpu::HostBuffer* host_buffer, + int offset_in_bytes, + int length_in_bytes) { + return BindUniform(wrapper, stage, slot_id, host_buffer, offset_in_bytes, + length_in_bytes); +} + +bool InternalFlutterGpu_RenderPass_Draw(flutter::gpu::RenderPass* wrapper) { + return wrapper->Draw(); +} diff --git a/lib/gpu/render_pass.h b/lib/gpu/render_pass.h new file mode 100644 index 0000000000000..77bfd1e7f9b05 --- /dev/null +++ b/lib/gpu/render_pass.h @@ -0,0 +1,155 @@ +// 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 +#include "flutter/lib/gpu/command_buffer.h" +#include "flutter/lib/gpu/export.h" +#include "flutter/lib/ui/dart_wrapper.h" +#include "fml/memory/ref_ptr.h" +#include "impeller/core/vertex_buffer.h" +#include "impeller/renderer/command.h" +#include "impeller/renderer/render_pass.h" +#include "impeller/renderer/render_target.h" +#include "lib/gpu/device_buffer.h" +#include "lib/gpu/host_buffer.h" +#include "lib/gpu/render_pipeline.h" +#include "lib/gpu/texture.h" + +namespace flutter { +namespace gpu { + +class RenderPass : public RefCountedDartWrappable { + DEFINE_WRAPPERTYPEINFO(); + FML_FRIEND_MAKE_REF_COUNTED(RenderPass); + + public: + RenderPass(); + + ~RenderPass() override; + + const std::weak_ptr& GetContext() const; + + impeller::Command& GetCommand(); + const impeller::Command& GetCommand() const; + + impeller::RenderTarget& GetRenderTarget(); + const impeller::RenderTarget& GetRenderTarget() const; + + impeller::VertexBuffer& GetVertexBuffer(); + + bool Begin(flutter::gpu::CommandBuffer& command_buffer); + + void SetPipeline(fml::RefPtr pipeline); + + /// Lookup an Impeller pipeline by building a descriptor based on the current + /// command state. + std::shared_ptr> + GetOrCreatePipeline(); + + impeller::Command ProvisionRasterCommand(); + + bool Draw(); + + private: + impeller::RenderTarget render_target_; + std::shared_ptr render_pass_; + + // Command encoding state. + impeller::Command command_; + fml::RefPtr render_pipeline_; + impeller::PipelineDescriptor pipeline_descriptor_; + + // Pipeline descriptor layout state. We always keep track of this state, but + // we'll only apply it as necessary to match the RenderTarget. + impeller::ColorAttachmentDescriptor color_desc_; + impeller::StencilAttachmentDescriptor stencil_front_desc_; + impeller::StencilAttachmentDescriptor stencil_back_desc_; + impeller::DepthAttachmentDescriptor depth_desc_; + + // Command state. + impeller::VertexBuffer vertex_buffer_; + + FML_DISALLOW_COPY_AND_ASSIGN(RenderPass); +}; + +} // namespace gpu +} // namespace flutter + +//---------------------------------------------------------------------------- +/// Exports +/// + +extern "C" { + +FLUTTER_GPU_EXPORT +extern void InternalFlutterGpu_RenderPass_Initialize(Dart_Handle wrapper); + +FLUTTER_GPU_EXPORT +extern Dart_Handle InternalFlutterGpu_RenderPass_SetColorAttachment( + flutter::gpu::RenderPass* wrapper, + int load_action, + int store_action, + int clear_color, + flutter::gpu::Texture* texture, + Dart_Handle resolve_texture_wrapper); + +FLUTTER_GPU_EXPORT +extern Dart_Handle InternalFlutterGpu_RenderPass_SetStencilAttachment( + flutter::gpu::RenderPass* wrapper, + int load_action, + int store_action, + int clear_stencil, + flutter::gpu::Texture* texture); + +FLUTTER_GPU_EXPORT +extern Dart_Handle InternalFlutterGpu_RenderPass_Begin( + flutter::gpu::RenderPass* wrapper, + flutter::gpu::CommandBuffer* command_buffer); + +FLUTTER_GPU_EXPORT +extern void InternalFlutterGpu_RenderPass_BindPipeline( + flutter::gpu::RenderPass* wrapper, + flutter::gpu::RenderPipeline* pipeline); + +FLUTTER_GPU_EXPORT +extern void InternalFlutterGpu_RenderPass_BindVertexBufferDevice( + flutter::gpu::RenderPass* wrapper, + flutter::gpu::DeviceBuffer* device_buffer, + int offset_in_bytes, + int length_in_bytes, + int vertex_count); + +FLUTTER_GPU_EXPORT +extern void InternalFlutterGpu_RenderPass_BindVertexBufferHost( + flutter::gpu::RenderPass* wrapper, + flutter::gpu::HostBuffer* host_buffer, + int offset_in_bytes, + int length_in_bytes, + int vertex_count); + +FLUTTER_GPU_EXPORT +extern bool InternalFlutterGpu_RenderPass_BindUniformDevice( + flutter::gpu::RenderPass* wrapper, + int stage, + int slot_id, + flutter::gpu::DeviceBuffer* device_buffer, + int offset_in_bytes, + int length_in_bytes); + +FLUTTER_GPU_EXPORT +extern bool InternalFlutterGpu_RenderPass_BindUniformHost( + flutter::gpu::RenderPass* wrapper, + int stage, + int slot_id, + flutter::gpu::HostBuffer* host_buffer, + int offset_in_bytes, + int length_in_bytes); + +FLUTTER_GPU_EXPORT +extern bool InternalFlutterGpu_RenderPass_Draw( + flutter::gpu::RenderPass* wrapper); + +} // extern "C" diff --git a/lib/gpu/render_pipeline.cc b/lib/gpu/render_pipeline.cc new file mode 100644 index 0000000000000..df93e8770ef83 --- /dev/null +++ b/lib/gpu/render_pipeline.cc @@ -0,0 +1,54 @@ +// 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 "flutter/lib/gpu/render_pipeline.h" + +#include "flutter/lib/gpu/shader.h" +#include "impeller/renderer/pipeline_descriptor.h" + +namespace flutter { +namespace gpu { + +IMPLEMENT_WRAPPERTYPEINFO(flutter_gpu, RenderPipeline); + +RenderPipeline::RenderPipeline( + fml::RefPtr vertex_shader, + fml::RefPtr fragment_shader) + : vertex_shader_(std::move(vertex_shader)), + fragment_shader_(std::move(fragment_shader)) {} + +void RenderPipeline::BindToPipelineDescriptor( + impeller::ShaderLibrary& library, + impeller::PipelineDescriptor& desc) { + desc.SetVertexDescriptor(vertex_shader_->GetVertexDescriptor()); + + desc.AddStageEntrypoint(vertex_shader_->GetFunctionFromLibrary(library)); + desc.AddStageEntrypoint(fragment_shader_->GetFunctionFromLibrary(library)); +} + +RenderPipeline::~RenderPipeline() = default; + +} // namespace gpu +} // namespace flutter + +//---------------------------------------------------------------------------- +/// Exports +/// + +Dart_Handle InternalFlutterGpu_RenderPipeline_Initialize( + Dart_Handle wrapper, + flutter::gpu::Context* gpu_context, + flutter::gpu::Shader* vertex_shader, + flutter::gpu::Shader* fragment_shader) { + // Lazily register the shaders synchronously if they haven't been already. + vertex_shader->RegisterSync(*gpu_context); + fragment_shader->RegisterSync(*gpu_context); + + auto res = fml::MakeRefCounted( + fml::RefPtr(vertex_shader), // + fml::RefPtr(fragment_shader)); + res->AssociateWithDartWrapper(wrapper); + + return Dart_Null(); +} diff --git a/lib/gpu/render_pipeline.h b/lib/gpu/render_pipeline.h new file mode 100644 index 0000000000000..2980d16d22243 --- /dev/null +++ b/lib/gpu/render_pipeline.h @@ -0,0 +1,52 @@ +// 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 "flutter/lib/gpu/context.h" +#include "flutter/lib/gpu/export.h" +#include "flutter/lib/gpu/shader.h" +#include "flutter/lib/ui/dart_wrapper.h" +#include "impeller/renderer/pipeline_descriptor.h" + +namespace flutter { +namespace gpu { + +class RenderPipeline : public RefCountedDartWrappable { + DEFINE_WRAPPERTYPEINFO(); + FML_FRIEND_MAKE_REF_COUNTED(RenderPipeline); + + public: + RenderPipeline(fml::RefPtr vertex_shader, + fml::RefPtr fragment_shader); + + ~RenderPipeline() override; + + void BindToPipelineDescriptor(impeller::ShaderLibrary& library, + impeller::PipelineDescriptor& desc); + + private: + fml::RefPtr vertex_shader_; + fml::RefPtr fragment_shader_; + + FML_DISALLOW_COPY_AND_ASSIGN(RenderPipeline); +}; + +} // namespace gpu +} // namespace flutter + +//---------------------------------------------------------------------------- +/// Exports +/// + +extern "C" { + +FLUTTER_GPU_EXPORT +extern Dart_Handle InternalFlutterGpu_RenderPipeline_Initialize( + Dart_Handle wrapper, + flutter::gpu::Context* gpu_context, + flutter::gpu::Shader* vertex_shader, + flutter::gpu::Shader* fragment_shader); + +} // extern "C" diff --git a/lib/gpu/shader.cc b/lib/gpu/shader.cc new file mode 100644 index 0000000000000..0d6eb5d8fbc49 --- /dev/null +++ b/lib/gpu/shader.cc @@ -0,0 +1,102 @@ +// 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 "flutter/lib/gpu/shader.h" + +#include + +#include "fml/make_copyable.h" +#include "impeller/renderer/shader_function.h" +#include "impeller/renderer/shader_library.h" +#include "lib/gpu/shader_library.h" +#include "tonic/converter/dart_converter.h" + +namespace flutter { +namespace gpu { + +IMPLEMENT_WRAPPERTYPEINFO(flutter_gpu, Shader); + +Shader::Shader() = default; + +Shader::~Shader() = default; + +fml::RefPtr Shader::Make( + std::string entrypoint, + impeller::ShaderStage stage, + std::shared_ptr code_mapping, + std::vector uniforms, + std::shared_ptr vertex_desc) { + auto shader = fml::MakeRefCounted(); + shader->entrypoint_ = std::move(entrypoint); + shader->stage_ = stage; + shader->code_mapping_ = std::move(code_mapping); + shader->uniforms_ = std::move(uniforms); + shader->vertex_desc_ = std::move(vertex_desc); + return shader; +} + +std::shared_ptr Shader::GetFunctionFromLibrary( + impeller::ShaderLibrary& library) { + return library.GetFunction(entrypoint_, stage_); +} + +bool Shader::IsRegistered(Context& context) { + auto& lib = *context.GetContext()->GetShaderLibrary(); + return GetFunctionFromLibrary(lib) != nullptr; +} + +bool Shader::RegisterSync(Context& context) { + if (IsRegistered(context)) { + return true; // Already registered. + } + + auto& lib = *context.GetContext()->GetShaderLibrary(); + + std::promise promise; + auto future = promise.get_future(); + lib.RegisterFunction( + entrypoint_, stage_, code_mapping_, + fml::MakeCopyable([promise = std::move(promise)](bool result) mutable { + promise.set_value(result); + })); + if (!future.get()) { + return false; // Registration failed. + } + return true; +} + +std::shared_ptr Shader::GetVertexDescriptor() + const { + return vertex_desc_; +} + +impeller::ShaderStage Shader::GetShaderStage() const { + return stage_; +} + +int Shader::GetUniformSlot(const std::string& name) const { + for (const auto& uniform : uniforms_) { + if (name == uniform.name) { + return uniform.location; + } + } + return -1; +} + +} // namespace gpu +} // namespace flutter + +//---------------------------------------------------------------------------- +/// Exports +/// + +int InternalFlutterGpu_Shader_GetShaderStage(flutter::gpu::Shader* wrapper) { + return static_cast(wrapper->GetShaderStage()); +} + +int InternalFlutterGpu_Shader_GetUniformSlot(flutter::gpu::Shader* wrapper, + Dart_Handle name_handle) { + auto name = tonic::StdStringFromDart(name_handle); + return wrapper->GetUniformSlot(name); +} diff --git a/lib/gpu/shader.h b/lib/gpu/shader.h new file mode 100644 index 0000000000000..ba453794408be --- /dev/null +++ b/lib/gpu/shader.h @@ -0,0 +1,79 @@ +// 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 +#include + +#include "flutter/lib/gpu/context.h" +#include "flutter/lib/ui/dart_wrapper.h" +#include "fml/memory/ref_ptr.h" +#include "impeller/core/runtime_types.h" +#include "impeller/core/shader_types.h" +#include "impeller/renderer/shader_function.h" +#include "impeller/renderer/vertex_descriptor.h" + +namespace flutter { +namespace gpu { + +/// An immutable collection of shaders loaded from a shader bundle asset. +class Shader : public RefCountedDartWrappable { + DEFINE_WRAPPERTYPEINFO(); + FML_FRIEND_MAKE_REF_COUNTED(Shader); + + public: + ~Shader() override; + + static fml::RefPtr Make( + std::string entrypoint, + impeller::ShaderStage stage, + std::shared_ptr code_mapping, + std::vector uniforms, + std::shared_ptr vertex_desc); + + std::shared_ptr GetFunctionFromLibrary( + impeller::ShaderLibrary& library); + + bool IsRegistered(Context& context); + + bool RegisterSync(Context& context); + + std::shared_ptr GetVertexDescriptor() const; + + impeller::ShaderStage GetShaderStage() const; + + int GetUniformSlot(const std::string& name) const; + + private: + Shader(); + + std::string entrypoint_; + impeller::ShaderStage stage_; + std::shared_ptr code_mapping_; + std::vector uniforms_; + std::shared_ptr vertex_desc_; + + FML_DISALLOW_COPY_AND_ASSIGN(Shader); +}; + +} // namespace gpu +} // namespace flutter + +//---------------------------------------------------------------------------- +/// Exports +/// + +extern "C" { + +FLUTTER_GPU_EXPORT +extern int InternalFlutterGpu_Shader_GetShaderStage( + flutter::gpu::Shader* wrapper); + +FLUTTER_GPU_EXPORT +extern int InternalFlutterGpu_Shader_GetUniformSlot( + flutter::gpu::Shader* wrapper, + Dart_Handle name_handle); + +} // extern "C" diff --git a/lib/gpu/shader_library.cc b/lib/gpu/shader_library.cc new file mode 100644 index 0000000000000..3abea3e574e6f --- /dev/null +++ b/lib/gpu/shader_library.cc @@ -0,0 +1,140 @@ +// 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 "flutter/lib/gpu/shader_library.h" + +#include + +#include "flutter/lib/gpu/fixtures.h" +#include "flutter/lib/gpu/shader.h" +#include "fml/mapping.h" +#include "fml/memory/ref_ptr.h" +#include "impeller/renderer/vertex_descriptor.h" +#include "impeller/runtime_stage/runtime_stage.h" + +namespace flutter { +namespace gpu { + +// ===[ BEGIN MEMES ]=========================================================== +static fml::RefPtr OpenRuntimeStageAsShader( + std::shared_ptr payload, + const std::shared_ptr& vertex_desc) { + impeller::RuntimeStage stage(std::move(payload)); + return Shader::Make(stage.GetEntrypoint(), + ToShaderStage(stage.GetShaderStage()), + stage.GetCodeMapping(), stage.GetUniforms(), vertex_desc); +} + +static void InstantiateTestShaderLibrary() { + ShaderLibrary::ShaderMap shaders; + auto vertex_desc = std::make_shared(); + vertex_desc->SetStageInputs( + // TODO(bdero): The stage inputs need to be packed into the flatbuffer. + FlutterGPUUnlitVertexShader::kAllShaderStageInputs, + // TODO(bdero): Make the vertex attribute layout fully configurable. + // When encoding commands, allow for specifying a stride, + // type, and vertex buffer slot for each attribute. + // Provide a way to lookup vertex attribute slot locations by + // name from the shader. + FlutterGPUUnlitVertexShader::kInterleavedBufferLayout); + shaders["UnlitVertex"] = OpenRuntimeStageAsShader( + std::make_shared(kFlutterGPUUnlitVertIPLR, + kFlutterGPUUnlitVertIPLRLength), + vertex_desc); + shaders["UnlitFragment"] = OpenRuntimeStageAsShader( + std::make_shared(kFlutterGPUUnlitFragIPLR, + kFlutterGPUUnlitFragIPLRLength), + nullptr); + auto library = ShaderLibrary::MakeFromShaders(std::move(shaders)); + ShaderLibrary::SetOverride(library); +} +// ===[ END MEMES ]============================================================= + +IMPLEMENT_WRAPPERTYPEINFO(flutter_gpu, ShaderLibrary); + +fml::RefPtr ShaderLibrary::override_shader_library_; + +fml::RefPtr ShaderLibrary::MakeFromAsset( + const std::string& name, + std::string& out_error) { + // =========================================================================== + // This is a temporary hack to get the shader library populated in the + // framework before the shader bundle format is landed! + InstantiateTestShaderLibrary(); + // =========================================================================== + + if (override_shader_library_) { + return override_shader_library_; + } + // TODO(bdero): Load the ShaderLibrary asset. + out_error = "Shader bundle asset unimplemented"; + return nullptr; +} + +fml::RefPtr ShaderLibrary::MakeFromShaders(ShaderMap shaders) { + auto res = + fml::MakeRefCounted(std::move(shaders)); + return res; +} + +void ShaderLibrary::SetOverride( + fml::RefPtr override_shader_library) { + override_shader_library_ = std::move(override_shader_library); +} + +fml::RefPtr ShaderLibrary::GetShader(const std::string& shader_name, + Dart_Handle shader_wrapper) const { + auto it = shaders_.find(shader_name); + if (it == shaders_.end()) { + return nullptr; // No matching shaders. + } + auto shader = it->second; + + if (shader->dart_wrapper() == nullptr) { + shader->AssociateWithDartWrapper(shader_wrapper); + } + return shader; +} + +ShaderLibrary::ShaderLibrary(ShaderMap shaders) + : shaders_(std::move(shaders)) {} + +ShaderLibrary::~ShaderLibrary() = default; + +} // namespace gpu +} // namespace flutter + +//---------------------------------------------------------------------------- +/// Exports +/// + +Dart_Handle InternalFlutterGpu_ShaderLibrary_InitializeWithAsset( + Dart_Handle wrapper, + Dart_Handle asset_name) { + if (!Dart_IsString(asset_name)) { + return tonic::ToDart("Asset name must be a string"); + } + + std::string error; + auto res = flutter::gpu::ShaderLibrary::MakeFromAsset( + tonic::StdStringFromDart(asset_name), error); + if (!res) { + return tonic::ToDart(error); + } + res->AssociateWithDartWrapper(wrapper); + return Dart_Null(); +} + +Dart_Handle InternalFlutterGpu_ShaderLibrary_GetShader( + flutter::gpu::ShaderLibrary* wrapper, + Dart_Handle shader_name, + Dart_Handle shader_wrapper) { + FML_DCHECK(Dart_IsString(shader_name)); + auto shader = + wrapper->GetShader(tonic::StdStringFromDart(shader_name), shader_wrapper); + if (!shader) { + return Dart_Null(); + } + return tonic::ToDart(shader.get()); +} diff --git a/lib/gpu/shader_library.h b/lib/gpu/shader_library.h new file mode 100644 index 0000000000000..35fd737f7a7a1 --- /dev/null +++ b/lib/gpu/shader_library.h @@ -0,0 +1,72 @@ +// 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 +#include + +#include "flutter/lib/gpu/export.h" +#include "flutter/lib/gpu/shader.h" +#include "flutter/lib/ui/dart_wrapper.h" +#include "fml/memory/ref_ptr.h" + +namespace flutter { +namespace gpu { + +/// An immutable collection of shaders loaded from a shader bundle asset. +class ShaderLibrary : public RefCountedDartWrappable { + DEFINE_WRAPPERTYPEINFO(); + FML_FRIEND_MAKE_REF_COUNTED(ShaderLibrary); + + public: + using ShaderMap = std::unordered_map>; + + static fml::RefPtr MakeFromAsset(const std::string& name, + std::string& out_error); + + static fml::RefPtr MakeFromShaders(ShaderMap shaders); + + /// Sets a return override for `MakeFromAsset` for testing purposes. + static void SetOverride(fml::RefPtr override_shader_library); + + fml::RefPtr GetShader(const std::string& shader_name, + Dart_Handle shader_wrapper) const; + + ~ShaderLibrary() override; + + private: + /// A global override used to inject a ShaderLibrary when running with the + /// Impeller playground. When set, `MakeFromAsset` will always just return + /// this library. + static fml::RefPtr override_shader_library_; + + ShaderMap shaders_; + + explicit ShaderLibrary(ShaderMap shaders); + + FML_DISALLOW_COPY_AND_ASSIGN(ShaderLibrary); +}; + +} // namespace gpu +} // namespace flutter + +//---------------------------------------------------------------------------- +/// Exports +/// + +extern "C" { + +FLUTTER_GPU_EXPORT +extern Dart_Handle InternalFlutterGpu_ShaderLibrary_InitializeWithAsset( + Dart_Handle wrapper, + Dart_Handle asset_name); + +FLUTTER_GPU_EXPORT +extern Dart_Handle InternalFlutterGpu_ShaderLibrary_GetShader( + flutter::gpu::ShaderLibrary* wrapper, + Dart_Handle shader_name, + Dart_Handle shader_wrapper); + +} // extern "C" diff --git a/lib/gpu/smoketest.cc b/lib/gpu/smoketest.cc index 54411d7397921..e7524cd10efa5 100644 --- a/lib/gpu/smoketest.cc +++ b/lib/gpu/smoketest.cc @@ -16,7 +16,7 @@ namespace flutter { // TODO(131346): Remove this once we migrate the Dart GPU API into this space. -IMPLEMENT_WRAPPERTYPEINFO(gpu, FlutterGpuTestClass); +IMPLEMENT_WRAPPERTYPEINFO(flutter_gpu, FlutterGpuTestClass); // TODO(131346): Remove this once we migrate the Dart GPU API into this space. FlutterGpuTestClass::~FlutterGpuTestClass() = default; diff --git a/lib/gpu/texture.cc b/lib/gpu/texture.cc index 648af7643d6d6..49382e631f16d 100644 --- a/lib/gpu/texture.cc +++ b/lib/gpu/texture.cc @@ -4,6 +4,7 @@ #include "flutter/lib/gpu/texture.h" +#include "flutter/lib/gpu/formats.h" #include "flutter/lib/ui/painting/image.h" #include "fml/mapping.h" #include "impeller/core/allocator.h" @@ -15,13 +16,17 @@ namespace flutter { namespace gpu { -IMPLEMENT_WRAPPERTYPEINFO(gpu, Texture); +IMPLEMENT_WRAPPERTYPEINFO(flutter_gpu, Texture); Texture::Texture(std::shared_ptr texture) : texture_(std::move(texture)) {} Texture::~Texture() = default; +std::shared_ptr Texture::GetTexture() { + return texture_; +} + void Texture::SetCoordinateSystem( impeller::TextureCoordinateSystem coordinate_system) { texture_->SetCoordinateSystem(coordinate_system); @@ -78,9 +83,11 @@ bool InternalFlutterGpu_Texture_Initialize(Dart_Handle wrapper, bool enable_shader_read_usage, bool enable_shader_write_usage) { impeller::TextureDescriptor desc; - desc.storage_mode = static_cast(storage_mode); + desc.storage_mode = flutter::gpu::ToImpellerStorageMode( + static_cast(storage_mode)); desc.size = {width, height}; - desc.format = static_cast(format); + desc.format = flutter::gpu::ToImpellerPixelFormat( + static_cast(format)); desc.usage = 0; if (enable_render_target_usage) { desc.usage |= static_cast( @@ -113,8 +120,9 @@ bool InternalFlutterGpu_Texture_Initialize(Dart_Handle wrapper, return false; } - texture->SetCoordinateSystem( - static_cast(coordinate_system)); + texture->SetCoordinateSystem(flutter::gpu::ToImpellerTextureCoordinateSystem( + static_cast( + coordinate_system))); auto res = fml::MakeRefCounted(std::move(texture)); res->AssociateWithDartWrapper(wrapper); @@ -126,7 +134,9 @@ void InternalFlutterGpu_Texture_SetCoordinateSystem( flutter::gpu::Texture* wrapper, int coordinate_system) { return wrapper->SetCoordinateSystem( - static_cast(coordinate_system)); + flutter::gpu::ToImpellerTextureCoordinateSystem( + static_cast( + coordinate_system))); } bool InternalFlutterGpu_Texture_Overwrite(flutter::gpu::Texture* texture, diff --git a/lib/gpu/texture.h b/lib/gpu/texture.h index f6329f936c5bb..b6105fae81b04 100644 --- a/lib/gpu/texture.h +++ b/lib/gpu/texture.h @@ -22,6 +22,8 @@ class Texture : public RefCountedDartWrappable { ~Texture() override; + std::shared_ptr GetTexture(); + void SetCoordinateSystem(impeller::TextureCoordinateSystem coordinate_system); bool Overwrite(const tonic::DartByteData& source_bytes);