Issues with font rendering and antialias

397 views
Skip to first unread message

Florian Hester

unread,
May 10, 2021, 12:07:48 PM5/10/21
to skia-discuss
Hello,

I am currently using Skia in combination with Vulkan, and noticed that when rendering text, the rendered glyph have incorrect antialias. I can't reproduce the issue when using software rendering (glyphs look fine).

I have used Renderdoc to examine the shader (decompiled from SPIRV) used to render the text:

void main()
{
    mediump vec4 outputColor_Stage0 = vinColor_Stage0;
    mediump vec4 texColor = texture(uTextureSampler_0_Stage0, vTextureCoords_Stage0).xxxx;
    mediump vec4 outputCoverage_Stage0 = texColor;
    sk_FragColor = outputColor_Stage0 * outputCoverage_Stage0;
}


This seems wrong to me. The atlas image is single channel, which as far i understand, is intended to be used only in the alpha component for the final color, but in the above shader it also used in the color components. When rendering white text upon a white background (in which case the text should be completely invisible) the above shader results in the antialiased parts to be darker. AFAIK, the color component should be whatever the color of the text is supposed to be, and the alpha channel equal to alpha value retrieved from the atlas image.

I'm certain this must be an oversight on my part somewhere, though can't find any setting or value to alter that would fix this.

Here is a screenshot from Renderdoc showing the rendered text, in the bottom bar you can see the value of one of the darker pixels:
Screenshot 2021-05-10 180218.png

I am on the master branch of Skia.

Kind regards,
Florian

Greg Daniel

unread,
May 10, 2021, 12:44:18 PM5/10/21
to skia-discuss
At least in terms of the text's mask texture, in Vulkan the only single channel image format is VK_IMAGE_FORMAT_R8. So the mask is stored in the red channel. That is why you see the .xxxx swizzle. This value is then multiplied by the input color which is the color the text should be. So the shader does look correct to me.

Greg

--
You received this message because you are subscribed to the Google Groups "skia-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to skia-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/skia-discuss/1ded12c9-4d5d-4b32-897c-679e6eddb20dn%40googlegroups.com.

Ben Wagner

unread,
May 10, 2021, 1:29:45 PM5/10/21
to skia-d...@googlegroups.com
As to the partial coverage showing up, it looks a lot like the text was composited against transparent black and that was then composited onto the final white background seen in the screen capture. However, there are many ways this could have happened. A reproduction on https://fiddle.skia.org/ might be helpful, though I think the "GPU" there is GL (we should probably label that a bit better now that there are four GPU backends). Did this only reproduce with Vulkan? Does it reproduce with GL? It looks like the values of all the channels are 0.53725 in the screen capture, which seems like a pre-multiplied white? Maybe this is just an issue with premultiplied vs unpremultiplied?

Florian Hester

unread,
May 10, 2021, 4:28:04 PM5/10/21
to skia-discuss
Hello,

I have set up a fiddle: https://fiddle.skia.org/c/64535e941d1387dc9b83b0f134dea484

This produces an image exactly as i would expect. It also uses a transparent black clear color.

My goal here is to take the rendered Skia image and overlay it over a 3D scene (so i can draw UI stuff with Skia), this is currently achieved by drawing the image using a window filling quad.
It does seems i require unpre-multiplied in my use case, based on the pixel color and alpha values of the anti-aliasing in GPU image of the fiddle, i have been using a pre-multiplied surface.

Unfortunately, when i attempt to request an unpre-multiplied SkSurface from Skia, it does not create an SkSurface (SkSurface::MakeRenderTarget() returns nullptr):

SkImageInfo sk_image_info = SkImageInfo::Make(p_surface_render_target.width(), p_surface_render_target.height(), SkColorType::kRGBA_8888_SkColorType, kUnpremul_SkAlphaType);

auto sk_surface = SkSurface::MakeRenderTarget(gr_direct_context_.get(), SkBudgeted::kNo, sk_image_info, 4, kTopLeft_GrSurfaceOrigin, nullptr);


I dug a little in the reason for the nullptr, and found that on line 66 of SkGpuDevice.cpp, it just says 'no' to unpre-multiplied, with not much of a reason given.

Using the fiddle code in my application produces the same issues, with a pre-multiplied surface.

Thanks for the help thus far, at least things are getting clearer :)

Florian
Reply all
Reply to author
Forward
0 new messages