From b10807d2171d3a69ab2b9627a086d946344d0973 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 15 Aug 2017 22:09:09 -0700 Subject: [PATCH] Initial setup for ECAA in the demo --- .gitignore | 5 + demo/client/index.html | 1 + demo/client/src/index.ts | 198 ++++++++++++++++++-------- shaders/gles2/common.inc.glsl | 4 + shaders/gles2/direct-curve.fs.glsl | 4 +- shaders/gles2/direct-curve.vs.glsl | 11 +- shaders/gles2/direct-interior.fs.glsl | 4 +- shaders/gles2/direct-interior.vs.glsl | 11 +- 8 files changed, 169 insertions(+), 69 deletions(-) diff --git a/.gitignore b/.gitignore index dfae4132..9001a8f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,11 @@ /font-renderer/target /partitioner/target /demo/client/target +/demo/client/*.js +/demo/client/src/*.js +/demo/client/src/*.js.map +/demo/client/node_modules +/demo/client/package-lock.json /demo/server/target Cargo.lock diff --git a/demo/client/index.html b/demo/client/index.html index 0c4781d1..cb3192d6 100644 --- a/demo/client/index.html +++ b/demo/client/index.html @@ -44,6 +44,7 @@
diff --git a/demo/client/src/index.ts b/demo/client/src/index.ts index a34d545a..bfe127a2 100644 --- a/demo/client/src/index.ts +++ b/demo/client/src/index.ts @@ -84,7 +84,7 @@ interface AttributeMap { interface AntialiasingStrategy { // Prepares any OpenGL data. This is only called on startup and canvas resize. - init(gl: WebGLRenderingContext, framebufferSize: Size2D): void; + init(view: PathfinderView, framebufferSize: Size2D): void; // Called before direct rendering. // @@ -95,11 +95,6 @@ interface AntialiasingStrategy { // // This usually performs the actual antialiasing and blits to the real framebuffer. resolve(view: PathfinderView, shaders: ShaderMap): void; - - // Returns the size of the framebuffer for direct rendering. - // - // For supersampling-based techniques, this may be larger than the actual framebuffer. - getFramebufferSize(): Size2D; } type ShaderType = number; @@ -318,7 +313,7 @@ class PathfinderView { this.antialiasingStrategy = new (ANTIALIASING_STRATEGIES[aaType])(aaLevel); let canvas = this.canvas; - this.antialiasingStrategy.init(this.gl, { width: canvas.width, height: canvas.height }); + this.antialiasingStrategy.init(this, { width: canvas.width, height: canvas.height }); this.setDirty(); } @@ -327,10 +322,10 @@ class PathfinderView { // Initialize the OpenGL context. this.gl = expectNotNull(this.canvas.getContext('webgl', { antialias: false, depth: true }), "Failed to initialize WebGL! Check that your browser supports it."); + this.drawBuffersExt = this.gl.getExtension('WEBGL_draw_buffers'); this.gl.getExtension('EXT_frag_depth'); this.gl.getExtension('OES_element_index_uint'); this.gl.getExtension('WEBGL_depth_texture'); - this.gl.getExtension('WEBGL_draw_buffers'); // Upload quad buffers. this.quadPositionsBuffer = unwrapNull(this.gl.createBuffer()); @@ -436,7 +431,7 @@ class PathfinderView { this.canvas.width = framebufferSize.width; this.canvas.height = framebufferSize.height; - this.antialiasingStrategy.init(this.gl, framebufferSize); + this.antialiasingStrategy.init(this, framebufferSize); this.setDirty(); } @@ -485,10 +480,10 @@ class PathfinderView { 0, 0); this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.meshes.bVertexInfo); - this.gl.vertexAttribPointer(directInteriorProgram.attributes.aPathDepth, + this.gl.vertexAttribPointer(directInteriorProgram.attributes.aPathID, 1, this.gl.UNSIGNED_SHORT, // FIXME(pcwalton) - true, + false, B_VERTEX_QUAD_SIZE, B_VERTEX_QUAD_PATH_ID_OFFSET); this.gl.enableVertexAttribArray(directInteriorProgram.attributes.aPosition); @@ -530,10 +525,10 @@ class PathfinderView { false, B_VERTEX_QUAD_SIZE, B_VERTEX_QUAD_TEX_COORD_OFFSET); - this.gl.vertexAttribPointer(directCurveProgram.attributes.aPathDepth, + this.gl.vertexAttribPointer(directCurveProgram.attributes.aPathID, 1, this.gl.UNSIGNED_SHORT, // FIXME(pcwalton) - true, + false, B_VERTEX_QUAD_SIZE, B_VERTEX_QUAD_PATH_ID_OFFSET); this.gl.vertexAttribPointer(directCurveProgram.attributes.aSign, @@ -566,6 +561,7 @@ class PathfinderView { canvas: HTMLCanvasElement; gl: WebGLRenderingContext; + drawBuffersExt: any; antialiasingStrategy: AntialiasingStrategy; shaderProgramsPromise: Promise>; meshes: PathfinderMeshBuffers; @@ -637,7 +633,7 @@ class NoAAStrategy implements AntialiasingStrategy { this.framebufferSize = { width: 0, height: 0 }; } - init(gl: WebGLRenderingContext, framebufferSize: Size2D) { + init(view: PathfinderView, framebufferSize: Size2D) { this.framebufferSize = framebufferSize; } @@ -647,10 +643,6 @@ class NoAAStrategy implements AntialiasingStrategy { resolve(view: PathfinderView, shaders: ShaderMap) {} - getFramebufferSize() { - return this.framebufferSize; - } - framebufferSize: Size2D; } @@ -661,55 +653,55 @@ class SSAAStrategy implements AntialiasingStrategy { this.supersampledFramebufferSize = { width: 0, height: 0 }; } - init(gl: WebGLRenderingContext, framebufferSize: Size2D) { + init(view: PathfinderView, framebufferSize: Size2D) { this.canvasFramebufferSize = framebufferSize; this.supersampledFramebufferSize = { width: framebufferSize.width * 2, height: framebufferSize.height * (this.level == 2 ? 1 : 2), }; - this.supersampledColorTexture = unwrapNull(gl.createTexture()); - gl.bindTexture(gl.TEXTURE_2D, this.supersampledColorTexture); - gl.texImage2D(gl.TEXTURE_2D, - 0, - gl.RGBA, - this.supersampledFramebufferSize.width, - this.supersampledFramebufferSize.height, - 0, - gl.RGBA, - gl.UNSIGNED_BYTE, - null); - setTextureParameters(gl, gl.LINEAR); + this.supersampledColorTexture = unwrapNull(view.gl.createTexture()); + view.gl.bindTexture(view.gl.TEXTURE_2D, this.supersampledColorTexture); + view.gl.texImage2D(view.gl.TEXTURE_2D, + 0, + view.gl.RGBA, + this.supersampledFramebufferSize.width, + this.supersampledFramebufferSize.height, + 0, + view.gl.RGBA, + view.gl.UNSIGNED_BYTE, + null); + setTextureParameters(view.gl, view.gl.LINEAR); - this.supersampledDepthTexture = unwrapNull(gl.createTexture()); - gl.bindTexture(gl.TEXTURE_2D, this.supersampledDepthTexture); - gl.texImage2D(gl.TEXTURE_2D, - 0, - gl.DEPTH_COMPONENT, - this.supersampledFramebufferSize.width, - this.supersampledFramebufferSize.height, - 0, - gl.DEPTH_COMPONENT, - gl.UNSIGNED_INT, - null); - setTextureParameters(gl, gl.NEAREST); + this.supersampledDepthTexture = unwrapNull(view.gl.createTexture()); + view.gl.bindTexture(view.gl.TEXTURE_2D, this.supersampledDepthTexture); + view.gl.texImage2D(view.gl.TEXTURE_2D, + 0, + view.gl.DEPTH_COMPONENT, + this.supersampledFramebufferSize.width, + this.supersampledFramebufferSize.height, + 0, + view.gl.DEPTH_COMPONENT, + view.gl.UNSIGNED_INT, + null); + setTextureParameters(view.gl, view.gl.NEAREST); - this.supersampledFramebuffer = unwrapNull(gl.createFramebuffer()); - gl.bindFramebuffer(gl.FRAMEBUFFER, this.supersampledFramebuffer); - gl.framebufferTexture2D(gl.FRAMEBUFFER, - gl.COLOR_ATTACHMENT0, - gl.TEXTURE_2D, - this.supersampledColorTexture, - 0); - gl.framebufferTexture2D(gl.FRAMEBUFFER, - gl.DEPTH_ATTACHMENT, - gl.TEXTURE_2D, - this.supersampledDepthTexture, - 0); - assert(gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE, + this.supersampledFramebuffer = unwrapNull(view.gl.createFramebuffer()); + view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, this.supersampledFramebuffer); + view.gl.framebufferTexture2D(view.gl.FRAMEBUFFER, + view.gl.COLOR_ATTACHMENT0, + view.gl.TEXTURE_2D, + this.supersampledColorTexture, + 0); + view.gl.framebufferTexture2D(view.gl.FRAMEBUFFER, + view.gl.DEPTH_ATTACHMENT, + view.gl.TEXTURE_2D, + this.supersampledDepthTexture, + 0); + assert(view.gl.checkFramebufferStatus(view.gl.FRAMEBUFFER) == view.gl.FRAMEBUFFER_COMPLETE, "The SSAA framebuffer was incomplete!"); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); + view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, null); } prepare(view: PathfinderView) { @@ -750,10 +742,6 @@ class SSAAStrategy implements AntialiasingStrategy { view.gl.drawArrays(view.gl.TRIANGLE_STRIP, 0, 4); } - getFramebufferSize() { - return this.supersampledFramebufferSize; - } - level: number; canvasFramebufferSize: Readonly; supersampledFramebufferSize: Readonly; @@ -762,14 +750,102 @@ class SSAAStrategy implements AntialiasingStrategy { supersampledFramebuffer: WebGLFramebuffer; } +class ECAAStrategy implements AntialiasingStrategy { + constructor(level: number) { + this.framebufferSize = { width: 0, height: 0 }; + } + + init(view: PathfinderView, framebufferSize: Size2D) { + this.framebufferSize = framebufferSize; + + this.directColorTexture = unwrapNull(view.gl.createTexture()); + view.gl.bindTexture(view.gl.TEXTURE_2D, this.directColorTexture); + view.gl.texImage2D(view.gl.TEXTURE_2D, + 0, + view.gl.RGBA, + framebufferSize.width, + framebufferSize.height, + 0, + view.gl.RGBA, + view.gl.UNSIGNED_BYTE, + null); + setTextureParameters(view.gl, view.gl.NEAREST); + + this.directPathIDTexture = unwrapNull(view.gl.createTexture()); + view.gl.bindTexture(view.gl.TEXTURE_2D, this.directPathIDTexture); + view.gl.texImage2D(view.gl.TEXTURE_2D, + 0, + view.gl.RGBA, // really should be RG + framebufferSize.width, + framebufferSize.height, + 0, + view.gl.RGBA, + view.gl.UNSIGNED_BYTE, + null); + setTextureParameters(view.gl, view.gl.NEAREST); + + this.directDepthTexture = unwrapNull(view.gl.createTexture()); + view.gl.bindTexture(view.gl.TEXTURE_2D, this.directDepthTexture); + view.gl.texImage2D(view.gl.TEXTURE_2D, + 0, + view.gl.DEPTH_COMPONENT, + framebufferSize.width, + framebufferSize.height, + 0, + view.gl.DEPTH_COMPONENT, + view.gl.UNSIGNED_INT, + null); + setTextureParameters(view.gl, view.gl.NEAREST); + + this.directFramebuffer = unwrapNull(view.gl.createFramebuffer()); + view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, this.directFramebuffer); + view.gl.framebufferTexture2D(view.gl.FRAMEBUFFER, + view.drawBuffersExt.COLOR_ATTACHMENT0_WEBGL, + view.gl.TEXTURE_2D, + this.directColorTexture, + 0); + view.gl.framebufferTexture2D(view.gl.FRAMEBUFFER, + view.drawBuffersExt.COLOR_ATTACHMENT1_WEBGL, + view.gl.TEXTURE_2D, + this.directPathIDTexture, + 0); + view.gl.framebufferTexture2D(view.gl.FRAMEBUFFER, + view.gl.DEPTH_ATTACHMENT, + view.gl.TEXTURE_2D, + this.directDepthTexture, + 0); + assert(view.gl.checkFramebufferStatus(view.gl.FRAMEBUFFER) == view.gl.FRAMEBUFFER_COMPLETE, + "The direct framebuffer was incomplete!"); + + view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, null); + } + + prepare(view: PathfinderView) { + view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, this.directFramebuffer); + view.gl.viewport(0, 0, this.framebufferSize.width, this.framebufferSize.height); + } + + resolve(view: PathfinderView, shaders: ShaderMap) { + // TODO(pcwalton) + } + + directColorTexture: WebGLTexture; + directPathIDTexture: WebGLTexture; + directDepthTexture: WebGLTexture; + directFramebuffer: WebGLFramebuffer; + framebufferSize: Size2D; +} + interface AntialiasingStrategyTable { none: typeof NoAAStrategy; ssaa: typeof SSAAStrategy; + ecaa: typeof ECAAStrategy; } const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = { none: NoAAStrategy, ssaa: SSAAStrategy, + ecaa: ECAAStrategy, }; function main() { diff --git a/shaders/gles2/common.inc.glsl b/shaders/gles2/common.inc.glsl index 7916accc..9620fe4a 100644 --- a/shaders/gles2/common.inc.glsl +++ b/shaders/gles2/common.inc.glsl @@ -38,3 +38,7 @@ vec4 fetchFloat4Data(sampler2D dataTexture, int index, ivec2 dimensions) { vec4 fetchFloat4NormIndexedData(sampler2D dataTexture, float normIndex, ivec2 dimensions) { return fetchFloat4Data(dataTexture, int(normIndex * float(dimensions.x)), dimensions); } + +vec2 packPathID(int pathID) { + return vec2(imod(pathID, 256), pathID / 256) / 255.0; +} diff --git a/shaders/gles2/direct-curve.fs.glsl b/shaders/gles2/direct-curve.fs.glsl index 80ad6c58..d95c8e4d 100644 --- a/shaders/gles2/direct-curve.fs.glsl +++ b/shaders/gles2/direct-curve.fs.glsl @@ -9,11 +9,13 @@ precision highp float; varying vec4 vColor; +varying vec2 vPathID; varying vec2 vTexCoord; varying float vSign; void main() { float side = vTexCoord.x * vTexCoord.x - vTexCoord.y; float alpha = float(sign(side) == sign(vSign)); - gl_FragColor = vec4(vColor.rgb, vColor.a * alpha); + gl_FragData[0] = vec4(vColor.rgb, vColor.a * alpha); + gl_FragData[1] = vec4(vPathID, 1.0, 1.0); } diff --git a/shaders/gles2/direct-curve.vs.glsl b/shaders/gles2/direct-curve.vs.glsl index ebd1e2bf..bb40fdc0 100644 --- a/shaders/gles2/direct-curve.vs.glsl +++ b/shaders/gles2/direct-curve.vs.glsl @@ -11,19 +11,24 @@ uniform sampler2D uPathColors; attribute vec2 aPosition; attribute vec2 aTexCoord; -attribute float aPathDepth; +attribute float aPathID; attribute float aSign; varying vec4 vColor; +varying vec2 vPathID; varying vec2 vTexCoord; varying float vSign; void main() { + int pathID = int(aPathID); + vec2 position = transformVertexPosition(aPosition, uTransform); position = convertScreenToClipSpace(position, uFramebufferSize); - gl_Position = vec4(position, aPathDepth, 1.0); + float depth = convertPathIndexToDepthValue(pathID); + gl_Position = vec4(position, depth, 1.0); - vColor = fetchFloat4NormIndexedData(uPathColors, aPathDepth, uPathColorsDimensions); + vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions); + vPathID = packPathID(pathID); vTexCoord = vec2(aTexCoord) / 2.0; vSign = aSign; } diff --git a/shaders/gles2/direct-interior.fs.glsl b/shaders/gles2/direct-interior.fs.glsl index 6f153a87..04e623b4 100644 --- a/shaders/gles2/direct-interior.fs.glsl +++ b/shaders/gles2/direct-interior.fs.glsl @@ -5,7 +5,9 @@ precision highp float; varying vec4 vColor; +varying vec2 vPathID; void main() { - gl_FragColor = vColor; + gl_FragData[0] = vColor; + gl_FragData[1] = vec4(vPathID, 1.0, 1.0); } diff --git a/shaders/gles2/direct-interior.vs.glsl b/shaders/gles2/direct-interior.vs.glsl index a1537a0b..31eaa4e7 100644 --- a/shaders/gles2/direct-interior.vs.glsl +++ b/shaders/gles2/direct-interior.vs.glsl @@ -10,14 +10,19 @@ uniform ivec2 uPathColorsDimensions; uniform sampler2D uPathColors; attribute vec2 aPosition; -attribute float aPathDepth; +attribute float aPathID; varying vec4 vColor; +varying vec2 vPathID; void main() { + int pathID = int(aPathID); + vec2 position = transformVertexPosition(aPosition, uTransform); position = convertScreenToClipSpace(position, uFramebufferSize); - gl_Position = vec4(position, aPathDepth, 1.0); + float depth = convertPathIndexToDepthValue(pathID); + gl_Position = vec4(position, depth, 1.0); - vColor = fetchFloat4NormIndexedData(uPathColors, aPathDepth, uPathColorsDimensions); + vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions); + vPathID = packPathID(pathID); }