Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] drawAtlas blend mode. #38335

Merged
merged 31 commits into from
Jan 24, 2023
Merged

Conversation

jonahwilliams
Copy link
Member

@jonahwilliams jonahwilliams commented Dec 15, 2022

Complete support for all blend modes in drawAtlas. Currently investigating if 1) we can share these blend mode shaders with drawVertices 2) if we can skip the normal blends by drawing colored trianges and then blending the image.

@jonahwilliams jonahwilliams self-assigned this Dec 15, 2022
@chinmaygarde chinmaygarde changed the title [WIP] Complete drawAtlas support [WIP] [Impeller] Complete drawAtlas support. Dec 16, 2022
@jonahwilliams jonahwilliams changed the title [WIP] [Impeller] Complete drawAtlas support. [Impeller] drawAtlas and drawVertices blend mode. Jan 11, 2023
@jonahwilliams jonahwilliams marked this pull request as ready for review January 11, 2023 20:41
@jonahwilliams

This comment was marked as outdated.

@cmkweber
Copy link

Here is an example of this not quite working:

flutter_01

// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' as ui;
import 'package:flutter/material.dart';

void main() =>
  runApp(MaterialApp(
    home: Scaffold(
      body:CustomPaint(painter: FooPainter())
    )
  ));


class FooPainter extends CustomPainter {
  final ui.Vertices vertices = ui.Vertices(
    VertexMode.triangles,
    <Offset>[
      Offset(0, 0),
      Offset(0, 100),
      Offset(100, 100),
      Offset(50, 50),
      Offset(50, 150),
      Offset(150, 150),
    ],
    colors: [
      Colors.red,
      Colors.green,
      Colors.blue,
      Colors.red,
      Colors.green,
      Colors.blue,
    ].map((x) => x.withAlpha(255)).toList(),
  );

