webgpuEngine.ts 101 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425
  1. import { Logger } from "../Misc/logger";
  2. import { Nullable, DataArray, IndicesArray, FloatArray } from "../types";
  3. import { Scene } from "../scene";
  4. import { Matrix, Color3, Color4 } from "../Maths/math";
  5. import { Scalar } from "../Maths/math.scalar";
  6. import { Engine, EngineCapabilities, InstancingAttributeInfo } from "../Engines/engine";
  7. import { RenderTargetCreationOptions } from "../Materials/Textures/renderTargetCreationOptions";
  8. import { InternalTexture } from "../Materials/Textures/internalTexture";
  9. import { EffectCreationOptions, EffectFallbacks, Effect } from "../Materials/effect";
  10. import { _TimeToken } from "../Instrumentation/timeToken";
  11. import { _DepthCullingState, _StencilState, _AlphaState } from "../States/index";
  12. import { Constants } from "./constants";
  13. import { WebGPUConstants } from "./WebGPU/webgpuConstants";
  14. import { VertexBuffer } from "../Meshes/buffer";
  15. import { WebGPUPipelineContext, IWebGPUPipelineContextVertexInputsCache } from './WebGPU/webgpuPipelineContext';
  16. import { IPipelineContext } from './IPipelineContext';
  17. import { DataBuffer } from '../Meshes/dataBuffer';
  18. import { WebGPUDataBuffer } from '../Meshes/WebGPU/webgpuDataBuffer';
  19. import { IInternalTextureLoader } from "../Materials/Textures/internalTextureLoader";
  20. import { BaseTexture } from "../Materials/Textures/baseTexture";
  21. import { IShaderProcessor } from "./Processors/iShaderProcessor";
  22. import { WebGPUShaderProcessor } from "./WebGPU/webgpuShaderProcessors";
  23. import { ShaderProcessingContext } from "./Processors/shaderProcessingOptions";
  24. import { WebGPUShaderProcessingContext } from "./WebGPU/webgpuShaderProcessingContext";
  25. /**
  26. * Options to create the WebGPU engine
  27. */
  28. export interface WebGPUEngineOptions extends GPURequestAdapterOptions {
  29. /**
  30. * If delta time between frames should be constant
  31. * @see https://doc.babylonjs.com/babylon101/animations#deterministic-lockstep
  32. */
  33. deterministicLockstep?: boolean;
  34. /**
  35. * Maximum about of steps between frames (Default: 4)
  36. * @see https://doc.babylonjs.com/babylon101/animations#deterministic-lockstep
  37. */
  38. lockstepMaxSteps?: number;
  39. /**
  40. * Defines that engine should ignore modifying touch action attribute and style
  41. * If not handle, you might need to set it up on your side for expected touch devices behavior.
  42. */
  43. doNotHandleTouchAction?: boolean;
  44. /**
  45. * Defines if webaudio should be initialized as well
  46. * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
  47. */
  48. audioEngine?: boolean;
  49. /**
  50. * Defines the category of adapter to use.
  51. * Is it the discrete or integrated device.
  52. */
  53. powerPreference?: GPUPowerPreference;
  54. /**
  55. * Defines the device descriptor used to create a device.
  56. */
  57. deviceDescriptor?: GPUDeviceDescriptor;
  58. /**
  59. * Defines the requested Swap Chain Format.
  60. */
  61. swapChainFormat?: GPUTextureFormat;
  62. }
  63. /**
  64. * The web GPU engine class provides support for WebGPU version of babylon.js.
  65. */
  66. export class WebGPUEngine extends Engine {
  67. // Page Life cycle and constants
  68. private readonly _uploadEncoderDescriptor = { label: "upload" };
  69. private readonly _renderEncoderDescriptor = { label: "render" };
  70. private readonly _blitDescriptor = { label: "upload" };
  71. // Engine Life Cycle
  72. private _canvas: HTMLCanvasElement;
  73. private _options: WebGPUEngineOptions;
  74. private _shaderc: any = null;
  75. private _adapter: GPUAdapter;
  76. private _device: GPUDevice;
  77. private _context: GPUCanvasContext;
  78. private _swapChain: GPUSwapChain;
  79. // Some of the internal state might change during the render pass.
  80. // This happens mainly during clear for the state
  81. // And when the frame starts to swap the target texture from the swap chain
  82. private _mainTextureCopyView: GPUTextureCopyView;
  83. private _mainColorAttachments: GPURenderPassColorAttachmentDescriptor[];
  84. private _mainTextureExtends: GPUExtent3D;
  85. private _mainDepthAttachment: GPURenderPassDepthStencilAttachmentDescriptor;
  86. // Frame Life Cycle (recreated each frame)
  87. private _uploadEncoder: GPUCommandEncoder;
  88. private _renderEncoder: GPUCommandEncoder;
  89. private _blitEncoder: GPUCommandEncoder;
  90. private _commandBuffers: GPUCommandBuffer[] = [null as any, null as any];
  91. // Frame Buffer Life Cycle (recreated for each render target pass)
  92. private _currentRenderPass: Nullable<GPURenderPassEncoder> = null;
  93. // DrawCall Life Cycle
  94. // Effect is on the parent class
  95. // protected _currentEffect: Nullable<Effect> = null;
  96. private _currentVertexBuffers: Nullable<{ [key: string]: Nullable<VertexBuffer> }> = null;
  97. private _currentIndexBuffer: Nullable<DataBuffer> = null;
  98. private __colorWrite = true;
  99. private _uniformsBuffers: { [name: string]: WebGPUDataBuffer } = {};
  100. // Caches
  101. private _compiledShaders: { [key: string]: {
  102. stages: GPURenderPipelineStageDescriptor,
  103. availableAttributes: { [key: string]: number },
  104. availableUBOs: { [key: string]: { setIndex: number, bindingIndex: number} },
  105. availableSamplers: { [key: string]: { setIndex: number, bindingIndex: number} },
  106. orderedAttributes: string[],
  107. orderedUBOsAndSamplers: { name: string, isSampler: boolean }[][],
  108. leftOverUniforms: { name: string, type: string, length: number }[],
  109. leftOverUniformsByName: { [name: string]: string },
  110. sources: {
  111. vertex: string
  112. fragment: string,
  113. }
  114. } } = {};
  115. // TODO WEBGPU. Texture Management. Temporary...
  116. private _decodeCanvas = document.createElement("canvas");
  117. private _decodeEngine = new Engine(this._decodeCanvas, false, {
  118. alpha: true,
  119. premultipliedAlpha: false,
  120. }, false);
  121. /**
  122. * Gets a boolean indicating that the engine supports uniform buffers
  123. * @see http://doc.babylonjs.com/features/webgl2#uniform-buffer-objets
  124. */
  125. public get supportsUniformBuffers(): boolean {
  126. return true;
  127. }
  128. /**
  129. * Create a new instance of the gpu engine.
  130. * @param canvas Defines the canvas to use to display the result
  131. * @param options Defines the options passed to the engine to create the GPU context dependencies
  132. */
  133. public constructor(canvas: HTMLCanvasElement, options: WebGPUEngineOptions = {}) {
  134. super(null);
  135. options.deviceDescriptor = options.deviceDescriptor || { };
  136. options.swapChainFormat = options.swapChainFormat || WebGPUConstants.GPUTextureFormat_bgra8unorm;
  137. this._decodeEngine.getCaps().textureFloat = false;
  138. this._decodeEngine.getCaps().textureFloatRender = false;
  139. this._decodeEngine.getCaps().textureHalfFloat = false;
  140. this._decodeEngine.getCaps().textureHalfFloatRender = false;
  141. Logger.Log(`Babylon.js v${Engine.Version} - WebGPU engine`);
  142. if (!navigator.gpu) {
  143. // TODO WEBGPU Fall back to webgl.
  144. Logger.Error("WebGPU is not supported by your browser.");
  145. return;
  146. }
  147. this._isWebGPU = true;
  148. this._shaderPlatformName = "WEBGPU";
  149. if (options.deterministicLockstep === undefined) {
  150. options.deterministicLockstep = false;
  151. }
  152. if (options.lockstepMaxSteps === undefined) {
  153. options.lockstepMaxSteps = 4;
  154. }
  155. if (options.audioEngine === undefined) {
  156. options.audioEngine = true;
  157. }
  158. this._deterministicLockstep = options.deterministicLockstep;
  159. this._lockstepMaxSteps = options.lockstepMaxSteps;
  160. this._doNotHandleContextLost = true;
  161. this._canvas = canvas;
  162. this._options = options;
  163. this._sharedInit(canvas, !!options.doNotHandleTouchAction, options.audioEngine);
  164. }
  165. //------------------------------------------------------------------------------
  166. // Initialization
  167. //------------------------------------------------------------------------------
  168. /**
  169. * Initializes the WebGPU context and dependencies.
  170. * @param shadercOptions Defines the ShaderC compiler options if necessary
  171. * @returns a promise notifying the readiness of the engine.
  172. */
  173. public initEngineAsync(shadercOptions: any = null): Promise<void> {
  174. // TODO WEBGPU. Rename to initAsync.
  175. return (window as any).Shaderc(shadercOptions)
  176. .then((shaderc: any) => {
  177. this._shaderc = shaderc;
  178. return navigator.gpu!.requestAdapter(this._options);
  179. })
  180. .then((adapter: GPUAdapter) => {
  181. this._adapter = adapter;
  182. return this._adapter.requestDevice(this._options.deviceDescriptor);
  183. })
  184. .then((device: GPUDevice) => this._device = device)
  185. .then(() => {
  186. this._initializeLimits();
  187. this._initializeContextAndSwapChain();
  188. this._initializeMainAttachments();
  189. })
  190. .catch((e: any) => {
  191. Logger.Error("Can not create WebGPU Device and/or context.");
  192. Logger.Error(e);
  193. });
  194. }
  195. private _initializeLimits(): void {
  196. // Init caps
  197. // TODO WEBGPU Real Capability check once limits will be working.
  198. this._caps = new EngineCapabilities();
  199. this._caps.maxTexturesImageUnits = 16;
  200. this._caps.maxVertexTextureImageUnits = 16;
  201. this._caps.maxTextureSize = 2048;
  202. this._caps.maxCubemapTextureSize = 2048;
  203. this._caps.maxRenderTextureSize = 2048;
  204. this._caps.maxVertexAttribs = 16;
  205. this._caps.maxVaryingVectors = 16;
  206. this._caps.maxFragmentUniformVectors = 1024;
  207. this._caps.maxVertexUniformVectors = 1024;
  208. // Extensions
  209. this._caps.standardDerivatives = true;
  210. this._caps.astc = null;
  211. this._caps.s3tc = null;
  212. this._caps.pvrtc = null;
  213. this._caps.etc1 = null;
  214. this._caps.etc2 = null;
  215. this._caps.textureAnisotropicFilterExtension = null;
  216. this._caps.maxAnisotropy = 0;
  217. this._caps.uintIndices = true;
  218. this._caps.fragmentDepthSupported = false;
  219. this._caps.highPrecisionShaderSupported = true;
  220. this._caps.colorBufferFloat = true;
  221. this._caps.textureFloat = false;
  222. this._caps.textureFloatLinearFiltering = false;
  223. this._caps.textureFloatRender = false;
  224. this._caps.textureHalfFloat = false;
  225. this._caps.textureHalfFloatLinearFiltering = false;
  226. this._caps.textureHalfFloatRender = false;
  227. this._caps.textureLOD = true;
  228. this._caps.drawBuffersExtension = true;
  229. this._caps.depthTextureExtension = true;
  230. // TODO WEBGPU. No need here but could be use to create descriptors ???
  231. this._caps.vertexArrayObject = false;
  232. this._caps.instancedArrays = true;
  233. // TODO WEBGPU. Unused for now.
  234. // this._caps.parallelShaderCompile = null;
  235. }
  236. private _initializeContextAndSwapChain(): void {
  237. this._context = this._canvas.getContext('gpupresent') as unknown as GPUCanvasContext;
  238. this._swapChain = this._context.configureSwapChain({
  239. device: this._device,
  240. format: this._options.swapChainFormat,
  241. usage: WebGPUConstants.GPUTextureUsage_TRANSFER_DST,
  242. });
  243. }
  244. // Set default values as WebGL with depth and stencil attachment for the broadest Compat.
  245. // TODO WEBGPU. Reinit on resize.
  246. private _initializeMainAttachments(): void {
  247. this._mainTextureExtends = {
  248. width: this.getRenderWidth(),
  249. height: this.getRenderHeight(),
  250. depth: 1
  251. };
  252. const mainTextureDescriptor = {
  253. size: this._mainTextureExtends,
  254. arrayLayerCount: 1,
  255. mipLevelCount: 1,
  256. // sampleCount: 1,
  257. dimension: WebGPUConstants.GPUTextureDimension_2d,
  258. format: WebGPUConstants.GPUTextureFormat_bgra8unorm,
  259. usage: WebGPUConstants.GPUTextureUsage_OUTPUT_ATTACHMENT | WebGPUConstants.GPUTextureUsage_TRANSFER_SRC,
  260. };
  261. const mainTexture = this._device.createTexture(mainTextureDescriptor);
  262. const mainTextureView = mainTexture.createDefaultView();
  263. this._mainTextureCopyView = {
  264. texture: mainTexture,
  265. origin: {
  266. x: 0,
  267. y: 0,
  268. z: 0
  269. },
  270. mipLevel: 0,
  271. arrayLayer: 0,
  272. };
  273. this._mainColorAttachments = [{
  274. attachment: mainTextureView,
  275. clearColor: new Color4(0, 0, 0, 1),
  276. loadOp: WebGPUConstants.GPULoadOp_clear,
  277. storeOp: WebGPUConstants.GPUStoreOp_store
  278. }];
  279. const depthTextureDescriptor = {
  280. size: this._mainTextureExtends,
  281. arrayLayerCount: 1,
  282. mipLevelCount: 1,
  283. sampleCount: 1,
  284. dimension: WebGPUConstants.GPUTextureDimension_2d,
  285. format: WebGPUConstants.GPUTextureFormat_depth32floatStencil8,
  286. usage: WebGPUConstants.GPUTextureUsage_OUTPUT_ATTACHMENT
  287. };
  288. const depthTexture = this._device.createTexture(depthTextureDescriptor);
  289. this._mainDepthAttachment = {
  290. attachment: depthTexture.createDefaultView(),
  291. depthLoadOp: WebGPUConstants.GPULoadOp_clear,
  292. depthStoreOp: WebGPUConstants.GPUStoreOp_store,
  293. stencilLoadOp: WebGPUConstants.GPULoadOp_clear,
  294. stencilStoreOp: WebGPUConstants.GPUStoreOp_store,
  295. clearDepth: 1.0
  296. };
  297. }
  298. /**
  299. * Gets a shader processor implementation fitting with the current engine type.
  300. * @returns The shader processor implementation.
  301. */
  302. protected _getShaderProcessor(): Nullable<IShaderProcessor> {
  303. return new WebGPUShaderProcessor();
  304. }
  305. /** @hidden */
  306. public _getShaderProcessingContext(): Nullable<ShaderProcessingContext> {
  307. return new WebGPUShaderProcessingContext();
  308. }
  309. //------------------------------------------------------------------------------
  310. // Static Pipeline WebGPU States
  311. //------------------------------------------------------------------------------
  312. public wipeCaches(bruteForce?: boolean): void {
  313. if (this.preventCacheWipeBetweenFrames) {
  314. return;
  315. }
  316. this.resetTextureCache();
  317. this._currentEffect = null;
  318. this._currentIndexBuffer = null;
  319. this._currentVertexBuffers = null;
  320. if (bruteForce) {
  321. this._currentProgram = null;
  322. this._stencilState.reset();
  323. this._depthCullingState.reset();
  324. this._alphaState.reset();
  325. }
  326. this._cachedVertexBuffers = null;
  327. this._cachedIndexBuffer = null;
  328. this._cachedEffectForVertexBuffers = null;
  329. }
  330. public setColorWrite(enable: boolean): void {
  331. this.__colorWrite = enable;
  332. }
  333. public getColorWrite(): boolean {
  334. return this.__colorWrite;
  335. }
  336. //------------------------------------------------------------------------------
  337. // Dynamic WebGPU States
  338. //------------------------------------------------------------------------------
  339. public _viewport(x: number, y: number, width: number, height: number): void {
  340. // TODO WEBGPU. Cache.
  341. // if (x !== this._viewportCached.x ||
  342. // y !== this._viewportCached.y ||
  343. // width !== this._viewportCached.z ||
  344. // height !== this._viewportCached.w) {
  345. // this._viewportCached.x = x;
  346. // this._viewportCached.y = y;
  347. // this._viewportCached.z = width;
  348. // this._viewportCached.w = height;
  349. // this._gl.viewport(x, y, width, height);
  350. // }
  351. if (!this._currentRenderPass) {
  352. this._startMainRenderPass();
  353. }
  354. // TODO WEBGPU. Viewport.
  355. // Use 0 1 like the default webgl values.
  356. // this._currentRenderPass!.setViewport(x, y, width, height, 0, 1);
  357. }
  358. public enableScissor(x: number, y: number, width: number, height: number): void {
  359. if (!this._currentRenderPass) {
  360. this._startMainRenderPass();
  361. }
  362. // TODO WEBGPU. Scissor.
  363. //this._currentRenderPass!.setScissorRect(x, y, width, height);
  364. }
  365. public disableScissor() {
  366. if (!this._currentRenderPass) {
  367. this._startMainRenderPass();
  368. }
  369. // TODO WEBGPU. Scissor.
  370. //this._currentRenderPass!.setScissorRect(0, 0, this.getRenderWidth(), this.getRenderHeight());
  371. }
  372. public clear(color: Color4, backBuffer: boolean, depth: boolean, stencil: boolean = false): void {
  373. this._mainColorAttachments[0].clearColor = color;
  374. this._mainColorAttachments[0].loadOp = backBuffer ? WebGPUConstants.GPULoadOp_clear : WebGPUConstants.GPULoadOp_load;
  375. this._mainDepthAttachment.depthLoadOp = depth ? WebGPUConstants.GPULoadOp_clear : WebGPUConstants.GPULoadOp_load;
  376. this._mainDepthAttachment.stencilLoadOp = stencil ? WebGPUConstants.GPULoadOp_clear : WebGPUConstants.GPULoadOp_load;
  377. // TODO WEBGPU. Where to store GPUOpStore ???
  378. // TODO WEBGPU. Should be main or rtt with a frame buffer like object.
  379. this._startMainRenderPass();
  380. }
  381. //------------------------------------------------------------------------------
  382. // WebGPU Buffers
  383. //------------------------------------------------------------------------------
  384. private _createBuffer(view: ArrayBufferView, flags: GPUBufferUsageFlags): DataBuffer {
  385. const padding = view.byteLength % 4;
  386. const verticesBufferDescriptor = {
  387. size: view.byteLength + padding,
  388. usage: flags
  389. };
  390. const buffer = this._device.createBuffer(verticesBufferDescriptor);
  391. const dataBuffer = new WebGPUDataBuffer(buffer);
  392. dataBuffer.references = 1;
  393. dataBuffer.capacity = view.byteLength;
  394. this._setSubData(dataBuffer, 0, view);
  395. return dataBuffer;
  396. }
  397. private _setSubData(dataBuffer: WebGPUDataBuffer, dstByteOffset: number, src: ArrayBufferView, srcByteOffset = 0, byteLength = 0): void {
  398. const buffer = dataBuffer.underlyingResource as GPUBuffer;
  399. byteLength = byteLength || src.byteLength;
  400. byteLength = Math.min(byteLength, dataBuffer.capacity - dstByteOffset);
  401. // After Migration to Canary
  402. // This would do from PR #261
  403. let chunkStart = src.byteOffset + srcByteOffset;
  404. let chunkEnd = chunkStart + byteLength;
  405. // 4 bytes alignments for upload
  406. const padding = byteLength % 4;
  407. if (padding !== 0) {
  408. const tempView = new Uint8Array(src.buffer.slice(chunkStart, chunkEnd));
  409. src = new Uint8Array(byteLength + padding);
  410. tempView.forEach((element, index) => {
  411. (src as Uint8Array)[index] = element;
  412. });
  413. srcByteOffset = 0;
  414. chunkStart = 0;
  415. chunkEnd = byteLength + padding;
  416. byteLength = byteLength + padding;
  417. }
  418. // Chunk
  419. const maxChunk = 1024 * 1024 * 15;
  420. let offset = 0;
  421. while ((chunkEnd - (chunkStart + offset)) > maxChunk) {
  422. // TODO WEBGPU.
  423. // Deprecated soon to be removed... replace by mappedBuffers
  424. buffer.setSubData(dstByteOffset + offset, src, srcByteOffset + offset, maxChunk);
  425. offset += maxChunk;
  426. }
  427. // TODO WEBGPU.
  428. // Deprecated soon to be removed... replace by mappedBuffers
  429. buffer.setSubData(dstByteOffset + offset, src, srcByteOffset + offset, byteLength - offset);
  430. }
  431. //------------------------------------------------------------------------------
  432. // Vertex/Index Buffers
  433. //------------------------------------------------------------------------------
  434. public createVertexBuffer(data: DataArray): DataBuffer {
  435. let view: ArrayBufferView;
  436. if (data instanceof Array) {
  437. view = new Float32Array(data);
  438. }
  439. else if (data instanceof ArrayBuffer) {
  440. view = new Uint8Array(data);
  441. }
  442. else {
  443. view = data;
  444. }
  445. const dataBuffer = this._createBuffer(view, WebGPUConstants.GPUBufferUsage_VERTEX | WebGPUConstants.GPUBufferUsage_TRANSFER_DST);
  446. return dataBuffer;
  447. }
  448. public createDynamicVertexBuffer(data: DataArray): DataBuffer {
  449. // TODO WEBGPU.
  450. return this.createVertexBuffer(data);
  451. }
  452. public updateDynamicVertexBuffer(vertexBuffer: DataBuffer, data: DataArray, byteOffset?: number, byteLength?: number): void {
  453. const dataBuffer = vertexBuffer as WebGPUDataBuffer;
  454. if (byteOffset === undefined) {
  455. byteOffset = 0;
  456. }
  457. let view: ArrayBufferView;
  458. if (byteLength === undefined) {
  459. if (data instanceof Array) {
  460. view = new Float32Array(data);
  461. }
  462. else if (data instanceof ArrayBuffer) {
  463. view = new Uint8Array(data);
  464. }
  465. else {
  466. view = data;
  467. }
  468. byteLength = view.byteLength;
  469. } else {
  470. if (data instanceof Array) {
  471. view = new Float32Array(data);
  472. }
  473. else if (data instanceof ArrayBuffer) {
  474. view = new Uint8Array(data);
  475. }
  476. else {
  477. view = data;
  478. }
  479. }
  480. this._setSubData(dataBuffer, byteOffset, view, 0, byteLength);
  481. }
  482. public createIndexBuffer(data: IndicesArray): DataBuffer {
  483. let is32Bits = true;
  484. let view: ArrayBufferView;
  485. if (data instanceof Uint32Array || data instanceof Int32Array) {
  486. view = data;
  487. }
  488. else if (data instanceof Uint16Array) {
  489. view = data;
  490. is32Bits = false;
  491. }
  492. else {
  493. if (data.length > 65535) {
  494. view = new Uint32Array(data);
  495. }
  496. else {
  497. view = new Uint16Array(data);
  498. is32Bits = false;
  499. }
  500. }
  501. const dataBuffer = this._createBuffer(view, WebGPUConstants.GPUBufferUsage_INDEX | WebGPUConstants.GPUBufferUsage_TRANSFER_DST);
  502. dataBuffer.is32Bits = is32Bits;
  503. return dataBuffer;
  504. }
  505. public updateDynamicIndexBuffer(indexBuffer: DataBuffer, indices: IndicesArray, offset: number = 0): void {
  506. const gpuBuffer = indexBuffer as WebGPUDataBuffer;
  507. // TODO WEBGPU. Manage buffer morphing from small int to bigint.
  508. var view: ArrayBufferView;
  509. if (indices instanceof Uint16Array) {
  510. if (indexBuffer.is32Bits) {
  511. view = Uint32Array.from(indices);
  512. }
  513. else {
  514. view = indices;
  515. }
  516. }
  517. else if (indices instanceof Uint32Array) {
  518. if (indexBuffer.is32Bits) {
  519. view = indices;
  520. }
  521. else {
  522. view = Uint16Array.from(indices);
  523. }
  524. }
  525. else {
  526. if (indexBuffer.is32Bits) {
  527. view = new Uint32Array(indices);
  528. }
  529. else {
  530. view = new Uint16Array(indices);
  531. }
  532. }
  533. // TODO WEBGPU. check if offset is in bytes ???
  534. this._setSubData(gpuBuffer, offset, view);
  535. }
  536. public bindBuffersDirectly(vertexBuffer: DataBuffer, indexBuffer: DataBuffer, vertexDeclaration: number[], vertexStrideSize: number, effect: Effect): void {
  537. throw "Not implemented on WebGPU so far.";
  538. }
  539. public updateAndBindInstancesBuffer(instancesBuffer: DataBuffer, data: Float32Array, offsetLocations: number[] | InstancingAttributeInfo[]): void {
  540. throw "Not implemented on WebGPU so far.";
  541. }
  542. public bindBuffers(vertexBuffers: { [key: string]: Nullable<VertexBuffer> }, indexBuffer: Nullable<DataBuffer>, effect: Effect): void {
  543. this._currentIndexBuffer = indexBuffer;
  544. this._currentVertexBuffers = vertexBuffers;
  545. }
  546. /** @hidden */
  547. public _releaseBuffer(buffer: DataBuffer): boolean {
  548. buffer.references--;
  549. if (buffer.references === 0) {
  550. (buffer.underlyingResource as GPUBuffer).destroy();
  551. return true;
  552. }
  553. return false;
  554. }
  555. //------------------------------------------------------------------------------
  556. // UBO
  557. //------------------------------------------------------------------------------
  558. public createUniformBuffer(elements: FloatArray): DataBuffer {
  559. let view: Float32Array;
  560. if (elements instanceof Array) {
  561. view = new Float32Array(elements);
  562. }
  563. else {
  564. view = elements;
  565. }
  566. const dataBuffer = this._createBuffer(view, WebGPUConstants.GPUBufferUsage_UNIFORM | WebGPUConstants.GPUBufferUsage_TRANSFER_DST);
  567. return dataBuffer;
  568. }
  569. public createDynamicUniformBuffer(elements: FloatArray): DataBuffer {
  570. // TODO WEBGPU. Implement dynamic buffers.
  571. return this.createUniformBuffer(elements);
  572. }
  573. public updateUniformBuffer(uniformBuffer: DataBuffer, elements: FloatArray, offset?: number, count?: number): void {
  574. if (offset === undefined) {
  575. offset = 0;
  576. }
  577. const dataBuffer = uniformBuffer as WebGPUDataBuffer;
  578. let view: Float32Array;
  579. if (count === undefined) {
  580. if (elements instanceof Float32Array) {
  581. view = elements;
  582. } else {
  583. view = new Float32Array(elements);
  584. }
  585. count = view.byteLength;
  586. } else {
  587. if (elements instanceof Float32Array) {
  588. view = elements;
  589. } else {
  590. view = new Float32Array(elements);
  591. }
  592. }
  593. // TODO WEBGPU. Check count and offset are in bytes.
  594. this._setSubData(dataBuffer, offset, view, 0, count);
  595. }
  596. public bindUniformBufferBase(buffer: DataBuffer, location: number, name: string): void {
  597. this._uniformsBuffers[name] = buffer as WebGPUDataBuffer;
  598. }
  599. //------------------------------------------------------------------------------
  600. // Effects
  601. //------------------------------------------------------------------------------
  602. public createEffect(baseName: any, attributesNamesOrOptions: string[] | EffectCreationOptions, uniformsNamesOrEngine: string[] | Engine, samplers?: string[], defines?: string, fallbacks?: EffectFallbacks,
  603. onCompiled?: Nullable<(effect: Effect) => void>, onError?: Nullable<(effect: Effect, errors: string) => void>, indexParameters?: any): Effect {
  604. const vertex = baseName.vertexElement || baseName.vertex || baseName;
  605. const fragment = baseName.fragmentElement || baseName.fragment || baseName;
  606. const name = vertex + "+" + fragment + "@" + (defines ? defines : (<EffectCreationOptions>attributesNamesOrOptions).defines);
  607. const shader = this._compiledShaders[name];
  608. if (shader) {
  609. return new Effect(baseName, attributesNamesOrOptions, uniformsNamesOrEngine, samplers, this, defines, fallbacks, onCompiled, onError, indexParameters, name, shader.sources);
  610. }
  611. else {
  612. return new Effect(baseName, attributesNamesOrOptions, uniformsNamesOrEngine, samplers, this, defines, fallbacks, onCompiled, onError, indexParameters, name);
  613. }
  614. }
  615. private _compileRawShaderToSpirV(source: string, type: string): Uint32Array {
  616. const Shaderc = this._shaderc;
  617. const compiler = new Shaderc.Compiler();
  618. const opts = new Shaderc.CompileOptions();
  619. const result = compiler.CompileGlslToSpv(source,
  620. type === "fragment" ? Shaderc.shader_kind.fragment :
  621. type === "vertex" ? Shaderc.shader_kind.vertex :
  622. type === "compute" ? Shaderc.shader_kind.compute : null,
  623. "tempCompilation.glsl", "main", opts);
  624. const error = result.GetErrorMessage();
  625. if (error) {
  626. Logger.Error(error);
  627. throw new Error("Something went wrong while compile the shader.");
  628. }
  629. return result.GetBinary().slice();
  630. }
  631. private _compileShaderToSpirV(source: string, type: string, defines: Nullable<string>, shaderVersion: string): Uint32Array {
  632. return this._compileRawShaderToSpirV(shaderVersion + (defines ? defines + "\n" : "") + source, type);
  633. }
  634. private _createPipelineStageDescriptor(vertexShader: Uint32Array, fragmentShader: Uint32Array): GPURenderPipelineStageDescriptor {
  635. return {
  636. vertexStage: {
  637. module: this._device.createShaderModule({
  638. code: vertexShader,
  639. }),
  640. entryPoint: "main",
  641. },
  642. fragmentStage: {
  643. module: this._device.createShaderModule({
  644. code: fragmentShader,
  645. }),
  646. entryPoint: "main"
  647. }
  648. };
  649. }
  650. private _compileRawPipelineStageDescriptor(vertexCode: string, fragmentCode: string): GPURenderPipelineStageDescriptor {
  651. var vertexShader = this._compileRawShaderToSpirV(vertexCode, "vertex");
  652. var fragmentShader = this._compileRawShaderToSpirV(fragmentCode, "fragment");
  653. return this._createPipelineStageDescriptor(vertexShader, fragmentShader);
  654. }
  655. private _compilePipelineStageDescriptor(vertexCode: string, fragmentCode: string, defines: Nullable<string>): GPURenderPipelineStageDescriptor {
  656. this.onBeforeShaderCompilationObservable.notifyObservers(this);
  657. var shaderVersion = "#version 450\n";
  658. var vertexShader = this._compileShaderToSpirV(vertexCode, "vertex", defines, shaderVersion);
  659. var fragmentShader = this._compileShaderToSpirV(fragmentCode, "fragment", defines, shaderVersion);
  660. let program = this._createPipelineStageDescriptor(vertexShader, fragmentShader);
  661. this.onAfterShaderCompilationObservable.notifyObservers(this);
  662. return program;
  663. }
  664. public createRawShaderProgram(pipelineContext: IPipelineContext, vertexCode: string, fragmentCode: string, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
  665. throw "Not available on WebGPU";
  666. }
  667. public createShaderProgram(pipelineContext: IPipelineContext, vertexCode: string, fragmentCode: string, defines: Nullable<string>, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
  668. throw "Not available on WebGPU";
  669. }
  670. public createPipelineContext(shaderProcessingContext: Nullable<ShaderProcessingContext>): IPipelineContext {
  671. var pipelineContext = new WebGPUPipelineContext(shaderProcessingContext! as WebGPUShaderProcessingContext, this);
  672. pipelineContext.engine = this;
  673. return pipelineContext;
  674. }
  675. /** @hidden */
  676. public _preparePipelineContext(pipelineContext: IPipelineContext, vertexSourceCode: string, fragmentSourceCode: string, createAsRaw: boolean,
  677. rebuildRebind: any,
  678. defines: Nullable<string>,
  679. transformFeedbackVaryings: Nullable<string[]>,
  680. key: string) {
  681. const webGpuContext = pipelineContext as WebGPUPipelineContext;
  682. // TODO WEBGPU. Check if caches could be reuse from piepline ???
  683. const shader = this._compiledShaders[key];
  684. if (shader) {
  685. webGpuContext.stages = shader.stages;
  686. webGpuContext.availableAttributes = shader.availableAttributes;
  687. webGpuContext.availableUBOs = shader.availableUBOs;
  688. webGpuContext.availableSamplers = shader.availableSamplers;
  689. webGpuContext.orderedAttributes = shader.orderedAttributes;
  690. webGpuContext.orderedUBOsAndSamplers = shader.orderedUBOsAndSamplers;
  691. webGpuContext.leftOverUniforms = shader.leftOverUniforms;
  692. webGpuContext.leftOverUniformsByName = shader.leftOverUniformsByName;
  693. webGpuContext.sources = shader.sources;
  694. }
  695. else {
  696. if (createAsRaw) {
  697. webGpuContext.stages = this._compileRawPipelineStageDescriptor(vertexSourceCode, fragmentSourceCode);
  698. }
  699. else {
  700. webGpuContext.stages = this._compilePipelineStageDescriptor(vertexSourceCode, fragmentSourceCode, defines);
  701. }
  702. this._compiledShaders[key] = {
  703. stages: webGpuContext.stages,
  704. availableAttributes: webGpuContext.availableAttributes,
  705. availableUBOs: webGpuContext.availableUBOs,
  706. availableSamplers: webGpuContext.availableSamplers,
  707. orderedAttributes: webGpuContext.orderedAttributes,
  708. orderedUBOsAndSamplers: webGpuContext.orderedUBOsAndSamplers,
  709. leftOverUniforms: webGpuContext.leftOverUniforms,
  710. leftOverUniformsByName: webGpuContext.leftOverUniformsByName,
  711. sources: {
  712. fragment: fragmentSourceCode,
  713. vertex: vertexSourceCode
  714. }
  715. };
  716. }
  717. }
  718. public getAttributes(pipelineContext: IPipelineContext, attributesNames: string[]): number[] {
  719. const results = new Array(attributesNames.length);
  720. const gpuPipelineContext = (pipelineContext as WebGPUPipelineContext);
  721. // TODO WEBGPU.
  722. // Hard coded for WebGPU until an introspection lib is available.
  723. // Should be done at processing time, not need to double the work in here.
  724. for (let i = 0; i < attributesNames.length; i++) {
  725. const attributeName = attributesNames[i];
  726. const attributeLocation = gpuPipelineContext.availableAttributes[attributeName];
  727. if (attributeLocation === undefined) {
  728. continue;
  729. }
  730. results[i] = attributeLocation;
  731. }
  732. return results;
  733. }
  734. public enableEffect(effect: Effect): void {
  735. this._currentEffect = effect;
  736. if (effect.onBind) {
  737. effect.onBind(effect);
  738. }
  739. if (effect._onBindObservable) {
  740. effect._onBindObservable.notifyObservers(effect);
  741. }
  742. }
  743. public _releaseEffect(effect: Effect): void {
  744. // Effect gets garbage collected without explicit destroy in WebGPU.
  745. }
  746. /**
  747. * Force the engine to release all cached effects. This means that next effect compilation will have to be done completely even if a similar effect was already compiled
  748. */
  749. public releaseEffects() {
  750. // Effect gets garbage collected without explicit destroy in WebGPU.
  751. }
  752. public _deletePipelineContext(pipelineContext: IPipelineContext): void {
  753. const webgpuPipelineContext = pipelineContext as WebGPUPipelineContext;
  754. if (webgpuPipelineContext) {
  755. // TODO WEBGPU. Spector like cleanup.
  756. // TODO WEBGPU. Any pipeline required cleanup.
  757. }
  758. }
  759. //------------------------------------------------------------------------------
  760. // Textures
  761. //------------------------------------------------------------------------------
  762. // TODO WEBGPU. SHOULD not be possible to return gl unwrapped from Engine.
  763. /** @hidden */
  764. public _createTexture(): WebGLTexture {
  765. return { };
  766. }
  767. /** @hidden */
  768. public _releaseTexture(texture: InternalTexture): void {
  769. // TODO WEBGPU. check if it is all to release.
  770. if (texture._webGPUTexture) {
  771. texture._webGPUTexture.destroy();
  772. }
  773. }
  774. private _uploadMipMapsFromWebglTexture(mipMaps: number, webglEngineTexture: InternalTexture, gpuTexture: GPUTexture, width: number, height: number, face: number) {
  775. this._uploadFromWebglTexture(webglEngineTexture, gpuTexture, width, height, face);
  776. let faceWidth = width;
  777. let faceHeight = height;
  778. for (let mip = 1; mip <= mipMaps; mip++) {
  779. faceWidth = Math.max(Math.floor(faceWidth / 2), 1);
  780. faceHeight = Math.max(Math.floor(faceHeight / 2), 1);
  781. this._uploadFromWebglTexture(webglEngineTexture, gpuTexture, faceWidth, faceHeight, face, mip);
  782. }
  783. }
  784. private _uploadFromWebglTexture(webglEngineTexture: InternalTexture, gpuTexture: GPUTexture, width: number, height: number, face: number, mip: number = 0): void {
  785. let pixels = this._decodeEngine._readTexturePixels(webglEngineTexture, width, height, face, mip);
  786. if (pixels instanceof Float32Array) {
  787. const newPixels = new Uint8ClampedArray(pixels.length);
  788. pixels.forEach((value, index) => newPixels[index] = value * 255);
  789. pixels = newPixels;
  790. }
  791. const textureView: GPUTextureCopyView = {
  792. texture: gpuTexture,
  793. origin: {
  794. x: 0,
  795. y: 0,
  796. z: 0
  797. },
  798. mipLevel: mip,
  799. arrayLayer: Math.max(face, 0),
  800. };
  801. const textureExtent = {
  802. width,
  803. height,
  804. depth: 1
  805. };
  806. const commandEncoder = this._device.createCommandEncoder({});
  807. const rowPitch = Math.ceil(width * 4 / 256) * 256;
  808. let dataBuffer: DataBuffer;
  809. if (rowPitch == width * 4) {
  810. dataBuffer = this._createBuffer(pixels, WebGPUConstants.GPUBufferUsage_TRANSFER_SRC | WebGPUConstants.GPUBufferUsage_TRANSFER_DST);
  811. const bufferView: GPUBufferCopyView = {
  812. buffer: dataBuffer.underlyingResource,
  813. rowPitch: rowPitch,
  814. imageHeight: height,
  815. offset: 0,
  816. };
  817. commandEncoder.copyBufferToTexture(bufferView, textureView, textureExtent);
  818. } else {
  819. const alignedPixels = new Uint8Array(rowPitch * height);
  820. let pixelsIndex = 0;
  821. for (let y = 0; y < height; ++y) {
  822. for (let x = 0; x < width; ++x) {
  823. let i = x * 4 + y * rowPitch;
  824. alignedPixels[i] = (pixels as any)[pixelsIndex];
  825. alignedPixels[i + 1] = (pixels as any)[pixelsIndex + 1];
  826. alignedPixels[i + 2] = (pixels as any)[pixelsIndex + 2];
  827. alignedPixels[i + 3] = (pixels as any)[pixelsIndex + 3];
  828. pixelsIndex += 4;
  829. }
  830. }
  831. dataBuffer = this._createBuffer(alignedPixels, WebGPUConstants.GPUBufferUsage_TRANSFER_SRC | WebGPUConstants.GPUBufferUsage_TRANSFER_DST);
  832. const bufferView: GPUBufferCopyView = {
  833. buffer: dataBuffer.underlyingResource,
  834. rowPitch: rowPitch,
  835. imageHeight: height,
  836. offset: 0,
  837. };
  838. commandEncoder.copyBufferToTexture(bufferView, textureView, textureExtent);
  839. }
  840. this._device.getQueue().submit([commandEncoder.finish()]);
  841. this._releaseBuffer(dataBuffer);
  842. }
  843. private _getSamplerFilterDescriptor(internalTexture: InternalTexture): {
  844. magFilter: GPUFilterMode,
  845. minFilter: GPUFilterMode,
  846. mipmapFilter: GPUFilterMode
  847. } {
  848. let magFilter: GPUFilterMode, minFilter: GPUFilterMode, mipmapFilter: GPUFilterMode;
  849. switch (internalTexture.samplingMode) {
  850. case Engine.TEXTURE_BILINEAR_SAMPLINGMODE:
  851. magFilter = WebGPUConstants.GPUFilterMode_linear;
  852. minFilter = WebGPUConstants.GPUFilterMode_linear;
  853. mipmapFilter = WebGPUConstants.GPUFilterMode_nearest;
  854. break;
  855. case Engine.TEXTURE_TRILINEAR_SAMPLINGMODE:
  856. magFilter = WebGPUConstants.GPUFilterMode_linear;
  857. minFilter = WebGPUConstants.GPUFilterMode_linear;
  858. mipmapFilter = WebGPUConstants.GPUFilterMode_linear;
  859. break;
  860. case Engine.TEXTURE_NEAREST_SAMPLINGMODE:
  861. magFilter = WebGPUConstants.GPUFilterMode_nearest;
  862. minFilter = WebGPUConstants.GPUFilterMode_nearest;
  863. mipmapFilter = WebGPUConstants.GPUFilterMode_linear;
  864. break;
  865. case Engine.TEXTURE_NEAREST_NEAREST_MIPNEAREST:
  866. magFilter = WebGPUConstants.GPUFilterMode_nearest;
  867. minFilter = WebGPUConstants.GPUFilterMode_nearest;
  868. mipmapFilter = WebGPUConstants.GPUFilterMode_nearest;
  869. break;
  870. case Engine.TEXTURE_NEAREST_LINEAR_MIPNEAREST:
  871. magFilter = WebGPUConstants.GPUFilterMode_nearest;
  872. minFilter = WebGPUConstants.GPUFilterMode_linear;
  873. mipmapFilter = WebGPUConstants.GPUFilterMode_nearest;
  874. break;
  875. case Engine.TEXTURE_NEAREST_LINEAR_MIPLINEAR:
  876. magFilter = WebGPUConstants.GPUFilterMode_nearest;
  877. minFilter = WebGPUConstants.GPUFilterMode_linear;
  878. mipmapFilter = WebGPUConstants.GPUFilterMode_linear;
  879. break;
  880. case Engine.TEXTURE_NEAREST_LINEAR:
  881. magFilter = WebGPUConstants.GPUFilterMode_nearest;
  882. minFilter = WebGPUConstants.GPUFilterMode_linear;
  883. mipmapFilter = WebGPUConstants.GPUFilterMode_nearest;
  884. break;
  885. case Engine.TEXTURE_NEAREST_NEAREST:
  886. magFilter = WebGPUConstants.GPUFilterMode_nearest;
  887. minFilter = WebGPUConstants.GPUFilterMode_nearest;
  888. mipmapFilter = WebGPUConstants.GPUFilterMode_nearest;
  889. break;
  890. case Engine.TEXTURE_LINEAR_NEAREST_MIPNEAREST:
  891. magFilter = WebGPUConstants.GPUFilterMode_linear;
  892. minFilter = WebGPUConstants.GPUFilterMode_nearest;
  893. mipmapFilter = WebGPUConstants.GPUFilterMode_nearest;
  894. break;
  895. case Engine.TEXTURE_LINEAR_NEAREST_MIPLINEAR:
  896. magFilter = WebGPUConstants.GPUFilterMode_linear;
  897. minFilter = WebGPUConstants.GPUFilterMode_nearest;
  898. mipmapFilter = WebGPUConstants.GPUFilterMode_linear;
  899. break;
  900. case Engine.TEXTURE_LINEAR_LINEAR:
  901. magFilter = WebGPUConstants.GPUFilterMode_linear;
  902. minFilter = WebGPUConstants.GPUFilterMode_linear;
  903. mipmapFilter = WebGPUConstants.GPUFilterMode_nearest;
  904. break;
  905. case Engine.TEXTURE_LINEAR_NEAREST:
  906. magFilter = WebGPUConstants.GPUFilterMode_linear;
  907. minFilter = WebGPUConstants.GPUFilterMode_nearest;
  908. mipmapFilter = WebGPUConstants.GPUFilterMode_nearest;
  909. break;
  910. default:
  911. magFilter = WebGPUConstants.GPUFilterMode_linear;
  912. minFilter = WebGPUConstants.GPUFilterMode_linear;
  913. mipmapFilter = WebGPUConstants.GPUFilterMode_linear;
  914. break;
  915. }
  916. return {
  917. magFilter,
  918. minFilter,
  919. mipmapFilter
  920. };
  921. }
  922. private _getWrappingMode(mode: number): GPUAddressMode {
  923. switch (mode) {
  924. case Engine.TEXTURE_WRAP_ADDRESSMODE:
  925. return WebGPUConstants.GPUAddressMode_repeat;
  926. case Engine.TEXTURE_CLAMP_ADDRESSMODE:
  927. return WebGPUConstants.GPUAddressMode_clampToEdge;
  928. case Engine.TEXTURE_MIRROR_ADDRESSMODE:
  929. return WebGPUConstants.GPUAddressMode_mirrorRepeat;
  930. // case Engine.TEXTURE_MIRROR_BORDERMODE:
  931. // return WebGPUConstants.GPUAddressMode_clampToBorderColor;
  932. }
  933. return WebGPUConstants.GPUAddressMode_repeat;
  934. }
  935. private _getSamplerWrappingDescriptor(internalTexture: InternalTexture): {
  936. addressModeU: GPUAddressMode,
  937. addressModeV: GPUAddressMode,
  938. addressModeW: GPUAddressMode
  939. } {
  940. return {
  941. addressModeU: this._getWrappingMode(internalTexture._cachedWrapU!),
  942. addressModeV: this._getWrappingMode(internalTexture._cachedWrapV!),
  943. addressModeW: this._getWrappingMode(internalTexture._cachedWrapR!),
  944. };
  945. }
  946. private _getSamplerDescriptor(internalTexture: InternalTexture): GPUSamplerDescriptor {
  947. return {
  948. ...this._getSamplerFilterDescriptor(internalTexture),
  949. ...this._getSamplerWrappingDescriptor(internalTexture),
  950. };
  951. }
  952. public createTexture(urlArg: string, noMipmap: boolean, invertY: boolean, scene: Scene, samplingMode: number = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE, onLoad: Nullable<() => void> = null, onError: Nullable<(message: string, exception: any) => void> = null, buffer: Nullable<ArrayBuffer | HTMLImageElement> = null, fallBack?: InternalTexture, format?: number): InternalTexture {
  953. const texture = new InternalTexture(this, InternalTexture.DATASOURCE_URL);
  954. const url = String(urlArg);
  955. // TODO WEBGPU. Find a better way.
  956. // TODO WEBGPU. this._options.textureSize
  957. texture.url = url;
  958. texture.generateMipMaps = !noMipmap;
  959. texture.samplingMode = samplingMode;
  960. texture.invertY = invertY;
  961. if (format) {
  962. texture.format = format;
  963. }
  964. let webglEngineTexture: InternalTexture;
  965. const onLoadInternal = () => {
  966. texture.isReady = webglEngineTexture.isReady;
  967. const width = webglEngineTexture.width;
  968. const height = webglEngineTexture.height;
  969. texture.width = width;
  970. texture.height = height;
  971. texture.baseWidth = width;
  972. texture.baseHeight = height;
  973. texture._isRGBD = webglEngineTexture._isRGBD;
  974. texture._sphericalPolynomial = webglEngineTexture._sphericalPolynomial;
  975. let mipMaps = Scalar.Log2(Math.max(width, height));
  976. mipMaps = Math.round(mipMaps);
  977. const textureExtent = {
  978. width,
  979. height,
  980. depth: 1
  981. };
  982. const textureDescriptor: GPUTextureDescriptor = {
  983. dimension: WebGPUConstants.GPUTextureDimension_2d,
  984. format: WebGPUConstants.GPUTextureFormat_rgba8unorm,
  985. arrayLayerCount: 1,
  986. mipLevelCount: noMipmap ? 1 : mipMaps + 1,
  987. sampleCount: 1,
  988. size: textureExtent,
  989. usage: WebGPUConstants.GPUTextureUsage_TRANSFER_DST | WebGPUConstants.GPUTextureUsage_SAMPLED
  990. };
  991. const gpuTexture = this._device.createTexture(textureDescriptor);
  992. texture._webGPUTexture = gpuTexture;
  993. if (noMipmap) {
  994. this._uploadFromWebglTexture(webglEngineTexture, gpuTexture, width, height, -1);
  995. }
  996. else {
  997. this._uploadMipMapsFromWebglTexture(mipMaps, webglEngineTexture, gpuTexture, width, height, -1);
  998. }
  999. texture._webGPUTextureView = gpuTexture.createDefaultView();
  1000. webglEngineTexture.dispose();
  1001. if (onLoad) {
  1002. onLoad();
  1003. }
  1004. };
  1005. webglEngineTexture = this._decodeEngine.createTexture(urlArg, noMipmap, invertY, scene, samplingMode,
  1006. onLoadInternal, onError, buffer, fallBack, format);
  1007. this._internalTexturesCache.push(texture);
  1008. return texture;
  1009. }
  1010. public createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad: Nullable<(data?: any) => void> = null, onError: Nullable<(message?: string, exception?: any) => void> = null, format?: number, forcedExtension: any = null, createPolynomials: boolean = false, lodScale: number = 0, lodOffset: number = 0, fallback: Nullable<InternalTexture> = null, excludeLoaders: Array<IInternalTextureLoader> = []): InternalTexture {
  1011. var texture = fallback ? fallback : new InternalTexture(this, InternalTexture.DATASOURCE_CUBE);
  1012. texture.isCube = true;
  1013. texture.url = rootUrl;
  1014. texture.generateMipMaps = !noMipmap;
  1015. // TODO WEBGPU. Cube Texture Sampling Mode.
  1016. texture.samplingMode = noMipmap ? Constants.TEXTURE_BILINEAR_SAMPLINGMODE : Constants.TEXTURE_TRILINEAR_SAMPLINGMODE;
  1017. texture._lodGenerationScale = lodScale;
  1018. texture._lodGenerationOffset = lodOffset;
  1019. if (!this._doNotHandleContextLost) {
  1020. texture._extension = forcedExtension;
  1021. texture._files = files;
  1022. }
  1023. let webglEngineTexture: InternalTexture;
  1024. const onLoadInternal = () => {
  1025. texture.isReady = webglEngineTexture.isReady;
  1026. const width = webglEngineTexture.width;
  1027. const height = webglEngineTexture.height;
  1028. const depth = 1;
  1029. texture.width = width;
  1030. texture.height = height;
  1031. texture.baseWidth = width;
  1032. texture.baseHeight = height;
  1033. texture.depth = depth;
  1034. texture.baseDepth = depth;
  1035. texture._isRGBD = webglEngineTexture._isRGBD;
  1036. texture._sphericalPolynomial = webglEngineTexture._sphericalPolynomial;
  1037. let mipMaps = Scalar.Log2(width);
  1038. mipMaps = Math.round(mipMaps);
  1039. const textureExtent = {
  1040. width,
  1041. height,
  1042. depth,
  1043. };
  1044. const textureDescriptor: GPUTextureDescriptor = {
  1045. dimension: WebGPUConstants.GPUTextureDimension_2d,
  1046. format: WebGPUConstants.GPUTextureFormat_rgba8unorm,
  1047. arrayLayerCount: 6,
  1048. mipLevelCount: noMipmap ? 1 : mipMaps + 1,
  1049. sampleCount: 1,
  1050. size: textureExtent,
  1051. usage: WebGPUConstants.GPUTextureUsage_TRANSFER_DST | WebGPUConstants.GPUTextureUsage_SAMPLED
  1052. };
  1053. const gpuTexture = this._device.createTexture(textureDescriptor);
  1054. texture._webGPUTexture = gpuTexture;
  1055. const faces = [0, 1, 2, 3, 4, 5];
  1056. for (let face of faces) {
  1057. if (noMipmap) {
  1058. this._uploadFromWebglTexture(webglEngineTexture, gpuTexture, width, height, face);
  1059. }
  1060. else {
  1061. this._uploadMipMapsFromWebglTexture(mipMaps, webglEngineTexture, gpuTexture, width, height, face);
  1062. }
  1063. }
  1064. texture._webGPUTextureView = gpuTexture.createView({
  1065. arrayLayerCount: 6,
  1066. dimension: "cube",
  1067. format: "rgba8unorm",
  1068. mipLevelCount: noMipmap ? 1 : mipMaps + 1,
  1069. baseArrayLayer: 0,
  1070. baseMipLevel: 0,
  1071. aspect: "all",
  1072. });
  1073. webglEngineTexture.dispose();
  1074. onLoad && onLoad();
  1075. };
  1076. webglEngineTexture = this._decodeEngine.createCubeTexture(rootUrl, scene, files, noMipmap, onLoadInternal, onError, format, forcedExtension, createPolynomials, lodScale, lodOffset, fallback, excludeLoaders);
  1077. this._internalTexturesCache.push(texture);
  1078. return texture;
  1079. }
  1080. public updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void {
  1081. texture.samplingMode = samplingMode;
  1082. }
  1083. public updateDynamicTexture(texture: Nullable<InternalTexture>, canvas: HTMLCanvasElement, invertY: boolean, premulAlpha: boolean = false, format?: number): void {
  1084. // TODO WEBGPU.
  1085. throw "Unimplemented updateDynamicTexture on WebGPU so far";
  1086. }
  1087. public setTexture(channel: number, _: Nullable<WebGLUniformLocation>, texture: Nullable<BaseTexture>, name: string): void {
  1088. if (this._currentEffect) {
  1089. const pipeline = this._currentEffect._pipelineContext as WebGPUPipelineContext;
  1090. if (!texture) {
  1091. pipeline.samplers[name] = null;
  1092. return;
  1093. }
  1094. const internalTexture = texture!.getInternalTexture();
  1095. if (internalTexture) {
  1096. internalTexture._cachedWrapU = texture.wrapU;
  1097. internalTexture._cachedWrapV = texture.wrapV;
  1098. internalTexture._cachedWrapR = texture.wrapR;
  1099. }
  1100. if (pipeline.samplers[name]) {
  1101. pipeline.samplers[name]!.texture = internalTexture!;
  1102. }
  1103. else {
  1104. // TODO WEBGPU. GC + 121 mapping samplers <-> availableSamplers
  1105. const availableSampler = pipeline.availableSamplers[name];
  1106. pipeline.samplers[name] = {
  1107. setIndex: availableSampler.setIndex,
  1108. textureBinding: availableSampler.bindingIndex,
  1109. samplerBinding: availableSampler.bindingIndex + 1,
  1110. texture: internalTexture!
  1111. };
  1112. }
  1113. }
  1114. }
  1115. public bindSamplers(effect: Effect): void { }
  1116. public _bindTextureDirectly(target: number, texture: InternalTexture): boolean {
  1117. if (this._boundTexturesCache[this._activeChannel] !== texture) {
  1118. this._boundTexturesCache[this._activeChannel] = texture;
  1119. return true;
  1120. }
  1121. return false;
  1122. }
  1123. /** @hidden */
  1124. public _bindTexture(channel: number, texture: InternalTexture): void {
  1125. if (channel < 0) {
  1126. return;
  1127. }
  1128. this._bindTextureDirectly(0, texture);
  1129. }
  1130. /** @hidden */
  1131. public _uploadCompressedDataToTextureDirectly(texture: InternalTexture, internalFormat: number, width: number, height: number, data: ArrayBufferView, faceIndex: number = 0, lod: number = 0) {
  1132. }
  1133. /** @hidden */
  1134. public _uploadDataToTextureDirectly(texture: InternalTexture, imageData: ArrayBufferView, faceIndex: number = 0, lod: number = 0): void {
  1135. }
  1136. /** @hidden */
  1137. public _uploadArrayBufferViewToTexture(texture: InternalTexture, imageData: ArrayBufferView, faceIndex: number = 0, lod: number = 0): void {
  1138. }
  1139. /** @hidden */
  1140. public _uploadImageToTexture(texture: InternalTexture, image: HTMLImageElement, faceIndex: number = 0, lod: number = 0) {
  1141. }
  1142. //------------------------------------------------------------------------------
  1143. // Render Target Textures
  1144. //------------------------------------------------------------------------------
  1145. public createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture {
  1146. let fullOptions = new RenderTargetCreationOptions();
  1147. if (options !== undefined && typeof options === "object") {
  1148. fullOptions.generateMipMaps = options.generateMipMaps;
  1149. fullOptions.generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
  1150. fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && options.generateStencilBuffer;
  1151. fullOptions.type = options.type === undefined ? Constants.TEXTURETYPE_UNSIGNED_INT : options.type;
  1152. fullOptions.samplingMode = options.samplingMode === undefined ? Constants.TEXTURE_TRILINEAR_SAMPLINGMODE : options.samplingMode;
  1153. } else {
  1154. fullOptions.generateMipMaps = <boolean>options;
  1155. fullOptions.generateDepthBuffer = true;
  1156. fullOptions.generateStencilBuffer = false;
  1157. fullOptions.type = Constants.TEXTURETYPE_UNSIGNED_INT;
  1158. fullOptions.samplingMode = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE;
  1159. }
  1160. var texture = new InternalTexture(this, InternalTexture.DATASOURCE_RENDERTARGET);
  1161. var width = size.width || size;
  1162. var height = size.height || size;
  1163. texture._depthStencilBuffer = {};
  1164. texture._framebuffer = {};
  1165. texture.baseWidth = width;
  1166. texture.baseHeight = height;
  1167. texture.width = width;
  1168. texture.height = height;
  1169. texture.isReady = true;
  1170. texture.samples = 1;
  1171. texture.generateMipMaps = fullOptions.generateMipMaps ? true : false;
  1172. texture.samplingMode = fullOptions.samplingMode;
  1173. texture.type = fullOptions.type;
  1174. texture._generateDepthBuffer = fullOptions.generateDepthBuffer;
  1175. texture._generateStencilBuffer = fullOptions.generateStencilBuffer ? true : false;
  1176. this._internalTexturesCache.push(texture);
  1177. return texture;
  1178. }
  1179. //------------------------------------------------------------------------------
  1180. // Render Commands
  1181. //------------------------------------------------------------------------------
  1182. /**
  1183. * Begin a new frame
  1184. */
  1185. public beginFrame(): void {
  1186. super.beginFrame();
  1187. this._uploadEncoder = this._device.createCommandEncoder(this._uploadEncoderDescriptor);
  1188. this._renderEncoder = this._device.createCommandEncoder(this._renderEncoderDescriptor);
  1189. this._blitEncoder = this._device.createCommandEncoder(this._blitDescriptor);
  1190. }
  1191. private _freezeCommands: boolean = false;
  1192. private _frozenCommands: Nullable<GPUCommandBuffer[]> = null;
  1193. public _shouldOnlyUpdateCameras(): boolean {
  1194. return this._frozenCommands !== null;
  1195. }
  1196. /**
  1197. * End the current frame
  1198. */
  1199. public endFrame(): void {
  1200. this._endRenderPass();
  1201. if (this._freezeCommands && this._frozenCommands) {
  1202. this._commandBuffers[0] = this._frozenCommands[0];
  1203. this._commandBuffers[1] = this._frozenCommands[1];
  1204. }
  1205. else {
  1206. this._commandBuffers[0] = this._uploadEncoder.finish();
  1207. this._commandBuffers[1] = this._renderEncoder.finish();
  1208. }
  1209. if (this._freezeCommands && !this._frozenCommands) {
  1210. this._frozenCommands = [ ];
  1211. this._frozenCommands[0] = this._commandBuffers[0];
  1212. this._frozenCommands[1] = this._commandBuffers[1];
  1213. }
  1214. // TODO WEBGPU. GC.
  1215. this._blitEncoder.copyTextureToTexture(this._mainTextureCopyView, {
  1216. texture: this._swapChain.getCurrentTexture(),
  1217. origin: {
  1218. x: 0,
  1219. y: 0,
  1220. z: 0
  1221. },
  1222. mipLevel: 0,
  1223. arrayLayer: 0,
  1224. },
  1225. this._mainTextureExtends);
  1226. this._commandBuffers[2] = this._blitEncoder.finish();
  1227. this._device.getQueue().submit(this._commandBuffers);
  1228. super.endFrame();
  1229. }
  1230. /**
  1231. * Freezes the current list of commands to speed up rendering of sub sequent frames.
  1232. */
  1233. public freezeCommands(): void {
  1234. this._freezeCommands = true;
  1235. this._frozenCommands = null;
  1236. }
  1237. /**
  1238. * Freezes the current list of commands to speed up rendering of sub sequent frames.
  1239. */
  1240. public unFreezeCommands(): void {
  1241. this._freezeCommands = false;
  1242. this._frozenCommands = null;
  1243. }
  1244. //------------------------------------------------------------------------------
  1245. // Render Pass
  1246. //------------------------------------------------------------------------------
  1247. private _startMainRenderPass(): void {
  1248. if (this._currentRenderPass) {
  1249. this._endRenderPass();
  1250. }
  1251. // this._mainColorAttachments[0].attachment = this._swapChain.getCurrentTexture().createDefaultView();
  1252. this._currentRenderPass = this._renderEncoder.beginRenderPass({
  1253. colorAttachments: this._mainColorAttachments,
  1254. depthStencilAttachment: this._mainDepthAttachment
  1255. });
  1256. }
  1257. private _endRenderPass(): void {
  1258. if (this._currentRenderPass) {
  1259. this._currentRenderPass.endPass();
  1260. this._currentRenderPass = null;
  1261. }
  1262. }
  1263. public bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void {
  1264. if (this._currentRenderTarget) {
  1265. this.unBindFramebuffer(this._currentRenderTarget);
  1266. }
  1267. this._currentRenderTarget = texture;
  1268. this._currentFramebuffer = texture._MSAAFramebuffer ? texture._MSAAFramebuffer : texture._framebuffer;
  1269. if (this._cachedViewport && !forceFullscreenViewport) {
  1270. this.setViewport(this._cachedViewport, requiredWidth, requiredHeight);
  1271. }
  1272. }
  1273. public unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps = false, onBeforeUnbind?: () => void): void {
  1274. this._currentRenderTarget = null;
  1275. if (onBeforeUnbind) {
  1276. if (texture._MSAAFramebuffer) {
  1277. this._currentFramebuffer = texture._framebuffer;
  1278. }
  1279. onBeforeUnbind();
  1280. }
  1281. this._currentFramebuffer = null;
  1282. }
  1283. //------------------------------------------------------------------------------
  1284. // Render
  1285. //------------------------------------------------------------------------------
  1286. private _getTopology(fillMode: number): GPUPrimitiveTopology {
  1287. switch (fillMode) {
  1288. // Triangle views
  1289. case Constants.MATERIAL_TriangleFillMode:
  1290. return WebGPUConstants.GPUPrimitiveTopology_triangleList;
  1291. case Constants.MATERIAL_PointFillMode:
  1292. return WebGPUConstants.GPUPrimitiveTopology_pointList;
  1293. case Constants.MATERIAL_WireFrameFillMode:
  1294. return WebGPUConstants.GPUPrimitiveTopology_lineList;
  1295. // Draw modes
  1296. case Constants.MATERIAL_PointListDrawMode:
  1297. return WebGPUConstants.GPUPrimitiveTopology_pointList;
  1298. case Constants.MATERIAL_LineListDrawMode:
  1299. return WebGPUConstants.GPUPrimitiveTopology_lineList;
  1300. case Constants.MATERIAL_LineLoopDrawMode:
  1301. // return this._gl.LINE_LOOP;
  1302. // TODO WEBGPU. Line Loop Mode
  1303. throw "LineLoop is an unsupported fillmode in WebGPU";
  1304. case Constants.MATERIAL_LineStripDrawMode:
  1305. return WebGPUConstants.GPUPrimitiveTopology_lineStrip;
  1306. case Constants.MATERIAL_TriangleStripDrawMode:
  1307. return WebGPUConstants.GPUPrimitiveTopology_triangleStrip;
  1308. case Constants.MATERIAL_TriangleFanDrawMode:
  1309. // return this._gl.TRIANGLE_FAN;
  1310. // TODO WEBGPU. Triangle Fan Mode
  1311. throw "TriangleFan is an unsupported fillmode in WebGPU";
  1312. default:
  1313. return WebGPUConstants.GPUPrimitiveTopology_triangleList;
  1314. }
  1315. }
  1316. private _getCompareFunction(compareFunction: Nullable<number>): GPUCompareFunction {
  1317. switch (compareFunction) {
  1318. case Constants.ALWAYS:
  1319. return WebGPUConstants.GPUCompareFunction_always;
  1320. case Constants.EQUAL:
  1321. return WebGPUConstants.GPUCompareFunction_equal;
  1322. case Constants.GREATER:
  1323. return WebGPUConstants.GPUCompareFunction_greater;
  1324. case Constants.GEQUAL:
  1325. return WebGPUConstants.GPUCompareFunction_greaterEqual;
  1326. case Constants.LESS:
  1327. return WebGPUConstants.GPUCompareFunction_less;
  1328. case Constants.LEQUAL:
  1329. return WebGPUConstants.GPUCompareFunction_lessEqual;
  1330. case Constants.NEVER:
  1331. return WebGPUConstants.GPUCompareFunction_never;
  1332. case Constants.NOTEQUAL:
  1333. return WebGPUConstants.GPUCompareFunction_notEqual;
  1334. default:
  1335. return WebGPUConstants.GPUCompareFunction_less;
  1336. }
  1337. }
  1338. private _getOpFunction(operation: Nullable<number>, defaultOp: GPUStencilOperation): GPUStencilOperation {
  1339. switch (operation) {
  1340. case Constants.KEEP:
  1341. return WebGPUConstants.GPUStencilOperation_keep;
  1342. case Constants.ZERO:
  1343. return WebGPUConstants.GPUStencilOperation_zero;
  1344. case Constants.REPLACE:
  1345. return WebGPUConstants.GPUStencilOperation_replace;
  1346. case Constants.INVERT:
  1347. return WebGPUConstants.GPUStencilOperation_invert;
  1348. case Constants.INCR:
  1349. return WebGPUConstants.GPUStencilOperation_incrementClamp;
  1350. case Constants.DECR:
  1351. return WebGPUConstants.GPUStencilOperation_decrementClamp;
  1352. case Constants.INCR_WRAP:
  1353. return WebGPUConstants.GPUStencilOperation_incrementWrap;
  1354. case Constants.DECR_WRAP:
  1355. return WebGPUConstants.GPUStencilOperation_decrementWrap;
  1356. default:
  1357. return defaultOp;
  1358. }
  1359. }
  1360. private _getDepthStencilStateDescriptor(): GPUDepthStencilStateDescriptor {
  1361. // TODO WEBGPU. Depth State according to the cached state.
  1362. // And the current render pass attachment setup.
  1363. const stencilFrontBack: GPUStencilStateFaceDescriptor = {
  1364. compare: this._getCompareFunction(this._stencilState.stencilFunc),
  1365. depthFailOp: this._getOpFunction(this._stencilState.stencilOpDepthFail, WebGPUConstants.GPUStencilOperation_keep),
  1366. failOp: this._getOpFunction(this._stencilState.stencilOpStencilFail, WebGPUConstants.GPUStencilOperation_keep),
  1367. passOp: this._getOpFunction(this._stencilState.stencilOpStencilDepthPass, WebGPUConstants.GPUStencilOperation_replace)
  1368. };
  1369. return {
  1370. depthWriteEnabled: this.getDepthWrite(),
  1371. depthCompare: this._getCompareFunction(this.getDepthFunction()),
  1372. format: WebGPUConstants.GPUTextureFormat_depth32floatStencil8,
  1373. stencilFront: stencilFrontBack,
  1374. stencilBack: stencilFrontBack,
  1375. stencilReadMask: this._stencilState.stencilFuncMask,
  1376. stencilWriteMask: this._stencilState.stencilMask,
  1377. };
  1378. }
  1379. /**
  1380. * Set various states to the webGL context
  1381. * @param culling defines backface culling state
  1382. * @param zOffset defines the value to apply to zOffset (0 by default)
  1383. * @param force defines if states must be applied even if cache is up to date
  1384. * @param reverseSide defines if culling must be reversed (CCW instead of CW and CW instead of CCW)
  1385. */
  1386. public setState(culling: boolean, zOffset: number = 0, force?: boolean, reverseSide = false): void {
  1387. // Culling
  1388. if (this._depthCullingState.cull !== culling || force) {
  1389. this._depthCullingState.cull = culling;
  1390. }
  1391. // Cull face
  1392. // var cullFace = this.cullBackFaces ? this._gl.BACK : this._gl.FRONT;
  1393. var cullFace = this.cullBackFaces ? 1 : 2;
  1394. if (this._depthCullingState.cullFace !== cullFace || force) {
  1395. this._depthCullingState.cullFace = cullFace;
  1396. }
  1397. // Z offset
  1398. this.setZOffset(zOffset);
  1399. // Front face
  1400. // var frontFace = reverseSide ? this._gl.CW : this._gl.CCW;
  1401. var frontFace = reverseSide ? 1 : 2;
  1402. if (this._depthCullingState.frontFace !== frontFace || force) {
  1403. this._depthCullingState.frontFace = frontFace;
  1404. }
  1405. }
  1406. private _getFrontFace(): GPUFrontFace {
  1407. switch (this._depthCullingState.frontFace) {
  1408. case 1:
  1409. return WebGPUConstants.GPUFrontFace_cw;
  1410. default:
  1411. return WebGPUConstants.GPUFrontFace_ccw;
  1412. }
  1413. }
  1414. private _getCullMode(): GPUCullMode {
  1415. if (this._depthCullingState.cull === false) {
  1416. return WebGPUConstants.GPUCullMode_none;
  1417. }
  1418. if (this._depthCullingState.cullFace === 2) {
  1419. return WebGPUConstants.GPUCullMode_front;
  1420. }
  1421. else {
  1422. return WebGPUConstants.GPUCullMode_back;
  1423. }
  1424. }
  1425. private _getRasterizationStateDescriptor(): GPURasterizationStateDescriptor {
  1426. // TODO WEBGPU. Cull State according to the cached state.
  1427. // And the current render pass attachment setup.
  1428. return {
  1429. frontFace: this._getFrontFace(),
  1430. cullMode: this._getCullMode(),
  1431. depthBias: this._depthCullingState.zOffset,
  1432. // depthBiasClamp: 0,
  1433. // depthBiasSlopeScale: 0,
  1434. };
  1435. }
  1436. private _getWriteMask(): number {
  1437. if (this.__colorWrite) {
  1438. return WebGPUConstants.GPUColorWriteBits_ALL;
  1439. }
  1440. return WebGPUConstants.GPUColorWriteBits_NONE;
  1441. }
  1442. /**
  1443. * Sets the current alpha mode
  1444. * @param mode defines the mode to use (one of the Engine.ALPHA_XXX)
  1445. * @param noDepthWriteChange defines if depth writing state should remains unchanged (false by default)
  1446. * @see http://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered
  1447. */
  1448. public setAlphaMode(mode: number, noDepthWriteChange: boolean = false): void {
  1449. if (this._alphaMode === mode) {
  1450. return;
  1451. }
  1452. switch (mode) {
  1453. case Engine.ALPHA_DISABLE:
  1454. this._alphaState.alphaBlend = false;
  1455. break;
  1456. case Engine.ALPHA_PREMULTIPLIED:
  1457. // this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE);
  1458. this._alphaState.setAlphaBlendFunctionParameters(1, 0x0303, 1, 1);
  1459. this._alphaState.alphaBlend = true;
  1460. break;
  1461. case Engine.ALPHA_PREMULTIPLIED_PORTERDUFF:
  1462. // this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA);
  1463. this._alphaState.setAlphaBlendFunctionParameters(1, 0x0303, 1, 0x0303);
  1464. this._alphaState.alphaBlend = true;
  1465. break;
  1466. case Engine.ALPHA_COMBINE:
  1467. // this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE);
  1468. this._alphaState.setAlphaBlendFunctionParameters(0x0302, 0x0303, 1, 1);
  1469. this._alphaState.alphaBlend = true;
  1470. break;
  1471. case Engine.ALPHA_ONEONE:
  1472. // this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE, this._gl.ZERO, this._gl.ONE);
  1473. this._alphaState.setAlphaBlendFunctionParameters(1, 1, 0, 1);
  1474. this._alphaState.alphaBlend = true;
  1475. break;
  1476. case Engine.ALPHA_ADD:
  1477. // this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE, this._gl.ZERO, this._gl.ONE);
  1478. this._alphaState.setAlphaBlendFunctionParameters(0x0302, 1, 0, 1);
  1479. this._alphaState.alphaBlend = true;
  1480. break;
  1481. case Engine.ALPHA_SUBTRACT:
  1482. // this._alphaState.setAlphaBlendFunctionParameters(this._gl.ZERO, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE, this._gl.ONE);
  1483. this._alphaState.setAlphaBlendFunctionParameters(0, 0x0301, 1, 1);
  1484. this._alphaState.alphaBlend = true;
  1485. break;
  1486. case Engine.ALPHA_MULTIPLY:
  1487. // this._alphaState.setAlphaBlendFunctionParameters(this._gl.DST_COLOR, this._gl.ZERO, this._gl.ONE, this._gl.ONE);
  1488. this._alphaState.setAlphaBlendFunctionParameters(0x0306, 0, 1, 1);
  1489. this._alphaState.alphaBlend = true;
  1490. break;
  1491. case Engine.ALPHA_MAXIMIZED:
  1492. // this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE, this._gl.ONE);
  1493. this._alphaState.setAlphaBlendFunctionParameters(0x0302, 0x0301, 1, 1);
  1494. this._alphaState.alphaBlend = true;
  1495. break;
  1496. case Engine.ALPHA_INTERPOLATE:
  1497. // this._alphaState.setAlphaBlendFunctionParameters(this._gl.CONSTANT_COLOR, this._gl.ONE_MINUS_CONSTANT_COLOR, this._gl.CONSTANT_ALPHA, this._gl.ONE_MINUS_CONSTANT_ALPHA);
  1498. this._alphaState.setAlphaBlendFunctionParameters(0x8001, 0x8002, 0x8003, 0x8004);
  1499. this._alphaState.alphaBlend = true;
  1500. break;
  1501. case Engine.ALPHA_SCREENMODE:
  1502. // this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA);
  1503. this._alphaState.setAlphaBlendFunctionParameters(1, 0x0301, 1, 0x0303);
  1504. this._alphaState.alphaBlend = true;
  1505. break;
  1506. }
  1507. if (!noDepthWriteChange) {
  1508. this.setDepthWrite(mode === Engine.ALPHA_DISABLE);
  1509. }
  1510. this._alphaMode = mode;
  1511. }
  1512. private _getAphaBlendOperation(operation: Nullable<number>): GPUBlendOperation {
  1513. switch (operation) {
  1514. case 0x8006:
  1515. return WebGPUConstants.GPUBlendOperation_add;
  1516. case 0x800A:
  1517. return WebGPUConstants.GPUBlendOperation_substract;
  1518. case 0x800B:
  1519. return WebGPUConstants.GPUBlendOperation_reverseSubtract;
  1520. default:
  1521. return WebGPUConstants.GPUBlendOperation_add;
  1522. }
  1523. }
  1524. private _getAphaBlendFactor(factor: Nullable<number>): GPUBlendFactor {
  1525. switch (factor) {
  1526. case 0:
  1527. return WebGPUConstants.GPUBlendFactor_zero;
  1528. case 1:
  1529. return WebGPUConstants.GPUBlendFactor_one;
  1530. case 0x0300:
  1531. return WebGPUConstants.GPUBlendFactor_srcColor;
  1532. case 0x0301:
  1533. return WebGPUConstants.GPUBlendFactor_oneMinusSrcColor;
  1534. case 0x0302:
  1535. return WebGPUConstants.GPUBlendFactor_srcAlpha;
  1536. case 0x0303:
  1537. return WebGPUConstants.GPUBlendFactor_oneMinusSrcAlpha;
  1538. case 0x0304:
  1539. return WebGPUConstants.GPUBlendFactor_dstAlpha;
  1540. case 0x0305:
  1541. return WebGPUConstants.GPUBlendFactor_oneMinusDstAlpha;
  1542. case 0x0306:
  1543. return WebGPUConstants.GPUBlendFactor_dstColor;
  1544. case 0x0307:
  1545. return WebGPUConstants.GPUBlendFactor_oneMinusDstColor;
  1546. case 0x0308:
  1547. return WebGPUConstants.GPUBlendFactor_srcAlphaSaturated;
  1548. case 0x8001:
  1549. return WebGPUConstants.GPUBlendFactor_blendColor;
  1550. case 0x8002:
  1551. return WebGPUConstants.GPUBlendFactor_oneMinusBlendColor;
  1552. case 0x8003:
  1553. return WebGPUConstants.GPUBlendFactor_blendColor;
  1554. case 0x8004:
  1555. return WebGPUConstants.GPUBlendFactor_oneMinusBlendColor;
  1556. default:
  1557. return WebGPUConstants.GPUBlendFactor_one;
  1558. }
  1559. }
  1560. private _getAphaBlendState(): GPUBlendDescriptor {
  1561. if (!this._alphaState.alphaBlend) {
  1562. return { };
  1563. }
  1564. return {
  1565. srcFactor: this._getAphaBlendFactor(this._alphaState._blendFunctionParameters[2]),
  1566. dstFactor: this._getAphaBlendFactor(this._alphaState._blendFunctionParameters[3]),
  1567. operation: this._getAphaBlendOperation(this._alphaState._blendEquationParameters[1]),
  1568. };
  1569. }
  1570. private _getColorBlendState(): GPUBlendDescriptor {
  1571. if (!this._alphaState.alphaBlend) {
  1572. return { };
  1573. }
  1574. return {
  1575. srcFactor: this._getAphaBlendFactor(this._alphaState._blendFunctionParameters[0]),
  1576. dstFactor: this._getAphaBlendFactor(this._alphaState._blendFunctionParameters[1]),
  1577. operation: this._getAphaBlendOperation(this._alphaState._blendEquationParameters[0]),
  1578. };
  1579. }
  1580. private _getColorStateDescriptors(): GPUColorStateDescriptor[] {
  1581. // TODO WEBGPU. Manage Multi render target.
  1582. return [{
  1583. format: this._options.swapChainFormat,
  1584. alphaBlend: this._getAphaBlendState(),
  1585. colorBlend: this._getColorBlendState(),
  1586. writeMask: this._getWriteMask(),
  1587. }];
  1588. }
  1589. private _getStages(): GPURenderPipelineStageDescriptor {
  1590. const gpuPipeline = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
  1591. return gpuPipeline.stages!;
  1592. }
  1593. private _getVertexInputDescriptorFormat(kind: string, type: number, normalized: boolean): GPUVertexFormat {
  1594. switch (kind) {
  1595. case VertexBuffer.UVKind:
  1596. case VertexBuffer.UV2Kind:
  1597. case VertexBuffer.UV3Kind:
  1598. case VertexBuffer.UV4Kind:
  1599. case VertexBuffer.UV5Kind:
  1600. case VertexBuffer.UV6Kind:
  1601. switch (type) {
  1602. case VertexBuffer.BYTE:
  1603. return normalized ? WebGPUConstants.GPUVertexFormat_char2norm : WebGPUConstants.GPUVertexFormat_char2;
  1604. case VertexBuffer.UNSIGNED_BYTE:
  1605. return normalized ? WebGPUConstants.GPUVertexFormat_uchar2norm : WebGPUConstants.GPUVertexFormat_uchar2;
  1606. case VertexBuffer.SHORT:
  1607. return normalized ? WebGPUConstants.GPUVertexFormat_short2norm : WebGPUConstants.GPUVertexFormat_short2;
  1608. case VertexBuffer.UNSIGNED_SHORT:
  1609. return normalized ? WebGPUConstants.GPUVertexFormat_ushort2norm : WebGPUConstants.GPUVertexFormat_ushort2;
  1610. case VertexBuffer.INT:
  1611. return WebGPUConstants.GPUVertexFormat_int2;
  1612. case VertexBuffer.UNSIGNED_INT:
  1613. return WebGPUConstants.GPUVertexFormat_uint2;
  1614. case VertexBuffer.FLOAT:
  1615. return WebGPUConstants.GPUVertexFormat_float2;
  1616. }
  1617. case VertexBuffer.NormalKind:
  1618. case VertexBuffer.PositionKind:
  1619. switch (type) {
  1620. case VertexBuffer.BYTE:
  1621. return normalized ? WebGPUConstants.GPUVertexFormat_char3norm : WebGPUConstants.GPUVertexFormat_char3;
  1622. case VertexBuffer.UNSIGNED_BYTE:
  1623. return normalized ? WebGPUConstants.GPUVertexFormat_uchar3norm : WebGPUConstants.GPUVertexFormat_uchar3;
  1624. case VertexBuffer.SHORT:
  1625. return normalized ? WebGPUConstants.GPUVertexFormat_short3norm : WebGPUConstants.GPUVertexFormat_short3;
  1626. case VertexBuffer.UNSIGNED_SHORT:
  1627. return normalized ? WebGPUConstants.GPUVertexFormat_ushort3norm : WebGPUConstants.GPUVertexFormat_ushort3;
  1628. case VertexBuffer.INT:
  1629. return WebGPUConstants.GPUVertexFormat_int3;
  1630. case VertexBuffer.UNSIGNED_INT:
  1631. return WebGPUConstants.GPUVertexFormat_uint3;
  1632. case VertexBuffer.FLOAT:
  1633. return WebGPUConstants.GPUVertexFormat_float3;
  1634. }
  1635. case VertexBuffer.ColorKind:
  1636. case VertexBuffer.MatricesIndicesKind:
  1637. case VertexBuffer.MatricesIndicesExtraKind:
  1638. case VertexBuffer.MatricesWeightsKind:
  1639. case VertexBuffer.MatricesWeightsExtraKind:
  1640. case VertexBuffer.TangentKind:
  1641. case "world0":
  1642. case "world1":
  1643. case "world2":
  1644. case "world3":
  1645. switch (type) {
  1646. case VertexBuffer.BYTE:
  1647. return normalized ? WebGPUConstants.GPUVertexFormat_char4norm : WebGPUConstants.GPUVertexFormat_char4;
  1648. case VertexBuffer.UNSIGNED_BYTE:
  1649. return normalized ? WebGPUConstants.GPUVertexFormat_uchar4norm : WebGPUConstants.GPUVertexFormat_uchar4;
  1650. case VertexBuffer.SHORT:
  1651. return normalized ? WebGPUConstants.GPUVertexFormat_short4norm : WebGPUConstants.GPUVertexFormat_short3;
  1652. case VertexBuffer.UNSIGNED_SHORT:
  1653. return normalized ? WebGPUConstants.GPUVertexFormat_ushort4norm : WebGPUConstants.GPUVertexFormat_ushort4;
  1654. case VertexBuffer.INT:
  1655. return WebGPUConstants.GPUVertexFormat_int4;
  1656. case VertexBuffer.UNSIGNED_INT:
  1657. return WebGPUConstants.GPUVertexFormat_uint4;
  1658. case VertexBuffer.FLOAT:
  1659. return WebGPUConstants.GPUVertexFormat_float4;
  1660. }
  1661. }
  1662. // MorphTargets
  1663. if (kind.indexOf("position") === 0 ||
  1664. kind.indexOf("normal") === 0 ||
  1665. kind.indexOf("tangent") === 0) {
  1666. switch (type) {
  1667. case VertexBuffer.BYTE:
  1668. return normalized ? WebGPUConstants.GPUVertexFormat_char3norm : WebGPUConstants.GPUVertexFormat_char3;
  1669. case VertexBuffer.UNSIGNED_BYTE:
  1670. return normalized ? WebGPUConstants.GPUVertexFormat_uchar3norm : WebGPUConstants.GPUVertexFormat_uchar3;
  1671. case VertexBuffer.SHORT:
  1672. return normalized ? WebGPUConstants.GPUVertexFormat_short3norm : WebGPUConstants.GPUVertexFormat_short3;
  1673. case VertexBuffer.UNSIGNED_SHORT:
  1674. return normalized ? WebGPUConstants.GPUVertexFormat_ushort3norm : WebGPUConstants.GPUVertexFormat_ushort3;
  1675. case VertexBuffer.INT:
  1676. return WebGPUConstants.GPUVertexFormat_int3;
  1677. case VertexBuffer.UNSIGNED_INT:
  1678. return WebGPUConstants.GPUVertexFormat_uint3;
  1679. case VertexBuffer.FLOAT:
  1680. return WebGPUConstants.GPUVertexFormat_float3;
  1681. }
  1682. }
  1683. if (kind.indexOf("uv_") === 0) {
  1684. switch (type) {
  1685. case VertexBuffer.BYTE:
  1686. return normalized ? WebGPUConstants.GPUVertexFormat_char2norm : WebGPUConstants.GPUVertexFormat_char2;
  1687. case VertexBuffer.UNSIGNED_BYTE:
  1688. return normalized ? WebGPUConstants.GPUVertexFormat_uchar2norm : WebGPUConstants.GPUVertexFormat_uchar2;
  1689. case VertexBuffer.SHORT:
  1690. return normalized ? WebGPUConstants.GPUVertexFormat_short2norm : WebGPUConstants.GPUVertexFormat_short2;
  1691. case VertexBuffer.UNSIGNED_SHORT:
  1692. return normalized ? WebGPUConstants.GPUVertexFormat_ushort2norm : WebGPUConstants.GPUVertexFormat_ushort2;
  1693. case VertexBuffer.INT:
  1694. return WebGPUConstants.GPUVertexFormat_int2;
  1695. case VertexBuffer.UNSIGNED_INT:
  1696. return WebGPUConstants.GPUVertexFormat_uint2;
  1697. case VertexBuffer.FLOAT:
  1698. return WebGPUConstants.GPUVertexFormat_float2;
  1699. }
  1700. }
  1701. // TODO WEBGPU. Manages Custom Attributes.
  1702. throw new Error("Invalid kind '" + kind + "'");
  1703. }
  1704. private _getVertexInputDescriptor(): GPUInputStateDescriptor {
  1705. const descriptors: GPUVertexInputDescriptor[] = [];
  1706. const effect = this._currentEffect!;
  1707. const attributes = effect.getAttributesNames();
  1708. for (var index = 0; index < attributes.length; index++) {
  1709. const location = effect.getAttributeLocation(index);
  1710. if (location >= 0) {
  1711. const vertexBuffer = this._currentVertexBuffers![attributes[index]];
  1712. if (!vertexBuffer) {
  1713. continue;
  1714. }
  1715. const positionAttributeDescriptor: GPUVertexAttributeDescriptor = {
  1716. shaderLocation: location,
  1717. offset: 0, // not available in WebGL
  1718. format: this._getVertexInputDescriptorFormat(vertexBuffer.getKind(), vertexBuffer.type, vertexBuffer.normalized),
  1719. };
  1720. // TODO WEBGPU. Factorize the one with the same underlying buffer.
  1721. // manage interleaved and instances.
  1722. const vertexBufferDescriptor: GPUVertexInputDescriptor = {
  1723. stride: vertexBuffer.byteStride,
  1724. stepMode: vertexBuffer.getIsInstanced() ? WebGPUConstants.GPUInputStepMode_instance : WebGPUConstants.GPUInputStepMode_vertex,
  1725. attributes: [positionAttributeDescriptor]
  1726. };
  1727. descriptors.push(vertexBufferDescriptor);
  1728. }
  1729. }
  1730. if (!this._currentIndexBuffer) {
  1731. return {
  1732. indexFormat: WebGPUConstants.GPUIndexFormat_uint32,
  1733. vertexBuffers: descriptors
  1734. };
  1735. }
  1736. const inputStateDescriptor: GPUInputStateDescriptor = {
  1737. indexFormat: this._currentIndexBuffer!.is32Bits ? WebGPUConstants.GPUIndexFormat_uint32 : WebGPUConstants.GPUIndexFormat_uint16,
  1738. vertexBuffers: descriptors
  1739. };
  1740. return inputStateDescriptor;
  1741. }
  1742. private _getPipelineLayout(): GPUPipelineLayout {
  1743. const bindGroupLayouts: GPUBindGroupLayout[] = [];
  1744. const webgpuPipelineContext = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
  1745. for (let i = 0; i < webgpuPipelineContext.orderedUBOsAndSamplers.length; i++) {
  1746. const setDefinition = webgpuPipelineContext.orderedUBOsAndSamplers[i];
  1747. if (setDefinition === undefined) {
  1748. continue;
  1749. }
  1750. const bindings: GPUBindGroupLayoutBinding[] = [];
  1751. for (let j = 0; j < setDefinition.length; j++) {
  1752. const bindingDefinition = webgpuPipelineContext.orderedUBOsAndSamplers[i][j];
  1753. if (bindingDefinition === undefined) {
  1754. continue;
  1755. }
  1756. // TODO WEBGPU. Authorize shared samplers and Vertex Textures.
  1757. if (bindingDefinition.isSampler) {
  1758. bindings.push({
  1759. binding: j,
  1760. visibility: WebGPUConstants.GPUShaderStageBit_FRAGMENT,
  1761. type: WebGPUConstants.GPUBindingType_sampledTexture,
  1762. }, {
  1763. // TODO WEBGPU. No Magic + 1.
  1764. binding: j + 1,
  1765. visibility: WebGPUConstants.GPUShaderStageBit_FRAGMENT,
  1766. type: WebGPUConstants.GPUBindingType_sampler
  1767. });
  1768. }
  1769. else {
  1770. bindings.push({
  1771. binding: j,
  1772. visibility: WebGPUConstants.GPUShaderStageBit_VERTEX | WebGPUConstants.GPUShaderStageBit_FRAGMENT,
  1773. type: WebGPUConstants.GPUBindingType_uniformBuffer,
  1774. });
  1775. }
  1776. }
  1777. if (bindings.length > 0) {
  1778. const uniformsBindGroupLayout = this._device.createBindGroupLayout({
  1779. bindings,
  1780. });
  1781. bindGroupLayouts[i] = uniformsBindGroupLayout;
  1782. }
  1783. }
  1784. webgpuPipelineContext.bindGroupLayouts = bindGroupLayouts;
  1785. return this._device.createPipelineLayout({ bindGroupLayouts });
  1786. }
  1787. private _getRenderPipeline(fillMode: number): GPURenderPipeline {
  1788. // This is wrong to cache this way but workarounds the need of cache in the simple demo context.
  1789. const gpuPipeline = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
  1790. if (gpuPipeline.renderPipeline) {
  1791. return gpuPipeline.renderPipeline;
  1792. }
  1793. // Unsupported at the moment but needs to be extracted from the MSAA param.
  1794. const sampleCount = 1;
  1795. const topology = this._getTopology(fillMode);
  1796. const rasterizationStateDescriptor = this._getRasterizationStateDescriptor();
  1797. const depthStateDescriptor = this._getDepthStencilStateDescriptor();
  1798. const colorStateDescriptors = this._getColorStateDescriptors();
  1799. const stages = this._getStages();
  1800. const inputStateDescriptor = this._getVertexInputDescriptor();
  1801. const pipelineLayout = this._getPipelineLayout();
  1802. gpuPipeline.renderPipeline = this._device.createRenderPipeline({
  1803. sampleCount: sampleCount,
  1804. primitiveTopology: topology,
  1805. rasterizationState: rasterizationStateDescriptor,
  1806. depthStencilState: depthStateDescriptor,
  1807. colorStates: colorStateDescriptors,
  1808. ...stages,
  1809. vertexInput: inputStateDescriptor,
  1810. layout: pipelineLayout,
  1811. });
  1812. return gpuPipeline.renderPipeline;
  1813. }
  1814. private _getVertexInputsToRender(): IWebGPUPipelineContextVertexInputsCache {
  1815. const effect = this._currentEffect!;
  1816. const gpuContext = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
  1817. let vertexInputs = gpuContext.vertexInputs;
  1818. if (vertexInputs) {
  1819. return vertexInputs;
  1820. }
  1821. vertexInputs = {
  1822. indexBuffer: null,
  1823. indexOffset: 0,
  1824. vertexStartSlot: 0,
  1825. vertexBuffers: [],
  1826. vertexOffsets: [],
  1827. };
  1828. gpuContext.vertexInputs = vertexInputs;
  1829. if (this._currentIndexBuffer) {
  1830. // TODO WEBGPU. Check if cache would be worth it.
  1831. vertexInputs.indexBuffer = this._currentIndexBuffer.underlyingResource;
  1832. vertexInputs.indexOffset = 0;
  1833. }
  1834. else {
  1835. vertexInputs.indexBuffer = null;
  1836. }
  1837. const attributes = effect.getAttributesNames();
  1838. for (var index = 0; index < attributes.length; index++) {
  1839. const order = effect.getAttributeLocation(index);
  1840. if (order >= 0) {
  1841. const vertexBuffer = this._currentVertexBuffers![attributes[index]];
  1842. if (!vertexBuffer) {
  1843. continue;
  1844. }
  1845. var buffer = vertexBuffer.getBuffer();
  1846. if (buffer) {
  1847. vertexInputs.vertexBuffers.push(buffer.underlyingResource);
  1848. vertexInputs.vertexOffsets.push(vertexBuffer.byteOffset);
  1849. }
  1850. }
  1851. }
  1852. // TODO WEBGPU. Optimize buffer reusability and types as more are now allowed.
  1853. return vertexInputs;
  1854. }
  1855. private _getBindGroupsToRender(): GPUBindGroup[] {
  1856. const webgpuPipelineContext = this._currentEffect!._pipelineContext as WebGPUPipelineContext;
  1857. let bindGroups = webgpuPipelineContext.bindGroups;
  1858. if (bindGroups) {
  1859. if (webgpuPipelineContext.uniformBuffer) {
  1860. webgpuPipelineContext.uniformBuffer.update();
  1861. }
  1862. return bindGroups;
  1863. }
  1864. if (webgpuPipelineContext.uniformBuffer) {
  1865. this.bindUniformBufferBase(webgpuPipelineContext.uniformBuffer.getBuffer()!, 0, "LeftOver");
  1866. webgpuPipelineContext.uniformBuffer.update();
  1867. }
  1868. bindGroups = [];
  1869. webgpuPipelineContext.bindGroups = bindGroups;
  1870. const bindGroupLayouts = webgpuPipelineContext.bindGroupLayouts;
  1871. for (let i = 0; i < webgpuPipelineContext.orderedUBOsAndSamplers.length; i++) {
  1872. const setDefinition = webgpuPipelineContext.orderedUBOsAndSamplers[i];
  1873. if (setDefinition === undefined) {
  1874. continue;
  1875. }
  1876. const bindings: GPUBindGroupBinding[] = [];
  1877. for (let j = 0; j < setDefinition.length; j++) {
  1878. const bindingDefinition = webgpuPipelineContext.orderedUBOsAndSamplers[i][j];
  1879. if (bindingDefinition === undefined) {
  1880. continue;
  1881. }
  1882. // TODO WEBGPU. Authorize shared samplers and Vertex Textures.
  1883. if (bindingDefinition.isSampler) {
  1884. const bindingInfo = webgpuPipelineContext.samplers[bindingDefinition.name];
  1885. if (bindingInfo) {
  1886. if (!bindingInfo.texture._webGPUSampler) {
  1887. const samplerDescriptor: GPUSamplerDescriptor = this._getSamplerDescriptor(bindingInfo.texture!);
  1888. const gpuSampler = this._device.createSampler(samplerDescriptor);
  1889. bindingInfo.texture._webGPUSampler = gpuSampler;
  1890. }
  1891. bindings.push({
  1892. binding: bindingInfo.textureBinding,
  1893. resource: bindingInfo.texture._webGPUTextureView!,
  1894. }, {
  1895. binding: bindingInfo.samplerBinding,
  1896. resource: bindingInfo.texture._webGPUSampler!,
  1897. });
  1898. }
  1899. else {
  1900. Logger.Error("Sampler has not been bound: " + bindingDefinition.name);
  1901. }
  1902. }
  1903. else {
  1904. const dataBuffer = this._uniformsBuffers[bindingDefinition.name];
  1905. if (dataBuffer) {
  1906. const webgpuBuffer = dataBuffer.underlyingResource as GPUBuffer;
  1907. bindings.push({
  1908. binding: j,
  1909. resource: {
  1910. buffer: webgpuBuffer,
  1911. offset: 0,
  1912. size: dataBuffer.capacity,
  1913. },
  1914. });
  1915. }
  1916. else {
  1917. Logger.Error("UBO has not been bound: " + bindingDefinition.name);
  1918. }
  1919. }
  1920. }
  1921. bindGroups[i] = this._device.createBindGroup({
  1922. layout: bindGroupLayouts[i],
  1923. bindings,
  1924. });
  1925. }
  1926. return bindGroups;
  1927. }
  1928. private _bindVertexInputs(vertexInputs: IWebGPUPipelineContextVertexInputsCache): void {
  1929. const renderPass = this._currentRenderPass!;
  1930. if (vertexInputs.indexBuffer) {
  1931. // TODO WEBGPU. Check if cache would be worth it.
  1932. renderPass.setIndexBuffer(vertexInputs.indexBuffer, vertexInputs.indexOffset);
  1933. }
  1934. // TODO WEBGPU. Optimize buffer reusability and types as more are now allowed.
  1935. this._currentRenderPass!.setVertexBuffers(vertexInputs.vertexStartSlot, vertexInputs.vertexBuffers, vertexInputs.vertexOffsets);
  1936. }
  1937. private _setRenderBindGroups(bindGroups: GPUBindGroup[]): void {
  1938. // TODO WEBGPU. Only set groups if changes happened.
  1939. const renderPass = this._currentRenderPass!;
  1940. for (let i = 0; i < bindGroups.length; i++) {
  1941. renderPass.setBindGroup(i, bindGroups[i]);
  1942. }
  1943. }
  1944. private _setRenderPipeline(fillMode: number): void {
  1945. // TODO WEBGPU. Add dynamicity to the data.
  1946. const pipeline = this._getRenderPipeline(fillMode);
  1947. this._currentRenderPass!.setPipeline(pipeline);
  1948. const vertexInputs = this._getVertexInputsToRender();
  1949. this._bindVertexInputs(vertexInputs);
  1950. const bindGroups = this._getBindGroupsToRender();
  1951. this._setRenderBindGroups(bindGroups);
  1952. if (this._alphaState.alphaBlend && this._alphaState._isBlendConstantsDirty) {
  1953. this._currentRenderPass!.setBlendColor(this._alphaState._blendConstants as any);
  1954. }
  1955. }
  1956. public drawElementsType(fillMode: number, indexStart: number, indexCount: number, instancesCount: number = 1): void {
  1957. this._setRenderPipeline(fillMode);
  1958. this._currentRenderPass!.drawIndexed(indexCount, instancesCount, indexStart, 0, 0);
  1959. }
  1960. public drawArraysType(fillMode: number, verticesStart: number, verticesCount: number, instancesCount: number = 1): void {
  1961. this._currentIndexBuffer = null;
  1962. this._setRenderPipeline(fillMode);
  1963. this._currentRenderPass!.draw(verticesCount, instancesCount, verticesStart, 0);
  1964. }
  1965. //------------------------------------------------------------------------------
  1966. // Dispose
  1967. //------------------------------------------------------------------------------
  1968. /**
  1969. * Dispose and release all associated resources
  1970. */
  1971. public dispose(): void {
  1972. this._decodeEngine.dispose();
  1973. this._compiledShaders = { };
  1974. super.dispose();
  1975. }
  1976. //------------------------------------------------------------------------------
  1977. // Misc
  1978. //------------------------------------------------------------------------------
  1979. public getRenderWidth(useScreen = false): number {
  1980. if (!useScreen && this._currentRenderTarget) {
  1981. return this._currentRenderTarget.width;
  1982. }
  1983. return this._canvas.width;
  1984. }
  1985. public getRenderHeight(useScreen = false): number {
  1986. if (!useScreen && this._currentRenderTarget) {
  1987. return this._currentRenderTarget.height;
  1988. }
  1989. return this._canvas.height;
  1990. }
  1991. public getRenderingCanvas(): Nullable<HTMLCanvasElement> {
  1992. return this._canvas;
  1993. }
  1994. //------------------------------------------------------------------------------
  1995. // Errors
  1996. //------------------------------------------------------------------------------
  1997. public getError(): number {
  1998. // TODO WEBGPU. from the webgpu errors.
  1999. return 0;
  2000. }
  2001. //------------------------------------------------------------------------------
  2002. // Unused WebGPU
  2003. //------------------------------------------------------------------------------
  2004. public areAllEffectsReady(): boolean {
  2005. // TODO WEBGPU.
  2006. // No parallel shader compilation.
  2007. return true;
  2008. }
  2009. public _executeWhenRenderingStateIsCompiled(pipelineContext: IPipelineContext, action: () => void) {
  2010. // TODO WEBGPU.
  2011. // No parallel shader compilation.
  2012. // No Async, so direct launch
  2013. action();
  2014. }
  2015. public _isRenderingStateCompiled(pipelineContext: IPipelineContext): boolean {
  2016. // TODO WEBGPU.
  2017. // No parallel shader compilation.
  2018. return true;
  2019. }
  2020. public _getUnpackAlignement(): number {
  2021. return 1;
  2022. }
  2023. public _unpackFlipY(value: boolean) { }
  2024. // TODO WEBGPU. All of this should go once engine split with baseEngine.
  2025. public applyStates() {
  2026. // TODO WEBGPU. Apply States dynamically.
  2027. // This is done at the pipeline creation level for the moment...
  2028. }
  2029. /** @hidden */
  2030. public _getSamplingParameters(samplingMode: number, generateMipMaps: boolean): { min: number; mag: number } {
  2031. throw "_getSamplingParameters is not available in WebGPU";
  2032. }
  2033. public bindUniformBlock(pipelineContext: IPipelineContext, blockName: string, index: number): void {
  2034. }
  2035. public getUniforms(pipelineContext: IPipelineContext, uniformsNames: string[]): Nullable<WebGLUniformLocation>[] {
  2036. return [];
  2037. }
  2038. public setIntArray(uniform: WebGLUniformLocation, array: Int32Array): void {
  2039. }
  2040. public setIntArray2(uniform: WebGLUniformLocation, array: Int32Array): void {
  2041. }
  2042. public setIntArray3(uniform: WebGLUniformLocation, array: Int32Array): void {
  2043. }
  2044. public setIntArray4(uniform: WebGLUniformLocation, array: Int32Array): void {
  2045. }
  2046. public setFloatArray(uniform: WebGLUniformLocation, array: Float32Array): void {
  2047. }
  2048. public setFloatArray2(uniform: WebGLUniformLocation, array: Float32Array): void {
  2049. }
  2050. public setFloatArray3(uniform: WebGLUniformLocation, array: Float32Array): void {
  2051. }
  2052. public setFloatArray4(uniform: WebGLUniformLocation, array: Float32Array): void {
  2053. }
  2054. public setArray(uniform: WebGLUniformLocation, array: number[]): void {
  2055. }
  2056. public setArray2(uniform: WebGLUniformLocation, array: number[]): void {
  2057. }
  2058. public setArray3(uniform: WebGLUniformLocation, array: number[]): void {
  2059. }
  2060. public setArray4(uniform: WebGLUniformLocation, array: number[]): void {
  2061. }
  2062. public setMatrices(uniform: WebGLUniformLocation, matrices: Float32Array): void {
  2063. }
  2064. public setMatrix(uniform: WebGLUniformLocation, matrix: Matrix): void {
  2065. }
  2066. public setMatrix3x3(uniform: WebGLUniformLocation, matrix: Float32Array): void {
  2067. }
  2068. public setMatrix2x2(uniform: WebGLUniformLocation, matrix: Float32Array): void {
  2069. }
  2070. public setFloat(uniform: WebGLUniformLocation, value: number): void {
  2071. }
  2072. public setFloat2(uniform: WebGLUniformLocation, x: number, y: number): void {
  2073. }
  2074. public setFloat3(uniform: WebGLUniformLocation, x: number, y: number, z: number): void {
  2075. }
  2076. public setBool(uniform: WebGLUniformLocation, bool: number): void {
  2077. }
  2078. public setFloat4(uniform: WebGLUniformLocation, x: number, y: number, z: number, w: number): void {
  2079. }
  2080. public setColor3(uniform: WebGLUniformLocation, color3: Color3): void {
  2081. }
  2082. public setColor4(uniform: WebGLUniformLocation, color3: Color3, alpha: number): void {
  2083. }
  2084. }