Backend.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  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 } 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. 'render': null,
  60. '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. * Creates a GPU sampler for the given texture.
  237. *
  238. * @abstract
  239. * @param {Texture} texture - The texture to create the sampler for.
  240. */
  241. createSampler( /*texture*/ ) { }
  242. /**
  243. * Destroys the GPU sampler for the given texture.
  244. *
  245. * @abstract
  246. * @param {Texture} texture - The texture to destroy the sampler for.
  247. */
  248. destroySampler( /*texture*/ ) {}
  249. /**
  250. * Creates a default texture for the given texture that can be used
  251. * as a placeholder until the actual texture is ready for usage.
  252. *
  253. * @abstract
  254. * @param {Texture} texture - The texture to create a default texture for.
  255. */
  256. createDefaultTexture( /*texture*/ ) { }
  257. /**
  258. * Defines a texture on the GPU for the given texture object.
  259. *
  260. * @abstract
  261. * @param {Texture} texture - The texture.
  262. * @param {Object} [options={}] - Optional configuration parameter.
  263. */
  264. createTexture( /*texture, options={}*/ ) { }
  265. /**
  266. * Uploads the updated texture data to the GPU.
  267. *
  268. * @abstract
  269. * @param {Texture} texture - The texture.
  270. * @param {Object} [options={}] - Optional configuration parameter.
  271. */
  272. updateTexture( /*texture, options = {}*/ ) { }
  273. /**
  274. * Generates mipmaps for the given texture.
  275. *
  276. * @abstract
  277. * @param {Texture} texture - The texture.
  278. */
  279. generateMipmaps( /*texture*/ ) { }
  280. /**
  281. * Destroys the GPU data for the given texture object.
  282. *
  283. * @abstract
  284. * @param {Texture} texture - The texture.
  285. * @param {boolean} [isDefaultTexture=false] - Whether the texture uses a default GPU texture or not.
  286. */
  287. destroyTexture( /*texture, isDefaultTexture*/ ) { }
  288. /**
  289. * Returns texture data as a typed array.
  290. *
  291. * @abstract
  292. * @async
  293. * @param {Texture} texture - The texture to copy.
  294. * @param {number} x - The x coordinate of the copy origin.
  295. * @param {number} y - The y coordinate of the copy origin.
  296. * @param {number} width - The width of the copy.
  297. * @param {number} height - The height of the copy.
  298. * @param {number} faceIndex - The face index.
  299. * @return {Promise<TypedArray>} A Promise that resolves with a typed array when the copy operation has finished.
  300. */
  301. async copyTextureToBuffer( /*texture, x, y, width, height, faceIndex*/ ) {}
  302. /**
  303. * Copies data of the given source texture to the given destination texture.
  304. *
  305. * @abstract
  306. * @param {Texture} srcTexture - The source texture.
  307. * @param {Texture} dstTexture - The destination texture.
  308. * @param {?(Box3|Box2)} [srcRegion=null] - The region of the source texture to copy.
  309. * @param {?(Vector2|Vector3)} [dstPosition=null] - The destination position of the copy.
  310. * @param {number} [srcLevel=0] - The source mip level to copy from.
  311. * @param {number} [dstLevel=0] - The destination mip level to copy to.
  312. */
  313. copyTextureToTexture( /*srcTexture, dstTexture, srcRegion = null, dstPosition = null, srcLevel = 0, dstLevel = 0*/ ) {}
  314. /**
  315. * Copies the current bound framebuffer to the given texture.
  316. *
  317. * @abstract
  318. * @param {Texture} texture - The destination texture.
  319. * @param {RenderContext} renderContext - The render context.
  320. * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy.
  321. */
  322. copyFramebufferToTexture( /*texture, renderContext, rectangle*/ ) {}
  323. // attributes
  324. /**
  325. * Creates the GPU buffer of a shader attribute.
  326. *
  327. * @abstract
  328. * @param {BufferAttribute} attribute - The buffer attribute.
  329. */
  330. createAttribute( /*attribute*/ ) { }
  331. /**
  332. * Creates the GPU buffer of an indexed shader attribute.
  333. *
  334. * @abstract
  335. * @param {BufferAttribute} attribute - The indexed buffer attribute.
  336. */
  337. createIndexAttribute( /*attribute*/ ) { }
  338. /**
  339. * Creates the GPU buffer of a storage attribute.
  340. *
  341. * @abstract
  342. * @param {BufferAttribute} attribute - The buffer attribute.
  343. */
  344. createStorageAttribute( /*attribute*/ ) { }
  345. /**
  346. * Updates the GPU buffer of a shader attribute.
  347. *
  348. * @abstract
  349. * @param {BufferAttribute} attribute - The buffer attribute to update.
  350. */
  351. updateAttribute( /*attribute*/ ) { }
  352. /**
  353. * Destroys the GPU buffer of a shader attribute.
  354. *
  355. * @abstract
  356. * @param {BufferAttribute} attribute - The buffer attribute to destroy.
  357. */
  358. destroyAttribute( /*attribute*/ ) { }
  359. // canvas
  360. /**
  361. * Returns the backend's rendering context.
  362. *
  363. * @abstract
  364. * @return {Object} The rendering context.
  365. */
  366. getContext() { }
  367. /**
  368. * Backends can use this method if they have to run
  369. * logic when the renderer gets resized.
  370. *
  371. * @abstract
  372. */
  373. updateSize() { }
  374. /**
  375. * Updates the viewport with the values from the given render context.
  376. *
  377. * @abstract
  378. * @param {RenderContext} renderContext - The render context.
  379. */
  380. updateViewport( /*renderContext*/ ) {}
  381. // utils
  382. /**
  383. * Returns a unique identifier for the given render context that can be used
  384. * to allocate resources like occlusion queries or timestamp queries.
  385. *
  386. * @param {RenderContext|ComputeNode} abstractRenderContext - The render context.
  387. * @return {string} The unique identifier.
  388. */
  389. getTimestampUID( abstractRenderContext ) {
  390. const contextData = this.get( abstractRenderContext );
  391. let uid = abstractRenderContext.isComputeNode === true ? 'c' : 'r';
  392. uid += ':' + contextData.frameCalls + ':' + abstractRenderContext.id;
  393. return uid;
  394. }
  395. /**
  396. * Returns `true` if the given 3D object is fully occluded by other
  397. * 3D objects in the scene. Backends must implement this method by using
  398. * a Occlusion Query API.
  399. *
  400. * @abstract
  401. * @param {RenderContext} renderContext - The render context.
  402. * @param {Object3D} object - The 3D object to test.
  403. * @return {boolean} Whether the 3D object is fully occluded or not.
  404. */
  405. isOccluded( /*renderContext, object*/ ) {}
  406. /**
  407. * Resolves the time stamp for the given render context and type.
  408. *
  409. * @async
  410. * @abstract
  411. * @param {string} [type='render'] - The type of the time stamp.
  412. * @return {Promise<number>} A Promise that resolves with the time stamp.
  413. */
  414. async resolveTimestampsAsync( type = 'render' ) {
  415. if ( ! this.trackTimestamp ) {
  416. warnOnce( 'WebGPURenderer: Timestamp tracking is disabled.' );
  417. return;
  418. }
  419. const queryPool = this.timestampQueryPool[ type ];
  420. if ( ! queryPool ) {
  421. warnOnce( `WebGPURenderer: No timestamp query pool for type '${type}' found.` );
  422. return;
  423. }
  424. const duration = await queryPool.resolveQueriesAsync();
  425. this.renderer.info[ type ].timestamp = duration;
  426. return duration;
  427. }
  428. /**
  429. * Can be used to synchronize CPU operations with GPU tasks. So when this method is called,
  430. * the CPU waits for the GPU to complete its operation (e.g. a compute task).
  431. *
  432. * @async
  433. * @abstract
  434. * @return {Promise} A Promise that resolves when synchronization has been finished.
  435. */
  436. async waitForGPU() {}
  437. /**
  438. * This method performs a readback operation by moving buffer data from
  439. * a storage buffer attribute from the GPU to the CPU.
  440. *
  441. * @async
  442. * @param {StorageBufferAttribute} attribute - The storage buffer attribute.
  443. * @return {Promise<ArrayBuffer>} A promise that resolves with the buffer data when the data are ready.
  444. */
  445. async getArrayBufferAsync( /* attribute */ ) {}
  446. /**
  447. * Checks if the given feature is supported by the backend.
  448. *
  449. * @async
  450. * @abstract
  451. * @param {string} name - The feature's name.
  452. * @return {Promise<boolean>} A Promise that resolves with a bool that indicates whether the feature is supported or not.
  453. */
  454. async hasFeatureAsync( /*name*/ ) { }
  455. /**
  456. * Checks if the given feature is supported by the backend.
  457. *
  458. * @abstract
  459. * @param {string} name - The feature's name.
  460. * @return {boolean} Whether the feature is supported or not.
  461. */
  462. hasFeature( /*name*/ ) {}
  463. /**
  464. * Returns the maximum anisotropy texture filtering value.
  465. *
  466. * @abstract
  467. * @return {number} The maximum anisotropy texture filtering value.
  468. */
  469. getMaxAnisotropy() {}
  470. /**
  471. * Returns the drawing buffer size.
  472. *
  473. * @return {Vector2} The drawing buffer size.
  474. */
  475. getDrawingBufferSize() {
  476. _vector2 = _vector2 || new Vector2();
  477. return this.renderer.getDrawingBufferSize( _vector2 );
  478. }
  479. /**
  480. * Defines the scissor test.
  481. *
  482. * @abstract
  483. * @param {boolean} boolean - Whether the scissor test should be enabled or not.
  484. */
  485. setScissorTest( /*boolean*/ ) { }
  486. /**
  487. * Returns the clear color and alpha into a single
  488. * color object.
  489. *
  490. * @return {Color4} The clear color.
  491. */
  492. getClearColor() {
  493. const renderer = this.renderer;
  494. _color4 = _color4 || new Color4();
  495. renderer.getClearColor( _color4 );
  496. _color4.getRGB( _color4 );
  497. return _color4;
  498. }
  499. /**
  500. * Returns the DOM element. If no DOM element exists, the backend
  501. * creates a new one.
  502. *
  503. * @return {HTMLCanvasElement} The DOM element.
  504. */
  505. getDomElement() {
  506. let domElement = this.domElement;
  507. if ( domElement === null ) {
  508. domElement = ( this.parameters.canvas !== undefined ) ? this.parameters.canvas : createCanvasElement();
  509. // OffscreenCanvas does not have setAttribute, see #22811
  510. if ( 'setAttribute' in domElement ) domElement.setAttribute( 'data-engine', `three.js r${REVISION} webgpu` );
  511. this.domElement = domElement;
  512. }
  513. return domElement;
  514. }
  515. /**
  516. * Sets a dictionary for the given object into the
  517. * internal data structure.
  518. *
  519. * @param {Object} object - The object.
  520. * @param {Object} value - The dictionary to set.
  521. */
  522. set( object, value ) {
  523. this.data.set( object, value );
  524. }
  525. /**
  526. * Returns the dictionary for the given object.
  527. *
  528. * @param {Object} object - The object.
  529. * @return {Object} The object's dictionary.
  530. */
  531. get( object ) {
  532. let map = this.data.get( object );
  533. if ( map === undefined ) {
  534. map = {};
  535. this.data.set( object, map );
  536. }
  537. return map;
  538. }
  539. /**
  540. * Checks if the given object has a dictionary
  541. * with data defined.
  542. *
  543. * @param {Object} object - The object.
  544. * @return {boolean} Whether a dictionary for the given object as been defined or not.
  545. */
  546. has( object ) {
  547. return this.data.has( object );
  548. }
  549. /**
  550. * Deletes an object from the internal data structure.
  551. *
  552. * @param {Object} object - The object to delete.
  553. */
  554. delete( object ) {
  555. this.data.delete( object );
  556. }
  557. /**
  558. * Frees internal resources.
  559. *
  560. * @abstract
  561. */
  562. dispose() { }
  563. }
  564. export default Backend;
粤ICP备19079148号