• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2022 The Khronos Group Inc.
2//
3// SPDX-License-Identifier: CC-BY-4.0
4
5= VK_EXT_legacy_dithering
6:toc: left
7:refpage: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/
8:sectnums:
9
10This proposal regards layering OpenGL over Vulkan, and provides an efficient
11path to implement OpenGL dithering on Vulkan.
12
13== Problem Statement
14
15Dithering is an important technique necessary to remove color banding, which in
16itself is an artifact of low-frequency sampling (by our eyes) of a step
17function (jumps from one color value to another due to quantization).
18This technique is particularly useful to improve the visuals of gradients
19quantized over a low-precision format (for example
20`VK_FORMAT_R5G6B5_UNORM_PACK16`), or even the highest-precision formats when
21the two ends of the gradient are close in value (for example sky at late dusk).
22
23**Dithering is best done by the Vulkan application.**
24For example, an application rendering to a swapchain with `R5G6B5` format can
25render instead to an `R8G8B8A8` (or even `B10G11R11`) lazily-allocated image in
26one subpass, then apply dithering in a second subpass along with other
27necessary work such as color space transformations.
28
29In OpenGL and OpenGL ES, the `GL_DITHER` state is enabled by default and
30dithering is made the responsibility of the driver.
31However, the dithering algorithm itself is undefined, and explicitly allows "no
32dithering" as a possible algorithm.
33As such, some vendors do not provide dithering in OpenGL at all, while others
34do, especially on some tile-based hardware.
35Those that do provide dithering implement it differently, including using
36different dithering matrix sizes, or performing dithering at different times
37(e.g. fragment output vs render pass store operation).
38Most importantly, devices that apply dithering in OpenGL have specialized
39hardware to perform this efficiently.
40
41As far as OpenGL layering is concerned, no dithering is technically an
42acceptable algorithm.
43However, in practice, due to this state being on by default and implemented by
44a number of vendors, numerous Android applications have come to (accidentally
45or otherwise) rely on the visual improvements dithering brings.
46It is therefore necessary for an OpenGL layer over Vulkan to provide a
47dithering implementation.
48
49== Solution Space
50
51=== Emulation Through Per-Draw Dithering
52
53Dithering could be emulated by applying the Bayer matrix at the end of the
54fragment shader.
55This can potentially be constrained to low-bit formats to limit its effect on
56performance and shader size.
57
58Pros:
59
60- Easy to implement by adding code to the fragment shader during shader
61  compilation.
62
63Cons:
64
65- When enabled, the dithering cost is paid extra for each pixel that is
66  overdrawn.
67- As dithering is non-temporal per the OpenGL spec, overdraw with additive
68  blending can accentuate the dithering that is applied, making the image look
69  grainy.
70- Dithering alpha can create visual artifacts as the background is leaked into
71  an otherwise completely opaque shape when blending is enabled.
72  * Quantizing alpha in the shader itself can alleviate this.
73- The generated shader size is increased, with the usual caveats regarding
74  performance.
75
76=== Emulation Through Per-Subpass Dithering
77
78Dithering can also be applied at the end of the subpass, closely emulating what
79some hardware do.
80For this to work, a post-process subpass needs to be added that applies
81dithering.
82The original subpass needs to render to a lazily-allocated image with higher
83precision.
84
85Pros:
86
87- Performant when possible.
88- No issues with blending.
89
90Cons:
91
92- Costly on non-tiled-based hardware both in memory and performance.
93- Relatively complicated to code.
94- Currently, Vulkan provides no feedback to ensure this is done efficiently
95  (e.g. whether the tile-based Vulkan driver could successfully merge and
96   execute the two subpasses on the tile, without implicit splits such as due
97   to memory constraints).
98- The high and low precision versions of the attachment live on the tile memory
99  at the same time for the final subpass, increasing tile memory usage and
100  potentially degrading performance (if the tile size has to change because of
101  that).
102
103=== Exposing Dithering Hardware Through a Vulkan Extension
104
105For vendors that support dithering in hardware, exposing it in a Vulkan
106extension would enable the OpenGL layer to match the vendors' current OpenGL
107driver in behavior.
108
109Pros:
110
111- Trivial to use.
112- Efficient.
113
114Cons:
115
116- Hardware vendors may be planning on removing this feature.
117- The dithering algorithm is grossly underspecified in OpenGL, and vendors are
118  known to apply it incompletely or incorrectly in some situations.
119  A Vulkan extension would necessarily be almost as vague as the OpenGL spec,
120  which is not in the spirit of Vulkan.
121
122== Proposal
123
124Despite the caveats, a Vulkan extension represents the most efficient way
125currently to provide equivalent visuals in an OpenGL layer compared to the
126vendors' OpenGL implementations.
127Once the OpenGL layer replaces vendors' implementations, and once the hardware
128features are removed, an emulation path can be chosen for dithering.
129By that time, it is hoped that applications requiring implicit dithering are a
130relic of the past, and paying the extra cost on newer more efficient hardware
131would be negligible, or at least acceptable.
132
133=== Features
134
135[source,c]
136----
137typedef struct VkPhysicalDeviceLegacyDitheringFeaturesEXT {
138    VkStructureType    sType;
139    void*              pNext;
140    VkBool32           legacyDithering;
141} VkPhysicalDeviceLegacyDitheringFeaturesEXT;
142----
143
144- `legacyDithering` specifies that OpenGL dithering is available.
145
146=== Enabling Dithering
147
148Extending `VkSubpassDescriptionFlagBits`,
149`VK_SUBPASS_DESCRIPTION_ENABLE_LEGACY_DITHERING_BIT_EXT` will enable dithering
150for the subpass.
151Extending `VkRenderingFlagBits`, `VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT`
152does the same when using dynamic rendering.
153
154The Vulkan implementation is expected to apply dithering equivalently to the
155vendor's OpenGL driver.
156
157=== Limitations
158
159The dithering applied through the use of this extension is unspecified, and
160it is possible that the implementation performs no dithering at all for some
161formats.
162However, it will be equivalent to the vendor's OpenGL driver given equivalent
163OpenGL API calls.
164The following limitations thus apply to OpenGL as well.
165
166- Only certain formats may actually be dithered.
167- The details of the dithering algorithm are unknown.
168- Correctness of the dithering algorithm with respect to sRGB are not
169  guaranteed.
170
171**It is strongly recommended that Vulkan applications implement dithering on
172their own if needed.**
173This extension is intended only for use by OpenGL emulation layers.
174