2 Copyright (c) 2020 The Khronos Group Inc.
3 Use of this source code is governed by an MIT-style license that can be
4 found in the LICENSE.txt file.
10 <meta charset=
"utf-8">
11 <title>WebGL2 can render to layers in
3D and
2D_ARRAY textures
</title>
12 <link rel=
"stylesheet" href=
"../../resources/js-test-style.css"/>
13 <script src=
"../../js/js-test-pre.js"></script>
14 <script src=
"../../js/webgl-test-utils.js"></script>
15 <script id=
"vshader" type=
"x-shader/x-vertex">#version
300 es
17 gl_Position = vec4(
0,
0,
0,
1);
23 <canvas id=
"example" width=
"100",
height=
"100"></canvas>
24 <div id=
"description"></div>
25 <div id=
"console"></div>
30 description("Test that WebGL2 can render to layers in 3D and 2D_ARRAY textures");
32 var wtu
= WebGLTestUtils
;
33 var gl
= wtu
.create3DContext("example", undefined, 2);
36 testFailed("WebGL context creation failed");
38 testPassed("WebGL context creation succeeded");
47 function makeFragmentShader(typeInfo
) {
48 const src
= `#version 300 es
49 precision mediump float;
50 out ${typeInfo.outType} color;
52 color = ${typeInfo.outValue};
58 const textureInternalFormatInfo
= {};
60 const t
= textureInternalFormatInfo
;
62 // If understand correctly these 3 unsized formats are not required to be color renderable
63 t
[gl
.ALPHA
] = { textureFormat
: gl
.ALPHA
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [1, 2, 2, 4], type
: [gl
.UNSIGNED_BYTE
, gl
.HALF_FLOAT
, gl
.HALF_FLOAT_OES
, gl
.FLOAT
], };
64 t
[gl
.LUMINANCE
] = { textureFormat
: gl
.LUMINANCE
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [1, 2, 2, 4], type
: [gl
.UNSIGNED_BYTE
, gl
.HALF_FLOAT
, gl
.HALF_FLOAT_OES
, gl
.FLOAT
], };
65 t
[gl
.LUMINANCE_ALPHA
] = { textureFormat
: gl
.LUMINANCE_ALPHA
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [2, 4, 4, 8], type
: [gl
.UNSIGNED_BYTE
, gl
.HALF_FLOAT
, gl
.HALF_FLOAT_OES
, gl
.FLOAT
], };
67 t
[gl
.RGB
] = { textureFormat
: gl
.RGB
, colorRenderable
: true, textureFilterable
: true, bytesPerElement
: [3, 6, 6, 12, 2], type
: [gl
.UNSIGNED_BYTE
, gl
.HALF_FLOAT
, gl
.HALF_FLOAT_OES
, gl
.FLOAT
, gl
.UNSIGNED_SHORT_5_6_5
], };
68 t
[gl
.RGBA
] = { textureFormat
: gl
.RGBA
, colorRenderable
: true, textureFilterable
: true, bytesPerElement
: [4, 8, 8, 16, 2, 2], type
: [gl
.UNSIGNED_BYTE
, gl
.HALF_FLOAT
, gl
.HALF_FLOAT_OES
, gl
.FLOAT
, gl
.UNSIGNED_SHORT_4_4_4_4
, gl
.UNSIGNED_SHORT_5_5_5_1
], };
71 t
[gl
.R8
] = { textureFormat
: gl
.RED
, colorRenderable
: true, textureFilterable
: true, bytesPerElement
: [1], type
: [gl
.UNSIGNED_BYTE
], };
72 t
[gl
.R8_SNORM
] = { textureFormat
: gl
.RED
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [1], type
: [gl
.BYTE
], };
73 t
[gl
.R16F
] = { textureFormat
: gl
.RED
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [4, 2], type
: [gl
.FLOAT
, gl
.HALF_FLOAT
], };
74 t
[gl
.R32F
] = { textureFormat
: gl
.RED
, colorRenderable
: false, textureFilterable
: false, bytesPerElement
: [4], type
: [gl
.FLOAT
], };
75 t
[gl
.R8UI
] = { textureFormat
: gl
.RED_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [1], type
: [gl
.UNSIGNED_BYTE
], };
76 t
[gl
.R8I
] = { textureFormat
: gl
.RED_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [1], type
: [gl
.BYTE
], };
77 t
[gl
.R16UI
] = { textureFormat
: gl
.RED_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [2], type
: [gl
.UNSIGNED_SHORT
], };
78 t
[gl
.R16I
] = { textureFormat
: gl
.RED_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [2], type
: [gl
.SHORT
], };
79 t
[gl
.R32UI
] = { textureFormat
: gl
.RED_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [4], type
: [gl
.UNSIGNED_INT
], };
80 t
[gl
.R32I
] = { textureFormat
: gl
.RED_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [4], type
: [gl
.INT
], };
81 t
[gl
.RG8
] = { textureFormat
: gl
.RG
, colorRenderable
: true, textureFilterable
: true, bytesPerElement
: [2], type
: [gl
.UNSIGNED_BYTE
], };
82 t
[gl
.RG8_SNORM
] = { textureFormat
: gl
.RG
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [2], type
: [gl
.BYTE
], };
83 t
[gl
.RG16F
] = { textureFormat
: gl
.RG
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [8, 4], type
: [gl
.FLOAT
, gl
.HALF_FLOAT
], };
84 t
[gl
.RG32F
] = { textureFormat
: gl
.RG
, colorRenderable
: false, textureFilterable
: false, bytesPerElement
: [8], type
: [gl
.FLOAT
], };
85 t
[gl
.RG8UI
] = { textureFormat
: gl
.RG_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [2], type
: [gl
.UNSIGNED_BYTE
], };
86 t
[gl
.RG8I
] = { textureFormat
: gl
.RG_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [2], type
: [gl
.BYTE
], };
87 t
[gl
.RG16UI
] = { textureFormat
: gl
.RG_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [4], type
: [gl
.UNSIGNED_SHORT
], };
88 t
[gl
.RG16I
] = { textureFormat
: gl
.RG_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [4], type
: [gl
.SHORT
], };
89 t
[gl
.RG32UI
] = { textureFormat
: gl
.RG_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [8], type
: [gl
.UNSIGNED_INT
], };
90 t
[gl
.RG32I
] = { textureFormat
: gl
.RG_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [8], type
: [gl
.INT
], };
91 t
[gl
.RGB8
] = { textureFormat
: gl
.RGB
, colorRenderable
: true, textureFilterable
: true, bytesPerElement
: [3], type
: [gl
.UNSIGNED_BYTE
], };
92 t
[gl
.SRGB8
] = { textureFormat
: gl
.RGB
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [3], type
: [gl
.UNSIGNED_BYTE
], };
93 t
[gl
.RGB565
] = { textureFormat
: gl
.RGB
, colorRenderable
: true, textureFilterable
: true, bytesPerElement
: [3, 2], type
: [gl
.UNSIGNED_BYTE
, gl
.UNSIGNED_SHORT_5_6_5
], };
94 t
[gl
.RGB8_SNORM
] = { textureFormat
: gl
.RGB
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [3], type
: [gl
.BYTE
], };
95 t
[gl
.R11F_G11F_B10F
] = { textureFormat
: gl
.RGB
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [12, 6, 4], type
: [gl
.FLOAT
, gl
.HALF_FLOAT
, gl
.UNSIGNED_INT_10F_11F_11F_REV
], };
96 t
[gl
.RGB9_E5
] = { textureFormat
: gl
.RGB
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [12, 6, 4], type
: [gl
.FLOAT
, gl
.HALF_FLOAT
, gl
.UNSIGNED_INT_5_9_9_9_REV
], };
97 t
[gl
.RGB16F
] = { textureFormat
: gl
.RGB
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [12, 6], type
: [gl
.FLOAT
, gl
.HALF_FLOAT
], };
98 t
[gl
.RGB32F
] = { textureFormat
: gl
.RGB
, colorRenderable
: false, textureFilterable
: false, bytesPerElement
: [12], type
: [gl
.FLOAT
], };
99 t
[gl
.RGB8UI
] = { textureFormat
: gl
.RGB_INTEGER
, colorRenderable
: false, textureFilterable
: false, bytesPerElement
: [3], type
: [gl
.UNSIGNED_BYTE
], };
100 t
[gl
.RGB8I
] = { textureFormat
: gl
.RGB_INTEGER
, colorRenderable
: false, textureFilterable
: false, bytesPerElement
: [3], type
: [gl
.BYTE
], };
101 t
[gl
.RGB16UI
] = { textureFormat
: gl
.RGB_INTEGER
, colorRenderable
: false, textureFilterable
: false, bytesPerElement
: [6], type
: [gl
.UNSIGNED_SHORT
], };
102 t
[gl
.RGB16I
] = { textureFormat
: gl
.RGB_INTEGER
, colorRenderable
: false, textureFilterable
: false, bytesPerElement
: [6], type
: [gl
.SHORT
], };
103 t
[gl
.RGB32UI
] = { textureFormat
: gl
.RGB_INTEGER
, colorRenderable
: false, textureFilterable
: false, bytesPerElement
: [12], type
: [gl
.UNSIGNED_INT
], };
104 t
[gl
.RGB32I
] = { textureFormat
: gl
.RGB_INTEGER
, colorRenderable
: false, textureFilterable
: false, bytesPerElement
: [12], type
: [gl
.INT
], };
105 t
[gl
.RGBA8
] = { textureFormat
: gl
.RGBA
, colorRenderable
: true, textureFilterable
: true, bytesPerElement
: [4], type
: [gl
.UNSIGNED_BYTE
], };
106 t
[gl
.SRGB8_ALPHA8
] = { textureFormat
: gl
.RGBA
, colorRenderable
: true, textureFilterable
: true, bytesPerElement
: [4], type
: [gl
.UNSIGNED_BYTE
], };
107 t
[gl
.RGBA8_SNORM
] = { textureFormat
: gl
.RGBA
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [4], type
: [gl
.BYTE
], };
108 t
[gl
.RGB5_A1
] = { textureFormat
: gl
.RGBA
, colorRenderable
: true, textureFilterable
: true, bytesPerElement
: [4, 2, 4], type
: [gl
.UNSIGNED_BYTE
, gl
.UNSIGNED_SHORT_5_5_5_1
, gl
.UNSIGNED_INT_2_10_10_10_REV
], };
109 t
[gl
.RGBA4
] = { textureFormat
: gl
.RGBA
, colorRenderable
: true, textureFilterable
: true, bytesPerElement
: [4, 2], type
: [gl
.UNSIGNED_BYTE
, gl
.UNSIGNED_SHORT_4_4_4_4
], };
110 t
[gl
.RGB10_A2
] = { textureFormat
: gl
.RGBA
, colorRenderable
: true, textureFilterable
: true, bytesPerElement
: [4], type
: [gl
.UNSIGNED_INT_2_10_10_10_REV
], };
111 t
[gl
.RGBA16F
] = { textureFormat
: gl
.RGBA
, colorRenderable
: false, textureFilterable
: true, bytesPerElement
: [16, 8], type
: [gl
.FLOAT
, gl
.HALF_FLOAT
], };
112 t
[gl
.RGBA32F
] = { textureFormat
: gl
.RGBA
, colorRenderable
: false, textureFilterable
: false, bytesPerElement
: [16], type
: [gl
.FLOAT
], };
113 t
[gl
.RGBA8UI
] = { textureFormat
: gl
.RGBA_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [4], type
: [gl
.UNSIGNED_BYTE
], };
114 t
[gl
.RGBA8I
] = { textureFormat
: gl
.RGBA_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [4], type
: [gl
.BYTE
], };
115 t
[gl
.RGB10_A2UI
] = { textureFormat
: gl
.RGBA_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [4], type
: [gl
.UNSIGNED_INT_2_10_10_10_REV
], };
116 t
[gl
.RGBA16UI
] = { textureFormat
: gl
.RGBA_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [8], type
: [gl
.UNSIGNED_SHORT
], };
117 t
[gl
.RGBA16I
] = { textureFormat
: gl
.RGBA_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [8], type
: [gl
.SHORT
], };
118 t
[gl
.RGBA32I
] = { textureFormat
: gl
.RGBA_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [16], type
: [gl
.INT
], };
119 t
[gl
.RGBA32UI
] = { textureFormat
: gl
.RGBA_INTEGER
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [16], type
: [gl
.UNSIGNED_INT
], };
122 t
[gl
.DEPTH_COMPONENT16
] = { textureFormat
: gl
.DEPTH_COMPONENT
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [2, 4], type
: [gl
.UNSIGNED_SHORT
, gl
.UNSIGNED_INT
], };
123 t
[gl
.DEPTH_COMPONENT24
] = { textureFormat
: gl
.DEPTH_COMPONENT
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [4], type
: [gl
.UNSIGNED_INT
], };
124 t
[gl
.DEPTH_COMPONENT32F
] = { textureFormat
: gl
.DEPTH_COMPONENT
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [4], type
: [gl
.FLOAT
], };
125 t
[gl
.DEPTH24_STENCIL8
] = { textureFormat
: gl
.DEPTH_STENCIL
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [4], type
: [gl
.UNSIGNED_INT_24_8
], };
126 t
[gl
.DEPTH32F_STENCIL8
] = { textureFormat
: gl
.DEPTH_STENCIL
, colorRenderable
: true, textureFilterable
: false, bytesPerElement
: [4], type
: [gl
.FLOAT_32_UNSIGNED_INT_24_8_REV
], };
128 Object
.keys(t
).forEach(function(internalFormat
) {
129 const info
= t
[internalFormat
];
130 info
.bytesPerElementMap
= {};
131 info
.bytesPerElement
.forEach(function(bytesPerElement
, ndx
) {
132 const type
= info
.type
[ndx
];
133 info
.bytesPerElementMap
[type
] = bytesPerElement
;
138 const validChannelsByTextureFormat
= {};
140 const v
= validChannelsByTextureFormat
;
141 v
[gl
.RED
] = [1, 0, 0, 0];
142 v
[gl
.RG
] = [1, 1, 0, 0];
143 v
[gl
.RGB
] = [1, 1, 1, 0];
144 v
[gl
.RGBA
] = [1, 1, 1, 1];
145 v
[gl
.RED_INTEGER
] = [1, 0, 0, 0];
146 v
[gl
.RG_INTEGER
] = [1, 1, 0, 0];
147 v
[gl
.RGB_INTEGER
] = [1, 1, 1, 0];
148 v
[gl
.RGBA_INTEGER
] = [1, 1, 1, 1];
151 const depthTextureFormats
= [
152 gl
.DEPTH_COMPONENT16
,
153 gl
.DEPTH_COMPONENT24
,
154 gl
.DEPTH_COMPONENT32F
,
156 gl
.DEPTH32F_STENCIL8
,
159 const intTextureFormats
= [
174 const unsignedIntTextureFormats
= [
190 const floatTextureFormats
= Object
.keys(textureInternalFormatInfo
).map(function(v
) {
192 }).filter(function(format
) {
193 return intTextureFormats
.indexOf(format
) < 0 &&
194 unsignedIntTextureFormats
.indexOf(format
) < 0 &&
195 depthTextureFormats
.indexOf(format
);
198 const expectedColorByInternalFormat
= {};
199 expectedColorByInternalFormat
[gl
.SRGB8_ALPHA8
] = [225, 188, 137, 255];
201 function clearFloat(gl
) {
202 gl
.clearBufferfv(gl
.COLOR
, 0, [0, 0, 0, 0]);
205 function clearInt(gl
) {
206 gl
.clearBufferiv(gl
.COLOR
, 0, [0, 0, 0, 0]);
209 function clearUint(gl
) {
210 gl
.clearBufferuiv(gl
.COLOR
, 0, [0, 0, 0, 0]);
214 function checkData(data
, expected
, internalFormat
, tolerance
) {
215 const internalFormatInfo
= textureInternalFormatInfo
[internalFormat
];
216 const validChannels
= validChannelsByTextureFormat
[internalFormatInfo
.textureFormat
];
217 if (!validChannels
) {
221 for (let y
= 0; y
< texHeight
; ++y
) {
222 for (let x
= 0; x
< texWidth
; ++x
) {
223 for (let c
= 0; c
< validChannels
.length
; ++c
) {
224 if (validChannels
[c
]) {
225 const offset
= (y
* texWidth
+ x
) * 4 + c
;
226 const pixel
= data
[offset
];
227 const diff
= Math
.abs(pixel
- expected
[c
]);
228 if (diff
> tolerance
) {
229 testFailed(`pixel ${x},${y} channel ${c} was ${pixel} expected ${expected[c]} +/- ${tolerance}`);
236 testPassed(`data was ${expected.join(',')}`);
239 function checkFloat(gl
, textureInfo
, expected
) {
240 const data
= new Uint8Array(texWidth
* texHeight
* 4);
241 gl
.readPixels(0, 0, texWidth
, texHeight
, gl
.RGBA
, gl
.UNSIGNED_BYTE
, data
);
242 const internalFormat
= textureInfo
.internalFormat
;
243 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, `No errors from readPixels with ${wtu.glEnumToString(gl, internalFormat)}`);
244 checkData(data
, expected
, internalFormat
, 9);
247 function checkInt(gl
, textureInfo
, expected
) {
248 const data
= new Int32Array(texWidth
* texHeight
* 4);
249 gl
.readPixels(0, 0, texWidth
, texHeight
, gl
.RGBA_INTEGER
, gl
.INT
, data
);
250 const internalFormat
= textureInfo
.internalFormat
;
251 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, `No errors from readPixels with ${wtu.glEnumToString(gl, internalFormat)}`);
252 checkData(data
, expected
, internalFormat
, 0);
255 function checkUint(gl
, textureInfo
, expected
) {
256 const data
= new Uint32Array(texWidth
* texHeight
* 4);
257 gl
.readPixels(0, 0, texWidth
, texHeight
, gl
.RGBA_INTEGER
, gl
.UNSIGNED_INT
, data
);
258 const internalFormat
= textureInfo
.internalFormat
;
259 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, `No errors from readPixels with ${wtu.glEnumToString(gl, internalFormat)}`);
260 checkData(data
, expected
, internalFormat
, 0);
263 const expectedFloatColor
= [.75 * 255 | 0, .5 * 255 | 0, .25 * 255 | 0, 1 * 255 | 0];
265 { outType
: 'vec4', outValue
: 'vec4(.75, .5, .25, 1)', expected
: expectedFloatColor
, clear
: clearFloat
, check
: checkFloat
, target
: gl
.TEXTURE_2D
, },
266 { outType
: 'vec4', outValue
: 'vec4(.75, .5, .25, 1)', expected
: expectedFloatColor
, clear
: clearFloat
, check
: checkFloat
, target
: gl
.TEXTURE_3D
, },
267 { outType
: 'vec4', outValue
: 'vec4(.75, .5, .25, 1)', expected
: expectedFloatColor
, clear
: clearFloat
, check
: checkFloat
, target
: gl
.TEXTURE_2D_ARRAY
, },
270 const expectedIntColor
= [1, 2, 4, 3];
271 const signedIntTypes
= [
272 { outType
: 'ivec4', outValue
: 'ivec4(1, 2, 4, 3)', expected
: expectedIntColor
, clear
: clearInt
, check
: checkInt
, target
: gl
.TEXTURE_2D
, },
273 { outType
: 'ivec4', outValue
: 'ivec4(1, 2, 4, 3)', expected
: expectedIntColor
, clear
: clearInt
, check
: checkInt
, target
: gl
.TEXTURE_3D
, },
274 { outType
: 'ivec4', outValue
: 'ivec4(1, 2, 4, 3)', expected
: expectedIntColor
, clear
: clearInt
, check
: checkInt
, target
: gl
.TEXTURE_2D_ARRAY
, },
277 const expectedUintColor
= [1, 2, 4, 3];
278 const unsignedIntTypes
= [
279 { outType
: 'uvec4', outValue
: 'uvec4(1, 2, 4, 3)', expected
: expectedUintColor
, clear
: clearUint
, check
: checkUint
, target
: gl
.TEXTURE_2D
, },
280 { outType
: 'uvec4', outValue
: 'uvec4(1, 2, 4, 3)', expected
: expectedUintColor
, clear
: clearUint
, check
: checkUint
, target
: gl
.TEXTURE_3D
, },
281 { outType
: 'uvec4', outValue
: 'uvec4(1, 2, 4, 3)', expected
: expectedUintColor
, clear
: clearUint
, check
: checkUint
, target
: gl
.TEXTURE_2D_ARRAY
, },
285 * Gets the number of bytes per element for a given internalFormat / type
286 * @param {number} internalFormat The internalFormat parameter from texImage2D etc..
287 * @param {number} type The type parameter for texImage2D etc..
288 * @return {number} the number of bytes per element for the given internalFormat, type combo
289 * @memberOf module:twgl/textures
291 function getBytesPerElementForInternalFormat(internalFormat
, type
) {
292 const info
= textureInternalFormatInfo
[internalFormat
];
294 throw "unknown internal format";
296 const bytesPerElement
= info
.bytesPerElementMap
[type
];
297 if (bytesPerElement
=== undefined) {
298 throw "unknown internal format";
300 return bytesPerElement
;
303 function make2DTexture(gl
, target
, internalFormat
, format
, type
) {
304 gl
.texImage2D(target
, 0, internalFormat
, texWidth
, texHeight
, 0, format
, type
, null);
307 function make3DTexture(gl
, target
, internalFormat
, format
, type
) {
308 gl
.texImage3D(target
, 0, internalFormat
, texWidth
, texHeight
, texDepth
, 0, format
, type
, null);
311 function attach2DTexture(gl
, target
, texture
) {
313 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, target
, texture
, level
);
316 function attach3DTexture(gl
, target
, texture
) {
318 const slice
= texDepth
- 1;
319 gl
.framebufferTextureLayer(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, texture
, level
, slice
);
323 targets
[gl
.TEXTURE_2D
] = { make
: make2DTexture
, attach
: attach2DTexture
, },
324 targets
[gl
.TEXTURE_3D
] = { make
: make3DTexture
, attach
: attach3DTexture
, },
325 targets
[gl
.TEXTURE_2D_ARRAY
] = { make
: make3DTexture
, attach
: attach3DTexture
, },
327 debug("create textures");
328 Object
.keys(targets
).forEach(function(target
) {
330 target
= parseInt(target
);
331 debug(wtu
.glEnumToString(gl
, target
))
332 const targetInfo
= targets
[target
];
333 targetInfo
.textures
= [];
334 Object
.keys(textureInternalFormatInfo
).forEach(function(internalFormat
) {
335 internalFormat
= parseInt(internalFormat
);
336 const isDepthFormat
= depthTextureFormats
.indexOf(internalFormat
) >= 0;
340 const info
= textureInternalFormatInfo
[internalFormat
];
341 if (!info
.colorRenderable
) {
344 const texture
= gl
.createTexture();
345 gl
.bindTexture(target
, texture
);
346 targetInfo
.make(gl
, target
, internalFormat
, info
.textureFormat
, info
.type
[0]);
347 targetInfo
.textures
.push({
348 internalFormat
: internalFormat
,
351 gl
.texParameteri(target
, gl
.TEXTURE_MIN_FILTER
, gl
.NEAREST
);
352 gl
.texParameteri(target
, gl
.TEXTURE_MAG_FILTER
, gl
.NEAREST
);
353 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, `No errors from setup for ${wtu.glEnumToString(gl, target)} ${wtu.glEnumToString(gl, internalFormat)}`);
357 // set the canvas to a known color
358 const half
= 127 / 255;
359 gl
.clearColor(half
, half
, half
, half
);
360 gl
.clear(gl
.COLOR_BUFFER_BIT
);
361 gl
.clearColor(0, 0, 0, 0);
363 const framebuffer
= gl
.createFramebuffer();
364 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, framebuffer
);
365 gl
.viewport(0, 0, texWidth
, texHeight
);
367 const rb
= gl
.createRenderbuffer();
368 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, rb
);
369 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.DEPTH_COMPONENT16
, texWidth
, texHeight
);
371 testTypes('float', floatTypes
, floatTextureFormats
);
372 testTypes('int', signedIntTypes
, intTextureFormats
);
373 testTypes('unsigned', unsignedIntTypes
, unsignedIntTextureFormats
);
375 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, null);
376 wtu
.checkCanvas(gl
, [127, 127, 127, 127], "canvas should be [127, 127, 127, 127]");
378 function testTypes(label
, types
, compatibleFormats
) {
380 types
.forEach(function(typeInfo
) {
381 debug(`\nchecking ${wtu.glEnumToString(gl, typeInfo.target)} with ${label} texture formats`);
382 const program
= wtu
.setupProgram(gl
, ['vshader', makeFragmentShader(typeInfo
)], [], console
.log
.bind(console
));
384 testFailed("Loading program failed");
387 testPassed("Loading program succeeded");
389 const target
= typeInfo
.target
;
390 const targetInfo
= targets
[target
];
391 targetInfo
.textures
.filter(function(textureInfo
) {
392 return compatibleFormats
.indexOf(textureInfo
.internalFormat
) >= 0;
393 }).forEach(function(textureInfo
) {
394 const internalFormat
= textureInfo
.internalFormat
;
395 const desc
= `${wtu.glEnumToString(gl, target)} ${wtu.glEnumToString(gl, internalFormat)}`;
396 const expected
= expectedColorByInternalFormat
[internalFormat
] || typeInfo
.expected
;
401 targetInfo
.attach(gl
, target
, textureInfo
.texture
);
402 wtu
.framebufferStatusShouldBe(gl
, gl
.FRAMEBUFFER
, gl
.FRAMEBUFFER_COMPLETE
, `for ${desc}`);
404 if (wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, `No errors from clear to ${desc}`)) {
407 typeInfo
.check(gl
, textureInfo
, [0, 0, 0, 0]);
408 gl
.drawArrays(gl
.POINTS
, 0, 1);
409 if (wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, `No errors from render to ${desc}`)) {
412 typeInfo
.check(gl
, textureInfo
, expected
);
415 if (wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, `No errors from clear to ${desc}`)) {
418 typeInfo
.check(gl
, textureInfo
, [0, 0, 0, 0]);
420 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
, gl
.RENDERBUFFER
, rb
);
421 wtu
.framebufferStatusShouldBe(gl
, gl
.FRAMEBUFFER
, gl
.FRAMEBUFFER_COMPLETE
, `for ${desc} with depth renderbuffer`);
422 gl
.clearBufferfv(gl
.DEPTH
, 0, [1]);
423 gl
.drawArrays(gl
.POINTS
, 0, 1);
424 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
, gl
.RENDERBUFFER
, null);
426 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, `No errors from render to ${desc}`);
428 typeInfo
.check(gl
, textureInfo
, expected
);
435 var successfullyParsed
= true;
437 <script src=
"../../js/js-test-post.js"></script>