2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/common/message-buffer.h>
26 #include <dali/integration-api/debug.h>
28 namespace // unnamed namespace
30 // Increase capacity by 1.5 when buffer limit reached
31 const uint32_t INCREMENT_NUMERATOR = 3u;
32 const uint32_t INCREMENT_DENOMINATOR = 2u;
34 const uint32_t MESSAGE_SIZE_FIELD = 1u; // Size required to mark the message size
35 const uint32_t MESSAGE_END_FIELD = 1u; // Size required to mark the end of messages
37 const uint32_t MESSAGE_SIZE_PLUS_END_FIELD = MESSAGE_SIZE_FIELD + MESSAGE_END_FIELD;
39 const std::size_t MAX_DIVISION_BY_WORD_REMAINDER = sizeof(Dali::Internal::MessageBuffer::WordType) - 1u; // For word alignment on ARM
40 const std::size_t WORD_SIZE = sizeof(Dali::Internal::MessageBuffer::WordType);
42 } // unnamed namespace
48 MessageBuffer::MessageBuffer(std::size_t initialCapacity)
49 : mInitialCapacity(initialCapacity / WORD_SIZE),
57 MessageBuffer::~MessageBuffer()
62 uint32_t* MessageBuffer::ReserveMessageSlot(std::size_t size)
64 DALI_ASSERT_DEBUG(0 != size);
66 // Number of aligned words required to handle a message of size in bytes
67 std::size_t requestedSize = (size + MAX_DIVISION_BY_WORD_REMAINDER) / WORD_SIZE;
68 std::size_t requiredSize = requestedSize + MESSAGE_SIZE_PLUS_END_FIELD;
70 // Keep doubling the additional capacity until we have enough
71 std::size_t nextCapacity = mCapacity ? mCapacity : mInitialCapacity;
73 if((nextCapacity - mSize) < requiredSize)
75 nextCapacity = nextCapacity * INCREMENT_NUMERATOR / INCREMENT_DENOMINATOR;
77 // Something has gone badly wrong if requiredSize is this big
78 DALI_ASSERT_DEBUG((nextCapacity - mSize) > requiredSize);
81 if(nextCapacity > mCapacity)
83 IncreaseCapacity(nextCapacity);
86 // Now reserve the slot
87 WordType* slot = mNextSlot;
89 *slot++ = requestedSize; // Object size marker is stored in first word
91 mSize += requestedSize + MESSAGE_SIZE_FIELD;
92 mNextSlot = mData + mSize;
97 return reinterpret_cast<uint32_t*>(slot);
100 std::size_t MessageBuffer::GetCapacity() const
102 return mCapacity * WORD_SIZE;
105 MessageBuffer::Iterator MessageBuffer::Begin() const
109 return Iterator(mData);
112 return Iterator(nullptr);
115 void MessageBuffer::Reset()
117 // All messages have been processed, reset the buffer
122 void MessageBuffer::IncreaseCapacity(std::size_t newCapacity)
124 DALI_ASSERT_DEBUG(newCapacity > mCapacity);
128 // Often this avoids the need to copy memory
130 WordType* oldData = mData;
131 mData = reinterpret_cast<WordType*>(realloc(mData, newCapacity * WORD_SIZE));
133 // if realloc fails the old data is still valid
136 // TODO: Process message queue to free up some data?
138 DALI_ASSERT_DEBUG(false && "Realloc failed we're out of memory!");
143 mData = reinterpret_cast<WordType*>(malloc(newCapacity * WORD_SIZE));
145 DALI_ASSERT_ALWAYS(nullptr != mData);
147 mCapacity = newCapacity;
148 mNextSlot = mData + mSize;
151 MessageBuffer::Iterator::Iterator(WordType* current)
155 if(nullptr != mCurrent)
157 // The first word is the size of the following object
158 mMessageSize = *mCurrent++;
162 MessageBuffer::Iterator::Iterator(const Iterator& copy) = default;
164 } // namespace Internal