Browse Source

Wrap InternalTexture._webGLTexture in HardwareTextureWrapper

Popov72 5 years ago
parent
commit
7f56cfc80c

+ 4 - 4
src/Engines/Extensions/engine.multiRender.ts

@@ -171,7 +171,7 @@ ThinEngine.prototype.createMultipleRenderTarget = function(size: any, options: I
         attachments.push(attachment);
 
         gl.activeTexture((<any>gl)["TEXTURE" + i]);
-        gl.bindTexture(gl.TEXTURE_2D, texture._webGLTexture);
+        gl.bindTexture(gl.TEXTURE_2D, texture._hardwareTexture?.underlyingResource ?? null);
 
         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filters.mag);
         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filters.min);
@@ -180,7 +180,7 @@ ThinEngine.prototype.createMultipleRenderTarget = function(size: any, options: I
 
         gl.texImage2D(gl.TEXTURE_2D, 0, this._getRGBABufferInternalSizedFormat(type), width, height, 0, gl.RGBA, this._getWebGLTextureType(type), null);
 
-        gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, attachment, gl.TEXTURE_2D, texture._webGLTexture, 0);
+        gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, attachment, gl.TEXTURE_2D, texture._hardwareTexture?.underlyingResource ?? null, 0);
 
         if (generateMipMaps) {
             this._gl.generateMipmap(this._gl.TEXTURE_2D);
@@ -213,7 +213,7 @@ ThinEngine.prototype.createMultipleRenderTarget = function(size: any, options: I
         var depthTexture = new InternalTexture(this, InternalTextureSource.MultiRenderTarget);
 
         gl.activeTexture(gl.TEXTURE0);
-        gl.bindTexture(gl.TEXTURE_2D, depthTexture._webGLTexture);
+        gl.bindTexture(gl.TEXTURE_2D, depthTexture._hardwareTexture?.underlyingResource ?? null);
         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
@@ -234,7 +234,7 @@ ThinEngine.prototype.createMultipleRenderTarget = function(size: any, options: I
             gl.FRAMEBUFFER,
             gl.DEPTH_ATTACHMENT,
             gl.TEXTURE_2D,
-            depthTexture._webGLTexture,
+            depthTexture._hardwareTexture?.underlyingResource ?? null,
             0
         );
 

+ 2 - 2
src/Engines/Extensions/engine.readTexture.ts

@@ -26,9 +26,9 @@ ThinEngine.prototype._readTexturePixels = function(texture: InternalTexture, wid
     gl.bindFramebuffer(gl.FRAMEBUFFER, this._dummyFramebuffer);
 
     if (faceIndex > -1) {
-        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._webGLTexture, level);
+        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._hardwareTexture?.underlyingResource ?? null, level);
     } else {
-        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture._webGLTexture, level);
+        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture._hardwareTexture?.underlyingResource ?? null, level);
     }
 
     let readType = (texture.type !== undefined) ? this._getWebGLTextureType(texture.type) : gl.UNSIGNED_BYTE;

+ 1 - 1
src/Engines/Extensions/engine.renderTarget.ts

@@ -101,7 +101,7 @@ ThinEngine.prototype.createRenderTargetTexture = function(this: ThinEngine, size
 
     // No need to rebind on every frame
     if (!texture.is2DArray) {
-        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture._webGLTexture, 0);
+        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture._hardwareTexture?.underlyingResource ?? null, 0);
     }
 
     this._bindUnboundFramebuffer(null);

+ 39 - 0
src/Engines/WebGL/webGLHardwareTexture.ts

@@ -0,0 +1,39 @@
+import { HardwareTextureWrapper } from '../../Materials/Textures/hardwareTextureWrapper';
+import { Nullable } from '../../types';
+
+/** @hidden */
+export class WebGLHardwareTexture implements HardwareTextureWrapper {
+
+    private _webGLTexture: WebGLTexture;
+    private _context: WebGLRenderingContext;
+
+    public get underlyingResource(): Nullable<WebGLTexture> {
+        return this._webGLTexture;
+    }
+
+    constructor(existingTexture: Nullable<WebGLTexture> = null, context: WebGLRenderingContext) {
+        this._context = context as WebGLRenderingContext;
+        if (!existingTexture) {
+            existingTexture = context.createTexture();
+            if (!existingTexture) {
+                throw new Error("Unable to create webGL texture");
+            }
+        }
+        this.set(existingTexture);
+    }
+
+    public set(hardwareTexture: WebGLTexture) {
+        this._webGLTexture = hardwareTexture;
+    }
+
+    public reset() {
+        this._webGLTexture = null as any;
+    }
+
+    public release() {
+        if (this._webGLTexture) {
+            this._context.deleteTexture(this._webGLTexture);
+        }
+        this.reset();
+    }
+};

+ 51 - 0
src/Engines/WebGPU/webgpuHardwareTexture.ts

@@ -0,0 +1,51 @@
+import { HardwareTextureWrapper } from '../../Materials/Textures/hardwareTextureWrapper';
+import { Nullable } from '../../types';
+
+/** @hidden */
+export class WebGPUHardwareTexture implements HardwareTextureWrapper {
+
+    private _webgpuTexture: Nullable<GPUTexture>;
+    private _webgpuTextureView: Nullable<GPUTextureView>;
+    private _webgpuSampler: Nullable<GPUSampler>;
+
+    public get underlyingResource(): Nullable<GPUTexture> {
+        return this._webgpuTexture;
+    }
+
+    public get view(): Nullable<GPUTextureView> {
+        return this._webgpuTextureView;
+    }
+
+    public get sampler(): Nullable<GPUSampler> {
+        return this._webgpuSampler;
+    }
+
+    constructor(existingTexture: Nullable<GPUTexture> = null) {
+        this._webgpuTexture = existingTexture;
+        this._webgpuTextureView = null;
+        this._webgpuSampler = null;
+    }
+
+    public set(hardwareTexture: GPUTexture) {
+        this._webgpuTexture = hardwareTexture;
+    }
+
+    public createView(descriptor?: GPUTextureViewDescriptor) {
+        this._webgpuTextureView = this._webgpuTexture!.createView(descriptor);
+    }
+
+    public setSampler(sampler: GPUSampler) {
+        this._webgpuSampler = sampler;
+    }
+
+    public reset() {
+        this._webgpuTexture = null;
+        this._webgpuTextureView = null as any;
+        this._webgpuSampler = null as any;
+    }
+
+    public release() {
+        this._webgpuTexture?.destroy();
+        this.reset();
+    }
+};

+ 12 - 12
src/Engines/nativeEngine.ts

@@ -1350,7 +1350,7 @@ export class NativeEngine extends Engine {
         this._cachedEffectForVertexBuffers = null;
     }
 
