/*
- * 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.
#include "gles-context.h"
#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+#include <dali/integration-api/debug.h>
#include <dali/integration-api/gl-abstraction.h>
#include <dali/integration-api/gl-defines.h>
#include <dali/internal/graphics/common/graphics-interface.h>
+#include <dali/public-api/math/math-utils.h>
#include "egl-graphics-controller.h"
#include "gles-graphics-buffer.h"
#include "gles-graphics-program.h"
#include "gles-graphics-render-pass.h"
#include "gles-graphics-render-target.h"
+#include "gles-texture-dependency-checker.h"
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <map>
+#include <unordered_map>
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<Dali::GLsizei>(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);
+ }
}
/**
*/
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);
+ }
}
}
}
*/
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
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<const GLES::ProgramImpl*, std::map<std::size_t, uint32_t>> mProgramVAOMap; ///< GL program-VAO map
+ uint32_t mProgramVAOCurrentState{0u}; ///< Currently bound VAO
+ GLStateCache mGlStateCache{}; ///< GL status cache
+ std::vector<Dali::GLuint> 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<Impl>(controller);
+ mImpl = std::make_unique<Impl>(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
newProgram = static_cast<const GLES::Program*>(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
// 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<GLES::Texture*>(static_cast<const GLES::Texture*>(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->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<const GLES::Program*>(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<void*>(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<void*>(attr.offset));
+ }
+ else
+ {
+ gl->VertexAttribIPointer(attr.location,
+ GLVertexFormat(attr.format).size,
+ GLVertexFormat(attr.format).format,
+ bufferBinding.stride,
+ reinterpret_cast<void*>(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)
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:
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<void*>(binding.offset));
+ if(drawCall.drawIndexed.instanceCount == 0)
+ {
+ gl->DrawElements(GLESTopology(ia->topology),
+ drawCall.drawIndexed.indexCount,
+ indexBufferFormat,
+ reinterpret_cast<void*>(binding.offset));
+ }
+ else
+ {
+ gl->DrawElementsInstanced(GLESTopology(ia->topology),
+ drawCall.drawIndexed.indexCount,
+ indexBufferFormat,
+ reinterpret_cast<void*>(binding.offset),
+ drawCall.drawIndexed.instanceCount);
+ }
break;
}
case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
}
}
-void Context::BindTextures(const std::vector<Graphics::TextureBinding>& 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)
{
}
}
-void Context::BindVertexBuffers(const std::vector<GLES::VertexBufferBindingDescriptor>& 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)
mImpl->mNewPipeline = &newPipeline->GetPipeline();
}
-void Context::BindUniformBuffers(const std::vector<UniformBufferBindingDescriptor>& 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;
}
}
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);
}
}
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));
}
}
}
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));
}
}
}
return;
}
- auto& gl = *mImpl->mController.GetGL();
+ auto* gl = mImpl->GetGL();
+ if(!gl) // Early out if no gl
+ {
+ return;
+ }
if(!currentRasterizationState ||
currentRasterizationState->cullMode != newRasterizationState->cullMode)
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));
}
}
}
{
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<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
-
- const auto& reflection = program->GetReflection();
+ const GLES::Program* program{nullptr};
- auto extraInfos = reflection.GetStandaloneUniformExtraInfo();
-
- const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset;
+ if(mImpl->mNewPipeline)
+ {
+ program = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
+ }
+ else if(mImpl->mCurrentPipeline)
+ {
+ program = static_cast<const GLES::Program*>(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<const float*>(&ptr[offset]));
- break;
- }
- case GLType::FLOAT_VEC3:
- {
- gl.Uniform3fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
- break;
- }
- case GLType::FLOAT_VEC4:
- {
- gl.Uniform4fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
- break;
- }
- case GLType::INT_VEC2:
- {
- gl.Uniform2iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
- break;
- }
- case GLType::INT_VEC3:
- {
- gl.Uniform3iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
- break;
- }
- case GLType::INT_VEC4:
- {
- gl.Uniform4iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&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<const float*>(&ptr[offset]));
- break;
- }
- case GLType::FLOAT_MAT2:
- {
- gl.UniformMatrix2fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
- break;
- }
- case GLType::FLOAT_MAT3:
- {
- gl.UniformMatrix3fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
- break;
- }
- case GLType::FLOAT_MAT4:
- {
- gl.UniformMatrix4fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
- break;
- }
- case GLType::SAMPLER_2D:
- {
- break;
- }
- case GLType::SAMPLER_CUBE:
- {
- break;
- }
- default:
- {
- }
- }
+ const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset;
+ // Update program uniforms
+ program->GetImplementation()->UpdateStandaloneUniformBlock(ptr);
}
}
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)
{
else if(targetInfo.framebuffer)
{
// bind framebuffer and swap.
- renderTarget.GetFramebuffer()->Bind();
+ auto framebuffer = renderTarget.GetFramebuffer();
+ framebuffer->Bind();
}
// clear (ideally cache the setup)
const auto& attachments = *renderPass.GetCreateInfo().attachments;
const auto& color0 = attachments[0];
GLuint mask = 0;
+
if(color0.loadOp == AttachmentLoadOp::CLEAR)
{
mask |= GL_COLOR_BUFFER_BIT;
// 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);
}
}
if(!mImpl->mGlStateCache.mDepthMaskEnabled)
{
mImpl->mGlStateCache.mDepthMaskEnabled = true;
- gl.DepthMask(true);
+ gl->DepthMask(true);
}
mask |= GL_DEPTH_BUFFER_BIT;
}
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);
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);
}
}
}
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);
}
}
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);
}
}
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);
}
}
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<uint32_t>(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()
{
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<const GLES::Program*>(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<EGLint> 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