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>
24 #include "egl-graphics-controller.h"
25 #include "gles-graphics-buffer.h"
26 #include "gles-graphics-pipeline.h"
27 #include "gles-graphics-program.h"
28 #include "gles-graphics-render-pass.h"
29 #include "gles-graphics-render-target.h"
32 #include <EGL/eglext.h>
35 namespace Dali::Graphics::GLES
39 explicit Impl(EglGraphicsController& controller)
40 : mController(controller)
47 * Binds (and creates) VAO
49 * VAO is fixed per program so it has to be created only once assuming
50 * that VertexInputState has been set correctly for the pipeline.
53 void BindProgramVAO(GLES::ProgramImpl* program, const VertexInputState& vertexInputState)
55 auto& gl = *mController.GetGL();
56 auto iter = mProgramVAOMap.find(program);
57 if(iter != mProgramVAOMap.end())
59 if(mProgramVAOCurrentState != iter->second)
61 mProgramVAOCurrentState = iter->second;
62 gl.BindVertexArray(iter->second);
68 gl.GenVertexArrays(1, &vao);
69 gl.BindVertexArray(vao);
70 mProgramVAOMap[program] = vao;
71 for(const auto& attr : vertexInputState.attributes)
73 gl.EnableVertexAttribArray(attr.location);
76 mProgramVAOCurrentState = vao;
80 * Sets the initial GL state.
82 void InitializeGlState()
84 auto& gl = *mController.GetGL();
86 mGlStateCache.mClearColorSet = false;
87 mGlStateCache.mColorMask = true;
88 mGlStateCache.mStencilMask = 0xFF;
89 mGlStateCache.mBlendEnabled = false;
90 mGlStateCache.mDepthBufferEnabled = false;
91 mGlStateCache.mDepthMaskEnabled = false;
92 mGlStateCache.mScissorTestEnabled = false;
93 mGlStateCache.mStencilBufferEnabled = false;
95 gl.Disable(GL_DITHER);
97 mGlStateCache.mBoundArrayBufferId = 0;
98 mGlStateCache.mBoundElementArrayBufferId = 0;
99 mGlStateCache.mActiveTextureUnit = 0;
101 mGlStateCache.mBlendFuncSeparateSrcRGB = BlendFactor::ONE;
102 mGlStateCache.mBlendFuncSeparateDstRGB = BlendFactor::ZERO;
103 mGlStateCache.mBlendFuncSeparateSrcAlpha = BlendFactor::ONE;
104 mGlStateCache.mBlendFuncSeparateDstAlpha = BlendFactor::ZERO;
106 // initial state is GL_FUNC_ADD for both RGB and Alpha blend modes
107 mGlStateCache.mBlendEquationSeparateModeRGB = BlendOp::ADD;
108 mGlStateCache.mBlendEquationSeparateModeAlpha = BlendOp::ADD;
110 mGlStateCache.mCullFaceMode = CullMode::NONE; //By default cullface is disabled, front face is set to CCW and cull face is set to back
112 //Initialze vertex attribute cache
113 memset(&mGlStateCache.mVertexAttributeCachedState, 0, sizeof(mGlStateCache.mVertexAttributeCachedState));
114 memset(&mGlStateCache.mVertexAttributeCurrentState, 0, sizeof(mGlStateCache.mVertexAttributeCurrentState));
116 //Initialize bound 2d texture cache
117 memset(&mGlStateCache.mBoundTextureId, 0, sizeof(mGlStateCache.mBoundTextureId));
119 mGlStateCache.mFrameBufferStateCache.Reset();
123 * Flushes vertex attribute location changes to the driver
125 void FlushVertexAttributeLocations()
127 auto& gl = *mController.GetGL();
129 for(unsigned int i = 0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i)
131 // see if the cached state is different to the actual state
132 if(mGlStateCache.mVertexAttributeCurrentState[i] != mGlStateCache.mVertexAttributeCachedState[i])
134 // it's different so make the change to the driver and update the cached state
135 mGlStateCache.mVertexAttributeCurrentState[i] = mGlStateCache.mVertexAttributeCachedState[i];
137 if(mGlStateCache.mVertexAttributeCurrentState[i])
139 gl.EnableVertexAttribArray(i);
143 gl.DisableVertexAttribArray(i);
150 * Either enables or disables a vertex attribute location in the cache
151 * The cahnges won't take affect until FlushVertexAttributeLocations is called
152 * @param location attribute location
153 * @param state attribute state
155 void SetVertexAttributeLocation(unsigned int location, bool state)
157 auto& gl = *mController.GetGL();
159 if(location >= MAX_ATTRIBUTE_CACHE_SIZE)
161 // not cached, make the gl call through context
164 gl.EnableVertexAttribArray(location);
168 gl.DisableVertexAttribArray(location);
173 // set the cached state, it will be set at the next draw call
174 // if it's different from the current driver state
175 mGlStateCache.mVertexAttributeCachedState[location] = state;
179 EglGraphicsController& mController;
181 const GLES::PipelineImpl* mCurrentPipeline{nullptr}; ///< Currently bound pipeline
182 const GLES::PipelineImpl* mNewPipeline{nullptr}; ///< New pipeline to be set on flush
184 std::vector<Graphics::TextureBinding> mCurrentTextureBindings{};
185 std::vector<Graphics::SamplerBinding> mCurrentSamplerBindings{};
186 GLES::IndexBufferBindingDescriptor mCurrentIndexBufferBinding{};
188 struct VertexBufferBinding
190 GLES::Buffer* buffer{nullptr};
194 // Currently bound buffers
195 std::vector<VertexBufferBindingDescriptor> mCurrentVertexBufferBindings{};
197 // Currently bound UBOs (check if it's needed per program!)
198 std::vector<UniformBufferBindingDescriptor> mCurrentUBOBindings{};
199 UniformBufferBindingDescriptor mCurrentStandaloneUBOBinding{};
201 // Current render pass and render target
202 const GLES::RenderTarget* mCurrentRenderTarget{nullptr};
203 const GLES::RenderPass* mCurrentRenderPass{nullptr};
205 // Each context must have own VAOs as they cannot be shared
206 std::map<GLES::ProgramImpl*, uint32_t> mProgramVAOMap; ///< GL program-VAO map
207 uint32_t mProgramVAOCurrentState{0u}; ///< Currently bound VAO
208 GLStateCache mGlStateCache{}; ///< GL status cache
210 bool mGlContextCreated{false}; ///< True if the OpenGL context has been created
212 EGLContext mNativeDrawContext{0u}; ///< Native rendering EGL context compatible with window context
214 EGLSurface mCacheDrawReadSurface{0u}; ///< cached 'read' surface
215 EGLSurface mCacheDrawWriteSurface{0u}; ///< cached 'write' surface
216 EGLContext mCacheEGLGraphicsContext{0u}; ///< cached window context
219 Context::Context(EglGraphicsController& controller)
221 mImpl = std::make_unique<Impl>(controller);
226 // Destroy native rendering context if one exists
227 if(mImpl->mNativeDrawContext)
229 eglDestroyContext(eglGetCurrentDisplay(), mImpl->mNativeDrawContext);
230 mImpl->mNativeDrawContext = EGL_NO_CONTEXT;
234 void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
236 auto& gl = *mImpl->mController.GetGL();
238 static const bool hasGLES3(mImpl->mController.GetGLESVersion() >= GLESVersion::GLES_30);
240 // early out if neither current nor new pipelines are set
241 // this behaviour may be valid so no assert
242 if(!mImpl->mCurrentPipeline && !mImpl->mNewPipeline)
247 // Execute states if pipeline is changed
248 const auto currentProgram = mImpl->mCurrentPipeline ? static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program) : nullptr;
250 // case when new pipeline has been set
251 const GLES::Program* newProgram = nullptr;
253 if(mImpl->mNewPipeline)
255 newProgram = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
258 if(mImpl->mNewPipeline && mImpl->mCurrentPipeline != mImpl->mNewPipeline)
260 if(!currentProgram || currentProgram->GetImplementation()->GetGlProgram() != newProgram->GetImplementation()->GetGlProgram())
262 mImpl->mNewPipeline->Bind(newProgram->GetImplementation()->GetGlProgram());
268 // Resolve rasterization state
269 ResolveRasterizationState();
272 // Resolve uniform buffers
273 ResolveUniformBuffers();
276 // Map binding# to sampler location
277 const auto& reflection = !newProgram ? currentProgram->GetReflection() : newProgram->GetReflection();
278 const auto& samplers = reflection.GetSamplers();
279 for(const auto& binding : mImpl->mCurrentTextureBindings)
281 auto texture = const_cast<GLES::Texture*>(static_cast<const GLES::Texture*>(binding.texture));
283 // Texture may not have been initialized yet...(tbm_surface timing issue?)
284 if(!texture->GetGLTexture())
286 // Attempt to reinitialize
287 // @todo need to put this somewhere else where it isn't const.
288 // Maybe post it back on end of initialize queue if initialization fails?
289 texture->InitializeResource();
292 texture->Bind(binding);
294 texture->Prepare(); // @todo also non-const.
296 if(binding.binding < samplers.size()) // binding maps to texture unit. (texture bindings should also be in binding order)
298 // Offset is set to the lexical offset within the frag shader, map it to the texture unit
299 // @todo Explicitly set the texture unit through the graphics interface
300 gl.Uniform1i(samplers[binding.binding].location, samplers[binding.binding].offset);
304 // for each attribute bind vertices
306 const auto& pipelineState = mImpl->mNewPipeline ? mImpl->mNewPipeline->GetCreateInfo() : mImpl->mCurrentPipeline->GetCreateInfo();
307 const auto& vertexInputState = pipelineState.vertexInputState;
311 mImpl->BindProgramVAO(static_cast<const GLES::Program*>(pipelineState.programState->program)->GetImplementation(), *vertexInputState);
314 for(const auto& attr : vertexInputState->attributes)
319 mImpl->SetVertexAttributeLocation(attr.location, true);
322 const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding];
323 const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding];
325 auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
328 BindBuffer(GL_ARRAY_BUFFER, glesBuffer);
330 gl.VertexAttribPointer(attr.location,
331 GLVertexFormat(attr.format).size,
332 GLVertexFormat(attr.format).format,
334 bufferBinding.stride,
335 reinterpret_cast<void*>(attr.offset));
339 const auto& ia = pipelineState.inputAssemblyState;
344 switch(drawCall.type)
346 case DrawCallDescriptor::Type::DRAW:
348 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
349 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
350 mImpl->mGlStateCache.StencilBufferWriteEnabled());
351 // For GLES3+ we use VAO, for GLES2 internal cache
354 mImpl->FlushVertexAttributeLocations();
357 gl.DrawArrays(GLESTopology(ia->topology),
358 drawCall.draw.firstVertex,
359 drawCall.draw.vertexCount);
362 case DrawCallDescriptor::Type::DRAW_INDEXED:
364 const auto& binding = mImpl->mCurrentIndexBufferBinding;
365 BindBuffer(GL_ELEMENT_ARRAY_BUFFER, binding.buffer->GetGLBuffer());
367 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
368 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
369 mImpl->mGlStateCache.StencilBufferWriteEnabled());
371 // For GLES3+ we use VAO, for GLES2 internal cache
374 mImpl->FlushVertexAttributeLocations();
377 auto indexBufferFormat = GLIndexFormat(binding.format).format;
378 gl.DrawElements(GLESTopology(ia->topology),
379 drawCall.drawIndexed.indexCount,
381 reinterpret_cast<void*>(binding.offset));
384 case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
393 if(mImpl->mNewPipeline)
395 mImpl->mCurrentPipeline = mImpl->mNewPipeline;
396 mImpl->mNewPipeline = nullptr;
400 void Context::BindTextures(const Graphics::TextureBinding* bindings, uint32_t count)
402 // for each texture allocate slot
403 for(auto i = 0u; i < count; ++i)
405 auto& binding = bindings[i];
407 // Resize binding array if needed
408 if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
410 mImpl->mCurrentTextureBindings.resize(binding.binding + 1);
412 // Store the binding details
413 mImpl->mCurrentTextureBindings[binding.binding] = binding;
417 void Context::BindVertexBuffers(const GLES::VertexBufferBindingDescriptor* bindings, uint32_t count)
419 if(count > mImpl->mCurrentVertexBufferBindings.size())
421 mImpl->mCurrentVertexBufferBindings.resize(count);
423 // Copy only set slots
424 std::copy_if(bindings, bindings + count, mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
425 return (nullptr != item.buffer);
429 void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding)
431 mImpl->mCurrentIndexBufferBinding = indexBufferBinding;
434 void Context::BindPipeline(const GLES::Pipeline* newPipeline)
436 DALI_ASSERT_ALWAYS(newPipeline && "Invalid pipeline");
437 mImpl->mNewPipeline = &newPipeline->GetPipeline();
440 void Context::BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindings,
442 const UniformBufferBindingDescriptor& standaloneBindings)
444 if(standaloneBindings.buffer)
446 mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
449 if(uboCount >= mImpl->mCurrentUBOBindings.size())
451 mImpl->mCurrentUBOBindings.resize(uboCount + 1);
454 auto it = uboBindings;
455 for(auto i = 0u; i < uboCount; ++i)
459 mImpl->mCurrentUBOBindings[i] = *it;
464 void Context::ResolveBlendState()
466 const auto& currentBlendState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().colorBlendState : nullptr;
467 const auto& newBlendState = mImpl->mNewPipeline->GetCreateInfo().colorBlendState;
469 // TODO: prevent leaking the state
475 auto& gl = *mImpl->mController.GetGL();
477 if(!currentBlendState || currentBlendState->blendEnable != newBlendState->blendEnable)
479 if(newBlendState->blendEnable != mImpl->mGlStateCache.mBlendEnabled)
481 mImpl->mGlStateCache.mBlendEnabled = newBlendState->blendEnable;
482 newBlendState->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND);
486 if(!newBlendState->blendEnable)
491 BlendFactor newSrcRGB(newBlendState->srcColorBlendFactor);
492 BlendFactor newDstRGB(newBlendState->dstColorBlendFactor);
493 BlendFactor newSrcAlpha(newBlendState->srcAlphaBlendFactor);
494 BlendFactor newDstAlpha(newBlendState->dstAlphaBlendFactor);
496 if(!currentBlendState ||
497 currentBlendState->srcColorBlendFactor != newSrcRGB ||
498 currentBlendState->dstColorBlendFactor != newDstRGB ||
499 currentBlendState->srcAlphaBlendFactor != newSrcAlpha ||
500 currentBlendState->dstAlphaBlendFactor != newDstAlpha)
502 if((mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB != newSrcRGB) ||
503 (mImpl->mGlStateCache.mBlendFuncSeparateDstRGB != newDstRGB) ||
504 (mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha != newSrcAlpha) ||
505 (mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha != newDstAlpha))
507 mImpl->mGlStateCache.mBlendFuncSeparateSrcRGB = newSrcRGB;
508 mImpl->mGlStateCache.mBlendFuncSeparateDstRGB = newDstRGB;
509 mImpl->mGlStateCache.mBlendFuncSeparateSrcAlpha = newSrcAlpha;
510 mImpl->mGlStateCache.mBlendFuncSeparateDstAlpha = newDstAlpha;
512 if(newSrcRGB == newSrcAlpha && newDstRGB == newDstAlpha)
514 gl.BlendFunc(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB));
518 gl.BlendFuncSeparate(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB), GLBlendFunc(newSrcAlpha), GLBlendFunc(newDstAlpha));
523 if(!currentBlendState ||
524 currentBlendState->colorBlendOp != newBlendState->colorBlendOp ||
525 currentBlendState->alphaBlendOp != newBlendState->alphaBlendOp)
527 if(mImpl->mGlStateCache.mBlendEquationSeparateModeRGB != newBlendState->colorBlendOp ||
528 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha != newBlendState->alphaBlendOp)
530 mImpl->mGlStateCache.mBlendEquationSeparateModeRGB = newBlendState->colorBlendOp;
531 mImpl->mGlStateCache.mBlendEquationSeparateModeAlpha = newBlendState->alphaBlendOp;
533 if(newBlendState->colorBlendOp == newBlendState->alphaBlendOp)
535 gl.BlendEquation(GLBlendOp(newBlendState->colorBlendOp));
536 if(newBlendState->colorBlendOp >= Graphics::ADVANCED_BLEND_OPTIONS_START)
543 gl.BlendEquationSeparate(GLBlendOp(newBlendState->colorBlendOp), GLBlendOp(newBlendState->alphaBlendOp));
549 void Context::ResolveRasterizationState()
551 const auto& currentRasterizationState = mImpl->mCurrentPipeline ? mImpl->mCurrentPipeline->GetCreateInfo().rasterizationState : nullptr;
552 const auto& newRasterizationState = mImpl->mNewPipeline->GetCreateInfo().rasterizationState;
554 // TODO: prevent leaking the state
555 if(!newRasterizationState)
560 auto& gl = *mImpl->mController.GetGL();
562 if(!currentRasterizationState ||
563 currentRasterizationState->cullMode != newRasterizationState->cullMode)
565 if(mImpl->mGlStateCache.mCullFaceMode != newRasterizationState->cullMode)
567 mImpl->mGlStateCache.mCullFaceMode = newRasterizationState->cullMode;
568 if(newRasterizationState->cullMode == CullMode::NONE)
570 gl.Disable(GL_CULL_FACE);
574 gl.Enable(GL_CULL_FACE);
575 gl.CullFace(GLCullMode(newRasterizationState->cullMode));
579 // TODO: implement polygon mode (fill, line, points)
580 // seems like we don't support it (no glPolygonMode())
583 void Context::ResolveUniformBuffers()
585 // Resolve standalone uniforms if we have binding
586 if(mImpl->mCurrentStandaloneUBOBinding.buffer)
588 ResolveStandaloneUniforms();
592 void Context::ResolveStandaloneUniforms()
594 // Find reflection for program
595 const GLES::Program* program{nullptr};
597 if(mImpl->mNewPipeline)
599 program = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
601 else if(mImpl->mCurrentPipeline)
603 program = static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program);
608 const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset;
609 // Update program uniforms
610 program->GetImplementation()->UpdateStandaloneUniformBlock(ptr);
614 void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
616 auto& renderPass = *renderPassBegin.renderPass;
617 auto& renderTarget = *renderPassBegin.renderTarget;
619 const auto& targetInfo = renderTarget.GetCreateInfo();
621 auto& gl = *mImpl->mController.GetGL();
623 if(targetInfo.surface)
626 BindFrameBuffer(GL_FRAMEBUFFER, 0);
628 else if(targetInfo.framebuffer)
630 // bind framebuffer and swap.
631 renderTarget.GetFramebuffer()->Bind();
634 // clear (ideally cache the setup)
636 // In GL we assume that the last attachment is depth/stencil (we may need
637 // to cache extra information inside GLES RenderTarget if we want to be
638 // more specific in case of MRT)
640 const auto& attachments = *renderPass.GetCreateInfo().attachments;
641 const auto& color0 = attachments[0];
643 if(color0.loadOp == AttachmentLoadOp::CLEAR)
645 mask |= GL_COLOR_BUFFER_BIT;
648 // Something goes wrong here if Alpha mask is GL_TRUE
651 const auto clearValues = renderPassBegin.clearValues.Ptr();
653 if(!mImpl->mGlStateCache.mClearColorSet ||
654 mImpl->mGlStateCache.mClearColor.r != clearValues[0].color.r ||
655 mImpl->mGlStateCache.mClearColor.g != clearValues[0].color.g ||
656 mImpl->mGlStateCache.mClearColor.b != clearValues[0].color.b ||
657 mImpl->mGlStateCache.mClearColor.a != clearValues[0].color.a)
659 gl.ClearColor(clearValues[0].color.r,
660 clearValues[0].color.g,
661 clearValues[0].color.b,
662 clearValues[0].color.a);
664 mImpl->mGlStateCache.mClearColorSet = true;
665 mImpl->mGlStateCache.mClearColor = Vector4(clearValues[0].color.r,
666 clearValues[0].color.g,
667 clearValues[0].color.b,
668 clearValues[0].color.a);
672 // check for depth stencil
673 if(attachments.size() > 1)
675 const auto& depthStencil = attachments.back();
676 if(depthStencil.loadOp == AttachmentLoadOp::CLEAR)
678 if(!mImpl->mGlStateCache.mDepthMaskEnabled)
680 mImpl->mGlStateCache.mDepthMaskEnabled = true;
683 mask |= GL_DEPTH_BUFFER_BIT;
685 if(depthStencil.stencilLoadOp == AttachmentLoadOp::CLEAR)
687 if(mImpl->mGlStateCache.mStencilMask != 0xFF)
689 mImpl->mGlStateCache.mStencilMask = 0xFF;
690 gl.StencilMask(0xFF);
692 mask |= GL_STENCIL_BUFFER_BIT;
696 SetScissorTestEnabled(true);
697 gl.Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height);
698 ClearBuffer(mask, true);
699 SetScissorTestEnabled(false);
701 mImpl->mCurrentRenderPass = &renderPass;
702 mImpl->mCurrentRenderTarget = &renderTarget;
705 void Context::EndRenderPass()
707 if(mImpl->mCurrentRenderTarget)
709 if(mImpl->mCurrentRenderTarget->GetFramebuffer())
711 auto& gl = *mImpl->mController.GetGL();
717 void Context::ClearState()
719 mImpl->mCurrentTextureBindings.clear();
722 void Context::ColorMask(bool enabled)
724 if(enabled != mImpl->mGlStateCache.mColorMask)
726 mImpl->mGlStateCache.mColorMask = enabled;
728 auto& gl = *mImpl->mController.GetGL();
729 gl.ColorMask(enabled, enabled, enabled, enabled);
733 void Context::ClearStencilBuffer()
735 ClearBuffer(GL_STENCIL_BUFFER_BIT, false);
738 void Context::ClearDepthBuffer()
740 ClearBuffer(GL_DEPTH_BUFFER_BIT, false);
743 void Context::ClearBuffer(uint32_t mask, bool forceClear)
745 mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled);
748 auto& gl = *mImpl->mController.GetGL();
753 void Context::InvalidateDepthStencilBuffers()
755 auto& gl = *mImpl->mController.GetGL();
757 GLenum attachments[] = {GL_DEPTH, GL_STENCIL};
758 gl.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
761 void Context::SetScissorTestEnabled(bool scissorEnabled)
763 if(mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled)
765 mImpl->mGlStateCache.mScissorTestEnabled = scissorEnabled;
767 auto& gl = *mImpl->mController.GetGL();
770 gl.Enable(GL_SCISSOR_TEST);
774 gl.Disable(GL_SCISSOR_TEST);
779 void Context::SetStencilTestEnable(bool stencilEnable)
781 if(stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled)
783 mImpl->mGlStateCache.mStencilBufferEnabled = stencilEnable;
785 auto& gl = *mImpl->mController.GetGL();
788 gl.Enable(GL_STENCIL_TEST);
792 gl.Disable(GL_STENCIL_TEST);
797 void Context::StencilMask(uint32_t writeMask)
799 if(writeMask != mImpl->mGlStateCache.mStencilMask)
801 mImpl->mGlStateCache.mStencilMask = writeMask;
803 auto& gl = *mImpl->mController.GetGL();
804 gl.StencilMask(writeMask);
808 void Context::StencilFunc(Graphics::CompareOp compareOp,
810 uint32_t compareMask)
812 if(compareOp != mImpl->mGlStateCache.mStencilFunc ||
813 reference != mImpl->mGlStateCache.mStencilFuncRef ||
814 compareMask != mImpl->mGlStateCache.mStencilFuncMask)
816 mImpl->mGlStateCache.mStencilFunc = compareOp;
817 mImpl->mGlStateCache.mStencilFuncRef = reference;
818 mImpl->mGlStateCache.mStencilFuncMask = compareMask;
820 auto& gl = *mImpl->mController.GetGL();
821 gl.StencilFunc(GLCompareOp(compareOp).op, reference, compareMask);
825 void Context::StencilOp(Graphics::StencilOp failOp,
826 Graphics::StencilOp depthFailOp,
827 Graphics::StencilOp passOp)
829 if(failOp != mImpl->mGlStateCache.mStencilOpFail ||
830 depthFailOp != mImpl->mGlStateCache.mStencilOpDepthFail ||
831 passOp != mImpl->mGlStateCache.mStencilOpDepthPass)
833 mImpl->mGlStateCache.mStencilOpFail = failOp;
834 mImpl->mGlStateCache.mStencilOpDepthFail = depthFailOp;
835 mImpl->mGlStateCache.mStencilOpDepthPass = passOp;
837 auto& gl = *mImpl->mController.GetGL();
838 gl.StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op);
842 void Context::SetDepthCompareOp(Graphics::CompareOp compareOp)
844 if(compareOp != mImpl->mGlStateCache.mDepthFunction)
846 mImpl->mGlStateCache.mDepthFunction = compareOp;
847 auto& gl = *mImpl->mController.GetGL();
848 gl.DepthFunc(GLCompareOp(compareOp).op);
852 void Context::SetDepthTestEnable(bool depthTestEnable)
854 if(depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled)
856 mImpl->mGlStateCache.mDepthBufferEnabled = depthTestEnable;
858 auto& gl = *mImpl->mController.GetGL();
861 gl.Enable(GL_DEPTH_TEST);
865 gl.Disable(GL_DEPTH_TEST);
870 void Context::SetDepthWriteEnable(bool depthWriteEnable)
872 if(depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled)
874 mImpl->mGlStateCache.mDepthMaskEnabled = depthWriteEnable;
876 auto& gl = *mImpl->mController.GetGL();
877 gl.DepthMask(depthWriteEnable);
881 void Context::ActiveTexture(uint32_t textureBindingIndex)
883 if(mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex)
885 mImpl->mGlStateCache.mActiveTextureUnit = textureBindingIndex;
887 auto& gl = *mImpl->mController.GetGL();
888 gl.ActiveTexture(GL_TEXTURE0 + textureBindingIndex);
892 void Context::BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId)
894 uint32_t typeId = static_cast<uint32_t>(textureTypeId);
895 if(mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] != textureId)
897 mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] = textureId;
899 auto& gl = *mImpl->mController.GetGL();
900 gl.BindTexture(target, textureId);
904 void Context::GenerateMipmap(GLenum target)
906 auto& gl = *mImpl->mController.GetGL();
907 gl.GenerateMipmap(target);
910 void Context::BindBuffer(GLenum target, uint32_t bufferId)
912 if(mImpl->mGlStateCache.mBoundArrayBufferId != bufferId)
914 mImpl->mGlStateCache.mBoundArrayBufferId = bufferId;
916 auto& gl = *mImpl->mController.GetGL();
917 gl.BindBuffer(target, bufferId);
921 void Context::DrawBuffers(uint32_t count, const GLenum* buffers)
923 mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
924 mImpl->mGlStateCache.DepthBufferWriteEnabled(),
925 mImpl->mGlStateCache.StencilBufferWriteEnabled());
927 auto& gl = *mImpl->mController.GetGL();
928 gl.DrawBuffers(count, buffers);
931 void Context::BindFrameBuffer(GLenum target, uint32_t bufferId)
933 mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId);
935 auto& gl = *mImpl->mController.GetGL();
936 gl.BindFramebuffer(target, bufferId);
939 void Context::GenFramebuffers(uint32_t count, uint32_t* framebuffers)
941 auto& gl = *mImpl->mController.GetGL();
942 gl.GenFramebuffers(count, framebuffers);
944 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersCreated(count, framebuffers);
947 void Context::DeleteFramebuffers(uint32_t count, uint32_t* framebuffers)
949 mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers);
951 auto& gl = *mImpl->mController.GetGL();
952 gl.DeleteFramebuffers(count, framebuffers);
955 GLStateCache& Context::GetGLStateCache()
957 return mImpl->mGlStateCache;
960 void Context::GlContextCreated()
962 if(!mImpl->mGlContextCreated)
964 mImpl->mGlContextCreated = true;
966 // Set the initial GL state
967 mImpl->InitializeGlState();
971 void Context::GlContextDestroyed()
973 mImpl->mGlContextCreated = false;
976 void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline)
978 // Since the pipeline is deleted, invalidate the cached pipeline.
979 if(mImpl->mCurrentPipeline == &pipeline->GetPipeline())
981 mImpl->mCurrentPipeline = nullptr;
985 void Context::PrepareForNativeRendering()
987 // this should be pretty much constant
988 auto display = eglGetCurrentDisplay();
989 auto drawSurface = eglGetCurrentSurface(EGL_DRAW);
990 auto readSurface = eglGetCurrentSurface(EGL_READ);
991 auto context = eglGetCurrentContext();
993 // push the surface and context data to the impl
994 // It's needed to restore context
995 if(!mImpl->mCacheEGLGraphicsContext)
997 mImpl->mCacheDrawWriteSurface = drawSurface;
998 mImpl->mCacheDrawReadSurface = readSurface;
999 mImpl->mCacheEGLGraphicsContext = context;
1002 if(!mImpl->mNativeDrawContext)
1004 EGLint configId{0u};
1006 eglGetConfigs(display, nullptr, 0, &size);
1007 std::vector<EGLConfig> configs;
1008 configs.resize(size);
1009 eglGetConfigs(display, configs.data(), configs.size(), &size);
1011 eglQueryContext(display, context, EGL_CONFIG_ID, &configId);
1013 auto version = int(mImpl->mController.GetGLESVersion());
1015 std::vector<EGLint> attribs;
1016 attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
1017 attribs.push_back(version / 10);
1018 attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
1019 attribs.push_back(version % 10);
1020 attribs.push_back(EGL_NONE);
1022 mImpl->mNativeDrawContext = eglCreateContext(display, configs[configId], mImpl->mController.GetSharedContext(), attribs.data());
1025 eglMakeCurrent(display, drawSurface, readSurface, mImpl->mNativeDrawContext);
1028 void Context::RestoreFromNativeRendering()
1030 auto display = eglGetCurrentDisplay();
1032 // bring back original context
1033 eglMakeCurrent(display, mImpl->mCacheDrawWriteSurface, mImpl->mCacheDrawReadSurface, mImpl->mCacheEGLGraphicsContext);
1036 } // namespace Dali::Graphics::GLES