Fix attribute cache bug
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-context.cpp
index f38ed4a..02d32ee 100644 (file)
 
 #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>
 
-
 namespace Dali::Graphics::GLES
 {
 struct Context::Impl
@@ -62,6 +64,13 @@ struct Context::Impl
         mProgramVAOCurrentState = iter->second;
         gl.BindVertexArray(iter->second);
       }
+
+      // We should re-check enable attribute usage because geometry might be changed.
+      // @todo : We can remove this loop if we enable vertex attrib by shader's information.
+      for(const auto& attr : vertexInputState.attributes)
+      {
+        gl.EnableVertexAttribArray(attr.location);
+      }
       return;
     }
 
@@ -69,6 +78,9 @@ struct Context::Impl
     gl.GenVertexArrays(1, &vao);
     gl.BindVertexArray(vao);
     mProgramVAOMap[program] = vao;
+    
+    // @todo : Enable vertex attrib only by shader's information, not with Geometry.
+    // Currently, vertexInputState.attributes depend on Geometry's VertexBuffer.
     for(const auto& attr : vertexInputState.attributes)
     {
       gl.EnableVertexAttribArray(attr.location);
@@ -232,7 +244,7 @@ Context::~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();
 
@@ -256,6 +268,13 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
     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(mImpl->mNewPipeline && mImpl->mCurrentPipeline != mImpl->mNewPipeline)
   {
     if(!currentProgram || currentProgram->GetImplementation()->GetGlProgram() != newProgram->GetImplementation()->GetGlProgram())
@@ -290,6 +309,9 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
       texture->InitializeResource();
     }
 
+    // Warning, this may cause glWaitSync to occur on the GPU.
+    dependencyChecker.CheckNeedsSync(this, texture);
+
     texture->Bind(binding);
 
     texture->Prepare(); // @todo also non-const.
@@ -593,11 +615,23 @@ void Context::ResolveUniformBuffers()
 void Context::ResolveStandaloneUniforms()
 {
   // Find reflection for program
-  const auto program = static_cast<const GLES::Program*>(mImpl->mNewPipeline->GetCreateInfo().programState->program);
-  const auto ptr     = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset;
+  const GLES::Program* program{nullptr};
+
+  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);
+  }
 
-  // Update program uniforms
-  program->GetImplementation()->UpdateStandaloneUniformBlock(ptr);
+  if(program)
+  {
+    const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset;
+    // Update program uniforms
+    program->GetImplementation()->UpdateStandaloneUniformBlock(ptr);
+  }
 }
 
 void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
@@ -617,7 +651,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)
@@ -629,6 +664,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;
@@ -639,11 +675,11 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
 
     const auto clearValues = renderPassBegin.clearValues.Ptr();
 
-    if(!mImpl->mGlStateCache.mClearColorSet ||
-       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)
+    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(clearValues[0].color.r,
                     clearValues[0].color.g,
@@ -691,14 +727,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();
+    if(framebuffer)
     {
       auto& gl = *mImpl->mController.GetGL();
       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);
     }
   }
 }
@@ -991,13 +1041,20 @@ void Context::PrepareForNativeRendering()
   if(!mImpl->mNativeDrawContext)
   {
     EGLint configId{0u};
-    EGLint size{0u};
-    eglGetConfigs(display, nullptr, 0, &size);
-    std::vector<EGLConfig> configs;
-    configs.resize(size);
-    eglGetConfigs(display, configs.data(), configs.size(), &size);
+    eglQueryContext(display, mImpl->mController.GetSharedContext(), EGL_CONFIG_ID, &configId);
 
-    eglQueryContext(display, context, 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());
 
@@ -1008,7 +1065,12 @@ void Context::PrepareForNativeRendering()
     attribs.push_back(version % 10);
     attribs.push_back(EGL_NONE);
 
-    mImpl->mNativeDrawContext = eglCreateContext(display, configs[configId], EGL_NO_CONTEXT, attribs.data());
+    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);