Skip to content

Commit

Permalink
Refactor shader source classes, in order to work around a Firefox bug.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
shunter committed Oct 22, 2014
1 parent f8c8d43 commit 3d19ddb
Show file tree
Hide file tree
Showing 26 changed files with 806 additions and 589 deletions.
4 changes: 2 additions & 2 deletions Source/Renderer/Context.js
Original file line number Diff line number Diff line change
Expand Up @@ -929,11 +929,11 @@ define([
});

Context.prototype.replaceShaderProgram = function(shaderProgram, vertexShaderSource, fragmentShaderSource, attributeLocations) {
return this.shaderCache.replaceShaderProgram(shaderProgram, vertexShaderSource, fragmentShaderSource, attributeLocations);
return this._shaderCache.replaceShaderProgram(shaderProgram, vertexShaderSource, fragmentShaderSource, attributeLocations);
};

Context.prototype.createShaderProgram = function(vertexShaderSource, fragmentShaderSource, attributeLocations) {
return this.shaderCache.getShaderProgram(vertexShaderSource, fragmentShaderSource, attributeLocations);
return this._shaderCache.getShaderProgram(vertexShaderSource, fragmentShaderSource, attributeLocations);
};

function createBuffer(gl, bufferTarget, typedArrayOrSizeInBytes, usage) {
Expand Down
57 changes: 47 additions & 10 deletions Source/Renderer/ShaderCache.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
define([
'../Core/defined',
'../Core/destroyObject',
'./ShaderProgram'
'./ShaderProgram',
'./ShaderSource'
], function(
defined,
destroyObject,
ShaderProgram) {
ShaderProgram,
ShaderSource) {
"use strict";

/**
Expand All @@ -27,16 +29,15 @@ define([
* </p>
*
* @param {ShaderProgram} shaderProgram The shader program that is being reassigned. This can be <code>undefined</code>.
* @param {String} vertexShaderSource The GLSL source for the vertex shader.
* @param {String} fragmentShaderSource The GLSL source for the fragment shader.
* @param {String|ShaderSource} vertexShaderSource The GLSL source for the vertex shader.
* @param {String|ShaderSource} fragmentShaderSource The GLSL source for the fragment shader.
* @param {Object} attributeLocations Indices for the attribute inputs to the vertex shader.
* @returns {ShaderProgram} The cached or newly created shader program.
*
* @see ShaderCache#getShaderProgram
*
* @example
* this._shaderProgram = context.shaderCache.replaceShaderProgram(
* this._shaderProgram, vs, fs, attributeLocations);
* this._shaderProgram = context.shaderCache.replaceShaderProgram(this._shaderProgram, vs, fs, attributeLocations);
*/
ShaderCache.prototype.replaceShaderProgram = function(shaderProgram, vertexShaderSource, fragmentShaderSource, attributeLocations) {
if (defined(shaderProgram)) {
Expand All @@ -46,8 +47,36 @@ define([
return this.getShaderProgram(vertexShaderSource, fragmentShaderSource, attributeLocations);
};

/**
* Returns a shader program from the cache, or creates and caches a new shader program,
* given the GLSL vertex and fragment shader source and attribute locations.
*
* @param {String|ShaderSource} vertexShaderSource The GLSL source for the vertex shader.
* @param {String|ShaderSource} fragmentShaderSource The GLSL source for the fragment shader.
* @param {Object} attributeLocations Indices for the attribute inputs to the vertex shader.
*
* @returns {ShaderProgram} The cached or newly created shader program.
*/
ShaderCache.prototype.getShaderProgram = function(vertexShaderSource, fragmentShaderSource, attributeLocations) {
var keyword = vertexShaderSource + fragmentShaderSource + JSON.stringify(attributeLocations);
// convert shaders which are provided as strings into ShaderSource objects
// because ShaderSource handles all the automatic including of built-in functions, etc.

if (typeof vertexShaderSource === 'string') {
vertexShaderSource = new ShaderSource({
sources : [vertexShaderSource]
});
}

if (typeof fragmentShaderSource === 'string') {
fragmentShaderSource = new ShaderSource({
sources : [fragmentShaderSource]
});
}

var vertexShaderText = vertexShaderSource.getCombinedShader(false);
var fragmentShaderText = fragmentShaderSource.getCombinedShader(true);

var keyword = vertexShaderText + fragmentShaderText + JSON.stringify(attributeLocations);
var cachedShader;

if (this._shaders[keyword]) {
Expand All @@ -57,17 +86,25 @@ define([
delete this._shadersToRelease[keyword];
} else {
var context = this._context;
var sp = new ShaderProgram(context._gl, context.logShaderCompilation, vertexShaderSource, fragmentShaderSource, attributeLocations);
var shaderProgram = new ShaderProgram({
gl : context._gl,
logShaderCompilation : context.logShaderCompilation,
vertexShaderSource : vertexShaderSource,
vertexShaderText : vertexShaderText,
fragmentShaderSource : fragmentShaderSource,
fragmentShaderText : fragmentShaderText,
attributeLocations : attributeLocations
});

cachedShader = {
cache : this,
shaderProgram : sp,
shaderProgram : shaderProgram,
keyword : keyword,
count : 0
};

// A shader can't be in more than one cache.
sp._cachedShader = cachedShader;
shaderProgram._cachedShader = cachedShader;
this._shaders[keyword] = cachedShader;
}

Expand Down
Loading

0 comments on commit 3d19ddb

Please sign in to comment.