DSDSServer2024/build/build.20240805/static/js/Cesium-1.53/Specs/Renderer/VertexArraySpec.js

840 lines
24 KiB
JavaScript

defineSuite([
'Renderer/VertexArray',
'Core/ComponentDatatype',
'Core/PrimitiveType',
'Renderer/Buffer',
'Renderer/BufferUsage',
'Renderer/DrawCommand',
'Renderer/ShaderProgram',
'Specs/createContext'
], function(
VertexArray,
ComponentDatatype,
PrimitiveType,
Buffer,
BufferUsage,
DrawCommand,
ShaderProgram,
createContext) {
'use strict';
var context;
beforeAll(function() {
context = createContext();
});
afterAll(function() {
context.destroyForSpecs();
});
it('binds', function() {
var positionBuffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 3,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
index : 0,
enabled : true,
vertexBuffer : positionBuffer,
componentsPerAttribute : 3,
componentDatatype : ComponentDatatype.FLOAT,
normalize : false,
offsetInBytes : 0,
strideInBytes : 0,
instanceDivisor : 0
// tightly packed
}];
var va = new VertexArray({
context : context,
attributes : attributes
});
va._bind();
va._unBind();
va = va.destroy();
});
it('binds with default values', function() {
var positionBuffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 3,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
vertexBuffer : positionBuffer,
componentsPerAttribute : 3
}];
var va = new VertexArray({
context : context,
attributes : attributes
});
expect(va.numberOfAttributes).toEqual(1);
expect(va.getAttribute(0).index).toEqual(0);
expect(va.getAttribute(0).enabled).toEqual(true);
expect(va.getAttribute(0).vertexBuffer).toEqual(positionBuffer);
expect(va.getAttribute(0).componentsPerAttribute).toEqual(3);
expect(va.getAttribute(0).componentDatatype).toEqual(ComponentDatatype.FLOAT);
expect(va.getAttribute(0).normalize).toEqual(false);
expect(va.getAttribute(0).offsetInBytes).toEqual(0);
expect(va.getAttribute(0).strideInBytes).toEqual(0);
expect(va.getAttribute(0).instanceDivisor).toEqual(0);
va._bind();
va._unBind();
va = va.destroy();
});
it('binds with multiple buffers', function() {
var attributeSize = 3 * Float32Array.BYTES_PER_ELEMENT;
var positionBuffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : attributeSize,
usage : BufferUsage.STATIC_DRAW
});
var normalBuffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : attributeSize,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
index : 0,
vertexBuffer : positionBuffer,
componentsPerAttribute : 3,
componentDatatype : ComponentDatatype.FLOAT
}, {
index : 1,
vertexBuffer : normalBuffer,
componentsPerAttribute : 3,
componentDatatype : ComponentDatatype.FLOAT
}];
var va = new VertexArray({
context : context,
attributes : attributes
});
expect(va.numberOfAttributes).toEqual(2);
va._bind();
va._unBind();
va = va.destroy();
});
it('binds with interleaved buffer', function() {
var attributeSize = 3 * Float32Array.BYTES_PER_ELEMENT;
var buffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : attributeSize,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
vertexBuffer : buffer,
componentsPerAttribute : 3,
componentDatatype : ComponentDatatype.FLOAT,
offsetInBytes : 0,
strideInBytes : 2 * attributeSize
}, {
vertexBuffer : buffer,
componentsPerAttribute : 3,
componentDatatype : ComponentDatatype.FLOAT,
normalize : true,
offsetInBytes : attributeSize,
strideInBytes : 2 * attributeSize
}];
var va = new VertexArray({
context : context,
attributes : attributes
});
expect(va.numberOfAttributes).toEqual(2);
va._bind();
va._unBind();
va = va.destroy();
});
it('adds attributes', function() {
var positionBuffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 3,
usage : BufferUsage.STATIC_DRAW
});
var va = new VertexArray({
context : context,
attributes : [{
vertexBuffer : positionBuffer,
componentsPerAttribute : 3
}]
});
expect(va.numberOfAttributes).toEqual(1);
expect(va.getAttribute(0).index).toEqual(0);
expect(va.getAttribute(0).enabled).toEqual(true);
expect(va.getAttribute(0).vertexBuffer).toEqual(positionBuffer);
expect(va.getAttribute(0).componentsPerAttribute).toEqual(3);
expect(va.getAttribute(0).componentDatatype).toEqual(ComponentDatatype.FLOAT);
expect(va.getAttribute(0).normalize).toEqual(false);
expect(va.getAttribute(0).offsetInBytes).toEqual(0);
expect(va.getAttribute(0).strideInBytes).toEqual(0);
expect(va.getAttribute(0).instanceDivisor).toEqual(0);
va = va.destroy();
});
it('modifies attributes', function() {
var buffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 6,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
vertexBuffer : buffer,
componentsPerAttribute : 3
}];
var va = new VertexArray({
context : context,
attributes : attributes
});
expect(va.numberOfAttributes).toEqual(1);
expect(va.getAttribute(0).enabled).toEqual(true);
va.getAttribute(0).enabled = false;
expect(va.getAttribute(0).enabled).toEqual(false);
va._bind();
va._unBind();
va = va.destroy();
});
// The following specs test draw calls that pull from a constant attribute.
// Due to what I believe is a range checking bug in Firefox (Section 6.4 of
// the WebGL spec), an attribute backed by a buffer must also be bound,
// otherwise drawArrays unjustly reports an INVALID_OPERATION, hence the
// firefoxWorkaround attribute below. In practice, we will always have
// an attribute backed by a buffer anyway.
it('renders with a one-component constant value', function() {
var vs =
'attribute float firefoxWorkaround;' +
'attribute float attr;' +
'varying vec4 v_color;' +
'void main() { ' +
' v_color = vec4(attr == 0.5) + vec4(firefoxWorkaround);' +
' gl_PointSize = 1.0;' +
' gl_Position = vec4(0.0, 0.0, 0.0, 1.0);' +
'}';
var fs =
'varying vec4 v_color;' +
'void main() { gl_FragColor = v_color; }';
var sp = ShaderProgram.fromCache({
context : context,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : {
firefoxWorkaround : 0,
attr : 1
}
});
var va = new VertexArray({
context : context,
attributes : [{
vertexBuffer : Buffer.createVertexBuffer({
context : context,
sizeInBytes : Float32Array.BYTES_PER_ELEMENT,
usage : BufferUsage.STATIC_DRAW
}),
componentsPerAttribute : 1
}, {
value : [0.5]
}]
});
var command = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp,
vertexArray : va,
count : 1
});
command.execute(context);
expect(context).toReadPixels([255, 255, 255, 255]);
sp = sp.destroy();
va = va.destroy();
});
it('renders with a two-component constant value', function() {
var vs =
'attribute float firefoxWorkaround;' +
'attribute vec2 attr;' +
'varying vec4 v_color;' +
'void main() { ' +
' v_color = vec4(attr == vec2(0.25, 0.75)) + vec4(firefoxWorkaround);' +
' gl_PointSize = 1.0;' +
' gl_Position = vec4(0.0, 0.0, 0.0, 1.0);' +
'}';
var fs =
'varying vec4 v_color;' +
'void main() { gl_FragColor = v_color; }';
var sp = ShaderProgram.fromCache({
context : context,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : {
firefoxWorkaround : 0,
attr : 1
}
});
var va = new VertexArray({
context : context,
attributes : [{
vertexBuffer : Buffer.createVertexBuffer({
context : context,
sizeInBytes : Float32Array.BYTES_PER_ELEMENT,
usage : BufferUsage.STATIC_DRAW
}),
componentsPerAttribute : 1
}, {
value : [0.25, 0.75]
}]
});
var command = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp,
vertexArray : va,
count : 1
});
command.execute(context);
expect(context).toReadPixels([255, 255, 255, 255]);
sp = sp.destroy();
va = va.destroy();
});
it('renders with a three-component constant value', function() {
var vs =
'attribute float firefoxWorkaround;' +
'attribute vec3 attr;' +
'varying vec4 v_color;' +
'void main() { ' +
' v_color = vec4(attr == vec3(0.25, 0.5, 0.75)) + vec4(firefoxWorkaround);' +
' gl_PointSize = 1.0;' +
' gl_Position = vec4(0.0, 0.0, 0.0, 1.0);' +
'}';
var fs =
'varying vec4 v_color;' +
'void main() { gl_FragColor = v_color; }';
var sp = ShaderProgram.fromCache({
context : context,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : {
firefoxWorkaround : 0,
attr : 1
}
});
var va = new VertexArray({
context : context,
attributes : [{
vertexBuffer : Buffer.createVertexBuffer({
context : context,
sizeInBytes : Float32Array.BYTES_PER_ELEMENT,
usage : BufferUsage.STATIC_DRAW
}),
componentsPerAttribute : 1
}, {
value : [0.25, 0.5, 0.75]
}]
});
var command = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp,
vertexArray : va,
count : 1
});
command.execute(context);
expect(context).toReadPixels([255, 255, 255, 255]);
sp = sp.destroy();
va = va.destroy();
});
it('renders with a four-component constant value', function() {
var vs =
'attribute float firefoxWorkaround;' +
'attribute vec4 attr;' +
'varying vec4 v_color;' +
'void main() { ' +
' v_color = vec4(attr == vec4(0.2, 0.4, 0.6, 0.8)) + vec4(firefoxWorkaround);' +
' gl_PointSize = 1.0;' +
' gl_Position = vec4(0.0, 0.0, 0.0, 1.0);' +
'}';
var fs =
'varying vec4 v_color;' +
'void main() { gl_FragColor = v_color; }';
var sp = ShaderProgram.fromCache({
context : context,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : {
firefoxWorkaround : 0,
attr : 1
}
});
var va = new VertexArray({
context : context,
attributes : [{
vertexBuffer : Buffer.createVertexBuffer({
context : context,
sizeInBytes : Float32Array.BYTES_PER_ELEMENT,
usage : BufferUsage.STATIC_DRAW
}),
componentsPerAttribute : 1
}, {
value : [0.2, 0.4, 0.6, 0.8]
}]
});
var command = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp,
vertexArray : va,
count : 1
});
command.execute(context);
expect(context).toReadPixels([255, 255, 255, 255]);
sp = sp.destroy();
va = va.destroy();
});
it('renders two vertex arrays with constant values', function() {
var vs =
'attribute float firefoxWorkaround;' +
'attribute vec4 attr;' +
'varying vec4 v_color;' +
'void main() { ' +
' v_color = attr + vec4(firefoxWorkaround);' +
' gl_PointSize = 1.0;' +
' gl_Position = vec4(0.0, 0.0, 0.0, 1.0);' +
'}';
var fs =
'varying vec4 v_color;' +
'void main() { gl_FragColor = v_color; }';
var sp = ShaderProgram.fromCache({
context : context,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : {
firefoxWorkaround : 0,
attr : 1
}
});
var vertexBuffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : Float32Array.BYTES_PER_ELEMENT,
usage : BufferUsage.STATIC_DRAW
});
var vaRed = new VertexArray({
context : context,
attributes : [{
vertexBuffer : vertexBuffer,
componentsPerAttribute : 1
}, {
value : [1, 0, 0, 1]
}]
});
var vaGreen = new VertexArray({
context : context,
attributes : [{
vertexBuffer : vertexBuffer,
componentsPerAttribute : 1
}, {
value : [0, 1, 0, 1]
}]
});
var commandRed = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp,
vertexArray : vaRed,
count : 1
});
var commandGreen = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp,
vertexArray : vaGreen,
count : 1
});
commandRed.execute(context);
expect(context).toReadPixels([255, 0, 0, 255]);
commandGreen.execute(context);
expect(context).toReadPixels([0, 255, 0, 255]);
sp = sp.destroy();
vaRed = vaRed.destroy();
vaGreen = vaGreen.destroy();
});
it('destroys', function() {
var va = new VertexArray({
context : context,
attributes : [{
vertexBuffer : Buffer.createVertexBuffer({
context : context,
sizeInBytes : new Float32Array([0, 0, 0, 1]).byteLength,
usage : BufferUsage.STATIC_DRAW
}),
componentsPerAttribute : 4
}]
});
expect(va.isDestroyed()).toEqual(false);
va.destroy();
expect(va.isDestroyed()).toEqual(true);
});
it('fails to create (missing vertexBuffer and value)', function() {
var attributes = [{
componentsPerAttribute : 3
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
});
it('fails to create (provides both vertexBuffer and value)', function() {
var buffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 3,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
vertexBuffer : buffer,
value : [1, 2, 3],
componentsPerAttribute : 3
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
});
it('fails to create with duplicate indices', function() {
var buffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 1,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
index : 1,
vertexBuffer : buffer,
componentsPerAttribute : 1
}, {
index : 1,
vertexBuffer : buffer,
componentsPerAttribute : 1
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
});
it('fails to create (componentsPerAttribute missing)', function() {
var buffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 3,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
vertexBuffer : buffer
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
});
it('fails to create (componentsPerAttribute < 1)', function() {
var attributes = [{
componentsPerAttribute : 0
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
});
it('fails to create (componentsPerAttribute > 4)', function() {
var attributes = [{
componentsPerAttribute : 5
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
});
it('fails to create (value.length < 1)', function() {
var attributes = [{
value : []
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
});
it('fails to create (value.length > 4)', function() {
var attributes = [{
value : [1.0, 2.0, 3.0, 4.0, 5.0]
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
});
it('fails to create (componentDatatype)', function() {
var buffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 3,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
vertexBuffer : buffer,
componentsPerAttribute : 3,
componentDatatype : 'invalid component datatype'
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
});
it('fails to create (strideInBytes)', function() {
var buffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 3,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
vertexBuffer : buffer,
componentsPerAttribute : 3,
strideInBytes : 256
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
});
it('fails to get attribute', function() {
var attributes = [{
value : [0.0, 0.0, 0.0],
componentsPerAttribute : 3
}];
var va = new VertexArray({
context : context,
attributes : attributes
});
expect(function() {
return va.getAttribute();
}).toThrowDeveloperError();
});
it('fails to destroy', function() {
var attributes = [{
value : [0.0, 0.0, 0.0],
componentsPerAttribute : 3
}];
var va = new VertexArray({
context : context,
attributes : attributes
});
va.destroy();
expect(function() {
va.destroy();
}).toThrowDeveloperError();
});
it('throws when there is no context', function() {
expect(function() {
return new VertexArray();
}).toThrowDeveloperError();
});
it('throws if instanceDivisor is less than zero', function() {
var buffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 3,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
vertexBuffer : buffer,
componentsPerAttribute : 3,
instanceDivisor : -1
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
});
// Direct3D 9 requires vertex attribute zero to not be instanced. While ANGLE can work around this, it is best
// to follow this convention. This test also guarantees that not all vertex attributes are instanced.
it('throws if vertex attribute zero is instanced', function() {
var buffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 3,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
index : 0,
vertexBuffer : buffer,
componentsPerAttribute : 3,
instanceDivisor : 1
}, {
index : 1,
vertexBuffer : buffer,
componentsPerAttribute : 3
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
});
it('throws if an attribute has an instanceDivisor and is not backed by a buffer', function() {
var buffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 3,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
index : 0,
vertexBuffer : buffer,
componentsPerAttribute : 3
}, {
index : 1,
value : [0.0, 0.0, 1.0],
componentsPerAttribute : 3,
instanceDivisor : 1
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
});
it('throws when instanceDivisor is greater than zero and the instanced arrays extension is not supported.', function() {
if (!context.instancedArrays) {
var buffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 3,
usage : BufferUsage.STATIC_DRAW
});
var attributes = [{
index : 0,
vertexBuffer : buffer,
componentsPerAttribute : 3
}, {
index : 1,
vertexBuffer : buffer,
componentsPerAttribute : 3,
instanceDivisor : 1
}];
expect(function() {
return new VertexArray({
context : context,
attributes : attributes
});
}).toThrowDeveloperError();
}
});
}, 'WebGL');