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:
parent
acf2e0be00
commit
82d2f076d7
|
@ -37,6 +37,13 @@
|
||||||
<option value="ecaa" selected>ECAA</option>
|
<option value="ecaa" selected>ECAA</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</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>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-arrow-box"></div>
|
<div class="pf-arrow-box"></div>
|
||||||
|
|
|
@ -117,10 +117,12 @@ class ThreeDView extends PathfinderDemoView {
|
||||||
this.pathTransformBufferTexture.upload(this.gl, pathTransforms);
|
this.pathTransformBufferTexture.upload(this.gl, pathTransforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number):
|
protected createAAStrategy(aaType: AntialiasingStrategyName,
|
||||||
|
aaLevel: number,
|
||||||
|
subpixelAA: boolean):
|
||||||
AntialiasingStrategy {
|
AntialiasingStrategy {
|
||||||
if (aaType != 'ecaa')
|
if (aaType != 'ecaa')
|
||||||
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel);
|
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel, subpixelAA);
|
||||||
throw new PathfinderError("Unsupported antialiasing type!");
|
throw new PathfinderError("Unsupported antialiasing type!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ export abstract class AntialiasingStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NoAAStrategy extends AntialiasingStrategy {
|
export class NoAAStrategy extends AntialiasingStrategy {
|
||||||
constructor(level: number) {
|
constructor(level: number, subpixelAA: boolean) {
|
||||||
super();
|
super();
|
||||||
this.framebufferSize = glmatrix.vec2.create();
|
this.framebufferSize = glmatrix.vec2.create();
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,11 @@ export abstract class DemoAppController<View extends PathfinderDemoView> extends
|
||||||
});
|
});
|
||||||
|
|
||||||
this.aaLevelSelect = document.getElementById('pf-aa-level-select') as HTMLSelectElement;
|
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);
|
this.aaLevelSelect.addEventListener('change', () => this.updateAALevel(), false);
|
||||||
|
if (this.subpixelAASwitch != null)
|
||||||
|
this.subpixelAASwitch.addEventListener('change', () => this.updateAALevel(), false);
|
||||||
this.updateAALevel();
|
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 aaValues = unwrapNull(/^([a-z-]+)(?:-([0-9]+))?$/.exec(selectedOption.value));
|
||||||
const aaType = aaValues[1] as AntialiasingStrategyName;
|
const aaType = aaValues[1] as AntialiasingStrategyName;
|
||||||
const aaLevel = aaValues[2] === "" ? 1 : parseInt(aaValues[2]);
|
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) {
|
protected loadFile(event: Event) {
|
||||||
|
@ -151,6 +156,8 @@ export abstract class DemoAppController<View extends PathfinderDemoView> extends
|
||||||
protected shaderSources: ShaderMap<ShaderProgramSource> | null;
|
protected shaderSources: ShaderMap<ShaderProgramSource> | null;
|
||||||
|
|
||||||
private aaLevelSelect: HTMLSelectElement;
|
private aaLevelSelect: HTMLSelectElement;
|
||||||
|
private subpixelAASwitch: HTMLInputElement | null;
|
||||||
|
|
||||||
private settingsCard: HTMLElement;
|
private settingsCard: HTMLElement;
|
||||||
private settingsButton: HTMLButtonElement;
|
private settingsButton: HTMLButtonElement;
|
||||||
private settingsCloseButton: HTMLButtonElement;
|
private settingsCloseButton: HTMLButtonElement;
|
||||||
|
|
|
@ -26,7 +26,7 @@ interface UpperAndLower<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class ECAAStrategy extends AntialiasingStrategy {
|
export abstract class ECAAStrategy extends AntialiasingStrategy {
|
||||||
constructor(level: number) {
|
constructor(level: number, subpixelAA: boolean) {
|
||||||
super();
|
super();
|
||||||
this.framebufferSize = glmatrix.vec2.create();
|
this.framebufferSize = glmatrix.vec2.create();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
||||||
'directInterior',
|
'directInterior',
|
||||||
'direct3DCurve',
|
'direct3DCurve',
|
||||||
'direct3DInterior',
|
'direct3DInterior',
|
||||||
|
'ssaaSubpixelResolve',
|
||||||
'ecaaEdgeDetect',
|
'ecaaEdgeDetect',
|
||||||
'ecaaCover',
|
'ecaaCover',
|
||||||
'ecaaLine',
|
'ecaaLine',
|
||||||
|
@ -54,6 +55,10 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
||||||
vertex: "/glsl/gles2/direct-3d-interior.vs.glsl",
|
vertex: "/glsl/gles2/direct-3d-interior.vs.glsl",
|
||||||
fragment: "/glsl/gles2/direct-interior.fs.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: {
|
ecaaEdgeDetect: {
|
||||||
vertex: "/glsl/gles2/ecaa-edge-detect.vs.glsl",
|
vertex: "/glsl/gles2/ecaa-edge-detect.vs.glsl",
|
||||||
fragment: "/glsl/gles2/ecaa-edge-detect.fs.glsl",
|
fragment: "/glsl/gles2/ecaa-edge-detect.fs.glsl",
|
||||||
|
@ -90,6 +95,7 @@ export interface ShaderMap<T> {
|
||||||
directInterior: T;
|
directInterior: T;
|
||||||
direct3DCurve: T;
|
direct3DCurve: T;
|
||||||
direct3DInterior: T;
|
direct3DInterior: T;
|
||||||
|
ssaaSubpixelResolve: T;
|
||||||
ecaaEdgeDetect: T;
|
ecaaEdgeDetect: T;
|
||||||
ecaaCover: T;
|
ecaaCover: T;
|
||||||
ecaaLine: T;
|
ecaaLine: T;
|
||||||
|
|
|
@ -16,9 +16,10 @@ import {unwrapNull} from './utils';
|
||||||
import {PathfinderDemoView} from './view';
|
import {PathfinderDemoView} from './view';
|
||||||
|
|
||||||
export default class SSAAStrategy extends AntialiasingStrategy {
|
export default class SSAAStrategy extends AntialiasingStrategy {
|
||||||
constructor(level: number) {
|
constructor(level: number, subpixelAA: boolean) {
|
||||||
super();
|
super();
|
||||||
this.level = level;
|
this.level = level;
|
||||||
|
this.subpixelAA = subpixelAA;
|
||||||
this.destFramebufferSize = glmatrix.vec2.create();
|
this.destFramebufferSize = glmatrix.vec2.create();
|
||||||
this.supersampledFramebufferSize = 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);
|
view.gl.disable(view.gl.DEPTH_TEST);
|
||||||
|
|
||||||
// Set up the blit program VAO.
|
// Set up the blit program VAO.
|
||||||
const blitProgram = view.shaderPrograms.blit;
|
let resolveProgram;
|
||||||
view.gl.useProgram(blitProgram.program);
|
if (this.subpixelAA)
|
||||||
view.initQuadVAO(blitProgram.attributes);
|
resolveProgram = view.shaderPrograms.ssaaSubpixelResolve;
|
||||||
|
else
|
||||||
|
resolveProgram = view.shaderPrograms.blit;
|
||||||
|
view.gl.useProgram(resolveProgram.program);
|
||||||
|
view.initQuadVAO(resolveProgram.attributes);
|
||||||
|
|
||||||
// Resolve framebuffer.
|
// Resolve framebuffer.
|
||||||
view.gl.activeTexture(view.gl.TEXTURE0);
|
view.gl.activeTexture(view.gl.TEXTURE0);
|
||||||
view.gl.bindTexture(view.gl.TEXTURE_2D, this.supersampledColorTexture);
|
view.gl.bindTexture(view.gl.TEXTURE_2D, this.supersampledColorTexture);
|
||||||
view.gl.uniform1i(blitProgram.uniforms.uSource, 0);
|
view.gl.uniform1i(resolveProgram.uniforms.uSource, 0);
|
||||||
view.setTransformAndTexScaleUniformsForDest(blitProgram.uniforms);
|
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.bindBuffer(view.gl.ELEMENT_ARRAY_BUFFER, view.quadElementsBuffer);
|
||||||
view.gl.drawElements(view.gl.TRIANGLES, 6, view.gl.UNSIGNED_BYTE, 0);
|
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 {
|
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 {
|
private usedSupersampledFramebufferSize(view: PathfinderDemoView): glmatrix.vec2 {
|
||||||
|
@ -116,6 +124,8 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
private level: number;
|
private level: number;
|
||||||
|
private subpixelAA: boolean;
|
||||||
|
|
||||||
private destFramebufferSize: glmatrix.vec2;
|
private destFramebufferSize: glmatrix.vec2;
|
||||||
private supersampledFramebufferSize: glmatrix.vec2;
|
private supersampledFramebufferSize: glmatrix.vec2;
|
||||||
private supersampledColorTexture: WebGLTexture;
|
private supersampledColorTexture: WebGLTexture;
|
||||||
|
|
|
@ -212,9 +212,11 @@ class SVGDemoView extends PathfinderDemoView {
|
||||||
this.pathTransformBufferTexture.upload(this.gl, pathTransforms);
|
this.pathTransformBufferTexture.upload(this.gl, pathTransforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number):
|
protected createAAStrategy(aaType: AntialiasingStrategyName,
|
||||||
|
aaLevel: number,
|
||||||
|
subpixelAA: boolean):
|
||||||
AntialiasingStrategy {
|
AntialiasingStrategy {
|
||||||
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel);
|
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel, subpixelAA);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected compositeIfNecessary(): void {}
|
protected compositeIfNecessary(): void {}
|
||||||
|
|
|
@ -73,7 +73,7 @@ const B_POSITION_SIZE: number = 8;
|
||||||
|
|
||||||
const B_PATH_INDEX_SIZE: number = 2;
|
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 {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
@ -477,9 +477,11 @@ class TextDemoView extends MonochromePathfinderView {
|
||||||
return this.appController.atlas.usedSize;
|
return this.appController.atlas.usedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number):
|
protected createAAStrategy(aaType: AntialiasingStrategyName,
|
||||||
|
aaLevel: number,
|
||||||
|
subpixelAA: boolean):
|
||||||
AntialiasingStrategy {
|
AntialiasingStrategy {
|
||||||
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel);
|
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel, subpixelAA);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected updateTimings(timings: Timings) {
|
protected updateTimings(timings: Timings) {
|
||||||
|
|
|
@ -107,12 +107,14 @@ export abstract class PathfinderDemoView extends PathfinderView {
|
||||||
this.pathTransformBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathTransform');
|
this.pathTransformBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathTransform');
|
||||||
this.pathColorsBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathColors');
|
this.pathColorsBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathColors');
|
||||||
|
|
||||||
this.antialiasingStrategy = new NoAAStrategy(0);
|
this.antialiasingStrategy = new NoAAStrategy(0, false);
|
||||||
this.antialiasingStrategy.init(this);
|
this.antialiasingStrategy.init(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
setAntialiasingOptions(aaType: AntialiasingStrategyName, aaLevel: number) {
|
setAntialiasingOptions(aaType: AntialiasingStrategyName,
|
||||||
this.antialiasingStrategy = this.createAAStrategy(aaType, aaLevel);
|
aaLevel: number,
|
||||||
|
subpixelAA: boolean) {
|
||||||
|
this.antialiasingStrategy = this.createAAStrategy(aaType, aaLevel, subpixelAA);
|
||||||
|
|
||||||
let canvas = this.canvas;
|
let canvas = this.canvas;
|
||||||
this.antialiasingStrategy.init(this);
|
this.antialiasingStrategy.init(this);
|
||||||
|
@ -409,7 +411,9 @@ export abstract class PathfinderDemoView extends PathfinderView {
|
||||||
this.gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]);
|
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;
|
AntialiasingStrategy;
|
||||||
|
|
||||||
protected abstract compositeIfNecessary(): void;
|
protected abstract compositeIfNecessary(): void;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue