12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139 |
- // Copyright 2020 Brandon Jones
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- // SOFTWARE.
- import * as WebGPUConstants from './webgpuConstants';
- import { Scalar } from '../../Maths/math.scalar';
- import { WebGPUBufferManager } from './webgpuBufferManager';
- import { Constants } from '../constants';
- import { Nullable } from '../../types';
- import { InternalTexture, InternalTextureSource } from '../../Materials/Textures/internalTexture';
- import { HardwareTextureWrapper } from '../../Materials/Textures/hardwareTextureWrapper';
- import { BaseTexture } from '../../Materials/Textures/baseTexture';
- import { WebGPUHardwareTexture } from './webgpuHardwareTexture';
- import { IColor4Like } from '../../Maths/math.like';
- // TODO WEBGPU improve mipmap generation by not using the OutputAttachment flag
- // see https://github.com/toji/web-texture-tool/tree/main/src
- // TODO WEBGPU optimize, don't recreate things that can be cached (bind groups, descriptors, etc)
- // TODO WEBGPU use WGSL instead of GLSL
- const mipmapVertexSource = `
- const vec2 pos[4] = vec2[4](vec2(-1.0f, 1.0f), vec2(1.0f, 1.0f), vec2(-1.0f, -1.0f), vec2(1.0f, -1.0f));
- const vec2 tex[4] = vec2[4](vec2(0.0f, 0.0f), vec2(1.0f, 0.0f), vec2(0.0f, 1.0f), vec2(1.0f, 1.0f));
- layout(location = 0) out vec2 vTex;
- void main() {
- vTex = tex[gl_VertexIndex];
- gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);
- }
- `;
- const mipmapFragmentSource = `
- layout(set = 0, binding = 0) uniform sampler imgSampler;
- layout(set = 0, binding = 1) uniform texture2D img;
- layout(location = 0) in vec2 vTex;
- layout(location = 0) out vec4 outColor;
- void main() {
- outColor = texture(sampler2D(img, imgSampler), vTex);
- }
- `;
- const invertYPreMultiplyAlphaVertexSource = `
- const vec2 pos[4] = vec2[4](vec2(-1.0f, 1.0f), vec2(1.0f, 1.0f), vec2(-1.0f, -1.0f), vec2(1.0f, -1.0f));
- const vec2 tex[4] = vec2[4](vec2(0.0f, 0.0f), vec2(1.0f, 0.0f), vec2(0.0f, 1.0f), vec2(1.0f, 1.0f));
- layout(location = 0) out vec2 vTex;
- void main() {
- vTex = tex[gl_VertexIndex];
- #ifdef INVERTY
- vTex.y = 1.0 - vTex.y;
- #endif
- gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);
- }
- `;
- const invertYPreMultiplyAlphaFragmentSource = `
- layout(set = 0, binding = 0) uniform sampler imgSampler;
- layout(set = 0, binding = 1) uniform texture2D img;
- layout(location = 0) in vec2 vTex;
- layout(location = 0) out vec4 outColor;
- void main() {
- vec4 color = texture(sampler2D(img, imgSampler), vTex);
- #ifdef PREMULTIPLYALPHA
- color.rgb *= color.a;
- #endif
- outColor = color;
- }
- `;
- const clearVertexSource = `
- const vec2 pos[4] = vec2[4](vec2(-1.0f, 1.0f), vec2(1.0f, 1.0f), vec2(-1.0f, -1.0f), vec2(1.0f, -1.0f));
- void main() {
- gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);
- }
- `;
- const clearFragmentSource = `
- layout(set = 0, binding = 0) uniform Uniforms {
- uniform vec4 color;
- };
- layout(location = 0) out vec4 outColor;
- void main() {
- outColor = color;
- }
- `;
- enum PipelineType {
- MipMap = 0,
- InvertYPremultiplyAlpha = 1,
- Clear = 2,
- }
- interface pipelineParameters {
- invertY?: boolean;
- premultiplyAlpha?: boolean;
- }
- const shadersForPipelineType = [
- { vertex: mipmapVertexSource, fragment: mipmapFragmentSource },
- { vertex: invertYPreMultiplyAlphaVertexSource, fragment: invertYPreMultiplyAlphaFragmentSource },
- { vertex: clearVertexSource, fragment: clearFragmentSource },
- ];
- /** @hidden */
- export class WebGPUTextureHelper {
- private _device: GPUDevice;
- private _glslang: any;
- private _bufferManager: WebGPUBufferManager;
- private _mipmapSampler: GPUSampler;
- private _invertYPreMultiplyAlphaSampler: GPUSampler;
- private _pipelines: { [format: string]: Array<GPURenderPipeline> } = {};
- private _compiledShaders: GPUShaderModule[][] = [];
- private _deferredReleaseTextures: Array<[Nullable<HardwareTextureWrapper | GPUTexture>, Nullable<BaseTexture>, Nullable<InternalTexture>]> = [];
- private _commandEncoderForCreation: GPUCommandEncoder;
- public static ComputeNumMipmapLevels(width: number, height: number) {
- return Scalar.ILog2(Math.max(width, height)) + 1;
- }
- //------------------------------------------------------------------------------
- // Initialization / Helpers
- //------------------------------------------------------------------------------
- constructor(device: GPUDevice, glslang: any, bufferManager: WebGPUBufferManager) {
- this._device = device;
- this._glslang = glslang;
- this._bufferManager = bufferManager;
- this._mipmapSampler = device.createSampler({ minFilter: WebGPUConstants.FilterMode.Linear });
- this._invertYPreMultiplyAlphaSampler = device.createSampler({ minFilter: WebGPUConstants.FilterMode.Nearest, magFilter: WebGPUConstants.FilterMode.Nearest });
- this._getPipeline(WebGPUConstants.TextureFormat.RGBA8Unorm);
- }
- private _getPipeline(format: GPUTextureFormat, type: PipelineType = PipelineType.MipMap, params?: pipelineParameters): GPURenderPipeline {
- const index =
- type === PipelineType.MipMap ? 1 << 0 :
- type === PipelineType.InvertYPremultiplyAlpha ? ((params!.invertY ? 1 : 0) << 1) + ((params!.premultiplyAlpha ? 1 : 0) << 2) :
- type === PipelineType.Clear ? 1 << 3 : 0;
- if (!this._pipelines[format]) {
- this._pipelines[format] = [];
- }
- let pipeline = this._pipelines[format][index];
- if (!pipeline) {
- let defines = "#version 450\r\n";
- if (type === PipelineType.InvertYPremultiplyAlpha) {
- if (params!.invertY) {
- defines += "#define INVERTY\r\n";
- }
- if (params!.premultiplyAlpha) {
- defines += "define PREMULTIPLYALPHA\r\n";
- }
- }
- let modules = this._compiledShaders[index];
- if (!modules) {
- const vertexModule = this._device.createShaderModule({
- code: this._glslang.compileGLSL(defines + shadersForPipelineType[type].vertex, 'vertex')
- });
- const fragmentModule = this._device.createShaderModule({
- code: this._glslang.compileGLSL(defines + shadersForPipelineType[type].fragment, 'fragment')
- });
- modules = this._compiledShaders[index] = [vertexModule, fragmentModule];
- }
- pipeline = this._pipelines[format][index] = this._device.createRenderPipeline({
- vertexStage: {
- module: modules[0],
- entryPoint: 'main'
- },
- fragmentStage: {
- module: modules[1],
- entryPoint: 'main'
- },
- primitiveTopology: WebGPUConstants.PrimitiveTopology.TriangleStrip,
- vertexState: {
- indexFormat: WebGPUConstants.IndexFormat.Uint16
- },
- colorStates: [{
- format,
- }]
- });
- }
- return pipeline;
- }
- private static _GetTextureTypeFromFormat(format: GPUTextureFormat): number {
- switch (format) {
- // One Component = 8 bits
- case WebGPUConstants.TextureFormat.R8Unorm:
- case WebGPUConstants.TextureFormat.R8Snorm:
- case WebGPUConstants.TextureFormat.R8Uint:
- case WebGPUConstants.TextureFormat.R8Sint:
- case WebGPUConstants.TextureFormat.RG8Unorm:
- case WebGPUConstants.TextureFormat.RG8Snorm:
- case WebGPUConstants.TextureFormat.RG8Uint:
- case WebGPUConstants.TextureFormat.RG8Sint:
- case WebGPUConstants.TextureFormat.RGBA8Unorm:
- case WebGPUConstants.TextureFormat.RGBA8UnormSRGB:
- case WebGPUConstants.TextureFormat.RGBA8Snorm:
- case WebGPUConstants.TextureFormat.RGBA8Uint:
- case WebGPUConstants.TextureFormat.RGBA8Sint:
- case WebGPUConstants.TextureFormat.BGRA8Unorm:
- case WebGPUConstants.TextureFormat.BGRA8UnormSRGB:
- case WebGPUConstants.TextureFormat.RGB10A2Unorm: // composite format - let's say it's byte...
- case WebGPUConstants.TextureFormat.RGB9E5UFloat: // composite format - let's say it's byte...
- case WebGPUConstants.TextureFormat.RG11B10UFloat: // composite format - let's say it's byte...
- case WebGPUConstants.TextureFormat.Depth24UnormStencil8: // composite format - let's say it's byte...
- case WebGPUConstants.TextureFormat.Depth32FloatStencil8: // composite format - let's say it's byte...
- case WebGPUConstants.TextureFormat.BC7RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC7RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC6HRGBUFloat:
- case WebGPUConstants.TextureFormat.BC6HRGBFloat:
- case WebGPUConstants.TextureFormat.BC5RGUnorm:
- case WebGPUConstants.TextureFormat.BC5RGSnorm:
- case WebGPUConstants.TextureFormat.BC3RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC3RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC2RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC2RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC4RUnorm:
- case WebGPUConstants.TextureFormat.BC4RSnorm:
- case WebGPUConstants.TextureFormat.BC1RGBAUNorm:
- case WebGPUConstants.TextureFormat.BC1RGBAUnormSRGB:
- return Constants.TEXTURETYPE_UNSIGNED_BYTE;
- // One component = 16 bits
- case WebGPUConstants.TextureFormat.R16Uint:
- case WebGPUConstants.TextureFormat.R16Sint:
- case WebGPUConstants.TextureFormat.RG16Uint:
- case WebGPUConstants.TextureFormat.RG16Sint:
- case WebGPUConstants.TextureFormat.RGBA16Uint:
- case WebGPUConstants.TextureFormat.RGBA16Sint:
- case WebGPUConstants.TextureFormat.Depth16Unorm:
- return Constants.TEXTURETYPE_UNSIGNED_SHORT;
- case WebGPUConstants.TextureFormat.R16Float:
- case WebGPUConstants.TextureFormat.RG16Float:
- case WebGPUConstants.TextureFormat.RGBA16Float:
- return Constants.TEXTURETYPE_HALF_FLOAT;
- // One component = 32 bits
- case WebGPUConstants.TextureFormat.R32Uint:
- case WebGPUConstants.TextureFormat.R32Sint:
- case WebGPUConstants.TextureFormat.RG32Uint:
- case WebGPUConstants.TextureFormat.RG32Sint:
- case WebGPUConstants.TextureFormat.RGBA32Uint:
- case WebGPUConstants.TextureFormat.RGBA32Sint:
- return Constants.TEXTURETYPE_UNSIGNED_INTEGER;
- case WebGPUConstants.TextureFormat.R32Float:
- case WebGPUConstants.TextureFormat.RG32Float:
- case WebGPUConstants.TextureFormat.RGBA32Float:
- case WebGPUConstants.TextureFormat.Depth32Float:
- return Constants.TEXTURETYPE_FLOAT;
- case WebGPUConstants.TextureFormat.Stencil8:
- throw "No fixed size for Stencil8 format!";
- case WebGPUConstants.TextureFormat.Depth24Plus:
- throw "No fixed size for Depth24Plus format!";
- case WebGPUConstants.TextureFormat.Depth24PlusStencil8:
- throw "No fixed size for Depth24PlusStencil8 format!";
- }
- return Constants.TEXTURETYPE_UNSIGNED_BYTE;
- }
- private static _GetBlockInformationFromFormat(format: GPUTextureFormat): { width: number, height: number, length: number } {
- switch (format) {
- // 8 bits formats
- case WebGPUConstants.TextureFormat.R8Unorm:
- case WebGPUConstants.TextureFormat.R8Snorm:
- case WebGPUConstants.TextureFormat.R8Uint:
- case WebGPUConstants.TextureFormat.R8Sint:
- return { width: 1, height: 1, length: 1 };
- // 16 bits formats
- case WebGPUConstants.TextureFormat.R16Uint:
- case WebGPUConstants.TextureFormat.R16Sint:
- case WebGPUConstants.TextureFormat.R16Float:
- case WebGPUConstants.TextureFormat.RG8Unorm:
- case WebGPUConstants.TextureFormat.RG8Snorm:
- case WebGPUConstants.TextureFormat.RG8Uint:
- case WebGPUConstants.TextureFormat.RG8Sint:
- return { width: 1, height: 1, length: 2 };
- // 32 bits formats
- case WebGPUConstants.TextureFormat.R32Uint:
- case WebGPUConstants.TextureFormat.R32Sint:
- case WebGPUConstants.TextureFormat.R32Float:
- case WebGPUConstants.TextureFormat.RG16Uint:
- case WebGPUConstants.TextureFormat.RG16Sint:
- case WebGPUConstants.TextureFormat.RG16Float:
- case WebGPUConstants.TextureFormat.RGBA8Unorm:
- case WebGPUConstants.TextureFormat.RGBA8UnormSRGB:
- case WebGPUConstants.TextureFormat.RGBA8Snorm:
- case WebGPUConstants.TextureFormat.RGBA8Uint:
- case WebGPUConstants.TextureFormat.RGBA8Sint:
- case WebGPUConstants.TextureFormat.BGRA8Unorm:
- case WebGPUConstants.TextureFormat.BGRA8UnormSRGB:
- case WebGPUConstants.TextureFormat.RGB9E5UFloat:
- case WebGPUConstants.TextureFormat.RGB10A2Unorm:
- case WebGPUConstants.TextureFormat.RG11B10UFloat:
- return { width: 1, height: 1, length: 4 };
- // 64 bits formats
- case WebGPUConstants.TextureFormat.RG32Uint:
- case WebGPUConstants.TextureFormat.RG32Sint:
- case WebGPUConstants.TextureFormat.RG32Float:
- case WebGPUConstants.TextureFormat.RGBA16Uint:
- case WebGPUConstants.TextureFormat.RGBA16Sint:
- case WebGPUConstants.TextureFormat.RGBA16Float:
- return { width: 1, height: 1, length: 8 };
- // 128 bits formats
- case WebGPUConstants.TextureFormat.RGBA32Uint:
- case WebGPUConstants.TextureFormat.RGBA32Sint:
- case WebGPUConstants.TextureFormat.RGBA32Float:
- return { width: 1, height: 1, length: 16 };
- // Depth and stencil formats
- case WebGPUConstants.TextureFormat.Stencil8:
- throw "No fixed size for Stencil8 format!";
- case WebGPUConstants.TextureFormat.Depth16Unorm:
- return { width: 1, height: 1, length: 2 };
- case WebGPUConstants.TextureFormat.Depth24Plus:
- throw "No fixed size for Depth24Plus format!";
- case WebGPUConstants.TextureFormat.Depth24PlusStencil8:
- throw "No fixed size for Depth24PlusStencil8 format!";
- case WebGPUConstants.TextureFormat.Depth32Float:
- return { width: 1, height: 1, length: 4 };
- case WebGPUConstants.TextureFormat.Depth24UnormStencil8:
- return { width: 1, height: 1, length: 4 };
- case WebGPUConstants.TextureFormat.Depth32FloatStencil8:
- return { width: 1, height: 1, length: 5 };
- // BC compressed formats usable if "texture-compression-bc" is both
- // supported by the device/user agent and enabled in requestDevice.
- case WebGPUConstants.TextureFormat.BC7RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC7RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC6HRGBUFloat:
- case WebGPUConstants.TextureFormat.BC6HRGBFloat:
- case WebGPUConstants.TextureFormat.BC5RGUnorm:
- case WebGPUConstants.TextureFormat.BC5RGSnorm:
- case WebGPUConstants.TextureFormat.BC3RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC3RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC2RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC2RGBAUnormSRGB:
- return { width: 4, height: 4, length: 16 };
- case WebGPUConstants.TextureFormat.BC4RUnorm:
- case WebGPUConstants.TextureFormat.BC4RSnorm:
- case WebGPUConstants.TextureFormat.BC1RGBAUNorm:
- case WebGPUConstants.TextureFormat.BC1RGBAUnormSRGB:
- return { width: 4, height: 4, length: 8 };
- }
- return { width: 1, height: 1, length: 4 };
- }
- private static _IsHardwareTexture(texture: HardwareTextureWrapper | GPUTexture): texture is HardwareTextureWrapper {
- return !!(texture as HardwareTextureWrapper).release;
- }
- private static _IsInternalTexture(texture: InternalTexture | GPUTexture): texture is InternalTexture {
- return !!(texture as InternalTexture).dispose;
- }
- public static GetCompareFunction(compareFunction: Nullable<number>): GPUCompareFunction {
- switch (compareFunction) {
- case Constants.ALWAYS:
- return WebGPUConstants.CompareFunction.Always;
- case Constants.EQUAL:
- return WebGPUConstants.CompareFunction.Equal;
- case Constants.GREATER:
- return WebGPUConstants.CompareFunction.Greater;
- case Constants.GEQUAL:
- return WebGPUConstants.CompareFunction.GreaterEqual;
- case Constants.LESS:
- return WebGPUConstants.CompareFunction.Less;
- case Constants.LEQUAL:
- return WebGPUConstants.CompareFunction.LessEqual;
- case Constants.NEVER:
- return WebGPUConstants.CompareFunction.Never;
- case Constants.NOTEQUAL:
- return WebGPUConstants.CompareFunction.NotEqual;
- default:
- return WebGPUConstants.CompareFunction.Less;
- }
- }
- public static IsImageBitmap(imageBitmap: ImageBitmap | { width: number, height: number }): imageBitmap is ImageBitmap {
- return (imageBitmap as ImageBitmap).close !== undefined;
- }
- public static IsImageBitmapArray(imageBitmap: ImageBitmap[] | { width: number, height: number }): imageBitmap is ImageBitmap[] {
- return Array.isArray(imageBitmap as ImageBitmap[]) && (imageBitmap as ImageBitmap[])[0].close !== undefined;
- }
- public setCommandEncoder(encoder: GPUCommandEncoder): void {
- this._commandEncoderForCreation = encoder;
- }
- public static IsCompressedFormat(format: GPUTextureFormat): boolean {
- switch (format) {
- case WebGPUConstants.TextureFormat.BC7RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC7RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC6HRGBFloat:
- case WebGPUConstants.TextureFormat.BC6HRGBUFloat:
- case WebGPUConstants.TextureFormat.BC5RGSnorm:
- case WebGPUConstants.TextureFormat.BC5RGUnorm:
- case WebGPUConstants.TextureFormat.BC4RSnorm:
- case WebGPUConstants.TextureFormat.BC4RUnorm:
- case WebGPUConstants.TextureFormat.BC3RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC3RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC2RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC2RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC1RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC1RGBAUNorm:
- return true;
- }
- return false;
- }
- public static GetWebGPUTextureFormat(type: number, format: number): GPUTextureFormat {
- switch (format) {
- case Constants.TEXTUREFORMAT_DEPTH24_STENCIL8:
- return WebGPUConstants.TextureFormat.Depth24PlusStencil8;
- case Constants.TEXTUREFORMAT_DEPTH32_FLOAT:
- return WebGPUConstants.TextureFormat.Depth32Float;
- case Constants.TEXTUREFORMAT_COMPRESSED_RGBA_BPTC_UNORM:
- return WebGPUConstants.TextureFormat.BC7RGBAUnorm;
- case Constants.TEXTUREFORMAT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
- return WebGPUConstants.TextureFormat.BC6HRGBUFloat;
- case Constants.TEXTUREFORMAT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
- return WebGPUConstants.TextureFormat.BC6HRGBFloat;
- case Constants.TEXTUREFORMAT_COMPRESSED_RGBA_S3TC_DXT5:
- return WebGPUConstants.TextureFormat.BC3RGBAUnorm;
- case Constants.TEXTUREFORMAT_COMPRESSED_RGBA_S3TC_DXT3:
- return WebGPUConstants.TextureFormat.BC2RGBAUnorm;
- case Constants.TEXTUREFORMAT_COMPRESSED_RGBA_S3TC_DXT1:
- return WebGPUConstants.TextureFormat.BC1RGBAUNorm;
- }
- switch (type) {
- case Constants.TEXTURETYPE_BYTE:
- switch (format) {
- case Constants.TEXTUREFORMAT_RED:
- return WebGPUConstants.TextureFormat.R8Snorm;
- case Constants.TEXTUREFORMAT_RG:
- return WebGPUConstants.TextureFormat.RG8Snorm;
- case Constants.TEXTUREFORMAT_RGB:
- throw "RGB format not supported in WebGPU";
- case Constants.TEXTUREFORMAT_RED_INTEGER:
- return WebGPUConstants.TextureFormat.R8Sint;
- case Constants.TEXTUREFORMAT_RG_INTEGER:
- return WebGPUConstants.TextureFormat.RG8Sint;
- case Constants.TEXTUREFORMAT_RGB_INTEGER:
- throw "RGB_INTEGER format not supported in WebGPU";
- case Constants.TEXTUREFORMAT_RGBA_INTEGER:
- return WebGPUConstants.TextureFormat.RGBA8Sint;
- default:
- return WebGPUConstants.TextureFormat.RGBA8Snorm;
- }
- case Constants.TEXTURETYPE_UNSIGNED_BYTE:
- switch (format) {
- case Constants.TEXTUREFORMAT_RED:
- return WebGPUConstants.TextureFormat.R8Unorm;
- case Constants.TEXTUREFORMAT_RG:
- return WebGPUConstants.TextureFormat.RG8Unorm;
- case Constants.TEXTUREFORMAT_RGB:
- throw "TEXTUREFORMAT_RGB format not supported in WebGPU";
- case Constants.TEXTUREFORMAT_RGBA:
- return WebGPUConstants.TextureFormat.RGBA8Unorm;
- case Constants.TEXTUREFORMAT_BGRA:
- return WebGPUConstants.TextureFormat.BGRA8Unorm;
- case Constants.TEXTUREFORMAT_RED_INTEGER:
- return WebGPUConstants.TextureFormat.R8Uint;
- case Constants.TEXTUREFORMAT_RG_INTEGER:
- return WebGPUConstants.TextureFormat.RG8Uint;
- case Constants.TEXTUREFORMAT_RGB_INTEGER:
- throw "RGB_INTEGER format not supported in WebGPU";
- case Constants.TEXTUREFORMAT_RGBA_INTEGER:
- return WebGPUConstants.TextureFormat.RGBA8Uint;
- case Constants.TEXTUREFORMAT_ALPHA:
- throw "TEXTUREFORMAT_ALPHA format not supported in WebGPU";
- case Constants.TEXTUREFORMAT_LUMINANCE:
- throw "TEXTUREFORMAT_LUMINANCE format not supported in WebGPU";
- case Constants.TEXTUREFORMAT_LUMINANCE_ALPHA:
- throw "TEXTUREFORMAT_LUMINANCE_ALPHA format not supported in WebGPU";
- default:
- return WebGPUConstants.TextureFormat.RGBA8Unorm;
- }
- case Constants.TEXTURETYPE_SHORT:
- switch (format) {
- case Constants.TEXTUREFORMAT_RED_INTEGER:
- return WebGPUConstants.TextureFormat.R16Sint;
- case Constants.TEXTUREFORMAT_RG_INTEGER:
- return WebGPUConstants.TextureFormat.RG16Sint;
- case Constants.TEXTUREFORMAT_RGB_INTEGER:
- throw "TEXTUREFORMAT_RGB_INTEGER format not supported in WebGPU";
- case Constants.TEXTUREFORMAT_RGBA_INTEGER:
- return WebGPUConstants.TextureFormat.RGBA16Sint;
- default:
- return WebGPUConstants.TextureFormat.RGBA16Sint;
- }
- case Constants.TEXTURETYPE_UNSIGNED_SHORT:
- switch (format) {
- case Constants.TEXTUREFORMAT_RED_INTEGER:
- return WebGPUConstants.TextureFormat.R16Uint;
- case Constants.TEXTUREFORMAT_RG_INTEGER:
- return WebGPUConstants.TextureFormat.RG16Uint;
- case Constants.TEXTUREFORMAT_RGB_INTEGER:
- throw "TEXTUREFORMAT_RGB_INTEGER format not supported in WebGPU";
- case Constants.TEXTUREFORMAT_RGBA_INTEGER:
- return WebGPUConstants.TextureFormat.RGBA16Uint;
- default:
- return WebGPUConstants.TextureFormat.RGBA16Uint;
- }
- case Constants.TEXTURETYPE_INT:
- switch (format) {
- case Constants.TEXTUREFORMAT_RED_INTEGER:
- return WebGPUConstants.TextureFormat.R32Sint;
- case Constants.TEXTUREFORMAT_RG_INTEGER:
- return WebGPUConstants.TextureFormat.RG32Sint;
- case Constants.TEXTUREFORMAT_RGB_INTEGER:
- throw "TEXTUREFORMAT_RGB_INTEGER format not supported in WebGPU";
- case Constants.TEXTUREFORMAT_RGBA_INTEGER:
- return WebGPUConstants.TextureFormat.RGBA32Sint;
- default:
- return WebGPUConstants.TextureFormat.RGBA32Sint;
- }
- case Constants.TEXTURETYPE_UNSIGNED_INTEGER: // Refers to UNSIGNED_INT
- switch (format) {
- case Constants.TEXTUREFORMAT_RED_INTEGER:
- return WebGPUConstants.TextureFormat.R32Uint;
- case Constants.TEXTUREFORMAT_RG_INTEGER:
- return WebGPUConstants.TextureFormat.RG32Uint;
- case Constants.TEXTUREFORMAT_RGB_INTEGER:
- throw "TEXTUREFORMAT_RGB_INTEGER format not supported in WebGPU";
- case Constants.TEXTUREFORMAT_RGBA_INTEGER:
- return WebGPUConstants.TextureFormat.RGBA32Uint;
- default:
- return WebGPUConstants.TextureFormat.RGBA32Uint;
- }
- case Constants.TEXTURETYPE_FLOAT:
- switch (format) {
- case Constants.TEXTUREFORMAT_RED:
- return WebGPUConstants.TextureFormat.R32Float; // By default. Other possibility is R16Float.
- case Constants.TEXTUREFORMAT_RG:
- return WebGPUConstants.TextureFormat.RG32Float; // By default. Other possibility is RG16Float.
- case Constants.TEXTUREFORMAT_RGB:
- throw "TEXTUREFORMAT_RGB format not supported in WebGPU";
- case Constants.TEXTUREFORMAT_RGBA:
- return WebGPUConstants.TextureFormat.RGBA32Float; // By default. Other possibility is RGBA16Float.
- default:
- return WebGPUConstants.TextureFormat.RGBA32Float;
- }
- case Constants.TEXTURETYPE_HALF_FLOAT:
- switch (format) {
- case Constants.TEXTUREFORMAT_RED:
- return WebGPUConstants.TextureFormat.R16Float;
- case Constants.TEXTUREFORMAT_RG:
- return WebGPUConstants.TextureFormat.RG16Float;
- case Constants.TEXTUREFORMAT_RGB:
- throw "TEXTUREFORMAT_RGB format not supported in WebGPU";
- case Constants.TEXTUREFORMAT_RGBA:
- return WebGPUConstants.TextureFormat.RGBA16Float;
- default:
- return WebGPUConstants.TextureFormat.RGBA16Float;
- }
- case Constants.TEXTURETYPE_UNSIGNED_SHORT_5_6_5:
- throw "TEXTURETYPE_UNSIGNED_SHORT_5_6_5 format not supported in WebGPU";
- case Constants.TEXTURETYPE_UNSIGNED_INT_10F_11F_11F_REV:
- throw "TEXTURETYPE_UNSIGNED_INT_10F_11F_11F_REV format not supported in WebGPU";
- case Constants.TEXTURETYPE_UNSIGNED_INT_5_9_9_9_REV:
- throw "TEXTURETYPE_UNSIGNED_INT_5_9_9_9_REV format not supported in WebGPU";
- case Constants.TEXTURETYPE_UNSIGNED_SHORT_4_4_4_4:
- throw "TEXTURETYPE_UNSIGNED_SHORT_4_4_4_4 format not supported in WebGPU";
- case Constants.TEXTURETYPE_UNSIGNED_SHORT_5_5_5_1:
- throw "TEXTURETYPE_UNSIGNED_SHORT_5_5_5_1 format not supported in WebGPU";
- case Constants.TEXTURETYPE_UNSIGNED_INT_2_10_10_10_REV:
- switch (format) {
- case Constants.TEXTUREFORMAT_RGBA:
- return WebGPUConstants.TextureFormat.RGB10A2Unorm;
- case Constants.TEXTUREFORMAT_RGBA_INTEGER:
- throw "TEXTUREFORMAT_RGBA_INTEGER format not supported in WebGPU when type is TEXTURETYPE_UNSIGNED_INT_2_10_10_10_REV";
- default:
- return WebGPUConstants.TextureFormat.RGB10A2Unorm;
- }
- }
- return WebGPUConstants.TextureFormat.RGBA8Unorm;
- }
- public invertYPreMultiplyAlpha(gpuTexture: GPUTexture, width: number, height: number, format: GPUTextureFormat, invertY = false, premultiplyAlpha = false, faceIndex= 0, commandEncoder?: GPUCommandEncoder): void {
- const useOwnCommandEncoder = commandEncoder === undefined;
- const pipeline = this._getPipeline(format, PipelineType.InvertYPremultiplyAlpha, { invertY, premultiplyAlpha });
- const bindGroupLayout = pipeline.getBindGroupLayout(0);
- if (useOwnCommandEncoder) {
- commandEncoder = this._device.createCommandEncoder({});
- }
- commandEncoder!.pushDebugGroup(`internal process texture - invertY=${invertY} premultiplyAlpha=${premultiplyAlpha}`);
- const outputTexture = this.createTexture({ width, height, layers: 1 }, false, false, false, false, false, format, 1, commandEncoder, WebGPUConstants.TextureUsage.CopySrc | WebGPUConstants.TextureUsage.OutputAttachment | WebGPUConstants.TextureUsage.Sampled);
- const passEncoder = commandEncoder!.beginRenderPass({
- colorAttachments: [{
- attachment: outputTexture.createView({
- dimension: WebGPUConstants.TextureViewDimension.E2d,
- baseMipLevel: 0,
- mipLevelCount: 1,
- arrayLayerCount: 1,
- baseArrayLayer: 0,
- }),
- loadValue: WebGPUConstants.LoadOp.Load,
- }],
- });
- const bindGroup = this._device.createBindGroup({
- layout: bindGroupLayout,
- entries: [{
- binding: 0,
- resource: this._invertYPreMultiplyAlphaSampler,
- }, {
- binding: 1,
- resource: gpuTexture.createView({
- dimension: WebGPUConstants.TextureViewDimension.E2d,
- baseMipLevel: 0,
- mipLevelCount: 1,
- arrayLayerCount: 1,
- baseArrayLayer: faceIndex,
- }),
- }],
- });
- passEncoder.setPipeline(pipeline);
- passEncoder.setBindGroup(0, bindGroup);
- passEncoder.draw(4, 1, 0, 0);
- passEncoder.endPass();
- commandEncoder!.copyTextureToTexture({
- texture: outputTexture,
- }, {
- texture: gpuTexture,
- origin: {
- x: 0,
- y: 0,
- z: Math.max(faceIndex, 0),
- }
- }, {
- width,
- height,
- depth: 1,
- }
- );
- this._deferredReleaseTextures.push([outputTexture, null, null]);
- commandEncoder!.popDebugGroup();
- if (useOwnCommandEncoder) {
- this._device.defaultQueue.submit([commandEncoder!.finish()]);
- commandEncoder = null as any;
- }
- }
- public clear(format: GPUTextureFormat, color: IColor4Like, passEncoder: GPURenderPassEncoder): void {
- const pipeline = this._getPipeline(format, PipelineType.Clear);
- const bindGroupLayout = pipeline.getBindGroupLayout(0);
- const buffer = this._bufferManager.createRawBuffer(4 * 4, WebGPUConstants.BufferUsage.CopySrc | WebGPUConstants.BufferUsage.Uniform, true);
- /*const arrayBuffer = buffer.getMappedRange();
- new Float32Array(arrayBuffer).set([color.r, color.g, color.b, color.a]);
- buffer.unmap();*/
- const bindGroup = this._device.createBindGroup({
- layout: bindGroupLayout,
- entries: [{
- binding: 0,
- resource: {
- buffer,
- },
- }],
- });
- passEncoder.setPipeline(pipeline);
- passEncoder.setBindGroup(0, bindGroup);
- passEncoder.draw(4, 1, 0, 0);
- this._bufferManager.releaseBuffer(buffer);
- }
- //------------------------------------------------------------------------------
- // Creation
- //------------------------------------------------------------------------------
- public createTexture(imageBitmap: ImageBitmap | { width: number, height: number, layers: number }, hasMipmaps = false, generateMipmaps = false, invertY = false, premultiplyAlpha = false, is3D = false, format: GPUTextureFormat = WebGPUConstants.TextureFormat.RGBA8Unorm,
- sampleCount = 1, commandEncoder?: GPUCommandEncoder, usage = -1): GPUTexture
- {
- if (sampleCount > 1) {
- // TODO WEBGPU for the time being, Chrome only accepts values of 1 or 4
- sampleCount = 4;
- }
- const layerCount = (imageBitmap as any).layers || 1;
- let textureSize = {
- width: imageBitmap.width,
- height: imageBitmap.height,
- depth: layerCount,
- };
- const mipLevelCount = hasMipmaps ? WebGPUTextureHelper.ComputeNumMipmapLevels(imageBitmap.width, imageBitmap.height) : 1;
- const usages = usage >= 0 ? usage : WebGPUConstants.TextureUsage.CopySrc | WebGPUConstants.TextureUsage.CopyDst | WebGPUConstants.TextureUsage.Sampled;
- const additionalUsages = hasMipmaps && !WebGPUTextureHelper.IsCompressedFormat(format) ? WebGPUConstants.TextureUsage.CopySrc | WebGPUConstants.TextureUsage.OutputAttachment : 0;
- const gpuTexture = this._device.createTexture({
- size: textureSize,
- dimension: is3D ? WebGPUConstants.TextureDimension.E3d : WebGPUConstants.TextureDimension.E2d,
- format,
- usage: usages | additionalUsages,
- sampleCount,
- mipLevelCount
- });
- if (WebGPUTextureHelper.IsImageBitmap(imageBitmap)) {
- this.updateTexture(imageBitmap, gpuTexture, imageBitmap.width, imageBitmap.height, layerCount, format, 0, 0, invertY, premultiplyAlpha, 0, 0, commandEncoder);
- if (hasMipmaps && generateMipmaps) {
- this.generateMipmaps(gpuTexture, format, mipLevelCount, 0, commandEncoder);
- }
- }
- return gpuTexture;
- }
- public createCubeTexture(imageBitmaps: ImageBitmap[] | { width: number, height: number }, hasMipmaps = false, generateMipmaps = false, invertY = false, premultiplyAlpha = false, format: GPUTextureFormat = WebGPUConstants.TextureFormat.RGBA8Unorm,
- sampleCount = 1, commandEncoder?: GPUCommandEncoder, usage = -1): GPUTexture
- {
- if (sampleCount > 1) {
- // TODO WEBGPU for the time being, Chrome only accepts values of 1 or 4
- sampleCount = 4;
- }
- const width = WebGPUTextureHelper.IsImageBitmapArray(imageBitmaps) ? imageBitmaps[0].width : imageBitmaps.width;
- const height = WebGPUTextureHelper.IsImageBitmapArray(imageBitmaps) ? imageBitmaps[0].height : imageBitmaps.height;
- const mipLevelCount = hasMipmaps ? WebGPUTextureHelper.ComputeNumMipmapLevels(width, height) : 1;
- const usages = usage >= 0 ? usage : WebGPUConstants.TextureUsage.CopySrc | WebGPUConstants.TextureUsage.CopyDst | WebGPUConstants.TextureUsage.Sampled;
- const additionalUsages = hasMipmaps && !WebGPUTextureHelper.IsCompressedFormat(format) ? WebGPUConstants.TextureUsage.CopySrc | WebGPUConstants.TextureUsage.OutputAttachment : 0;
- const gpuTexture = this._device.createTexture({
- size: {
- width,
- height,
- depth: 6,
- },
- dimension: WebGPUConstants.TextureDimension.E2d,
- format,
- usage: usages | additionalUsages,
- sampleCount,
- mipLevelCount
- });
- if (WebGPUTextureHelper.IsImageBitmapArray(imageBitmaps)) {
- this.updateCubeTextures(imageBitmaps, gpuTexture, width, height, format, invertY, premultiplyAlpha, 0, 0, commandEncoder);
- if (hasMipmaps && generateMipmaps) {
- this.generateCubeMipmaps(gpuTexture, format, mipLevelCount, commandEncoder);
- }
- }
- return gpuTexture;
- }
- public generateCubeMipmaps(gpuTexture: GPUTexture, format: GPUTextureFormat, mipLevelCount: number, commandEncoder?: GPUCommandEncoder): void {
- const useOwnCommandEncoder = commandEncoder === undefined;
- if (useOwnCommandEncoder) {
- commandEncoder = this._device.createCommandEncoder({});
- }
- commandEncoder!.pushDebugGroup(`create cube mipmaps - ${mipLevelCount} levels`);
- for (let f = 0; f < 6; ++f) {
- this.generateMipmaps(gpuTexture, format, mipLevelCount, f, commandEncoder);
- }
- commandEncoder!.popDebugGroup();
- if (useOwnCommandEncoder) {
- this._device.defaultQueue.submit([commandEncoder!.finish()]);
- commandEncoder = null as any;
- }
- }
- public generateMipmaps(gpuTexture: GPUTexture, format: GPUTextureFormat, mipLevelCount: number, faceIndex= 0, commandEncoder?: GPUCommandEncoder): void {
- const useOwnCommandEncoder = commandEncoder === undefined;
- const pipeline = this._getPipeline(format);
- const bindGroupLayout = pipeline.getBindGroupLayout(0);
- if (useOwnCommandEncoder) {
- commandEncoder = this._device.createCommandEncoder({});
- }
- commandEncoder!.pushDebugGroup(`create mipmaps for face #${faceIndex} - ${mipLevelCount} levels`);
- for (let i = 1; i < mipLevelCount; ++i) {
- const passEncoder = commandEncoder!.beginRenderPass({
- colorAttachments: [{
- attachment: gpuTexture.createView({
- dimension: WebGPUConstants.TextureViewDimension.E2d,
- baseMipLevel: i,
- mipLevelCount: 1,
- arrayLayerCount: 1,
- baseArrayLayer: faceIndex,
- }),
- loadValue: WebGPUConstants.LoadOp.Load,
- }],
- });
- const bindGroup = this._device.createBindGroup({
- layout: bindGroupLayout,
- entries: [{
- binding: 0,
- resource: this._mipmapSampler,
- }, {
- binding: 1,
- resource: gpuTexture.createView({
- dimension: WebGPUConstants.TextureViewDimension.E2d,
- baseMipLevel: i - 1,
- mipLevelCount: 1,
- arrayLayerCount: 1,
- baseArrayLayer: faceIndex,
- }),
- }],
- });
- passEncoder.setPipeline(pipeline);
- passEncoder.setBindGroup(0, bindGroup);
- passEncoder.draw(4, 1, 0, 0);
- passEncoder.endPass();
- }
- commandEncoder!.popDebugGroup();
- if (useOwnCommandEncoder) {
- this._device.defaultQueue.submit([commandEncoder!.finish()]);
- commandEncoder = null as any;
- }
- }
- public createGPUTextureForInternalTexture(texture: InternalTexture, width?: number, height?: number, depth?: number): WebGPUHardwareTexture {
- if (!texture._hardwareTexture) {
- texture._hardwareTexture = new WebGPUHardwareTexture();
- }
- if (width === undefined) {
- width = texture.width;
- }
- if (height === undefined) {
- height = texture.height;
- }
- if (depth === undefined) {
- depth = texture.depth;
- }
- const gpuTextureWrapper = texture._hardwareTexture as WebGPUHardwareTexture;
- gpuTextureWrapper.format = WebGPUTextureHelper.GetWebGPUTextureFormat(texture.type, texture.format);
- gpuTextureWrapper.textureUsages =
- texture._source === InternalTextureSource.RenderTarget || texture.source === InternalTextureSource.MultiRenderTarget ? WebGPUConstants.TextureUsage.Sampled | WebGPUConstants.TextureUsage.CopySrc | WebGPUConstants.TextureUsage.OutputAttachment :
- texture._source === InternalTextureSource.Depth ? WebGPUConstants.TextureUsage.Sampled | WebGPUConstants.TextureUsage.OutputAttachment : -1;
- const hasMipMaps = texture.generateMipMaps;
- const layerCount = depth || 1;
- if (texture.isCube) {
- const gpuTexture = this.createCubeTexture({ width, height }, texture.generateMipMaps, texture.generateMipMaps, texture.invertY, false, gpuTextureWrapper.format, 1, this._commandEncoderForCreation, gpuTextureWrapper.textureUsages);
- gpuTextureWrapper.set(gpuTexture);
- gpuTextureWrapper.createView({
- dimension: WebGPUConstants.TextureViewDimension.Cube,
- mipLevelCount: hasMipMaps ? WebGPUTextureHelper.ComputeNumMipmapLevels(width!, height!) : 1,
- baseArrayLayer: 0,
- baseMipLevel: 0,
- aspect: WebGPUConstants.TextureAspect.All
- });
- } else {
- const gpuTexture = this.createTexture({ width, height, layers: layerCount }, texture.generateMipMaps, texture.generateMipMaps, texture.invertY, false, texture.is3D, gpuTextureWrapper.format, 1, this._commandEncoderForCreation, gpuTextureWrapper.textureUsages);
- gpuTextureWrapper.set(gpuTexture);
- gpuTextureWrapper.createView({
- dimension: texture.is2DArray ? WebGPUConstants.TextureViewDimension.E2dArray : texture.is3D ? WebGPUConstants.TextureDimension.E3d : WebGPUConstants.TextureViewDimension.E2d,
- mipLevelCount: hasMipMaps ? WebGPUTextureHelper.ComputeNumMipmapLevels(width!, height!) : 1,
- baseArrayLayer: 0,
- baseMipLevel: 0,
- arrayLayerCount: layerCount,
- aspect: WebGPUConstants.TextureAspect.All
- });
- }
- texture.width = texture.baseWidth = width;
- texture.height = texture.baseHeight = height;
- texture.depth = texture.baseDepth = depth;
- this.createMSAATexture(texture, texture.samples);
- return gpuTextureWrapper;
- }
- public createMSAATexture(texture: InternalTexture, samples: number): void {
- const gpuTextureWrapper = texture._hardwareTexture as Nullable<WebGPUHardwareTexture>;
- if (gpuTextureWrapper?.msaaTexture) {
- this.releaseTexture(gpuTextureWrapper.msaaTexture);
- gpuTextureWrapper.msaaTexture = null;
- }
- if (!gpuTextureWrapper || (samples ?? 1) <= 1) {
- return;
- }
- const width = texture.width;
- const height = texture.height;
- const layerCount = texture.depth || 1;
- if (texture.isCube) {
- const gpuMSAATexture = this.createCubeTexture({ width, height }, false, false, texture.invertY, false, gpuTextureWrapper.format, samples, this._commandEncoderForCreation, gpuTextureWrapper.textureUsages);
- gpuTextureWrapper.setMSAATexture(gpuMSAATexture);
- } else {
- const gpuMSAATexture = this.createTexture({ width, height, layers: layerCount }, false, false, texture.invertY, false, texture.is3D, gpuTextureWrapper.format, samples, this._commandEncoderForCreation, gpuTextureWrapper.textureUsages);
- gpuTextureWrapper.setMSAATexture(gpuMSAATexture);
- }
- }
- //------------------------------------------------------------------------------
- // Update
- //------------------------------------------------------------------------------
- public updateCubeTextures(imageBitmaps: ImageBitmap[] | Uint8Array[], gpuTexture: GPUTexture, width: number, height: number, format: GPUTextureFormat, invertY = false, premultiplyAlpha = false, offsetX = 0, offsetY = 0,
- commandEncoder?: GPUCommandEncoder): void {
- const faces = [0, 3, 1, 4, 2, 5];
- for (let f = 0; f < faces.length; ++f) {
- let imageBitmap = imageBitmaps[faces[f]];
- this.updateTexture(imageBitmap, gpuTexture, width, height, 1, format, f, 0, invertY, premultiplyAlpha, offsetX, offsetY, commandEncoder);
- }
- }
- // TODO WEBGPU handle data source not being in the same format than the destination texture?
- public updateTexture(imageBitmap: ImageBitmap | Uint8Array, gpuTexture: GPUTexture, width: number, height: number, layers: number, format: GPUTextureFormat, faceIndex: number = 0, mipLevel: number = 0, invertY = false, premultiplyAlpha = false, offsetX = 0, offsetY = 0,
- commandEncoder?: GPUCommandEncoder): void
- {
- const blockInformation = WebGPUTextureHelper._GetBlockInformationFromFormat(format);
- const textureCopyView: GPUTextureCopyView = {
- texture: gpuTexture,
- origin: {
- x: offsetX,
- y: offsetY,
- z: Math.max(faceIndex, 0)
- },
- mipLevel: mipLevel
- };
- const textureExtent = {
- width: Math.ceil(width / blockInformation.width) * blockInformation.width,
- height: Math.ceil(height / blockInformation.height) * blockInformation.height,
- depth: layers || 1
- };
- if ((imageBitmap as Uint8Array).byteLength !== undefined) {
- imageBitmap = imageBitmap as Uint8Array;
- const bytesPerRow = Math.ceil(width / blockInformation.width) * blockInformation.length;
- const aligned = Math.ceil(bytesPerRow / 256) * 256 === bytesPerRow;
- if (aligned) {
- const useOwnCommandEncoder = commandEncoder === undefined;
- if (useOwnCommandEncoder) {
- commandEncoder = this._device.createCommandEncoder({});
- }
- const buffer = this._bufferManager.createRawBuffer(imageBitmap.byteLength, WebGPUConstants.BufferUsage.MapWrite | WebGPUConstants.BufferUsage.CopySrc, true);
- const arrayBuffer = buffer.getMappedRange();
- new Uint8Array(arrayBuffer).set(imageBitmap);
- buffer.unmap();
- commandEncoder!.copyBufferToTexture({
- buffer: buffer,
- offset: 0,
- bytesPerRow
- }, textureCopyView, textureExtent);
- if (useOwnCommandEncoder) {
- this._device.defaultQueue.submit([commandEncoder!.finish()]);
- commandEncoder = null as any;
- }
- this._bufferManager.releaseBuffer(buffer);
- } else {
- this._device.defaultQueue.writeTexture(textureCopyView, imageBitmap, {
- offset: 0,
- bytesPerRow
- }, textureExtent);
- }
- if (invertY || premultiplyAlpha) {
- this.invertYPreMultiplyAlpha(gpuTexture, width, height, format, invertY, premultiplyAlpha, faceIndex, commandEncoder);
- }
- } else {
- imageBitmap = imageBitmap as ImageBitmap;
- if (invertY || premultiplyAlpha) {
- createImageBitmap(imageBitmap, { imageOrientation: invertY ? "flipY" : "none", premultiplyAlpha: premultiplyAlpha ? "premultiply" : "none" }).then((imageBitmap) => {
- this._device.defaultQueue.copyImageBitmapToTexture({ imageBitmap }, textureCopyView, textureExtent);
- });
- } else {
- this._device.defaultQueue.copyImageBitmapToTexture({ imageBitmap }, textureCopyView, textureExtent);
- }
- }
- }
- public readPixels(texture: GPUTexture, x: number, y: number, width: number, height: number, format: GPUTextureFormat, faceIndex: number = 0, mipLevel: number = 0, buffer: Nullable<ArrayBufferView> = null): Promise<ArrayBufferView> {
- const blockInformation = WebGPUTextureHelper._GetBlockInformationFromFormat(format);
- const bytesPerRow = Math.ceil(width / blockInformation.width) * blockInformation.length;
- const bytesPerRowAligned = Math.ceil(bytesPerRow / 256) * 256;
- const size = bytesPerRowAligned * height;
- const gpuBuffer = this._bufferManager.createRawBuffer(size, WebGPUConstants.BufferUsage.MapRead | WebGPUConstants.BufferUsage.CopyDst);
- const commandEncoder = this._device.createCommandEncoder({});
- commandEncoder.copyTextureToBuffer({
- texture,
- mipLevel,
- origin: {
- x,
- y,
- z: Math.max(faceIndex, 0)
- }
- }, {
- buffer: gpuBuffer,
- offset: 0,
- bytesPerRow: bytesPerRowAligned
- }, {
- width,
- height,
- depth: 1
- });
- this._device.defaultQueue.submit([commandEncoder!.finish()]);
- const type = WebGPUTextureHelper._GetTextureTypeFromFormat(format);
- const floatFormat = type === Constants.TEXTURETYPE_FLOAT ? 2 : type === Constants.TEXTURETYPE_HALF_FLOAT ? 1 : 0;
- return this._bufferManager.readDataFromBuffer(gpuBuffer, size, width, height, bytesPerRow, bytesPerRowAligned, floatFormat, 0, buffer);
- }
- //------------------------------------------------------------------------------
- // Dispose
- //------------------------------------------------------------------------------
- public releaseTexture(texture: InternalTexture | GPUTexture): void {
- if (WebGPUTextureHelper._IsInternalTexture(texture)) {
- const hardwareTexture = texture._hardwareTexture;
- const irradianceTexture = texture._irradianceTexture;
- const depthStencilTexture = texture._depthStencilTexture;
- // We can't destroy the objects just now because they could be used in the current frame - we delay the destroying after the end of the frame
- this._deferredReleaseTextures.push([hardwareTexture, irradianceTexture, depthStencilTexture]);
- } else {
- this._deferredReleaseTextures.push([texture, null, null]);
- }
- }
- public destroyDeferredTextures(): void {
- for (let i = 0; i < this._deferredReleaseTextures.length; ++i) {
- const [hardwareTexture, irradianceTexture, depthStencilTexture] = this._deferredReleaseTextures[i];
- if (hardwareTexture) {
- if (WebGPUTextureHelper._IsHardwareTexture(hardwareTexture)) {
- hardwareTexture.release();
- } else {
- hardwareTexture.destroy();
- }
- }
- irradianceTexture?.dispose();
- depthStencilTexture?.dispose();
- }
- this._deferredReleaseTextures.length = 0;
- }
- }
|