ecae48338cbdec283978a76ae862a07d24bfa36f
[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       memcpy(ptr, data, size);
185     }
186     bufferDesc.memory->Unlock(true);
187   }
188 }
189
190 void UniformBuffer::Map( uint32_t bufferIndex)
191 {
192   auto& buffer = mBuffers[bufferIndex];
193
194   if(buffer.needsUpdate)
195   {
196     mController->WaitIdle();
197     buffer.needsUpdate = false;
198   }
199
200   if(!buffer.memory)
201   {
202     Graphics::MapBufferInfo info{};
203     info.buffer = buffer.buffer.get();
204     info.usage  = 0 | Graphics::MemoryUsageFlagBits::WRITE;
205     info.offset = 0;
206     info.size   = buffer.createInfo.size;
207     buffer.memory = mController->MapBufferRange(info);
208   }
209 }
210
211 void UniformBuffer::Unmap( uint32_t bufferIndex)
212 {
213   auto& buffer = mBuffers[bufferIndex];
214   if(buffer.memory)
215   {
216     mController->UnmapMemory(std::move(buffer.memory));
217   }
218 }
219 }