23 start_point_ = start_point;
24 end_point_ = end_point;
28 colors_ = std::move(colors);
32 stops_ = std::move(stops);
44 tile_mode_ = tile_mode;
51 for (
auto color : colors_) {
52 if (!
color.IsOpaque()) {
59 bool LinearGradientContents::CanApplyFastGradient()
const {
64 if (!maybe_rect.has_value()) {
67 Rect rect = maybe_rect.value();
71 Point start = (start_point_.
y < end_point_.
y) ? start_point_ : end_point_;
72 Point end = (start_point_.
y < end_point_.
y) ? end_point_ : start_point_;
84 Point start = (start_point_.
x < end_point_.
x) ? start_point_ : end_point_;
85 Point end = (start_point_.
x < end_point_.
x) ? end_point_ : start_point_;
104 bool LinearGradientContents::FastLinearGradient(
const ContentContext& renderer,
105 const Entity& entity,
106 RenderPass& pass)
const {
111 bool force_stencil = !geometry->IsAxisAlignedRect();
113 auto geom_callback = [&](
const ContentContext& renderer,
const Entity& entity,
115 const Geometry* geometry) -> GeometryResult {
120 std::optional<Rect> maybe_rect = geometry->GetCoverage(Matrix());
121 if (!maybe_rect.has_value()) {
124 Rect rect = maybe_rect.value();
125 bool horizontal_axis = start_point_.
y == end_point_.
y;
130 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
131 vtx_builder.Reserve(6 * (stops_.size() - 1));
132 Point prev = start_point_;
133 for (
auto i = 1u; i < stops_.size(); i++) {
135 Point current = (1.0 - t) * start_point_ + t * end_point_;
136 Rect section = horizontal_axis
138 current.x - prev.x, rect.GetHeight())
140 :
Rect::MakeXYWH(rect.GetX(), prev.y, rect.GetWidth(),
142 vtx_builder.AddVertices({
143 {section.GetLeftTop(), colors_[i - 1]},
144 {section.GetRightTop(),
145 horizontal_axis ? colors_[i] : colors_[i - 1]},
146 {section.GetLeftBottom(),
147 horizontal_axis ? colors_[i - 1] : colors_[i]},
148 {section.GetRightTop(),
149 horizontal_axis ? colors_[i] : colors_[i - 1]},
150 {section.GetLeftBottom(),
151 horizontal_axis ? colors_[i - 1] : colors_[i]},
152 {section.GetRightBottom(), colors_[i]},
156 return GeometryResult{
159 vtx_builder.CreateVertexBuffer(renderer.GetTransientsBuffer()),
160 .transform = entity.GetShaderTransform(pass),
164 pass.SetLabel(
"LinearGradient");
166 VS::FrameInfo frame_info;
169 [&renderer](ContentContextOptions options) {
170 return renderer.GetFastGradientPipeline(options);
172 return ColorSourceContents::DrawGeometry<VS>(
173 renderer, entity, pass, pipeline_callback, frame_info,
174 [
this, &renderer, &entity](RenderPass& pass) {
175 auto& host_buffer = renderer.GetTransientsBuffer();
177 FS::FragInfo frag_info;
182 FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
186 force_stencil, geom_callback);
195 if (CanApplyFastGradient()) {
196 return FastLinearGradient(renderer, entity, pass);
199 return RenderSSBO(renderer, entity, pass);
201 return RenderTexture(renderer, entity, pass);
204 bool LinearGradientContents::RenderTexture(
const ContentContext& renderer,
210 VS::FrameInfo frame_info;
217 return ColorSourceContents::DrawGeometry<VS>(
218 renderer, entity, pass, pipeline_callback, frame_info,
219 [
this, &renderer, &entity](RenderPass& pass) {
221 auto gradient_texture =
223 if (gradient_texture ==
nullptr) {
227 FS::FragInfo frag_info;
228 frag_info.start_point = start_point_;
229 frag_info.end_point = end_point_;
230 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
231 frag_info.decal_border_color = decal_border_color_;
232 frag_info.texture_sampler_y_coord_scale =
233 gradient_texture->GetYCoordScale();
238 frag_info.half_texel =
239 Vector2(0.5 / gradient_texture->GetSize().width,
240 0.5 / gradient_texture->GetSize().height);
242 pass.SetCommandLabel(
"LinearGradientFill");
244 SamplerDescriptor sampler_desc;
248 FS::BindTextureSampler(
249 pass, std::move(gradient_texture),
250 renderer.
GetContext()->GetSamplerLibrary()->GetSampler(
260 Point start_to_end = end_point - start_point;
262 (start_to_end.x * start_to_end.x + start_to_end.y * start_to_end.y);
263 return dot == 0.0f ? 0.0f : 1.0f / dot;
267 bool LinearGradientContents::RenderSSBO(
const ContentContext& renderer,
268 const Entity& entity,
269 RenderPass& pass)
const {
273 VS::FrameInfo frame_info;
277 [&renderer](ContentContextOptions options) {
278 return renderer.GetLinearGradientSSBOFillPipeline(options);
280 return ColorSourceContents::DrawGeometry<VS>(
281 renderer, entity, pass, pipeline_callback, frame_info,
282 [
this, &renderer, &entity](RenderPass& pass) {
283 FS::FragInfo frag_info;
284 frag_info.start_point = start_point_;
285 frag_info.end_point = end_point_;
286 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
287 frag_info.decal_border_color = decal_border_color_;
291 frag_info.start_to_end = end_point_ - start_point_;
292 frag_info.inverse_dot_start_to_end =
293 CalculateInverseDotStartToEnd(start_point_, end_point_);
295 auto& host_buffer = renderer.GetTransientsBuffer();
298 frag_info.colors_length = colors.size();
300 host_buffer.Emplace(colors.data(), colors.size() *
sizeof(StopData),
303 pass.SetCommandLabel(
"LinearGradientSSBOFill");
306 pass, renderer.GetTransientsBuffer().EmplaceUniform(frag_info));
307 FS::BindColorData(pass, color_buffer);
318 decal_border_color_ = color_filter_proc(decal_border_color_);