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.
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
) {
33 throw new Error('Assert failed');
40 * @param {function(!KeyT, !KeyT):boolean} comparefnc
42 glsFboUtil
.Map = function(comparefnc
) {
43 /** @type {Array<{first: !KeyT, second: ValueT}>} */
45 this.compare
= comparefnc
;
50 * @param {number} num1
51 * @param {number} num2
54 glsFboUtil
.Map
.compareNumber = function(num1
, num2
) {
60 * @param {ValueT} value
61 * @return {{first: !KeyT, second: ValueT}}
63 glsFboUtil
.Map
.prototype.pair = function(key
, value
) {
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;
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).
89 * @param {number} index
92 glsFboUtil
.Map
.prototype.foundIndexMatches = function(key
, index
) {
94 this.store
[index
] !== undefined &&
95 !this.compare(this.store
[index
].first
, key
)
103 glsFboUtil
.Map
.prototype.isset = function(key
) {
104 return this.foundIndexMatches(key
, this.findInsertionPoint(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
;
116 this.store
.splice(index
, 0, this.pair(key
, value
));
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);
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
];
150 glsFboUtil
.Map
.prototype.getValue = function(key
) {
151 var index
= this.findInsertionPoint(key
);
152 if (this.foundIndexMatches(key
, index
)) return this.store
[index
].second
;
158 * @param {ValueT} fallback
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
;
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
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
);
186 this.store
.splice(index
, 0, this.pair(key
, callback()));
192 * removed all elements from the Map
194 glsFboUtil
.Map
.prototype.clear = function() {
195 this.store
.splice(0, this.length
);
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
);
234 * @param {glsFboUtil.ImageFormat} format
235 * @param {number} fallback
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
248 glsFboUtil
.lookupDefault = function(map
, key
, fallback
) {
249 return (map
[key
] !== undefined) ? map
[key
] : fallback
;
253 * @param {Array<number>} array
254 * @param {number} item
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;
265 * @typedef {Array<(number | glsFboUtil.Range<number>)>}
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
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;
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
317 glsFboUtil
.formatFlag = function(glenum
, gl
) {
318 if (!(gl
= gl
|| window
.gl
)) throw new Error('Invalid gl object');
322 return glsFboUtil
.FormatFlags
.ANY_FORMAT
;
323 case gl
.RENDERBUFFER
:
324 return glsFboUtil
.FormatFlags
.RENDERBUFFER_VALID
;
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
;
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
) {
346 while ((index
= array
.indexOf(value
)) != -1) {
347 array
.splice(index
, 1);
352 * glsFboUtil.FormatExtEntry
355 * @param {string=} extensions
356 * @param {number=} flags
357 * @param {glsFboUtil.Range=} formats
359 glsFboUtil
.FormatExtEntry = function(extensions
, flags
, formats
) {
360 this.extensions
= null;
364 if (extensions
!== undefined) {
365 this.extensions
= extensions
;
366 if (flags
!== undefined) {
368 if (formats
!== undefined)
369 this.formats
= formats
;
380 * @param {Array<T>} array
381 * @param {number=} begin
382 * @param {number=} end
384 glsFboUtil
.Range = function(array
, begin
, end
) {
386 this.m_begin
= (begin
=== undefined ? 0 : begin
);
388 this.m_end
= end
|| array
.length
;
393 this.m_array
= array
;
395 this.m_index
= this.m_begin
;
401 glsFboUtil
.Range
.prototype.array = function() {
408 glsFboUtil
.Range
.prototype.begin = function() {
412 /** *generated by script*
415 glsFboUtil
.Range
.prototype.end = function() {
420 * Returns the current pointer index as well as the current object
422 * @return {{first: number, second: T}}
424 glsFboUtil
.Range
.prototype.get = function(id
) {
427 second
: this.m_array
[id
]
432 * Sets the internal pointer to the beginning of the range, and returns the first object.
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.
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() {
456 * glsFboUtil.rangeArray
457 * replaces the macro GLS_ARRAY_RANGE
458 * Creates a new Range object from the specified array, spanning the whole array.
460 * @param {Array<T>} array
461 * @return {glsFboUtil.Range<T>}
463 glsFboUtil
.rangeArray = function(array
) {
464 return new glsFboUtil
.Range(array
);
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
485 glsFboUtil
.ImageFormat
.lessthan = function(obj1
, obj2
) {
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() {
497 this.unsizedType
= 0;
501 * @return {glsFboUtil.ImageFormat}
503 glsFboUtil
.ImageFormat
.none = function() {
504 var obj
= new glsFboUtil
.ImageFormat();
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(
518 (key
& 0xffff0000) >>> 16
523 * glsFboUtil.Config Class.
526 glsFboUtil
.Config = function() {
527 this.type
= glsFboUtil
.Config
.s_types
.CONFIG
;
528 this.target
= glsFboUtil
.Config
.s_target
.NONE
;
533 glsFboUtil
.Config
.s_target
= {
535 RENDERBUFFER
: 0x8D41,
537 TEXTURE_CUBE_MAP
: 0x8513,
539 TEXTURE_2D_ARRAY
: 0x8C1A,
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.
551 glsFboUtil
.Config
.s_types
= {
555 RENDERBUFFER
: 0x000020,
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,
574 * glsFboUtil.Image Class.
576 * @extends {glsFboUtil.Config}
578 glsFboUtil
.Image = function() {
579 glsFboUtil
.Config
.call(this);
580 this.type
|= glsFboUtil
.Config
.s_types
.IMAGE
;
583 this.internalFormat
= new glsFboUtil
.ImageFormat();
587 * glsFboUtil.Renderbuffer Class.
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
;
599 * glsFboUtil.Texture Class.
601 * @extends {glsFboUtil.Image}
603 glsFboUtil
.Texture = function() {
604 glsFboUtil
.Image
.call(this);
605 this.type
|= glsFboUtil
.Config
.s_types
.TEXTURE
;
610 * glsFboUtil.TextureFlat Class.
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.
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.
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.
644 * @extends {glsFboUtil.Texture}
646 glsFboUtil
.TextureLayered = function() {
647 glsFboUtil
.Texture
.call(this);
648 this.type
|= glsFboUtil
.Config
.s_types
.TEXTURE_LAYERED
;
653 * glsFboUtil.Texture3D Class.
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.
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.
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.
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.
715 * @extends {glsFboUtil.Attachment}
717 glsFboUtil
.TextureAttachment = function() {
718 glsFboUtil
.Attachment
.call(this);
719 this.type
|= glsFboUtil
.Config
.s_types
.ATT_TEXTURE
;
722 glsFboUtil
.TextureAttachment
.prototype = Object
.create(glsFboUtil
.Attachment
.prototype);
723 glsFboUtil
.TextureAttachment
.prototype.constructor = glsFboUtil
.TextureAttachment
;
726 * glsFboUtil.TextureFlatAttachment Class.
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.
741 * @extends {glsFboUtil.TextureAttachment}
743 glsFboUtil
.TextureLayerAttachment = function() {
744 glsFboUtil
.TextureAttachment
.call(this);
745 this.type
|= glsFboUtil
.Config
.s_types
.ATT_TEXTURE_LAYER
;
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
);
773 for (var level
= 0; level
< cfg
.numLevels
; ++level
) {
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
);
787 var depth
= cfg
.numLayers
;
788 for (var level
= 0; level
< cfg
.numLevels
; ++level
) {
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(
809 cfg
.internalFormat
.format
,
810 cfg
.width
, cfg
.height
813 gl
.renderbufferStorageMultisample(
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
);
826 gl
.bindTexture(glTarget(cfg
, gl
), null);
829 throw new Error('Impossible image type');
834 var glTarget = function(cfg
, gl
) {
835 if (!(gl
= gl
|| window
.gl
)) throw new Error('Invalid gl object');
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
;
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
);
860 throw new Error('Impossible image type');
870 /** *generated by script*
871 * @param {number} img
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
884 glsFboUtil
.attachAttachment = function(att
, attPoint
, gl
) {
885 if (!(gl
= gl
|| window
.gl
)) throw new Error('Invalid gl object');
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
)
899 case glsFboUtil
.Config
.s_types
.ATT_TEXTURE_FLAT
:
900 gl
.framebufferTexture2D(
901 att
.target
, attPoint
, att
.texTarget
, /** @type {WebGLTexture} */(att
.imageName
), att
.level
904 case glsFboUtil
.Config
.s_types
.ATT_TEXTURE_LAYER
:
905 gl
.framebufferTextureLayer(
906 att
.target
, attPoint
, /** @type {WebGLTexture} */(att
.imageName
), att
.level
, att
.layer
910 throw new Error('Impossible attachment type');
915 /** *generated by script*
916 * @param {glsFboUtil.Attachment} att
917 * @param {WebGLRenderingContextBase=} gl
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
) {
930 throw new Error('Impossible attachment type.');
935 * @param {glsFboUtil.Attachment} att
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
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"
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
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.
974 glsFboUtil
.textureLayer(att
) < image
.numLayers
,
975 gl
.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
979 // "The width and height of image are non-zero."
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.
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
1011 glsFboUtil
.formatkey = function(format
, type
) {
1012 // The formatkey value should be 32-bit unsigned int.
1013 return ((type
<< 16) >>> 0 | format
) & 0xFFFFFFFF;
1019 glsFboUtil
.FormatFlags
= {
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
1032 * @param {WebGLRenderingContextBase=} gl
1034 glsFboUtil
.Framebuffer = function(gl
) {
1035 this.m_gl
= gl
|| window
.gl
;
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
) {
1059 this.attachments
.remove(attPoint
);
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}
1089 glsFboUtil
.Framebuffer
.prototype.getImage = function(type
, imgName
) {
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);
1095 throw new Error('Bad image type.');
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() {
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
);
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];
1144 * @param {number} attPoint
1145 * @param {glsFboUtil.Attachment} att
1147 glsFboUtil
.FboBuilder
.prototype.glAttach = function(attPoint
, att
) {
1149 this.m_gl
.framebufferRenderbuffer(this.m_target
, attPoint
, this.m_gl
.RENDERBUFFER
, null);
1151 glsFboUtil
.attachAttachment(att
, attPoint
, this.m_gl
);
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
);
1164 this.setTexture(texName
, texCfg
);
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
);
1175 this.setRbo(rbName
, rbCfg
);
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
);
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*
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
;
1226 for(var ndx
= 0; ndx
< this.m_errorStatusCodes
.length
; ++ndx
) {
1227 if (this.m_errorStatusCodes
[ndx
] == fboStatus
)
1234 glsFboUtil
.ValidStatusCodes
.prototype.isFBOStatusRequired = function(fboStatus
) {
1235 if (fboStatus
== gl
.FRAMEBUFFER_COMPLETE
)
1236 return this.m_allowComplete
&& this.m_errorStatusCodes
.length
== 0;
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;
1246 // rule violation exists?
1247 for (var ndx
= 0; ndx
< this.m_errorCodes
.length
; ++ndx
) {
1248 if (this.m_errorCodes
[ndx
] == errorCode
)
1255 glsFboUtil
.ValidStatusCodes
.prototype.isErrorCodeRequired = function(errorCode
) {
1256 if (this.m_errorCodes
.length
== 0 && errorCode
== gl
.NO_ERROR
)
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
;
1286 * @param {WebGLRenderingContextBase=} gl
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
) {
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
) {
1316 this.m_statusCodes
.addErrorCode(error
);
1321 * @param {boolean} condition
1322 * @param {number} status
1324 glsFboUtil
.Checker
.prototype.addFBOStatus = function(condition
, status
) {
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
) {
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}
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
));
1359 return new gluTextureUtil
.TransferFormat(imgFormat
.format
, imgFormat
.unsizedType
);
1362 // FormatDB, CheckerFactory
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
);
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
);
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();