{"record":{"id":"260b8fd7c429a8d6","repo":"BabylonJS/Babylon.js","slug":"updatewrappednativetexture-new-handle-dimensions","errorCode":null,"errorMessage":"updateWrappedNativeTexture: new handle dimensions (${newWidth}x${newHeight}) must match the wrapped texture's dimensions (${internalTexture.baseWidth}x${internalTexture.baseHeight}).","messagePattern":"updateWrappedNativeTexture: new handle dimensions \\((.+?)x(.+?)\\) must match the wrapped texture's dimensions \\((.+?)x(.+?)\\)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Engines/thinNativeEngine.pure.ts","lineNumber":2164,"sourceCode":"     * texture and call {@link wrapNativeTexture} again. Sampling mode and mip-map flag are properties of the logical\r\n     * wrapped texture and are re-applied to the new resource. Any render-target wrapper holding this texture as its\r\n     * color attachment has its framebuffer rebuilt with the new handle.\r\n     *\r\n     * Throws if the target was not produced by {@link wrapNativeTexture}, if the new handle's dimensions don't match,\r\n     * if the wrapped texture is part of a multi render-target, or if the wrapper has a depth/stencil texture (these\r\n     * are not supported in this version; dispose and re-wrap).\r\n     * @param internalTexture defines the wrapped InternalTexture to repoint\r\n     * @param texture defines the new native texture handle to wrap\r\n     */\r\n    public updateWrappedNativeTexture(internalTexture: InternalTexture, texture: NativeTexture): void {\r\n        if (internalTexture.source !== InternalTextureSource.External) {\r\n            throw new Error(\"updateWrappedNativeTexture: target InternalTexture was not produced by wrapNativeTexture.\");\r\n        }\r\n\r\n        const newWidth = this._engine.getTextureWidth(texture);\r\n        const newHeight = this._engine.getTextureHeight(texture);\r\n        if (newWidth !== internalTexture.baseWidth || newHeight !== internalTexture.baseHeight) {\r\n            throw new Error(\r\n                `updateWrappedNativeTexture: new handle dimensions (${newWidth}x${newHeight}) must match the wrapped texture's dimensions (${internalTexture.baseWidth}x${internalTexture.baseHeight}).`\r\n            );\r\n        }\r\n        if (this._engine.getTextureLayerCount) {\r\n            const newLayerCount = this._engine.getTextureLayerCount(texture);\r\n            const oldLayerCount = internalTexture.is2DArray ? internalTexture.depth : 1;\r\n            if (newLayerCount !== oldLayerCount) {\r\n                throw new Error(`updateWrappedNativeTexture: new handle layer count (${newLayerCount}) must match the wrapped texture's layer count (${oldLayerCount}).`);\r\n            }\r\n        }\r\n\r\n        // Pre-validate before mutating any state so a thrown precondition leaves the InternalTexture untouched.\r\n        // Note: rtWrapper.texture only returns _textures[0]; walk every attachment to catch the multi-RT case where\r\n        // the wrapped texture is at index > 0.\r\n        for (const rtWrapper of this._renderTargetWrapperCache) {\r\n            if (!rtWrapper.textures?.includes(internalTexture)) {\r\n                continue;\r\n            }\r","sourceCodeStart":2146,"sourceCodeEnd":2182,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Engines/thinNativeEngine.pure.ts#L2146-L2182","documentation":"updateWrappedNativeTexture requires the new native texture handle to have exactly the same dimensions as the wrapped InternalTexture (baseWidth/baseHeight), because bgfx framebuffers and engine caches bake the size into state that is not rebuilt here.","triggerScenarios":"engine.updateWrappedNativeTexture(wrapped, newNativeTex) where engine._engine.getTextureWidth/Height(newNativeTex) differ from wrapped.baseWidth/baseHeight, e.g. after resizing an offscreen render target.","commonSituations":"Window/resize events recreate a native texture at a new resolution and the caller tries to swap it into the existing wrapped texture instead of disposing and re-wrapping at the new size.","solutions":["Dispose the wrapped texture and call wrapNativeTexture again with the new handle and its actual dimensions.","Recreate the new native texture at the original dimensions before updating.","Update dependent render targets and viewport state after recreating at the new size."],"exampleFix":"// before\nengine.updateWrappedNativeTexture(wrapped, resizedNativeTex); // throws on size mismatch\n\n// after\nwrapped.dispose();\nconst wrapped2 = engine.wrapNativeTexture(resizedNativeTex, newW, newH, ...);","handlingStrategy":"validation","validationCode":"const w = engine._engine.getTextureWidth(newNativeTex);\nconst h = engine._engine.getTextureHeight(newNativeTex);\nif (w !== wrapped.baseWidth || h !== wrapped.baseHeight) {\n  throw new Error(`Resize mismatch: ${w}x${h} vs ${wrapped.baseWidth}x${wrapped.baseHeight}; dispose and re-wrap.`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  engine.updateWrappedNativeTexture(wrapped, newNativeTex);\n} catch (e) {\n  if (e.message.includes(\"dimensions\")) {\n    wrapped.dispose();\n    wrapped = engine.wrapNativeTexture(newNativeTex, newW, newH, sampling, ...);\n  } else throw e;\n}","preventionTips":["On resize events, always dispose + re-wrap rather than updating in place.","Store expected dimensions alongside wrapped handles and assert before updates.","Pin render-target sizes during a frame; resize only between frames with full re-wrap."],"tags":["native","texture-wrapping","dimension-mismatch"],"backgroundTag":"texture-size-mismatch","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}