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.
18 #include <dali/internal/graphics/gles-impl/egl-graphics-controller.h>
21 #include <dali/integration-api/gl-abstraction.h>
22 #include <dali/integration-api/gl-defines.h>
23 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
24 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
25 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
26 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
27 #include <dali/public-api/common/dali-common.h>
29 namespace Dali::Graphics
34 * @brief Custom deleter for all Graphics objects created
35 * with use of the Controller.
37 * When Graphics object dies the unique pointer (Graphics::UniquePtr)
38 * doesn't destroy it directly but passes the ownership back
39 * to the Controller. The GLESDeleter is responsible for passing
40 * the object to the discard queue (by calling Resource::DiscardResource()).
45 GLESDeleter() = default;
47 void operator()(T* object)
49 // Discard resource (add it to discard queue)
50 object->DiscardResource();
55 * @brief Helper function allocating graphics object
57 * @param[in] info Create info structure
58 * @param[in] controller Controller object
59 * @param[out] out Unique pointer to the return object
61 template<class GLESType, class GfxCreateInfo, class T>
62 auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&& oldObject)
65 using Type = typename T::element_type;
66 using UPtr = Graphics::UniquePtr<Type>;
67 if(info.allocationCallbacks)
69 auto* memory = info.allocationCallbacks->allocCallback(
72 info.allocationCallbacks->userData);
73 return UPtr(new(memory) GLESType(info, controller), GLESDeleter<GLESType>());
75 else // Use standard allocator
77 return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
81 template<class T0, class T1>
82 T0* CastObject(T1* apiObject)
84 return static_cast<T0*>(apiObject);
89 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
91 mGlAbstraction = &glAbstraction;
92 mContext = std::make_unique<GLES::Context>(*this);
95 void EglGraphicsController::Initialize(Integration::GlSyncAbstraction& glSyncAbstraction,
96 Integration::GlContextHelperAbstraction& glContextHelperAbstraction)
98 mGlSyncAbstraction = &glSyncAbstraction;
99 mGlContextHelperAbstraction = &glContextHelperAbstraction;
102 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
104 for(auto& cmdbuf : submitInfo.cmdBuffer)
106 // Push command buffers
107 mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
110 // If flush bit set, flush all pending tasks
111 if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
117 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
119 DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
120 return *mGlAbstraction;
123 Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
125 DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
126 return *mGlSyncAbstraction;
129 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
131 DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
132 return *mGlContextHelperAbstraction;
135 Graphics::UniquePtr<CommandBuffer>
136 EglGraphicsController::CreateCommandBuffer(const CommandBufferCreateInfo& commandBufferCreateInfo,
137 Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
139 return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
142 Graphics::UniquePtr<Texture>
143 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
145 return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
148 Graphics::UniquePtr<Buffer>
149 EglGraphicsController::CreateBuffer(const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
151 return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
154 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Pipeline>&& oldPipeline)
156 return NewObject<GLES::Pipeline>(pipelineCreateInfo, *this, std::move(oldPipeline));
159 void EglGraphicsController::AddTexture(GLES::Texture& texture)
161 // Assuming we are on the correct context
162 mCreateTextureQueue.push(&texture);
165 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
167 // Assuming we are on the correct context
168 mCreateBufferQueue.push(&buffer);
171 void EglGraphicsController::ProcessDiscardQueues()
174 ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
177 ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
180 void EglGraphicsController::ProcessCreateQueues()
183 ProcessCreateQueue(mCreateTextureQueue);
186 ProcessCreateQueue(mCreateBufferQueue);
189 void EglGraphicsController::ProcessCommandQueues()
191 // TODO: command queue per context, sync between queues should be
194 while(!mCommandQueue.empty())
196 auto cmdBuf = mCommandQueue.front();
199 for(auto& cmd : cmdBuf->GetCommands())
204 case GLES::CommandType::FLUSH:
206 // Nothing to do here
209 case GLES::CommandType::BIND_TEXTURES:
211 mContext->BindTextures(cmd.bindTextures.textureBindings);
214 case GLES::CommandType::BIND_VERTEX_BUFFERS:
216 auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
217 mContext->BindVertexBuffers(bindings);
220 case GLES::CommandType::BIND_INDEX_BUFFER:
222 mContext->BindIndexBuffer(cmd.bindIndexBuffer);
225 case GLES::CommandType::BIND_SAMPLERS:
229 case GLES::CommandType::BIND_PIPELINE:
231 mContext->BindPipeline(cmd.bindPipeline.pipeline);
234 case GLES::CommandType::DRAW:
236 mContext->Flush(false, cmd.draw);
239 case GLES::CommandType::DRAW_INDEXED:
241 mContext->Flush(false, cmd.draw);
244 case GLES::CommandType::DRAW_INDEXED_INDIRECT:
246 mContext->Flush(false, cmd.draw);
254 void EglGraphicsController::ProcessTextureUpdateQueue()
256 while(!mTextureUpdateRequests.empty())
258 TextureUpdateRequest& request = mTextureUpdateRequests.front();
260 auto& info = request.first;
261 auto& source = request.second;
263 if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
265 // GPU memory must be already allocated (glTexImage2D())
266 auto* texture = static_cast<GLES::Texture*>(info.dstTexture);
267 const auto& createInfo = texture->GetCreateInfo();
269 mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
271 mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
272 mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
276 info.srcExtent2D.width,
277 info.srcExtent2D.height,
278 GLES::GLTextureFormatType(createInfo.format).format,
279 GLES::GLTextureFormatType(createInfo.format).type,
280 source.memorySource.memory);
282 // free staging memory
283 free(source.memorySource.memory);
287 // TODO: other sources
290 mTextureUpdateRequests.pop();
294 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>& updateInfoList,
295 const std::vector<TextureUpdateSourceInfo>& sourceList)
298 for(auto& info : updateInfoList)
300 mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
301 auto& pair = mTextureUpdateRequests.back();
302 switch(pair.second.sourceType)
304 case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
306 auto& info = pair.first;
307 auto& source = pair.second;
309 // allocate staging memory and copy the data
310 // TODO: using PBO with GLES3, this is just naive
313 char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
314 std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
315 reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
318 // store staging buffer
319 source.memorySource.memory = stagingBuffer;
322 case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
324 // TODO, with PBO support
327 case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
329 // TODO texture 2 texture in-GPU copy
336 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
338 // Mapping buffer requires the object to be created NOW
339 // Workaround - flush now, otherwise there will be given a staging buffer
340 // in case when the buffer is not there yet
341 ProcessCreateQueues();
343 return Graphics::UniquePtr<Memory>(new GLES::Memory(mapInfo, *this));
346 } // namespace Dali::Graphics