mirror of
https://github.com/photonstorm/phaser
synced 2024-11-23 05:03:37 +00:00
Upgrade WebGLProgramWrapper to generate uniforms and attributes.
It assumes that programs do not change after creation, so these values are static, and much can be inferred about their behaviour. Uniform-setting code is implemented and has been tested on Shader. Attribute binding has not been finished. - Change `gl` parameter to `renderer`.
This commit is contained in:
parent
8272cf1a26
commit
de3fc50979
4 changed files with 313 additions and 18 deletions
|
@ -553,6 +553,25 @@ var WebGLRenderer = new Class({
|
||||||
*/
|
*/
|
||||||
this.glFuncMap = null;
|
this.glFuncMap = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal GL function mapping for setting uniform data.
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/uniform
|
||||||
|
*
|
||||||
|
* Each key is a WebGL constant for a specific uniform type.
|
||||||
|
* Each value has these properties:
|
||||||
|
* - `size`: The number of terms in the uniform, i.e. the length of the vector.
|
||||||
|
* - `set`: The function to call to set the uniform value.
|
||||||
|
* - If it is a matrix:
|
||||||
|
* - `matrix: true`
|
||||||
|
* - Otherwise:
|
||||||
|
* - `setV`: The function to call to set the uniform value as an array.
|
||||||
|
*
|
||||||
|
* @name Phaser.Renderer.WebGL.WebGLRenderer#uniformSetterMap
|
||||||
|
* @type {any}
|
||||||
|
* @since 3.90.0
|
||||||
|
*/
|
||||||
|
this.uniformSetterMap = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The `type` of the Game Object being currently rendered.
|
* The `type` of the Game Object being currently rendered.
|
||||||
* This can be used by advanced render functions for batching look-ahead.
|
* This can be used by advanced render functions for batching look-ahead.
|
||||||
|
@ -917,6 +936,40 @@ var WebGLRenderer = new Class({
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Map uniform types to WebGL functions
|
||||||
|
this.uniformSetterMap = {
|
||||||
|
0x1404: { size: 1, set: gl.uniform1i, setV: gl.uniform1iv, int: true },
|
||||||
|
0x8B53: { size: 2, set: gl.uniform2i, setV: gl.uniform2iv, int: true },
|
||||||
|
0x8B54: { size: 3, set: gl.uniform3i, setV: gl.uniform3iv, int: true },
|
||||||
|
0x8B55: { size: 4, set: gl.uniform4i, setV: gl.uniform4iv, int: true },
|
||||||
|
0x1406: { size: 1, set: gl.uniform1f, setV: gl.uniform1fv },
|
||||||
|
0x8B50: { size: 2, set: gl.uniform2f, setV: gl.uniform2fv },
|
||||||
|
0x8B51: { size: 3, set: gl.uniform3f, setV: gl.uniform3fv },
|
||||||
|
0x8B52: { size: 4, set: gl.uniform4f, setV: gl.uniform4fv },
|
||||||
|
0x8B5A: { size: 4, matrix: true, set: gl.uniformMatrix2fv },
|
||||||
|
0x8B5B: { size: 9, matrix: true, set: gl.uniformMatrix3fv },
|
||||||
|
0x8B5C: { size: 16, matrix: true, set: gl.uniformMatrix4fv }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Map extra uniform types to integers.
|
||||||
|
// BOOL
|
||||||
|
this.uniformSetterMap[0x8B56] = this.uniformSetterMap[0x1404];
|
||||||
|
|
||||||
|
// BOOL_VEC2
|
||||||
|
this.uniformSetterMap[0x8B57] = this.uniformSetterMap[0x8B53];
|
||||||
|
|
||||||
|
// BOOL_VEC3
|
||||||
|
this.uniformSetterMap[0x8B58] = this.uniformSetterMap[0x8B54];
|
||||||
|
|
||||||
|
// BOOL_VEC4
|
||||||
|
this.uniformSetterMap[0x8B59] = this.uniformSetterMap[0x8B55];
|
||||||
|
|
||||||
|
// SAMPLER_2D
|
||||||
|
this.uniformSetterMap[0x8B5E] = this.uniformSetterMap[0x1404];
|
||||||
|
|
||||||
|
// SAMPLER_CUBE
|
||||||
|
this.uniformSetterMap[0x8B60] = this.uniformSetterMap[0x1404];
|
||||||
|
|
||||||
if (!config.maxTextures || config.maxTextures === -1)
|
if (!config.maxTextures || config.maxTextures === -1)
|
||||||
{
|
{
|
||||||
config.maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
|
config.maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
|
||||||
|
|
15
src/renderer/webgl/typedefs/WebGLUniform.js
Normal file
15
src/renderer/webgl/typedefs/WebGLUniform.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/**
|
||||||
|
* @author Benjamin D. Richards <benjamindrichards@gmail.com>
|
||||||
|
* @copyright 2013-2024 Phaser Studio Inc.
|
||||||
|
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} Phaser.Types.Renderer.WebGL.WebGLUniform
|
||||||
|
* @since 3.90.0
|
||||||
|
*
|
||||||
|
* @property {GLint} location - The location of the uniform.
|
||||||
|
* @property {GLenum} type - The type of the uniform.
|
||||||
|
* @property {GLint} size - The size of the uniform, in elements.
|
||||||
|
* @property {number|number[]} value - The value of the uniform.
|
||||||
|
*/
|
|
@ -150,10 +150,10 @@ var WebGLBufferWrapper = new Class({
|
||||||
*/
|
*/
|
||||||
destroy: function ()
|
destroy: function ()
|
||||||
{
|
{
|
||||||
this.gl.deleteBuffer(this.webGLBuffer);
|
this.renderer.gl.deleteBuffer(this.webGLBuffer);
|
||||||
this.webGLBuffer = null;
|
this.webGLBuffer = null;
|
||||||
this.initialDataOrSize = null;
|
this.initialDataOrSize = null;
|
||||||
this.gl = null;
|
this.renderer = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var Map = require('../../../structs/Map');
|
||||||
var Class = require('../../../utils/Class');
|
var Class = require('../../../utils/Class');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,7 +20,7 @@ var Class = require('../../../utils/Class');
|
||||||
* @constructor
|
* @constructor
|
||||||
* @since 3.80.0
|
* @since 3.80.0
|
||||||
*
|
*
|
||||||
* @param {WebGLRenderingContext} gl - The WebGLRenderingContext to create the WebGLProgram for.
|
* @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - The WebGLRenderer instance that owns this wrapper.
|
||||||
* @param {string} vertexSource - The vertex shader source code as a string.
|
* @param {string} vertexSource - The vertex shader source code as a string.
|
||||||
* @param {string} fragmentShader - The fragment shader source code as a string.
|
* @param {string} fragmentShader - The fragment shader source code as a string.
|
||||||
*/
|
*/
|
||||||
|
@ -27,8 +28,17 @@ var WebGLProgramWrapper = new Class({
|
||||||
|
|
||||||
initialize:
|
initialize:
|
||||||
|
|
||||||
function WebGLProgramWrapper (gl, vertexSource, fragmentSource)
|
function WebGLProgramWrapper (renderer, vertexSource, fragmentSource)
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The WebGLRenderer instance that owns this wrapper.
|
||||||
|
*
|
||||||
|
* @name Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#renderer
|
||||||
|
* @type {Phaser.Renderer.WebGL.WebGLRenderer}
|
||||||
|
* @since 3.90.0
|
||||||
|
*/
|
||||||
|
this.renderer = renderer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The WebGLProgram being wrapped by this class.
|
* The WebGLProgram being wrapped by this class.
|
||||||
*
|
*
|
||||||
|
@ -43,15 +53,6 @@ var WebGLProgramWrapper = new Class({
|
||||||
*/
|
*/
|
||||||
this.webGLProgram = null;
|
this.webGLProgram = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* The WebGLRenderingContext that owns this WebGLProgram.
|
|
||||||
*
|
|
||||||
* @name Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#gl
|
|
||||||
* @type {WebGLRenderingContext}
|
|
||||||
* @since 3.80.0
|
|
||||||
*/
|
|
||||||
this.gl = gl;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The vertex shader source code as a string.
|
* The vertex shader source code as a string.
|
||||||
*
|
*
|
||||||
|
@ -92,6 +93,60 @@ var WebGLProgramWrapper = new Class({
|
||||||
*/
|
*/
|
||||||
this._fragmentShader = null;
|
this._fragmentShader = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attribute state of this program.
|
||||||
|
*
|
||||||
|
* These represent the actual state in WebGL, and are only updated when
|
||||||
|
* the program is used to draw.
|
||||||
|
*
|
||||||
|
* @name Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#glAttributes
|
||||||
|
* @type {{ location: WebGLAttribLocation, name: string, size: number, type: GLenum }[]}
|
||||||
|
* @since 3.90.0
|
||||||
|
*/
|
||||||
|
this.glAttributes = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of attribute names to their indexes in `glAttributes`.
|
||||||
|
*
|
||||||
|
* @name Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#glAttributeNames
|
||||||
|
* @type {Map<string, number>}
|
||||||
|
* @since 3.90.0
|
||||||
|
*/
|
||||||
|
this.glAttributeNames = new Map();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The buffer which this program is using for its attributes.
|
||||||
|
*
|
||||||
|
* @name Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#glAttributeBuffer
|
||||||
|
* @type {?WebGLBuffer}
|
||||||
|
* @default null
|
||||||
|
* @since 3.90.0
|
||||||
|
*/
|
||||||
|
this.glAttributeBuffer = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The uniform state of this program.
|
||||||
|
*
|
||||||
|
* These represent the actual state in WebGL, and are only updated when
|
||||||
|
* the program is used to draw.
|
||||||
|
*
|
||||||
|
* @name Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#glUniforms
|
||||||
|
* @type {Map<string, Phaser.Types.Renderer.WebGL.WebGLUniform>}
|
||||||
|
* @since 3.90.0
|
||||||
|
*/
|
||||||
|
this.glUniforms = new Map();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests to update the uniform state.
|
||||||
|
* Set a request by name to a new value.
|
||||||
|
* These are only processed when the program is used to draw.
|
||||||
|
*
|
||||||
|
* @name Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#uniformRequests
|
||||||
|
* @type {Map<string, any>}
|
||||||
|
* @since 3.90.0
|
||||||
|
*/
|
||||||
|
this.uniformRequests = new Map();
|
||||||
|
|
||||||
this.createResource();
|
this.createResource();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -107,7 +162,12 @@ var WebGLProgramWrapper = new Class({
|
||||||
*/
|
*/
|
||||||
createResource: function ()
|
createResource: function ()
|
||||||
{
|
{
|
||||||
var gl = this.gl;
|
var renderer = this.renderer;
|
||||||
|
var gl = renderer.gl;
|
||||||
|
|
||||||
|
// Ensure that there is no vertex buffer associated with this program,
|
||||||
|
// so that the attributes are reset.
|
||||||
|
this.glAttributeBuffer = null;
|
||||||
|
|
||||||
if (gl.isContextLost())
|
if (gl.isContextLost())
|
||||||
{
|
{
|
||||||
|
@ -118,6 +178,8 @@ var WebGLProgramWrapper = new Class({
|
||||||
|
|
||||||
var program = gl.createProgram();
|
var program = gl.createProgram();
|
||||||
|
|
||||||
|
this.webGLProgram = program;
|
||||||
|
|
||||||
var vs = gl.createShader(gl.VERTEX_SHADER);
|
var vs = gl.createShader(gl.VERTEX_SHADER);
|
||||||
var fs = gl.createShader(gl.FRAGMENT_SHADER);
|
var fs = gl.createShader(gl.FRAGMENT_SHADER);
|
||||||
|
|
||||||
|
@ -159,9 +221,164 @@ var WebGLProgramWrapper = new Class({
|
||||||
throw new Error('Link Shader failed:' + gl.getProgramInfoLog(program));
|
throw new Error('Link Shader failed:' + gl.getProgramInfoLog(program));
|
||||||
}
|
}
|
||||||
|
|
||||||
gl.useProgram(program);
|
// Extract attributes.
|
||||||
|
this.glAttributeNames.clear();
|
||||||
|
this.glAttributes.length = 0;
|
||||||
|
var attributeCount = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
|
||||||
|
|
||||||
this.webGLProgram = program;
|
for (var index = 0; index < attributeCount; index++)
|
||||||
|
{
|
||||||
|
var attribute = gl.getActiveAttrib(program, index);
|
||||||
|
var location = gl.getAttribLocation(program, attribute.name);
|
||||||
|
|
||||||
|
this.glAttributeNames.set(attribute.name, index);
|
||||||
|
this.glAttributes[index] = {
|
||||||
|
location: location,
|
||||||
|
name: attribute.name,
|
||||||
|
size: attribute.size,
|
||||||
|
type: attribute.type
|
||||||
|
};
|
||||||
|
gl.enableVertexAttribArray(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract uniforms.
|
||||||
|
if (this.glUniforms.size > 0)
|
||||||
|
{
|
||||||
|
// Send the old uniforms to the request map,
|
||||||
|
// so they are recreated with the new program.
|
||||||
|
this.glUniforms.each(function (name, uniform)
|
||||||
|
{
|
||||||
|
if (!this.uniformRequests.has(name))
|
||||||
|
{
|
||||||
|
this.uniformRequests.set(name, uniform.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.glUniforms.clear();
|
||||||
|
var uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
|
||||||
|
|
||||||
|
for (index = 0; index < uniformCount; index++)
|
||||||
|
{
|
||||||
|
var uniform = gl.getActiveUniform(program, index);
|
||||||
|
var setter = renderer.uniformSetterMap[uniform.type];
|
||||||
|
|
||||||
|
var initialValue = setter.int
|
||||||
|
? new Int32Array(uniform.size * setter.size)
|
||||||
|
: new Float32Array(uniform.size * setter.size);
|
||||||
|
|
||||||
|
this.glUniforms.set(uniform.name, {
|
||||||
|
location: gl.getUniformLocation(program, uniform.name),
|
||||||
|
size: uniform.size,
|
||||||
|
type: uniform.type,
|
||||||
|
value: initialValue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a uniform value for this WebGLProgram.
|
||||||
|
*
|
||||||
|
* This method doesn't set the WebGL value directly.
|
||||||
|
* Instead, it adds a request to the `uniforms.requests` map.
|
||||||
|
* These requests are processed when the program is used to draw.
|
||||||
|
*
|
||||||
|
* @method Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#setUniform
|
||||||
|
* @since 3.90.0
|
||||||
|
* @param {string} name - The name of the uniform.
|
||||||
|
* @param {number|number[]|Int32Array|Float32Array} value - The value to set.
|
||||||
|
*/
|
||||||
|
setUniform: function (name, value)
|
||||||
|
{
|
||||||
|
this.uniformRequests.set(name, value);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set this program as the active program in the WebGL context.
|
||||||
|
*
|
||||||
|
* This will also update the attribute and uniform state.
|
||||||
|
*
|
||||||
|
* @method Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#bind
|
||||||
|
* @since 3.90.0
|
||||||
|
*/
|
||||||
|
bind: function ()
|
||||||
|
{
|
||||||
|
var _this = this;
|
||||||
|
var renderer = this.renderer;
|
||||||
|
var gl = renderer.gl;
|
||||||
|
|
||||||
|
renderer.glWrapper.updateBindingsProgram({
|
||||||
|
bindings: { program: this }
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Bind the vertex buffer to the attributes.
|
||||||
|
|
||||||
|
// Process uniform requests.
|
||||||
|
this.uniformRequests.each(function (name, value)
|
||||||
|
{
|
||||||
|
var uniform = _this.glUniforms.get(name);
|
||||||
|
|
||||||
|
if (!uniform) { return; }
|
||||||
|
|
||||||
|
var uniformValue = uniform.value;
|
||||||
|
|
||||||
|
// Update stored values if they are different.
|
||||||
|
if (uniformValue.length)
|
||||||
|
{
|
||||||
|
var different = false;
|
||||||
|
for (var i = 0; i < uniformValue.length; i++)
|
||||||
|
{
|
||||||
|
if (uniformValue[i] !== value[i])
|
||||||
|
{
|
||||||
|
different = true;
|
||||||
|
uniformValue[i] = value[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!different) { return; }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (uniformValue === value) { return; }
|
||||||
|
uniformValue = value;
|
||||||
|
uniform.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get info about the uniform.
|
||||||
|
var location = uniform.location;
|
||||||
|
var type = uniform.type;
|
||||||
|
var size = uniform.size;
|
||||||
|
var setter = renderer.uniformSetterMap[type];
|
||||||
|
|
||||||
|
// Set the value.
|
||||||
|
if (setter.matrix)
|
||||||
|
{
|
||||||
|
setter.set.call(gl, location, false, uniformValue);
|
||||||
|
}
|
||||||
|
else if (size > 1)
|
||||||
|
{
|
||||||
|
setter.setV.call(gl, location, uniformValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (setter.size)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
setter.set.call(gl, location, value);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
setter.set.call(gl, location, value[0], value[1]);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
setter.set.call(gl, location, value[0], value[1], value[2]);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
setter.set.call(gl, location, value[0], value[1], value[2], value[3]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.uniformRequests.clear();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -177,7 +394,7 @@ var WebGLProgramWrapper = new Class({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var gl = this.gl;
|
var gl = this.renderer.gl;
|
||||||
if (!gl.isContextLost())
|
if (!gl.isContextLost())
|
||||||
{
|
{
|
||||||
if (this._vertexShader)
|
if (this._vertexShader)
|
||||||
|
@ -189,12 +406,22 @@ var WebGLProgramWrapper = new Class({
|
||||||
gl.deleteShader(this._fragmentShader);
|
gl.deleteShader(this._fragmentShader);
|
||||||
}
|
}
|
||||||
gl.deleteProgram(this.webGLProgram);
|
gl.deleteProgram(this.webGLProgram);
|
||||||
|
|
||||||
|
for (var i = 0; i < this.glAttributes.length; i++)
|
||||||
|
{
|
||||||
|
gl.disableVertexAttribArray(this.glAttributes[i].location);
|
||||||
|
}
|
||||||
|
this.glAttributes.length = 0;
|
||||||
|
this.glUniforms.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.glAttributeBuffer = null;
|
||||||
|
this.glAttributeNames.clear();
|
||||||
|
this.uniformRequests.clear();
|
||||||
this._vertexShader = null;
|
this._vertexShader = null;
|
||||||
this._fragmentShader = null;
|
this._fragmentShader = null;
|
||||||
this.webGLProgram = null;
|
this.webGLProgram = null;
|
||||||
this.gl = null;
|
this.renderer = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue