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/adaptor-framework/render-surface-interface.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/gl-abstraction.h>
24 #include <dali/integration-api/gl-defines.h>
25 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
26 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
27 #include <dali/internal/graphics/gles-impl/gles-graphics-render-pass.h>
28 #include <dali/internal/graphics/gles-impl/gles-graphics-render-target.h>
29 #include <dali/internal/graphics/gles-impl/gles-graphics-shader.h>
30 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
31 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
32 #include <dali/internal/graphics/gles-impl/gles3-graphics-memory.h>
33 #include <dali/public-api/common/dali-common.h>
34 #include "gles-graphics-program.h"
36 namespace Dali::Graphics
41 * @brief Custom deleter for all Graphics objects created
42 * with use of the Controller.
44 * When Graphics object dies the unique pointer (Graphics::UniquePtr)
45 * doesn't destroy it directly but passes the ownership back
46 * to the Controller. The GLESDeleter is responsible for passing
47 * the object to the discard queue (by calling Resource::DiscardResource()).
52 GLESDeleter() = default;
54 void operator()(T* object)
56 // Discard resource (add it to discard queue)
57 object->DiscardResource();
62 * @brief Helper function allocating graphics object
64 * @param[in] info Create info structure
65 * @param[in] controller Controller object
66 * @param[out] out Unique pointer to the return object
68 template<class GLESType, class GfxCreateInfo, class T>
69 auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&& oldObject)
72 using Type = typename T::element_type;
73 using UPtr = Graphics::UniquePtr<Type>;
74 if(info.allocationCallbacks)
76 auto* memory = info.allocationCallbacks->allocCallback(
79 info.allocationCallbacks->userData);
80 return UPtr(new(memory) GLESType(info, controller), GLESDeleter<GLESType>());
82 else // Use standard allocator
84 return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
88 template<class T0, class T1>
89 T0* CastObject(T1* apiObject)
91 return static_cast<T0*>(apiObject);
96 EglGraphicsController::~EglGraphicsController() = default;
98 void EglGraphicsController::InitializeGLES(Integration::GlAbstraction& glAbstraction)
100 DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #1\n");
101 mGlAbstraction = &glAbstraction;
102 mContext = std::make_unique<GLES::Context>(*this);
105 void EglGraphicsController::Initialize(Integration::GlSyncAbstraction& glSyncAbstraction,
106 Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
107 Internal::Adaptor::GraphicsInterface& graphicsInterface)
109 DALI_LOG_RELEASE_INFO("Initializing New Graphics Controller #2\n");
110 mGlSyncAbstraction = &glSyncAbstraction;
111 mGlContextHelperAbstraction = &glContextHelperAbstraction;
112 mGraphics = &graphicsInterface;
115 void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
117 for(auto& cmdbuf : submitInfo.cmdBuffer)
119 // Push command buffers
120 mCommandQueue.push(static_cast<GLES::CommandBuffer*>(cmdbuf));
123 // If flush bit set, flush all pending tasks
124 if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
130 void EglGraphicsController::PresentRenderTarget(RenderTarget* renderTarget)
132 // Use command buffer to execute presentation (we should pool it)
133 CommandBufferCreateInfo info;
134 info.SetLevel(CommandBufferLevel::PRIMARY);
135 info.fixedCapacity = 1; // only one command
136 auto presentCommandBuffer = new GLES::CommandBuffer(info, *this);
137 presentCommandBuffer->PresentRenderTarget(static_cast<GLES::RenderTarget*>(renderTarget));
138 SubmitInfo submitInfo;
139 submitInfo.cmdBuffer = {presentCommandBuffer};
140 submitInfo.flags = 0 | SubmitFlagBits::FLUSH;
141 SubmitCommandBuffers(submitInfo);
144 void EglGraphicsController::ResolvePresentRenderTarget(GLES::RenderTarget* renderTarget)
146 auto* rt = static_cast<GLES::RenderTarget*>(renderTarget);
147 if(rt->GetCreateInfo().surface)
149 auto* surfaceInterface = reinterpret_cast<Dali::RenderSurfaceInterface*>(rt->GetCreateInfo().surface);
150 surfaceInterface->MakeContextCurrent();
151 surfaceInterface->PostRender();
155 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
157 DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
158 return *mGlAbstraction;
161 Integration::GlSyncAbstraction& EglGraphicsController::GetGlSyncAbstraction()
163 DALI_ASSERT_DEBUG(mGlSyncAbstraction && "Graphics controller not initialized");
164 return *mGlSyncAbstraction;
167 Integration::GlContextHelperAbstraction& EglGraphicsController::GetGlContextHelperAbstraction()
169 DALI_ASSERT_DEBUG(mGlContextHelperAbstraction && "Graphics controller not initialized");
170 return *mGlContextHelperAbstraction;
173 Graphics::UniquePtr<CommandBuffer> EglGraphicsController::CreateCommandBuffer(
174 const CommandBufferCreateInfo& commandBufferCreateInfo,
175 Graphics::UniquePtr<CommandBuffer>&& oldCommandBuffer)
177 return NewObject<GLES::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
180 Graphics::UniquePtr<RenderPass> EglGraphicsController::CreateRenderPass(const RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<RenderPass>&& oldRenderPass)
182 return NewObject<GLES::RenderPass>(renderPassCreateInfo, *this, std::move(oldRenderPass));
185 Graphics::UniquePtr<Texture>
186 EglGraphicsController::CreateTexture(const TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Texture>&& oldTexture)
188 return NewObject<GLES::Texture>(textureCreateInfo, *this, std::move(oldTexture));
191 Graphics::UniquePtr<Buffer> EglGraphicsController::CreateBuffer(
192 const BufferCreateInfo& bufferCreateInfo, Graphics::UniquePtr<Buffer>&& oldBuffer)
194 return NewObject<GLES::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
197 Graphics::UniquePtr<Framebuffer> EglGraphicsController::CreateFramebuffer(
198 const FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Framebuffer>&& oldFramebuffer)
200 return NewObject<GLES::Framebuffer>(framebufferCreateInfo, *this, std::move(oldFramebuffer));
203 Graphics::UniquePtr<Pipeline> EglGraphicsController::CreatePipeline(
204 const PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
206 // Create pipeline cache if needed
209 mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
212 return mPipelineCache->GetPipeline(pipelineCreateInfo, std::move(oldPipeline));
215 Graphics::UniquePtr<Program> EglGraphicsController::CreateProgram(
216 const ProgramCreateInfo& programCreateInfo, UniquePtr<Program>&& oldProgram)
218 // Create program cache if needed
221 mPipelineCache = std::make_unique<GLES::PipelineCache>(*this);
224 return mPipelineCache->GetProgram(programCreateInfo, std::move(oldProgram));
227 Graphics::UniquePtr<Shader> EglGraphicsController::CreateShader(const ShaderCreateInfo& shaderCreateInfo, Graphics::UniquePtr<Shader>&& oldShader)
229 return NewObject<GLES::Shader>(shaderCreateInfo, *this, std::move(oldShader));
232 Graphics::UniquePtr<Sampler> EglGraphicsController::CreateSampler(const SamplerCreateInfo& samplerCreateInfo, Graphics::UniquePtr<Sampler>&& oldSampler)
234 return NewObject<GLES::Sampler>(samplerCreateInfo, *this, std::move(oldSampler));
237 Graphics::UniquePtr<RenderTarget> EglGraphicsController::CreateRenderTarget(const RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<RenderTarget>&& oldRenderTarget)
239 return NewObject<GLES::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
242 const Graphics::Reflection& EglGraphicsController::GetProgramReflection(const Graphics::Program& program)
244 return static_cast<const Graphics::GLES::Program*>(&program)->GetReflection();
247 void EglGraphicsController::AddTexture(GLES::Texture& texture)
249 // Assuming we are on the correct context
250 mCreateTextureQueue.push(&texture);
253 void EglGraphicsController::AddBuffer(GLES::Buffer& buffer)
255 // Assuming we are on the correct context
256 mCreateBufferQueue.push(&buffer);
259 void EglGraphicsController::AddFramebuffer(GLES::Framebuffer& framebuffer)
261 // Assuming we are on the correct context
262 mCreateFramebufferQueue.push(&framebuffer);
265 void EglGraphicsController::ProcessDiscardQueues()
268 ProcessDiscardQueue<GLES::Texture>(mDiscardTextureQueue);
271 ProcessDiscardQueue<GLES::Buffer>(mDiscardBufferQueue);
273 // Process Framebuffers
274 ProcessDiscardQueue<GLES::Framebuffer>(mDiscardFramebufferQueue);
277 ProcessDiscardQueue<GLES::Pipeline>(mDiscardPipelineQueue);
280 ProcessDiscardQueue<GLES::Program>(mDiscardProgramQueue);
283 ProcessDiscardQueue<GLES::Shader>(mDiscardShaderQueue);
286 ProcessDiscardQueue<GLES::Sampler>(mDiscardSamplerQueue);
288 // Process command buffers
289 ProcessDiscardQueue<GLES::CommandBuffer>(mDiscardCommandBufferQueue);
292 void EglGraphicsController::ProcessCreateQueues()
295 ProcessCreateQueue(mCreateTextureQueue);
298 ProcessCreateQueue(mCreateBufferQueue);
300 // Process framebuffers
301 ProcessCreateQueue(mCreateFramebufferQueue);
304 void EglGraphicsController::ProcessCommandBuffer(GLES::CommandBuffer& commandBuffer)
306 for(auto& cmd : commandBuffer.GetCommands())
311 case GLES::CommandType::FLUSH:
313 // Nothing to do here
316 case GLES::CommandType::BIND_TEXTURES:
318 mContext->BindTextures(cmd.bindTextures.textureBindings);
321 case GLES::CommandType::BIND_VERTEX_BUFFERS:
323 auto& bindings = cmd.bindVertexBuffers.vertexBufferBindings;
324 mContext->BindVertexBuffers(bindings);
327 case GLES::CommandType::BIND_UNIFORM_BUFFER:
329 auto& bindings = cmd.bindUniformBuffers;
330 mContext->BindUniformBuffers(bindings.uniformBufferBindings, bindings.standaloneUniformsBufferBinding);
333 case GLES::CommandType::BIND_INDEX_BUFFER:
335 mContext->BindIndexBuffer(cmd.bindIndexBuffer);
338 case GLES::CommandType::BIND_SAMPLERS:
342 case GLES::CommandType::BIND_PIPELINE:
344 auto pipeline = static_cast<const GLES::Pipeline*>(cmd.bindPipeline.pipeline);
345 mContext->BindPipeline(pipeline);
348 case GLES::CommandType::DRAW:
350 mContext->Flush(false, cmd.draw);
353 case GLES::CommandType::DRAW_INDEXED:
355 mContext->Flush(false, cmd.draw);
358 case GLES::CommandType::DRAW_INDEXED_INDIRECT:
360 mContext->Flush(false, cmd.draw);
363 case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
365 mGlAbstraction->Scissor(cmd.scissor.region.x, cmd.scissor.region.y, cmd.scissor.region.width, cmd.scissor.region.height);
368 case GLES::CommandType::SET_SCISSOR_TEST:
370 if(cmd.scissorTest.enable)
372 mGlAbstraction->Enable(GL_SCISSOR_TEST);
376 mGlAbstraction->Disable(GL_SCISSOR_TEST);
380 case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
382 mGlAbstraction->Viewport(cmd.viewport.region.x, cmd.viewport.region.y, cmd.viewport.region.width, cmd.viewport.region.height);
385 case GLES::CommandType::BEGIN_RENDERPASS:
387 mContext->BeginRenderPass(cmd.beginRenderPass);
390 case GLES::CommandType::END_RENDERPASS:
392 mContext->EndRenderPass();
395 case GLES::CommandType::PRESENT_RENDER_TARGET:
397 ResolvePresentRenderTarget(cmd.presentRenderTarget.targetToPresent);
399 // push this command buffer to the discard queue
400 mDiscardCommandBufferQueue.push(&commandBuffer);
403 case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
405 // Process secondary command buffers
406 // todo: check validity of the secondaries
407 // there are operations which are illigal to be done
408 // within secondaries.
409 for(auto& buf : cmd.executeCommandBuffers.buffers)
411 ProcessCommandBuffer(*static_cast<GLES::CommandBuffer*>(buf));
419 void EglGraphicsController::ProcessCommandQueues()
421 // TODO: command queue per context, sync between queues should be
423 currentFramebuffer = nullptr;
425 while(!mCommandQueue.empty())
427 auto cmdBuf = mCommandQueue.front();
429 ProcessCommandBuffer(*cmdBuf);
433 void EglGraphicsController::ProcessTextureUpdateQueue()
435 while(!mTextureUpdateRequests.empty())
437 TextureUpdateRequest& request = mTextureUpdateRequests.front();
439 auto& info = request.first;
440 auto& source = request.second;
442 if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
444 // GPU memory must be already allocated (glTexImage2D())
445 auto* texture = static_cast<GLES::Texture*>(info.dstTexture);
446 const auto& createInfo = texture->GetCreateInfo();
448 mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
450 mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture());
451 mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D,
455 info.srcExtent2D.width,
456 info.srcExtent2D.height,
457 GLES::GLTextureFormatType(createInfo.format).format,
458 GLES::GLTextureFormatType(createInfo.format).type,
459 source.memorySource.memory);
461 // free staging memory
462 free(source.memorySource.memory);
466 // TODO: other sources
469 mTextureUpdateRequests.pop();
473 void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>& updateInfoList,
474 const std::vector<TextureUpdateSourceInfo>& sourceList)
477 for(auto& info : updateInfoList)
479 mTextureUpdateRequests.push(std::make_pair(info, sourceList[info.srcReference]));
480 auto& pair = mTextureUpdateRequests.back();
481 switch(pair.second.sourceType)
483 case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
485 auto& info = pair.first;
486 auto& source = pair.second;
488 // allocate staging memory and copy the data
489 // TODO: using PBO with GLES3, this is just naive
492 char* stagingBuffer = reinterpret_cast<char*>(malloc(info.srcSize));
493 std::copy(&reinterpret_cast<char*>(source.memorySource.memory)[info.srcOffset],
494 reinterpret_cast<char*>(source.memorySource.memory) + info.srcSize,
497 // store staging buffer
498 source.memorySource.memory = stagingBuffer;
501 case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
503 // TODO, with PBO support
506 case Graphics::TextureUpdateSourceInfo::Type::TEXTURE:
508 // TODO texture 2 texture in-GPU copy
515 Graphics::UniquePtr<Memory> EglGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
517 mGraphics->ActivateResourceContext();
519 // Mapping buffer requires the object to be created NOW
520 // Workaround - flush now, otherwise there will be given a staging buffer
521 // in case when the buffer is not there yet
522 ProcessCreateQueues();
524 if(GetGLESVersion() < GLES::GLESVersion::GLES_30)
526 return Graphics::UniquePtr<Memory>(new GLES::Memory2(mapInfo, *this));
530 return Graphics::UniquePtr<Memory>(new GLES::Memory3(mapInfo, *this));
534 bool EglGraphicsController::GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData)
536 return static_cast<GLES::Program*>(&program)->GetImplementation()->GetParameter(parameterId, outData);
539 GLES::PipelineCache& EglGraphicsController::GetPipelineCache() const
541 return *mPipelineCache;
544 } // namespace Dali::Graphics