1. Don't lock-unlock Graphics::Memory for each properties.
This patch lock stand-alone uniform buffer map and unlock only few times during rendering.
(We called this API as ReadyToLockUniformBuffer and UnlockUniformBuffer)
It will reduce Renderer::Render time near 6%
2. Don't convert from std::string_vew to std::string
when we get uniform map info from shader
3. Make BufferPropertiesFlags as input of UniformBuffer Constructor
Change-Id: I50055a24c1aad59e2a29b8c50485254b71ea5b73
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
application.Render();
{
+ const TestGlAbstraction::BufferSubDataCalls& bufferSubDataCalls =
+ application.GetGlAbstraction().GetBufferSubDataCalls();
+
const TestGlAbstraction::BufferDataCalls& bufferDataCalls =
application.GetGlAbstraction().GetBufferDataCalls();
+ // Should be 1 (Flush standalone uniform buffer per each RenderScene)
+ DALI_TEST_EQUALS(bufferSubDataCalls.size(), 1u, TEST_LOCATION);
DALI_TEST_EQUALS(bufferDataCalls.size(), 2u, TEST_LOCATION);
DALI_TEST_EQUALS(bufferDataCalls[0], sizeof(texturedQuadVertexData), TEST_LOCATION);
const TestGlAbstraction::BufferDataCalls& bufferDataCalls =
application.GetGlAbstraction().GetBufferDataCalls();
- // Should be 17 (using single uniform buffer now)
- DALI_TEST_EQUALS(bufferSubDataCalls.size(), 17u, TEST_LOCATION);
+ // Should be 3 (2 Render + 1 vertexBuffer reload)
+ DALI_TEST_EQUALS(bufferSubDataCalls.size(), 3u, TEST_LOCATION);
DALI_TEST_EQUALS(bufferDataCalls.size(), 3u, TEST_LOCATION);
- if(bufferSubDataCalls.size())
+ if(bufferSubDataCalls.size() >= 2)
{
- DALI_TEST_EQUALS(bufferSubDataCalls[0], sizeof(texturedQuadVertexData), TEST_LOCATION);
+ DALI_TEST_EQUALS(bufferSubDataCalls[1], sizeof(texturedQuadVertexData), TEST_LOCATION);
}
}
clippingRect = Rect<int>();
}
+ // Prepare to lock and map standalone uniform buffer.
+ mImpl->uniformBufferManager->ReadyToLockUniformBuffer(mImpl->renderBufferIndex);
+
for(uint32_t i = 0; i < count; ++i)
{
RenderInstruction& instruction = sceneObject->GetRenderInstructions().At(mImpl->renderBufferIndex, i);
}
mainCommandBuffer->EndRenderPass(syncObject);
}
+
+ // Unlock standalone uniform buffer.
+ mImpl->uniformBufferManager->UnlockUniformBuffer(mImpl->renderBufferIndex);
+
mImpl->renderAlgorithms.SubmitCommandBuffer();
std::sort(targetstoPresent.begin(), targetstoPresent.end());
const SceneGraph::CollectedUniformMap& uniformMap = uniformMapDataProvider.GetUniformMap(bufferIndex);
const SceneGraph::CollectedUniformMap& uniformMapNode = node.GetUniformMap(bufferIndex);
- auto maxMaps = static_cast<uint32_t>(uniformMap.Count() + uniformMapNode.Count()); // 4,294,967,295 maps should be enough
- mUniformIndexMap.Clear(); // Clear contents, but keep memory if we don't change size
- mUniformIndexMap.Resize(maxMaps);
+ const uint32_t mapCount = uniformMap.Count();
+ const uint32_t mapNodeCount = uniformMapNode.Count();
+
+ mUniformIndexMap.Clear(); // Clear contents, but keep memory if we don't change size
+ mUniformIndexMap.Resize(mapCount + mapNodeCount);
// Copy uniform map into mUniformIndexMap
uint32_t mapIndex = 0;
- for(; mapIndex < uniformMap.Count(); ++mapIndex)
+ for(; mapIndex < mapCount; ++mapIndex)
{
mUniformIndexMap[mapIndex].propertyValue = uniformMap[mapIndex].propertyPtr;
mUniformIndexMap[mapIndex].uniformName = uniformMap[mapIndex].uniformName;
mUniformIndexMap[mapIndex].arrayIndex = uniformMap[mapIndex].arrayIndex;
}
- for(uint32_t nodeMapIndex = 0; nodeMapIndex < uniformMapNode.Count(); ++nodeMapIndex)
+ for(uint32_t nodeMapIndex = 0; nodeMapIndex < mapNodeCount; ++nodeMapIndex)
{
auto hash = uniformMapNode[nodeMapIndex].uniformNameHash;
auto& name = uniformMapNode[nodeMapIndex].uniformName;
bool found(false);
- for(uint32_t i = 0; i < uniformMap.Count(); ++i)
+ for(uint32_t i = 0; i < mapCount; ++i)
{
if(mUniformIndexMap[i].uniformNameHash == hash &&
mUniformIndexMap[i].uniformName == name)
if(uniformBlockAllocationBytes)
{
auto uboPoolView = mUniformBufferManager->GetUniformBufferViewPool(bufferIndex);
-
- uboView = uboPoolView->CreateUniformBufferView(uniformBlockAllocationBytes);
+ uboView = uboPoolView->CreateUniformBufferView(uniformBlockAllocationBytes);
}
// update the uniform buffer
if(!uniform.uniformFunc)
{
auto uniformInfo = Graphics::UniformInfo{};
- auto uniformFound = program.GetUniform(uniform.uniformName.GetCString(),
+ auto uniformFound = program.GetUniform(uniform.uniformName.GetStringView(),
uniform.uniformNameHash,
uniform.uniformNameHashNoArray,
uniformInfo);
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <dali/internal/render/renderers/uniform-buffer-manager.h>
// INTERNAL INCLUDES
-#include <dali/internal/render/renderers/uniform-buffer.h>
-#include <dali/internal/render/renderers/uniform-buffer-view.h>
#include <dali/internal/render/renderers/uniform-buffer-view-pool.h>
+#include <dali/internal/render/renderers/uniform-buffer-view.h>
+#include <dali/internal/render/renderers/uniform-buffer.h>
#include <dali/graphics-api/graphics-buffer-create-info.h>
#include <dali/graphics-api/graphics-buffer.h>
namespace Dali::Internal::Render
{
-
UniformBufferManager::UniformBufferManager(Dali::Graphics::Controller* controller)
: mController(controller)
{
Graphics::UniquePtr<UniformBuffer> UniformBufferManager::AllocateUniformBuffer(uint32_t size, uint32_t alignment)
{
+ // TODO : Current code only assume CPU_ALLOCATED uniform buffer now
return Graphics::UniquePtr<UniformBuffer>(
- new UniformBuffer(mController, size, alignment, true, Dali::Graphics::BufferUsageFlags{0u} | Dali::Graphics::BufferUsage::TRANSFER_DST | Dali::Graphics::BufferUsage::UNIFORM_BUFFER));
+ new UniformBuffer(mController,
+ size,
+ alignment,
+ Dali::Graphics::BufferUsageFlags{0u} | Dali::Graphics::BufferUsage::TRANSFER_DST | Dali::Graphics::BufferUsage::UNIFORM_BUFFER,
+ Dali::Graphics::BufferPropertiesFlags{0u} | Dali::Graphics::BufferPropertiesFlagBit::CPU_ALLOCATED));
}
-Graphics::UniquePtr<UniformBufferView> UniformBufferManager::CreateUniformBufferView( UniformBuffer* uniformBuffer, uint32_t offset, uint32_t size )
+Graphics::UniquePtr<UniformBufferView> UniformBufferManager::CreateUniformBufferView(UniformBuffer* uniformBuffer, uint32_t offset, uint32_t size)
{
// Allocate offset of given UBO (allocation strategy may reuse memory)
- return Graphics::UniquePtr<UniformBufferView>( new UniformBufferView(*uniformBuffer, offset, size) );
+ return Graphics::UniquePtr<UniformBufferView>(new UniformBufferView(*uniformBuffer, offset, size));
}
Graphics::UniquePtr<UniformBufferViewPool> UniformBufferManager::CreateUniformBufferViewPool()
{
return Graphics::UniquePtr<UniformBufferViewPool>(
- new UniformBufferViewPool( *this, 1 )
- );
+ new UniformBufferViewPool(*this, 1));
}
-[[nodiscard]] UniformBufferViewPool* UniformBufferManager::GetUniformBufferViewPool( uint32_t bufferIndex )
+[[nodiscard]] UniformBufferViewPool* UniformBufferManager::GetUniformBufferViewPool(uint32_t bufferIndex)
{
if(!mUniformBufferPoolStorage[bufferIndex])
{
return mUniformBufferPoolStorage[bufferIndex].get();
}
+void UniformBufferManager::ReadyToLockUniformBuffer(uint32_t bufferIndex)
+{
+ GetUniformBufferViewPool(bufferIndex)->ReadyToLockUniformBuffer();
+}
+
+void UniformBufferManager::UnlockUniformBuffer(uint32_t bufferIndex)
+{
+ GetUniformBufferViewPool(bufferIndex)->UnlockUniformBuffer();
+}
+
} // namespace Dali::Internal::Render
#define DALI_INTERNAL_UNIFORM_BUFFER_MANAGER_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
class UniformBufferManager
{
public:
-
explicit UniformBufferManager(Dali::Graphics::Controller* controller);
~UniformBufferManager();
/**
- * Allocates uniform buffer with given size and alignment
+ * @brief Allocates uniform buffer with given size and alignment
* @param size Size of uniform buffer
* @param alignment Alignment
* @return new UniformBuffer
Graphics::UniquePtr<UniformBuffer> AllocateUniformBuffer(uint32_t size, uint32_t alignment = 256);
/**
- * Creates a view on UniformBuffer
+ * @brief Creates a view on UniformBuffer
*
* @param uniformBuffer
* @param size
* @return Uniform buffer view
*/
- Graphics::UniquePtr<UniformBufferView> CreateUniformBufferView( UniformBuffer* uniformBuffer, uint32_t offset, uint32_t size);
+ Graphics::UniquePtr<UniformBufferView> CreateUniformBufferView(UniformBuffer* uniformBuffer, uint32_t offset, uint32_t size);
/**
- * Creates uniform buffer pool view
+ * @brief Creates uniform buffer pool view
* @param size
* @return
*/
Graphics::UniquePtr<UniformBufferViewPool> CreateUniformBufferViewPool();
/**
- * Returns Controller object
+ * @brief Returns Controller object
* @return controller object
*/
[[nodiscard]] Graphics::Controller& GetController() const
}
/**
- * Returns embedded uniform buffer pool view for specified DAli buffer index
+ * @brief Returns embedded uniform buffer pool view for specified DAli buffer index
* @return Pointer to valid uniform buffer pool view
*/
- [[nodiscard]] UniformBufferViewPool* GetUniformBufferViewPool( uint32_t bufferIndex );
+ [[nodiscard]] UniformBufferViewPool* GetUniformBufferViewPool(uint32_t bufferIndex);
-private:
+ /**
+ * @brief Prepare to lock the uniform buffer so we can write to the standalone uniform map directly.
+ * Uniform buffer will be locked at the first call of UniformBuffer::Write after call this API.
+ * @note After all write done, We should call UnlockUniformBuffer.
+ *
+ * @param bufferIndex current update/render buffer index
+ */
+ void ReadyToLockUniformBuffer(uint32_t bufferIndex);
+ /**
+ * @brief Unlock the uniform buffer.
+ * @note We should call ReadyToLockUniformBuffer before call this.
+ *
+ * @param bufferIndex current update/render buffer index
+ */
+ void UnlockUniformBuffer(uint32_t bufferIndex);
+
+private:
Dali::Graphics::Controller* mController;
Graphics::UniquePtr<UniformBufferViewPool> mUniformBufferPoolStorage[2u]; ///< The pool view into UniformBuffer (double buffered)
};
-} // namespace Dali
+} // namespace Dali::Internal::Render
#endif // DALI_INTERNAL_UNIFORM_BUFFER_MANAGER_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <dali/internal/render/renderers/uniform-buffer-view-pool.h>
// INTERNAL INCLUDES
-#include <dali/internal/render/renderers/uniform-buffer-manager.h>
-#include <dali/internal/render/renderers/uniform-buffer.h>
-#include <dali/internal/render/renderers/uniform-buffer-view.h>
#include <dali/graphics-api/graphics-buffer-create-info.h>
#include <dali/graphics-api/graphics-buffer.h>
+#include <dali/internal/render/renderers/uniform-buffer-manager.h>
+#include <dali/internal/render/renderers/uniform-buffer-view.h>
+#include <dali/internal/render/renderers/uniform-buffer.h>
namespace Dali::Internal::Render
{
{
// Default UBO page size set to 32kb
const uint32_t DEFAULT_UBO_PAGE_SIZE = 32768;
-}
+} // namespace
-UniformBufferViewPool::UniformBufferViewPool( UniformBufferManager& manager, uint32_t alignment ) :
- mUboManager(manager)
+UniformBufferViewPool::UniformBufferViewPool(UniformBufferManager& manager, uint32_t alignment)
+: mUboManager(manager)
{
// Create initial UBO
- mUniformBufferStorage = mUboManager.AllocateUniformBuffer( DEFAULT_UBO_PAGE_SIZE, alignment );
- mAlignment = alignment;
- mCurrentOffset = 0;
+ mUniformBufferStorage = mUboManager.AllocateUniformBuffer(DEFAULT_UBO_PAGE_SIZE, alignment);
+ mAlignment = alignment;
+ mCurrentOffset = 0;
}
UniformBufferViewPool::~UniformBufferViewPool() = default;
// turn buffer into single allocation by resizing it
// to current size with invalidation
auto currentSize = mUniformBufferStorage->GetSize();
- mUniformBufferStorage->Resize( currentSize ? currentSize : DEFAULT_UBO_PAGE_SIZE, true );
+ mUniformBufferStorage->Resize(currentSize ? currentSize : DEFAULT_UBO_PAGE_SIZE, true);
}
-Graphics::UniquePtr<UniformBufferView> UniformBufferViewPool::CreateUniformBufferView( size_t size )
+Graphics::UniquePtr<UniformBufferView> UniformBufferViewPool::CreateUniformBufferView(size_t size)
{
// find new offset
auto newOffset = ((mCurrentOffset + size) / mAlignment) * mAlignment;
}
// resize Ubo if needed
- if( newOffset >= mUniformBufferStorage->GetSize())
+ if(newOffset >= mUniformBufferStorage->GetSize())
{
// move offset to the new buffer
mCurrentOffset = mUniformBufferStorage->GetSize();
- newOffset = ((mCurrentOffset + size) / mAlignment) * mAlignment;
-
- // Adjust current offset so the view doesn't intersect multiple buffers
- auto prevSize = mUniformBufferStorage->GetSize();
- if(mCurrentOffset + size >= prevSize )
+ newOffset = ((mCurrentOffset + size) / mAlignment) * mAlignment;
+ if(mAlignment > 1 && newOffset < mCurrentOffset + size)
{
- mCurrentOffset = prevSize;
- newOffset = ((mCurrentOffset + size) / mAlignment) * mAlignment;
+ newOffset += mAlignment;
}
- mUniformBufferStorage->Resize( mUniformBufferStorage->GetSize()+DEFAULT_UBO_PAGE_SIZE, false );
+
+ size_t increaseBufferStorageSize = DALI_LIKELY(size > 0) ? ((size - 1) / DEFAULT_UBO_PAGE_SIZE + 1) * DEFAULT_UBO_PAGE_SIZE : DEFAULT_UBO_PAGE_SIZE;
+
+ mUniformBufferStorage->Resize(mUniformBufferStorage->GetSize() + increaseBufferStorageSize, false);
}
// create buffer view from
return uboView;
}
+void UniformBufferViewPool::ReadyToLockUniformBuffer()
+{
+ mUniformBufferStorage->ReadyToLockUniformBuffer();
+}
+
+void UniformBufferViewPool::UnlockUniformBuffer()
+{
+ mUniformBufferStorage->UnlockUniformBuffer();
+}
+
} // namespace Dali::Internal::Render
\ No newline at end of file
#define DALI_INTERNAL_UNIFORM_BUFFER_VIEW_POOL_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
namespace Dali::Internal::Render
{
-
class UniformBufferManager;
class UniformBufferView;
class UniformBuffer;
friend class UniformBufferManager;
private:
-
- UniformBufferViewPool( UniformBufferManager& manager, uint32_t alignment );
+ UniformBufferViewPool(UniformBufferManager& manager, uint32_t alignment);
public:
-
~UniformBufferViewPool();
/**
- * Rolls back allocation to the beginning of pool
+ * @brief Rolls back allocation to the beginning of pool
*/
void Rollback();
/**
- * Creates view for next free chunk of UBO memory of specified size.
+ * @brief Creates view for next free chunk of UBO memory of specified size.
*/
- Graphics::UniquePtr<UniformBufferView> CreateUniformBufferView( size_t size );
+ Graphics::UniquePtr<UniformBufferView> CreateUniformBufferView(size_t size);
-private:
+ /**
+ * @copydoc Dali::Internal::Render::UniformBufferManager::ReadyToLockUniformBuffer
+ */
+ void ReadyToLockUniformBuffer();
- UniformBufferManager& mUboManager;
+ /**
+ * @copydoc Dali::Internal::Render::UniformBufferManager::UnlockUniformBuffer
+ */
+ void UnlockUniformBuffer();
+
+private:
+ UniformBufferManager& mUboManager;
Graphics::UniquePtr<UniformBuffer> mUniformBufferStorage;
uint32_t mAlignment; // 1 for tightly packed emulated UBO
#define DALI_INTERNAL_UNIFORM_BUFFER_VIEW_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
}
namespace Internal::Render
{
-
class UniformBuffer;
/**
class UniformBufferView
{
public:
-
- UniformBufferView(UniformBuffer &ubo, uint32_t offset, size_t size);
+ UniformBufferView(UniformBuffer& ubo, uint32_t offset, size_t size);
~UniformBufferView();
- void Write(const void *data, uint32_t size, uint32_t offset);
+ /**
+ * @brief Writes data into the current uniform buffer view.
+ * @note We prefer to call UniformBuffer::ReadyToLockUniformBuffer before call Write API.
+ * And also, prefer to call UniformBuffer::UnlockUniformBuffer if current frame's all Write API action done.
+ *
+ * @param[in] data pointer to the source data
+ * @param[in] size size of source data
+ * @param[in] offset destination offset
+ */
+ void Write(const void* data, uint32_t size, uint32_t offset);
/**
- * Returns the size of the view
+ * @brief Returns the size of the view
*
* @return size of view
*/
}
/**
- * Returns the offset within the UBO
+ * @brief Returns the offset within the UBO
* @return Offset
*/
[[nodiscard]] uint32_t GetOffset() const
}
/**
- * Returns Graphics buffer associated with this View
+ * @brief Returns Graphics buffer associated with this View
*
* If 'relativeOffset' isn't nullptr then the offset into the individual
* Graphics::Buffer is written.
*
* @return Pointer to a valid Graphics::Buffer object
*/
- [[nodiscard]] Graphics::Buffer *GetBuffer(uint32_t *relativeOffset = nullptr);
+ [[nodiscard]] Graphics::Buffer* GetBuffer(uint32_t* relativeOffset = nullptr);
private:
-
- UniformBuffer *mUniformBuffer{nullptr}; ///< UniformBuffer that the view views
- uint32_t mOffset{0u}; ///< Offset within the buffer
- size_t mSize{0u}; ///< Size of view
+ UniformBuffer* mUniformBuffer{nullptr}; ///< UniformBuffer that the view views
+ uint32_t mOffset{0u}; ///< Offset within the buffer
+ size_t mSize{0u}; ///< Size of view
};
} // Namespace Internal::Render
} // Namespace Dali
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// CLASS HEADER
#include <dali/internal/render/renderers/uniform-buffer.h>
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+#ifdef DEBUG_ENABLED
+Debug::Filter* gUniformBufferLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_UNIFORM_BUFFER");
+#endif
+
namespace Dali::Internal::Render
{
-UniformBuffer::UniformBuffer(Dali::Graphics::Controller* controller,
- uint32_t sizeInBytes,
- uint32_t alignment,
- bool persistentMappedEnabled,
- Graphics::BufferUsageFlags usageFlags)
- : mController(controller),
- mSize(0u),
- mUsageFlags(usageFlags)
+namespace
+{
+static constexpr uint32_t INVALID_BUFFER_INDEX = std::numeric_limits<uint32_t>::max();
+}
+UniformBuffer::UniformBuffer(Dali::Graphics::Controller* controller,
+ uint32_t sizeInBytes,
+ uint32_t alignment,
+ Graphics::BufferUsageFlags usageFlags,
+ Graphics::BufferPropertiesFlags propertiesFlags)
+: mController(controller),
+ mSize(0u),
+ mUsageFlags(usageFlags),
+ mPropertiesFlags(propertiesFlags),
+ mLockedBufferIndex(INVALID_BUFFER_INDEX),
+ mLockedPtr(nullptr),
+ mReadyToBeLocked(false)
{
mAlignment = alignment;
if(sizeInBytes)
UniformBuffer::~UniformBuffer()
{
// Unmap and flush all allocated buffers
- for( auto i = 0u; i < mBuffers.size(); ++i)
+ for(auto i = 0u; i < mBuffers.size(); ++i)
{
Flush(i);
Unmap(i);
void UniformBuffer::Flush(uint32_t bufferIndex)
{
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::General, "Flush (bufferIndex : %d / %d [%d])\n", bufferIndex, mBuffers.size(), mSize);
const auto& buffer = mBuffers[bufferIndex];
if(buffer.buffer && buffer.memory)
{
}
}
-void UniformBuffer::Resize( uint32_t newSize, bool invalidate )
+void UniformBuffer::Resize(uint32_t newSize, bool invalidate)
{
+ // Adjust alignment, the alignment is needed for
+ // real UBOs (it should be given by the buffer requirements)
+ if(DALI_LIKELY(mAlignment && newSize > 0))
+ {
+ newSize = (((newSize - 1) / mAlignment) + 1) * mAlignment;
+ }
+
// The buffer is already optimal
if(newSize == mSize && !invalidate)
{
return;
}
+ if(DALI_UNLIKELY(mReadyToBeLocked))
+ {
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::Verbose, "Resize %d --> %d with %s [mBuffers : %d] during lock (lockedBufferIndex : %d, lockedPtr : %p)\n", mSize, newSize, invalidate ? "Invalidate" : "Rendering", mBuffers.size(), mLockedBufferIndex, mLockedPtr);
+ }
+ else
+ {
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::Verbose, "Resize %d --> %d with %s [mBuffers : %d]\n", mSize, newSize, invalidate ? "Invalidate" : "Rendering", mBuffers.size());
+ }
+
// Throw away content
if(invalidate)
{
+ if(mReadyToBeLocked)
+ {
+ UnlockUniformBuffer();
+ mReadyToBeLocked = true;
+ }
+ // Flush and unmap all allocated buffers
+ for(auto i = 0u; i < mBuffers.size(); ++i)
+ {
+ Flush(i);
+ Unmap(i);
+ }
mBuffers.clear();
mSize = 0;
}
- // Adjust alignment, the alignment is needed for
- // real UBOs (it should be given by the buffer requirements)
- if(mAlignment)
- {
- newSize = ((newSize / mAlignment)+1)*mAlignment;
- }
-
if(newSize > mSize)
{
auto createInfo = Graphics::BufferCreateInfo()
- .SetSize(newSize - mSize)
- .SetBufferPropertiesFlags(0 | Graphics::BufferPropertiesFlagBit::CPU_ALLOCATED)
- .SetUsage(mUsageFlags);
+ .SetSize(newSize - mSize)
+ .SetBufferPropertiesFlags(mPropertiesFlags)
+ .SetUsage(mUsageFlags);
auto buffer = mController->CreateBuffer(createInfo, nullptr);
mSize = newSize;
}
-}
+ // If invalidate during locked, begin lock again.
+ if(DALI_UNLIKELY(invalidate && mReadyToBeLocked))
+ {
+ mReadyToBeLocked = false;
+ ReadyToLockUniformBuffer();
+ }
-const UniformBuffer::GfxBuffer* UniformBuffer::GetBufferByOffset( uint32_t offset, uint32_t* newOffset, uint32_t* outBufferIndex ) const
+ if(DALI_UNLIKELY(mReadyToBeLocked))
+ {
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::Verbose, "Resize done as %d with %s [mBuffers : %d] during lock (lockedBufferIndex : %d, lockedPtr : %p)\n", newSize, invalidate ? "Invalidate" : "Rendering", mBuffers.size(), mLockedBufferIndex, mLockedPtr);
+ }
+ else
+ {
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::Verbose, "Resize done as %d with %s [mBuffers : %d]\n", newSize, invalidate ? "Invalidate" : "Rendering", mBuffers.size());
+ }
+}
+
+const UniformBuffer::GfxBuffer* UniformBuffer::GetBufferByOffset(uint32_t offset, uint32_t* newOffset, uint32_t* outBufferIndex) const
{
uint32_t bufferOffset = offset;
- uint32_t bufferIndex = 0u;
+ uint32_t bufferIndex = 0u;
// Find buffer if UBO is fragmented
if(mBuffers.size() > 1)
{
for(const auto& buffer : mBuffers)
{
- if( bufferOffset >= buffer.createInfo.size)
+ if(bufferOffset >= buffer.createInfo.size)
{
bufferOffset -= buffer.createInfo.size;
}
*newOffset = bufferOffset;
}
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::Verbose, "GetBufferByOffset (bufferIndex : %d / %d [%d], bufferOffset : %d, Graphics::BufferPtr : %p)\n", bufferIndex, mBuffers.size(), mSize, bufferOffset, bufferDesc.buffer.get());
+
return &bufferDesc;
}
{
// find which buffer we want to write into
uint32_t bufferOffset = dstOffset;
- uint32_t bufferIndex = 0u;
+ uint32_t bufferIndex = 0u;
// Find buffer if UBO is fragmented
if(mBuffers.size() > 1)
{
for(const auto& buffer : mBuffers)
{
- if( bufferOffset >= buffer.createInfo.size)
+ if(bufferOffset >= buffer.createInfo.size)
{
bufferOffset -= buffer.createInfo.size;
}
bufferDesc.needsUpdate = false;
}
- DALI_ASSERT_ALWAYS( mBuffers.size() > bufferIndex );
- DALI_ASSERT_ALWAYS( mBuffers[bufferIndex].buffer );
- DALI_ASSERT_ALWAYS( mBuffers[bufferIndex].createInfo.size > bufferOffset + size );
+ DALI_ASSERT_ALWAYS(mBuffers.size() > bufferIndex);
+ DALI_ASSERT_ALWAYS(mBuffers[bufferIndex].buffer);
+ DALI_ASSERT_ALWAYS(mBuffers[bufferIndex].createInfo.size > bufferOffset + size);
- bool locallyMapped = (bufferDesc.mappedPtr != nullptr);
+ const bool locallyMapped = (bufferDesc.mappedPtr != nullptr);
if(!locallyMapped)
{
// Map once and keep it
- Map( bufferIndex );
+ Map(bufferIndex);
}
if(bufferDesc.memory)
{
- void* ptr = bufferDesc.memory->LockRegion(bufferOffset, size);
- if(ptr && bufferOffset + size < mSize)
+ // Rarely happened that we use over the locked memory
+ // Unlock previous buffer, and lock as current bufferIndex again
+ if(DALI_UNLIKELY(mLockedBufferIndex != bufferIndex))
{
- // size always divides by 4 (std140 alignment rules, so we can replace memcpy with unrolled assignments)
- auto ptr32 = reinterpret_cast<uint32_t*>(ptr);
- auto data32 = reinterpret_cast<const uint32_t*>(data);
- for(auto i = 0u; i < size; i +=4 )
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::General, "Unlock (lockedBufferIndex : %d / %d [%d], lockedPtr : %p)\n", mLockedBufferIndex, mBuffers.size(), mSize, mLockedPtr);
+
+ // mLockedBufferIndex == INVALID_BUFFER_INDEX only first time of current RenderScene.
+ if(DALI_LIKELY(mLockedBufferIndex != INVALID_BUFFER_INDEX))
+ {
+ // Unlock previous memory
+ if(mBuffers[mLockedBufferIndex].memory)
+ {
+ mBuffers[mLockedBufferIndex].memory->Unlock(true);
+ }
+ }
+ mLockedBufferIndex = bufferIndex;
+ mLockedPtr = nullptr;
+
+ // Initial mapping done previously. Just lock and roll now.
+ if(mBuffers[mLockedBufferIndex].memory)
{
- *ptr32++ = *data32++;;
+ mLockedPtr = reinterpret_cast<uint8_t*>(mBuffers[mLockedBufferIndex].memory->LockRegion(0, mBuffers[mLockedBufferIndex].createInfo.size));
}
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::General, "Lock (lockedBufferIndex : %d / %d [%d], lockedPtr : %p)\n", mLockedBufferIndex, mBuffers.size(), mSize, mLockedPtr);
+ }
+
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::Verbose, "memcpy (lockedBufferIndex : %d / %d [%d], lockedPtr : %p, offset : %d, size : %d, lockedBufferSize : %d)\n", mLockedBufferIndex, mBuffers.size(), mSize, mLockedPtr, bufferOffset, size, mBuffers[mLockedBufferIndex].createInfo.size);
+
+ // We already check validation of buffer range. We can assume that bufferOffset + size <= mBuffers[mLockedBufferIndex].createInfo.size
+ if(mLockedPtr)
+ {
+ memcpy(mLockedPtr + bufferOffset, data, size);
}
- bufferDesc.memory->Unlock(true);
}
}
-void UniformBuffer::Map( uint32_t bufferIndex)
+void UniformBuffer::Map(uint32_t bufferIndex)
{
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::General, "Map (bufferIndex : %d / %d [%d])\n", bufferIndex, mBuffers.size(), mSize);
auto& buffer = mBuffers[bufferIndex];
if(buffer.needsUpdate)
if(!buffer.memory)
{
Graphics::MapBufferInfo info{};
- info.buffer = buffer.buffer.get();
- info.usage = 0 | Graphics::MemoryUsageFlagBits::WRITE;
- info.offset = 0;
- info.size = buffer.createInfo.size;
+ info.buffer = buffer.buffer.get();
+ info.usage = 0 | Graphics::MemoryUsageFlagBits::WRITE;
+ info.offset = 0;
+ info.size = buffer.createInfo.size;
buffer.memory = mController->MapBufferRange(info);
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::Verbose, "GraphicsMemoryMapped (bufferIndex : %d / %d [%d], size : %d)\n", bufferIndex, mBuffers.size(), mSize, info.size);
}
}
-void UniformBuffer::Unmap( uint32_t bufferIndex)
+void UniformBuffer::Unmap(uint32_t bufferIndex)
{
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::General, "Unmap (bufferIndex : %d / %d [%d])\n", bufferIndex, mBuffers.size(), mSize);
auto& buffer = mBuffers[bufferIndex];
if(buffer.memory)
{
mController->UnmapMemory(std::move(buffer.memory));
}
}
-}
\ No newline at end of file
+
+void UniformBuffer::ReadyToLockUniformBuffer()
+{
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::General, "LockUniformBuffer\n");
+ if(DALI_UNLIKELY(mReadyToBeLocked && mLockedBufferIndex != INVALID_BUFFER_INDEX))
+ {
+ // Unlock previous locked buffer first
+ DALI_LOG_ERROR("Warning! : called LockUniformBuffer() before called UnlockUniformBuffer()!\n");
+ UnlockUniformBuffer();
+ }
+
+ mReadyToBeLocked = true;
+ mLockedBufferIndex = INVALID_BUFFER_INDEX;
+ mLockedPtr = nullptr;
+}
+
+void UniformBuffer::UnlockUniformBuffer()
+{
+ DALI_LOG_INFO(gUniformBufferLogFilter, Debug::General, "UnlockUniformBuffer (lockedBufferIndex : %d / %d [%d], lockedPtr : %p)\n", mLockedBufferIndex, mBuffers.size(), mSize, mLockedPtr);
+ if(mReadyToBeLocked && mLockedBufferIndex != INVALID_BUFFER_INDEX)
+ {
+ auto& bufferDesc = mBuffers[mLockedBufferIndex];
+ if(bufferDesc.memory)
+ {
+ bufferDesc.memory->Unlock(true);
+ }
+ // Flush all allocated buffers
+ for(auto i = 0u; i < mBuffers.size(); ++i)
+ {
+ Flush(i);
+ }
+ }
+ mLockedPtr = nullptr;
+ mLockedBufferIndex = INVALID_BUFFER_INDEX;
+ mReadyToBeLocked = false;
+}
+
+} // namespace Dali::Internal::Render
\ No newline at end of file
#define DALI_INTERNAL_UNIFORM_BUFFER_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* @param[in] mController Pointer of the graphics controller
* @param[in] sizeInBytes initial size of allocated buffer
* @param[in] alignment memory alignment in bytes
- * @param[in] persistentMappingEnabled if true, buffer is mapped persistently
* @param[in] usageFlags type of usage ( Graphics::BufferUsage )
+ * @param[in] propertiesFlags buffer properties (Gracphis::BufferPropertiesFlags)
*/
- UniformBuffer(Dali::Graphics::Controller* mController,
- uint32_t sizeInBytes,
- uint32_t alignment,
- bool persistentMappingEnabled,
- Graphics::BufferUsageFlags usageFlags);
+ UniformBuffer(Dali::Graphics::Controller* mController,
+ uint32_t sizeInBytes,
+ uint32_t alignment,
+ Graphics::BufferUsageFlags usageFlags,
+ Graphics::BufferPropertiesFlags propertiesFlags);
public:
/**
~UniformBuffer();
/**
- * Writes data into the buffer
+ * @brief Writes data into the buffer
+ * @note We prefer to call ReadyToLockUniformBuffer before call Write API.
+ * And also, prefer to call UnlockUniformBuffer if current frame's all Write API action done.
*
* @param[in] data pointer to the source data
* @param[in] size size of source data
void Write(const void* data, uint32_t size, uint32_t offset);
/**
- * Flushes whole buffer range
+ * @brief Flushes whole buffer range
*
* @param[in] bufferIndex Index of Graphics::Buffer
*/
- void Flush( uint32_t bufferIndex = 0);
+ void Flush(uint32_t bufferIndex = 0);
/**
- * Returns allocated ( requested ) size
+ * @brief Returns allocated ( requested ) size
* @return size of buffer
*/
[[nodiscard]] uint32_t GetSize() const
}
/**
- * Return Graphics::Buffer object at specified array index
+ * @brief Return Graphics::Buffer object at specified array index
*
* @param[in] bufferIndex index of Graphics buffer
*
* @return pointer to the buffer object
*/
- [[nodiscard]] Dali::Graphics::Buffer* GetBuffer( uint32_t bufferIndex ) const
+ [[nodiscard]] Dali::Graphics::Buffer* GetBuffer(uint32_t bufferIndex) const
{
return mBuffers[bufferIndex].buffer.get();
}
/**
- * Maps individual Graphics buffer memory
+ * @brief Maps individual Graphics buffer memory
*
* @param[in] bufferIndex index of Graphics buffer
*/
- void Map( uint32_t bufferIndex = 0);
+ void Map(uint32_t bufferIndex = 0);
/**
* Unmaps individual Graphics buffer memory
*
* @param[in] bufferIndex index of Graphics buffer
*/
- void Unmap( uint32_t bufferIndex = 0);
+ void Unmap(uint32_t bufferIndex = 0);
/**
- * Resizes the buffer
+ * @brief Resizes the buffer
*
* The resize strategy depends on 'invalidate' parameter.
*
* @param[in] invalidate specifies whether the content should be discarded
*
*/
- void Resize( uint32_t newSize, bool invalidate );
+ void Resize(uint32_t newSize, bool invalidate);
-private:
+ /**
+ * @copydoc Dali::Internal::Render::UniformBufferViewPool::ReadyToLockUniformBuffer
+ */
+ void ReadyToLockUniformBuffer();
/**
- * GfxBuffer wraps single GPU buffer and encapsulates individual
+ * @copydoc Dali::Internal::Render::UniformBufferViewPool::UnlockUniformBuffer
+ */
+ void UnlockUniformBuffer();
+
+private:
+ /**
+ * @brief GfxBuffer wraps single GPU buffer and encapsulates individual
* buffer mapping and create info details.
*
* The array of GfxBuffers makes a single UniformBuffer.
*/
struct GfxBuffer
{
- GfxBuffer() = default;
- ~GfxBuffer() = default;
- GfxBuffer( GfxBuffer&& ) = default;
- GfxBuffer(Graphics::UniquePtr<Graphics::Buffer>&& b, const Graphics::BufferCreateInfo& i) :
- buffer(std::move(b)),
+ GfxBuffer() = default;
+ ~GfxBuffer() = default;
+ GfxBuffer(GfxBuffer&&) = default;
+ GfxBuffer(Graphics::UniquePtr<Graphics::Buffer>&& b, const Graphics::BufferCreateInfo& i)
+ : buffer(std::move(b)),
createInfo(i)
{
}
- Graphics::UniquePtr<Graphics::Buffer> buffer{}; ///< Graphics buffer
- Graphics::UniquePtr<Graphics::Memory> memory{}; ///< Mapped memory associated with buffer
- Graphics::BufferCreateInfo createInfo{}; ///< create info describing the buffer
- void* mappedPtr{}; ///< Mapped pointer (if mapped)
- bool needsUpdate{true}; ///< Indicates whether the buffer needs flushing the queue
+ Graphics::UniquePtr<Graphics::Buffer> buffer{}; ///< Graphics buffer
+ Graphics::UniquePtr<Graphics::Memory> memory{}; ///< Mapped memory associated with buffer
+ Graphics::BufferCreateInfo createInfo{}; ///< create info describing the buffer
+ void* mappedPtr{}; ///< Mapped pointer (if mapped)
+ bool needsUpdate{true}; ///< Indicates whether the buffer needs flushing the queue
};
/**
- * Returns GfxBuffer object by offset
+ * @brief Returns GfxBuffer object by offset
*
* The memory of UniformBuffer is considered to be continuous, however,
* it may contain multiple graphics buffers.
*
*/
- const GfxBuffer* GetBufferByOffset( uint32_t offset, uint32_t* newOffset, uint32_t* bufferIndex ) const;
+ const GfxBuffer* GetBufferByOffset(uint32_t offset, uint32_t* newOffset, uint32_t* bufferIndex) const;
std::vector<GfxBuffer> mBuffers; ///< List of GfxBuffer objects
Dali::Graphics::Controller* mController; ///< Pointer to the controller
- uint32_t mSize; ///< Current size of buffer
+ uint32_t mSize; ///< Current size of buffer
uint32_t mAlignment{0}; ///< Buffer alignment
- Graphics::BufferUsageFlags mUsageFlags;
+ Graphics::BufferUsageFlags mUsageFlags;
+ Graphics::BufferPropertiesFlags mPropertiesFlags;
- bool mValid{false};
+ uint32_t mLockedBufferIndex; ///< Current locked buffer region index.
+ uint8_t* mLockedPtr; ///< Current locked buffer pointer.
+ bool mReadyToBeLocked : 1; ///< True if current uniform buffer is ready to be locked.
};
-}
+} // namespace Dali::Internal::Render
#endif //DALI_INTERNAL_UNIFORM_BUFFER_H
BuildReflection(mGfxController.GetProgramReflection(*mGfxProgram.get()));
}
-bool Program::GetUniform(const std::string& name, Hash hashedName, Hash hashedNameNoArray, Graphics::UniformInfo& out) const
+bool Program::GetUniform(const std::string_view& name, Hash hashedName, Hash hashedNameNoArray, Graphics::UniformInfo& out) const
{
if(mReflection.empty())
{
// If the name contains a "]" anywhere but the end, it's a structure element. The reflection
// does contain such elements, so use normal hash.
- Hash hash = hashedName;
- const std::string* match = &name;
+ Hash hash = hashedName;
+ std::string_view match = name;
- std::string baseName;
if(!name.empty() && name.back() == ']')
{
hash = hashedNameNoArray;
auto pos = name.rfind("[");
- baseName = name.substr(0, pos - 1); // Remove subscript
- match = &baseName;
+ match = name.substr(0, pos - 1); // Remove subscript
}
for(const ReflectionUniformInfo& item : mReflection)
{
if(item.hashValue == hash)
{
- if(!item.hasCollision || item.uniformInfo.name == *match)
+ if(!item.hasCollision || item.uniformInfo.name == match)
{
out = item.uniformInfo;
return true;
*
* @return False when uniform is not found or due to hash collision the result is ambiguous
*/
- bool GetUniform(const std::string& name, Hash hashedName, Hash hashedNameNoArray, Graphics::UniformInfo& out) const;
+ bool GetUniform(const std::string_view& name, Hash hashedName, Hash hashedNameNoArray, Graphics::UniformInfo& out) const;
/**
* Retrieves default uniform