33// Copyright (c) vis.gl contributors
44
55import { Buffer , Texture } from '@luma.gl/core' ;
6- import type { Device } from '@luma.gl/core' ;
6+ import type { CanvasContext , Device } from '@luma.gl/core' ;
77import PickLayersPass , { PickingColorDecoder } from '../passes/pick-layers-pass' ;
88import log from '../utils/log' ;
99import { getClosestObject , getUniqueObjects , PickedPixel } from './picking/query-object' ;
@@ -44,6 +44,7 @@ type PickOperationContext = {
4444 layers : Layer [ ] ;
4545 views : Record < string , View > ;
4646 viewports : Viewport [ ] ;
47+ canvasContext ?: CanvasContext ;
4748 onViewportActive : ( viewport : Viewport ) => void ;
4849 effects : Effect [ ] ;
4950} ;
@@ -157,7 +158,7 @@ export default class DeckPicker {
157158 // Private
158159
159160 /** Ensures that picking framebuffer exists and matches the canvas size */
160- _resizeBuffer ( ) {
161+ _resizeBuffer ( canvasContext : CanvasContext = this . device . getDefaultCanvasContext ( ) ) {
161162 // Create a frame buffer if not already available
162163 if ( ! this . pickingFBO ) {
163164 const pickingColorTexture = this . device . createTexture ( {
@@ -186,10 +187,11 @@ export default class DeckPicker {
186187 }
187188 }
188189
189- // Resize it to current canvas size (this is a noop if size hasn't changed)
190- const { canvas} = this . device . getDefaultCanvasContext ( ) ;
191- this . pickingFBO ?. resize ( { width : canvas . width , height : canvas . height } ) ;
192- this . depthFBO ?. resize ( { width : canvas . width , height : canvas . height } ) ;
190+ // Picking renders in drawing-buffer pixels. DPR and useDevicePixels can make that size
191+ // differ from the canvas/CSS size used for viewport bookkeeping.
192+ const [ width , height ] = canvasContext . getDrawingBufferSize ( ) ;
193+ this . pickingFBO ?. resize ( { width, height} ) ;
194+ this . depthFBO ?. resize ( { width, height} ) ;
193195 }
194196
195197 /** Preliminary filtering of the layers list. Skid picking pass if no layer is pickable. */
@@ -217,14 +219,15 @@ export default class DeckPicker {
217219 depth = 1 ,
218220 mode = 'query' ,
219221 unproject3D,
222+ canvasContext = this . device . getDefaultCanvasContext ( ) ,
220223 onViewportActive,
221224 effects
222225 } : PickByPointOptions & PickOperationContext ) : Promise < {
223226 result : PickingInfo [ ] ;
224227 emptyInfo : PickingInfo ;
225228 } > {
226- // @ts -expect-error TODO - assuming WebGL context
227- const pixelRatio = this . device . canvasContext . cssToDeviceRatio ( ) ;
229+ // Picking starts in CSS pixels, so use the canvas context's current conversion ratio.
230+ const pixelRatio = canvasContext . cssToDeviceRatio ( ) ;
228231
229232 const pickableLayers = this . _getPickable ( layers ) ;
230233
@@ -235,13 +238,12 @@ export default class DeckPicker {
235238 } ;
236239 }
237240
238- this . _resizeBuffer ( ) ;
241+ this . _resizeBuffer ( canvasContext ) ;
239242
240243 // Convert from canvas top-left to WebGL bottom-left coordinates
241244 // Top-left coordinates [x, y] to bottom-left coordinates [deviceX, deviceY]
242- // And compensate for pixelRatio
243- // @ts -expect-error TODO - assuming WebGL context
244- const devicePixelRange = this . device . canvasContext . cssToDevicePixels ( [ x , y ] , true ) ;
245+ // And compensate for the context's current CSS-to-device ratio.
246+ const devicePixelRange = canvasContext . cssToDevicePixels ( [ x , y ] , true ) ;
245247 const devicePixel = [
246248 devicePixelRange . x + Math . floor ( devicePixelRange . width / 2 ) ,
247249 devicePixelRange . y + Math . floor ( devicePixelRange . height / 2 )
@@ -381,14 +383,15 @@ export default class DeckPicker {
381383 depth = 1 ,
382384 mode = 'query' ,
383385 unproject3D,
386+ canvasContext = this . device . getDefaultCanvasContext ( ) ,
384387 onViewportActive,
385388 effects
386389 } : PickByPointOptions & PickOperationContext ) : {
387390 result : PickingInfo [ ] ;
388391 emptyInfo : PickingInfo ;
389392 } {
390- // @ts -expect-error TODO - assuming WebGL context
391- const pixelRatio = this . device . canvasContext . cssToDeviceRatio ( ) ;
393+ // Keep the sync picking path aligned with the same canvas context state used for drawing.
394+ const pixelRatio = canvasContext . cssToDeviceRatio ( ) ;
392395
393396 const pickableLayers = this . _getPickable ( layers ) ;
394397
@@ -399,13 +402,12 @@ export default class DeckPicker {
399402 } ;
400403 }
401404
402- this . _resizeBuffer ( ) ;
405+ this . _resizeBuffer ( canvasContext ) ;
403406
404407 // Convert from canvas top-left to WebGL bottom-left coordinates
405408 // Top-left coordinates [x, y] to bottom-left coordinates [deviceX, deviceY]
406- // And compensate for pixelRatio
407- // @ts -expect-error TODO - assuming WebGL context
408- const devicePixelRange = this . device . canvasContext . cssToDevicePixels ( [ x , y ] , true ) ;
409+ // And compensate for the context's current CSS-to-device ratio.
410+ const devicePixelRange = canvasContext . cssToDevicePixels ( [ x , y ] , true ) ;
409411 const devicePixel = [
410412 devicePixelRange . x + Math . floor ( devicePixelRange . width / 2 ) ,
411413 devicePixelRange . y + Math . floor ( devicePixelRange . height / 2 )
@@ -544,6 +546,7 @@ export default class DeckPicker {
544546 height = 1 ,
545547 mode = 'query' ,
546548 maxObjects = null ,
549+ canvasContext = this . device . getDefaultCanvasContext ( ) ,
547550 onViewportActive,
548551 effects
549552 } : PickByRectOptions & PickOperationContext ) : Promise < PickingInfo [ ] > {
@@ -553,22 +556,19 @@ export default class DeckPicker {
553556 return [ ] ;
554557 }
555558
556- this . _resizeBuffer ( ) ;
559+ this . _resizeBuffer ( canvasContext ) ;
557560
558561 // Convert from canvas top-left to WebGL bottom-left coordinates
559- // And compensate for pixelRatio
560- // @ts -expect-error TODO - assuming WebGL context
561- const pixelRatio = this . device . canvasContext . cssToDeviceRatio ( ) ;
562- // @ts -expect-error TODO - assuming WebGL context
563- const leftTop = this . device . canvasContext . cssToDevicePixels ( [ x , y ] , true ) ;
562+ // And compensate for the context's current CSS-to-device ratio.
563+ const pixelRatio = canvasContext . cssToDeviceRatio ( ) ;
564+ const leftTop = canvasContext . cssToDevicePixels ( [ x , y ] , true ) ;
564565
565566 // take left and top (y inverted in device pixels) from start location
566567 const deviceLeft = leftTop . x ;
567568 const deviceTop = leftTop . y + leftTop . height ;
568569
569570 // take right and bottom (y inverted in device pixels) from end location
570- // @ts -expect-error TODO - assuming WebGL context
571- const rightBottom = this . device . canvasContext . cssToDevicePixels ( [ x + width , y + height ] , true ) ;
571+ const rightBottom = canvasContext . cssToDevicePixels ( [ x + width , y + height ] , true ) ;
572572 const deviceRight = rightBottom . x + rightBottom . width ;
573573 const deviceBottom = rightBottom . y ;
574574
@@ -651,6 +651,7 @@ export default class DeckPicker {
651651 height = 1 ,
652652 mode = 'query' ,
653653 maxObjects = null ,
654+ canvasContext = this . device . getDefaultCanvasContext ( ) ,
654655 onViewportActive,
655656 effects
656657 } : PickByRectOptions & PickOperationContext ) : PickingInfo [ ] {
@@ -660,22 +661,19 @@ export default class DeckPicker {
660661 return [ ] ;
661662 }
662663
663- this . _resizeBuffer ( ) ;
664+ this . _resizeBuffer ( canvasContext ) ;
664665
665666 // Convert from canvas top-left to WebGL bottom-left coordinates
666- // And compensate for pixelRatio
667- // @ts -expect-error TODO - assuming WebGL context
668- const pixelRatio = this . device . canvasContext . cssToDeviceRatio ( ) ;
669- // @ts -expect-error TODO - assuming WebGL context
670- const leftTop = this . device . canvasContext . cssToDevicePixels ( [ x , y ] , true ) ;
667+ // And compensate for the context's current CSS-to-device ratio.
668+ const pixelRatio = canvasContext . cssToDeviceRatio ( ) ;
669+ const leftTop = canvasContext . cssToDevicePixels ( [ x , y ] , true ) ;
671670
672671 // take left and top (y inverted in device pixels) from start location
673672 const deviceLeft = leftTop . x ;
674673 const deviceTop = leftTop . y + leftTop . height ;
675674
676675 // take right and bottom (y inverted in device pixels) from end location
677- // @ts -expect-error TODO - assuming WebGL context
678- const rightBottom = this . device . canvasContext . cssToDevicePixels ( [ x + width , y + height ] , true ) ;
676+ const rightBottom = canvasContext . cssToDevicePixels ( [ x + width , y + height ] , true ) ;
679677 const deviceRight = rightBottom . x + rightBottom . width ;
680678 const deviceBottom = rightBottom . y ;
681679
0 commit comments