<p>Almost a month after I posted this question I finally found the answer.</p>
<p>The steps I took:</p>
<ol>
<li><p>I decided to disable blending altogether and play with it:
<a href="https://i.sstatic.net/zgOAA.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/zgOAA.png" alt="no-blending" /></a></p>
</li>
<li><p>But when inspecting the produced image more closely I noticed that the outline was still there, and it was sticking outside of the rendered quad, which suggested that it's a post-processing effect:
<a href="https://i.sstatic.net/7BKlL.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/7BKlL.png" alt="more closely" /></a></p>
</li>
<li><p>I decided to browse through the settings of the graphics driver and found this:
<a href="https://i.sstatic.net/vULgf.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/vULgf.png" alt="oh dear, radeon" /></a></p>
</li>
</ol>
<p>Disabling it removed the outline.</p>
<p>[hard-facepalm-sound.ogg]</p>

CC BY-SA 4.0
2022-04-13T02:20:57.773Z
2022-04-13T02:20:57.773Z
Ivan Ivanov
<p>I'm writing a simple text editor using Vulkan for rendering, and I'm seeing some strange outline around the rendered letters if I take a screenshot of the text and zoom in, which bothers me because I can't explain why it's there.</p>
<p>Here's what RenderDoc shows in the texture view (note that in the pixel context view at the bottom right there's no outline around the text)
<a href="https://i.sstatic.net/RDHpa.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/RDHpa.png" alt="RenderDoc textyre view" /></a></p>
<p>However, if I take a screenshot and zoom in, I'll see this border around the letters:
<a href="https://i.sstatic.net/2cgt1.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/2cgt1.png" alt="text border" /></a></p>
<p>I use a pre-rendered font atlas in a texture stored as R8_UNORM. Then I use a very basic shader which takes the texture and produces a pixel with premultiplied alpha, ready to be blended by just adding the colors of src and dest:</p>
<pre><code>#version 450 core

layout(set = 1, binding = 0) uniform sampler2D texSampler;

layout(location = 0) in vec2 v_tex_coord;
layout(location = 1) in vec3 v_color;

layout(location = 0) out vec4 f_color;

void main() {
    f_color = vec4(v_color, 1.0) * texture(texSampler, v_tex_coord).a;
}
</code></pre>
<p>I'm puzzled and out of ideas on why this outline is there - I don't see why the pixels next to text border would suddenly become darker when I'm only adding positive color components and none of them are negative (just to make sure there are no negative components I tried modifying the shader and took absolute value of every component with exactly the same result).</p>
<p>In case it matters, my swapchain surface format is B8G8R8A8_UNORM and the colorspace is SRGB_NONLINEAR_KHR. The colors are exactly what I expect them to be so I assumed that gamma-wise it's OK but maybe I'm wrong.</p>
<p>Would appreciate any help with this.</p>
<p>UPD. I just made it work on my office Macbook and there's no outline there! So it must be something to do with either my window surface on windows or even with screenshot-taking apps (I've tried snipping tool, printscr and snip &amp; sketch)
<a href="https://i.sstatic.net/jFIgN.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/jFIgN.png" alt="enter image description here" /></a></p>

