Replace the multicolor (SVG) XCAA with a multipass compositing algorithm
This commit is contained in:
parent
b87d4126b0
commit
2604151521
|
@ -359,14 +359,6 @@ class ThreeDRenderer extends Renderer {
|
|||
return this.destAllocatedSize;
|
||||
}
|
||||
|
||||
protected get directCurveProgramName(): keyof ShaderMap<void> {
|
||||
return 'direct3DCurve';
|
||||
}
|
||||
|
||||
protected get directInteriorProgramName(): keyof ShaderMap<void> {
|
||||
return 'direct3DInterior';
|
||||
}
|
||||
|
||||
protected get depthFunction(): GLenum {
|
||||
return this.renderContext.gl.LESS;
|
||||
}
|
||||
|
@ -528,6 +520,14 @@ class ThreeDRenderer extends Renderer {
|
|||
this.renderContext.appController.newTimingsReceived(newTimings);
|
||||
}
|
||||
|
||||
protected directCurveProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||
return 'direct3DCurve';
|
||||
}
|
||||
|
||||
protected directInteriorProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||
return 'direct3DInterior';
|
||||
}
|
||||
|
||||
// Cheap but effective backface culling.
|
||||
private objectIsVisible(objectIndex: number): boolean {
|
||||
const textFrameIndex = this.renderContext
|
||||
|
|
|
@ -15,7 +15,7 @@ import {DemoView} from './view';
|
|||
|
||||
export type AntialiasingStrategyName = 'none' | 'ssaa' | 'xcaa';
|
||||
|
||||
export type DirectRenderingMode = 'none' | 'color' | 'pathID';
|
||||
export type DirectRenderingMode = 'none' | 'color' | 'two-pass';
|
||||
|
||||
export type SubpixelAAType = 'none' | 'medium';
|
||||
|
||||
|
@ -42,7 +42,7 @@ export abstract class AntialiasingStrategy {
|
|||
// Called before direct rendering.
|
||||
//
|
||||
// Typically, this redirects direct rendering to a framebuffer of some sort.
|
||||
abstract prepare(renderer: Renderer): void;
|
||||
abstract prepareForDirectRendering(renderer: Renderer): void;
|
||||
|
||||
// Called after direct rendering.
|
||||
//
|
||||
|
@ -73,7 +73,7 @@ export class NoAAStrategy extends AntialiasingStrategy {
|
|||
return glmatrix.mat4.create();
|
||||
}
|
||||
|
||||
prepare(renderer: Renderer) {
|
||||
prepareForDirectRendering(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, renderer.destFramebuffer);
|
||||
renderContext.gl.viewport(0, 0, this.framebufferSize[0], this.framebufferSize[1]);
|
||||
|
|
|
@ -309,14 +309,6 @@ class BenchmarkRenderer extends Renderer {
|
|||
return glmatrix.vec2.clone([1.0, 1.0]);
|
||||
}
|
||||
|
||||
protected get directCurveProgramName(): keyof ShaderMap<void> {
|
||||
return 'directCurve';
|
||||
}
|
||||
|
||||
protected get directInteriorProgramName(): keyof ShaderMap<void> {
|
||||
return 'directInterior';
|
||||
}
|
||||
|
||||
protected get depthFunction(): number {
|
||||
return this.renderContext.gl.GREATER;
|
||||
}
|
||||
|
@ -445,6 +437,14 @@ class BenchmarkRenderer extends Renderer {
|
|||
|
||||
return pathTransforms;
|
||||
}
|
||||
|
||||
protected directCurveProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||
return 'directCurve';
|
||||
}
|
||||
|
||||
protected directInteriorProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||
return 'directInterior';
|
||||
}
|
||||
}
|
||||
|
||||
function computeMedian(values: number[]): number | null {
|
||||
|
|
|
@ -18,6 +18,7 @@ import {PathfinderMeshBuffers, PathfinderMeshData} from "./meshes";
|
|||
import {ShaderMap} from './shader-loader';
|
||||
import {FLOAT32_SIZE, Range, UINT16_SIZE, UINT32_SIZE, unwrapNull} from './utils';
|
||||
import {RenderContext, Timings} from "./view";
|
||||
import {MCAAMulticolorStrategy} from './xcaa-strategy';
|
||||
|
||||
const MAX_PATHS: number = 65535;
|
||||
|
||||
|
@ -64,8 +65,6 @@ export abstract class Renderer {
|
|||
}
|
||||
|
||||
protected abstract get depthFunction(): GLenum;
|
||||
protected abstract get directCurveProgramName(): keyof ShaderMap<void>;
|
||||
protected abstract get directInteriorProgramName(): keyof ShaderMap<void>;
|
||||
protected abstract get usedSizeFactor(): glmatrix.vec2;
|
||||
protected abstract get worldTransform(): glmatrix.mat4;
|
||||
|
||||
|
@ -112,22 +111,22 @@ export abstract class Renderer {
|
|||
renderContext.atlasRenderingTimerQuery);
|
||||
}
|
||||
|
||||
// Prepare for direct rendering.
|
||||
// Draw "scenery" (used in the 3D view).
|
||||
this.drawSceneryIfNecessary();
|
||||
|
||||
// Antialias.
|
||||
const antialiasingStrategy = unwrapNull(this.antialiasingStrategy);
|
||||
antialiasingStrategy.prepare(this);
|
||||
antialiasingStrategy.antialias(this);
|
||||
|
||||
// Prepare for direct rendering.
|
||||
antialiasingStrategy.prepareForDirectRendering(this);
|
||||
|
||||
// Clear.
|
||||
this.clearForDirectRendering();
|
||||
|
||||
// Draw "scenery" (used in the 3D view).
|
||||
this.drawSceneryIfNecessary();
|
||||
|
||||
// Perform direct rendering (Loop-Blinn).
|
||||
if (antialiasingStrategy.directRenderingMode !== 'none')
|
||||
this.renderDirect();
|
||||
|
||||
// Antialias.
|
||||
antialiasingStrategy.antialias(this);
|
||||
this.renderDirect(0);
|
||||
|
||||
// End the timer, and start a new one.
|
||||
if (this.timerQueryPollInterval == null) {
|
||||
|
@ -138,6 +137,9 @@ export abstract class Renderer {
|
|||
|
||||
antialiasingStrategy.resolve(this);
|
||||
|
||||
if (antialiasingStrategy.directRenderingMode === 'two-pass')
|
||||
this.renderDirect(1);
|
||||
|
||||
// Draw the glyphs with the resolved atlas to the default framebuffer.
|
||||
this.compositeIfNecessary();
|
||||
|
||||
|
@ -167,9 +169,10 @@ export abstract class Renderer {
|
|||
}
|
||||
|
||||
setFramebufferSizeUniform(uniforms: UniformMap) {
|
||||
this.renderContext.gl.uniform2i(uniforms.uFramebufferSize,
|
||||
this.destAllocatedSize[0],
|
||||
this.destAllocatedSize[1]);
|
||||
const gl = this.renderContext.gl;
|
||||
gl.uniform2i(uniforms.uFramebufferSize,
|
||||
this.destAllocatedSize[0],
|
||||
this.destAllocatedSize[1]);
|
||||
}
|
||||
|
||||
setTransformAndTexScaleUniformsForDest(uniforms: UniformMap): void {
|
||||
|
@ -186,29 +189,29 @@ export abstract class Renderer {
|
|||
|
||||
setTransformSTAndTexScaleUniformsForDest(uniforms: UniformMap): void {
|
||||
const renderContext = this.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const usedSize = this.usedSizeFactor;
|
||||
renderContext.gl.uniform4f(uniforms.uTransformST,
|
||||
2.0 * usedSize[0],
|
||||
2.0 * usedSize[1],
|
||||
-1.0,
|
||||
-1.0);
|
||||
renderContext.gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]);
|
||||
gl.uniform4f(uniforms.uTransformST, 2.0 * usedSize[0], 2.0 * usedSize[1], -1.0, -1.0);
|
||||
gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]);
|
||||
}
|
||||
|
||||
setTransformSTUniform(uniforms: UniformMap, objectIndex: number) {
|
||||
// FIXME(pcwalton): Lossy conversion from a 4x4 matrix to an ST matrix is ugly and fragile.
|
||||
// Refactor.
|
||||
const renderContext = this.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const transform = glmatrix.mat4.clone(this.worldTransform);
|
||||
glmatrix.mat4.mul(transform, transform, this.getModelviewTransform(objectIndex));
|
||||
|
||||
const translation = glmatrix.vec4.clone([transform[12], transform[13], 0.0, 1.0]);
|
||||
|
||||
renderContext.gl.uniform4f(uniforms.uTransformST,
|
||||
transform[0],
|
||||
transform[5],
|
||||
transform[12],
|
||||
transform[13]);
|
||||
gl.uniform4f(uniforms.uTransformST,
|
||||
transform[0],
|
||||
transform[5],
|
||||
transform[12],
|
||||
transform[13]);
|
||||
}
|
||||
|
||||
uploadPathColors(objectCount: number) {
|
||||
|
@ -248,9 +251,8 @@ export abstract class Renderer {
|
|||
}
|
||||
|
||||
setPathColorsUniform(objectIndex: number, uniforms: UniformMap, textureUnit: number): void {
|
||||
this.pathColorsBufferTextures[objectIndex].bind(this.renderContext.gl,
|
||||
uniforms,
|
||||
textureUnit);
|
||||
const gl = this.renderContext.gl;
|
||||
this.pathColorsBufferTextures[objectIndex].bind(gl, uniforms, textureUnit);
|
||||
}
|
||||
|
||||
protected abstract createAAStrategy(aaType: AntialiasingStrategyName,
|
||||
|
@ -262,6 +264,9 @@ export abstract class Renderer {
|
|||
protected abstract pathColorsForObject(objectIndex: number): Uint8Array;
|
||||
protected abstract pathTransformsForObject(objectIndex: number): Float32Array;
|
||||
|
||||
protected abstract directCurveProgramNameForPass(pass: number): keyof ShaderMap<void>;
|
||||
protected abstract directInteriorProgramNameForPass(pass: number): keyof ShaderMap<void>;
|
||||
|
||||
protected drawSceneryIfNecessary(): void {}
|
||||
|
||||
protected clearForDirectRendering(): void {
|
||||
|
@ -269,22 +274,21 @@ export abstract class Renderer {
|
|||
const renderContext = this.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const clearColor = this.backgroundColor;
|
||||
gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
|
||||
|
||||
switch (renderingMode) {
|
||||
case 'color':
|
||||
const clearColor = this.backgroundColor;
|
||||
gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
|
||||
gl.clearDepth(0.0);
|
||||
gl.depthMask(true);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
break;
|
||||
case 'pathID':
|
||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
gl.clearDepth(0.0);
|
||||
gl.depthMask(true);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
case 'two-pass':
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
break;
|
||||
case 'none':
|
||||
// Nothing to do.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -300,11 +304,13 @@ export abstract class Renderer {
|
|||
/// Called whenever new GPU timing statistics are available.
|
||||
protected newTimingsReceived(): void {}
|
||||
|
||||
private renderDirect(): void {
|
||||
const renderingMode = unwrapNull(this.antialiasingStrategy).directRenderingMode;
|
||||
private renderDirect(pass: number): void {
|
||||
const renderContext = this.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const antialiasingStrategy = unwrapNull(this.antialiasingStrategy);
|
||||
const renderingMode = antialiasingStrategy.directRenderingMode;
|
||||
|
||||
for (let objectIndex = 0; objectIndex < this.meshes.length; objectIndex++) {
|
||||
const instanceRange = this.instanceRangeForObject(objectIndex);
|
||||
if (instanceRange.isEmpty)
|
||||
|
@ -319,23 +325,26 @@ export abstract class Renderer {
|
|||
gl.disable(gl.BLEND);
|
||||
|
||||
// Set up the implicit cover interior VAO.
|
||||
const directInteriorProgram =
|
||||
renderContext.shaderPrograms[this.directInteriorProgramName];
|
||||
const directInteriorProgramName = this.directInteriorProgramNameForPass(pass);
|
||||
const directInteriorProgram = renderContext.shaderPrograms[directInteriorProgramName];
|
||||
if (this.implicitCoverInteriorVAO == null) {
|
||||
this.implicitCoverInteriorVAO = renderContext.vertexArrayObjectExt
|
||||
.createVertexArrayOES();
|
||||
}
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverInteriorVAO);
|
||||
this.initImplicitCoverInteriorVAO(objectIndex, instanceRange);
|
||||
this.initImplicitCoverInteriorVAO(pass, objectIndex, instanceRange);
|
||||
|
||||
// Draw direct interior parts.
|
||||
this.setTransformUniform(directInteriorProgram.uniforms, objectIndex);
|
||||
this.setFramebufferSizeUniform(directInteriorProgram.uniforms);
|
||||
this.setHintsUniform(directInteriorProgram.uniforms);
|
||||
if (renderingMode === 'color')
|
||||
this.setPathColorsUniform(objectIndex, directInteriorProgram.uniforms, 0);
|
||||
this.setPathColorsUniform(objectIndex, directInteriorProgram.uniforms, 0);
|
||||
this.pathTransformBufferTextures[objectIndex]
|
||||
.bind(gl, directInteriorProgram.uniforms, 1);
|
||||
if (renderingMode === 'two-pass') {
|
||||
const strategy = antialiasingStrategy as MCAAMulticolorStrategy;
|
||||
strategy.bindEdgeDepthTexture(gl, directInteriorProgram.uniforms, 2);
|
||||
}
|
||||
let indexCount = meshData.coverInteriorIndices.byteLength / UINT32_SIZE;
|
||||
if (!this.pathIDsAreInstanced) {
|
||||
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
|
||||
|
@ -356,21 +365,25 @@ export abstract class Renderer {
|
|||
// Set up the direct curve VAO.
|
||||
//
|
||||
// TODO(pcwalton): Cache these.
|
||||
const directCurveProgram = renderContext.shaderPrograms[this.directCurveProgramName];
|
||||
const directCurveProgramName = this.directCurveProgramNameForPass(pass);
|
||||
const directCurveProgram = renderContext.shaderPrograms[directCurveProgramName];
|
||||
if (this.implicitCoverCurveVAO == null) {
|
||||
this.implicitCoverCurveVAO = renderContext.vertexArrayObjectExt
|
||||
.createVertexArrayOES();
|
||||
}
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverCurveVAO);
|
||||
this.initImplicitCoverCurveVAO(objectIndex, instanceRange);
|
||||
this.initImplicitCoverCurveVAO(pass, objectIndex, instanceRange);
|
||||
|
||||
// Draw direct curve parts.
|
||||
this.setTransformUniform(directCurveProgram.uniforms, objectIndex);
|
||||
this.setFramebufferSizeUniform(directCurveProgram.uniforms);
|
||||
this.setHintsUniform(directCurveProgram.uniforms);
|
||||
if (renderingMode === 'color')
|
||||
this.setPathColorsUniform(objectIndex, directCurveProgram.uniforms, 0);
|
||||
this.setPathColorsUniform(objectIndex, directCurveProgram.uniforms, 0);
|
||||
this.pathTransformBufferTextures[objectIndex].bind(gl, directCurveProgram.uniforms, 1);
|
||||
if (renderingMode === 'two-pass') {
|
||||
const strategy = antialiasingStrategy as MCAAMulticolorStrategy;
|
||||
strategy.bindEdgeDepthTexture(gl, directCurveProgram.uniforms, 2);
|
||||
}
|
||||
indexCount = meshData.coverCurveIndices.byteLength / UINT32_SIZE;
|
||||
if (!this.pathIDsAreInstanced) {
|
||||
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
|
||||
|
@ -426,104 +439,104 @@ export abstract class Renderer {
|
|||
}, TIME_INTERVAL_DELAY);
|
||||
}
|
||||
|
||||
private initImplicitCoverCurveVAO(objectIndex: number, instanceRange: Range): void {
|
||||
private initImplicitCoverCurveVAO(pass: number, objectIndex: number, instanceRange: Range):
|
||||
void {
|
||||
const renderContext = this.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
const meshes = this.meshes[objectIndex];
|
||||
|
||||
const directCurveProgram = renderContext.shaderPrograms[this.directCurveProgramName];
|
||||
renderContext.gl.useProgram(directCurveProgram.program);
|
||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, meshes.bVertexPositions);
|
||||
renderContext.gl.vertexAttribPointer(directCurveProgram.attributes.aPosition,
|
||||
2,
|
||||
renderContext.gl.FLOAT,
|
||||
false,
|
||||
0,
|
||||
0);
|
||||
const directCurveProgramName = this.directCurveProgramNameForPass(pass);
|
||||
const directCurveProgram = renderContext.shaderPrograms[directCurveProgramName];
|
||||
gl.useProgram(directCurveProgram.program);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPositions);
|
||||
gl.vertexAttribPointer(directCurveProgram.attributes.aPosition, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
if (this.pathIDsAreInstanced)
|
||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
||||
else
|
||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, meshes.bVertexPathIDs);
|
||||
renderContext.gl.vertexAttribPointer(directCurveProgram.attributes.aPathID,
|
||||
1,
|
||||
renderContext.gl.UNSIGNED_SHORT,
|
||||
false,
|
||||
0,
|
||||
instanceRange.start * UINT16_SIZE);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPathIDs);
|
||||
gl.vertexAttribPointer(directCurveProgram.attributes.aPathID,
|
||||
1,
|
||||
gl.UNSIGNED_SHORT,
|
||||
false,
|
||||
0,
|
||||
instanceRange.start * UINT16_SIZE);
|
||||
if (this.pathIDsAreInstanced) {
|
||||
renderContext.instancedArraysExt
|
||||
.vertexAttribDivisorANGLE(directCurveProgram.attributes.aPathID, 1);
|
||||
}
|
||||
|
||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, meshes.bVertexLoopBlinnData);
|
||||
renderContext.gl.vertexAttribPointer(directCurveProgram.attributes.aTexCoord,
|
||||
2,
|
||||
renderContext.gl.UNSIGNED_BYTE,
|
||||
false,
|
||||
B_LOOP_BLINN_DATA_SIZE,
|
||||
B_LOOP_BLINN_DATA_TEX_COORD_OFFSET);
|
||||
renderContext.gl.vertexAttribPointer(directCurveProgram.attributes.aSign,
|
||||
1,
|
||||
renderContext.gl.BYTE,
|
||||
false,
|
||||
B_LOOP_BLINN_DATA_SIZE,
|
||||
B_LOOP_BLINN_DATA_SIGN_OFFSET);
|
||||
renderContext.gl.enableVertexAttribArray(directCurveProgram.attributes.aPosition);
|
||||
renderContext.gl.enableVertexAttribArray(directCurveProgram.attributes.aTexCoord);
|
||||
renderContext.gl.enableVertexAttribArray(directCurveProgram.attributes.aPathID);
|
||||
renderContext.gl.enableVertexAttribArray(directCurveProgram.attributes.aSign);
|
||||
renderContext.gl.bindBuffer(renderContext.gl.ELEMENT_ARRAY_BUFFER,
|
||||
meshes.coverCurveIndices);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexLoopBlinnData);
|
||||
gl.vertexAttribPointer(directCurveProgram.attributes.aTexCoord,
|
||||
2,
|
||||
gl.UNSIGNED_BYTE,
|
||||
false,
|
||||
B_LOOP_BLINN_DATA_SIZE,
|
||||
B_LOOP_BLINN_DATA_TEX_COORD_OFFSET);
|
||||
gl.vertexAttribPointer(directCurveProgram.attributes.aSign,
|
||||
1,
|
||||
gl.BYTE,
|
||||
false,
|
||||
B_LOOP_BLINN_DATA_SIZE,
|
||||
B_LOOP_BLINN_DATA_SIGN_OFFSET);
|
||||
gl.enableVertexAttribArray(directCurveProgram.attributes.aPosition);
|
||||
gl.enableVertexAttribArray(directCurveProgram.attributes.aTexCoord);
|
||||
gl.enableVertexAttribArray(directCurveProgram.attributes.aPathID);
|
||||
gl.enableVertexAttribArray(directCurveProgram.attributes.aSign);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, meshes.coverCurveIndices);
|
||||
}
|
||||
|
||||
private initImplicitCoverInteriorVAO(objectIndex: number, instanceRange: Range): void {
|
||||
private initImplicitCoverInteriorVAO(pass: number,
|
||||
objectIndex: number,
|
||||
instanceRange: Range):
|
||||
void {
|
||||
const renderContext = this.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
const meshes = this.meshes[objectIndex];
|
||||
|
||||
const directInteriorProgram = renderContext.shaderPrograms[this.directInteriorProgramName];
|
||||
renderContext.gl.useProgram(directInteriorProgram.program);
|
||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, meshes.bVertexPositions);
|
||||
renderContext.gl.vertexAttribPointer(directInteriorProgram.attributes.aPosition,
|
||||
2,
|
||||
renderContext.gl.FLOAT,
|
||||
false,
|
||||
0,
|
||||
0);
|
||||
const directInteriorProgramName = this.directInteriorProgramNameForPass(pass);
|
||||
const directInteriorProgram = renderContext.shaderPrograms[directInteriorProgramName];
|
||||
gl.useProgram(directInteriorProgram.program);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPositions);
|
||||
gl.vertexAttribPointer(directInteriorProgram.attributes.aPosition,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
0,
|
||||
0);
|
||||
|
||||
if (this.pathIDsAreInstanced)
|
||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
||||
else
|
||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, meshes.bVertexPathIDs);
|
||||
renderContext.gl.vertexAttribPointer(directInteriorProgram.attributes.aPathID,
|
||||
1,
|
||||
renderContext.gl.UNSIGNED_SHORT,
|
||||
false,
|
||||
0,
|
||||
instanceRange.start * UINT16_SIZE);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPathIDs);
|
||||
gl.vertexAttribPointer(directInteriorProgram.attributes.aPathID,
|
||||
1,
|
||||
gl.UNSIGNED_SHORT,
|
||||
false,
|
||||
0,
|
||||
instanceRange.start * UINT16_SIZE);
|
||||
if (this.pathIDsAreInstanced) {
|
||||
renderContext.instancedArraysExt
|
||||
.vertexAttribDivisorANGLE(directInteriorProgram.attributes.aPathID, 1);
|
||||
}
|
||||
|
||||
renderContext.gl.enableVertexAttribArray(directInteriorProgram.attributes.aPosition);
|
||||
renderContext.gl.enableVertexAttribArray(directInteriorProgram.attributes.aPathID);
|
||||
renderContext.gl.bindBuffer(renderContext.gl.ELEMENT_ARRAY_BUFFER,
|
||||
meshes.coverInteriorIndices);
|
||||
gl.enableVertexAttribArray(directInteriorProgram.attributes.aPosition);
|
||||
gl.enableVertexAttribArray(directInteriorProgram.attributes.aPathID);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, meshes.coverInteriorIndices);
|
||||
}
|
||||
|
||||
private initInstancedPathIDVBO(): void {
|
||||
const renderContext = this.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
const pathIDs = new Uint16Array(MAX_PATHS);
|
||||
for (let pathIndex = 0; pathIndex < MAX_PATHS; pathIndex++)
|
||||
pathIDs[pathIndex] = pathIndex + 1;
|
||||
|
||||
this.instancedPathIDVBO = renderContext.gl.createBuffer();
|
||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
||||
renderContext.gl.bufferData(renderContext.gl.ARRAY_BUFFER,
|
||||
pathIDs,
|
||||
renderContext.gl.STATIC_DRAW);
|
||||
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, null);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, pathIDs, gl.STATIC_DRAW);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||
}
|
||||
|
||||
private setTransformUniform(uniforms: UniformMap, objectIndex: number) {
|
||||
|
|
|
@ -25,11 +25,12 @@ export interface ShaderMap<T> {
|
|||
mcaaLine: T;
|
||||
mcaaCurve: T;
|
||||
ssaaSubpixelResolve: T;
|
||||
xcaaEdgeDetect: T;
|
||||
xcaaMonoResolve: T;
|
||||
xcaaMonoSubpixelResolve: T;
|
||||
xcaaMultiDirectCurve: T;
|
||||
xcaaMultiDirectInterior: T;
|
||||
xcaaMultiBGDirectCurve: T;
|
||||
xcaaMultiBGDirectInterior: T;
|
||||
xcaaMultiEdgeMaskCurve: T;
|
||||
xcaaMultiEdgeMaskLine: T;
|
||||
xcaaMultiResolve: T;
|
||||
}
|
||||
|
||||
|
@ -47,7 +48,6 @@ export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
|||
'direct3DCurve',
|
||||
'direct3DInterior',
|
||||
'ssaaSubpixelResolve',
|
||||
'xcaaEdgeDetect',
|
||||
'mcaaCover',
|
||||
'mcaaLine',
|
||||
'mcaaCurve',
|
||||
|
@ -55,8 +55,10 @@ export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
|||
'ecaaCurve',
|
||||
'xcaaMonoResolve',
|
||||
'xcaaMonoSubpixelResolve',
|
||||
'xcaaMultiDirectCurve',
|
||||
'xcaaMultiDirectInterior',
|
||||
'xcaaMultiBGDirectCurve',
|
||||
'xcaaMultiBGDirectInterior',
|
||||
'xcaaMultiEdgeMaskCurve',
|
||||
'xcaaMultiEdgeMaskLine',
|
||||
'xcaaMultiResolve',
|
||||
'demo3DDistantGlyph',
|
||||
'demo3DMonument',
|
||||
|
@ -115,10 +117,6 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
|||
fragment: "/glsl/gles2/ssaa-subpixel-resolve.fs.glsl",
|
||||
vertex: "/glsl/gles2/ssaa-subpixel-resolve.vs.glsl",
|
||||
},
|
||||
xcaaEdgeDetect: {
|
||||
fragment: "/glsl/gles2/xcaa-edge-detect.fs.glsl",
|
||||
vertex: "/glsl/gles2/xcaa-edge-detect.vs.glsl",
|
||||
},
|
||||
xcaaMonoResolve: {
|
||||
fragment: "/glsl/gles2/xcaa-mono-resolve.fs.glsl",
|
||||
vertex: "/glsl/gles2/xcaa-mono-resolve.vs.glsl",
|
||||
|
@ -127,13 +125,21 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
|||
fragment: "/glsl/gles2/xcaa-mono-subpixel-resolve.fs.glsl",
|
||||
vertex: "/glsl/gles2/xcaa-mono-subpixel-resolve.vs.glsl",
|
||||
},
|
||||
xcaaMultiDirectCurve: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-direct-curve.fs.glsl",
|
||||
vertex: "/glsl/gles2/xcaa-multi-direct-curve.vs.glsl",
|
||||
xcaaMultiBGDirectCurve: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-bg-direct-curve.fs.glsl",
|
||||
vertex: "/glsl/gles2/xcaa-multi-bg-direct-curve.vs.glsl",
|
||||
},
|
||||
xcaaMultiDirectInterior: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-direct-interior.fs.glsl",
|
||||
vertex: "/glsl/gles2/xcaa-multi-direct-interior.vs.glsl",
|
||||
xcaaMultiBGDirectInterior: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-bg-direct-interior.fs.glsl",
|
||||
vertex: "/glsl/gles2/xcaa-multi-bg-direct-interior.vs.glsl",
|
||||
},
|
||||
xcaaMultiEdgeMaskCurve: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-edge-mask-curve.fs.glsl",
|
||||
vertex: "/glsl/gles2/mcaa-curve.vs.glsl",
|
||||
},
|
||||
xcaaMultiEdgeMaskLine: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-edge-mask-line.fs.glsl",
|
||||
vertex: "/glsl/gles2/mcaa-line.vs.glsl",
|
||||
},
|
||||
xcaaMultiResolve: {
|
||||
fragment: "/glsl/gles2/xcaa-multi-resolve.fs.glsl",
|
||||
|
|
|
@ -38,6 +38,7 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
|||
|
||||
setFramebufferSize(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
this.destFramebufferSize = glmatrix.vec2.clone(renderer.destAllocatedSize);
|
||||
|
||||
|
@ -46,28 +47,28 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
|||
this.destFramebufferSize,
|
||||
this.supersampleScale);
|
||||
|
||||
this.supersampledColorTexture = unwrapNull(renderContext.gl.createTexture());
|
||||
renderContext.gl.activeTexture(renderContext.gl.TEXTURE0);
|
||||
renderContext.gl.bindTexture(renderContext.gl.TEXTURE_2D, this.supersampledColorTexture);
|
||||
renderContext.gl.texImage2D(renderContext.gl.TEXTURE_2D,
|
||||
0,
|
||||
renderContext.colorAlphaFormat,
|
||||
this.supersampledFramebufferSize[0],
|
||||
this.supersampledFramebufferSize[1],
|
||||
0,
|
||||
renderContext.colorAlphaFormat,
|
||||
renderContext.gl.UNSIGNED_BYTE,
|
||||
null);
|
||||
setTextureParameters(renderContext.gl, renderContext.gl.LINEAR);
|
||||
this.supersampledColorTexture = unwrapNull(gl.createTexture());
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.supersampledColorTexture);
|
||||
gl.texImage2D(gl.TEXTURE_2D,
|
||||
0,
|
||||
renderContext.colorAlphaFormat,
|
||||
this.supersampledFramebufferSize[0],
|
||||
this.supersampledFramebufferSize[1],
|
||||
0,
|
||||
renderContext.colorAlphaFormat,
|
||||
gl.UNSIGNED_BYTE,
|
||||
null);
|
||||
setTextureParameters(gl, gl.LINEAR);
|
||||
|
||||
this.supersampledDepthTexture =
|
||||
createFramebufferDepthTexture(renderContext.gl, this.supersampledFramebufferSize);
|
||||
createFramebufferDepthTexture(gl, this.supersampledFramebufferSize);
|
||||
|
||||
this.supersampledFramebuffer = createFramebuffer(renderContext.gl,
|
||||
this.supersampledFramebuffer = createFramebuffer(gl,
|
||||
this.supersampledColorTexture,
|
||||
this.supersampledDepthTexture);
|
||||
|
||||
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, null);
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
}
|
||||
|
||||
get transform(): glmatrix.mat4 {
|
||||
|
@ -79,7 +80,7 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
|||
return transform;
|
||||
}
|
||||
|
||||
prepare(renderer: Renderer) {
|
||||
prepareForDirectRendering(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
|
@ -95,13 +96,12 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
|||
|
||||
resolve(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, renderer.destFramebuffer);
|
||||
renderContext.gl.viewport(0,
|
||||
0,
|
||||
renderer.destAllocatedSize[0],
|
||||
renderer.destAllocatedSize[1]);
|
||||
renderContext.gl.disable(renderContext.gl.DEPTH_TEST);
|
||||
renderContext.gl.disable(renderContext.gl.BLEND);
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, renderer.destFramebuffer);
|
||||
gl.viewport(0, 0, renderer.destAllocatedSize[0], renderer.destAllocatedSize[1]);
|
||||
gl.disable(gl.DEPTH_TEST);
|
||||
gl.disable(gl.BLEND);
|
||||
|
||||
// Set up the blit program VAO.
|
||||
let resolveProgram;
|
||||
|
@ -109,23 +109,19 @@ export default class SSAAStrategy extends AntialiasingStrategy {
|
|||
resolveProgram = renderContext.shaderPrograms.ssaaSubpixelResolve;
|
||||
else
|
||||
resolveProgram = renderContext.shaderPrograms.blit;
|
||||
renderContext.gl.useProgram(resolveProgram.program);
|
||||
gl.useProgram(resolveProgram.program);
|
||||
renderContext.initQuadVAO(resolveProgram.attributes);
|
||||
|
||||
// Resolve framebuffer.
|
||||
renderContext.gl.activeTexture(renderContext.gl.TEXTURE0);
|
||||
renderContext.gl.bindTexture(renderContext.gl.TEXTURE_2D, this.supersampledColorTexture);
|
||||
renderContext.gl.uniform1i(resolveProgram.uniforms.uSource, 0);
|
||||
renderContext.gl.uniform2i(resolveProgram.uniforms.uSourceDimensions,
|
||||
this.supersampledFramebufferSize[0],
|
||||
this.supersampledFramebufferSize[1]);
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.supersampledColorTexture);
|
||||
gl.uniform1i(resolveProgram.uniforms.uSource, 0);
|
||||
gl.uniform2i(resolveProgram.uniforms.uSourceDimensions,
|
||||
this.supersampledFramebufferSize[0],
|
||||
this.supersampledFramebufferSize[1]);
|
||||
renderer.setTransformAndTexScaleUniformsForDest(resolveProgram.uniforms);
|
||||
renderContext.gl.bindBuffer(renderContext.gl.ELEMENT_ARRAY_BUFFER,
|
||||
renderContext.quadElementsBuffer);
|
||||
renderContext.gl.drawElements(renderContext.gl.TRIANGLES,
|
||||
6,
|
||||
renderContext.gl.UNSIGNED_BYTE,
|
||||
0);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
||||
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
|
||||
}
|
||||
|
||||
get directRenderingMode(): DirectRenderingMode {
|
||||
|
|
|
@ -115,10 +115,8 @@ class SVGDemoRenderer extends Renderer {
|
|||
camera: OrthographicCamera;
|
||||
|
||||
get destAllocatedSize(): glmatrix.vec2 {
|
||||
return glmatrix.vec2.clone([
|
||||
this.renderContext.canvas.width,
|
||||
this.renderContext.canvas.height,
|
||||
]);
|
||||
const canvas = this.renderContext.canvas;
|
||||
return glmatrix.vec2.clone([canvas.width, canvas.height]);
|
||||
}
|
||||
|
||||
get destFramebuffer(): WebGLFramebuffer | null {
|
||||
|
@ -183,15 +181,15 @@ class SVGDemoRenderer extends Renderer {
|
|||
return transform;
|
||||
}
|
||||
|
||||
protected get directCurveProgramName(): keyof ShaderMap<void> {
|
||||
if (this.antialiasingStrategy instanceof XCAAStrategy)
|
||||
return 'xcaaMultiDirectCurve';
|
||||
protected directCurveProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||
if (this.antialiasingStrategy instanceof XCAAStrategy && pass === 0)
|
||||
return 'xcaaMultiBGDirectCurve';
|
||||
return 'directCurve';
|
||||
}
|
||||
|
||||
protected get directInteriorProgramName(): keyof ShaderMap<void> {
|
||||
if (this.antialiasingStrategy instanceof XCAAStrategy)
|
||||
return 'xcaaMultiDirectInterior';
|
||||
protected directInteriorProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||
if (this.antialiasingStrategy instanceof XCAAStrategy && pass === 0)
|
||||
return 'xcaaMultiBGDirectInterior';
|
||||
return 'directInterior';
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ import {panic, unwrapNull} from "./utils";
|
|||
|
||||
export const BUILTIN_SVG_URI: string = "/svg/demo";
|
||||
|
||||
const parseColor = require('parse-color');
|
||||
|
||||
const PARTITION_SVG_PATHS_ENDPOINT_URL: string = "/partition-svg-paths";
|
||||
|
||||
/// The minimum size of a stroke.
|
||||
|
@ -105,9 +107,9 @@ export class SVGLoader {
|
|||
|
||||
if (element instanceof SVGPathElement) {
|
||||
const style = window.getComputedStyle(element);
|
||||
if (style.fill !== 'none')
|
||||
if (hasRenderingOperation(style.fill))
|
||||
this.pathInstances.push({ element: element, stroke: 'fill' });
|
||||
if (style.stroke !== 'none') {
|
||||
if (hasRenderingOperation(style.stroke)) {
|
||||
this.pathInstances.push({
|
||||
element: element,
|
||||
stroke: parseInt(style.strokeWidth!, 10),
|
||||
|
@ -159,3 +161,7 @@ export class SVGLoader {
|
|||
this.bounds = glmatrix.vec4.clone([minX, minY, maxX, maxY]);
|
||||
}
|
||||
}
|
||||
|
||||
function hasRenderingOperation(style: string | null): boolean {
|
||||
return style != null && style !== 'none' && parseColor(style).rgba[3] > 0.0;
|
||||
}
|
||||
|
|
|
@ -109,14 +109,6 @@ export abstract class TextRenderer extends Renderer {
|
|||
return glmatrix.vec2.create();
|
||||
}
|
||||
|
||||
protected get directCurveProgramName(): keyof ShaderMap<void> {
|
||||
return 'directCurve';
|
||||
}
|
||||
|
||||
protected get directInteriorProgramName(): keyof ShaderMap<void> {
|
||||
return 'directInterior';
|
||||
}
|
||||
|
||||
protected get depthFunction(): number {
|
||||
return this.renderContext.gl.GREATER;
|
||||
}
|
||||
|
@ -272,4 +264,12 @@ export abstract class TextRenderer extends Renderer {
|
|||
this.displayPixelsPerUnit,
|
||||
this.renderContext.useHinting);
|
||||
}
|
||||
|
||||
protected directCurveProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||
return 'directCurve';
|
||||
}
|
||||
|
||||
protected directInteriorProgramNameForPass(pass: number): keyof ShaderMap<void> {
|
||||
return 'directInterior';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,9 +47,9 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
|
||||
protected resolveVAO: WebGLVertexArrayObject;
|
||||
protected aaAlphaTexture: WebGLTexture;
|
||||
protected aaFramebuffer: WebGLFramebuffer;
|
||||
|
||||
private directFramebuffer: WebGLFramebuffer;
|
||||
private aaFramebuffer: WebGLFramebuffer;
|
||||
|
||||
constructor(level: number, subpixelAA: SubpixelAAType) {
|
||||
super();
|
||||
|
@ -66,7 +66,6 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
|
||||
attachMeshes(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
this.createEdgeDetectVAO(renderContext);
|
||||
this.createResolveVAO(renderer);
|
||||
}
|
||||
|
||||
|
@ -78,13 +77,12 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
this.destFramebufferSize,
|
||||
this.supersampleScale);
|
||||
|
||||
this.initDirectFramebuffer(renderer);
|
||||
this.initDirectFramebufferIfNecessary(renderer);
|
||||
this.initAAAlphaFramebuffer(renderer);
|
||||
this.initEdgeDetectFramebuffer(renderer);
|
||||
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, null);
|
||||
}
|
||||
|
||||
prepare(renderer: Renderer) {
|
||||
prepareForDirectRendering(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
|
@ -105,14 +103,17 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
}
|
||||
|
||||
antialias(renderer: Renderer) {
|
||||
// Detect edges if necessary.
|
||||
this.detectEdgesIfNecessary(renderer);
|
||||
// Perform early preparations.
|
||||
this.createPathBoundsBufferTexture(renderer);
|
||||
|
||||
// Mask edges if necessary.
|
||||
this.maskEdgesIfNecessary(renderer);
|
||||
|
||||
// Set up antialiasing.
|
||||
this.prepareAA(renderer);
|
||||
|
||||
// Clear.
|
||||
this.clear(renderer);
|
||||
this.clearForAA(renderer);
|
||||
}
|
||||
|
||||
resolve(renderer: Renderer) {
|
||||
|
@ -124,20 +125,14 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
return glmatrix.mat4.create();
|
||||
}
|
||||
|
||||
protected initDirectFramebuffer(renderer: Renderer) {
|
||||
protected initDirectFramebufferIfNecessary(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
let textureFormat;
|
||||
if (this.directRenderingMode === 'pathID')
|
||||
textureFormat = gl.RGBA;
|
||||
else
|
||||
textureFormat = renderContext.colorAlphaFormat;
|
||||
|
||||
this.directTexture = createFramebufferColorTexture(gl,
|
||||
this.destFramebufferSize,
|
||||
textureFormat);
|
||||
this.directFramebuffer = createFramebuffer(renderContext.gl,
|
||||
renderContext.colorAlphaFormat);
|
||||
this.directFramebuffer = createFramebuffer(gl,
|
||||
this.directTexture,
|
||||
this.directDepthTexture);
|
||||
}
|
||||
|
@ -159,8 +154,6 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
this.supersampledFramebufferSize[1]);
|
||||
renderContext.gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
||||
renderContext.gl.enable(renderContext.gl.SCISSOR_TEST);
|
||||
|
||||
this.createPathBoundsBufferTexture(renderer);
|
||||
}
|
||||
|
||||
protected setAAState(renderer: Renderer) {
|
||||
|
@ -200,8 +193,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
gl.viewport(0, 0, this.destFramebufferSize[0], this.destFramebufferSize[1]);
|
||||
gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
||||
gl.enable(gl.SCISSOR_TEST);
|
||||
gl.disable(gl.DEPTH_TEST);
|
||||
gl.disable(gl.BLEND);
|
||||
this.setDepthAndBlendModeForResolve(renderContext);
|
||||
|
||||
// Clear out the resolve buffer, if necessary.
|
||||
this.clearForResolve(renderer);
|
||||
|
@ -224,15 +216,25 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
|||
if (renderer.fgColor != null)
|
||||
gl.uniform4fv(resolveProgram.uniforms.uFGColor, renderer.fgColor);
|
||||
renderer.setTransformSTAndTexScaleUniformsForDest(resolveProgram.uniforms);
|
||||
this.setAdditionalStateForResolveIfNecessary(renderer, resolveProgram, 1);
|
||||
gl.drawElements(renderContext.gl.TRIANGLES, 6, renderContext.gl.UNSIGNED_BYTE, 0);
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected abstract clear(renderer: Renderer): void;
|
||||
protected setDepthAndBlendModeForResolve(renderContext: RenderContext): void {
|
||||
const gl = renderContext.gl;
|
||||
gl.disable(gl.DEPTH_TEST);
|
||||
gl.disable(gl.BLEND);
|
||||
}
|
||||
|
||||
protected setAdditionalStateForResolveIfNecessary(renderer: Renderer,
|
||||
resolveProgram: PathfinderShaderProgram,
|
||||
firstFreeTextureUnit: number):
|
||||
void {}
|
||||
|
||||
protected abstract clearForAA(renderer: Renderer): void;
|
||||
protected abstract getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram;
|
||||
protected abstract initEdgeDetectFramebuffer(renderer: Renderer): void;
|
||||
protected abstract createEdgeDetectVAO(renderContext: RenderContext): void;
|
||||
protected abstract detectEdgesIfNecessary(renderer: Renderer): void;
|
||||
protected abstract maskEdgesIfNecessary(renderer: Renderer): void;
|
||||
protected abstract setAADepthState(renderer: Renderer): void;
|
||||
protected abstract clearForResolve(renderer: Renderer): void;
|
||||
|
||||
|
@ -323,7 +325,7 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
renderContext.gl.blendFunc(renderContext.gl.ONE, renderContext.gl.ONE);
|
||||
renderContext.gl.enable(renderContext.gl.BLEND);
|
||||
|
||||
this.clear(renderer);
|
||||
this.clearForAA(renderer);
|
||||
}
|
||||
|
||||
protected setCoverDepthState(renderer: Renderer): void {
|
||||
|
@ -331,6 +333,64 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
renderContext.gl.disable(renderContext.gl.DEPTH_TEST);
|
||||
}
|
||||
|
||||
protected antialiasLinesWithProgram(renderer: Renderer,
|
||||
lineProgram: PathfinderShaderProgram): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
|
||||
const uniforms = lineProgram.uniforms;
|
||||
this.setAAUniforms(renderer, uniforms);
|
||||
|
||||
for (const direction of DIRECTIONS) {
|
||||
const vao = this.lineVAOs[direction];
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
this.setBlendModeForAA(renderer, direction);
|
||||
renderContext.gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
||||
|
||||
const count = {
|
||||
lower: renderer.meshData[0].edgeLowerLineCount,
|
||||
upper: renderer.meshData[0].edgeUpperLineCount,
|
||||
}[direction];
|
||||
renderContext.instancedArraysExt
|
||||
.drawElementsInstancedANGLE(renderContext.gl.TRIANGLES,
|
||||
6,
|
||||
renderContext.gl.UNSIGNED_BYTE,
|
||||
0,
|
||||
count);
|
||||
}
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected antialiasCurvesWithProgram(renderer: Renderer,
|
||||
curveProgram: PathfinderShaderProgram): void {
|
||||
const renderContext = renderer.renderContext;
|
||||
|
||||
const uniforms = curveProgram.uniforms;
|
||||
this.setAAUniforms(renderer, uniforms);
|
||||
|
||||
for (const direction of DIRECTIONS) {
|
||||
const vao = this.curveVAOs[direction];
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
this.setBlendModeForAA(renderer, direction);
|
||||
renderContext.gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
||||
|
||||
const count = {
|
||||
lower: renderer.meshData[0].edgeLowerCurveCount,
|
||||
upper: renderer.meshData[0].edgeUpperCurveCount,
|
||||
}[direction];
|
||||
renderContext.instancedArraysExt
|
||||
.drawElementsInstancedANGLE(renderContext.gl.TRIANGLES,
|
||||
6,
|
||||
renderContext.gl.UNSIGNED_BYTE,
|
||||
0,
|
||||
count);
|
||||
}
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
private createCoverVAO(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
|
||||
|
@ -561,35 +621,13 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
|
||||
private antialiasLines(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
|
||||
this.setAAState(renderer);
|
||||
|
||||
const lineProgram = renderContext.shaderPrograms.mcaaLine;
|
||||
|
||||
renderContext.gl.useProgram(lineProgram.program);
|
||||
const uniforms = lineProgram.uniforms;
|
||||
this.setAAUniforms(renderer, uniforms);
|
||||
|
||||
for (const direction of DIRECTIONS) {
|
||||
const vao = this.lineVAOs[direction];
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
this.setBlendModeForAA(renderer, direction);
|
||||
renderContext.gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
||||
|
||||
const count = {
|
||||
lower: renderer.meshData[0].edgeLowerLineCount,
|
||||
upper: renderer.meshData[0].edgeUpperLineCount,
|
||||
}[direction];
|
||||
renderContext.instancedArraysExt
|
||||
.drawElementsInstancedANGLE(renderContext.gl.TRIANGLES,
|
||||
6,
|
||||
renderContext.gl.UNSIGNED_BYTE,
|
||||
0,
|
||||
count);
|
||||
}
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
// FIXME(pcwalton): Refactor.
|
||||
this.antialiasLinesWithProgram(renderer, lineProgram);
|
||||
}
|
||||
|
||||
private antialiasCurves(renderer: Renderer) {
|
||||
|
@ -600,30 +638,10 @@ export abstract class MCAAStrategy extends XCAAStrategy {
|
|||
const curveProgram = renderContext.shaderPrograms.mcaaCurve;
|
||||
|
||||
renderContext.gl.useProgram(curveProgram.program);
|
||||
const uniforms = curveProgram.uniforms;
|
||||
this.setAAUniforms(renderer, uniforms);
|
||||
|
||||
for (const direction of DIRECTIONS) {
|
||||
const vao = this.curveVAOs[direction];
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||
|
||||
this.setBlendModeForAA(renderer, direction);
|
||||
renderContext.gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0);
|
||||
|
||||
const count = {
|
||||
lower: renderer.meshData[0].edgeLowerCurveCount,
|
||||
upper: renderer.meshData[0].edgeUpperCurveCount,
|
||||
}[direction];
|
||||
renderContext.instancedArraysExt
|
||||
.drawElementsInstancedANGLE(renderContext.gl.TRIANGLES,
|
||||
6,
|
||||
renderContext.gl.UNSIGNED_BYTE,
|
||||
0,
|
||||
count);
|
||||
}
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
this.antialiasCurvesWithProgram(renderer, curveProgram);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ECAAStrategy extends XCAAStrategy {
|
||||
|
@ -663,13 +681,9 @@ export class ECAAStrategy extends XCAAStrategy {
|
|||
return renderContext.shaderPrograms.xcaaMonoResolve;
|
||||
}
|
||||
|
||||
protected initEdgeDetectFramebuffer(renderer: Renderer) {}
|
||||
protected maskEdgesIfNecessary(renderer: Renderer) {}
|
||||
|
||||
protected createEdgeDetectVAO(renderContext: RenderContext) {}
|
||||
|
||||
protected detectEdgesIfNecessary(renderer: Renderer) {}
|
||||
|
||||
protected clear(renderer: Renderer) {
|
||||
protected clearForAA(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
renderContext.gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
renderContext.gl.clearDepth(0.0);
|
||||
|
@ -910,13 +924,9 @@ export class MCAAMonochromeStrategy extends MCAAStrategy {
|
|||
return renderContext.shaderPrograms.xcaaMonoResolve;
|
||||
}
|
||||
|
||||
protected initEdgeDetectFramebuffer(renderer: Renderer) {}
|
||||
protected maskEdgesIfNecessary(renderer: Renderer) {}
|
||||
|
||||
protected createEdgeDetectVAO(renderContext: RenderContext) {}
|
||||
|
||||
protected detectEdgesIfNecessary(renderer: Renderer) {}
|
||||
|
||||
protected clear(renderer: Renderer) {
|
||||
protected clearForAA(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
renderContext.gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
renderContext.gl.clearDepth(0.0);
|
||||
|
@ -975,8 +985,8 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
|||
return this.mcaaStrategy.transform;
|
||||
}
|
||||
|
||||
prepare(renderer: Renderer): void {
|
||||
this.getAppropriateStrategy(renderer).prepare(renderer);
|
||||
prepareForDirectRendering(renderer: Renderer): void {
|
||||
this.getAppropriateStrategy(renderer).prepareForDirectRendering(renderer);
|
||||
}
|
||||
|
||||
antialias(renderer: Renderer): void {
|
||||
|
@ -995,120 +1005,54 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
|||
}
|
||||
|
||||
export class MCAAMulticolorStrategy extends MCAAStrategy {
|
||||
private _directDepthTexture: WebGLTexture;
|
||||
private edgeMaskVAO: WebGLVertexArrayObject;
|
||||
|
||||
private edgeDetectFramebuffer: WebGLFramebuffer;
|
||||
private edgeDetectVAO: WebGLVertexArrayObject;
|
||||
private edgePathIDTexture: WebGLTexture;
|
||||
bindEdgeDepthTexture(gl: WebGLRenderingContext, uniforms: UniformMap, textureUnit: number):
|
||||
void {
|
||||
gl.activeTexture(gl.TEXTURE0 + textureUnit);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.aaDepthTexture);
|
||||
gl.uniform1i(uniforms.uEdgeDepth, textureUnit);
|
||||
}
|
||||
|
||||
protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram {
|
||||
return renderContext.shaderPrograms.xcaaMultiResolve;
|
||||
}
|
||||
|
||||
protected initDirectFramebuffer(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
this._directDepthTexture = createFramebufferDepthTexture(renderContext.gl,
|
||||
this.supersampledFramebufferSize);
|
||||
super.initDirectFramebuffer(renderer);
|
||||
}
|
||||
protected initDirectFramebufferIfNecessary(renderer: Renderer) {}
|
||||
|
||||
protected initEdgeDetectFramebuffer(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
this.edgePathIDTexture = createFramebufferColorTexture(renderContext.gl,
|
||||
this.supersampledFramebufferSize,
|
||||
renderContext.gl.RGBA);
|
||||
this.edgeDetectFramebuffer = createFramebuffer(renderContext.gl,
|
||||
this.edgePathIDTexture,
|
||||
this.aaDepthTexture);
|
||||
}
|
||||
|
||||
protected createEdgeDetectVAO(renderContext: RenderContext) {
|
||||
this.edgeDetectVAO = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.edgeDetectVAO);
|
||||
|
||||
const edgeDetectProgram = renderContext.shaderPrograms.xcaaEdgeDetect;
|
||||
renderContext.gl.useProgram(edgeDetectProgram.program);
|
||||
renderContext.initQuadVAO(edgeDetectProgram.attributes);
|
||||
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected detectEdgesIfNecessary(renderer: Renderer) {
|
||||
protected maskEdgesIfNecessary(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
// Set state for edge detection.
|
||||
const edgeDetectProgram = renderContext.shaderPrograms.xcaaEdgeDetect;
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, this.edgeDetectFramebuffer);
|
||||
// Set state for edge masking.
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, this.aaFramebuffer);
|
||||
gl.viewport(0,
|
||||
0,
|
||||
this.supersampledFramebufferSize[0],
|
||||
this.supersampledFramebufferSize[1]);
|
||||
|
||||
gl.colorMask(false, false, false, false);
|
||||
gl.depthMask(true);
|
||||
gl.depthFunc(renderContext.gl.ALWAYS);
|
||||
gl.enable(renderContext.gl.DEPTH_TEST);
|
||||
gl.disable(renderContext.gl.BLEND);
|
||||
gl.depthFunc(gl.GREATER);
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
gl.disable(gl.BLEND);
|
||||
|
||||
gl.clearDepth(0.0);
|
||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
|
||||
// Perform edge detection.
|
||||
gl.useProgram(edgeDetectProgram.program);
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.edgeDetectVAO);
|
||||
renderer.setFramebufferSizeUniform(edgeDetectProgram.uniforms);
|
||||
renderer.setTransformSTAndTexScaleUniformsForDest(edgeDetectProgram.uniforms);
|
||||
renderer.setPathColorsUniform(0, edgeDetectProgram.uniforms, 0);
|
||||
gl.activeTexture(renderContext.gl.TEXTURE1);
|
||||
gl.bindTexture(renderContext.gl.TEXTURE_2D, this.directTexture);
|
||||
gl.uniform1i(edgeDetectProgram.uniforms.uPathID, 1);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
||||
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
|
||||
// Perform edge masking.
|
||||
const edgeMaskLineProgram = renderer.renderContext.shaderPrograms.xcaaMultiEdgeMaskLine;
|
||||
gl.useProgram(edgeMaskLineProgram.program);
|
||||
this.antialiasLinesWithProgram(renderer, edgeMaskLineProgram);
|
||||
const edgeMaskCurveProgram = renderer.renderContext.shaderPrograms.xcaaMultiEdgeMaskCurve;
|
||||
gl.useProgram(edgeMaskCurveProgram.program);
|
||||
this.antialiasCurvesWithProgram(renderer, edgeMaskCurveProgram);
|
||||
|
||||
gl.colorMask(true, true, true, true);
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
}
|
||||
|
||||
protected resolveAA(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
// Set state for ECAA resolve.
|
||||
const usedSize = renderer.destUsedSize;
|
||||
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, renderer.destFramebuffer);
|
||||
renderContext.gl.viewport(0, 0, this.destFramebufferSize[0], this.destFramebufferSize[1]);
|
||||
renderContext.gl.scissor(0, 0, usedSize[0], usedSize[1]);
|
||||
renderContext.gl.enable(renderContext.gl.SCISSOR_TEST);
|
||||
renderContext.gl.disable(renderContext.gl.DEPTH_TEST);
|
||||
renderContext.gl.disable(renderContext.gl.BLEND);
|
||||
|
||||
// Resolve.
|
||||
const resolveProgram = this.getResolveProgram(renderContext);
|
||||
gl.useProgram(resolveProgram.program);
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO);
|
||||
gl.uniform2i(resolveProgram.uniforms.uFramebufferSize,
|
||||
this.destFramebufferSize[0],
|
||||
this.destFramebufferSize[1]);
|
||||
renderContext.gl.activeTexture(renderContext.gl.TEXTURE0);
|
||||
renderContext.gl.bindTexture(renderContext.gl.TEXTURE_2D, this.aaAlphaTexture);
|
||||
renderContext.gl.uniform1i(resolveProgram.uniforms.uAAAlpha, 0);
|
||||
renderContext.gl.uniform2i(resolveProgram.uniforms.uAAAlphaDimensions,
|
||||
this.supersampledFramebufferSize[0],
|
||||
this.supersampledFramebufferSize[1]);
|
||||
renderContext.gl.activeTexture(renderContext.gl.TEXTURE1);
|
||||
renderContext.gl.bindTexture(renderContext.gl.TEXTURE_2D, this.edgePathIDTexture);
|
||||
renderContext.gl.uniform1i(resolveProgram.uniforms.uBGFGPathID, 1);
|
||||
renderer.setPathColorsUniform(0, resolveProgram.uniforms, 2);
|
||||
renderer.setTransformSTAndTexScaleUniformsForDest(resolveProgram.uniforms);
|
||||
renderContext.gl.drawElements(renderContext.gl.TRIANGLES,
|
||||
6,
|
||||
renderContext.gl.UNSIGNED_BYTE,
|
||||
0);
|
||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||
|
||||
renderContext.gl.bindFramebuffer(renderContext.gl.FRAMEBUFFER, null);
|
||||
}
|
||||
|
||||
protected setCoverDepthState(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
renderContext.gl.depthMask(false);
|
||||
|
@ -1116,26 +1060,56 @@ export class MCAAMulticolorStrategy extends MCAAStrategy {
|
|||
renderContext.gl.enable(renderContext.gl.DEPTH_TEST);
|
||||
}
|
||||
|
||||
protected clear(renderer: Renderer) {
|
||||
protected clearForAA(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
renderContext.gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
renderContext.gl.clear(renderContext.gl.COLOR_BUFFER_BIT);
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
protected setAADepthState(renderer: Renderer) {
|
||||
const renderContext = renderer.renderContext;
|
||||
renderContext.gl.depthMask(false);
|
||||
renderContext.gl.depthFunc(renderContext.gl.EQUAL);
|
||||
renderContext.gl.enable(renderContext.gl.DEPTH_TEST);
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.depthMask(false);
|
||||
gl.depthFunc(gl.EQUAL);
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
}
|
||||
|
||||
protected setDepthAndBlendModeForResolve(renderContext: RenderContext): void {
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.depthMask(true);
|
||||
gl.depthFunc(gl.GREATER);
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
|
||||
gl.enable(gl.BLEND);
|
||||
}
|
||||
|
||||
protected clearForResolve(renderer: Renderer) {}
|
||||
|
||||
get directRenderingMode(): DirectRenderingMode {
|
||||
return 'pathID';
|
||||
protected setAdditionalStateForResolveIfNecessary(renderer: Renderer,
|
||||
resolveProgram: PathfinderShaderProgram,
|
||||
firstFreeTextureUnit: number):
|
||||
void {
|
||||
const renderContext = renderer.renderContext;
|
||||
const gl = renderContext.gl;
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0 + firstFreeTextureUnit + 0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.aaDepthTexture);
|
||||
gl.uniform1i(resolveProgram.uniforms.uAADepth, firstFreeTextureUnit + 0);
|
||||
|
||||
renderer.setPathColorsUniform(0, resolveProgram.uniforms, firstFreeTextureUnit + 1);
|
||||
}
|
||||
|
||||
protected get directDepthTexture(): WebGLTexture {
|
||||
return this._directDepthTexture;
|
||||
get directRenderingMode(): DirectRenderingMode {
|
||||
return 'two-pass';
|
||||
}
|
||||
|
||||
protected get directDepthTexture(): WebGLTexture | null {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,6 +109,11 @@ float convertPathIndexToWindowDepthValue(int pathIndex) {
|
|||
return float(pathIndex) / float(MAX_PATHS);
|
||||
}
|
||||
|
||||
int convertWindowDepthValueToPathIndex(float depthValue) {
|
||||
float pathIndex = floor(depthValue * float(MAX_PATHS));
|
||||
return int(pathIndex);
|
||||
}
|
||||
|
||||
bool computeMCAAQuadPosition(out vec2 outPosition,
|
||||
inout vec2 leftPosition,
|
||||
inout vec2 rightPosition,
|
||||
|
@ -261,6 +266,37 @@ float computeCoverage(vec2 p0, vec2 dp, vec2 center, float winding) {
|
|||
return abs(area) * winding * 0.5;
|
||||
}
|
||||
|
||||
// FIXME(pcwalton): Combine with `computeCoverage`.
|
||||
bool isPartiallyCovered(vec2 p0, vec2 dp, vec2 center, float winding) {
|
||||
// Set some flags.
|
||||
bool slopeNegative = dp.y < -0.001;
|
||||
bool slopeZero = abs(dp.y) < 0.001;
|
||||
|
||||
// Determine the bounds of this pixel.
|
||||
vec4 pixelExtents = center.xxyy + vec4(-0.5, 0.5, -0.5, 0.5);
|
||||
|
||||
// Set up Liang-Barsky clipping.
|
||||
vec4 q = pixelExtents - p0.xxyy;
|
||||
|
||||
// Use Liang-Barsky to clip to the left and right sides of this pixel.
|
||||
vec2 t = clamp(q.xy / dp.xx, 0.0, 1.0);
|
||||
vec2 spanP0 = p0 + dp * t.x, spanP1 = p0 + dp * t.y;
|
||||
|
||||
// Likewise, clip to the to the bottom and top.
|
||||
if (!slopeZero) {
|
||||
vec2 tVertical = q.zw / dp.yy;
|
||||
if (slopeNegative)
|
||||
tVertical.xy = tVertical.yx; // FIXME(pcwalton): Can this be removed?
|
||||
t = vec2(max(t.x, tVertical.x), min(t.y, tVertical.y));
|
||||
}
|
||||
|
||||
// If the line doesn't pass through this pixel, detect that and bail.
|
||||
//
|
||||
// This should be worth a branch because it's very common for fragment blocks to all hit this
|
||||
// path.
|
||||
return !(t.x >= t.y || (slopeZero && (p0.y < pixelExtents.z || p0.y > pixelExtents.w)));
|
||||
}
|
||||
|
||||
// https://www.freetype.org/freetype2/docs/reference/ft2-lcd_filtering.html
|
||||
float lcdFilter(float shadeL2, float shadeL1, float shade0, float shadeR1, float shadeR2) {
|
||||
return LCD_FILTER_FACTOR_2 * shadeL2 +
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-direct-curve.fs.glsl
|
||||
// pathfinder/shaders/gles2/xcaa-multi-bg-direct-curve.fs.glsl
|
||||
//
|
||||
// Copyright (c) 2017 The Pathfinder Project Developers.
|
||||
//
|
||||
|
@ -12,12 +12,23 @@
|
|||
|
||||
precision highp float;
|
||||
|
||||
varying vec2 vPathID;
|
||||
uniform ivec2 uFramebufferSize;
|
||||
uniform sampler2D uEdgeDepth;
|
||||
|
||||
varying vec4 vColor;
|
||||
varying vec2 vTexCoord;
|
||||
varying float vSign;
|
||||
|
||||
void main() {
|
||||
vec2 center = floor(gl_FragCoord.xy);
|
||||
float depth = gl_FragCoord.z;
|
||||
vec2 texCoord = floor(center) / vec2(uFramebufferSize);
|
||||
|
||||
// TODO(pcwalton): Remove this if possible?
|
||||
if (depth >= texture2D(uEdgeDepth, texCoord).r)
|
||||
discard;
|
||||
|
||||
float side = vTexCoord.x * vTexCoord.x - vTexCoord.y;
|
||||
float alpha = float(sign(side) == sign(vSign));
|
||||
gl_FragColor = vec4(vPathID, 0.0, alpha);
|
||||
gl_FragColor = vec4(vColor.rgb, vColor.a * alpha);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-direct-curve.vs.glsl
|
||||
// pathfinder/shaders/gles2/xcaa-multi-bg-direct-curve.vs.glsl
|
||||
//
|
||||
// Copyright (c) 2017 The Pathfinder Project Developers.
|
||||
//
|
||||
|
@ -12,6 +12,8 @@ precision highp float;
|
|||
|
||||
uniform mat4 uTransform;
|
||||
uniform vec4 uHints;
|
||||
uniform ivec2 uPathColorsDimensions;
|
||||
uniform sampler2D uPathColors;
|
||||
uniform ivec2 uPathTransformDimensions;
|
||||
uniform sampler2D uPathTransform;
|
||||
|
||||
|
@ -20,7 +22,7 @@ attribute vec2 aTexCoord;
|
|||
attribute float aPathID;
|
||||
attribute float aSign;
|
||||
|
||||
varying vec2 vPathID;
|
||||
varying vec4 vColor;
|
||||
varying vec2 vTexCoord;
|
||||
varying float vSign;
|
||||
|
||||
|
@ -36,7 +38,7 @@ void main() {
|
|||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||
gl_Position = vec4(position, depth, 1.0);
|
||||
|
||||
vPathID = packPathID(pathID);
|
||||
vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions);
|
||||
vTexCoord = vec2(aTexCoord) / 2.0;
|
||||
vSign = aSign;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-bg-direct-interior.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 highp float;
|
||||
|
||||
uniform ivec2 uFramebufferSize;
|
||||
uniform sampler2D uEdgeDepth;
|
||||
|
||||
varying vec4 vColor;
|
||||
|
||||
void main() {
|
||||
vec2 center = floor(gl_FragCoord.xy);
|
||||
float depth = gl_FragCoord.z;
|
||||
vec2 texCoord = floor(center) / vec2(uFramebufferSize);
|
||||
|
||||
// TODO(pcwalton): Remove this if possible?
|
||||
if (depth >= texture2D(uEdgeDepth, texCoord).r)
|
||||
discard;
|
||||
|
||||
gl_FragColor = vColor;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-direct-interior.vs.glsl
|
||||
// pathfinder/shaders/gles2/xcaa-multi-bg-direct-interior.vs.glsl
|
||||
//
|
||||
// Copyright (c) 2017 The Pathfinder Project Developers.
|
||||
//
|
||||
|
@ -12,13 +12,16 @@ precision highp float;
|
|||
|
||||
uniform mat4 uTransform;
|
||||
uniform vec4 uHints;
|
||||
uniform ivec2 uPathColorsDimensions;
|
||||
uniform ivec2 uPathTransformDimensions;
|
||||
uniform sampler2D uPathColors;
|
||||
uniform sampler2D uPathTransform;
|
||||
|
||||
attribute vec2 aPosition;
|
||||
attribute float aPathID;
|
||||
|
||||
varying vec2 vPathID;
|
||||
varying vec4 vColor;
|
||||
varying float vSign;
|
||||
|
||||
void main() {
|
||||
int pathID = int(aPathID);
|
||||
|
@ -32,5 +35,5 @@ void main() {
|
|||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||
gl_Position = vec4(position, depth, 1.0);
|
||||
|
||||
vPathID = packPathID(pathID);
|
||||
vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions);
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-direct-interior.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 highp float;
|
||||
|
||||
varying vec2 vPathID;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = vec4(vPathID, 0.0, 1.0);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-edge-mask-curve.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 highp float;
|
||||
|
||||
varying vec4 vEndpoints;
|
||||
varying vec2 vControlPoint;
|
||||
varying float vWinding;
|
||||
|
||||
// Solve the equation:
|
||||
//
|
||||
// x = p0x + t^2 * (p0x - 2*p1x + p2x) + t*(2*p1x - 2*p0x)
|
||||
//
|
||||
// We use the Citardauq Formula to avoid floating point precision issues.
|
||||
float solveCurveT(float p0x, float p1x, float p2x, float x) {
|
||||
float a = p0x - 2.0 * p1x + p2x;
|
||||
float b = 2.0 * p1x - 2.0 * p0x;
|
||||
float c = p0x - x;
|
||||
return 2.0 * c / (-b - sqrt(b * b - 4.0 * a * c));
|
||||
}
|
||||
|
||||
void main() {
|
||||
// Unpack.
|
||||
vec2 center = gl_FragCoord.xy;
|
||||
vec2 p0 = vEndpoints.xy, p1 = vEndpoints.zw;
|
||||
vec2 cp = vControlPoint;
|
||||
|
||||
// Compute pixel extents.
|
||||
vec4 pixelExtents = center.xxyy + vec4(-0.5, 0.5, -0.5, 0.5);
|
||||
|
||||
// Clip the curve to the left and right edges to create a line.
|
||||
//
|
||||
// TODO(pcwalton): Consider clipping to the bottom and top edges properly too. (I kind of doubt
|
||||
// it's worth it to do this, though, given that the maximum error doing it this way will always
|
||||
// be less than a pixel, and it saves a lot of time.)
|
||||
//
|
||||
// FIXME(pcwalton): Factor out shared terms to avoid computing them multiple times.
|
||||
vec2 t = vec2(p0.x < pixelExtents.x ? solveCurveT(p0.x, cp.x, p1.x, pixelExtents.x) : 0.0,
|
||||
p1.x > pixelExtents.y ? solveCurveT(p0.x, cp.x, p1.x, pixelExtents.y) : 1.0);
|
||||
|
||||
vec2 clippedP0 = mix(mix(p0, cp, t.x), mix(cp, p1, t.x), t.x);
|
||||
vec2 clippedP1 = mix(mix(p0, cp, t.y), mix(cp, p1, t.y), t.y);
|
||||
|
||||
// Discard if not edge.
|
||||
if (!isPartiallyCovered(clippedP0, clippedP1 - clippedP0, center, vWinding))
|
||||
discard;
|
||||
gl_FragColor = vec4(1.0);
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// pathfinder/shaders/gles2/xcaa-multi-edge-mask-line.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 highp float;
|
||||
|
||||
varying vec4 vEndpoints;
|
||||
varying float vWinding;
|
||||
|
||||
void main() {
|
||||
// Unpack.
|
||||
vec2 center = gl_FragCoord.xy;
|
||||
vec2 p0 = vEndpoints.xy, p1 = vEndpoints.zw;
|
||||
|
||||
// Set up Liang-Barsky clipping.
|
||||
vec4 pixelExtents = center.xxyy + vec4(-0.5, 0.5, -0.5, 0.5);
|
||||
vec2 dp = p1 - p0;
|
||||
vec4 q = pixelExtents - p0.xxyy;
|
||||
|
||||
// Use Liang-Barsky to clip to the left and right sides of this pixel.
|
||||
vec2 t = clamp(q.xy / dp.xx, 0.0, 1.0);
|
||||
vec2 spanP0 = p0 + dp * t.x, spanP1 = p0 + dp * t.y;
|
||||
|
||||
// Discard if not edge.
|
||||
if (!isPartiallyCovered(p0, dp, center, vWinding))
|
||||
discard;
|
||||
gl_FragColor = vec4(1.0);
|
||||
}
|
|
@ -11,20 +11,17 @@
|
|||
precision highp float;
|
||||
|
||||
uniform ivec2 uPathColorsDimensions;
|
||||
uniform sampler2D uBGFGPathID;
|
||||
uniform sampler2D uAAAlpha;
|
||||
uniform sampler2D uAADepth;
|
||||
uniform sampler2D uPathColors;
|
||||
|
||||
varying vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
vec4 packedPathIDsBGFG = texture2D(uBGFGPathID, vTexCoord);
|
||||
int pathIDBG = unpackPathID(packedPathIDsBGFG.xy);
|
||||
int pathIDFG = unpackPathID(packedPathIDsBGFG.zw);
|
||||
vec4 bgColor = fetchFloat4Data(uPathColors, pathIDBG, uPathColorsDimensions);
|
||||
vec4 fgColor = fetchFloat4Data(uPathColors, pathIDFG, uPathColorsDimensions);
|
||||
float alpha = clamp(texture2D(uAAAlpha, vTexCoord).r, 0.0, 1.0);
|
||||
gl_FragColor = mix(bgColor, fgColor, alpha);
|
||||
//gl_FragColor = vec4(vec3(alpha), 1.0);
|
||||
//gl_FragColor = bgColor != fgColor ? vec4(1.0, 0.0, 0.0, 1.0) : vec4(1.0);
|
||||
float edgeDepth = texture2D(uAADepth, vTexCoord).r;
|
||||
int edgePathID = convertWindowDepthValueToPathIndex(edgeDepth);
|
||||
vec4 edgeColor = fetchFloat4Data(uPathColors, edgePathID, uPathColorsDimensions);
|
||||
float edgeAlpha = texture2D(uAAAlpha, vTexCoord).r;
|
||||
gl_FragColor = vec4(edgeColor.rgb, edgeColor.a * edgeAlpha);
|
||||
gl_FragDepthEXT = edgeDepth;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue