Commit 3f647b1b by Jamie Madill Committed by Commit Bot

Vulkan: Improve Bresenham line emulation.

Clamps the vertex position to the subpixel grid before interpolation. This will give more correct results on systems that have less than 8 bits of subpixel accuracy. Also uses a more accurate formulation for the emulation filter in the fragment shader using dfdx and dfdy. Fixes line raster CTS tests on SwiftShader. Still does not produce spec conformant lines. Updates the public docs to indicate this. Bug: angleproject:2830 Change-Id: Ib9a268df3e7d986bd2b1348be664389fe8fc0ef2 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1826598 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent b9b1bae4
...@@ -504,6 +504,9 @@ struct ShBuiltInResources ...@@ -504,6 +504,9 @@ struct ShBuiltInResources
int MaxGeometryShaderStorageBlocks; int MaxGeometryShaderStorageBlocks;
int MaxGeometryShaderInvocations; int MaxGeometryShaderInvocations;
int MaxGeometryImageUniforms; int MaxGeometryImageUniforms;
// Subpixel bits used in rasterization.
int SubPixelBits;
}; };
// //
......
...@@ -253,6 +253,8 @@ void InitBuiltInResources(ShBuiltInResources *resources) ...@@ -253,6 +253,8 @@ void InitBuiltInResources(ShBuiltInResources *resources)
resources->MaxGeometryShaderStorageBlocks = 0; resources->MaxGeometryShaderStorageBlocks = 0;
resources->MaxGeometryShaderInvocations = 32; resources->MaxGeometryShaderInvocations = 32;
resources->MaxGeometryImageUniforms = 0; resources->MaxGeometryImageUniforms = 0;
resources->SubPixelBits = 8;
} }
// //
......
...@@ -73,6 +73,23 @@ TIntermTyped *CreateBuiltInFunctionCallNode(const char *name, ...@@ -73,6 +73,23 @@ TIntermTyped *CreateBuiltInFunctionCallNode(const char *name,
const TSymbolTable &symbolTable, const TSymbolTable &symbolTable,
int shaderVersion); int shaderVersion);
inline void GetSwizzleIndex(TVector<int> *indexOut) {}
template <typename T, typename... ArgsT>
void GetSwizzleIndex(TVector<int> *indexOut, T arg, ArgsT... args)
{
indexOut->push_back(arg);
GetSwizzleIndex(indexOut, args...);
}
template <typename... ArgsT>
TIntermSwizzle *CreateSwizzle(TIntermTyped *reference, ArgsT... args)
{
TVector<int> swizzleIndex;
GetSwizzleIndex(&swizzleIndex, args...);
return new TIntermSwizzle(reference, swizzleIndex);
}
} // namespace sh } // namespace sh
#endif // COMPILER_TRANSLATOR_INTERMNODEUTIL_H_ #endif // COMPILER_TRANSLATOR_INTERMNODEUTIL_H_
...@@ -187,6 +187,9 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const State &state) ...@@ -187,6 +187,9 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const State &state)
mResources.MaxGeometryShaderStorageBlocks = caps.maxShaderStorageBlocks[ShaderType::Geometry]; mResources.MaxGeometryShaderStorageBlocks = caps.maxShaderStorageBlocks[ShaderType::Geometry];
mResources.MaxGeometryShaderInvocations = caps.maxGeometryShaderInvocations; mResources.MaxGeometryShaderInvocations = caps.maxGeometryShaderInvocations;
mResources.MaxGeometryImageUniforms = caps.maxShaderImageUniforms[ShaderType::Geometry]; mResources.MaxGeometryImageUniforms = caps.maxShaderImageUniforms[ShaderType::Geometry];
// Subpixel bits.
mResources.SubPixelBits = static_cast<int>(caps.subPixelBits);
} }
Compiler::~Compiler() Compiler::~Compiler()
......
...@@ -23,22 +23,29 @@ more info. See the below diagram for an illustration of the diamond rule: ...@@ -23,22 +23,29 @@ more info. See the below diagram for an illustration of the diamond rule:
![OpenGL Diamond Rule Example][DiamondRule] ![OpenGL Diamond Rule Example][DiamondRule]
We can implement the OpenGL test by checking the intersection of the line and the medial axes of the The diamond rule can be implemented in the fragment shader by computing the
pixel `p`. If the length of the line segment between intersections `p` and the point center is intersection between the line segment and the grid that crosses the pixel
greater than a half-pixel for all possible `p` then the pixel is not on the segment. To solve for center. If the distance between an intersection and the pixel center is less
`p` we use the pixel center `a` given by `gl_FragCoord` and the projection of `a` onto the line than half a pixel then the line enters and exits the diamond. `f` is the pixel
segment `b` given by the interpolated `gl_Position`. Since `gl_Position` is not available in the center in the diagram. The green circle indicates a diamond exit and the red
fragment shader we must add an internal position varying when drawing lines. circles indicate intersections that do not exit the diamond. We detect
non-Bresenham fragments when both intersections are outside the diamond.
The full code derivation is omitted for brevity. It reduces to the following shader snippet:
The full code derivation is omitted for brevity. It produces the following
```vec2 position = PositionVarying.xy / PositionVarying.w; fragment shader patch implementation:
vec2 b = ((position * 0.5) + 0.5) * gl_Viewport.zw + gl_Viewport.xy;
vec2 ba = abs(b - gl_FragCoord.xy); ```
vec2 ba2 = 2.0 * (ba * ba); vec2 p = (((((ANGLEPosition.xy) * 0.5) + 0.5) * viewport.zw) + viewport.xy);
vec2 bp = ba2 + ba2.yx - ba; vec2 d = dFdx(p) + dFdy(p);
if (bp.x > epsilon && bp.y > epsilon) vec2 f = gl_FragCoord.xy;
discard; vec2 p_ = p.yx;
vec2 d_ = d.yx;
vec2 f_ = f.yx;
vec2 i = abs(p - f + (d/d_) * (f_ - p_));
if (i.x > 0.500001 && i.y > 0.500001)
discard;
``` ```
Note that we must also pass the viewport size as an internal uniform. We use a small epsilon value Note that we must also pass the viewport size as an internal uniform. We use a small epsilon value
...@@ -46,8 +53,22 @@ to correct for cases when the line segment is perfectly parallel or perpendicula ...@@ -46,8 +53,22 @@ to correct for cases when the line segment is perfectly parallel or perpendicula
code please see [TranslatorVulkan.cpp][TranslatorVulkan.cpp] under code please see [TranslatorVulkan.cpp][TranslatorVulkan.cpp] under
`AddLineSegmentRasterizationEmulation`. `AddLineSegmentRasterizationEmulation`.
## Limitations
Although this emulation passes all current GLES CTS tests it is not guaranteed
to produce conformant lines. In particular lines that very nearly intersect
the junction of four pixels render with holes. For example:
![Holes in the emulated Bresenham line][Holes]
Therefore for a complete implementation we require the Bresenham line
rasterization feature from
[VK_EXT_line_rasterization][VK_EXT_line_rasterization].
[Bresenham]: https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm [Bresenham]: https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
[DiamondRule]: img/LineRasterPixelExample.png [DiamondRule]: img/LineRasterPixelExample.png
[Holes]: img/LineRasterHoles.jpg
[TranslatorVulkan.cpp]: https://chromium.googlesource.com/angle/angle/+/refs/heads/master/src/compiler/translator/TranslatorVulkan.cpp [TranslatorVulkan.cpp]: https://chromium.googlesource.com/angle/angle/+/refs/heads/master/src/compiler/translator/TranslatorVulkan.cpp
[VK_EXT_line_rasterization]: https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VK_EXT_line_rasterization.html
[VulkanLineRaster]: https://www.khronos.org/registry/vulkan/specs/1.1/html/chap24.html#primsrast-lines-basic [VulkanLineRaster]: https://www.khronos.org/registry/vulkan/specs/1.1/html/chap24.html#primsrast-lines-basic
[VulkanVsGLLineRaster]: img/LineRasterComparison.gif [VulkanVsGLLineRaster]: img/LineRasterComparison.gif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment