Backend.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. let _vector2 = null;
  2. let _color4 = null;
  3. import Color4 from './Color4.js';
  4. import { Vector2 } from '../../math/Vector2.js';
  5. import { createCanvasElement, warnOnce } from '../../utils.js';
  6. import { REVISION, TimestampQuery } from '../../constants.js';
  7. /**
  8. * Most of the rendering related logic is implemented in the
  9. * {@link Renderer} module and related management components.
  10. * Sometimes it is required though to execute commands which are
  11. * specific to the current 3D backend (which is WebGPU or WebGL 2).
  12. * This abstract base class defines an interface that encapsulates
  13. * all backend-related logic. Derived classes for each backend must
  14. * implement the interface.
  15. *
  16. * @abstract
  17. * @private
  18. */
  19. class Backend {
  20. /**
  21. * Constructs a new backend.
  22. *
  23. * @param {Object} parameters - An object holding parameters for the backend.
  24. */
  25. constructor( parameters = {} ) {
  26. /**
  27. * The parameters of the backend.
  28. *
  29. * @type {Object}
  30. */
  31. this.parameters = Object.assign( {}, parameters );
  32. /**
  33. * This weak map holds backend-specific data of objects
  34. * like textures, attributes or render targets.
  35. *
  36. * @type {WeakMap<Object, Object>}
  37. */
  38. this.data = new WeakMap();
  39. /**
  40. * A reference to the renderer.
  41. *
  42. * @type {?Renderer}
  43. * @default null
  44. */
  45. this.renderer = null;
  46. /**
  47. * A reference to the canvas element the renderer is drawing to.
  48. *
  49. * @type {?(HTMLCanvasElement|OffscreenCanvas)}
  50. * @default null
  51. */
  52. this.domElement = null;
  53. /**
  54. * A reference to the timestamp query pool.
  55. *
  56. * @type {{render: ?TimestampQueryPool, compute: ?TimestampQueryPool}}
  57. */
  58. this.timestampQueryPool = {
  59. [ TimestampQuery.RENDER ]: null,
  60. [ TimestampQuery.COMPUTE ]: null
  61. };
  62. /**
  63. * Whether to track timestamps with a Timestamp Query API or not.
  64. *
  65. * @type {boolean}
  66. * @default false
  67. */
  68. this.trackTimestamp = ( parameters.trackTimestamp === true );
  69. }
  70. /**
  71. * Initializes the backend so it is ready for usage. Concrete backends
  72. * are supposed to implement their rendering context creation and related
  73. * operations in this method.
  74. *
  75. * @async
  76. * @param {Renderer} renderer - The renderer.
  77. * @return {Promise} A Promise that resolves when the backend has been initialized.
  78. */
  79. async init( renderer ) {
  80. this.renderer = renderer;
  81. }
  82. /**
  83. * The coordinate system of the backend.
  84. *
  85. * @abstract
  86. * @type {number}
  87. * @readonly
  88. */
  89. get coordinateSystem() {}
  90. // render context
  91. /**
  92. * This method is executed at the beginning of a render call and
  93. * can be used by the backend to prepare the state for upcoming
  94. * draw calls.
  95. *
  96. * @abstract
  97. * @param {RenderContext} renderContext - The render context.
  98. */
  99. beginRender( /*renderContext*/ ) {}
  100. /**
  101. * This method is executed at the end of a render call and
  102. * can be used by the backend to finalize work after draw
  103. * calls.
  104. *
  105. * @abstract
  106. * @param {RenderContext} renderContext - The render context.
  107. */
  108. finishRender( /*renderContext*/ ) {}
  109. /**
  110. * This method is executed at the beginning of a compute call and
  111. * can be used by the backend to prepare the state for upcoming
  112. * compute tasks.
  113. *
  114. * @abstract
  115. * @param {Node|Array<Node>} computeGroup - The compute node(s).
  116. */
  117. beginCompute( /*computeGroup*/ ) {}
  118. /**
  119. * This method is executed at the end of a compute call and
  120. * can be used by the backend to finalize work after compute
  121. * tasks.
  122. *
  123. * @abstract
  124. * @param {Node|Array<Node>} computeGroup - The compute node(s).
  125. */
  126. finishCompute( /*computeGroup*/ ) {}
  127. // render object
  128. /**
  129. * Executes a draw command for the given render object.
  130. *
  131. * @abstract
  132. * @param {RenderObject} renderObject - The render object to draw.
  133. * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process.
  134. */
  135. draw( /*renderObject, info*/ ) { }
  136. // compute node
  137. /**
  138. * Executes a compute command for the given compute node.
  139. *
  140. * @abstract
  141. * @param {Node|Array<Node>} computeGroup - The group of compute nodes of a compute call. Can be a single compute node.
  142. * @param {Node} computeNode - The compute node.
  143. * @param {Array<BindGroup>} bindings - The bindings.
  144. * @param {ComputePipeline} computePipeline - The compute pipeline.
  145. */
  146. compute( /*computeGroup, computeNode, computeBindings, computePipeline*/ ) { }
  147. // program
  148. /**
  149. * Creates a shader program from the given programmable stage.
  150. *
  151. * @abstract
  152. * @param {ProgrammableStage} program - The programmable stage.
  153. */
  154. createProgram( /*program*/ ) { }
  155. /**
  156. * Destroys the shader program of the given programmable stage.
  157. *
  158. * @abstract
  159. * @param {ProgrammableStage} program - The programmable stage.
  160. */
  161. destroyProgram( /*program*/ ) { }
  162. // bindings
  163. /**
  164. * Creates bindings from the given bind group definition.
  165. *
  166. * @abstract
  167. * @param {BindGroup} bindGroup - The bind group.
  168. * @param {Array<BindGroup>} bindings - Array of bind groups.
  169. * @param {number} cacheIndex - The cache index.
  170. * @param {number} version - The version.
  171. */
  172. createBindings( /*bindGroup, bindings, cacheIndex, version*/ ) { }
  173. /**
  174. * Updates the given bind group definition.
  175. *
  176. * @abstract
  177. * @param {BindGroup} bindGroup - The bind group.
  178. * @param {Array<BindGroup>} bindings - Array of bind groups.
  179. * @param {number} cacheIndex - The cache index.
  180. * @param {number} version - The version.
  181. */
  182. updateBindings( /*bindGroup, bindings, cacheIndex, version*/ ) { }
  183. /**
  184. * Updates a buffer binding.
  185. *
  186. * @abstract
  187. * @param {Buffer} binding - The buffer binding to update.
  188. */
  189. updateBinding( /*binding*/ ) { }
  190. // pipeline
  191. /**
  192. * Creates a render pipeline for the given render object.
  193. *
  194. * @abstract
  195. * @param {RenderObject} renderObject - The render object.
  196. * @param {Array<Promise>} promises - An array of compilation promises which are used in `compileAsync()`.
  197. */
  198. createRenderPipeline( /*renderObject, promises*/ ) { }
  199. /**
  200. * Creates a compute pipeline for the given compute node.
  201. *
  202. * @abstract
  203. * @param {ComputePipeline} computePipeline - The compute pipeline.
  204. * @param {Array<BindGroup>} bindings - The bindings.
  205. */
  206. createComputePipeline( /*computePipeline, bindings*/ ) { }
  207. // cache key
  208. /**
  209. * Returns `true` if the render pipeline requires an update.
  210. *
  211. * @abstract
  212. * @param {RenderObject} renderObject - The render object.
  213. * @return {boolean} Whether the render pipeline requires an update or not.
  214. */
  215. needsRenderUpdate( /*renderObject*/ ) { }
  216. /**
  217. * Returns a cache key that is used to identify render pipelines.
  218. *
  219. * @abstract
  220. * @param {RenderObject} renderObject - The render object.
  221. * @return {string} The cache key.
  222. */
  223. getRenderCacheKey( /*renderObject*/ ) { }
  224. // node builder
  225. /**
  226. * Returns a node builder for the given render object.
  227. *
  228. * @abstract
  229. * @param {RenderObject} renderObject - The render object.
  230. * @param {Renderer} renderer - The renderer.
  231. * @return {NodeBuilder} The node builder.
  232. */
  233. createNodeBuilder( /*renderObject, renderer*/ ) { }
  234. // textures
  235. /**
  236. * Updates a GPU sampler for the given texture.
  237. *
  238. * @abstract
  239. * @param {Texture} texture - The texture to update the sampler for.
  240. * @return {string} The current sampler key.
  241. */
  242. updateSampler( /*texture*/ ) { }
  243. /**
  244. * Creates a default texture for the given texture that can be used
  245. * as a placeholder until the actual texture is ready for usage.
  246. *
  247. * @abstract
  248. * @param {Texture} texture - The texture to create a default texture for.
  249. */
  250. createDefaultTexture( /*texture*/ ) { }
  251. /**
  252. * Defines a texture on the GPU for the given texture object.
  253. *
  254. * @abstract
  255. * @param {Texture} texture - The texture.
  256. * @param {Object} [options={}] - Optional configuration parameter.
  257. */
  258. createTexture( /*texture, options={}*/ ) { }
  259. /**
  260. * Uploads the updated texture data to the GPU.
  261. *
  262. * @abstract
  263. * @param {Texture} texture - The texture.
  264. * @param {Object} [options={}] - Optional configuration parameter.
  265. */
  266. updateTexture( /*texture, options = {}*/ ) { }
  267. /**
  268. * Generates mipmaps for the given texture.
  269. *
  270. * @abstract
  271. * @param {Texture} texture - The texture.
  272. */
  273. generateMipmaps( /*texture*/ ) { }
  274. /**
  275. * Destroys the GPU data for the given texture object.
  276. *
  277. * @abstract
  278. * @param {Texture} texture - The texture.
  279. * @param {boolean} [isDefaultTexture=false] - Whether the texture uses a default GPU texture or not.
  280. */
  281. destroyTexture( /*texture, isDefaultTexture*/ ) { }
  282. /**
  283. * Returns texture data as a typed array.
  284. *
  285. * @abstract
  286. * @async
  287. * @param {Texture} texture - The texture to copy.
  288. * @param {number} x - The x coordinate of the copy origin.
  289. * @param {number} y - The y coordinate of the copy origin.
  290. * @param {number} width - The width of the copy.
  291. * @param {number} height - The height of the copy.
  292. * @param {number} faceIndex - The face index.
  293. * @return {Promise<TypedArray>} A Promise that resolves with a typed array when the copy operation has finished.
  294. */
  295. async copyTextureToBuffer( /*texture, x, y, width, height, faceIndex*/ ) {}
  296. /**
  297. * Copies data of the given source texture to the given destination texture.
  298. *
  299. * @abstract
  300. * @param {Texture} srcTexture - The source texture.
  301. * @param {Texture} dstTexture - The destination texture.
  302. * @param {?(Box3|Box2)} [srcRegion=null] - The region of the source texture to copy.
  303. * @param {?(Vector2|Vector3)} [dstPosition=null] - The destination position of the copy.
  304. * @param {number} [srcLevel=0] - The source mip level to copy from.
  305. * @param {number} [dstLevel=0] - The destination mip level to copy to.
  306. */
  307. copyTextureToTexture( /*srcTexture, dstTexture, srcRegion = null, dstPosition = null, srcLevel = 0, dstLevel = 0*/ ) {}
  308. /**
  309. * Copies the current bound framebuffer to the given texture.
  310. *
  311. * @abstract
  312. * @param {Texture} texture - The destination texture.
  313. * @param {RenderContext} renderContext - The render context.
  314. * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy.
  315. */
  316. copyFramebufferToTexture( /*texture, renderContext, rectangle*/ ) {}
  317. // attributes
  318. /**
  319. * Creates the GPU buffer of a shader attribute.
  320. *
  321. * @abstract
  322. * @param {BufferAttribute} attribute - The buffer attribute.
  323. */
  324. createAttribute( /*attribute*/ ) { }
  325. /**
  326. * Creates the GPU buffer of an indexed shader attribute.
  327. *
  328. * @abstract
  329. * @param {BufferAttribute} attribute - The indexed buffer attribute.
  330. */
  331. createIndexAttribute( /*attribute*/ ) { }
  332. /**
  333. * Creates the GPU buffer of a storage attribute.
  334. *
  335. * @abstract
  336. * @param {BufferAttribute} attribute - The buffer attribute.
  337. */
  338. createStorageAttribute( /*attribute*/ ) { }
  339. /**
  340. * Updates the GPU buffer of a shader attribute.
  341. *
  342. * @abstract
  343. * @param {BufferAttribute} attribute - The buffer attribute to update.
  344. */
  345. updateAttribute( /*attribute*/ ) { }
  346. /**
  347. * Destroys the GPU buffer of a shader attribute.
  348. *
  349. * @abstract
  350. * @param {BufferAttribute} attribute - The buffer attribute to destroy.
  351. */
  352. destroyAttribute( /*attribute*/ ) { }
  353. // canvas
  354. /**
  355. * Returns the backend's rendering context.
  356. *
  357. * @abstract
  358. * @return {Object} The rendering context.
  359. */
  360. getContext() { }
  361. /**
  362. * Backends can use this method if they have to run
  363. * logic when the renderer gets resized.
  364. *
  365. * @abstract
  366. */
  367. updateSize() { }
  368. /**
  369. * Updates the viewport with the values from the given render context.
  370. *
  371. * @abstract
  372. * @param {RenderContext} renderContext - The render context.
  373. */
  374. updateViewport( /*renderContext*/ ) {}
  375. // utils
  376. /**
  377. * Updates a unique identifier for the given render context that can be used
  378. * to allocate resources like occlusion queries or timestamp queries.
  379. *
  380. * @param {RenderContext|ComputeNode} abstractRenderContext - The render context.
  381. */
  382. updateTimeStampUID( abstractRenderContext ) {
  383. const contextData = this.get( abstractRenderContext );
  384. const frame = this.renderer.info.frame;
  385. let prefix;
  386. if ( abstractRenderContext.isComputeNode === true ) {
  387. prefix = 'c:' + this.renderer.info.compute.frameCalls;
  388. } else {
  389. prefix = 'r:' + this.renderer.info.render.frameCalls;
  390. }
  391. contextData.timestampUID = prefix + ':' + abstractRenderContext.id + ':f' + frame;
  392. }
  393. /**
  394. * Returns a unique identifier for the given render context that can be used
  395. * to allocate resources like occlusion queries or timestamp queries.
  396. *
  397. * @param {RenderContext|ComputeNode} abstractRenderContext - The render context.
  398. * @return {string} The unique identifier.
  399. */
  400. getTimestampUID( abstractRenderContext ) {
  401. return this.get( abstractRenderContext ).timestampUID;
  402. }
  403. /**
  404. * Returns all timestamp frames for the given type.
  405. *
  406. * @param {string} type - The type of the time stamp.
  407. * @return {Array<number>} The timestamp frames.
  408. */
  409. getTimestampFrames( type ) {
  410. const queryPool = this.timestampQueryPool[ type ];
  411. return queryPool ? queryPool.getTimestampFrames() : [];
  412. }
  413. /**
  414. * Returns the query pool for the given uid.
  415. *
  416. * @param {string} uid - The unique identifier.
  417. * @return {TimestampQueryPool} The query pool.
  418. */
  419. _getQueryPool( uid ) {
  420. const type = uid.startsWith( 'c:' ) ? TimestampQuery.COMPUTE : TimestampQuery.RENDER;
  421. const queryPool = this.timestampQueryPool[ type ];
  422. return queryPool;
  423. }
  424. /**
  425. * Returns the timestamp for the given uid.
  426. *
  427. * @param {string} uid - The unique identifier.
  428. * @return {number} The timestamp.
  429. */
  430. getTimestamp( uid ) {
  431. const queryPool = this._getQueryPool( uid );
  432. return queryPool.getTimestamp( uid );
  433. }
  434. /**
  435. * Returns `true` if a timestamp for the given uid is available.
  436. *
  437. * @param {string} uid - The unique identifier.
  438. * @return {boolean} Whether the timestamp is available or not.
  439. */
  440. hasTimestamp( uid ) {
  441. const queryPool = this._getQueryPool( uid );
  442. return queryPool.hasTimestamp( uid );
  443. }
  444. /**
  445. * Returns `true` if the given 3D object is fully occluded by other
  446. * 3D objects in the scene. Backends must implement this method by using
  447. * a Occlusion Query API.
  448. *
  449. * @abstract
  450. * @param {RenderContext} renderContext - The render context.
  451. * @param {Object3D} object - The 3D object to test.
  452. * @return {boolean} Whether the 3D object is fully occluded or not.
  453. */
  454. isOccluded( /*renderContext, object*/ ) {}
  455. /**
  456. * Resolves the time stamp for the given render context and type.
  457. *
  458. * @async
  459. * @abstract
  460. * @param {string} [type='render'] - The type of the time stamp.
  461. * @return {Promise<number>} A Promise that resolves with the time stamp.
  462. */
  463. async resolveTimestampsAsync( type = 'render' ) {
  464. if ( ! this.trackTimestamp ) {
  465. warnOnce( 'WebGPURenderer: Timestamp tracking is disabled.' );
  466. return;
  467. }
  468. const queryPool = this.timestampQueryPool[ type ];
  469. if ( ! queryPool ) {
  470. return;
  471. }
  472. const duration = await queryPool.resolveQueriesAsync();
  473. this.renderer.info[ type ].timestamp = duration;
  474. return duration;
  475. }
  476. /**
  477. * This method performs a readback operation by moving buffer data from
  478. * a storage buffer attribute from the GPU to the CPU.
  479. *
  480. * @async
  481. * @param {StorageBufferAttribute} attribute - The storage buffer attribute.
  482. * @return {Promise<ArrayBuffer>} A promise that resolves with the buffer data when the data are ready.
  483. */
  484. async getArrayBufferAsync( /* attribute */ ) {}
  485. /**
  486. * Checks if the given feature is supported by the backend.
  487. *
  488. * @async
  489. * @abstract
  490. * @param {string} name - The feature's name.
  491. * @return {Promise<boolean>} A Promise that resolves with a bool that indicates whether the feature is supported or not.
  492. */
  493. async hasFeatureAsync( /*name*/ ) { }
  494. /**
  495. * Checks if the given feature is supported by the backend.
  496. *
  497. * @abstract
  498. * @param {string} name - The feature's name.
  499. * @return {boolean} Whether the feature is supported or not.
  500. */
  501. hasFeature( /*name*/ ) {}
  502. /**
  503. * Returns the maximum anisotropy texture filtering value.
  504. *
  505. * @abstract
  506. * @return {number} The maximum anisotropy texture filtering value.
  507. */
  508. getMaxAnisotropy() {}
  509. /**
  510. * Returns the drawing buffer size.
  511. *
  512. * @return {Vector2} The drawing buffer size.
  513. */
  514. getDrawingBufferSize() {
  515. _vector2 = _vector2 || new Vector2();
  516. return this.renderer.getDrawingBufferSize( _vector2 );
  517. }
  518. /**
  519. * Defines the scissor test.
  520. *
  521. * @abstract
  522. * @param {boolean} boolean - Whether the scissor test should be enabled or not.
  523. */
  524. setScissorTest( /*boolean*/ ) { }
  525. /**
  526. * Returns the clear color and alpha into a single
  527. * color object.
  528. *
  529. * @return {Color4} The clear color.
  530. */
  531. getClearColor() {
  532. const renderer = this.renderer;
  533. _color4 = _color4 || new Color4();
  534. renderer.getClearColor( _color4 );
  535. _color4.getRGB( _color4 );
  536. return _color4;
  537. }
  538. /**
  539. * Returns the DOM element. If no DOM element exists, the backend
  540. * creates a new one.
  541. *
  542. * @return {HTMLCanvasElement} The DOM element.
  543. */
  544. getDomElement() {
  545. let domElement = this.domElement;
  546. if ( domElement === null ) {
  547. domElement = ( this.parameters.canvas !== undefined ) ? this.parameters.canvas : createCanvasElement();
  548. // OffscreenCanvas does not have setAttribute, see #22811
  549. if ( 'setAttribute' in domElement ) domElement.setAttribute( 'data-engine', `three.js r${REVISION} webgpu` );
  550. this.domElement = domElement;
  551. }
  552. return domElement;
  553. }
  554. /**
  555. * Checks if the backend has the given compatibility.
  556. *
  557. * @abstract
  558. * @param {string} name - The compatibility.
  559. * @return {boolean} Whether the backend has the given compatibility or not.
  560. */
  561. hasCompatibility( /*name*/ ) {
  562. return false;
  563. }
  564. /**
  565. * Initializes the render target defined in the given render context.
  566. *
  567. * @abstract
  568. * @param {RenderContext} renderContext - The render context.
  569. */
  570. initRenderTarget( /*renderContext*/ ) {}
  571. /**
  572. * Sets a dictionary for the given object into the
  573. * internal data structure.
  574. *
  575. * @param {Object} object - The object.
  576. * @param {Object} value - The dictionary to set.
  577. */
  578. set( object, value ) {
  579. this.data.set( object, value );
  580. }
  581. /**
  582. * Returns the dictionary for the given object.
  583. *
  584. * @param {Object} object - The object.
  585. * @return {Object} The object's dictionary.
  586. */
  587. get( object ) {
  588. let map = this.data.get( object );
  589. if ( map === undefined ) {
  590. map = {};
  591. this.data.set( object, map );
  592. }
  593. return map;
  594. }
  595. /**
  596. * Checks if the given object has a dictionary
  597. * with data defined.
  598. *
  599. * @param {Object} object - The object.
  600. * @return {boolean} Whether a dictionary for the given object as been defined or not.
  601. */
  602. has( object ) {
  603. return this.data.has( object );
  604. }
  605. /**
  606. * Deletes an object from the internal data structure.
  607. *
  608. * @param {Object} object - The object to delete.
  609. */
  610. delete( object ) {
  611. this.data.delete( object );
  612. }
  613. /**
  614. * Delete GPU data associated with a bind group.
  615. *
  616. * @abstract
  617. * @param {BindGroup} bindGroup - The bind group.
  618. */
  619. deleteBindGroupData( /*bindGroup*/ ) { }
  620. /**
  621. * Frees internal resources.
  622. *
  623. * @abstract
  624. */
  625. dispose() { }
  626. }
  627. export default Backend;
粤ICP备19079148号