mirror of
https://github.com/DeviceFarmer/stf.git
synced 2026-04-22 22:05:21 +02:00
- Added benchmark comparing JPEG, PNG, WEBP, DDS DXT1, and CRN DXT1 formats.
- Pixi Canvas and WebGL render was added for quick benchmarking but it's going away soon, because WebGL is even slower than Canvas for big textures. The browsers nowadays use OpenGL in the backend for rendering Canvas. - There is 3 different WebGL Renders but they need adjusting so they work with Non Power Of Two textures. - For now the winner is JPEG+Canvas, however CRN+WebGL will be better almost for sure if server side supports it.
This commit is contained in:
@@ -3,35 +3,7 @@
|
||||
// See http://jsperf.com/canvas-drawimage-vs-webgl-drawarrays
|
||||
|
||||
|
||||
function FastImageLoader(url) {
|
||||
var that = this
|
||||
this.loader = new Image()
|
||||
|
||||
if (url) {
|
||||
this.load(url)
|
||||
}
|
||||
|
||||
this.loader.onload = function () {
|
||||
if (typeof(that.onLoad) === 'function') {
|
||||
that.onLoad(this)
|
||||
}
|
||||
}
|
||||
|
||||
this.loader.onerror = function () {
|
||||
|
||||
if (typeof(that.onError) === 'function') {
|
||||
that.onError(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an URL
|
||||
* @param {string} url
|
||||
*/
|
||||
FastImageLoader.prototype.load = function (url) {
|
||||
this.loader.src = url
|
||||
}
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function FastPixiRender(canvasElement, options) {
|
||||
@@ -79,6 +51,7 @@ FastPixiRender.prototype.draw = function (image) {
|
||||
this.renderer.render(this.stage)
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
function CanvasRender(canvasElement, options) {
|
||||
var checkForCanvasElement = function checkForCanvasElement() {
|
||||
@@ -107,6 +80,215 @@ CanvasRender.prototype.clear = function () {
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
// Based on http://www-cs-students.stanford.edu/~eparker/files/crunch/renderer.js
|
||||
|
||||
/**
|
||||
* Constructs a renderer object.
|
||||
* @param {WebGLRenderingContext} gl The GL context.
|
||||
* @constructor
|
||||
*/
|
||||
var Renderer = function (gl) {
|
||||
/**
|
||||
* The GL context.
|
||||
* @type {WebGLRenderingContext}
|
||||
* @private
|
||||
*/
|
||||
this.gl_ = gl;
|
||||
|
||||
/**
|
||||
* The WebGLProgram.
|
||||
* @type {WebGLProgram}
|
||||
* @private
|
||||
*/
|
||||
this.program_ = gl.createProgram();
|
||||
|
||||
/**
|
||||
* @type {WebGLShader}
|
||||
* @private
|
||||
*/
|
||||
this.vertexShader_ = this.compileShader_(
|
||||
Renderer.vertexShaderSource_, gl.VERTEX_SHADER);
|
||||
|
||||
/**
|
||||
* @type {WebGLShader}
|
||||
* @private
|
||||
*/
|
||||
this.fragmentShader_ = this.compileShader_(
|
||||
Renderer.fragmentShaderSource_, gl.FRAGMENT_SHADER);
|
||||
|
||||
/**
|
||||
* Cached uniform locations.
|
||||
* @type {Object.<string, WebGLUniformLocation>}
|
||||
* @private
|
||||
*/
|
||||
this.uniformLocations_ = {};
|
||||
|
||||
/**
|
||||
* Cached attribute locations.
|
||||
* @type {Object.<string, WebGLActiveInfo>}
|
||||
* @private
|
||||
*/
|
||||
this.attribLocations_ = {};
|
||||
|
||||
/**
|
||||
* A vertex buffer containing a single quad with xy coordinates from [-1,-1]
|
||||
* to [1,1] and uv coordinates from [0,0] to [1,1].
|
||||
* @private
|
||||
*/
|
||||
this.quadVertexBuffer_ = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVertexBuffer_);
|
||||
var vertices = new Float32Array(
|
||||
[-1.0, -1.0, 0.0, 1.0,
|
||||
+1.0, -1.0, 1.0, 1.0,
|
||||
-1.0, +1.0, 0.0, 0.0,
|
||||
1.0, +1.0, 1.0, 0.0]);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
||||
|
||||
|
||||
// Init shaders
|
||||
gl.attachShader(this.program_, this.vertexShader_);
|
||||
gl.attachShader(this.program_, this.fragmentShader_);
|
||||
gl.bindAttribLocation(this.program_, 0, 'vert');
|
||||
gl.linkProgram(this.program_);
|
||||
gl.useProgram(this.program_);
|
||||
gl.enableVertexAttribArray(0);
|
||||
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
gl.disable(gl.CULL_FACE);
|
||||
|
||||
var count = gl.getProgramParameter(this.program_, gl.ACTIVE_UNIFORMS);
|
||||
for (var i = 0; i < /** @type {number} */(count); i++) {
|
||||
var infoU = gl.getActiveUniform(this.program_, i);
|
||||
this.uniformLocations_[infoU.name] = gl.getUniformLocation(this.program_, infoU.name);
|
||||
}
|
||||
|
||||
count = gl.getProgramParameter(this.program_, gl.ACTIVE_ATTRIBUTES);
|
||||
for (var j = 0; j < /** @type {number} */(count); j++) {
|
||||
var infoA = gl.getActiveAttrib(this.program_, j);
|
||||
this.attribLocations_[infoA.name] = gl.getAttribLocation(this.program_, infoA.name);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Renderer.prototype.finishInit = function () {
|
||||
this.draw();
|
||||
};
|
||||
|
||||
|
||||
Renderer.prototype.createDxtTexture = function (dxtData, width, height, format) {
|
||||
var gl = this.gl_;
|
||||
var tex = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||
gl.compressedTexImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
0,
|
||||
format,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
dxtData);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
//gl.generateMipmap(gl.TEXTURE_2D)
|
||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
return tex;
|
||||
};
|
||||
|
||||
|
||||
Renderer.prototype.createRgb565Texture = function (rgb565Data, width, height) {
|
||||
var gl = this.gl_;
|
||||
var tex = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||
gl.texImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
0,
|
||||
gl.RGB,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
gl.RGB,
|
||||
gl.UNSIGNED_SHORT_5_6_5,
|
||||
rgb565Data);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
//gl.generateMipmap(gl.TEXTURE_2D)
|
||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
return tex;
|
||||
};
|
||||
|
||||
|
||||
Renderer.prototype.drawTexture = function (texture, width, height) {
|
||||
var gl = this.gl_;
|
||||
// draw scene
|
||||
gl.clearColor(0, 0, 0, 1);
|
||||
gl.clearDepth(1.0);
|
||||
gl.viewport(0, 0, width, height);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
gl.uniform1i(this.uniformLocations_.texSampler, 0);
|
||||
|
||||
gl.enableVertexAttribArray(this.attribLocations_.vert);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVertexBuffer_);
|
||||
gl.vertexAttribPointer(this.attribLocations_.vert, 4, gl.FLOAT,
|
||||
false, 0, 0);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Compiles a GLSL shader and returns a WebGLShader.
|
||||
* @param {string} shaderSource The shader source code string.
|
||||
* @param {number} type Either VERTEX_SHADER or FRAGMENT_SHADER.
|
||||
* @return {WebGLShader} The new WebGLShader.
|
||||
* @private
|
||||
*/
|
||||
Renderer.prototype.compileShader_ = function (shaderSource, type) {
|
||||
var gl = this.gl_;
|
||||
var shader = gl.createShader(type);
|
||||
gl.shaderSource(shader, shaderSource);
|
||||
gl.compileShader(shader);
|
||||
return shader;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
Renderer.vertexShaderSource_ = [
|
||||
'attribute vec4 vert;',
|
||||
'varying vec2 v_texCoord;',
|
||||
'void main() {',
|
||||
' gl_Position = vec4(vert.xy, 0.0, 1.0);',
|
||||
' v_texCoord = vert.zw;',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
Renderer.fragmentShaderSource_ = [
|
||||
'precision highp float;',
|
||||
'uniform sampler2D texSampler;',
|
||||
'varying vec2 v_texCoord;',
|
||||
'void main() {',
|
||||
' gl_FragColor = texture2D(texSampler, v_texCoord);',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function WebGLRender(canvasElement, options) {
|
||||
var checkForCanvasElement = function checkForCanvasElement() {
|
||||
if (!canvasElement) {
|
||||
@@ -139,6 +321,13 @@ function WebGLRender(canvasElement, options) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.ctx.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc')) {
|
||||
this.dxtSupported = false
|
||||
}
|
||||
|
||||
this.renderer = new Renderer(this.ctx)
|
||||
|
||||
|
||||
this.contextLost = false
|
||||
|
||||
// gl.useProgram(this.shaderManager.defaultShader.program)
|
||||
@@ -146,7 +335,7 @@ function WebGLRender(canvasElement, options) {
|
||||
//this.ctx.disable(this.ctx.DEPTH_TEST)
|
||||
//this.ctx.disable(this.ctx.CULL_FACE)
|
||||
|
||||
this.setup()
|
||||
//this.setup()
|
||||
}
|
||||
|
||||
WebGLRender.prototype.setup = function () {
|
||||
@@ -207,6 +396,13 @@ WebGLRender.prototype.setup = function () {
|
||||
}
|
||||
|
||||
WebGLRender.prototype.draw = function (image) {
|
||||
// this.renderer.drawTexture(image, image.width, image.height)
|
||||
this.renderer.drawTexture(image, 643, 1149)
|
||||
|
||||
}
|
||||
|
||||
|
||||
WebGLRender.prototype.drawOld = function (image) {
|
||||
var tex = this.ctx.createTexture()
|
||||
this.ctx.bindTexture(this.ctx.TEXTURE_2D, tex)
|
||||
this.ctx.texParameteri(this.ctx.TEXTURE_2D, this.ctx.TEXTURE_MIN_FILTER, this.ctx.NEAREST)
|
||||
@@ -233,10 +429,29 @@ WebGLRender.prototype.clear = function () {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function FastImageRender(canvasElement, options) {
|
||||
var that = this
|
||||
this.options = options || {}
|
||||
this.canvasElement = canvasElement
|
||||
|
||||
if (true) {
|
||||
this.loader = new Image()
|
||||
this.loader.onload = function () {
|
||||
if (typeof(that.onLoad) === 'function') {
|
||||
that.onLoad(this)
|
||||
}
|
||||
}
|
||||
this.loader.onerror = function () {
|
||||
if (typeof(that.onError) === 'function') {
|
||||
that.onError(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.render === 'webgl') {
|
||||
this.render = new WebGLRender(canvasElement, options)
|
||||
} else if (this.options.render.indexOf('pixi') !== -1) {
|
||||
@@ -244,6 +459,36 @@ function FastImageRender(canvasElement, options) {
|
||||
} else {
|
||||
this.render = new CanvasRender(canvasElement, options)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
FastImageRender.prototype.load = function (url, type) {
|
||||
var that = this
|
||||
|
||||
if (this.options.textureLoader) {
|
||||
if (!this.textureLoader) {
|
||||
this.textureLoader = new TextureUtil.TextureLoader(this.render.ctx)
|
||||
}
|
||||
var texture = null
|
||||
if (type) {
|
||||
texture = this.render.ctx.createTexture();
|
||||
this.textureLoader.loadEx(url, texture, true, function (tex) {
|
||||
if (typeof(that.onLoad) === 'function') {
|
||||
that.onLoad(texture)
|
||||
}
|
||||
}, type)
|
||||
} else {
|
||||
this.textureLoader.load(url, function (texture) {
|
||||
if (typeof(that.onLoad) === 'function') {
|
||||
that.onLoad(texture)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
} else {
|
||||
this.loader.src = url
|
||||
}
|
||||
}
|
||||
|
||||
FastImageRender.prototype.draw = function (image) {
|
||||
@@ -335,10 +580,12 @@ Object.defineProperty(FastImageRender.prototype, 'canvasStyleHeight', {
|
||||
})
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Check for Non CommonJS world
|
||||
if (typeof module !== 'undefined') {
|
||||
module.exports = {
|
||||
FastImageRender: FastImageRender,
|
||||
FastImageLoader: FastImageLoader
|
||||
FastImageRender: FastImageRender
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user