Apply Visual's transform + borderline properties for partial update
[platform/core/uifw/dali-core.git] / dali / internal / common / message-buffer.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/common/message-buffer.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstdlib>
23 #include <limits>
24
25 // INTERNAL INCLUDES
26 #include <dali/integration-api/debug.h>
27
28 namespace // unnamed namespace
29 {
30 // Increase capacity by 1.5 when buffer limit reached
31 const uint32_t INCREMENT_NUMERATOR   = 3u;
32 const uint32_t INCREMENT_DENOMINATOR = 2u;
33
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
36
37 const uint32_t MESSAGE_SIZE_PLUS_END_FIELD = MESSAGE_SIZE_FIELD + MESSAGE_END_FIELD;
38
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);
41
42 } // unnamed namespace
43
44 namespace Dali
45 {
46 namespace Internal
47 {
48 MessageBuffer::MessageBuffer(std::size_t initialCapacity)
49 : mInitialCapacity(initialCapacity / WORD_SIZE),
50   mData(nullptr),
51   mNextSlot(nullptr),
52   mCapacity(0),
53   mSize(0)
54 {
55 }
56
57 MessageBuffer::~MessageBuffer()
58 {
59   free(mData);
60 }
61
62 uint32_t* MessageBuffer::ReserveMessageSlot(std::size_t size)
63 {
64   DALI_ASSERT_DEBUG(0 != size);
65
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;
69
70   // Keep doubling the additional capacity until we have enough
71   std::size_t nextCapacity = mCapacity ? mCapacity : mInitialCapacity;
72
73   if((nextCapacity - mSize) < requiredSize)
74   {
75     nextCapacity = nextCapacity * INCREMENT_NUMERATOR / INCREMENT_DENOMINATOR;
76
77     // Something has gone badly wrong if requiredSize is this big
78     DALI_ASSERT_DEBUG((nextCapacity - mSize) > requiredSize);
79   }
80
81   if(nextCapacity > mCapacity)
82   {
83     IncreaseCapacity(nextCapacity);
84   }
85
86   // Now reserve the slot
87   WordType* slot = mNextSlot;
88
89   *slot++ = requestedSize; // Object size marker is stored in first word
90
91   mSize += requestedSize + MESSAGE_SIZE_FIELD;
92   mNextSlot = mData + mSize;
93
94   // End marker
95   *mNextSlot = 0;
96
97   return reinterpret_cast<uint32_t*>(slot);
98 }
99
100 std::size_t MessageBuffer::GetCapacity() const
101 {
102   return mCapacity * WORD_SIZE;
103 }
104
105 MessageBuffer::Iterator MessageBuffer::Begin() const
106 {
107   if(0 != mSize)
108   {
109     return Iterator(mData);
110   }
111
112   return Iterator(nullptr);
113 }
114
115 void MessageBuffer::Reset()
116 {
117   // All messages have been processed, reset the buffer
118   mSize     = 0;
119   mNextSlot = mData;
120 }
121
122 void MessageBuffer::IncreaseCapacity(std::size_t newCapacity)
123 {
124   DALI_ASSERT_DEBUG(newCapacity > mCapacity);
125
126   if(mData)
127   {
128     // Often this avoids the need to copy memory
129
130     WordType* oldData = mData;
131     mData             = reinterpret_cast<WordType*>(realloc(mData, newCapacity * WORD_SIZE));
132
133     // if realloc fails the old data is still valid
134     if(!mData)
135     {
136       // TODO: Process message queue to free up some data?
137       free(oldData);
138       DALI_ASSERT_DEBUG(false && "Realloc failed we're out of memory!");
139     }
140   }
141   else
142   {
143     mData = reinterpret_cast<WordType*>(malloc(newCapacity * WORD_SIZE));
144   }
145   DALI_ASSERT_ALWAYS(nullptr != mData);
146
147   mCapacity = newCapacity;
148   mNextSlot = mData + mSize;
149 }
150
151 MessageBuffer::Iterator::Iterator(WordType* current)
152 : mCurrent(current),
153   mMessageSize(0)
154 {
155   if(nullptr != mCurrent)
156   {
157     // The first word is the size of the following object
158     mMessageSize = *mCurrent++;
159   }
160 }
161
162 MessageBuffer::Iterator::Iterator(const Iterator& copy) = default;
163
164 } // namespace Internal
165
166 } // namespace Dali