DirectRendering demo 99/284099/6
authorAdam Bialogonski <adam.b@samsung.com>
Wed, 9 Nov 2022 15:27:57 +0000 (15:27 +0000)
committerAdam Bialogonski <adam.b@samsung.com>
Fri, 11 Nov 2022 14:15:41 +0000 (14:15 +0000)
Environment variables:
MAX_CUBES = [integer] - number of cubes to render (default 100)
DR_THREAD_ENABLED = 0|1 - renders with parallel thread
EGL_ENABED = 0|1 - uses EGL instead (not working on Ubuntu)

Change-Id: I185bec2667d25c713ca9c63cf97702a8de9ea539

examples-reel/dali-examples-reel.cpp
examples/direct-rendering/direct-rendering-example.cpp [new file with mode: 0644]
examples/direct-rendering/native-renderer.cpp [new file with mode: 0644]
examples/direct-rendering/native-renderer.h [new file with mode: 0644]
resources/po/en_US.po
shared/dali-demo-strings.h

index 17fc2d7..e86f459 100644 (file)
@@ -52,6 +52,7 @@ int DALI_EXPORT_API main(int argc, char** argv)
   demo.AddExample(Example("color-transition.example", DALI_DEMO_STR_TITLE_COLOR_TRANSITION));
   demo.AddExample(Example("color-visual.example", DALI_DEMO_STR_TITLE_COLOR_VISUAL));
   demo.AddExample(Example("deferred-shading.example", DALI_DEMO_STR_TITLE_DEFERRED_SHADING));
+  demo.AddExample(Example("direct-rendering.example", DALI_DEMO_STR_TITLE_DIRECT_RENDERING));
   demo.AddExample(Example("dissolve-effect.example", DALI_DEMO_STR_TITLE_DISSOLVE_TRANSITION));
   demo.AddExample(Example("drag-and-drop.example", DALI_DEMO_STR_TITLE_DRAG_AND_DROP));
   demo.AddExample(Example("drawable-actor.example", DALI_DEMO_STR_TITLE_DRAWABLE_ACTOR));
