var check = require('./util/check') var values = require('./util/values') var GL_RENDERBUFFER = 0x8D41 var GL_RGBA4 = 0x8056 var GL_RGB5_A1 = 0x8057 var GL_RGB565 = 0x8D62 var GL_DEPTH_COMPONENT16 = 0x81A5 var GL_STENCIL_INDEX8 = 0x8D48 var GL_DEPTH_STENCIL = 0x84F9 var GL_SRGB8_ALPHA8_EXT = 0x8C43 var GL_RGBA32F_EXT = 0x8814 var GL_RGBA16F_EXT = 0x881A var GL_RGB16F_EXT = 0x881B var FORMAT_SIZES = [] FORMAT_SIZES[GL_RGBA4] = 2 FORMAT_SIZES[GL_RGB5_A1] = 2 FORMAT_SIZES[GL_RGB565] = 2 FORMAT_SIZES[GL_DEPTH_COMPONENT16] = 2 FORMAT_SIZES[GL_STENCIL_INDEX8] = 1 FORMAT_SIZES[GL_DEPTH_STENCIL] = 4 FORMAT_SIZES[GL_SRGB8_ALPHA8_EXT] = 4 FORMAT_SIZES[GL_RGBA32F_EXT] = 16 FORMAT_SIZES[GL_RGBA16F_EXT] = 8 FORMAT_SIZES[GL_RGB16F_EXT] = 6 function getRenderbufferSize (format, width, height) { return FORMAT_SIZES[format] * width * height } module.exports = function (gl, extensions, limits, stats, config) { var formatTypes = { 'rgba4': GL_RGBA4, 'rgb565': GL_RGB565, 'rgb5 a1': GL_RGB5_A1, 'depth': GL_DEPTH_COMPONENT16, 'stencil': GL_STENCIL_INDEX8, 'depth stencil': GL_DEPTH_STENCIL } if (extensions.ext_srgb) { formatTypes['srgba'] = GL_SRGB8_ALPHA8_EXT } if (extensions.ext_color_buffer_half_float) { formatTypes['rgba16f'] = GL_RGBA16F_EXT formatTypes['rgb16f'] = GL_RGB16F_EXT } if (extensions.webgl_color_buffer_float) { formatTypes['rgba32f'] = GL_RGBA32F_EXT } var formatTypesInvert = [] Object.keys(formatTypes).forEach(function (key) { var val = formatTypes[key] formatTypesInvert[val] = key }) var renderbufferCount = 0 var renderbufferSet = {} function REGLRenderbuffer (renderbuffer) { this.id = renderbufferCount++ this.refCount = 1 this.renderbuffer = renderbuffer this.format = GL_RGBA4 this.width = 0 this.height = 0 if (config.profile) { this.stats = { size: 0 } } } REGLRenderbuffer.prototype.decRef = function () { if (--this.refCount <= 0) { destroy(this) } } function destroy (rb) { var handle = rb.renderbuffer check(handle, 'must not double destroy renderbuffer') gl.bindRenderbuffer(GL_RENDERBUFFER, null) gl.deleteRenderbuffer(handle) rb.renderbuffer = null rb.refCount = 0 delete renderbufferSet[rb.id] stats.renderbufferCount-- } function createRenderbuffer (a, b) { var renderbuffer = new REGLRenderbuffer(gl.createRenderbuffer()) renderbufferSet[renderbuffer.id] = renderbuffer stats.renderbufferCount++ function reglRenderbuffer (a, b) { var w = 0 var h = 0 var format = GL_RGBA4 if (typeof a === 'object' && a) { var options = a if ('shape' in options) { var shape = options.shape check(Array.isArray(shape) && shape.length >= 2, 'invalid renderbuffer shape') w = shape[0] | 0 h = shape[1] | 0 } else { if ('radius' in options) { w = h = options.radius | 0 } if ('width' in options) { w = options.width | 0 } if ('height' in options) { h = options.height | 0 } } if ('format' in options) { check.parameter(options.format, formatTypes, 'invalid renderbuffer format') format = formatTypes[options.format] } } else if (typeof a === 'number') { w = a | 0 if (typeof b === 'number') { h = b | 0 } else { h = w } } else if (!a) { w = h = 1 } else { check.raise('invalid arguments to renderbuffer constructor') } // check shape check( w > 0 && h > 0 && w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize, 'invalid renderbuffer size') if (w === renderbuffer.width && h === renderbuffer.height && format === renderbuffer.format) { return } reglRenderbuffer.width = renderbuffer.width = w reglRenderbuffer.height = renderbuffer.height = h renderbuffer.format = format gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer) gl.renderbufferStorage(GL_RENDERBUFFER, format, w, h) check( gl.getError() === 0, 'invalid render buffer format') if (config.profile) { renderbuffer.stats.size = getRenderbufferSize(renderbuffer.format, renderbuffer.width, renderbuffer.height) } reglRenderbuffer.format = formatTypesInvert[renderbuffer.format] return reglRenderbuffer } function resize (w_, h_) { var w = w_ | 0 var h = (h_ | 0) || w if (w === renderbuffer.width && h === renderbuffer.height) { return reglRenderbuffer } // check shape check( w > 0 && h > 0 && w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize, 'invalid renderbuffer size') reglRenderbuffer.width = renderbuffer.width = w reglRenderbuffer.height = renderbuffer.height = h gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer) gl.renderbufferStorage(GL_RENDERBUFFER, renderbuffer.format, w, h) check( gl.getError() === 0, 'invalid render buffer format') // also, recompute size. if (config.profile) { renderbuffer.stats.size = getRenderbufferSize( renderbuffer.format, renderbuffer.width, renderbuffer.height) } return reglRenderbuffer } reglRenderbuffer(a, b) reglRenderbuffer.resize = resize reglRenderbuffer._reglType = 'renderbuffer' reglRenderbuffer._renderbuffer = renderbuffer if (config.profile) { reglRenderbuffer.stats = renderbuffer.stats } reglRenderbuffer.destroy = function () { renderbuffer.decRef() } return reglRenderbuffer } if (config.profile) { stats.getTotalRenderbufferSize = function () { var total = 0 Object.keys(renderbufferSet).forEach(function (key) { total += renderbufferSet[key].stats.size }) return total } } function restoreRenderbuffers () { values(renderbufferSet).forEach(function (rb) { rb.renderbuffer = gl.createRenderbuffer() gl.bindRenderbuffer(GL_RENDERBUFFER, rb.renderbuffer) gl.renderbufferStorage(GL_RENDERBUFFER, rb.format, rb.width, rb.height) }) gl.bindRenderbuffer(GL_RENDERBUFFER, null) } return { create: createRenderbuffer, clear: function () { values(renderbufferSet).forEach(destroy) }, restore: restoreRenderbuffers } }