Added: trunk/LayoutTests/fast/canvas/webgl/texture-alternating-npot.html (0 => 198588)
--- trunk/LayoutTests/fast/canvas/webgl/texture-alternating-npot.html (rev 0)
+++ trunk/LayoutTests/fast/canvas/webgl/texture-alternating-npot.html 2016-03-23 19:21:11 UTC (rev 198588)
@@ -0,0 +1,205 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>WebGL Non-Power of 2 texture conformance test.</title>
+<script src=""
+<script src="" </script>
+<script src="" </script>
+</head>
+<body>
+<canvas id="example" width="4" height="4" style="width: 40px; height: 30px;"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+attribute vec2 texCoord0;
+varying vec2 texCoord;
+void main()
+{
+ gl_Position = vPosition;
+ texCoord = texCoord0;
+}
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+#ifdef GL_ES
+precision mediump float;
+#endif
+uniform samplerCube tex;
+varying vec2 texCoord;
+void main()
+{
+ gl_FragColor = textureCube(tex, normalize(vec3(texCoord, 1)));
+}
+</script>
+<script>
+if (window.internals)
+ window.internals.settings.setWebGLErrorsToConsoleEnabled(false);
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("example");
+var gl = wtu.create3DContext(canvas);
+var program = wtu.setupTexturedQuad(gl);
+
+glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup.");
+
+// Make 3 textures by using 3 active texture units.
+var textures = [];
+for (var ii = 0; ii < 3; ++ii) {
+ var tex = gl.createTexture();
+ gl.activeTexture(gl.TEXTURE0 + ii);
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ textures[ii] = tex;
+}
+shouldBe("gl.getError()", "gl.NO_ERROR");
+
+// Alternate POT and NPOT textures, ending with NPOT.
+//
+// 1. Check that an NPOT texture not on level 0 generates INVALID_VALUE (alternating, ending in NPOT texture)
+gl.activeTexture(gl.TEXTURE0 + 0);
+wtu.fillTexture(gl, textures[0], 5, 3, [0, 192, 128, 255], 1);
+glErrorShouldBe(gl, gl.INVALID_VALUE, "gl.texImage2D[0] with NPOT texture with level > 0 should return INVALID_VALUE");
+
+gl.activeTexture(gl.TEXTURE0 + 1);
+wtu.fillTexture(gl, textures[1], 4, 4, [0, 192, 128, 255], 1);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D[1] with POT texture with level > 0 should succeed");
+
+gl.activeTexture(gl.TEXTURE0 + 2);
+wtu.fillTexture(gl, textures[2], 5, 3, [0, 192, 128, 255], 1);
+glErrorShouldBe(gl, gl.INVALID_VALUE, "gl.texImage2D[2] with NPOT texture with level > 0 should return INVALID_VALUE");
+
+// 2. Check that an NPOT texture not on level 0 generates INVALID_VALUE (alternating, ending in POT texture)
+gl.activeTexture(gl.TEXTURE0 + 0);
+wtu.fillTexture(gl, textures[0], 4, 4, [0, 192, 128, 255], 1);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D[0] with POT texture with level > 0 should succeed");
+
+gl.activeTexture(gl.TEXTURE0 + 1);
+wtu.fillTexture(gl, textures[1], 5, 3, [0, 192, 128, 255], 1);
+glErrorShouldBe(gl, gl.INVALID_VALUE, "gl.texImage2D[1] with POT texture with level > 0 should return INVALID_VALUE");
+
+gl.activeTexture(gl.TEXTURE0 + 2);
+wtu.fillTexture(gl, textures[2], 4, 4, [0, 192, 128, 255], 1);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D[2] with POT texture with level > 0 should succeed");
+
+// 3. Check that an NPOT texture on level 0 succeeds (alternating, ending in NPOT texture)
+gl.activeTexture(gl.TEXTURE0 + 0);
+wtu.fillTexture(gl, textures[0], 5, 3, [0, 192, 128, 255]);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D[0] with NPOT texture at level 0 should succeed");
+
+gl.activeTexture(gl.TEXTURE0 + 1);
+wtu.fillTexture(gl, textures[1], 4, 4, [0, 192, 128, 255]);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D[1] with POT texture at level 0 should succeed");
+
+gl.activeTexture(gl.TEXTURE0 + 2);
+wtu.fillTexture(gl, textures[2], 5, 3, [0, 192, 128, 255]);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D[2] with NPOT texture at level 0 should succeed");
+
+// 4. Check that an NPOT texture on level 0 succeeds (alternating, ending in POT texture)
+gl.activeTexture(gl.TEXTURE0 + 0);
+wtu.fillTexture(gl, textures[0], 4, 4, [0, 192, 128, 255]);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D[0] with POT texture at level 0 should succeed");
+
+gl.activeTexture(gl.TEXTURE0 + 1);
+wtu.fillTexture(gl, textures[1], 5, 3, [0, 192, 128, 255]);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D[1] with NPOT texture at level 0 should succeed");
+
+gl.activeTexture(gl.TEXTURE0 + 2);
+wtu.fillTexture(gl, textures[2], 4, 4, [0, 192, 128, 255]);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D[2] with POT texture at level 0 should succeed");
+
+debug("");
+debug("check using cubemap");
+var program = wtu.setupProgram(
+ gl,
+ [wtu.loadShaderFromScript(gl, 'vshader', gl.VERTEX_SHADER),
+ wtu.loadShaderFromScript(gl, 'fshader', gl.FRAGMENT_SHADER)],
+ ['vPosition', 'texCoord0'], [0, 1]);
+
+// Make 3 textures by using 3 active texture units.
+var cubeTextures = [];
+for (var ii = 0; ii < 3; ++ii) {
+ var tex = gl.createTexture();
+ gl.activeTexture(gl.TEXTURE0 + ii);
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
+ cubeTextures[ii] = tex;
+}
+shouldBe("gl.getError()", "gl.NO_ERROR");
+
+// 5. Check that an NPOT texture not on level 0 generates INVALID_VALUE (alternating, ending in NPOT texture)
+gl.activeTexture(gl.TEXTURE0 + 0);
+fillCubeTexture(gl, cubeTextures[0], 5, 3, [0, 192, 128, 255], 1);
+glErrorShouldBe(gl, gl.INVALID_VALUE, "gl.texImage2D with NPOT texture with level > 0 should return INVALID_VALUE");
+
+gl.activeTexture(gl.TEXTURE0 + 1);
+fillCubeTexture(gl, cubeTextures[1], 4, 4, [0, 192, 128, 255], 1);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D with POT texture with level > 0 should succeed");
+
+gl.activeTexture(gl.TEXTURE0 + 2);
+fillCubeTexture(gl, cubeTextures[2], 5, 3, [0, 192, 128, 255], 1);
+glErrorShouldBe(gl, gl.INVALID_VALUE, "gl.texImage2D with NPOT texture with level > 0 should return INVALID_VALUE");
+
+// 6. Check that an NPOT texture not on level 0 generates INVALID_VALUE (alternating, ending in POT texture)
+gl.activeTexture(gl.TEXTURE0 + 0);
+fillCubeTexture(gl, cubeTextures[0], 4, 4, [0, 192, 128, 255], 1);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D with POT texture with level > 0 should succeed");
+
+gl.activeTexture(gl.TEXTURE0 + 1);
+fillCubeTexture(gl, cubeTextures[1], 5, 3, [0, 192, 128, 255], 1);
+glErrorShouldBe(gl, gl.INVALID_VALUE, "gl.texImage2D with NPOT texture with level > 0 should return INVALID_VALUE");
+
+gl.activeTexture(gl.TEXTURE0 + 2);
+fillCubeTexture(gl, cubeTextures[2], 4, 4, [0, 192, 128, 255], 1);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D with POT texture with level > 0 should succeed");
+
+// 7. Check that an NPOT texture on level 0 succeeds (alternating, ending in NPOT texture)
+gl.activeTexture(gl.TEXTURE0 + 0);
+fillCubeTexture(gl, cubeTextures[0], 5, 5, [0, 192, 128, 255]);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D with NPOT texture at level 0 should succeed");
+
+gl.activeTexture(gl.TEXTURE0 + 1);
+fillCubeTexture(gl, cubeTextures[1], 4, 4, [0, 192, 128, 255]);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D with POT texture at level 0 should succeed");
+
+gl.activeTexture(gl.TEXTURE0 + 2);
+fillCubeTexture(gl, cubeTextures[2], 5, 5, [0, 192, 128, 255]);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D with NPOT texture at level 0 should succeed");
+
+// 8. Check that an NPOT texture on level 0 succeeds (alternating, ending in POT texture)
+gl.activeTexture(gl.TEXTURE0 + 0);
+fillCubeTexture(gl, cubeTextures[0], 4, 4, [0, 192, 128, 255]);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D with POT texture at level 0 should succeed");
+
+gl.activeTexture(gl.TEXTURE0 + 1);
+fillCubeTexture(gl, cubeTextures[1], 5, 5, [0, 192, 128, 255]);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D with NPOT texture at level 0 should succeed");
+
+gl.activeTexture(gl.TEXTURE0 + 2);
+fillCubeTexture(gl, cubeTextures[2], 4, 4, [0, 192, 128, 255]);
+glErrorShouldBe(gl, gl.NO_ERROR, "gl.texImage2D with POT texture at level 0 should succeed");
+
+function fillCubeTexture(gl, tex, width, height, color, opt_level) {
+ opt_level = opt_level || 0;
+ var canvas = document.createElement('canvas');
+ canvas.width = width;
+ canvas.height = height;
+ var ctx2d = canvas.getContext('2d');
+ ctx2d.fillStyle = "rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + color[3] + ")";
+ ctx2d.fillRect(0, 0, width, height);
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
+ var targets = [
+ gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ for (var tt = 0; tt < targets.length; ++tt) {
+ gl.texImage2D(
+ targets[tt], opt_level, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
+ }
+};
+
+</script>
+</body>
+</html>
+
Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp (198587 => 198588)
--- trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp 2016-03-23 18:00:43 UTC (rev 198587)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp 2016-03-23 19:21:11 UTC (rev 198588)
@@ -1268,12 +1268,8 @@
WebGLTexture* tex = validateTextureBinding("compressedTexImage2D", target, true);
if (!tex)
return;
- if (!isGLES2NPOTStrict()) {
- if (level && WebGLTexture::isNPOT(width, height)) {
- synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "level > 0 not power of 2");
- return;
- }
- }
+ if (!validateNPOTTextureLevel(width, height, level, "compressedTexImage2D"))
+ return;
m_context->moveErrorsToSyntheticErrorList();
m_context->compressedTexImage2D(target, level, internalformat, width, height,
border, data->byteLength(), data->baseAddress());
@@ -1604,6 +1600,16 @@
m_context->disableVertexAttribArray(index);
}
+bool WebGLRenderingContextBase::validateNPOTTextureLevel(GC3Dsizei width, GC3Dsizei height, GC3Dint level, const char* functionName)
+{
+ if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
+ synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level > 0 not power of 2");
+ return false;
+ }
+
+ return true;
+}
+
bool WebGLRenderingContextBase::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
{
RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
@@ -1915,14 +1921,15 @@
bool vertexAttrib0Simulated = false;
if (!isGLES2Compliant())
vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
+ bool usesFallbackTexture = false;
if (!isGLES2NPOTStrict())
- checkTextureCompleteness("drawArrays", true);
+ usesFallbackTexture = checkTextureCompleteness("drawArrays", true);
m_context->drawArrays(mode, first, count);
if (!isGLES2Compliant() && vertexAttrib0Simulated)
restoreStatesAfterVertexAttrib0Simulation();
- if (!isGLES2NPOTStrict())
+ if (usesFallbackTexture)
checkTextureCompleteness("drawArrays", false);
markContextChanged();
}
@@ -1941,14 +1948,16 @@
validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements);
vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
}
+
+ bool usesFallbackTexture = false;
if (!isGLES2NPOTStrict())
- checkTextureCompleteness("drawElements", true);
+ usesFallbackTexture = checkTextureCompleteness("drawElements", true);
m_context->drawElements(mode, count, type, static_cast<GC3Dintptr>(offset));
if (!isGLES2Compliant() && vertexAttrib0Simulated)
restoreStatesAfterVertexAttrib0Simulation();
- if (!isGLES2NPOTStrict())
+ if (usesFallbackTexture)
checkTextureCompleteness("drawElements", false);
markContextChanged();
}
@@ -2999,7 +3008,7 @@
WebGLTexture* tex = validateTextureBinding("texImage2D", target, true);
ASSERT(validateTexFuncParameters("texImage2D", TexImage, target, level, internalformat, width, height, border, format, type));
ASSERT(tex);
- ASSERT(!level || !WebGLTexture::isNPOT(width, height));
+ ASSERT(validateNPOTTextureLevel(width, height, level, "texImage2D"));
if (!pixels) {
// Note: Chromium's OpenGL implementation clears textures and isResourceSafe() is therefore true.
// For other implementations, if they are using ANGLE_depth_texture, ANGLE depth textures
@@ -3067,10 +3076,8 @@
return false;
if (functionType != TexSubImage) {
- if (level && WebGLTexture::isNPOT(width, height)) {
- synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level > 0 not power of 2");
+ if (!validateNPOTTextureLevel(width, height, level, functionName))
return false;
- }
// For SourceArrayBufferView, function validateTexFuncData() would handle whether to validate the SettableTexFormat
// by checking if the ArrayBufferView is null or not.
if (sourceType != SourceArrayBufferView) {
@@ -3978,9 +3985,10 @@
return WebGLGetInfo(Int32Array::create(value, length).release());
}
-void WebGLRenderingContextBase::checkTextureCompleteness(const char* functionName, bool prepareToDraw)
+bool WebGLRenderingContextBase::checkTextureCompleteness(const char* functionName, bool prepareToDraw)
{
bool resetActiveUnit = false;
+ bool usesAtLeastOneBlackTexture = false;
WebGLTexture::TextureExtensionFlag extensions = textureExtensionFlags();
Vector<unsigned> noLongerUnrenderable;
@@ -3995,6 +4003,8 @@
continue;
}
+ usesAtLeastOneBlackTexture = true;
+
if (badTexture != m_activeTextureUnit) {
m_context->activeTexture(badTexture + GraphicsContext3D::TEXTURE0);
resetActiveUnit = true;
@@ -4025,6 +4035,8 @@
for (unsigned renderable : noLongerUnrenderable)
m_unrenderableTextureUnits.remove(renderable);
+
+ return usesAtLeastOneBlackTexture;
}
void WebGLRenderingContextBase::createFallbackBlackTextures1x1()