-    public _createTexture(): WebGLTexture {
+    protected _createTexture(): WebGLTexture {
         return this._native.createTexture();
     }
 
@@ -1457,7 +1457,7 @@ export class NativeEngine extends Engine {
             throw new Error("Loading textures from IInternalTextureLoader not yet implemented.");
         } else {
             const onload = (data: ArrayBufferView) => {
-                const webGLTexture = texture._webGLTexture;
+                const webGLTexture = texture._hardwareTexture?.underlyingResource ?? null;
                 if (!webGLTexture) {
                     if (scene) {
                         scene._removePendingData(texture);
@@ -1586,7 +1586,7 @@ export class NativeEngine extends Engine {
                 texture._isRGBD = true;
                 texture.invertY = true;
 
-                this._native.loadCubeTextureWithMips(texture._webGLTexture!, imageData, () => {
+                this._native.loadCubeTextureWithMips(texture._hardwareTexture!.underlyingResource, imageData, () => {
                     texture.isReady = true;
                     if (onLoad) {
                         onLoad();
@@ -1618,7 +1618,7 @@ export class NativeEngine extends Engine {
             const reorderedFiles = [files[0], files[3], files[1], files[4], files[2], files[5]];
             Promise.all(reorderedFiles.map((file) => Tools.LoadFileAsync(file).then((data) => new Uint8Array(data as ArrayBuffer)))).then((data) => {
                 return new Promise((resolve, reject) => {
-                    this._native.loadCubeTexture(texture._webGLTexture!, data, !noMipmap, resolve, reject);
+                    this._native.loadCubeTexture(texture._hardwareTexture!.underlyingResource, data, !noMipmap, resolve, reject);
                 });
             }).then(() => {
                 texture.isReady = true;
@@ -1723,7 +1723,7 @@ export class NativeEngine extends Engine {
         }
 
         var framebuffer = this._native.createFramebuffer(
-            texture._webGLTexture!,
+            texture._hardwareTexture!.underlyingResource,
             width,
             height,
             NativeEngine._GetNativeTextureFormat(fullOptions.format, fullOptions.type),
@@ -1752,9 +1752,9 @@ export class NativeEngine extends Engine {
     }
 
     public updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void {
-        if (texture._webGLTexture) {
+        if (texture._hardwareTexture?.underlyingResource ?? false) {
             var filter = this._getSamplingFilter(samplingMode);
-            this._native.setTextureSampling(texture._webGLTexture, filter);
+            this._native.setTextureSampling(texture._hardwareTexture?.underlyingResource ?? null, filter);
         }
         texture.samplingMode = samplingMode;
     }
@@ -1858,18 +1858,18 @@ export class NativeEngine extends Engine {
         this._activeChannel = channel;
 
         if (!internalTexture ||
-            !internalTexture._webGLTexture) {
+            !(internalTexture._hardwareTexture?.underlyingResource ?? null)) {
             return false;
         }
 
         this._native.setTextureWrapMode(
-            internalTexture._webGLTexture,
+            internalTexture._hardwareTexture?.underlyingResource ?? null,
             this._getAddressMode(texture.wrapU),
             this._getAddressMode(texture.wrapV),
             this._getAddressMode(texture.wrapR));
         this._updateAnisotropicLevel(texture);
 
-        this._native.setTexture(uniform, internalTexture._webGLTexture);
+        this._native.setTexture(uniform, internalTexture._hardwareTexture?.underlyingResource ?? null);
 
         return true;
     }
@@ -1880,12 +1880,12 @@ export class NativeEngine extends Engine {
         var internalTexture = texture.getInternalTexture();
         var value = texture.anisotropicFilteringLevel;
 
-        if (!internalTexture || !internalTexture._webGLTexture) {
+        if (!internalTexture || !(internalTexture._hardwareTexture?.underlyingResource ?? null)) {
             return;
         }
 
         if (internalTexture._cachedAnisotropicFilteringLevel !== value) {
-            this._native.setTextureAnisotropicLevel(internalTexture._webGLTexture, value);
+            this._native.setTextureAnisotropicLevel(internalTexture._hardwareTexture?.underlyingResource ?? null, value);
             internalTexture._cachedAnisotropicFilteringLevel = value;
         }
     }

+ 1 - 1
src/Engines/nullEngine.ts

@@ -537,7 +537,7 @@ export class NullEngine extends Engine {
     }
 
     /** @hidden */
-    public _createTexture(): WebGLTexture {
+    protected _createTexture(): WebGLTexture {
         return {};
     }
 

+ 20 - 11
src/Engines/thinEngine.ts

@@ -31,6 +31,8 @@ import { IWebRequest } from '../Misc/interfaces/iWebRequest';
 import { CanvasGenerator } from '../Misc/canvasGenerator';
 import { PerformanceConfigurator } from './performanceConfigurator';
 import { EngineFeatures } from './engineFeatures';
+import { HardwareTextureWrapper } from '../Materials/Textures/hardwareTextureWrapper';
+import { WebGLHardwareTexture } from './WebGL/webGLHardwareTexture';
 
 declare type WebRequest = import("../Misc/webRequest").WebRequest;
 declare type LoadFileError = import("../Misc/fileTools").LoadFileError;
@@ -160,7 +162,7 @@ export class ThinEngine {
     public static Features: EngineFeatures = {
         forceBitmapOverHTMLImageElement: false,
         supportRenderAndCopyToLodForFloatTextures: false,
-    }
+    };
 
     /**
      * Returns a string describing the current engine
@@ -1363,23 +1365,23 @@ export class ThinEngine {
 
         const gl = this._gl;
         if (texture.is2DArray) {
-            gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture._webGLTexture, lodLevel, layer);
+            gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture._hardwareTexture!.underlyingResource, lodLevel, layer);
         }
         else if (texture.isCube) {
-            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._webGLTexture, lodLevel);
+            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._hardwareTexture!.underlyingResource, lodLevel);
         }
 
         const depthStencilTexture = texture._depthStencilTexture;
         if (depthStencilTexture) {
             const attachment = (depthStencilTexture._generateStencilBuffer) ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT;
             if (texture.is2DArray) {
-                gl.framebufferTextureLayer(gl.FRAMEBUFFER, attachment, depthStencilTexture._webGLTexture, lodLevel, layer);
+                gl.framebufferTextureLayer(gl.FRAMEBUFFER, attachment, depthStencilTexture._hardwareTexture!.underlyingResource, lodLevel, layer);
             }
             else if (texture.isCube) {
-                gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._webGLTexture, lodLevel);
+                gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._hardwareTexture!.underlyingResource, lodLevel);
             }
             else {
-                gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, depthStencilTexture._webGLTexture, lodLevel);
+                gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, depthStencilTexture._hardwareTexture!.underlyingResource, lodLevel);
             }
         }
 
@@ -2836,7 +2838,7 @@ export class ThinEngine {
     }
 
     /** @hidden */
-    public _createTexture(): WebGLTexture {
+    protected _createTexture(): WebGLTexture {
         let texture = this._gl.createTexture();
 
         if (!texture) {
@@ -2846,6 +2848,11 @@ export class ThinEngine {
         return texture;
     }
 
+    /** @hidden */
+    public _createHardwareTexture(): HardwareTextureWrapper {
+        return new WebGLHardwareTexture(this._createTexture(), this._gl);
+    }
+
     protected _createTextureBase(url: Nullable<string>, noMipmap: boolean, invertY: boolean, scene: Nullable<ISceneLike>, samplingMode: number = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE,
         onLoad: Nullable<() => void> = null, onError: Nullable<(message: string, exception: any) => void> = null,
         prepareTexture: (texture: InternalTexture, extension: string, scene: Nullable<ISceneLike>, img: HTMLImageElement | ImageBitmap | { width: number, height: number }, invertY: boolean, noMipmap: boolean, isCompressed: boolean,
@@ -3393,7 +3400,7 @@ export class ThinEngine {
             return;
         }
 
-        if (!texture._webGLTexture) {
+        if (!texture._hardwareTexture!.underlyingResource) {
             //  this.resetTextureCache();
             if (scene) {
                 scene._removePendingData(texture);
@@ -3492,7 +3499,7 @@ export class ThinEngine {
     public _releaseTexture(texture: InternalTexture): void {
         this._releaseFramebufferObjects(texture);
 
-        this._deleteTexture(texture._webGLTexture);
+        this._deleteTexture(texture._hardwareTexture?.underlyingResource);
 
         // Unbind channels
         this.unbindAllTextures();
@@ -3520,7 +3527,9 @@ export class ThinEngine {
     }
 
     protected _deleteTexture(texture: Nullable<WebGLTexture>): void {
-        this._gl.deleteTexture(texture);
+        if (texture) {
+            this._gl.deleteTexture(texture);
+        }
     }
 
     protected _setProgram(program: WebGLProgram): void {
@@ -3573,7 +3582,7 @@ export class ThinEngine {
             if (texture && texture.isMultiview) {
                 this._gl.bindTexture(target, texture ? texture._colorTextureArray : null);
             } else {
-                this._gl.bindTexture(target, texture ? texture._webGLTexture : null);
+                this._gl.bindTexture(target, texture ? texture._hardwareTexture!.underlyingResource : null);
             }
 
             this._boundTexturesCache[this._activeChannel] = texture;

+ 121 - 27
src/Engines/webgpuEngine.ts

@@ -27,6 +27,8 @@ import { Scene } from '../scene';
 import { Scalar } from '../Maths/math.scalar';
 import { WebGPUBufferManager } from './WebGPU/webgpuBufferManager';
 import { DepthTextureCreationOptions } from './depthTextureCreationOptions';
+import { HardwareTextureWrapper } from '../Materials/Textures/hardwareTextureWrapper';
+import { WebGPUHardwareTexture } from './WebGPU/webgpuHardwareTexture';
 
 /**
  * Options to load the associated Glslang library
@@ -879,15 +881,17 @@ export class WebGPUEngine extends Engine {
     //------------------------------------------------------------------------------
 
     /** @hidden */
-    public _createTexture(): WebGLTexture {
-        // TODO WEBGPU. This should return the GPUTexture, WebGLTexture might need to be wrapped like the buffers.
-        return { };
+    public _createHardwareTexture(): HardwareTextureWrapper {
+        return new WebGPUHardwareTexture();
     }
 
     /** @hidden */
     public _releaseTexture(texture: InternalTexture): void {
-        if (texture._webGPUTexture) {
-            texture._webGPUTexture.destroy();
+        texture._hardwareTexture?.release();
+
+        const index = this._internalTexturesCache.indexOf(texture);
+        if (index !== -1) {
+            this._internalTexturesCache.splice(index, 1);
         }
 
         delete this._cacheTextureCreation[texture.id];
@@ -1206,8 +1210,10 @@ export class WebGPUEngine extends Engine {
 
                     // TODO WEBGPU: handle format if <> 0. Note that it seems "rgb" formats don't exist in WebGPU...
                     //let internalFormat = format ? this._getInternalFormat(format) : ((extension === ".jpg") ? gl.RGB : gl.RGBA);
-                    texture._webGPUTexture = await this._textureHelper.createTexture(imageBitmap, !noMipmap, invertY, false, this._getWebGPUTextureFormat(texture.type, texture.format));
-                    texture._webGPUTextureView = texture._webGPUTexture.createView();
+                    const gpuTexture = await this._textureHelper.createTexture(imageBitmap, !noMipmap, invertY, false, this._getWebGPUTextureFormat(texture.type, texture.format));
+
+                    texture._hardwareTexture!.set(gpuTexture);
+                    (texture._hardwareTexture as WebGPUHardwareTexture).createView();
 
                     if (scene) {
                         scene._removePendingData(texture);
@@ -1248,8 +1254,10 @@ export class WebGPUEngine extends Engine {
 
                 // TODO WEBGPU. handle format if <> 0
                 //const internalFormat = format ? this._getInternalFormat(format) : this._gl.RGBA;
-                texture._webGPUTexture = await this._textureHelper.createCubeTexture(imageBitmaps, !noMipmap, false, false, this._getWebGPUTextureFormat(texture.type, texture.format));
-                texture._webGPUTextureView = texture._webGPUTexture.createView({
+                const gpuTexture = await this._textureHelper.createCubeTexture(imageBitmaps, !noMipmap, false, false, this._getWebGPUTextureFormat(texture.type, texture.format));
+
+                texture._hardwareTexture!.set(gpuTexture);
+                (texture._hardwareTexture as WebGPUHardwareTexture).createView({
                     dimension: WebGPUConstants.TextureViewDimension.Cube
                 });
 
@@ -1278,13 +1286,6 @@ export class WebGPUEngine extends Engine {
         }
     }
 
-    /** @hidden */
-    public _createDepthStencilCubeTexture(size: number, options: DepthTextureCreationOptions): InternalTexture {
-        console.warn("_createDepthStencilCubeTexture not implemented yet in WebGPU");
-
-        return null as any;
-    }
-
     public updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void {
         texture.samplingMode = samplingMode;
     }
@@ -1348,7 +1349,7 @@ export class WebGPUEngine extends Engine {
             return promise;
         }
 
-        promise = Promise.resolve(texture._webGPUTexture as GPUTexture);
+        promise = Promise.resolve(texture._hardwareTexture!.underlyingResource ?? null);
 
         if (width === undefined) {
             width = texture.width;
@@ -1357,11 +1358,11 @@ export class WebGPUEngine extends Engine {
             height = texture.height;
         }
 
-        if (!texture._webGPUTexture) {
+        if (!texture._hardwareTexture!.underlyingResource) {
             if (texture.isCube) {
                 promise = this._textureHelper.createCubeTexture({ width, height }, texture.generateMipMaps, texture.invertY, false, this._getWebGPUTextureFormat(texture.type, texture.format)).then((gpuTexture) => {
-                    texture._webGPUTexture = gpuTexture;
-                    texture._webGPUTextureView = texture._webGPUTexture.createView({
+                    texture._hardwareTexture!.set(gpuTexture);
+                    (texture._hardwareTexture as WebGPUHardwareTexture).createView({
                         dimension: WebGPUConstants.TextureViewDimension.Cube,
                         mipLevelCount: Math.round(Scalar.Log2(Math.max(width!, height!))) + 1,
                         baseArrayLayer: 0,
@@ -1372,8 +1373,8 @@ export class WebGPUEngine extends Engine {
                 });
             } else {
                 promise = this._textureHelper.createTexture({ width, height }, texture.generateMipMaps, texture.invertY, false, this._getWebGPUTextureFormat(texture.type, texture.format)).then((gpuTexture) => {
-                    texture._webGPUTexture = gpuTexture;
-                    texture._webGPUTextureView = texture._webGPUTexture.createView();
+                    texture._hardwareTexture!.set(gpuTexture);
+                    (texture._hardwareTexture as WebGPUHardwareTexture).createView();
                     return gpuTexture;
                 });
             }
@@ -1421,6 +1422,35 @@ export class WebGPUEngine extends Engine {
         });
     }
 
+    public updateVideoTexture(texture: Nullable<InternalTexture>, video: HTMLVideoElement, invertY: boolean): void {
+        console.warn("updateVideoTexture not implemented yet in WebGPU");
+
+        // TODO WEBGPU is there/will be a native way to handle video textures?
+        /*if (!texture._workingCanvas) {
+            texture._workingCanvas = CanvasGenerator.CreateCanvas(texture.width, texture.height);
+            let context = texture._workingCanvas.getContext("2d");
+
+            if (!context) {
+                throw new Error("Unable to get 2d context");
+            }
+
+            texture._workingContext = context;
+            texture._workingCanvas.width = texture.width;
+            texture._workingCanvas.height = texture.height;
+        }
+
+        texture._workingContext!.clearRect(0, 0, texture.width, texture.height);
+        texture._workingContext!.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, texture.width, texture.height);
+
+        this._gl.texImage2D(this._gl.TEXTURE_2D, 0, this._gl.RGBA, this._gl.RGBA, this._gl.UNSIGNED_BYTE, texture._workingCanvas);
+
+        if (texture.generateMipMaps) {
+            this._gl.generateMipmap(this._gl.TEXTURE_2D);
+        }
+
+        texture.isReady = true;*/
+    }
+
     /** @hidden */
     public _uploadCompressedDataToTextureDirectly(texture: InternalTexture, internalFormat: number, width: number, height: number, data: ArrayBufferView, faceIndex: number = 0, lod: number = 0) {
         console.warn("_uploadCompressedDataToTextureDirectly not implemented yet in WebGPU");
@@ -1460,10 +1490,40 @@ export class WebGPUEngine extends Engine {
         });
     }
 
+    /** @hidden */
+    public _readTexturePixels(texture: InternalTexture, width: number, height: number, faceIndex = -1, level = 0, buffer: Nullable<ArrayBufferView> = null): ArrayBufferView {
+        console.warn("_readTexturePixels not implemented yet in WebGPU");
+
+        return null as any;
+        /*let readType = (texture.type !== undefined) ? this._getWebGLTextureType(texture.type) : gl.UNSIGNED_BYTE;
+
+        switch (readType) {
+            case gl.UNSIGNED_BYTE:
+                if (!buffer) {
+                    buffer = new Uint8Array(4 * width * height);
+                }
+                readType = gl.UNSIGNED_BYTE;
+                break;
+            default:
+                if (!buffer) {
+                    buffer = new Float32Array(4 * width * height);
+                }
+                readType = gl.FLOAT;
+                break;
+        }
+
+        gl.readPixels(0, 0, width, height, gl.RGBA, readType, <DataView>buffer);*/
+    }
+
     //------------------------------------------------------------------------------
     //                              Render Target Textures
     //------------------------------------------------------------------------------
 
+    /** @hidden */
+    public _setupDepthStencilTexture(internalTexture: InternalTexture, size: number | { width: number, height: number, layers?: number }, generateStencil: boolean, bilinearFiltering: boolean, comparisonFunction: number): void {
+        console.warn("_setupDepthStencilTexture not implemented yet in WebGPU");
+    }
+
     public createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture {
         let fullOptions = new RenderTargetCreationOptions();
 
@@ -1473,18 +1533,22 @@ export class WebGPUEngine extends Engine {
             fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && options.generateStencilBuffer;
             fullOptions.type = options.type === undefined ? Constants.TEXTURETYPE_UNSIGNED_INT : options.type;
             fullOptions.samplingMode = options.samplingMode === undefined ? Constants.TEXTURE_TRILINEAR_SAMPLINGMODE : options.samplingMode;
+            // TODO WEBGPU fullOptions.format not set?
         } else {
             fullOptions.generateMipMaps = <boolean>options;
             fullOptions.generateDepthBuffer = true;
             fullOptions.generateStencilBuffer = false;
             fullOptions.type = Constants.TEXTURETYPE_UNSIGNED_INT;
             fullOptions.samplingMode = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE;
+            // TODO WEBGPU fullOptions.format not set?
         }
         var texture = new InternalTexture(this, InternalTextureSource.RenderTarget);
 
         var width = size.width || size;
         var height = size.height || size;
 
+        // TODO WEBGPU handle layers
+
         texture._depthStencilBuffer = {};
         texture._framebuffer = {};
         texture.baseWidth = width;
@@ -1504,6 +1568,35 @@ export class WebGPUEngine extends Engine {
         return texture;
     }
 
+    public createRenderTargetCubeTexture(size: number, options?: Partial<RenderTargetCreationOptions>): InternalTexture {
+        var texture = new InternalTexture(this, InternalTextureSource.RenderTarget);
+
+        this._internalTexturesCache.push(texture);
+
+        console.warn("createRenderTargetCubeTexture not implemented yet in WebGPU");
+
+        return texture;
+    }
+
+    /** @hidden */
+    public _createDepthStencilTexture(size: number | { width: number, height: number, layers?: number }, options: DepthTextureCreationOptions): InternalTexture {
+        const internalTexture = new InternalTexture(this, InternalTextureSource.Depth);
+
+        console.warn("_createDepthStencilTexture not implemented yet in WebGPU");
+
+        return internalTexture;
+    }
+
+    /** @hidden */
+    public _createDepthStencilCubeTexture(size: number, options: DepthTextureCreationOptions): InternalTexture {
+        var internalTexture = new InternalTexture(this, InternalTextureSource.Unknown);
+        internalTexture.isCube = true;
+
+        console.warn("_createDepthStencilCubeTexture not implemented yet in WebGPU");
+
+        return internalTexture;
+    }
+
     //------------------------------------------------------------------------------
     //                              Render Commands
     //------------------------------------------------------------------------------
@@ -2234,24 +2327,25 @@ export class WebGPUEngine extends Engine {
                 if (bindingDefinition.isSampler) {
                     const bindingInfo = webgpuPipelineContext.samplers[bindingDefinition.name];
                     if (bindingInfo) {
-                        if (!bindingInfo.texture._webGPUSampler) {
+                        const hardwareTexture = bindingInfo.texture._hardwareTexture as WebGPUHardwareTexture;
+                        if (!hardwareTexture.sampler) {
                             const samplerDescriptor: GPUSamplerDescriptor = this._getSamplerDescriptor(bindingInfo.texture!);
                             const gpuSampler = this._device.createSampler(samplerDescriptor);
-                            bindingInfo.texture._webGPUSampler = gpuSampler;
+                            hardwareTexture.setSampler(gpuSampler);
                         }
 
                         // TODO WEBGPU Remove this when all testings are ok
-                        if (!bindingInfo.texture._webGPUTextureView) {
+                        if (!hardwareTexture.view) {
                             console.error("Trying to bind a null gpu texture! bindingDefinition=", bindingDefinition, " | bindingInfo=", bindingInfo);
                             debugger;
                         }
 
                         entries.push({
                             binding: bindingInfo.textureBinding,
-                            resource: bindingInfo.texture._webGPUTextureView!,
+                            resource: hardwareTexture.view!,
                         }, {
                             binding: bindingInfo.samplerBinding,
-                            resource: bindingInfo.texture._webGPUSampler!,
+                            resource: hardwareTexture.sampler!,
                         });
                     }
                     else {

+ 9 - 0
src/Materials/Textures/hardwareTextureWrapper.ts

@@ -0,0 +1,9 @@
+/** @hidden */
+export interface HardwareTextureWrapper {
+
+    underlyingResource: any;
+
+    set(hardwareTexture: any): void;
+    reset(): void;
+    release(): void;
+}

+ 7 - 18
src/Materials/Textures/internalTexture.ts

@@ -4,6 +4,7 @@ import { RenderTargetCreationOptions } from "../../Materials/Textures/renderTarg
 import { Constants } from "../../Engines/constants";
 import { _DevTools } from '../../Misc/devTools';
 import { Engine } from '../../Engines/engine';
+import { HardwareTextureWrapper } from "./hardwareTextureWrapper";
 
 declare type ThinEngine = import("../../Engines/thinEngine").ThinEngine;
 declare type BaseTexture = import("../../Materials/Textures/baseTexture").BaseTexture;
@@ -249,13 +250,7 @@ export class InternalTexture {
     public _irradianceTexture: Nullable<BaseTexture> = null;
 
     /** @hidden */
-    public _webGLTexture: Nullable<WebGLTexture> = null;
-    /** @hidden */
-    public _webGPUTexture: Nullable<GPUTexture> = null;
-    /** @hidden */
-    public _webGPUSampler: Nullable<GPUSampler> = null;
-    /** @hidden */
-    public _webGPUTextureView: Nullable<GPUTextureView> = null;
+    public _hardwareTexture: Nullable<HardwareTextureWrapper> = null;
 
     /** @hidden */
     public _references: number = 1;
@@ -297,7 +292,7 @@ export class InternalTexture {
         this._id = InternalTexture._Counter++;
 
         if (!delayAllocation) {
-            this._webGLTexture = engine._createTexture(); // TODO WebGPU: don't do this in WebGPU
+            this._hardwareTexture = engine._createHardwareTexture();
         }
     }
 
@@ -456,9 +451,9 @@ export class InternalTexture {
 
     /** @hidden */
     public _swapAndDie(target: InternalTexture): void {
-        target._webGLTexture = this._webGLTexture;
-        target._webGPUTexture = this._webGPUTexture;
-        target._webGPUTextureView = this._webGPUTextureView;
+        // TODO what about refcount on target?
+
+        target._hardwareTexture = this._hardwareTexture;
         target._isRGBD = this._isRGBD;
 
         if (this._framebuffer) {
@@ -515,16 +510,10 @@ export class InternalTexture {
      * Dispose the current allocated resources
      */
     public dispose(): void {
-        if (!this._webGLTexture && !this._webGPUTexture) {
-            return;
-        }
-
         this._references--;
         if (this._references === 0) {
             this._engine._releaseTexture(this);
-            this._webGLTexture = null;
-            this._webGPUTexture = null;
-            this._webGPUSampler = null;
+            this._hardwareTexture = null;
         }
     }
 }

+ 4 - 1
src/Misc/khronosTextureContainer2.ts

@@ -41,7 +41,10 @@ export class KhronosTextureContainer2 {
 
                 const result = ktxTexture.glUpload();
                 if (result.error === 0) {
-                    internalTexture._webGLTexture = result.texture;
+                    if (!internalTexture._hardwareTexture) {
+                        internalTexture._hardwareTexture = internalTexture.getEngine()._createHardwareTexture();
+                    }
+                    internalTexture._hardwareTexture.set(result.texture);
                 }
                 else {
                     throw new Error(`Failed to upload: ${result.error}`);