c944880687dad27917b507362c8c32ee08f43961
[platform/core/uifw/dali-core.git] / dali / internal / render / renderers / uniform-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/render/renderers/uniform-buffer.h>
20
21 namespace Dali::Internal::Render
22 {
23 UniformBuffer::UniformBuffer(Dali::Graphics::Controller* controller,
24                              uint32_t                    sizeInBytes,
25                              uint32_t                    alignment,
26                              bool                        persistentMappedEnabled,
27                              Graphics::BufferUsageFlags  usageFlags)
28   : mController(controller),
29     mSize(0u),
30     mUsageFlags(usageFlags)
31 {
32   mAlignment = alignment;
33   if(sizeInBytes)
34   {
35     Resize(sizeInBytes, true);
36   }
37 }
38
39 UniformBuffer::~UniformBuffer()
40 {
41   // Unmap and flush all allocated buffers
42   for( auto i = 0u; i < mBuffers.size(); ++i)
43   {
44     Flush(i);
45     Unmap(i);
46   }
47 }
48
49 void UniformBuffer::Flush(uint32_t bufferIndex)
50 {
51   const auto& buffer = mBuffers[bufferIndex];
52   if(buffer.buffer && buffer.memory)
53   {
54     buffer.memory->Flush();
55   }
56 }
57
58 void UniformBuffer::Resize( uint32_t newSize, bool invalidate )
59 {
60   // The buffer is already optimal
61   if(newSize == mSize && !invalidate)
62   {
63     return;
64   }
65   if(invalidate && newSize == mSize && mBuffers.size() == 1)
66   {
67     return;
68   }
69
70   // Throw away content
71   if(invalidate)
72   {
73     mBuffers.clear();
74     mSize = 0;
75   }
76
77   // Adjust alignment, the alignment is needed for
78   // real UBOs (it should be given by the buffer requirements)
79   if(mAlignment)
80   {
81     newSize = ((newSize / mAlignment)+1)*mAlignment;
82   }
83
84   if(newSize > mSize)
85   {
86     auto createInfo = Graphics::BufferCreateInfo()
87       .SetSize(newSize - mSize)
88       .SetBufferPropertiesFlags(0 | Graphics::BufferPropertiesFlagBit::CPU_ALLOCATED)
89       .SetUsage(mUsageFlags);
90
91     auto buffer = mController->CreateBuffer(createInfo, nullptr);
92
93     mBuffers.emplace_back(GfxBuffer(std::move(buffer), createInfo));
94
95     mSize = newSize;
96   }
97 }
98
99
100 const UniformBuffer::GfxBuffer* UniformBuffer::GetBufferByOffset( uint32_t offset, uint32_t* newOffset, uint32_t* outBufferIndex ) const
101 {
102   uint32_t bufferOffset = offset;
103   uint32_t bufferIndex = 0u;
104
105   // Find buffer if UBO is fragmented
106   if(mBuffers.size() > 1)
107   {
108     for(const auto& buffer : mBuffers)
109     {
110       if( bufferOffset >= buffer.createInfo.size)
111       {
112         bufferOffset -= buffer.createInfo.size;
113       }
114       else
115       {
116         break;
117       }
118       bufferIndex++;
119     }
120   }
121
122   auto& bufferDesc = mBuffers[bufferIndex];
123
124   if(outBufferIndex)
125   {
126     *outBufferIndex = bufferIndex;
127   }
128
129   if(newOffset)
130   {
131     *newOffset = bufferOffset;
132   }
133
134   return &bufferDesc;
135 }
136
137 void UniformBuffer::Write(const void* data, uint32_t size, uint32_t dstOffset)
138 {
139   // find which buffer we want to write into
140   uint32_t bufferOffset = dstOffset;
141   uint32_t bufferIndex = 0u;
142
143   // Find buffer if UBO is fragmented
144   if(mBuffers.size() > 1)
145   {
146     for(const auto& buffer : mBuffers)
147     {
148       if( bufferOffset >= buffer.createInfo.size)
149       {
150         bufferOffset -= buffer.createInfo.size;
151       }
152       else
153       {
154         break;
155       }
156       bufferIndex++;
157     }
158   }
159
160   auto& bufferDesc = mBuffers[bufferIndex];
161
162   if(bufferDesc.needsUpdate)
163   {
164     mController->WaitIdle();
165     bufferDesc.needsUpdate = false;
166   }
167
168   DALI_ASSERT_ALWAYS( mBuffers.size() > bufferIndex );
169   DALI_ASSERT_ALWAYS( mBuffers[bufferIndex].buffer );
170   DALI_ASSERT_ALWAYS( mBuffers[bufferIndex].createInfo.size > bufferOffset + size );
171
172   bool locallyMapped = (bufferDesc.mappedPtr != nullptr);
173   if(!locallyMapped)
174   {
175     // Map once and keep it
176     Map( bufferIndex );
177   }
178
179   if(bufferDesc.memory)
180   {
181     void* ptr = bufferDesc.memory->LockRegion(bufferOffset, size);
182     if(ptr && bufferOffset + size < mSize)
183     {
184       // size always divides by 4 (std140 alignment rules, so we can replace memcpy with unrolled assignments)
185       auto ptr32 = reinterpret_cast<uint32_t*>(ptr);
186       auto data32 = reinterpret_cast<const uint32_t*>(data);
187       for(auto i = 0u; i < size; i +=4 )
188       {
189         *ptr32++ = *data32++;;
190       }
191     }
192     bufferDesc.memory->Unlock(true);
193   }
194 }
195
196 void UniformBuffer::Map( uint32_t bufferIndex)
197 {
198   auto& buffer = mBuffers[bufferIndex];
199
200   if(buffer.needsUpdate)
201   {
202     mController->WaitIdle();
203     buffer.needsUpdate = false;
204   }
205
206   if(!buffer.memory)
207   {
208     Graphics::MapBufferInfo info{};
209     info.buffer = buffer.buffer.get();
210     info.usage  = 0 | Graphics::MemoryUsageFlagBits::WRITE;
211     info.offset = 0;
212     info.size   = buffer.createInfo.size;
213     buffer.memory = mController->MapBufferRange(info);
214   }
215 }
216
217 void UniformBuffer::Unmap( uint32_t bufferIndex)
218 {
219   auto& buffer = mBuffers[bufferIndex];
220   if(buffer.memory)
221   {
222     mController->UnmapMemory(std::move(buffer.memory));
223   }
224 }
225 }