2 * Copyright (c) 2023 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 "gles-context.h"
19 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
20 #include <dali/integration-api/debug.h>
21 #include <dali/integration-api/gl-abstraction.h>
22 #include <dali/integration-api/gl-defines.h>
23 #include <dali/internal/graphics/common/graphics-interface.h>
24 #include <dali/public-api/math/math-utils.h>
26 #include "egl-graphics-controller.h"
27 #include "gles-graphics-buffer.h"
28 #include "gles-graphics-pipeline.h"
29 #include "gles-graphics-program.h"
30 #include "gles-graphics-render-pass.h"
31 #include "gles-graphics-render-target.h"
32 #include "gles-texture-dependency-checker.h"
35 #include <EGL/eglext.h>
37 #include <unordered_map>
39 namespace Dali::Graphics::GLES
43 explicit Impl(EglGraphicsController& controller)
44 : mController(controller)
51 * Binds (and creates) VAO
53 * VAO is fixed per program so it has to be created only once assuming
54 * that VertexInputState has been set correctly for the pipeline.
57 void BindProgramVAO(const GLES::ProgramImpl* program, const VertexInputState& vertexInputState)
59 // Calculate attributes location hash unordered.
61 for(const auto& attr : vertexInputState.attributes)
63 // Make unordered hash value by location.
64 // Note : This hash function varified for locations only under < 20.
65 std::size_t salt = attr.location + 1;
66 hash += salt << (sizeof(std::size_t) * 6);
68 salt ^= attr.location;
69 hash += salt << (sizeof(std::size_t) * 4);
74 auto& gl = *mController.GetGL();
76 if(DALI_UNLIKELY(!mDiscardedVAOList.empty()))
78 gl.DeleteVertexArrays(static_cast<Dali::GLsizei>(mDiscardedVAOList.size()), mDiscardedVAOList.data());
79 mDiscardedVAOList.clear();
82 auto iter = mProgramVAOMap.find(program);
83 if(iter != mProgramVAOMap.end())
85 auto attributeIter = iter->second.find(hash);
86 if(attributeIter != iter->second.end())
88 if(mProgramVAOCurrentState != attributeIter->second)
90 mProgramVAOCurrentState = attributeIter->second;
91 gl.BindVertexArray(attributeIter->second);
93 // Binding VAO seems to reset the index buffer binding so the cache must be reset
94 mGlStateCache.mBoundElementArrayBufferId = 0;
101 gl.GenVertexArrays(1, &vao);
102 gl.BindVertexArray(vao);
104 // Binding VAO seems to reset the index buffer binding so the cache must be reset
105 mGlStateCache.mBoundElementArrayBufferId = 0;
107 mProgramVAOMap[program][hash] = vao;
108 for(const auto& attr : vertexInputState.attributes)
110 gl.EnableVertexAttribArray(attr.location);
113 mProgramVAOCurrentState = vao;
117 * Sets the initial GL state.
119 void InitializeGlState()
121 auto& gl = *mController.GetGL();
123 mGlStateCache.mClearColorSet = false;
124 mGlStateCache.mColorMask = true;
125 mGlStateCache.mStencilMask = 0xFF;
126 mGlStateCache.mBlendEnabled = false;
127 mGlStateCache.mDepthBufferEnabled = false;
128 mGlStateCache.mDepthMaskEnabled = false;
129 mGlStateCache.mScissorTestEnabled = false;
130 mGlStateCache.mStencilBufferEnabled = false;
132 gl.Disable(GL_DITHER);
134 mGlStateCache.mBoundArrayBufferId = 0;
135 mGlStateCache.mBoundElementArrayBufferId = 0;
136 mGlStateCache.mActiveTextureUnit = 0;
138 mGlStateCache.mBlendFuncSeparateSrcRGB = BlendFactor::ONE;
139 mGlStateCache.mBlendFuncSeparateDstRGB = BlendFactor::ZERO;
140 mGlStateCache.mBlendFuncSeparateSrcAlpha = BlendFactor::ONE;
141 mGlStateCache.mBlendFuncSeparateDstAlpha = BlendFactor::ZERO;
143 // initial state is GL_FUNC_ADD for both RGB and Alpha blend modes
144 mGlStateCache.mBlendEquationSeparateModeRGB = BlendOp::ADD;
145 mGlStateCache.mBlendEquationSeparateModeAlpha = BlendOp::ADD;
147 mGlStateCache.mCullFaceMode = CullMode::NONE; //By default cullface is disabled, front face is set to CCW and cull face is set to back
149 //Initialze vertex attribute cache
150 memset(&mGlStateCache.mVertexAttributeCachedState, 0, sizeof(mGlStateCache.mVertexAttributeCachedState));
151 memset(&mGlStateCache.mVertexAttributeCurrentState, 0, sizeof(mGlStateCache.mVertexAttributeCurrentState));
153 //Initialize bound 2d texture cache
154 memset(&mGlStateCache.mBoundTextureId, 0, sizeof(mGlStateCache.mBoundTextureId));
156 mGlStateCache.mFrameBufferStateCache.Reset();
159 gl.GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextures);
160 DALI_LOG_RELEASE_INFO("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d\n", maxTextures);
164 * Flushes vertex attribute location changes to the driver
166 void FlushVertexAttributeLocations()
168 auto& gl = *mController.GetGL();
170 for(unsigned int i = 0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i)
172 // see if the cached state is different to the actual state
173 if(mGlStateCache.mVertexAttributeCurrentState[i] != mGlStateCache.mVertexAttributeCachedState[i])
175 // it's different so make the change to the driver and update the cached state
176 mGlStateCache.mVertexAttributeCurrentState[i] = mGlStateCache.mVertexAttributeCachedState[i];
178 if(mGlStateCache.mVertexAttributeCurrentState[i])
180 gl.EnableVertexAttribArray(i);
184 gl.DisableVertexAttribArray(i);
191 * Either enables or disables a vertex attribute location in the cache
192 * The cahnges won't take affect until FlushVertexAttributeLocations is called
193 * @param location attribute location
194 * @param state attribute state
196 void SetVertexAttributeLocation(unsigned int location, bool state)
198 auto& gl = *mController.GetGL();
200 if(location >= MAX_ATTRIBUTE_CACHE_SIZE)
202 // not cached, make the gl call through context
205 gl.EnableVertexAttribArray(location);
209 gl.DisableVertexAttribArray(location);
214 // set the cached state, it will be set at the next draw call
215 // if it's different from the current driver state
216 mGlStateCache.mVertexAttributeCachedState[location] = state;
220 EglGraphicsController& mController;
222 const GLES::PipelineImpl* mCurrentPipeline{nullptr}; ///< Currently bound pipeline
223 const GLES::PipelineImpl* mNewPipeline{nullptr}; ///< New pipeline to be set on flush
225 std::vector<Graphics::TextureBinding> mCurrentTextureBindings{};
226 std::vector<Graphics::SamplerBinding> mCurrentSamplerBindings{};
227 GLES::IndexBufferBindingDescriptor mCurrentIndexBufferBinding{};
229 struct VertexBufferBinding
231 GLES::Buffer* buffer{nullptr};
235 // Currently bound buffers
236 std::vector<VertexBufferBindingDescriptor> mCurrentVertexBufferBindings{};
238 // Currently bound UBOs (check if it's needed per program!)
239 std::vector<UniformBufferBindingDescriptor> mCurrentUBOBindings{};
240 UniformBufferBindingDescriptor mCurrentStandaloneUBOBinding{};
242 // Current render pass and render target
243 const GLES::RenderTarget* mCurrentRenderTarget{nullptr};
244 const GLES::RenderPass* mCurrentRenderPass{nullptr};
246 // Each context must have own VAOs as they cannot be shared
247 std::unordered_map<const GLES::ProgramImpl*, std::map<std::size_t, uint32_t>> mProgramVAOMap; ///< GL program-VAO map
248 uint32_t mProgramVAOCurrentState{0u}; ///< Currently bound VAO
249 GLStateCache mGlStateCache{}; ///< GL status cache
250 std::vector<Dali::GLuint> mDiscardedVAOList{};
252 bool mGlContextCreated{false}; ///< True if the OpenGL context has been created
253 bool mVertexBuffersChanged{true}; ///< True if BindVertexBuffers changed any buffer bindings
255 EGLContext mNativeDrawContext{0u}; ///< Native rendering EGL context compatible with window context
257 EGLSurface mCacheDrawReadSurface{0u}; ///< cached 'read' surface
258 EGLSurface mCacheDrawWriteSurface{0u}; ///< cached 'write' surface
259 EGLContext mCacheEGLGraphicsContext{0u}; ///< cached window context
262 Context::Context(EglGraphicsController& controller)
264 mImpl = std::make_unique<Impl>(controller);
269 // Destroy native rendering context if one exists
270 if(mImpl->mNativeDrawContext)
272 eglDestroyContext(eglGetCurrentDisplay(), mImpl->mNativeDrawContext);
273 mImpl->mNativeDrawContext = EGL_NO_CONTEXT;
277 void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES::TextureDependencyChecker& dependencyChecker)
279 auto& gl = *mImpl->mController.GetGL();
281 static const bool hasGLES3(mImpl->mController.GetGLESVersion() >= GLESVersion::GLES_30);
283 // early out if neither current nor new pipelines are set
284 // this behaviour may be valid so no assert
285 if(!mImpl->mCurrentPipeline && !mImpl->mNewPipeline)
290 // Execute states if pipeline is changed
291 const auto currentProgram = mImpl->mCurrentPipeline ? static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program) : nullptr;
293 // case when new pipeline has been set
294 const GLES::Program* newProgram = nullptr;
296 if(mImpl->mNewPipeline)
298 newProgram = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
301 if(!currentProgram && !newProgram)
303 // Early out if we have no program for this pipeline.
304 DALI_LOG_ERROR("No program defined for pipeline\n");
308 // If this draw uses a different pipeline _AND_ the pipeline has a different GL Program,
309 // Then bind the new program. Ensure vertex atrributes are set.
311 bool programChanged = false;
312 if(mImpl->mNewPipeline && mImpl->mCurrentPipeline != mImpl->mNewPipeline)
314 if(!currentProgram || currentProgram->GetImplementation()->GetGlProgram() != newProgram->GetImplementation()->GetGlProgram())
316 mImpl->mNewPipeline->Bind(newProgram->GetImplementation()->GetGlProgram());
317 programChanged = true;
323 // Resolve rasterization state
324 ResolveRasterizationState();
327 // Resolve uniform buffers
328 ResolveUniformBuffers();
331 // Map binding# to sampler location
332 const auto& reflection = !newProgram ? currentProgram->GetReflection() : newProgram->GetReflection();
333 const auto& samplers = reflection.GetSamplers();
335 uint32_t currentSampler = 0;
336 uint32_t currentElement = 0;
338 // @warning Assume that binding.binding is strictly linear in the same order as mCurrentTextureBindings
339 // elements. This avoids having to sort the bindings.
340 for(const auto& binding : mImpl->mCurrentTextureBindings)
342 if(currentSampler >= samplers.size())
344 // Don't bind more textures than there are active samplers.
348 auto texture = const_cast<GLES::Texture*>(static_cast<const GLES::Texture*>(binding.texture));
350 // Texture may not have been initialized yet...(tbm_surface timing issue?)
351 if(!texture->GetGLTexture())
353 texture->InitializeResource();
356 // Warning, this may cause glWaitSync to occur on the GPU.
357 dependencyChecker.CheckNeedsSync(this, texture);
358 texture->Bind(binding);
363 // @warning Assume that location of array elements is sequential.
364 // @warning GL does not guarantee this, but in practice, it is.
365 gl.Uniform1i(samplers[currentSampler].location + currentElement,
366 samplers[currentSampler].offset + currentElement);
368 if(currentElement >= samplers[currentSampler].elementCount)
376 const auto& pipelineState = mImpl->mNewPipeline ? mImpl->mNewPipeline->GetCreateInfo() : mImpl->mCurrentPipeline->GetCreateInfo();
377 const auto& vertexInputState = pipelineState.vertexInputState;
379 // for each attribute bind vertices, unless the pipeline+buffer is the same
380 if(programChanged || mImpl->mVertexBuffersChanged)
384 mImpl->BindProgramVAO(static_cast<const GLES::Program*>(pipelineState.programState->program)->GetImplementation(), *vertexInputState);
387 for(const auto& attr : vertexInputState->attributes)
392 mImpl->SetVertexAttributeLocation(attr.location, true);
395 const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding];
396 const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding];
398 auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
400 BindBuffer(GL_ARRAY_BUFFER, glesBuffer); // Cached
402 if(attr.format == VertexInputFormat::FLOAT ||
403 attr.format == VertexInputFormat::FVECTOR2 ||
404 attr.format == VertexInputFormat::FVECTOR3 ||
405 attr.format == VertexInputFormat::FVECTOR4)
407 gl.VertexAttribPointer(attr.location, // Not cached...
408 GLVertexFormat(attr.format).size,
409 GLVertexFormat(attr.format).format,
411 bufferBinding.stride,
412 reinterpret_cast<void*>(attr.offset));
416 gl.VertexAttribIPointer(attr.location,
417 GLVertexFormat(attr.format).size,
418 GLVertexFormat(attr.format).format,
419 bufferBinding.stride,
420 reinterpret_cast<void*>(attr.offset));
425 switch(bufferBinding.inputRate)
427 case Graphics::VertexInputRate::PER_VERTEX:
429 gl.VertexAttribDivisor(attr.location, 0);
432 case Graphics::VertexInputRate::PER_INSTANCE:
434 //@todo Get actual instance rate...
435 gl.VertexAttribDivisor(attr.location, 1);
444 const auto& ia = pipelineState.inputAssemblyState;
447 switch(drawCall.type)
449 case DrawCallDescriptor::Type::DRAW:
451 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
452 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
453 mImpl->mGlStateCache.StencilBufferWriteEnabled());
454 // For GLES3+ we use VAO, for GLES2 internal cache
457 mImpl->FlushVertexAttributeLocations();
460 if(drawCall.draw.instanceCount == 0)
462 gl.DrawArrays(GLESTopology(ia->topology),
463 drawCall.draw.firstVertex,
464 drawCall.draw.vertexCount);
468 gl.DrawArraysInstanced(GLESTopology(ia->topology),
469 drawCall.draw.firstVertex,
470 drawCall.draw.vertexCount,
471 drawCall.draw.instanceCount);
475 case DrawCallDescriptor::Type::DRAW_INDEXED:
477 const auto& binding = mImpl->mCurrentIndexBufferBinding;
478 BindBuffer(GL_ELEMENT_ARRAY_BUFFER, binding.buffer->GetGLBuffer());
480 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
481 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
482 mImpl->mGlStateCache.StencilBufferWriteEnabled());
484 // For GLES3+ we use VAO, for GLES2 internal cache
487 mImpl->FlushVertexAttributeLocations();
490 auto indexBufferFormat = GLIndexFormat(binding.format).format;
491 if(drawCall.drawIndexed.instanceCount == 0)
493 gl.DrawElements(GLESTopology(ia->topology),
494 drawCall.drawIndexed.indexCount,
496 reinterpret_cast<void*>(binding.offset));
500 gl.DrawElementsInstanced(GLESTopology(ia->topology),
501 drawCall.drawIndexed.indexCount,
503 reinterpret_cast<void*>(binding.offset),
504 drawCall.drawIndexed.instanceCount);
508 case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
517 if(mImpl->mNewPipeline)
519 mImpl->mCurrentPipeline = mImpl->mNewPipeline;
520 mImpl->mNewPipeline = nullptr;
524 void Context::BindTextures(const Graphics::TextureBinding* bindings, uint32_t count)
526 // for each texture allocate slot
527 for(auto i = 0u; i < count; ++i)
529 auto& binding = bindings[i];
531 // Resize binding array if needed
532 if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
534 mImpl->mCurrentTextureBindings.resize(binding.binding + 1);
536 // Store the binding details
537 mImpl->mCurrentTextureBindings[binding.binding] = binding;
541 void Context::BindVertexBuffers(const GLES::VertexBufferBindingDescriptor* bindings, uint32_t count)
543 if(count > mImpl->mCurrentVertexBufferBindings.size())
545 mImpl->mCurrentVertexBufferBindings.resize(count);
547 // Copy only set slots
548 mImpl->mVertexBuffersChanged = false;
549 auto toIter = mImpl->mCurrentVertexBufferBindings.begin();
550 for(auto fromIter = bindings, end = bindings + count; fromIter != end; ++fromIter)
552 if(fromIter->buffer != nullptr)
554 if(toIter->buffer != fromIter->buffer || toIter->offset != fromIter->offset)
556 mImpl->mVertexBuffersChanged = true;
558 *toIter++ = *fromIter;
563 void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding)
565 mImpl->mCurrentIndexBufferBinding = indexBufferBinding;
568 void Context::BindPipeline(const GLES::Pipeline* newPipeline)
570 DALI_ASSERT_ALWAYS(newPipeline && "Invalid pipeline");
571 mImpl->mNewPipeline = &newPipeline->GetPipeline();
574 void Context::BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindings,
576 const UniformBufferBindingDescriptor& standaloneBindings)
578 if(standaloneBindings.buffer)
580 mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
583 if(uboCount && uboCount > mImpl->mCurrentUBOBindings.size())
585 mImpl->mCurrentUBOBindings.resize(uboCount);
588 auto it = uboBindings;
589 for(auto i = 0u; i < uboCount; ++i)
593 mImpl->mCurrentUBOBindings[i] = *it;
599 void Context::ResolveBlendState()
601 const auto& currentBlendState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().colorBlendState : nullptr;
602 const auto& newBlendState = mImpl->mNewPipeline->GetCreateInfo().colorBlendState;
604 // TODO: prevent leaking the state
610 auto& gl = *mImpl->mController.GetGL();
612 if(!currentBlendState || currentBlendState->blendEnable != newBlendState->blendEnable)
614 if(newBlendState->blendEnable != mImpl->mGlStateCache.mBlendEnabled)
616 mImpl->mGlStateCache.mBlendEnabled = newBlendState->blendEnable;
617 newBlendState->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND);
621 if(!newBlendState->blendEnable)
626 BlendFactor newSrcRGB(newBlendState->srcColorBlendFactor);
627 BlendFactor newDstRGB(newBlendState->dstColorBlendFactor);
628 BlendFactor newSrcAlpha(newBlendState->srcAlphaBlendFactor);
629 BlendFactor newDstAlpha(newBlendState->dstAlphaBlendFactor);
631 if(!currentBlendState ||
632 currentBlendState->srcColorBlendFactor != newSrcRGB ||
633 currentBlendState->dstColorBlendFactor != newDstRGB ||
634 currentBlendState->srcAlphaBlendFactor != newSrcAlpha ||
635 currentBlendState->dstAlphaBlendFactor != newDstAlpha)
637 if((mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB != newSrcRGB) ||
638 (mImpl->mGlStateCache.mBlendFuncSeparateDstRGB != newDstRGB) ||
639 (mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha != newSrcAlpha) ||
640 (mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha != newDstAlpha))
642 mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB = newSrcRGB;
643 mImpl->mGlStateCache.mBlendFuncSeparateDstRGB = newDstRGB;
644 mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha = newSrcAlpha;
645 mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha = newDstAlpha;
647 if(newSrcRGB == newSrcAlpha && newDstRGB == newDstAlpha)
649 gl.BlendFunc(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB));
653 gl.BlendFuncSeparate(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB), GLBlendFunc(newSrcAlpha), GLBlendFunc(newDstAlpha));
658 if(!currentBlendState ||
659 currentBlendState->colorBlendOp != newBlendState->colorBlendOp ||
660 currentBlendState->alphaBlendOp != newBlendState->alphaBlendOp)
662 if(mImpl->mGlStateCache.mBlendEquationSeparateModeRGB != newBlendState->colorBlendOp ||
663 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha != newBlendState->alphaBlendOp)
665 mImpl->mGlStateCache.mBlendEquationSeparateModeRGB = newBlendState->colorBlendOp;
666 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha = newBlendState->alphaBlendOp;
668 if(newBlendState->colorBlendOp == newBlendState->alphaBlendOp)
670 gl.BlendEquation(GLBlendOp(newBlendState->colorBlendOp));
671 if(newBlendState->colorBlendOp >= Graphics::ADVANCED_BLEND_OPTIONS_START)
678 gl.BlendEquationSeparate(GLBlendOp(newBlendState->colorBlendOp), GLBlendOp(newBlendState->alphaBlendOp));
684 void Context::ResolveRasterizationState()
686 const auto& currentRasterizationState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().rasterizationState : nullptr;
687 const auto& newRasterizationState = mImpl->mNewPipeline->GetCreateInfo().rasterizationState;
689 // TODO: prevent leaking the state
690 if(!newRasterizationState)
695 auto& gl = *mImpl->mController.GetGL();
697 if(!currentRasterizationState ||
698 currentRasterizationState->cullMode != newRasterizationState->cullMode)
700 if(mImpl->mGlStateCache.mCullFaceMode != newRasterizationState->cullMode)
702 mImpl->mGlStateCache.mCullFaceMode = newRasterizationState->cullMode;
703 if(newRasterizationState->cullMode == CullMode::NONE)
705 gl.Disable(GL_CULL_FACE);
709 gl.Enable(GL_CULL_FACE);
710 gl.CullFace(GLCullMode(newRasterizationState->cullMode));
714 // TODO: implement polygon mode (fill, line, points)
715 // seems like we don't support it (no glPolygonMode())
718 void Context::ResolveUniformBuffers()
720 // Resolve standalone uniforms if we have binding
721 if(mImpl->mCurrentStandaloneUBOBinding.buffer)
723 ResolveStandaloneUniforms();
725 if(!mImpl->mCurrentUBOBindings.empty())
727 ResolveGpuUniformBuffers();
731 void Context::ResolveGpuUniformBuffers()
733 auto& gl = *mImpl->mController.GetGL();
735 for(auto& binding : mImpl->mCurrentUBOBindings)
737 gl.BindBufferRange(GL_UNIFORM_BUFFER, i++, binding.buffer->GetGLBuffer(), GLintptr(binding.offset), GLintptr(binding.dataSize));
741 void Context::ResolveStandaloneUniforms()
743 // Find reflection for program
744 const GLES::Program* program{nullptr};
746 if(mImpl->mNewPipeline)
748 program = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
750 else if(mImpl->mCurrentPipeline)
752 program = static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program);
757 const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset;
758 // Update program uniforms
759 program->GetImplementation()->UpdateStandaloneUniformBlock(ptr);
763 void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
765 auto& renderPass = *renderPassBegin.renderPass;
766 auto& renderTarget = *renderPassBegin.renderTarget;
768 const auto& targetInfo = renderTarget.GetCreateInfo();
770 auto& gl = *mImpl->mController.GetGL();
772 if(targetInfo.surface)
775 BindFrameBuffer(GL_FRAMEBUFFER, 0);
777 else if(targetInfo.framebuffer)
779 // bind framebuffer and swap.
780 auto framebuffer = renderTarget.GetFramebuffer();
784 // clear (ideally cache the setup)
786 // In GL we assume that the last attachment is depth/stencil (we may need
787 // to cache extra information inside GLES RenderTarget if we want to be
788 // more specific in case of MRT)
790 const auto& attachments = *renderPass.GetCreateInfo().attachments;
791 const auto& color0 = attachments[0];
794 if(color0.loadOp == AttachmentLoadOp::CLEAR)
796 mask |= GL_COLOR_BUFFER_BIT;
799 // Something goes wrong here if Alpha mask is GL_TRUE
802 const auto clearValues = renderPassBegin.clearValues.Ptr();
804 if(!Dali::Equals(mImpl->mGlStateCache.mClearColor.r, clearValues[0].color.r) ||
805 !Dali::Equals(mImpl->mGlStateCache.mClearColor.g, clearValues[0].color.g) ||
806 !Dali::Equals(mImpl->mGlStateCache.mClearColor.b, clearValues[0].color.b) ||
807 !Dali::Equals(mImpl->mGlStateCache.mClearColor.a, clearValues[0].color.a) ||
808 !mImpl->mGlStateCache.mClearColorSet)
810 gl.ClearColor(clearValues[0].color.r,
811 clearValues[0].color.g,
812 clearValues[0].color.b,
813 clearValues[0].color.a);
815 mImpl->mGlStateCache.mClearColorSet = true;
816 mImpl->mGlStateCache.mClearColor = Vector4(clearValues[0].color.r,
817 clearValues[0].color.g,
818 clearValues[0].color.b,
819 clearValues[0].color.a);
823 // check for depth stencil
824 if(attachments.size() > 1)
826 const auto& depthStencil = attachments.back();
827 if(depthStencil.loadOp == AttachmentLoadOp::CLEAR)
829 if(!mImpl->mGlStateCache.mDepthMaskEnabled)
831 mImpl->mGlStateCache.mDepthMaskEnabled = true;
834 mask |= GL_DEPTH_BUFFER_BIT;
836 if(depthStencil.stencilLoadOp == AttachmentLoadOp::CLEAR)
838 if(mImpl->mGlStateCache.mStencilMask != 0xFF)
840 mImpl->mGlStateCache.mStencilMask = 0xFF;
841 gl.StencilMask(0xFF);
843 mask |= GL_STENCIL_BUFFER_BIT;
847 SetScissorTestEnabled(true);
848 gl.Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height);
849 ClearBuffer(mask, true);
850 SetScissorTestEnabled(false);
852 mImpl->mCurrentRenderPass = &renderPass;
853 mImpl->mCurrentRenderTarget = &renderTarget;
856 void Context::EndRenderPass(GLES::TextureDependencyChecker& dependencyChecker)
858 if(mImpl->mCurrentRenderTarget)
860 GLES::Framebuffer* framebuffer = mImpl->mCurrentRenderTarget->GetFramebuffer();
863 auto& gl = *mImpl->mController.GetGL();
866 /* @todo Full dependency checking would need to store textures in Begin, and create
867 * fence objects here; but we're going to draw all fbos on shared context in serial,
868 * so no real need (yet). Might want to consider ensuring order of render passes,
869 * but that needs doing in the controller, and would need doing before ProcessCommandQueues.
871 * Currently up to the client to create render tasks in the right order.
874 /* Create fence sync objects. Other contexts can then wait on these fences before reading
877 dependencyChecker.AddTextures(this, framebuffer);
882 void Context::ClearState()
884 mImpl->mCurrentTextureBindings.clear();
885 mImpl->mCurrentUBOBindings.clear();
888 void Context::ColorMask(bool enabled)
890 if(enabled != mImpl->mGlStateCache.mColorMask)
892 mImpl->mGlStateCache.mColorMask = enabled;
894 auto& gl = *mImpl->mController.GetGL();
895 gl.ColorMask(enabled, enabled, enabled, enabled);
899 void Context::ClearStencilBuffer()
901 ClearBuffer(GL_STENCIL_BUFFER_BIT, false);
904 void Context::ClearDepthBuffer()
906 ClearBuffer(GL_DEPTH_BUFFER_BIT, false);
909 void Context::ClearBuffer(uint32_t mask, bool forceClear)
911 mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled);
914 auto& gl = *mImpl->mController.GetGL();
919 void Context::InvalidateDepthStencilBuffers()
921 auto& gl = *mImpl->mController.GetGL();
923 GLenum attachments[] = {GL_DEPTH, GL_STENCIL};
924 gl.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
927 void Context::SetScissorTestEnabled(bool scissorEnabled)
929 if(mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled)
931 mImpl->mGlStateCache.mScissorTestEnabled = scissorEnabled;
933 auto& gl = *mImpl->mController.GetGL();
936 gl.Enable(GL_SCISSOR_TEST);
940 gl.Disable(GL_SCISSOR_TEST);
945 void Context::SetStencilTestEnable(bool stencilEnable)
947 if(stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled)
949 mImpl->mGlStateCache.mStencilBufferEnabled = stencilEnable;
951 auto& gl = *mImpl->mController.GetGL();
954 gl.Enable(GL_STENCIL_TEST);
958 gl.Disable(GL_STENCIL_TEST);
963 void Context::StencilMask(uint32_t writeMask)
965 if(writeMask != mImpl->mGlStateCache.mStencilMask)
967 mImpl->mGlStateCache.mStencilMask = writeMask;
969 auto& gl = *mImpl->mController.GetGL();
970 gl.StencilMask(writeMask);
974 void Context::StencilFunc(Graphics::CompareOp compareOp,
976 uint32_t compareMask)
978 if(compareOp != mImpl->mGlStateCache.mStencilFunc ||
979 reference != mImpl->mGlStateCache.mStencilFuncRef ||
980 compareMask != mImpl->mGlStateCache.mStencilFuncMask)
982 mImpl->mGlStateCache.mStencilFunc = compareOp;
983 mImpl->mGlStateCache.mStencilFuncRef = reference;
984 mImpl->mGlStateCache.mStencilFuncMask = compareMask;
986 auto& gl = *mImpl->mController.GetGL();
987 gl.StencilFunc(GLCompareOp(compareOp).op, reference, compareMask);
991 void Context::StencilOp(Graphics::StencilOp failOp,
992 Graphics::StencilOp depthFailOp,
993 Graphics::StencilOp passOp)
995 if(failOp != mImpl->mGlStateCache.mStencilOpFail ||
996 depthFailOp != mImpl->mGlStateCache.mStencilOpDepthFail ||
997 passOp != mImpl->mGlStateCache.mStencilOpDepthPass)
999 mImpl->mGlStateCache.mStencilOpFail = failOp;
1000 mImpl->mGlStateCache.mStencilOpDepthFail = depthFailOp;
1001 mImpl->mGlStateCache.mStencilOpDepthPass = passOp;
1003 auto& gl = *mImpl->mController.GetGL();
1004 gl.StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op);
1008 void Context::SetDepthCompareOp(Graphics::CompareOp compareOp)
1010 if(compareOp != mImpl->mGlStateCache.mDepthFunction)
1012 mImpl->mGlStateCache.mDepthFunction = compareOp;
1013 auto& gl = *mImpl->mController.GetGL();
1014 gl.DepthFunc(GLCompareOp(compareOp).op);
1018 void Context::SetDepthTestEnable(bool depthTestEnable)
1020 if(depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled)
1022 mImpl->mGlStateCache.mDepthBufferEnabled = depthTestEnable;
1024 auto& gl = *mImpl->mController.GetGL();
1027 gl.Enable(GL_DEPTH_TEST);
1031 gl.Disable(GL_DEPTH_TEST);
1036 void Context::SetDepthWriteEnable(bool depthWriteEnable)
1038 if(depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled)
1040 mImpl->mGlStateCache.mDepthMaskEnabled = depthWriteEnable;
1042 auto& gl = *mImpl->mController.GetGL();
1043 gl.DepthMask(depthWriteEnable);
1047 void Context::ActiveTexture(uint32_t textureBindingIndex)
1049 if(mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex)
1051 mImpl->mGlStateCache.mActiveTextureUnit = textureBindingIndex;
1053 auto& gl = *mImpl->mController.GetGL();
1054 gl.ActiveTexture(GL_TEXTURE0 + textureBindingIndex);
1058 void Context::BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId)
1060 uint32_t typeId = static_cast<uint32_t>(textureTypeId);
1061 if(mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] != textureId)
1063 mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] = textureId;
1065 auto& gl = *mImpl->mController.GetGL();
1066 gl.BindTexture(target, textureId);
1070 void Context::GenerateMipmap(GLenum target)
1072 auto& gl = *mImpl->mController.GetGL();
1073 gl.GenerateMipmap(target);
1076 bool Context::BindBuffer(GLenum target, uint32_t bufferId)
1080 case GL_ARRAY_BUFFER:
1082 if(mImpl->mGlStateCache.mBoundArrayBufferId == bufferId)
1086 mImpl->mGlStateCache.mBoundArrayBufferId = bufferId;
1089 case GL_ELEMENT_ARRAY_BUFFER:
1091 if(mImpl->mGlStateCache.mBoundElementArrayBufferId == bufferId)
1095 mImpl->mGlStateCache.mBoundElementArrayBufferId = bufferId;
1100 // Cache miss. Bind buffer.
1101 auto& gl = *mImpl->mController.GetGL();
1102 gl.BindBuffer(target, bufferId);
1106 void Context::DrawBuffers(uint32_t count, const GLenum* buffers)
1108 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
1109 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
1110 mImpl->mGlStateCache.StencilBufferWriteEnabled());
1112 auto& gl = *mImpl->mController.GetGL();
1113 gl.DrawBuffers(count, buffers);
1116 void Context::BindFrameBuffer(GLenum target, uint32_t bufferId)
1118 mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId);
1120 auto& gl = *mImpl->mController.GetGL();
1121 gl.BindFramebuffer(target, bufferId);
1124 void Context::GenFramebuffers(uint32_t count, uint32_t* framebuffers)
1126 auto& gl = *mImpl->mController.GetGL();
1127 gl.GenFramebuffers(count, framebuffers);
1129 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersCreated(count, framebuffers);
1132 void Context::DeleteFramebuffers(uint32_t count, uint32_t* framebuffers)
1134 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers);
1136 auto& gl = *mImpl->mController.GetGL();
1137 gl.DeleteFramebuffers(count, framebuffers);
1140 GLStateCache& Context::GetGLStateCache()
1142 return mImpl->mGlStateCache;
1145 void Context::GlContextCreated()
1147 if(!mImpl->mGlContextCreated)
1149 mImpl->mGlContextCreated = true;
1151 // Set the initial GL state
1152 mImpl->InitializeGlState();
1156 void Context::GlContextDestroyed()
1158 mImpl->mGlContextCreated = false;
1161 void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline)
1163 // Since the pipeline is deleted, invalidate the cached pipeline.
1164 if(mImpl->mCurrentPipeline == &pipeline->GetPipeline())
1166 mImpl->mCurrentPipeline = nullptr;
1169 // Remove cached VAO map
1170 auto* gl = mImpl->mController.GetGL();
1173 const auto* program = pipeline->GetCreateInfo().programState->program;
1176 const auto* programImpl = static_cast<const GLES::Program*>(program)->GetImplementation();
1179 auto iter = mImpl->mProgramVAOMap.find(programImpl);
1180 if(iter != mImpl->mProgramVAOMap.end())
1182 for(auto& attributeHashPair : iter->second)
1184 auto vao = attributeHashPair.second;
1186 // Do not delete vao now. (Since Context might not be current.)
1187 mImpl->mDiscardedVAOList.emplace_back(vao);
1188 if(mImpl->mProgramVAOCurrentState == vao)
1190 mImpl->mProgramVAOCurrentState = 0u;
1194 // Clear cached Vertex buffer.
1195 mImpl->mCurrentVertexBufferBindings.clear();
1197 mImpl->mProgramVAOMap.erase(iter);
1204 void Context::PrepareForNativeRendering()
1206 // this should be pretty much constant
1207 auto display = eglGetCurrentDisplay();
1208 auto drawSurface = eglGetCurrentSurface(EGL_DRAW);
1209 auto readSurface = eglGetCurrentSurface(EGL_READ);
1210 auto context = eglGetCurrentContext();
1212 // push the surface and context data to the impl
1213 // It's needed to restore context
1214 if(!mImpl->mCacheEGLGraphicsContext)
1216 mImpl->mCacheDrawWriteSurface = drawSurface;
1217 mImpl->mCacheDrawReadSurface = readSurface;
1218 mImpl->mCacheEGLGraphicsContext = context;
1221 if(!mImpl->mNativeDrawContext)
1223 EGLint configId{0u};
1224 eglQueryContext(display, mImpl->mController.GetSharedContext(), EGL_CONFIG_ID, &configId);
1226 EGLint configAttribs[3];
1227 configAttribs[0] = EGL_CONFIG_ID;
1228 configAttribs[1] = configId;
1229 configAttribs[2] = EGL_NONE;
1233 if(eglChooseConfig(display, configAttribs, &config, 1, &numConfigs) != EGL_TRUE)
1235 DALI_LOG_ERROR("eglChooseConfig failed!\n");
1239 auto version = int(mImpl->mController.GetGLESVersion());
1241 std::vector<EGLint> attribs;
1242 attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
1243 attribs.push_back(version / 10);
1244 attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
1245 attribs.push_back(version % 10);
1246 attribs.push_back(EGL_NONE);
1248 mImpl->mNativeDrawContext = eglCreateContext(display, config, mImpl->mController.GetSharedContext(), attribs.data());
1249 if(mImpl->mNativeDrawContext == EGL_NO_CONTEXT)
1251 DALI_LOG_ERROR("eglCreateContext failed!\n");
1256 eglMakeCurrent(display, drawSurface, readSurface, mImpl->mNativeDrawContext);
1259 void Context::RestoreFromNativeRendering()
1261 auto display = eglGetCurrentDisplay();
1263 // bring back original context
1264 eglMakeCurrent(display, mImpl->mCacheDrawWriteSurface, mImpl->mCacheDrawReadSurface, mImpl->mCacheEGLGraphicsContext);
1267 } // namespace Dali::Graphics::GLES