/* All material copyright ESRI, All Rights Reserved, unless otherwise specified. See https://js.arcgis.com/4.25/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 h}from"./checkWebGLError.js";import{ContextType as s}from"./context-util.js";import{ResourceType as n,ColorAttachment as c,DepthStencilTargetType as o,PixelFormat as _,PixelType as a,DepthStencilAttachment as l,RenderbufferFormat as T,FramebufferTarget as E,TextureType as d,Usage as u,BufferType as f,TargetType as m,SizedPixelFormat as A,TextureSamplingMode as p,TextureWrapMode as R}from"./enums.js";import{Renderbuffer as g}from"./Renderbuffer.js";import{Texture as N}from"./Texture.js";import{getGpuMemoryUsage as F}from"./Util.js";class x{constructor(t,i,r=null,h=null){if(this._context=t,this._glName=null,this._depthAttachment=null,this._stencilAttachment=null,this._colorAttachments=new Map,this._depthStencilTexture=null,this._initialized=!1,this._desc={...i},t.instanceCounter.increment(n.FramebufferObject,this),e(r)){Array.isArray(r)||(r=[r]);for(let t=0;tt+F(i)),0)+F(this.depthStencilAttachment)}getColorTexture(t){const e=this._colorAttachments.get(t);return e&&b(e)?e:null}attachColorTexture(t,e=c.COLOR_ATTACHMENT0){if(!t)return;this._validateColorAttachmentPoint(e);U(t.descriptor,this._desc),this._disposeColorAttachments(),this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(t.glName,e)),this._colorAttachments.set(e,t)}detachColorTexture(t=c.COLOR_ATTACHMENT0){const e=this._colorAttachments.get(t);if(b(e)){const i=e;return this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(null,t)),this._colorAttachments.delete(t),i}}setColorTextureTarget(t,e=c.COLOR_ATTACHMENT0){const i=this._colorAttachments.get(e);b(i)&&this._framebufferTexture2D(i.glName,e,t)}attachDepthStencilTexture(t){if(i(t))return;const e=t.descriptor;e.pixelFormat!==_.DEPTH_STENCIL&&console.error("Depth/Stencil texture must have a pixel type of DEPTH_STENCIL!"),e.dataType!==a.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!"),U(e,this._desc),this._desc.depthStencilTarget&&this._desc.depthStencilTarget!==o.DEPTH_STENCIL_TEXTURE&&(this._desc.depthStencilTarget=o.DEPTH_STENCIL_TEXTURE),this._disposeDepthStencilAttachments(),this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(t.glName,l)),this._depthStencilTexture=t}detachDepthStencilTexture(){const t=this._depthStencilTexture;return t&&this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(null,l)),this._depthStencilTexture=null,t}attachDepthStencilBuffer(t){if(i(t))return;const e=t.descriptor;if(e.internalFormat!==T.DEPTH_STENCIL&&e.internalFormat!==T.DEPTH_COMPONENT16&&console.error("Depth/Stencil buffer must have correct internalFormat"),H(e,this._desc),this._disposeDepthStencilAttachments(),this._desc.depthStencilTarget=e.internalFormat===T.DEPTH_STENCIL?o.DEPTH_STENCIL_RENDER_BUFFER:o.DEPTH_RENDER_BUFFER,this._initialized){this._context.bindFramebuffer(this);const e=this._context.gl,i=this._desc.depthStencilTarget===o.DEPTH_RENDER_BUFFER?e.DEPTH_ATTACHMENT:e.DEPTH_STENCIL_ATTACHMENT;e.framebufferRenderbuffer(E.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===o.DEPTH_RENDER_BUFFER?t.DEPTH_ATTACHMENT:t.DEPTH_STENCIL_ATTACHMENT;t.framebufferRenderbuffer(E.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,h,s,n){(t<0||e<0||h<0||s<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!==d.TEXTURE_2D&&console.error("Texture target must be TEXTURE_2D!"),(null==c?.width||null==c?.height||null==o?.width||null==o?.height||t+i>c.width||e+r>c.height||h+i>o.width||s+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,N.TEXTURE_UNIT_FOR_UPDATES);_.setActiveTexture(N.TEXTURE_UNIT_FOR_UPDATES),_.bindFramebuffer(this),_.gl.copyTexSubImage2D(d.TEXTURE_2D,0,h,s,t,e,i,r),_.bindTexture(a,N.TEXTURE_UNIT_FOR_UPDATES)}readPixels(t,e,i,r,h,s,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,h,s,n)}async readPixelsAsync(t,e,i,n,c,o,_){if(this._context.type!==s.WEBGL2)return h()&&console.warn("Attempting to read pixels using pixel buffer object without WebGL2"),void this.readPixels(t,e,i,n,c,o,_);const a=this._context.gl,l=r.createPixelPack(this._context,u.STREAM_READ,_.byteLength);this._context.bindBuffer(l),this._context.bindFramebuffer(this),a.readPixels(t,e,i,n,c,o,0),this._context.unbindBuffer(f.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=E.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??m.RENDER_BUFFER,l=s.width??1,u=s.height??1;if(e.bindFramebuffer(t,r),0===this._colorAttachments.size)if(n===m.TEXTURE||n===m.CUBEMAP)this._colorAttachments.set(c.COLOR_ATTACHMENT0,S(i,s,this.descriptor.colorTarget===m.CUBEMAP?d.TEXTURE_CUBE_MAP:d.TEXTURE_2D));else{const t=new g(i,{internalFormat:A.RGBA4,width:l,height:u});this._colorAttachments.set(c.COLOR_ATTACHMENT0,t)}this._colorAttachments.forEach(((i,r)=>{i&&(b(i)?this._framebufferTexture2D(i.glName,r,P(i),t):e.framebufferRenderbuffer(t,r,e.RENDERBUFFER,i.glName))}));const f=s.depthStencilTarget??o.NONE;switch(f){case o.DEPTH_RENDER_BUFFER:case o.DEPTH_STENCIL_RENDER_BUFFER:{this._depthAttachment||(this._depthAttachment=new g(i,{internalFormat:s.depthStencilTarget===o.DEPTH_RENDER_BUFFER?T.DEPTH_COMPONENT16:T.DEPTH_STENCIL,width:l,height:u}));const r=f===o.DEPTH_RENDER_BUFFER?e.DEPTH_ATTACHMENT:e.DEPTH_STENCIL_ATTACHMENT;e.framebufferRenderbuffer(t,r,e.RENDERBUFFER,this._depthAttachment.glName);break}case o.STENCIL_RENDER_BUFFER:this._stencilAttachment||(this._stencilAttachment=new g(i,{internalFormat:T.STENCIL_INDEX8,width:l,height:u})),e.framebufferRenderbuffer(t,e.STENCIL_ATTACHMENT,e.RENDERBUFFER,this._stencilAttachment.glName);break;case o.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:d.TEXTURE_2D,pixelFormat:_.DEPTH_STENCIL,dataType:a.UNSIGNED_INT_24_8,samplingMode:p.NEAREST,wrapMode:R.CLAMP_TO_EDGE,width:l,height:u};this._depthStencilTexture=new N(i,t)}this._framebufferTexture2D(this._depthStencilTexture.glName,e.DEPTH_STENCIL_ATTACHMENT,P(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=c.COLOR_ATTACHMENT0,i=d.TEXTURE_2D,r=E.FRAMEBUFFER,h=0){this._context.gl.framebufferTexture2D(r,e,i,t,h)}_detachColorAttachment(t){h()&&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 b(i)?this._initialized&&(this._context.bindFramebuffer(this),this._framebufferTexture2D(null,t)):this._initialized&&(this._context.bindFramebuffer(this),e.framebufferRenderbuffer(E.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===o.DEPTH_RENDER_BUFFER?t.DEPTH_ATTACHMENT:t.DEPTH_STENCIL_ATTACHMENT;t.framebufferRenderbuffer(E.FRAMEBUFFER,e,t.RENDERBUFFER,null)}this._depthAttachment.dispose(),this._depthAttachment=null}this._stencilAttachment&&(this._initialized&&(this._context.bindFramebuffer(this),t.framebufferRenderbuffer(E.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(e){if(-1===x._MAX_COLOR_ATTACHMENTS){const t=this._context.capabilities.drawBuffers;if(t){const e=this._context.gl;x._MAX_COLOR_ATTACHMENTS=e.getParameter(t.MAX_COLOR_ATTACHMENTS)}else x._MAX_COLOR_ATTACHMENTS=1}const i=e-c.COLOR_ATTACHMENT0;i+1>x._MAX_COLOR_ATTACHMENTS&&t.getLogger("esri.views.webgl.FrameBufferObject").error("esri.FrameBufferObject",`illegal attachment point for color attachment: ${i+1}. Implementation supports up to ${x._MAX_COLOR_ATTACHMENTS} color attachments`)}}function b(t){return null!=t&&"type"in t&&"texture"===t.type}function D(t){return null!=t&&"type"in t&&"renderbuffer"===t.type}function C(t){return b(t)||null!=t&&"pixelFormat"in t}function S(t,e,i){return new N(t,{target:i,pixelFormat:_.RGBA,dataType:a.UNSIGNED_BYTE,samplingMode:p.NEAREST,wrapMode:R.CLAMP_TO_EDGE,width:e.width,height:e.height})}function U(t,e){t.target!==d.TEXTURE_2D&&t.target!==d.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 H(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 P(t){return t.descriptor.target===d.TEXTURE_CUBE_MAP?d.TEXTURE_CUBE_MAP_POSITIVE_X:d.TEXTURE_2D}x._MAX_COLOR_ATTACHMENTS=-1;export{x as FramebufferObject};