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/debug.h>
22 #include <dali/integration-api/gl-abstraction.h>
23 #include <dali/integration-api/gl-defines.h>
24 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
25 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
26 #include <dali/internal/graphics/gles-impl/gles-graphics-render-pass.h>
27 #include <dali/internal/graphics/gles-impl/gles-graphics-render-target.h>
28 #include <dali/internal/graphics/gles-impl/gles-graphics-shader.h>
29 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
30 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
31 #include <dali/internal/graphics/gles-impl/gles3-graphics-memory.h>
32 #include <dali/public-api/common/dali-common.h>
33 #include "gles-graphics-program.h"
35 namespace Dali::Graphics
40 * @brief Custom deleter for all Graphics objects created
41 * with use of the Controller.
43 * When Graphics object dies the unique pointer (Graphics::UniquePtr)
44 * doesn't destroy it directly but passes the ownership back
45 * to the Controller. The GLESDeleter is responsible for passing
46 * the object to the discard queue (by calling Resource::DiscardResource()).
51 GLESDeleter() = default;
53 void operator()(T* object)
55 // Discard resource (add it to discard queue)
56 object->DiscardResource();
61 * @brief Helper function allocating graphics object
63 * @param[in] info Create info structure
64 * @param[in] controller Controller object
65 * @param[out] out Unique pointer to the return object
67 template<class GLESType, class GfxCreateInfo, class T>
68 auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&& oldObject)
71 using Type = typename T::element_type;
72 using UPtr = Graphics::UniquePtr<Type>;
73 if(info.allocationCallbacks)
75 auto* memory = info.allocationCallbacks->allocCallback(
78 info.allocationCallbacks->userData);
79 return UPtr(new(memory) GLESType(info, controller), GLESDeleter<GLESType>());
81 else // Use standard allocator
83 return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
87 template<class T0, class T1>
88 T0* CastObject(T1* apiObject)
90 return static_cast<T0*>(apiObject);
95 EglGraphicsController::~EglGraphicsController() = default;
97 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
99 DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #1\n");
100 mGlAbstraction = &glAbstraction;
101 mContext = std::make_unique<GLES::Context>(*this);
104 void EglGraphicsController::Initialize(Integration::GlSyncAbstraction& glSyncAbstraction,
105 Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
106 Internal::Adaptor::GraphicsInterface& graphicsInterface)
108 DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #2\n");
109 mGlSyncAbstraction = &glSyncAbstraction;
110 mGlContextHelperAbstraction = &glContextHelperAbstraction;
111 mGraphics = &graphicsInterface;
114 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
116 for(auto& cmdbuf : submitInfo.cmdBuffer)
118 // Push command buffers
119 mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
122 // If flush bit set, flush all pending tasks
123 if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
129 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
131 DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
132 return *mGlAbstraction;
135 Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
137 DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
138 return *mGlSyncAbstraction;
141 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
143 DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
144 return *mGlContextHelperAbstraction;
147 Graphics::UniquePtr<CommandBuffer> EglGraphicsController::CreateCommandBuffer(
148 const CommandBufferCreateInfo& commandBufferCreateInfo,
149 Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
151 return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
154 Graphics::UniquePtr<RenderPass> EglGraphicsController::CreateRenderPass(const RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<RenderPass>&& oldRenderPass)
156 return NewObject<GLES::RenderPass>(renderPassCreateInfo, *this, std::move(oldRenderPass));
159 Graphics::UniquePtr<Texture>
160 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
162 return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
165 Graphics::UniquePtr<Buffer> EglGraphicsController::CreateBuffer(
166 const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
168 return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
171 Graphics::UniquePtr<Framebuffer> EglGraphicsController::CreateFramebuffer(
172 const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Framebuffer>&& oldFramebuffer)
174 return NewObject<GLES::Framebuffer>(framebufferCreateInfo, *this, std::move(oldFramebuffer));
177 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(
178 const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
180 // Create pipeline cache if needed
183 mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
186 return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline));
189 Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(
190 const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
192 // Create program cache if needed
195 mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
198 return mPipelineCache->GetProgram(programCreateInfo, std::move(oldProgram));
201 Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
203 return NewObject<GLES::Shader>(shaderCreateInfo, *this, std::move(oldShader));
206 Graphics::UniquePtr<Sampler> EglGraphicsController::CreateSampler(const SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Sampler>&& oldSampler)
208 return NewObject<GLES::Sampler>(samplerCreateInfo, *this, std::move(oldSampler));
211 Graphics::UniquePtr<RenderTarget> EglGraphicsController::CreateRenderTarget(const RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<RenderTarget>&& oldRenderTarget)
213 return NewObject<GLES::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
216 const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program)
218 return static_cast<const Graphics::GLES::Program*>(&program)->GetReflection();
221 void EglGraphicsController::AddTexture(GLES::Texture& texture)
223 // Assuming we are on the correct context
224 mCreateTextureQueue.push(&texture);
227 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
229 // Assuming we are on the correct context
230 mCreateBufferQueue.push(&buffer);
233 void EglGraphicsController::AddFramebuffer(GLES::Framebuffer& framebuffer)
235 // Assuming we are on the correct context
236 mCreateFramebufferQueue.push(&framebuffer);
239 void EglGraphicsController::ProcessDiscardQueues()
242 ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
245 ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
247 // Process Framebuffers
248 ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
251 ProcessDiscardQueue<GLES::Pipeline>(mDiscardPipelineQueue);
254 ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
257 ProcessDiscardQueue<GLES::Shader>(mDiscardShaderQueue);
260 ProcessDiscardQueue<GLES::Sampler>(mDiscardSamplerQueue);
262 // Process command buffers
263 ProcessDiscardQueue<GLES::CommandBuffer>(mDiscardCommandBufferQueue);
266 void EglGraphicsController::ProcessCreateQueues()
269 ProcessCreateQueue(mCreateTextureQueue);
272 ProcessCreateQueue(mCreateBufferQueue);
274 // Process framebuffers
275 ProcessCreateQueue(mCreateFramebufferQueue);
278 void EglGraphicsController::ProcessCommandBuffer(GLES::CommandBuffer& commandBuffer)
280 for(auto& cmd : commandBuffer.GetCommands())
285 case GLES::CommandType::FLUSH:
287 // Nothing to do here
290 case GLES::CommandType::BIND_TEXTURES:
292 mContext->BindTextures(cmd.bindTextures.textureBindings);
295 case GLES::CommandType::BIND_VERTEX_BUFFERS:
297 auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
298 mContext->BindVertexBuffers(bindings);
301 case GLES::CommandType::BIND_UNIFORM_BUFFER:
303 auto& bindings = cmd.bindUniformBuffers;
304 mContext->BindUniformBuffers(bindings.uniformBufferBindings, bindings.standaloneUniformsBufferBinding);
307 case GLES::CommandType::BIND_INDEX_BUFFER:
309 mContext->BindIndexBuffer(cmd.bindIndexBuffer);
312 case GLES::CommandType::BIND_SAMPLERS:
316 case GLES::CommandType::BIND_PIPELINE:
318 auto pipeline = static_cast<const GLES::Pipeline*>(cmd.bindPipeline.pipeline);
319 mContext->BindPipeline(pipeline);
322 case GLES::CommandType::DRAW:
324 mContext->Flush(false, cmd.draw);
327 case GLES::CommandType::DRAW_INDEXED:
329 mContext->Flush(false, cmd.draw);
332 case GLES::CommandType::DRAW_INDEXED_INDIRECT:
334 mContext->Flush(false, cmd.draw);
337 case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
339 mGlAbstraction->Scissor(cmd.scissor.region.x, cmd.scissor.region.y, cmd.scissor.region.width, cmd.scissor.region.height);
342 case GLES::CommandType::SET_SCISSOR_TEST:
344 if(cmd.scissorTest.enable)
346 mGlAbstraction->Enable(GL_SCISSOR_TEST);
350 mGlAbstraction->Disable(GL_SCISSOR_TEST);
354 case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
356 mGlAbstraction->Viewport(cmd.viewport.region.x, cmd.viewport.region.y, cmd.viewport.region.width, cmd.viewport.region.height);
359 case GLES::CommandType::BEGIN_RENDERPASS:
361 mContext->BeginRenderPass(cmd.beginRenderPass);
364 case GLES::CommandType::END_RENDERPASS:
366 mContext->EndRenderPass();
369 case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
371 // Process secondary command buffers
372 // todo: check validity of the secondaries
373 // there are operations which are illigal to be done
374 // within secondaries.
375 for(auto& buf : cmd.executeCommandBuffers.buffers)
377 ProcessCommandBuffer(*static_cast<GLES::CommandBuffer*>(buf));
385 void EglGraphicsController::ProcessCommandQueues()
387 // TODO: command queue per context, sync between queues should be
389 currentFramebuffer = nullptr;
391 while(!mCommandQueue.empty())
393 auto cmdBuf = mCommandQueue.front();
395 ProcessCommandBuffer(*cmdBuf);
399 void EglGraphicsController::ProcessTextureUpdateQueue()
401 while(!mTextureUpdateRequests.empty())
403 TextureUpdateRequest& request = mTextureUpdateRequests.front();
405 auto& info = request.first;
406 auto& source = request.second;
408 if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
410 // GPU memory must be already allocated (glTexImage2D())
411 auto* texture = static_cast<GLES::Texture*>(info.dstTexture);
412 const auto& createInfo = texture->GetCreateInfo();
414 mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
416 mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
417 mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
421 info.srcExtent2D.width,
422 info.srcExtent2D.height,
423 GLES::GLTextureFormatType(createInfo.format).format,
424 GLES::GLTextureFormatType(createInfo.format).type,
425 source.memorySource.memory);
427 // free staging memory
428 free(source.memorySource.memory);
432 // TODO: other sources
435 mTextureUpdateRequests.pop();
439 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>& updateInfoList,
440 const std::vector<TextureUpdateSourceInfo>& sourceList)
443 for(auto& info : updateInfoList)
445 mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
446 auto& pair = mTextureUpdateRequests.back();
447 switch(pair.second.sourceType)
449 case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
451 auto& info = pair.first;
452 auto& source = pair.second;
454 // allocate staging memory and copy the data
455 // TODO: using PBO with GLES3, this is just naive
458 char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
459 std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
460 reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
463 // store staging buffer
464 source.memorySource.memory = stagingBuffer;
467 case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
469 // TODO, with PBO support
472 case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
474 // TODO texture 2 texture in-GPU copy
481 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
483 mGraphics->ActivateResourceContext();
485 // Mapping buffer requires the object to be created NOW
486 // Workaround - flush now, otherwise there will be given a staging buffer
487 // in case when the buffer is not there yet
488 ProcessCreateQueues();
490 if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
492 return Graphics::UniquePtr<Memory>(new GLES::Memory2(mapInfo, *this));
496 return Graphics::UniquePtr<Memory>(new GLES::Memory3(mapInfo, *this));
500 bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
502 return static_cast<GLES::Program*>(&program)->GetImplementation()->GetParameter(parameterId, outData);
505 GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
507 return *mPipelineCache;
510 } // namespace Dali::Graphics