1- import { BufferReader , BufferWriter , getSystemEndianness } from 'typed-binary' ;
21import { getCompiledWriter } from '../../data/compiledIO.ts' ;
3- import { readData , writeData } from '../../data/dataIO.ts' ;
42import type { AnyData } from '../../data/dataTypes.ts' ;
5- import {
6- type WriteInstruction ,
7- convertPartialToPatch ,
8- getPatchInstructions ,
9- } from '../../data/partialIO.ts' ;
3+ import { convertPartialToPatch , getPatchInstructions } from '../../data/partialIO.ts' ;
104import { sizeOf } from '../../data/sizeOf.ts' ;
115import type { BaseData } from '../../data/wgslTypes.ts' ;
12- import { isWgslArray , isWgslData } from '../../data/wgslTypes.ts' ;
6+ import { isWgslData } from '../../data/wgslTypes.ts' ;
137import type { StorageFlag } from '../../extension.ts' ;
148import type { TgpuNamable } from '../../shared/meta.ts' ;
159import { getName , setName } from '../../shared/meta.ts' ;
@@ -37,8 +31,8 @@ import {
3731 type TgpuFixedBufferUsage ,
3832 uniform ,
3933} from './bufferUsage.ts' ;
40- import { alignmentOf } from '../../data/alignmentOf .ts' ;
41- import { roundUp } from '../../mathUtils .ts' ;
34+ import { calculateOffsets , readFromArrayBuffer , writeToArrayBuffer } from '../../data/dataIO .ts' ;
35+ import { patchArrayBuffer } from '../../data/partialIO .ts' ;
4236
4337// ----------
4438// Public API
@@ -193,8 +187,6 @@ export function isUsableAsIndex<T extends TgpuBuffer<BaseData>>(
193187// --------------
194188// Implementation
195189// --------------
196- const endianness = getSystemEndianness ( ) ;
197-
198190class TgpuBufferImpl < TData extends BaseData > implements TgpuBuffer < TData > {
199191 readonly [ $internal ] = true ;
200192 readonly resourceType = 'buffer' ;
@@ -261,7 +253,7 @@ class TgpuBufferImpl<TData extends BaseData> implements TgpuBuffer<TData> {
261253 if ( this . #initialCallback) {
262254 this . #initialCallback( this ) ;
263255 } else if ( this . initial ) {
264- this . #writeToTarget ( this . #getMappedRange( ) , this . initial ) ;
256+ writeToArrayBuffer ( this . #getMappedRange( ) , this . dataType , this . initial ) ;
265257 }
266258 this . #unmapBuffer( ) ;
267259 }
@@ -354,77 +346,10 @@ class TgpuBufferImpl<TData extends BaseData> implements TgpuBuffer<TData> {
354346 getCompiledWriter ( this . dataType ) ;
355347 }
356348
357- #writeToTarget(
358- target : ArrayBuffer ,
359- data : InferInput < TData > | ArrayBuffer ,
360- options ?: BufferWriteOptions ,
361- ) : void {
362- const startOffset = options ?. startOffset ?? 0 ;
363- const endOffset = options ?. endOffset ?? target . byteLength ;
364-
365- // Fast path: raw byte copy, user guarantees the padded layout
366- if ( data instanceof ArrayBuffer || ArrayBuffer . isView ( data ) ) {
367- const src =
368- data instanceof ArrayBuffer
369- ? new Uint8Array ( data )
370- : new Uint8Array ( data . buffer , data . byteOffset , data . byteLength ) ;
371- const regionSize = endOffset - startOffset ;
372- if ( src . byteLength !== regionSize ) {
373- console . warn (
374- `Buffer size mismatch: expected ${ regionSize } bytes, got ${ src . byteLength } . ` +
375- ( src . byteLength < regionSize ? 'Data truncated.' : 'Excess ignored.' ) ,
376- ) ;
377- }
378- const copyLen = Math . min ( src . byteLength , regionSize ) ;
379- new Uint8Array ( target ) . set ( src . subarray ( 0 , copyLen ) , startOffset ) ;
380- return ;
381- }
382-
383- const dataView = new DataView ( target ) ;
384- const isLittleEndian = endianness === 'little' ;
385-
386- const compiledWriter = getCompiledWriter ( this . dataType ) ;
387-
388- if ( compiledWriter ) {
389- try {
390- compiledWriter ( dataView , startOffset , data , isLittleEndian , endOffset ) ;
391- return ;
392- } catch ( error ) {
393- console . error (
394- `Error when using compiled writer for buffer ${
395- getName ( this ) ?? '<unnamed>'
396- } - this is likely a bug, please submit an issue at https://github.com/software-mansion/TypeGPU/issues\nUsing fallback writer instead.`,
397- error ,
398- ) ;
399- }
400- }
401-
402- const writer = new BufferWriter ( target ) ;
403- writer . seekTo ( startOffset ) ;
404- writeData ( writer , this . dataType , data as Infer < TData > ) ;
405- }
406-
407349 write ( data : InferInput < TData > , options ?: BufferWriteOptions ) : void ;
408350 write ( data : ArrayBuffer , options ?: BufferWriteOptions ) : void ;
409351 write ( data : InferInput < TData > | ArrayBuffer , options ?: BufferWriteOptions ) : void {
410352 const gpuBuffer = this . buffer ;
411- const bufferSize = sizeOf ( this . dataType ) ;
412- const startOffset = options ?. startOffset ?? 0 ;
413-
414- let naturalSize : number | undefined = undefined ;
415- if ( isWgslArray ( this . dataType ) && Array . isArray ( data ) ) {
416- const arrayData = data as unknown [ ] ;
417- naturalSize =
418- arrayData . length *
419- roundUp ( sizeOf ( this . dataType . elementType ) , alignmentOf ( this . dataType . elementType ) ) ;
420- } else if ( ArrayBuffer . isView ( data ) || data instanceof ArrayBuffer ) {
421- naturalSize = data . byteLength ;
422- }
423- const naturalEndOffset =
424- naturalSize !== undefined ? Math . min ( startOffset + naturalSize , bufferSize ) : undefined ;
425-
426- const endOffset = options ?. endOffset ?? naturalEndOffset ?? bufferSize ;
427- const size = endOffset - startOffset ;
428353
429354 if ( gpuBuffer . mapState === 'mapped' ) {
430355 const mapped = this . #getMappedRange( ) ;
@@ -433,43 +358,34 @@ class TgpuBufferImpl<TData extends BaseData> implements TgpuBuffer<TData> {
433358 // via arrayBuffer. Nothing to do here
434359 return ;
435360 }
436- this . #writeToTarget ( mapped , data , options ) ;
361+ writeToArrayBuffer ( mapped , this . dataType , data , options ) ;
437362 return ;
438363 }
439364
440365 // If the caller already wrote directly into #hostBuffer via
441366 // arrayBuffer, skip the redundant copy, the data is already in place.
442367 if ( ! ( data instanceof ArrayBuffer && data === this . #hostBuffer) ) {
443- this . #writeToTarget ( this . #hostBuffer, data , options ) ;
368+ writeToArrayBuffer ( this . #hostBuffer, this . dataType , data , options ) ;
444369 }
370+
371+ const { startOffset, endOffset } = calculateOffsets ( options , this . dataType , data ) ;
372+ const size = endOffset - startOffset ;
373+
445374 this . #device. queue . writeBuffer ( gpuBuffer , startOffset , this . #hostBuffer, startOffset , size ) ;
446375 }
447376
448377 /** @deprecated Use {@link patch} instead. */
449378 public writePartial ( data : InferPartial < TData > ) : void {
450- this . #applyInstructions(
451- getPatchInstructions (
452- this . dataType ,
453- convertPartialToPatch ( this . dataType , data ) ,
454- this . #hostBuffer,
455- ) ,
456- ) ;
379+ this . patch ( convertPartialToPatch ( this . dataType , data ) as InferPatch < TData > ) ;
457380 }
458381
459382 public patch ( data : InferPatch < TData > ) : void {
460- this . #applyInstructions( getPatchInstructions ( this . dataType , data , this . #hostBuffer) ) ;
461- }
462-
463- #applyInstructions( instructions : WriteInstruction [ ] ) : void {
464383 const gpuBuffer = this . buffer ;
465384
466385 if ( gpuBuffer . mapState === 'mapped' ) {
467- const mappedRange = this . #getMappedRange( ) ;
468- const mappedView = new Uint8Array ( mappedRange ) ;
469- for ( const { data, gpuOffset } of instructions ) {
470- mappedView . set ( data , gpuOffset ) ;
471- }
386+ patchArrayBuffer ( this . #getMappedRange( ) , this . dataType , data ) ;
472387 } else {
388+ const instructions = getPatchInstructions ( this . dataType , data , this . #hostBuffer) ;
473389 for ( const { data, gpuOffset } of instructions ) {
474390 this . #device. queue . writeBuffer ( gpuBuffer , gpuOffset , data ) ;
475391 }
@@ -504,14 +420,12 @@ class TgpuBufferImpl<TData extends BaseData> implements TgpuBuffer<TData> {
504420 const gpuBuffer = this . buffer ;
505421
506422 if ( gpuBuffer . mapState === 'mapped' ) {
507- const mapped = this . #getMappedRange( ) ;
508- return readData ( new BufferReader ( mapped ) , this . dataType ) ;
423+ return readFromArrayBuffer ( this . #getMappedRange( ) , this . dataType ) ;
509424 }
510425
511426 if ( gpuBuffer . usage & GPUBufferUsage . MAP_READ ) {
512427 await gpuBuffer . mapAsync ( GPUMapMode . READ ) ;
513- const mapped = this . #getMappedRange( ) ;
514- const res = readData ( new BufferReader ( mapped ) , this . dataType ) ;
428+ const res = readFromArrayBuffer ( this . #getMappedRange( ) , this . dataType ) ;
515429 this . #unmapBuffer( ) ;
516430 return res ;
517431 }
@@ -527,7 +441,7 @@ class TgpuBufferImpl<TData extends BaseData> implements TgpuBuffer<TData> {
527441 this . #device. queue . submit ( [ commandEncoder . finish ( ) ] ) ;
528442 await stagingBuffer . mapAsync ( GPUMapMode . READ , 0 , sizeOf ( this . dataType ) ) ;
529443
530- const res = readData ( new BufferReader ( stagingBuffer . getMappedRange ( ) ) , this . dataType ) ;
444+ const res = readFromArrayBuffer ( stagingBuffer . getMappedRange ( ) , this . dataType ) ;
531445
532446 stagingBuffer . unmap ( ) ;
533447 stagingBuffer . destroy ( ) ;
0 commit comments