gltfio: add async cancellation API

This commit is contained in:
Philip Rideout
2020-09-22 14:11:53 -07:00
parent 450fe214f9
commit 1ebdb18eae
5 changed files with 60 additions and 0 deletions

View File

@@ -220,6 +220,7 @@ class ModelViewer(val engine: Engine) : android.view.View.OnTouchListener {
*/
fun destroyModel() {
fetchResourcesJob?.cancel()
resourceLoader.asyncCancelLoad()
asset?.let { asset ->
this.scene.removeEntities(asset.entities)
assetLoader.destroyAsset(asset)

View File

@@ -99,3 +99,10 @@ Java_com_google_android_filament_gltfio_ResourceLoader_nAsyncUpdateLoad(JNIEnv*,
ResourceLoader* loader = (ResourceLoader*) nativeLoader;
loader->asyncUpdateLoad();
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_ResourceLoader_nAsyncCancelLoad(JNIEnv*, jclass,
jlong nativeLoader) {
ResourceLoader* loader = (ResourceLoader*) nativeLoader;
loader->asyncCancelLoad();
}

View File

@@ -146,6 +146,16 @@ public class ResourceLoader {
nAsyncUpdateLoad(mNativeObject);
}
/**
* Cancels pending decoder jobs and frees all CPU-side texel data.
*
* Calling this is only necessary if the asyncBeginLoad API was used
* and cancellation is required before progress reaches 100%.
*/
public void asyncCancelLoad() {
nAsyncCancelLoad(mNativeObject);
}
private static native long nCreateResourceLoader(long nativeEngine,
boolean normalizeSkinningWeights, boolean recomputeBoundingBoxes);
private static native void nDestroyResourceLoader(long nativeLoader);
@@ -156,4 +166,5 @@ public class ResourceLoader {
private static native boolean nAsyncBeginLoad(long nativeLoader, long nativeAsset);
private static native float nAsyncGetLoadProgress(long nativeLoader);
private static native void nAsyncUpdateLoad(long nativeLoader);
private static native void nAsyncCancelLoad(long nativeLoader);
}

View File

@@ -130,6 +130,14 @@ public:
*/
void asyncUpdateLoad();
/**
* Cancels pending decoder jobs and frees all CPU-side texel data.
*
* Calling this is only necessary if the asyncBeginLoad API was used
* and cancellation is required before progress reaches 100%.
*/
void asyncCancelLoad();
private:
bool loadResources(FFilamentAsset* asset, bool async);
void applySparseData(FFilamentAsset* asset) const;

View File

@@ -104,10 +104,12 @@ struct ResourceLoader::Impl {
void computeTangents(FFilamentAsset* asset);
bool createTextures(bool async);
void cancelTextureDecoding();
void addTextureCacheEntry(const TextureSlot& tb);
void bindTextureToMaterial(const TextureSlot& tb);
void decodeSingleTexture();
void uploadPendingTextures();
void releasePendingTextures();
~Impl();
};
@@ -450,6 +452,10 @@ bool ResourceLoader::asyncBeginLoad(FilamentAsset* asset) {
return loadResources(upcast(asset), true);
}
void ResourceLoader::asyncCancelLoad() {
pImpl->cancelTextureDecoding();
}
float ResourceLoader::asyncGetLoadProgress() const {
const float finished = pImpl->mNumDecoderTasksFinished;
const float total = pImpl->mNumDecoderTasks;
@@ -527,6 +533,20 @@ void ResourceLoader::Impl::uploadPendingTextures() {
for (auto& pair : mUriTextureCache) upload(pair.second.get(), *mEngine);
}
void ResourceLoader::Impl::releasePendingTextures() {
auto release = [this](TextureCacheEntry* entry, Engine& engine) {
Texture* texture = entry->texture;
uint8_t* texels = entry->texels;
if (texture && texels && !entry->completed) {
// Normally the ownership of these texels is transferred to PixelBufferDescriptor, but
// if uploads have been cancelled then we need to free them explicitly.
free(texels);
}
};
for (auto& pair : mBufferTextureCache) release(pair.second.get(), *mEngine);
for (auto& pair : mUriTextureCache) release(pair.second.get(), *mEngine);
}
void ResourceLoader::Impl::addTextureCacheEntry(const TextureSlot& tb) {
TextureCacheEntry* entry = nullptr;
@@ -602,6 +622,19 @@ void ResourceLoader::Impl::bindTextureToMaterial(const TextureSlot& tb) {
asset->bindTexture(tb, entry->texture);
}
}
void ResourceLoader::Impl::cancelTextureDecoding() {
JobSystem* js = &mEngine->getJobSystem();
if (mDecoderRootJob) {
js->waitAndRelease(mDecoderRootJob);
mDecoderRootJob = nullptr;
}
releasePendingTextures();
mBufferTextureCache.clear();
mUriTextureCache.clear();
mCurrentAsset = nullptr;
mNumDecoderTasksFinished = 0;
mNumDecoderTasks = 0;
}
bool ResourceLoader::Impl::createTextures(bool async) {
// If any decoding jobs are still underway, wait for them to finish.