Implement 8xSSAA and 16xSSAA in the SVG demo

This commit is contained in:
Patrick Walton 2017-12-11 18:56:26 -08:00
parent 1102965f6d
commit b8785a31db
6 changed files with 133 additions and 32 deletions

View File

@ -47,6 +47,8 @@
<option value="none" selected>None</option>
<option value="ssaa-2">2&times;SSAA</option>
<option value="ssaa-4">4&times;SSAA</option>
<option value="ssaa-8">8&times;SSAA</option>
<option value="ssaa-16">16&times;SSAA</option>
<option value="xcaa">XCAA</option>
</select>
</div>

View File

@ -55,6 +55,8 @@
<option value="none">None</option>
<option value="ssaa-2">2&times;SSAA</option>
<option value="ssaa-4" selected>4&times;SSAA</option>
<option value="ssaa-8">8&times;SSAA</option>
<option value="ssaa-16">16&times;SSAA</option>
<option value="xcaa">XCAA (experimental)</option>
</select>
</div>

View File

@ -26,10 +26,18 @@ export type GammaCorrectionMode = 'off' | 'on';
export type StemDarkeningMode = 'none' | 'dark';
export interface TileInfo {
size: glmatrix.vec2;
position: glmatrix.vec2;
}
export abstract class AntialiasingStrategy {
// The type of direct rendering that should occur, if any.
abstract readonly directRenderingMode: DirectRenderingMode;
// How many rendering passes this AA strategy requires.
abstract readonly passCount: number;
// Prepares any OpenGL data. This is only called on startup and canvas resize.
init(renderer: Renderer): void {
this.setFramebufferSize(renderer);
@ -70,12 +78,20 @@ export abstract class AntialiasingStrategy {
// Called after antialiasing.
//
// This usually blits to the real framebuffer.
abstract resolve(renderer: Renderer): void;
abstract resolve(pass: number, renderer: Renderer): void;
worldTransformForPass(renderer: Renderer, pass: number): glmatrix.mat4 {
return glmatrix.mat4.create();
}
}
export class NoAAStrategy extends AntialiasingStrategy {
framebufferSize: glmatrix.vec2;
get passCount(): number {
return 1;
}
private renderTargetColorTextures: WebGLTexture[];
private renderTargetDepthTextures: WebGLTexture[];
private renderTargetFramebuffers: WebGLFramebuffer[];
@ -161,7 +177,7 @@ export class NoAAStrategy extends AntialiasingStrategy {
resolveAAForObject(renderer: Renderer): void {}
resolve(renderer: Renderer): void {}
resolve(pass: number, renderer: Renderer): void {}
get directRenderingMode(): DirectRenderingMode {
return 'color';

View File

@ -12,6 +12,7 @@ import * as glmatrix from 'gl-matrix';
import * as _ from 'lodash';
import {AntialiasingStrategy, AntialiasingStrategyName, GammaCorrectionMode} from './aa-strategy';
import {TileInfo} from './aa-strategy';
import {NoAAStrategy, StemDarkeningMode, SubpixelAAType} from './aa-strategy';
import {AAOptions} from './app-controller';
import PathfinderBufferTexture from "./buffer-texture";
@ -150,6 +151,8 @@ export abstract class Renderer {
// Draw "scenery" (used in the 3D view).
this.drawSceneryIfNecessary();
const passCount = antialiasingStrategy.passCount;
for (let pass = 0; pass < passCount; pass++) {
if (antialiasingStrategy.directRenderingMode !== 'none')
antialiasingStrategy.prepareForDirectRendering(this);
@ -166,21 +169,23 @@ export abstract class Renderer {
// Clear.
this.clearForDirectRendering(objectIndex);
this.directlyRenderObject(objectIndex);
this.directlyRenderObject(pass, objectIndex);
}
antialiasingStrategy.resolveAAForObject(this, objectIndex);
}
antialiasingStrategy.resolve(pass, this);
}
// End the timer, and start a new one.
// FIXME(pcwalton): Removed this for multipass; get it split out again somehow.
if (this.timerQueryPollInterval == null) {
renderContext.timerQueryExt.endQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT);
renderContext.timerQueryExt.beginQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT,
renderContext.compositingTimerQuery);
}
antialiasingStrategy.resolve(this);
// Draw the glyphs with the resolved atlas to the default framebuffer.
this.compositeIfNecessary();
@ -219,13 +224,27 @@ export abstract class Renderer {
this.destAllocatedSize[1]);
}
setTransformAndTexScaleUniformsForDest(uniforms: UniformMap): void {
setTransformAndTexScaleUniformsForDest(uniforms: UniformMap, tileInfo?: TileInfo): void {
const renderContext = this.renderContext;
const usedSize = this.usedSizeFactor;
let tileSize, tilePosition;
if (tileInfo == null) {
tileSize = glmatrix.vec2.clone([1.0, 1.0]);
tilePosition = glmatrix.vec2.create();
} else {
tileSize = tileInfo.size;
tilePosition = tileInfo.position;
}
const transform = glmatrix.mat4.create();
glmatrix.mat4.fromTranslation(transform, [-1.0, -1.0, 0.0]);
glmatrix.mat4.fromTranslation(transform, [
-1.0 + tilePosition[0] / tileSize[0] * 2.0,
-1.0 + tilePosition[1] / tileSize[1] * 2.0,
0.0,
]);
glmatrix.mat4.scale(transform, transform, [2.0 * usedSize[0], 2.0 * usedSize[1], 1.0]);
glmatrix.mat4.scale(transform, transform, [1.0 / tileSize[0], 1.0 / tileSize[1], 1.0]);
renderContext.gl.uniformMatrix4fv(uniforms.uTransform, false, transform);
renderContext.gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]);
@ -240,8 +259,14 @@ export abstract class Renderer {
gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]);
}
setTransformUniform(uniforms: UniformMap, objectIndex: number): void {
const transform = glmatrix.mat4.clone(this.worldTransform);
setTransformUniform(uniforms: UniformMap, pass: number, objectIndex: number): void {
let transform;
if (this.antialiasingStrategy == null)
transform = glmatrix.mat4.create();
else
transform = this.antialiasingStrategy.worldTransformForPass(this, pass);
glmatrix.mat4.mul(transform, transform, this.worldTransform);
glmatrix.mat4.mul(transform, transform, this.getModelviewTransform(objectIndex));
this.renderContext.gl.uniformMatrix4fv(uniforms.uTransform, false, transform);
}
@ -424,7 +449,7 @@ export abstract class Renderer {
};
}
private directlyRenderObject(objectIndex: number): void {
private directlyRenderObject(pass: number, objectIndex: number): void {
if (this.meshes == null || this.meshData == null)
return;
@ -462,7 +487,7 @@ export abstract class Renderer {
this.initImplicitCoverInteriorVAO(objectIndex, instanceRange);
// Draw direct interior parts.
this.setTransformUniform(directInteriorProgram.uniforms, objectIndex);
this.setTransformUniform(directInteriorProgram.uniforms, pass, objectIndex);
this.setFramebufferSizeUniform(directInteriorProgram.uniforms);
this.setHintsUniform(directInteriorProgram.uniforms);
this.setPathColorsUniform(objectIndex, directInteriorProgram.uniforms, 0);
@ -507,7 +532,7 @@ export abstract class Renderer {
this.initImplicitCoverCurveVAO(objectIndex, instanceRange);
// Draw direct curve parts.
this.setTransformUniform(directCurveProgram.uniforms, objectIndex);
this.setTransformUniform(directCurveProgram.uniforms, pass, objectIndex);
this.setFramebufferSizeUniform(directCurveProgram.uniforms);
this.setHintsUniform(directCurveProgram.uniforms);
this.setPathColorsUniform(objectIndex, directCurveProgram.uniforms, 0);

View File

@ -10,7 +10,7 @@
import * as glmatrix from 'gl-matrix';
import {AntialiasingStrategy, DirectRenderingMode, SubpixelAAType} from './aa-strategy';
import {AntialiasingStrategy, DirectRenderingMode, SubpixelAAType, TileInfo} from './aa-strategy';
import {createFramebuffer, createFramebufferColorTexture} from './gl-utils';
import {createFramebufferDepthTexture, setTextureParameters} from './gl-utils';
import {Renderer} from './renderer';
@ -18,6 +18,16 @@ import {unwrapNull} from './utils';
import {DemoView} from './view';
export default class SSAAStrategy extends AntialiasingStrategy {
get passCount(): number {
switch (this.level) {
case 16:
return 4;
case 8:
return 2;
}
return 1;
}
private level: number;
private subpixelAA: SubpixelAAType;
@ -159,7 +169,7 @@ export default class SSAAStrategy extends AntialiasingStrategy {
resolveAAForObject(renderer: Renderer): void {}
resolve(renderer: Renderer): void {
resolve(pass: number, renderer: Renderer): void {
const renderContext = renderer.renderContext;
const gl = renderContext.gl;
@ -184,11 +194,35 @@ export default class SSAAStrategy extends AntialiasingStrategy {
gl.uniform2i(resolveProgram.uniforms.uSourceDimensions,
this.supersampledFramebufferSize[0],
this.supersampledFramebufferSize[1]);
renderer.setTransformAndTexScaleUniformsForDest(resolveProgram.uniforms);
const tileInfo = this.tileInfoForPass(pass);
renderer.setTransformAndTexScaleUniformsForDest(resolveProgram.uniforms, tileInfo);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
}
worldTransformForPass(renderer: Renderer, pass: number): glmatrix.mat4 {
const tileInfo = this.tileInfoForPass(pass);
const usedSize = renderer.destUsedSize;
const transform = glmatrix.mat4.create();
glmatrix.mat4.fromTranslation(transform, [-1.0, -1.0, 1.0]);
glmatrix.mat4.scale(transform, transform, [tileInfo.size[0], tileInfo.size[1], 1.0]);
glmatrix.mat4.translate(transform, transform, [
-tileInfo.position[0] / tileInfo.size[0] * 2.0,
-tileInfo.position[1] / tileInfo.size[1] * 2.0,
0.0,
]);
glmatrix.mat4.translate(transform, transform, [1.0, 1.0, 1.0]);
return transform;
}
private tileInfoForPass(pass: number): TileInfo {
const tileSize = this.tileSize;
return {
position: glmatrix.vec2.clone([pass % tileSize[0], Math.floor(pass / tileSize[0])]),
size: tileSize,
};
}
get directRenderingMode(): DirectRenderingMode {
return 'color';
}
@ -197,6 +231,16 @@ export default class SSAAStrategy extends AntialiasingStrategy {
return glmatrix.vec2.clone([this.subpixelAA !== 'none' ? 3 : 2, this.level === 2 ? 1 : 2]);
}
private get tileSize(): glmatrix.vec2 {
switch (this.level) {
case 16:
return glmatrix.vec2.clone([2.0, 2.0]);
case 8:
return glmatrix.vec2.clone([2.0, 1.0]);
}
return glmatrix.vec2.clone([1.0, 1.0]);
}
private usedSupersampledFramebufferSize(renderer: Renderer): glmatrix.vec2 {
const result = glmatrix.vec2.create();
glmatrix.vec2.mul(result, renderer.destUsedSize, this.supersampleScale);

View File

@ -36,6 +36,10 @@ const DIRECTIONS: Direction[] = ['upper', 'lower'];
export abstract class XCAAStrategy extends AntialiasingStrategy {
abstract readonly directRenderingMode: DirectRenderingMode;
get passCount(): number {
return 1;
}
protected abstract get usesDilationTransforms(): boolean;
protected pathBoundsBufferTexture: PathfinderBufferTexture;
@ -180,7 +184,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
compositingOperation.composite(renderer, objectIndex, this.renderTargetColorTextures);
}
resolve(renderer: Renderer): void {}
resolve(pass: number, renderer: Renderer): void {}
get transform(): glmatrix.mat4 {
return glmatrix.mat4.create();
@ -230,7 +234,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
if (this.usesDilationTransforms)
renderer.setTransformSTUniform(uniforms, 0);
else
renderer.setTransformUniform(uniforms, 0);
renderer.setTransformUniform(uniforms, 0, 0);
gl.uniform2i(uniforms.uFramebufferSize,
this.supersampledFramebufferSize[0],
@ -1134,6 +1138,10 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
return 'none';
}
get passCount(): number {
return 1;
}
constructor(level: number, subpixelAA: SubpixelAAType) {
this.mcaaStrategy = new MCAAMonochromeStrategy(level, subpixelAA);
this.ecaaStrategy = new ECAAMonochromeStrategy(level, subpixelAA);
@ -1182,8 +1190,12 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
this.getAppropriateStrategy(renderer).resolveAAForObject(renderer, objectIndex);
}
resolve(renderer: Renderer): void {
this.getAppropriateStrategy(renderer).resolve(renderer);
resolve(pass: number, renderer: Renderer): void {
this.getAppropriateStrategy(renderer).resolve(pass, renderer);
}
worldTransformForPass(renderer: Renderer, pass: number): glmatrix.mat4 {
return glmatrix.mat4.create();
}
private getAppropriateStrategy(renderer: Renderer): AntialiasingStrategy {