webgl - Must render buffer texture dimensions be power-of-two? -
does texture use webgl render buffer storage need have dimensions power-of-two?
background info
i'm chasing framebuffer_incomplete_attachment reported client on setup:
windows 7 enterprise 32-bit firefox version: 33 video card: intel q45/q43 express chipset driver version 8.13.10.2413
and far i'm @ loss why it's happening, guessing might npot textures.
here's render buffer implementation, not have power-of-two-texture yet:
scenejs._webgl.renderbuffer = function (cfg) { /** * true buffer allocated , ready go * @type {boolean} */ this.allocated = false; this.canvas = cfg.canvas; this.gl = cfg.canvas.gl; this.buf = null; this.bound = false; }; /** * called after webgl context restored. */ scenejs._webgl.renderbuffer.prototype.webglrestored = function (_gl) { this.gl = _gl; this.buf = null; }; /** * binds buffer */ scenejs._webgl.renderbuffer.prototype.bind = function () { this._touch(); if (this.bound) { return; } this.gl.bindframebuffer(this.gl.framebuffer, this.buf.framebuf); this.bound = true; }; scenejs._webgl.renderbuffer.prototype._touch = function () { var width = this.canvas.canvas.width; var height = this.canvas.canvas.height; if (this.buf) { // have buffer if (this.buf.width == width && this.buf.height == height) { // canvas size unchanged, buffer still return; } else { // buffer needs reallocation new canvas size this.gl.deletetexture(this.buf.texture); this.gl.deleteframebuffer(this.buf.framebuf); this.gl.deleterenderbuffer(this.buf.renderbuf); } } this.buf = { framebuf: this.gl.createframebuffer(), renderbuf: this.gl.createrenderbuffer(), texture: this.gl.createtexture(), width: width, height: height }; this.gl.bindframebuffer(this.gl.framebuffer, this.buf.framebuf); this.gl.bindtexture(this.gl.texture_2d, this.buf.texture); this.gl.texparameteri(this.gl.texture_2d, this.gl.texture_mag_filter, this.gl.nearest); this.gl.texparameteri(this.gl.texture_2d, this.gl.texture_min_filter, this.gl.nearest); this.gl.texparameteri(this.gl.texture_2d, this.gl.texture_wrap_s, this.gl.clamp_to_edge); this.gl.texparameteri(this.gl.texture_2d, this.gl.texture_wrap_t, this.gl.clamp_to_edge); try { // way spec requires this.gl.teximage2d(this.gl.texture_2d, 0, this.gl.rgba, width, height, 0, this.gl.rgba, this.gl.unsigned_byte, null); } catch (exception) { // workaround appears minefield bug. var texturestorage = new webglunsignedbytearray(width * height * 3); this.gl.teximage2d(this.gl.texture_2d, 0, this.gl.rgba, width, height, 0, this.gl.rgba, this.gl.unsigned_byte, texturestorage); } this.gl.bindrenderbuffer(this.gl.renderbuffer, this.buf.renderbuf); this.gl.renderbufferstorage(this.gl.renderbuffer, this.gl.depth_component16, width, height); this.gl.framebuffertexture2d(this.gl.framebuffer, this.gl.color_attachment0, this.gl.texture_2d, this.buf.texture, 0); this.gl.framebufferrenderbuffer(this.gl.framebuffer, this.gl.depth_attachment, this.gl.renderbuffer, this.buf.renderbuf); this.gl.bindtexture(this.gl.texture_2d, null); this.gl.bindrenderbuffer(this.gl.renderbuffer, null); this.gl.bindframebuffer(this.gl.framebuffer, null); // verify framebuffer ok this.gl.bindframebuffer(this.gl.framebuffer, this.buf.framebuf); if (!this.gl.isframebuffer(this.buf.framebuf)) { throw scenejs_error.fatalerror(scenejs.errors.error, "invalid framebuffer"); } var status = this.gl.checkframebufferstatus(this.gl.framebuffer); switch (status) { case this.gl.framebuffer_complete: break; case this.gl.framebuffer_incomplete_attachment: throw scenejs_error.fatalerror(scenejs.errors.error, "incomplete framebuffer: framebuffer_incomplete_attachment"); case this.gl.framebuffer_incomplete_missing_attachment: throw scenejs_error.fatalerror(scenejs.errors.error, "incomplete framebuffer: framebuffer_incomplete_missing_attachment"); case this.gl.framebuffer_incomplete_dimensions: throw scenejs_error.fatalerror(scenejs.errors.error, "incomplete framebuffer: framebuffer_incomplete_dimensions"); case this.gl.framebuffer_unsupported: throw scenejs_error.fatalerror(scenejs.errors.error, "incomplete framebuffer: framebuffer_unsupported"); default: throw scenejs_error.fatalerror(scenejs.errors.error, "incomplete framebuffer: " + status); } this.bound = false; }; /** * clears renderbuffer */ scenejs._webgl.renderbuffer.prototype.clear = function () { if (!this.bound) { throw "render buffer not bound"; } this.gl.clear(this.gl.color_buffer_bit | this.gl.depth_buffer_bit); this.gl.disable(this.gl.blend); }; /** * reads buffer pixel @ given coordinates */ scenejs._webgl.renderbuffer.prototype.read = function (pickx, picky) { var x = pickx; var y = this.canvas.canvas.height - picky; var pix = new uint8array(4); this.gl.readpixels(x, y, 1, 1, this.gl.rgba, this.gl.unsigned_byte, pix); return pix; }; /** * unbinds renderbuffer */ scenejs._webgl.renderbuffer.prototype.unbind = function () { this.gl.bindframebuffer(this.gl.framebuffer, null); this.bound = false; }; /** returns texture */ scenejs._webgl.renderbuffer.prototype.gettexture = function () { var self = this; return { bind: function (unit) { if (self.buf && self.buf.texture) { self.gl.activetexture(self.gl["texture" + unit]); self.gl.bindtexture(self.gl.texture_2d, self.buf.texture); return true; } return false; }, unbind: function (unit) { if (self.buf && self.buf.texture) { self.gl.activetexture(self.gl["texture" + unit]); self.gl.bindtexture(self.gl.texture_2d, null); } } }; }; /** destroys buffer */ scenejs._webgl.renderbuffer.prototype.destroy = function () { if (this.buf) { this.gl.deletetexture(this.buf.texture); this.gl.deleteframebuffer(this.buf.framebuf); this.gl.deleterenderbuffer(this.buf.renderbuf); this.buf = null; this.bound = false; } };
as far find (i don't use webgl), webgl spec delegates opengl es 2.0 spec on these fbo related calls. rgba 8 bits per component not format supported render target in es 2.0. many devices support (advertised oes_rgb8_rgba8 extension), not part of standard.
the texture using color_attachment0
rgba 8-bit components:
this.gl.teximage2d(this.gl.texture_2d, 0, this.gl.rgba, width, height, 0, this.gl.rgba, this.gl.unsigned_byte, texturestorage);
try specifying rgb565, color renderable:
this.gl.teximage2d(this.gl.texture_2d, 0, this.gl.rgba, width, height, 0, this.gl.rgb, this.gl.unsigned_short_5_6_5, texturestorage);
if need alpha component in texture, rgba4444 or rgb5_a1 portable options:
this.gl.teximage2d(this.gl.texture_2d, 0, this.gl.rgba, width, height, 0, this.gl.rgba, this.gl.unsigned_short_4_4_4_4, texturestorage); this.gl.teximage2d(this.gl.texture_2d, 0, this.gl.rgba, width, height, 0, this.gl.rgba, this.gl.unsigned_short_5_5_5_1, texturestorage);
the spec looks contradictory me. under "differences between webgl , opengl es 2.0", says:
the following combinations of framebuffer object attachments, when of attachments framebuffer attachment complete, non-zero, , have same width , height, must result in framebuffer being framebuffer complete:
color_attachment0 = rgba/unsigned_byte texture
which @ first sight suggests rgba/unsigned_byte
supported. that's under condition "when of attachments framebuffer attachment complete", , according es 2.0 spec, attachments format not attachment complete. , there no override in webgl spec on "attachment complete" means.
Comments
Post a Comment