| // 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 <iostream> |
| |
| #include "flutter/lib/ui/painting/fragment_program.h" |
| |
| #include "flutter/assets/asset_manager.h" |
| #include "flutter/fml/trace_event.h" |
| #include "flutter/impeller/runtime_stage/runtime_stage.h" |
| #include "flutter/lib/ui/dart_wrapper.h" |
| #include "flutter/lib/ui/ui_dart_state.h" |
| #include "flutter/lib/ui/window/platform_configuration.h" |
| #include "third_party/skia/include/core/SkString.h" |
| #include "third_party/tonic/converter/dart_converter.h" |
| #include "third_party/tonic/dart_args.h" |
| #include "third_party/tonic/dart_binding_macros.h" |
| #include "third_party/tonic/dart_library_natives.h" |
| #include "third_party/tonic/typed_data/typed_list.h" |
| |
| namespace flutter { |
| |
| IMPLEMENT_WRAPPERTYPEINFO(ui, FragmentProgram); |
| |
| std::string FragmentProgram::initFromAsset(std::string asset_name) { |
| FML_TRACE_EVENT("flutter", "FragmentProgram::initFromAsset", "asset", |
| asset_name); |
| std::shared_ptr<AssetManager> asset_manager = UIDartState::Current() |
| ->platform_configuration() |
| ->client() |
| ->GetAssetManager(); |
| std::unique_ptr<fml::Mapping> data = asset_manager->GetAsMapping(asset_name); |
| if (data == nullptr) { |
| return std::string("Asset '") + asset_name + std::string("' not found"); |
| } |
| |
| auto runtime_stage = impeller::RuntimeStage(std::move(data)); |
| if (!runtime_stage.IsValid()) { |
| return std::string("Asset '") + asset_name + |
| std::string("' does not contain valid shader data."); |
| } |
| { |
| auto code_mapping = runtime_stage.GetCodeMapping(); |
| auto code_size = code_mapping->GetSize(); |
| const char* sksl = |
| reinterpret_cast<const char*>(code_mapping->GetMapping()); |
| // SkString makes a copy. |
| SkRuntimeEffect::Result result = |
| SkRuntimeEffect::MakeForShader(SkString(sksl, code_size)); |
| if (result.effect == nullptr) { |
| return std::string("Invalid SkSL:\n") + sksl + |
| std::string("\nSkSL Error:\n") + result.errorText.c_str(); |
| } |
| runtime_effect_ = result.effect; |
| } |
| |
| int sampled_image_count = 0; |
| size_t other_uniforms_bytes = 0; |
| for (const auto& uniform_description : runtime_stage.GetUniforms()) { |
| if (uniform_description.type == |
| impeller::RuntimeUniformType::kSampledImage) { |
| sampled_image_count++; |
| } else { |
| size_t size = uniform_description.dimensions.rows * |
| uniform_description.dimensions.cols * |
| uniform_description.bit_width / 8u; |
| if (uniform_description.array_elements > 0) { |
| size *= uniform_description.array_elements; |
| } |
| other_uniforms_bytes += size; |
| } |
| } |
| |
| Dart_Handle ths = Dart_HandleFromWeakPersistent(dart_wrapper()); |
| if (Dart_IsError(ths)) { |
| Dart_PropagateError(ths); |
| } |
| |
| Dart_Handle result = Dart_SetField(ths, tonic::ToDart("_samplerCount"), |
| Dart_NewInteger(sampled_image_count)); |
| if (Dart_IsError(result)) { |
| Dart_PropagateError(result); |
| } |
| |
| size_t rounded_uniform_bytes = |
| (other_uniforms_bytes + sizeof(float) - 1) & ~(sizeof(float) - 1); |
| size_t float_count = rounded_uniform_bytes / sizeof(float); |
| result = Dart_SetField(ths, tonic::ToDart("_uniformFloatCount"), |
| Dart_NewInteger(float_count)); |
| if (Dart_IsError(result)) { |
| Dart_PropagateError(result); |
| } |
| |
| return ""; |
| } |
| |
| fml::RefPtr<FragmentShader> FragmentProgram::shader(Dart_Handle shader, |
| Dart_Handle uniforms_handle, |
| Dart_Handle samplers) { |
| auto sampler_shaders = |
| tonic::DartConverter<std::vector<ImageShader*>>::FromDart(samplers); |
| tonic::Float32List uniforms(uniforms_handle); |
| size_t uniform_count = uniforms.num_elements(); |
| size_t uniform_data_size = |
| (uniform_count + 2 * sampler_shaders.size()) * sizeof(float); |
| sk_sp<SkData> uniform_data = SkData::MakeUninitialized(uniform_data_size); |
| // uniform_floats must only be referenced BEFORE the call to makeShader below. |
| auto* uniform_floats = |
| reinterpret_cast<float*>(uniform_data->writable_data()); |
| for (size_t i = 0; i < uniform_count; i++) { |
| uniform_floats[i] = uniforms[i]; |
| } |
| uniforms.Release(); |
| std::vector<sk_sp<SkShader>> sk_samplers(sampler_shaders.size()); |
| for (size_t i = 0; i < sampler_shaders.size(); i++) { |
| DlImageSampling sampling = DlImageSampling::kNearestNeighbor; |
| ImageShader* image_shader = sampler_shaders[i]; |
| // ImageShaders can hold a preferred value for sampling options and |
| // developers are encouraged to use that value or the value will be supplied |
| // by "the environment where it is used". The environment here does not |
| // contain a value to be used if the developer did not specify a preference |
| // when they constructed the ImageShader, so we will use kNearest which is |
| // the default filterQuality in a Paint object. |
| sk_samplers[i] = image_shader->shader(sampling)->skia_object(); |
| uniform_floats[uniform_count + 2 * i] = image_shader->width(); |
| uniform_floats[uniform_count + 2 * i + 1] = image_shader->height(); |
| } |
| auto sk_shader = runtime_effect_->makeShader( |
| std::move(uniform_data), sk_samplers.data(), sk_samplers.size()); |
| return FragmentShader::Create(shader, std::move(sk_shader)); |
| } |
| |
| void FragmentProgram::Create(Dart_Handle wrapper) { |
| auto res = fml::MakeRefCounted<FragmentProgram>(); |
| res->AssociateWithDartWrapper(wrapper); |
| } |
| |
| FragmentProgram::FragmentProgram() = default; |
| |
| FragmentProgram::~FragmentProgram() = default; |
| |
| } // namespace flutter |