blob: 38f62ef3d507e9c702e4016d7f251fa9aa3e1a31 [file] [log] [blame]
// 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 <memory>
#include <utility>
#include "flutter/lib/ui/painting/fragment_shader.h"
#include "flutter/lib/ui/dart_wrapper.h"
#include "flutter/lib/ui/painting/fragment_program.h"
#include "flutter/lib/ui/ui_dart_state.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, ReusableFragmentShader);
ReusableFragmentShader::ReusableFragmentShader(
fml::RefPtr<FragmentProgram> program,
uint64_t float_count,
uint64_t sampler_count)
: program_(std::move(program)),
uniform_data_(SkData::MakeUninitialized(
(float_count + 2 * sampler_count) * sizeof(float))),
samplers_(sampler_count),
float_count_(float_count) {}
Dart_Handle ReusableFragmentShader::Create(Dart_Handle wrapper,
Dart_Handle program,
Dart_Handle float_count_handle,
Dart_Handle sampler_count_handle) {
auto* fragment_program =
tonic::DartConverter<FragmentProgram*>::FromDart(program);
uint64_t float_count =
tonic::DartConverter<uint64_t>::FromDart(float_count_handle);
uint64_t sampler_count =
tonic::DartConverter<uint64_t>::FromDart(sampler_count_handle);
auto res = fml::MakeRefCounted<ReusableFragmentShader>(
fml::Ref(fragment_program), float_count, sampler_count);
res->AssociateWithDartWrapper(wrapper);
void* raw_uniform_data =
reinterpret_cast<void*>(res->uniform_data_->writable_data());
return Dart_NewExternalTypedData(Dart_TypedData_kFloat32, raw_uniform_data,
float_count);
}
bool ReusableFragmentShader::ValidateSamplers() {
for (auto i = 0u; i < samplers_.size(); i += 1) {
if (samplers_[i] == nullptr) {
return false;
}
}
return true;
}
void ReusableFragmentShader::SetSampler(Dart_Handle index_handle,
Dart_Handle sampler_handle) {
uint64_t index = tonic::DartConverter<uint64_t>::FromDart(index_handle);
ImageShader* sampler =
tonic::DartConverter<ImageShader*>::FromDart(sampler_handle);
if (index >= samplers_.size()) {
Dart_ThrowException(tonic::ToDart("Sampler index out of bounds"));
}
// 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.
DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
auto* uniform_floats =
reinterpret_cast<float*>(uniform_data_->writable_data());
samplers_[index] = sampler->shader(sampling);
uniform_floats[float_count_ + 2 * index] = sampler->width();
uniform_floats[float_count_ + 2 * index + 1] = sampler->height();
}
std::shared_ptr<DlColorSource> ReusableFragmentShader::shader(
DlImageSampling sampling) {
FML_CHECK(program_);
// The lifetime of this object is longer than a frame, and the uniforms can be
// continually changed on the UI thread. So we take a copy of the uniforms
// before handing it to the DisplayList for consumption on the render thread.
auto uniform_data = std::make_shared<std::vector<uint8_t>>();
uniform_data->resize(uniform_data_->size());
memcpy(uniform_data->data(), uniform_data_->bytes(), uniform_data->size());
return program_->MakeDlColorSource(std::move(uniform_data), samplers_);
}
void ReusableFragmentShader::Dispose() {
uniform_data_.reset();
program_ = nullptr;
samplers_.clear();
ClearDartWrapper();
}
ReusableFragmentShader::~ReusableFragmentShader() = default;
} // namespace flutter