12345 |
- /*
- All material copyright ESRI, All Rights Reserved, unless otherwise specified.
- See https://js.arcgis.com/4.24/esri/copyright.txt for details.
- */
- import t from"../../core/Logger.js";import{isSome as e,isNone as i}from"../../core/maybe.js";import{BufferObject as r}from"./BufferObject.js";import{webglDebugEnabled as s,webglValidateShadersEnabled as h}from"./checkWebGLError.js";import{ContextType as n}from"./context-util.js";import{ResourceType as c,ColorAttachment as o,DepthStencilTargetType as _,PixelFormat as a,PixelType as l,DepthStencilAttachment as T,RenderbufferFormat as E,FramebufferTarget as d,TextureType as u,Usage as f,BufferType as m,TargetType as A,TextureSamplingMode as p,TextureWrapMode as R,SizedPixelFormat as N}from"./enums.js";import{Renderbuffer as g}from"./Renderbuffer.js";import{Texture as F}from"./Texture.js";import{getGpuMemoryUsage as x}from"./Util.js";const b=t.getLogger("esri.views.webgl.FrameBufferObject");class D{constructor(t,i,r=null,s=null){if(this._context=t,this._glName=null,this._depthAttachment=null,this._stencilAttachment=null,this._colorAttachments=new Map,this._initialized=!1,this._desc={...i},t.instanceCounter.increment(c.FramebufferObject,this),e(r)){Array.isArray(r)||(r=[r]);for(let t=0;t<r.length;++t){const e=r[t],i=o.COLOR_ATTACHMENT0+t;let s;U(e)?(C(e)?(s=e.descriptor,this._colorAttachments.set(i,e)):(s=e,this._colorAttachments.set(i,new F(this._context,s))),P(s,this._desc)):(S(e)?(s=e.descriptor,this._colorAttachments.set(i,e)):(s=e,this._colorAttachments.set(i,new g(this._context,s))),B(s,this._desc)),this._validateColorAttachmentPoint(i)}}if(e(s)){let t,e;if(U(s))this._context.capabilities.depthTexture||console.error("Setting the depth/stencil texture as an attachment requires WEBGL_depth_texture or WebGL2"),C(s)?(e=s.descriptor,this._depthStencilTexture=s):(e=s,this._depthStencilTexture=new F(this._context,e)),P(e,this._desc);else{S(s)?(e=s.descriptor,t=s):(e=s,t=new g(this._context,e));const i=this._desc.depthStencilTarget??_.DEPTH_STENCIL_RENDER_BUFFER;i===_.STENCIL_RENDER_BUFFER?this._stencilAttachment=t:i===_.DEPTH_RENDER_BUFFER||i===_.DEPTH_STENCIL_RENDER_BUFFER?this._depthAttachment=t:console.error('If a Renderbuffer is provided, "depthStencilTarget" must be one of STENCIL_RENDER_BUFFER, DEPTH_RENDER_BUFFER or DEPTH_STENCIL_RENDER_BUFFER'),B(e,this._desc)}}}dispose(){if(!this._desc)return;const t=this._context.getBoundFramebufferObject();if(this._disposeColorAttachments(),this._disposeDepthStencilAttachments(),this._glName){this._context.gl.deleteFramebuffer(this._glName),this._glName=null}this._context.bindFramebuffer(t),this._context.instanceCounter.decrement(c.FramebufferObject,this),this._desc=null}get glName(){return this._glName}get descriptor(){return this._desc}get colorTexture(){const t=this._colorAttachments.get(o.COLOR_ATTACHMENT0);return t&&C(t)?t:null}get colorAttachment(){return this._colorAttachments.get(o.COLOR_ATTACHMENT0)}get depthStencilAttachment(){return this._depthStencilTexture||this._depthAttachment||this._stencilAttachment}get depthStencilTexture(){return this._depthStencilTexture}get width(){return this._desc.width}get height(){return this._desc.height}get gpuMemoryUsage(){return[...this._colorAttachments].reduce(((t,[e,i])=>t+x(i)),0)+x(this.depthStencilAttachment)}getColorTexture(t){const e=this._colorAttachments.get(t);return e&&C(e)?e:null}attachColorTexture(t,e=o.COLOR_ATTACHMENT0){if(!t)return;this._validateColorAttachmentPoint(e);P(t.descriptor,this._desc),this._disposeColorAttachments(),this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(t.glName,e)),this._colorAttachments.set(e,t)}detachColorTexture(t=o.COLOR_ATTACHMENT0){const e=this._colorAttachments.get(t);if(C(e)){const i=e;return this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(null,t)),this._colorAttachments.delete(t),i}}setColorTextureTarget(t,e=o.COLOR_ATTACHMENT0){const i=this._colorAttachments.get(e);C(i)&&this._framebufferTexture2D(i.glName,e,t)}attachDepthStencilTexture(t){if(i(t))return;const e=t.descriptor;e.pixelFormat!==a.DEPTH_STENCIL&&console.error("Depth/Stencil texture must have a pixel type of DEPTH_STENCIL!"),e.dataType!==l.UNSIGNED_INT_24_8&&console.error("Depth/Stencil texture must have data type of UNSIGNED_INT_24_8!"),this._context.capabilities.depthTexture||console.error("Extension WEBGL_depth_texture isn't supported therefore it is no possible to set the depth/stencil texture!"),P(e,this._desc),this._desc.depthStencilTarget&&this._desc.depthStencilTarget!==_.DEPTH_STENCIL_TEXTURE&&(this._desc.depthStencilTarget=_.DEPTH_STENCIL_TEXTURE),this._disposeDepthStencilAttachments(),this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(t.glName,T)),this._depthStencilTexture=t}detachDepthStencilTexture(){const t=this._depthStencilTexture;return t&&this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(null,T)),this._depthStencilTexture=null,t}attachDepthStencilBuffer(t){if(i(t))return;const e=t.descriptor;if(e.internalFormat!==E.DEPTH_STENCIL&&e.internalFormat!==E.DEPTH_COMPONENT16&&console.error("Depth/Stencil buffer must have correct internalFormat"),B(e,this._desc),this._disposeDepthStencilAttachments(),this._desc.depthStencilTarget=e.internalFormat===E.DEPTH_STENCIL?_.DEPTH_STENCIL_RENDER_BUFFER:_.DEPTH_RENDER_BUFFER,this._initialized){this._context.bindFramebuffer(this);const e=this._context.gl,i=this._desc.depthStencilTarget===_.DEPTH_RENDER_BUFFER?e.DEPTH_ATTACHMENT:e.DEPTH_STENCIL_ATTACHMENT;e.framebufferRenderbuffer(d.FRAMEBUFFER,i,e.RENDERBUFFER,t.glName)}this._depthAttachment=t}detachDepthStencilBuffer(){const t=this._context.gl,e=this._depthAttachment;if(e&&this._initialized){this._context.bindFramebuffer(this);const e=this._desc.depthStencilTarget===_.DEPTH_RENDER_BUFFER?t.DEPTH_ATTACHMENT:t.DEPTH_STENCIL_ATTACHMENT;t.framebufferRenderbuffer(d.FRAMEBUFFER,e,t.RENDERBUFFER,null)}return this._depthAttachment=null,e}detachAll(){this._colorAttachments.forEach(((t,e)=>this._detachColorAttachment(e))),this.detachDepthStencilBuffer(),this.detachDepthStencilTexture()}copyToTexture(t,e,i,r,s,h,n){(t<0||e<0||s<0||h<0)&&console.error("Offsets cannot be negative!"),(i<=0||r<=0)&&console.error("Copy width and height must be greater than zero!");const c=this._desc,o=n.descriptor;n.descriptor.target!==u.TEXTURE_2D&&console.error("Texture target must be TEXTURE_2D!"),(t+i>c.width||e+r>c.height||s+i>o.width||h+r>o.height)&&console.error("Bad dimensions, the current input values will attempt to read or copy out of bounds!");const _=this._context,a=_.bindTexture(n,F.TEXTURE_UNIT_FOR_UPDATES);_.setActiveTexture(F.TEXTURE_UNIT_FOR_UPDATES),_.bindFramebuffer(this),_.gl.copyTexSubImage2D(u.TEXTURE_2D,0,s,h,t,e,i,r),_.bindTexture(a,F.TEXTURE_UNIT_FOR_UPDATES)}readPixels(t,e,i,r,s,h,n){(i<=0||r<=0)&&console.error("Copy width and height must be greater than zero!"),n||console.error("Target memory is not initialized!"),this._context.bindFramebuffer(this);this._context.gl.readPixels(t,e,i,r,s,h,n)}async readPixelsAsync(t,e,i,h,c,o,_){if(this._context.type!==n.WEBGL2)return s()&&console.warn("Attempting to read pixels using pixel buffer object without WebGL2"),void this.readPixels(t,e,i,h,c,o,_);const a=this._context.gl,l=r.createPixelPack(this._context,f.STREAM_READ,_.byteLength);this._context.bindBuffer(l),this._context.bindFramebuffer(this),a.readPixels(t,e,i,h,c,o,0),this._context.unbindBuffer(m.PIXEL_PACK_BUFFER),await l.getSubDataAsync(_),l.dispose()}resize(t,e){const i=this._desc;if(i.width!==t||i.height!==e){if(!this._initialized)return i.width=t,i.height=e,this._colorAttachments.forEach((i=>{i&&i.resize(t,e)})),void(this._depthStencilTexture&&this._depthStencilTexture.resize(t,e));i.width=t,i.height=e,this._colorAttachments.forEach((i=>{i&&i.resize(t,e)})),null!=this._depthStencilTexture?this._depthStencilTexture.resize(t,e):(this._depthAttachment||this._stencilAttachment)&&(this._depthAttachment&&this._depthAttachment.resize(t,e),this._stencilAttachment&&this._stencilAttachment.resize(t,e)),this._context.getBoundFramebufferObject()===this&&this._context.bindFramebuffer(null),this._initialized=!1}}initializeAndBind(t=d.FRAMEBUFFER){const e=this._context.gl;if(this._initialized)return void e.bindFramebuffer(t,this.glName);this._glName&&e.deleteFramebuffer(this._glName);const i=this._context,r=e.createFramebuffer(),s=this._desc,n=s.colorTarget??A.RENDER_BUFFER,c=s.width??1,T=s.height??1;if(e.bindFramebuffer(t,r),0===this._colorAttachments.size)if(n===A.TEXTURE||n===A.CUBEMAP)this._colorAttachments.set(o.COLOR_ATTACHMENT0,H(i,s,this.descriptor.colorTarget===A.CUBEMAP?u.TEXTURE_CUBE_MAP:u.TEXTURE_2D));else{const t=new g(i,{internalFormat:N.RGBA4,width:c,height:T});this._colorAttachments.set(o.COLOR_ATTACHMENT0,t)}this._colorAttachments.forEach(((i,r)=>{i&&(C(i)?this._framebufferTexture2D(i.glName,r,M(i),t):e.framebufferRenderbuffer(t,r,e.RENDERBUFFER,i.glName))}));const f=s.depthStencilTarget??_.NONE;switch(f){case _.DEPTH_RENDER_BUFFER:case _.DEPTH_STENCIL_RENDER_BUFFER:{this._depthAttachment||(this._depthAttachment=new g(i,{internalFormat:s.depthStencilTarget===_.DEPTH_RENDER_BUFFER?E.DEPTH_COMPONENT16:E.DEPTH_STENCIL,width:c,height:T}));const r=f===_.DEPTH_RENDER_BUFFER?e.DEPTH_ATTACHMENT:e.DEPTH_STENCIL_ATTACHMENT;e.framebufferRenderbuffer(t,r,e.RENDERBUFFER,this._depthAttachment.glName);break}case _.STENCIL_RENDER_BUFFER:this._stencilAttachment||(this._stencilAttachment=new g(i,{internalFormat:E.STENCIL_INDEX8,width:c,height:T})),e.framebufferRenderbuffer(t,e.STENCIL_ATTACHMENT,e.RENDERBUFFER,this._stencilAttachment.glName);break;case _.DEPTH_STENCIL_TEXTURE:if(!this._depthStencilTexture){i.capabilities.depthTexture||console.error("Extension WEBGL_depth_texture isn't supported therefore it is no possible to set the depth/stencil texture as an attachment!");const t={target:u.TEXTURE_2D,pixelFormat:a.DEPTH_STENCIL,dataType:l.UNSIGNED_INT_24_8,samplingMode:p.NEAREST,wrapMode:R.CLAMP_TO_EDGE,width:c,height:T};this._depthStencilTexture=new F(i,t)}this._framebufferTexture2D(this._depthStencilTexture.glName,e.DEPTH_STENCIL_ATTACHMENT,M(this._depthStencilTexture),t)}if(h()){e.checkFramebufferStatus(t)!==e.FRAMEBUFFER_COMPLETE&&console.error("Framebuffer is incomplete!")}this._glName=r,this._initialized=!0}_framebufferTexture2D(t,e=o.COLOR_ATTACHMENT0,i=u.TEXTURE_2D,r=d.FRAMEBUFFER,s=0){this._context.gl.framebufferTexture2D(r,e,i,t,s)}_detachColorAttachment(t){s()&&console.warn("Detaching an FBO attachment can be a slow due to invalidating framebuffer completeness!");const e=this._context.gl,i=this._colorAttachments.get(t);return C(i)?this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(null,t)):this._initialized&&(this._context.bindFramebuffer(this),e.framebufferRenderbuffer(d.FRAMEBUFFER,t,e.RENDERBUFFER,null)),this._colorAttachments.delete(t),i}_disposeColorAttachments(){this._colorAttachments.forEach(((t,e)=>{this._detachColorAttachment(e),t.dispose()})),this._colorAttachments.clear()}_disposeDepthStencilAttachments(){const t=this._context.gl;if(this._depthAttachment){if(this._initialized){this._context.bindFramebuffer(this);const e=this._desc.depthStencilTarget===_.DEPTH_RENDER_BUFFER?t.DEPTH_ATTACHMENT:t.DEPTH_STENCIL_ATTACHMENT;t.framebufferRenderbuffer(d.FRAMEBUFFER,e,t.RENDERBUFFER,null)}this._depthAttachment.dispose(),this._depthAttachment=null}this._stencilAttachment&&(this._initialized&&(this._context.bindFramebuffer(this),t.framebufferRenderbuffer(d.FRAMEBUFFER,t.STENCIL_ATTACHMENT,t.RENDERBUFFER,null)),this._stencilAttachment.dispose(),this._stencilAttachment=null),this._depthStencilTexture&&(this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(null,t.DEPTH_STENCIL_ATTACHMENT)),this._depthStencilTexture.dispose(),this._depthStencilTexture=null)}_validateColorAttachmentPoint(t){if(-1===D._MAX_COLOR_ATTACHMENTS){const t=this._context.capabilities.drawBuffers;if(t){const e=this._context.gl;D._MAX_COLOR_ATTACHMENTS=e.getParameter(t.MAX_COLOR_ATTACHMENTS)}else D._MAX_COLOR_ATTACHMENTS=1}const e=t-o.COLOR_ATTACHMENT0;e+1>D._MAX_COLOR_ATTACHMENTS&&b.error("esri.FrameBufferObject",`illegal attachment point for color attachment: ${e+1}. Implementation supports up to ${D._MAX_COLOR_ATTACHMENTS} color attachments`)}}function C(t){return"type"in t&&"texture"===t.type}function S(t){return"type"in t&&"renderbuffer"===t.type}function U(t){return C(t)||"pixelFormat"in t}function H(t,e,i){return new F(t,{target:i,pixelFormat:a.RGBA,dataType:l.UNSIGNED_BYTE,samplingMode:p.NEAREST,wrapMode:R.CLAMP_TO_EDGE,width:e.width,height:e.height})}function P(t,e){t.target!==u.TEXTURE_2D&&t.target!==u.TEXTURE_CUBE_MAP&&console.error("Texture type must be TEXTURE_2D or TEXTURE_CUBE_MAP!"),void 0!==e.width&&e.width>=0&&void 0!==e.height&&e.height>=0?e.width===t.width&&e.height===t.height||console.error("Color attachment texture must match the framebuffer's!"):(e.width=t.width,e.height=t.height)}function B(t,e){void 0!==e.width&&e.width>=0&&void 0!==e.height&&e.height>=0?e.width===t.width&&e.height===t.height||console.error("Renderbuffer dimensions must match the framebuffer's!"):(e.width=t.width,e.height=t.height)}function M(t){return t.descriptor.target===u.TEXTURE_CUBE_MAP?u.TEXTURE_CUBE_MAP_POSITIVE_X:u.TEXTURE_2D}D._MAX_COLOR_ATTACHMENTS=-1;export{D as FramebufferObject};
|