diff --git a/Components/Overlay/src/OgreFont.cpp b/Components/Overlay/src/OgreFont.cpp index 5ac92c667a3..fceac59bc35 100644 --- a/Components/Overlay/src/OgreFont.cpp +++ b/Components/Overlay/src/OgreFont.cpp @@ -498,8 +498,6 @@ namespace Ogre OGRE_FREE_SIMD( imageData, MEMCATEGORY_RESOURCE ); imageData = 0; - mTexture->notifyDataIsReady(); - FT_Done_FreeType(ftLibrary); } //--------------------------------------------------------------------- diff --git a/OgreMain/include/OgreStagingTexture.h b/OgreMain/include/OgreStagingTexture.h index dea9e574862..f297a2ff1b2 100644 --- a/OgreMain/include/OgreStagingTexture.h +++ b/OgreMain/include/OgreStagingTexture.h @@ -65,8 +65,6 @@ namespace Ogre stagingTexture->upload( box0, texture0 ); stagingTexture->upload( box1, texture1 ); textureManager.removeStagingTexture( stagingTexture ); - texture0->notifyDataIsReady(); - texture1->notifyDataIsReady(); @par There are other possibilities, as you can request a StagingTexture with twice the width & height and then start calling mapRegion with smaller textures and we'll diff --git a/OgreMain/include/OgreTextureGpu.h b/OgreMain/include/OgreTextureGpu.h index 84e92fc312d..d9d115dd3e1 100644 --- a/OgreMain/include/OgreTextureGpu.h +++ b/OgreMain/include/OgreTextureGpu.h @@ -310,6 +310,15 @@ namespace Ogre /// @see TextureSourceType::TextureSourceType uint8 mSourceType; + /// See TextureGpu::_isDataReadyImpl + /// + /// It is increased with every scheduleReupload/scheduleTransitionTo (to resident) + /// It is decreased every time the loading is done + /// + /// _isDataReadyImpl can NOT return true if mDataReady != 0 + /// _isDataReadyImpl CAN return false if mDataReady == 0 + uint8 mDataPreparationsPending; + /// This setting can only be altered if mResidencyStatus == OnStorage). TextureTypes::TextureTypes mTextureType; PixelFormatGpu mPixelFormat; @@ -387,6 +396,40 @@ namespace Ogre void scheduleTransitionTo( GpuResidency::GpuResidency nextResidency, Image2 *image=0, bool autoDeleteImage=true ); + /** There are times where you want to reload a texture again (e.g. file on + disk changed, uploading a new Image2, etc) without visual disruption. + + e.g. if you were to call: + @code + tex->scheduleTransitionTo( GpuResidency::OnStorage ); + tex->scheduleTransitionTo( GpuResidency::Resident, ... ); + @endcode + + you'll achieve the same result, however the texture becomes immediately + unavailable causing a few frames were all the user sees is a blank texture + until it is fully reloaded. + + This routine allows for an in-place hot-reload, where the old texture + is swapped for the new one once it's done loading. + + This is also faster because DescriptorTextureSets don't change + + @remarks + 1. Assumes the last queued transition to perform is into + Resident or OnSystemRam + 2. Visual hitches are unavoidable if metadata changes (e.g. new + texture is of different pixel format, different number of + mipmaps, resolution, etc) + If that's the case, it is faster to transition to OnStorage, + remove the metadata entry from cache, then to Resident again + + @param image + See TextureGpu::unsafeScheduleTransitionTo + @param autoDeleteImage + Same TextureGpu::unsafeScheduleTransitionTo + */ + void scheduleReupload( Image2 *image = 0, bool autoDeleteImage = true ); + // See isMetadataReady for threadsafety on these functions. void setResolution( uint32 width, uint32 height, uint32 depthOrSlices=1u ); uint32 getWidth(void) const; diff --git a/OgreMain/include/OgreTextureGpuManager.h b/OgreMain/include/OgreTextureGpuManager.h index b7cc1981793..c2b34ed0c5b 100644 --- a/OgreMain/include/OgreTextureGpuManager.h +++ b/OgreMain/include/OgreTextureGpuManager.h @@ -469,13 +469,15 @@ namespace Ogre GpuResidency::GpuResidency targetResidency; Image2 *image; bool autoDeleteImage; + bool reuploadOnly; - void init( GpuResidency::GpuResidency _targetResidency, - Image2 *_image, bool _autoDeleteImage ) + void init( GpuResidency::GpuResidency _targetResidency, Image2 *_image, + bool _autoDeleteImage, bool _reuploadOnly ) { targetResidency = _targetResidency; - image = _image; + image = _image; autoDeleteImage = _autoDeleteImage; + reuploadOnly = _reuploadOnly; } }; @@ -742,7 +744,7 @@ namespace Ogre /// It is not enough to call waitForStreamingCompletion to render /// single frame with all textures loaded, as new loading requests - /// could be added during frame rendering. In this case waiting + /// could be added during frame rendering. In this case waiting /// and rendering could be repeated to avoid the problem. bool hasNewLoadRequests() const { return mAddedNewLoadRequestsSinceWaitingForStreamingCompletion; } @@ -1159,8 +1161,8 @@ namespace Ogre VaoManager* getVaoManager(void) const; protected: - void scheduleLoadRequest( TextureGpu *texture, Image2 *image, - bool autoDeleteImage, bool toSysRam ); + void scheduleLoadRequest( TextureGpu *texture, Image2 *image, bool autoDeleteImage, + bool toSysRam, bool reuploadOnly ); /// Transitions a texture from OnSystemRam to Resident; and asks the worker thread /// to transfer the data in the background. @@ -1169,14 +1171,18 @@ namespace Ogre /// disk and loading listeners. void scheduleLoadFromRam( TextureGpu *texture ); - void scheduleLoadRequest( TextureGpu *texture, - const String &name, const String &resourceGroup, + void scheduleLoadRequest( TextureGpu *texture, const String &name, const String &resourceGroup, uint32 filters, Image2 *image, bool autoDeleteImage, bool toSysRam, - bool skipMetadataCache=false, - uint32 sliceOrDepth=std::numeric_limits::max() ); + bool reuploadOnly, bool skipMetadataCache = false, + uint32 sliceOrDepth = std::numeric_limits::max() ); + public: + void _scheduleUpdate( TextureGpu *texture, uint32 filters, Image2 *image, bool autoDeleteImage, + bool skipMetadataCache = false, + uint32 sliceOrDepth = std::numeric_limits::max() ); + void _scheduleTransitionTo( TextureGpu *texture, GpuResidency::GpuResidency targetResidency, - Image2 *image, bool autoDeleteImage ); + Image2 *image, bool autoDeleteImage, bool reuploadOnly ); void _queueDownloadToRam( TextureGpu *texture, bool resyncOnly ); /// When true we will ignore all tasks in mScheduledTasks and execute transitions immediately /// Caller is responsible for ensuring this is safe to do. diff --git a/OgreMain/src/OgreTextureGpu.cpp b/OgreMain/src/OgreTextureGpu.cpp index 5428ca5f516..676bf2932e7 100644 --- a/OgreMain/src/OgreTextureGpu.cpp +++ b/OgreMain/src/OgreTextureGpu.cpp @@ -61,6 +61,7 @@ namespace Ogre mNumMipmaps( 1 ), mInternalSliceStart( 0 ), mSourceType( TextureSourceType::Standard ), + mDataPreparationsPending( 0u ), mTextureType( initialType ), mPixelFormat( PFG_UNKNOWN ), mTextureFlags( textureFlags ), @@ -161,7 +162,7 @@ namespace Ogre else { //Schedule transition, we'll be loading from a worker thread. - mTextureManager->_scheduleTransitionTo( this, nextResidency, image, autoDeleteImage ); + mTextureManager->_scheduleTransitionTo( this, nextResidency, image, autoDeleteImage, false ); } } //----------------------------------------------------------------------------------- @@ -172,6 +173,25 @@ namespace Ogre unsafeScheduleTransitionTo( nextResidency, image, autoDeleteImage ); } //----------------------------------------------------------------------------------- + void TextureGpu::scheduleReupload( Image2 *image, bool autoDeleteImage ) + { + OGRE_ASSERT_LOW( mNextResidencyStatus != GpuResidency::OnStorage ); + OGRE_ASSERT_LOW( mDataPreparationsPending < std::numeric_limits::max() && + "Overflow. Too many transitions queued up" ); + + if( mNextResidencyStatus == GpuResidency::OnSystemRam ) + { + scheduleTransitionTo( Ogre::GpuResidency::OnStorage ); + scheduleTransitionTo( Ogre::GpuResidency::OnSystemRam, image, autoDeleteImage ); + } + else + { + ++mDataPreparationsPending; + mTextureManager->_scheduleTransitionTo( this, GpuResidency::Resident, image, autoDeleteImage, + true ); + } + } + //----------------------------------------------------------------------------------- void TextureGpu::setResolution( uint32 width, uint32 height, uint32 depthOrSlices ) { assert( mResidencyStatus == GpuResidency::OnStorage || isRenderWindowSpecific() ); @@ -479,6 +499,25 @@ namespace Ogre bool allowResidencyChange = true; TextureGpuListener::Reason listenerReason = TextureGpuListener::Unknown; + if( mResidencyStatus == GpuResidency::Resident ) + { + const uint8 savedValue = mDataPreparationsPending; + mDataPreparationsPending = 0u; + const bool bWasDataReady = _isDataReadyImpl(); + mDataPreparationsPending = savedValue; + + if( !bWasDataReady ) + { + OGRE_ASSERT_LOW( mDataPreparationsPending > 0u && "This should never happen" ); + // If we reach here, then we're aborting a load. e.g. + // user went to Resident then to OnStorage without ever + // calling notifyDataIsReady() + // This is perfectly valid, and can happen if the texture + // metadata cache got out of date for example. + --mDataPreparationsPending; + } + } + if( newResidency == GpuResidency::Resident ) { if( mPageOutStrategy != GpuPageOutStrategy::AlwaysKeepSystemRamCopy ) @@ -496,6 +535,10 @@ namespace Ogre mSysRamCopy = sysRamCopy; } + OGRE_ASSERT_LOW( mDataPreparationsPending < std::numeric_limits::max() && + "Overflow. Too many transitions queued up" ); + ++mDataPreparationsPending; + transitionToResident(); listenerReason = TextureGpuListener::GainedResidency; } diff --git a/OgreMain/src/OgreTextureGpuManager.cpp b/OgreMain/src/OgreTextureGpuManager.cpp index 0afe009b163..d353c3bb816 100644 --- a/OgreMain/src/OgreTextureGpuManager.cpp +++ b/OgreMain/src/OgreTextureGpuManager.cpp @@ -1440,15 +1440,19 @@ namespace Ogre const GpuResidency::GpuResidency targetResidency = task.residencyTransitionTask.targetResidency; - if( texture->getResidencyStatus() == GpuResidency::OnStorage ) + if( texture->getResidencyStatus() == GpuResidency::OnStorage || + task.residencyTransitionTask.reuploadOnly ) { OGRE_ASSERT_MEDIUM( targetResidency == GpuResidency::Resident || targetResidency == GpuResidency::OnSystemRam ); + OGRE_ASSERT_MEDIUM( !task.residencyTransitionTask.reuploadOnly || + texture->getResidencyStatus() == GpuResidency::Resident ); scheduleLoadRequest( texture, task.residencyTransitionTask.image, task.residencyTransitionTask.autoDeleteImage, - targetResidency == GpuResidency::OnSystemRam ); + targetResidency == GpuResidency::OnSystemRam, + task.residencyTransitionTask.reuploadOnly ); } else { @@ -1631,16 +1635,15 @@ namespace Ogre return mVaoManager; } //----------------------------------------------------------------------------------- - void TextureGpuManager::scheduleLoadRequest( TextureGpu *texture, - const String &name, - const String &resourceGroup, - uint32 filters, - Image2 *image, - bool autoDeleteImage, - bool toSysRam, - bool skipMetadataCache, + void TextureGpuManager::scheduleLoadRequest( TextureGpu *texture, const String &name, + const String &resourceGroup, uint32 filters, + Image2 *image, bool autoDeleteImage, bool toSysRam, + bool reuploadOnly, bool skipMetadataCache, uint32 sliceOrDepth ) { + // These two can't be true at the same time + OGRE_ASSERT_MEDIUM( !( toSysRam && reuploadOnly ) ); + Archive *archive = 0; ResourceLoadingListener *loadingListener = 0; if( resourceGroup != BLANKSTRING ) @@ -1658,7 +1661,7 @@ namespace Ogre archive = resourceGroupManager._getArchiveToResource( name, resourceGroup ); } - if( !skipMetadataCache && !toSysRam && + if( !skipMetadataCache && !toSysRam && !reuploadOnly && texture->getGpuPageOutStrategy() != GpuPageOutStrategy::AlwaysKeepSystemRamCopy ) { bool metadataSuccess = applyMetadataCacheTo( texture ); @@ -1677,10 +1680,29 @@ namespace Ogre mWorkerWaitableEvent.wake(); } //----------------------------------------------------------------------------------- + void TextureGpuManager::_scheduleUpdate( TextureGpu *texture, uint32 filters, Image2 *image, bool autoDeleteImage, + bool skipMetadataCache, + uint32 sliceOrDepth ) + { + Archive *archive = 0; + ResourceLoadingListener *loadingListener = 0; + + mAddedNewLoadRequests = true; + mAddedNewLoadRequestsSinceWaitingForStreamingCompletion = true; + ThreadData &mainData = mThreadData[c_mainThread]; + mLoadRequestsMutex.lock(); + mainData.loadRequests.push_back( LoadRequest( "", archive, loadingListener, image, + texture, sliceOrDepth, filters, + autoDeleteImage, false ) ); + mLoadRequestsMutex.unlock(); + mWorkerWaitableEvent.wake(); + } + //----------------------------------------------------------------------------------- void TextureGpuManager::scheduleLoadRequest( TextureGpu *texture, Image2 *image, - bool autoDeleteImage, bool toSysRam ) + bool autoDeleteImage, bool toSysRam, bool reuploadOnly ) { - OGRE_ASSERT_LOW( texture->getResidencyStatus() == GpuResidency::OnStorage ); + OGRE_ASSERT_LOW( ( texture->getResidencyStatus() == GpuResidency::OnStorage && !reuploadOnly ) || + ( texture->getResidencyStatus() == GpuResidency::Resident && reuploadOnly ) ); String name, resourceGroup; uint32 filters = 0; @@ -1695,7 +1717,7 @@ namespace Ogre if( texture->getTextureType() != TextureTypes::TypeCube ) { scheduleLoadRequest( texture, name, resourceGroup, filters, - image, autoDeleteImage, toSysRam ); + image, autoDeleteImage, toSysRam, reuploadOnly ); } else { @@ -1720,7 +1742,7 @@ namespace Ogre // XX HACK there should be a better way to specify whether // all faces are in the same file or not scheduleLoadRequest( texture, name, resourceGroup, filters, - image, autoDeleteImage, toSysRam ); + image, autoDeleteImage, toSysRam, reuploadOnly ); } else { @@ -1729,9 +1751,9 @@ namespace Ogre for( uint32 i=0; i<6u; ++i ) { const bool skipMetadataCache = i != 0; - scheduleLoadRequest( texture, baseName + suffixes[i] + ext, - resourceGroup, filters, i == 0 ? image : 0, - autoDeleteImage, toSysRam, skipMetadataCache, i ); + scheduleLoadRequest( texture, baseName + suffixes[i] + ext, resourceGroup, filters, + i == 0 ? image : 0, autoDeleteImage, toSysRam, reuploadOnly, + skipMetadataCache, i ); } } } @@ -1796,16 +1818,18 @@ namespace Ogre //----------------------------------------------------------------------------------- void TextureGpuManager::_scheduleTransitionTo( TextureGpu *texture, GpuResidency::GpuResidency targetResidency, - Image2 *image, bool autoDeleteImage ) + Image2 *image, bool autoDeleteImage, + bool reuploadOnly ) { ScheduledTasks task; task.tasksType = TaskTypeResidencyTransition; - task.residencyTransitionTask.init( targetResidency, image, autoDeleteImage ); + task.residencyTransitionTask.init( targetResidency, image, autoDeleteImage, reuploadOnly ); //getPendingResidencyChanges should be > 1 because it gets incremented by caller - OGRE_ASSERT_MEDIUM( texture->getPendingResidencyChanges() != 0u ); + OGRE_ASSERT_MEDIUM( texture->getPendingResidencyChanges() != 0u || reuploadOnly ); - if( texture->getPendingResidencyChanges() == 1u || mIgnoreScheduledTasks ) + if( texture->getPendingResidencyChanges() == 1u || + ( reuploadOnly && texture->getPendingResidencyChanges() == 0u ) || mIgnoreScheduledTasks ) { //If we're here, there are no pending tasks that will perform further work //on the texture (with one exception: if _isDataReadyImpl does not return true; which diff --git a/RenderSystems/Direct3D11/src/OgreD3D11TextureGpu.cpp b/RenderSystems/Direct3D11/src/OgreD3D11TextureGpu.cpp index c58443da1a7..86e8de4a3a9 100644 --- a/RenderSystems/Direct3D11/src/OgreD3D11TextureGpu.cpp +++ b/RenderSystems/Direct3D11/src/OgreD3D11TextureGpu.cpp @@ -364,6 +364,11 @@ namespace Ogre assert( mResidencyStatus == GpuResidency::Resident ); assert( mFinalTextureName || mPixelFormat == PFG_NULL ); + OGRE_ASSERT_LOW( mDataPreparationsPending > 0u && + "Calling notifyDataIsReady too often! Remove this call" + "See https://github.com/OGRECave/ogre-next/issues/101" ); + --mDataPreparationsPending; + mDefaultDisplaySrv.Reset(); mDisplayTextureName = mFinalTextureName.Get(); @@ -379,7 +384,7 @@ namespace Ogre //----------------------------------------------------------------------------------- bool D3D11TextureGpu::_isDataReadyImpl(void) const { - return mDisplayTextureName == mFinalTextureName.Get(); + return mDisplayTextureName == mFinalTextureName.Get() && mDataPreparationsPending == 0u; } //----------------------------------------------------------------------------------- void D3D11TextureGpu::_setToDisplayDummyTexture(void) diff --git a/RenderSystems/Direct3D11/src/OgreD3D11TextureGpuWindow.cpp b/RenderSystems/Direct3D11/src/OgreD3D11TextureGpuWindow.cpp index f0622401724..2f48c234f44 100644 --- a/RenderSystems/Direct3D11/src/OgreD3D11TextureGpuWindow.cpp +++ b/RenderSystems/Direct3D11/src/OgreD3D11TextureGpuWindow.cpp @@ -76,6 +76,10 @@ namespace Ogre void D3D11TextureGpuWindow::notifyDataIsReady(void) { assert( mResidencyStatus == GpuResidency::Resident ); + OGRE_ASSERT_LOW( mDataPreparationsPending > 0u && + "Calling notifyDataIsReady too often! Remove this call" + "See https://github.com/OGRECave/ogre-next/issues/101" ); + --mDataPreparationsPending; notifyAllListenersTextureChanged( TextureGpuListener::ReadyForRendering ); } //----------------------------------------------------------------------------------- diff --git a/RenderSystems/GL3Plus/src/OgreGL3PlusTextureGpu.cpp b/RenderSystems/GL3Plus/src/OgreGL3PlusTextureGpu.cpp index 4b867b23acc..c9a1147b188 100644 --- a/RenderSystems/GL3Plus/src/OgreGL3PlusTextureGpu.cpp +++ b/RenderSystems/GL3Plus/src/OgreGL3PlusTextureGpu.cpp @@ -241,6 +241,11 @@ namespace Ogre assert( mResidencyStatus == GpuResidency::Resident ); assert( mFinalTextureName || mPixelFormat == PFG_NULL ); + OGRE_ASSERT_LOW( mDataPreparationsPending > 0u && + "Calling notifyDataIsReady too often! Remove this call" + "See https://github.com/OGRECave/ogre-next/issues/101" ); + --mDataPreparationsPending; + mDisplayTextureName = mFinalTextureName; notifyAllListenersTextureChanged( TextureGpuListener::ReadyForRendering ); @@ -248,7 +253,7 @@ namespace Ogre //----------------------------------------------------------------------------------- bool GL3PlusTextureGpu::_isDataReadyImpl(void) const { - return mDisplayTextureName == mFinalTextureName; + return mDisplayTextureName == mFinalTextureName && mDataPreparationsPending == 0u; } //----------------------------------------------------------------------------------- void GL3PlusTextureGpu::_setToDisplayDummyTexture(void) diff --git a/RenderSystems/GL3Plus/src/OgreGL3PlusTextureGpuWindow.cpp b/RenderSystems/GL3Plus/src/OgreGL3PlusTextureGpuWindow.cpp index a90ded1d183..c61038d75ca 100644 --- a/RenderSystems/GL3Plus/src/OgreGL3PlusTextureGpuWindow.cpp +++ b/RenderSystems/GL3Plus/src/OgreGL3PlusTextureGpuWindow.cpp @@ -74,6 +74,10 @@ namespace Ogre void GL3PlusTextureGpuWindow::notifyDataIsReady(void) { assert( mResidencyStatus == GpuResidency::Resident ); + OGRE_ASSERT_LOW( mDataPreparationsPending > 0u && + "Calling notifyDataIsReady too often! Remove this call" + "See https://github.com/OGRECave/ogre-next/issues/101" ); + --mDataPreparationsPending; notifyAllListenersTextureChanged( TextureGpuListener::ReadyForRendering ); } //----------------------------------------------------------------------------------- diff --git a/RenderSystems/Metal/src/OgreMetalTextureGpu.mm b/RenderSystems/Metal/src/OgreMetalTextureGpu.mm index c3d92cf287d..f587faac229 100644 --- a/RenderSystems/Metal/src/OgreMetalTextureGpu.mm +++ b/RenderSystems/Metal/src/OgreMetalTextureGpu.mm @@ -183,6 +183,11 @@ of this software and associated documentation files (the "Software"), to deal assert( mResidencyStatus == GpuResidency::Resident ); assert( mFinalTextureName || mPixelFormat == PFG_NULL ); + OGRE_ASSERT_LOW( mDataPreparationsPending > 0u && + "Calling notifyDataIsReady too often! Remove this call" + "See https://github.com/OGRECave/ogre-next/issues/101" ); + --mDataPreparationsPending; + mDisplayTextureName = mFinalTextureName; notifyAllListenersTextureChanged( TextureGpuListener::ReadyForRendering ); @@ -190,7 +195,7 @@ of this software and associated documentation files (the "Software"), to deal //----------------------------------------------------------------------------------- bool MetalTextureGpu::_isDataReadyImpl(void) const { - return mDisplayTextureName == mFinalTextureName; + return mDisplayTextureName == mFinalTextureName && mDataPreparationsPending == 0u; } //----------------------------------------------------------------------------------- void MetalTextureGpu::_setToDisplayDummyTexture(void) diff --git a/RenderSystems/Metal/src/OgreMetalTextureGpuWindow.mm b/RenderSystems/Metal/src/OgreMetalTextureGpuWindow.mm index 0f7e080c57f..1f389b70f87 100644 --- a/RenderSystems/Metal/src/OgreMetalTextureGpuWindow.mm +++ b/RenderSystems/Metal/src/OgreMetalTextureGpuWindow.mm @@ -72,6 +72,10 @@ of this software and associated documentation files (the "Software"), to deal void MetalTextureGpuWindow::notifyDataIsReady(void) { assert( mResidencyStatus == GpuResidency::Resident ); + OGRE_ASSERT_LOW( mDataPreparationsPending > 0u && + "Calling notifyDataIsReady too often! Remove this call" + "See https://github.com/OGRECave/ogre-next/issues/101" ); + --mDataPreparationsPending; notifyAllListenersTextureChanged( TextureGpuListener::ReadyForRendering ); } //----------------------------------------------------------------------------------- diff --git a/RenderSystems/NULL/src/OgreNULLTextureGpu.cpp b/RenderSystems/NULL/src/OgreNULLTextureGpu.cpp index 85820ca7411..471baab877c 100644 --- a/RenderSystems/NULL/src/OgreNULLTextureGpu.cpp +++ b/RenderSystems/NULL/src/OgreNULLTextureGpu.cpp @@ -63,6 +63,10 @@ namespace Ogre //----------------------------------------------------------------------------------- void NULLTextureGpu::notifyDataIsReady(void) { + OGRE_ASSERT_LOW( mDataPreparationsPending > 0u && + "Calling notifyDataIsReady too often! Remove this call" + "See https://github.com/OGRECave/ogre-next/issues/101" ); + --mDataPreparationsPending; } //----------------------------------------------------------------------------------- void NULLTextureGpu::_autogenerateMipmaps( CopyEncTransitionMode::CopyEncTransitionMode @@ -76,7 +80,7 @@ namespace Ogre //----------------------------------------------------------------------------------- bool NULLTextureGpu::_isDataReadyImpl(void) const { - return true; + return true && mDataPreparationsPending == 0u; } //----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- diff --git a/RenderSystems/Vulkan/src/OgreVulkanTextureGpu.cpp b/RenderSystems/Vulkan/src/OgreVulkanTextureGpu.cpp index 25a2ac9e58c..8893ae19527 100644 --- a/RenderSystems/Vulkan/src/OgreVulkanTextureGpu.cpp +++ b/RenderSystems/Vulkan/src/OgreVulkanTextureGpu.cpp @@ -301,6 +301,11 @@ namespace Ogre mOwnsSrv = false; } + OGRE_ASSERT_LOW( mDataPreparationsPending > 0u && + "Calling notifyDataIsReady too often! Remove this call" + "See https://github.com/OGRECave/ogre-next/issues/101" ); + --mDataPreparationsPending; + mDisplayTextureName = mFinalTextureName; if( isTexture() ) @@ -326,7 +331,7 @@ namespace Ogre //----------------------------------------------------------------------------------- bool VulkanTextureGpu::_isDataReadyImpl( void ) const { - return mDisplayTextureName == mFinalTextureName; + return mDisplayTextureName == mFinalTextureName && mDataPreparationsPending == 0u; } //----------------------------------------------------------------------------------- void VulkanTextureGpu::_setToDisplayDummyTexture( void ) diff --git a/RenderSystems/Vulkan/src/OgreVulkanTextureGpuWindow.cpp b/RenderSystems/Vulkan/src/OgreVulkanTextureGpuWindow.cpp index 68cd8bd45fd..0f1879be9a1 100644 --- a/RenderSystems/Vulkan/src/OgreVulkanTextureGpuWindow.cpp +++ b/RenderSystems/Vulkan/src/OgreVulkanTextureGpuWindow.cpp @@ -94,6 +94,10 @@ namespace Ogre void VulkanTextureGpuWindow::notifyDataIsReady( void ) { assert( mResidencyStatus == GpuResidency::Resident ); + OGRE_ASSERT_LOW( mDataPreparationsPending > 0u && + "Calling notifyDataIsReady too often! Remove this call" + "See https://github.com/OGRECave/ogre-next/issues/101" ); + --mDataPreparationsPending; notifyAllListenersTextureChanged( TextureGpuListener::ReadyForRendering ); } //----------------------------------------------------------------------------------- diff --git a/Samples/2.0/Showcase/Postprocessing/PostprocessingGameState.cpp b/Samples/2.0/Showcase/Postprocessing/PostprocessingGameState.cpp index a980b303c16..5c7cbdc3918 100644 --- a/Samples/2.0/Showcase/Postprocessing/PostprocessingGameState.cpp +++ b/Samples/2.0/Showcase/Postprocessing/PostprocessingGameState.cpp @@ -110,7 +110,6 @@ namespace Demo stagingTexture->stopMapRegion(); stagingTexture->upload( texBox, tex, 0, 0, 0, true ); - tex->notifyDataIsReady(); textureManager->removeStagingTexture( stagingTexture ); stagingTexture = 0; @@ -149,7 +148,6 @@ namespace Demo stagingTexture->stopMapRegion(); stagingTexture->upload( texBox, tex, 0, 0, 0, true ); - tex->notifyDataIsReady(); textureManager->removeStagingTexture( stagingTexture ); stagingTexture = 0; diff --git a/Samples/2.0/Tutorials/Tutorial_SSAO/Tutorial_SSAOGameState.cpp b/Samples/2.0/Tutorials/Tutorial_SSAO/Tutorial_SSAOGameState.cpp index dd0bf8bc78f..213fb890f92 100644 --- a/Samples/2.0/Tutorials/Tutorial_SSAO/Tutorial_SSAOGameState.cpp +++ b/Samples/2.0/Tutorials/Tutorial_SSAO/Tutorial_SSAOGameState.cpp @@ -284,7 +284,6 @@ namespace Demo stagingTexture->upload( texBox, noiseTexture, 0, 0, 0 ); textureManager->removeStagingTexture( stagingTexture ); stagingTexture = 0; - noiseTexture->notifyDataIsReady(); //--------------------------------------------------------------------------------- //Get GpuProgramParametersSharedPtr to set uniforms that we need diff --git a/Samples/2.0/Tutorials/Tutorial_Terrain/src/Terra/Terra.cpp b/Samples/2.0/Tutorials/Tutorial_Terrain/src/Terra/Terra.cpp index ba7d54f21cb..f6ad2a932a9 100644 --- a/Samples/2.0/Tutorials/Tutorial_Terrain/src/Terra/Terra.cpp +++ b/Samples/2.0/Tutorials/Tutorial_Terrain/src/Terra/Terra.cpp @@ -132,8 +132,6 @@ namespace Ogre stagingTexture->upload( texBox, m_heightMapTex, 0, 0, 0 ); textureManager->removeStagingTexture( stagingTexture ); stagingTexture = 0; - - m_heightMapTex->notifyDataIsReady(); } //----------------------------------------------------------------------------------- void Terra::createHeightmap( Image2 &image, const String &imageName, @@ -227,7 +225,6 @@ namespace Ogre m_normalMapTex->setPixelFormat( PFG_RGBA8_UNORM ); } m_normalMapTex->scheduleTransitionTo( GpuResidency::Resident ); - m_normalMapTex->notifyDataIsReady(); Ogre::TextureGpu *tmpRtt = TerraSharedResources::getTempTexture( "TMP NormalMapTex_", getId(), m_sharedResources, TerraSharedResources::TmpNormalMap,