CC BY-SA 4.0
2022-03-24T01:49:54.430Z
Looks like you're "zooming in" with a cubic filter.
Wyck
CC BY-SA 4.0
2022-03-24T03:46:18.307Z
@Wyck I'm zooming in in GIMP, I've tried capturing both my text and text from VSCode on the same screenshot - my text has an outline, the other doesn't. So it must be something else
Ivan Ivanov
CC BY-SA 4.0
2022-03-24T03:54:22.567Z
Premultiplied alpha doesn't mean you "just add src and dest" you still have to multiply the dest by `1-src.alpha`.  Non-premultiplied src: `dest' = dest * (1-src.alpha) + src * (src.alpha)`  Premultiplied src: `dest' = dest * (1-src.alpha) + src`
Wyck
CC BY-SA 4.0
2022-03-24T05:13:51.390Z
@Wyck that's a good point - however, it still wouldn't explain why the pixels got darker. Imagine that the `src` is a white pixel with a 10% opacity and the `dest` is some `dest_color`. Then the resulting color will be `dest_color * 0.9 + 0.1 * 1.0`, which is always brighter than `dest_color`. I've just made all the text white and there's still an outline :(. Thank you very much for looking into it, it's hard to debug without having the app running.
Ivan Ivanov
CC BY-SA 4.0
2022-03-24T05:31:10.867Z
I'm talking about your **blend** function not your shader.  You've prepared a pre-multiplied color value but you assigned an alpha value of `1.0` (why not assign an alpha value of `texture(texSampler, v_tex_coord).a`?).  Presumably your DST blend factor should be set to VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA.  And the SRC blend factor should be set to VK_BLEND_FACTOR_ONE.  How did you set up your blending?  Is blending enabled? (I assume so)  Pedantically:  `alpha = texture(texSampler, v_tex_coord).a;  f_color = vec4(v_color, 1.0) * alpha` or `vec4(v_color * alpha, alpha)`
Wyck
CC BY-SA 4.0
2022-03-24T05:38:29.487Z
Yes, I've tried all sorts of things, including non-premultiplied alpha. I've updated the shader code in the question - and I'm pretty sure blending is correct - it's enabled and is currently set to ONE for src, ONE_MINUS_SRC_ALPHA for dest. It works as expected on MacOS so my only idea left is that I'm misunderstanding something about gamma processing or surface texture formats.
Ivan Ivanov
CC BY-SA 4.0
2022-03-24T05:45:59.027Z
I've made the code public just in case. Here's where the pipeline is set up - https://github.com/obiwanus/focus/blob/main/src/vulkan/pipelines.zig#L181. It's all in Zig, so that's why I haven't shared it before - assuming not too many Zig users. However, if zig is installed, then it should run out of the box on a Vulkan-capable machine with just `zig build run`
Ivan Ivanov
CC BY-SA 4.0
2022-03-24T12:43:38.120Z
It's also consistent with double-multiplied alpha (alpha * alpha), where completely transparent and completely opaque are treated correctly but semi-transparent values are treated incorrectly.  That's because:  0^2 = 0 and 1^2 = 1, but 0.5^2 = 0.25.
Wyck
CC BY-SA 4.0
2022-03-24T16:58:19.413Z
I've got another Windows machine with an Nvidia GPU (my main machine has an AMD card) and tried my code there - no outline, everything works OK. The blending must be correct. I'll check the differences in surface formats etc later when I have a moment - I don't see what else can be the reason.
Ivan Ivanov
<rendering><vulkan>
Text rendering - weird outline when zoomed
Ivan Ivanov
# Text rendering - weird outline when zoomed

(Asked by: username_0 on 2022-03-22)

I'm writing a simple text editor using Vulkan for rendering, and I'm seeing some strange outline around the rendered letters if I take a screenshot of the text and zoom in, which bothers me because I can't explain why it's there.

Here's what RenderDoc shows in the texture view (note that in the pixel context view at the bottom right there's no outline around the text)
[![RenderDoc textyre view](https://i.sstatic.net/RDHpa.png)](https://i.sstatic.net/RDHpa.png)

However, if I take a screenshot and zoom in, I'll see this border around the letters:
[![text border](https://i.sstatic.net/2cgt1.png)](https://i.sstatic.net/2cgt1.png)

I use a pre-rendered font atlas in a texture stored as R8\_UNORM. Then I use a very basic shader which takes the texture and produces a pixel with premultiplied alpha, ready to be blended by just adding the colors of src and dest:

```
#version 450 core

layout(set = 1, binding = 0) uniform sampler2D texSampler;

layout(location = 0) in vec2 v_tex_coord;
layout(location = 1) in vec3 v_color;

layout(location = 0) out vec4 f_color;

void main() {
    f_color = vec4(v_color, 1.0) * texture(texSampler, v_tex_coord).a;
}

```

I'm puzzled and out of ideas on why this outline is there - I don't see why the pixels next to text border would suddenly become darker when I'm only adding positive color components and none of them are negative (just to make sure there are no negative components I tried modifying the shader and took absolute value of every component with exactly the same result).

In case it matters, my swapchain surface format is B8G8R8A8\_UNORM and the colorspace is SRGB\_NONLINEAR\_KHR. The colors are exactly what I expect them to be so I assumed that gamma-wise it's OK but maybe I'm wrong.

Would appreciate any help with this.

UPD. I just made it work on my office Macbook and there's no outline there! So it must be something to do with either my window surface on windows or even with screenshot-taking apps (I've tried snipping tool, printscr and snip & sketch)
[![enter image description here](https://i.sstatic.net/jFIgN.png)](https://i.sstatic.net/jFIgN.png)

**Tags:** rendering, vulkan

> **Comments:**
> **username_1**: Looks like you're "zooming in" with a cubic filter.  
> **username_0**: @username_1 I'm zooming in in GIMP, I've tried capturing both my text and text from VSCode on the same screenshot - my text has an outline, the other doesn't. So it must be something else  
> **username_1**: Premultiplied alpha doesn't mean you "just add src and dest" you still have to multiply the dest by `1-src.alpha`.  Non-premultiplied src: `dest' = dest * (1-src.alpha) + src * (src.alpha)`  Premultiplied src: `dest' = dest * (1-src.alpha) + src`  
> **username_0**: @username_1 that's a good point - however, it still wouldn't explain why the pixels got darker. Imagine that the `src` is a white pixel with a 10% opacity and the `dest` is some `dest_color`. Then the resulting color will be `dest_color * 0.9 + 0.1 * 1.0`, which is always brighter than `dest_color`. I've just made all the text white and there's still an outline :(. Thank you very much for looking into it, it's hard to debug without having the app running.  
> **username_1**: I'm talking about your **blend** function not your shader.  You've prepared a pre-multiplied color value but you assigned an alpha value of `1.0` (why not assign an alpha value of `texture(texSampler, v_tex_coord).a`?).  Presumably your DST blend factor should be set to VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA.  And the SRC blend factor should be set to VK_BLEND_FACTOR_ONE.  How did you set up your blending?  Is blending enabled? (I assume so)  Pedantically:  `alpha = texture(texSampler, v_tex_coord).a;  f_color = vec4(v_color, 1.0) * alpha` or `vec4(v_color * alpha, alpha)`  
> **username_0**: Yes, I've tried all sorts of things, including non-premultiplied alpha. I've updated the shader code in the question - and I'm pretty sure blending is correct - it's enabled and is currently set to ONE for src, ONE_MINUS_SRC_ALPHA for dest. It works as expected on MacOS so my only idea left is that I'm misunderstanding something about gamma processing or surface texture formats.  
> **username_0**: I've made the code public just in case. Here's where the pipeline is set up - https://github.com/obiwanus/focus/blob/main/src/vulkan/pipelines.zig#L181. It's all in Zig, so that's why I haven't shared it before - assuming not too many Zig users. However, if zig is installed, then it should run out of the box on a Vulkan-capable machine with just `zig build run`  
> **username_1**: It's also consistent with double-multiplied alpha (alpha * alpha), where completely transparent and completely opaque are treated correctly but semi-transparent values are treated incorrectly.  That's because:  0^2 = 0 and 1^2 = 1, but 0.5^2 = 0.25.  
> **username_0**: I've got another Windows machine with an Nvidia GPU (my main machine has an AMD card) and tried my code there - no outline, everything works OK. The blending must be correct. I'll check the differences in surface formats etc later when I have a moment - I don't see what else can be the reason.  

---

## 1 answers

### Answer by username_0 on 2022-04-13. Score: 1 | Accepted answer

Almost a month after I posted this question I finally found the answer.

The steps I took:

1. I decided to disable blending altogether and play with it:
   [![no-blending](https://i.sstatic.net/zgOAA.png)](https://i.sstatic.net/zgOAA.png)
2. But when inspecting the produced image more closely I noticed that the outline was still there, and it was sticking outside of the rendered quad, which suggested that it's a post-processing effect:
   [![more closely](https://i.sstatic.net/7BKlL.png)](https://i.sstatic.net/7BKlL.png)
3. I decided to browse through the settings of the graphics driver and found this:
   [![oh dear, radeon](https://i.sstatic.net/vULgf.png)](https://i.sstatic.net/vULgf.png)

Disabling it removed the outline.

[hard-facepalm-sound.ogg]


---

