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/gl-abstraction.h>
21 #include <dali/integration-api/gl-defines.h>
22 #include <dali/internal/graphics/common/graphics-interface.h>
23 #include <dali/public-api/math/math-utils.h>
25 #include "egl-graphics-controller.h"
26 #include "gles-graphics-buffer.h"
27 #include "gles-graphics-pipeline.h"
28 #include "gles-graphics-program.h"
29 #include "gles-graphics-render-pass.h"
30 #include "gles-graphics-render-target.h"
31 #include "gles-texture-dependency-checker.h"
34 #include <EGL/eglext.h>
37 namespace Dali::Graphics::GLES
41 explicit Impl(EglGraphicsController& controller)
42 : mController(controller)
49 * Binds (and creates) VAO
51 * VAO is fixed per program so it has to be created only once assuming
52 * that VertexInputState has been set correctly for the pipeline.
55 void BindProgramVAO(GLES::ProgramImpl* program, const VertexInputState& vertexInputState)
57 auto& gl = *mController.GetGL();
58 auto iter = mProgramVAOMap.find(program);
59 if(iter != mProgramVAOMap.end())
61 if(mProgramVAOCurrentState != iter->second)
63 mProgramVAOCurrentState = iter->second;
64 gl.BindVertexArray(iter->second);
70 gl.GenVertexArrays(1, &vao);
71 gl.BindVertexArray(vao);
72 mProgramVAOMap[program] = vao;
73 for(const auto& attr : vertexInputState.attributes)
75 gl.EnableVertexAttribArray(attr.location);
78 mProgramVAOCurrentState = vao;
82 * Sets the initial GL state.
84 void InitializeGlState()
86 auto& gl = *mController.GetGL();
88 mGlStateCache.mClearColorSet = false;
89 mGlStateCache.mColorMask = true;
90 mGlStateCache.mStencilMask = 0xFF;
91 mGlStateCache.mBlendEnabled = false;
92 mGlStateCache.mDepthBufferEnabled = false;
93 mGlStateCache.mDepthMaskEnabled = false;
94 mGlStateCache.mScissorTestEnabled = false;
95 mGlStateCache.mStencilBufferEnabled = false;
97 gl.Disable(GL_DITHER);
99 mGlStateCache.mBoundArrayBufferId = 0;
100 mGlStateCache.mBoundElementArrayBufferId = 0;
101 mGlStateCache.mActiveTextureUnit = 0;
103 mGlStateCache.mBlendFuncSeparateSrcRGB = BlendFactor::ONE;
104 mGlStateCache.mBlendFuncSeparateDstRGB = BlendFactor::ZERO;
105 mGlStateCache.mBlendFuncSeparateSrcAlpha = BlendFactor::ONE;
106 mGlStateCache.mBlendFuncSeparateDstAlpha = BlendFactor::ZERO;
108 // initial state is GL_FUNC_ADD for both RGB and Alpha blend modes
109 mGlStateCache.mBlendEquationSeparateModeRGB = BlendOp::ADD;
110 mGlStateCache.mBlendEquationSeparateModeAlpha = BlendOp::ADD;
112 mGlStateCache.mCullFaceMode = CullMode::NONE; //By default cullface is disabled, front face is set to CCW and cull face is set to back
114 //Initialze vertex attribute cache
115 memset(&mGlStateCache.mVertexAttributeCachedState, 0, sizeof(mGlStateCache.mVertexAttributeCachedState));
116 memset(&mGlStateCache.mVertexAttributeCurrentState, 0, sizeof(mGlStateCache.mVertexAttributeCurrentState));
118 //Initialize bound 2d texture cache
119 memset(&mGlStateCache.mBoundTextureId, 0, sizeof(mGlStateCache.mBoundTextureId));
121 mGlStateCache.mFrameBufferStateCache.Reset();
125 * Flushes vertex attribute location changes to the driver
127 void FlushVertexAttributeLocations()
129 auto& gl = *mController.GetGL();
131 for(unsigned int i = 0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i)
133 // see if the cached state is different to the actual state
134 if(mGlStateCache.mVertexAttributeCurrentState[i] != mGlStateCache.mVertexAttributeCachedState[i])
136 // it's different so make the change to the driver and update the cached state
137 mGlStateCache.mVertexAttributeCurrentState[i] = mGlStateCache.mVertexAttributeCachedState[i];
139 if(mGlStateCache.mVertexAttributeCurrentState[i])
141 gl.EnableVertexAttribArray(i);
145 gl.DisableVertexAttribArray(i);
152 * Either enables or disables a vertex attribute location in the cache
153 * The cahnges won't take affect until FlushVertexAttributeLocations is called
154 * @param location attribute location
155 * @param state attribute state
157 void SetVertexAttributeLocation(unsigned int location, bool state)
159 auto& gl = *mController.GetGL();
161 if(location >= MAX_ATTRIBUTE_CACHE_SIZE)
163 // not cached, make the gl call through context
166 gl.EnableVertexAttribArray(location);
170 gl.DisableVertexAttribArray(location);
175 // set the cached state, it will be set at the next draw call
176 // if it's different from the current driver state
177 mGlStateCache.mVertexAttributeCachedState[location] = state;
181 EglGraphicsController& mController;
183 const GLES::PipelineImpl* mCurrentPipeline{nullptr}; ///< Currently bound pipeline
184 const GLES::PipelineImpl* mNewPipeline{nullptr}; ///< New pipeline to be set on flush
186 std::vector<Graphics::TextureBinding> mCurrentTextureBindings{};
187 std::vector<Graphics::SamplerBinding> mCurrentSamplerBindings{};
188 GLES::IndexBufferBindingDescriptor mCurrentIndexBufferBinding{};
190 struct VertexBufferBinding
192 GLES::Buffer* buffer{nullptr};
196 // Currently bound buffers
197 std::vector<VertexBufferBindingDescriptor> mCurrentVertexBufferBindings{};
199 // Currently bound UBOs (check if it's needed per program!)
200 std::vector<UniformBufferBindingDescriptor> mCurrentUBOBindings{};
201 UniformBufferBindingDescriptor mCurrentStandaloneUBOBinding{};
203 // Current render pass and render target
204 const GLES::RenderTarget* mCurrentRenderTarget{nullptr};
205 const GLES::RenderPass* mCurrentRenderPass{nullptr};
207 // Each context must have own VAOs as they cannot be shared
208 std::map<GLES::ProgramImpl*, uint32_t> mProgramVAOMap; ///< GL program-VAO map
209 uint32_t mProgramVAOCurrentState{0u}; ///< Currently bound VAO
210 GLStateCache mGlStateCache{}; ///< GL status cache
212 bool mGlContextCreated{false}; ///< True if the OpenGL context has been created
214 EGLContext mNativeDrawContext{0u}; ///< Native rendering EGL context compatible with window context
216 EGLSurface mCacheDrawReadSurface{0u}; ///< cached 'read' surface
217 EGLSurface mCacheDrawWriteSurface{0u}; ///< cached 'write' surface
218 EGLContext mCacheEGLGraphicsContext{0u}; ///< cached window context
221 Context::Context(EglGraphicsController& controller)
223 mImpl = std::make_unique<Impl>(controller);
228 // Destroy native rendering context if one exists
229 if(mImpl->mNativeDrawContext)
231 eglDestroyContext(eglGetCurrentDisplay(), mImpl->mNativeDrawContext);
232 mImpl->mNativeDrawContext = EGL_NO_CONTEXT;
236 void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES::TextureDependencyChecker& dependencyChecker)
238 auto& gl = *mImpl->mController.GetGL();
240 static const bool hasGLES3(mImpl->mController.GetGLESVersion() >= GLESVersion::GLES_30);
242 // early out if neither current nor new pipelines are set
243 // this behaviour may be valid so no assert
244 if(!mImpl->mCurrentPipeline && !mImpl->mNewPipeline)
249 // Execute states if pipeline is changed
250 const auto currentProgram = mImpl->mCurrentPipeline ? static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program) : nullptr;
252 // case when new pipeline has been set
253 const GLES::Program* newProgram = nullptr;
255 if(mImpl->mNewPipeline)
257 newProgram = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
260 if(mImpl->mNewPipeline && mImpl->mCurrentPipeline != mImpl->mNewPipeline)
262 if(!currentProgram || currentProgram->GetImplementation()->GetGlProgram() != newProgram->GetImplementation()->GetGlProgram())
264 mImpl->mNewPipeline->Bind(newProgram->GetImplementation()->GetGlProgram());
270 // Resolve rasterization state
271 ResolveRasterizationState();
274 // Resolve uniform buffers
275 ResolveUniformBuffers();
278 // Map binding# to sampler location
279 const auto& reflection = !newProgram ? currentProgram->GetReflection() : newProgram->GetReflection();
280 const auto& samplers = reflection.GetSamplers();
281 for(const auto& binding : mImpl->mCurrentTextureBindings)
283 auto texture = const_cast<GLES::Texture*>(static_cast<const GLES::Texture*>(binding.texture));
285 // Texture may not have been initialized yet...(tbm_surface timing issue?)
286 if(!texture->GetGLTexture())
288 // Attempt to reinitialize
289 // @todo need to put this somewhere else where it isn't const.
290 // Maybe post it bac/k on end of initialize queue if initialization fails?
291 texture->InitializeResource();
294 // Warning, this may cause glWaitSync to occur on the GPU.
295 dependencyChecker.CheckNeedsSync(this, texture);
297 texture->Bind(binding);
299 texture->Prepare(); // @todo also non-const.
301 if(binding.binding < samplers.size()) // binding maps to texture unit. (texture bindings should also be in binding order)
303 // Offset is set to the lexical offset within the frag shader, map it to the texture unit
304 // @todo Explicitly set the texture unit through the graphics interface
305 gl.Uniform1i(samplers[binding.binding].location, samplers[binding.binding].offset);
309 // for each attribute bind vertices
311 const auto& pipelineState = mImpl->mNewPipeline ? mImpl->mNewPipeline->GetCreateInfo() : mImpl->mCurrentPipeline->GetCreateInfo();
312 const auto& vertexInputState = pipelineState.vertexInputState;
316 mImpl->BindProgramVAO(static_cast<const GLES::Program*>(pipelineState.programState->program)->GetImplementation(), *vertexInputState);
319 for(const auto& attr : vertexInputState->attributes)
324 mImpl->SetVertexAttributeLocation(attr.location, true);
327 const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding];
328 const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding];
330 auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
333 BindBuffer(GL_ARRAY_BUFFER, glesBuffer);
335 gl.VertexAttribPointer(attr.location,
336 GLVertexFormat(attr.format).size,
337 GLVertexFormat(attr.format).format,
339 bufferBinding.stride,
340 reinterpret_cast<void*>(attr.offset));
344 const auto& ia = pipelineState.inputAssemblyState;
349 switch(drawCall.type)
351 case DrawCallDescriptor::Type::DRAW:
353 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
354 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
355 mImpl->mGlStateCache.StencilBufferWriteEnabled());
356 // For GLES3+ we use VAO, for GLES2 internal cache
359 mImpl->FlushVertexAttributeLocations();
362 //@todo Wait if textures need syncing
363 gl.DrawArrays(GLESTopology(ia->topology),
364 drawCall.draw.firstVertex,
365 drawCall.draw.vertexCount);
368 case DrawCallDescriptor::Type::DRAW_INDEXED:
370 const auto& binding = mImpl->mCurrentIndexBufferBinding;
371 BindBuffer(GL_ELEMENT_ARRAY_BUFFER, binding.buffer->GetGLBuffer());
373 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
374 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
375 mImpl->mGlStateCache.StencilBufferWriteEnabled());
377 // For GLES3+ we use VAO, for GLES2 internal cache
380 mImpl->FlushVertexAttributeLocations();
383 auto indexBufferFormat = GLIndexFormat(binding.format).format;
384 gl.DrawElements(GLESTopology(ia->topology),
385 drawCall.drawIndexed.indexCount,
387 reinterpret_cast<void*>(binding.offset));
390 case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
399 if(mImpl->mNewPipeline)
401 mImpl->mCurrentPipeline = mImpl->mNewPipeline;
402 mImpl->mNewPipeline = nullptr;
406 void Context::BindTextures(const Graphics::TextureBinding* bindings, uint32_t count)
408 // for each texture allocate slot
409 for(auto i = 0u; i < count; ++i)
411 auto& binding = bindings[i];
413 // Resize binding array if needed
414 if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
416 mImpl->mCurrentTextureBindings.resize(binding.binding + 1);
418 // Store the binding details
419 mImpl->mCurrentTextureBindings[binding.binding] = binding;
423 void Context::BindVertexBuffers(const GLES::VertexBufferBindingDescriptor* bindings, uint32_t count)
425 if(count > mImpl->mCurrentVertexBufferBindings.size())
427 mImpl->mCurrentVertexBufferBindings.resize(count);
429 // Copy only set slots
430 std::copy_if(bindings, bindings + count, mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
431 return (nullptr != item.buffer);
435 void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding)
437 mImpl->mCurrentIndexBufferBinding = indexBufferBinding;
440 void Context::BindPipeline(const GLES::Pipeline* newPipeline)
442 DALI_ASSERT_ALWAYS(newPipeline && "Invalid pipeline");
443 mImpl->mNewPipeline = &newPipeline->GetPipeline();
446 void Context::BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindings,
448 const UniformBufferBindingDescriptor& standaloneBindings)
450 if(standaloneBindings.buffer)
452 mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
455 if(uboCount >= mImpl->mCurrentUBOBindings.size())
457 mImpl->mCurrentUBOBindings.resize(uboCount + 1);
460 auto it = uboBindings;
461 for(auto i = 0u; i < uboCount; ++i)
465 mImpl->mCurrentUBOBindings[i] = *it;
470 void Context::ResolveBlendState()
472 const auto& currentBlendState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().colorBlendState : nullptr;
473 const auto& newBlendState = mImpl->mNewPipeline->GetCreateInfo().colorBlendState;
475 // TODO: prevent leaking the state
481 auto& gl = *mImpl->mController.GetGL();
483 if(!currentBlendState || currentBlendState->blendEnable != newBlendState->blendEnable)
485 if(newBlendState->blendEnable != mImpl->mGlStateCache.mBlendEnabled)
487 mImpl->mGlStateCache.mBlendEnabled = newBlendState->blendEnable;
488 newBlendState->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND);
492 if(!newBlendState->blendEnable)
497 BlendFactor newSrcRGB(newBlendState->srcColorBlendFactor);
498 BlendFactor newDstRGB(newBlendState->dstColorBlendFactor);
499 BlendFactor newSrcAlpha(newBlendState->srcAlphaBlendFactor);
500 BlendFactor newDstAlpha(newBlendState->dstAlphaBlendFactor);
502 if(!currentBlendState ||
503 currentBlendState->srcColorBlendFactor != newSrcRGB ||
504 currentBlendState->dstColorBlendFactor != newDstRGB ||
505 currentBlendState->srcAlphaBlendFactor != newSrcAlpha ||
506 currentBlendState->dstAlphaBlendFactor != newDstAlpha)
508 if((mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB != newSrcRGB) ||
509 (mImpl->mGlStateCache.mBlendFuncSeparateDstRGB != newDstRGB) ||
510 (mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha != newSrcAlpha) ||
511 (mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha != newDstAlpha))
513 mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB = newSrcRGB;
514 mImpl->mGlStateCache.mBlendFuncSeparateDstRGB = newDstRGB;
515 mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha = newSrcAlpha;
516 mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha = newDstAlpha;
518 if(newSrcRGB == newSrcAlpha && newDstRGB == newDstAlpha)
520 gl.BlendFunc(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB));
524 gl.BlendFuncSeparate(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB), GLBlendFunc(newSrcAlpha), GLBlendFunc(newDstAlpha));
529 if(!currentBlendState ||
530 currentBlendState->colorBlendOp != newBlendState->colorBlendOp ||
531 currentBlendState->alphaBlendOp != newBlendState->alphaBlendOp)
533 if(mImpl->mGlStateCache.mBlendEquationSeparateModeRGB != newBlendState->colorBlendOp ||
534 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha != newBlendState->alphaBlendOp)
536 mImpl->mGlStateCache.mBlendEquationSeparateModeRGB = newBlendState->colorBlendOp;
537 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha = newBlendState->alphaBlendOp;
539 if(newBlendState->colorBlendOp == newBlendState->alphaBlendOp)
541 gl.BlendEquation(GLBlendOp(newBlendState->colorBlendOp));
542 if(newBlendState->colorBlendOp >= Graphics::ADVANCED_BLEND_OPTIONS_START)
549 gl.BlendEquationSeparate(GLBlendOp(newBlendState->colorBlendOp), GLBlendOp(newBlendState->alphaBlendOp));
555 void Context::ResolveRasterizationState()
557 const auto& currentRasterizationState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().rasterizationState : nullptr;
558 const auto& newRasterizationState = mImpl->mNewPipeline->GetCreateInfo().rasterizationState;
560 // TODO: prevent leaking the state
561 if(!newRasterizationState)
566 auto& gl = *mImpl->mController.GetGL();
568 if(!currentRasterizationState ||
569 currentRasterizationState->cullMode != newRasterizationState->cullMode)
571 if(mImpl->mGlStateCache.mCullFaceMode != newRasterizationState->cullMode)
573 mImpl->mGlStateCache.mCullFaceMode = newRasterizationState->cullMode;
574 if(newRasterizationState->cullMode == CullMode::NONE)
576 gl.Disable(GL_CULL_FACE);
580 gl.Enable(GL_CULL_FACE);
581 gl.CullFace(GLCullMode(newRasterizationState->cullMode));
585 // TODO: implement polygon mode (fill, line, points)
586 // seems like we don't support it (no glPolygonMode())
589 void Context::ResolveUniformBuffers()
591 // Resolve standalone uniforms if we have binding
592 if(mImpl->mCurrentStandaloneUBOBinding.buffer)
594 ResolveStandaloneUniforms();
598 void Context::ResolveStandaloneUniforms()
600 // Find reflection for program
601 const GLES::Program* program{nullptr};
603 if(mImpl->mNewPipeline)
605 program = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
607 else if(mImpl->mCurrentPipeline)
609 program = static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program);
614 const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset;
615 // Update program uniforms
616 program->GetImplementation()->UpdateStandaloneUniformBlock(ptr);
620 void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
622 auto& renderPass = *renderPassBegin.renderPass;
623 auto& renderTarget = *renderPassBegin.renderTarget;
625 const auto& targetInfo = renderTarget.GetCreateInfo();
627 auto& gl = *mImpl->mController.GetGL();
629 if(targetInfo.surface)
632 BindFrameBuffer(GL_FRAMEBUFFER, 0);
634 else if(targetInfo.framebuffer)
636 // bind framebuffer and swap.
637 auto framebuffer = renderTarget.GetFramebuffer();
641 // clear (ideally cache the setup)
643 // In GL we assume that the last attachment is depth/stencil (we may need
644 // to cache extra information inside GLES RenderTarget if we want to be
645 // more specific in case of MRT)
647 const auto& attachments = *renderPass.GetCreateInfo().attachments;
648 const auto& color0 = attachments[0];
651 if(color0.loadOp == AttachmentLoadOp::CLEAR)
653 mask |= GL_COLOR_BUFFER_BIT;
656 // Something goes wrong here if Alpha mask is GL_TRUE
659 const auto clearValues = renderPassBegin.clearValues.Ptr();
661 if(!Dali::Equals(mImpl->mGlStateCache.mClearColor.r, clearValues[0].color.r) ||
662 !Dali::Equals(mImpl->mGlStateCache.mClearColor.g, clearValues[0].color.g) ||
663 !Dali::Equals(mImpl->mGlStateCache.mClearColor.b, clearValues[0].color.b) ||
664 !Dali::Equals(mImpl->mGlStateCache.mClearColor.a, clearValues[0].color.a) ||
665 !mImpl->mGlStateCache.mClearColorSet)
667 gl.ClearColor(clearValues[0].color.r,
668 clearValues[0].color.g,
669 clearValues[0].color.b,
670 clearValues[0].color.a);
672 mImpl->mGlStateCache.mClearColorSet = true;
673 mImpl->mGlStateCache.mClearColor = Vector4(clearValues[0].color.r,
674 clearValues[0].color.g,
675 clearValues[0].color.b,
676 clearValues[0].color.a);
680 // check for depth stencil
681 if(attachments.size() > 1)
683 const auto& depthStencil = attachments.back();
684 if(depthStencil.loadOp == AttachmentLoadOp::CLEAR)
686 if(!mImpl->mGlStateCache.mDepthMaskEnabled)
688 mImpl->mGlStateCache.mDepthMaskEnabled = true;
691 mask |= GL_DEPTH_BUFFER_BIT;
693 if(depthStencil.stencilLoadOp == AttachmentLoadOp::CLEAR)
695 if(mImpl->mGlStateCache.mStencilMask != 0xFF)
697 mImpl->mGlStateCache.mStencilMask = 0xFF;
698 gl.StencilMask(0xFF);
700 mask |= GL_STENCIL_BUFFER_BIT;
704 SetScissorTestEnabled(true);
705 gl.Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height);
706 ClearBuffer(mask, true);
707 SetScissorTestEnabled(false);
709 mImpl->mCurrentRenderPass = &renderPass;
710 mImpl->mCurrentRenderTarget = &renderTarget;
713 void Context::EndRenderPass(GLES::TextureDependencyChecker& dependencyChecker)
715 if(mImpl->mCurrentRenderTarget)
717 GLES::Framebuffer* framebuffer = mImpl->mCurrentRenderTarget->GetFramebuffer();
720 auto& gl = *mImpl->mController.GetGL();
723 /* @todo Full dependency checking would need to store textures in Begin, and create
724 * fence objects here; but we're going to draw all fbos on shared context in serial,
725 * so no real need (yet). Might want to consider ensuring order of render passes,
726 * but that needs doing in the controller, and would need doing before ProcessCommandQueues.
728 * Currently up to the client to create render tasks in the right order.
731 /* Create fence sync objects. Other contexts can then wait on these fences before reading
734 dependencyChecker.AddTextures(this, framebuffer);
739 void Context::ClearState()
741 mImpl->mCurrentTextureBindings.clear();
744 void Context::ColorMask(bool enabled)
746 if(enabled != mImpl->mGlStateCache.mColorMask)
748 mImpl->mGlStateCache.mColorMask = enabled;
750 auto& gl = *mImpl->mController.GetGL();
751 gl.ColorMask(enabled, enabled, enabled, enabled);
755 void Context::ClearStencilBuffer()
757 ClearBuffer(GL_STENCIL_BUFFER_BIT, false);
760 void Context::ClearDepthBuffer()
762 ClearBuffer(GL_DEPTH_BUFFER_BIT, false);
765 void Context::ClearBuffer(uint32_t mask, bool forceClear)
767 mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled);
770 auto& gl = *mImpl->mController.GetGL();
775 void Context::InvalidateDepthStencilBuffers()
777 auto& gl = *mImpl->mController.GetGL();
779 GLenum attachments[] = {GL_DEPTH, GL_STENCIL};
780 gl.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
783 void Context::SetScissorTestEnabled(bool scissorEnabled)
785 if(mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled)
787 mImpl->mGlStateCache.mScissorTestEnabled = scissorEnabled;
789 auto& gl = *mImpl->mController.GetGL();
792 gl.Enable(GL_SCISSOR_TEST);
796 gl.Disable(GL_SCISSOR_TEST);
801 void Context::SetStencilTestEnable(bool stencilEnable)
803 if(stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled)
805 mImpl->mGlStateCache.mStencilBufferEnabled = stencilEnable;
807 auto& gl = *mImpl->mController.GetGL();
810 gl.Enable(GL_STENCIL_TEST);
814 gl.Disable(GL_STENCIL_TEST);
819 void Context::StencilMask(uint32_t writeMask)
821 if(writeMask != mImpl->mGlStateCache.mStencilMask)
823 mImpl->mGlStateCache.mStencilMask = writeMask;
825 auto& gl = *mImpl->mController.GetGL();
826 gl.StencilMask(writeMask);
830 void Context::StencilFunc(Graphics::CompareOp compareOp,
832 uint32_t compareMask)
834 if(compareOp != mImpl->mGlStateCache.mStencilFunc ||
835 reference != mImpl->mGlStateCache.mStencilFuncRef ||
836 compareMask != mImpl->mGlStateCache.mStencilFuncMask)
838 mImpl->mGlStateCache.mStencilFunc = compareOp;
839 mImpl->mGlStateCache.mStencilFuncRef = reference;
840 mImpl->mGlStateCache.mStencilFuncMask = compareMask;
842 auto& gl = *mImpl->mController.GetGL();
843 gl.StencilFunc(GLCompareOp(compareOp).op, reference, compareMask);
847 void Context::StencilOp(Graphics::StencilOp failOp,
848 Graphics::StencilOp depthFailOp,
849 Graphics::StencilOp passOp)
851 if(failOp != mImpl->mGlStateCache.mStencilOpFail ||
852 depthFailOp != mImpl->mGlStateCache.mStencilOpDepthFail ||
853 passOp != mImpl->mGlStateCache.mStencilOpDepthPass)
855 mImpl->mGlStateCache.mStencilOpFail = failOp;
856 mImpl->mGlStateCache.mStencilOpDepthFail = depthFailOp;
857 mImpl->mGlStateCache.mStencilOpDepthPass = passOp;
859 auto& gl = *mImpl->mController.GetGL();
860 gl.StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op);
864 void Context::SetDepthCompareOp(Graphics::CompareOp compareOp)
866 if(compareOp != mImpl->mGlStateCache.mDepthFunction)
868 mImpl->mGlStateCache.mDepthFunction = compareOp;
869 auto& gl = *mImpl->mController.GetGL();
870 gl.DepthFunc(GLCompareOp(compareOp).op);
874 void Context::SetDepthTestEnable(bool depthTestEnable)
876 if(depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled)
878 mImpl->mGlStateCache.mDepthBufferEnabled = depthTestEnable;
880 auto& gl = *mImpl->mController.GetGL();
883 gl.Enable(GL_DEPTH_TEST);
887 gl.Disable(GL_DEPTH_TEST);
892 void Context::SetDepthWriteEnable(bool depthWriteEnable)
894 if(depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled)
896 mImpl->mGlStateCache.mDepthMaskEnabled = depthWriteEnable;
898 auto& gl = *mImpl->mController.GetGL();
899 gl.DepthMask(depthWriteEnable);
903 void Context::ActiveTexture(uint32_t textureBindingIndex)
905 if(mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex)
907 mImpl->mGlStateCache.mActiveTextureUnit = textureBindingIndex;
909 auto& gl = *mImpl->mController.GetGL();
910 gl.ActiveTexture(GL_TEXTURE0 + textureBindingIndex);
914 void Context::BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId)
916 uint32_t typeId = static_cast<uint32_t>(textureTypeId);
917 if(mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] != textureId)
919 mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] = textureId;
921 auto& gl = *mImpl->mController.GetGL();
922 gl.BindTexture(target, textureId);
926 void Context::GenerateMipmap(GLenum target)
928 auto& gl = *mImpl->mController.GetGL();
929 gl.GenerateMipmap(target);
932 void Context::BindBuffer(GLenum target, uint32_t bufferId)
934 if(mImpl->mGlStateCache.mBoundArrayBufferId != bufferId)
936 mImpl->mGlStateCache.mBoundArrayBufferId = bufferId;
938 auto& gl = *mImpl->mController.GetGL();
939 gl.BindBuffer(target, bufferId);
943 void Context::DrawBuffers(uint32_t count, const GLenum* buffers)
945 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
946 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
947 mImpl->mGlStateCache.StencilBufferWriteEnabled());
949 auto& gl = *mImpl->mController.GetGL();
950 gl.DrawBuffers(count, buffers);
953 void Context::BindFrameBuffer(GLenum target, uint32_t bufferId)
955 mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId);
957 auto& gl = *mImpl->mController.GetGL();
958 gl.BindFramebuffer(target, bufferId);
961 void Context::GenFramebuffers(uint32_t count, uint32_t* framebuffers)
963 auto& gl = *mImpl->mController.GetGL();
964 gl.GenFramebuffers(count, framebuffers);
966 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersCreated(count, framebuffers);
969 void Context::DeleteFramebuffers(uint32_t count, uint32_t* framebuffers)
971 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers);
973 auto& gl = *mImpl->mController.GetGL();
974 gl.DeleteFramebuffers(count, framebuffers);
977 GLStateCache& Context::GetGLStateCache()
979 return mImpl->mGlStateCache;
982 void Context::GlContextCreated()
984 if(!mImpl->mGlContextCreated)
986 mImpl->mGlContextCreated = true;
988 // Set the initial GL state
989 mImpl->InitializeGlState();
993 void Context::GlContextDestroyed()
995 mImpl->mGlContextCreated = false;
998 void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline)
1000 // Since the pipeline is deleted, invalidate the cached pipeline.
1001 if(mImpl->mCurrentPipeline == &pipeline->GetPipeline())
1003 mImpl->mCurrentPipeline = nullptr;
1007 void Context::PrepareForNativeRendering()
1009 // this should be pretty much constant
1010 auto display = eglGetCurrentDisplay();
1011 auto drawSurface = eglGetCurrentSurface(EGL_DRAW);
1012 auto readSurface = eglGetCurrentSurface(EGL_READ);
1013 auto context = eglGetCurrentContext();
1015 // push the surface and context data to the impl
1016 // It's needed to restore context
1017 if(!mImpl->mCacheEGLGraphicsContext)
1019 mImpl->mCacheDrawWriteSurface = drawSurface;
1020 mImpl->mCacheDrawReadSurface = readSurface;
1021 mImpl->mCacheEGLGraphicsContext = context;
1024 if(!mImpl->mNativeDrawContext)
1026 EGLint configId{0u};
1028 eglGetConfigs(display, nullptr, 0, &size);
1029 std::vector<EGLConfig> configs;
1030 configs.resize(size);
1031 eglGetConfigs(display, configs.data(), configs.size(), &size);
1033 eglQueryContext(display, context, EGL_CONFIG_ID, &configId);
1035 auto version = int(mImpl->mController.GetGLESVersion());
1037 std::vector<EGLint> attribs;
1038 attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
1039 attribs.push_back(version / 10);
1040 attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
1041 attribs.push_back(version % 10);
1042 attribs.push_back(EGL_NONE);
1044 mImpl->mNativeDrawContext = eglCreateContext(display, configs[configId], mImpl->mController.GetSharedContext(), attribs.data());
1047 eglMakeCurrent(display, drawSurface, readSurface, mImpl->mNativeDrawContext);
1050 void Context::RestoreFromNativeRendering()
1052 auto display = eglGetCurrentDisplay();
1054 // bring back original context
1055 eglMakeCurrent(display, mImpl->mCacheDrawWriteSurface, mImpl->mCacheDrawReadSurface, mImpl->mCacheEGLGraphicsContext);
1058 } // namespace Dali::Graphics::GLES