Initial setup for ECAA in the demo

This commit is contained in:
Patrick Walton 2017-08-15 22:09:09 -07:00
parent 3f7fc8baf6
commit b10807d217
8 changed files with 169 additions and 69 deletions

5
.gitignore vendored
View File

@ -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

View File

@ -44,6 +44,7 @@
<div class="pf-bottom-control" id="pf-rendering-options-group">
<select class="custom-select" id="pf-aa-level-select">
<option data-pf-type="none" data-pf-level="0" selected>No AA</option>
<option data-pf-type="ecaa" data-pf-level="0">ECAA</option>
<option data-pf-type="ssaa" data-pf-level="2">2&times;SSAA</option>
<option data-pf-type="ssaa" data-pf-level="4">4&times;SSAA</option>
</select>

View File

@ -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<PathfinderShaderProgram>): 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<ShaderMap<PathfinderShaderProgram>>;
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<PathfinderShaderProgram>) {}
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,
this.supersampledColorTexture = unwrapNull(view.gl.createTexture());
view.gl.bindTexture(view.gl.TEXTURE_2D, this.supersampledColorTexture);
view.gl.texImage2D(view.gl.TEXTURE_2D,
0,
gl.RGBA,
view.gl.RGBA,
this.supersampledFramebufferSize.width,
this.supersampledFramebufferSize.height,
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
view.gl.RGBA,
view.gl.UNSIGNED_BYTE,
null);
setTextureParameters(gl, gl.LINEAR);
setTextureParameters(view.gl, view.gl.LINEAR);
this.supersampledDepthTexture = unwrapNull(gl.createTexture());
gl.bindTexture(gl.TEXTURE_2D, this.supersampledDepthTexture);
gl.texImage2D(gl.TEXTURE_2D,
this.supersampledDepthTexture = unwrapNull(view.gl.createTexture());
view.gl.bindTexture(view.gl.TEXTURE_2D, this.supersampledDepthTexture);
view.gl.texImage2D(view.gl.TEXTURE_2D,
0,
gl.DEPTH_COMPONENT,
view.gl.DEPTH_COMPONENT,
this.supersampledFramebufferSize.width,
this.supersampledFramebufferSize.height,
0,
gl.DEPTH_COMPONENT,
gl.UNSIGNED_INT,
view.gl.DEPTH_COMPONENT,
view.gl.UNSIGNED_INT,
null);
setTextureParameters(gl, gl.NEAREST);
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.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);
gl.framebufferTexture2D(gl.FRAMEBUFFER,
gl.DEPTH_ATTACHMENT,
gl.TEXTURE_2D,
view.gl.framebufferTexture2D(view.gl.FRAMEBUFFER,
view.gl.DEPTH_ATTACHMENT,
view.gl.TEXTURE_2D,
this.supersampledDepthTexture,
0);
assert(gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE,
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<Size2D>;
supersampledFramebufferSize: Readonly<Size2D>;
@ -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<PathfinderShaderProgram>) {
// 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() {

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}