tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

glsLifetimeTests.js (42386B)


      1 /*-------------------------------------------------------------------------
      2 * drawElements Quality Program OpenGL ES Utilities
      3 * ------------------------------------------------
      4 *
      5 * Copyright 2014 The Android Open Source Project
      6 *
      7 * Licensed under the Apache License, Version 2.0 (the "License");
      8 * you may not use this file except in compliance with the License.
      9 * You may obtain a copy of the License at
     10 *
     11 *      http://www.apache.org/licenses/LICENSE-2.0
     12 *
     13 * Unless required by applicable law or agreed to in writing, software
     14 * distributed under the License is distributed on an "AS IS" BASIS,
     15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16 * See the License for the specific language governing permissions and
     17 * limitations under the License.
     18 *
     19 */
     20 'use strict';
     21 goog.provide('modules.shared.glsLifetimeTests');
     22 goog.require('framework.common.tcuImageCompare');
     23 goog.require('framework.common.tcuStringTemplate');
     24 goog.require('framework.common.tcuSurface');
     25 goog.require('framework.common.tcuTestCase');
     26 goog.require('framework.delibs.debase.deRandom');
     27 goog.require('framework.opengl.gluShaderProgram');
     28 goog.require('modules.shared.glsTextureTestUtil');
     29 
     30 goog.scope(function() {
     31 var glsLifetimeTests = modules.shared.glsLifetimeTests;
     32 var tcuStringTemplate = framework.common.tcuStringTemplate;
     33 var tcuSurface = framework.common.tcuSurface;
     34 var deRandom = framework.delibs.debase.deRandom;
     35 var glsTextureTestUtil = modules.shared.glsTextureTestUtil;
     36 var gluShaderProgram = framework.opengl.gluShaderProgram;
     37 var tcuTestCase = framework.common.tcuTestCase;
     38 var tcuImageCompare = framework.common.tcuImageCompare;
     39 
     40 /** @const */ var VIEWPORT_SIZE = 128;
     41 /** @const */ var FRAMEBUFFER_SIZE = 128;
     42 
     43 var setParentClass = function(child, parent) {
     44    child.prototype = Object.create(parent.prototype);
     45    child.prototype.constructor = child;
     46 };
     47 
     48 /** @const */ var s_vertexShaderSrc =
     49    '#version 100\n' +
     50    'attribute vec2 pos;\n' +
     51    'void main()\n' +
     52    '{\n' +
     53    ' gl_Position = vec4(pos.xy, 0.0, 1.0);\n' +
     54    '}\n';
     55 
     56 /** @const */ var s_fragmentShaderSrc =
     57   '#version 100\n' +
     58    'void main()\n' +
     59    '{\n' +
     60    ' gl_FragColor = vec4(1.0);\n' +
     61    '}\n';
     62 
     63 /**
     64 * @constructor
     65 * @extends {gluShaderProgram.Shader}
     66 * @param {gluShaderProgram.shaderType} type
     67 * @param {string} src
     68 */
     69 glsLifetimeTests.CheckedShader = function(type, src) {
     70    gluShaderProgram.Shader.call(this, gl, type);
     71    this.setSources(src);
     72    this.compile();
     73    assertMsgOptions(this.getCompileStatus() === true, 'Failed to compile shader', false, true);
     74 };
     75 
     76 setParentClass(glsLifetimeTests.CheckedShader, gluShaderProgram.Shader);
     77 
     78 /**
     79 * @constructor
     80 * @extends {gluShaderProgram.Program}
     81 * @param {WebGLShader} vtxShader
     82 * @param {WebGLShader} fragShader
     83 */
     84 glsLifetimeTests.CheckedProgram = function(vtxShader, fragShader) {
     85    gluShaderProgram.Program.call(this, gl);
     86    this.attachShader(vtxShader);
     87    this.attachShader(fragShader);
     88    this.link();
     89    assertMsgOptions(this.info.linkOk === true, 'Failed to link program', false, true);
     90 };
     91 
     92 setParentClass(glsLifetimeTests.CheckedProgram, gluShaderProgram.Program);
     93 
     94 /**
     95 * @constructor
     96 */
     97 glsLifetimeTests.Binder = function() {
     98 };
     99 
    100 /**
    101 * @param {WebGLObject} obj
    102 */
    103 glsLifetimeTests.Binder.prototype.bind = function(obj) { throw new Error('Virtual function'); };
    104 
    105 /**
    106 * @return {WebGLObject}
    107 */
    108 glsLifetimeTests.Binder.prototype.getBinding = function() { throw new Error('Virtual function'); };
    109 
    110 /**
    111 * @constructor
    112 * @extends {glsLifetimeTests.Binder}
    113 * @param {?function(number, ?)} bindFunc
    114 * @param {number} bindTarget
    115 * @param {number} bindingParam
    116 */
    117 glsLifetimeTests.SimpleBinder = function(bindFunc, bindTarget, bindingParam) {
    118    glsLifetimeTests.Binder.call(this);
    119    this.m_bindFunc = bindFunc;
    120    this.m_bindTarget = bindTarget;
    121    this.m_bindingParam = bindingParam;
    122 };
    123 
    124 setParentClass(glsLifetimeTests.SimpleBinder, glsLifetimeTests.Binder);
    125 
    126 glsLifetimeTests.SimpleBinder.prototype.bind = function(obj) {
    127    this.m_bindFunc.call(gl, this.m_bindTarget, obj);
    128 };
    129 
    130 glsLifetimeTests.SimpleBinder.prototype.getBinding = function() {
    131    return /** @type {WebGLObject} */ (gl.getParameter(this.m_bindingParam));
    132 };
    133 
    134 /**
    135 * @constructor
    136 */
    137 glsLifetimeTests.Type = function() {
    138 };
    139 
    140 /**
    141 * Create a type
    142 * @return {WebGLObject}
    143 */
    144 glsLifetimeTests.Type.prototype.gen = function() { throw new Error('Virtual function'); };
    145 
    146 /**
    147 * Destroy a type
    148 * @param {WebGLObject} obj
    149 */
    150 glsLifetimeTests.Type.prototype.release = function(obj) { throw new Error('Virtual function'); };
    151 
    152 /**
    153 * Is object valid
    154 * @param {WebGLObject} obj
    155 */
    156 glsLifetimeTests.Type.prototype.exists = function(obj) { throw new Error('Virtual function'); };
    157 
    158 /**
    159 * Is object flagged for deletion
    160 * @param {WebGLObject} obj
    161 */
    162 glsLifetimeTests.Type.prototype.isDeleteFlagged = function(obj) { return false; };
    163 
    164 /**
    165 * @return {glsLifetimeTests.Binder}
    166 */
    167 glsLifetimeTests.Type.prototype.binder = function() { return null; };
    168 
    169 /**
    170 * @return {string}
    171 */
    172 glsLifetimeTests.Type.prototype.getName = function() { throw new Error('Virtual function'); };
    173 
    174 /**
    175 * Is the object unbound automatically when it is deleted?
    176 * @return {boolean}
    177 */
    178 glsLifetimeTests.Type.prototype.nameLingers = function() { return false; };
    179 
    180 /**
    181 * Does 'create' creates the object fully?
    182 * If not, the object is created at bound time
    183 * @return {boolean}
    184 */
    185 glsLifetimeTests.Type.prototype.genCreates = function() { return false; };
    186 
    187 /**
    188 * @constructor
    189 * @extends {glsLifetimeTests.Type}
    190 * @param {string} name
    191 * @param {function(): WebGLObject} genFunc
    192 * @param {function(?)} deleteFunc
    193 * @param {function(?): boolean} existsFunc
    194 * @param {glsLifetimeTests.Binder} binder
    195 * @param {boolean=} genCreates
    196 */
    197 glsLifetimeTests.SimpleType = function(name, genFunc, deleteFunc, existsFunc, binder, genCreates) {
    198    glsLifetimeTests.Type.call(this);
    199    this.m_getName = name;
    200    this.m_genFunc = genFunc;
    201    this.m_deleteFunc = deleteFunc;
    202    this.m_existsFunc = existsFunc;
    203    this.m_binder = binder;
    204    this.m_genCreates = genCreates || false;
    205 };
    206 
    207 setParentClass(glsLifetimeTests.SimpleType, glsLifetimeTests.Type);
    208 
    209 glsLifetimeTests.SimpleType.prototype.gen = function() { return this.m_genFunc.call(gl); };
    210 
    211 glsLifetimeTests.SimpleType.prototype.release = function(obj) { return this.m_deleteFunc.call(gl, obj); };
    212 
    213 glsLifetimeTests.SimpleType.prototype.exists = function(obj) { return this.m_existsFunc.call(gl, obj); };
    214 
    215 glsLifetimeTests.SimpleType.prototype.binder = function() { return this.m_binder; };
    216 
    217 glsLifetimeTests.SimpleType.prototype.getName = function() { return this.m_getName; };
    218 
    219 glsLifetimeTests.SimpleType.prototype.genCreates = function() { return this.m_genCreates; };
    220 
    221 /**
    222 * @constructor
    223 * @extends {glsLifetimeTests.Type}
    224 */
    225 glsLifetimeTests.ProgramType = function() {
    226    glsLifetimeTests.Type.call(this);
    227 };
    228 
    229 setParentClass(glsLifetimeTests.ProgramType, glsLifetimeTests.Type);
    230 
    231 glsLifetimeTests.ProgramType.prototype.gen = function() { return gl.createProgram(); };
    232 
    233 glsLifetimeTests.ProgramType.prototype.release = function(obj) { return gl.deleteProgram(/** @type {WebGLProgram} */ (obj)); };
    234 
    235 glsLifetimeTests.ProgramType.prototype.exists = function(obj) { return gl.isProgram(/** @type {WebGLProgram} */ (obj)); };
    236 
    237 glsLifetimeTests.ProgramType.prototype.getName = function() { return 'program'; };
    238 
    239 glsLifetimeTests.ProgramType.prototype.genCreates = function() { return true; };
    240 
    241 glsLifetimeTests.ProgramType.prototype.nameLingers = function() { return true; };
    242 
    243 glsLifetimeTests.ProgramType.prototype.isDeleteFlagged = function(obj) { return gl.getProgramParameter(/** @type {WebGLProgram} */ (obj), gl.DELETE_STATUS); };
    244 
    245 /**
    246 * @constructor
    247 * @extends {glsLifetimeTests.Type}
    248 */
    249 glsLifetimeTests.ShaderType = function() {
    250    glsLifetimeTests.Type.call(this);
    251 };
    252 
    253 setParentClass(glsLifetimeTests.ShaderType, glsLifetimeTests.Type);
    254 
    255 glsLifetimeTests.ShaderType.prototype.gen = function() { return gl.createShader(gl.FRAGMENT_SHADER); };
    256 
    257 glsLifetimeTests.ShaderType.prototype.release = function(obj) { return gl.deleteShader(/** @type {WebGLShader} */ (obj)); };
    258 
    259 glsLifetimeTests.ShaderType.prototype.exists = function(obj) { return gl.isShader(/** @type {WebGLShader} */ (obj)); };
    260 
    261 glsLifetimeTests.ShaderType.prototype.getName = function() { return 'shader'; };
    262 
    263 glsLifetimeTests.ShaderType.prototype.genCreates = function() { return true; };
    264 
    265 glsLifetimeTests.ShaderType.prototype.nameLingers = function() { return true; };
    266 
    267 glsLifetimeTests.ShaderType.prototype.isDeleteFlagged = function(obj) { return gl.getShaderParameter(/** @type {WebGLShader} */ (obj), gl.DELETE_STATUS); };
    268 
    269 /**
    270 * @constructor
    271 * @param {glsLifetimeTests.Type} elementType
    272 * @param {glsLifetimeTests.Type} containerType
    273 */
    274 glsLifetimeTests.Attacher = function(elementType, containerType) {
    275    this.m_elementType = elementType;
    276    this.m_containerType = containerType;
    277 };
    278 
    279 /**
    280 * @param {number} seed
    281 * @param {WebGLObject} obj
    282 */
    283 glsLifetimeTests.Attacher.prototype.initAttachment = function(seed, obj) { throw new Error('Virtual function'); };
    284 
    285 /**
    286 * @param {WebGLObject} element
    287 * @param {WebGLObject} target
    288 */
    289 glsLifetimeTests.Attacher.prototype.attach = function(element, target) { throw new Error('Virtual function'); };
    290 
    291 /**
    292 * @param {WebGLObject} element
    293 * @param {WebGLObject} target
    294 */
    295 glsLifetimeTests.Attacher.prototype.detach = function(element, target) { throw new Error('Virtual function'); };
    296 glsLifetimeTests.Attacher.prototype.canAttachDeleted = function() { return true; };
    297 
    298 /**
    299 * @return {glsLifetimeTests.Type}
    300 */
    301 glsLifetimeTests.Attacher.prototype.getElementType = function() { return this.m_elementType; };
    302 
    303 /**
    304 * @return {glsLifetimeTests.Type}
    305 */
    306 glsLifetimeTests.Attacher.prototype.getContainerType = function() { return this.m_containerType; };
    307 
    308 /**
    309 * @constructor
    310 */
    311 glsLifetimeTests.InputAttacher = function(attacher) {
    312    this.m_attacher = attacher;
    313 };
    314 
    315 glsLifetimeTests.InputAttacher.prototype.getAttacher = function() { return this.m_attacher; };
    316 
    317 /**
    318 * @param {WebGLObject} container
    319 * @param {tcuSurface.Surface} dst
    320 */
    321 glsLifetimeTests.InputAttacher.prototype.drawContainer = function(container, dst) { throw new Error('Virtual function'); };
    322 
    323 /**
    324 * @constructor
    325 */
    326 glsLifetimeTests.OutputAttacher = function(attacher) {
    327    this.m_attacher = attacher;
    328 };
    329 
    330 glsLifetimeTests.OutputAttacher.prototype.getAttacher = function() { return this.m_attacher; };
    331 
    332 /**
    333 * @param {number} seed
    334 * @param {WebGLObject} container
    335 */
    336 glsLifetimeTests.OutputAttacher.prototype.setupContainer = function(seed, container) { throw new Error('Virtual function'); };
    337 
    338 /**
    339 * @param {WebGLObject} attachment
    340 * @param {tcuSurface.Surface} dst
    341 */
    342 glsLifetimeTests.OutputAttacher.prototype.drawAttachment = function(attachment, dst) { throw new Error('Virtual function'); };
    343 
    344 /**
    345 * @constructor
    346 */
    347 glsLifetimeTests.Types = function() {
    348    /** @type {Array<glsLifetimeTests.Type>} */ this.m_types = [];
    349    /** @type {Array<glsLifetimeTests.Attacher>} */ this.m_attachers = [];
    350    /** @type {Array<glsLifetimeTests.InputAttacher>} */ this.m_inAttachers = [];
    351    /** @type {Array<glsLifetimeTests.OutputAttacher>} */ this.m_outAttachers = [];
    352 };
    353 
    354 /**
    355 * @return {glsLifetimeTests.ProgramType}
    356 */
    357 glsLifetimeTests.Types.prototype.getProgramType = function() { throw new Error('Virtual function'); };
    358 
    359 glsLifetimeTests.Types.prototype.getTypes = function() { return this.m_types; };
    360 
    361 glsLifetimeTests.Types.prototype.getAttachers = function() { return this.m_attachers; };
    362 
    363 glsLifetimeTests.Types.prototype.getInputAttachers = function() { return this.m_inAttachers; };
    364 
    365 glsLifetimeTests.Types.prototype.getOutputAttachers = function() { return this.m_outAttachers; };
    366 
    367 /**
    368 * @param {number} seed
    369 * @param {WebGLFramebuffer} fbo
    370 */
    371 glsLifetimeTests.setupFbo = function(seed, fbo) {
    372    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    373 
    374    if (seed == 0) {
    375        gl.clearColor(0.0, 0.0, 0.0, 1.0);
    376        gl.clear(gl.COLOR_BUFFER_BIT);
    377    } else {
    378        var rnd = new deRandom.Random(seed);
    379        var width = rnd.getInt(0, FRAMEBUFFER_SIZE);
    380        var height = rnd.getInt(0, FRAMEBUFFER_SIZE);
    381        var x = rnd.getInt(0, FRAMEBUFFER_SIZE - width);
    382        var y = rnd.getInt(0, FRAMEBUFFER_SIZE - height);
    383        var r1 = rnd.getFloat();
    384        var g1 = rnd.getFloat();
    385        var b1 = rnd.getFloat();
    386        var a1 = rnd.getFloat();
    387        var r2 = rnd.getFloat();
    388        var g2 = rnd.getFloat();
    389        var b2 = rnd.getFloat();
    390        var a2 = rnd.getFloat();
    391 
    392        gl.clearColor(r1, g1, b1, a1);
    393        gl.clear(gl.COLOR_BUFFER_BIT);
    394        gl.scissor(x, y, width, height);
    395        gl.enable(gl.SCISSOR_TEST);
    396        gl.clearColor(r2, g2, b2, a2);
    397        gl.clear(gl.COLOR_BUFFER_BIT);
    398        gl.disable(gl.SCISSOR_TEST);
    399    }
    400 
    401    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    402 };
    403 
    404 /**
    405 * @param {{x: number, y:number, width: number, height: number}} rect
    406 * @param {tcuSurface.Surface} dst
    407 */
    408 glsLifetimeTests.readRectangle = function(rect, dst) {
    409    dst.readViewport(gl, rect);
    410 };
    411 
    412 /**
    413 * @param {WebGLFramebuffer} fbo
    414 * @param {tcuSurface.Surface} dst
    415 */
    416 glsLifetimeTests.drawFbo = function(fbo, dst) {
    417    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    418    dst.readViewport(gl, [0, 0, FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE]);
    419    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    420 };
    421 
    422 /**
    423 * @constructor
    424 * @extends {glsLifetimeTests.Attacher}
    425 */
    426 glsLifetimeTests.FboAttacher = function(elementType, containerType) {
    427    glsLifetimeTests.Attacher.call(this, elementType, containerType);
    428 };
    429 
    430 setParentClass(glsLifetimeTests.FboAttacher, glsLifetimeTests.Attacher);
    431 
    432 glsLifetimeTests.FboAttacher.prototype.initStorage = function() { throw new Error('Virtual function'); };
    433 
    434 glsLifetimeTests.FboAttacher.prototype.initAttachment = function(seed, element) {
    435    var binder = this.getElementType().binder();
    436    var fbo = gl.createFramebuffer();
    437 
    438    binder.bind(element);
    439    this.initStorage();
    440    binder.bind(null);
    441 
    442    this.attach(element, fbo);
    443    glsLifetimeTests.setupFbo(seed, fbo);
    444    this.detach(element, fbo);
    445 
    446    gl.deleteFramebuffer(fbo);
    447 
    448    bufferedLogToConsole('Drew to ' + this.getElementType().getName() + ' ' + element + ' with seed ' + seed + '.');
    449 };
    450 
    451 /**
    452 * @constructor
    453 * @extends {glsLifetimeTests.InputAttacher}
    454 */
    455 glsLifetimeTests.FboInputAttacher = function(attacher) {
    456    glsLifetimeTests.InputAttacher.call(this, attacher);
    457 };
    458 
    459 setParentClass(glsLifetimeTests.FboInputAttacher, glsLifetimeTests.InputAttacher);
    460 
    461 glsLifetimeTests.FboInputAttacher.prototype.drawContainer = function(obj, dst) {
    462    var fbo = /** @type {WebGLFramebuffer} */ (obj);
    463    glsLifetimeTests.drawFbo(fbo, dst);
    464    bufferedLogToConsole('Read pixels from framebuffer ' + fbo + ' to output image.');
    465 };
    466 
    467 /**
    468 * @constructor
    469 * @extends {glsLifetimeTests.OutputAttacher}
    470 */
    471 glsLifetimeTests.FboOutputAttacher = function(attacher) {
    472    glsLifetimeTests.OutputAttacher.call(this, attacher);
    473 };
    474 
    475 setParentClass(glsLifetimeTests.FboOutputAttacher, glsLifetimeTests.OutputAttacher);
    476 
    477 glsLifetimeTests.FboOutputAttacher.prototype.setupContainer = function(seed, fbo) {
    478    glsLifetimeTests.setupFbo(seed, /** @type {WebGLFramebuffer} */ (fbo));
    479   bufferedLogToConsole('Drew to framebuffer ' + fbo + ' with seed ' + seed + '.');
    480 };
    481 
    482 glsLifetimeTests.FboOutputAttacher.prototype.drawAttachment = function(element, dst) {
    483    var fbo = gl.createFramebuffer();
    484    this.m_attacher.attach(element, fbo);
    485    glsLifetimeTests.drawFbo(fbo, dst);
    486    this.m_attacher.detach(element, fbo);
    487    gl.deleteFramebuffer(fbo);
    488    bufferedLogToConsole('Read pixels from ' + this.m_attacher.getElementType().getName() + ' ' + element + ' to output image.');
    489 };
    490 
    491 /**
    492 * @constructor
    493 * @extends {glsLifetimeTests.FboAttacher}
    494 */
    495 glsLifetimeTests.TextureFboAttacher = function(elementType, containerType) {
    496    glsLifetimeTests.FboAttacher.call(this, elementType, containerType);
    497 };
    498 
    499 setParentClass(glsLifetimeTests.TextureFboAttacher, glsLifetimeTests.FboAttacher);
    500 
    501 glsLifetimeTests.TextureFboAttacher.prototype.initStorage = function() {
    502    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE, 0,
    503                     gl.RGBA, gl.UNSIGNED_SHORT_4_4_4_4, null);
    504 
    505 };
    506 
    507 glsLifetimeTests.TextureFboAttacher.prototype.attach = function(element, target) {
    508    var texture = /** @type {WebGLTexture} */ (element);
    509    var fbo = /** @type {WebGLFramebuffer} */ (target);
    510    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    511    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
    512                              gl.TEXTURE_2D, texture, 0);
    513    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    514 };
    515 
    516 glsLifetimeTests.TextureFboAttacher.prototype.detach = function(texture, target) {
    517    var fbo = /** @type {WebGLFramebuffer} */ (target);
    518    this.attach(null, fbo);
    519 };
    520 
    521 glsLifetimeTests.getFboAttachment = function(fbo, requiredType) {
    522    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    523    var type = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
    524                                               gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
    525    var name = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
    526                                               gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
    527    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    528 
    529    var ret = type == requiredType ? name : null;
    530    return ret;
    531 };
    532 
    533 glsLifetimeTests.TextureFboAttacher.prototype.getAttachment = function(fbo) {
    534    return glsLifetimeTests.getFboAttachment(fbo, gl.TEXTURE);
    535 };
    536 
    537 /**
    538 * @constructor
    539 * @extends {glsLifetimeTests.FboAttacher}
    540 */
    541 glsLifetimeTests.RboFboAttacher = function(elementType, containerType) {
    542    glsLifetimeTests.FboAttacher.call(this, elementType, containerType);
    543 };
    544 
    545 setParentClass(glsLifetimeTests.RboFboAttacher, glsLifetimeTests.FboAttacher);
    546 
    547 glsLifetimeTests.RboFboAttacher.prototype.initStorage = function() {
    548    gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE);
    549 
    550 };
    551 
    552 glsLifetimeTests.RboFboAttacher.prototype.attach = function(element, target) {
    553    var rbo = /** @type {WebGLRenderbuffer} */ (element);
    554    var fbo = /** @type {WebGLFramebuffer} */ (target);
    555    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    556    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
    557    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    558 };
    559 
    560 glsLifetimeTests.RboFboAttacher.prototype.detach = function(rbo, target) {
    561    var fbo = /** @type {WebGLFramebuffer} */ (target);
    562    this.attach(null, fbo);
    563 };
    564 
    565 glsLifetimeTests.RboFboAttacher.prototype.getAttachment = function(fbo) {
    566    return glsLifetimeTests.getFboAttachment(fbo, gl.RENDERBUFFER);
    567 };
    568 
    569 /**
    570 * @constructor
    571 * @extends {glsLifetimeTests.Attacher}
    572 */
    573 glsLifetimeTests.ShaderProgramAttacher = function(elementType, containerType) {
    574    glsLifetimeTests.Attacher.call(this, elementType, containerType);
    575 };
    576 
    577 setParentClass(glsLifetimeTests.ShaderProgramAttacher, glsLifetimeTests.Attacher);
    578 
    579 glsLifetimeTests.ShaderProgramAttacher.prototype.initAttachment = function(seed, obj) {
    580    var shader = /** @type {WebGLShader} */ (obj);
    581    var s_fragmentShaderTemplate =
    582    '#version 100\n' +
    583    'void main()\n' +
    584    '{\n' +
    585    ' gl_FragColor = vec4(${RED}, ${GREEN}, ${BLUE}, 1.0);\n' +
    586    '}';
    587 
    588    var rnd = new deRandom.Random(seed);
    589    var params = [];
    590    params['RED'] = rnd.getFloat().toString(10);
    591    params['GREEN'] = rnd.getFloat().toString(10);
    592    params['BLUE'] = rnd.getFloat().toString(10);
    593 
    594    var source = tcuStringTemplate.specialize(s_fragmentShaderTemplate, params);
    595    gl.shaderSource(shader, source);
    596    gl.compileShader(shader);
    597    var compileStatus = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
    598    assertMsgOptions(compileStatus === true, 'Failed to compile shader: ' + source, false, true);
    599 };
    600 
    601 glsLifetimeTests.ShaderProgramAttacher.prototype.attach = function(element, target) {
    602    var shader = /** @type {WebGLShader} */ (element);
    603    var program = /** @type {WebGLProgram} */ (target);
    604    gl.attachShader(program, shader);
    605 };
    606 
    607 glsLifetimeTests.ShaderProgramAttacher.prototype.detach = function(element, target) {
    608    var shader = /** @type {WebGLShader} */ (element);
    609    var program = /** @type {WebGLProgram} */ (target);
    610    gl.detachShader(program, shader);
    611 };
    612 
    613 glsLifetimeTests.ShaderProgramAttacher.prototype.getAttachment = function(program) {
    614    var shaders = gl.getAttachedShaders(program);
    615    for (var i = 0; i < shaders.length; i++) {
    616        var shader = shaders[i];
    617        var type = gl.getShaderParameter(shader, gl.SHADER_TYPE);
    618        if (type === gl.FRAGMENT_SHADER)
    619            return shader;
    620    }
    621    return null;
    622 };
    623 
    624 /**
    625 * @constructor
    626 * @extends {glsLifetimeTests.InputAttacher}
    627 */
    628 glsLifetimeTests.ShaderProgramInputAttacher = function(attacher) {
    629    glsLifetimeTests.InputAttacher.call(this, attacher);
    630 };
    631 
    632 setParentClass(glsLifetimeTests.ShaderProgramInputAttacher, glsLifetimeTests.InputAttacher);
    633 
    634 glsLifetimeTests.ShaderProgramInputAttacher.prototype.drawContainer = function(container, dst) {
    635    var program = /** @type {WebGLProgram} */ (container);
    636    var s_vertices = [-1.0, 0.0, 1.0, 1.0, 0.0, -1.0];
    637    glsLifetimeTests.ShaderProgramInputAttacher.seed = glsLifetimeTests.ShaderProgramInputAttacher.seed || 0;
    638    var vtxShader = new glsLifetimeTests.CheckedShader(gluShaderProgram.shaderType.VERTEX, s_vertexShaderSrc);
    639    var viewport = new glsTextureTestUtil.RandomViewport(document.getElementById('canvas'), VIEWPORT_SIZE, VIEWPORT_SIZE, glsLifetimeTests.ShaderProgramInputAttacher.seed);
    640 
    641    gl.attachShader(program, vtxShader.getShader());
    642    gl.linkProgram(program);
    643 
    644    var linkStatus = gl.getProgramParameter(program, gl.LINK_STATUS);
    645    assertMsgOptions(linkStatus === true, 'Program link failed', false, true);
    646 
    647    bufferedLogToConsole('Attached a temporary vertex shader and linked program ' + program);
    648 
    649    gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
    650 
    651    bufferedLogToConsole('Positioned viewport randomly');
    652 
    653    gl.useProgram(program);
    654 
    655    var posLoc = gl.getAttribLocation(program, 'pos');
    656    assertMsgOptions(posLoc >= 0, 'Could not find pos attribute', false, true);
    657 
    658    var buf = gl.createBuffer();
    659    gl.bindBuffer(gl.ARRAY_BUFFER, buf);
    660    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(s_vertices), gl.STATIC_DRAW);
    661    gl.enableVertexAttribArray(posLoc);
    662    gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);
    663    gl.bindBuffer(gl.ARRAY_BUFFER, null);
    664 
    665    gl.clearColor(0, 0, 0, 1);
    666    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    667    gl.drawArrays(gl.TRIANGLES, 0, 3);
    668 
    669    gl.disableVertexAttribArray(posLoc);
    670    gl.deleteBuffer(buf);
    671    bufferedLogToConsole('Drew a fixed triangle');
    672 
    673    gl.useProgram(null);
    674 
    675    glsLifetimeTests.readRectangle(viewport, dst);
    676    bufferedLogToConsole('Copied viewport to output image');
    677 
    678    gl.detachShader(program, vtxShader.getShader());
    679    bufferedLogToConsole('Removed temporary vertex shader');
    680 };
    681 
    682 /**
    683 * @constructor
    684 * @extends {glsLifetimeTests.Types}
    685 */
    686 glsLifetimeTests.ES2Types = function() {
    687    glsLifetimeTests.Types.call(this);
    688    this.m_bufferBind = new glsLifetimeTests.SimpleBinder(gl.bindBuffer, gl.ARRAY_BUFFER, gl.ARRAY_BUFFER_BINDING);
    689    this.m_bufferType = new glsLifetimeTests.SimpleType('buffer', gl.createBuffer, gl.deleteBuffer, gl.isBuffer, this.m_bufferBind);
    690    this.m_textureBind = new glsLifetimeTests.SimpleBinder(gl.bindTexture, gl.TEXTURE_2D, gl.TEXTURE_BINDING_2D);
    691    this.m_textureType = new glsLifetimeTests.SimpleType('texture', gl.createTexture, gl.deleteTexture, gl.isTexture, this.m_textureBind);
    692    this.m_rboBind = new glsLifetimeTests.SimpleBinder(gl.bindRenderbuffer, gl.RENDERBUFFER, gl.RENDERBUFFER_BINDING);
    693    this.m_rboType = new glsLifetimeTests.SimpleType('renderbuffer', gl.createRenderbuffer, gl.deleteRenderbuffer, gl.isRenderbuffer, this.m_rboBind);
    694    this.m_fboBind = new glsLifetimeTests.SimpleBinder(gl.bindFramebuffer, gl.FRAMEBUFFER, gl.FRAMEBUFFER_BINDING);
    695    this.m_fboType = new glsLifetimeTests.SimpleType('framebuffer', gl.createFramebuffer, gl.deleteFramebuffer, gl.isFramebuffer, this.m_fboBind);
    696    this.m_shaderType = new glsLifetimeTests.ShaderType();
    697    this.m_programType = new glsLifetimeTests.ProgramType();
    698    this.m_texFboAtt = new glsLifetimeTests.TextureFboAttacher(this.m_textureType, this.m_fboType);
    699    this.m_texFboInAtt = new glsLifetimeTests.FboInputAttacher(this.m_texFboAtt);
    700    this.m_texFboOutAtt = new glsLifetimeTests.FboOutputAttacher(this.m_texFboAtt);
    701    this.m_rboFboAtt = new glsLifetimeTests.RboFboAttacher(this.m_rboType, this.m_fboType);
    702    this.m_rboFboInAtt = new glsLifetimeTests.FboInputAttacher(this.m_rboFboAtt);
    703    this.m_rboFboOutAtt = new glsLifetimeTests.FboOutputAttacher(this.m_rboFboAtt);
    704    this.m_shaderAtt = new glsLifetimeTests.ShaderProgramAttacher(this.m_shaderType, this.m_programType);
    705    this.m_shaderInAtt = new glsLifetimeTests.ShaderProgramInputAttacher(this.m_shaderAtt);
    706 
    707    this.m_types.push(this.m_bufferType, this.m_textureType, this.m_rboType, this.m_fboType, this.m_shaderType, this.m_programType);
    708    this.m_attachers.push(this.m_texFboAtt, this.m_rboFboAtt, this.m_shaderAtt);
    709    this.m_inAttachers.push(this.m_texFboInAtt, this.m_rboFboInAtt, this.m_shaderInAtt);
    710    this.m_outAttachers.push(this.m_texFboOutAtt, this.m_rboFboOutAtt);
    711 };
    712 
    713 setParentClass(glsLifetimeTests.ES2Types, glsLifetimeTests.Types);
    714 
    715 glsLifetimeTests.ES2Types.prototype.getProgramType = function() { return this.m_programType; };
    716 
    717 /**
    718 * @constructor
    719 * @extends {tcuTestCase.DeqpTest}
    720 * @param {string} name
    721 * @param {string} description
    722 * @param {glsLifetimeTests.Type} type
    723 * @param {function()} test
    724 */
    725 glsLifetimeTests.LifeTest = function(name, description, type, test) {
    726    tcuTestCase.DeqpTest.call(this, name, description);
    727    this.m_type = type;
    728    this.m_test = test;
    729 };
    730 
    731 setParentClass(glsLifetimeTests.LifeTest, tcuTestCase.DeqpTest);
    732 
    733 glsLifetimeTests.LifeTest.prototype.iterate = function() {
    734    this.m_test();
    735    return tcuTestCase.IterateResult.STOP;
    736 };
    737 
    738 /**
    739 * @this {glsLifetimeTests.LifeTest}
    740 */
    741 glsLifetimeTests.LifeTest.testGen = function() {
    742    var obj = this.m_type.gen();
    743    if (this.m_type.genCreates())
    744        assertMsgOptions(this.m_type.exists(obj), "create* should have created an object, but didn't", false, true);
    745    else
    746        assertMsgOptions(!this.m_type.exists(obj), 'create* should not have created an object, but did', false, true);
    747    this.m_type.release(obj);
    748    testPassed();
    749 };
    750 
    751 /**
    752 * @this {glsLifetimeTests.LifeTest}
    753 */
    754 glsLifetimeTests.LifeTest.testDelete = function() {
    755    var obj = this.m_type.gen();
    756    this.m_type.release(obj);
    757    assertMsgOptions(!this.m_type.exists(obj), 'Object still exists after deletion', false, true);
    758    testPassed();
    759 };
    760 
    761 /**
    762 * @this {glsLifetimeTests.LifeTest}
    763 */
    764 glsLifetimeTests.LifeTest.testBind = function() {
    765    var obj = this.m_type.gen();
    766    this.m_type.binder().bind(obj);
    767    var err = gl.getError();
    768    assertMsgOptions(err == gl.NONE, 'Bind failed', false, true);
    769    assertMsgOptions(this.m_type.exists(obj), 'Object does not exist after binding', false, true);
    770    this.m_type.binder().bind(null);
    771    this.m_type.release(obj);
    772    testPassed();
    773 };
    774 
    775 /**
    776 * @this {glsLifetimeTests.LifeTest}
    777 */
    778 glsLifetimeTests.LifeTest.testDeleteBound = function() {
    779    var obj = this.m_type.gen();
    780    this.m_type.binder().bind(obj);
    781    this.m_type.release(obj);
    782    if (this.m_type.nameLingers()) {
    783        assertMsgOptions(gl.getError() == gl.NONE, 'Deleting bound object failed', false, true);
    784        assertMsgOptions(this.m_type.binder().getBinding() === obj, 'Deleting bound object did not retain binding', false, true);
    785        assertMsgOptions(this.m_type.exists(obj), 'Deleting bound object made its name invalid', false, true);
    786        assertMsgOptions(this.m_type.isDeleteFlagged(obj), 'Deleting bound object did not flag the object for deletion', false, true);
    787        this.m_type.binder().bind(null);
    788    } else {
    789        assertMsgOptions(gl.getError() == gl.NONE, 'Deleting bound object failed', false, true);
    790        assertMsgOptions(this.m_type.binder().getBinding() === null, 'Deleting bound object did not remove binding', false, true);
    791        assertMsgOptions(!this.m_type.exists(obj), 'Deleting bound object did not make its name invalid', false, true);
    792    }
    793    assertMsgOptions(this.m_type.binder().getBinding() === null, "Unbinding didn't remove binding", false, true);
    794    assertMsgOptions(!this.m_type.exists(obj), 'Name is still valid after deleting and unbinding', false, true);
    795    testPassed();
    796 };
    797 
    798 /**
    799 * @this {glsLifetimeTests.LifeTest}
    800 */
    801 glsLifetimeTests.LifeTest.testDeleteUsed = function() {
    802    var vtxShader = new glsLifetimeTests.CheckedShader(gluShaderProgram.shaderType.VERTEX, s_vertexShaderSrc);
    803    var fragShader = new glsLifetimeTests.CheckedShader(gluShaderProgram.shaderType.FRAGMENT, s_fragmentShaderSrc);
    804    var program = new glsLifetimeTests.CheckedProgram(vtxShader.getShader(), fragShader.getShader());
    805    var programId = program.getProgram();
    806    bufferedLogToConsole('Created and linked program ' + programId);
    807    gl.useProgram(programId);
    808 
    809    gl.deleteProgram(programId);
    810    bufferedLogToConsole('Deleted program ' + programId);
    811    assertMsgOptions(gl.isProgram(programId), 'Deleted current program', false, true);
    812    var deleteFlagged = gl.getProgramParameter(programId, gl.DELETE_STATUS);
    813    assertMsgOptions(deleteFlagged == true, 'Program object was not flagged as deleted', false, true);
    814    gl.useProgram(null);
    815    assertMsgOptions(!gl.isProgram(programId), 'Deleted program name still valid after being made non-current', false, true);
    816    testPassed();
    817 };
    818 
    819 /**
    820 * @constructor
    821 * @extends {tcuTestCase.DeqpTest}
    822 * @param {string} name
    823 * @param {string} description
    824 * @param {glsLifetimeTests.Attacher} attacher
    825 * @param {function()} test
    826 */
    827 glsLifetimeTests.AttachmentTest = function(name, description, attacher, test) {
    828    tcuTestCase.DeqpTest.call(this, name, description);
    829    this.m_attacher = attacher;
    830    this.m_test = test;
    831 };
    832 
    833 setParentClass(glsLifetimeTests.AttachmentTest, tcuTestCase.DeqpTest);
    834 
    835 glsLifetimeTests.AttachmentTest.prototype.iterate = function() {
    836    this.m_test();
    837    return tcuTestCase.IterateResult.STOP;
    838 };
    839 
    840 /**
    841 * @this {glsLifetimeTests.AttachmentTest}
    842 */
    843 glsLifetimeTests.AttachmentTest.testDeletedNames = function() {
    844    var getAttachment = function(attacher, container) {
    845        var queriedAttachment = attacher.getAttachment(container);
    846        bufferedLogToConsole('Result of query for ' + attacher.getElementType().getName() +
    847                       ' attached to ' + attacher.getContainerType().getName() + ' ' +
    848                       container + ': ' + queriedAttachment);
    849        return queriedAttachment;
    850    };
    851 
    852    var elemType = this.m_attacher.getElementType();
    853    var containerType = this.m_attacher.getContainerType();
    854    var container = containerType.gen();
    855 
    856    var element = elemType.gen();
    857    this.m_attacher.initAttachment(0, element);
    858    this.m_attacher.attach(element, container);
    859    assertMsgOptions(getAttachment(this.m_attacher, container) == element,
    860                 'Attachment not returned by query even before deletion.', false, true);
    861 
    862    elemType.release(element);
    863    // "Such a container or other context may continue using the object, and
    864    // may still contain state identifying its name as being currently bound"
    865    //
    866    // We here interpret "may" to mean that whenever the container has a
    867    // deleted object attached to it, a query will return that object's former
    868    // name.
    869    assertMsgOptions(getAttachment(this.m_attacher, container) == element,
    870                 'Attachment name not returned by query after attachment was deleted.', false, true);
    871 
    872    if (elemType.nameLingers())
    873        assertMsgOptions(elemType.exists(element),
    874                     'Attached object name no longer valid after deletion.', false, true);
    875    else
    876        assertMsgOptions(!elemType.exists(element),
    877                     'Attached object name still valid after deletion.', false, true);
    878 
    879    this.m_attacher.detach(element, container);
    880    assertMsgOptions(getAttachment(this.m_attacher, container) == null,
    881                 'Attachment name returned by query even after detachment.', false, true);
    882    assertMsgOptions(!elemType.exists(element),
    883                 'Deleted attached object name still usable after detachment.', false, true);
    884    testPassed();
    885 };
    886 
    887 /**
    888 * @constructor
    889 * @extends {tcuTestCase.DeqpTest}
    890 * @param {string} name
    891 * @param {string} description
    892 * @param {glsLifetimeTests.InputAttacher} attacher
    893 */
    894 glsLifetimeTests.InputAttachmentTest = function(name, description, attacher) {
    895    tcuTestCase.DeqpTest.call(this, name, description);
    896    this.m_inputAttacher = attacher;
    897 };
    898 
    899 setParentClass(glsLifetimeTests.InputAttachmentTest, tcuTestCase.DeqpTest);
    900 
    901 glsLifetimeTests.InputAttachmentTest.prototype.iterate = function() {
    902    var attacher = this.m_inputAttacher.getAttacher();
    903    var containerType = attacher.getContainerType();
    904    var elementType = attacher.getElementType();
    905    var container = containerType.gen();
    906 
    907    glsLifetimeTests.InputAttachmentTest.seed = glsLifetimeTests.InputAttachmentTest.seed || 0;
    908    ++glsLifetimeTests.InputAttachmentTest.seed;
    909    var rnd = new deRandom.Random(glsLifetimeTests.InputAttachmentTest.seed);
    910    var refSeed = rnd.getInt();
    911    var newSeed = rnd.getInt();
    912 
    913    var refSurface = new tcuSurface.Surface(VIEWPORT_SIZE, VIEWPORT_SIZE); // Surface from drawing with refSeed-seeded attachment
    914    var delSurface = new tcuSurface.Surface(VIEWPORT_SIZE, VIEWPORT_SIZE); // Surface from drawing with deleted refSeed attachment
    915    var newSurface = new tcuSurface.Surface(VIEWPORT_SIZE, VIEWPORT_SIZE); // Surface from drawing with newSeed-seeded attachment
    916 
    917    bufferedLogToConsole('Testing if writing to a newly created object modifies a deleted attachment');
    918 
    919    bufferedLogToConsole('Writing to an original attachment');
    920    var element = elementType.gen();
    921 
    922    attacher.initAttachment(refSeed, element);
    923    attacher.attach(element, container);
    924    this.m_inputAttacher.drawContainer(container, refSurface);
    925    // element gets deleted here
    926    bufferedLogToConsole('Deleting attachment');
    927    elementType.release(element);
    928 
    929    bufferedLogToConsole('Writing to a new attachment after deleting the original');
    930    var newElement = elementType.gen();
    931 
    932    attacher.initAttachment(newSeed, newElement);
    933 
    934    this.m_inputAttacher.drawContainer(container, delSurface);
    935    attacher.detach(element, container);
    936 
    937    attacher.attach(newElement, container);
    938    this.m_inputAttacher.drawContainer(container, newSurface);
    939    attacher.detach(newElement, container);
    940    var surfacesMatch = tcuImageCompare.pixelThresholdCompare(
    941        'Reading from deleted',
    942        'Comparison result from reading from a container with a deleted attachment ' +
    943        'before and after writing to a fresh object.',
    944        refSurface, delSurface, [0, 0, 0, 0]);
    945 
    946    /* TODO: Add logging images */
    947    // if (!surfacesMatch)
    948    //     log() << TestLog::Image("New attachment",
    949    //                             "Container state after attached to the fresh object",
    950    //                             newSurface);
    951 
    952    assertMsgOptions(surfacesMatch,
    953        'Writing to a fresh object modified the container with a deleted attachment.', false, true);
    954 
    955    testPassed();
    956    return tcuTestCase.IterateResult.STOP;
    957 };
    958 
    959 /**
    960 * @constructor
    961 * @extends {tcuTestCase.DeqpTest}
    962 * @param {string} name
    963 * @param {string} description
    964 * @param {glsLifetimeTests.OutputAttacher} attacher
    965 */
    966 glsLifetimeTests.OutputAttachmentTest = function(name, description, attacher) {
    967    tcuTestCase.DeqpTest.call(this, name, description);
    968    this.m_outputAttacher = attacher;
    969 };
    970 
    971 setParentClass(glsLifetimeTests.OutputAttachmentTest, tcuTestCase.DeqpTest);
    972 
    973 glsLifetimeTests.OutputAttachmentTest.prototype.iterate = function() {
    974    var attacher = this.m_outputAttacher.getAttacher();
    975    var containerType = attacher.getContainerType();
    976    var elementType = attacher.getElementType();
    977    var container = containerType.gen();
    978    glsLifetimeTests.InputAttachmentTest.seed = glsLifetimeTests.InputAttachmentTest.seed || 0;
    979    ++glsLifetimeTests.InputAttachmentTest.seed;
    980    var rnd = new deRandom.Random(glsLifetimeTests.InputAttachmentTest.seed);
    981    var refSeed = rnd.getInt();
    982    var newSeed = rnd.getInt();
    983 
    984    var refSurface = new tcuSurface.Surface(VIEWPORT_SIZE, VIEWPORT_SIZE); // Surface from drawing with refSeed-seeded attachment
    985    var delSurface = new tcuSurface.Surface(VIEWPORT_SIZE, VIEWPORT_SIZE); // Surface from drawing with deleted refSeed attachment
    986    var newSurface = new tcuSurface.Surface(VIEWPORT_SIZE, VIEWPORT_SIZE); // Surface from drawing with newSeed-seeded attachment
    987 
    988    bufferedLogToConsole('Testing if writing to a container with a deleted attachment ' +
    989          'modifies a newly created object');
    990 
    991    bufferedLogToConsole('Writing to a container with an existing attachment');
    992    var element = elementType.gen();
    993 
    994    attacher.initAttachment(0, element);
    995    attacher.attach(element, container);
    996 
    997    // For reference purposes, make note of what refSeed looks like.
    998    this.m_outputAttacher.setupContainer(refSeed, container);
    999    // Since in WebGL, buffer bound to TRANSFORM_FEEDBACK_BUFFER can not be bound to other targets.
   1000    // Unfortunately, element will be bound again in drawAttachment() for drawing.
   1001    // Detach element from container before drawing, then reattach it after drawing.
   1002    attacher.detach(element, container);
   1003    this.m_outputAttacher.drawAttachment(element, refSurface);
   1004    attacher.attach(element, container);
   1005    elementType.release(element);
   1006 
   1007    bufferedLogToConsole('Writing to a container after deletion of attachment');
   1008    var newElement = elementType.gen();
   1009    bufferedLogToConsole('Creating a new object ');
   1010 
   1011    bufferedLogToConsole('Recording state of new object before writing to container');
   1012    attacher.initAttachment(newSeed, newElement);
   1013    this.m_outputAttacher.drawAttachment(newElement, newSurface);
   1014 
   1015    bufferedLogToConsole('Writing to container');
   1016 
   1017    // Now re-write refSeed to the container.
   1018    this.m_outputAttacher.setupContainer(refSeed, container);
   1019    // Does it affect the newly created attachment object?
   1020    this.m_outputAttacher.drawAttachment(newElement, delSurface);
   1021    attacher.detach(element, container);
   1022 
   1023    var surfacesMatch = tcuImageCompare.pixelThresholdCompare(
   1024        'Writing to deleted',
   1025        'Comparison result from reading from a fresh object before and after ' +
   1026        'writing to a container with a deleted attachment',
   1027        newSurface, delSurface, [0, 0, 0, 0]);
   1028 
   1029    /* TODO: Add logging images */
   1030    // if (!surfacesMatch)
   1031    //     log() << TestLog::Image(
   1032    //         "Original attachment",
   1033    //         "Result of container modification on original attachment before deletion.",
   1034    //         refSurface);
   1035 
   1036    assertMsgOptions(surfacesMatch,
   1037                 'Writing to container with deleted attachment modified a new object.', false, true);
   1038 
   1039    testPassed();
   1040    return tcuTestCase.IterateResult.STOP;
   1041 };
   1042 
   1043 glsLifetimeTests.createLifeTestGroup = function(spec, types) {
   1044    var group = tcuTestCase.newTest(spec.name, spec.name);
   1045 
   1046    for (var i = 0; i < types.length; i++) {
   1047        var type = types[i];
   1048        var name = type.getName();
   1049        if (!spec.needBind || type.binder() != null)
   1050            group.addChild(new glsLifetimeTests.LifeTest(name, name, type, spec.func));
   1051    }
   1052 
   1053    return group;
   1054 };
   1055 
   1056 /**
   1057 * @param {tcuTestCase.DeqpTest} group
   1058 * @param {glsLifetimeTests.Types} types
   1059 */
   1060 glsLifetimeTests.addTestCases = function(group, types) {
   1061    var attacherName = function(attacher) {
   1062        return attacher.getElementType().getName() + '_' + attacher.getContainerType().getName();
   1063    };
   1064 
   1065    var s_lifeTests = [
   1066        /* Create */ { name: 'gen', func: glsLifetimeTests.LifeTest.testGen, needBind: false },
   1067        /* Delete */ { name: 'delete', func: glsLifetimeTests.LifeTest.testDelete, needBind: false },
   1068        /* Bind */ { name: 'bind', func: glsLifetimeTests.LifeTest.testBind, needBind: true },
   1069        /* Delete bound */ { name: 'delete_bound', func: glsLifetimeTests.LifeTest.testDeleteBound, needBind: true }
   1070    ];
   1071 
   1072    s_lifeTests.forEach(function(spec) {
   1073        group.addChild(glsLifetimeTests.createLifeTestGroup(spec, types.getTypes()));
   1074    });
   1075 
   1076    var delUsedGroup = tcuTestCase.newTest('delete_used', 'Delete current program');
   1077    group.addChild(delUsedGroup);
   1078 
   1079    delUsedGroup.addChild(new glsLifetimeTests.LifeTest('program', 'program', types.getProgramType(),
   1080                     glsLifetimeTests.LifeTest.testDeleteUsed));
   1081 
   1082    var attGroup = tcuTestCase.newTest('attach', 'Attachment tests');
   1083    group.addChild(attGroup);
   1084 
   1085    var nameGroup = tcuTestCase.newTest('deleted_name', 'Name of deleted attachment');
   1086    attGroup.addChild(nameGroup);
   1087 
   1088    var atts = types.getAttachers();
   1089    for (var i = 0; i < atts.length; i++) {
   1090        var att = atts[i];
   1091        var name = attacherName(att);
   1092        nameGroup.addChild(new glsLifetimeTests.AttachmentTest(name, name, att,
   1093                                               glsLifetimeTests.AttachmentTest.testDeletedNames));
   1094    }
   1095 
   1096    var inputGroup = tcuTestCase.newTest('deleted_input', 'Input from deleted attachment');
   1097    attGroup.addChild(inputGroup);
   1098 
   1099    var inAtts = types.getInputAttachers();
   1100    for (var i = 0; i < inAtts.length; i++) {
   1101        var att = inAtts[i];
   1102        var name = attacherName(att.getAttacher());
   1103        inputGroup.addChild(new glsLifetimeTests.InputAttachmentTest(name, name, att));
   1104    }
   1105 
   1106    var outputGroup = tcuTestCase.newTest('deleted_output', 'Output to deleted attachment');
   1107    attGroup.addChild(outputGroup);
   1108 
   1109    var outAtts = types.getOutputAttachers();
   1110    for (var i = 0; i < outAtts.length; i++) {
   1111        var att = outAtts[i];
   1112        var name = attacherName(att.getAttacher());
   1113        outputGroup.addChild(new glsLifetimeTests.OutputAttachmentTest(name, name, att));
   1114    }
   1115 
   1116 };
   1117 
   1118 });