DSDSWeb/static/js/Cesium-1.53/Specs/Renderer/FramebufferSpec.js

976 lines
31 KiB
JavaScript
Raw Normal View History

2024-07-11 18:02:47 +08:00
defineSuite([
'Renderer/Framebuffer',
'Core/Color',
'Core/PixelFormat',
'Core/PrimitiveType',
'Core/WebGLConstants',
'Renderer/Buffer',
'Renderer/BufferUsage',
'Renderer/ClearCommand',
'Renderer/ContextLimits',
'Renderer/CubeMap',
'Renderer/DrawCommand',
'Renderer/PixelDatatype',
'Renderer/Renderbuffer',
'Renderer/RenderbufferFormat',
'Renderer/RenderState',
'Renderer/ShaderProgram',
'Renderer/Texture',
'Renderer/VertexArray',
'Specs/createContext'
], function(
Framebuffer,
Color,
PixelFormat,
PrimitiveType,
WebGLConstants,
Buffer,
BufferUsage,
ClearCommand,
ContextLimits,
CubeMap,
DrawCommand,
PixelDatatype,
Renderbuffer,
RenderbufferFormat,
RenderState,
ShaderProgram,
Texture,
VertexArray,
createContext) {
'use strict';
var context;
var sp;
var va;
var framebuffer;
beforeAll(function() {
context = createContext();
});
afterAll(function() {
context.destroyForSpecs();
});
afterEach(function() {
sp = sp && sp.destroy();
va = va && va.destroy();
framebuffer = framebuffer && framebuffer.destroy();
});
it('has a color texture attachment', function() {
framebuffer = new Framebuffer({
context : context,
colorTextures : [new Texture({
context : context,
width : 1,
height : 1
})]
});
expect(framebuffer.getColorTexture(0)).toBeDefined();
});
it('has a color renderbuffer attachment', function() {
framebuffer = new Framebuffer({
context : context,
colorRenderbuffers : [new Renderbuffer({
context : context,
format : RenderbufferFormat.RGBA4
})]
});
expect(framebuffer.getColorRenderbuffer(0)).toBeDefined();
});
it('has a depth texture attachment', function() {
if (context.depthTexture) {
framebuffer = new Framebuffer({
context : context,
depthTexture : new Texture({
context : context,
width : 1,
height : 1,
pixelFormat : PixelFormat.DEPTH_COMPONENT,
pixelDatatype : PixelDatatype.UNSIGNED_SHORT
})
});
expect(framebuffer.depthTexture).toBeDefined();
}
});
it('has a depth renderbuffer attachment', function() {
framebuffer = new Framebuffer({
context : context,
depthRenderbuffer : new Renderbuffer({
context : context,
format : RenderbufferFormat.DEPTH_COMPONENT16
})
});
expect(framebuffer.depthRenderbuffer).toBeDefined();
});
it('has a stencil renderbuffer attachment', function() {
framebuffer = new Framebuffer({
context : context,
stencilRenderbuffer : new Renderbuffer({
context : context,
format : RenderbufferFormat.STENCIL_INDEX8
})
});
expect(framebuffer.stencilRenderbuffer).toBeDefined();
});
it('has a depth-stencil texture attachment', function() {
if (context.depthTexture) {
framebuffer = new Framebuffer({
context : context,
depthStencilTexture : new Texture({
context : context,
width : 1,
height : 1,
pixelFormat : PixelFormat.DEPTH_STENCIL,
pixelDatatype : PixelDatatype.UNSIGNED_INT_24_8
})
});
expect(framebuffer.depthStencilTexture).toBeDefined();
}
});
it('has a depth-stencil renderbuffer attachment', function() {
framebuffer = new Framebuffer({
context : context,
depthStencilRenderbuffer : new Renderbuffer({
context : context,
format : RenderbufferFormat.DEPTH_STENCIL
})
});
expect(framebuffer.depthStencilRenderbuffer).toBeDefined();
});
it('has a depth attachment', function() {
framebuffer = new Framebuffer({
context : context
});
expect(framebuffer.hasDepthAttachment).toEqual(false);
framebuffer.destroy();
framebuffer = new Framebuffer({
context : context,
depthRenderbuffer : new Renderbuffer({
context : context,
format : RenderbufferFormat.DEPTH_COMPONENT16
})
});
expect(framebuffer.hasDepthAttachment).toEqual(true);
});
it('clears a color attachment', function() {
// 1 of 3. Clear default color buffer to black.
ClearCommand.ALL.execute(context);
expect(context).toReadPixels([0, 0, 0, 255]);
// 2 of 3. Clear framebuffer color attachment to green.
var colorTexture = new Texture({
context : context,
width : 1,
height : 1
});
framebuffer = new Framebuffer({
context : context,
colorTextures : [colorTexture]
});
var clearCommand = new ClearCommand({
color : new Color (0.0, 1.0, 0.0, 1.0),
framebuffer : framebuffer
});
clearCommand.execute(context);
// 3 of 3. Render green to default color buffer by reading from previous color attachment
var fs = 'uniform sampler2D u_texture; void main() { gl_FragColor = texture2D(u_texture, vec2(0.0)); }';
var uniformMap = {
u_texture : function() {
return colorTexture;
}
};
expect({
context : context,
fragmentShader : fs,
uniformMap : uniformMap
}).contextToRender([0, 255, 0, 255]);
});
it('clears a cube map face color attachment', function() {
var cubeMap = new CubeMap({
context : context,
width : 1,
height : 1
});
// 1 of 3. Clear default color buffer to black.
ClearCommand.ALL.execute(context);
expect(context).toReadPixels([0, 0, 0, 255]);
// 2 of 3. Clear framebuffer color attachment to green.
framebuffer = new Framebuffer({
context : context,
colorTextures : [cubeMap.positiveX],
destroyAttachments : false
});
var clearCommand = new ClearCommand({
color : new Color (0.0, 1.0, 0.0, 1.0),
framebuffer : framebuffer
});
clearCommand.execute(context);
// 3 of 3. Render green to default color buffer by reading from previous color attachment
var fs = 'uniform samplerCube u_cubeMap; void main() { gl_FragColor = textureCube(u_cubeMap, vec3(1.0, 0.0, 0.0)); }';
var uniformMap = {
u_cubeMap : function() {
return cubeMap;
}
};
expect({
context : context,
fragmentShader : fs,
uniformMap : uniformMap
}).contextToRender([0, 255, 0, 255]);
cubeMap = cubeMap.destroy();
});
function renderColorTexture(framebuffer, color, expectedColor) {
var vs = 'attribute vec4 position; void main() { gl_PointSize = 1.0; gl_Position = position; }';
var fs = 'uniform vec4 color; void main() { gl_FragColor = color; }';
sp = ShaderProgram.fromCache({
context : context,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : {
position : 0
}
});
va = new VertexArray({
context : context,
attributes : [{
index : 0,
vertexBuffer : Buffer.createVertexBuffer({
context : context,
typedArray : new Float32Array([0, 0, 0, 1]),
usage : BufferUsage.STATIC_DRAW
}),
componentsPerAttribute : 4
}]
});
var uniformMap = {
color : function() {
return color;
}
};
var command = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp,
vertexArray : va,
uniformMap : uniformMap,
framebuffer : framebuffer
});
command.execute(context);
expect({
context : context,
framebuffer : framebuffer
}).toReadPixels(expectedColor);
}
it('draws to a color attachment', function() {
framebuffer = new Framebuffer({
context : context,
colorTextures : [new Texture({
context : context,
width : 1,
height : 1
})]
});
renderColorTexture(framebuffer, new Color(0.0, 1.0, 0.0, 1.0), [0, 255, 0, 255]);
});
it('draws to a floating-point color attachment', function() {
if (!context.colorBufferFloat) {
return;
}
framebuffer = new Framebuffer({
context : context,
colorTextures : [new Texture({
context : context,
width : 1,
height : 1,
pixelDatatype : PixelDatatype.FLOAT
})]
});
renderColorTexture(framebuffer, new Color(0.5, 1.5, 2.0, 1.0), [0.5, 1.5, 2.0, 1.0]);
});
it('draws to a half floating-point color attachment', function() {
if (!context.colorBufferHalfFloat) {
return;
}
framebuffer = new Framebuffer({
context : context,
colorTextures : [new Texture({
context : context,
width : 1,
height : 1,
pixelDatatype : PixelDatatype.HALF_FLOAT
})]
});
renderColorTexture(framebuffer, new Color(0.5, 1.5, 2.0, 1.0), [14336, 15872, 16384, 15360]);
});
function renderDepthAttachment(framebuffer, texture) {
ClearCommand.ALL.execute(context);
var framebufferClear = new ClearCommand({
depth : 1.0,
framebuffer : framebuffer
});
framebufferClear.execute(context);
// 1 of 3. Render green point into color attachment.
var vs = 'attribute vec4 position; void main() { gl_PointSize = 1.0; gl_Position = position; }';
var fs = 'void main() { gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); }';
sp = ShaderProgram.fromCache({
context : context,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : {
position : 0
}
});
va = new VertexArray({
context : context,
attributes : [{
index : 0,
vertexBuffer : Buffer.createVertexBuffer({
context : context,
typedArray : new Float32Array([0, 0, 0, 1]),
usage : BufferUsage.STATIC_DRAW
}),
componentsPerAttribute : 4
}]
});
var command = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp,
vertexArray : va,
framebuffer : framebuffer,
renderState : RenderState.fromCache({
depthTest : {
enabled : true
}
})
});
command.execute(context);
// 2 of 3. Verify default color buffer is still black.
expect(context).toReadPixels([0, 0, 0, 255]);
// 3 of 3. Render green to default color buffer by reading from previous color attachment
var vs2 = 'attribute vec4 position; void main() { gl_PointSize = 1.0; gl_Position = position; }';
var fs2 = 'uniform sampler2D u_texture; void main() { gl_FragColor = texture2D(u_texture, vec2(0.0)).rrrr; }';
var sp2 = ShaderProgram.fromCache({
context : context,
vertexShaderSource : vs2,
fragmentShaderSource : fs2,
attributeLocations : {
position : 0
}
});
var uniformMap = {
u_texture : function() {
return texture;
}
};
command = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp2,
vertexArray : va,
uniformMap : uniformMap
});
command.execute(context);
sp2 = sp2.destroy();
return context.readPixels();
}
it('draws to a depth texture attachment', function() {
if (context.depthTexture) {
framebuffer = new Framebuffer({
context : context,
colorTextures : [new Texture({
context : context,
width : 1,
height : 1
})],
depthTexture : new Texture({
context : context,
width : 1,
height : 1,
pixelFormat : PixelFormat.DEPTH_COMPONENT,
pixelDatatype : PixelDatatype.UNSIGNED_SHORT
})
});
if (framebuffer.status === WebGLConstants.FRAMEBUFFER_COMPLETE) {
expect(renderDepthAttachment(framebuffer, framebuffer.depthTexture)).toEqualEpsilon([128, 128, 128, 255], 1);
}
}
});
it('draws to a depth-stencil texture attachment', function() {
if (context.depthTexture) {
framebuffer = new Framebuffer({
context : context,
colorTextures : [new Texture({
context : context,
width : 1,
height : 1
})],
depthStencilTexture : new Texture({
context : context,
width : 1,
height : 1,
pixelFormat : PixelFormat.DEPTH_STENCIL,
pixelDatatype : PixelDatatype.UNSIGNED_INT_24_8
})
});
if (framebuffer.status === WebGLConstants.FRAMEBUFFER_COMPLETE) {
expect(renderDepthAttachment(framebuffer, framebuffer.depthStencilTexture)).toEqualEpsilon([128, 128, 128, 255], 1);
}
}
});
it('draws with a depth attachment', function() {
framebuffer = new Framebuffer({
context : context,
colorTextures : [new Texture({
context : context,
width : 1,
height : 1
})],
depthRenderbuffer : new Renderbuffer({
context : context,
format : RenderbufferFormat.DEPTH_COMPONENT16,
width : 1,
height : 1
})
});
var vs = 'attribute vec4 position; void main() { gl_PointSize = 1.0; gl_Position = position; }';
var fs = 'void main() { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); }';
sp = ShaderProgram.fromCache({
context : context,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : {
position : 0
}
});
va = new VertexArray({
context : context,
attributes : [{
index : 0,
vertexBuffer : Buffer.createVertexBuffer({
context : context,
typedArray : new Float32Array([0, 0, 0, 1]),
usage : BufferUsage.STATIC_DRAW
}),
componentsPerAttribute : 4
}]
});
// 1 of 3. Clear framebuffer
var clearCommand = new ClearCommand({
color : new Color(0.0, 0.0, 0.0, 0.0),
depth : 1.0,
framebuffer : framebuffer
});
clearCommand.execute(context);
expect({
context : context,
framebuffer : framebuffer
}).toReadPixels([0, 0, 0, 0]);
// 2 of 3. Does not pass depth test
var command = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp,
vertexArray : va,
framebuffer : framebuffer,
renderState : RenderState.fromCache({
depthTest : {
enabled : true,
func : WebGLConstants.NEVER
}
})
});
command.execute(context);
expect({
context : context,
framebuffer : framebuffer
}).toReadPixels([0, 0, 0, 0]);
// 3 of 3. Passes depth test
command = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp,
vertexArray : va,
framebuffer : framebuffer,
renderState : RenderState.fromCache({
depthTest : {
enabled : true,
func : WebGLConstants.ALWAYS
}
})
});
command.execute(context);
expect({
context : context,
framebuffer : framebuffer
}).toReadPixels([255, 255, 255, 255]);
});
it('draws with multiple render targets', function() {
if (!context.drawBuffers) {
return;
}
var source = new Uint8Array(4);
var colorTexture0 = new Texture({
context : context,
source : {
arrayBufferView : source,
width : 1,
height : 1
}
});
var colorTexture1 = new Texture({
context : context,
source : {
arrayBufferView : source,
width : 1,
height : 1
}
});
framebuffer = new Framebuffer({
context : context,
colorTextures : [colorTexture0, colorTexture1]
});
// 1 of 5. Clear default color buffer to black.
ClearCommand.ALL.execute(context);
expect(context).toReadPixels([0, 0, 0, 255]);
// 2 of 5. Render red point into color attachment 0 and green point to color attachment 1.
var vs = 'attribute vec4 position; void main() { gl_PointSize = 1.0; gl_Position = position; }';
var fs = '#extension GL_EXT_draw_buffers : enable \n void main() { gl_FragData[0] = vec4(1.0, 0.0, 0.0, 1.0); gl_FragData[1] = vec4(0.0, 1.0, 0.0, 1.0); }';
sp = ShaderProgram.fromCache({
context : context,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : {
position : 0
}
});
va = new VertexArray({
context : context,
attributes : [{
index : 0,
vertexBuffer : Buffer.createVertexBuffer({
context : context,
typedArray : new Float32Array([0, 0, 0, 1]),
usage : BufferUsage.STATIC_DRAW
}),
componentsPerAttribute : 4
}]
});
var command = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp,
vertexArray : va,
framebuffer : framebuffer
});
command.execute(context);
// 3 of 5. Verify default color buffer is still black.
expect(context).toReadPixels([0, 0, 0, 255]);
// 4 of 5. Render yellow to default color buffer by reading from previous color attachments
var vs2 = 'attribute vec4 position; void main() { gl_PointSize = 1.0; gl_Position = position; }';
var fs2 = 'uniform sampler2D u_texture0; uniform sampler2D u_texture1; void main() { gl_FragColor = texture2D(u_texture0, vec2(0.0)) + texture2D(u_texture1, vec2(0.0)); }';
var sp2 = ShaderProgram.fromCache({
context : context,
vertexShaderSource : vs2,
fragmentShaderSource : fs2,
attributeLocations : {
position : 0
}
});
var uniformMap = {
u_texture0 : function() {
return colorTexture0;
},
u_texture1 : function() {
return colorTexture1;
}
};
command = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp2,
vertexArray : va,
uniformMap : uniformMap
});
command.execute(context);
expect(context).toReadPixels([255, 255, 0, 255]);
// 5 of 5. Verify clearing multiple color attachments
var clearCommand = new ClearCommand({
color : new Color (0.0, 0.0, 0.0, 0.0),
framebuffer : framebuffer
});
clearCommand.execute(context);
command = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp2,
vertexArray : va
});
command.execute(context);
expect(context).toReadPixels([0, 0, 0, 255]);
sp2 = sp2.destroy();
});
it('gets the status of a complete framebuffer', function() {
framebuffer = new Framebuffer({
context : context,
colorTextures : [new Texture({
context : context,
width : 1,
height : 1
})],
depthRenderbuffer : new Renderbuffer({
context : context,
format : RenderbufferFormat.DEPTH_COMPONENT16,
width : 1,
height : 1
})
});
expect(framebuffer.status).toEqual(WebGLConstants.FRAMEBUFFER_COMPLETE);
});
it('gets the status of a incomplete framebuffer', function() {
if (!!window.webglStub) {
return;
}
framebuffer = new Framebuffer({
context : context,
colorTextures : [new Texture({
context : context,
width : 1,
height : 1
})],
depthRenderbuffer : new Renderbuffer({
context : context,
format : RenderbufferFormat.RGBA4,
width : 2,
height : 2
})
});
expect(framebuffer.status).not.toEqual(WebGLConstants.FRAMEBUFFER_COMPLETE);
});
it('destroys', function() {
var f = new Framebuffer({
context : context
});
expect(f.isDestroyed()).toEqual(false);
f.destroy();
expect(f.isDestroyed()).toEqual(true);
});
it('throws when created with color texture and color renderbuffer attachments', function() {
expect(function() {
framebuffer = new Framebuffer({
context : context,
colorTextures : 'not undefined',
colorRenderbuffers : 'not undefined'
});
}).toThrowDeveloperError();
});
it('throws when created with depth texture and depth renderbuffer attachments', function() {
expect(function() {
framebuffer = new Framebuffer({
context : context,
depthTexture : 'not undefined',
depthRenderbuffer : 'not undefined'
});
}).toThrowDeveloperError();
});
it('throws when created with depth-stencil texture and depth-stencil renderbuffer attachments', function() {
expect(function() {
framebuffer = new Framebuffer({
context : context,
depthStencilTexture : 'not undefined',
depthStencilRenderbuffer : 'not undefined'
});
}).toThrowDeveloperError();
});
it('throws when created with depth and depth-stencil attachments', function() {
expect(function() {
framebuffer = new Framebuffer({
context : context,
depthRenderbuffer : 'not undefined',
depthStencilRenderbuffer : 'not undefined'
});
}).toThrowDeveloperError();
});
it('throws when created with stencil and depth-stencil attachments', function() {
expect(function() {
framebuffer = new Framebuffer({
context : context,
stencilRenderbuffer : 'not undefined',
depthStencilRenderbuffer : 'not undefined'
});
}).toThrowDeveloperError();
});
it('throws when created with depth and stencil attachments', function() {
expect(function() {
framebuffer = new Framebuffer({
context : context,
depthRenderbuffer : 'not undefined',
stencilRenderbuffer : 'not undefined'
});
}).toThrowDeveloperError();
});
it('throws when created with a color texture with a non-color pixel format', function() {
if (context.depthTexture) {
expect(function() {
framebuffer = new Framebuffer({
context : context,
colorTextures : [new Texture({
context : context,
width : 1,
height : 1,
pixelFormat : PixelFormat.DEPTH_COMPONENT,
pixelDatatype : PixelDatatype.UNSIGNED_SHORT
})]
});
}).toThrowDeveloperError();
}
});
it('throws when created with a depth texture without a DEPTH_COMPONENT pixel format', function() {
expect(function() {
framebuffer = new Framebuffer({
context : context,
depthTexture : new Texture({
context : context,
width : 1,
height : 1
})
});
}).toThrowDeveloperError();
});
it('throws when created with a depth-stencil texture without a DEPTH_STENCIL pixel format', function() {
expect(function() {
framebuffer = new Framebuffer({
context : context,
depthStencilTexture : new Texture({
context : context,
width : 1,
height : 1
})
});
}).toThrowDeveloperError();
});
it('throws when the depth test is enabled without an appropriate attachment', function() {
framebuffer = new Framebuffer({
context : context,
colorTextures : [new Texture({
context : context,
width : 1,
height : 1
})]
});
var vs = 'attribute vec4 position; void main() { gl_PointSize = 1.0; gl_Position = position; }';
var fs = 'void main() { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); }';
sp = ShaderProgram.fromCache({
context : context,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : {
position : 0
}
});
va = new VertexArray({
context : context,
attributes : [{
index : 0,
vertexBuffer : Buffer.createVertexBuffer({
context : context,
typedArray : new Float32Array([0, 0, 0, 1]),
usage : BufferUsage.STATIC_DRAW
}),
componentsPerAttribute : 4
}]
});
expect(function() {
var command = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
shaderProgram : sp,
vertexArray : va,
framebuffer : framebuffer,
renderState : RenderState.fromCache({
depthTest : {
enabled : true
}
})
});
command.execute(context);
}).toThrowDeveloperError();
});
it('throws when the number of color texture exceeds the number color attachments supported', function() {
expect(function() {
return new Framebuffer({
context : context,
colorTextures : new Array(ContextLimits.maximumColorAttachments + 1)
});
}).toThrowDeveloperError();
});
it('throws when the number of color renderbuffers exceeds the number color attachments supported', function() {
expect(function() {
return new Framebuffer({
context : context,
colorRenderbuffers : new Array(ContextLimits.maximumColorAttachments + 1)
});
}).toThrowDeveloperError();
});
it('throws when the index to getColorTexture is out of bounds', function(){
framebuffer = new Framebuffer({
context : context
});
expect(function() {
framebuffer.getColorTexture();
}).toThrowDeveloperError();
expect(function() {
framebuffer.getColorTexture(-1);
}).toThrowDeveloperError();
expect(function() {
framebuffer.getColorTexture(ContextLimits.maximumColorAttachments + 1);
}).toThrowDeveloperError();
});
it('throws when the index to getColorRenderbuffer is out of bounds', function(){
framebuffer = new Framebuffer({
context : context
});
expect(function() {
framebuffer.getColorRenderbuffer();
}).toThrowDeveloperError();
expect(function() {
framebuffer.getColorRenderbuffer(-1);
}).toThrowDeveloperError();
expect(function() {
framebuffer.getColorRenderbuffer(ContextLimits.maximumColorAttachments + 1);
}).toThrowDeveloperError();
});
it('throws when a color attachment has a floating-point datatype but the EXT_color_buffer_float extension is not supported', function() {
if (context.colorBufferFloat) {
return;
}
expect(function() {
return new Framebuffer({
context : context,
colorTextures : [new Texture({
context : context,
width : 1,
height : 1,
pixelDatatype : PixelDatatype.FLOAT
})]
});
}).toThrowDeveloperError();
});
it('throws when a color attachment has a half floating-point datatype but the EXT_color_buffer_half_float extension is not supported', function() {
if (context.colorBufferHalfFloat) {
return;
}
expect(function() {
return new Framebuffer({
context : context,
colorTextures : [new Texture({
context : context,
width : 1,
height : 1,
pixelDatatype : PixelDatatype.HALF_FLOAT
})]
});
}).toThrowDeveloperError();
});
it('fails to destroy', function() {
var f = new Framebuffer({
context : context
});
f.destroy();
expect(function() {
f.destroy();
}).toThrowDeveloperError();
});
it('throws when there is no context', function() {
expect(function() {
return new Framebuffer();
}).toThrowDeveloperError();
});
}, 'WebGL');