diff --git a/examples/direct-rendering/direct-rendering-example.cpp b/examples/direct-rendering/direct-rendering-example.cpp
new file mode 100644 (file)
index 0000000..ae549f4
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit/dali-toolkit.h>
+#include "native-renderer.h"
+
+using namespace Dali;
+
+namespace
+{
+/**
+ * Helper function reading env variable as integer
+ */
+int GetEnvInt(const char* name, int def)
+{
+  auto v = getenv(name);
+  return v ? atoi(v) : def;
+}
+
+/**
+ * Environment variable: DR_THREAD_ENABLE
+ *
+ * if set to 1 the Direct Rendering will use offscreen buffer and render in parallel. It is a direct
+ * equivalent of the EGL Image mode.
+ */
+const uint32_t DR_THREAD_ENABLED = GetEnvInt("DR_THREAD_ENABLED", 0);
+
+/**
+ * Environment variable: EGL_ENABLED
+ *
+ * When set to 1 the native image is used for direct rendering (rendering is parallel by default).
+ */
+const Toolkit::GlView::BackendMode BACKEND_MODE =
+  Toolkit::GlView::BackendMode(GetEnvInt("EGL_ENABLED", 0));
+}
+
+/**
+ * RenderView encapsulates single GLView callback and its parameters.
+ */
+struct RenderView
+{
+  explicit RenderView( const Dali::Window& window )
+  {
+    mWindow = window;
+  }
+
+  int Create(const Vector2& pos, Toolkit::GlView::BackendMode mode )
+  {
+    auto w = mWindow.GetSize().GetWidth();
+    auto h = mWindow.GetSize().GetHeight();
+
+    NativeRenderer::CreateInfo info{};
+    info.clearColor = {0, 0, 0, 0};
+    info.name = "DR";
+    info.offscreen = (mode == Toolkit::GlView::BackendMode::EGL_IMAGE_OFFSCREEN_RENDERING || DR_THREAD_ENABLED);
+    info.viewportX = 0;
+    info.viewportY = 0;
+    info.width = w;
+    info.height = h;
+    info.threaded = (mode != Toolkit::GlView::BackendMode::EGL_IMAGE_OFFSCREEN_RENDERING) && (DR_THREAD_ENABLED);
+
+    // Enable threaded rendering
+    if(info.threaded && mode == Dali::Toolkit::GlView::BackendMode::DIRECT_RENDERING)
+    {
+      mode = Dali::Toolkit::GlView::BackendMode::DIRECT_RENDERING_THREADED;
+    }
+
+    mRenderer            = std::make_unique<NativeRenderer>(info);
+    mGlInitCallback      = MakeCallback(mRenderer.get(), &NativeRenderer::GlViewInitCallback);
+    mGlRenderCallback    = MakeCallback(mRenderer.get(), &NativeRenderer::GlViewRenderCallback);
+    mGlTerminateCallback = MakeCallback(mRenderer.get(), &NativeRenderer::GlViewTerminateCallback);
+
+    // Create GlView with callbacks
+    auto glView = Toolkit::GlView::New(mode, Toolkit::GlView::ColorFormat::RGBA8888); //, Toolkit::GlView::BackendMode::DIRECT_RENDERING);
+    glView.SetGraphicsConfig(true, false, 0, Toolkit::GlView::GraphicsApiVersion::GLES_VERSION_3_0);
+    glView.RegisterGlCallbacks(mGlInitCallback, mGlRenderCallback, mGlTerminateCallback);
+
+    glView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+    glView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+
+    // Set size on the actor (half the window size to show that glClear() and scissor test work together)
+    glView.SetProperty(Actor::Property::SIZE, Size(w, h));
+    glView.SetProperty(Actor::Property::POSITION, pos);
+    glView.SetRenderingMode(Toolkit::GlView::RenderingMode::CONTINUOUS);
+    mWindow.Add(glView);
+
+    mGlView = glView;
+
+    return 0;
+  }
+
+
+  Dali::Window mWindow;
+  Toolkit::GlView mGlView;
+  std::unique_ptr<NativeRenderer> mRenderer{};
+
+  CallbackBase* mGlInitCallback{};
+  CallbackBase* mGlRenderCallback{};
+  CallbackBase* mGlTerminateCallback{};
+};
+
+// This example oresents DirectRendering feature which allows injecting
+// custom GL code into the DALi render commands stream
+
+class DirectRenderingExampleController : public ConnectionTracker
+{
+public:
+
+  explicit DirectRenderingExampleController(Application& application)
+    : mApplication(application)
+  {
+    // Connect to the Application's Init signal
+    mApplication.InitSignal().Connect(this, &DirectRenderingExampleController::Create);
+  }
+
+  ~DirectRenderingExampleController() override = default; // Nothing to do in destructor
+
+  void Create(Application& application)
+  {
+    // Get a handle to the window
+    Dali::Window window = application.GetWindow();
+    window.SetBackgroundColor(Color::WHITE);
+
+    mDRView = std::make_unique<RenderView>(window);
+    mDRView->Create( Vector2::ZERO, BACKEND_MODE );
+  }
+
+  bool OnTouch(Actor actor, const TouchEvent& touch)
+  {
+    // quit the application
+    mApplication.Quit();
+    return true;
+  }
+
+  void OnKeyEvent(const KeyEvent& event)
+  {
+    if(event.GetState() == KeyEvent::DOWN)
+    {
+      if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
+      {
+        mApplication.Quit();
+      }
+    }
+  }
+
+private:
+  Application& mApplication;
+  std::unique_ptr<RenderView> mDRView;
+};
+
+int DALI_EXPORT_API main(int argc, char** argv)
+{
+  Application          application = Application::New(&argc, &argv);
+  DirectRenderingExampleController test(application);
+  application.MainLoop();
+  return 0;
+}
diff --git a/examples/direct-rendering/native-renderer.cpp b/examples/direct-rendering/native-renderer.cpp
new file mode 100644 (file)
index 0000000..2c83427
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "native-renderer.h"
+#include <iostream>
+
+/**
+ * Set of math helper functions
+ */
+namespace
+{
+
+[[maybe_unused]] std::vector<std::string> split(const std::string& s, char seperator)
+{
+  std::vector<std::string> output;
+  std::string::size_type prev_pos = 0, pos = 0;
+  while((pos = s.find(seperator, pos)) != std::string::npos)
+  {
+    std::string substring( s.substr(prev_pos, pos-prev_pos) );
+    output.push_back(substring);
+    prev_pos = ++pos;
+  }
+  output.push_back(s.substr(prev_pos, pos-prev_pos)); // Last word
+  return output;
+}
+
+int GetEnvInt(const char* name, int def)
+{
+  auto v = getenv(name);
+  return v ? atoi(v) : def;
+}
+
+[[maybe_unused]] std::string GetEnvString(const char* name, std::string def = "")
+{
+  auto v = getenv(name);
+  return v ? std::string(v) : def;
+}
+
+const uint32_t MAX_CUBES = GetEnvInt("MAX_CUBES", 200);
+
+#define GL(x) {glGetError();{x;};auto err = glGetError();if(err){ \
+printf("%p:%d: ERROR: 0x%X\n", this, __LINE__, int(err));} }
+
+constexpr GLfloat CUBE_VERTICES[] = {-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f};
+
+constexpr GLfloat CUBE_COLOURS[] = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
+
+constexpr GLushort CUBE_INDICES[] = {0, 2, 3, 0, 1, 3, 4, 6, 7, 4, 5, 7, 8, 9, 10, 11, 8, 10, 12, 13, 14, 15, 12, 14, 16, 17, 18, 16, 19, 18, 20, 21, 22, 20, 23, 22};
+
+constexpr float QUAD_VERTS[] = {
+  // positions          // colors           // texture coords
+  1.0f,  1.0f,
+  1.0f, -1.0f,
+  -1.0f, -1.0f,
+  -1.0f,  1.0f,
+};
+
+constexpr unsigned short QUAD_INDICES[] = {
+  0, 1, 2,
+  3, 0, 2
+};
+
+constexpr float QUAD_UV[] = {
+  // positions          // colors           // texture coords
+  1.0f, 1.0f,   // top right
+  1.0f, 0.0f,   // bottom right
+  0.0f, 0.0f,   // bottom left
+  0.0f, 1.0f    // top left
+};
+
+float matrixDegreesToRadians(float degrees)
+{
+  return M_PI * degrees / 180.0f;
+}
+
+[[maybe_unused]] void matrixIdentityFunction(float* matrix)
+{
+  if(matrix == NULL)
+  {
+    return;
+  }
+  matrix[0]  = 1.0f;
+  matrix[1]  = 0.0f;
+  matrix[2]  = 0.0f;
+  matrix[3]  = 0.0f;
+  matrix[4]  = 0.0f;
+  matrix[5]  = 1.0f;
+  matrix[6]  = 0.0f;
+  matrix[7]  = 0.0f;
+  matrix[8]  = 0.0f;
+  matrix[9]  = 0.0f;
+  matrix[10] = 1.0f;
+  matrix[11] = 0.0f;
+  matrix[12] = 0.0f;
+  matrix[13] = 0.0f;
+  matrix[14] = 0.0f;
+  matrix[15] = 1.0f;
+}
+
+[[maybe_unused]] void matrixMultiply(float* destination, float* operand1, float* operand2)
+{
+  float theResult[16];
+  int   i, j = 0;
+  for(i = 0; i < 4; i++)
+  {
+    for(j = 0; j < 4; j++)
+    {
+      theResult[4 * i + j] = operand1[j] * operand2[4 * i] + operand1[4 + j] * operand2[4 * i + 1] +
+                             operand1[8 + j] * operand2[4 * i + 2] + operand1[12 + j] * operand2[4 * i + 3];
+    }
+  }
+  for(int i = 0; i < 16; i++)
+  {
+    destination[i] = theResult[i];
+  }
+}
+
+[[maybe_unused]] void matrixTranslate(float* matrix, float x, float y, float z)
+{
+  float temporaryMatrix[16];
+  matrixIdentityFunction(temporaryMatrix);
+  temporaryMatrix[12] = x;
+  temporaryMatrix[13] = y;
+  temporaryMatrix[14] = z;
+  matrixMultiply(matrix, temporaryMatrix, matrix);
+}
+
+[[maybe_unused]] void matrixScale(float* matrix, float x, float y, float z)
+{
+  float tempMatrix[16];
+  matrixIdentityFunction(tempMatrix);
+  tempMatrix[0]  = x;
+  tempMatrix[5]  = y;
+  tempMatrix[10] = z;
+  matrixMultiply(matrix, tempMatrix, matrix);
+}
+
+[[maybe_unused]] void matrixRotateX(float* matrix, float angle)
+{
+  float tempMatrix[16];
+  matrixIdentityFunction(tempMatrix);
+  tempMatrix[5]  = cos(matrixDegreesToRadians(angle));
+  tempMatrix[9]  = -sin(matrixDegreesToRadians(angle));
+  tempMatrix[6]  = sin(matrixDegreesToRadians(angle));
+  tempMatrix[10] = cos(matrixDegreesToRadians(angle));
+  matrixMultiply(matrix, tempMatrix, matrix);
+}
+[[maybe_unused]] void matrixRotateY(float* matrix, float angle)
+{
+  float tempMatrix[16];
+  matrixIdentityFunction(tempMatrix);
+  tempMatrix[0]  = cos(matrixDegreesToRadians(angle));
+  tempMatrix[8]  = sin(matrixDegreesToRadians(angle));
+  tempMatrix[2]  = -sin(matrixDegreesToRadians(angle));
+  tempMatrix[10] = cos(matrixDegreesToRadians(angle));
+  matrixMultiply(matrix, tempMatrix, matrix);
+}
+[[maybe_unused]] void matrixRotateZ(float* matrix, float angle)
+{
+  float tempMatrix[16];
+  matrixIdentityFunction(tempMatrix);
+  tempMatrix[0] = cos(matrixDegreesToRadians(angle));
+  tempMatrix[4] = -sin(matrixDegreesToRadians(angle));
+  tempMatrix[1] = sin(matrixDegreesToRadians(angle));
+  tempMatrix[5] = cos(matrixDegreesToRadians(angle));
+  matrixMultiply(matrix, tempMatrix, matrix);
+}
+
+void matrixFrustum(float* matrix, float left, float right, float bottom, float top, float zNear, float zFar)
+{
+  float temp, xDistance, yDistance, zDistance;
+  temp      = 2.0 * zNear;
+  xDistance = right - left;
+  yDistance = top - bottom;
+  zDistance = zFar - zNear;
+  matrixIdentityFunction(matrix);
+  matrix[0]  = temp / xDistance;
+  matrix[5]  = temp / yDistance;
+  matrix[8]  = (right + left) / xDistance;
+  matrix[9]  = (top + bottom) / yDistance;
+  matrix[10] = (-zFar - zNear) / zDistance;
+  matrix[11] = -1.0f;
+  matrix[14] = (-temp * zFar) / zDistance;
+  matrix[15] = 0.0f;
+}
+
+[[maybe_unused]] void matrixPerspective(float* matrix, float fieldOfView, float aspectRatio, float zNear, float zFar)
+{
+  float ymax, xmax;
+  ymax = zNear * tanf(fieldOfView * M_PI / 360.0);
+  xmax = ymax * aspectRatio;
+  matrixFrustum(matrix, -xmax, xmax, -ymax, ymax, zNear, zFar);
+}
+
+} // namespace
+
+NativeRenderer::~NativeRenderer() = default;
+
+NativeRenderer::NativeRenderer(const CreateInfo& info )
+: mWidth(info.width),
+  mHeight(info.height),
+  mCreateInfo(info)
+{
+}
+
+void NativeRenderer::PrepareShader()
+{
+  static const char glVertexShader[] =
+    "attribute vec4 vertexPosition;\n"
+    "attribute vec3 vertexColour;\n"
+    "varying vec3 fragColour;\n"
+    "uniform mat4 projection;\n"
+    "uniform mat4 modelView;\n"
+    "void main()\n"
+    "{\n"
+    "    gl_Position = projection * modelView * vertexPosition;\n"
+    "    fragColour = vertexColour;\n"
+    "}\n";
+
+  static const char glFragmentShader[] =
+    "precision mediump float;\n"
+    "varying vec3 fragColour;\n"
+    "void main()\n"
+    "{\n"
+    "    gl_FragColor = vec4(fragColour, 1.0);\n"
+    "}\n";
+
+  mProgramId = CreateProgram(glVertexShader, glFragmentShader);
+}
+
+void NativeRenderer::Setup(int width, int height)
+{
+  PrepareShader();
+
+  mVertexLocation       = glGetAttribLocation(mProgramId, "vertexPosition");
+  mVertexColourLocation = glGetAttribLocation(mProgramId, "vertexColour");
+  mProjectionLocation   = glGetUniformLocation(mProgramId, "projection");
+  mModelViewLocation    = glGetUniformLocation(mProgramId, "modelView");
+
+  GL(glEnable(GL_DEPTH_TEST));
+}
+
+GLuint NativeRenderer::CreateProgram(const char* vertexSource, const char* fragmentSource)
+{
+  GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, vertexSource);
+  if(!vertexShader)
+  {
+    return 0;
+  }
+  GLuint fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentSource);
+  if(!fragmentShader)
+  {
+    return 0;
+  }
+  GLuint program = glCreateProgram();
+  if(program)
+  {
+    GL(glAttachShader(program, vertexShader));
+    GL(glAttachShader(program, fragmentShader));
+    GL(glLinkProgram(program));
+    GLint linkStatus = GL_FALSE;
+    GL(glGetProgramiv(program, GL_LINK_STATUS, &linkStatus));
+    if(linkStatus != GL_TRUE)
+    {
+      GLint bufLength = 0;
+      glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+      if(bufLength)
+      {
+        char* buf = (char*)malloc(bufLength);
+        if(buf)
+        {
+          glGetProgramInfoLog(program, bufLength, NULL, buf);
+          free(buf);
+        }
+      }
+      glDeleteProgram(program);
+      program = 0;
+    }
+  }
+  return program;
+}
+
+GLuint NativeRenderer::LoadShader(GLenum shaderType, const char* shaderSource)
+{
+  GLuint shader = glCreateShader(shaderType);
+  if(shader != 0)
+  {
+    GL(glShaderSource(shader, 1, &shaderSource, NULL));
+    GL(glCompileShader(shader));
+    GLint compiled = 0;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+    if(compiled != GL_TRUE)
+    {
+      GLint infoLen = 0;
+      glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+
+      if(infoLen > 0)
+      {
+        char* logBuffer = (char*)malloc(infoLen);
+
+        if(logBuffer != NULL)
+        {
+          glGetShaderInfoLog(shader, infoLen, NULL, logBuffer);
+          free(logBuffer);
+          logBuffer = NULL;
+        }
+
+        glDeleteShader(shader);
+        shader = 0;
+      }
+    }
+  }
+
+  return shader;
+}
+
+void NativeRenderer::RenderCube(const Dali::RenderCallbackInput& input)
+{
+  uint32_t drawCount = 0;
+
+  float& angle = mAngle;
+
+  [[maybe_unused]] auto x = mCreateInfo.viewportX; // float(mWidth - input.size.width) * 0.5f;
+  [[maybe_unused]] auto y = mCreateInfo.viewportY; // float(mHeight - input.size.height) * 0.5f;
+  auto                  w = mCreateInfo.width;
+  auto                  h = mCreateInfo.height;
+  
+  matrixPerspective(mProjectionMatrix, 45, (float)w / (float)h, 0.1f, 100);
+
+  GL(glViewport(x, y, w, h));
+  GL(glEnable(GL_DEPTH_TEST));
+  if(!mCreateInfo.offscreen)
+  {
+    GL(glEnable(GL_SCISSOR_TEST));
+    GL(glScissor(x, y, w, h));
+  }
+  else
+  {
+    GL(glDisable(GL_SCISSOR_TEST));
+  }
+  GL(glClearColor(mCreateInfo.clearColor[0],
+                  mCreateInfo.clearColor[1],
+                  mCreateInfo.clearColor[2],
+                  mCreateInfo.clearColor[3]
+                  ));
+  {
+    GL(glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT));
+  }
+  GL(glUseProgram(mProgramId));
+  GL(glVertexAttribPointer(mVertexLocation, 3, GL_FLOAT, GL_FALSE, 0, CUBE_VERTICES));
+  GL(glEnableVertexAttribArray(mVertexLocation));
+  GL(glVertexAttribPointer(mVertexColourLocation, 3, GL_FLOAT, GL_FALSE, 0, CUBE_COLOURS));
+  GL(glEnableVertexAttribArray(mVertexColourLocation));
+
+  srand(10);
+
+  const auto maxCubes = int(MAX_CUBES);
+
+  for( int i = 0; i < int(maxCubes); ++i)
+  {
+    GL(matrixIdentityFunction(mModelViewMatrix));
+    matrixScale(mModelViewMatrix, 0.2f, 0.2f, 0.2f);
+    matrixRotateX(mModelViewMatrix, angle);
+    matrixRotateY(mModelViewMatrix, angle);
+    auto max = 7000;
+    if(mPosX.size() == uint32_t(i))
+    {
+      auto x = float((rand() % max) - (max / 2)) / 1000.0f;
+      auto y = float((rand() % max) - (max / 2)) / 1000.0f;
+      mPosX.emplace_back(x);
+      mPosY.emplace_back(y);
+    }
+    matrixTranslate(mModelViewMatrix, mPosX[i], mPosY[i], -5.0f);
+    GL(glUniformMatrix4fv(mProjectionLocation, 1, GL_FALSE, mProjectionMatrix));
+    GL(glUniformMatrix4fv(mModelViewLocation, 1, GL_FALSE, mModelViewMatrix));
+    GL(glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, CUBE_INDICES));
+    drawCount++;
+  }
+  angle += 1;
+  if(angle > 360)
+  {
+    angle -= 360;
+  }
+}
+
+void NativeRenderer::GlViewInitCallback(const Dali::RenderCallbackInput& input)
+{
+  Setup(mWidth, mHeight);
+  mState = State::RENDER;
+}
+
+int NativeRenderer::GlViewRenderCallback(const Dali::RenderCallbackInput& input)
+{
+  RenderCube(input);
+  return true;
+}
+
+void NativeRenderer::GlViewTerminateCallback(const Dali::RenderCallbackInput& input)
+{
+  // Nothing to do here
+}
diff --git a/examples/direct-rendering/native-renderer.h b/examples/direct-rendering/native-renderer.h
new file mode 100644 (file)
index 0000000..30deaf0
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef DALI_DIRECT_RENDERING_NATIVE_RENDERER_H
+#define DALI_DIRECT_RENDERING_NATIVE_RENDERER_H
+
+/*
+ * Copyright (c) 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/signals/render-callback.h>
+
+#include <cmath>
+#include <GLES3/gl3.h>
+#include <EGL/egl.h>
+#include <vector>
+#include <thread>
+#include <atomic>
+#include <mutex>
+#include <deque>
+#include <map>
+#include <array>
+
+/**
+ * Class NativeRenderer uses GL directly in order to render
+ * custom GL code within DirectRendering callbacks.
+ */
+class NativeRenderer
+{
+public:
+
+  /**
+   * Structure encapsulates initialization parameters
+   */
+  struct CreateInfo
+  {
+    std::string name;
+    uint32_t width;
+    uint32_t height;
+    int32_t viewportX;
+    int32_t viewportY;
+    std::array<float,4> clearColor { 0, 0, 0, 1};
+    bool offscreen{false};
+    bool threaded{false};
+  };
+
+  /**
+   * Constructor
+   */
+  explicit NativeRenderer(const CreateInfo& info);
+
+  /**
+   * Destructor
+   */
+  ~NativeRenderer();
+
+  /**
+   * Prepare main shader
+   */
+  void PrepareShader();
+
+  /**
+   * Setup custom scene
+   */
+  void Setup(int width, int height);
+
+  /**
+   * Render cube with given callback input
+   */
+  void RenderCube( const Dali::RenderCallbackInput& input );
+
+  /**
+   * Creates GL program from shader sources
+   */
+  GLuint CreateProgram(const char* vertexSource, const char* fragmentSource);
+
+  /**
+   * Loads shader
+   */
+  GLuint LoadShader(GLenum shaderType, const char* shaderSource);
+
+  enum class State
+  {
+    INIT,
+    RENDER
+  };
+
+  // GLView-compatible callbacks
+  void GlViewInitCallback(const Dali::RenderCallbackInput& input);
+  int GlViewRenderCallback(const Dali::RenderCallbackInput& input);
+  void GlViewTerminateCallback(const Dali::RenderCallbackInput& input);
+
+private:
+
+  State mState {State::INIT};
+
+  GLuint mProgramId{0u};
+
+  GLint mVertexLocation{};
+  GLint mVertexColourLocation{};
+  GLint mProjectionLocation{};
+  GLint mModelViewLocation{};
+
+  float mModelViewMatrix[16];
+  float mProjectionMatrix[16];
+
+  uint32_t mWidth;
+  uint32_t mHeight;
+
+  CreateInfo mCreateInfo;
+
+  float mAngle{0.f};
+
+  std::vector<float> mPosX;
+  std::vector<float> mPosY;
+};
+
+#endif // DALI_DIRECT_RENDERING_NATIVE_RENDERER_H
index ab66673..7b18947 100755 (executable)
@@ -61,6 +61,9 @@ msgstr "Color Visual"
 msgid "DALI_DEMO_STR_TITLE_DEFERRED_SHADING"
 msgstr "Deferred Shading"
 
