Bug 1918529 - fix some subpixel misalignment issues with gfx.webrender.svg-filter...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / deqp / modules / shared / glsFboUtil.js
blob86d05891f2e494a65fafd4f9933932cb5cb463a6
1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
3 * ------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 'use strict';
22 goog.provide('modules.shared.glsFboUtil');
23 goog.require('framework.opengl.gluTextureUtil');
24 goog.require('framework.opengl.gluStrUtil');
26 goog.scope(function() {
28 var glsFboUtil = modules.shared.glsFboUtil;
29 var gluTextureUtil = framework.opengl.gluTextureUtil;
30 var gluStrUtil = framework.opengl.gluStrUtil;
31 var DE_ASSERT = function(x) {
32 if (!x)
33 throw new Error('Assert failed');
36 /**
37 * @constructor
38 * @template KeyT
39 * @template ValueT
40 * @param {function(!KeyT, !KeyT):boolean} comparefnc
42 glsFboUtil.Map = function(comparefnc) {
43 /** @type {Array<{first: !KeyT, second: ValueT}>} */
44 this.store = [];
45 this.compare = comparefnc;
46 this.length = 0;
49 /**
50 * @param {number} num1
51 * @param {number} num2
52 * @return {boolean}
54 glsFboUtil.Map.compareNumber = function(num1, num2) {
55 return num1 < num2;
58 /**
59 * @param {!KeyT} key
60 * @param {ValueT} value
61 * @return {{first: !KeyT, second: ValueT}}
63 glsFboUtil.Map.prototype.pair = function(key, value) {
64 return {
65 first: key,
66 second: value
70 /**
71 * @protected
72 * @param {!KeyT} key
73 * @return {number}
75 glsFboUtil.Map.prototype.findInsertionPoint = function(key) {
76 var /** @type {number} */i, /** @type {number} */length;
77 for (i = 0, length = this.store.length; i < length; ++i) {
78 if (!this.compare(key, this.store[i].first)) break;
80 return i;
83 /**
84 * index should be a value returned from findInsertionPoint.
85 * returns true if the compare function returns false reflexively
86 * (i.e. no matter the order in which the keys are passed as arguments).
87 * @protected
88 * @param {!KeyT} key
89 * @param {number} index
90 * @return {boolean}
92 glsFboUtil.Map.prototype.foundIndexMatches = function(key, index) {
93 return (
94 this.store[index] !== undefined &&
95 !this.compare(this.store[index].first, key)
99 /**
100 * @param {!KeyT} key
101 * @return {boolean}
103 glsFboUtil.Map.prototype.isset = function(key) {
104 return this.foundIndexMatches(key, this.findInsertionPoint(key));
108 * @param {!KeyT} key
109 * @param {ValueT} value
111 glsFboUtil.Map.prototype.set = function(key, value) {
112 var index = this.findInsertionPoint(key);
113 if (this.foundIndexMatches(key, index)) {
114 this.store[index].second = value;
115 } else {
116 this.store.splice(index, 0, this.pair(key, value));
117 ++this.length;
122 * @param {!KeyT} key
123 * @return {?ValueT}
125 glsFboUtil.Map.prototype.remove = function(key) {
126 var index = this.findInsertionPoint(key);
127 /** @type {?ValueT} */ var ret = null;
128 if (this.foundIndexMatches(key, index)) {
129 ret = this.store[index].second;
130 this.store.splice(index, 1);
131 --this.length;
133 return ret;
137 * @param {KeyT} key
138 * @return {?{first: KeyT, second: ValueT}}
140 glsFboUtil.Map.prototype.get = function(key) {
141 var index = this.findInsertionPoint(key);
142 if (this.foundIndexMatches(key, index)) return this.store[index];
143 return null;
147 * @param {KeyT} key
148 * @return {?ValueT}
150 glsFboUtil.Map.prototype.getValue = function(key) {
151 var index = this.findInsertionPoint(key);
152 if (this.foundIndexMatches(key, index)) return this.store[index].second;
153 return null;
157 * @param {!KeyT} key
158 * @param {ValueT} fallback
159 * @return {ValueT}
161 glsFboUtil.Map.prototype.lookupDefault = function(key, fallback) {
162 var index = this.findInsertionPoint(key);
163 if (this.foundIndexMatches(key, index)) return this.store[index].second;
164 return fallback;
168 * @param {number} index
169 * @return {{first: KeyT, second: ValueT}|undefined}
171 glsFboUtil.Map.prototype.getIndex = function(index) {
172 return this.store[index];
176 * Use the callback to set the value to be identified by key.
177 * If a value is already identified by the key, it will be passed to the callback
178 * @param {!KeyT} key
179 * @param {function(ValueT=):!ValueT} callback
181 glsFboUtil.Map.prototype.transform = function(key, callback) {
182 var index = this.findInsertionPoint(key);
183 if (this.foundIndexMatches(key, index)) {
184 this.store[index].second = callback(this.store[index].second);
185 } else {
186 this.store.splice(index, 0, this.pair(key, callback()));
187 ++this.length;
192 * removed all elements from the Map
194 glsFboUtil.Map.prototype.clear = function() {
195 this.store.splice(0, this.length);
196 this.length = 0;
200 * @constructor
202 glsFboUtil.FormatDB = function() {
203 this.m_map = /** @type {glsFboUtil.Map<glsFboUtil.ImageFormat,number>} */(
204 new glsFboUtil.Map(glsFboUtil.ImageFormat.lessthan)
209 * @param {glsFboUtil.ImageFormat} format
210 * @param {number} newFlags
212 glsFboUtil.FormatDB.prototype.addFormat = function(format, newFlags) {
213 this.m_map.transform(format, function(flags) {
214 return flags | newFlags;
219 * @param {number} requirements
220 * @return {Array<glsFboUtil.ImageFormat>}
222 glsFboUtil.FormatDB.prototype.getFormats = function(requirements) {
223 /** @type {Array<glsFboUtil.ImageFormat>} */ var ret = [];
224 for (var i = 0; i < this.m_map.length; ++i) {
225 var pair = this.m_map.getIndex(i);
226 if ((pair.second & requirements) == requirements)
227 ret.push(pair.first);
230 return ret;
234 * @param {glsFboUtil.ImageFormat} format
235 * @param {number} fallback
236 * @return {number}
238 glsFboUtil.FormatDB.prototype.getFormatInfo = function(format, fallback) {
239 return this.m_map.lookupDefault(format, fallback);
243 * @param {Object} map
244 * @param {number} key
245 * @param {number} fallback
246 * @return {number}
248 glsFboUtil.lookupDefault = function(map, key, fallback) {
249 return (map[key] !== undefined) ? map[key] : fallback;
253 * @param {Array<number>} array
254 * @param {number} item
255 * @return {boolean}
257 glsFboUtil.contains = function(array, item) {
258 var l = array.length;
259 for (var i = 0; i < l; ++i)
260 if (array[i] == item) return true;
261 return false;
265 * @typedef {Array<(number | glsFboUtil.Range<number>)>}
267 glsFboUtil.formatT;
270 * @param {glsFboUtil.FormatDB} db
271 * @param {glsFboUtil.Range<glsFboUtil.formatT>} stdFmts
273 glsFboUtil.addFormats = function(db, stdFmts) {
274 for (var set = stdFmts.reset(); set = stdFmts.current(); stdFmts.next()) {
275 for (var fmt = set[1].reset(); fmt = set[1].current(); set[1].next()) {
276 db.addFormat(glsFboUtil.formatKeyInfo(fmt), set[0]);
282 * @param {glsFboUtil.FormatDB} db
283 * @param {glsFboUtil.Range} extFmts
284 * @param {WebGLRenderingContextBase=} gl
285 * @throws {Error}
287 glsFboUtil.addExtFormats = function(db, extFmts, gl) {
288 if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
289 var extensions = gl.getSupportedExtensions();
291 // loop through the range, looking at the extentions.
292 for (var ext = extFmts.reset(); ext = extFmts.current(); extFmts.next()) {
293 var tokens = ext.extensions.split(/\s+/);
295 var supported = function() {
296 for (var i = 0, l = tokens.length; i < l; ++i)
297 if (extensions.indexOf(tokens[i]) === -1) return false;
298 return true;
299 }();
301 if (supported) {
302 for (var format = ext.formats.reset(); format = ext.formats.current(); ext.formats.next()) {
303 db.addFormat(glsFboUtil.formatKeyInfo(format), ext.flags);
312 * @param {number} glenum
313 * @param {WebGLRenderingContextBase=} gl
314 * @return {number}
315 * @throws {Error}
317 glsFboUtil.formatFlag = function(glenum, gl) {
318 if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
320 switch (glenum) {
321 case gl.NONE:
322 return glsFboUtil.FormatFlags.ANY_FORMAT;
323 case gl.RENDERBUFFER:
324 return glsFboUtil.FormatFlags.RENDERBUFFER_VALID;
325 case gl.TEXTURE:
326 return glsFboUtil.FormatFlags.TEXTURE_VALID;
327 case gl.STENCIL_ATTACHMENT:
328 return glsFboUtil.FormatFlags.STENCIL_RENDERABLE;
329 case gl.DEPTH_ATTACHMENT:
330 return glsFboUtil.FormatFlags.DEPTH_RENDERABLE;
331 default:
332 if (glenum < gl.COLOR_ATTACHMENT0 || glenum > gl.COLOR_ATTACHMENT15) {
333 throw new Error('glenum out of range');
336 return glsFboUtil.FormatFlags.COLOR_RENDERABLE;
340 * Remove value from array
341 * @param {Array} array
342 * @param {number} value
344 glsFboUtil.remove_from_array = function(array, value) {
345 var index = 0;
346 while ((index = array.indexOf(value)) != -1) {
347 array.splice(index, 1);
352 * glsFboUtil.FormatExtEntry
353 * @constructor
354 * @struct
355 * @param {string=} extensions
356 * @param {number=} flags
357 * @param {glsFboUtil.Range=} formats
359 glsFboUtil.FormatExtEntry = function(extensions, flags, formats) {
360 this.extensions = null;
361 this.flags = null;
362 this.formats = null;
364 if (extensions !== undefined) {
365 this.extensions = extensions;
366 if (flags !== undefined) {
367 this.flags = flags;
368 if (formats !== undefined)
369 this.formats = formats;
376 * glsFboUtil.Range
377 * @constructor
378 * @struct
379 * @template T
380 * @param {Array<T>} array
381 * @param {number=} begin
382 * @param {number=} end
384 glsFboUtil.Range = function(array, begin, end) {
385 // @private
386 this.m_begin = (begin === undefined ? 0 : begin);
387 // @private
388 this.m_end = end || array.length;
390 * @private
391 * @type {Array<T>}
393 this.m_array = array;
394 // @private
395 this.m_index = this.m_begin;
399 * @return {Array<T>}
401 glsFboUtil.Range.prototype.array = function() {
402 return this.m_array;
406 * @return {number}
408 glsFboUtil.Range.prototype.begin = function() {
409 return this.m_begin;
412 /** *generated by script*
413 * @return {number}
415 glsFboUtil.Range.prototype.end = function() {
416 return this.m_end;
420 * Returns the current pointer index as well as the current object
421 * @param {number} id
422 * @return {{first: number, second: T}}
424 glsFboUtil.Range.prototype.get = function(id) {
425 return {
426 first: id,
427 second: this.m_array[id]
432 * Sets the internal pointer to the beginning of the range, and returns the first object.
433 * @return {T}
435 glsFboUtil.Range.prototype.reset = function() {
436 this.m_index = this.m_begin;
437 return this.current();
441 * returns the current object within the specified range. The internal pointer is unaltered.
442 * @return {T}
444 glsFboUtil.Range.prototype.current = function() {
445 return this.m_index < this.m_end ? this.m_array[this.m_index] : null;
449 * Increments the internal pointer
451 glsFboUtil.Range.prototype.next = function() {
452 ++this.m_index;
456 * glsFboUtil.rangeArray
457 * replaces the macro GLS_ARRAY_RANGE
458 * Creates a new Range object from the specified array, spanning the whole array.
459 * @template T
460 * @param {Array<T>} array
461 * @return {glsFboUtil.Range<T>}
463 glsFboUtil.rangeArray = function(array) {
464 return new glsFboUtil.Range(array);
468 * @constructor
469 * @struct
470 * @param {number=} format
471 * @param {number=} unsizedType
473 glsFboUtil.ImageFormat = function(format, unsizedType) {
474 this.format = format || 0;
475 //! Type if format is unsized, gl.NONE if sized.
476 this.unsizedType = unsizedType || 0;
481 * @param {!glsFboUtil.ImageFormat} obj1
482 * @param {!glsFboUtil.ImageFormat} obj2
483 * @return {boolean}
485 glsFboUtil.ImageFormat.lessthan = function(obj1, obj2) {
486 return (
487 (obj1.format < obj2.format) ||
488 (obj1.format == obj2.format && obj1.unsizedType < obj2.unsizedType)
493 * Sets the object's parameters to gl.NONE
495 glsFboUtil.ImageFormat.prototype.none = function() {
496 this.format = 0;
497 this.unsizedType = 0;
501 * @return {glsFboUtil.ImageFormat}
503 glsFboUtil.ImageFormat.none = function() {
504 var obj = new glsFboUtil.ImageFormat();
505 obj.none();
506 return obj;
509 // where key is a FormatKey, and a FormatKey is a unsigned 32bit int.
512 * @param {number} key
513 * @return {glsFboUtil.ImageFormat}
515 glsFboUtil.formatKeyInfo = function(key) {
516 return new glsFboUtil.ImageFormat(
517 (key & 0x0000ffff),
518 (key & 0xffff0000) >>> 16
523 * glsFboUtil.Config Class.
524 * @constructor
526 glsFboUtil.Config = function() {
527 this.type = glsFboUtil.Config.s_types.CONFIG;
528 this.target = glsFboUtil.Config.s_target.NONE;
531 * @enum {number}
533 glsFboUtil.Config.s_target = {
534 NONE: 0,
535 RENDERBUFFER: 0x8D41,
536 TEXTURE_2D: 0x0DE1,
537 TEXTURE_CUBE_MAP: 0x8513,
538 TEXTURE_3D: 0x806F,
539 TEXTURE_2D_ARRAY: 0x8C1A,
541 FRAMEBUFFER: 0x8D40
544 // the c++ uses dynamic casts to determain if an object inherits from a
545 // given class. Here, each class' constructor assigns a bit to obj.type.
546 // look for the bit to see if an object inherits that class.
549 * @enum
551 glsFboUtil.Config.s_types = {
552 CONFIG: 0x000001,
554 IMAGE: 0x000010,
555 RENDERBUFFER: 0x000020,
556 TEXTURE: 0x000040,
557 TEXTURE_FLAT: 0x000080,
558 TEXTURE_2D: 0x000100,
559 TEXTURE_CUBE_MAP: 0x000200,
560 TEXTURE_LAYERED: 0x000400,
561 TEXTURE_3D: 0x000800,
562 TEXTURE_2D_ARRAY: 0x001000,
564 ATTACHMENT: 0x010000,
565 ATT_RENDERBUFFER: 0x020000,
566 ATT_TEXTURE: 0x040000,
567 ATT_TEXTURE_FLAT: 0x080000,
568 ATT_TEXTURE_LAYER: 0x100000,
570 UNUSED: 0xFFE0E00E
574 * glsFboUtil.Image Class.
575 * @constructor
576 * @extends {glsFboUtil.Config}
578 glsFboUtil.Image = function() {
579 glsFboUtil.Config.call(this);
580 this.type |= glsFboUtil.Config.s_types.IMAGE;
581 this.width = 0;
582 this.height = 0;
583 this.internalFormat = new glsFboUtil.ImageFormat();
587 * glsFboUtil.Renderbuffer Class.
588 * @constructor
589 * @extends {glsFboUtil.Image}
591 glsFboUtil.Renderbuffer = function() {
592 glsFboUtil.Image.call(this);
593 this.type |= glsFboUtil.Config.s_types.RENDERBUFFER;
594 this.target = glsFboUtil.Config.s_target.RENDERBUFFER;
595 this.numSamples = 0;
599 * glsFboUtil.Texture Class.
600 * @constructor
601 * @extends {glsFboUtil.Image}
603 glsFboUtil.Texture = function() {
604 glsFboUtil.Image.call(this);
605 this.type |= glsFboUtil.Config.s_types.TEXTURE;
606 this.numLevels = 1;
610 * glsFboUtil.TextureFlat Class.
611 * @constructor
612 * @extends {glsFboUtil.Texture}
614 glsFboUtil.TextureFlat = function() {
615 glsFboUtil.Texture.call(this);
616 this.type |= glsFboUtil.Config.s_types.TEXTURE_FLAT;
620 * glsFboUtil.Texture2D Class.
621 * @constructor
622 * @extends {glsFboUtil.TextureFlat}
624 glsFboUtil.Texture2D = function() {
625 glsFboUtil.TextureFlat.call(this);
626 this.type |= glsFboUtil.Config.s_types.TEXTURE_2D;
627 this.target = glsFboUtil.Config.s_target.TEXTURE_2D;
631 * glsFboUtil.TextureCubeMap Class.
632 * @constructor
633 * @extends {glsFboUtil.TextureFlat}
635 glsFboUtil.TextureCubeMap = function() {
636 glsFboUtil.TextureFlat.call(this);
637 this.type |= glsFboUtil.Config.s_types.TEXTURE_CUBE_MAP;
638 this.target = glsFboUtil.Config.s_target.TEXTURE_CUBE_MAP;
642 * glsFboUtil.TextureLayered Class.
643 * @constructor
644 * @extends {glsFboUtil.Texture}
646 glsFboUtil.TextureLayered = function() {
647 glsFboUtil.Texture.call(this);
648 this.type |= glsFboUtil.Config.s_types.TEXTURE_LAYERED;
649 this.numLayers = 1;
653 * glsFboUtil.Texture3D Class.
654 * @constructor
655 * @extends {glsFboUtil.TextureLayered}
657 glsFboUtil.Texture3D = function() {
658 glsFboUtil.TextureLayered.call(this);
659 this.type |= glsFboUtil.Config.s_types.TEXTURE_3D;
660 this.target = glsFboUtil.Config.s_target.TEXTURE_3D;
664 * glsFboUtil.Texture2DArray Class.
665 * @constructor
666 * @extends {glsFboUtil.TextureLayered}
668 glsFboUtil.Texture2DArray = function() {
669 glsFboUtil.TextureLayered.call(this);
670 this.type |= glsFboUtil.Config.s_types.TEXTURE_2D_ARRAY;
671 this.target = glsFboUtil.Config.s_target.TEXTURE_2D_ARRAY;
675 * glsFboUtil.Attachment Class.
676 * @constructor
677 * @extends {glsFboUtil.Config}
679 glsFboUtil.Attachment = function() {
680 glsFboUtil.Config.call(this);
682 this.type |= glsFboUtil.Config.s_types.ATTACHMENT;
684 /** @type {glsFboUtil.Config.s_target} */
685 this.target = glsFboUtil.Config.s_target.FRAMEBUFFER;
687 /** @type {WebGLObject} */
688 this.imageName = null;
692 * this function is declared, but has no definition/is unused in the c++
693 * @param {number} attPoint
694 * @param {number} image
695 * @param {number} vfr
697 glsFboUtil.Attachment.prototype.isComplete = function(attPoint, image, vfr) { };
700 * glsFboUtil.RenderBufferAttachments Class.
701 * @constructor
702 * @extends {glsFboUtil.Attachment}
704 glsFboUtil.RenderbufferAttachment = function() {
705 glsFboUtil.Attachment.call(this);
706 this.type |= glsFboUtil.Config.s_types.ATT_RENDERBUFFER;
707 this.renderbufferTarget = glsFboUtil.Config.s_target.RENDERBUFFER;
709 glsFboUtil.RenderbufferAttachment.prototype = Object.create(glsFboUtil.Attachment.prototype);
710 glsFboUtil.RenderbufferAttachment.prototype.constructor = glsFboUtil.RenderbufferAttachment;
713 * glsFboUtil.TextureAttachment Class.
714 * @constructor
715 * @extends {glsFboUtil.Attachment}
717 glsFboUtil.TextureAttachment = function() {
718 glsFboUtil.Attachment.call(this);
719 this.type |= glsFboUtil.Config.s_types.ATT_TEXTURE;
720 this.level = 0;
722 glsFboUtil.TextureAttachment.prototype = Object.create(glsFboUtil.Attachment.prototype);
723 glsFboUtil.TextureAttachment.prototype.constructor = glsFboUtil.TextureAttachment;
726 * glsFboUtil.TextureFlatAttachment Class.
727 * @constructor
728 * @extends {glsFboUtil.TextureAttachment}
730 glsFboUtil.TextureFlatAttachment = function() {
731 glsFboUtil.TextureAttachment.call(this);
732 this.type |= glsFboUtil.Config.s_types.ATT_TEXTURE_FLAT;
733 this.texTarget = glsFboUtil.Config.s_target.NONE;
735 glsFboUtil.TextureFlatAttachment.prototype = Object.create(glsFboUtil.TextureAttachment.prototype);
736 glsFboUtil.TextureFlatAttachment.prototype.constructor = glsFboUtil.TextureFlatAttachment;
739 * glsFboUtil.TextureLayerAttachment Class.
740 * @constructor
741 * @extends {glsFboUtil.TextureAttachment}
743 glsFboUtil.TextureLayerAttachment = function() {
744 glsFboUtil.TextureAttachment.call(this);
745 this.type |= glsFboUtil.Config.s_types.ATT_TEXTURE_LAYER;
746 this.layer = 0;
748 glsFboUtil.TextureLayerAttachment.prototype = Object.create(glsFboUtil.TextureAttachment.prototype);
749 glsFboUtil.TextureLayerAttachment.prototype.constructor = glsFboUtil.TextureLayerAttachment;
751 // these are a collection of helper functions for creating various gl textures.
752 glsFboUtil.glsup = function() {
754 var glInit = function(cfg, gl) {
755 if ((cfg.type & glsFboUtil.Config.s_types.TEXTURE_2D) != 0) {
756 glInitFlat(cfg, glTarget(cfg, gl), gl);
758 } else if ((cfg.type & glsFboUtil.Config.s_types.TEXTURE_CUBE_MAP) != 0) {
759 for (var i = gl.TEXTURE_CUBE_MAP_NEGATIVE_X; i <= gl.TEXTURE_CUBE_MAP_POSITIVE_Z; ++i)
760 glInitFlat(cfg, i, gl);
761 } else if ((cfg.type & glsFboUtil.Config.s_types.TEXTURE_3D) != 0) {
762 glInitLayered(cfg, 2, gl);
764 } else if ((cfg.type & glsFboUtil.Config.s_types.TEXTURE_2D_ARRAY) != 0) {
765 glInitLayered(cfg, 1, gl);
769 var glInitFlat = function(cfg, target, gl) {
770 var format = glsFboUtil.transferImageFormat(cfg.internalFormat, gl);
771 var w = cfg.width;
772 var h = cfg.height;
773 for (var level = 0; level < cfg.numLevels; ++level) {
774 gl.texImage2D(
775 target, level, cfg.internalFormat.format,
776 w, h, 0, format.format, format.dataType, null
778 w = Math.max(1, w / 2);
779 h = Math.max(1, h / 2);
783 var glInitLayered = function(cfg, depth_divider, gl) {
784 var format = glsFboUtil.transferImageFormat(cfg.internalFormat, gl);
785 var w = cfg.width;
786 var h = cfg.height;
787 var depth = cfg.numLayers;
788 for (var level = 0; level < cfg.numLevels; ++level) {
789 gl.texImage3D(
790 glTarget(cfg, gl), level, cfg.internalFormat.format,
791 w, h, depth, 0, format.format, format.dataType, null
793 w = Math.max(1, w / 2);
794 h = Math.max(1, h / 2);
795 depth = Math.max(1, depth / depth_divider);
799 var glCreate = function(cfg, gl) {
800 if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
802 if (cfg.type & glsFboUtil.Config.s_types.RENDERBUFFER) {
803 var ret = gl.createRenderbuffer();
804 gl.bindRenderbuffer(gl.RENDERBUFFER, ret);
806 if (cfg.numSamples == 0) {
807 gl.renderbufferStorage(
808 gl.RENDERBUFFER,
809 cfg.internalFormat.format,
810 cfg.width, cfg.height
812 } else {
813 gl.renderbufferStorageMultisample(
814 gl.RENDERBUFFER,
815 cfg.numSamples,
816 cfg.internalFormat.format,
817 cfg.width, cfg.height
820 gl.bindRenderbuffer(gl.RENDERBUFFER, null);
822 } else if (cfg.type & glsFboUtil.Config.s_types.TEXTURE) {
823 var ret = gl.createTexture();
824 gl.bindTexture(glTarget(cfg, gl), ret);
825 glInit(cfg, gl);
826 gl.bindTexture(glTarget(cfg, gl), null);
828 } else {
829 throw new Error('Impossible image type');
831 return ret;
834 var glTarget = function(cfg, gl) {
835 if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
836 var mask = (
837 glsFboUtil.Config.s_types.RENDERBUFFER |
838 glsFboUtil.Config.s_types.TEXTURE_2D |
839 glsFboUtil.Config.s_types.TEXTURE_CUBE_MAP |
840 glsFboUtil.Config.s_types.TEXTURE_3D |
841 glsFboUtil.Config.s_types.TEXTURE_2D_ARRAY
843 switch (cfg.type & mask) {
844 case glsFboUtil.Config.s_types.RENDERBUFFER: return gl.RENDERBUFFER;
845 case glsFboUtil.Config.s_types.TEXTURE_2D: return gl.TEXTURE_2D;
846 case glsFboUtil.Config.s_types.TEXTURE_CUBE_MAP: return gl.TEXTURE_CUBE_MAP;
847 case glsFboUtil.Config.s_types.TEXTURE_3D: return gl.TEXTURE_3D;
848 case glsFboUtil.Config.s_types.TEXTURE_2D_ARRAY: return gl.TEXTURE_2D_ARRAY;
849 default: break;
851 throw new Error('Impossible image type.');
854 var glDelete = function(cfg, img, gl) {
855 if (cfg.type & glsFboUtil.Config.s_types.RENDERBUFFER)
856 gl.deleteRenderbuffer(img);
857 else if (cfg.type & glsFboUtil.Config.s_types.TEXTURE)
858 gl.deleteTexture(img);
859 else
860 throw new Error('Impossible image type');
863 return {
864 create: glCreate,
865 remove: glDelete
868 }();
870 /** *generated by script*
871 * @param {number} img
872 * @return {number}
874 glsFboUtil.imageNumSamples = function(img) {
875 return (img.numSamples != undefined) ? img.numSamples : 0;
878 /** *generated by script*
879 * @param {glsFboUtil.Attachment} att
880 * @param {number} attPoint
881 * @param {WebGLRenderingContextBase=} gl
882 * @throws {Error}
884 glsFboUtil.attachAttachment = function(att, attPoint, gl) {
885 if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
887 var mask = (
888 glsFboUtil.Config.s_types.ATT_RENDERBUFFER |
889 glsFboUtil.Config.s_types.ATT_TEXTURE_FLAT |
890 glsFboUtil.Config.s_types.ATT_TEXTURE_LAYER
893 switch (att.type & mask) {
894 case glsFboUtil.Config.s_types.ATT_RENDERBUFFER:
895 gl.framebufferRenderbuffer(
896 att.target, attPoint, att.renderbufferTarget, /** @type {WebGLRenderbuffer} */(att.imageName)
898 break;
899 case glsFboUtil.Config.s_types.ATT_TEXTURE_FLAT:
900 gl.framebufferTexture2D(
901 att.target, attPoint, att.texTarget, /** @type {WebGLTexture} */(att.imageName), att.level
903 break;
904 case glsFboUtil.Config.s_types.ATT_TEXTURE_LAYER:
905 gl.framebufferTextureLayer(
906 att.target, attPoint, /** @type {WebGLTexture} */(att.imageName), att.level, att.layer
908 break;
909 default:
910 throw new Error('Impossible attachment type');
915 /** *generated by script*
916 * @param {glsFboUtil.Attachment} att
917 * @param {WebGLRenderingContextBase=} gl
918 * @return {number}
919 * @throws {Error}
921 glsFboUtil.attachmentType = function(att, gl) {
922 if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
924 if (att.type & glsFboUtil.Config.s_types.ATT_RENDERBUFFER) {
925 return gl.RENDERBUFFER;
927 if (att.type & glsFboUtil.Config.s_types.ATT_TEXTURE) {
928 return gl.TEXTURE;
930 throw new Error('Impossible attachment type.');
935 * @param {glsFboUtil.Attachment} att
936 * @return {number}
937 * @throws {Error}
939 glsFboUtil.textureLayer = function(att) {
940 if (att.type & glsFboUtil.Config.s_types.ATT_TEXTURE_FLAT) return 0;
941 if (att.type & glsFboUtil.Config.s_types.ATT_TEXTURE_LAYER) return att.layer;
942 throw new Error('Impossible attachment type.');
946 * @param {glsFboUtil.Checker} cctx
947 * @param {glsFboUtil.Attachment} att
948 * @param {number} attPoint
949 * @param {glsFboUtil.Image} image
950 * @param {glsFboUtil.FormatDB} db
951 * @param {WebGLRenderingContextBase=} gl
952 * @throws {Error}
954 glsFboUtil.checkAttachmentCompleteness = function(cctx, att, attPoint, image, db, gl) {
955 if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
957 // GLES2 4.4.5 / GLES3 4.4.4, "glsFboUtil.Framebuffer attachment completeness"
958 if (
959 (att.type & glsFboUtil.Config.s_types.ATT_TEXTURE) &&
960 (image.type & glsFboUtil.Config.s_types.TEXTURE_LAYERED)
962 // GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is
963 // TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a
964 // three-dimensional texture, then the value of
965 // FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the depth
966 // of the texture.
968 // GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is
969 // TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a
970 // two-dimensional array texture, then the value of
971 // FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the
972 // number of layers in the texture.
973 cctx.addFBOStatus(
974 glsFboUtil.textureLayer(att) < image.numLayers,
975 gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
979 // "The width and height of image are non-zero."
980 cctx.addFBOStatus(
981 image.width > 0 && image.height > 0,
982 gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
985 // Check for renderability
986 var flags = db.getFormatInfo(image.internalFormat, glsFboUtil.FormatFlags.ANY_FORMAT);
988 // If the format does not have the proper renderability flag, the
989 // completeness check _must_ fail.
990 cctx.addFBOStatus(
991 (flags & glsFboUtil.formatFlag(attPoint)) != 0,
992 gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
995 // If the format is only optionally renderable, the completeness check _can_ fail.
996 cctx.addPotentialFBOStatus(
997 (flags & glsFboUtil.FormatFlags.REQUIRED_RENDERABLE) != 0,
998 gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
1003 // replaces GLS_UNSIZED_FORMATKEY
1006 * All params and return types for this function are 32 bit
1007 * @param {number} format
1008 * @param {number} type
1009 * @return {number}
1011 glsFboUtil.formatkey = function(format, type) {
1012 // The formatkey value should be 32-bit unsigned int.
1013 return ((type << 16) >>> 0 | format) & 0xFFFFFFFF;
1017 * @enum
1019 glsFboUtil.FormatFlags = {
1020 ANY_FORMAT: 0x00,
1021 COLOR_RENDERABLE: 0x01,
1022 DEPTH_RENDERABLE: 0x02,
1023 STENCIL_RENDERABLE: 0x04,
1024 RENDERBUFFER_VALID: 0x08,
1025 TEXTURE_VALID: 0x10,
1026 REQUIRED_RENDERABLE: 0x20 //< Without this, renderability is allowed, not required.
1030 * A framebuffer configuration
1031 * @constructor
1032 * @param {WebGLRenderingContextBase=} gl
1034 glsFboUtil.Framebuffer = function(gl) {
1035 this.m_gl = gl || window.gl;
1036 this.fbid = 0;
1038 var fbidCompare = function(obj1, obj2) {
1039 return obj1._fbid < obj2._fbid;
1042 this.attachments = /** @type {glsFboUtil.Map<number,glsFboUtil.Attachment>} */(
1043 new glsFboUtil.Map(glsFboUtil.Map.compareNumber)
1045 this.textures = /** @type {glsFboUtil.Map<Object,glsFboUtil.Texture>} */(
1046 new glsFboUtil.Map(fbidCompare)
1048 this.rbos = /** @type {glsFboUtil.Map<Object,glsFboUtil.Renderbuffer>} */(
1049 new glsFboUtil.Map(fbidCompare)
1054 * @param {number} attPoint
1055 * @param {glsFboUtil.Attachment} att
1057 glsFboUtil.Framebuffer.prototype.attach = function(attPoint, att) {
1058 if (!att) {
1059 this.attachments.remove(attPoint);
1060 } else {
1061 this.attachments.set(attPoint, att);
1066 * @param {WebGLTexture} texName
1067 * @param {glsFboUtil.Texture} texCfg
1069 glsFboUtil.Framebuffer.prototype.setTexture = function(texName, texCfg) {
1070 texName._fbid = this.fbid++;
1071 this.textures.set(texName, texCfg);
1075 * @param {WebGLRenderbuffer} rbName
1076 * @param {glsFboUtil.Renderbuffer} rbCfg
1078 glsFboUtil.Framebuffer.prototype.setRbo = function(rbName, rbCfg) {
1079 rbName._fbid = this.fbid++;
1080 this.rbos.set(rbName, rbCfg);
1084 * @param {number} type
1085 * @param {WebGLObject} imgName
1086 * @return {glsFboUtil.Image}
1087 * @throws {Error}
1089 glsFboUtil.Framebuffer.prototype.getImage = function(type, imgName) {
1090 switch (type) {
1091 case this.m_gl.TEXTURE: return this.textures.lookupDefault(/** @type {WebGLTexture} */(imgName), null);
1092 case this.m_gl.RENDERBUFFER: return this.rbos.lookupDefault(/** @type {WebGLTexture} */(imgName), null);
1093 default: break;
1095 throw new Error('Bad image type.');
1099 * @constructor
1100 * @extends {glsFboUtil.Framebuffer}
1101 * @param {WebGLFramebuffer} fbo
1102 * @param {number} target
1103 * @param {WebGLRenderingContextBase=} gl
1105 glsFboUtil.FboBuilder = function(fbo, target, gl) {
1106 glsFboUtil.Framebuffer.call(this, gl);
1108 this.m_gl = gl || window.gl;
1109 this.m_target = target;
1110 this.m_configs = [];
1111 this.m_error = this.m_gl.NO_ERROR;
1113 this.m_gl.bindFramebuffer(this.m_target, fbo);
1117 glsFboUtil.FboBuilder.prototype = Object.create(glsFboUtil.Framebuffer.prototype);
1118 glsFboUtil.FboBuilder.prototype.constructor = glsFboUtil.FboBuilder;
1120 glsFboUtil.FboBuilder.prototype.deinit = function() {
1122 var pair;
1123 for (var i = 0; i < this.textures.length; ++i) {
1124 pair = this.textures.getIndex(i);
1125 glsFboUtil.glsup.remove(pair.second, pair.first, this.m_gl);
1127 this.textures.clear();
1129 for (var i = 0; i < this.rbos.length; ++i) {
1130 pair = this.rbos.getIndex(i);
1131 glsFboUtil.glsup.remove(pair.second, pair.first, this.m_gl);
1133 this.rbos.clear();
1135 this.m_gl.bindFramebuffer(this.m_target, null);
1137 for (var i = 0 ; i < this.m_configs.length ; ++i) {
1138 delete this.m_configs[i];
1140 //*/
1144 * @param {number} attPoint
1145 * @param {glsFboUtil.Attachment} att
1147 glsFboUtil.FboBuilder.prototype.glAttach = function(attPoint, att) {
1148 if (!att) {
1149 this.m_gl.framebufferRenderbuffer(this.m_target, attPoint, this.m_gl.RENDERBUFFER, null);
1150 } else {
1151 glsFboUtil.attachAttachment(att, attPoint, this.m_gl);
1153 this.checkError();
1154 this.attach(attPoint, att);
1158 * @param {glsFboUtil.Texture} texCfg
1159 * @return {WebGLTexture}
1161 glsFboUtil.FboBuilder.prototype.glCreateTexture = function(texCfg) {
1162 var texName = glsFboUtil.glsup.create(texCfg, this.m_gl);
1163 this.checkError();
1164 this.setTexture(texName, texCfg);
1165 return texName;
1168 /** *generated by script*
1169 * @param {glsFboUtil.Renderbuffer} rbCfg
1170 * @return {WebGLRenderbuffer}
1172 glsFboUtil.FboBuilder.prototype.glCreateRbo = function(rbCfg) {
1173 var rbName = glsFboUtil.glsup.create(rbCfg, this.m_gl);
1174 this.checkError();
1175 this.setRbo(rbName, rbCfg);
1176 return rbName;
1180 * @param {function(new:glsFboUtil.Config)} Definition
1181 * @return {glsFboUtil.Config}
1183 glsFboUtil.FboBuilder.prototype.makeConfig = function(Definition) {
1184 var cfg = new Definition();
1185 this.m_configs.push(cfg);
1186 return cfg;
1191 glsFboUtil.FboBuilder.prototype.checkError = function() {
1192 var error = this.m_gl.getError();
1193 if (error != this.m_gl.NO_ERROR && this.m_error == this.m_gl.NO_ERROR) {
1194 this.m_error = error;
1198 /** *generated by script*
1199 * @return {number}
1201 glsFboUtil.FboBuilder.prototype.getError = function() {
1202 return this.m_error;
1205 glsFboUtil.isFramebufferStatus = function(fboStatus) {
1206 return gluStrUtil.getFramebufferStatusName(fboStatus) != '';
1209 glsFboUtil.isErrorCode = function(errorCode) {
1210 return gluStrUtil.getErrorName(errorCode) != '';
1214 * @typedef {funcion(): glsFboUtil.ValidStatusCodes}
1216 glsFboUtil.ValidStatusCodes = function() {
1217 this.m_errorCodes = [];
1218 this.m_errorStatusCodes = [];
1219 this.m_allowComplete = false;
1222 glsFboUtil.ValidStatusCodes.prototype.isFBOStatusValid = function(fboStatus) {
1223 if (fboStatus == gl.FRAMEBUFFER_COMPLETE)
1224 return this.m_allowComplete;
1225 else {
1226 for(var ndx = 0; ndx < this.m_errorStatusCodes.length; ++ndx) {
1227 if (this.m_errorStatusCodes[ndx] == fboStatus)
1228 return true;
1230 return false;
1234 glsFboUtil.ValidStatusCodes.prototype.isFBOStatusRequired = function(fboStatus) {
1235 if (fboStatus == gl.FRAMEBUFFER_COMPLETE)
1236 return this.m_allowComplete && this.m_errorStatusCodes.length == 0;
1237 else
1238 // fboStatus is the only allowed error status and succeeding is forbidden
1239 return !this.m_allowComplete && this.m_errorStatusCodes.length == 1 && this.m_errorStatusCodes[0] == fboStatus;
1242 glsFboUtil.ValidStatusCodes.prototype.isErrorCodeValid = function(errorCode) {
1243 if (errorCode == gl.NO_ERROR)
1244 return this.m_errorCodes.length == 0;
1245 else {
1246 // rule violation exists?
1247 for (var ndx = 0; ndx < this.m_errorCodes.length; ++ndx) {
1248 if (this.m_errorCodes[ndx] == errorCode)
1249 return true;
1251 return false;
1255 glsFboUtil.ValidStatusCodes.prototype.isErrorCodeRequired = function(errorCode) {
1256 if (this.m_errorCodes.length == 0 && errorCode == gl.NO_ERROR)
1257 return true;
1258 else
1259 // only this error code listed
1260 return this.m_errorCodes.length == 1 && merrorCodes[0] == errorCode;
1263 glsFboUtil.ValidStatusCodes.prototype.addErrorCode = function(error) {
1264 DE_ASSERT(glsFboUtil.isErrorCode(error));
1265 DE_ASSERT(error != gl.NO_ERROR)
1266 this.m_errorCodes.push(error);
1269 glsFboUtil.ValidStatusCodes.prototype.addFBOErrorStatus = function(status) {
1270 DE_ASSERT(glsFboUtil.isFramebufferStatus(status));
1271 DE_ASSERT(status != gl.FRAMEBUFFER_COMPLETE)
1272 this.m_errorStatusCodes.push(status);
1275 glsFboUtil.ValidStatusCodes.prototype.setAllowComplete = function(b) {
1276 this.m_allowComplete = b;
1280 * @typedef {function(): glsFboUtil.Checker}
1282 glsFboUtil.CheckerFactory;
1285 * @constructor
1286 * @param {WebGLRenderingContextBase=} gl
1287 * @throws {Error}
1289 glsFboUtil.Checker = function(gl) {
1290 if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
1292 this.m_statusCodes = new glsFboUtil.ValidStatusCodes();
1293 this.m_statusCodes.setAllowComplete(true);
1295 if (typeof(this.check) != 'function')
1296 throw new Error('Constructor called on virtual class: glsFboUtil.Checker');
1300 * @param {boolean} condition
1301 * @param {number} error
1303 glsFboUtil.Checker.prototype.addGLError = function(condition, error) {
1304 if (!condition) {
1305 this.m_statusCodes.addErrorCode(error);
1306 this.m_statusCodes.setAllowComplete(false);
1311 * @param {boolean} condition
1312 * @param {number} error
1314 glsFboUtil.Checker.prototype.addPotentialGLError = function(condition, error) {
1315 if (!condition) {
1316 this.m_statusCodes.addErrorCode(error);
1321 * @param {boolean} condition
1322 * @param {number} status
1324 glsFboUtil.Checker.prototype.addFBOStatus = function(condition, status) {
1325 if (!condition) {
1326 this.m_statusCodes.addFBOErrorStatus(status);
1327 this.m_statusCodes.setAllowComplete(false);
1332 * @param {boolean} condition
1333 * @param {number} status
1335 glsFboUtil.Checker.prototype.addPotentialFBOStatus = function(condition, status) {
1336 if (!condition) {
1337 this.m_statusCodes.addFBOErrorStatus(status);
1342 * @return {Array<number>}
1344 glsFboUtil.Checker.prototype.getStatusCodes = function () {
1345 return this.m_statusCodes;
1349 * @param {glsFboUtil.ImageFormat} imgFormat
1350 * @param {WebGLRenderingContextBase=} gl
1351 * @return {gluTextureUtil.TransferFormat}
1352 * @throws {Error}
1354 glsFboUtil.transferImageFormat = function(imgFormat, gl) {
1355 if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
1356 if (imgFormat.unsizedType == gl.NONE)
1357 return gluTextureUtil.getTransferFormat(gluTextureUtil.mapGLInternalFormat(imgFormat.format));
1358 else
1359 return new gluTextureUtil.TransferFormat(imgFormat.format, imgFormat.unsizedType);
1362 // FormatDB, CheckerFactory
1365 * @constructor
1366 * @param {glsFboUtil.FormatDB} formats
1367 * @param {glsFboUtil.CheckerFactory} factory
1369 glsFboUtil.FboVerifier = function(formats, factory) {
1370 this.m_formats = formats;
1371 this.m_factory = factory;
1373 // config::Framebuffer
1374 glsFboUtil.FboVerifier.prototype.validStatusCodes = function(cfg, gl) {
1375 if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
1377 /** @type {glsFboUtil.Checker} */
1378 var cctx = this.m_factory();
1380 for (var id = 0; id < cfg.textures.length; ++id) {
1381 var flags = this.m_formats.getFormatInfo(cfg.textures.getIndex(id).second.internalFormat, glsFboUtil.FormatFlags.ANY_FORMAT);
1382 var textureIsValid = (flags & glsFboUtil.FormatFlags.TEXTURE_VALID) != 0;
1383 cctx.addGLError(textureIsValid, gl.INVALID_ENUM);
1384 cctx.addGLError(textureIsValid, gl.INVALID_OPERATION);
1385 cctx.addGLError(textureIsValid, gl.INVALID_VALUE);
1388 for (var id = 0; id < cfg.rbos.length; ++id) {
1389 var flags = this.m_formats.getFormatInfo(cfg.rbos.getIndex(id).second.internalFormat, glsFboUtil.FormatFlags.ANY_FORMAT);
1390 var rboIsValid = (flags & glsFboUtil.FormatFlags.RENDERBUFFER_VALID) != 0;
1391 cctx.addGLError(rboIsValid, gl.INVALID_ENUM);
1394 var count = 0;
1395 for (var index = 0; index < cfg.attachments.length; ++index) {
1396 var attPoint = cfg.attachments.getIndex(index).first;
1397 var att = cfg.attachments.getIndex(index).second;
1398 /** @type {glsFboUtil.Image}*/
1399 var image = cfg.getImage(glsFboUtil.attachmentType(att, gl), att.imageName);
1400 glsFboUtil.checkAttachmentCompleteness(cctx, att, attPoint, image, this.m_formats, gl);
1401 cctx.check(attPoint, att, image);
1402 ++count;
1405 // "There is at least one image attached to the framebuffer."
1406 // TODO: support XXX_framebuffer_no_attachments
1407 cctx.addFBOStatus(count > 0, gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
1409 return cctx.getStatusCodes();