[dali_2.3.23] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / integration-api / lockless-buffer.cpp
1 /*
2  * Copyright (c) 2022 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 "lockless-buffer.h"
20
21 // INTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23
24 namespace Dali
25 {
26 namespace Integration
27 {
28 LocklessBuffer::LocklessBuffer(uint32_t size)
29 : mState(R0W1),
30   mSize(size)
31 {
32   // allocate memory to speed up operation
33   mBuffer[0] = new uint8_t[size];
34   mBuffer[1] = new uint8_t[size];
35
36   memset(mBuffer[0], 0, size);
37   memset(mBuffer[1], 0, size);
38 }
39
40 LocklessBuffer::~LocklessBuffer()
41 {
42   delete[] mBuffer[0];
43   delete[] mBuffer[1];
44 }
45
46 void LocklessBuffer::Write(const uint8_t* src, uint32_t size)
47 {
48   DALI_ASSERT_ALWAYS(size <= mSize);
49
50   // set WRITING bit
51   BufferState currentState(__sync_fetch_and_or(&mState, WRITING));
52   DALI_ASSERT_DEBUG(!(currentState & WRITING_MASK)); // WRITING bit should never be set when we get here
53
54   // copy data to current write buffer, negate state to get actual index (recap: R0W1 = 0, R1W0 = 1)
55   const unsigned int index = (currentState & WRITE_BUFFER_MASK);
56   memcpy(mBuffer[index], src, size);
57
58   // unset WRITING bit, set UPDATED bit
59   BufferState checkState = __sync_val_compare_and_swap(&mState,
60                                                        static_cast<BufferState>(currentState | WRITING),
61                                                        static_cast<BufferState>(index | UPDATED));
62
63   DALI_ASSERT_DEBUG(checkState & WRITING);
64   (void)checkState; // Avoid unused variable warning
65 }
66
67 const uint8_t* LocklessBuffer::Read()
68 {
69   // current state (only to avoid multiple memory reads with volatile variable)
70   BufferState currentState(mState);
71   BufferState currentWriteBuf(static_cast<BufferState>(currentState & WRITE_BUFFER_MASK));
72
73   if(currentState & UPDATED_MASK)
74   {
75     // Try to swap buffers.
76     // This will set mState to 1 if readbuffer 0 was updated, 0 if readbuffer 1 was updated and fail if WRITING is set
77     if(__sync_bool_compare_and_swap(&mState,
78                                     static_cast<BufferState>(currentWriteBuf | UPDATED),
79                                     static_cast<BufferState>((currentWriteBuf == R1W0) ? R0W1 : R1W0)))
80     {
81       // swap successful
82       return mBuffer[currentWriteBuf];
83     }
84   }
85
86   // UPDATE bit wasn't set or WRITING bit was set in other thread
87   // swap failed, read from current readbuffer
88   return mBuffer[(currentWriteBuf == R1W0) ? R0W1 : R1W0];
89 }
90
91 uint32_t LocklessBuffer::GetSize() const
92 {
93   return static_cast<unsigned int>(mSize);
94 }
95
96 } // namespace Integration
97
98 } // namespace Dali