After months of research, two proof-of-concept tests and 2 weeks of solid banging my head against code I finally got the first half of an incredibly awesome texture streaming system working at a very basic level.
Had to redesign this system more than 20 times!
The psuedo code for loading an image into GPU memory is;
<span style="color: #ff0000; font-style: italic;">/* Renderer initialisation */
xiSharedLibrary * const sharedLibrary = fileSystem.CreateSharedLibrary( <span style="color: #666666;">"ren_vulkan10" );
api_renderer_t rendererAPI;
sharedLibrary->GetAPI( <span style="color: #666666;">"api_renderer", &rendererAPI );
xiRenderer * const renderer = rendererAPI.Create_f();
<span style="color: #ff0000; font-style: italic;">/* Pixel buffer initialisation */
xiBuffer * const buffer = renderer->CreateBuffer( 0x100000 ); // Create GPU memory
xiAsyncBuffer * const asyncBuffer = <span style="color: #0000dd;">new xiAsyncBuffer( buffer ); // Create asynchronous stream manager for GPU memory
<span style="color: #ff0000; font-style: italic;">/* Image loader initialisation */
xiImageLoader * const imageLoader = renderer->CreateImageLoader( asyncBuffer ); // Create image loader, targeting the GPU asynchronous buffer
imageLoader->AddImageFormat( xiTGAImageFormat::SINGLETON ); // Add TGA support for this loader
<span style="color: #ff0000; font-style: italic;">/* Load image */
xiReadStream * const readStream = fileSystem.CreateReadStream( <span style="color: #666666;">"texture.tga" ); // Create file read stream
xiImageSource * const imageSource = imageLoader->CreateImageSourceFromStream( readStream ); // Create image source
if ( imageSource->LoadAsync2D( imageSource->GetWidth(), imageSource->GetHeight() ) ) {
// readStream is now loading asynchronously on a second thread into buffer
}
That is a lot of code for simply decoding a texture, but what will happen is the ::LoadAsync2D() will be called automagically when a texture is needed at a certain resolution and the buffer/asyncbuffer is shared across image loaders, of which there are only a handful, so in practise it will be;
xiImageSource * const imageSource = imageLoader->CreateImageSourceFromStream( readStream );
xiTexture * const texture = renderer->CreateTexture( imageSource );
// The pixel coverage of the texture is passed to ::LoadAsync2D() by the material management system
So now I'm going to be working on getting the texture data to display again which is the 2nd half of this system.
After that, I'll need to sort out how other mipmaps are handled. Some formats will contain the mipmaps in them (the texture binary format I am developing will certainly do this) and some formats, like TGA, have mipmap 0 and will need the other mipmaps generated after 0 is loaded. No clue what I'm going to do for that.