@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
6 lines (5 loc) • 11 kB
JavaScript
/*
All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/4.33/esri/copyright.txt for details.
*/
import"../../core/has.js";import t from"../../core/Logger.js";import{disposeMaybe as e}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,TextureType as h,FramebufferTarget as o,UnsizedDepthFormat as c,PixelType as a,Usage as u,BufferType as f,SizedStencilFormat as l,StencilAttachment as _,SizedDepthStencilFormat as d,DepthStencilAttachment as m,SizedDepthFormat as T,DepthAttachment as p}from"./enums.js";import{FBOAttachmentType as E}from"./FBOAttachmentType.js";import{Renderbuffer as x}from"./Renderbuffer.js";import{Texture as b}from"./Texture.js";const g=()=>t.getLogger("esri.views.webgl.FramebufferObject");class R{constructor(t,e,r){if(this._context=t,this._glName=null,this._colorAttachments=new Map,this._depthStencilBuffer=null,this._depthStencilTexture=null,this._initialized=!1,t.instanceCounter.increment(s.FramebufferObject,this),null!=e){const r=S(e)?e:new b(t,e);this._colorAttachments.set(n,r),this._validateTextureDescriptor(r.descriptor),this._validateColorAttachmentPoint(n)}if(null!=r)if(A(r))this._depthStencilTexture=S(r)?r:new b(t,r),this._validateTextureDescriptor(this._depthStencilTexture.descriptor);else{const e=F(r)?r:new x(t,r);this._depthStencilBuffer=e,this._validateRenderbufferDescriptor(e.descriptor)}}dispose(){const{_colorAttachments:t,_glName:e}=this;if(0===t.size&&!this._depthStencilBuffer&&!this._depthStencilTexture&&!e)return;const{_context:r}=this,i=r.getBoundFramebufferObject();t.forEach(((t,e)=>this.detachColorTexture(e)?.dispose())),this.detachDepthStencilBuffer()?.dispose(),this.detachDepthStencilTexture()?.dispose(),r.gl.deleteFramebuffer(e),this._glName=null,r.bindFramebuffer(i===this?null:i),r.instanceCounter.decrement(s.FramebufferObject,this)}get glName(){return this._glName}get colorTexture(){return this._colorAttachments.get(n)}get depthStencil(){return this._depthStencilTexture||this._depthStencilBuffer}get depthStencilTexture(){return this._depthStencilTexture}get width(){const t=this._colorAttachments.get(n)??this._depthStencilTexture??this._depthStencilBuffer;return t?.descriptor?.width??0}get height(){const t=this._colorAttachments.get(n)??this._depthStencilTexture??this._depthStencilBuffer;return t?.descriptor?.height??0}get usedMemory(){return[...this._colorAttachments].reduce(((t,[e,r])=>t+r.usedMemory),this.depthStencil?.usedMemory??0)}static{this._MAX_COLOR_ATTACHMENTS=-1}getColorTexture(t){const e=this._colorAttachments.get(t);return e&&S(e)?e:null}get colorAttachments(){return[...this._colorAttachments.keys()]}attachColorTexture(t,e=n){if(!t)return;this._validateColorAttachmentPoint(e);const{descriptor:r}=t;this._validateTextureDescriptor(r),this.detachColorTexture(e)?.dispose(),this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(t.glName,e)),this._colorAttachments.set(e,t)}detachColorTexture(t=n){const e=this._colorAttachments.get(t);if(e)return this._initialized&&this._context.temporaryBindFramebufferObject(this,(()=>{this._framebufferTexture2D(null,t)})),this._colorAttachments.delete(t),e}setColorTextureTarget(t,e=n,r=0){const i=this._colorAttachments.get(e);i&&(t===h.TEXTURE_2D_ARRAY?this._framebufferTextureLayer(i.glName,e,o.FRAMEBUFFER,0,r):this._framebufferTexture2D(i.glName,e,t,o.FRAMEBUFFER,0))}attachDepthStencil(t){if(t)switch(t.type){case E.Texture:return this._attachDepthStencilTexture(t);case E.Renderbuffer:return this._attachDepthStencilBuffer(t)}}_attachDepthStencilTexture(t){if(null==t)return;const{descriptor:e}=t,{pixelFormat:r,dataType:i}=e;r===c.DEPTH_STENCIL||r===c.DEPTH_COMPONENT?r!==c.DEPTH_STENCIL||i===a.UNSIGNED_INT_24_8?r!==c.DEPTH_COMPONENT||i===a.UNSIGNED_INT||i===a.UNSIGNED_SHORT?(this._validateTextureDescriptor(e),this._disposeDepthStencilAttachments(),this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(t.glName,O(r))),this._depthStencilTexture?.dispose(),this._depthStencilTexture=t):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 t=this._depthStencilTexture;return t&&this._initialized&&this._context.temporaryBindFramebufferObject(this,(()=>{this._framebufferTexture2D(null,O(t.descriptor.pixelFormat))})),this._depthStencilTexture=null,t}_attachDepthStencilBuffer(t){if(null==t)return;const e=t.descriptor;if(this._validateRenderbufferDescriptor(e),this._disposeDepthStencilAttachments(),this._initialized){this._context.bindFramebuffer(this);const{gl:r}=this._context,i=this._getGLAttachmentPoint(e);r.framebufferRenderbuffer(o.FRAMEBUFFER,i,r.RENDERBUFFER,t.glName)}this._depthStencilBuffer=t}detachDepthStencilBuffer(){const t=this._depthStencilBuffer;if(t&&this._initialized){const{_context:e}=this,r=e.getBoundFramebufferObject();e.bindFramebuffer(this);const{gl:i}=e,s=this._getGLAttachmentPoint(t.descriptor);i.framebufferRenderbuffer(o.FRAMEBUFFER,s,i.RENDERBUFFER,null),e.bindFramebuffer(r)}return this._depthStencilBuffer=null,t}invalidateAttachments(t){const{_context:e}=this;e.temporaryBindFramebufferObject(this,(()=>e.gl.invalidateFramebuffer(o.FRAMEBUFFER,t)),!0)}copyToTexture(t,e,r,i,s,n,o){(t<0||e<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 c=o.descriptor;o.descriptor.target!==h.TEXTURE_2D&&console.error("Texture target must be TEXTURE_2D!"),(null==c?.width||null==c?.height||t+r>this.width||e+i>this.height||s+r>c.width||n+i>c.height)&&console.error("Bad dimensions, the current input values will attempt to read or copy out of bounds!");const a=this._context,u=a.bindTexture(o,b.TEXTURE_UNIT_FOR_UPDATES);a.setActiveTexture(b.TEXTURE_UNIT_FOR_UPDATES),a.bindFramebuffer(this),a.gl.copyTexSubImage2D(h.TEXTURE_2D,0,s,n,t,e,r,i),a.bindTexture(u,b.TEXTURE_UNIT_FOR_UPDATES)}readPixels(t,e,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(t,e,r,i,s,n,h)}async readPixelsAsync(t,e,i,s,n,h,o){const{gl:c}=this._context,a=r.createPixelPack(this._context,u.STREAM_READ,o.byteLength);this._context.bindBuffer(a);const l=this._context.getBoundFramebufferObject();this._context.bindFramebuffer(this),c.readPixels(t,e,i,s,n,h,0),this._context.unbindBuffer(f.PIXEL_PACK_BUFFER),this._context.bindFramebuffer(l),await a.getSubDataAsync(o),a.dispose()}resize(t,e){if(this.width===t&&this.height===e)return;const r={width:t,height:e};B(r,this._context.parameters.maxTextureSize),this._colorAttachments.forEach((t=>t.resize(r.width,r.height))),this._depthStencilTexture?.resize(r.width,r.height),this._initialized&&(B(r,this._context.parameters.maxRenderbufferSize),this._depthStencilBuffer?.resize(r.width,r.height),this._context.getBoundFramebufferObject()===this&&this._context.bindFramebuffer(null),this._initialized=!1)}initializeAndBind(t=o.FRAMEBUFFER){const{gl:e}=this._context;if(this._initialized)return void e.bindFramebuffer(t,this.glName);this._glName&&e.deleteFramebuffer(this._glName);const r=e.createFramebuffer();if(e.bindFramebuffer(t,r),this._colorAttachments.forEach(((e,r)=>{const i=U(e);i===h.TEXTURE_2D_ARRAY?this._framebufferTextureLayer(e.glName,r,t,0,0):this._framebufferTexture2D(e.glName,r,i,t)})),this._depthStencilBuffer){const r=this._getGLAttachmentPoint(this._depthStencilBuffer.descriptor);e.framebufferRenderbuffer(t,r,e.RENDERBUFFER,this._depthStencilBuffer.glName)}else if(this._depthStencilTexture){const e=O(this._depthStencilTexture.descriptor.pixelFormat);this._framebufferTexture2D(this._depthStencilTexture.glName,e,U(this._depthStencilTexture),t)}if(i()){e.checkFramebufferStatus(t)!==e.FRAMEBUFFER_COMPLETE&&console.error("Framebuffer is incomplete!")}this._glName=r,this._initialized=!0}_framebufferTexture2D(t,e=n,r=h.TEXTURE_2D,i=o.FRAMEBUFFER,s=0){this._context.gl.framebufferTexture2D(i,e,r,t,s)}_framebufferTextureLayer(t,e=n,r=o.FRAMEBUFFER,i=0,s=0){this._context.gl.framebufferTextureLayer(r,e,t,i,s)}_disposeDepthStencilAttachments(){const t=this._context.gl;if(this._depthStencilBuffer){if(this._initialized){this._context.bindFramebuffer(this);const e=this._getGLAttachmentPoint(this._depthStencilBuffer.descriptor);t.framebufferRenderbuffer(o.FRAMEBUFFER,e,t.RENDERBUFFER,null)}this._depthStencilBuffer=e(this._depthStencilBuffer)}this._depthStencilTexture&&(this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(null,O(this._depthStencilTexture.descriptor.pixelFormat))),this._depthStencilTexture=e(this._depthStencilTexture))}_validateTextureDescriptor(t){t.target!==h.TEXTURE_2D&&t.target!==h.TEXTURE_CUBE_MAP&&t.target!==h.TEXTURE_2D_ARRAY&&console.error("Texture type must be TEXTURE_2D, TEXTURE_2D_ARRAY or TEXTURE_CUBE_MAP!"),B(t,this._context.parameters.maxTextureSize),this._validateBufferDimensions(t)}_validateRenderbufferDescriptor(t){B(t,this._context.parameters.maxRenderbufferSize),this._validateBufferDimensions(t)}_validateBufferDimensions(t){t.width<=0&&(t.width=this.width),t.height<=0&&(t.height=this.height),this.width>0&&this.height>0&&(this.width===t.width&&this.height===t.height||console.error("Attachment size must match framebuffer size!"))}_getGLAttachmentPoint(t){switch(t.internalFormat){case T.DEPTH_COMPONENT16:case T.DEPTH_COMPONENT24:case T.DEPTH_COMPONENT32F:return p;case d.DEPTH24_STENCIL8:case d.DEPTH32F_STENCIL8:return m;case l.STENCIL_INDEX8:return _}}_validateColorAttachmentPoint(e){if(-1===R._MAX_COLOR_ATTACHMENTS){const{gl:t}=this._context;R._MAX_COLOR_ATTACHMENTS=t.getParameter(t.MAX_COLOR_ATTACHMENTS)}const r=e-n;r+1>R._MAX_COLOR_ATTACHMENTS&&t.getLogger("esri.views.webgl.FrameBufferObject").error("esri.FrameBufferObject",`illegal attachment point for color attachment: ${r+1}. Implementation supports up to ${R._MAX_COLOR_ATTACHMENTS} color attachments`)}}function S(t){return N(t)===E.Texture}function F(t){return N(t)===E.Renderbuffer}function A(t){return S(t)||D(t)}function D(t){return N(t)===E.TextureDescriptor}function N(t){return null!=t&&"type"in t?t.type:null}function B(t,e){const r=Math.max(t.width,t.height);if(r>e){g().warnOnce(`Resizing FBO attachment size ${t.width}x${t.height} to device limit ${e}`);const i=e/r;return t.width=Math.round(t.width*i),t.height=Math.round(t.height*i),!1}return!0}function U(t){return t.descriptor.target===h.TEXTURE_CUBE_MAP?h.TEXTURE_CUBE_MAP_POSITIVE_X:t.descriptor.target===h.TEXTURE_2D_ARRAY?h.TEXTURE_2D_ARRAY:h.TEXTURE_2D}function O(t){return t===c.DEPTH_COMPONENT?p:m}export{R as FramebufferObject,B as ensureAttachmentMaxSize};