gltfio: add async cancellation API
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user