diff --git a/com.samsung.dali-demo.xml b/com.samsung.dali-demo.xml
index 93194a1..67e34dd 100644
--- a/com.samsung.dali-demo.xml
+++ b/com.samsung.dali-demo.xml
@@ -373,6 +373,9 @@
+
+
+
diff --git a/examples/uniform-blocks/README.md b/examples/uniform-blocks/README.md
new file mode 100644
index 0000000..96b133e
--- /dev/null
+++ b/examples/uniform-blocks/README.md
@@ -0,0 +1,22 @@
+This test is to validate the behaviour of UniformBlocks.
+
+It generates 200 actors with the same renderer. The frag shader
+has a 1k color table in a uniform block, with a color index property
+that is incremented for each actor that's created.
+
+On a 100ms timer, it removes the oldest actor and creates a new actor
+with the next color index.
+
+On first touch, it changes the shader, and subtracts the currently indexed
+color from the color in the vertex buffer.
+
+This shows that:
+ o Many uniform blocks are instantiated on a double-buffered UniformBuffer,
+ o Despite being a sparse shader, the full uniform block size is allocated,
+ o After touch, if everything is grey, then the color defined in the uniform
+ block is the same as the color defined in the vertex buffer.
+
+
+
+
+
diff --git a/examples/uniform-blocks/shaders/uniform-block-alt.frag b/examples/uniform-blocks/shaders/uniform-block-alt.frag
new file mode 100644
index 0000000..81cd3df
--- /dev/null
+++ b/examples/uniform-blocks/shaders/uniform-block-alt.frag
@@ -0,0 +1,12 @@
+layout(std140) uniform FragmentBlock
+{
+ lowp vec4 uColor;
+ mediump vec4 uColorArray[1024];
+ mediump int uColorIndex;
+};
+
+void main()
+{
+ // Test that the array color is the same as the actor color
+ fragColor = vec4(vec3(0.5, 0.5, 0.5) + vec3(uColorArray[uColorIndex].xyz-uColor.xyz)*0.5, 1.0);
+}
diff --git a/examples/uniform-blocks/shaders/uniform-block.frag b/examples/uniform-blocks/shaders/uniform-block.frag
new file mode 100644
index 0000000..9e699bf
--- /dev/null
+++ b/examples/uniform-blocks/shaders/uniform-block.frag
@@ -0,0 +1,11 @@
+layout(std140) uniform FragmentBlock
+{
+ lowp vec4 uColor;
+ mediump vec4 uColorArray[1024];
+ mediump int uColorIndex;
+};
+
+void main()
+{
+ fragColor = uColorArray[uColorIndex];
+}
diff --git a/examples/uniform-blocks/shaders/uniform-block.vert b/examples/uniform-blocks/shaders/uniform-block.vert
new file mode 100644
index 0000000..cbf8ff9
--- /dev/null
+++ b/examples/uniform-blocks/shaders/uniform-block.vert
@@ -0,0 +1,13 @@
+INPUT vec2 aPosition;
+
+layout(std140) uniform VertexBlock
+{
+ highp mat4 uMvpMatrix;
+ highp vec3 uSize;
+};
+
+void main()
+{
+ vec3 position = vec3(aPosition, 1.0) * uSize;
+ gl_Position = uMvpMatrix * vec4(position, 1);
+}
diff --git a/examples/uniform-blocks/uniform-blocks-example.cpp b/examples/uniform-blocks/uniform-blocks-example.cpp
new file mode 100644
index 0000000..30853b9
--- /dev/null
+++ b/examples/uniform-blocks/uniform-blocks-example.cpp
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2020 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
+
+#include "generated/uniform-block-vert.h"
+#include "generated/uniform-block-frag.h"
+#include "generated/uniform-block-alt-frag.h"
+
+using namespace Dali;
+using Dali::Toolkit::TextLabel;
+
+
+
+/**
+ * This application tests that shaders with uniform blocks work as expected.
+ */
+class UniformBlocksController : public ConnectionTracker
+{
+public:
+ UniformBlocksController(Application& application)
+ : mApplication(application)
+ {
+ // Connect to the Application's Init signal
+ mApplication.InitSignal().Connect(this, &UniformBlocksController::Create);
+ }
+
+ ~UniformBlocksController() = default; // Nothing to do in destructor
+
+ // The Init signal is received once (only) during the Application lifetime
+ void Create(Application& application)
+ {
+ // Get a handle to the window
+ Window window = application.GetWindow();
+ window.SetBackgroundColor(Color::WHITE);
+
+ CreateShader(0);
+ CreateGeometry();
+ CreateRenderer();
+ mFirstActor = window.GetRootLayer().GetChildCount();
+
+ for(int i=0; i<200; ++i)
+ {
+ AddActor(i);
+ }
+
+ // Respond to a touch anywhere on the window
+ window.GetRootLayer().TouchedSignal().Connect(this, &UniformBlocksController::OnTouch);
+
+ // Respond to key events
+ window.KeyEventSignal().Connect(this, &UniformBlocksController::OnKeyEvent);
+ mTimer = Timer::New(100);
+ mTimer.TickSignal().Connect(this, &UniformBlocksController::OnTick);
+ mTimer.Start();
+ }
+
+ bool OnTick()
+ {
+ static int index=200;
+ Window window = mApplication.GetWindow();
+ Layer layer = window.GetRootLayer();
+ Actor child = layer.GetChildAt(mFirstActor);
+ UnparentAndReset(child);
+ AddActor(index);
+ index = (index+1)%1024;
+ return true;
+ }
+
+ bool OnTouch(Actor actor, const TouchEvent& touch)
+ {
+ static int testNumber=0;
+ if(touch.GetState(0) == PointState::STARTED)
+ {
+ testNumber++;
+ if(testNumber >=2)
+ mApplication.Quit();
+
+ CreateShader(testNumber);
+ mRenderer = Renderer::New(mGeometry, mShader);
+
+ Actor parent = mApplication.GetWindow().GetRootLayer();
+ for(uint32_t i=0; i