Skip to content

Commit

Permalink
Main: add lightweight DefaultBuffer class for shadow buffering
Browse files Browse the repository at this point in the history
  • Loading branch information
paroj committed Feb 8, 2020
1 parent 8aa3028 commit 5bddef5
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 59 deletions.
16 changes: 16 additions & 0 deletions OgreMain/include/OgreDefaultHardwareBufferManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
82 changes: 30 additions & 52 deletions OgreMain/include/OgreHardwareBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ namespace Ogre {
HBL_WRITE_ONLY

};
Buffer(size_t sizeInBytes, Usage usage) : mSizeInBytes(sizeInBytes), mUsage(usage) {}
Buffer(size_t sizeInBytes, Usage usage) : mSizeInBytes(sizeInBytes), mUsage(usage), mIsLocked(false) {}

virtual ~Buffer() {}
/** Reads data from the buffer and places it in the memory pointed to by pDest.
Expand All @@ -152,7 +152,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
Expand All @@ -173,8 +173,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
Expand Down Expand Up @@ -202,15 +220,15 @@ 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
Usage getUsage(void) const { return mUsage; }
protected:
size_t mSizeInBytes;
Usage mUsage;
bool mIsLocked;
};

/** Abstract class defining common features of hardware buffers.
Expand Down Expand Up @@ -247,10 +265,9 @@ namespace Ogre {
class _OgreExport HardwareBuffer : public Buffer
{
protected:
bool mIsLocked;
size_t mLockStart;
size_t mLockSize;
std::unique_ptr<HardwareBuffer> mShadowBuffer;
std::unique_ptr<Buffer> mShadowBuffer;
bool mSystemMemory;
bool mUseShadowBuffer;
bool mShadowUpdated;
Expand All @@ -264,7 +281,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)
{
Expand Down Expand Up @@ -333,58 +350,19 @@ 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;
}
}
Expand Down
33 changes: 33 additions & 0 deletions OgreMain/src/OgreDefaultHardwareBufferManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,39 @@ THE SOFTWARE.
#include "OgreDefaultHardwareBufferManager.h"

namespace Ogre {
DefaultBuffer::DefaultBuffer(size_t sizeInBytes)
: Buffer(sizeInBytes, HBU_DYNAMIC)
{
// Allocate aligned memory for better SIMD processing friendly.
mData = static_cast<unsigned char*>(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)
Expand Down
3 changes: 1 addition & 2 deletions OgreMain/src/OgreHardwareIndexBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}


Expand Down
2 changes: 1 addition & 1 deletion OgreMain/src/OgreHardwareUniformBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}

Expand Down
3 changes: 1 addition & 2 deletions OgreMain/src/OgreHardwareVertexBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

}
Expand Down
2 changes: 1 addition & 1 deletion RenderSystems/Direct3D11/include/OgreD3D11HardwareBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion RenderSystems/Direct3D11/src/OgreD3D11HardwareBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,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...
Expand Down

0 comments on commit 5bddef5

Please sign in to comment.