Decouple antialiasing strategies from views in the demo

This commit is contained in:
Patrick Walton 2017-10-16 13:36:22 -07:00
parent d8713f214c
commit cc16158a91
8 changed files with 785 additions and 690 deletions

View File

@ -14,6 +14,7 @@
"@types/lodash": "^4.14.74",
"@types/node": "^8.0.28",
"@types/opentype.js": "0.0.0",
"@types/webgl-ext": "0.0.29",
"base64-js": "^1.2.1",
"bootstrap": "^4.0.0-beta",
"gl-matrix": "^2.4.0",

View File

@ -10,7 +10,7 @@
import * as glmatrix from 'gl-matrix';
import {DemoView} from './view';
import {DemoView, Renderer} from './view';
export type AntialiasingStrategyName = 'none' | 'ssaa' | 'xcaa';
@ -23,15 +23,15 @@ export abstract class AntialiasingStrategy {
shouldRenderDirect: boolean;
// Prepares any OpenGL data. This is only called on startup and canvas resize.
init(view: DemoView): void {
this.setFramebufferSize(view);
init(renderer: Renderer): void {
this.setFramebufferSize(renderer);
}
// Uploads any mesh data. This is called whenever a new set of meshes is supplied.
abstract attachMeshes(view: DemoView): void;
abstract attachMeshes(renderer: Renderer): void;
// This is called whenever the framebuffer has changed.
abstract setFramebufferSize(view: DemoView): void;
abstract setFramebufferSize(renderer: Renderer): void;
// Returns the transformation matrix that should be applied when directly rendering.
abstract get transform(): glmatrix.mat4;
@ -39,17 +39,17 @@ export abstract class AntialiasingStrategy {
// Called before direct rendering.
//
// Typically, this redirects direct rendering to a framebuffer of some sort.
abstract prepare(view: DemoView): void;
abstract prepare(renderer: Renderer): void;
// Called after direct rendering.
//
// This usually performs the actual antialiasing.
abstract antialias(view: DemoView): void;
abstract antialias(renderer: Renderer): void;
// Called after antialiasing.
//
// This usually blits to the real framebuffer.
abstract resolve(view: DemoView): void;
abstract resolve(renderer: Renderer): void;
}
export class NoAAStrategy extends AntialiasingStrategy {
@ -60,25 +60,25 @@ export class NoAAStrategy extends AntialiasingStrategy {
this.framebufferSize = glmatrix.vec2.create();
}
attachMeshes(view: DemoView) {}
attachMeshes(renderer: Renderer) {}
setFramebufferSize(view: DemoView) {
this.framebufferSize = view.destAllocatedSize;
setFramebufferSize(renderer: Renderer) {
this.framebufferSize = renderer.destAllocatedSize;
}
get transform(): glmatrix.mat4 {
return glmatrix.mat4.create();
}
prepare(view: DemoView) {
view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, view.destFramebuffer);
view.gl.viewport(0, 0, this.framebufferSize[0], this.framebufferSize[1]);
view.gl.disable(view.gl.SCISSOR_TEST);
prepare(renderer: Renderer) {
renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, renderer.destFramebuffer);
renderer.gl.viewport(0, 0, this.framebufferSize[0], this.framebufferSize[1]);
renderer.gl.disable(renderer.gl.SCISSOR_TEST);
}
antialias(view: DemoView) {}
antialias(renderer: Renderer) {}
resolve(view: DemoView) {}
resolve(renderer: Renderer) {}
get shouldRenderDirect() {
return true;

View File

@ -11,7 +11,7 @@
import * as glmatrix from 'gl-matrix';
import {assert, UINT32_SIZE, unwrapNull} from './utils';
import { DemoView } from './view';
import {DemoView} from './view';
export type WebGLVertexArrayObject = any;
@ -23,26 +23,49 @@ export interface UniformMap {
[uniformName: string]: WebGLUniformLocation;
}
export interface EXTDisjointTimerQuery {
readonly QUERY_COUNTER_BITS_EXT: GLenum;
readonly CURRENT_QUERY_EXT: GLenum;
readonly QUERY_RESULT_EXT: GLenum;
readonly QUERY_RESULT_AVAILABLE_EXT: GLenum;
readonly TIME_ELAPSED_EXT: GLenum;
readonly TIMESTAMP_EXT: GLenum;
readonly GPU_DISJOINT_EXT: GLenum;
createQueryEXT(): WebGLQuery;
deleteQueryEXT(query: WebGLQuery): void;
isQueryEXT(query: any): GLboolean;
beginQueryEXT(target: GLenum, query: WebGLQuery): void;
endQueryEXT(target: GLenum): void;
queryCounterEXT(query: WebGLQuery, target: GLenum): void;
getQueryEXT(target: GLenum, pname: GLenum): any;
getQueryObjectEXT(query: WebGLQuery, pname: GLenum): any;
}
export class WebGLQuery {}
export const QUAD_ELEMENTS: Uint8Array = new Uint8Array([2, 0, 1, 1, 3, 2]);
export function createFramebufferColorTexture(view: DemoView, size: glmatrix.vec2): WebGLTexture {
export function createFramebufferColorTexture(gl: WebGLRenderingContext,
size: glmatrix.vec2,
colorAlphaFormat: GLenum):
WebGLTexture {
// Firefox seems to have a bug whereby textures don't get marked as initialized when cleared
// if they're anything other than the first attachment of an FBO. To work around this, supply
// zero data explicitly when initializing the texture.
const zeroes = new Uint8Array(size[0] * size[1] * UINT32_SIZE);
const texture = unwrapNull(view.gl.createTexture());
view.gl.activeTexture(view.gl.TEXTURE0);
view.gl.bindTexture(view.gl.TEXTURE_2D, texture);
view.gl.texImage2D(view.gl.TEXTURE_2D,
const texture = unwrapNull(gl.createTexture());
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D,
0,
view.colorAlphaFormat,
colorAlphaFormat,
size[0],
size[1],
0,
view.colorAlphaFormat,
view.gl.UNSIGNED_BYTE,
colorAlphaFormat,
gl.UNSIGNED_BYTE,
zeroes);
setTextureParameters(view.gl, view.gl.NEAREST);
setTextureParameters(gl, gl.NEAREST);
return texture;
}
@ -72,7 +95,7 @@ export function setTextureParameters(gl: WebGLRenderingContext, filter: number)
}
export function createFramebuffer(gl: WebGLRenderingContext,
drawBuffersExt: any,
drawBuffersExt: WebGLDrawBuffers,
colorAttachments: WebGLTexture[],
depthAttachment: WebGLTexture | null):
WebGLFramebuffer {
@ -83,11 +106,9 @@ export function createFramebuffer(gl: WebGLRenderingContext,
for (let colorAttachmentIndex = 0;
colorAttachmentIndex < colorAttachmentCount;
colorAttachmentIndex++) {
gl.framebufferTexture2D(gl.FRAMEBUFFER,
drawBuffersExt[`COLOR_ATTACHMENT${colorAttachmentIndex}_WEBGL`],
gl.TEXTURE_2D,
colorAttachments[colorAttachmentIndex],
0);
const glEnum = (drawBuffersExt as any)[`COLOR_ATTACHMENT${colorAttachmentIndex}_WEBGL`];
const attachment = colorAttachments[colorAttachmentIndex];
gl.framebufferTexture2D(gl.FRAMEBUFFER, glEnum, gl.TEXTURE_2D, attachment, 0);
}
if (depthAttachment != null) {

View File

@ -13,7 +13,7 @@ import * as glmatrix from 'gl-matrix';
import {AntialiasingStrategy, SubpixelAAType} from './aa-strategy';
import {createFramebuffer, createFramebufferDepthTexture, setTextureParameters} from './gl-utils';
import {unwrapNull} from './utils';
import {DemoView} from './view';
import {DemoView, Renderer} from './view';
export default class SSAAStrategy extends AntialiasingStrategy {
private level: number;
@ -33,39 +33,39 @@ export default class SSAAStrategy extends AntialiasingStrategy {
this.supersampledFramebufferSize = glmatrix.vec2.create();
}
attachMeshes(view: DemoView) {}
attachMeshes(renderer: Renderer) {}
setFramebufferSize(view: DemoView) {
this.destFramebufferSize = glmatrix.vec2.clone(view.destAllocatedSize);
setFramebufferSize(renderer: Renderer) {
this.destFramebufferSize = glmatrix.vec2.clone(renderer.destAllocatedSize);
this.supersampledFramebufferSize = glmatrix.vec2.create();
glmatrix.vec2.mul(this.supersampledFramebufferSize,
this.destFramebufferSize,
this.supersampleScale);
this.supersampledColorTexture = unwrapNull(view.gl.createTexture());
view.gl.activeTexture(view.gl.TEXTURE0);
view.gl.bindTexture(view.gl.TEXTURE_2D, this.supersampledColorTexture);
view.gl.texImage2D(view.gl.TEXTURE_2D,
0,
view.colorAlphaFormat,
this.supersampledFramebufferSize[0],
this.supersampledFramebufferSize[1],
0,
view.colorAlphaFormat,
view.gl.UNSIGNED_BYTE,
null);
setTextureParameters(view.gl, view.gl.LINEAR);
this.supersampledColorTexture = unwrapNull(renderer.gl.createTexture());
renderer.gl.activeTexture(renderer.gl.TEXTURE0);
renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.supersampledColorTexture);
renderer.gl.texImage2D(renderer.gl.TEXTURE_2D,
0,
renderer.colorAlphaFormat,
this.supersampledFramebufferSize[0],
this.supersampledFramebufferSize[1],
0,
renderer.colorAlphaFormat,
renderer.gl.UNSIGNED_BYTE,
null);
setTextureParameters(renderer.gl, renderer.gl.LINEAR);
this.supersampledDepthTexture =
createFramebufferDepthTexture(view.gl, this.supersampledFramebufferSize);
createFramebufferDepthTexture(renderer.gl, this.supersampledFramebufferSize);
this.supersampledFramebuffer = createFramebuffer(view.gl,
view.drawBuffersExt,
this.supersampledFramebuffer = createFramebuffer(renderer.gl,
renderer.drawBuffersExt,
[this.supersampledColorTexture],
this.supersampledDepthTexture);
view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, null);
renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, null);
}
get transform(): glmatrix.mat4 {
@ -77,42 +77,42 @@ export default class SSAAStrategy extends AntialiasingStrategy {
return transform;
}
prepare(view: DemoView) {
prepare(renderer: Renderer) {
const framebufferSize = this.supersampledFramebufferSize;
const usedSize = this.usedSupersampledFramebufferSize(view);
view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, this.supersampledFramebuffer);
view.gl.viewport(0, 0, framebufferSize[0], framebufferSize[1]);
view.gl.scissor(0, 0, usedSize[0], usedSize[1]);
view.gl.enable(view.gl.SCISSOR_TEST);
const usedSize = this.usedSupersampledFramebufferSize(renderer);
renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, this.supersampledFramebuffer);
renderer.gl.viewport(0, 0, framebufferSize[0], framebufferSize[1]);
renderer.gl.scissor(0, 0, usedSize[0], usedSize[1]);
renderer.gl.enable(renderer.gl.SCISSOR_TEST);
}
antialias(view: DemoView) {}
antialias(renderer: Renderer) {}
resolve(view: DemoView) {
view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, view.destFramebuffer);
view.gl.viewport(0, 0, view.destAllocatedSize[0], view.destAllocatedSize[1]);
view.gl.disable(view.gl.DEPTH_TEST);
view.gl.disable(view.gl.BLEND);
resolve(renderer: Renderer) {
renderer.gl.bindFramebuffer(renderer.gl.FRAMEBUFFER, renderer.destFramebuffer);
renderer.gl.viewport(0, 0, renderer.destAllocatedSize[0], renderer.destAllocatedSize[1]);
renderer.gl.disable(renderer.gl.DEPTH_TEST);
renderer.gl.disable(renderer.gl.BLEND);
// Set up the blit program VAO.
let resolveProgram;
if (this.subpixelAA !== 'none')
resolveProgram = view.shaderPrograms.ssaaSubpixelResolve;
resolveProgram = renderer.shaderPrograms.ssaaSubpixelResolve;
else
resolveProgram = view.shaderPrograms.blit;
view.gl.useProgram(resolveProgram.program);
view.initQuadVAO(resolveProgram.attributes);
resolveProgram = renderer.shaderPrograms.blit;
renderer.gl.useProgram(resolveProgram.program);
renderer.initQuadVAO(resolveProgram.attributes);
// Resolve framebuffer.
view.gl.activeTexture(view.gl.TEXTURE0);
view.gl.bindTexture(view.gl.TEXTURE_2D, this.supersampledColorTexture);
view.gl.uniform1i(resolveProgram.uniforms.uSource, 0);
view.gl.uniform2i(resolveProgram.uniforms.uSourceDimensions,
renderer.gl.activeTexture(renderer.gl.TEXTURE0);
renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.supersampledColorTexture);
renderer.gl.uniform1i(resolveProgram.uniforms.uSource, 0);
renderer.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);
renderer.setTransformAndTexScaleUniformsForDest(resolveProgram.uniforms);
renderer.gl.bindBuffer(renderer.gl.ELEMENT_ARRAY_BUFFER, renderer.quadElementsBuffer);
renderer.gl.drawElements(renderer.gl.TRIANGLES, 6, renderer.gl.UNSIGNED_BYTE, 0);
}
get shouldRenderDirect() {
@ -123,9 +123,9 @@ export default class SSAAStrategy extends AntialiasingStrategy {
return glmatrix.vec2.clone([this.subpixelAA !== 'none' ? 3 : 2, this.level === 2 ? 1 : 2]);
}
private usedSupersampledFramebufferSize(view: DemoView): glmatrix.vec2 {
private usedSupersampledFramebufferSize(renderer: Renderer): glmatrix.vec2 {
const result = glmatrix.vec2.create();
glmatrix.vec2.mul(result, view.destUsedSize, this.supersampleScale);
glmatrix.vec2.mul(result, renderer.destUsedSize, this.supersampleScale);
return result;
}
}

View File

@ -288,8 +288,13 @@ class TextDemoView extends MonochromeDemoView {
return glmatrix.vec2.create();
}
readonly bgColor: glmatrix.vec4 = glmatrix.vec4.fromValues(1.0, 1.0, 1.0, 0.0);
readonly fgColor: glmatrix.vec4 = glmatrix.vec4.fromValues(0.0, 0.0, 0.0, 1.0);
get bgColor(): glmatrix.vec4 {
return glmatrix.vec4.fromValues(1.0, 1.0, 1.0, 0.0);
}
get fgColor(): glmatrix.vec4 {
return glmatrix.vec4.fromValues(0.0, 0.0, 0.0, 1.0);
}
protected depthFunction: number = this.gl.GREATER;

View File

@ -17,7 +17,7 @@ import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from "./aa
import {StemDarkeningMode, SubpixelAAType} from "./aa-strategy";
import PathfinderBufferTexture from './buffer-texture';
import {Camera} from "./camera";
import {QUAD_ELEMENTS, UniformMap} from './gl-utils';
import {EXTDisjointTimerQuery, QUAD_ELEMENTS, UniformMap} from './gl-utils';
import {PathfinderMeshBuffers, PathfinderMeshData} from './meshes';
import {PathfinderShaderProgram, SHADER_NAMES, ShaderMap} from './shader-loader';
import {ShaderProgramSource, UnlinkedShaderProgram} from './shader-loader';
@ -121,15 +121,15 @@ export abstract class PathfinderView {
}
}
export abstract class DemoView extends PathfinderView {
export abstract class DemoView extends PathfinderView implements Renderer {
gl: WebGLRenderingContext;
shaderPrograms: ShaderMap<PathfinderShaderProgram>;
drawBuffersExt: any;
instancedArraysExt: any;
textureHalfFloatExt: any;
vertexArrayObjectExt: any;
drawBuffersExt: WebGLDrawBuffers;
instancedArraysExt: ANGLEInstancedArrays;
textureHalfFloatExt: OESTextureHalfFloat;
vertexArrayObjectExt: OESVertexArrayObject;
quadPositionsBuffer: WebGLBuffer;
quadTexCoordsBuffer: WebGLBuffer;
@ -140,16 +140,24 @@ export abstract class DemoView extends PathfinderView {
pathTransformBufferTextures: PathfinderBufferTexture[];
get bgColor(): glmatrix.vec4 | null {
return null;
}
get fgColor(): glmatrix.vec4 | null {
return null;
}
get emboldenAmount(): glmatrix.vec2 {
return glmatrix.vec2.create();
}
get colorAlphaFormat(): number {
get colorAlphaFormat(): GLenum {
return this.sRGBExt == null ? this.gl.RGBA : this.sRGBExt.SRGB_ALPHA_EXT;
}
protected sRGBExt: any;
protected timerQueryExt: any;
protected sRGBExt: EXTsRGB;
protected timerQueryExt: EXTDisjointTimerQuery;
protected antialiasingStrategy: AntialiasingStrategy | null;
protected colorBufferHalfFloatExt: any;
@ -216,7 +224,7 @@ export abstract class DemoView extends PathfinderView {
this.setDirty();
}
initQuadVAO(attributes: any) {
initQuadVAO(attributes: any): void {
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.quadPositionsBuffer);
this.gl.vertexAttribPointer(attributes.aPosition, 2, this.gl.FLOAT, false, 0, 0);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.quadTexCoordsBuffer);
@ -246,13 +254,13 @@ export abstract class DemoView extends PathfinderView {
transform[13]);
}
setTransformSTAndTexScaleUniformsForDest(uniforms: UniformMap) {
setTransformSTAndTexScaleUniformsForDest(uniforms: UniformMap): void {
const usedSize = this.usedSizeFactor;
this.gl.uniform4f(uniforms.uTransformST, 2.0 * usedSize[0], 2.0 * usedSize[1], -1.0, -1.0);
this.gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]);
}
setTransformAndTexScaleUniformsForDest(uniforms: UniformMap) {
setTransformAndTexScaleUniformsForDest(uniforms: UniformMap): void {
const usedSize = this.usedSizeFactor;
const transform = glmatrix.mat4.create();
@ -727,3 +735,45 @@ export abstract class MonochromeDemoView extends DemoView {
abstract get bgColor(): glmatrix.vec4;
abstract get fgColor(): glmatrix.vec4;
}
export interface Renderer {
/// The OpenGL context.
readonly gl: WebGLRenderingContext;
/// The `WEBGL_draw_buffers` extension.
readonly drawBuffersExt: WebGLDrawBuffers;
readonly instancedArraysExt: ANGLEInstancedArrays;
readonly textureHalfFloatExt: OESTextureHalfFloat;
readonly vertexArrayObjectExt: OESVertexArrayObject;
readonly shaderPrograms: ShaderMap<PathfinderShaderProgram>;
readonly quadPositionsBuffer: WebGLBuffer;
readonly quadElementsBuffer: WebGLBuffer;
readonly destFramebuffer: WebGLFramebuffer | null;
readonly pathTransformBufferTextures: PathfinderBufferTexture[];
readonly meshes: PathfinderMeshBuffers[];
readonly meshData: PathfinderMeshData[];
readonly colorAlphaFormat: GLenum;
readonly destAllocatedSize: glmatrix.vec2;
readonly destUsedSize: glmatrix.vec2;
readonly emboldenAmount: glmatrix.vec2;
readonly bgColor: glmatrix.vec4 | null;
readonly fgColor: glmatrix.vec4 | null;
initQuadVAO(attributes: any): void;
pathBoundingRects(objectIndex: number): Float32Array;
setFramebufferSizeUniform(uniforms: UniformMap): void;
setHintsUniform(uniforms: UniformMap): void;
setTransformAndTexScaleUniformsForDest(uniforms: UniformMap): void;
setTransformSTAndTexScaleUniformsForDest(uniforms: UniformMap): void;
setTransformSTUniform(uniforms: UniformMap, objectIndex: number): void;
}

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,8 @@
"gl-matrix",
"lodash",
"node",
"opentype.js"
"opentype.js",
"webgl-ext"
],
"typeRoots": [
"node_modules/@types"