@@ -17,6 +17,7 @@ import {
1717 getArrowRecordBatchAsyncIterator ,
1818 readArrowGPUVectorAsync ,
1919 resolveArrowPathSourceVectors ,
20+ type ArrowColorType ,
2021 type ArrowPathSourceVectors ,
2122 type ArrowPathSourceVectorSelectors ,
2223 type ArrowRecordBatchSource ,
@@ -35,7 +36,7 @@ import {
3536 GPUVector ,
3637 PathAttributeModel ,
3738 PathStorageModel ,
38- type VertexList
39+ type GPUVectorFormat
3940} from '@luma.gl/tables' ;
4041import {
4142 DataType ,
@@ -57,7 +58,10 @@ import {
5758 type ArrowLayerPickingInfo
5859} from './arrow-layer-types' ;
5960import {
61+ assertArrowLayerColorGPUVector ,
6062 assertArrowLayerGPUVector ,
63+ convertArrowLayerColorGPUVector ,
64+ convertArrowLayerColorVector ,
6165 getArrowLayerInputNullValue ,
6266 getArrowLayerInputSource ,
6367 hasArrowLayerColumn ,
@@ -69,11 +73,10 @@ import {
6973} from './arrow-layer-input' ;
7074
7175type ArrowPathColor = [ number , number , number , number ] ;
72- type ArrowPathRowColorType = FixedSizeList < Uint8 > ;
73- type ArrowPathVertexColorType = List < ArrowPathRowColorType > ;
76+ type ArrowPathRowColorType = ArrowColorType ;
77+ type ArrowPathVertexColorType = List < FixedSizeList < Uint8 > > ;
7478type ArrowPathColorSource = ArrowLayerColumnSource <
75- ArrowPathRowColorType | ArrowPathVertexColorType ,
76- 'unorm8x4' | VertexList < 'unorm8x4' >
79+ ArrowPathRowColorType | ArrowPathVertexColorType
7780> ;
7881type ArrowPathWidthSource = ArrowLayerColumnSource < Float32 , 'float32' > ;
7982
@@ -424,6 +427,7 @@ type ArrowPathLayerBatch = {
424427 rowIndexOffset : number ;
425428 rowCount : number ;
426429 temporalBuffer : Buffer | null ;
430+ convertedColorVector : GPUVector | null ;
427431} ;
428432
429433/** Deck-facing props for an Arrow-backed path layer. */
@@ -640,10 +644,7 @@ export class ArrowPathLayer extends Layer<ArrowPathLayerProps> {
640644 widthNullValue
641645 ) ;
642646 if ( isArrowLayerGPUVector ( colorSource ) ) {
643- assertArrowLayerGPUVector ( 'ArrowPathLayer color' , colorSource , [
644- 'unorm8x4' ,
645- 'vertex-list<unorm8x4>'
646- ] ) ;
647+ assertArrowLayerColorGPUVector ( 'ArrowPathLayer color' , colorSource ) ;
647648 }
648649 if ( isArrowLayerGPUVector ( widthSource ) ) {
649650 assertArrowLayerGPUVector ( 'ArrowPathLayer width' , widthSource , [ 'float32' ] ) ;
@@ -656,18 +657,28 @@ export class ArrowPathLayer extends Layer<ArrowPathLayerProps> {
656657 model === 'storage' && isArrowLayerGPUVector ( widthSource )
657658 ? undefined
658659 : await this . resolvePathStyleSource ( widthSource , rowIndexOffset , recordBatch ?. numRows ) ;
659- const sourceVectors = fillNullablePathStyleVectors (
660+ let sourceVectors = fillNullablePathStyleVectors (
660661 resolveArrowPathSourceVectors ( model === 'storage' ? PathStorageModel : PathAttributeModel , {
661662 data : recordBatch ,
662663 selectors : {
663664 paths : props . paths ,
664- colors : colorSelector ?? null ,
665+ colors : ( colorSelector ?? null ) as ArrowPathSourceVectorSelectors [ 'colors' ] ,
665666 widths : widthSelector ?? null
666667 }
667668 } ) ,
668669 colorNullValue ,
669670 widthNullValue
670671 ) ;
672+ if ( sourceVectors . colors && ! DataType . isList ( sourceVectors . colors . type ) ) {
673+ sourceVectors = {
674+ ...sourceVectors ,
675+ colors : ( await convertArrowLayerColorVector (
676+ this . context . device ,
677+ sourceVectors . colors ,
678+ `${ props . id } -batch-${ batchIndex } -arrow-colors`
679+ ) ) as NonNullable < ArrowPathSourceVectors [ 'colors' ] >
680+ } ;
681+ }
671682 const prepared = await ArrowPathRenderer . convertToGPUVectors (
672683 this . context . device ,
673684 sourceVectors ,
@@ -682,10 +693,32 @@ export class ArrowPathLayer extends Layer<ArrowPathLayerProps> {
682693 return ;
683694 }
684695
685- const preparedColorColumn =
686- model === 'storage' && isArrowLayerGPUVector ( colorSource )
687- ? getPathStorageGPUVectorBatch ( colorSource , batchIndex , sourceVectors . paths . length )
688- : prepared . colors ;
696+ let convertedColorVector : GPUVector | null = null ;
697+ let preparedColorColumn = prepared . colors ;
698+ if ( model === 'storage' && isArrowLayerGPUVector ( colorSource ) ) {
699+ try {
700+ const sourceColorBatch = getPathStorageGPUVectorBatch (
701+ colorSource ,
702+ batchIndex ,
703+ sourceVectors . paths . length
704+ ) ;
705+ const normalized = await convertArrowLayerColorGPUVector (
706+ this . context . device ,
707+ sourceColorBatch ,
708+ `${ props . id } -batch-${ batchIndex } -colors`
709+ ) ;
710+ preparedColorColumn = normalized . vector ;
711+ convertedColorVector = normalized . converted ? normalized . vector : null ;
712+ } catch ( error ) {
713+ prepared . destroy ( ) ;
714+ throw error ;
715+ }
716+ if ( ! this . isActiveLoad ( loadVersion ) ) {
717+ convertedColorVector ?. destroy ( ) ;
718+ prepared . destroy ( ) ;
719+ return ;
720+ }
721+ }
689722 const preparedWidthColumn =
690723 model === 'storage' && isArrowLayerGPUVector ( widthSource )
691724 ? getPathStorageGPUVectorBatch ( widthSource , batchIndex , sourceVectors . paths . length )
@@ -748,12 +781,14 @@ export class ArrowPathLayer extends Layer<ArrowPathLayerProps> {
748781 }
749782 } catch ( error ) {
750783 destroyBuffers ( constantStyle . buffers ) ;
784+ convertedColorVector ?. destroy ( ) ;
751785 prepared . destroy ( ) ;
752786 throw error ;
753787 }
754788 if ( ! this . isActiveLoad ( loadVersion ) ) {
755789 renderModel . destroy ( ) ;
756790 destroyBuffers ( constantStyle . buffers ) ;
791+ convertedColorVector ?. destroy ( ) ;
757792 prepared . destroy ( ) ;
758793 return ;
759794 }
@@ -766,7 +801,8 @@ export class ArrowPathLayer extends Layer<ArrowPathLayerProps> {
766801 batchIndex,
767802 rowIndexOffset,
768803 rowCount,
769- temporalBuffer : constantStyle . temporalBuffer
804+ temporalBuffer : constantStyle . temporalBuffer ,
805+ convertedColorVector
770806 } ;
771807 const batches = [ ...this . getLayerState ( ) . batches , batch ] ;
772808 this . setState ( { batches, loadVersion, sourceInitialized : true } ) ;
@@ -807,7 +843,20 @@ export class ArrowPathLayer extends Layer<ArrowPathLayerProps> {
807843 const cache = this . getLayerState ( ) . gpuVectorSourceCache ;
808844 let arrowVectorPromise = cache . get ( source ) ;
809845 if ( ! arrowVectorPromise ) {
810- arrowVectorPromise = readArrowGPUVectorAsync ( source ) ;
846+ arrowVectorPromise = ( async ( ) => {
847+ const normalized = await convertArrowLayerColorGPUVector (
848+ this . context . device ,
849+ source ,
850+ `${ this . id } -colors`
851+ ) ;
852+ try {
853+ return await readArrowGPUVectorAsync ( normalized . vector ) ;
854+ } finally {
855+ if ( normalized . converted ) {
856+ normalized . vector . destroy ( ) ;
857+ }
858+ }
859+ } ) ( ) ;
811860 cache . set ( source , arrowVectorPromise ) ;
812861 }
813862 const arrowVector = await arrowVectorPromise ;
@@ -905,9 +954,11 @@ function hasArrowDataNulls(data: Data): boolean {
905954 return data . nullCount > 0 || data . children . some ( hasArrowDataNulls ) ;
906955}
907956
908- function getPathStorageGPUVectorBatch <
909- Format extends 'unorm8x4' | VertexList < 'unorm8x4' > | 'float32'
910- > ( vector : GPUVector < Format > , batchIndex : number , expectedRowCount : number ) : GPUVector < Format > {
957+ function getPathStorageGPUVectorBatch < Format extends GPUVectorFormat > (
958+ vector : GPUVector < Format > ,
959+ batchIndex : number ,
960+ expectedRowCount : number
961+ ) : GPUVector < Format > {
911962 const useWholeVector =
912963 vector . data . length === 1 && batchIndex === 0 && vector . length === expectedRowCount ;
913964 const data = useWholeVector ? vector . data [ 0 ] : vector . data [ batchIndex ] ;
@@ -1085,6 +1136,7 @@ function destroyPathBatches(batches: ArrowPathLayerBatch[]): void {
10851136 for ( const batch of batches ) {
10861137 batch . model . destroy ( ) ;
10871138 destroyBuffers ( batch . constantBuffers ) ;
1139+ batch . convertedColorVector ?. destroy ( ) ;
10881140 batch . prepared . destroy ( ) ;
10891141 }
10901142}
0 commit comments