2 * Copyright (c) 2022 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>
38 namespace Dali::Graphics::GLES
42 explicit Impl(EglGraphicsController& controller)
43 : mController(controller)
50 * Binds (and creates) VAO
52 * VAO is fixed per program so it has to be created only once assuming
53 * that VertexInputState has been set correctly for the pipeline.
56 void BindProgramVAO(GLES::ProgramImpl* program, const VertexInputState& vertexInputState)
58 auto& gl = *mController.GetGL();
59 auto iter = mProgramVAOMap.find(program);
60 if(iter != mProgramVAOMap.end())
62 if(mProgramVAOCurrentState != iter->second)
64 mProgramVAOCurrentState = iter->second;
65 gl.BindVertexArray(iter->second);
68 // We should re-check enable attribute usage because geometry might be changed.
69 for(const auto& attr : vertexInputState.attributes)
71 gl.EnableVertexAttribArray(attr.location);
77 gl.GenVertexArrays(1, &vao);
78 gl.BindVertexArray(vao);
79 mProgramVAOMap[program] = vao;
80 for(const auto& attr : vertexInputState.attributes)
82 gl.EnableVertexAttribArray(attr.location);
85 mProgramVAOCurrentState = vao;
89 * Sets the initial GL state.
91 void InitializeGlState()
93 auto& gl = *mController.GetGL();
95 mGlStateCache.mClearColorSet = false;
96 mGlStateCache.mColorMask = true;
97 mGlStateCache.mStencilMask = 0xFF;
98 mGlStateCache.mBlendEnabled = false;
99 mGlStateCache.mDepthBufferEnabled = false;
100 mGlStateCache.mDepthMaskEnabled = false;
101 mGlStateCache.mScissorTestEnabled = false;
102 mGlStateCache.mStencilBufferEnabled = false;
104 gl.Disable(GL_DITHER);
106 mGlStateCache.mBoundArrayBufferId = 0;
107 mGlStateCache.mBoundElementArrayBufferId = 0;
108 mGlStateCache.mActiveTextureUnit = 0;
110 mGlStateCache.mBlendFuncSeparateSrcRGB = BlendFactor::ONE;
111 mGlStateCache.mBlendFuncSeparateDstRGB = BlendFactor::ZERO;
112 mGlStateCache.mBlendFuncSeparateSrcAlpha = BlendFactor::ONE;
113 mGlStateCache.mBlendFuncSeparateDstAlpha = BlendFactor::ZERO;
115 // initial state is GL_FUNC_ADD for both RGB and Alpha blend modes
116 mGlStateCache.mBlendEquationSeparateModeRGB = BlendOp::ADD;
117 mGlStateCache.mBlendEquationSeparateModeAlpha = BlendOp::ADD;
119 mGlStateCache.mCullFaceMode = CullMode::NONE; //By default cullface is disabled, front face is set to CCW and cull face is set to back
121 //Initialze vertex attribute cache
122 memset(&mGlStateCache.mVertexAttributeCachedState, 0, sizeof(mGlStateCache.mVertexAttributeCachedState));
123 memset(&mGlStateCache.mVertexAttributeCurrentState, 0, sizeof(mGlStateCache.mVertexAttributeCurrentState));
125 //Initialize bound 2d texture cache
126 memset(&mGlStateCache.mBoundTextureId, 0, sizeof(mGlStateCache.mBoundTextureId));
128 mGlStateCache.mFrameBufferStateCache.Reset();
132 * Flushes vertex attribute location changes to the driver
134 void FlushVertexAttributeLocations()
136 auto& gl = *mController.GetGL();
138 for(unsigned int i = 0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i)
140 // see if the cached state is different to the actual state
141 if(mGlStateCache.mVertexAttributeCurrentState[i] != mGlStateCache.mVertexAttributeCachedState[i])
143 // it's different so make the change to the driver and update the cached state
144 mGlStateCache.mVertexAttributeCurrentState[i] = mGlStateCache.mVertexAttributeCachedState[i];
146 if(mGlStateCache.mVertexAttributeCurrentState[i])
148 gl.EnableVertexAttribArray(i);
152 gl.DisableVertexAttribArray(i);
159 * Either enables or disables a vertex attribute location in the cache
160 * The cahnges won't take affect until FlushVertexAttributeLocations is called
161 * @param location attribute location
162 * @param state attribute state
164 void SetVertexAttributeLocation(unsigned int location, bool state)
166 auto& gl = *mController.GetGL();
168 if(location >= MAX_ATTRIBUTE_CACHE_SIZE)
170 // not cached, make the gl call through context
173 gl.EnableVertexAttribArray(location);
177 gl.DisableVertexAttribArray(location);
182 // set the cached state, it will be set at the next draw call
183 // if it's different from the current driver state
184 mGlStateCache.mVertexAttributeCachedState[location] = state;
188 EglGraphicsController& mController;
190 const GLES::PipelineImpl* mCurrentPipeline{nullptr}; ///< Currently bound pipeline
191 const GLES::PipelineImpl* mNewPipeline{nullptr}; ///< New pipeline to be set on flush
193 std::vector<Graphics::TextureBinding> mCurrentTextureBindings{};
194 std::vector<Graphics::SamplerBinding> mCurrentSamplerBindings{};
195 GLES::IndexBufferBindingDescriptor mCurrentIndexBufferBinding{};
197 struct VertexBufferBinding
199 GLES::Buffer* buffer{nullptr};
203 // Currently bound buffers
204 std::vector<VertexBufferBindingDescriptor> mCurrentVertexBufferBindings{};
206 // Currently bound UBOs (check if it's needed per program!)
207 std::vector<UniformBufferBindingDescriptor> mCurrentUBOBindings{};
208 UniformBufferBindingDescriptor mCurrentStandaloneUBOBinding{};
210 // Current render pass and render target
211 const GLES::RenderTarget* mCurrentRenderTarget{nullptr};
212 const GLES::RenderPass* mCurrentRenderPass{nullptr};
214 // Each context must have own VAOs as they cannot be shared
215 std::map<GLES::ProgramImpl*, uint32_t> mProgramVAOMap; ///< GL program-VAO map
216 uint32_t mProgramVAOCurrentState{0u}; ///< Currently bound VAO
217 GLStateCache mGlStateCache{}; ///< GL status cache
219 bool mGlContextCreated{false}; ///< True if the OpenGL context has been created
221 EGLContext mNativeDrawContext{0u}; ///< Native rendering EGL context compatible with window context
223 EGLSurface mCacheDrawReadSurface{0u}; ///< cached 'read' surface
224 EGLSurface mCacheDrawWriteSurface{0u}; ///< cached 'write' surface
225 EGLContext mCacheEGLGraphicsContext{0u}; ///< cached window context
228 Context::Context(EglGraphicsController& controller)
230 mImpl = std::make_unique<Impl>(controller);
235 // Destroy native rendering context if one exists
236 if(mImpl->mNativeDrawContext)
238 eglDestroyContext(eglGetCurrentDisplay(), mImpl->mNativeDrawContext);
239 mImpl->mNativeDrawContext = EGL_NO_CONTEXT;
243 void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES::TextureDependencyChecker& dependencyChecker)
245 auto& gl = *mImpl->mController.GetGL();
247 static const bool hasGLES3(mImpl->mController.GetGLESVersion() >= GLESVersion::GLES_30);
249 // early out if neither current nor new pipelines are set
250 // this behaviour may be valid so no assert
251 if(!mImpl->mCurrentPipeline && !mImpl->mNewPipeline)
256 // Execute states if pipeline is changed
257 const auto currentProgram = mImpl->mCurrentPipeline ? static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program) : nullptr;
259 // case when new pipeline has been set
260 const GLES::Program* newProgram = nullptr;
262 if(mImpl->mNewPipeline)
264 newProgram = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
267 if(!currentProgram && !newProgram)
269 // Early out if we have no program for this pipeline.
270 DALI_LOG_ERROR("No program defined for pipeline\n");
274 if(mImpl->mNewPipeline && mImpl->mCurrentPipeline != mImpl->mNewPipeline)
276 if(!currentProgram || currentProgram->GetImplementation()->GetGlProgram() != newProgram->GetImplementation()->GetGlProgram())
278 mImpl->mNewPipeline->Bind(newProgram->GetImplementation()->GetGlProgram());
284 // Resolve rasterization state
285 ResolveRasterizationState();
288 // Resolve uniform buffers
289 ResolveUniformBuffers();
292 // Map binding# to sampler location
293 const auto& reflection = !newProgram ? currentProgram->GetReflection() : newProgram->GetReflection();
294 const auto& samplers = reflection.GetSamplers();
295 for(const auto& binding : mImpl->mCurrentTextureBindings)
297 auto texture = const_cast<GLES::Texture*>(static_cast<const GLES::Texture*>(binding.texture));
299 // Texture may not have been initialized yet...(tbm_surface timing issue?)
300 if(!texture->GetGLTexture())
302 // Attempt to reinitialize
303 // @todo need to put this somewhere else where it isn't const.
304 // Maybe post it back on end of initialize queue if initialization fails?
305 texture->InitializeResource();
308 // Warning, this may cause glWaitSync to occur on the GPU.
309 dependencyChecker.CheckNeedsSync(this, texture);
311 texture->Bind(binding);
313 texture->Prepare(); // @todo also non-const.
315 if(binding.binding < samplers.size()) // binding maps to texture unit. (texture bindings should also be in binding order)
317 // Offset is set to the lexical offset within the frag shader, map it to the texture unit
318 // @todo Explicitly set the texture unit through the graphics interface
319 gl.Uniform1i(samplers[binding.binding].location, samplers[binding.binding].offset);
323 // for each attribute bind vertices
325 const auto& pipelineState = mImpl->mNewPipeline ? mImpl->mNewPipeline->GetCreateInfo() : mImpl->mCurrentPipeline->GetCreateInfo();
326 const auto& vertexInputState = pipelineState.vertexInputState;
330 mImpl->BindProgramVAO(static_cast<const GLES::Program*>(pipelineState.programState->program)->GetImplementation(), *vertexInputState);
333 for(const auto& attr : vertexInputState->attributes)
338 mImpl->SetVertexAttributeLocation(attr.location, true);
341 const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding];
342 const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding];
344 auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
347 BindBuffer(GL_ARRAY_BUFFER, glesBuffer);
349 gl.VertexAttribPointer(attr.location,
350 GLVertexFormat(attr.format).size,
351 GLVertexFormat(attr.format).format,
353 bufferBinding.stride,
354 reinterpret_cast<void*>(attr.offset));
358 const auto& ia = pipelineState.inputAssemblyState;
363 switch(drawCall.type)
365 case DrawCallDescriptor::Type::DRAW:
367 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
368 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
369 mImpl->mGlStateCache.StencilBufferWriteEnabled());
370 // For GLES3+ we use VAO, for GLES2 internal cache
373 mImpl->FlushVertexAttributeLocations();
376 gl.DrawArrays(GLESTopology(ia->topology),
377 drawCall.draw.firstVertex,
378 drawCall.draw.vertexCount);
381 case DrawCallDescriptor::Type::DRAW_INDEXED:
383 const auto& binding = mImpl->mCurrentIndexBufferBinding;
384 BindBuffer(GL_ELEMENT_ARRAY_BUFFER, binding.buffer->GetGLBuffer());
386 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
387 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
388 mImpl->mGlStateCache.StencilBufferWriteEnabled());
390 // For GLES3+ we use VAO, for GLES2 internal cache
393 mImpl->FlushVertexAttributeLocations();
396 auto indexBufferFormat = GLIndexFormat(binding.format).format;
397 gl.DrawElements(GLESTopology(ia->topology),
398 drawCall.drawIndexed.indexCount,
400 reinterpret_cast<void*>(binding.offset));
403 case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
412 if(mImpl->mNewPipeline)
414 mImpl->mCurrentPipeline = mImpl->mNewPipeline;
415 mImpl->mNewPipeline = nullptr;
419 void Context::BindTextures(const Graphics::TextureBinding* bindings, uint32_t count)
421 // for each texture allocate slot
422 for(auto i = 0u; i < count; ++i)
424 auto& binding = bindings[i];
426 // Resize binding array if needed
427 if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
429 mImpl->mCurrentTextureBindings.resize(binding.binding + 1);
431 // Store the binding details
432 mImpl->mCurrentTextureBindings[binding.binding] = binding;
436 void Context::BindVertexBuffers(const GLES::VertexBufferBindingDescriptor* bindings, uint32_t count)
438 if(count > mImpl->mCurrentVertexBufferBindings.size())
440 mImpl->mCurrentVertexBufferBindings.resize(count);
442 // Copy only set slots
443 std::copy_if(bindings, bindings + count, mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
444 return (nullptr != item.buffer);
448 void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding)
450 mImpl->mCurrentIndexBufferBinding = indexBufferBinding;
453 void Context::BindPipeline(const GLES::Pipeline* newPipeline)
455 DALI_ASSERT_ALWAYS(newPipeline && "Invalid pipeline");
456 mImpl->mNewPipeline = &newPipeline->GetPipeline();
459 void Context::BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindings,
461 const UniformBufferBindingDescriptor& standaloneBindings)
463 if(standaloneBindings.buffer)
465 mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
468 if(uboCount >= mImpl->mCurrentUBOBindings.size())
470 mImpl->mCurrentUBOBindings.resize(uboCount + 1);
473 auto it = uboBindings;
474 for(auto i = 0u; i < uboCount; ++i)
478 mImpl->mCurrentUBOBindings[i] = *it;
483 void Context::ResolveBlendState()
485 const auto& currentBlendState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().colorBlendState : nullptr;
486 const auto& newBlendState = mImpl->mNewPipeline->GetCreateInfo().colorBlendState;
488 // TODO: prevent leaking the state
494 auto& gl = *mImpl->mController.GetGL();
496 if(!currentBlendState || currentBlendState->blendEnable != newBlendState->blendEnable)
498 if(newBlendState->blendEnable != mImpl->mGlStateCache.mBlendEnabled)
500 mImpl->mGlStateCache.mBlendEnabled = newBlendState->blendEnable;
501 newBlendState->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND);
505 if(!newBlendState->blendEnable)
510 BlendFactor newSrcRGB(newBlendState->srcColorBlendFactor);
511 BlendFactor newDstRGB(newBlendState->dstColorBlendFactor);
512 BlendFactor newSrcAlpha(newBlendState->srcAlphaBlendFactor);
513 BlendFactor newDstAlpha(newBlendState->dstAlphaBlendFactor);
515 if(!currentBlendState ||
516 currentBlendState->srcColorBlendFactor != newSrcRGB ||
517 currentBlendState->dstColorBlendFactor != newDstRGB ||
518 currentBlendState->srcAlphaBlendFactor != newSrcAlpha ||
519 currentBlendState->dstAlphaBlendFactor != newDstAlpha)
521 if((mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB != newSrcRGB) ||
522 (mImpl->mGlStateCache.mBlendFuncSeparateDstRGB != newDstRGB) ||
523 (mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha != newSrcAlpha) ||
524 (mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha != newDstAlpha))
526 mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB = newSrcRGB;
527 mImpl->mGlStateCache.mBlendFuncSeparateDstRGB = newDstRGB;
528 mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha = newSrcAlpha;
529 mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha = newDstAlpha;
531 if(newSrcRGB == newSrcAlpha && newDstRGB == newDstAlpha)
533 gl.BlendFunc(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB));
537 gl.BlendFuncSeparate(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB), GLBlendFunc(newSrcAlpha), GLBlendFunc(newDstAlpha));
542 if(!currentBlendState ||
543 currentBlendState->colorBlendOp != newBlendState->colorBlendOp ||
544 currentBlendState->alphaBlendOp != newBlendState->alphaBlendOp)
546 if(mImpl->mGlStateCache.mBlendEquationSeparateModeRGB != newBlendState->colorBlendOp ||
547 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha != newBlendState->alphaBlendOp)
549 mImpl->mGlStateCache.mBlendEquationSeparateModeRGB = newBlendState->colorBlendOp;
550 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha = newBlendState->alphaBlendOp;
552 if(newBlendState->colorBlendOp == newBlendState->alphaBlendOp)
554 gl.BlendEquation(GLBlendOp(newBlendState->colorBlendOp));
555 if(newBlendState->colorBlendOp >= Graphics::ADVANCED_BLEND_OPTIONS_START)
562 gl.BlendEquationSeparate(GLBlendOp(newBlendState->colorBlendOp), GLBlendOp(newBlendState->alphaBlendOp));
568 void Context::ResolveRasterizationState()
570 const auto& currentRasterizationState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().rasterizationState : nullptr;
571 const auto& newRasterizationState = mImpl->mNewPipeline->GetCreateInfo().rasterizationState;
573 // TODO: prevent leaking the state
574 if(!newRasterizationState)
579 auto& gl = *mImpl->mController.GetGL();
581 if(!currentRasterizationState ||
582 currentRasterizationState->cullMode != newRasterizationState->cullMode)
584 if(mImpl->mGlStateCache.mCullFaceMode != newRasterizationState->cullMode)
586 mImpl->mGlStateCache.mCullFaceMode = newRasterizationState->cullMode;
587 if(newRasterizationState->cullMode == CullMode::NONE)
589 gl.Disable(GL_CULL_FACE);
593 gl.Enable(GL_CULL_FACE);
594 gl.CullFace(GLCullMode(newRasterizationState->cullMode));
598 // TODO: implement polygon mode (fill, line, points)
599 // seems like we don't support it (no glPolygonMode())
602 void Context::ResolveUniformBuffers()
604 // Resolve standalone uniforms if we have binding
605 if(mImpl->mCurrentStandaloneUBOBinding.buffer)
607 ResolveStandaloneUniforms();
611 void Context::ResolveStandaloneUniforms()
613 // Find reflection for program
614 const GLES::Program* program{nullptr};
616 if(mImpl->mNewPipeline)
618 program = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
620 else if(mImpl->mCurrentPipeline)
622 program = static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program);
627 const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset;
628 // Update program uniforms
629 program->GetImplementation()->UpdateStandaloneUniformBlock(ptr);
633 void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
635 auto& renderPass = *renderPassBegin.renderPass;
636 auto& renderTarget = *renderPassBegin.renderTarget;
638 const auto& targetInfo = renderTarget.GetCreateInfo();
640 auto& gl = *mImpl->mController.GetGL();
642 if(targetInfo.surface)
645 BindFrameBuffer(GL_FRAMEBUFFER, 0);
647 else if(targetInfo.framebuffer)
649 // bind framebuffer and swap.
650 auto framebuffer = renderTarget.GetFramebuffer();
654 // clear (ideally cache the setup)
656 // In GL we assume that the last attachment is depth/stencil (we may need
657 // to cache extra information inside GLES RenderTarget if we want to be
658 // more specific in case of MRT)
660 const auto& attachments = *renderPass.GetCreateInfo().attachments;
661 const auto& color0 = attachments[0];
664 if(color0.loadOp == AttachmentLoadOp::CLEAR)
666 mask |= GL_COLOR_BUFFER_BIT;
669 // Something goes wrong here if Alpha mask is GL_TRUE
672 const auto clearValues = renderPassBegin.clearValues.Ptr();
674 if(!Dali::Equals(mImpl->mGlStateCache.mClearColor.r, clearValues[0].color.r) ||
675 !Dali::Equals(mImpl->mGlStateCache.mClearColor.g, clearValues[0].color.g) ||
676 !Dali::Equals(mImpl->mGlStateCache.mClearColor.b, clearValues[0].color.b) ||
677 !Dali::Equals(mImpl->mGlStateCache.mClearColor.a, clearValues[0].color.a) ||
678 !mImpl->mGlStateCache.mClearColorSet)
680 gl.ClearColor(clearValues[0].color.r,
681 clearValues[0].color.g,
682 clearValues[0].color.b,
683 clearValues[0].color.a);
685 mImpl->mGlStateCache.mClearColorSet = true;
686 mImpl->mGlStateCache.mClearColor = Vector4(clearValues[0].color.r,
687 clearValues[0].color.g,
688 clearValues[0].color.b,
689 clearValues[0].color.a);
693 // check for depth stencil
694 if(attachments.size() > 1)
696 const auto& depthStencil = attachments.back();
697 if(depthStencil.loadOp == AttachmentLoadOp::CLEAR)
699 if(!mImpl->mGlStateCache.mDepthMaskEnabled)
701 mImpl->mGlStateCache.mDepthMaskEnabled = true;
704 mask |= GL_DEPTH_BUFFER_BIT;
706 if(depthStencil.stencilLoadOp == AttachmentLoadOp::CLEAR)
708 if(mImpl->mGlStateCache.mStencilMask != 0xFF)
710 mImpl->mGlStateCache.mStencilMask = 0xFF;
711 gl.StencilMask(0xFF);
713 mask |= GL_STENCIL_BUFFER_BIT;
717 SetScissorTestEnabled(true);
718 gl.Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height);
719 ClearBuffer(mask, true);
720 SetScissorTestEnabled(false);
722 mImpl->mCurrentRenderPass = &renderPass;
723 mImpl->mCurrentRenderTarget = &renderTarget;
726 void Context::EndRenderPass(GLES::TextureDependencyChecker& dependencyChecker)
728 if(mImpl->mCurrentRenderTarget)
730 GLES::Framebuffer* framebuffer = mImpl->mCurrentRenderTarget->GetFramebuffer();
733 auto& gl = *mImpl->mController.GetGL();
736 /* @todo Full dependency checking would need to store textures in Begin, and create
737 * fence objects here; but we're going to draw all fbos on shared context in serial,
738 * so no real need (yet). Might want to consider ensuring order of render passes,
739 * but that needs doing in the controller, and would need doing before ProcessCommandQueues.
741 * Currently up to the client to create render tasks in the right order.
744 /* Create fence sync objects. Other contexts can then wait on these fences before reading
747 dependencyChecker.AddTextures(this, framebuffer);
752 void Context::ClearState()
754 mImpl->mCurrentTextureBindings.clear();
757 void Context::ColorMask(bool enabled)
759 if(enabled != mImpl->mGlStateCache.mColorMask)
761 mImpl->mGlStateCache.mColorMask = enabled;
763 auto& gl = *mImpl->mController.GetGL();
764 gl.ColorMask(enabled, enabled, enabled, enabled);
768 void Context::ClearStencilBuffer()
770 ClearBuffer(GL_STENCIL_BUFFER_BIT, false);
773 void Context::ClearDepthBuffer()
775 ClearBuffer(GL_DEPTH_BUFFER_BIT, false);
778 void Context::ClearBuffer(uint32_t mask, bool forceClear)
780 mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled);
783 auto& gl = *mImpl->mController.GetGL();
788 void Context::InvalidateDepthStencilBuffers()
790 auto& gl = *mImpl->mController.GetGL();
792 GLenum attachments[] = {GL_DEPTH, GL_STENCIL};
793 gl.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
796 void Context::SetScissorTestEnabled(bool scissorEnabled)
798 if(mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled)
800 mImpl->mGlStateCache.mScissorTestEnabled = scissorEnabled;
802 auto& gl = *mImpl->mController.GetGL();
805 gl.Enable(GL_SCISSOR_TEST);
809 gl.Disable(GL_SCISSOR_TEST);
814 void Context::SetStencilTestEnable(bool stencilEnable)
816 if(stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled)
818 mImpl->mGlStateCache.mStencilBufferEnabled = stencilEnable;
820 auto& gl = *mImpl->mController.GetGL();
823 gl.Enable(GL_STENCIL_TEST);
827 gl.Disable(GL_STENCIL_TEST);
832 void Context::StencilMask(uint32_t writeMask)
834 if(writeMask != mImpl->mGlStateCache.mStencilMask)
836 mImpl->mGlStateCache.mStencilMask = writeMask;
838 auto& gl = *mImpl->mController.GetGL();
839 gl.StencilMask(writeMask);
843 void Context::StencilFunc(Graphics::CompareOp compareOp,
845 uint32_t compareMask)
847 if(compareOp != mImpl->mGlStateCache.mStencilFunc ||
848 reference != mImpl->mGlStateCache.mStencilFuncRef ||
849 compareMask != mImpl->mGlStateCache.mStencilFuncMask)
851 mImpl->mGlStateCache.mStencilFunc = compareOp;
852 mImpl->mGlStateCache.mStencilFuncRef = reference;
853 mImpl->mGlStateCache.mStencilFuncMask = compareMask;
855 auto& gl = *mImpl->mController.GetGL();
856 gl.StencilFunc(GLCompareOp(compareOp).op, reference, compareMask);
860 void Context::StencilOp(Graphics::StencilOp failOp,
861 Graphics::StencilOp depthFailOp,
862 Graphics::StencilOp passOp)
864 if(failOp != mImpl->mGlStateCache.mStencilOpFail ||
865 depthFailOp != mImpl->mGlStateCache.mStencilOpDepthFail ||
866 passOp != mImpl->mGlStateCache.mStencilOpDepthPass)
868 mImpl->mGlStateCache.mStencilOpFail = failOp;
869 mImpl->mGlStateCache.mStencilOpDepthFail = depthFailOp;
870 mImpl->mGlStateCache.mStencilOpDepthPass = passOp;
872 auto& gl = *mImpl->mController.GetGL();
873 gl.StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op);
877 void Context::SetDepthCompareOp(Graphics::CompareOp compareOp)
879 if(compareOp != mImpl->mGlStateCache.mDepthFunction)
881 mImpl->mGlStateCache.mDepthFunction = compareOp;
882 auto& gl = *mImpl->mController.GetGL();
883 gl.DepthFunc(GLCompareOp(compareOp).op);
887 void Context::SetDepthTestEnable(bool depthTestEnable)
889 if(depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled)
891 mImpl->mGlStateCache.mDepthBufferEnabled = depthTestEnable;
893 auto& gl = *mImpl->mController.GetGL();
896 gl.Enable(GL_DEPTH_TEST);
900 gl.Disable(GL_DEPTH_TEST);
905 void Context::SetDepthWriteEnable(bool depthWriteEnable)
907 if(depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled)
909 mImpl->mGlStateCache.mDepthMaskEnabled = depthWriteEnable;
911 auto& gl = *mImpl->mController.GetGL();
912 gl.DepthMask(depthWriteEnable);
916 void Context::ActiveTexture(uint32_t textureBindingIndex)
918 if(mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex)
920 mImpl->mGlStateCache.mActiveTextureUnit = textureBindingIndex;
922 auto& gl = *mImpl->mController.GetGL();
923 gl.ActiveTexture(GL_TEXTURE0 + textureBindingIndex);
927 void Context::BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId)
929 uint32_t typeId = static_cast<uint32_t>(textureTypeId);
930 if(mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] != textureId)
932 mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] = textureId;
934 auto& gl = *mImpl->mController.GetGL();
935 gl.BindTexture(target, textureId);
939 void Context::GenerateMipmap(GLenum target)
941 auto& gl = *mImpl->mController.GetGL();
942 gl.GenerateMipmap(target);
945 void Context::BindBuffer(GLenum target, uint32_t bufferId)
947 if(mImpl->mGlStateCache.mBoundArrayBufferId != bufferId)
949 mImpl->mGlStateCache.mBoundArrayBufferId = bufferId;
951 auto& gl = *mImpl->mController.GetGL();
952 gl.BindBuffer(target, bufferId);
956 void Context::DrawBuffers(uint32_t count, const GLenum* buffers)
958 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
959 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
960 mImpl->mGlStateCache.StencilBufferWriteEnabled());
962 auto& gl = *mImpl->mController.GetGL();
963 gl.DrawBuffers(count, buffers);
966 void Context::BindFrameBuffer(GLenum target, uint32_t bufferId)
968 mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId);
970 auto& gl = *mImpl->mController.GetGL();
971 gl.BindFramebuffer(target, bufferId);
974 void Context::GenFramebuffers(uint32_t count, uint32_t* framebuffers)
976 auto& gl = *mImpl->mController.GetGL();
977 gl.GenFramebuffers(count, framebuffers);
979 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersCreated(count, framebuffers);
982 void Context::DeleteFramebuffers(uint32_t count, uint32_t* framebuffers)
984 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers);
986 auto& gl = *mImpl->mController.GetGL();
987 gl.DeleteFramebuffers(count, framebuffers);
990 GLStateCache& Context::GetGLStateCache()
992 return mImpl->mGlStateCache;
995 void Context::GlContextCreated()
997 if(!mImpl->mGlContextCreated)
999 mImpl->mGlContextCreated = true;
1001 // Set the initial GL state
1002 mImpl->InitializeGlState();
1006 void Context::GlContextDestroyed()
1008 mImpl->mGlContextCreated = false;
1011 void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline)
1013 // Since the pipeline is deleted, invalidate the cached pipeline.
1014 if(mImpl->mCurrentPipeline == &pipeline->GetPipeline())
1016 mImpl->mCurrentPipeline = nullptr;
1020 void Context::PrepareForNativeRendering()
1022 // this should be pretty much constant
1023 auto display = eglGetCurrentDisplay();
1024 auto drawSurface = eglGetCurrentSurface(EGL_DRAW);
1025 auto readSurface = eglGetCurrentSurface(EGL_READ);
1026 auto context = eglGetCurrentContext();
1028 // push the surface and context data to the impl
1029 // It's needed to restore context
1030 if(!mImpl->mCacheEGLGraphicsContext)
1032 mImpl->mCacheDrawWriteSurface = drawSurface;
1033 mImpl->mCacheDrawReadSurface = readSurface;
1034 mImpl->mCacheEGLGraphicsContext = context;
1037 if(!mImpl->mNativeDrawContext)
1039 EGLint configId{0u};
1040 eglQueryContext(display, mImpl->mController.GetSharedContext(), EGL_CONFIG_ID, &configId);
1042 EGLint configAttribs[3];
1043 configAttribs[0] = EGL_CONFIG_ID;
1044 configAttribs[1] = configId;
1045 configAttribs[2] = EGL_NONE;
1049 if(eglChooseConfig(display, configAttribs, &config, 1, &numConfigs) != EGL_TRUE)
1051 DALI_LOG_ERROR("eglChooseConfig failed!\n");
1055 auto version = int(mImpl->mController.GetGLESVersion());
1057 std::vector<EGLint> attribs;
1058 attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
1059 attribs.push_back(version / 10);
1060 attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
1061 attribs.push_back(version % 10);
1062 attribs.push_back(EGL_NONE);
1064 mImpl->mNativeDrawContext = eglCreateContext(display, config, mImpl->mController.GetSharedContext(), attribs.data());
1065 if(mImpl->mNativeDrawContext == EGL_NO_CONTEXT)
1067 DALI_LOG_ERROR("eglCreateContext failed!\n");
1072 eglMakeCurrent(display, drawSurface, readSurface, mImpl->mNativeDrawContext);
1075 void Context::RestoreFromNativeRendering()
1077 auto display = eglGetCurrentDisplay();
1079 // bring back original context
1080 eglMakeCurrent(display, mImpl->mCacheDrawWriteSurface, mImpl->mCacheDrawReadSurface, mImpl->mCacheEGLGraphicsContext);
1083 } // namespace Dali::Graphics::GLES