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 hash ^= std::hash<uint32_t>{}(attr.location);
66 auto& gl = *mController.GetGL();
68 if(DALI_UNLIKELY(!mDiscardedVAOList.empty()))
70 gl.DeleteVertexArrays(static_cast<Dali::GLsizei>(mDiscardedVAOList.size()), mDiscardedVAOList.data());
71 mDiscardedVAOList.clear();
74 auto iter = mProgramVAOMap.find(program);
75 if(iter != mProgramVAOMap.end())
77 auto attributeIter = iter->second.find(hash);
78 if(attributeIter != iter->second.end())
80 if(mProgramVAOCurrentState != attributeIter->second)
82 mProgramVAOCurrentState = attributeIter->second;
83 gl.BindVertexArray(attributeIter->second);
85 // Binding VAO seems to reset the index buffer binding so the cache must be reset
86 mGlStateCache.mBoundElementArrayBufferId = 0;
93 gl.GenVertexArrays(1, &vao);
94 gl.BindVertexArray(vao);
96 // Binding VAO seems to reset the index buffer binding so the cache must be reset
97 mGlStateCache.mBoundElementArrayBufferId = 0;
99 mProgramVAOMap[program][hash] = vao;
100 for(const auto& attr : vertexInputState.attributes)
102 gl.EnableVertexAttribArray(attr.location);
105 mProgramVAOCurrentState = vao;
109 * Sets the initial GL state.
111 void InitializeGlState()
113 auto& gl = *mController.GetGL();
115 mGlStateCache.mClearColorSet = false;
116 mGlStateCache.mColorMask = true;
117 mGlStateCache.mStencilMask = 0xFF;
118 mGlStateCache.mBlendEnabled = false;
119 mGlStateCache.mDepthBufferEnabled = false;
120 mGlStateCache.mDepthMaskEnabled = false;
121 mGlStateCache.mScissorTestEnabled = false;
122 mGlStateCache.mStencilBufferEnabled = false;
124 gl.Disable(GL_DITHER);
126 mGlStateCache.mBoundArrayBufferId = 0;
127 mGlStateCache.mBoundElementArrayBufferId = 0;
128 mGlStateCache.mActiveTextureUnit = 0;
130 mGlStateCache.mBlendFuncSeparateSrcRGB = BlendFactor::ONE;
131 mGlStateCache.mBlendFuncSeparateDstRGB = BlendFactor::ZERO;
132 mGlStateCache.mBlendFuncSeparateSrcAlpha = BlendFactor::ONE;
133 mGlStateCache.mBlendFuncSeparateDstAlpha = BlendFactor::ZERO;
135 // initial state is GL_FUNC_ADD for both RGB and Alpha blend modes
136 mGlStateCache.mBlendEquationSeparateModeRGB = BlendOp::ADD;
137 mGlStateCache.mBlendEquationSeparateModeAlpha = BlendOp::ADD;
139 mGlStateCache.mCullFaceMode = CullMode::NONE; //By default cullface is disabled, front face is set to CCW and cull face is set to back
141 //Initialze vertex attribute cache
142 memset(&mGlStateCache.mVertexAttributeCachedState, 0, sizeof(mGlStateCache.mVertexAttributeCachedState));
143 memset(&mGlStateCache.mVertexAttributeCurrentState, 0, sizeof(mGlStateCache.mVertexAttributeCurrentState));
145 //Initialize bound 2d texture cache
146 memset(&mGlStateCache.mBoundTextureId, 0, sizeof(mGlStateCache.mBoundTextureId));
148 mGlStateCache.mFrameBufferStateCache.Reset();
152 * Flushes vertex attribute location changes to the driver
154 void FlushVertexAttributeLocations()
156 auto& gl = *mController.GetGL();
158 for(unsigned int i = 0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i)
160 // see if the cached state is different to the actual state
161 if(mGlStateCache.mVertexAttributeCurrentState[i] != mGlStateCache.mVertexAttributeCachedState[i])
163 // it's different so make the change to the driver and update the cached state
164 mGlStateCache.mVertexAttributeCurrentState[i] = mGlStateCache.mVertexAttributeCachedState[i];
166 if(mGlStateCache.mVertexAttributeCurrentState[i])
168 gl.EnableVertexAttribArray(i);
172 gl.DisableVertexAttribArray(i);
179 * Either enables or disables a vertex attribute location in the cache
180 * The cahnges won't take affect until FlushVertexAttributeLocations is called
181 * @param location attribute location
182 * @param state attribute state
184 void SetVertexAttributeLocation(unsigned int location, bool state)
186 auto& gl = *mController.GetGL();
188 if(location >= MAX_ATTRIBUTE_CACHE_SIZE)
190 // not cached, make the gl call through context
193 gl.EnableVertexAttribArray(location);
197 gl.DisableVertexAttribArray(location);
202 // set the cached state, it will be set at the next draw call
203 // if it's different from the current driver state
204 mGlStateCache.mVertexAttributeCachedState[location] = state;
208 EglGraphicsController& mController;
210 const GLES::PipelineImpl* mCurrentPipeline{nullptr}; ///< Currently bound pipeline
211 const GLES::PipelineImpl* mNewPipeline{nullptr}; ///< New pipeline to be set on flush
213 std::vector<Graphics::TextureBinding> mCurrentTextureBindings{};
214 std::vector<Graphics::SamplerBinding> mCurrentSamplerBindings{};
215 GLES::IndexBufferBindingDescriptor mCurrentIndexBufferBinding{};
217 struct VertexBufferBinding
219 GLES::Buffer* buffer{nullptr};
223 // Currently bound buffers
224 std::vector<VertexBufferBindingDescriptor> mCurrentVertexBufferBindings{};
226 // Currently bound UBOs (check if it's needed per program!)
227 std::vector<UniformBufferBindingDescriptor> mCurrentUBOBindings{};
228 UniformBufferBindingDescriptor mCurrentStandaloneUBOBinding{};
230 // Current render pass and render target
231 const GLES::RenderTarget* mCurrentRenderTarget{nullptr};
232 const GLES::RenderPass* mCurrentRenderPass{nullptr};
234 // Each context must have own VAOs as they cannot be shared
235 std::unordered_map<const GLES::ProgramImpl*, std::map<std::size_t, uint32_t>> mProgramVAOMap; ///< GL program-VAO map
236 uint32_t mProgramVAOCurrentState{0u}; ///< Currently bound VAO
237 GLStateCache mGlStateCache{}; ///< GL status cache
238 std::vector<Dali::GLuint> mDiscardedVAOList{};
240 bool mGlContextCreated{false}; ///< True if the OpenGL context has been created
242 EGLContext mNativeDrawContext{0u}; ///< Native rendering EGL context compatible with window context
244 EGLSurface mCacheDrawReadSurface{0u}; ///< cached 'read' surface
245 EGLSurface mCacheDrawWriteSurface{0u}; ///< cached 'write' surface
246 EGLContext mCacheEGLGraphicsContext{0u}; ///< cached window context
249 Context::Context(EglGraphicsController& controller)
251 mImpl = std::make_unique<Impl>(controller);
256 // Destroy native rendering context if one exists
257 if(mImpl->mNativeDrawContext)
259 eglDestroyContext(eglGetCurrentDisplay(), mImpl->mNativeDrawContext);
260 mImpl->mNativeDrawContext = EGL_NO_CONTEXT;
264 void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES::TextureDependencyChecker& dependencyChecker)
266 auto& gl = *mImpl->mController.GetGL();
268 static const bool hasGLES3(mImpl->mController.GetGLESVersion() >= GLESVersion::GLES_30);
270 // early out if neither current nor new pipelines are set
271 // this behaviour may be valid so no assert
272 if(!mImpl->mCurrentPipeline && !mImpl->mNewPipeline)
277 // Execute states if pipeline is changed
278 const auto currentProgram = mImpl->mCurrentPipeline ? static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program) : nullptr;
280 // case when new pipeline has been set
281 const GLES::Program* newProgram = nullptr;
283 if(mImpl->mNewPipeline)
285 newProgram = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
288 if(!currentProgram && !newProgram)
290 // Early out if we have no program for this pipeline.
291 DALI_LOG_ERROR("No program defined for pipeline\n");
295 if(mImpl->mNewPipeline && mImpl->mCurrentPipeline != mImpl->mNewPipeline)
297 if(!currentProgram || currentProgram->GetImplementation()->GetGlProgram() != newProgram->GetImplementation()->GetGlProgram())
299 mImpl->mNewPipeline->Bind(newProgram->GetImplementation()->GetGlProgram());
305 // Resolve rasterization state
306 ResolveRasterizationState();
309 // Resolve uniform buffers
310 ResolveUniformBuffers();
313 // Map binding# to sampler location
314 const auto& reflection = !newProgram ? currentProgram->GetReflection() : newProgram->GetReflection();
315 const auto& samplers = reflection.GetSamplers();
317 uint32_t currentSampler = 0;
318 uint32_t currentElement = 0;
320 // @warning Assume that binding.binding is strictly linear in the same order as mCurrentTextureBindings
321 // elements. This avoids having to sort the bindings.
322 for(const auto& binding : mImpl->mCurrentTextureBindings)
324 if(currentSampler >= samplers.size())
326 // Don't bind more textures than there are active samplers.
330 auto texture = const_cast<GLES::Texture*>(static_cast<const GLES::Texture*>(binding.texture));
332 // Texture may not have been initialized yet...(tbm_surface timing issue?)
333 if(!texture->GetGLTexture())
335 texture->InitializeResource();
338 // Warning, this may cause glWaitSync to occur on the GPU.
339 dependencyChecker.CheckNeedsSync(this, texture);
340 texture->Bind(binding);
343 // @warning Assume that location of array elements is sequential.
344 // @warning GL does not guarantee this, but in practice, it is.
345 gl.Uniform1i(samplers[currentSampler].location + currentElement,
346 samplers[currentSampler].offset + currentElement);
348 if(currentElement >= samplers[currentSampler].elementCount)
355 // for each attribute bind vertices
357 const auto& pipelineState = mImpl->mNewPipeline ? mImpl->mNewPipeline->GetCreateInfo() : mImpl->mCurrentPipeline->GetCreateInfo();
358 const auto& vertexInputState = pipelineState.vertexInputState;
362 mImpl->BindProgramVAO(static_cast<const GLES::Program*>(pipelineState.programState->program)->GetImplementation(), *vertexInputState);
365 for(const auto& attr : vertexInputState->attributes)
370 mImpl->SetVertexAttributeLocation(attr.location, true);
373 const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding];
374 const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding];
376 auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
379 BindBuffer(GL_ARRAY_BUFFER, glesBuffer);
381 gl.VertexAttribPointer(attr.location,
382 GLVertexFormat(attr.format).size,
383 GLVertexFormat(attr.format).format,
385 bufferBinding.stride,
386 reinterpret_cast<void*>(attr.offset));
390 const auto& ia = pipelineState.inputAssemblyState;
395 switch(drawCall.type)
397 case DrawCallDescriptor::Type::DRAW:
399 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
400 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
401 mImpl->mGlStateCache.StencilBufferWriteEnabled());
402 // For GLES3+ we use VAO, for GLES2 internal cache
405 mImpl->FlushVertexAttributeLocations();
408 gl.DrawArrays(GLESTopology(ia->topology),
409 drawCall.draw.firstVertex,
410 drawCall.draw.vertexCount);
413 case DrawCallDescriptor::Type::DRAW_INDEXED:
415 const auto& binding = mImpl->mCurrentIndexBufferBinding;
416 BindBuffer(GL_ELEMENT_ARRAY_BUFFER, binding.buffer->GetGLBuffer());
418 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
419 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
420 mImpl->mGlStateCache.StencilBufferWriteEnabled());
422 // For GLES3+ we use VAO, for GLES2 internal cache
425 mImpl->FlushVertexAttributeLocations();
428 auto indexBufferFormat = GLIndexFormat(binding.format).format;
429 gl.DrawElements(GLESTopology(ia->topology),
430 drawCall.drawIndexed.indexCount,
432 reinterpret_cast<void*>(binding.offset));
435 case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
444 if(mImpl->mNewPipeline)
446 mImpl->mCurrentPipeline = mImpl->mNewPipeline;
447 mImpl->mNewPipeline = nullptr;
451 void Context::BindTextures(const Graphics::TextureBinding* bindings, uint32_t count)
453 // for each texture allocate slot
454 for(auto i = 0u; i < count; ++i)
456 auto& binding = bindings[i];
458 // Resize binding array if needed
459 if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
461 mImpl->mCurrentTextureBindings.resize(binding.binding + 1);
463 // Store the binding details
464 mImpl->mCurrentTextureBindings[binding.binding] = binding;
468 void Context::BindVertexBuffers(const GLES::VertexBufferBindingDescriptor* bindings, uint32_t count)
470 if(count > mImpl->mCurrentVertexBufferBindings.size())
472 mImpl->mCurrentVertexBufferBindings.resize(count);
474 // Copy only set slots
475 std::copy_if(bindings, bindings + count, mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
476 return (nullptr != item.buffer);
480 void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding)
482 mImpl->mCurrentIndexBufferBinding = indexBufferBinding;
485 void Context::BindPipeline(const GLES::Pipeline* newPipeline)
487 DALI_ASSERT_ALWAYS(newPipeline && "Invalid pipeline");
488 mImpl->mNewPipeline = &newPipeline->GetPipeline();
491 void Context::BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindings,
493 const UniformBufferBindingDescriptor& standaloneBindings)
495 if(standaloneBindings.buffer)
497 mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
500 if(uboCount >= mImpl->mCurrentUBOBindings.size())
502 mImpl->mCurrentUBOBindings.resize(uboCount + 1);
505 auto it = uboBindings;
506 for(auto i = 0u; i < uboCount; ++i)
510 mImpl->mCurrentUBOBindings[i] = *it;
515 void Context::ResolveBlendState()
517 const auto& currentBlendState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().colorBlendState : nullptr;
518 const auto& newBlendState = mImpl->mNewPipeline->GetCreateInfo().colorBlendState;
520 // TODO: prevent leaking the state
526 auto& gl = *mImpl->mController.GetGL();
528 if(!currentBlendState || currentBlendState->blendEnable != newBlendState->blendEnable)
530 if(newBlendState->blendEnable != mImpl->mGlStateCache.mBlendEnabled)
532 mImpl->mGlStateCache.mBlendEnabled = newBlendState->blendEnable;
533 newBlendState->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND);
537 if(!newBlendState->blendEnable)
542 BlendFactor newSrcRGB(newBlendState->srcColorBlendFactor);
543 BlendFactor newDstRGB(newBlendState->dstColorBlendFactor);
544 BlendFactor newSrcAlpha(newBlendState->srcAlphaBlendFactor);
545 BlendFactor newDstAlpha(newBlendState->dstAlphaBlendFactor);
547 if(!currentBlendState ||
548 currentBlendState->srcColorBlendFactor != newSrcRGB ||
549 currentBlendState->dstColorBlendFactor != newDstRGB ||
550 currentBlendState->srcAlphaBlendFactor != newSrcAlpha ||
551 currentBlendState->dstAlphaBlendFactor != newDstAlpha)
553 if((mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB != newSrcRGB) ||
554 (mImpl->mGlStateCache.mBlendFuncSeparateDstRGB != newDstRGB) ||
555 (mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha != newSrcAlpha) ||
556 (mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha != newDstAlpha))
558 mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB = newSrcRGB;
559 mImpl->mGlStateCache.mBlendFuncSeparateDstRGB = newDstRGB;
560 mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha = newSrcAlpha;
561 mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha = newDstAlpha;
563 if(newSrcRGB == newSrcAlpha && newDstRGB == newDstAlpha)
565 gl.BlendFunc(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB));
569 gl.BlendFuncSeparate(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB), GLBlendFunc(newSrcAlpha), GLBlendFunc(newDstAlpha));
574 if(!currentBlendState ||
575 currentBlendState->colorBlendOp != newBlendState->colorBlendOp ||
576 currentBlendState->alphaBlendOp != newBlendState->alphaBlendOp)
578 if(mImpl->mGlStateCache.mBlendEquationSeparateModeRGB != newBlendState->colorBlendOp ||
579 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha != newBlendState->alphaBlendOp)
581 mImpl->mGlStateCache.mBlendEquationSeparateModeRGB = newBlendState->colorBlendOp;
582 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha = newBlendState->alphaBlendOp;
584 if(newBlendState->colorBlendOp == newBlendState->alphaBlendOp)
586 gl.BlendEquation(GLBlendOp(newBlendState->colorBlendOp));
587 if(newBlendState->colorBlendOp >= Graphics::ADVANCED_BLEND_OPTIONS_START)
594 gl.BlendEquationSeparate(GLBlendOp(newBlendState->colorBlendOp), GLBlendOp(newBlendState->alphaBlendOp));
600 void Context::ResolveRasterizationState()
602 const auto& currentRasterizationState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().rasterizationState : nullptr;
603 const auto& newRasterizationState = mImpl->mNewPipeline->GetCreateInfo().rasterizationState;
605 // TODO: prevent leaking the state
606 if(!newRasterizationState)
611 auto& gl = *mImpl->mController.GetGL();
613 if(!currentRasterizationState ||
614 currentRasterizationState->cullMode != newRasterizationState->cullMode)
616 if(mImpl->mGlStateCache.mCullFaceMode != newRasterizationState->cullMode)
618 mImpl->mGlStateCache.mCullFaceMode = newRasterizationState->cullMode;
619 if(newRasterizationState->cullMode == CullMode::NONE)
621 gl.Disable(GL_CULL_FACE);
625 gl.Enable(GL_CULL_FACE);
626 gl.CullFace(GLCullMode(newRasterizationState->cullMode));
630 // TODO: implement polygon mode (fill, line, points)
631 // seems like we don't support it (no glPolygonMode())
634 void Context::ResolveUniformBuffers()
636 // Resolve standalone uniforms if we have binding
637 if(mImpl->mCurrentStandaloneUBOBinding.buffer)
639 ResolveStandaloneUniforms();
643 void Context::ResolveStandaloneUniforms()
645 // Find reflection for program
646 const GLES::Program* program{nullptr};
648 if(mImpl->mNewPipeline)
650 program = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
652 else if(mImpl->mCurrentPipeline)
654 program = static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program);
659 const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset;
660 // Update program uniforms
661 program->GetImplementation()->UpdateStandaloneUniformBlock(ptr);
665 void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
667 auto& renderPass = *renderPassBegin.renderPass;
668 auto& renderTarget = *renderPassBegin.renderTarget;
670 const auto& targetInfo = renderTarget.GetCreateInfo();
672 auto& gl = *mImpl->mController.GetGL();
674 if(targetInfo.surface)
677 BindFrameBuffer(GL_FRAMEBUFFER, 0);
679 else if(targetInfo.framebuffer)
681 // bind framebuffer and swap.
682 auto framebuffer = renderTarget.GetFramebuffer();
686 // clear (ideally cache the setup)
688 // In GL we assume that the last attachment is depth/stencil (we may need
689 // to cache extra information inside GLES RenderTarget if we want to be
690 // more specific in case of MRT)
692 const auto& attachments = *renderPass.GetCreateInfo().attachments;
693 const auto& color0 = attachments[0];
696 if(color0.loadOp == AttachmentLoadOp::CLEAR)
698 mask |= GL_COLOR_BUFFER_BIT;
701 // Something goes wrong here if Alpha mask is GL_TRUE
704 const auto clearValues = renderPassBegin.clearValues.Ptr();
706 if(!Dali::Equals(mImpl->mGlStateCache.mClearColor.r, clearValues[0].color.r) ||
707 !Dali::Equals(mImpl->mGlStateCache.mClearColor.g, clearValues[0].color.g) ||
708 !Dali::Equals(mImpl->mGlStateCache.mClearColor.b, clearValues[0].color.b) ||
709 !Dali::Equals(mImpl->mGlStateCache.mClearColor.a, clearValues[0].color.a) ||
710 !mImpl->mGlStateCache.mClearColorSet)
712 gl.ClearColor(clearValues[0].color.r,
713 clearValues[0].color.g,
714 clearValues[0].color.b,
715 clearValues[0].color.a);
717 mImpl->mGlStateCache.mClearColorSet = true;
718 mImpl->mGlStateCache.mClearColor = Vector4(clearValues[0].color.r,
719 clearValues[0].color.g,
720 clearValues[0].color.b,
721 clearValues[0].color.a);
725 // check for depth stencil
726 if(attachments.size() > 1)
728 const auto& depthStencil = attachments.back();
729 if(depthStencil.loadOp == AttachmentLoadOp::CLEAR)
731 if(!mImpl->mGlStateCache.mDepthMaskEnabled)
733 mImpl->mGlStateCache.mDepthMaskEnabled = true;
736 mask |= GL_DEPTH_BUFFER_BIT;
738 if(depthStencil.stencilLoadOp == AttachmentLoadOp::CLEAR)
740 if(mImpl->mGlStateCache.mStencilMask != 0xFF)
742 mImpl->mGlStateCache.mStencilMask = 0xFF;
743 gl.StencilMask(0xFF);
745 mask |= GL_STENCIL_BUFFER_BIT;
749 SetScissorTestEnabled(true);
750 gl.Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height);
751 ClearBuffer(mask, true);
752 SetScissorTestEnabled(false);
754 mImpl->mCurrentRenderPass = &renderPass;
755 mImpl->mCurrentRenderTarget = &renderTarget;
758 void Context::EndRenderPass(GLES::TextureDependencyChecker& dependencyChecker)
760 if(mImpl->mCurrentRenderTarget)
762 GLES::Framebuffer* framebuffer = mImpl->mCurrentRenderTarget->GetFramebuffer();
765 auto& gl = *mImpl->mController.GetGL();
768 /* @todo Full dependency checking would need to store textures in Begin, and create
769 * fence objects here; but we're going to draw all fbos on shared context in serial,
770 * so no real need (yet). Might want to consider ensuring order of render passes,
771 * but that needs doing in the controller, and would need doing before ProcessCommandQueues.
773 * Currently up to the client to create render tasks in the right order.
776 /* Create fence sync objects. Other contexts can then wait on these fences before reading
779 dependencyChecker.AddTextures(this, framebuffer);
784 void Context::ClearState()
786 mImpl->mCurrentTextureBindings.clear();
789 void Context::ColorMask(bool enabled)
791 if(enabled != mImpl->mGlStateCache.mColorMask)
793 mImpl->mGlStateCache.mColorMask = enabled;
795 auto& gl = *mImpl->mController.GetGL();
796 gl.ColorMask(enabled, enabled, enabled, enabled);
800 void Context::ClearStencilBuffer()
802 ClearBuffer(GL_STENCIL_BUFFER_BIT, false);
805 void Context::ClearDepthBuffer()
807 ClearBuffer(GL_DEPTH_BUFFER_BIT, false);
810 void Context::ClearBuffer(uint32_t mask, bool forceClear)
812 mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled);
815 auto& gl = *mImpl->mController.GetGL();
820 void Context::InvalidateDepthStencilBuffers()
822 auto& gl = *mImpl->mController.GetGL();
824 GLenum attachments[] = {GL_DEPTH, GL_STENCIL};
825 gl.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
828 void Context::SetScissorTestEnabled(bool scissorEnabled)
830 if(mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled)
832 mImpl->mGlStateCache.mScissorTestEnabled = scissorEnabled;
834 auto& gl = *mImpl->mController.GetGL();
837 gl.Enable(GL_SCISSOR_TEST);
841 gl.Disable(GL_SCISSOR_TEST);
846 void Context::SetStencilTestEnable(bool stencilEnable)
848 if(stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled)
850 mImpl->mGlStateCache.mStencilBufferEnabled = stencilEnable;
852 auto& gl = *mImpl->mController.GetGL();
855 gl.Enable(GL_STENCIL_TEST);
859 gl.Disable(GL_STENCIL_TEST);
864 void Context::StencilMask(uint32_t writeMask)
866 if(writeMask != mImpl->mGlStateCache.mStencilMask)
868 mImpl->mGlStateCache.mStencilMask = writeMask;
870 auto& gl = *mImpl->mController.GetGL();
871 gl.StencilMask(writeMask);
875 void Context::StencilFunc(Graphics::CompareOp compareOp,
877 uint32_t compareMask)
879 if(compareOp != mImpl->mGlStateCache.mStencilFunc ||
880 reference != mImpl->mGlStateCache.mStencilFuncRef ||
881 compareMask != mImpl->mGlStateCache.mStencilFuncMask)
883 mImpl->mGlStateCache.mStencilFunc = compareOp;
884 mImpl->mGlStateCache.mStencilFuncRef = reference;
885 mImpl->mGlStateCache.mStencilFuncMask = compareMask;
887 auto& gl = *mImpl->mController.GetGL();
888 gl.StencilFunc(GLCompareOp(compareOp).op, reference, compareMask);
892 void Context::StencilOp(Graphics::StencilOp failOp,
893 Graphics::StencilOp depthFailOp,
894 Graphics::StencilOp passOp)
896 if(failOp != mImpl->mGlStateCache.mStencilOpFail ||
897 depthFailOp != mImpl->mGlStateCache.mStencilOpDepthFail ||
898 passOp != mImpl->mGlStateCache.mStencilOpDepthPass)
900 mImpl->mGlStateCache.mStencilOpFail = failOp;
901 mImpl->mGlStateCache.mStencilOpDepthFail = depthFailOp;
902 mImpl->mGlStateCache.mStencilOpDepthPass = passOp;
904 auto& gl = *mImpl->mController.GetGL();
905 gl.StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op);
909 void Context::SetDepthCompareOp(Graphics::CompareOp compareOp)
911 if(compareOp != mImpl->mGlStateCache.mDepthFunction)
913 mImpl->mGlStateCache.mDepthFunction = compareOp;
914 auto& gl = *mImpl->mController.GetGL();
915 gl.DepthFunc(GLCompareOp(compareOp).op);
919 void Context::SetDepthTestEnable(bool depthTestEnable)
921 if(depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled)
923 mImpl->mGlStateCache.mDepthBufferEnabled = depthTestEnable;
925 auto& gl = *mImpl->mController.GetGL();
928 gl.Enable(GL_DEPTH_TEST);
932 gl.Disable(GL_DEPTH_TEST);
937 void Context::SetDepthWriteEnable(bool depthWriteEnable)
939 if(depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled)
941 mImpl->mGlStateCache.mDepthMaskEnabled = depthWriteEnable;
943 auto& gl = *mImpl->mController.GetGL();
944 gl.DepthMask(depthWriteEnable);
948 void Context::ActiveTexture(uint32_t textureBindingIndex)
950 if(mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex)
952 mImpl->mGlStateCache.mActiveTextureUnit = textureBindingIndex;
954 auto& gl = *mImpl->mController.GetGL();
955 gl.ActiveTexture(GL_TEXTURE0 + textureBindingIndex);
959 void Context::BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId)
961 uint32_t typeId = static_cast<uint32_t>(textureTypeId);
962 if(mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] != textureId)
964 mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] = textureId;
966 auto& gl = *mImpl->mController.GetGL();
967 gl.BindTexture(target, textureId);
971 void Context::GenerateMipmap(GLenum target)
973 auto& gl = *mImpl->mController.GetGL();
974 gl.GenerateMipmap(target);
977 void Context::BindBuffer(GLenum target, uint32_t bufferId)
981 case GL_ARRAY_BUFFER:
983 if(mImpl->mGlStateCache.mBoundArrayBufferId == bufferId)
987 mImpl->mGlStateCache.mBoundArrayBufferId = bufferId;
990 case GL_ELEMENT_ARRAY_BUFFER:
992 if(mImpl->mGlStateCache.mBoundElementArrayBufferId == bufferId)
996 mImpl->mGlStateCache.mBoundElementArrayBufferId = bufferId;
1001 // Cache miss. Bind buffer.
1002 auto& gl = *mImpl->mController.GetGL();
1003 gl.BindBuffer(target, bufferId);
1006 void Context::DrawBuffers(uint32_t count, const GLenum* buffers)
1008 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
1009 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
1010 mImpl->mGlStateCache.StencilBufferWriteEnabled());
1012 auto& gl = *mImpl->mController.GetGL();
1013 gl.DrawBuffers(count, buffers);
1016 void Context::BindFrameBuffer(GLenum target, uint32_t bufferId)
1018 mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId);
1020 auto& gl = *mImpl->mController.GetGL();
1021 gl.BindFramebuffer(target, bufferId);
1024 void Context::GenFramebuffers(uint32_t count, uint32_t* framebuffers)
1026 auto& gl = *mImpl->mController.GetGL();
1027 gl.GenFramebuffers(count, framebuffers);
1029 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersCreated(count, framebuffers);
1032 void Context::DeleteFramebuffers(uint32_t count, uint32_t* framebuffers)
1034 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers);
1036 auto& gl = *mImpl->mController.GetGL();
1037 gl.DeleteFramebuffers(count, framebuffers);
1040 GLStateCache& Context::GetGLStateCache()
1042 return mImpl->mGlStateCache;
1045 void Context::GlContextCreated()
1047 if(!mImpl->mGlContextCreated)
1049 mImpl->mGlContextCreated = true;
1051 // Set the initial GL state
1052 mImpl->InitializeGlState();
1056 void Context::GlContextDestroyed()
1058 mImpl->mGlContextCreated = false;
1061 void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline)
1063 // Since the pipeline is deleted, invalidate the cached pipeline.
1064 if(mImpl->mCurrentPipeline == &pipeline->GetPipeline())
1066 mImpl->mCurrentPipeline = nullptr;
1069 // Remove cached VAO map
1070 auto* gl = mImpl->mController.GetGL();
1073 const auto* program = pipeline->GetCreateInfo().programState->program;
1076 const auto* programImpl = static_cast<const GLES::Program*>(program)->GetImplementation();
1079 auto iter = mImpl->mProgramVAOMap.find(programImpl);
1080 if(iter != mImpl->mProgramVAOMap.end())
1082 for(auto& attributeHashPair : iter->second)
1084 auto vao = attributeHashPair.second;
1086 // Do not delete vao now. (Since Context might not be current.)
1087 mImpl->mDiscardedVAOList.emplace_back(vao);
1088 if(mImpl->mProgramVAOCurrentState == vao)
1090 mImpl->mProgramVAOCurrentState = 0u;
1094 // Clear cached Vertex buffer.
1095 mImpl->mCurrentVertexBufferBindings.clear();
1097 mImpl->mProgramVAOMap.erase(iter);
1104 void Context::PrepareForNativeRendering()
1106 // this should be pretty much constant
1107 auto display = eglGetCurrentDisplay();
1108 auto drawSurface = eglGetCurrentSurface(EGL_DRAW);
1109 auto readSurface = eglGetCurrentSurface(EGL_READ);
1110 auto context = eglGetCurrentContext();
1112 // push the surface and context data to the impl
1113 // It's needed to restore context
1114 if(!mImpl->mCacheEGLGraphicsContext)
1116 mImpl->mCacheDrawWriteSurface = drawSurface;
1117 mImpl->mCacheDrawReadSurface = readSurface;
1118 mImpl->mCacheEGLGraphicsContext = context;
1121 if(!mImpl->mNativeDrawContext)
1123 EGLint configId{0u};
1124 eglQueryContext(display, mImpl->mController.GetSharedContext(), EGL_CONFIG_ID, &configId);
1126 EGLint configAttribs[3];
1127 configAttribs[0] = EGL_CONFIG_ID;
1128 configAttribs[1] = configId;
1129 configAttribs[2] = EGL_NONE;
1133 if(eglChooseConfig(display, configAttribs, &config, 1, &numConfigs) != EGL_TRUE)
1135 DALI_LOG_ERROR("eglChooseConfig failed!\n");
1139 auto version = int(mImpl->mController.GetGLESVersion());
1141 std::vector<EGLint> attribs;
1142 attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
1143 attribs.push_back(version / 10);
1144 attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
1145 attribs.push_back(version % 10);
1146 attribs.push_back(EGL_NONE);
1148 mImpl->mNativeDrawContext = eglCreateContext(display, config, mImpl->mController.GetSharedContext(), attribs.data());
1149 if(mImpl->mNativeDrawContext == EGL_NO_CONTEXT)
1151 DALI_LOG_ERROR("eglCreateContext failed!\n");
1156 eglMakeCurrent(display, drawSurface, readSurface, mImpl->mNativeDrawContext);
1159 void Context::RestoreFromNativeRendering()
1161 auto display = eglGetCurrentDisplay();
1163 // bring back original context
1164 eglMakeCurrent(display, mImpl->mCacheDrawWriteSurface, mImpl->mCacheDrawReadSurface, mImpl->mCacheEGLGraphicsContext);
1167 } // namespace Dali::Graphics::GLES