vendredi 25 novembre 2016

std::shared_ptr::reset() "invalidates" other references

All my code is single-threaded at this time.

I have a texture manager that owns a collection of "texture collections" which in turn hold, "own" and manage all my game's textures as std::shared_ptr's. One collection is dedicated to my framebuffer textures. At initialization, it instantiates all my framebuffer textures, and later, a separate framebuffer object requests them all and stores its own std::shared_ptr references to these textures. I use this object in my deferred renderer. No problem so far: looking at the debug information in Visual Studio (2015), it shows two strong references (the one in the collection, and the one in the framebuffer object) per framebuffer texture; working as it should.

The problem arises when my window dimensions change. I listen for the WM_SIZE event, and upon a resize, my WndProc calls the following (again, on the references in my framebuffer texture collection, rather than my framebuffer object -- adhering to my ownership convention):

void PantheraTextureCollectionFramebuffer::Resize( unsigned int width, unsigned int height ) {
    _textures["depth"].reset( new PantheraTexture( width, height, PantheraTextureFormat::Depth24,
            PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );

    _textures["diffuseSpecular"].reset( new PantheraTexture( width, height, PantheraTextureFormat::RGBA8,
            PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );

    _textures["normalParallax"].reset( new PantheraTexture( width, height, PantheraTextureFormat::RGBA8,
            PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );

    _textures["position"].reset( new PantheraTexture( width, height, PantheraTextureFormat::RGB16F,
            PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );

    _textures["uvMaterial"].reset( new PantheraTexture( width, height, PantheraTextureFormat::RGB16F,
            PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );
}

Which recreates all the textures with the new window dimensions. BUT, the std::shared_ptr's in the framebuffer object remain unchanged (apart from the ref counts for each texture, which drop to one). It seems I've fundamentally misjudged std::shared_ptr and its reset() method.

I've also tried reassigning using indirection, for example:

*_textures["depth"] = PantheraTexture(...)

which, aside from feeling unpleasantly hacky, doesn't call my texture objects' destructors and so OpenGL never frees the invalid textures.

I am stumped. I'd like to keep the texture objects immutable themselves, otherwise I'd probably implement an internal Resize method for them, leveraging glTexImage*D. How would you suggest going about maintaining continuity between my texture collection and my framebuffer object without resorting to that?

Thanks in advance.

Aucun commentaire:

Enregistrer un commentaire