Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
695d60d
change requestRender condition in DataSourceDIsplay.update
Beilinson May 21, 2025
356f3d4
Fix logic
Beilinson May 22, 2025
b1b67e1
Update CONTRIBUTORS and CHANGES
Beilinson May 22, 2025
3c9b061
Fix billboard requestRender issue
Beilinson Jun 11, 2025
99c4b49
Naming fixes
Beilinson Sep 15, 2025
17db07c
rerenderOnUpdateComplete Implementation
Beilinson Sep 16, 2025
80063dc
Update CHANGES.md
Beilinson Sep 16, 2025
148fea3
Fix documentation
Beilinson Sep 16, 2025
5c0323f
minor documentation fixes
Beilinson Sep 16, 2025
a2efc44
Move renderOnUpdateComplete flag to scene
Beilinson Sep 17, 2025
933b003
Fix syncronous billboards rendering
Beilinson Sep 17, 2025
08800ba
Fix BillboardCollection tests
Beilinson Sep 17, 2025
f707aaf
Better sync solution for TextureAtlas.addImage
Beilinson Sep 21, 2025
d2cae27
Merge branch 'main' into fix-requestrendermode
Beilinson Sep 21, 2025
7cf84a9
Remove renderOnUpdateComplete, fix CR comments on TextureAtlas
Beilinson Sep 24, 2025
47c1084
Merge branch 'main' into fix-requestrendermode
Beilinson Sep 24, 2025
e82f415
Merge branch 'main' into fix-requestrendermode
ggetz Sep 29, 2025
3e74c7b
Merge branch 'main' into fix-requestrendermode
Beilinson Oct 10, 2025
3a4cda2
Fix tsd-jsdoc error
Beilinson Oct 10, 2025
0148da8
Fix failing test, add synchronous image test
Beilinson Oct 10, 2025
a18caf7
Merge branch 'main' into fix-requestrendermode
Beilinson Oct 10, 2025
eeddd24
Merge branch 'main' into fix-requestrendermode
Beilinson Oct 16, 2025
62707ad
Merge branch 'main' into fix-requestrendermode
Beilinson Oct 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- Improved performance when removing primitives. [#3018](https://github.com/CesiumGS/cesium/pull/3018)
- Improved performance of terrain Quadtree handling of custom data [#12907](https://github.com/CesiumGS/cesium/pull/12907)
- Fixed picking of `GroundPrimitive` with multiple `PolygonGeometry` instances selecting the wrong instance. [#12978](https://github.com/CesiumGS/cesium/pull/12978)
- Fix render issues when updating Billboards with syncronous textures with `requestRenderMode=true`. [#12543](https://github.com/CesiumGS/cesium/issues/12543)

## 1.134.1 - 2025-10-10

Expand Down
7 changes: 5 additions & 2 deletions packages/engine/Source/DataSources/BillboardVisualizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ function BillboardVisualizer(entityCluster, entityCollection) {
* Entity counterpart at the given time.
*
* @param {JulianDate} time The time to update to.
* @returns {boolean} This function always returns true.
* @returns {boolean} True if the visualizer successfully updated to the provided time,
* false if the visualizer is waiting for asynchronous work to be completed.
*/
BillboardVisualizer.prototype.update = function (time) {
//>>includeStart('debug', pragmas.debug);
Expand All @@ -89,6 +90,7 @@ BillboardVisualizer.prototype.update = function (time) {
const items = this._items.values;
const cluster = this._cluster;

let isUpdated = true;
for (let i = 0, len = items.length; i < len; i++) {
const item = items[i];
const entity = item.entity;
Expand Down Expand Up @@ -226,6 +228,7 @@ BillboardVisualizer.prototype.update = function (time) {
time,
defaultSplitDirection,
);
isUpdated = billboard.ready && isUpdated;

const subRegion = Property.getValueOrUndefined(
billboardGraphics._imageSubRegion,
Expand All @@ -236,7 +239,7 @@ BillboardVisualizer.prototype.update = function (time) {
billboard.setImageSubRegion(billboard.image, subRegion);
}
}
return true;
return isUpdated;
};

/**
Expand Down
19 changes: 10 additions & 9 deletions packages/engine/Source/DataSources/DataSourceDisplay.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ function DataSourceDisplay(options) {
this._removeDataSourceCollectionListener = removeDataSourceCollectionListener;

this._ready = false;
this._prevUpdateResult = this._ready;
}

const ExtraVisualizers = [];
Expand Down Expand Up @@ -295,7 +296,7 @@ DataSourceDisplay.prototype.update = function (time) {
return false;
}

let result = true;
let updateResult = true;

let i;
let x;
Expand All @@ -306,33 +307,33 @@ DataSourceDisplay.prototype.update = function (time) {
for (i = 0; i < length; i++) {
const dataSource = dataSources.get(i);
if (defined(dataSource.update)) {
result = dataSource.update(time) && result;
updateResult = dataSource.update(time) && updateResult;
}

visualizers = dataSource._visualizers;
vLength = visualizers.length;
for (x = 0; x < vLength; x++) {
result = visualizers[x].update(time) && result;
updateResult = visualizers[x].update(time) && updateResult;
}
}

visualizers = this._defaultDataSource._visualizers;
vLength = visualizers.length;
for (x = 0; x < vLength; x++) {
result = visualizers[x].update(time) && result;
updateResult = visualizers[x].update(time) && updateResult;
}

// Request a rendering of the scene when the data source
// becomes 'ready' for the first time
if (!this._ready && result) {
// Trigger an event when all of the data sources finish updating
if (!this._prevUpdateResult && updateResult) {
this._scene.requestRender();
}
this._prevUpdateResult = updateResult;

// once the DataSourceDisplay is ready it should stay ready to prevent
// entities from breaking updates when they become "un-ready"
this._ready = this._ready || result;
this._ready = this._ready || updateResult;

return result;
return updateResult;
};

DataSourceDisplay.prototype._postRender = function () {
Expand Down
27 changes: 18 additions & 9 deletions packages/engine/Source/Renderer/TextureAtlas.js
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,14 @@ TextureAtlas.prototype.update = function (context) {
return this._processImageQueue(context);
};

async function resolveImage(image, id) {
/**
* Gets an image from various possible input types.
* @private
* @param {HTMLImageElement|HTMLCanvasElement|string|Resource|Promise<TexturePacker.PackableObject>|TextureAtlas.CreateImageCallback} image An image or canvas to add to the texture atlas
* @param {string} id An identifier to detect whether the image already exists in the atlas.
* @returns {TexturePacker.PackableObject | Promise<TexturePacker.PackableObject>} The image or a Promise that resolves to it.
*/
function getImage(image, id) {
if (typeof image === "function") {
image = image(id);
}
Expand Down Expand Up @@ -660,21 +667,23 @@ TextureAtlas.prototype.addImage = function (id, image) {

const index = this._nextIndex++;
this._indexById.set(id, index);

const resolveAndAddImage = async () => {
image = await resolveImage(image, id);
//>>includeStart('debug', pragmas.debug);
Check.defined("image", image);
//>>includeEnd('debug');

image = getImage(image, id);

const resolveAndAddImage = async (index, image) => {
// The initial part of an async function runs synchronously up to the first await
// If the image is synchronous, skip the await: add and process the image the current frame.
if (image instanceof Promise) {
// Effectively return a promise chain. The image promise will resolve and be processed on a later frame
image = await image;
}
if (this.isDestroyed() || !defined(image)) {
return -1;
}

return this._addImage(index, image);
};
promise = resolveAndAddImage(index, image);

promise = resolveAndAddImage();
this._indexPromiseById.set(id, promise);
return promise;
};
Expand Down
4 changes: 1 addition & 3 deletions packages/engine/Source/Scene/Scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,7 @@ import getMetadataProperty from "./getMetadataProperty.js";

const requestRenderAfterFrame = function (scene) {
return function () {
scene.frameState.afterRender.push(function () {
scene.requestRender();
});
scene.frameState.afterRender.push(() => true);
};
};

Expand Down
19 changes: 16 additions & 3 deletions packages/engine/Specs/Renderer/TextureAtlasSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,14 @@ describe("Scene/TextureAtlas", function () {
}).toThrowDeveloperError();
});

it("add image throws if a promise returns undefined", async function () {
it("add image returns -1 if a promise returns undefined", async function () {
atlas = new TextureAtlas();

const promise = atlas.addImage(greenGuid, Promise.resolve());

expect(atlas.numberOfImages).toEqual(1);
await expectAsync(promise).toBeRejectedWithDeveloperError();
const index = await promise;
expect(index).toEqual(-1);
});

it("add image rejects if a promised image rejects", async function () {
Expand Down Expand Up @@ -1297,11 +1298,23 @@ describe("Scene/TextureAtlas", function () {
expect(guid1).not.toEqual(guid2);
});

it("destroys successfully while image is queued", async function () {
it("Syncronous texture resolves immediately", async function () {
atlas = new TextureAtlas();

const promise = atlas.addImage(greenGuid, greenImage);

atlas.update(scene.frameState.context);
const index = await promise;

expect(index).toEqual(0);
atlas = undefined;
});

it("destroys successfully while image promise is queued", async function () {
atlas = new TextureAtlas();

const promise = atlas.addImage(greenGuid, Promise.resolve(greenImage));

atlas.update(scene.frameState.context);
const texture = atlas.texture;

Expand Down