X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fgraphics%2Fgles-impl%2Fgles-context.cpp;h=b7e2b5edbc5b21a907433bc87338958257c4c6d1;hb=3c26763ff93197deeaba6129aa44cb66505012c3;hp=077d2c6d483869002d2615b0285c3522bd4c0fb6;hpb=19fd2891ef4b2ecf6504f727ca24d93f8a83fc69;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git diff --git a/dali/internal/graphics/gles-impl/gles-context.cpp b/dali/internal/graphics/gles-impl/gles-context.cpp index 077d2c6..b7e2b5e 100644 --- a/dali/internal/graphics/gles-impl/gles-context.cpp +++ b/dali/internal/graphics/gles-impl/gles-context.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,11 @@ #include "gles-context.h" #include +#include #include #include #include +#include #include "egl-graphics-controller.h" #include "gles-graphics-buffer.h" @@ -27,59 +29,142 @@ #include "gles-graphics-program.h" #include "gles-graphics-render-pass.h" #include "gles-graphics-render-target.h" +#include "gles-texture-dependency-checker.h" + +#include +#include +#include +#include namespace Dali::Graphics::GLES { struct Context::Impl { - Impl(EglGraphicsController& controller) - : mController(controller) + explicit Impl(EglGraphicsController& controller, Integration::GlAbstraction* gl) + : mController(controller), + mGL(gl) { } ~Impl() = default; /** + * Binds (and creates) VAO + * + * VAO is fixed per program so it has to be created only once assuming + * that VertexInputState has been set correctly for the pipeline. + * + */ + void BindProgramVAO(const GLES::ProgramImpl* program, const VertexInputState& vertexInputState) + { + // Calculate attributes location hash unordered. + std::size_t hash = 0; + for(const auto& attr : vertexInputState.attributes) + { + // Make unordered hash value by location. + // Note : This hash function varified for locations only under < 20. + std::size_t salt = attr.location + 1; + hash += salt << (sizeof(std::size_t) * 6); + salt *= salt; + salt ^= attr.location; + hash += salt << (sizeof(std::size_t) * 4); + salt *= salt; + hash += salt; + } + + auto* gl = GetGL(); + if(!gl) // early out if no gl + { + return; + } + + if(DALI_UNLIKELY(!mDiscardedVAOList.empty())) + { + gl->DeleteVertexArrays(static_cast(mDiscardedVAOList.size()), mDiscardedVAOList.data()); + mDiscardedVAOList.clear(); + } + + auto iter = mProgramVAOMap.find(program); + if(iter != mProgramVAOMap.end()) + { + auto attributeIter = iter->second.find(hash); + if(attributeIter != iter->second.end()) + { + if(mProgramVAOCurrentState != attributeIter->second) + { + mProgramVAOCurrentState = attributeIter->second; + gl->BindVertexArray(attributeIter->second); + + // Binding VAO seems to reset the index buffer binding so the cache must be reset + mGlStateCache.mBoundElementArrayBufferId = 0; + } + return; + } + } + + uint32_t vao; + gl->GenVertexArrays(1, &vao); + gl->BindVertexArray(vao); + + // Binding VAO seems to reset the index buffer binding so the cache must be reset + mGlStateCache.mBoundElementArrayBufferId = 0; + + mProgramVAOMap[program][hash] = vao; + for(const auto& attr : vertexInputState.attributes) + { + gl->EnableVertexAttribArray(attr.location); + } + + mProgramVAOCurrentState = vao; + } + + /** * Sets the initial GL state. */ void InitializeGlState() { - auto& gl = *mController.GetGL(); + auto* gl = GetGL(); + if(gl) + { + mGlStateCache.mClearColorSet = false; + mGlStateCache.mColorMask = true; + mGlStateCache.mStencilMask = 0xFF; + mGlStateCache.mBlendEnabled = false; + mGlStateCache.mDepthBufferEnabled = false; + mGlStateCache.mDepthMaskEnabled = false; + mGlStateCache.mScissorTestEnabled = false; + mGlStateCache.mStencilBufferEnabled = false; - mGlStateCache.mClearColorSet = false; - mGlStateCache.mColorMask = true; - mGlStateCache.mStencilMask = 0xFF; - mGlStateCache.mBlendEnabled = false; - mGlStateCache.mDepthBufferEnabled = false; - mGlStateCache.mDepthMaskEnabled = false; - mGlStateCache.mScissorTestEnabled = false; - mGlStateCache.mStencilBufferEnabled = false; + gl->Disable(GL_DITHER); - gl.Disable(GL_DITHER); + mGlStateCache.mBoundArrayBufferId = 0; + mGlStateCache.mBoundElementArrayBufferId = 0; + mGlStateCache.mActiveTextureUnit = 0; - mGlStateCache.mBoundArrayBufferId = 0; - mGlStateCache.mBoundElementArrayBufferId = 0; - mGlStateCache.mActiveTextureUnit = 0; + mGlStateCache.mBlendFuncSeparateSrcRGB = BlendFactor::ONE; + mGlStateCache.mBlendFuncSeparateDstRGB = BlendFactor::ZERO; + mGlStateCache.mBlendFuncSeparateSrcAlpha = BlendFactor::ONE; + mGlStateCache.mBlendFuncSeparateDstAlpha = BlendFactor::ZERO; - mGlStateCache.mBlendFuncSeparateSrcRGB = BlendFactor::ONE; - mGlStateCache.mBlendFuncSeparateDstRGB = BlendFactor::ZERO; - mGlStateCache.mBlendFuncSeparateSrcAlpha = BlendFactor::ONE; - mGlStateCache.mBlendFuncSeparateDstAlpha = BlendFactor::ZERO; + // initial state is GL_FUNC_ADD for both RGB and Alpha blend modes + mGlStateCache.mBlendEquationSeparateModeRGB = BlendOp::ADD; + mGlStateCache.mBlendEquationSeparateModeAlpha = BlendOp::ADD; - // initial state is GL_FUNC_ADD for both RGB and Alpha blend modes - mGlStateCache.mBlendEquationSeparateModeRGB = BlendOp::ADD; - mGlStateCache.mBlendEquationSeparateModeAlpha = BlendOp::ADD; + mGlStateCache.mCullFaceMode = CullMode::NONE; // By default cullface is disabled, front face is set to CCW and cull face is set to back - mGlStateCache.mCullFaceMode = CullMode::NONE; //By default cullface is disabled, front face is set to CCW and cull face is set to back + // Initialze vertex attribute cache + memset(&mGlStateCache.mVertexAttributeCachedState, 0, sizeof(mGlStateCache.mVertexAttributeCachedState)); + memset(&mGlStateCache.mVertexAttributeCurrentState, 0, sizeof(mGlStateCache.mVertexAttributeCurrentState)); - //Initialze vertex attribute cache - memset(&mGlStateCache.mVertexAttributeCachedState, 0, sizeof(mGlStateCache.mVertexAttributeCachedState)); - memset(&mGlStateCache.mVertexAttributeCurrentState, 0, sizeof(mGlStateCache.mVertexAttributeCurrentState)); + // Initialize bound 2d texture cache + memset(&mGlStateCache.mBoundTextureId, 0, sizeof(mGlStateCache.mBoundTextureId)); - //Initialize bound 2d texture cache - memset(&mGlStateCache.mBoundTextureId, 0, sizeof(mGlStateCache.mBoundTextureId)); + mGlStateCache.mFrameBufferStateCache.Reset(); - mGlStateCache.mFrameBufferStateCache.Reset(); + GLint maxTextures; + gl->GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextures); + DALI_LOG_RELEASE_INFO("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d\n", maxTextures); + } } /** @@ -87,23 +172,25 @@ struct Context::Impl */ void FlushVertexAttributeLocations() { - auto& gl = *mController.GetGL(); - - for(unsigned int i = 0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i) + auto* gl = GetGL(); + if(gl) { - // see if the cached state is different to the actual state - if(mGlStateCache.mVertexAttributeCurrentState[i] != mGlStateCache.mVertexAttributeCachedState[i]) + for(unsigned int i = 0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i) { - // it's different so make the change to the driver and update the cached state - mGlStateCache.mVertexAttributeCurrentState[i] = mGlStateCache.mVertexAttributeCachedState[i]; - - if(mGlStateCache.mVertexAttributeCurrentState[i]) - { - gl.EnableVertexAttribArray(i); - } - else + // see if the cached state is different to the actual state + if(mGlStateCache.mVertexAttributeCurrentState[i] != mGlStateCache.mVertexAttributeCachedState[i]) { - gl.DisableVertexAttribArray(i); + // it's different so make the change to the driver and update the cached state + mGlStateCache.mVertexAttributeCurrentState[i] = mGlStateCache.mVertexAttributeCachedState[i]; + + if(mGlStateCache.mVertexAttributeCurrentState[i]) + { + gl->EnableVertexAttribArray(i); + } + else + { + gl->DisableVertexAttribArray(i); + } } } } @@ -117,29 +204,41 @@ struct Context::Impl */ void SetVertexAttributeLocation(unsigned int location, bool state) { - auto& gl = *mController.GetGL(); - - if(location >= MAX_ATTRIBUTE_CACHE_SIZE) + auto* gl = GetGL(); + if(gl) { - // not cached, make the gl call through context - if(state) + if(location >= MAX_ATTRIBUTE_CACHE_SIZE) { - gl.EnableVertexAttribArray(location); + // not cached, make the gl call through context + if(state) + { + gl->EnableVertexAttribArray(location); + } + else + { + gl->DisableVertexAttribArray(location); + } } else { - gl.DisableVertexAttribArray(location); + // set the cached state, it will be set at the next draw call + // if it's different from the current driver state + mGlStateCache.mVertexAttributeCachedState[location] = state; } } - else - { - // set the cached state, it will be set at the next draw call - // if it's different from the current driver state - mGlStateCache.mVertexAttributeCachedState[location] = state; - } } - EglGraphicsController& mController; + /** + * Get the pointer to the GL implementation + * @return The GL implementation, nullptr if the context has not been created or shutting down + */ + [[nodiscard]] inline Integration::GlAbstraction* GetGL() const + { + return mGlContextCreated ? mGL : nullptr; + } + + EglGraphicsController& mController; + Integration::GlAbstraction* mGL{nullptr}; const GLES::PipelineImpl* mCurrentPipeline{nullptr}; ///< Currently bound pipeline const GLES::PipelineImpl* mNewPipeline{nullptr}; ///< New pipeline to be set on flush @@ -165,21 +264,46 @@ struct Context::Impl const GLES::RenderTarget* mCurrentRenderTarget{nullptr}; const GLES::RenderPass* mCurrentRenderPass{nullptr}; - GLStateCache mGlStateCache{}; ///< GL status cache + // Each context must have own VAOs as they cannot be shared + std::unordered_map> mProgramVAOMap; ///< GL program-VAO map + uint32_t mProgramVAOCurrentState{0u}; ///< Currently bound VAO + GLStateCache mGlStateCache{}; ///< GL status cache + std::vector mDiscardedVAOList{}; + + bool mGlContextCreated{false}; ///< True if the OpenGL context has been created + bool mVertexBuffersChanged{true}; ///< True if BindVertexBuffers changed any buffer bindings + + EGLContext mNativeDrawContext{0u}; ///< Native rendering EGL context compatible with window context - bool mGlContextCreated{false}; ///< True if the OpenGL context has been created + EGLSurface mCacheDrawReadSurface{0u}; ///< cached 'read' surface + EGLSurface mCacheDrawWriteSurface{0u}; ///< cached 'write' surface + EGLContext mCacheEGLGraphicsContext{0u}; ///< cached window context }; -Context::Context(EglGraphicsController& controller) +Context::Context(EglGraphicsController& controller, Integration::GlAbstraction* glAbstraction) { - mImpl = std::make_unique(controller); + mImpl = std::make_unique(controller, glAbstraction); } -Context::~Context() = default; +Context::~Context() +{ + // Destroy native rendering context if one exists + if(mImpl->mNativeDrawContext) + { + eglDestroyContext(eglGetCurrentDisplay(), mImpl->mNativeDrawContext); + mImpl->mNativeDrawContext = EGL_NO_CONTEXT; + } +} -void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall) +void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES::TextureDependencyChecker& dependencyChecker) { - auto& gl = *mImpl->mController.GetGL(); + auto* gl = mImpl->GetGL(); + if(!gl) // Early out if no gl + { + return; + } + + static const bool hasGLES3(mImpl->mController.GetGLESVersion() >= GLESVersion::GLES_30); // early out if neither current nor new pipelines are set // this behaviour may be valid so no assert @@ -199,11 +323,23 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall) newProgram = static_cast(mImpl->mNewPipeline->GetCreateInfo().programState->program); } + if(!currentProgram && !newProgram) + { + // Early out if we have no program for this pipeline. + DALI_LOG_ERROR("No program defined for pipeline\n"); + return; + } + + // If this draw uses a different pipeline _AND_ the pipeline has a different GL Program, + // Then bind the new program. Ensure vertex atrributes are set. + + bool programChanged = false; if(mImpl->mNewPipeline && mImpl->mCurrentPipeline != mImpl->mNewPipeline) { if(!currentProgram || currentProgram->GetImplementation()->GetGlProgram() != newProgram->GetImplementation()->GetGlProgram()) { mImpl->mNewPipeline->Bind(newProgram->GetImplementation()->GetGlProgram()); + programChanged = true; } // Blend state @@ -220,59 +356,117 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall) // Map binding# to sampler location const auto& reflection = !newProgram ? currentProgram->GetReflection() : newProgram->GetReflection(); const auto& samplers = reflection.GetSamplers(); + + uint32_t currentSampler = 0; + uint32_t currentElement = 0; + + // @warning Assume that binding.binding is strictly linear in the same order as mCurrentTextureBindings + // elements. This avoids having to sort the bindings. for(const auto& binding : mImpl->mCurrentTextureBindings) { + if(currentSampler >= samplers.size()) + { + // Don't bind more textures than there are active samplers. + break; + } + auto texture = const_cast(static_cast(binding.texture)); // Texture may not have been initialized yet...(tbm_surface timing issue?) if(!texture->GetGLTexture()) { - // Attempt to reinitialize - // @todo need to put this somewhere else where it isn't const. - // Maybe post it back on end of initialize queue if initialization fails? texture->InitializeResource(); } + // Warning, this may cause glWaitSync to occur on the GPU. + dependencyChecker.CheckNeedsSync(this, texture); texture->Bind(binding); + texture->Prepare(); - texture->Prepare(); // @todo also non-const. - - if(binding.binding < samplers.size()) // binding maps to texture unit. (texture bindings should also be in binding order) + if(programChanged) { - // Offset is set to the lexical offset within the frag shader, map it to the texture unit - // @todo Explicitly set the texture unit through the graphics interface - gl.Uniform1i(samplers[binding.binding].location, samplers[binding.binding].offset); + // @warning Assume that location of array elements is sequential. + // @warning GL does not guarantee this, but in practice, it is. + gl->Uniform1i(samplers[currentSampler].location + currentElement, + samplers[currentSampler].offset + currentElement); + ++currentElement; + if(currentElement >= samplers[currentSampler].elementCount) + { + ++currentSampler; + currentElement = 0; + } } } - // for each attribute bind vertices - const auto& pipelineState = mImpl->mNewPipeline ? mImpl->mNewPipeline->GetCreateInfo() : mImpl->mCurrentPipeline->GetCreateInfo(); - const auto& vi = pipelineState.vertexInputState; - for(const auto& attr : vi->attributes) + const auto& pipelineState = mImpl->mNewPipeline ? mImpl->mNewPipeline->GetCreateInfo() : mImpl->mCurrentPipeline->GetCreateInfo(); + const auto& vertexInputState = pipelineState.vertexInputState; + + // for each attribute bind vertices, unless the pipeline+buffer is the same + if(programChanged || mImpl->mVertexBuffersChanged) { - // Enable location - mImpl->SetVertexAttributeLocation(attr.location, true); + if(hasGLES3) + { + mImpl->BindProgramVAO(static_cast(pipelineState.programState->program)->GetImplementation(), *vertexInputState); + } + + for(const auto& attr : vertexInputState->attributes) + { + // Enable location + if(!hasGLES3) + { + mImpl->SetVertexAttributeLocation(attr.location, true); + } - const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding]; - const auto& bufferBinding = vi->bufferBindings[attr.binding]; + const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding]; + const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding]; - auto glesBuffer = bufferSlot.buffer->GetGLBuffer(); + auto glesBuffer = bufferSlot.buffer->GetGLBuffer(); - // Bind buffer - BindBuffer(GL_ARRAY_BUFFER, glesBuffer); + BindBuffer(GL_ARRAY_BUFFER, glesBuffer); // Cached - gl.VertexAttribPointer(attr.location, - GLVertexFormat(attr.format).size, - GLVertexFormat(attr.format).format, - GL_FALSE, - bufferBinding.stride, - reinterpret_cast(attr.offset)); + if(attr.format == VertexInputFormat::FLOAT || + attr.format == VertexInputFormat::FVECTOR2 || + attr.format == VertexInputFormat::FVECTOR3 || + attr.format == VertexInputFormat::FVECTOR4) + { + gl->VertexAttribPointer(attr.location, // Not cached... + GLVertexFormat(attr.format).size, + GLVertexFormat(attr.format).format, + GL_FALSE, + bufferBinding.stride, + reinterpret_cast(attr.offset)); + } + else + { + gl->VertexAttribIPointer(attr.location, + GLVertexFormat(attr.format).size, + GLVertexFormat(attr.format).format, + bufferBinding.stride, + reinterpret_cast(attr.offset)); + } + + if(hasGLES3) + { + switch(bufferBinding.inputRate) + { + case Graphics::VertexInputRate::PER_VERTEX: + { + gl->VertexAttribDivisor(attr.location, 0); + break; + } + case Graphics::VertexInputRate::PER_INSTANCE: + { + //@todo Get actual instance rate... + gl->VertexAttribDivisor(attr.location, 1); + break; + } + } + } + } } // Resolve topology - const auto& ia = mImpl->mNewPipeline->GetCreateInfo().inputAssemblyState; - - // Bind uniforms + const auto& ia = pipelineState.inputAssemblyState; // Resolve draw call switch(drawCall.type) @@ -282,11 +476,25 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall) mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask, mImpl->mGlStateCache.DepthBufferWriteEnabled(), mImpl->mGlStateCache.StencilBufferWriteEnabled()); - mImpl->FlushVertexAttributeLocations(); + // For GLES3+ we use VAO, for GLES2 internal cache + if(!hasGLES3) + { + mImpl->FlushVertexAttributeLocations(); + } - gl.DrawArrays(GLESTopology(ia->topology), - drawCall.draw.firstVertex, - drawCall.draw.vertexCount); + if(drawCall.draw.instanceCount == 0) + { + gl->DrawArrays(GLESTopology(ia->topology), + drawCall.draw.firstVertex, + drawCall.draw.vertexCount); + } + else + { + gl->DrawArraysInstanced(GLESTopology(ia->topology), + drawCall.draw.firstVertex, + drawCall.draw.vertexCount, + drawCall.draw.instanceCount); + } break; } case DrawCallDescriptor::Type::DRAW_INDEXED: @@ -297,13 +505,29 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall) mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask, mImpl->mGlStateCache.DepthBufferWriteEnabled(), mImpl->mGlStateCache.StencilBufferWriteEnabled()); - mImpl->FlushVertexAttributeLocations(); + + // For GLES3+ we use VAO, for GLES2 internal cache + if(!hasGLES3) + { + mImpl->FlushVertexAttributeLocations(); + } auto indexBufferFormat = GLIndexFormat(binding.format).format; - gl.DrawElements(GLESTopology(ia->topology), - drawCall.drawIndexed.indexCount, - indexBufferFormat, - reinterpret_cast(binding.offset)); + if(drawCall.drawIndexed.instanceCount == 0) + { + gl->DrawElements(GLESTopology(ia->topology), + drawCall.drawIndexed.indexCount, + indexBufferFormat, + reinterpret_cast(binding.offset)); + } + else + { + gl->DrawElementsInstanced(GLESTopology(ia->topology), + drawCall.drawIndexed.indexCount, + indexBufferFormat, + reinterpret_cast(binding.offset), + drawCall.drawIndexed.instanceCount); + } break; } case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT: @@ -322,11 +546,13 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall) } } -void Context::BindTextures(const std::vector& bindings) +void Context::BindTextures(const Graphics::TextureBinding* bindings, uint32_t count) { // for each texture allocate slot - for(const auto& binding : bindings) + for(auto i = 0u; i < count; ++i) { + auto& binding = bindings[i]; + // Resize binding array if needed if(mImpl->mCurrentTextureBindings.size() <= binding.binding) { @@ -337,16 +563,26 @@ void Context::BindTextures(const std::vector& bindings } } -void Context::BindVertexBuffers(const std::vector& bindings) +void Context::BindVertexBuffers(const GLES::VertexBufferBindingDescriptor* bindings, uint32_t count) { - if(bindings.size() > mImpl->mCurrentVertexBufferBindings.size()) + if(count > mImpl->mCurrentVertexBufferBindings.size()) { - mImpl->mCurrentVertexBufferBindings.resize(bindings.size()); + mImpl->mCurrentVertexBufferBindings.resize(count); } // Copy only set slots - std::copy_if(bindings.begin(), bindings.end(), mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) { - return (nullptr != item.buffer); - }); + mImpl->mVertexBuffersChanged = false; + auto toIter = mImpl->mCurrentVertexBufferBindings.begin(); + for(auto fromIter = bindings, end = bindings + count; fromIter != end; ++fromIter) + { + if(fromIter->buffer != nullptr) + { + if(toIter->buffer != fromIter->buffer || toIter->offset != fromIter->offset) + { + mImpl->mVertexBuffersChanged = true; + } + *toIter++ = *fromIter; + } + } } void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding) @@ -360,26 +596,28 @@ void Context::BindPipeline(const GLES::Pipeline* newPipeline) mImpl->mNewPipeline = &newPipeline->GetPipeline(); } -void Context::BindUniformBuffers(const std::vector& uboBindings, - const UniformBufferBindingDescriptor& standaloneBindings) +void Context::BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindings, + uint32_t uboCount, + const UniformBufferBindingDescriptor& standaloneBindings) { if(standaloneBindings.buffer) { mImpl->mCurrentStandaloneUBOBinding = standaloneBindings; } - if(uboBindings.size() >= mImpl->mCurrentUBOBindings.size()) + if(uboCount && uboCount > mImpl->mCurrentUBOBindings.size()) { - mImpl->mCurrentUBOBindings.resize(uboBindings.size() + 1); + mImpl->mCurrentUBOBindings.resize(uboCount); } - auto it = uboBindings.begin(); - for(auto i = 0u; i < uboBindings.size(); ++i) + auto it = uboBindings; + for(auto i = 0u; i < uboCount; ++i) { if(it->buffer) { mImpl->mCurrentUBOBindings[i] = *it; } + ++it; } } @@ -394,14 +632,18 @@ void Context::ResolveBlendState() return; } - auto& gl = *mImpl->mController.GetGL(); + auto* gl = mImpl->GetGL(); + if(!gl) // Early out if no gl + { + return; + } if(!currentBlendState || currentBlendState->blendEnable != newBlendState->blendEnable) { if(newBlendState->blendEnable != mImpl->mGlStateCache.mBlendEnabled) { mImpl->mGlStateCache.mBlendEnabled = newBlendState->blendEnable; - newBlendState->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND); + newBlendState->blendEnable ? gl->Enable(GL_BLEND) : gl->Disable(GL_BLEND); } } @@ -433,11 +675,11 @@ void Context::ResolveBlendState() if(newSrcRGB == newSrcAlpha && newDstRGB == newDstAlpha) { - gl.BlendFunc(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB)); + gl->BlendFunc(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB)); } else { - gl.BlendFuncSeparate(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB), GLBlendFunc(newSrcAlpha), GLBlendFunc(newDstAlpha)); + gl->BlendFuncSeparate(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB), GLBlendFunc(newSrcAlpha), GLBlendFunc(newDstAlpha)); } } } @@ -454,11 +696,15 @@ void Context::ResolveBlendState() if(newBlendState->colorBlendOp == newBlendState->alphaBlendOp) { - gl.BlendEquation(GLBlendOp(newBlendState->colorBlendOp)); + gl->BlendEquation(GLBlendOp(newBlendState->colorBlendOp)); + if(newBlendState->colorBlendOp >= Graphics::ADVANCED_BLEND_OPTIONS_START) + { + gl->BlendBarrier(); + } } else { - gl.BlendEquationSeparate(GLBlendOp(newBlendState->colorBlendOp), GLBlendOp(newBlendState->alphaBlendOp)); + gl->BlendEquationSeparate(GLBlendOp(newBlendState->colorBlendOp), GLBlendOp(newBlendState->alphaBlendOp)); } } } @@ -475,7 +721,11 @@ void Context::ResolveRasterizationState() return; } - auto& gl = *mImpl->mController.GetGL(); + auto* gl = mImpl->GetGL(); + if(!gl) // Early out if no gl + { + return; + } if(!currentRasterizationState || currentRasterizationState->cullMode != newRasterizationState->cullMode) @@ -485,12 +735,12 @@ void Context::ResolveRasterizationState() mImpl->mGlStateCache.mCullFaceMode = newRasterizationState->cullMode; if(newRasterizationState->cullMode == CullMode::NONE) { - gl.Disable(GL_CULL_FACE); + gl->Disable(GL_CULL_FACE); } else { - gl.Enable(GL_CULL_FACE); - gl.CullFace(GLCullMode(newRasterizationState->cullMode)); + gl->Enable(GL_CULL_FACE); + gl->CullFace(GLCullMode(newRasterizationState->cullMode)); } } } @@ -505,109 +755,43 @@ void Context::ResolveUniformBuffers() { ResolveStandaloneUniforms(); } + if(!mImpl->mCurrentUBOBindings.empty()) + { + ResolveGpuUniformBuffers(); + } } -void Context::ResolveStandaloneUniforms() +void Context::ResolveGpuUniformBuffers() { - auto& gl = *mImpl->mController.GetGL(); + if(auto* gl = mImpl->GetGL()) + { + auto i = 0u; + for(auto& binding : mImpl->mCurrentUBOBindings) + { + gl->BindBufferRange(GL_UNIFORM_BUFFER, i++, binding.buffer->GetGLBuffer(), GLintptr(binding.offset), GLintptr(binding.dataSize)); + } + } +} +void Context::ResolveStandaloneUniforms() +{ // Find reflection for program - const auto program = static_cast(mImpl->mNewPipeline->GetCreateInfo().programState->program); - - const auto& reflection = program->GetReflection(); + const GLES::Program* program{nullptr}; - auto extraInfos = reflection.GetStandaloneUniformExtraInfo(); - - const auto ptr = reinterpret_cast(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset; + if(mImpl->mNewPipeline) + { + program = static_cast(mImpl->mNewPipeline->GetCreateInfo().programState->program); + } + else if(mImpl->mCurrentPipeline) + { + program = static_cast(mImpl->mCurrentPipeline->GetCreateInfo().programState->program); + } - for(const auto& info : extraInfos) + if(program) { - auto type = GLTypeConversion(info.type).type; - auto offset = info.offset; - switch(type) - { - case GLType::FLOAT_VEC2: - { - gl.Uniform2fv(info.location, info.arraySize, reinterpret_cast(&ptr[offset])); - break; - } - case GLType::FLOAT_VEC3: - { - gl.Uniform3fv(info.location, info.arraySize, reinterpret_cast(&ptr[offset])); - break; - } - case GLType::FLOAT_VEC4: - { - gl.Uniform4fv(info.location, info.arraySize, reinterpret_cast(&ptr[offset])); - break; - } - case GLType::INT_VEC2: - { - gl.Uniform2iv(info.location, info.arraySize, reinterpret_cast(&ptr[offset])); - break; - } - case GLType::INT_VEC3: - { - gl.Uniform3iv(info.location, info.arraySize, reinterpret_cast(&ptr[offset])); - break; - } - case GLType::INT_VEC4: - { - gl.Uniform4iv(info.location, info.arraySize, reinterpret_cast(&ptr[offset])); - break; - } - case GLType::BOOL: - { - // not supported by DALi - break; - } - case GLType::BOOL_VEC2: - { - // not supported by DALi - break; - } - case GLType::BOOL_VEC3: - { - // not supported by DALi - break; - } - case GLType::BOOL_VEC4: - { - // not supported by DALi - break; - } - case GLType::FLOAT: - { - gl.Uniform1fv(info.location, info.arraySize, reinterpret_cast(&ptr[offset])); - break; - } - case GLType::FLOAT_MAT2: - { - gl.UniformMatrix2fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast(&ptr[offset])); - break; - } - case GLType::FLOAT_MAT3: - { - gl.UniformMatrix3fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast(&ptr[offset])); - break; - } - case GLType::FLOAT_MAT4: - { - gl.UniformMatrix4fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast(&ptr[offset])); - break; - } - case GLType::SAMPLER_2D: - { - break; - } - case GLType::SAMPLER_CUBE: - { - break; - } - default: - { - } - } + const auto ptr = reinterpret_cast(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset; + // Update program uniforms + program->GetImplementation()->UpdateStandaloneUniformBlock(ptr); } } @@ -618,7 +802,11 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) const auto& targetInfo = renderTarget.GetCreateInfo(); - auto& gl = *mImpl->mController.GetGL(); + auto* gl = mImpl->GetGL(); + if(!gl) // Early out if no gl + { + return; + } if(targetInfo.surface) { @@ -628,7 +816,8 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) else if(targetInfo.framebuffer) { // bind framebuffer and swap. - renderTarget.GetFramebuffer()->Bind(); + auto framebuffer = renderTarget.GetFramebuffer(); + framebuffer->Bind(); } // clear (ideally cache the setup) @@ -640,6 +829,7 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) const auto& attachments = *renderPass.GetCreateInfo().attachments; const auto& color0 = attachments[0]; GLuint mask = 0; + if(color0.loadOp == AttachmentLoadOp::CLEAR) { mask |= GL_COLOR_BUFFER_BIT; @@ -648,22 +838,24 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) // Something goes wrong here if Alpha mask is GL_TRUE ColorMask(true); - if(!mImpl->mGlStateCache.mClearColorSet || - mImpl->mGlStateCache.mClearColor.r != renderPassBegin.clearValues[0].color.r || - mImpl->mGlStateCache.mClearColor.g != renderPassBegin.clearValues[0].color.g || - mImpl->mGlStateCache.mClearColor.b != renderPassBegin.clearValues[0].color.b || - mImpl->mGlStateCache.mClearColor.a != renderPassBegin.clearValues[0].color.a) + const auto clearValues = renderPassBegin.clearValues.Ptr(); + + if(!Dali::Equals(mImpl->mGlStateCache.mClearColor.r, clearValues[0].color.r) || + !Dali::Equals(mImpl->mGlStateCache.mClearColor.g, clearValues[0].color.g) || + !Dali::Equals(mImpl->mGlStateCache.mClearColor.b, clearValues[0].color.b) || + !Dali::Equals(mImpl->mGlStateCache.mClearColor.a, clearValues[0].color.a) || + !mImpl->mGlStateCache.mClearColorSet) { - gl.ClearColor(renderPassBegin.clearValues[0].color.r, - renderPassBegin.clearValues[0].color.g, - renderPassBegin.clearValues[0].color.b, - renderPassBegin.clearValues[0].color.a); + gl->ClearColor(clearValues[0].color.r, + clearValues[0].color.g, + clearValues[0].color.b, + clearValues[0].color.a); mImpl->mGlStateCache.mClearColorSet = true; - mImpl->mGlStateCache.mClearColor = Vector4(renderPassBegin.clearValues[0].color.r, - renderPassBegin.clearValues[0].color.g, - renderPassBegin.clearValues[0].color.b, - renderPassBegin.clearValues[0].color.a); + mImpl->mGlStateCache.mClearColor = Vector4(clearValues[0].color.r, + clearValues[0].color.g, + clearValues[0].color.b, + clearValues[0].color.a); } } @@ -676,7 +868,7 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) if(!mImpl->mGlStateCache.mDepthMaskEnabled) { mImpl->mGlStateCache.mDepthMaskEnabled = true; - gl.DepthMask(true); + gl->DepthMask(true); } mask |= GL_DEPTH_BUFFER_BIT; } @@ -685,14 +877,14 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) if(mImpl->mGlStateCache.mStencilMask != 0xFF) { mImpl->mGlStateCache.mStencilMask = 0xFF; - gl.StencilMask(0xFF); + gl->StencilMask(0xFF); } mask |= GL_STENCIL_BUFFER_BIT; } } SetScissorTestEnabled(true); - gl.Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height); + gl->Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height); ClearBuffer(mask, true); SetScissorTestEnabled(false); @@ -700,14 +892,28 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) mImpl->mCurrentRenderTarget = &renderTarget; } -void Context::EndRenderPass() +void Context::EndRenderPass(GLES::TextureDependencyChecker& dependencyChecker) { if(mImpl->mCurrentRenderTarget) { - if(mImpl->mCurrentRenderTarget->GetFramebuffer()) + GLES::Framebuffer* framebuffer = mImpl->mCurrentRenderTarget->GetFramebuffer(); + auto* gl = mImpl->GetGL(); + if(framebuffer && gl) { - auto& gl = *mImpl->mController.GetGL(); - gl.Flush(); + gl->Flush(); + + /* @todo Full dependency checking would need to store textures in Begin, and create + * fence objects here; but we're going to draw all fbos on shared context in serial, + * so no real need (yet). Might want to consider ensuring order of render passes, + * but that needs doing in the controller, and would need doing before ProcessCommandQueues. + * + * Currently up to the client to create render tasks in the right order. + */ + + /* Create fence sync objects. Other contexts can then wait on these fences before reading + * textures. + */ + dependencyChecker.AddTextures(this, framebuffer); } } } @@ -715,16 +921,16 @@ void Context::EndRenderPass() void Context::ClearState() { mImpl->mCurrentTextureBindings.clear(); + mImpl->mCurrentUBOBindings.clear(); } void Context::ColorMask(bool enabled) { - if(enabled != mImpl->mGlStateCache.mColorMask) + auto* gl = mImpl->GetGL(); + if(gl && enabled != mImpl->mGlStateCache.mColorMask) { mImpl->mGlStateCache.mColorMask = enabled; - - auto& gl = *mImpl->mController.GetGL(); - gl.ColorMask(enabled, enabled, enabled, enabled); + gl->ColorMask(enabled, enabled, enabled, enabled); } } @@ -740,58 +946,67 @@ void Context::ClearDepthBuffer() void Context::ClearBuffer(uint32_t mask, bool forceClear) { - mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled); - if(mask > 0) + mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled); + auto* gl = mImpl->GetGL(); + if(mask > 0 && gl) + { + gl->Clear(mask); + } +} + +void Context::InvalidateDepthStencilBuffers() +{ + if(auto* gl = mImpl->GetGL()) { - auto& gl = *mImpl->mController.GetGL(); - gl.Clear(mask); + GLenum attachments[] = {GL_DEPTH, GL_STENCIL}; + gl->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); } } void Context::SetScissorTestEnabled(bool scissorEnabled) { - if(mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled) + auto* gl = mImpl->GetGL(); + if(gl && mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled) { mImpl->mGlStateCache.mScissorTestEnabled = scissorEnabled; - auto& gl = *mImpl->mController.GetGL(); if(scissorEnabled) { - gl.Enable(GL_SCISSOR_TEST); + gl->Enable(GL_SCISSOR_TEST); } else { - gl.Disable(GL_SCISSOR_TEST); + gl->Disable(GL_SCISSOR_TEST); } } } void Context::SetStencilTestEnable(bool stencilEnable) { - if(stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled) + auto* gl = mImpl->GetGL(); + if(gl && stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled) { mImpl->mGlStateCache.mStencilBufferEnabled = stencilEnable; - auto& gl = *mImpl->mController.GetGL(); if(stencilEnable) { - gl.Enable(GL_STENCIL_TEST); + gl->Enable(GL_STENCIL_TEST); } else { - gl.Disable(GL_STENCIL_TEST); + gl->Disable(GL_STENCIL_TEST); } } } void Context::StencilMask(uint32_t writeMask) { - if(writeMask != mImpl->mGlStateCache.mStencilMask) + auto* gl = mImpl->GetGL(); + if(gl && writeMask != mImpl->mGlStateCache.mStencilMask) { mImpl->mGlStateCache.mStencilMask = writeMask; - auto& gl = *mImpl->mController.GetGL(); - gl.StencilMask(writeMask); + gl->StencilMask(writeMask); } } @@ -799,16 +1014,17 @@ void Context::StencilFunc(Graphics::CompareOp compareOp, uint32_t reference, uint32_t compareMask) { - if(compareOp != mImpl->mGlStateCache.mStencilFunc || - reference != mImpl->mGlStateCache.mStencilFuncRef || - compareMask != mImpl->mGlStateCache.mStencilFuncMask) + auto* gl = mImpl->GetGL(); + if(gl && + (compareOp != mImpl->mGlStateCache.mStencilFunc || + reference != mImpl->mGlStateCache.mStencilFuncRef || + compareMask != mImpl->mGlStateCache.mStencilFuncMask)) { mImpl->mGlStateCache.mStencilFunc = compareOp; mImpl->mGlStateCache.mStencilFuncRef = reference; mImpl->mGlStateCache.mStencilFuncMask = compareMask; - auto& gl = *mImpl->mController.GetGL(); - gl.StencilFunc(GLCompareOp(compareOp).op, reference, compareMask); + gl->StencilFunc(GLCompareOp(compareOp).op, reference, compareMask); } } @@ -816,130 +1032,163 @@ void Context::StencilOp(Graphics::StencilOp failOp, Graphics::StencilOp depthFailOp, Graphics::StencilOp passOp) { - if(failOp != mImpl->mGlStateCache.mStencilOpFail || - depthFailOp != mImpl->mGlStateCache.mStencilOpDepthFail || - passOp != mImpl->mGlStateCache.mStencilOpDepthPass) + auto* gl = mImpl->GetGL(); + if(gl && + (failOp != mImpl->mGlStateCache.mStencilOpFail || + depthFailOp != mImpl->mGlStateCache.mStencilOpDepthFail || + passOp != mImpl->mGlStateCache.mStencilOpDepthPass)) { mImpl->mGlStateCache.mStencilOpFail = failOp; mImpl->mGlStateCache.mStencilOpDepthFail = depthFailOp; mImpl->mGlStateCache.mStencilOpDepthPass = passOp; - auto& gl = *mImpl->mController.GetGL(); - gl.StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op); + gl->StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op); } } void Context::SetDepthCompareOp(Graphics::CompareOp compareOp) { - if(compareOp != mImpl->mGlStateCache.mDepthFunction) + auto* gl = mImpl->GetGL(); + if(gl && compareOp != mImpl->mGlStateCache.mDepthFunction) { mImpl->mGlStateCache.mDepthFunction = compareOp; - auto& gl = *mImpl->mController.GetGL(); - gl.DepthFunc(GLCompareOp(compareOp).op); + + gl->DepthFunc(GLCompareOp(compareOp).op); } } void Context::SetDepthTestEnable(bool depthTestEnable) { - if(depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled) + auto* gl = mImpl->GetGL(); + if(gl && depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled) { mImpl->mGlStateCache.mDepthBufferEnabled = depthTestEnable; - auto& gl = *mImpl->mController.GetGL(); if(depthTestEnable) { - gl.Enable(GL_DEPTH_TEST); + gl->Enable(GL_DEPTH_TEST); } else { - gl.Disable(GL_DEPTH_TEST); + gl->Disable(GL_DEPTH_TEST); } } } void Context::SetDepthWriteEnable(bool depthWriteEnable) { - if(depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled) + auto* gl = mImpl->GetGL(); + if(gl && depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled) { mImpl->mGlStateCache.mDepthMaskEnabled = depthWriteEnable; - auto& gl = *mImpl->mController.GetGL(); - gl.DepthMask(depthWriteEnable); + gl->DepthMask(depthWriteEnable); } } void Context::ActiveTexture(uint32_t textureBindingIndex) { - if(mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex) + auto* gl = mImpl->GetGL(); + if(gl && mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex) { mImpl->mGlStateCache.mActiveTextureUnit = textureBindingIndex; - auto& gl = *mImpl->mController.GetGL(); - gl.ActiveTexture(GL_TEXTURE0 + textureBindingIndex); + gl->ActiveTexture(GL_TEXTURE0 + textureBindingIndex); } } void Context::BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId) { uint32_t typeId = static_cast(textureTypeId); - if(mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] != textureId) + auto* gl = mImpl->GetGL(); + if(gl && mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] != textureId) { mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] = textureId; - auto& gl = *mImpl->mController.GetGL(); - gl.BindTexture(target, textureId); + gl->BindTexture(target, textureId); } } void Context::GenerateMipmap(GLenum target) { - auto& gl = *mImpl->mController.GetGL(); - gl.GenerateMipmap(target); + if(auto* gl = mImpl->GetGL()) + { + gl->GenerateMipmap(target); + } } -void Context::BindBuffer(GLenum target, uint32_t bufferId) +bool Context::BindBuffer(GLenum target, uint32_t bufferId) { - if(mImpl->mGlStateCache.mBoundArrayBufferId != bufferId) + if(auto* gl = mImpl->GetGL()) { - mImpl->mGlStateCache.mBoundArrayBufferId = bufferId; + switch(target) + { + case GL_ARRAY_BUFFER: + { + if(mImpl->mGlStateCache.mBoundArrayBufferId == bufferId) + { + return false; + } + mImpl->mGlStateCache.mBoundArrayBufferId = bufferId; + break; + } + case GL_ELEMENT_ARRAY_BUFFER: + { + if(mImpl->mGlStateCache.mBoundElementArrayBufferId == bufferId) + { + return false; + } + mImpl->mGlStateCache.mBoundElementArrayBufferId = bufferId; + break; + } + } - auto& gl = *mImpl->mController.GetGL(); - gl.BindBuffer(target, bufferId); + // Cache miss. Bind buffer. + gl->BindBuffer(target, bufferId); + return true; } + return false; } void Context::DrawBuffers(uint32_t count, const GLenum* buffers) { - mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask, - mImpl->mGlStateCache.DepthBufferWriteEnabled(), - mImpl->mGlStateCache.StencilBufferWriteEnabled()); + if(auto* gl = mImpl->GetGL()) + { + mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask, + mImpl->mGlStateCache.DepthBufferWriteEnabled(), + mImpl->mGlStateCache.StencilBufferWriteEnabled()); - auto& gl = *mImpl->mController.GetGL(); - gl.DrawBuffers(count, buffers); + gl->DrawBuffers(count, buffers); + } } void Context::BindFrameBuffer(GLenum target, uint32_t bufferId) { - mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId); + if(auto* gl = mImpl->GetGL()) + { + mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId); - auto& gl = *mImpl->mController.GetGL(); - gl.BindFramebuffer(target, bufferId); + gl->BindFramebuffer(target, bufferId); + } } void Context::GenFramebuffers(uint32_t count, uint32_t* framebuffers) { - auto& gl = *mImpl->mController.GetGL(); - gl.GenFramebuffers(count, framebuffers); - - mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersCreated(count, framebuffers); + if(auto* gl = mImpl->GetGL()) + { + gl->GenFramebuffers(count, framebuffers); + mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersCreated(count, framebuffers); + } } void Context::DeleteFramebuffers(uint32_t count, uint32_t* framebuffers) { - mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers); + if(auto* gl = mImpl->GetGL()) + { + mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers); - auto& gl = *mImpl->mController.GetGL(); - gl.DeleteFramebuffers(count, framebuffers); + gl->DeleteFramebuffers(count, framebuffers); + } } GLStateCache& Context::GetGLStateCache() @@ -970,6 +1219,103 @@ void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline) { mImpl->mCurrentPipeline = nullptr; } + + // Remove cached VAO map + auto* gl = mImpl->GetGL(); + if(gl) + { + const auto* program = pipeline->GetCreateInfo().programState->program; + if(program) + { + const auto* programImpl = static_cast(program)->GetImplementation(); + if(programImpl) + { + auto iter = mImpl->mProgramVAOMap.find(programImpl); + if(iter != mImpl->mProgramVAOMap.end()) + { + for(auto& attributeHashPair : iter->second) + { + auto vao = attributeHashPair.second; + + // Do not delete vao now. (Since Context might not be current.) + mImpl->mDiscardedVAOList.emplace_back(vao); + if(mImpl->mProgramVAOCurrentState == vao) + { + mImpl->mProgramVAOCurrentState = 0u; + } + } + + // Clear cached Vertex buffer. + mImpl->mCurrentVertexBufferBindings.clear(); + + mImpl->mProgramVAOMap.erase(iter); + } + } + } + } +} + +void Context::PrepareForNativeRendering() +{ + // this should be pretty much constant + auto display = eglGetCurrentDisplay(); + auto drawSurface = eglGetCurrentSurface(EGL_DRAW); + auto readSurface = eglGetCurrentSurface(EGL_READ); + auto context = eglGetCurrentContext(); + + // push the surface and context data to the impl + // It's needed to restore context + if(!mImpl->mCacheEGLGraphicsContext) + { + mImpl->mCacheDrawWriteSurface = drawSurface; + mImpl->mCacheDrawReadSurface = readSurface; + mImpl->mCacheEGLGraphicsContext = context; + } + + if(!mImpl->mNativeDrawContext) + { + EGLint configId{0u}; + eglQueryContext(display, mImpl->mController.GetSharedContext(), EGL_CONFIG_ID, &configId); + + EGLint configAttribs[3]; + configAttribs[0] = EGL_CONFIG_ID; + configAttribs[1] = configId; + configAttribs[2] = EGL_NONE; + + EGLConfig config; + EGLint numConfigs; + if(eglChooseConfig(display, configAttribs, &config, 1, &numConfigs) != EGL_TRUE) + { + DALI_LOG_ERROR("eglChooseConfig failed!\n"); + return; + } + + auto version = int(mImpl->mController.GetGLESVersion()); + + std::vector attribs; + attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); + attribs.push_back(version / 10); + attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR); + attribs.push_back(version % 10); + attribs.push_back(EGL_NONE); + + mImpl->mNativeDrawContext = eglCreateContext(display, config, mImpl->mController.GetSharedContext(), attribs.data()); + if(mImpl->mNativeDrawContext == EGL_NO_CONTEXT) + { + DALI_LOG_ERROR("eglCreateContext failed!\n"); + return; + } + } + + eglMakeCurrent(display, drawSurface, readSurface, mImpl->mNativeDrawContext); +} + +void Context::RestoreFromNativeRendering() +{ + auto display = eglGetCurrentDisplay(); + + // bring back original context + eglMakeCurrent(display, mImpl->mCacheDrawWriteSurface, mImpl->mCacheDrawReadSurface, mImpl->mCacheEGLGraphicsContext); } } // namespace Dali::Graphics::GLES