Commit ea67eb70 authored by skyostil@chromium.org's avatar skyostil@chromium.org

Handle very large images correctly

Large images may get downscaled during decoding to keep them within
the configured memory limits. When this happens while loading a WebGL
texture, bail out because otherwise the resulting texture will not have
the correct dimensions nor contents.

Tested with Nexus 5.

BUG=356181
TEST=fast/canvas/webgl/webgl-large-texture.html
R=kbr@chromium.org

Review URL: https://codereview.chromium.org/215713002

git-svn-id: svn://svn.chromium.org/blink/trunk@170339 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 1369d34f
Test loading a large texture using texImage2D
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Image width and height: 3900, 3900
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Loading a large texture using texImage2D</title>
<script src="../../../resources/js-test.js"></script>
<script src="resources/webgl-test.js"></script>
</head>
<body>
<canvas id="canvas" width="64" height="64"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
var successfullyParsed = false;
function init()
{
if (window.initNonKhronosFramework)
window.initNonKhronosFramework(true);
if (window.internals)
window.internals.settings.setWebGLErrorsToConsoleEnabled(false);
description('Test loading a large texture using texImage2D');
runTest();
}
function generateImageData(width, height)
{
var srcCanvas = document.createElement('canvas');
srcCanvas.width = width;
srcCanvas.height = height;
var ctx = srcCanvas.getContext('2d');
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, srcCanvas.width, srcCanvas.height);
return srcCanvas.toDataURL('image/jpeg');
}
function runTest() {
var canvas = document.getElementById('canvas');
var gl = canvas.getContext('webgl');
var texture = gl.createTexture();
var image = new Image();
image.onerror = function (e) {
testFailed('Image failed to load');
}
image.onload = function () {
var width = image.width;
var height = image.height;
debug('Image width and height: ' + width + ', ' + height);
var pixels = new Uint8Array(width * height * 4);
if (width > gl.getParameter(gl.MAX_TEXTURE_SIZE) ||
width > gl.getParameter(gl.MAX_RENDERBUFFER_SIZE)) {
// The image is allowed to be too big to be used as a texture.
finishJSTest();
return;
}
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
if (gl.getError() != gl.NO_ERROR) {
// Loading the texture is allowed to fail due to resource constraints.
finishJSTest();
return;
}
var fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
for (var i = 0; i < pixels.length; ++i) {
// The image is filled with white, 254 to account for decoding rounding differences.
if (pixels[i] < 254) {
testFailed('Texture was not loaded correctly.');
return;
}
}
finishJSTest();
}
image.src = generateImageData(3900, 3900);
}
init();
</script>
</body>
</html>
......@@ -3301,7 +3301,7 @@ void WebGLRenderingContextBase::texImage2DImpl(GLenum target, GLint level, GLenu
if (m_unpackAlignment != 1)
m_context->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
texImage2DBase(target, level, internalformat, image->width(), image->height(), 0, format, type, needConversion ? data.data() : imagePixelData, exceptionState);
texImage2DBase(target, level, internalformat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), 0, format, type, needConversion ? data.data() : imagePixelData, exceptionState);
if (m_unpackAlignment != 1)
m_context->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
}
......@@ -3597,7 +3597,7 @@ void WebGLRenderingContextBase::texSubImage2DImpl(GLenum target, GLint level, GL
if (m_unpackAlignment != 1)
m_context->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(), format, type, needConversion ? data.data() : imagePixelData, exceptionState);
texSubImage2DBase(target, level, xoffset, yoffset, imageExtractor.imageWidth(), imageExtractor.imageHeight(), format, type, needConversion ? data.data() : imagePixelData, exceptionState);
if (m_unpackAlignment != 1)
m_context->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
}
......
......@@ -1586,6 +1586,9 @@ bool WebGLImageConversion::ImageExtractor::extractImage(bool premultiplyAlpha, b
m_imageHeight = m_skiaImage->bitmap().height();
if (!m_imageWidth || !m_imageHeight)
return false;
// Fail if the image was downsampled because of memory limits.
if (m_imageWidth != (unsigned)m_image->size().width() || m_imageHeight != (unsigned)m_image->size().height())
return false;
m_imageSourceUnpackAlignment = 0;
m_skiaImage->bitmap().lockPixels();
m_imagePixelData = m_skiaImage->bitmap().getPixels();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment