Skip to content
This repository has been archived by the owner on Mar 8, 2023. It is now read-only.

HARP-12700: Disposal of POI resources by reference counting. #1946

Merged
merged 2 commits into from
Nov 6, 2020

Conversation

atomicsulfate
Copy link
Collaborator

@atomicsulfate atomicsulfate commented Nov 3, 2020

  • Share material and texture across pois with same image even if they have different render order.
  • Do reference counting on resources to dispose of them when they're not used any longer.

@atomicsulfate atomicsulfate force-pushed the HARP-12700_DynamicMarkers branch 2 times, most recently from bf51876 to 73c71e3 Compare November 4, 2020 12:12
@atomicsulfate atomicsulfate changed the title HARP-12700: Refactor PoiRenderBuffer HARP-12700: Disposal of POI resources by reference counting. Nov 4, 2020
- Share material and texture across pois with same image even if they have different render order.
- Do reference counting on resources to dispose of them when they're not used any longer.
Comment on lines +969 to +971
this.textElementGroups.forEach((element: TextElement) => {
element.dispose();
});
Copy link
Collaborator Author

@atomicsulfate atomicsulfate Nov 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to TextElement.dispose() on Tile disposal to ensure that it releases it's poi buffer (if any).

Comment on lines +538 to +543
dispose() {
const poiBuffer = this.poiInfo?.buffer;
if (poiBuffer) {
poiBuffer.decreaseRefCount();
}
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decrease ref counting on TextElement disposal to ensure the poi buffer and associated resources are released when ref count reaches 0.

Comment on lines 649 to +667
const imageWidth = imageItem.imageData.width;
const imageHeight = imageItem.imageData.height;
const paddedSize = MipMapGenerator.getPaddedSize(imageWidth, imageHeight);
const trilinearFiltering = PoiRenderBufferBatch.trilinear && imageItem.mipMaps;
const trilinearFiltering = PoiBatch.trilinear && imageItem.mipMaps;
const paddedImageWidth = trilinearFiltering ? paddedSize.width : imageWidth;
const paddedImageHeight = trilinearFiltering ? paddedSize.height : imageHeight;

const iconWidth = imageTexture.width !== undefined ? imageTexture.width : imageWidth;
const iconHeight = imageTexture.height !== undefined ? imageTexture.height : imageHeight;
const iconWidth = imageTexture?.width !== undefined ? imageTexture.width : imageWidth;
const iconHeight = imageTexture?.height !== undefined ? imageTexture.height : imageHeight;

let minS = 0;
let maxS = 1;
let minT = 0;
let maxT = 1;
const width = imageTexture?.width !== undefined ? imageTexture.width : imageWidth;
const height = imageTexture?.height !== undefined ? imageTexture.height : imageHeight;
const xOffset = imageTexture?.xOffset !== undefined ? imageTexture.xOffset : 0;
const yOffset = imageTexture?.yOffset !== undefined ? imageTexture.yOffset : 0;

const minS = xOffset / paddedImageWidth;
const maxS = (xOffset + width) / paddedImageWidth;
const minT = yOffset / paddedImageHeight;
const maxT = (yOffset + height) / paddedImageHeight;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no actual change, just removing unused code and simplifying.

Comment on lines +602 to +621
if (imageItem.loadingPromise) {
// already being loaded, will be rendered once available
return;
}

const result = imageCache.loadImage(imageItem);
assert(result instanceof Promise);
const loadPromise = result as Promise<ImageItem | undefined>;
loadPromise
.then(loadedImageItem => {
if (loadedImageItem === undefined) {
logger.error(`preparePoi: Failed to load imageItem: '${imageItem.url}`);
return;
}
this.setupPoiInfo(poiInfo, loadedImageItem, env, imageTexture);
})
.catch(error => {
logger.error(`preparePoi: Failed to load imageItem: '${imageItem.url}`, error);
poiInfo.isValid = false;
});
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just rearranging the code to reduce nesting level.

Comment on lines 578 to +591
} else {
// No image texture found. Either this is a user image or it's missing.
const image = this.mapView.userImageCache.findImageByName(imageTextureName);

if (!image) {
// Warn about a missing texture, but only once.
if (PoiRenderer.m_missingTextureName.get(imageTextureName) === undefined) {
PoiRenderer.m_missingTextureName.set(imageTextureName, true);
logger.error(
`preparePoi: No imageTexture with name '${imageTextureName}' found`
);
}
poiInfo.isValid = false;
return;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the user images don't need to be registered both in MapView's userImageCache and PoiManager. This only makes sense internally for theme atlases.

boxBuffer: BoxBuffer | undefined;

private m_material?: THREE.Material | THREE.Material[];
export class PoiBuffer {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the class where we do reference counting and propagate disposal of any resources when ref count reaches 0.

* There is a `PoiBatch` for every icon in a texture atlas, since the size of the icon in the atlas
* as well as the texture coordinates are specified in the `PoiBatch`.
*/
class PoiBatch {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the old PoiRenderBufferBatch, but I've moved in all PoiBuffers with same image but different render order, which now share same material and texture (before we didn't share them for different render orders of the same image).

Comment on lines +194 to +218
pickBoxes(
screenPosition: THREE.Vector2,
pickCallback: (pickData: any | undefined) => void,
imageData?: ImageBitmap | ImageData
) {
for (const poiBuffer of this.m_poiBuffers.values()) {
poiBuffer.buffer.pickBoxes(screenPosition, pickCallback, imageData);
}
}

/**
* Update the info with the memory footprint caused by objects owned by the `PoiBatch`.
*
* @param info - The info object to increment with the values from this `PoiBatch`.
*/
updateMemoryUsage(info: MemoryUsage) {
if (this.imageItem.imageData !== undefined) {
const imageBytes = this.imageItem.imageData.width * this.imageItem.imageData.height * 4;
info.heapSize += imageBytes;
info.gpuSize += imageBytes;
}
for (const poiBuffer of this.m_poiBuffers.values()) {
poiBuffer.buffer.updateMemoryUsage(info);
}
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing new here, just moved.

Comment on lines +221 to +224
this.m_poiBuffers.clear();
this.m_material.map.dispose();
this.m_material.dispose();
this.m_onDispose();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we dispose of material and texture, which we never diposed of before.


if (batch === undefined) {
batch = new PoiBatch(this.mapView, this.textCanvas, imageItem, () => {
this.deleteBatch(batchKey);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This callback deletes a batch when it's empty.

@@ -707,11 +707,13 @@ export interface MarkerTechniqueParams extends BaseTechniqueParams {
*/
poiNameField?: string;
/**
* Name of [[ImageTexture]] definition to use.
* Name of [[ImageTexture]] definition or image in {@link @here/harp-mapview#userImageCache}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the imageTextures from the theme go to some internal cache in MapViewThemeManager, not to MapView.userImageCache

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant, it's the name of either a theme's image or a user image in userImageCache. I'll rewrite the documentation to make it clearer.

@here/harp-mapview/lib/poi/PoiRenderer.ts Show resolved Hide resolved
@codecov
Copy link

codecov bot commented Nov 5, 2020

Codecov Report

Merging #1946 into master will increase coverage by 0.52%.
The diff coverage is 46.61%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1946      +/-   ##
==========================================
+ Coverage   65.25%   65.78%   +0.52%     
==========================================
  Files         293      293              
  Lines       26329    26327       -2     
  Branches     5951     5936      -15     
==========================================
+ Hits        17181    17319     +138     
+ Misses       9148     9008     -140     
Impacted Files Coverage Δ
...re/harp-datasource-protocol/lib/TechniqueParams.ts 72.13% <ø> (ø)
@here/harp-mapview/lib/MapView.ts 73.48% <ø> (ø)
@here/harp-mapview/lib/poi/BoxBuffer.ts 29.21% <41.05%> (+23.04%) ⬆️
@here/harp-mapview/lib/poi/PoiRenderer.ts 44.14% <48.32%> (+26.06%) ⬆️
@here/harp-mapview/lib/text/TextElement.ts 86.41% <80.00%> (-0.60%) ⬇️
@here/harp-mapview/lib/Tile.ts 83.23% <100.00%> (+0.09%) ⬆️
@here/harp-mapview/lib/text/FontCatalogLoader.ts 85.71% <0.00%> (-7.15%) ⬇️
@here/harp-mapview/lib/MapViewFog.ts 63.49% <0.00%> (-2.69%) ⬇️
@here/harp-mapview/lib/MapViewEnvironment.ts 35.55% <0.00%> (ø)
... and 8 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d230e1e...84ef311. Read the comment docs.

@atomicsulfate atomicsulfate merged commit e9e44a6 into master Nov 6, 2020
@atomicsulfate atomicsulfate deleted the HARP-12700_DynamicMarkers branch November 6, 2020 08:24
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants