diff --git a/demo/client/src/aa-strategy.ts b/demo/client/src/aa-strategy.ts index b743bbd6..54380ea4 100644 --- a/demo/client/src/aa-strategy.ts +++ b/demo/client/src/aa-strategy.ts @@ -18,7 +18,7 @@ import {DemoView} from './view'; export type AntialiasingStrategyName = 'none' | 'ssaa' | 'xcaa'; -export type DirectRenderingMode = 'none' | 'color' | 'color-depth'; +export type DirectRenderingMode = 'none' | 'color'; export type SubpixelAAType = 'none' | 'medium'; @@ -73,6 +73,9 @@ export abstract class AntialiasingStrategy { abstract antialiasObject(renderer: Renderer, objectIndex: number): void; // Called after antialiasing each object. + abstract finishAntialiasingObject(renderer: Renderer, objectIndex: number): void; + + // Called before rendering each object directly. abstract resolveAAForObject(renderer: Renderer, objectIndex: number): void; // Called after antialiasing. @@ -175,6 +178,8 @@ export class NoAAStrategy extends AntialiasingStrategy { antialiasObject(renderer: Renderer, objectIndex: number): void {} + finishAntialiasingObject(renderer: Renderer, objectIndex: number): void {} + resolveAAForObject(renderer: Renderer): void {} resolve(pass: number, renderer: Renderer): void {} diff --git a/demo/client/src/meshes.ts b/demo/client/src/meshes.ts index 18db9753..99214fbe 100644 --- a/demo/client/src/meshes.ts +++ b/demo/client/src/meshes.ts @@ -76,6 +76,7 @@ const B_QUAD_FIELD_COUNT: number = B_QUAD_SIZE / UINT32_SIZE; // FIXME(pcwalton): This duplicates information below in `MESH_TYPES`. const INDEX_SIZE: number = 4; +const B_QUAD_VERTEX_POSITION_SIZE: number = 12 * 4; const B_VERTEX_POSITION_SIZE: number = 4 * 2; const EDGE_BOUNDING_BOX_VERTEX_POSITION_SIZE: number = 4 * 4; const EDGE_UPPER_LINE_VERTEX_POSITION_SIZE: number = 4 * 4; @@ -86,6 +87,7 @@ const SEGMENT_LINE_SIZE: number = 4 * 4; const SEGMENT_CURVE_SIZE: number = 4 * 6; const MESH_TYPES: Meshes = { + bQuadVertexPositions: { type: 'Float32', size: 12 }, bQuads: { type: 'Uint32', size: B_QUAD_FIELD_COUNT }, bVertexLoopBlinnData: { type: 'Uint32', size: 1 }, bVertexNormals: { type: 'Float32', size: 1 }, @@ -112,6 +114,7 @@ const MESH_TYPES: Meshes = { }; const BUFFER_TYPES: Meshes = { + bQuadVertexPositions: 'ARRAY_BUFFER', bQuads: 'ARRAY_BUFFER', bVertexLoopBlinnData: 'ARRAY_BUFFER', bVertexNormals: 'ARRAY_BUFFER', @@ -146,6 +149,7 @@ const MESH_LIBRARY_FOURCC: string = 'PFML'; // Must match the FourCCs in `pathfinder_partitioner::mesh_library::MeshLibrary::serialize_into()`. const BUFFER_TYPE_FOURCCS: BufferTypeFourCCTable = { bqua: 'bQuads', + bqvp: 'bQuadVertexPositions', bvlb: 'bVertexLoopBlinnData', bvno: 'bVertexNormals', bvpo: 'bVertexPositions', @@ -166,6 +170,7 @@ const BUFFER_TYPE_FOURCCS: BufferTypeFourCCTable = { // `pathfinder_partitioner::mesh_library::MeshLibrary::serialize_into::write_path_ranges()`. const PATH_RANGE_TYPE_FOURCCS: PathRangeTypeFourCCTable = { bqua: 'bQuadPathRanges', + bqvp: 'bQuadVertexPositionPathRanges', bver: 'bVertexPathRanges', cvci: 'coverCurveIndexRanges', cvii: 'coverInteriorIndexRanges', @@ -180,6 +185,7 @@ const PATH_RANGE_TYPE_FOURCCS: PathRangeTypeFourCCTable = { const RANGE_TO_COUNT_TABLE: RangeToCountTable = { bQuadPathRanges: 'bQuadCount', + bQuadVertexPositionPathRanges: 'bQuadVertexPositionCount', bVertexPathRanges: 'bVertexCount', coverCurveIndexRanges: 'coverCurveCount', coverInteriorIndexRanges: 'coverInteriorCount', @@ -205,6 +211,7 @@ const RANGE_TO_RANGE_BUFFER_TABLE: RangeToRangeBufferTable = { const RANGE_KEYS: Array = [ 'bQuadPathRanges', + 'bQuadVertexPositionPathRanges', 'bVertexPathRanges', 'coverInteriorIndexRanges', 'coverCurveIndexRanges', @@ -221,6 +228,7 @@ type BufferType = 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER'; export interface Meshes { readonly bQuads: T; + readonly bQuadVertexPositions: T; readonly bVertexPositions: T; readonly bVertexLoopBlinnData: T; readonly bVertexNormals: T; @@ -248,6 +256,7 @@ export interface Meshes { interface MeshDataCounts { readonly bQuadCount: number; + readonly bQuadVertexPositionCount: number; readonly bVertexCount: number; readonly coverCurveCount: number; readonly coverInteriorCount: number; @@ -262,6 +271,7 @@ interface MeshDataCounts { interface PathRanges { bQuadPathRanges: Range[]; + bQuadVertexPositionPathRanges: Range[]; bVertexPathRanges: Range[]; coverInteriorIndexRanges: Range[]; coverCurveIndexRanges: Range[]; @@ -276,6 +286,7 @@ interface PathRanges { export class PathfinderMeshData implements Meshes, MeshDataCounts, PathRanges { readonly bQuads: ArrayBuffer; + readonly bQuadVertexPositions: ArrayBuffer; readonly bVertexPositions: ArrayBuffer; readonly bVertexLoopBlinnData: ArrayBuffer; readonly bVertexNormals: ArrayBuffer; @@ -292,6 +303,7 @@ export class PathfinderMeshData implements Meshes, MeshDataCounts, readonly segmentCurveNormals: ArrayBuffer; readonly bQuadCount: number; + readonly bQuadVertexPositionCount: number; readonly bVertexCount: number; readonly coverCurveCount: number; readonly coverInteriorCount: number; @@ -313,6 +325,7 @@ export class PathfinderMeshData implements Meshes, MeshDataCounts, segmentLinePathIDs: ArrayBuffer; bQuadPathRanges: Range[]; + bQuadVertexPositionPathRanges: Range[]; bVertexPathRanges: Range[]; coverInteriorIndexRanges: Range[]; coverCurveIndexRanges: Range[]; @@ -356,6 +369,8 @@ export class PathfinderMeshData implements Meshes, MeshDataCounts, } this.bQuadCount = this.bQuads.byteLength / B_QUAD_SIZE; + this.bQuadVertexPositionCount = this.bQuadVertexPositions.byteLength / + B_QUAD_VERTEX_POSITION_SIZE; this.bVertexCount = this.bVertexPositions.byteLength / B_VERTEX_POSITION_SIZE; this.coverCurveCount = this.coverCurveIndices.byteLength / INDEX_SIZE; this.coverInteriorCount = this.coverInteriorIndices.byteLength / INDEX_SIZE; @@ -421,6 +436,16 @@ export class PathfinderMeshData implements Meshes, MeshDataCounts, const firstBVertexIndex = bVertexCopyResult.originalStartIndex; const lastBVertexIndex = bVertexCopyResult.originalEndIndex; + // Copy over B-quad vertex positions. + copyVertices(['bQuadVertexPositions'], + 'bQuadVertexPositionPathRanges', + expandedArrays, + expandedRanges, + originalBuffers, + originalRanges, + expandedPathID, + originalPathID); + // Copy over edge data. copyVertices(['edgeBoundingBoxVertexPositions'], 'edgeBoundingBoxRanges', @@ -555,6 +580,7 @@ export class PathfinderMeshData implements Meshes, MeshDataCounts, export class PathfinderMeshBuffers implements Meshes, PathRanges { readonly bQuads: WebGLBuffer; + readonly bQuadVertexPositions: WebGLBuffer; readonly bVertexPositions: WebGLBuffer; readonly bVertexPathIDs: WebGLBuffer; readonly bVertexLoopBlinnData: WebGLBuffer; @@ -579,6 +605,7 @@ export class PathfinderMeshBuffers implements Meshes, PathRanges { readonly segmentCurveNormals: WebGLBuffer; readonly bQuadPathRanges: Range[]; + readonly bQuadVertexPositionPathRanges: Range[]; readonly bVertexPathRanges: Range[]; readonly coverInteriorIndexRanges: Range[]; readonly coverCurveIndexRanges: Range[]; diff --git a/demo/client/src/renderer.ts b/demo/client/src/renderer.ts index 50c20489..0c03bdce 100644 --- a/demo/client/src/renderer.ts +++ b/demo/client/src/renderer.ts @@ -22,7 +22,6 @@ import {CompositingOperation, RenderTaskType} from './render-task'; import {ShaderMap} from './shader-loader'; import {FLOAT32_SIZE, Range, UINT16_SIZE, UINT32_SIZE, unwrapNull, unwrapUndef} from './utils'; import {RenderContext, Timings} from "./view"; -import {ECAAMulticolorStrategy} from './xcaa-strategy'; const MAX_PATHS: number = 65535; @@ -161,11 +160,14 @@ export abstract class Renderer { // Antialias. antialiasingStrategy.antialiasObject(this, objectIndex); - // Prepare for direct rendering. - antialiasingStrategy.prepareToRenderObject(this, objectIndex); + // Perform post-antialiasing tasks. + antialiasingStrategy.finishAntialiasingObject(this, objectIndex); // Perform direct rendering (Loop-Blinn). if (antialiasingStrategy.directRenderingMode !== 'none') { + // Prepare for direct rendering. + antialiasingStrategy.prepareToRenderObject(this, objectIndex); + // Clear. this.clearForDirectRendering(objectIndex); @@ -420,9 +422,6 @@ export abstract class Renderer { gl.depthMask(true); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); break; - case 'color-depth': - gl.clear(gl.COLOR_BUFFER_BIT); - break; case 'none': // Nothing to do. break; @@ -496,10 +495,6 @@ export abstract class Renderer { this.pathTransformBufferTextures[meshIndex] .ext .bind(gl, directInteriorProgram.uniforms, 2); - if (renderingMode === 'color-depth') { - const strategy = antialiasingStrategy as ECAAMulticolorStrategy; - strategy.bindEdgeDepthTexture(gl, directInteriorProgram.uniforms, 3); - } const coverInteriorRange = getMeshIndexRange(meshes.coverInteriorIndexRanges, pathRange); if (!this.pathIDsAreInstanced) { gl.drawElements(gl.TRIANGLES, @@ -516,7 +511,7 @@ export abstract class Renderer { } // Set up direct curve state. - gl.depthMask(renderingMode === 'color-depth'); + gl.depthMask(false); gl.enable(gl.BLEND); gl.blendEquation(gl.FUNC_ADD); gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE); @@ -539,10 +534,6 @@ export abstract class Renderer { this.setEmboldenAmountUniform(objectIndex, directCurveProgram.uniforms); this.pathTransformBufferTextures[meshIndex].st.bind(gl, directCurveProgram.uniforms, 1); this.pathTransformBufferTextures[meshIndex].ext.bind(gl, directCurveProgram.uniforms, 2); - if (renderingMode === 'color-depth') { - const strategy = antialiasingStrategy as ECAAMulticolorStrategy; - strategy.bindEdgeDepthTexture(gl, directCurveProgram.uniforms, 3); - } const coverCurveRange = getMeshIndexRange(meshes.coverCurveIndexRanges, pathRange); if (!this.pathIDsAreInstanced) { gl.drawElements(gl.TRIANGLES, diff --git a/demo/client/src/shader-loader.ts b/demo/client/src/shader-loader.ts index 33717725..8ce6b067 100644 --- a/demo/client/src/shader-loader.ts +++ b/demo/client/src/shader-loader.ts @@ -27,15 +27,10 @@ export interface ShaderMap { mcaaCover: T; mcaaLine: T; mcaaCurve: T; + mcaaMulti: T; ssaaSubpixelResolve: T; xcaaMonoResolve: T; xcaaMonoSubpixelResolve: T; - xcaaMultiDirectCurve: T; - xcaaMultiDirectInterior: T; - xcaaMultiEdgeMaskCurve: T; - xcaaMultiEdgeMaskTransformedCurve: T; - xcaaMultiEdgeMaskLine: T; - xcaaMultiResolve: T; } export interface UnlinkedShaderProgram { @@ -57,17 +52,12 @@ export const SHADER_NAMES: Array> = [ 'mcaaCover', 'mcaaLine', 'mcaaCurve', + 'mcaaMulti', 'ecaaLine', 'ecaaCurve', 'ecaaTransformedCurve', 'xcaaMonoResolve', 'xcaaMonoSubpixelResolve', - 'xcaaMultiDirectCurve', - 'xcaaMultiDirectInterior', - 'xcaaMultiEdgeMaskCurve', - 'xcaaMultiEdgeMaskTransformedCurve', - 'xcaaMultiEdgeMaskLine', - 'xcaaMultiResolve', 'demo3DDistantGlyph', 'demo3DMonument', ]; @@ -133,6 +123,10 @@ const SHADER_URLS: ShaderMap = { fragment: "/glsl/gles2/xcaa-line.fs.glsl", vertex: "/glsl/gles2/mcaa-line.vs.glsl", }, + mcaaMulti: { + fragment: "/glsl/gles2/mcaa-multi.fs.glsl", + vertex: "/glsl/gles2/mcaa-multi.vs.glsl", + }, ssaaSubpixelResolve: { fragment: "/glsl/gles2/ssaa-subpixel-resolve.fs.glsl", vertex: "/glsl/gles2/blit.vs.glsl", @@ -145,30 +139,6 @@ const SHADER_URLS: ShaderMap = { 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", - }, - xcaaMultiDirectInterior: { - fragment: "/glsl/gles2/xcaa-multi-direct-interior.fs.glsl", - vertex: "/glsl/gles2/xcaa-multi-direct-interior.vs.glsl", - }, - xcaaMultiEdgeMaskCurve: { - fragment: "/glsl/gles2/xcaa-multi-edge-mask-curve.fs.glsl", - vertex: "/glsl/gles2/ecaa-multi-edge-mask-curve.vs.glsl", - }, - xcaaMultiEdgeMaskLine: { - fragment: "/glsl/gles2/xcaa-multi-edge-mask-line.fs.glsl", - vertex: "/glsl/gles2/ecaa-multi-edge-mask-line.vs.glsl", - }, - xcaaMultiEdgeMaskTransformedCurve: { - fragment: "/glsl/gles2/xcaa-multi-edge-mask-curve.fs.glsl", - vertex: "/glsl/gles2/ecaa-multi-edge-mask-transformed-curve.vs.glsl", - }, - xcaaMultiResolve: { - fragment: "/glsl/gles2/xcaa-multi-resolve.fs.glsl", - vertex: "/glsl/gles2/xcaa-multi-resolve.vs.glsl", - }, }; export interface ShaderProgramSource { diff --git a/demo/client/src/ssaa-strategy.ts b/demo/client/src/ssaa-strategy.ts index b07b95aa..ee5e87f0 100644 --- a/demo/client/src/ssaa-strategy.ts +++ b/demo/client/src/ssaa-strategy.ts @@ -167,6 +167,8 @@ export default class SSAAStrategy extends AntialiasingStrategy { antialiasObject(renderer: Renderer): void {} + finishAntialiasingObject(renderer: Renderer, objectIndex: number): void {} + resolveAAForObject(renderer: Renderer): void {} resolve(pass: number, renderer: Renderer): void { diff --git a/demo/client/src/svg-renderer.ts b/demo/client/src/svg-renderer.ts index b7964b4a..2aa58ac6 100644 --- a/demo/client/src/svg-renderer.ts +++ b/demo/client/src/svg-renderer.ts @@ -22,7 +22,7 @@ import SSAAStrategy from './ssaa-strategy'; import {SVGLoader} from './svg-loader'; import {Range} from './utils'; import {RenderContext} from './view'; -import {ECAAMulticolorStrategy, XCAAStrategy} from './xcaa-strategy'; +import {MCAAMulticolorStrategy, XCAAStrategy} from './xcaa-strategy'; interface AntialiasingStrategyTable { none: typeof NoAAStrategy; @@ -33,7 +33,7 @@ interface AntialiasingStrategyTable { const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = { none: NoAAStrategy, ssaa: SSAAStrategy, - xcaa: ECAAMulticolorStrategy, + xcaa: MCAAMulticolorStrategy, }; export abstract class SVGRenderer extends Renderer { @@ -41,6 +41,14 @@ export abstract class SVGRenderer extends Renderer { camera: OrthographicCamera; + get bgColor(): glmatrix.vec4 { + return glmatrix.vec4.clone([1.0, 1.0, 1.0, 1.0]); + } + + get fgColor(): glmatrix.vec4 { + return glmatrix.vec4.clone([0.0, 0.0, 0.0, 1.0]); + } + get usesSTTransform(): boolean { return this.camera.usesSTTransform; } @@ -150,14 +158,10 @@ export abstract class SVGRenderer extends Renderer { } protected directCurveProgramName(): keyof ShaderMap { - if (this.antialiasingStrategy instanceof XCAAStrategy) - return 'xcaaMultiDirectCurve'; return 'directCurve'; } protected directInteriorProgramName(): keyof ShaderMap { - if (this.antialiasingStrategy instanceof XCAAStrategy) - return 'xcaaMultiDirectInterior'; return 'directInterior'; } diff --git a/demo/client/src/xcaa-strategy.ts b/demo/client/src/xcaa-strategy.ts index 9ada28aa..b61dda92 100644 --- a/demo/client/src/xcaa-strategy.ts +++ b/demo/client/src/xcaa-strategy.ts @@ -41,6 +41,7 @@ export abstract class XCAAStrategy extends AntialiasingStrategy { } protected abstract get usesDilationTransforms(): boolean; + protected abstract get usesAAFramebuffer(): boolean; protected pathBoundsBufferTexture: PathfinderBufferTexture; @@ -49,11 +50,11 @@ export abstract class XCAAStrategy extends AntialiasingStrategy { protected subpixelAA: SubpixelAAType; - protected resolveVAO: WebGLVertexArrayObject; + protected resolveVAO: WebGLVertexArrayObject | null; - protected aaAlphaTexture: WebGLTexture; - protected aaDepthTexture: WebGLTexture; - protected aaFramebuffer: WebGLFramebuffer; + protected aaAlphaTexture: WebGLTexture | null; + protected aaDepthTexture: WebGLTexture | null; + protected aaFramebuffer: WebGLFramebuffer | null; protected renderTargetColorTextures: WebGLTexture[]; protected renderTargetDepthTextures: WebGLTexture[]; @@ -98,23 +99,27 @@ export abstract class XCAAStrategy extends AntialiasingStrategy { prepareForDirectRendering(renderer: Renderer): void {} - prepareToRenderObject(renderer: Renderer, objectIndex: number): void { + finishAntialiasingObject(renderer: Renderer, objectIndex: number): void { const renderContext = renderer.renderContext; const gl = renderContext.gl; this.initResolveFramebufferForObject(renderer, objectIndex); - const usedSize = this.supersampledUsedSize(renderer); - gl.scissor(0, 0, usedSize[0], usedSize[1]); - gl.enable(gl.SCISSOR_TEST); + if (this.usesAAFramebuffer) { + const usedSize = this.supersampledUsedSize(renderer); + gl.scissor(0, 0, usedSize[0], usedSize[1]); + gl.enable(gl.SCISSOR_TEST); - // Clear out the color and depth textures. - gl.clearColor(1.0, 1.0, 1.0, 1.0); - gl.clearDepth(0.0); - gl.depthMask(true); - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + // Clear out the color and depth textures. + gl.clearColor(1.0, 1.0, 1.0, 1.0); + gl.clearDepth(0.0); + gl.depthMask(true); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + } } + prepareToRenderObject(renderer: Renderer, objectIndex: number): void {} + finishDirectlyRenderingObject(renderer: Renderer, objectIndex: number): void { // TODO(pcwalton) } @@ -123,9 +128,6 @@ export abstract class XCAAStrategy extends AntialiasingStrategy { // Perform early preparations. this.createPathBoundsBufferTextureForObject(renderer, objectIndex); - // Mask edges if necessary. - this.maskEdgesOfObjectIfNecessary(renderer, objectIndex); - // Set up antialiasing. this.prepareAA(renderer); @@ -137,6 +139,10 @@ export abstract class XCAAStrategy extends AntialiasingStrategy { const renderContext = renderer.renderContext; const gl = renderContext.gl; + const resolveProgram = this.getResolveProgram(renderContext); + if (resolveProgram == null) + return; + // Set state for ECAA resolve. const usedSize = renderer.destUsedSize; gl.scissor(0, 0, usedSize[0], usedSize[1]); @@ -147,7 +153,6 @@ export abstract class XCAAStrategy extends AntialiasingStrategy { this.clearForResolve(renderer); // Resolve. - const resolveProgram = this.getResolveProgram(renderContext); gl.useProgram(resolveProgram.program); renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO); gl.uniform2i(resolveProgram.uniforms.uFramebufferSize, @@ -257,8 +262,8 @@ export abstract class XCAAStrategy extends AntialiasingStrategy { void {} protected abstract clearForAA(renderer: Renderer): void; - protected abstract getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram; - protected abstract maskEdgesOfObjectIfNecessary(renderer: Renderer, objectIndex: number): void; + protected abstract getResolveProgram(renderContext: RenderContext): + PathfinderShaderProgram | null; protected abstract setAADepthState(renderer: Renderer): void; protected abstract clearForResolve(renderer: Renderer): void; @@ -295,6 +300,13 @@ export abstract class XCAAStrategy extends AntialiasingStrategy { } private initAAAlphaFramebuffer(renderer: Renderer): void { + if (!this.usesAAFramebuffer) { + this.aaAlphaTexture = null; + this.aaDepthTexture = null; + this.aaFramebuffer = null; + return; + } + const renderContext = renderer.renderContext; const gl = renderContext.gl; @@ -329,10 +341,13 @@ export abstract class XCAAStrategy extends AntialiasingStrategy { const renderContext = renderer.renderContext; const gl = renderContext.gl; + const resolveProgram = this.getResolveProgram(renderContext); + if (resolveProgram == null) + return; + this.resolveVAO = renderContext.vertexArrayObjectExt.createVertexArrayOES(); renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.resolveVAO); - const resolveProgram = this.getResolveProgram(renderContext); gl.useProgram(resolveProgram.program); renderContext.initQuadVAO(resolveProgram.attributes); @@ -348,15 +363,20 @@ export abstract class XCAAStrategy extends AntialiasingStrategy { } } -export abstract class MCAAStrategy extends XCAAStrategy { - private coverVAO: WebGLVertexArrayObject; - private lineVAOs: FastEdgeVAOs; - private curveVAOs: FastEdgeVAOs; +export class MCAAMonochromeStrategy extends XCAAStrategy { + protected coverVAO: WebGLVertexArrayObject | null; + + protected lineVAOs: FastEdgeVAOs; + protected curveVAOs: FastEdgeVAOs; + + protected get usesDilationTransforms(): boolean { + return true; + } attachMeshes(renderer: Renderer): void { super.attachMeshes(renderer); - this.createCoverVAO(renderer); + this.createCoverVAOIfNecessary(renderer); this.createLineVAOs(renderer); this.createCurveVAOs(renderer); } @@ -365,13 +385,58 @@ export abstract class MCAAStrategy extends XCAAStrategy { super.antialiasObject(renderer, objectIndex); // Conservatively cover. - this.coverObject(renderer, objectIndex); + this.coverObjectIfNecessary(renderer, objectIndex); // Antialias. this.antialiasLinesOfObject(renderer, objectIndex); this.antialiasCurvesOfObject(renderer, objectIndex); } + protected get usesAAFramebuffer(): boolean { + return true; + } + + protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram { + if (this.subpixelAA !== 'none') + return renderContext.shaderPrograms.xcaaMonoSubpixelResolve; + return renderContext.shaderPrograms.xcaaMonoResolve; + } + + protected clearForAA(renderer: Renderer): void { + const renderContext = renderer.renderContext; + const gl = renderContext.gl; + + gl.clearColor(0.0, 0.0, 0.0, 0.0); + gl.clearDepth(0.0); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + } + + protected setAADepthState(renderer: Renderer): void { + const renderContext = renderer.renderContext; + renderContext.gl.disable(renderContext.gl.DEPTH_TEST); + } + + protected clearForResolve(renderer: Renderer): void { + const renderContext = renderer.renderContext; + const gl = renderContext.gl; + + gl.clearColor(1.0, 1.0, 1.0, 1.0); + gl.clear(gl.COLOR_BUFFER_BIT); + } + + protected createCoverVAOIfNecessary(renderer: Renderer): void { + this.coverVAO = renderer.renderContext.vertexArrayObjectExt.createVertexArrayOES(); + } + + protected setBlendModeForAA(renderer: Renderer): void { + const renderContext = renderer.renderContext; + const gl = renderContext.gl; + + gl.blendEquation(gl.FUNC_ADD); + gl.blendFunc(gl.ONE, gl.ONE); + gl.enable(gl.BLEND); + } + protected prepareAA(renderer: Renderer): void { super.prepareAA(renderer); @@ -415,7 +480,7 @@ export abstract class MCAAStrategy extends XCAAStrategy { const vao = this.lineVAOs[direction]; renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao); - this.setBlendModeForAA(renderer, direction); + this.setBlendModeForAA(renderer); gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0); const indexRanges = { @@ -431,6 +496,113 @@ export abstract class MCAAStrategy extends XCAAStrategy { renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); } + protected coverObjectIfNecessary(renderer: Renderer, objectIndex: number): void { + if (renderer.meshes == null || renderer.meshData == null) + return; + + const renderContext = renderer.renderContext; + const gl = renderContext.gl; + + const pathRange = renderer.pathRangeForObject(objectIndex); + const meshIndex = renderer.meshIndexForObject(objectIndex); + + this.initCoverVAOForObject(renderer, objectIndex); + + // Conservatively cover. + const coverProgram = renderContext.shaderPrograms.mcaaCover; + gl.useProgram(coverProgram.program); + renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO); + this.setAAUniforms(renderer, coverProgram.uniforms, objectIndex); + + const bQuadRange = renderer.meshData[meshIndex].bQuadPathRanges; + const count = calculateCountFromIndexRanges(pathRange, bQuadRange); + + renderContext.instancedArraysExt + .drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count); + renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); + } + + protected initCurveVAOsForObject(renderer: Renderer, objectIndex: number): void { + if (renderer.meshes == null || renderer.meshData == null) + return; + + const renderContext = renderer.renderContext; + const gl = renderContext.gl; + + const pathRange = renderer.pathRangeForObject(objectIndex); + const meshIndex = renderer.meshIndexForObject(objectIndex); + + const curveProgram = this.curveProgram(renderer); + const attributes = curveProgram.attributes; + + for (const direction of DIRECTIONS) { + const vao = this.curveVAOs[direction]; + renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao); + + const curveVertexPositionsBuffer = { + lower: renderer.meshes[meshIndex].edgeLowerCurveVertexPositions, + upper: renderer.meshes[meshIndex].edgeUpperCurveVertexPositions, + }[direction]; + const curvePathIDsBuffer = { + lower: renderer.meshes[meshIndex].edgeLowerCurvePathIDs, + upper: renderer.meshes[meshIndex].edgeUpperCurvePathIDs, + }[direction]; + const curveIndexRanges = { + lower: renderer.meshData[meshIndex].edgeLowerCurveIndexRanges, + upper: renderer.meshData[meshIndex].edgeUpperCurveIndexRanges, + }[direction]; + + const offset = calculateStartFromIndexRanges(pathRange, curveIndexRanges); + + gl.useProgram(curveProgram.program); + gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer); + gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, curveVertexPositionsBuffer); + gl.vertexAttribPointer(attributes.aLeftPosition, + 2, + gl.FLOAT, + false, + FLOAT32_SIZE * 6, + FLOAT32_SIZE * 6 * offset); + gl.vertexAttribPointer(attributes.aControlPointPosition, + 2, + gl.FLOAT, + false, + FLOAT32_SIZE * 6, + FLOAT32_SIZE * 6 * offset + FLOAT32_SIZE * 2); + gl.vertexAttribPointer(attributes.aRightPosition, + 2, + gl.FLOAT, + false, + FLOAT32_SIZE * 6, + FLOAT32_SIZE * 6 * offset + FLOAT32_SIZE * 4); + gl.bindBuffer(gl.ARRAY_BUFFER, curvePathIDsBuffer); + gl.vertexAttribPointer(attributes.aPathID, + 1, + gl.UNSIGNED_SHORT, + false, + 0, + UINT16_SIZE * offset); + + gl.enableVertexAttribArray(attributes.aQuadPosition); + gl.enableVertexAttribArray(attributes.aLeftPosition); + gl.enableVertexAttribArray(attributes.aControlPointPosition); + gl.enableVertexAttribArray(attributes.aRightPosition); + gl.enableVertexAttribArray(attributes.aPathID); + + renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1); + renderContext.instancedArraysExt + .vertexAttribDivisorANGLE(attributes.aControlPointPosition, 1); + renderContext.instancedArraysExt + .vertexAttribDivisorANGLE(attributes.aRightPosition, 1); + renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer); + } + + renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); + } + protected antialiasCurvesOfObjectWithProgram(renderer: Renderer, objectIndex: number, curveProgram: PathfinderShaderProgram): @@ -454,7 +626,7 @@ export abstract class MCAAStrategy extends XCAAStrategy { const vao = this.curveVAOs[direction]; renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao); - this.setBlendModeForAA(renderer, direction); + this.setBlendModeForAA(renderer); gl.uniform1i(uniforms.uWinding, direction === 'upper' ? 1 : 0); const indexRanges = { @@ -470,62 +642,12 @@ export abstract class MCAAStrategy extends XCAAStrategy { renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); } - private createCoverVAO(renderer: Renderer): void { - this.coverVAO = renderer.renderContext.vertexArrayObjectExt.createVertexArrayOES(); + protected lineProgram(renderer: Renderer): PathfinderShaderProgram { + return renderer.renderContext.shaderPrograms.mcaaLine; } - private initCoverVAOForObject(renderer: Renderer, objectIndex: number): void { - if (renderer.meshes == null || renderer.meshData == null) - return; - - const renderContext = renderer.renderContext; - const gl = renderContext.gl; - - const pathRange = renderer.pathRangeForObject(objectIndex); - const meshIndex = renderer.meshIndexForObject(objectIndex); - - renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO); - - const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges; - const offset = calculateStartFromIndexRanges(pathRange, bQuadRanges); - - const coverProgram = renderContext.shaderPrograms.mcaaCover; - const attributes = coverProgram.attributes; - gl.useProgram(coverProgram.program); - gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer); - gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0); - gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxVertexPositions); - gl.vertexAttribPointer(attributes.aUpperLeftPosition, - 2, - gl.FLOAT, - false, - FLOAT32_SIZE * 4, - FLOAT32_SIZE * 4 * offset); - gl.vertexAttribPointer(attributes.aLowerRightPosition, - 2, - gl.FLOAT, - false, - FLOAT32_SIZE * 4, - FLOAT32_SIZE * 4 * offset + FLOAT32_SIZE * 2); - gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxPathIDs); - gl.vertexAttribPointer(attributes.aPathID, - 1, - gl.UNSIGNED_SHORT, - false, - 0, - UINT16_SIZE * offset); - gl.enableVertexAttribArray(attributes.aQuadPosition); - gl.enableVertexAttribArray(attributes.aUpperLeftPosition); - gl.enableVertexAttribArray(attributes.aLowerRightPosition); - gl.enableVertexAttribArray(attributes.aPathID); - renderContext.instancedArraysExt - .vertexAttribDivisorANGLE(attributes.aUpperLeftPosition, 1); - renderContext.instancedArraysExt - .vertexAttribDivisorANGLE(attributes.aLowerRightPosition, 1); - renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer); - - renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); + protected curveProgram(renderer: Renderer): PathfinderShaderProgram { + return renderer.renderContext.shaderPrograms.mcaaCurve; } private createLineVAOs(renderer: Renderer): void { @@ -547,7 +669,7 @@ export abstract class MCAAStrategy extends XCAAStrategy { const pathRange = renderer.pathRangeForObject(objectIndex); const meshIndex = renderer.meshIndexForObject(objectIndex); - const lineProgram = renderContext.shaderPrograms.mcaaLine; + const lineProgram = this.lineProgram(renderer); const attributes = lineProgram.attributes; for (const direction of DIRECTIONS) { @@ -619,88 +741,11 @@ export abstract class MCAAStrategy extends XCAAStrategy { this.curveVAOs = vaos as FastEdgeVAOs; } - private initCurveVAOsForObject(renderer: Renderer, objectIndex: number): void { - if (renderer.meshes == null || renderer.meshData == null) - return; - - const renderContext = renderer.renderContext; - const gl = renderContext.gl; - - const pathRange = renderer.pathRangeForObject(objectIndex); - const meshIndex = renderer.meshIndexForObject(objectIndex); - - const curveProgram = renderContext.shaderPrograms.mcaaCurve; - const attributes = curveProgram.attributes; - - for (const direction of DIRECTIONS) { - const vao = this.curveVAOs[direction]; - renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao); - - const curveVertexPositionsBuffer = { - lower: renderer.meshes[meshIndex].edgeLowerCurveVertexPositions, - upper: renderer.meshes[meshIndex].edgeUpperCurveVertexPositions, - }[direction]; - const curvePathIDsBuffer = { - lower: renderer.meshes[meshIndex].edgeLowerCurvePathIDs, - upper: renderer.meshes[meshIndex].edgeUpperCurvePathIDs, - }[direction]; - const curveIndexRanges = { - lower: renderer.meshData[meshIndex].edgeLowerCurveIndexRanges, - upper: renderer.meshData[meshIndex].edgeUpperCurveIndexRanges, - }[direction]; - - const offset = calculateStartFromIndexRanges(pathRange, curveIndexRanges); - - gl.useProgram(curveProgram.program); - gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer); - gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0); - gl.bindBuffer(gl.ARRAY_BUFFER, curveVertexPositionsBuffer); - gl.vertexAttribPointer(attributes.aLeftPosition, - 2, - gl.FLOAT, - false, - FLOAT32_SIZE * 6, - FLOAT32_SIZE * 6 * offset); - gl.vertexAttribPointer(attributes.aControlPointPosition, - 2, - gl.FLOAT, - false, - FLOAT32_SIZE * 6, - FLOAT32_SIZE * 6 * offset + FLOAT32_SIZE * 2); - gl.vertexAttribPointer(attributes.aRightPosition, - 2, - gl.FLOAT, - false, - FLOAT32_SIZE * 6, - FLOAT32_SIZE * 6 * offset + FLOAT32_SIZE * 4); - gl.bindBuffer(gl.ARRAY_BUFFER, curvePathIDsBuffer); - gl.vertexAttribPointer(attributes.aPathID, - 1, - gl.UNSIGNED_SHORT, - false, - 0, - UINT16_SIZE * offset); - - gl.enableVertexAttribArray(attributes.aQuadPosition); - gl.enableVertexAttribArray(attributes.aLeftPosition); - gl.enableVertexAttribArray(attributes.aControlPointPosition); - gl.enableVertexAttribArray(attributes.aRightPosition); - gl.enableVertexAttribArray(attributes.aPathID); - - renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aLeftPosition, 1); - renderContext.instancedArraysExt - .vertexAttribDivisorANGLE(attributes.aControlPointPosition, 1); - renderContext.instancedArraysExt - .vertexAttribDivisorANGLE(attributes.aRightPosition, 1); - renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer); - } - - renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); + get directRenderingMode(): DirectRenderingMode { + return 'none'; } - private coverObject(renderer: Renderer, objectIndex: number): void { + private initCoverVAOForObject(renderer: Renderer, objectIndex: number): void { if (renderer.meshes == null || renderer.meshData == null) return; @@ -710,36 +755,55 @@ export abstract class MCAAStrategy extends XCAAStrategy { const pathRange = renderer.pathRangeForObject(objectIndex); const meshIndex = renderer.meshIndexForObject(objectIndex); - this.initCoverVAOForObject(renderer, objectIndex); - - // Conservatively cover. - const coverProgram = renderContext.shaderPrograms.mcaaCover; - gl.useProgram(coverProgram.program); renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.coverVAO); - this.setAAUniforms(renderer, coverProgram.uniforms, objectIndex); - const bQuadRange = renderer.meshData[meshIndex].bQuadPathRanges; - const count = calculateCountFromIndexRanges(pathRange, bQuadRange); + const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges; + const offset = calculateStartFromIndexRanges(pathRange, bQuadRanges); + const coverProgram = renderContext.shaderPrograms.mcaaCover; + const attributes = coverProgram.attributes; + gl.useProgram(coverProgram.program); + gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer); + gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxVertexPositions); + gl.vertexAttribPointer(attributes.aUpperLeftPosition, + 2, + gl.FLOAT, + false, + FLOAT32_SIZE * 4, + FLOAT32_SIZE * 4 * offset); + gl.vertexAttribPointer(attributes.aLowerRightPosition, + 2, + gl.FLOAT, + false, + FLOAT32_SIZE * 4, + FLOAT32_SIZE * 4 * offset + FLOAT32_SIZE * 2); + gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxPathIDs); + gl.vertexAttribPointer(attributes.aPathID, + 1, + gl.UNSIGNED_SHORT, + false, + 0, + UINT16_SIZE * offset); + gl.enableVertexAttribArray(attributes.aQuadPosition); + gl.enableVertexAttribArray(attributes.aUpperLeftPosition); + gl.enableVertexAttribArray(attributes.aLowerRightPosition); + gl.enableVertexAttribArray(attributes.aPathID); renderContext.instancedArraysExt - .drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count); + .vertexAttribDivisorANGLE(attributes.aUpperLeftPosition, 1); + renderContext.instancedArraysExt + .vertexAttribDivisorANGLE(attributes.aLowerRightPosition, 1); + renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer); + renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); } - private setBlendModeForAA(renderer: Renderer, direction: 'upper' | 'lower'): void { - const renderContext = renderer.renderContext; - const gl = renderContext.gl; - - gl.blendEquation(gl.FUNC_ADD); - gl.blendFunc(gl.ONE, gl.ONE); - gl.enable(gl.BLEND); - } - private antialiasLinesOfObject(renderer: Renderer, objectIndex: number): void { const renderContext = renderer.renderContext; this.setAAState(renderer); - const lineProgram = renderContext.shaderPrograms.mcaaLine; + const lineProgram = this.lineProgram(renderer); renderContext.gl.useProgram(lineProgram.program); // FIXME(pcwalton): Refactor. @@ -750,7 +814,7 @@ export abstract class MCAAStrategy extends XCAAStrategy { const renderContext = renderer.renderContext; this.setAAState(renderer); - const curveProgram = renderContext.shaderPrograms.mcaaCurve; + const curveProgram = this.curveProgram(renderer); renderContext.gl.useProgram(curveProgram.program); this.antialiasCurvesOfObjectWithProgram(renderer, objectIndex, curveProgram); @@ -803,8 +867,6 @@ export abstract class ECAAStrategy extends XCAAStrategy { return renderContext.shaderPrograms.xcaaMonoResolve; } - protected maskEdgesOfObjectIfNecessary(renderer: Renderer, objectIndex: number): void {} - protected clearForAA(renderer: Renderer): void { const renderContext = renderer.renderContext; const gl = renderContext.gl; @@ -1078,6 +1140,10 @@ export class ECAAMonochromeStrategy extends ECAAStrategy { return false; } + protected get usesAAFramebuffer(): boolean { + return true; + } + protected get lineShaderProgramNames(): Array> { return ['ecaaLine']; } @@ -1087,39 +1153,182 @@ export class ECAAMonochromeStrategy extends ECAAStrategy { } } -export class MCAAMonochromeStrategy extends MCAAStrategy { +export class MCAAMulticolorStrategy extends XCAAStrategy { + protected vao: WebGLVertexArrayObject; + protected get usesDilationTransforms(): boolean { return true; } - protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram { - if (this.subpixelAA !== 'none') - return renderContext.shaderPrograms.xcaaMonoSubpixelResolve; - return renderContext.shaderPrograms.xcaaMonoResolve; + attachMeshes(renderer: Renderer): void { + super.attachMeshes(renderer); + + const renderContext = renderer.renderContext; + this.vao = renderContext.vertexArrayObjectExt.createVertexArrayOES(); } - protected maskEdgesOfObjectIfNecessary(renderer: Renderer, objectIndex: number): void {} + antialiasObject(renderer: Renderer, objectIndex: number): void { + super.antialiasObject(renderer, objectIndex); + + const shaderProgram = this.edgeProgram(renderer); + this.antialiasEdgesOfObjectWithProgram(renderer, objectIndex, shaderProgram); + } + + protected get usesAAFramebuffer(): boolean { + return false; + } + + protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram | null { + return null; + } + + protected prepareAA(renderer: Renderer): void { + super.prepareAA(renderer); + + this.clearForAA(renderer); + } + + protected coverObjectIfNecessary(renderer: Renderer, objectIndex: number): void {} + + protected antialiasEdgesOfObjectWithProgram(renderer: Renderer, + objectIndex: number, + shaderProgram: PathfinderShaderProgram): + void { + if (renderer.meshData == null) + return; + + const renderContext = renderer.renderContext; + const gl = renderContext.gl; + + const pathRange = renderer.pathRangeForObject(objectIndex); + const meshIndex = renderer.meshIndexForObject(objectIndex); + + this.initVAOForObject(renderer, objectIndex); + + gl.useProgram(shaderProgram.program); + const uniforms = shaderProgram.uniforms; + this.setAAUniforms(renderer, uniforms, objectIndex); + + // FIXME(pcwalton): Refactor. + const vao = this.vao; + renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao); + + this.setBlendModeForAA(renderer); + + const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges; + const count = calculateCountFromIndexRanges(pathRange, bQuadRanges); + + renderContext.instancedArraysExt + .drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count); + + renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); + } protected clearForAA(renderer: Renderer): void { const renderContext = renderer.renderContext; const gl = renderContext.gl; - gl.clearColor(0.0, 0.0, 0.0, 0.0); + gl.clearColor(1.0, 1.0, 1.0, 1.0); gl.clearDepth(0.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); } protected setAADepthState(renderer: Renderer): void { const renderContext = renderer.renderContext; - renderContext.gl.disable(renderContext.gl.DEPTH_TEST); + const gl = renderContext.gl; + + gl.disable(gl.DEPTH_TEST); } - protected clearForResolve(renderer: Renderer): void { + protected clearForResolve(renderer: Renderer): void {} + + protected setBlendModeForAA(renderer: Renderer): void { const renderContext = renderer.renderContext; const gl = renderContext.gl; - gl.clearColor(0.0, 0.0, 0.0, 0.0); - gl.clear(gl.COLOR_BUFFER_BIT); + gl.blendEquation(gl.FUNC_ADD); + gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE); + gl.enable(gl.BLEND); + } + + protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number): + void { + super.setAAUniforms(renderer, uniforms, objectIndex); + renderer.setPathColorsUniform(0, uniforms, 2); + } + + protected initVAOForObject(renderer: Renderer, objectIndex: number): void { + if (renderer.meshes == null || renderer.meshData == null) + return; + + const renderContext = renderer.renderContext; + const gl = renderContext.gl; + + const pathRange = renderer.pathRangeForObject(objectIndex); + const meshIndex = renderer.meshIndexForObject(objectIndex); + + const shaderProgram = this.edgeProgram(renderer); + const attributes = shaderProgram.attributes; + + // FIXME(pcwalton): Refactor. + const vao = this.vao; + renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao); + + const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges; + const offset = calculateStartFromIndexRanges(pathRange, bQuadRanges); + + gl.useProgram(shaderProgram.program); + gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer); + gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].bQuadVertexPositions); + gl.vertexAttribPointer(attributes.aUpperEndpointPositions, + 4, + gl.FLOAT, + false, + FLOAT32_SIZE * 12, + FLOAT32_SIZE * 12 * offset); + gl.vertexAttribPointer(attributes.aLowerEndpointPositions, + 4, + gl.FLOAT, + false, + FLOAT32_SIZE * 12, + FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 4); + gl.vertexAttribPointer(attributes.aControlPointPositions, + 4, + gl.FLOAT, + false, + FLOAT32_SIZE * 12, + FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 8); + gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxPathIDs); + gl.vertexAttribPointer(attributes.aPathID, + 1, + gl.UNSIGNED_SHORT, + false, + 0, + UINT16_SIZE * offset); + gl.enableVertexAttribArray(attributes.aQuadPosition); + gl.enableVertexAttribArray(attributes.aUpperEndpointPositions); + gl.enableVertexAttribArray(attributes.aLowerEndpointPositions); + gl.enableVertexAttribArray(attributes.aControlPointPositions); + gl.enableVertexAttribArray(attributes.aPathID); + renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer); + + renderContext.instancedArraysExt + .vertexAttribDivisorANGLE(attributes.aUpperEndpointPositions, 1); + renderContext.instancedArraysExt + .vertexAttribDivisorANGLE(attributes.aLowerEndpointPositions, 1); + renderContext.instancedArraysExt + .vertexAttribDivisorANGLE(attributes.aControlPointPositions, 1); + renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer); + + renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); + } + + protected edgeProgram(renderer: Renderer): PathfinderShaderProgram { + return renderer.renderContext.shaderPrograms.mcaaMulti; } get directRenderingMode(): DirectRenderingMode { @@ -1174,6 +1383,10 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy { this.getAppropriateStrategy(renderer).prepareForDirectRendering(renderer); } + finishAntialiasingObject(renderer: Renderer, objectIndex: number): void { + this.getAppropriateStrategy(renderer).finishAntialiasingObject(renderer, objectIndex); + } + prepareToRenderObject(renderer: Renderer, objectIndex: number): void { this.getAppropriateStrategy(renderer).prepareToRenderObject(renderer, objectIndex); } @@ -1208,132 +1421,6 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy { } } -export class ECAAMulticolorStrategy extends ECAAStrategy { - protected get usesDilationTransforms(): boolean { - return false; - } - - protected get lineShaderProgramNames(): Array> { - return ['ecaaLine', 'xcaaMultiEdgeMaskLine']; - } - - protected get curveShaderProgramNames(): Array> { - return [ - 'ecaaCurve', - 'ecaaTransformedCurve', - 'xcaaMultiEdgeMaskCurve', - 'xcaaMultiEdgeMaskTransformedCurve', - ]; - } - - private edgeMaskVAO: WebGLVertexArrayObject; - - 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); - gl.activeTexture(gl.TEXTURE0 + textureUnit + 1); - gl.bindTexture(gl.TEXTURE_2D, this.aaAlphaTexture); - gl.uniform1i(uniforms.uEdgeAlpha, textureUnit); - } - - protected getResolveProgram(renderContext: RenderContext): PathfinderShaderProgram { - return renderContext.shaderPrograms.xcaaMultiResolve; - } - - protected initDirectFramebufferIfNecessary(renderer: Renderer): void {} - - protected maskEdgesOfObjectIfNecessary(renderer: Renderer, objectIndex: number): void { - const renderContext = renderer.renderContext; - const gl = renderContext.gl; - - // Set state for edge masking. - gl.bindFramebuffer(gl.FRAMEBUFFER, this.aaFramebuffer); - gl.viewport(0, - 0, - this.supersampledFramebufferSize[0], - this.supersampledFramebufferSize[1]); - - gl.colorMask(true, true, true, true); - gl.depthMask(true); - 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 masking. - gl.colorMask(false, false, false, false); - this.antialiasLinesOfObjectWithProgram(renderer, objectIndex, 'xcaaMultiEdgeMaskLine'); - this.antialiasCurvesOfObjectWithPrograms(renderer, - objectIndex, - 'xcaaMultiEdgeMaskCurve', - 'xcaaMultiEdgeMaskTransformedCurve'); - - gl.colorMask(true, true, true, true); - renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); - } - - protected setCoverDepthState(renderer: Renderer): void { - const renderContext = renderer.renderContext; - const gl = renderContext.gl; - - gl.depthMask(false); - gl.depthFunc(gl.EQUAL); - gl.enable(gl.DEPTH_TEST); - } - - protected clearForAA(renderer: Renderer): void {} - - protected setAADepthState(renderer: Renderer): void { - const renderContext = renderer.renderContext; - 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): void {} - - 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); - } - - get directRenderingMode(): DirectRenderingMode { - return 'color-depth'; - } - - protected get directDepthTexture(): WebGLTexture | null { - return null; - } -} - function calculateStartFromIndexRanges(pathRange: Range, indexRanges: Range[]): number { return indexRanges.length === 0 ? 0 : indexRanges[pathRange.start - 1].start; } diff --git a/partitioner/src/mesh_library.rs b/partitioner/src/mesh_library.rs index fdcfa32b..205ac958 100644 --- a/partitioner/src/mesh_library.rs +++ b/partitioner/src/mesh_library.rs @@ -24,6 +24,8 @@ use {BQuad, BVertexLoopBlinnData}; pub struct MeshLibrary { pub path_ranges: Vec, pub b_quads: Vec, + // FIXME(pcwalton): Merge with `b_vertex_positions` below. + pub b_quad_vertex_positions: Vec>, pub b_vertex_positions: Vec>, pub b_vertex_loop_blinn_data: Vec, pub b_vertex_normals: Vec, @@ -39,6 +41,7 @@ impl MeshLibrary { MeshLibrary { path_ranges: vec![], b_quads: vec![], + b_quad_vertex_positions: vec![], b_vertex_positions: vec![], b_vertex_loop_blinn_data: vec![], b_vertex_normals: vec![], @@ -52,6 +55,7 @@ impl MeshLibrary { pub fn clear(&mut self) { self.path_ranges.clear(); self.b_quads.clear(); + self.b_quad_vertex_positions.clear(); self.b_vertex_positions.clear(); self.b_vertex_loop_blinn_data.clear(); self.b_vertex_normals.clear(); @@ -90,6 +94,13 @@ impl MeshLibrary { let lower_right_position = &self.b_vertex_positions[b_quad.lower_right_vertex_index as usize]; + self.b_quad_vertex_positions.extend_from_slice(&[ + *upper_left_position, + *upper_right_position, + *lower_left_position, + *lower_right_position, + ]); + let upper_left_bounding_box_position = Point2D::new(upper_left_position.x, f32::max(upper_left_position.y, upper_right_position.y)); @@ -103,6 +114,7 @@ impl MeshLibrary { }); if b_quad.upper_control_point_vertex_index == u32::MAX { + self.b_quad_vertex_positions.push(Point2D::zero()); self.edge_data.upper_line_vertex_positions.push(EdgeLineVertexPositions { left: *upper_left_position, right: *upper_right_position, @@ -110,6 +122,7 @@ impl MeshLibrary { } else { let upper_control_point_position = &self.b_vertex_positions[b_quad.upper_control_point_vertex_index as usize]; + self.b_quad_vertex_positions.push(*upper_control_point_position); self.edge_data.upper_curve_vertex_positions.push(EdgeCurveVertexPositions { left: *upper_left_position, control_point: *upper_control_point_position, @@ -118,6 +131,7 @@ impl MeshLibrary { } if b_quad.lower_control_point_vertex_index == u32::MAX { + self.b_quad_vertex_positions.push(Point2D::zero()); self.edge_data.lower_line_vertex_positions.push(EdgeLineVertexPositions { left: *lower_left_position, right: *lower_right_position, @@ -125,6 +139,7 @@ impl MeshLibrary { } else { let lower_control_point_position = &self.b_vertex_positions[b_quad.lower_control_point_vertex_index as usize]; + self.b_quad_vertex_positions.push(*lower_control_point_position); self.edge_data.lower_curve_vertex_positions.push(EdgeCurveVertexPositions { left: *lower_left_position, control_point: *lower_control_point_position, @@ -205,6 +220,7 @@ impl MeshLibrary { try!(write_chunk(writer, b"prng", |writer| write_path_ranges(writer, &self.path_ranges))); try!(write_simple_chunk(writer, b"bqua", &self.b_quads)); + try!(write_simple_chunk(writer, b"bqvp", &self.b_quad_vertex_positions)); try!(write_simple_chunk(writer, b"bvpo", &self.b_vertex_positions)); try!(write_simple_chunk(writer, b"bvlb", &self.b_vertex_loop_blinn_data)); try!(write_simple_chunk(writer, b"bvno", &self.b_vertex_normals)); @@ -255,6 +271,10 @@ impl MeshLibrary { fn write_path_ranges(writer: &mut W, path_ranges: &[PathRanges]) -> io::Result<()> where W: Write + Seek { try!(write_path_range(writer, b"bqua", path_ranges, |ranges| &ranges.b_quads)); + try!(write_path_range(writer, + b"bqvp", + path_ranges, + |ranges| &ranges.b_quad_vertex_positions)); try!(write_path_range(writer, b"bver", path_ranges, |ranges| &ranges.b_vertices)); try!(write_path_range(writer, b"cvii", @@ -309,6 +329,7 @@ impl MeshLibrary { pub(crate) fn snapshot_lengths(&self) -> MeshLibraryLengths { MeshLibraryLengths { b_quads: self.b_quads.len() as u32, + b_quad_vertex_positions: self.b_quad_vertex_positions.len() as u32, b_vertices: self.b_vertex_positions.len() as u32, cover_interior_indices: self.cover_indices.interior_indices.len() as u32, cover_curve_indices: self.cover_indices.curve_indices.len() as u32, @@ -344,6 +365,7 @@ impl MeshLibraryCoverIndices { pub(crate) struct MeshLibraryLengths { b_quads: u32, + b_quad_vertex_positions: u32, b_vertices: u32, cover_interior_indices: u32, cover_curve_indices: u32, @@ -357,6 +379,7 @@ pub(crate) struct MeshLibraryLengths { #[derive(Clone, Debug)] pub struct PathRanges { pub b_quads: Range, + pub b_quad_vertex_positions: Range, pub b_vertices: Range, pub cover_interior_indices: Range, pub cover_curve_indices: Range, @@ -373,6 +396,7 @@ impl PathRanges { fn new() -> PathRanges { PathRanges { b_quads: 0..0, + b_quad_vertex_positions: 0..0, b_vertices: 0..0, cover_interior_indices: 0..0, cover_curve_indices: 0..0, @@ -390,6 +414,7 @@ impl PathRanges { start: &MeshLibraryLengths, end: &MeshLibraryLengths) { self.b_quads = start.b_quads..end.b_quads; + self.b_quad_vertex_positions = start.b_quad_vertex_positions..end.b_quad_vertex_positions; self.b_vertices = start.b_vertices..end.b_vertices; self.cover_interior_indices = start.cover_interior_indices..end.cover_interior_indices; self.cover_curve_indices = start.cover_curve_indices..end.cover_curve_indices; diff --git a/shaders/gles2/common.inc.glsl b/shaders/gles2/common.inc.glsl index 41e3cedb..8283ce2b 100644 --- a/shaders/gles2/common.inc.glsl +++ b/shaders/gles2/common.inc.glsl @@ -131,12 +131,39 @@ vec2 computeMCAAPosition(vec2 position, vec4 localTransformST, vec4 globalTransformST, ivec2 framebufferSize) { + if (position == vec2(0.0)) + return position; + position = hintPosition(position, hints); position = transformVertexPositionST(position, localTransformST); position = transformVertexPositionST(position, globalTransformST); return convertClipToScreenSpace(position, framebufferSize); } +vec2 computeMCAASnappedPosition(vec2 position, + vec4 hints, + vec4 localTransformST, + vec4 globalTransformST, + ivec2 framebufferSize, + float tanTheta) { + position = hintPosition(position, hints); + position = transformVertexPositionST(position, localTransformST); + position = transformVertexPositionST(position, globalTransformST); + position = convertClipToScreenSpace(position, framebufferSize); + //position.x = abs(mod(position.x, 1.0)) < 0.5 ? floor(position.x) : ceil(position.x); + + float xNudge = fract(position.x); + if (xNudge < 0.5) + xNudge = -xNudge; + else + xNudge = 1.0 - xNudge; + + position.x += xNudge; + position.y += xNudge * tanTheta; + + return position; +} + bool computeMCAAQuadPosition(out vec2 outPosition, inout vec2 leftPosition, inout vec2 rightPosition, @@ -440,6 +467,13 @@ vec2 solveCurveT(float p0x, float p1x, float p2x, vec2 x) { return 2.0 * c / (-b - sqrt(b * b - 4.0 * a * c)); } +vec2 solveCurveT1(float p0x, float p1x, float p2x, vec2 x) { + float a = p0x - 2.0 * p1x + p2x; + float b = 2.0 * p1x - 2.0 * p0x; + vec2 c = p0x - x; + return (-b + sqrt(b * b - 4.0 * a * c)) / (2.0 * a); +} + // 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 + diff --git a/shaders/gles2/ecaa-multi-edge-mask-curve.vs.glsl b/shaders/gles2/ecaa-multi-edge-mask-curve.vs.glsl deleted file mode 100644 index 48f08226..00000000 --- a/shaders/gles2/ecaa-multi-edge-mask-curve.vs.glsl +++ /dev/null @@ -1,77 +0,0 @@ -// pathfinder/shaders/gles2/ecaa-multi-edge-mask-curve.vs.glsl -// -// Copyright (c) 2017 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -precision highp float; - -uniform mat4 uTransform; -uniform ivec2 uFramebufferSize; -uniform ivec2 uPathTransformSTDimensions; -uniform sampler2D uPathTransformST; -uniform ivec2 uPathTransformExtDimensions; -uniform sampler2D uPathTransformExt; - -attribute vec2 aQuadPosition; -attribute vec2 aLeftPosition; -attribute vec2 aControlPointPosition; -attribute vec2 aRightPosition; -attribute float aPathID; - -varying vec4 vEndpoints; -varying vec2 vControlPoint; - -void main() { - vec2 leftPosition = aLeftPosition; - vec2 controlPointPosition = aControlPointPosition; - vec2 rightPosition = aRightPosition; - int pathID = int(aPathID); - - vec2 pathTransformExt; - vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt, - uPathTransformST, - uPathTransformSTDimensions, - uPathTransformExt, - uPathTransformExtDimensions, - pathID); - - // Transform the points. - leftPosition = transformECAAPositionToScreenSpace(leftPosition, - pathTransformST, - pathTransformExt, - uTransform, - uFramebufferSize); - rightPosition = transformECAAPositionToScreenSpace(rightPosition, - pathTransformST, - pathTransformExt, - uTransform, - uFramebufferSize); - controlPointPosition = transformECAAPositionToScreenSpace(controlPointPosition, - pathTransformST, - pathTransformExt, - uTransform, - uFramebufferSize); - - float winding = computeECAAWinding(leftPosition, rightPosition); - if (winding == 0.0) { - gl_Position = vec4(0.0); - return; - } - - vec4 extents = vec4(leftPosition.x, - min(leftPosition.y, rightPosition.y), - rightPosition.x, - max(leftPosition.y, rightPosition.y)); - vec2 position = computeXCAAClipSpaceQuadPosition(extents, aQuadPosition, uFramebufferSize); - - float depth = convertPathIndexToViewportDepthValue(pathID); - - gl_Position = vec4(position, depth, 1.0); - vEndpoints = vec4(leftPosition, rightPosition); - vControlPoint = controlPointPosition; -} diff --git a/shaders/gles2/ecaa-multi-edge-mask-line.vs.glsl b/shaders/gles2/ecaa-multi-edge-mask-line.vs.glsl deleted file mode 100644 index 72daf5b9..00000000 --- a/shaders/gles2/ecaa-multi-edge-mask-line.vs.glsl +++ /dev/null @@ -1,69 +0,0 @@ -// pathfinder/shaders/gles2/ecaa-multi-edge-mask-line.vs.glsl -// -// Copyright (c) 2017 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -precision highp float; - -uniform mat4 uTransform; -uniform vec4 uHints; -uniform ivec2 uFramebufferSize; -uniform ivec2 uPathTransformSTDimensions; -uniform sampler2D uPathTransformST; -uniform ivec2 uPathTransformExtDimensions; -uniform sampler2D uPathTransformExt; - -attribute vec2 aQuadPosition; -attribute vec2 aLeftPosition; -attribute vec2 aRightPosition; -attribute float aPathID; - -varying vec4 vEndpoints; - -void main() { - vec2 leftPosition = aLeftPosition; - vec2 rightPosition = aRightPosition; - int pathID = int(aPathID); - - vec2 pathTransformExt; - vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt, - uPathTransformST, - uPathTransformSTDimensions, - uPathTransformExt, - uPathTransformExtDimensions, - pathID); - - // Transform the points. - leftPosition = transformECAAPositionToScreenSpace(leftPosition, - pathTransformST, - pathTransformExt, - uTransform, - uFramebufferSize); - rightPosition = transformECAAPositionToScreenSpace(rightPosition, - pathTransformST, - pathTransformExt, - uTransform, - uFramebufferSize); - - float winding = computeECAAWinding(leftPosition, rightPosition); - if (winding == 0.0) { - gl_Position = vec4(0.0); - return; - } - - vec4 extents = vec4(min(leftPosition.x, rightPosition.x), - min(leftPosition.y, rightPosition.y), - max(rightPosition.x, rightPosition.x), - max(leftPosition.y, rightPosition.y)); - vec2 position = computeXCAAClipSpaceQuadPosition(extents, aQuadPosition, uFramebufferSize); - - float depth = convertPathIndexToViewportDepthValue(pathID); - - gl_Position = vec4(position, depth, 1.0); - vEndpoints = vec4(leftPosition, rightPosition); -} diff --git a/shaders/gles2/ecaa-multi-edge-mask-transformed-curve.vs.glsl b/shaders/gles2/ecaa-multi-edge-mask-transformed-curve.vs.glsl deleted file mode 100644 index 0637aaca..00000000 --- a/shaders/gles2/ecaa-multi-edge-mask-transformed-curve.vs.glsl +++ /dev/null @@ -1,83 +0,0 @@ -// pathfinder/shaders/gles2/ecaa-multi-edge-mask-transformed-curve.vs.glsl -// -// Copyright (c) 2017 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -precision highp float; - -uniform mat4 uTransform; -uniform ivec2 uFramebufferSize; -uniform ivec2 uPathTransformSTDimensions; -uniform sampler2D uPathTransformST; -uniform ivec2 uPathTransformExtDimensions; -uniform sampler2D uPathTransformExt; -uniform int uPassIndex; - -attribute vec2 aQuadPosition; -attribute vec2 aLeftPosition; -attribute vec2 aControlPointPosition; -attribute vec2 aRightPosition; -attribute float aPathID; - -varying vec4 vEndpoints; -varying vec2 vControlPoint; - -void main() { - vec2 leftPosition = aLeftPosition; - vec2 controlPointPosition = aControlPointPosition; - vec2 rightPosition = aRightPosition; - int pathID = int(aPathID); - - vec2 pathTransformExt; - vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt, - uPathTransformST, - uPathTransformSTDimensions, - uPathTransformExt, - uPathTransformExtDimensions, - pathID); - - // Transform the points. - leftPosition = transformECAAPositionToScreenSpace(leftPosition, - pathTransformST, - pathTransformExt, - uTransform, - uFramebufferSize); - rightPosition = transformECAAPositionToScreenSpace(rightPosition, - pathTransformST, - pathTransformExt, - uTransform, - uFramebufferSize); - controlPointPosition = transformECAAPositionToScreenSpace(controlPointPosition, - pathTransformST, - pathTransformExt, - uTransform, - uFramebufferSize); - - float winding; - vec3 leftTopRightEdges; - if (!splitCurveAndComputeECAAWinding(winding, - leftTopRightEdges, - leftPosition, - rightPosition, - controlPointPosition, - uPassIndex)) { - gl_Position = vec4(0.0); - return; - } - - vec4 extents = vec4(leftTopRightEdges, - max(max(leftPosition.y, rightPosition.y), controlPointPosition.y)); - vec2 position = computeXCAAClipSpaceQuadPosition(extents, aQuadPosition, uFramebufferSize); - - float depth = convertPathIndexToViewportDepthValue(pathID); - - gl_Position = vec4(position, depth, 1.0); - vEndpoints = vec4(leftPosition, rightPosition); - vControlPoint = controlPointPosition; -} - diff --git a/shaders/gles2/mcaa-multi.fs.glsl b/shaders/gles2/mcaa-multi.fs.glsl new file mode 100644 index 00000000..92c1d206 --- /dev/null +++ b/shaders/gles2/mcaa-multi.fs.glsl @@ -0,0 +1,58 @@ +// pathfinder/shaders/gles2/mcaa-multi.fs.glsl +// +// Copyright (c) 2017 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +precision highp float; + +varying vec4 vUpperEndpoints; +varying vec4 vLowerEndpoints; +varying vec4 vControlPoints; +varying vec4 vColor; + +float computeCoverageForSide(vec2 p0, vec2 cp, vec2 p1, float winding) { + // Compute pixel extents. + vec2 pixelCenter = gl_FragCoord.xy; + vec2 pixelColumnBounds = pixelCenter.xx + vec2(-0.5, 0.5); + + vec2 clippedP0, clippedDP; + if (cp == vec2(0.0)) { + vec4 p0DPX = clipLineToPixelColumn(p0, p1 - p0, pixelCenter.x); + clippedP0 = p0DPX.xy; + clippedDP = p0DPX.zw; + } else { + // Clip the curve to the left and right edges to create a line. + vec2 t = solveCurveT(p0.x, cp.x, p1.x, pixelColumnBounds); + + // Handle endpoints properly. These tests are negated to handle NaNs. + if (!(p0.x < pixelColumnBounds.x)) + t.x = 0.0; + if (!(p1.x > pixelColumnBounds.y)) + t.y = 1.0; + + clippedP0 = mix(mix(p0, cp, t.x), mix(cp, p1, t.x), t.x); + clippedDP = mix(mix(p0, cp, t.y), mix(cp, p1, t.y), t.y) - clippedP0; + } + + return computeCoverage(clippedP0, clippedDP, pixelCenter.y, winding); +} + +void main() { + float alpha = computeCoverageForSide(vLowerEndpoints.xy, + vControlPoints.zw, + vLowerEndpoints.zw, + -1.0); + + alpha += computeCoverageForSide(vUpperEndpoints.xy, + vControlPoints.xy, + vUpperEndpoints.zw, + 1.0); + + // Compute area. + gl_FragColor = vec4(vColor.rgb, vColor.a * alpha); +} diff --git a/shaders/gles2/mcaa-multi.vs.glsl b/shaders/gles2/mcaa-multi.vs.glsl new file mode 100644 index 00000000..b96d8af4 --- /dev/null +++ b/shaders/gles2/mcaa-multi.vs.glsl @@ -0,0 +1,101 @@ +// pathfinder/shaders/gles2/mcaa-multi.vs.glsl +// +// Copyright (c) 2017 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +precision highp float; + +uniform vec4 uTransformST; +uniform vec4 uHints; +uniform ivec2 uFramebufferSize; +uniform ivec2 uPathTransformSTDimensions; +uniform sampler2D uPathTransformST; +uniform ivec2 uPathColorsDimensions; +uniform sampler2D uPathColors; + +attribute vec2 aQuadPosition; +attribute vec4 aUpperEndpointPositions; +attribute vec4 aLowerEndpointPositions; +attribute vec4 aControlPointPositions; +attribute float aPathID; + +varying vec4 vUpperEndpoints; +varying vec4 vLowerEndpoints; +varying vec4 vControlPoints; +varying vec4 vColor; + +void main() { + vec2 tlPosition = aUpperEndpointPositions.xy; + vec2 tcPosition = aControlPointPositions.xy; + vec2 trPosition = aUpperEndpointPositions.zw; + vec2 blPosition = aLowerEndpointPositions.xy; + vec2 bcPosition = aControlPointPositions.zw; + vec2 brPosition = aLowerEndpointPositions.zw; + vec2 quadPosition = aQuadPosition; + int pathID = int(aPathID); + + vec4 transformST = fetchFloat4Data(uPathTransformST, pathID, uPathTransformSTDimensions); + + vec4 color = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions); + + vec2 topVector = trPosition - tlPosition, bottomVector = brPosition - blPosition; + float topTanTheta = topVector.y / topVector.x; + float bottomTanTheta = bottomVector.y / bottomVector.x; + + // Transform the points, and compute the position of this vertex. + tlPosition = computeMCAASnappedPosition(tlPosition, + uHints, + transformST, + uTransformST, + uFramebufferSize, + topTanTheta); + trPosition = computeMCAASnappedPosition(trPosition, + uHints, + transformST, + uTransformST, + uFramebufferSize, + topTanTheta); + tcPosition = computeMCAAPosition(tcPosition, + uHints, + transformST, + uTransformST, + uFramebufferSize); + blPosition = computeMCAASnappedPosition(blPosition, + uHints, + transformST, + uTransformST, + uFramebufferSize, + bottomTanTheta); + brPosition = computeMCAASnappedPosition(brPosition, + uHints, + transformST, + uTransformST, + uFramebufferSize, + bottomTanTheta); + bcPosition = computeMCAAPosition(bcPosition, + uHints, + transformST, + uTransformST, + uFramebufferSize); + + float depth = convertPathIndexToViewportDepthValue(pathID); + + vec2 position; + position.x = mix(tlPosition.x, brPosition.x, quadPosition.x); + if (quadPosition.y < 0.5) + position.y = floor(min(tlPosition.y, trPosition.y)); + else + position.y = ceil(max(blPosition.y, brPosition.y)); + position = convertScreenToClipSpace(position, uFramebufferSize); + + gl_Position = vec4(position, depth, 1.0); + vUpperEndpoints = vec4(tlPosition, trPosition); + vLowerEndpoints = vec4(blPosition, brPosition); + vControlPoints = vec4(tcPosition, bcPosition); + vColor = color; +} diff --git a/shaders/gles2/xcaa-multi-direct-curve.fs.glsl b/shaders/gles2/xcaa-multi-direct-curve.fs.glsl deleted file mode 100644 index 25192d0c..00000000 --- a/shaders/gles2/xcaa-multi-direct-curve.fs.glsl +++ /dev/null @@ -1,36 +0,0 @@ -// pathfinder/shaders/gles2/xcaa-multi-direct-curve.fs.glsl -// -// Copyright (c) 2017 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This shader implements the quadratic Loop-Blinn formulation. - -precision highp float; - -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): Get back early Z somehow? - if (depth == texture2D(uEdgeDepth, texCoord).r) - discard; - - float side = vTexCoord.x * vTexCoord.x - vTexCoord.y; - if (sign(side) != sign(vSign)) - discard; - - gl_FragColor = vColor; -} diff --git a/shaders/gles2/xcaa-multi-direct-curve.vs.glsl b/shaders/gles2/xcaa-multi-direct-curve.vs.glsl deleted file mode 100644 index 5c1292e3..00000000 --- a/shaders/gles2/xcaa-multi-direct-curve.vs.glsl +++ /dev/null @@ -1,55 +0,0 @@ -// pathfinder/shaders/gles2/xcaa-multi-direct-curve.vs.glsl -// -// Copyright (c) 2017 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -precision highp float; - -uniform mat4 uTransform; -uniform vec4 uHints; -uniform vec2 uEmboldenAmount; -uniform ivec2 uPathColorsDimensions; -uniform sampler2D uPathColors; -uniform ivec2 uPathTransformSTDimensions; -uniform sampler2D uPathTransformST; -uniform ivec2 uPathTransformExtDimensions; -uniform sampler2D uPathTransformExt; - -attribute vec2 aPosition; -attribute vec2 aTexCoord; -attribute float aPathID; -attribute float aSign; -attribute float aNormalAngle; - -varying vec4 vColor; -varying vec2 vTexCoord; -varying float vSign; - -void main() { - int pathID = int(aPathID); - - vec2 pathTransformExt; - vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt, - uPathTransformST, - uPathTransformSTDimensions, - uPathTransformExt, - uPathTransformExtDimensions, - pathID); - - vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount); - position = hintPosition(position, uHints); - position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt); - position = transformVertexPosition(position, uTransform); - - float depth = convertPathIndexToViewportDepthValue(pathID); - gl_Position = vec4(position, depth, 1.0); - - vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions); - vTexCoord = vec2(aTexCoord) / 2.0; - vSign = aSign; -} diff --git a/shaders/gles2/xcaa-multi-direct-interior.fs.glsl b/shaders/gles2/xcaa-multi-direct-interior.fs.glsl deleted file mode 100644 index b43f6026..00000000 --- a/shaders/gles2/xcaa-multi-direct-interior.fs.glsl +++ /dev/null @@ -1,29 +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 or the MIT license -// , 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 uEdgeAlpha; -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); - - vec4 color = vColor; - if (depth == texture2D(uEdgeDepth, texCoord).r) - color.a = texture2D(uEdgeAlpha, texCoord).r; - - gl_FragColor = vColor; -} diff --git a/shaders/gles2/xcaa-multi-direct-interior.vs.glsl b/shaders/gles2/xcaa-multi-direct-interior.vs.glsl deleted file mode 100644 index 0609140d..00000000 --- a/shaders/gles2/xcaa-multi-direct-interior.vs.glsl +++ /dev/null @@ -1,50 +0,0 @@ -// pathfinder/shaders/gles2/xcaa-multi-direct-interior.vs.glsl -// -// Copyright (c) 2017 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -precision highp float; - -uniform mat4 uTransform; -uniform vec4 uHints; -uniform vec2 uEmboldenAmount; -uniform ivec2 uPathColorsDimensions; -uniform sampler2D uPathColors; -uniform ivec2 uPathTransformSTDimensions; -uniform sampler2D uPathTransformST; -uniform ivec2 uPathTransformExtDimensions; -uniform sampler2D uPathTransformExt; - -attribute vec2 aPosition; -attribute float aPathID; -attribute float aNormalAngle; - -varying vec4 vColor; -varying float vSign; - -void main() { - int pathID = int(aPathID); - - vec2 pathTransformExt; - vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt, - uPathTransformST, - uPathTransformSTDimensions, - uPathTransformExt, - uPathTransformExtDimensions, - pathID); - - vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount); - position = hintPosition(position, uHints); - position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt); - position = transformVertexPosition(position, uTransform); - - float depth = convertPathIndexToViewportDepthValue(pathID); - gl_Position = vec4(position, depth, 1.0); - - vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions); -} diff --git a/shaders/gles2/xcaa-multi-edge-mask-curve.fs.glsl b/shaders/gles2/xcaa-multi-edge-mask-curve.fs.glsl deleted file mode 100644 index 98a991dd..00000000 --- a/shaders/gles2/xcaa-multi-edge-mask-curve.fs.glsl +++ /dev/null @@ -1,41 +0,0 @@ -// 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 or the MIT license -// , 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; - -void main() { - // Unpack. - vec2 pixelCenter = gl_FragCoord.xy; - vec2 p0 = vEndpoints.xy, p1 = vEndpoints.zw; - vec2 cp = vControlPoint; - - // Clip to left and right pixel boundaries. - vec2 pixelColumnBounds = pixelCenter.xx + vec2(-0.5, 0.5); - - // Clip the curve to the left and right edges to create a line. - vec2 t = solveCurveT(p0.x, cp.x, p1.x, pixelColumnBounds); - - // Handle endpoints properly. These tests are negated to handle NaNs. - if (!(p0.x < pixelColumnBounds.x)) - t.x = 0.0; - if (!(p1.x > pixelColumnBounds.y)) - t.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, pixelCenter.y)) - discard; - gl_FragColor = vec4(1.0); -} diff --git a/shaders/gles2/xcaa-multi-edge-mask-line.fs.glsl b/shaders/gles2/xcaa-multi-edge-mask-line.fs.glsl deleted file mode 100644 index 6b97fb43..00000000 --- a/shaders/gles2/xcaa-multi-edge-mask-line.fs.glsl +++ /dev/null @@ -1,28 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -precision highp float; - -varying vec4 vEndpoints; - -void main() { - // Unpack. - vec2 pixelCenter = gl_FragCoord.xy; - vec2 p0 = vEndpoints.xy, p1 = vEndpoints.zw; - - // Clip to left and right pixel boundaries. - vec2 dP = p1 - p0; - vec4 p0DPX = clipLineToPixelColumn(p0, dP, pixelCenter.x); - - // Discard if not edge. - if (!isPartiallyCovered(p0DPX.xy, p0DPX.zw, pixelCenter.y)) - discard; - gl_FragColor = vec4(1.0); -} diff --git a/shaders/gles2/xcaa-multi-resolve.fs.glsl b/shaders/gles2/xcaa-multi-resolve.fs.glsl deleted file mode 100644 index e2a64c46..00000000 --- a/shaders/gles2/xcaa-multi-resolve.fs.glsl +++ /dev/null @@ -1,27 +0,0 @@ -// pathfinder/shaders/gles2/xcaa-multi-resolve.fs.glsl -// -// Copyright (c) 2017 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -precision highp float; - -uniform ivec2 uPathColorsDimensions; -uniform sampler2D uAAAlpha; -uniform sampler2D uAADepth; -uniform sampler2D uPathColors; - -varying vec2 vTexCoord; - -void main() { - float edgeDepth = texture2D(uAADepth, vTexCoord).r; - int edgePathID = convertWindowDepthValueToPathIndex(edgeDepth); - vec4 edgeColor = fetchFloat4Data(uPathColors, edgePathID, uPathColorsDimensions); - float edgeAlpha = abs(texture2D(uAAAlpha, vTexCoord).r); - gl_FragColor = vec4(edgeColor.rgb, edgeColor.a * edgeAlpha); - gl_FragDepthEXT = edgeDepth; -} diff --git a/shaders/gles2/xcaa-multi-resolve.vs.glsl b/shaders/gles2/xcaa-multi-resolve.vs.glsl deleted file mode 100644 index 9bd21368..00000000 --- a/shaders/gles2/xcaa-multi-resolve.vs.glsl +++ /dev/null @@ -1,22 +0,0 @@ -// pathfinder/shaders/gles2/xcaa-multi-resolve.vs.glsl -// -// Copyright (c) 2017 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -precision highp float; - -attribute vec2 aPosition; -attribute vec2 aTexCoord; - -varying vec2 vTexCoord; - -void main() { - float depth = convertPathIndexToViewportDepthValue(0); - gl_Position = vec4(mix(vec2(-1.0), vec2(1.0), aPosition), depth, 1.0); - vTexCoord = aTexCoord; -}