Fix compile errors in shaders

This commit is contained in:
Patrick Walton 2017-08-13 13:39:51 -07:00
parent d0dd883ddf
commit 5f89f7ba50
10 changed files with 107 additions and 81 deletions

View File

@ -8,6 +8,8 @@ const FONT_SIZE: number = 16.0;
const PARTITION_FONT_ENDPOINT_URL: string = "/partition-font"; const PARTITION_FONT_ENDPOINT_URL: string = "/partition-font";
const COMMON_SHADER_URL: string = '/glsl/gles2/common.inc.glsl';
const SHADER_URLS: ShaderURLMap = { const SHADER_URLS: ShaderURLMap = {
directCurve: { directCurve: {
vertex: "/glsl/gles2/direct-curve.vs.glsl", vertex: "/glsl/gles2/direct-curve.vs.glsl",
@ -20,7 +22,7 @@ const SHADER_URLS: ShaderURLMap = {
}; };
interface ShaderURLMap { interface ShaderURLMap {
[shaderName: string]: { 'vertex': string, 'fragment': string } [shaderName: string]: { 'vertex': string, 'fragment': string };
} }
interface ShaderMap { interface ShaderMap {
@ -37,15 +39,21 @@ type ShaderTypeName = 'vertex' | 'fragment';
function expect<T>(value: T | null, message: string): T { function expect<T>(value: T | null, message: string): T {
if (value == null) if (value == null)
throw new Error(message); throw new PathfinderError(message);
return value; return value;
} }
class PathfinderError extends Error {
constructor(message?: string | undefined) {
super(message);
}
}
class PathfinderMeshes { class PathfinderMeshes {
constructor(encodedResponse: string) { constructor(encodedResponse: string) {
const response = JSON.parse(encodedResponse); const response = JSON.parse(encodedResponse);
if (!('Ok' in response)) if (!('Ok' in response))
throw new Error("Failed to partition the font!"); throw new PathfinderError("Failed to partition the font!");
const meshes = response.Ok; const meshes = response.Ok;
this.bQuadPositions = base64js.toByteArray(meshes.bQuadPositions); this.bQuadPositions = base64js.toByteArray(meshes.bQuadPositions);
this.bQuadInfo = base64js.toByteArray(meshes.bQuadInfo); this.bQuadInfo = base64js.toByteArray(meshes.bQuadInfo);
@ -80,7 +88,7 @@ class AppController {
fontLoaded() { fontLoaded() {
this.font = opentype.parse(this.fontData); this.font = opentype.parse(this.fontData);
if (!this.font.supported) if (!this.font.supported)
throw new Error("The font type is unsupported."); throw new PathfinderError("The font type is unsupported.");
const glyphIDs = this.font.stringToGlyphs(TEXT).map((glyph: any) => glyph.index); const glyphIDs = this.font.stringToGlyphs(TEXT).map((glyph: any) => glyph.index);
@ -120,7 +128,7 @@ class PathfinderView {
this.initContext(); this.initContext();
this.loadShaders().then(shaders => this.shaderProgramsPromise = this.linkShaders(shaders)); this.shaderProgramsPromise = this.loadShaders().then(shaders => this.linkShaders(shaders));
window.addEventListener('resize', () => this.resizeToFit(), false); window.addEventListener('resize', () => this.resizeToFit(), false);
this.resizeToFit(); this.resizeToFit();
@ -137,38 +145,65 @@ class PathfinderView {
loadShaders(): Promise<ShaderMap> { loadShaders(): Promise<ShaderMap> {
let shaders: ShaderMap = {}; let shaders: ShaderMap = {};
const shaderKeys = Object.keys(SHADER_URLS); return window.fetch(COMMON_SHADER_URL)
.then((response) => response.text())
.then((commonSource) => {
const shaderKeys = Object.keys(SHADER_URLS);
let promises = []; let promises = [];
for (const shaderKey of shaderKeys) { for (const shaderKey of shaderKeys) {
for (const typeName of ['vertex', 'fragment'] as Array<ShaderTypeName>) { for (const typeName of ['vertex', 'fragment'] as Array<ShaderTypeName>) {
const type = { const type = {
vertex: this.gl.VERTEX_SHADER, vertex: this.gl.VERTEX_SHADER,
fragment: this.gl.FRAGMENT_SHADER, fragment: this.gl.FRAGMENT_SHADER,
}[typeName]; }[typeName];
const url = SHADER_URLS[shaderKey][typeName]; const url = SHADER_URLS[shaderKey][typeName];
promises.push(window.fetch(url).then((response) => { promises.push(window.fetch(url)
return response.text().then((source) => { .then(response => response.text())
.then(source => {
const shader = this.gl.createShader(type); const shader = this.gl.createShader(type);
if (shader == null) if (shader == null)
throw new Error("Failed to create shader!"); throw new PathfinderError("Failed to create shader!");
this.gl.shaderSource(shader, source); this.gl.shaderSource(shader, commonSource + "\n#line 1\n" + source);
this.gl.compileShader(shader); this.gl.compileShader(shader);
if (this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS) == 0) {
const infoLog = this.gl.getShaderInfoLog(shader);
throw new PathfinderError(`Failed to compile ${typeName} shader ` +
`"${shaderKey}":\n${infoLog}`);
}
if (!(shaderKey in shaders)) if (!(shaderKey in shaders))
shaders[shaderKey] = {}; shaders[shaderKey] = {};
shaders[shaderKey][type] = shader; shaders[shaderKey][type] = shader;
}); }));
})); }
} }
}
return Promise.all(promises).then(() => shaders); return Promise.all(promises);
}).then(() => shaders);
} }
linkShaders(shaders: ShaderMap): Promise<ShaderProgramMap> { linkShaders(shaders: ShaderMap): Promise<ShaderProgramMap> {
// TODO(pcwalton) return new Promise((resolve, reject) => {
throw new Error("TODO"); let shaderProgramMap: ShaderProgramMap = {};
for (const shaderKey of Object.keys(shaders)) {
const program = expect(this.gl.createProgram(), "Failed to create shader program!");
const compiledShaders = shaders[shaderKey];
for (const compiledShader of Object.values(compiledShaders))
this.gl.attachShader(program, compiledShader);
this.gl.linkProgram(program);
if (this.gl.getProgramParameter(program, this.gl.LINK_STATUS) == 0) {
const infoLog = this.gl.getProgramInfoLog(program);
throw new PathfinderError(`Failed to link program "${program}":\n${infoLog}`);
}
shaderProgramMap[shaderKey] = program;
}
resolve(shaderProgramMap);
});
} }
resizeToFit() { resizeToFit() {
@ -182,7 +217,7 @@ class PathfinderView {
} }
class PathfinderShaderProgram { class PathfinderShaderProgram {
constructor(vertexShaderSource: string, fragmentShaderSource: string) { constructor(vertexShader: WebGLShader, fragmentShader: WebGLShader) {
// TODO(pcwalton) // TODO(pcwalton)
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es6", "target": "ES2017",
"module": "commonjs", "module": "commonjs",
"types": [ "types": [
"node" "node"

View File

@ -80,13 +80,13 @@ pub enum AntialiasingMode {
Ecaa = 1, Ecaa = 1,
} }
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)] #[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u8)] #[repr(u8)]
pub enum BVertexKind { pub(crate) enum BVertexKind {
Endpoint0 = 0, Endpoint0,
Endpoint1 = 1, Endpoint1,
ConvexControlPoint = 2, ConvexControlPoint,
ConcaveControlPoint = 3, ConcaveControlPoint,
} }
#[derive(Clone, Copy, Debug, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, Serialize, Deserialize)]
@ -94,22 +94,23 @@ pub enum BVertexKind {
pub struct BVertexInfo { pub struct BVertexInfo {
pub path_id: u32, pub path_id: u32,
pub tex_coord: [u8; 2], pub tex_coord: [u8; 2],
pub kind: BVertexKind, pub sign: i8,
pad: u8, pad: u8,
} }
impl BVertexInfo { impl BVertexInfo {
#[inline] #[inline]
pub fn new(kind: BVertexKind, path_id: u32) -> BVertexInfo { pub(crate) fn new(kind: BVertexKind, path_id: u32) -> BVertexInfo {
let tex_coord = match kind { let (tex_coord, sign) = match kind {
BVertexKind::Endpoint0 => [0, 0], BVertexKind::Endpoint0 => ([0, 0], 0),
BVertexKind::Endpoint1 => [2, 2], BVertexKind::Endpoint1 => ([2, 2], 0),
BVertexKind::ConcaveControlPoint | BVertexKind::ConvexControlPoint => [1, 0], BVertexKind::ConcaveControlPoint => ([1, 0], 1),
BVertexKind::ConvexControlPoint => ([1, 0], -1),
}; };
BVertexInfo { BVertexInfo {
path_id: path_id, path_id: path_id,
tex_coord: tex_coord, tex_coord: tex_coord,
kind: kind, sign: sign,
pad: 0, pad: 0,
} }
} }

View File

@ -9,11 +9,6 @@
#define PF_ANTIALIASING_MODE_MSAA 0 #define PF_ANTIALIASING_MODE_MSAA 0
#define PF_ANTIALIASING_MODE_ECAA 1 #define PF_ANTIALIASING_MODE_ECAA 1
#define PF_B_VERTEX_KIND_ENDPOINT_0 0
#define PF_B_VERTEX_KIND_ENDPOINT_1 1
#define PF_B_VERTEX_KIND_CONVEX_CONTROL_POINT 2
#define PF_B_VERTEX_KIND_CONCAVE_CONTROL_POINT 3
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -22,8 +17,6 @@ typedef uint8_t pf_antialiasing_mode_t;
typedef uint16_t pf_float16_t; typedef uint16_t pf_float16_t;
typedef uint8_t pf_b_vertex_kind_t;
struct pf_point2d_f32 { struct pf_point2d_f32 {
float x, y; float x, y;
}; };
@ -40,7 +33,7 @@ typedef struct pf_matrix2d_f32 pf_matrix2d_f32_t;
struct pf_b_vertex_info { struct pf_b_vertex_info {
uint32_t path_id; uint32_t path_id;
uint8_t tex_coord[2]; uint8_t tex_coord[2];
pf_b_vertex_kind_t kind; int8_t sign;
uint8_t pad; uint8_t pad;
}; };

View File

@ -1017,11 +1017,11 @@ struct SubdividedActiveEdge {
impl SubdividedActiveEdge { impl SubdividedActiveEdge {
fn shape(&self, b_vertex_info: &[BVertexInfo]) -> Shape { fn shape(&self, b_vertex_info: &[BVertexInfo]) -> Shape {
if self.left_curve_control_point == u32::MAX { if self.left_curve_control_point == u32::MAX {
return Shape::Flat Shape::Flat
} } else if b_vertex_info[self.left_curve_control_point as usize].sign < 0 {
match b_vertex_info[self.left_curve_control_point as usize].kind { Shape::Convex
BVertexKind::ConvexControlPoint => Shape::Convex, } else {
_ => Shape::Concave, Shape::Concave
} }
} }
} }

View File

@ -2,8 +2,19 @@
// //
// Copyright (c) 2017 Mozilla Foundation // Copyright (c) 2017 Mozilla Foundation
#version 100
#define MAX_PATHS 65536 #define MAX_PATHS 65536
precision highp float;
// https://stackoverflow.com/a/36078859
int imod(int ia, int ib) {
float a = float(ia), b = float(ib);
float m = a - floor((a + 0.5) / b) * b;
return int(floor(m + 0.5));
}
vec2 transformVertexPosition(vec2 position, mat4 transform) { vec2 transformVertexPosition(vec2 position, mat4 transform) {
return (transform * vec4(position, 0.0, 1.0)).xy; return (transform * vec4(position, 0.0, 1.0)).xy;
} }
@ -17,5 +28,10 @@ float convertPathIndexToDepthValue(int pathIndex) {
} }
vec4 fetchFloat4Data(sampler2D dataTexture, int index, ivec2 dimensions) { vec4 fetchFloat4Data(sampler2D dataTexture, int index, ivec2 dimensions) {
return texture2D(dataTexture, (float(index) + 0.5) / vec2(dimensions)); ivec2 pixelCoord = ivec2(imod(index, dimensions.x), index / dimensions.x);
return texture2D(dataTexture, (vec2(pixelCoord) + 0.5) / vec2(dimensions));
}
vec4 fetchFloat4NormIndexedData(sampler2D dataTexture, float normIndex, ivec2 dimensions) {
return fetchFloat4Data(dataTexture, int(normIndex * float(dimensions.x)), dimensions);
} }

View File

@ -6,8 +6,6 @@
// It is therefore unsuitable for ECAA, but it's fast (specifically, preserving early Z) and // It is therefore unsuitable for ECAA, but it's fast (specifically, preserving early Z) and
// compatible with OpenGL ES 2.0. // compatible with OpenGL ES 2.0.
#version 100
precision highp float; precision highp float;
varying vec4 vColor; varying vec4 vColor;

View File

@ -2,8 +2,6 @@
// //
// Copyright (c) 2017 Mozilla Foundation // Copyright (c) 2017 Mozilla Foundation
#version 100
precision highp float; precision highp float;
uniform mat4 uTransform; uniform mat4 uTransform;
@ -12,8 +10,9 @@ uniform ivec2 uPathColorsDimensions;
uniform sampler2D uPathColors; uniform sampler2D uPathColors;
attribute vec2 aPosition; attribute vec2 aPosition;
attribute ivec2 aTexCoord; attribute vec2 aTexCoord;
attribute int aKind; attribute float aPathDepth;
attribute float aSign;
varying vec4 vColor; varying vec4 vColor;
varying vec2 vTexCoord; varying vec2 vTexCoord;
@ -22,20 +21,9 @@ varying float vSign;
void main() { void main() {
vec2 position = transformVertexPosition(aPosition, uTransform); vec2 position = transformVertexPosition(aPosition, uTransform);
position = convertScreenToClipSpace(position, uFramebufferSize); position = convertScreenToClipSpace(position, uFramebufferSize);
float depth = convertPathIndexToDepthValue(aPathIndex); gl_Position = vec4(position, aPathDepth, 1.0);
gl_Position = vec4(position, depth, 1.0);
vColor = fetchFloat4Data(uPathColors, aPathIndex, uPathColorsDimensions); vColor = fetchFloat4NormIndexedData(uPathColors, aPathDepth, uPathColorsDimensions);
vTexCoord = vec2(aTexCoord) / 2.0; vTexCoord = vec2(aTexCoord) / 2.0;
vSign = aSign;
switch (aKind) {
case PF_B_VERTEX_KIND_CONVEX_CONTROL_POINT:
vSign = -1.0;
break;
case PF_B_VERTEX_KIND_CONCAVE_CONTROL_POINT:
vSign = 1.0;
break;
default:
vSign = 0.0;
}
} }

View File

@ -2,8 +2,6 @@
// //
// Copyright (c) 2017 Mozilla Foundation // Copyright (c) 2017 Mozilla Foundation
#version 100
precision highp float; precision highp float;
varying vec4 vColor; varying vec4 vColor;

View File

@ -2,8 +2,6 @@
// //
// Copyright (c) 2017 Mozilla Foundation // Copyright (c) 2017 Mozilla Foundation
#version 100
precision highp float; precision highp float;
uniform mat4 uTransform; uniform mat4 uTransform;
@ -13,15 +11,14 @@ uniform ivec2 uPathColorsDimensions;
uniform sampler2D uPathColors; uniform sampler2D uPathColors;
attribute vec2 aPosition; attribute vec2 aPosition;
attribute int aPathIndex; attribute float aPathDepth;
varying vec4 vColor; varying vec4 vColor;
void main() { void main() {
vec2 position = transformVertexPosition(aPosition, uTransform); vec2 position = transformVertexPosition(aPosition, uTransform);
position = convertScreenToClipSpace(position, uFramebufferSize); position = convertScreenToClipSpace(position, uFramebufferSize);
float depth = convertPathIndexToDepthValue(aPathIndex); gl_Position = vec4(position, aPathDepth, 1.0);
gl_Position = vec4(position, depth, 1.0);
vColor = fetchFloat4Data(uPathColors, aPathIndex, uPathColorsDimensions); vColor = fetchFloat4NormIndexedData(uPathColors, aPathDepth, uPathColorsDimensions);
} }