|
|
@@ -11,161 +11,68 @@
|
|
|
namespace anki
|
|
|
{
|
|
|
|
|
|
-/// Texture upload async task.
|
|
|
-class TexUploadTask : public AsyncLoaderTask
|
|
|
+class TextureResource::LoadingContext
|
|
|
{
|
|
|
public:
|
|
|
- static constexpr U MAX_COPIES_BEFORE_FLUSH = 8;
|
|
|
-
|
|
|
ImageLoader m_loader;
|
|
|
- TexturePtr m_tex;
|
|
|
- GrManager* m_gr ANKI_DBG_NULLIFY;
|
|
|
- TransferGpuAllocator* m_transferAlloc ANKI_DBG_NULLIFY;
|
|
|
- U m_layers = 0;
|
|
|
U m_faces = 0;
|
|
|
+ U m_layerCount = 0;
|
|
|
+ GrManager* m_gr ANKI_DBG_NULLIFY;
|
|
|
+ TransferGpuAllocator* m_trfAlloc ANKI_DBG_NULLIFY;
|
|
|
TextureType m_texType;
|
|
|
+ TexturePtr m_tex;
|
|
|
|
|
|
- TexUploadTask(GenericMemoryPoolAllocator<U8> alloc)
|
|
|
+ LoadingContext(GenericMemoryPoolAllocator<U8> alloc)
|
|
|
: m_loader(alloc)
|
|
|
{
|
|
|
}
|
|
|
-
|
|
|
- Error operator()(AsyncLoaderTaskContext& ctx) final;
|
|
|
-
|
|
|
- void flush(WeakArray<TransferGpuAllocatorHandle> handles, CommandBufferPtr& cmdb);
|
|
|
};
|
|
|
|
|
|
-void TexUploadTask::flush(WeakArray<TransferGpuAllocatorHandle> handles, CommandBufferPtr& cmdb)
|
|
|
+/// Texture upload async task.
|
|
|
+class TextureResource::TexUploadTask : public AsyncLoaderTask
|
|
|
{
|
|
|
- FencePtr fence;
|
|
|
- cmdb->flush(&fence);
|
|
|
+public:
|
|
|
+ TextureResource::LoadingContext m_ctx;
|
|
|
|
|
|
- for(TransferGpuAllocatorHandle& handle : handles)
|
|
|
+ TexUploadTask(GenericMemoryPoolAllocator<U8> alloc)
|
|
|
+ : m_ctx(alloc)
|
|
|
{
|
|
|
- m_transferAlloc->release(handle, fence);
|
|
|
}
|
|
|
|
|
|
- cmdb.reset(nullptr);
|
|
|
-}
|
|
|
+ Error operator()(AsyncLoaderTaskContext& ctx) final
|
|
|
+ {
|
|
|
+ return TextureResource::load(m_ctx);
|
|
|
+ }
|
|
|
+};
|
|
|
|
|
|
-Error TexUploadTask::operator()(AsyncLoaderTaskContext& ctx)
|
|
|
+TextureResource::~TextureResource()
|
|
|
{
|
|
|
- CommandBufferPtr cmdb;
|
|
|
+}
|
|
|
|
|
|
- Array<TransferGpuAllocatorHandle, MAX_COPIES_BEFORE_FLUSH> handles;
|
|
|
- U handleCount = 0;
|
|
|
+Error TextureResource::load(const ResourceFilename& filename, Bool async)
|
|
|
+{
|
|
|
+ TexUploadTask* task;
|
|
|
+ LoadingContext* ctx;
|
|
|
+ LoadingContext localCtx(getTempAllocator());
|
|
|
|
|
|
- // Upload the data
|
|
|
- for(U layer = 0; layer < m_layers; ++layer)
|
|
|
+ if(async)
|
|
|
{
|
|
|
- for(U face = 0; face < m_faces; ++face)
|
|
|
- {
|
|
|
- for(U mip = 0; mip < m_loader.getMipLevelsCount(); ++mip)
|
|
|
- {
|
|
|
- if(!cmdb)
|
|
|
- {
|
|
|
- CommandBufferInitInfo ci;
|
|
|
- ci.m_flags = CommandBufferFlag::TRANSFER_WORK | CommandBufferFlag::SMALL_BATCH;
|
|
|
- cmdb = m_gr->newInstance<CommandBuffer>(ci);
|
|
|
- }
|
|
|
-
|
|
|
- PtrSize surfOrVolSize;
|
|
|
- const void* surfOrVolData;
|
|
|
- PtrSize allocationSize;
|
|
|
-
|
|
|
- if(m_texType == TextureType::_3D)
|
|
|
- {
|
|
|
- const auto& vol = m_loader.getVolume(mip);
|
|
|
- surfOrVolSize = vol.m_data.getSize();
|
|
|
- surfOrVolData = &vol.m_data[0];
|
|
|
-
|
|
|
- m_gr->getTextureVolumeUploadInfo(m_tex, TextureVolumeInfo(mip), allocationSize);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- const auto& surf = m_loader.getSurface(mip, face, layer);
|
|
|
- surfOrVolSize = surf.m_data.getSize();
|
|
|
- surfOrVolData = &surf.m_data[0];
|
|
|
-
|
|
|
- m_gr->getTextureSurfaceUploadInfo(m_tex, TextureSurfaceInfo(mip, 0, face, layer), allocationSize);
|
|
|
- }
|
|
|
-
|
|
|
- ANKI_ASSERT(allocationSize >= surfOrVolSize);
|
|
|
-
|
|
|
- TransferGpuAllocatorHandle& handle = handles[handleCount++];
|
|
|
- ANKI_CHECK(m_transferAlloc->allocate(allocationSize, handle));
|
|
|
- void* data = handle.getMappedMemory();
|
|
|
- ANKI_ASSERT(data);
|
|
|
-
|
|
|
- memcpy(data, surfOrVolData, surfOrVolSize);
|
|
|
-
|
|
|
- if(m_texType == TextureType::_3D)
|
|
|
- {
|
|
|
- TextureVolumeInfo vol(mip);
|
|
|
-
|
|
|
- cmdb->setTextureVolumeBarrier(
|
|
|
- m_tex, TextureUsageBit::NONE, TextureUsageBit::TRANSFER_DESTINATION, vol);
|
|
|
-
|
|
|
- cmdb->copyBufferToTextureVolume(
|
|
|
- handle.getBuffer(), handle.getOffset(), handle.getRange(), m_tex, vol);
|
|
|
-
|
|
|
- cmdb->setTextureVolumeBarrier(m_tex,
|
|
|
- TextureUsageBit::TRANSFER_DESTINATION,
|
|
|
- TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::SAMPLED_TESSELLATION_EVALUATION,
|
|
|
- vol);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- TextureSurfaceInfo surf(mip, 0, face, layer);
|
|
|
-
|
|
|
- cmdb->setTextureSurfaceBarrier(
|
|
|
- m_tex, TextureUsageBit::NONE, TextureUsageBit::TRANSFER_DESTINATION, surf);
|
|
|
-
|
|
|
- cmdb->copyBufferToTextureSurface(
|
|
|
- handle.getBuffer(), handle.getOffset(), handle.getRange(), m_tex, surf);
|
|
|
-
|
|
|
- cmdb->setTextureSurfaceBarrier(m_tex,
|
|
|
- TextureUsageBit::TRANSFER_DESTINATION,
|
|
|
- TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::SAMPLED_TESSELLATION_EVALUATION,
|
|
|
- surf);
|
|
|
- }
|
|
|
-
|
|
|
- // Check if you should flush the batch
|
|
|
- if(handleCount == handles.getSize())
|
|
|
- {
|
|
|
- flush({&handles[0], handleCount}, cmdb);
|
|
|
- handleCount = 0;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ task = getManager().getAsyncLoader().newTask<TexUploadTask>(getManager().getAsyncLoader().getAllocator());
|
|
|
+ ctx = &task->m_ctx;
|
|
|
}
|
|
|
-
|
|
|
- // Enque what remains
|
|
|
- if(handleCount)
|
|
|
+ else
|
|
|
{
|
|
|
- flush({&handles[0], handleCount}, cmdb);
|
|
|
+ task = nullptr;
|
|
|
+ ctx = &localCtx;
|
|
|
}
|
|
|
+ ImageLoader& loader = ctx->m_loader;
|
|
|
|
|
|
- return ErrorCode::NONE;
|
|
|
-}
|
|
|
-
|
|
|
-TextureResource::~TextureResource()
|
|
|
-{
|
|
|
-}
|
|
|
-
|
|
|
-Error TextureResource::load(const ResourceFilename& filename)
|
|
|
-{
|
|
|
TextureInitInfo init;
|
|
|
init.m_usage = TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::SAMPLED_TESSELLATION_EVALUATION
|
|
|
| TextureUsageBit::TRANSFER_DESTINATION;
|
|
|
init.m_usageWhenEncountered = TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::SAMPLED_TESSELLATION_EVALUATION;
|
|
|
U faces = 0;
|
|
|
|
|
|
- // Load image
|
|
|
- TexUploadTask* task =
|
|
|
- getManager().getAsyncLoader().newTask<TexUploadTask>(getManager().getAsyncLoader().getAllocator());
|
|
|
- ImageLoader& loader = task->m_loader;
|
|
|
-
|
|
|
ResourceFilePtr file;
|
|
|
ANKI_CHECK(openFile(filename, file));
|
|
|
|
|
|
@@ -269,20 +176,151 @@ Error TextureResource::load(const ResourceFilename& filename)
|
|
|
// Create the texture
|
|
|
m_tex = getManager().getGrManager().newInstance<Texture>(init);
|
|
|
|
|
|
- // Upload the data asynchronously
|
|
|
- task->m_layers = init.m_layerCount;
|
|
|
- task->m_faces = faces;
|
|
|
- task->m_gr = &getManager().getGrManager();
|
|
|
- task->m_transferAlloc = &getManager().getTransferGpuAllocator();
|
|
|
- task->m_tex = m_tex;
|
|
|
- task->m_texType = init.m_type;
|
|
|
+ // Set the context
|
|
|
+ ctx->m_faces = faces;
|
|
|
+ ctx->m_layerCount = init.m_layerCount;
|
|
|
+ ctx->m_gr = &getManager().getGrManager();
|
|
|
+ ctx->m_trfAlloc = &getManager().getTransferGpuAllocator();
|
|
|
+ ctx->m_texType = init.m_type;
|
|
|
+ ctx->m_tex = m_tex;
|
|
|
|
|
|
- getManager().getAsyncLoader().submitTask(task);
|
|
|
+ // Upload the data
|
|
|
+ if(async)
|
|
|
+ {
|
|
|
+ getManager().getAsyncLoader().submitTask(task);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ANKI_CHECK(load(*ctx));
|
|
|
+ }
|
|
|
|
|
|
- // Done
|
|
|
m_size = UVec3(init.m_width, init.m_height, init.m_depth);
|
|
|
m_layerCount = init.m_layerCount;
|
|
|
return ErrorCode::NONE;
|
|
|
}
|
|
|
|
|
|
+Error TextureResource::load(LoadingContext& ctx)
|
|
|
+{
|
|
|
+ const U copyCount = ctx.m_layerCount * ctx.m_faces * ctx.m_loader.getMipLevelsCount();
|
|
|
+
|
|
|
+ for(U b = 0; b < copyCount; b += MAX_COPIES_BEFORE_FLUSH)
|
|
|
+ {
|
|
|
+ const U begin = b;
|
|
|
+ const U end = min(copyCount, b + MAX_COPIES_BEFORE_FLUSH);
|
|
|
+
|
|
|
+ CommandBufferInitInfo ci;
|
|
|
+ ci.m_flags = CommandBufferFlag::TRANSFER_WORK | CommandBufferFlag::SMALL_BATCH;
|
|
|
+ CommandBufferPtr cmdb = ctx.m_gr->newInstance<CommandBuffer>(ci);
|
|
|
+
|
|
|
+ // Set the barriers of the batch
|
|
|
+ for(U i = begin; i < end; ++i)
|
|
|
+ {
|
|
|
+ U mip, layer, face;
|
|
|
+ unflatten3dArrayIndex(ctx.m_layerCount, ctx.m_faces, ctx.m_loader.getMipLevelsCount(), i, layer, face, mip);
|
|
|
+
|
|
|
+ if(ctx.m_texType == TextureType::_3D)
|
|
|
+ {
|
|
|
+ TextureVolumeInfo vol(mip);
|
|
|
+ cmdb->setTextureVolumeBarrier(
|
|
|
+ ctx.m_tex, TextureUsageBit::NONE, TextureUsageBit::TRANSFER_DESTINATION, vol);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TextureSurfaceInfo surf(mip, 0, face, layer);
|
|
|
+ cmdb->setTextureSurfaceBarrier(
|
|
|
+ ctx.m_tex, TextureUsageBit::NONE, TextureUsageBit::TRANSFER_DESTINATION, surf);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Do the copies
|
|
|
+ Array<TransferGpuAllocatorHandle, MAX_COPIES_BEFORE_FLUSH> handles;
|
|
|
+ U handleCount = 0;
|
|
|
+ for(U i = begin; i < end; ++i)
|
|
|
+ {
|
|
|
+ U mip, layer, face;
|
|
|
+ unflatten3dArrayIndex(ctx.m_layerCount, ctx.m_faces, ctx.m_loader.getMipLevelsCount(), i, layer, face, mip);
|
|
|
+
|
|
|
+ PtrSize surfOrVolSize;
|
|
|
+ const void* surfOrVolData;
|
|
|
+ PtrSize allocationSize;
|
|
|
+
|
|
|
+ if(ctx.m_texType == TextureType::_3D)
|
|
|
+ {
|
|
|
+ const auto& vol = ctx.m_loader.getVolume(mip);
|
|
|
+ surfOrVolSize = vol.m_data.getSize();
|
|
|
+ surfOrVolData = &vol.m_data[0];
|
|
|
+
|
|
|
+ ctx.m_gr->getTextureVolumeUploadInfo(ctx.m_tex, TextureVolumeInfo(mip), allocationSize);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ const auto& surf = ctx.m_loader.getSurface(mip, face, layer);
|
|
|
+ surfOrVolSize = surf.m_data.getSize();
|
|
|
+ surfOrVolData = &surf.m_data[0];
|
|
|
+
|
|
|
+ ctx.m_gr->getTextureSurfaceUploadInfo(
|
|
|
+ ctx.m_tex, TextureSurfaceInfo(mip, 0, face, layer), allocationSize);
|
|
|
+ }
|
|
|
+
|
|
|
+ ANKI_ASSERT(allocationSize >= surfOrVolSize);
|
|
|
+ TransferGpuAllocatorHandle& handle = handles[handleCount++];
|
|
|
+ ANKI_CHECK(ctx.m_trfAlloc->allocate(allocationSize, handle));
|
|
|
+ void* data = handle.getMappedMemory();
|
|
|
+ ANKI_ASSERT(data);
|
|
|
+
|
|
|
+ memcpy(data, surfOrVolData, surfOrVolSize);
|
|
|
+
|
|
|
+ if(ctx.m_texType == TextureType::_3D)
|
|
|
+ {
|
|
|
+ TextureVolumeInfo vol(mip);
|
|
|
+ cmdb->copyBufferToTextureVolume(
|
|
|
+ handle.getBuffer(), handle.getOffset(), handle.getRange(), ctx.m_tex, vol);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TextureSurfaceInfo surf(mip, 0, face, layer);
|
|
|
+
|
|
|
+ cmdb->copyBufferToTextureSurface(
|
|
|
+ handle.getBuffer(), handle.getOffset(), handle.getRange(), ctx.m_tex, surf);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Set the barriers of the batch
|
|
|
+ for(U i = begin; i < end; ++i)
|
|
|
+ {
|
|
|
+ U mip, layer, face;
|
|
|
+ unflatten3dArrayIndex(ctx.m_layerCount, ctx.m_faces, ctx.m_loader.getMipLevelsCount(), i, layer, face, mip);
|
|
|
+
|
|
|
+ if(ctx.m_texType == TextureType::_3D)
|
|
|
+ {
|
|
|
+ TextureVolumeInfo vol(mip);
|
|
|
+ cmdb->setTextureVolumeBarrier(ctx.m_tex,
|
|
|
+ TextureUsageBit::TRANSFER_DESTINATION,
|
|
|
+ TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::SAMPLED_TESSELLATION_EVALUATION,
|
|
|
+ vol);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TextureSurfaceInfo surf(mip, 0, face, layer);
|
|
|
+ cmdb->setTextureSurfaceBarrier(ctx.m_tex,
|
|
|
+ TextureUsageBit::TRANSFER_DESTINATION,
|
|
|
+ TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::SAMPLED_TESSELLATION_EVALUATION,
|
|
|
+ surf);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Flush batch
|
|
|
+ FencePtr fence;
|
|
|
+ cmdb->flush(&fence);
|
|
|
+
|
|
|
+ for(U i = 0; i < handleCount; ++i)
|
|
|
+ {
|
|
|
+ ctx.m_trfAlloc->release(handles[i], fence);
|
|
|
+ }
|
|
|
+ cmdb.reset(nullptr);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ErrorCode::NONE;
|
|
|
+}
|
|
|
+
|
|
|
} // end namespace anki
|