linebender / piet

An abstraction for 2D graphics.
Apache License 2.0
1.26k stars 94 forks source link

Subpixel text rendering #289

Open eliemichel opened 4 years ago

eliemichel commented 4 years ago

Is there any way already to perform subpixel rendering? Or any plan to support so? It'd quite useful in order to get readable text in typical UI widgets!

cmyr commented 4 years ago

We should be using the platform default rendering options; subpixel should be disabled on recent versions of macOS (10.14+) and (I believe) enabled on windows?

Linux is another story, and I'm honestly not sure what cairo is doing.

eliemichel commented 4 years ago

Mmm, Windows here, no subpixel rendering when using druid.

raphlinus commented 4 years ago

I think I know why, it's probably because the clipping is not respecting ClearType. The relevant bit of code is push_layer_mask, where it's setting D2D1_LAYER_OPTIONS_NONE and that should probably be D2D1_LAYER_OPTIONS_INITIALIZE_FOR_CLEARTYPE.

cmyr commented 4 years ago

I won't have a windows machine handy until early next week, @eliemichel if you wanted to try this fix a PR would be welcome!

eliemichel commented 4 years ago

Ok, I gave it a shot, but changing the line suggested by @raphlinus is not enough: druidaa

This part of the doc says that:

If the render target has an alpha channel and is not set to D2D1_ALPHA_MODE_IGNORE, then the default text antialiasing mode is grayscale.

So I naively tried to replace any occurence to other alpha modes by D2D1_ALPHA_MODE_IGNORE, just to see, but still no subpixel AA.

PS: Was there an easier way to try this change than cloning druid, changing all references to piet-common in the Cargo.toml files to point to my own local copy of piet?

cmyr commented 4 years ago

the main piet backends have the ability to generate a number of reference images; you would run,

cargo run --example=test-picture  -- N

were N is the number of a picture; they're listed in piet/src/samples. For this I would try using no. 13.

raphlinus commented 4 years ago

PS: Was there an easier way to try this change than cloning druid, changing all references to piet-common in the Cargo.toml files to point to my own local copy of piet?

Yes, that's what [patch] is for.

I thought I looked at this a year or so ago, and am pretty sure I was seeing ClearType rendering. But there a few things that can go wrong.

raphlinus commented 4 years ago

Also, one issue with using the reference image command line is that it uses a different process for creating the render targets than for screen presentation, and that might be where the problem is.

eliemichel commented 4 years ago

@cmyr oh thx but the examples (and tests as well) refer to data from outside the repo:

   Compiling piet v0.2.0-pre2 (E:\SourceCode\piet\piet)
error: couldn't read piet\src\samples\../../../snapshots/resources/Anaheim-Regular.ttf: The system cannot find the path specified. (os error 3)
  --> piet\src\samples\picture_13.rs:16:28
   |
16 |       let _ = text.load_font(include_bytes!(
   |  ____________________________^
17 | |         "../../../snapshots/resources/Anaheim-Regular.ttf"
18 | |     ));
   | |_____^
   |

@raphlinus great I did not know about patch it's perfect (I'm still pretty new to rust)

cmyr commented 4 years ago

oops yea it's in a submodule. git submodule init && git submodule update.

eliemichel commented 4 years ago

Oh yes my bad then! Here is fig. 13:

d2d-test-13

No ClearType on sight..

raphlinus commented 4 years ago

Hmm, this is a deeper problem than I thought. That flag should work in Windows 7, but according to the docs, Starting in Windows 8, you cannot render with ClearType in a layer. I was going to mention in an earlier comment, using axis aligned clips should improve the situation (as well as be a performance boost), but the problem is that then not all clip paths are handled the same. For example, if you clip to a rounded rect (as you might in a button), then the ClearType would also disappear.

raphlinus commented 4 years ago

Yes, after a bit more digging, it seems the solution is to use the axis aligned clip methods when the clip shape is a rectangle. That'd actually be a great issue to take on.

(ClearType works when there's no clipping, but the problem got worse with the partial invalidation work, now we always clip to the invalidation region)

eliemichel commented 4 years ago

Ok I don't think I am aware enough of the way Direct2D is working nor piet is designed to take this over..

cmyr commented 4 years ago

@eliemichel no worries, thanks for opening the issue, someone will get to it before too long. :)

smmalis37 commented 4 years ago

Some quick profiling on https://github.com/smmalis37/sudoku_rust turned up that 40% of all of the cpu time was being consumed inside this call to clip https://github.com/linebender/druid/blob/9564af60b12e749c2b2c6d91dde1b235cec5d159/druid/src/widget/label.rs#L339

Changing my label's line break mode to either of the other options made the app significantly more responsive feeling.

cmyr commented 4 years ago

@smmalis37 interesting. The very least we can do is overflow by default, I'd happily take that patch in druid if you like?