+msgid "DALI_DEMO_STR_TITLE_DIRECT_RENDERING"
+msgstr "Direct Rendering"
+
 msgid "DALI_DEMO_STR_TITLE_GAUSSIAN_BLUR_VIEW"
 msgstr "Gaussian Blur"
 
index 3552ed3..bf174f5 100644 (file)
@@ -55,6 +55,7 @@ extern "C"
 #define DALI_DEMO_STR_TITLE_COLOR_TRANSITION dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_COLOR_TRANSITION")
 #define DALI_DEMO_STR_TITLE_COLOR_VISUAL dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_COLOR_VISUAL")
 #define DALI_DEMO_STR_TITLE_DEFERRED_SHADING dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_DEFERRED_SHADING")
+#define DALI_DEMO_STR_TITLE_DIRECT_RENDERING dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_DIRECT_RENDERING")
 #define DALI_DEMO_STR_TITLE_GAUSSIAN_BLUR_VIEW dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_GAUSSIAN_BLUR_VIEW")
 #define DALI_DEMO_STR_TITLE_GESTURES dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_GESTURES")
 #define DALI_DEMO_STR_TITLE_COLOR_GRADIENT dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_COLOR_GRADIENT")
@@ -173,6 +174,7 @@ extern "C"
 #define DALI_DEMO_STR_TITLE_CONTACT_CARDS "Contact Cards"
 #define DALI_DEMO_STR_TITLE_CUBE_TRANSITION "Cube Effect"
 #define DALI_DEMO_STR_TITLE_DEFERRED_SHADING "Deferred Shading"
+#define DALI_DEMO_STR_TITLE_DIRECT_RENDERING "Direct Rendering"
 #define DALI_DEMO_STR_TITLE_DISSOLVE_TRANSITION "Dissolve Effect"
 #define DALI_DEMO_STR_TITLE_DRAG_AND_DROP "Drag and Drop"
 #define DALI_DEMO_STR_TITLE_DRAWABLE_ACTOR "DrawableActor"