  @override
  void paint(ui.Canvas canvas, ui.Size size) {
    canvas.drawVertices(vertices, BlendMode.srcATop, Paint()
    // ..color = Colors.black.withAlpha(100)
    ..shader = LinearGradient(colors: [
      Colors.yellow,
      Colors.green,
    ]).createShader(Rect.fromLTWH(0, 0, size.width, size.height)));
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}

Could it be that you are creating the gradient shader at the painters size (size.width, size.height) instead of the triangles size (150, 150) ?

@jonahwilliams
Copy link
Member Author

Yeah, the shader was a bit out of bounds, however the biggest issues was that I was accidentally dividing twice here: 0c23ff4 which made all the UVs tiny.

@jonahwilliams
Copy link
Member Author

TODO:

@jonahwilliams
Copy link
Member Author

I cheated a bit for src blend modes but that might have bitten me for supporting texture coordinates.

@jonahwilliams
Copy link
Member Author

TODO figure out if texture coordinates apply if there are no per-vertex colors (I would think they do)

@jonahwilliams
Copy link
Member Author

updates: texcoordinates should be treated as being in the coordinate space of whatever is being sampled and not already normalized 0-1. It should apply on src and it should apply if there are no colors, but not if there is only a solid color paint obviously

@jonahwilliams
Copy link
Member Author

also as an optimization we should avoid calling makeSnapshot if the paint shader just contains an image

@jonahwilliams
Copy link
Member Author

I've udpated this to make alpha work correctly for the pipeline blends. Seems inefficient for a lot of the src blend modes if we know the src image has no opacity. Do we have any tags/data on our images to be able to tell this?

@jonahwilliams
Copy link
Member Author

I guess a fair question would be why even use the colors and srcOver if you know your image has no alpha.

@jonahwilliams jonahwilliams requested a review from bdero January 19, 2023 18:16
@bdero
Copy link
Member

bdero commented Jan 20, 2023

Do we have any tags/data on our images to be able to tell this?

Huh, I feel like @chinmaygarde and I have briefly mentioned doing this several times, but I guess we never made a bug about it. Added one here: flutter/flutter#118854

@jonahwilliams
Copy link
Member Author

It would probably useful for tracking in general. For example on the vertices blend modes, we could apply similar optimziations based on knowing if the color source has any transparency. Probably low priority compared to other optimizations though

private:
bool absorb_opacity_ = false;
std::optional<Scalar> alpha_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is no longer being used. Remove?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used now

@@ -27,8 +27,7 @@
#include "impeller/entity/advanced_blend_saturation.frag.h"
#include "impeller/entity/advanced_blend_screen.frag.h"
#include "impeller/entity/advanced_blend_softlight.frag.h"
#include "impeller/entity/atlas_fill.frag.h"
#include "impeller/entity/atlas_fill.vert.h"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Extra newline.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}
auto texture_contents = TextureContents::MakeRect(coverage);
texture_contents->SetTexture(subpass_texture);
texture_contents->SetOpacity(alpha_);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the filter graph is rendered, it will already perform a separate blit if necessary to apply the entity properties when drawing to the render pass, so this extra subpass is almost redundant; just doing filter_contents->Render(renderer, entity, pass); would nearly work without the subpass.

The one thing that wouldn't work is making this alpha apply on the final blit as you're doing here. But, we already have a mechanism to propagate alpha to the final blit in the filter graph and can trivially add support to BlendFilterContents by repurposing the new/unused SetAlpha setter (added another comment about this).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -109,7 +110,8 @@ static std::optional<Snapshot> AdvancedBlend(
auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});
FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, sampler);
blend_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale();
blend_info.dst_input_alpha = absorb_opacity ? dst_snapshot->opacity : 1.0f;
blend_info.dst_input_alpha =
(absorb_opacity ? dst_snapshot->opacity : 1.0) * alpha.value_or(1.0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this alpha value is no longer being used by AtlasContents, we could repurpose it to just forward down the filter chain by multiplying it into the returned Snapshot::opacity, which would allow us to remove the need for the extra subpass as mentioned in my other comment (this snapshot alpha forwarding can be supported for both the pipeline and advanced blend case with no inconsistencies/ill effects).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahh, Yeah that is what I missed. I had a similar technique for the pipeline blends which didn't work since it would just blend the alpha with one of the inputs. Will fix so both are applied to the snapshot.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@jonahwilliams
Copy link
Member Author

Filled flutter/flutter#118903 for the blend issue, I verified by modifying the shader the the dst needs to be in the second slot for advanced blends, but the first for pipeline blends. Don't see the issue elsewhere though

@jonahwilliams
Copy link
Member Author

This is updated now, PTAL @bdero

@jonahwilliams
Copy link
Member Author

Filled flutter/flutter#118914 for the remaing alpha issue

Copy link
Member

@bdero bdero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@jonahwilliams
Copy link
Member Author

yaaaay!

@jonahwilliams jonahwilliams added the autosubmit Merge PR when tree becomes green via auto submit App label Jan 24, 2023
@auto-submit auto-submit bot merged commit 334c92e into flutter:main Jan 24, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jan 24, 2023
@chinmaygarde
Copy link
Member

🎉 We can update the section about this in go/impeller-wiki#status

@jonahwilliams jonahwilliams deleted the drawAtlas branch January 24, 2023 23:24
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Jan 24, 2023
…119089)

* 334c92e56 [Impeller] drawAtlas blend mode. (flutter/engine#38335)

* 2499a5d9f Roll Fuchsia Mac SDK from HxpwvvbQdk54L6_8q... to MUvFS0baOnigVUIND... (flutter/engine#39105)
ricardoamador pushed a commit to ricardoamador/engine that referenced this pull request Jan 25, 2023
* fill out drawAtlas

* ++

* add drawVertices uage

* ++

* test fixes

* dont double divide

* CI cleanups

* some texture coordinates work

* ++

* basic texture coordiantes work

* ++

* ++

* ++

* Delete color blending

* back out vertices change

* ++

* ++

* ++

* remove atlas_fill from licenses

* blending cleanup

* Use sub-contents

* fix opacity for pipeline blends

* use alpha in snapshot to avoid extra pass

* ++

* ++

* fix order
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
autosubmit Merge PR when tree becomes green via auto submit App e: impeller
Projects
No open projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants