@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
3 lines (2 loc) • 10.8 kB
JavaScript
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.19/LICENSE.txt */
import e from"../../core/Logger.js";import{disposeMaybe as t}from"../../core/maybe.js";import{BufferObject as r}from"./BufferObject.js";import{webglDebugEnabled as i}from"./checkWebGLError.js";import{ResourceType as s,ColorAttachment0 as n,PixelType as h,StencilAttachment as o,SizedDepthStencilFormat as c,DepthStencilAttachment as a,SizedDepthFormat as u,DepthAttachment as f}from"./enums.js";import{Renderbuffer as l}from"./Renderbuffer.js";import d from"./Texture.js";const _=()=>e.getLogger("esri.views.webgl.FramebufferObject");class m{constructor(e,t,r){if(this._context=e,this._glName=null,this._colorAttachments=new Map,this._depthStencilBuffer=null,this._depthStencilTexture=null,this._initialized=!1,e.instanceCounter.increment(s.FramebufferObject,this),null!=t){const r=E(e,t);null!=r&&(this._colorAttachments.set(n,r),p(r)?this._validateTextureDescriptor(r.descriptor):this._validateRenderbufferDescriptor(r.descriptor)),this._validateColorAttachmentPoint(n)}if(null!=r)if(x(r))this._depthStencilTexture=p(r)?r:new d(e,r),this._validateTextureDescriptor(this._depthStencilTexture.descriptor);else{const t=T(r)?r:new l(e,r);this._depthStencilBuffer=t,this._validateRenderbufferDescriptor(t.descriptor)}}dispose(){const{_colorAttachments:e,_glName:t}=this;if(0===e.size&&!this._depthStencilBuffer&&!this._depthStencilTexture&&!t)return;const{_context:r}=this,i=r.getBoundFramebufferObject();e.forEach((e,t)=>this.detachColorTexture(t)?.dispose()),this.detachDepthStencilBuffer()?.dispose(),this.detachDepthStencilTexture()?.dispose(),r.gl.deleteFramebuffer(t),this._glName=null,r.bindFramebuffer(i===this?null:i),r.instanceCounter.decrement(s.FramebufferObject,this)}get glName(){return this._glName}get colorTexture(){const e=this._colorAttachments.get(n);return p(e)?e:null}get depthStencil(){return this._depthStencilTexture||this._depthStencilBuffer}get depthStencilTexture(){return this._depthStencilTexture}get width(){const e=this._colorAttachments.get(n)??this._depthStencilTexture??this._depthStencilBuffer;return e?.descriptor?.width??0}get height(){const e=this._colorAttachments.get(n)??this._depthStencilTexture??this._depthStencilBuffer;return e?.descriptor?.height??0}get usedMemory(){return[...this._colorAttachments].reduce((e,[t,r])=>e+r.usedMemory,this.depthStencil?.usedMemory??0)}static{this._MAX_COLOR_ATTACHMENTS=-1}getColorTexture(e){const t=this._colorAttachments.get(e);return t&&p(t)?t:null}get colorAttachments(){return Array.from(this._colorAttachments.keys())}attachColorTexture(e,t=n){if(!e)return;this._validateColorAttachmentPoint(t);const{descriptor:r}=e;this._validateTextureDescriptor(r),this.detachColorTexture(t)?.dispose(),this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(e.glName,t)),this._colorAttachments.set(t,e)}detachColorTexture(e=n){const t=this._colorAttachments.get(e);if(!t)return;const r=p(t);return this._initialized&&this._context.temporaryBindFramebufferObject(this,()=>{if(r)this._framebufferTexture2D(null,e);else{const t=this._context.gl;t.framebufferRenderbuffer(t.FRAMEBUFFER,e,t.RENDERBUFFER,null)}}),this._colorAttachments.delete(e),r?t:void 0}setColorTextureTarget(e,t=n,r=0){const i=this._colorAttachments.get(t);i&&(35866===e?this._framebufferTextureLayer(i.glName,t,36160,0,r):this._framebufferTexture2D(i.glName,t,e,36160,0))}attachDepthStencil(e){if(e)switch(e.type){case 1:return this._attachDepthStencilTexture(e);case 2:return this._attachDepthStencilBuffer(e)}}_attachDepthStencilTexture(e){if(null==e)return;const{descriptor:t}=e,{pixelFormat:r,dataType:i}=t;34041===r||6402===r?34041!==r||i===h.UNSIGNED_INT_24_8?6402!==r||i===h.UNSIGNED_INT||i===h.UNSIGNED_SHORT?(this._validateTextureDescriptor(t),this._disposeDepthStencilAttachments(),this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(e.glName,A(r))),this._depthStencilTexture?.dispose(),this._depthStencilTexture=e):console.error("Depth texture must have data type of UNSIGNED_INT or UNSIGNED_SHORT!"):console.error("Depth/Stencil texture must have data type of UNSIGNED_INT_24_8!"):console.error("Depth/Stencil texture must have a pixel type of DEPTH_STENCIL!")}detachDepthStencilTexture(){const e=this._depthStencilTexture;return e&&this._initialized&&this._context.temporaryBindFramebufferObject(this,()=>{this._framebufferTexture2D(null,A(e.descriptor.pixelFormat))}),this._depthStencilTexture=null,e}_attachDepthStencilBuffer(e){if(null==e)return;const t=e.descriptor;if(this._validateRenderbufferDescriptor(t),this._disposeDepthStencilAttachments(),this._initialized){this._context.bindFramebuffer(this);const{gl:r}=this._context,i=this._getGLAttachmentPoint(t);r.framebufferRenderbuffer(36160,i,r.RENDERBUFFER,e.glName)}this._depthStencilBuffer=e}detachDepthStencilBuffer(){const e=this._depthStencilBuffer;if(e&&this._initialized){const{_context:t}=this,r=t.getBoundFramebufferObject();t.bindFramebuffer(this);const{gl:i}=t,s=this._getGLAttachmentPoint(e.descriptor);i.framebufferRenderbuffer(36160,s,i.RENDERBUFFER,null),t.bindFramebuffer(r)}return this._depthStencilBuffer=null,e}invalidateAttachments(e){const{_context:t}=this;t.temporaryBindFramebufferObject(this,()=>t.gl.invalidateFramebuffer(36160,e),!0)}copyToTexture(e,t,r,i,s,n,h){(e<0||t<0||s<0||n<0)&&console.error("Offsets cannot be negative!"),(r<=0||i<=0)&&console.error("Copy width and height must be greater than zero!");const o=h.descriptor;3553!==h.descriptor.target&&console.error("Texture target must be TEXTURE_2D!"),(null==o?.width||null==o?.height||e+r>this.width||t+i>this.height||s+r>o.width||n+i>o.height)&&console.error("Bad dimensions, the current input values will attempt to read or copy out of bounds!");const c=this._context,a=c.bindTexture(h,d.TEXTURE_UNIT_FOR_UPDATES);c.setActiveTexture(d.TEXTURE_UNIT_FOR_UPDATES),c.bindFramebuffer(this),c.gl.copyTexSubImage2D(3553,0,s,n,e,t,r,i),c.bindTexture(a,d.TEXTURE_UNIT_FOR_UPDATES)}readPixels(e,t,r,i,s,n,h){(r<=0||i<=0)&&console.error("Copy width and height must be greater than zero!"),h||console.error("Target memory is not initialized!"),this._context.bindFramebuffer(this),this._context.gl.readPixels(e,t,r,i,s,n,h)}async readPixelsAsync(e,t,i,s,n,h,o){const{gl:c}=this._context,a=r.createPixelPack(this._context,35041,o.byteLength);this._context.bindBuffer(a);const u=this._context.getBoundFramebufferObject();this._context.bindFramebuffer(this),c.readPixels(e,t,i,s,n,h,0),this._context.unbindBuffer(35051),this._context.bindFramebuffer(u),await a.getSubDataAsync(o),a.dispose()}resize(e,t){if(this.width===e&&this.height===t)return;const r={width:e,height:t};if(F(r,this._context.parameters.maxTextureSize),this._colorAttachments.forEach(e=>e.resize(r.width,r.height)),this._depthStencilTexture?.resize(r.width,r.height),this._initialized&&(F(r,this._context.parameters.maxRenderbufferSize),this._depthStencilBuffer?.resize(r.width,r.height),i())){const{gl:e}=this._context;e.checkFramebufferStatus(36160)!==e.FRAMEBUFFER_COMPLETE&&console.error("Framebuffer is incomplete!")}}initializeAndBind(e=36160){const{gl:t}=this._context;if(this._initialized)return void t.bindFramebuffer(e,this.glName);this._glName&&t.deleteFramebuffer(this._glName);const r=t.createFramebuffer();if(t.bindFramebuffer(e,r),this._colorAttachments.forEach((t,r)=>{if(p(t)){const i=D(t);35866===i?this._framebufferTextureLayer(t.glName,r,e,0,0):this._framebufferTexture2D(t.glName,r,i,e)}else if(T(t)){const i=this._context.gl;i.framebufferRenderbuffer(e,r,i.RENDERBUFFER,t.glName)}}),this._depthStencilBuffer){const r=this._getGLAttachmentPoint(this._depthStencilBuffer.descriptor);t.framebufferRenderbuffer(e,r,t.RENDERBUFFER,this._depthStencilBuffer.glName)}else if(this._depthStencilTexture){const t=A(this._depthStencilTexture.descriptor.pixelFormat);this._framebufferTexture2D(this._depthStencilTexture.glName,t,D(this._depthStencilTexture),e)}if(i()){t.checkFramebufferStatus(e)!==t.FRAMEBUFFER_COMPLETE&&console.error("Framebuffer is incomplete!")}this._glName=r,this._initialized=!0}_framebufferTexture2D(e,t=n,r=3553,i=36160,s=0){this._context.gl.framebufferTexture2D(i,t,r,e,s)}_framebufferTextureLayer(e,t=n,r=36160,i=0,s=0){this._context.gl.framebufferTextureLayer(r,t,e,i,s)}_disposeDepthStencilAttachments(){const e=this._context.gl;if(this._depthStencilBuffer){if(this._initialized){this._context.bindFramebuffer(this);const t=this._getGLAttachmentPoint(this._depthStencilBuffer.descriptor);e.framebufferRenderbuffer(36160,t,e.RENDERBUFFER,null)}this._depthStencilBuffer=t(this._depthStencilBuffer)}this._depthStencilTexture&&(this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(null,A(this._depthStencilTexture.descriptor.pixelFormat))),this._depthStencilTexture=t(this._depthStencilTexture))}_validateTextureDescriptor(e){3553!==e.target&&34067!==e.target&&35866!==e.target&&console.error("Texture type must be TEXTURE_2D, TEXTURE_2D_ARRAY or TEXTURE_CUBE_MAP!"),F(e,this._context.parameters.maxTextureSize),this._validateBufferDimensions(e)}_validateRenderbufferDescriptor(e){F(e,this._context.parameters.maxRenderbufferSize),this._validateBufferDimensions(e)}_validateBufferDimensions(e){e.width<=0&&(e.width=this.width),e.height<=0&&(e.height=this.height),this.width>0&&this.height>0&&(this.width===e.width&&this.height===e.height||console.error("Attachment size must match framebuffer size!"))}_getGLAttachmentPoint(e){switch(e.internalFormat){case u.DEPTH_COMPONENT16:case u.DEPTH_COMPONENT24:case u.DEPTH_COMPONENT32F:return f;case c.DEPTH24_STENCIL8:case c.DEPTH32F_STENCIL8:return a;case 36168:return o;default:return n}}_validateColorAttachmentPoint(t){if(-1===m._MAX_COLOR_ATTACHMENTS){const{gl:e}=this._context;m._MAX_COLOR_ATTACHMENTS=e.getParameter(e.MAX_COLOR_ATTACHMENTS)}const r=t-n;r+1>m._MAX_COLOR_ATTACHMENTS&&e.getLogger("esri.views.webgl.FrameBufferObject").error("esri.FrameBufferObject",`illegal attachment point for color attachment: ${r+1}. Implementation supports up to ${m._MAX_COLOR_ATTACHMENTS} color attachments`)}}function p(e){return 1===S(e)}function T(e){return 2===S(e)}function x(e){return p(e)||b(e)}function b(e){return 0===S(e)}function g(e){return 3===S(e)||null!=e&&"samples"in e}function S(e){return null!=e&&"type"in e?e.type:null}function E(e,t){return p(t)||T(t)?t:b(t)?new d(e,t):g(t)?new l(e,t):null}function F(e,t){const r=Math.max(e.width,e.height);if(r>t){_().warnOnce(`Resizing FBO attachment size ${e.width}x${e.height} to device limit ${t}`);const i=t/r;return e.width=Math.round(e.width*i),e.height=Math.round(e.height*i),!1}return!0}function D(e){return 34067===e.descriptor.target?34069:35866===e.descriptor.target?35866:3553}function A(e){return 6402===e?f:a}export{m as FramebufferObject,F as ensureAttachmentMaxSize};