blob: 023312c771317974f941e8cef2a4d8bd64dab63e [file] [log] [blame]
/*
* Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
* for details. All rights reserved. Use of this source code is governed by a
* BSD-style license that can be found in the LICENSE file.
*/
/**
* @description Tests deletion behavior for texture, renderbuffer, shader, and
* program
*/
import "dart:html";
import "dart:web_gl" as wgl;
import 'dart:typed_data';
import "../../../testcommon.dart";
import "resources/webgl-test.dart";
import "resources/webgl-test-utils.dart" as wtu;
import "resources/desktop-gl-constants.dart";
import "../../../../Utils/async_utils.dart";
main() {
document.body.setInnerHtml('''
<div id="console"></div>
''', treeSanitizer: new NullTreeSanitizer());
var gl = wtu.create3DContext();
var shouldGenerateGLError = wtu.shouldGenerateGLError;
debug("");
debug("shader and program deletion");
var vertexShader = wtu.loadStandardVertexShader(gl);
assertMsg(vertexShader != null, "vertex shader loaded");
var fragmentShader = wtu.loadStandardFragmentShader(gl);
assertMsg(fragmentShader != null, "fragment shader loaded");
var program = gl.createProgram();
shouldBeNonNull(program);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.attachShader(program, vertexShader));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.attachShader(program, fragmentShader));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.linkProgram(program));
shouldBeTrue(gl.getProgramParameter(program, wgl.LINK_STATUS));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.useProgram(program));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteShader(vertexShader));
shouldBeTrue(gl.isShader(vertexShader));
shouldBeTrue(gl.getShaderParameter(vertexShader, wgl.DELETE_STATUS));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.detachShader(program, vertexShader));
shouldBeFalse(gl.isShader(vertexShader));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteShader(fragmentShader));
shouldBeTrue(gl.isShader(fragmentShader));
shouldBeTrue(gl.getShaderParameter(fragmentShader, wgl.DELETE_STATUS));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteProgram(program));
shouldBeTrue(gl.isProgram(program));
shouldBeTrue(gl.getProgramParameter(program, wgl.DELETE_STATUS));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.useProgram(null));
shouldBeFalse(gl.isProgram(program));
shouldBeFalse(gl.isShader(fragmentShader));
debug("");
debug("texture deletion");
var fbo = gl.createFramebuffer(), fbo2 = gl.createFramebuffer(), fbo3 = gl.createFramebuffer();
shouldBeNonNull(fbo);
shouldBeNonNull(fbo2);
shouldBeNonNull(fbo3);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
var tex = gl.createTexture();
shouldBeNonNull(tex);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindTexture(wgl.TEXTURE_2D, tex));
shouldBe(gl.getParameter(wgl.TEXTURE_BINDING_2D), tex);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.framebufferTexture2D(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.TEXTURE_2D, tex, 0));
shouldBe(gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME), tex);
shouldBe(gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE), wgl.TEXTURE);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteTexture(tex));
// Deleting a texture bound to the currently-bound fbo is the same as
// detaching the textue from fbo first, then delete the texture.
shouldBe(gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE), wgl.NONE);
shouldGenerateGLError(gl, wgl.INVALID_ENUM, () => gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME));
shouldBeFalse(gl.isTexture(tex));
shouldBeNull(gl.getParameter(wgl.TEXTURE_BINDING_2D));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindTexture(wgl.TEXTURE_2D, tex));
shouldBeNull(gl.getParameter(wgl.TEXTURE_BINDING_2D));
var texCubeMap = gl.createTexture();
shouldBeNonNull(texCubeMap);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindTexture(wgl.TEXTURE_CUBE_MAP, texCubeMap));
shouldBe(gl.getParameter(wgl.TEXTURE_BINDING_CUBE_MAP), texCubeMap);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteTexture(texCubeMap));
shouldBeFalse(gl.isTexture(texCubeMap));
shouldBeNull(gl.getParameter(wgl.TEXTURE_BINDING_CUBE_MAP));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindTexture(wgl.TEXTURE_CUBE_MAP, texCubeMap));
shouldBeNull(gl.getParameter(wgl.TEXTURE_BINDING_CUBE_MAP));
var t = gl.createTexture();
shouldBeNonNull(t);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindTexture(wgl.TEXTURE_2D, t));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.texParameteri(wgl.TEXTURE_2D, wgl.TEXTURE_WRAP_S, wgl.CLAMP_TO_EDGE));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteTexture(t));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindTexture(wgl.TEXTURE_2D, t));
shouldGenerateGLError(gl, wgl.INVALID_OPERATION, () => gl.texParameteri(wgl.TEXTURE_2D, wgl.TEXTURE_WRAP_S, wgl.CLAMP_TO_EDGE));
var t2 = gl.createTexture();
shouldBeNonNull(t2);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.activeTexture(wgl.TEXTURE0));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindTexture(wgl.TEXTURE_2D, t2));
shouldBe(gl.getParameter(wgl.TEXTURE_BINDING_2D), t2);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.activeTexture(wgl.TEXTURE1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindTexture(wgl.TEXTURE_2D, t2));
shouldBe(gl.getParameter(wgl.TEXTURE_BINDING_2D), t2);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteTexture(t2));
shouldBeNull(gl.getParameter(wgl.TEXTURE_BINDING_2D));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.activeTexture(wgl.TEXTURE0));
shouldBeNull(gl.getParameter(wgl.TEXTURE_BINDING_2D));
debug("");
debug("renderbuffer deletion");
var rbo = gl.createRenderbuffer(), rbo2 = gl.createRenderbuffer(), rbo3 = gl.createRenderbuffer();
shouldBeNonNull(rbo);
shouldBeNonNull(rbo2);
shouldBeNonNull(rbo3);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindRenderbuffer(wgl.RENDERBUFFER, rbo));
shouldBe(gl.getParameter(wgl.RENDERBUFFER_BINDING), rbo);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.framebufferRenderbuffer(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.RENDERBUFFER, rbo));
shouldBe(gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME), rbo);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteRenderbuffer(rbo));
// Deleting a renderbuffer bound to the currently-bound fbo is the same as
// detaching the renderbuffer from fbo first, then delete the renderbuffer.
shouldBe(gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE), wgl.NONE);
shouldGenerateGLError(gl, wgl.INVALID_ENUM, () => gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME));
shouldBeFalse(gl.isRenderbuffer(rbo));
shouldBeNull(gl.getParameter(wgl.RENDERBUFFER_BINDING));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindRenderbuffer(wgl.RENDERBUFFER, rbo));
shouldBeNull(gl.getParameter(wgl.RENDERBUFFER_BINDING));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindRenderbuffer(wgl.RENDERBUFFER, rbo2));
shouldBe(gl.getParameter(wgl.RENDERBUFFER_BINDING), rbo2);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteRenderbuffer(rbo3));
shouldBe(gl.getParameter(wgl.RENDERBUFFER_BINDING), rbo2);
debug("");
debug("using deleted renderbuffer");
rbo = gl.createRenderbuffer();
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindRenderbuffer(wgl.RENDERBUFFER, rbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.renderbufferStorage(wgl.RENDERBUFFER, wgl.RGBA4, 16, 16));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.framebufferRenderbuffer(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.RENDERBUFFER, rbo));
if (gl.checkFramebufferStatus(wgl.FRAMEBUFFER) == wgl.FRAMEBUFFER_COMPLETE) {
// make backbuffer red
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, null));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clearColor(1,0,0,1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clear(wgl.COLOR_BUFFER_BIT));
// make fbo green
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clearColor(0,1,0,1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clear(wgl.COLOR_BUFFER_BIT));
// Bind backbuffer.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, null));
// delete renderbuffer. It should still be attached to fbo though.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteRenderbuffer(rbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red"));
// Use fbo that has deleted rbo.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,255,0,255], "fbo should be green"));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clearColor(0,0,1,1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clear(wgl.COLOR_BUFFER_BIT));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,0,255,255], "fbo should be blue"));
// Bind backbuffer.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, null));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red"));
}
debug("");
debug("renderbuffer attached twice to same framebuffer");
rbo = gl.createRenderbuffer();
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindRenderbuffer(wgl.RENDERBUFFER, rbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.renderbufferStorage(wgl.RENDERBUFFER, wgl.RGBA4, 16, 16));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.framebufferRenderbuffer(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.RENDERBUFFER, rbo));
if (gl.checkFramebufferStatus(wgl.FRAMEBUFFER) == wgl.FRAMEBUFFER_COMPLETE) {
rbo2 = gl.createRenderbuffer();
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindRenderbuffer(wgl.RENDERBUFFER, rbo2));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.renderbufferStorage(wgl.RENDERBUFFER, wgl.RGBA4, 16, 16));
// attach rbo2 at two attachment points incompatible with it
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.framebufferRenderbuffer(wgl.FRAMEBUFFER, wgl.DEPTH_ATTACHMENT, wgl.RENDERBUFFER, rbo2));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.framebufferRenderbuffer(wgl.FRAMEBUFFER, wgl.STENCIL_ATTACHMENT, wgl.RENDERBUFFER, rbo2));
shouldBe(gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.DEPTH_ATTACHMENT, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME), rbo2);
shouldBe(gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.STENCIL_ATTACHMENT, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME), rbo2);
// fbo can't be complete as rbo2 is attached at incompatible attachment points
shouldNotBe(gl.checkFramebufferStatus(wgl.FRAMEBUFFER), wgl.FRAMEBUFFER_COMPLETE);
// now we delete rbo2, which detaches it from the two attachment points where it currently is attached
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteRenderbuffer(rbo2));
shouldBe(gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.DEPTH_ATTACHMENT, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE), wgl.NONE);
shouldBe(gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.STENCIL_ATTACHMENT, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE), wgl.NONE);
// we should now be in the same state as before with only rbo attached, so fbo should be complete again
shouldBe(gl.checkFramebufferStatus(wgl.FRAMEBUFFER), wgl.FRAMEBUFFER_COMPLETE);
shouldBe(gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME), rbo);
}
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteRenderbuffer(rbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, null));
debug("");
debug("using deleted texture");
tex = gl.createTexture();
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindTexture(wgl.TEXTURE_2D, tex));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.framebufferTexture2D(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.TEXTURE_2D, tex, 0));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.texImage2D(wgl.TEXTURE_2D, 0, wgl.RGBA, 1, 1, 0, wgl.RGBA, wgl.UNSIGNED_BYTE, null));
if (gl.checkFramebufferStatus(wgl.FRAMEBUFFER) == wgl.FRAMEBUFFER_COMPLETE) {
// make fbo green
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clearColor(0,1,0,1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clear(wgl.COLOR_BUFFER_BIT));
// Bind backbuffer.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, null));
// delete texture. It should still be attached to fbo though.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteTexture(tex));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 1, 1, [255,0,0,255], "backbuffer should be red"));
// Use fbo that has deleted texture.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,255,0,255], "fbo should be green"));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clearColor(0,0,1,1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clear(wgl.COLOR_BUFFER_BIT));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,0,255,255], "fbo should be blue"));
// Bind backbuffer.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, null));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red"));
}
debug("");
debug("using deleted renderbuffer");
rbo = gl.createRenderbuffer();
shouldBeNonNull(rbo);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindRenderbuffer(wgl.RENDERBUFFER, rbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.renderbufferStorage(wgl.RENDERBUFFER, wgl.RGBA4, 16, 16));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.framebufferRenderbuffer(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.RENDERBUFFER, rbo));
if (gl.checkFramebufferStatus(wgl.FRAMEBUFFER) == wgl.FRAMEBUFFER_COMPLETE) {
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo2));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.framebufferRenderbuffer(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.RENDERBUFFER, rbo));
shouldBe(gl.checkFramebufferStatus(wgl.FRAMEBUFFER), wgl.FRAMEBUFFER_COMPLETE);
// make backbuffer red
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, null));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clearColor(1,0,0,1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clear(wgl.COLOR_BUFFER_BIT));
// make fbo green
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clearColor(0,1,0,1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clear(wgl.COLOR_BUFFER_BIT));
// delete renderbuffer. It should still be attached to fbo2 though.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteRenderbuffer(rbo));
// fbo has no attachments
shouldNotBe(gl.checkFramebufferStatus(wgl.FRAMEBUFFER), wgl.FRAMEBUFFER_COMPLETE);
// Use fbo2 that has deleted rbo.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo2));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,255,0,255], "fbo should be green"));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clearColor(0,0,1,1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clear(wgl.COLOR_BUFFER_BIT));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,0,255,255], "fbo should be blue"));
shouldBe(gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME), rbo);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.INVALID_ENUM, () => gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME));
shouldGenerateGLError(gl, wgl.NONE, () => gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE));
shouldNotBe(gl.checkFramebufferStatus(wgl.FRAMEBUFFER), wgl.FRAMEBUFFER_COMPLETE);
// Bind backbuffer.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, null));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red"));
}
debug("");
debug("using deleted texture");
tex = gl.createTexture();
shouldBeNonNull(tex);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindTexture(wgl.TEXTURE_2D, tex));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.framebufferTexture2D(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.TEXTURE_2D, tex, 0));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.texImage2D(wgl.TEXTURE_2D, 0, wgl.RGBA, 1, 1, 0, wgl.RGBA, wgl.UNSIGNED_BYTE, null));
if (gl.checkFramebufferStatus(wgl.FRAMEBUFFER) == wgl.FRAMEBUFFER_COMPLETE) {
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo2));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.framebufferTexture2D(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.TEXTURE_2D, tex, 0));
// make fbo green
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clearColor(0,1,0,1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clear(wgl.COLOR_BUFFER_BIT));
// delete texture. It should still be attached to fbo2 though.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteTexture(tex));
// fbo has no attachments
shouldNotBe(gl.checkFramebufferStatus(wgl.FRAMEBUFFER), wgl.FRAMEBUFFER_COMPLETE);
// Use fbo that has deleted texture.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo2));
shouldBe(gl.checkFramebufferStatus(wgl.FRAMEBUFFER), wgl.FRAMEBUFFER_COMPLETE);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,255,0,255], "fbo should be green"));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clearColor(0,0,1,1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clear(wgl.COLOR_BUFFER_BIT));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,0,255,255], "fbo should be blue"));
shouldBe(gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME), tex);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.INVALID_ENUM, () => gl.getFramebufferAttachmentParameter(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME));
shouldNotBe(gl.checkFramebufferStatus(wgl.FRAMEBUFFER), wgl.FRAMEBUFFER_COMPLETE);
// Bind backbuffer.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, null));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red"));
}
debug("");
debug("buffer deletion");
var buffer = gl.createBuffer();
shouldBeNonNull(buffer);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindBuffer(wgl.ARRAY_BUFFER, buffer));
shouldBe(gl.getParameter(wgl.ARRAY_BUFFER_BINDING), buffer);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteBuffer(buffer));
shouldBeFalse(gl.isBuffer(buffer));
shouldBeNull(gl.getParameter(wgl.ARRAY_BUFFER_BINDING));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindBuffer(wgl.ARRAY_BUFFER, buffer));
shouldBeNull(gl.getParameter(wgl.ARRAY_BUFFER_BINDING));
var buffer2 = gl.createBuffer();
shouldBeNonNull(buffer2);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindBuffer(wgl.ARRAY_BUFFER, buffer2));
shouldBe(gl.getParameter(wgl.ARRAY_BUFFER_BINDING), buffer2);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindBuffer(wgl.ARRAY_BUFFER, null));
shouldBeNull(gl.getParameter(wgl.ARRAY_BUFFER_BINDING));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteBuffer(buffer2));
shouldBeFalse(gl.isBuffer(buffer2));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindBuffer(wgl.ARRAY_BUFFER, buffer2));
shouldBeNull(gl.getParameter(wgl.ARRAY_BUFFER_BINDING));
var bufferElement = gl.createBuffer();
shouldBeNonNull(bufferElement);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindBuffer(wgl.ELEMENT_ARRAY_BUFFER, bufferElement));
shouldBe(gl.getParameter(wgl.ELEMENT_ARRAY_BUFFER_BINDING), bufferElement);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteBuffer(bufferElement));
shouldBeFalse(gl.isBuffer(bufferElement));
shouldBeNull(gl.getParameter(wgl.ELEMENT_ARRAY_BUFFER_BINDING));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindBuffer(wgl.ELEMENT_ARRAY_BUFFER, bufferElement));
shouldBeNull(gl.getParameter(wgl.ELEMENT_ARRAY_BUFFER_BINDING));
var b = gl.createBuffer();
shouldBeNonNull(b);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindBuffer(wgl.ARRAY_BUFFER, b));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bufferData(wgl.ARRAY_BUFFER, 1, wgl.STATIC_DRAW));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteBuffer(b));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindBuffer(wgl.ARRAY_BUFFER, b));
shouldGenerateGLError(gl, wgl.INVALID_OPERATION, () => gl.bufferData(wgl.ARRAY_BUFFER, 1, wgl.STATIC_DRAW));
var b1 = gl.createBuffer();
shouldBeNonNull(b1);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindBuffer(wgl.ARRAY_BUFFER, b1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.enableVertexAttribArray(1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.vertexAttribPointer(1, 4, wgl.FLOAT, false, 0, 0));
var b2 = gl.createBuffer();
shouldBeNonNull(b2);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindBuffer(wgl.ARRAY_BUFFER, b2));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.enableVertexAttribArray(2));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.vertexAttribPointer(2, 4, wgl.FLOAT, false, 0, 0));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.enableVertexAttribArray(3));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.vertexAttribPointer(3, 4, wgl.FLOAT, false, 0, 0));
shouldBe(gl.getVertexAttrib(1, wgl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING), b1);
shouldBe(gl.getVertexAttrib(2, wgl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING), b2);
shouldBe(gl.getVertexAttrib(3, wgl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING), b2);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteBuffer(b2));
shouldBe(gl.getVertexAttrib(1, wgl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING), b1);
shouldBeNull(gl.getVertexAttrib(2, wgl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING));
shouldBeNull(gl.getVertexAttrib(3, wgl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteBuffer(b1));
shouldBeNull(gl.getVertexAttrib(1, wgl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING));
debug("");
debug("framebuffer deletion");
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldBe(gl.getParameter(wgl.FRAMEBUFFER_BINDING), fbo);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteFramebuffer(fbo));
shouldBeFalse(gl.isFramebuffer(fbo));
shouldBeNull(gl.getParameter(wgl.FRAMEBUFFER_BINDING));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldBeNull(gl.getParameter(wgl.FRAMEBUFFER_BINDING));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo2));
shouldBe(gl.getParameter(wgl.FRAMEBUFFER_BINDING), fbo2);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteFramebuffer(fbo3));
shouldBe(gl.getParameter(wgl.FRAMEBUFFER_BINDING), fbo2);
fbo = gl.createFramebuffer();
rbo = gl.createRenderbuffer();
shouldBeNonNull(fbo);
shouldBeNonNull(rbo);
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindRenderbuffer(wgl.RENDERBUFFER, rbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.renderbufferStorage(wgl.RENDERBUFFER, wgl.RGBA4, 16, 16));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.framebufferRenderbuffer(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.RENDERBUFFER, rbo));
if (gl.checkFramebufferStatus(wgl.FRAMEBUFFER) == wgl.FRAMEBUFFER_COMPLETE) {
// set backbuffer to red
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, null));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clearColor(1,0,0,1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clear(wgl.COLOR_BUFFER_BIT));
// set framebuffer to green
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clearColor(0,1,0,1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clear(wgl.COLOR_BUFFER_BIT));
// check framebuffer
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,255,0,255], "fbo should be green"));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 16, 16, 1, 1, [0,0,0,0], "outside fbo should be black"));
// delete framebuffer. because this was the bound fbo the backbuffer should be active now
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.deleteFramebuffer(fbo));
// check backbuffer
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 300, 150, [255,0,0,255], "backbuffer should be red"));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 300, 0, 300, 300, [0,0,0,0], "outside backbuffer should be black"));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 150, 300, 300, [0,0,0,0], "outside backbuffer should be black"));
// check drawing to backbuffer
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clearColor(0,1,0,1));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.clear(wgl.COLOR_BUFFER_BIT));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 300, 150, [0,255,0,255], "fbo should be green"));
shouldGenerateGLError(gl, wgl.NO_ERROR, () => gl.bindFramebuffer(wgl.FRAMEBUFFER, null));
// check again because many buggy implementations will have bound to the true backbuffer on deleteFramebuffer.
shouldGenerateGLError(gl, wgl.NO_ERROR, () => wtu.checkCanvasRect(gl, 0, 0, 300, 150, [0,255,0,255], "fbo should be green"));
}
}