Add basic subpixel AA support for SSAA.

No LCD filter is implemented yet, so the color fringing is currently fairly extreme.
This commit is contained in:
Patrick Walton 2017-09-06 16:32:11 -07:00
parent acf2e0be00
commit 82d2f076d7
12 changed files with 109 additions and 21 deletions

View File

@ -37,6 +37,13 @@
<option value="ecaa" selected>ECAA</option>
</select>
</div>
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" value="" type="checkbox"
id="pf-subpixel-aa">
Subpixel AA
</label>
</div>
</form>
</div>
<div class="pf-arrow-box"></div>

View File

@ -117,10 +117,12 @@ class ThreeDView extends PathfinderDemoView {
this.pathTransformBufferTexture.upload(this.gl, pathTransforms);
}
protected createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number):
protected createAAStrategy(aaType: AntialiasingStrategyName,
aaLevel: number,
subpixelAA: boolean):
AntialiasingStrategy {
if (aaType != 'ecaa')
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel);
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel, subpixelAA);
throw new PathfinderError("Unsupported antialiasing type!");
}

View File

@ -44,7 +44,7 @@ export abstract class AntialiasingStrategy {
}
export class NoAAStrategy extends AntialiasingStrategy {
constructor(level: number) {
constructor(level: number, subpixelAA: boolean) {
super();
this.framebufferSize = glmatrix.vec2.create();
}

View File

@ -93,7 +93,11 @@ export abstract class DemoAppController<View extends PathfinderDemoView> extends
});
this.aaLevelSelect = document.getElementById('pf-aa-level-select') as HTMLSelectElement;
this.subpixelAASwitch =
document.getElementById('pf-subpixel-aa') as HTMLInputElement | null;
this.aaLevelSelect.addEventListener('change', () => this.updateAALevel(), false);
if (this.subpixelAASwitch != null)
this.subpixelAASwitch.addEventListener('change', () => this.updateAALevel(), false);
this.updateAALevel();
}
@ -102,7 +106,8 @@ export abstract class DemoAppController<View extends PathfinderDemoView> extends
const aaValues = unwrapNull(/^([a-z-]+)(?:-([0-9]+))?$/.exec(selectedOption.value));
const aaType = aaValues[1] as AntialiasingStrategyName;
const aaLevel = aaValues[2] === "" ? 1 : parseInt(aaValues[2]);
this.view.then(view => view.setAntialiasingOptions(aaType, aaLevel));
const subpixelAA = this.subpixelAASwitch == null ? false : this.subpixelAASwitch.checked;
this.view.then(view => view.setAntialiasingOptions(aaType, aaLevel, subpixelAA));
}
protected loadFile(event: Event) {
@ -151,6 +156,8 @@ export abstract class DemoAppController<View extends PathfinderDemoView> extends
protected shaderSources: ShaderMap<ShaderProgramSource> | null;
private aaLevelSelect: HTMLSelectElement;
private subpixelAASwitch: HTMLInputElement | null;
private settingsCard: HTMLElement;
private settingsButton: HTMLButtonElement;
private settingsCloseButton: HTMLButtonElement;

View File

@ -26,7 +26,7 @@ interface UpperAndLower<T> {
}
export abstract class ECAAStrategy extends AntialiasingStrategy {
constructor(level: number) {
constructor(level: number, subpixelAA: boolean) {
super();
this.framebufferSize = glmatrix.vec2.create();
}

View File

@ -24,6 +24,7 @@ export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
'directInterior',
'direct3DCurve',
'direct3DInterior',
'ssaaSubpixelResolve',
'ecaaEdgeDetect',
'ecaaCover',
'ecaaLine',
@ -54,6 +55,10 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
vertex: "/glsl/gles2/direct-3d-interior.vs.glsl",
fragment: "/glsl/gles2/direct-interior.fs.glsl",
},
ssaaSubpixelResolve: {
vertex: "/glsl/gles2/ssaa-subpixel-resolve.vs.glsl",
fragment: "/glsl/gles2/ssaa-subpixel-resolve.fs.glsl",
},
ecaaEdgeDetect: {
vertex: "/glsl/gles2/ecaa-edge-detect.vs.glsl",
fragment: "/glsl/gles2/ecaa-edge-detect.fs.glsl",
@ -90,6 +95,7 @@ export interface ShaderMap<T> {
directInterior: T;
direct3DCurve: T;
direct3DInterior: T;
ssaaSubpixelResolve: T;
ecaaEdgeDetect: T;
ecaaCover: T;
ecaaLine: T;

View File

@ -16,9 +16,10 @@ import {unwrapNull} from './utils';
import {PathfinderDemoView} from './view';
export default class SSAAStrategy extends AntialiasingStrategy {
constructor(level: number) {
constructor(level: number, subpixelAA: boolean) {
super();
this.level = level;
this.subpixelAA = subpixelAA;
this.destFramebufferSize = glmatrix.vec2.create();
this.supersampledFramebufferSize = glmatrix.vec2.create();
}
@ -88,15 +89,22 @@ export default class SSAAStrategy extends AntialiasingStrategy {
view.gl.disable(view.gl.DEPTH_TEST);
// Set up the blit program VAO.
const blitProgram = view.shaderPrograms.blit;
view.gl.useProgram(blitProgram.program);
view.initQuadVAO(blitProgram.attributes);
let resolveProgram;
if (this.subpixelAA)
resolveProgram = view.shaderPrograms.ssaaSubpixelResolve;
else
resolveProgram = view.shaderPrograms.blit;
view.gl.useProgram(resolveProgram.program);
view.initQuadVAO(resolveProgram.attributes);
// Resolve framebuffer.
view.gl.activeTexture(view.gl.TEXTURE0);
view.gl.bindTexture(view.gl.TEXTURE_2D, this.supersampledColorTexture);
view.gl.uniform1i(blitProgram.uniforms.uSource, 0);
view.setTransformAndTexScaleUniformsForDest(blitProgram.uniforms);
view.gl.uniform1i(resolveProgram.uniforms.uSource, 0);
view.gl.uniform2i(resolveProgram.uniforms.uSourceDimensions,
this.supersampledFramebufferSize[0],
this.supersampledFramebufferSize[1]);
view.setTransformAndTexScaleUniformsForDest(resolveProgram.uniforms);
view.gl.bindBuffer(view.gl.ELEMENT_ARRAY_BUFFER, view.quadElementsBuffer);
view.gl.drawElements(view.gl.TRIANGLES, 6, view.gl.UNSIGNED_BYTE, 0);
}
@ -106,7 +114,7 @@ export default class SSAAStrategy extends AntialiasingStrategy {
}
private get supersampleScale(): glmatrix.vec2 {
return glmatrix.vec2.fromValues(2, this.level == 2 ? 1 : 2);
return glmatrix.vec2.fromValues(this.subpixelAA ? 3 : 2, this.level == 2 ? 1 : 2);
}
private usedSupersampledFramebufferSize(view: PathfinderDemoView): glmatrix.vec2 {
@ -116,6 +124,8 @@ export default class SSAAStrategy extends AntialiasingStrategy {
}
private level: number;
private subpixelAA: boolean;
private destFramebufferSize: glmatrix.vec2;
private supersampledFramebufferSize: glmatrix.vec2;
private supersampledColorTexture: WebGLTexture;

View File

@ -212,9 +212,11 @@ class SVGDemoView extends PathfinderDemoView {
this.pathTransformBufferTexture.upload(this.gl, pathTransforms);
}
protected createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number):
protected createAAStrategy(aaType: AntialiasingStrategyName,
aaLevel: number,
subpixelAA: boolean):
AntialiasingStrategy {
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel);
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel, subpixelAA);
}
protected compositeIfNecessary(): void {}

View File

@ -73,7 +73,7 @@ const B_POSITION_SIZE: number = 8;
const B_PATH_INDEX_SIZE: number = 2;
const ATLAS_SIZE: glmatrix.vec2 = glmatrix.vec2.fromValues(3072, 3072);
const ATLAS_SIZE: glmatrix.vec2 = glmatrix.vec2.fromValues(2048, 4096);
declare global {
interface Window {
@ -477,9 +477,11 @@ class TextDemoView extends MonochromePathfinderView {
return this.appController.atlas.usedSize;
}
protected createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number):
protected createAAStrategy(aaType: AntialiasingStrategyName,
aaLevel: number,
subpixelAA: boolean):
AntialiasingStrategy {
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel);
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel, subpixelAA);
}
protected updateTimings(timings: Timings) {

View File

@ -107,12 +107,14 @@ export abstract class PathfinderDemoView extends PathfinderView {
this.pathTransformBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathTransform');
this.pathColorsBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathColors');
this.antialiasingStrategy = new NoAAStrategy(0);
this.antialiasingStrategy = new NoAAStrategy(0, false);
this.antialiasingStrategy.init(this);
}
setAntialiasingOptions(aaType: AntialiasingStrategyName, aaLevel: number) {
this.antialiasingStrategy = this.createAAStrategy(aaType, aaLevel);
setAntialiasingOptions(aaType: AntialiasingStrategyName,
aaLevel: number,
subpixelAA: boolean) {
this.antialiasingStrategy = this.createAAStrategy(aaType, aaLevel, subpixelAA);
let canvas = this.canvas;
this.antialiasingStrategy.init(this);
@ -409,7 +411,9 @@ export abstract class PathfinderDemoView extends PathfinderView {
this.gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]);
}
protected abstract createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number):
protected abstract createAAStrategy(aaType: AntialiasingStrategyName,
aaLevel: number,
subpixelAA: boolean):
AntialiasingStrategy;
protected abstract compositeIfNecessary(): void;

View File

@ -0,0 +1,24 @@
// pathfinder/shaders/gles2/ssaa-subpixel-resolve.fs.glsl
//
// Copyright (c) 2017 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision mediump float;
uniform sampler2D uSource;
uniform ivec2 uSourceDimensions;
varying vec2 vTexCoord;
void main() {
float onePixel = 1.0 / float(uSourceDimensions.x);
gl_FragColor = vec4(texture2D(uSource, vec2(vTexCoord.s - onePixel, vTexCoord.t)).r,
texture2D(uSource, vec2(vTexCoord.s, vTexCoord.t)).r,
texture2D(uSource, vec2(vTexCoord.s + onePixel, vTexCoord.t)).r,
1.0);
}

View File

@ -0,0 +1,24 @@
// pathfinder/shaders/gles2/ssaa-subpixel-resolve.vs.glsl
//
// Copyright (c) 2017 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision mediump float;
uniform mat4 uTransform;
uniform vec2 uTexScale;
attribute vec2 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
void main() {
gl_Position = uTransform * vec4(aPosition, 0.0, 1.0);
vTexCoord = aTexCoord * uTexScale;
}