Skip to content

Commit 3d19ddb

Browse files
committed
Refactor shader source classes, in order to work around a Firefox bug.
The Firefox bug prevents shaders from compiling with the CORDIC algorithm, so we detect Firefox and fall back to the original algorithm. Issue #2197. The overall goal of the refactoring is to allow `#defines` to affect built-in functions, which was not possible before. In order to do this, we need the `#defines` to appear at the top of the source, so I've merged the procedural shader generation previously done in `ShaderProgram` with the generation done in `createShaderSource`. * `createShaderSource` (private) is removed and replaced by `ShaderSource`. `ShaderSource` now manages an array of `#defines`, concating source shaders, and automatically including built-in functions, keeping everything in the correct order. * `ShaderCache` (and by extension `Context.createShaderProgram` and `Context.replaceShaderProgram`) now accept either `ShaderSource` objects, or a single string, for vertex and fragment shaders. * `ShaderProgram` constructor (private) now takes an options object. It also exposes the vertex and fragment shaders as `ShaderSource` objects instead of strings. External code can still clone the `ShaderSources` and then screw around with the implementation to make new shaders procedurally, as `OIT` does.
1 parent f8c8d43 commit 3d19ddb

26 files changed

+806
-589
lines changed

Source/Renderer/Context.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -929,11 +929,11 @@ define([
929929
});
930930

931931
Context.prototype.replaceShaderProgram = function(shaderProgram, vertexShaderSource, fragmentShaderSource, attributeLocations) {
932-
return this.shaderCache.replaceShaderProgram(shaderProgram, vertexShaderSource, fragmentShaderSource, attributeLocations);
932+
return this._shaderCache.replaceShaderProgram(shaderProgram, vertexShaderSource, fragmentShaderSource, attributeLocations);
933933
};
934934

935935
Context.prototype.createShaderProgram = function(vertexShaderSource, fragmentShaderSource, attributeLocations) {
936-
return this.shaderCache.getShaderProgram(vertexShaderSource, fragmentShaderSource, attributeLocations);
936+
return this._shaderCache.getShaderProgram(vertexShaderSource, fragmentShaderSource, attributeLocations);
937937
};
938938

939939
function createBuffer(gl, bufferTarget, typedArrayOrSizeInBytes, usage) {

Source/Renderer/ShaderCache.js

+47-10
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
define([
33
'../Core/defined',
44
'../Core/destroyObject',
5-
'./ShaderProgram'
5+
'./ShaderProgram',
6+
'./ShaderSource'
67
], function(
78
defined,
89
destroyObject,
9-
ShaderProgram) {
10+
ShaderProgram,
11+
ShaderSource) {
1012
"use strict";
1113

1214
/**
@@ -27,16 +29,15 @@ define([
2729
* </p>
2830
*
2931
* @param {ShaderProgram} shaderProgram The shader program that is being reassigned. This can be <code>undefined</code>.
30-
* @param {String} vertexShaderSource The GLSL source for the vertex shader.
31-
* @param {String} fragmentShaderSource The GLSL source for the fragment shader.
32+
* @param {String|ShaderSource} vertexShaderSource The GLSL source for the vertex shader.
33+
* @param {String|ShaderSource} fragmentShaderSource The GLSL source for the fragment shader.
3234
* @param {Object} attributeLocations Indices for the attribute inputs to the vertex shader.
3335
* @returns {ShaderProgram} The cached or newly created shader program.
3436
*
3537
* @see ShaderCache#getShaderProgram
3638
*
3739
* @example
38-
* this._shaderProgram = context.shaderCache.replaceShaderProgram(
39-
* this._shaderProgram, vs, fs, attributeLocations);
40+
* this._shaderProgram = context.shaderCache.replaceShaderProgram(this._shaderProgram, vs, fs, attributeLocations);
4041
*/
4142
ShaderCache.prototype.replaceShaderProgram = function(shaderProgram, vertexShaderSource, fragmentShaderSource, attributeLocations) {
4243
if (defined(shaderProgram)) {
@@ -46,8 +47,36 @@ define([
4647
return this.getShaderProgram(vertexShaderSource, fragmentShaderSource, attributeLocations);
4748
};
4849

50+
/**
51+
* Returns a shader program from the cache, or creates and caches a new shader program,
52+
* given the GLSL vertex and fragment shader source and attribute locations.
53+
*
54+
* @param {String|ShaderSource} vertexShaderSource The GLSL source for the vertex shader.
55+
* @param {String|ShaderSource} fragmentShaderSource The GLSL source for the fragment shader.
56+
* @param {Object} attributeLocations Indices for the attribute inputs to the vertex shader.
57+
*
58+
* @returns {ShaderProgram} The cached or newly created shader program.
59+
*/
4960
ShaderCache.prototype.getShaderProgram = function(vertexShaderSource, fragmentShaderSource, attributeLocations) {
50-
var keyword = vertexShaderSource + fragmentShaderSource + JSON.stringify(attributeLocations);
61+
// convert shaders which are provided as strings into ShaderSource objects
62+
// because ShaderSource handles all the automatic including of built-in functions, etc.
63+
64+
if (typeof vertexShaderSource === 'string') {
65+
vertexShaderSource = new ShaderSource({
66+
sources : [vertexShaderSource]
67+
});
68+
}
69+
70+
if (typeof fragmentShaderSource === 'string') {
71+
fragmentShaderSource = new ShaderSource({
72+
sources : [fragmentShaderSource]
73+
});
74+
}
75+
76+
var vertexShaderText = vertexShaderSource.getCombinedShader(false);
77+
var fragmentShaderText = fragmentShaderSource.getCombinedShader(true);
78+
79+
var keyword = vertexShaderText + fragmentShaderText + JSON.stringify(attributeLocations);
5180
var cachedShader;
5281

5382
if (this._shaders[keyword]) {
@@ -57,17 +86,25 @@ define([
5786
delete this._shadersToRelease[keyword];
5887
} else {
5988
var context = this._context;
60-
var sp = new ShaderProgram(context._gl, context.logShaderCompilation, vertexShaderSource, fragmentShaderSource, attributeLocations);
89+
var shaderProgram = new ShaderProgram({
90+
gl : context._gl,
91+
logShaderCompilation : context.logShaderCompilation,
92+
vertexShaderSource : vertexShaderSource,
93+
vertexShaderText : vertexShaderText,
94+
fragmentShaderSource : fragmentShaderSource,
95+
fragmentShaderText : fragmentShaderText,
96+
attributeLocations : attributeLocations
97+
});
6198

6299
cachedShader = {
63100
cache : this,
64-
shaderProgram : sp,
101+
shaderProgram : shaderProgram,
65102
keyword : keyword,
66103
count : 0
67104
};
68105

69106
// A shader can't be in more than one cache.
70-
sp._cachedShader = cachedShader;
107+
shaderProgram._cachedShader = cachedShader;
71108
this._shaders[keyword] = cachedShader;
72109
}
73110

0 commit comments

Comments
 (0)