#include "gles-graphics-render-pass.h"
#include "gles-graphics-render-target.h"
+#include <map>
+
namespace Dali::Graphics::GLES
{
struct Context::Impl
~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(GLES::ProgramImpl* program, const VertexInputState& vertexInputState)
+ {
+ auto& gl = *mController.GetGL();
+ auto iter = mProgramVAOMap.find(program);
+ if(iter != mProgramVAOMap.end())
+ {
+ if(mProgramVAOCurrentState != iter->second)
+ {
+ mProgramVAOCurrentState = iter->second;
+ gl.BindVertexArray(iter->second);
+ }
+ return;
+ }
+
+ uint32_t vao;
+ gl.GenVertexArrays(1, &vao);
+ gl.BindVertexArray(vao);
+ mProgramVAOMap[program] = vao;
+ for(const auto& attr : vertexInputState.attributes)
+ {
+ gl.EnableVertexAttribArray(attr.location);
+ }
+
+ mProgramVAOCurrentState = vao;
+ }
+
+ /**
* Sets the initial GL state.
*/
void InitializeGlState()
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::map<GLES::ProgramImpl*, uint32_t> mProgramVAOMap; ///< GL program-VAO map
+ uint32_t mProgramVAOCurrentState{0u}; ///< Currently bound VAO
+ GLStateCache mGlStateCache{}; ///< GL status cache
bool mGlContextCreated{false}; ///< True if the OpenGL context has been created
};
{
auto& gl = *mImpl->mController.GetGL();
+ 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
if(!mImpl->mCurrentPipeline && !mImpl->mNewPipeline)
}
// 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;
+
+ if(hasGLES3)
+ {
+ mImpl->BindProgramVAO(static_cast<const GLES::Program*>(pipelineState.programState->program)->GetImplementation(), *vertexInputState);
+ }
+
+ for(const auto& attr : vertexInputState->attributes)
{
// Enable location
- mImpl->SetVertexAttributeLocation(attr.location, true);
+ if(!hasGLES3)
+ {
+ mImpl->SetVertexAttributeLocation(attr.location, true);
+ }
const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding];
- const auto& bufferBinding = vi->bufferBindings[attr.binding];
+ const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding];
auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
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,
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),
}
}
-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) {
+ std::copy_if(bindings, bindings + count, mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
return (nullptr != item.buffer);
});
}
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 >= mImpl->mCurrentUBOBindings.size())
{
- mImpl->mCurrentUBOBindings.resize(uboBindings.size() + 1);
+ mImpl->mCurrentUBOBindings.resize(uboCount + 1);
}
- 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)
{
// Something goes wrong here if Alpha mask is GL_TRUE
ColorMask(true);
+ const auto clearValues = renderPassBegin.clearValues.Ptr();
+
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)
+ mImpl->mGlStateCache.mClearColor.r != clearValues[0].color.r ||
+ mImpl->mGlStateCache.mClearColor.g != clearValues[0].color.g ||
+ mImpl->mGlStateCache.mClearColor.b != clearValues[0].color.b ||
+ mImpl->mGlStateCache.mClearColor.a != clearValues[0].color.a)
{
- 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);
}
}
}
}
+void Context::InvalidateDepthStencilBuffers()
+{
+ auto& gl = *mImpl->mController.GetGL();
+
+ GLenum attachments[] = {GL_DEPTH, GL_STENCIL};
+ gl.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
+}
+
void Context::SetScissorTestEnabled(bool scissorEnabled)
{
if(mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled)