[scenes/opengl] Pad decoration parts
AbandonedPublic

Authored by zzag on Jun 16 2018, 8:09 PM.

Details

Reviewers
davidedmundson
fredrik
graesslin
Group Reviewers
KWin
Summary

Internally, OpenGL scene plugin stores each decoration in a texture
atlas to avoid unnecessary texture bind calls and use less memory.
This works great until there is no need for the linear filter. If the texture
atlas is scaled and the linear filter is used, texture bleeding could happen:

Decoration and content of the window "bleed".

Texture bleeding happens because linear filter samples texels that are
outside of a subtexture.

There are several ways to fix the texture bleeding:

  • the first one is so known "half pixel correction". With half pixel correction value of half a texel is added or subtracted so when linear filter comes in it samples texels in desired region;
  • another way to fix the texture bleeding are array texture. Unfortunately, decoration pieces could have different size so array textures wouldn't help;
  • and the last one is to pad each subtexture.

It's very easy to implement half pixel correction. But because mapped
subtexture is smaller by 1px, the linear filter would always kick in and
"blur" fonts.

So, the only choice we have is to pad each subtexture. This diff, as its
name suggests, makes decoration renderer to pad each decoration piece by
1px:


Decoration texture atlas for active Dolphin window.

Yet, there are still some problems on X11. Because window pixmaps also
include window decorations, clamp to edge would not help. I.e. window
pixmaps bleed on X11.


X11: Zoom effect.


Wayland: Zoom effect.

CCBUG: 360549

Test Plan

Zoomed screen, decorations are no longer bleeding.

Diff Detail

Repository
R108 KWin
Branch
decoration-atlas-padding
Lint
No Linters Available
Unit
No Unit Test Coverage
Build Status
Buildable 67
Build 67: arc lint + arc unit
zzag created this revision.Jun 16 2018, 8:09 PM
Restricted Application added a project: KWin. · View Herald TranscriptJun 16 2018, 8:09 PM
Restricted Application added a subscriber: kwin. · View Herald Transcript
zzag requested review of this revision.Jun 16 2018, 8:09 PM
zzag edited the summary of this revision. (Show Details)Jun 16 2018, 8:11 PM
zzag edited the summary of this revision. (Show Details)Jun 16 2018, 8:15 PM
zzag edited the summary of this revision. (Show Details)Jun 16 2018, 8:18 PM
zzag edited the summary of this revision. (Show Details)

I think you can do it without copying the image by just copying the relevant parts of the image as multiple uploads in renderPart

i.e

QPoint mainTexturePoint = (geo.topLeft() - partRect.topLeft() + offset) * image.devicePixelRatio());
 m_texture->update(image, texturePos; //main contents

//upload the top line of the image again slightly above the main GL texture
 m_texture->update(image, (texturePos - QPoint(padding,0), QRect(0,0,image.width(), padding);
//left
 m_texture->update(image, (texturePos - QPoint(0,padding)), QRect(0,0,padding, image.height());
//right
 m_texture->update(image, (texturePos - QPoint(image.width(),padding)), QRect(image.width(),0,padding, image));
//bottom
...

Completely untested and arguably the corners would be slightly wrong, but I think it would work out cleaner and faster

zzag added a comment.Jun 16 2018, 8:24 PM

I think you can do it without copying the image by just copying the relevant parts of the image as multiple uploads in renderPart

i.e

QPoint mainTexturePoint = (geo.topLeft() - partRect.topLeft() + offset) * image.devicePixelRatio());
 m_texture->update(image, texturePos; //main contents

//upload the top line of the image again slightly above the main GL texture
 m_texture->update(image, (texturePos - QPoint(padding,0), QRect(0,0,image.width(), padding);
//leftBecause there's 
 m_texture->update(image, (texturePos - QPoint(0,padding)), QRect(0,0,padding, image.height());
//right
 m_texture->update(image, (texturePos - QPoint(image.width(),padding)), QRect(image.width(),0,padding, image));
//bottom
...

Completely untested and arguably the corners would be slightly wrong, but I think it would work out cleaner and faster

Good point. I think corners would be okay (padding is just 1px).

zzag added a comment.Jun 16 2018, 9:01 PM

After thinking for a while, I'm not sure whether uploading each side would work out well. FWIW, pad() is cache friendly and decoration parts are usually small. So, that's not really clear whether uploading relevant parts would be faster. Also, to get correct corners one need to call m_texture->upload() 8 times.

zzag added a comment.Nov 26 2018, 10:03 AM

Another way to fix this problem is to render an untransformed window into an off-screen texture, then map it on the screen. The problem with this method is that we probably would need to get rid of different window quad types (e.g. WindowQuadShadow, WindowQuadDecoration, etc), which might break some effects, like the Screenshot. This would probably also fix T4441. We could maybe introduce different flags to control what parts of windows(e.g. shadows, etc) are rendered.

Difficult.

In D13575#366246, @zzag wrote:

Another way to fix this problem is to render an untransformed window into an off-screen texture, then map it on the screen. The problem with this method is that we probably would need to get rid of different window quad types (e.g. WindowQuadShadow, WindowQuadDecoration, etc), which might break some effects, like the Screenshot. This would probably also fix T4441. We could maybe introduce different flags to control what parts of windows(e.g. shadows, etc) are rendered.

Difficult.

I don't think we need to get rid of anything, but we would need to add a WindowQuadComposite type that would be a union of all the other quads.
The texture coordinates in these quads would be coordinates in the offscreen texture.
Effects that transform quads (wobbly windows, etc.) would need to be changed to split and transform only the composite quads.

zzag added a comment.Nov 26 2018, 2:17 PM

I don't think we need to get rid of anything, but we would need to add a WindowQuadComposite type that would be a union of all the other quads.
The texture coordinates in these quads would be coordinates in the offscreen texture.
Effects that transform quads (wobbly windows, etc.) would need to be changed to split and transform only the composite quads.

So, if I understand you correctly, we could have either WindowQuadShadow/WindowQuadContents/WindowQuadDecoration/WindowQuadSubSurface or WindowQuadComposite(which is the union of the previously mentioned quads), depending on what an effect would like to do, right?

In D13575#366344, @zzag wrote:

So, if I understand you correctly, we could have either WindowQuadShadow/WindowQuadContents/WindowQuadDecoration/WindowQuadSubSurface or WindowQuadComposite(which is the union of the previously mentioned quads), depending on what an effect would like to do, right?

I think all quad types need to be present in the quad list, but:

  • Effects are only allowed to transform WindowQuadComposite quads.
  • If the window or screen is transformed in any way (except for translations), or if the window has sub-surfaces, the WindowQuadComposite quads will be used to render the window. Otherwise the normal quads are used.

We could also add a flag to force the use of the composite quad type.

zzag abandoned this revision.Nov 26 2018, 5:36 PM

or if the window has sub-surfaces, the WindowQuadComposite quads will be used to render the window.

If we do that, then the Screenshot effect will be broken.

We could also add a flag to force the use of the composite quad type.

Hmm, this seems to be a good idea. Effects know better what they need.


Anyway, I'll abandon this revision in favor of that solution. Also, maybe we need more brainstorming.