2 Copyright (c) 2019 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 <link rel=
"stylesheet" href=
"../../resources/js-test-style.css"/>
12 <script src=
"../../js/js-test-pre.js"></script>
13 <script src=
"../../js/webgl-test-utils.js"></script>
16 <canvas id=
"example" width=
"4" height=
"4"></canvas>
17 <div id=
"description"></div>
18 <div id=
"console"></div>
22 var wtu
= WebGLTestUtils
;
23 var initialColor
= [1, 2, 3, 4];
24 var expectedColor
= [[249, 102, 0, 255],
29 function calculatePaddingBytes(bytesPerPixel
, packAlignment
, width
)
32 switch (packAlignment
) {
37 padding
= (bytesPerPixel
* width
) % packAlignment
;
39 padding
= packAlignment
- padding
;
42 testFailed("should not reach here");
47 function paintWebGLCanvas(gl
)
49 var program
= wtu
.setupTexturedQuad(gl
);
50 gl
.disable(gl
.DEPTH_TEST
);
53 var data
= new Uint8Array(4 * 4);
54 for (var ii
= 0; ii
< 4; ++ii
) {
55 data
[ii
* 4] = expectedColor
[ii
][0];
56 data
[ii
* 4 + 1] = expectedColor
[ii
][1];
57 data
[ii
* 4 + 2] = expectedColor
[ii
][2];
58 data
[ii
* 4 + 3] = expectedColor
[ii
][3];
61 var tex
= gl
.createTexture();
62 gl
.bindTexture(gl
.TEXTURE_2D
, tex
);
63 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, 1, 4, 0, gl
.RGBA
, gl
.UNSIGNED_BYTE
, data
);
65 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_MIN_FILTER
, gl
.NEAREST
);
66 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_MAG_FILTER
, gl
.NEAREST
);
67 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_WRAP_S
, gl
.CLAMP_TO_EDGE
);
68 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_WRAP_T
, gl
.CLAMP_TO_EDGE
);
70 var loc
= gl
.getUniformLocation(program
, "tex");
73 wtu
.clearAndDrawUnitQuad(gl
);
76 function samePixel(array
, index
, refPixel
, row
, pixelTag
)
78 for (var ii
= 0; ii
< refPixel
.length
; ++ii
) {
79 if (array
[index
] == refPixel
[ii
][0] &&
80 array
[index
+ 1] == refPixel
[ii
][1] &&
81 array
[index
+ 2] == refPixel
[ii
][2] &&
82 array
[index
+ 3] == refPixel
[ii
][3]) {
86 var refPixelText
= "";
87 for (var ii
= 0; ii
< refPixel
.length
; ++ii
) {
89 refPixelText
+= " or ";
90 refPixelText
+= "[" + refPixel
[ii
] + "]";
92 testFailed(pixelTag
+ " pixel of row " + row
+ ": expected " + refPixelText
+ ", got [" +
93 [array
[index
], array
[index
+ 1], array
[index
+ 2], array
[index
+ 3]] + "]");
97 function runTestIteration(xoffset
, yoffset
, width
, height
, packParams
, usePixelPackBuffer
, packParamsValid
)
99 if (!("alignment" in packParams
))
100 packParams
.alignment
= 4;
101 if (!("rowLength" in packParams
))
102 packParams
.rowLength
= 0;
103 if (!("skipPixels" in packParams
))
104 packParams
.skipPixels
= 0;
105 if (!("skipRows" in packParams
))
106 packParams
.skipRows
= 0;
107 debug("Testing xoffset = " + xoffset
+ ", yoffset " + yoffset
+
108 ", width = " + width
+ ", height = " + height
+
109 ", PACK_ALIGNMENT = " + packParams
.alignment
+ ", PACK_ROW_LENGTH = " + packParams
.rowLength
+
110 ", PACK_SKIP_PIXELS = " + packParams
.skipPixels
+ " , PACK_SKIP_ROWS = " + packParams
.skipRows
);
111 gl
.pixelStorei(gl
.PACK_ALIGNMENT
, packParams
.alignment
);
112 gl
.pixelStorei(gl
.PACK_ROW_LENGTH
, packParams
.rowLength
);
113 gl
.pixelStorei(gl
.PACK_SKIP_PIXELS
, packParams
.skipPixels
);
114 gl
.pixelStorei(gl
.PACK_SKIP_ROWS
, packParams
.skipRows
);
116 var actualWidth
= packParams
.rowLength
> 0 ? packParams
.rowLength
: width
;
118 var bytesPerPixel
= 4; // see readPixels' parameters below, the format is gl.RGBA, type is gl.UNSIGNED_BYTE
119 var padding
= calculatePaddingBytes(bytesPerPixel
, packParams
.alignment
, actualWidth
);
120 var bytesPerRow
= actualWidth
* bytesPerPixel
+ padding
;
122 var size
= bytesPerRow
* (height
- 1) + bytesPerPixel
* width
;
123 var skipSize
= packParams
.skipPixels
* bytesPerPixel
+ packParams
.skipRows
* bytesPerRow
;
124 var array
= new Uint8Array(skipSize
+ size
);
125 for (var ii
= 0; ii
< skipSize
+ size
; ++ii
) {
126 array
[ii
] = initialColor
[ii
% bytesPerPixel
];
128 var arrayWrongSize
= null;
130 arrayWrongSize
= new Uint8Array(skipSize
+ size
- 1);
131 if (usePixelPackBuffer
) {
134 var buffer
= gl
.createBuffer();
135 gl
.bindBuffer(gl
.PIXEL_PACK_BUFFER
, buffer
);
137 gl
.bufferData(gl
.PIXEL_PACK_BUFFER
, arrayWrongSize
, gl
.STATIC_DRAW
);
138 gl
.readPixels(xoffset
, yoffset
, width
, height
, gl
.RGBA
, gl
.UNSIGNED_BYTE
, offset
);
139 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "buffer too small");
141 gl
.bufferData(gl
.PIXEL_PACK_BUFFER
, array
, gl
.STATIC_DRAW
);
142 gl
.readPixels(xoffset
, yoffset
, width
, height
, gl
.RGBA
, gl
.UNSIGNED_BYTE
, offset
);
145 gl
.readPixels(xoffset
, yoffset
, width
, height
, gl
.RGBA
, gl
.UNSIGNED_BYTE
, arrayWrongSize
);
146 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "buffer too small");
148 gl
.readPixels(xoffset
, yoffset
, width
, height
, gl
.RGBA
, gl
.UNSIGNED_BYTE
, array
);
150 if (packParamsValid
) {
151 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "readPixels should succeed");
153 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "Invalid pack params combination");
160 if (usePixelPackBuffer
) {
161 array
= new Uint8Array(skipSize
+ size
);
162 gl
.getBufferSubData(gl
.PIXEL_PACK_BUFFER
, 0, array
);
165 // Check skipped bytes are unchanged.
166 for (var ii
= 0; ii
< skipSize
; ++ii
) {
167 if (array
[ii
] != initialColor
[ii
% bytesPerPixel
]) {
168 testFailed("skipped bytes changed at index " + ii
+ ": expected " +
169 initialColor
[ii
% bytesPerPixel
] + " got " + array
[ii
]);
173 // Check the first and last pixels of each row.
175 var canvasHeight
= 4;
176 for (var row
= 0; row
< height
; ++row
) {
178 var yIndex
= yoffset
+ row
;
182 var pos
= skipSize
+ bytesPerRow
* row
;
184 if (xIndex
< 0 || xIndex
>= canvasWidth
|| yIndex
< 0 || yIndex
>= canvasHeight
) {
185 if (row
> 0 && usePixelPackBuffer
&& packParams
.rowLength
> 0 && packParams
.rowLength
< width
)
186 refColor
= [initialColor
, expectedColor
[yIndex
- 1]];
188 refColor
= [initialColor
];
190 refColor
= [expectedColor
[yIndex
]];
192 samePixel(array
, pos
, refColor
, row
, "first");
196 if (row
+ 1 == height
|| packParams
.rowLength
> width
)
200 xIndex
= xoffset
+ xSpan
- 1;
201 pos
+= (xSpan
- 1) * bytesPerPixel
;
202 if (xIndex
< 0 || xIndex
>= canvasWidth
|| yIndex
< 0 || yIndex
>= canvasHeight
) {
203 if (row
> 0 && usePixelPackBuffer
&& packParams
.rowLength
> 0 && packParams
.rowLength
< width
)
204 refColor
= [initialColor
, expectedColor
[yIndex
- 1]];
206 refColor
= [initialColor
];
208 refColor
= [expectedColor
[yIndex
]];
210 samePixel(array
, pos
, refColor
, row
, "last");
212 // Check padding bytes are unchanged and bytes beyond rowLength set correctly.
213 pos
+= bytesPerPixel
;
214 if (row
+ 1 < height
) {
215 // Beyond bytes filled for PACK_ROW_LENGTH, the row could have extra bytes due to
216 // padding. These extra bytes could be either filled with pixel data if
217 // PACK_ROW_LENGTH is set to be less than width, or they could be left unchanged
218 // if they are beyond |width| pixels.
219 if (packParams
.rowLength
> 0 && packParams
.rowLength
< width
) {
220 var trailingBytes
= Math
.min((width
- packParams
.rowLength
) * bytesPerPixel
,
221 bytesPerRow
- packParams
.rowLength
* bytesPerPixel
);
222 for (var ii
= 0; ii
< trailingBytes
; ++ii
) {
223 if (array
[pos
+ ii
] != refColor
[0][ii
% bytesPerPixel
]) {
224 testFailed("Trailing byte " + ii
+ " after rowLength of row " + row
+ " : expected " +
225 refColor
[0][ii
% bytesPerPixel
] + ", got " + array
[pos
+ ii
]);
229 pos
+= trailingBytes
;
231 var paddingBytes
= skipSize
+ bytesPerRow
* (row
+ 1) - pos
;
232 for (var ii
= 0; ii
< paddingBytes
; ++ii
) {
233 if (array
[pos
+ ii
] != initialColor
[ii
% bytesPerPixel
]) {
234 testFailed("Padding byte " + ii
+ " of row " + row
+ " changed: expected " +
235 initialColor
[ii
% bytesPerPixel
] + ", got " + array
[pos
+ ii
]);
243 function testPackParameters(usePixelPackBuffer
)
246 var destText
= usePixelPackBuffer
? "PIXEL_PACK buffer" : "array buffer";
247 debug("Verify that reading pixels to " + destText
+ " works fine with various pack alignments.");
248 runTestIteration(0, 0, 1, 3, {alignment
:1}, usePixelPackBuffer
, true);
249 runTestIteration(0, 0, 1, 3, {alignment
:2}, usePixelPackBuffer
, true);
250 runTestIteration(0, 0, 1, 3, {alignment
:4}, usePixelPackBuffer
, true);
251 runTestIteration(0, 0, 1, 3, {alignment
:8}, usePixelPackBuffer
, true);
252 runTestIteration(0, 0, 2, 3, {alignment
:4}, usePixelPackBuffer
, true);
253 runTestIteration(0, 0, 2, 3, {alignment
:8}, usePixelPackBuffer
, true);
254 runTestIteration(0, 0, 3, 3, {alignment
:4}, usePixelPackBuffer
, true);
255 runTestIteration(0, 0, 3, 3, {alignment
:8}, usePixelPackBuffer
, true);
256 runTestIteration(0, 0, 0, 0, {alignment
:1}, usePixelPackBuffer
, true);
257 runTestIteration(0, 0, 1, 3, {alignment
:4}, usePixelPackBuffer
, true);
258 runTestIteration(0, 0, 1, 3, {alignment
:8}, usePixelPackBuffer
, true);
261 debug("Verify that reading pixels to " + destText
+ " is disallowed when PACK_ROW_LENGTH < width.");
262 runTestIteration(0, 0, 3, 3, {alignment
:8, rowLength
:2}, usePixelPackBuffer
, false);
263 runTestIteration(-1, 0, 3, 3, {alignment
:8, rowLength
:2}, usePixelPackBuffer
, false);
264 runTestIteration(0, -1, 3, 3, {alignment
:8, rowLength
:2}, usePixelPackBuffer
, false);
265 runTestIteration(-1, -1, 3, 3, {alignment
:8, rowLength
:2}, usePixelPackBuffer
, false);
266 runTestIteration(-5, 0, 3, 3, {alignment
:8, rowLength
:2}, usePixelPackBuffer
, false);
267 runTestIteration(0, -5, 3, 3, {alignment
:8, rowLength
:2}, usePixelPackBuffer
, false);
268 runTestIteration(2, 0, 3, 3, {alignment
:8, rowLength
:2}, usePixelPackBuffer
, false);
269 runTestIteration(0, 2, 3, 3, {alignment
:8, rowLength
:2}, usePixelPackBuffer
, false);
270 runTestIteration(2, 2, 3, 3, {alignment
:8, rowLength
:2}, usePixelPackBuffer
, false);
271 runTestIteration(5, 0, 3, 3, {alignment
:8, rowLength
:2}, usePixelPackBuffer
, false);
272 runTestIteration(0, 5, 3, 3, {alignment
:8, rowLength
:2}, usePixelPackBuffer
, false);
273 runTestIteration(0, 0, 3, 3, {alignment
:8, rowLength
:1}, usePixelPackBuffer
, false);
276 debug("Verify that reading pixels to " + destText
+ " works fine with PACK_ROW_LENGTH == width.");
277 runTestIteration(0, 0, 3, 3, {alignment
:8, rowLength
:3}, usePixelPackBuffer
, true);
278 runTestIteration(-1, 0, 3, 3, {alignment
:8, rowLength
:3}, usePixelPackBuffer
, true);
279 runTestIteration(0, -1, 3, 3, {alignment
:8, rowLength
:3}, usePixelPackBuffer
, true);
280 runTestIteration(-1, -1, 3, 3, {alignment
:8, rowLength
:3}, usePixelPackBuffer
, true);
281 runTestIteration(-5, 0, 3, 3, {alignment
:8, rowLength
:3}, usePixelPackBuffer
, true);
282 runTestIteration(0, -5, 3, 3, {alignment
:8, rowLength
:3}, usePixelPackBuffer
, true);
283 runTestIteration(2, 0, 3, 3, {alignment
:8, rowLength
:3}, usePixelPackBuffer
, true);
284 runTestIteration(0, 2, 3, 3, {alignment
:8, rowLength
:3}, usePixelPackBuffer
, true);
285 runTestIteration(2, 2, 3, 3, {alignment
:8, rowLength
:3}, usePixelPackBuffer
, true);
286 runTestIteration(5, 0, 3, 3, {alignment
:8, rowLength
:3}, usePixelPackBuffer
, true);
287 runTestIteration(0, 5, 3, 3, {alignment
:8, rowLength
:3}, usePixelPackBuffer
, true);
290 debug("Verify that reading pixels to " + destText
+ " works fine with PACK_ROW_LENGTH > width and with no padding");
291 runTestIteration(0, 0, 3, 3, {alignment
:8, rowLength
:4}, usePixelPackBuffer
, true);
292 runTestIteration(-1, 0, 3, 3, {alignment
:8, rowLength
:4}, usePixelPackBuffer
, true);
293 runTestIteration(0, -1, 3, 3, {alignment
:8, rowLength
:4}, usePixelPackBuffer
, true);
294 runTestIteration(-1, -1, 3, 3, {alignment
:8, rowLength
:4}, usePixelPackBuffer
, true);
295 runTestIteration(-5, 0, 3, 3, {alignment
:8, rowLength
:4}, usePixelPackBuffer
, true);
296 runTestIteration(0, -5, 3, 3, {alignment
:8, rowLength
:4}, usePixelPackBuffer
, true);
297 runTestIteration(2, 0, 3, 3, {alignment
:8, rowLength
:4}, usePixelPackBuffer
, true);
298 runTestIteration(0, 2, 3, 3, {alignment
:8, rowLength
:4}, usePixelPackBuffer
, true);
299 runTestIteration(2, 2, 3, 3, {alignment
:8, rowLength
:4}, usePixelPackBuffer
, true);
300 runTestIteration(5, 0, 3, 3, {alignment
:8, rowLength
:4}, usePixelPackBuffer
, true);
301 runTestIteration(0, 5, 3, 3, {alignment
:8, rowLength
:4}, usePixelPackBuffer
, true);
304 debug("Verify that reading pixels to " + destText
+ " works fine with PACK_ROW_LENGTH > width and with padding");
305 runTestIteration(0, 0, 3, 3, {alignment
:8, rowLength
:5}, usePixelPackBuffer
, true);
306 runTestIteration(-1, 0, 3, 3, {alignment
:8, rowLength
:5}, usePixelPackBuffer
, true);
307 runTestIteration(0, -1, 3, 3, {alignment
:8, rowLength
:5}, usePixelPackBuffer
, true);
308 runTestIteration(-1, -1, 3, 3, {alignment
:8, rowLength
:5}, usePixelPackBuffer
, true);
309 runTestIteration(-5, 0, 3, 3, {alignment
:8, rowLength
:5}, usePixelPackBuffer
, true);
310 runTestIteration(0, -5, 3, 3, {alignment
:8, rowLength
:5}, usePixelPackBuffer
, true);
311 runTestIteration(2, 0, 3, 3, {alignment
:8, rowLength
:5}, usePixelPackBuffer
, true);
312 runTestIteration(0, 2, 3, 3, {alignment
:8, rowLength
:5}, usePixelPackBuffer
, true);
313 runTestIteration(2, 2, 3, 3, {alignment
:8, rowLength
:5}, usePixelPackBuffer
, true);
314 runTestIteration(5, 0, 3, 3, {alignment
:8, rowLength
:5}, usePixelPackBuffer
, true);
315 runTestIteration(0, 5, 3, 3, {alignment
:8, rowLength
:5}, usePixelPackBuffer
, true);
318 debug("Verify that reading pixels to " + destText
+ " works fine with pack skip parameters.");
319 runTestIteration(0, 0, 3, 3, {alignment
:8, skipPixels
:2}, usePixelPackBuffer
, false);
320 runTestIteration(0, 0, 3, 3, {alignment
:8, skipPixels
:1, skipRows
:3}, usePixelPackBuffer
, false);
321 runTestIteration(0, 0, 3, 3, {alignment
:8, skipRows
:3}, usePixelPackBuffer
, true);
322 runTestIteration(0, 0, 2, 3, {alignment
:8, skipPixels
:2}, usePixelPackBuffer
, false);
323 runTestIteration(0, 0, 2, 3, {alignment
:8, skipPixels
:1, skipRows
:3}, usePixelPackBuffer
, false);
324 runTestIteration(0, 0, 2, 3, {alignment
:8, skipRows
:3}, usePixelPackBuffer
, true);
325 runTestIteration(0, 0, 2, 3, {skipPixels
:1, rowLength
:4}, usePixelPackBuffer
, true);
329 debug("Canvas.getContext");
331 var canvas
= document
.getElementById("example");
332 var gl
= wtu
.create3DContext(canvas
, undefined, 2);
335 testFailed("context does not exist");
337 testPassed("context exists");
340 description('ReadPixels into array buffer');
341 paintWebGLCanvas(gl
);
342 var usePixelPackBuffer
= false;
343 testPackParameters(usePixelPackBuffer
);
344 usePixelPackBuffer
= true;
345 testPackParameters(usePixelPackBuffer
);
349 var successfullyParsed
= true;
351 <script src=
"../../js/js-test-post.js"></script>