From bda92ed352643ddc0ddfef429b575a3bbca89383 Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Sun, 2 Feb 2020 22:33:58 +0100 Subject: [PATCH] Main: add lightweight DefaultBuffer class for shadow buffering --- .../OgreDefaultHardwareBufferManager.h | 16 ++++ OgreMain/include/OgreHardwareBuffer.h | 82 +++++++------------ .../src/OgreDefaultHardwareBufferManager.cpp | 33 ++++++++ OgreMain/src/OgreHardwareIndexBuffer.cpp | 3 +- OgreMain/src/OgreHardwareUniformBuffer.cpp | 2 +- OgreMain/src/OgreHardwareVertexBuffer.cpp | 3 +- .../include/OgreD3D11HardwareBuffer.h | 2 +- .../src/OgreD3D11HardwareBuffer.cpp | 2 +- 8 files changed, 84 insertions(+), 59 deletions(-) diff --git a/OgreMain/include/OgreDefaultHardwareBufferManager.h b/OgreMain/include/OgreDefaultHardwareBufferManager.h index 22092efb8eef..5ac7e3756916 100644 --- a/OgreMain/include/OgreDefaultHardwareBufferManager.h +++ b/OgreMain/include/OgreDefaultHardwareBufferManager.h @@ -43,6 +43,22 @@ namespace Ogre { * @{ */ + /// Specialisation of Buffer using malloc e.g. for use as shadow buffer + class _OgreExport DefaultBuffer : public Buffer + { + protected: + unsigned char* mData; + void* lockImpl(size_t offset, size_t length, LockOptions options); + void unlockImpl(void); + public: + explicit DefaultBuffer(size_t sizeInBytes); + ~DefaultBuffer(); + void readData(size_t offset, size_t length, void* pDest); + void writeData(size_t offset, size_t length, const void* pSource, bool discardWholeBuffer = false); + void* lock(size_t offset, size_t length, LockOptions options); + void unlock(void); + }; + /// Specialisation of HardwareVertexBuffer for emulation class _OgreExport DefaultHardwareVertexBuffer : public HardwareVertexBuffer { diff --git a/OgreMain/include/OgreHardwareBuffer.h b/OgreMain/include/OgreHardwareBuffer.h index b48f3e7744aa..1cdb0f3aaa6a 100644 --- a/OgreMain/include/OgreHardwareBuffer.h +++ b/OgreMain/include/OgreHardwareBuffer.h @@ -122,7 +122,7 @@ namespace Ogre { HBL_WRITE_ONLY }; - Buffer(size_t sizeInBytes, int usage) : mSizeInBytes(sizeInBytes), mUsage(usage) {} + Buffer(size_t sizeInBytes, int usage) : mSizeInBytes(sizeInBytes), mUsage(usage), mIsLocked(false) {} virtual ~Buffer() {} /** Reads data from the buffer and places it in the memory pointed to by pDest. @@ -131,7 +131,7 @@ namespace Ogre { @param pDest The area of memory in which to place the data, must be large enough to accommodate the data! */ - virtual void readData(size_t offset, size_t length, void* pDest) = 0; + virtual void readData(size_t offset, size_t length, void* pDest) /* const */ = 0; /** Writes data to the buffer from an area of system memory; note that you must ensure that your buffer is big enough. @param offset The byte offset from the start of the buffer to start writing @@ -152,8 +152,26 @@ namespace Ogre { @param length Length of the data to copy, in bytes. @param discardWholeBuffer If true, will discard the entire contents of this buffer before copying */ - virtual void copyData(HardwareBuffer& srcBuffer, size_t srcOffset, size_t dstOffset, size_t length, - bool discardWholeBuffer = false) = 0; + virtual void copyData(HardwareBuffer& _srcBuffer, size_t srcOffset, size_t dstOffset, size_t length, + bool discardWholeBuffer = false) + { + auto& srcBuffer = (Buffer&)_srcBuffer; // backward compat + const void* srcData = srcBuffer.lock(srcOffset, length, HBL_READ_ONLY); + this->writeData(dstOffset, length, srcData, discardWholeBuffer); + srcBuffer.unlock(); + } + + /** Copy all data from another buffer into this one. + @remarks + Normally these buffers should be of identical size, but if they're + not, the routine will use the smallest of the two sizes. + */ + void copyData(HardwareBuffer& _srcBuffer) + { + auto& srcBuffer = (Buffer&)_srcBuffer; // backward compat + size_t sz = std::min(getSizeInBytes(), srcBuffer.getSizeInBytes()); + copyData(_srcBuffer, 0, 0, sz, true); + } /** Lock the buffer for (potentially) reading / writing. @param offset The byte offset from the start of the buffer to lock @@ -181,8 +199,7 @@ namespace Ogre { virtual void unlock() = 0; /// Returns whether or not this buffer is currently locked. - virtual bool isLocked() const = 0; - + virtual bool isLocked() const { return mIsLocked; } /// Returns the size of this buffer in bytes size_t getSizeInBytes(void) const { return mSizeInBytes; } /// Returns the Usage flags with which this buffer was created @@ -190,6 +207,7 @@ namespace Ogre { protected: size_t mSizeInBytes; int mUsage; + bool mIsLocked; }; @@ -248,10 +266,9 @@ namespace Ogre { HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE = HBU_CPU_TO_GPU, }; protected: - bool mIsLocked; size_t mLockStart; size_t mLockSize; - std::unique_ptr mShadowBuffer; + std::unique_ptr mShadowBuffer; bool mSystemMemory; bool mUseShadowBuffer; bool mShadowUpdated; @@ -265,7 +282,7 @@ namespace Ogre { public: /// Constructor, to be called by HardwareBufferManager only HardwareBuffer(Usage usage, bool systemMemory, bool useShadowBuffer) - : Buffer(0, usage), mIsLocked(false), mLockStart(0), mLockSize(0), mSystemMemory(systemMemory), + : Buffer(0, usage), mLockStart(0), mLockSize(0), mSystemMemory(systemMemory), mUseShadowBuffer(useShadowBuffer), mShadowUpdated(false), mSuppressHardwareUpdate(false) { @@ -330,57 +347,18 @@ namespace Ogre { } - /** Copy data from another buffer into this one. - @remarks - Note that the source buffer must not be created with the - usage HBU_WRITE_ONLY otherwise this will fail. - @param srcBuffer The buffer from which to read the copied data - @param srcOffset Offset in the source buffer at which to start reading - @param dstOffset Offset in the destination buffer to start writing - @param length Length of the data to copy, in bytes. - @param discardWholeBuffer If true, will discard the entire contents of this buffer before copying - */ - void copyData(HardwareBuffer& srcBuffer, size_t srcOffset, size_t dstOffset, size_t length, - bool discardWholeBuffer = false) override - { - const void *srcData = srcBuffer.lock( - srcOffset, length, HBL_READ_ONLY); - this->writeData(dstOffset, length, srcData, discardWholeBuffer); - srcBuffer.unlock(); - } - - /** Copy all data from another buffer into this one. - @remarks - Normally these buffers should be of identical size, but if they're - not, the routine will use the smallest of the two sizes. - */ - virtual void copyData(HardwareBuffer& srcBuffer) - { - size_t sz = std::min(getSizeInBytes(), srcBuffer.getSizeInBytes()); - copyData(srcBuffer, 0, 0, sz, true); - } - /// Updates the real buffer from the shadow buffer, if required virtual void _updateFromShadow(void) { if (mUseShadowBuffer && mShadowUpdated && !mSuppressHardwareUpdate) { - // Do this manually to avoid locking problems - const void *srcData = mShadowBuffer->lockImpl( - mLockStart, mLockSize, HBL_READ_ONLY); // Lock with discard if the whole buffer was locked, otherwise w/o - LockOptions lockOpt; - if (mLockStart == 0 && mLockSize == mSizeInBytes) - lockOpt = HBL_DISCARD; - else - lockOpt = HBL_WRITE_ONLY; - - void *destData = this->lockImpl( - mLockStart, mLockSize, lockOpt); + LockOptions lockOpt = mLockSize == mSizeInBytes ? HBL_DISCARD : HBL_WRITE_ONLY; + // Do this manually to avoid locking problems + void* destData = this->lockImpl(mLockStart, mLockSize, lockOpt); // Copy shadow to real - memcpy(destData, srcData, mLockSize); + mShadowBuffer->readData(mLockStart, mLockSize, destData); this->unlockImpl(); - mShadowBuffer->unlockImpl(); mShadowUpdated = false; } } diff --git a/OgreMain/src/OgreDefaultHardwareBufferManager.cpp b/OgreMain/src/OgreDefaultHardwareBufferManager.cpp index 451f89cbd1e5..f9376a2ccc87 100644 --- a/OgreMain/src/OgreDefaultHardwareBufferManager.cpp +++ b/OgreMain/src/OgreDefaultHardwareBufferManager.cpp @@ -29,6 +29,39 @@ THE SOFTWARE. #include "OgreDefaultHardwareBufferManager.h" namespace Ogre { + DefaultBuffer::DefaultBuffer(size_t sizeInBytes) + : Buffer(sizeInBytes, HBU_CPU_ONLY) + { + // Allocate aligned memory for better SIMD processing friendly. + mData = static_cast(AlignedMemory::allocate(mSizeInBytes)); + } + //----------------------------------------------------------------------- + DefaultBuffer::~DefaultBuffer() { AlignedMemory::deallocate(mData); } + //----------------------------------------------------------------------- + void* DefaultBuffer::lockImpl(size_t offset, size_t length, LockOptions options) { return mData + offset; } + //----------------------------------------------------------------------- + void DefaultBuffer::unlockImpl() {} + //----------------------------------------------------------------------- + void* DefaultBuffer::lock(size_t offset, size_t length, LockOptions options) + { + mIsLocked = true; + return mData + offset; + } + void DefaultBuffer::unlock(void) { mIsLocked = false; } + //----------------------------------------------------------------------- + void DefaultBuffer::readData(size_t offset, size_t length, void* pDest) + { + assert((offset + length) <= mSizeInBytes); + memcpy(pDest, mData + offset, length); + } + //----------------------------------------------------------------------- + void DefaultBuffer::writeData(size_t offset, size_t length, const void* pSource, bool discardWholeBuffer) + { + assert((offset + length) <= mSizeInBytes); + // ignore discard, memory is not guaranteed to be zeroised + memcpy(mData + offset, pSource, length); + } + DefaultHardwareVertexBuffer::DefaultHardwareVertexBuffer(size_t vertexSize, size_t numVertices, HardwareBuffer::Usage usage) diff --git a/OgreMain/src/OgreHardwareIndexBuffer.cpp b/OgreMain/src/OgreHardwareIndexBuffer.cpp index f62b2fcf301d..1b8b3fdb301f 100644 --- a/OgreMain/src/OgreHardwareIndexBuffer.cpp +++ b/OgreMain/src/OgreHardwareIndexBuffer.cpp @@ -56,8 +56,7 @@ namespace Ogre { // Create a shadow buffer if required if (mUseShadowBuffer) { - mShadowBuffer.reset(new DefaultHardwareIndexBuffer(mIndexType, - mNumIndexes, HardwareBuffer::HBU_DYNAMIC)); + mShadowBuffer.reset(new DefaultBuffer(mSizeInBytes)); } diff --git a/OgreMain/src/OgreHardwareUniformBuffer.cpp b/OgreMain/src/OgreHardwareUniformBuffer.cpp index 1d835e20a7e0..3a90ed772cb3 100644 --- a/OgreMain/src/OgreHardwareUniformBuffer.cpp +++ b/OgreMain/src/OgreHardwareUniformBuffer.cpp @@ -44,7 +44,7 @@ namespace Ogre { // Create a shadow buffer if required if (mUseShadowBuffer) { - mShadowBuffer.reset(new DefaultHardwareUniformBuffer(mMgr, sizeBytes, HardwareBuffer::HBU_DYNAMIC, false)); + mShadowBuffer.reset(new DefaultBuffer(sizeBytes)); } } diff --git a/OgreMain/src/OgreHardwareVertexBuffer.cpp b/OgreMain/src/OgreHardwareVertexBuffer.cpp index 67c0c2a62fed..9189da3c83ab 100644 --- a/OgreMain/src/OgreHardwareVertexBuffer.cpp +++ b/OgreMain/src/OgreHardwareVertexBuffer.cpp @@ -48,8 +48,7 @@ namespace Ogre { // Create a shadow buffer if required if (mUseShadowBuffer) { - mShadowBuffer.reset(new DefaultHardwareVertexBuffer(mMgr, mVertexSize, - mNumVertices, HardwareBuffer::HBU_DYNAMIC)); + mShadowBuffer.reset(new DefaultBuffer(mSizeInBytes)); } } diff --git a/RenderSystems/Direct3D11/include/OgreD3D11HardwareBuffer.h b/RenderSystems/Direct3D11/include/OgreD3D11HardwareBuffer.h index 4a0446e7ee3b..a77ff347afc5 100644 --- a/RenderSystems/Direct3D11/include/OgreD3D11HardwareBuffer.h +++ b/RenderSystems/Direct3D11/include/OgreD3D11HardwareBuffer.h @@ -74,7 +74,7 @@ namespace Ogre { /** See HardwareBuffer. We perform a hardware copy here. */ void copyData(HardwareBuffer& srcBuffer, size_t srcOffset, size_t dstOffset, size_t length, bool discardWholeBuffer = false); - void copyDataImpl(HardwareBuffer& srcBuffer, size_t srcOffset, + void copyDataImpl(Buffer& srcBuffer, size_t srcOffset, size_t dstOffset, size_t length, bool discardWholeBuffer = false); /// Updates the real buffer from the shadow buffer, if required virtual void _updateFromShadow(void); diff --git a/RenderSystems/Direct3D11/src/OgreD3D11HardwareBuffer.cpp b/RenderSystems/Direct3D11/src/OgreD3D11HardwareBuffer.cpp index 1255dfa66314..eff6c5eaf5b2 100644 --- a/RenderSystems/Direct3D11/src/OgreD3D11HardwareBuffer.cpp +++ b/RenderSystems/Direct3D11/src/OgreD3D11HardwareBuffer.cpp @@ -213,7 +213,7 @@ namespace Ogre { copyDataImpl(srcBuffer, srcOffset, dstOffset, length, discardWholeBuffer); } //--------------------------------------------------------------------- - void D3D11HardwareBuffer::copyDataImpl(HardwareBuffer& srcBuffer, size_t srcOffset, + void D3D11HardwareBuffer::copyDataImpl(Buffer& srcBuffer, size_t srcOffset, size_t dstOffset, size_t length, bool discardWholeBuffer) { // If we're copying same-size buffers in their entirety...