| /* |
| Copyright (c) 2019 The Khronos Group Inc. |
| Use of this source code is governed by an MIT-style license that can be |
| found in the LICENSE.txt file. |
| */ |
| |
| function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) { |
| var wtu = WebGLTestUtils; |
| var tiu = TexImageUtils; |
| var gl = null; |
| var successfullyParsed = false; |
| var imageData = null; |
| var blackColor = [0, 0, 0]; |
| var originalPixels = (function() { |
| // (red|green|blue|cyan)(opaque|transparent) |
| var ro = [255, 0, 0, 255]; var rt = [255, 0, 0, 0]; |
| var go = [0, 255, 0, 255]; var gt = [0, 255, 0, 0]; |
| var bo = [0, 0, 255, 255]; var bt = [0, 0, 255, 0]; |
| var co = [0, 255, 255, 255]; var ct = [0, 255, 255, 0]; |
| return [ro, rt, go, gt, |
| ro, rt, go, gt, |
| bo, bt, co, ct, |
| bo, bt, co, ct]; |
| })(); |
| |
| function init() |
| { |
| description('Verify texImage3D and texSubImage3D code paths taking ImageData (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')'); |
| |
| // Set the default context version while still allowing the webglVersion URL query string to override it. |
| wtu.setDefault3DContextVersion(defaultContextVersion); |
| gl = wtu.create3DContext("example"); |
| |
| if (!prologue(gl)) { |
| finishTest(); |
| return; |
| } |
| |
| gl.clearColor(0,0,0,1); |
| gl.clearDepth(1); |
| gl.disable(gl.BLEND); |
| |
| var canvas2d = document.getElementById("texcanvas"); |
| var context2d = canvas2d.getContext("2d"); |
| imageData = context2d.createImageData(4, 4); |
| var data = imageData.data; |
| for (var i = 0; i < originalPixels.length; i++) { |
| data.set(originalPixels[i], 4 * i); |
| } |
| |
| runTest(); |
| } |
| |
| function runOneIteration(useTexSubImage3D, flipY, premultiplyAlpha, bindingTarget, |
| depth, sourceSubRectangle, rTexCoord, program) |
| { |
| var expected = simulate(flipY, premultiplyAlpha, depth, sourceSubRectangle, rTexCoord); |
| var sourceSubRectangleString = ''; |
| if (sourceSubRectangle) { |
| sourceSubRectangleString = ', sourceSubRectangle=' + sourceSubRectangle; |
| sourceSubRectangleString += ', rTexCoord=' + rTexCoord; |
| } |
| debug(''); |
| debug('Testing ' + (useTexSubImage3D ? 'texSubImage3D' : 'texImage3D') + |
| ' with flipY=' + flipY + ', premultiplyAlpha=' + premultiplyAlpha + |
| ', bindingTarget=' + (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') + |
| sourceSubRectangleString); |
| gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); |
| // Enable writes to the RGBA channels |
| gl.colorMask(1, 1, 1, 0); |
| var texture = gl.createTexture(); |
| // Bind the texture to texture unit 0 |
| gl.bindTexture(bindingTarget, texture); |
| // Set up texture parameters |
| gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST); |
| gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST); |
| gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); |
| gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); |
| gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE); |
| // Set up pixel store parameters |
| gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY); |
| gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha); |
| gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); |
| var uploadWidth = imageData.width; |
| var uploadHeight = imageData.height; |
| if (sourceSubRectangle) { |
| gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]); |
| gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]); |
| uploadWidth = sourceSubRectangle[2]; |
| uploadHeight = sourceSubRectangle[3]; |
| } |
| // Upload the image into the texture |
| if (useTexSubImage3D) { |
| // Initialize the texture to black first |
| gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0, |
| gl[pixelFormat], gl[pixelType], null); |
| gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, uploadWidth, uploadHeight, depth, |
| gl[pixelFormat], gl[pixelType], imageData); |
| } else { |
| gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0, |
| gl[pixelFormat], gl[pixelType], imageData); |
| } |
| gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0); |
| gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from texture upload"); |
| |
| var tl = expected[0][0]; |
| var tr = expected[0][1]; |
| var bl = expected[1][0]; |
| var br = expected[1][1]; |
| |
| var rCoordLocation = gl.getUniformLocation(program, 'uRCoord'); |
| if (!rCoordLocation) { |
| testFailed("Shader incorrectly set up; couldn't find uRCoord uniform"); |
| return; |
| } |
| gl.uniform1f(rCoordLocation, rTexCoord); |
| // Draw the triangles |
| wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]); |
| |
| var width = gl.canvas.width; |
| var halfWidth = Math.floor(width / 2); |
| var height = gl.canvas.height; |
| var halfHeight = Math.floor(height / 2); |
| |
| var top = 0; |
| var bottom = height - halfHeight; |
| var left = 0; |
| var right = width - halfWidth; |
| |
| debug("Checking pixel values"); |
| debug("Expecting: " + expected); |
| var expectedH = expected.length; |
| var expectedW = expected[0].length; |
| var texelH = Math.floor(gl.canvas.height / expectedH); |
| var texelW = Math.floor(gl.canvas.width / expectedW); |
| // For each entry of the expected[][] array, check the appropriate |
| // canvas rectangle for correctness. |
| for (var row = 0; row < expectedH; row++) { |
| var y = row * texelH; |
| for (var col = 0; col < expectedW; col++) { |
| var x = col * texelW; |
| var val = expected[row][col]; |
| wtu.checkCanvasRect(gl, x, y, texelW, texelH, val, "should be " + val); |
| } |
| } |
| } |
| |
| function runTest() |
| { |
| var program = tiu.setupTexturedQuadWith3D(gl, internalFormat); |
| runTestOnBindingTarget(gl.TEXTURE_3D, program); |
| program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat); |
| runTestOnBindingTarget(gl.TEXTURE_2D_ARRAY, program); |
| |
| debug(""); |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); |
| finishTest(); |
| } |
| |
| function simulate(flipY, premultiplyAlpha, depth, sourceSubRectangle, rTexCoord) { |
| var ro = [255, 0, 0]; var rt = premultiplyAlpha ? [0, 0, 0] : [255, 0, 0]; |
| var go = [0, 255, 0]; var gt = premultiplyAlpha ? [0, 0, 0] : [0, 255, 0]; |
| var bo = [0, 0, 255]; var bt = premultiplyAlpha ? [0, 0, 0] : [0, 0, 255]; |
| var co = [0, 255, 255]; var ct = premultiplyAlpha ? [0, 0, 0] : [0, 255, 255]; |
| var expected = [[ro, rt, go, gt], |
| [ro, rt, go, gt], |
| [bo, bt, co, ct], |
| [bo, bt, co, ct]]; |
| switch (gl[pixelFormat]) { |
| case gl.RED: |
| case gl.RED_INTEGER: |
| for (var row = 0; row < 4; row++) { |
| for (var col = 0; col < 4; col++) { |
| expected[row][col][1] = 0; // zero the green channel |
| } |
| } |
| // fall-through |
| case gl.RG: |
| case gl.RG_INTEGER: |
| for (var row = 0; row < 4; row++) { |
| for (var col = 0; col < 4; col++) { |
| expected[row][col][2] = 0; // zero the blue channel |
| } |
| } |
| break; |
| default: |
| break; |
| } |
| |
| if (flipY) { |
| expected.reverse(); |
| } |
| |
| if (sourceSubRectangle) { |
| let expected2 = []; |
| for (var row = 0; row < sourceSubRectangle[3]; row++) { |
| expected2[row] = []; |
| for (var col = 0; col < sourceSubRectangle[2]; col++) { |
| expected2[row][col] = |
| expected[sourceSubRectangle[1] + row + rTexCoord * sourceSubRectangle[3]][sourceSubRectangle[0] + col]; |
| } |
| } |
| expected = expected2; |
| } |
| |
| return expected; |
| } |
| |
| function runTestOnBindingTarget(bindingTarget, program) { |
| var rects = [ |
| undefined, |
| [0, 0, 2, 2], |
| [2, 0, 2, 2], |
| ]; |
| var dbg = false; // Set to true for debug output images |
| if (dbg) { |
| (function() { |
| debug(""); |
| debug("Original ImageData (transparent pixels appear black):"); |
| var cvs = document.createElement("canvas"); |
| cvs.width = 4; |
| cvs.height = 4; |
| cvs.style.width = "32px"; |
| cvs.style.height = "32px"; |
| cvs.style.imageRendering = "pixelated"; |
| cvs.style.background = "#000"; |
| var ctx = cvs.getContext("2d"); |
| ctx.putImageData(imageData, 0, 0); |
| var output = document.getElementById("console"); |
| output.appendChild(cvs); |
| })(); |
| } |
| for (const sub of [false, true]) { |
| for (const flipY of [false, true]) { |
| for (const premul of [false, true]) { |
| for (let irect = 0; irect < rects.length; irect++) { |
| var rect = rects[irect]; |
| let depth = rect ? 2 : 1; |
| for (let rTexCoord = 0; rTexCoord < depth; rTexCoord++) { |
| // TODO: add tests for UNPACK_IMAGE_HEIGHT. |
| runOneIteration(sub, flipY, premul, bindingTarget, |
| depth, rect, rTexCoord, program); |
| if (dbg) { |
| debug("Actual:"); |
| var img = document.createElement("img"); |
| img.src = gl.canvas.toDataURL("image/png"); |
| var output = document.getElementById("console"); |
| output.appendChild(img); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| return init; |
| } |