Added image renderer clip space culling 85/24085/1
authorDavid Steele <david.steele@partner.samsung.com>
Thu, 12 Jun 2014 18:11:43 +0000 (19:11 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Tue, 8 Jul 2014 13:15:33 +0000 (14:15 +0100)
[problem]      Render thread taking too long setting up renderers that will be clipped by GPU
[solution]     Calculate which renderers are in clip space, and cull those that aren't.

Now uses OBB culling (which is relatively expensive, but still less expensive than drawing)

Adds an API to RenderTask to disable culling (enabled by default)

Change-Id: Ibe0c9c454b97fb02d8a63d17aeed9e2d4ff5d12e
Signed-off-by: David Steele <david.steele@partner.samsung.com>
40 files changed:
automated-tests/src/dali-internal/CMakeLists.txt
automated-tests/src/dali-internal/tct-dali-internal-core.h
automated-tests/src/dali-internal/utc-Dali-Internal-Image-Culling.cpp [new file with mode: 0644]
automated-tests/src/dali-internal/utc-Dali-Internal-Material.cpp
automated-tests/src/dali-internal/utc-Dali-Internal-ResourceClient.cpp
automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.h
automated-tests/src/dali/dali-test-suite-utils/test-trace-call-stack.cpp
automated-tests/src/dali/dali-test-suite-utils/test-trace-call-stack.h
capi/dali/public-api/render-tasks/render-task.h
dali/internal/common/message.h
dali/internal/event/effects/shader-effect-impl.cpp
dali/internal/event/effects/shader-effect-impl.h
dali/internal/event/effects/shader-factory.cpp
dali/internal/event/render-tasks/render-task-impl.cpp
dali/internal/event/render-tasks/render-task-impl.h
dali/internal/render/common/render-algorithms.cpp
dali/internal/render/common/render-debug.cpp
dali/internal/render/common/render-debug.h
dali/internal/render/common/render-instruction.cpp
dali/internal/render/common/render-instruction.h
dali/internal/render/common/render-manager.cpp
dali/internal/render/gl-resources/context.h
dali/internal/render/renderers/scene-graph-image-renderer.cpp
dali/internal/render/renderers/scene-graph-image-renderer.h
dali/internal/render/renderers/scene-graph-mesh-renderer.cpp
dali/internal/render/renderers/scene-graph-mesh-renderer.h
dali/internal/render/renderers/scene-graph-renderer.cpp
dali/internal/render/renderers/scene-graph-renderer.h
dali/internal/render/renderers/scene-graph-text-renderer.cpp
dali/internal/render/renderers/scene-graph-text-renderer.h
dali/internal/render/shaders/program.cpp
dali/internal/render/shaders/program.h
dali/internal/render/shaders/shader.cpp
dali/internal/render/shaders/shader.h
dali/internal/update/manager/prepare-render-instructions.cpp
dali/internal/update/manager/update-manager.cpp
dali/internal/update/manager/update-manager.h
dali/internal/update/render-tasks/scene-graph-render-task.cpp
dali/internal/update/render-tasks/scene-graph-render-task.h
dali/public-api/render-tasks/render-task.cpp

index c0c886f..9082ae4 100644 (file)
@@ -12,6 +12,7 @@ SET(TC_SOURCES
         utc-Dali-Internal-Material.cpp
         utc-Dali-Internal-Text.cpp
         utc-Dali-Internal-ResourceClient.cpp
+        utc-Dali-Internal-Image-Culling.cpp
 )
 
 LIST(APPEND TC_SOURCES
index 5559789..e99f34b 100644 (file)
@@ -5,6 +5,8 @@
 
 extern void utc_dali_material_startup(void);
 extern void utc_dali_material_cleanup(void);
+extern void utc_dali_internal_image_culling_startup(void);
+extern void utc_dali_internal_image_culling_cleanup(void);
 
 extern int UtcDaliFontMeasureTextWidth(void);
 extern int UtcDaliFontMeasureTextWidthNegative(void);
@@ -69,6 +71,30 @@ extern int UtcDaliInternalAllocateTexture01(void);
 extern int UtcDaliInternalAddNativeImage(void);
 extern int UtcDaliInternalAddFrameBufferImage(void);
 extern int UtcDaliInternalAllocateMesh01(void);
+extern int UtcDaliImageCulling_Inside01(void);
+extern int UtcDaliImageCulling_Inside02(void);
+extern int UtcDaliImageCulling_Inside03(void);
+extern int UtcDaliImageCulling_Inside04(void);
+extern int UtcDaliImageCulling_Inside05(void);
+extern int UtcDaliImageCulling_WithinBoundary01(void);
+extern int UtcDaliImageCulling_WithinBoundary02(void);
+extern int UtcDaliImageCulling_WithinBoundary03(void);
+extern int UtcDaliImageCulling_WithinBoundary04(void);
+extern int UtcDaliImageCulling_WithinBoundary05(void);
+extern int UtcDaliImageCulling_OutsideBoundary01(void);
+extern int UtcDaliImageCulling_OutsideBoundary02(void);
+extern int UtcDaliImageCulling_OutsideBoundary03(void);
+extern int UtcDaliImageCulling_OutsideBoundary04(void);
+extern int UtcDaliImageCulling_OutsideBoundary05(void);
+extern int UtcDaliImageCulling_OutsideIntersect01(void);
+extern int UtcDaliImageCulling_OutsideIntersect02(void);
+extern int UtcDaliImageCulling_OutsideIntersect03(void);
+extern int UtcDaliImageCulling_OutsideIntersect04(void);
+extern int UtcDaliImageCulling_Plane01(void);
+extern int UtcDaliImageCulling_Plane02(void);
+extern int UtcDaliImageCulling_Plane03(void);
+extern int UtcDaliImageCulling_Plane04(void);
+extern int UtcDaliImageCulling_Disable(void);
 
 testcase tc_array[] = {
     {"UtcDaliFontMeasureTextWidth", UtcDaliFontMeasureTextWidth, NULL, NULL},
@@ -134,6 +160,30 @@ testcase tc_array[] = {
     {"UtcDaliInternalAddNativeImage", UtcDaliInternalAddNativeImage, utc_dali_material_startup, utc_dali_material_cleanup},
     {"UtcDaliInternalAddFrameBufferImage", UtcDaliInternalAddFrameBufferImage, utc_dali_material_startup, utc_dali_material_cleanup},
     {"UtcDaliInternalAllocateMesh01", UtcDaliInternalAllocateMesh01, utc_dali_material_startup, utc_dali_material_cleanup},
+    {"UtcDaliImageCulling_Inside01", UtcDaliImageCulling_Inside01, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_Inside02", UtcDaliImageCulling_Inside02, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_Inside03", UtcDaliImageCulling_Inside03, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_Inside04", UtcDaliImageCulling_Inside04, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_Inside05", UtcDaliImageCulling_Inside05, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_WithinBoundary01", UtcDaliImageCulling_WithinBoundary01, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_WithinBoundary02", UtcDaliImageCulling_WithinBoundary02, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_WithinBoundary03", UtcDaliImageCulling_WithinBoundary03, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_WithinBoundary04", UtcDaliImageCulling_WithinBoundary04, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_WithinBoundary05", UtcDaliImageCulling_WithinBoundary05, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_OutsideBoundary01", UtcDaliImageCulling_OutsideBoundary01, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_OutsideBoundary02", UtcDaliImageCulling_OutsideBoundary02, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_OutsideBoundary03", UtcDaliImageCulling_OutsideBoundary03, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_OutsideBoundary04", UtcDaliImageCulling_OutsideBoundary04, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_OutsideBoundary05", UtcDaliImageCulling_OutsideBoundary05, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_OutsideIntersect01", UtcDaliImageCulling_OutsideIntersect01, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_OutsideIntersect02", UtcDaliImageCulling_OutsideIntersect02, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_OutsideIntersect03", UtcDaliImageCulling_OutsideIntersect03, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_OutsideIntersect04", UtcDaliImageCulling_OutsideIntersect04, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_Plane01", UtcDaliImageCulling_Plane01, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_Plane02", UtcDaliImageCulling_Plane02, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_Plane03", UtcDaliImageCulling_Plane03, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_Plane04", UtcDaliImageCulling_Plane04, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
+    {"UtcDaliImageCulling_Disable", UtcDaliImageCulling_Disable, utc_dali_internal_image_culling_startup, utc_dali_internal_image_culling_cleanup},
     {NULL, NULL}
 };
 
diff --git a/automated-tests/src/dali-internal/utc-Dali-Internal-Image-Culling.cpp b/automated-tests/src/dali-internal/utc-Dali-Internal-Image-Culling.cpp
new file mode 100644 (file)
index 0000000..a759a77
--- /dev/null
@@ -0,0 +1,842 @@
+/*
+ * Copyright (c) 2014 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 <iostream>
+
+#include <stdlib.h>
+#include <dali/dali.h>
+
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+void utc_dali_internal_image_culling_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_internal_image_culling_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+
+namespace
+{
+#define NUM_ROWS 9
+#define NUM_COLS 9
+#define NUM_ROWS_PER_PANE 3
+#define NUM_COLS_PER_PANE 3
+const unsigned int TEXTURE_ID_OFFSET = 23;
+
+Image LoadImage( TestApplication& application, GLuint textureId, int width, int height )
+{
+  Image image;
+  char* filename = NULL;
+  int numChars = asprintf(&filename, "image%u.png", textureId );
+  if( numChars > 0 )
+  {
+    image = Image::New( filename, Image::Immediate, Image::Never );
+    free (filename);
+  }
+  DALI_TEST_CHECK(image);
+  application.SendNotification();
+  application.Render(16);
+
+  std::vector<GLuint> ids;
+  ids.push_back( textureId );
+  application.GetGlAbstraction().SetNextTextureIds( ids );
+
+  Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, true );
+  Integration::ResourcePointer resource(bitmap);
+  bitmap->GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGBA8888, width, height, width, height);
+  DALI_TEST_CHECK( application.GetPlatform().WasCalled(TestPlatformAbstraction::LoadResourceFunc) );
+  Integration::ResourceRequest* request = application.GetPlatform().GetRequest();
+  DALI_TEST_CHECK( request != NULL );
+  if(request)
+  {
+    application.GetPlatform().SetResourceLoaded(request->GetId(), request->GetType()->id, resource);
+  }
+  application.SendNotification();
+  application.Render(16);
+  application.GetPlatform().ClearReadyResources();
+  application.GetPlatform().DiscardRequest();
+  application.SendNotification();
+  application.Render(16);
+
+  return image;
+}
+
+ImageActor CreateOnStageActor(TestApplication& application, Image image, int width, int height, bool testDraw)
+{
+  ImageActor imageActor = ImageActor::New(image);
+  Stage::GetCurrent().Add(imageActor);
+
+  imageActor.SetParentOrigin(ParentOrigin::CENTER);
+  application.SendNotification();
+  application.Render(16);
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = glAbstraction.GetTextureTrace();
+  TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+
+  if(testDraw)
+  {
+    DALI_TEST_CHECK( drawTrace.FindMethod( "DrawArrays" ) );
+    DALI_TEST_CHECK( textureTrace.FindMethod( "BindTexture" ) );
+    const std::vector<GLuint>& textures = glAbstraction.GetBoundTextures(GL_TEXTURE0);
+    DALI_TEST_CHECK( textures.size() > 0 );
+    if( textures.size() > 0 )
+    {
+      DALI_TEST_CHECK( textures[0] == 23 );
+    }
+  }
+  return imageActor;
+}
+
+
+void TestImageInside( TestApplication& application, int width, int height )
+{
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = glAbstraction.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+  drawTrace.Enable(true);
+
+  Image image = LoadImage( application, 23, width, height );
+
+  ImageActor imageActor = CreateOnStageActor(application, image, width, height, true);
+  imageActor.SetPosition(0.0f, 0.0f, 0.0f);
+
+  Vector3 imageSize = imageActor.GetCurrentSize();
+  DALI_TEST_EQUALS( imageSize, Vector3(width, height, std::min(width, height)), TEST_LOCATION);
+
+  drawTrace.Reset();
+  imageActor.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_CHECK( drawTrace.FindMethod( "DrawArrays" ) );
+
+  drawTrace.Reset();
+  imageActor.SetParentOrigin(ParentOrigin::TOP_RIGHT);
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_CHECK( drawTrace.FindMethod( "DrawArrays" ) );
+
+  drawTrace.Reset();
+  imageActor.SetParentOrigin(ParentOrigin::BOTTOM_RIGHT);
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_CHECK( drawTrace.FindMethod( "DrawArrays" ) );
+
+  drawTrace.Reset();
+  imageActor.SetParentOrigin(ParentOrigin::BOTTOM_LEFT);
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_CHECK( drawTrace.FindMethod( "DrawArrays" ) );
+}
+
+
+void RepositionActor(TestApplication& application, Actor actor, float x, float y, bool inside)
+{
+  TraceCallStack& drawTrace = application.GetGlAbstraction().GetDrawTrace();
+
+  drawTrace.Reset();
+  actor.SetPosition( x, y, 0.0f);
+  application.SendNotification();
+  application.Render(16);
+  if( inside )
+  {
+    bool found = drawTrace.FindMethod( "DrawArrays" );
+    if( ! found ) tet_printf( "Not drawn: Position:(%3.0f, %3.0f)\n", x, y );
+    DALI_TEST_CHECK( found );
+  }
+  else
+  {
+    bool found = drawTrace.FindMethod( "DrawArrays" );
+    if( found ) tet_printf( "Drawn when not needed: Position:(%3.0f, %3.0f)\n", x, y );
+    DALI_TEST_CHECK( ! found );
+  }
+}
+
+void RepositionActorWithAngle(TestApplication& application, Actor actor, float x, float y, float angle, bool inside)
+{
+  TraceCallStack& drawTrace = application.GetGlAbstraction().GetDrawTrace();
+
+  drawTrace.Reset();
+  actor.SetPosition( x, y, 0.0f);
+  actor.SetRotation( Degree(angle), Vector3::ZAXIS );
+  application.SendNotification();
+  application.Render(16);
+  if( inside )
+  {
+    bool found = drawTrace.FindMethod( "DrawArrays" );
+    if( ! found ) tet_printf( "Not drawn: Position:(%3.0f, %3.0f)\n", x, y );
+    DALI_TEST_CHECK( found );
+  }
+  else
+  {
+    bool found = drawTrace.FindMethod( "DrawArrays" );
+    if( found ) tet_printf( "Drawn when not needed: Position:(%3.0f, %3.0f)\n", x, y );
+    DALI_TEST_CHECK( ! found );
+  }
+}
+
+void RepositionActorOutside(TestApplication& application, Actor actor, float x, float y, bool drawn )
+{
+  TraceCallStack& drawTrace = application.GetGlAbstraction().GetDrawTrace();
+
+  drawTrace.Reset();
+  actor.SetPosition( x, y, 0.0f);
+  application.SendNotification();
+  application.Render(16);
+  if( drawn )
+  {
+    bool found = drawTrace.FindMethod( "DrawArrays" );
+    if( ! found ) tet_printf( "Not drawn: Position:(%3.0f, %3.0f)\n", x, y );
+    DALI_TEST_CHECK( found );
+  }
+  else
+  {
+    bool found = drawTrace.FindMethod( "DrawArrays" );
+    if( found ) tet_printf( "Drawn unnecessarily: Position:(%3.0f, %3.0f)\n", x, y );
+    DALI_TEST_CHECK( ! found );
+  }
+
+}
+
+void SphereTestImageAtBoundary( TestApplication& application, int width, int height )
+{
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = glAbstraction.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+  drawTrace.Enable(true);
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+
+  Image image = LoadImage(application, 23, width, height);
+  ImageActor imageActor = CreateOnStageActor(application, image, width, height, true);
+
+  Vector3 imageSize = imageActor.GetCurrentSize();
+  DALI_TEST_EQUALS( imageSize, Vector3(width, height, std::min(width, height)), TEST_LOCATION);
+
+  imageSize.z = 0.0f;
+  float radius = imageSize.Length() * 0.5f; // Radius of bounding box
+  tet_printf("Testing Stage Size: (%3.0f, %3.0f) image size:(%3.0f, %3.0f) := radius=%3.0f\n",
+             stageSize.x, stageSize.y, imageSize.x, imageSize.y, radius);
+
+  for( int i=0; i<=radius; i++ )
+  {
+    float x1 = -stageSize.x/2.0f - i;
+    float x2 =  stageSize.x/2.0f + i;
+    float y1 = -stageSize.y/2.0f - i;
+    float y2 =  stageSize.y/2.0f + i;
+
+    //tet_printf("Testing i=%d\n",i);
+
+    // Test paths marked with dots
+    //  + . . . . . .
+    //  .\_     ^
+    //  .  \_   | within radius
+    //  .    \  v
+    //  .     +-----
+    //  .     | Stage
+
+    for( int j=-10; j<=10; j++ )
+    {
+      float x = ((stageSize.x+2*radius)/21.0f) * j;
+      float y = ((stageSize.y+2*radius)/21.0f) * j;
+
+      RepositionActor( application, imageActor, x1, y, true );
+      RepositionActor( application, imageActor, x2, y, true );
+      RepositionActor( application, imageActor, x, y1, true );
+      RepositionActor( application, imageActor, x, y2, true );
+    }
+  }
+}
+
+void OBBTestImageAtBoundary( TestApplication& application, int width, int height )
+{
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = glAbstraction.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+  drawTrace.Enable(true);
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+
+  Image image = LoadImage(application, 23, width, height);
+  ImageActor imageActor = CreateOnStageActor(application, image, width, height, true);
+
+  Vector3 imageSize = imageActor.GetCurrentSize();
+  DALI_TEST_EQUALS( imageSize, Vector3(width, height, std::min(width, height)), TEST_LOCATION);
+
+  imageSize.z = 0.0f;
+  tet_printf("Testing Stage Size: (%3.0f, %3.0f) image size:(%3.0f, %3.0f) \n",
+             stageSize.x, stageSize.y, imageSize.x, imageSize.y);
+
+  for( int i=0; i<100; i++ )
+  {
+    float x1 = -stageSize.x/2.0f - imageSize.x*i/200.0f;
+    float x2 =  stageSize.x/2.0f + imageSize.x*i/200.0f;
+    float y1 = -stageSize.y/2.0f - imageSize.y*i/200.0f;
+    float y2 =  stageSize.y/2.0f + imageSize.y*i/200.0f;
+
+    //tet_printf("Testing i=%d\n",i);
+
+    // Test paths marked with dots
+    //  + . . . . . .
+    //  .\_     ^
+    //  .  \_   | within radius
+    //  .    \  v
+    //  .     +-----
+    //  .     | Stage
+
+    for( int j=-10; j<=10; j++ )
+    {
+      float x = ((stageSize.x+imageSize.x/2.0f)/21.0f) * j;
+      float y = ((stageSize.y+imageSize.y/2.0f)/21.0f) * j;
+
+      RepositionActor( application, imageActor, x1, y, true );
+      RepositionActor( application, imageActor, x2, y, true );
+      RepositionActor( application, imageActor, x, y1, true );
+      RepositionActor( application, imageActor, x, y2, true );
+    }
+  }
+}
+
+
+void SphereTestImageOutsideBoundary( TestApplication& application, int width, int height )
+{
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = glAbstraction.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+  drawTrace.Enable(true);
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+
+  Image image = LoadImage( application, 23, width, height );
+
+  ImageActor imageActor = CreateOnStageActor(application, image, width, height, true);
+  Vector3 imageSize = imageActor.GetCurrentSize();
+  DALI_TEST_EQUALS( imageSize, Vector3(width, height, std::min(width, height)), TEST_LOCATION);
+
+  imageSize.z = 0.0f;
+  float radius = imageSize.Length() * 0.5f; // Radius of bounding box
+  tet_printf("Testing Stage Size: (%3.0f, %3.0f) image size:(%3.0f, %3.0f) := radius=%3.0f\n",
+             stageSize.x, stageSize.y, imageSize.x, imageSize.y, radius);
+
+  for( int i=0; i<100; i++ )
+  {
+    // Try from 3 times
+    float x1 = -stageSize.x/2.0f - imageSize.x*i/200.0f;
+    float x2 =  stageSize.x/2.0f + imageSize.x*i/200.0f;
+    float y1 = -stageSize.y/2.0f - imageSize.y*i/200.0f;
+    float y2 =  stageSize.y/2.0f + imageSize.y*i/200.0f;
+
+
+    //tet_printf("Testing i=%d\n",i);
+    for( int j=-10; j<=10; j++ )
+    {
+      float x = (stageSize.x/17.0f) * j; // use larger intervals to test more area
+      float y = (stageSize.y/17.0f) * j;
+
+      RepositionActor( application, imageActor, x1, y, false );
+      RepositionActor( application, imageActor, x2, y, false );
+      RepositionActor( application, imageActor, x, y1, false );
+      RepositionActor( application, imageActor, x, y2, false );
+    }
+  }
+}
+
+void OBBTestImageOutsideBoundary( TestApplication& application, int width, int height )
+{
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = glAbstraction.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+  drawTrace.Enable(true);
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+
+  Image image = LoadImage( application, 23, width, height );
+
+  ImageActor imageActor = CreateOnStageActor(application, image, width, height, true);
+  Vector3 imageSize = imageActor.GetCurrentSize();
+  DALI_TEST_EQUALS( imageSize, Vector3(width, height, std::min(width, height)), TEST_LOCATION);
+
+  imageSize.z = 0.0f;
+  tet_printf("Testing Stage Size: (%3.0f, %3.0f) image size:(%3.0f, %3.0f)\n",
+             stageSize.x, stageSize.y, imageSize.x, imageSize.y);
+
+  for( int i=0; i<=100; i++ )
+  {
+    float x1 = -stageSize.x/2.0f - imageSize.x * (1.5f + i/100.0f);
+    float x2 =  stageSize.x/2.0f + imageSize.x * (1.5f + i/100.0f);
+    float y1 = -stageSize.y/2.0f - imageSize.y * (1.5f + i/100.0f);
+    float y2 =  stageSize.y/2.0f + imageSize.y * (1.5f + i/100.0f);
+
+    for( int j=-10; j<=10; j++ )
+    {
+      float x = (stageSize.x/17.0f) * j; // use larger intervals to test more area
+      float y = (stageSize.y/17.0f) * j;
+
+      RepositionActor( application, imageActor, x1, y, false );
+      RepositionActor( application, imageActor, x2, y, false );
+      RepositionActor( application, imageActor, x, y1, false );
+      RepositionActor( application, imageActor, x, y2, false );
+    }
+  }
+}
+
+void TestPlaneOfImages(TestApplication& application, float z)
+{
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  Vector2 imageSize = stageSize/3.0f;
+
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = glAbstraction.GetTextureTrace();
+  TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+
+  // Create a grid of 9 x 9 actors; only the central 3x3 are in viewport
+
+  ActorContainer actors;
+  for( int i = 0; i < NUM_ROWS*NUM_COLS; i++ )
+  {
+    GLuint textureId = TEXTURE_ID_OFFSET+i;
+    Image image = LoadImage( application, textureId, imageSize.x, imageSize.y );
+    ImageActor imageActor = CreateOnStageActor(application, image, imageSize.x, imageSize.y, false );
+    actors.push_back(imageActor);
+  }
+  application.SendNotification();
+  application.Render(16);
+
+  drawTrace.Reset();
+  textureTrace.Reset();
+  drawTrace.Enable(true);
+  textureTrace.Enable(true);
+  application.GetGlAbstraction().ClearBoundTextures();
+
+  for( int row=0; row<NUM_ROWS; row++)
+  {
+    for( int col=0; col<NUM_COLS; col++)
+    {
+      // col:    0   1   2  | 3   4   5 | 6   7   8
+      //
+      //        -4/3 -1 -2/3 -1/3  0 1/3 |2/3 1  4/3
+      // col*2 -5
+      //         0   2   4
+      // NUM_COLS = 9 NUM_COLS_PER_PANE = 3   (A pane is stage sized)
+      //
+      // NUM_COLS / NUM_COLS_PER_PANE => number of panes
+      // 3 per pane, splits into -1/3, 0, +1/3
+      // number of lh planes * number of cols per plane
+      // Center column maps to zero, index of center column = num_cols / 2 rounded down
+      // index - that  and divide by number of cols per pane.
+      // 0 1 2 3 4  5 6 7 8  9 10 11 12
+      float xOffset = (int)(col - (NUM_COLS/2));
+      float yOffset = (int)(row - (NUM_ROWS/2));
+      float x = stageSize.x*xOffset / (float)(NUM_COLS_PER_PANE);
+      float y = stageSize.y*yOffset / (float)(NUM_ROWS_PER_PANE);
+      actors[row*NUM_COLS+col].SetPosition( x, y, z );
+    }
+  }
+
+  application.SendNotification();
+  application.Render(16);
+
+  DALI_TEST_CHECK( drawTrace.FindMethod( "DrawArrays" ) );
+
+  typedef std::vector<GLuint> TexVec;
+  const TexVec& textures = glAbstraction.GetBoundTextures(GL_TEXTURE0);
+  DALI_TEST_CHECK( textures.size() >= NUM_ROWS_PER_PANE * NUM_COLS_PER_PANE );
+  if( textures.size() > 0 )
+  {
+    int foundCount=0;
+    int expectedCount = 0;
+    for(unsigned int row=0; row<NUM_ROWS; row++)
+    {
+      for(unsigned int col=0; col<NUM_ROWS; col++)
+      {
+        Vector3 pos = actors[row*NUM_COLS+col].GetCurrentPosition();
+        if( -stageSize.x/2.0f <= pos.x && pos.x <= stageSize.x/2.0f &&
+            -stageSize.y/2.0f <= pos.y && pos.y <= stageSize.y/2.0f )
+        {
+          expectedCount++;
+          GLuint texId = (row*NUM_COLS+col)+TEXTURE_ID_OFFSET;
+
+          for(TexVec::const_iterator iter = textures.begin(); iter != textures.end(); iter++)
+          {
+            if(*iter == texId)
+            {
+              foundCount++;
+            }
+          }
+        }
+      }
+    }
+    tet_printf("Number of expected draws: %u\n", expectedCount);
+    DALI_TEST_EQUALS(foundCount, expectedCount, TEST_LOCATION);
+  }
+  int numDrawCalls = drawTrace.CountMethod("DrawArrays");
+  DALI_TEST_CHECK( numDrawCalls >= NUM_ROWS_PER_PANE * NUM_COLS_PER_PANE );
+
+  tet_printf("Number of bound textures: %u\n", textures.size());
+  tet_printf("Number of draw calls: %d\n", numDrawCalls);
+}
+
+} // namespace
+
+int UtcDaliImageCulling_Inside01(void)
+{
+  tet_infoline( "Testing that 80x80 image positioned inside the stage is drawn\n");
+
+  TestApplication application;
+
+  TestImageInside(application, 80, 80);
+
+  END_TEST;
+}
+
+int UtcDaliImageCulling_Inside02(void)
+{
+  tet_infoline( "Testing that 120x40 image positioned inside the stage is drawn\n");
+
+  TestApplication application;
+
+  TestImageInside(application, 120, 40);
+
+  END_TEST;
+}
+
+int UtcDaliImageCulling_Inside03(void)
+{
+  tet_infoline( "Testing that 40x120 image positioned inside the stage is drawn\n");
+
+  TestApplication application;
+
+  TestImageInside(application, 40, 120);
+
+  END_TEST;
+}
+
+int UtcDaliImageCulling_Inside04(void)
+{
+  tet_infoline( "Testing that 500x2 image positioned inside the stage is drawn\n");
+  TestApplication application;
+  TestImageInside(application, 500, 2);
+  END_TEST;
+}
+
+int UtcDaliImageCulling_Inside05(void)
+{
+  tet_infoline( "Testing that 2x500 image positioned inside the stage is drawn\n");
+  TestApplication application;
+  TestImageInside(application, 2, 500);
+  END_TEST;
+}
+
+
+int UtcDaliImageCulling_WithinBoundary01(void)
+{
+  tet_infoline("Test that 80x80 image positioned outside the stage but with bounding box intersecting the stage is drawn\n");
+
+  TestApplication application;
+  OBBTestImageAtBoundary( application, 80, 80);
+  END_TEST;
+}
+int UtcDaliImageCulling_WithinBoundary02(void)
+{
+  tet_infoline("Test that 120x40 image positioned outside the stage but with bounding box intersecting the stage is drawn\n");
+
+  TestApplication application;
+  OBBTestImageAtBoundary( application, 120, 40 );
+  END_TEST;
+}
+int UtcDaliImageCulling_WithinBoundary03(void)
+{
+  tet_infoline("Test that 40x120 image positioned outside the stage but with bounding box intersecting the stage is drawn\n");
+
+  TestApplication application;
+  OBBTestImageAtBoundary( application, 40, 120);
+  END_TEST;
+}
+
+int UtcDaliImageCulling_WithinBoundary04(void)
+{
+  tet_infoline("Test that 500x2 images positioned outside the stage but with bounding box intersecting the stage is drawn\n");
+
+  TestApplication application;
+  OBBTestImageAtBoundary( application, 500, 2 );
+  END_TEST;
+}
+
+int UtcDaliImageCulling_WithinBoundary05(void)
+{
+  tet_infoline("Test that 2x500 images positioned outside the stage but with bounding box intersecting the stage is drawn\n");
+
+  TestApplication application;
+  OBBTestImageAtBoundary( application, 2, 500 );
+  END_TEST;
+}
+
+int UtcDaliImageCulling_OutsideBoundary01(void)
+{
+  tet_infoline("Test that 80x80 image positioned outside the stage by more than 2 times\n"
+               "the radius of the bounding circle  is not drawn\n");
+
+  TestApplication application;
+  OBBTestImageOutsideBoundary( application, 80, 80 );
+  END_TEST;
+}
+
+int UtcDaliImageCulling_OutsideBoundary02(void)
+{
+  tet_infoline("Test that 120x40 image positioned outside the stage by more than 2 times\n"
+               "the radius of the bounding circle  is not drawn\n");
+
+  TestApplication application;
+  OBBTestImageOutsideBoundary( application, 120, 40 );
+  END_TEST;
+}
+int UtcDaliImageCulling_OutsideBoundary03(void)
+{
+  tet_infoline("Test that 40x120 image positioned outside the stage by more than 2 times\n"
+               "the radius of the bounding circle  is not drawn\n");
+
+  TestApplication application;
+  OBBTestImageOutsideBoundary( application, 40, 120 );
+  END_TEST;
+}
+
+int UtcDaliImageCulling_OutsideBoundary04(void)
+{
+  tet_infoline("Test that 500x2 image positioned outside the stage by more than 2 times\n"
+               "the radius of the bounding circle  is not drawn\n");
+
+  TestApplication application;
+  OBBTestImageOutsideBoundary( application, 500, 2 );
+  END_TEST;
+}
+
+int UtcDaliImageCulling_OutsideBoundary05(void)
+{
+  tet_infoline("Test that 2x500 image positioned outside the stage by more than 2 times\n"
+               "the radius of the bounding circle  is not drawn\n");
+
+  TestApplication application;
+  OBBTestImageOutsideBoundary( application, 2, 500 );
+  END_TEST;
+}
+
+int UtcDaliImageCulling_OutsideIntersect01(void)
+{
+  TestApplication application;
+
+  tet_infoline("Test that actors positioned outside the stage with bounding boxes also\n"
+               "outside the stage but intersecting it are still drawn");
+
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = glAbstraction.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+  drawTrace.Enable(true);
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+
+  float width = stageSize.x*5.0f;
+  float height = stageSize.y*0.2f;
+  Image image = LoadImage( application, 23,  width, height);
+  ImageActor imageActor = CreateOnStageActor(application, image, width, height, true);
+
+  RepositionActor( application, imageActor, stageSize.x*1.2f, 0.0f, true);
+  RepositionActor( application, imageActor, stageSize.x*1.2f, -stageSize.y*0.55f, true);
+  RepositionActor( application, imageActor, stageSize.x*1.2f, stageSize.y*0.55f, true);
+  END_TEST;
+}
+
+int UtcDaliImageCulling_OutsideIntersect02(void)
+{
+  TestApplication application;
+
+  tet_infoline("Test that actors positioned outside the stage with bounding boxes also\n"
+               "outside the stage that cross planes are not drawn");
+
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = glAbstraction.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+  drawTrace.Enable(true);
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+
+  float width = stageSize.x*5.0f;
+  float height = stageSize.y*0.2f;
+  Image image = LoadImage( application, 23,  width, height);
+  ImageActor imageActor = CreateOnStageActor(application, image, width, height, true);
+
+  RepositionActor( application, imageActor,  stageSize.x*10.0f,  stageSize.y*0.5f, false);
+  RepositionActor( application, imageActor, -stageSize.x*10.0f,  stageSize.y*0.5f, false);
+  RepositionActor( application, imageActor,  stageSize.x*10.0f, -stageSize.y*0.5f, false);
+  RepositionActor( application, imageActor, -stageSize.x*10.0f, -stageSize.y*0.5f, false);
+  END_TEST;
+}
+
+int UtcDaliImageCulling_OutsideIntersect03(void)
+{
+  TestApplication application;
+
+  tet_infoline("Test that image actor larger than the stage, positioned outside the stage \n"
+               "with bounding boxes also outside the stage but intersecting it is still drawn\n");
+
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = glAbstraction.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+  drawTrace.Enable(true);
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+
+  // Try an actor bigger than the stage, with center outside stage
+  float width = stageSize.x*5.0f;
+  float height = stageSize.y*5.0f;
+  Image image = LoadImage( application, 23,  width, height);
+  ImageActor imageActor = CreateOnStageActor(application, image, width, height, true);
+
+  RepositionActor( application, imageActor, stageSize.x*1.2f, 0.0f, true);
+  RepositionActor( application, imageActor, stageSize.x*1.2f, -stageSize.y*1.1f, true);
+  RepositionActor( application, imageActor, stageSize.x*1.2f, stageSize.y*1.1f, true);
+
+  END_TEST;
+}
+
+int UtcDaliImageCulling_OutsideIntersect04(void)
+{
+  TestApplication application;
+
+  tet_infoline("Test that image actors positioned outside the stage, with bounding boxes\n"
+               "also outside the stage but intersecting it, and angled at 45 degrees to\n"
+               "the corners are still drawn\n");
+
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = glAbstraction.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+  drawTrace.Enable(true);
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+
+  // Test image at 45 degrees outside corners of stage
+  float width = 400.0f;
+  float height = 200.0f;
+  Image image = LoadImage( application, 23,  width, height);
+  ImageActor imageActor = CreateOnStageActor(application, image, width, height, true);
+
+  RepositionActorWithAngle( application, imageActor, -stageSize.x*0.55f, -stageSize.y*0.55, 135.0f, true);
+  RepositionActorWithAngle( application, imageActor, -stageSize.x*0.55f,  stageSize.y*0.55, 225.0f, true);
+  RepositionActorWithAngle( application, imageActor,  stageSize.x*0.55f, -stageSize.y*0.55,  45.0f, true);
+  RepositionActorWithAngle( application, imageActor,  stageSize.x*0.55f,  stageSize.y*0.55, 315.0f, true);
+
+  END_TEST;
+}
+
+int UtcDaliImageCulling_Plane01(void)
+{
+  tet_infoline("Test that a set of image actors with different images are drawn appropriately");
+
+  TestApplication application;
+
+  TestPlaneOfImages(application, 0.0f);
+  END_TEST;
+}
+
+int UtcDaliImageCulling_Plane02(void)
+{
+  tet_infoline("Test that a set of image actors with different images are drawn appropriately");
+
+  TestApplication application;
+
+  TestPlaneOfImages(application, 100.0f);
+  END_TEST;
+}
+
+int UtcDaliImageCulling_Plane03(void)
+{
+  tet_infoline("Test that a set of image actors with different images are drawn appropriately");
+
+  TestApplication application;
+
+  TestPlaneOfImages(application, -100.0f);
+  END_TEST;
+}
+
+int UtcDaliImageCulling_Plane04(void)
+{
+  tet_infoline("Test that a set of image actors with different images are drawn appropriately");
+
+  TestApplication application;
+
+  TestPlaneOfImages(application, -200.0f);
+  END_TEST;
+}
+
+
+
+int UtcDaliImageCulling_Disable(void)
+{
+  tet_infoline("Test that culling can be disabled");
+
+  TestApplication application;
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = glAbstraction.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+  drawTrace.Enable(true);
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  float width=80;
+  float height=80;
+  Image image = LoadImage( application, 23, width, height );
+
+  ImageActor imageActor = CreateOnStageActor(application, image, width, height, true);
+  Vector3 imageSize = imageActor.GetCurrentSize();
+  DALI_TEST_EQUALS( imageSize, Vector3(width, height, std::min(width, height)), TEST_LOCATION);
+
+  imageSize.z = 0.0f;
+  float radius = imageSize.Length() * 0.5f; // Radius of bounding box
+
+  tet_infoline("Setting cull mode to false\n");
+  Stage::GetCurrent().GetRenderTaskList().GetTask(0).SetCullMode(false);
+
+  float x1 = -stageSize.x/2.0f - imageSize.x;
+  float x2 =  stageSize.x/2.0f + imageSize.x;
+  float y1 = -stageSize.y/2.0f - imageSize.y;
+  float y2 =  stageSize.y/2.0f + imageSize.y;
+
+  // Positioning actors well outside stage, with no culling, they should still be drawn.
+  RepositionActorOutside( application, imageActor, x1, y1, true );
+  RepositionActorOutside( application, imageActor, x2, y1, true );
+  RepositionActorOutside( application, imageActor, x1, y2, true );
+  RepositionActorOutside( application, imageActor, x2, y2, true );
+
+  tet_infoline("Setting cull mode to true\n");
+  Stage::GetCurrent().GetRenderTaskList().GetTask(0).SetCullMode(true);
+
+  RepositionActorOutside( application, imageActor, x1, y1, false );
+  RepositionActorOutside( application, imageActor, x2, y1, false );
+  RepositionActorOutside( application, imageActor, x1, y2, false );
+  RepositionActorOutside( application, imageActor, x2, y2, false );
+
+  END_TEST;
+}
index e9a73b7..516c3c4 100644 (file)
@@ -79,7 +79,7 @@ public:
     shaderData->AllocateBuffer(10);
 
     Integration::ResourceId resourceId = 100;
-    program = Internal::Program::New(resourceId, shaderData.Get(), *testContext);
+    program = Internal::Program::New(resourceId, shaderData.Get(), *testContext, true);
     programId = app.GetGlAbstraction().GetLastProgramCreated();
     program->Use();
   }
index 1218c28..45a37ec 100644 (file)
@@ -1045,7 +1045,7 @@ int UtcDaliInternalLoadShaderRequest02(void)
   AddShaderMessage( updateManager, *sceneObject );
 
   size_t shaderHash=0;
-  SetShaderProgramMessage( updateManager, *sceneObject, GEOMETRY_TYPE_IMAGE, Internal::SHADER_DEFAULT, ticket->GetId(), shaderHash );
+  SetShaderProgramMessage( updateManager, *sceneObject, GEOMETRY_TYPE_IMAGE, Internal::SHADER_DEFAULT, ticket->GetId(), shaderHash, true );
 
   DALI_TEST_CHECK( ticket );
 
index 06357b4..a3cbaef 100644 (file)
@@ -130,6 +130,10 @@ public:
         mActiveTextures[ mActiveTextureUnit ].mBoundTextures.push_back( texture );
       }
     }
+
+    std::stringstream out;
+    out << target << ", " << texture;
+    mTextureTrace.PushCall("BindTexture", out.str());
   }
 
   inline void BlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
@@ -472,6 +476,17 @@ public:
         *(textures+i) = ++mLastAutoTextureIdUsed;
       }
     }
+
+    std::stringstream out;
+    for(int i=0; i<n; i++)
+    {
+      out << textures[i];
+      if(i<n-1)
+      {
+        out << ", ";
+      }
+    }
+    mTextureTrace.PushCall("GenTexture", out.str());
   }
 
   inline void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
index 9ed53ec..921088b 100644 (file)
@@ -34,6 +34,8 @@ TraceCallStack::~TraceCallStack() { }
  */
 void TraceCallStack::Enable(bool enable) { mTraceActive = enable; }
 
+bool TraceCallStack::IsEnabled() { return mTraceActive; }
+
 /**
  * Push a call onto the stack if the trace is active
  * @param[in] method The name of the method
@@ -69,6 +71,20 @@ bool TraceCallStack::FindMethod(std::string method) const
   return found;
 }
 
+int TraceCallStack::CountMethod(std::string method) const
+{
+  int numCalls = 0;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i][0].compare(method) )
+    {
+      numCalls++;
+    }
+  }
+  return numCalls;
+}
+
+
 /**
  * Search for a method in the stack with the given parameter list
  * @param[in] method The name of the method
index 3dd6065..25b77f8 100644 (file)
@@ -45,6 +45,8 @@ public:
    */
   void Enable(bool enable);
 
+  bool IsEnabled();
+
   /**
    * Push a call onto the stack if the trace is active
    * @param[in] method The name of the method
@@ -61,6 +63,13 @@ public:
   bool FindMethod(std::string method) const;
 
   /**
+   * Count how many times a method was called
+   * @param[in] method The name of the method
+   * @return The number of times it was called
+   */
+  int CountMethod(std::string method) const;
+
+  /**
    * Search for a method in the stack with the given parameter list
    * @param[in] method The name of the method
    * @param[in] params A comma separated list of parameter values
index ebeb7ff..aef6daa 100644 (file)
@@ -130,6 +130,7 @@ public:
   static const bool         DEFAULT_INPUT_ENABLED; ///< true
   static const Vector4      DEFAULT_CLEAR_COLOR;   ///< Color::BLACK
   static const bool         DEFAULT_CLEAR_ENABLED; ///< false
+  static const bool         DEFAULT_CULL_MODE;     ///< true
   static const unsigned int DEFAULT_REFRESH_RATE;  ///< REFRESH_ALWAYS
 
   /**
@@ -338,6 +339,22 @@ public:
   bool GetClearEnabled() const;
 
   /**
+   * @brief Set whether the render task will cull the actors to the camera's view frustum.
+   *
+   * Note that this will only affect image actors that use the default vertex shader.
+   * The default mode is to cull actors.
+   * @param[in] cullMode True if the renderers should be culled.
+   */
+  void SetCullMode( bool cullMode );
+
+  /**
+   * @brief Get the cull mode.
+   *
+   * @return True if the render task should cull the actors to the camera's view frustum
+   */
+  bool GetCullMode() const;
+
+  /**
    * @brief Set the refresh-rate of the RenderTask.
    *
    * The default is REFRESH_ALWAYS (1), meaning that the RenderTask will be processed every frame.
index a1068ae..13c67bb 100644 (file)
@@ -457,6 +457,94 @@ private:
 
 /**
  * Templated message which calls a member function of an object.
+ * This overload passes six value-type parameters.
+ * Template parameters need to match the MemberFunction!
+ * The message will contain copy of the value (in case of & or const&)
+ */
+template< typename T, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6 >
+class MessageValue6 : public MessageBase
+{
+public:
+
+  typedef void(T::*MemberFunction)(
+      typename ParameterType< P1 >::PassingType,
+      typename ParameterType< P2 >::PassingType,
+      typename ParameterType< P3 >::PassingType,
+      typename ParameterType< P4 >::PassingType,
+      typename ParameterType< P5 >::PassingType,
+      typename ParameterType< P6 >::PassingType );
+
+  /**
+   * Create a message.
+   * @note The object is expected to be const in the thread which sends this message.
+   * However it can be modified when Process() is called in a different thread.
+   * @param[in] obj The object.
+   * @param[in] member The member function of the object.
+   * @param[in] p1 The first parameter to pass to the member function.
+   * @param[in] p2 The second parameter to pass to the member function.
+   * @param[in] p3 The third parameter to pass to the member function.
+   * @param[in] p4 The fourth parameter to pass to the member function.
+   * @param[in] p5 The fifth parameter to pass to the member function.
+   * @param[in] p6 The sixth parameter to pass to the member function.
+   */
+  MessageValue6( const T* obj,
+                 MemberFunction member,
+                 typename ParameterType< P1 >::PassingType p1,
+                 typename ParameterType< P2 >::PassingType p2,
+                 typename ParameterType< P3 >::PassingType p3,
+                 typename ParameterType< P4 >::PassingType p4,
+                 typename ParameterType< P5 >::PassingType p5,
+                 typename ParameterType< P6 >::PassingType p6 )
+  : MessageBase(),
+    object( const_cast< T* >( obj ) ),
+    memberFunction( member ),
+    param1( p1 ),
+    param2( p2 ),
+    param3( p3 ),
+    param4( p4 ),
+    param5( p5 ),
+    param6( p6 )
+  {
+  }
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~MessageValue6()
+  {
+  }
+
+  /**
+   * @copydoc MessageBase::Process
+   */
+  virtual void Process( BufferIndex /*bufferIndex*/ )
+  {
+    DALI_ASSERT_DEBUG( object && "Message does not have an object" );
+    (object->*memberFunction)(
+        ParameterType< P1 >::PassObject( param1 ),
+        ParameterType< P2 >::PassObject( param2 ),
+        ParameterType< P3 >::PassObject( param3 ),
+        ParameterType< P4 >::PassObject( param4 ),
+        ParameterType< P5 >::PassObject( param5 ),
+        ParameterType< P6 >::PassObject( param6 ) );
+
+  }
+
+private:
+
+  T* object;
+  MemberFunction memberFunction;
+  typename ParameterType< P1 >::HolderType param1;
+  typename ParameterType< P2 >::HolderType param2;
+  typename ParameterType< P3 >::HolderType param3;
+  typename ParameterType< P4 >::HolderType param4;
+  typename ParameterType< P5 >::HolderType param5;
+  typename ParameterType< P6 >::HolderType param6;
+
+};
+
+/**
+ * Templated message which calls a member function of an object.
  * This overload passes a value-type to set a double-buffered property.
  * Template parameters need to match the MemberFunction!
  * The message will contain copy of the value (in case of & or const&)
index 537ca4e..163a15c 100644 (file)
@@ -454,7 +454,8 @@ const Dali::ShaderEffect::Extension& ShaderEffect::GetExtension() const
 }
 
 void ShaderEffect::SetProgram( GeometryType geometryType, ShaderSubTypes subType,
-                               const std::string& vertexSource, const std::string& fragmentSource )
+                               const std::string& vertexSource, const std::string& fragmentSource,
+                               ShaderEffect::FixedVertexShader fixedShader )
 {
   // Load done asynchronously in update thread. SetProgram message below must be processed afterwards.
   // Therefore, resource manager cannot farm out the loading to the adaptor resource threads,
@@ -464,8 +465,9 @@ void ShaderEffect::SetProgram( GeometryType geometryType, ShaderSubTypes subType
 
   DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "ShaderEffect: SetProgram(geometryType %d subType:%d ticket.id:%d)\n", geometryType, subType, ticket->GetId() );
 
+  bool areVerticesFixed = (fixedShader == ShaderEffect::FIXED);
   // Add shader program to scene-object using a message to the UpdateManager
-  SetShaderProgramMessage( mUpdateManager, *mSceneObject, geometryType, subType, ticket->GetId(), shaderHash );
+  SetShaderProgramMessage( mUpdateManager, *mSceneObject, geometryType, subType, ticket->GetId(), shaderHash, areVerticesFixed );
 
   mTickets.push_back(ticket);       // add ticket to collection to keep it alive.
 }
@@ -473,11 +475,12 @@ void ShaderEffect::SetProgram( GeometryType geometryType, ShaderSubTypes subType
 
 void ShaderEffect::SetProgram( GeometryType geometryType, ShaderSubTypes subType,
                                const std::string& vertexPrefix, const std::string& fragmentPrefix,
-                               const std::string& vertexSource, const std::string& fragmentSource )
+                               const std::string& vertexSource, const std::string& fragmentSource,
+                               ShaderEffect::FixedVertexShader fixedShader )
 {
   const std::string vertex( vertexPrefix + vertexSource );
   const std::string fragment( fragmentPrefix + fragmentSource );
-  SetProgram( geometryType, subType, vertex, fragment );
+  SetProgram( geometryType, subType, vertex, fragment, fixedShader );
 }
 
 void ShaderEffect::Connect()
index b9b3a2a..fcd62df 100644 (file)
@@ -146,6 +146,12 @@ public:
    */
   const Dali::ShaderEffect::Extension& GetExtension() const;
 
+  enum FixedVertexShader
+  {
+    FLEXIBLE,
+    FIXED,
+  };
+
   /**
    * Add a GeometryType specific default program to this ShaderEffect
    * @param[in] geometryType    The GeometryType rendered by the shader program
@@ -154,7 +160,8 @@ public:
    * @param[in] fragmentSource  The source code for the fragment shader
    */
   void SetProgram( GeometryType geometryType, ShaderSubTypes subType,
-                   const std::string& vertexSource, const std::string& fragmentSource );
+                   const std::string& vertexSource, const std::string& fragmentSource,
+                   FixedVertexShader fixedVertexShader=FLEXIBLE);
 
   /**
    * Add a GeometryType specific default program to this ShaderEffect.
@@ -166,10 +173,12 @@ public:
    * @param[in] fragmentPrefix  The prefix source code for the fragment shader
    * @param[in] vertexSource    The source code for the vertex shader
    * @param[in] fragmentSource  The source code for the fragment shader
+   * @param[in] fixedVertexShader True if this shader doesn't change the vertices
    */
   void SetProgram( GeometryType geometryType, ShaderSubTypes subType,
                    const std::string& vertexPrefix, const std::string& fragmentPrefix,
-                   const std::string& vertexSource, const std::string& fragmentSource );
+                   const std::string& vertexSource, const std::string& fragmentSource,
+                   FixedVertexShader fixedVertexShader=FLEXIBLE);
 
   /**
    * Notify ShaderEffect that it's being used by an Actor.
index 06d2e94..24ae9f2 100644 (file)
@@ -113,9 +113,9 @@ void ShaderFactory::LoadDefaultShaders()
 {
   mDefaultShader = ShaderEffect::New();
 
-  mDefaultShader->SetProgram( GEOMETRY_TYPE_IMAGE, SHADER_DEFAULT, FlatColorTextureVertex, FlatColorTextureFragment );
+  mDefaultShader->SetProgram( GEOMETRY_TYPE_IMAGE, SHADER_DEFAULT, FlatColorTextureVertex, FlatColorTextureFragment, ShaderEffect::FIXED );
 
-  mDefaultShader->SetProgram( GEOMETRY_TYPE_TEXT, SHADER_DEFAULT, DistanceFieldFontVertex, DistanceFieldFontFragment );
+  mDefaultShader->SetProgram( GEOMETRY_TYPE_TEXT, SHADER_DEFAULT, DistanceFieldFontVertex, DistanceFieldFontFragment, ShaderEffect::FIXED );
 
   LoadTextSubtypeShaders(mDefaultShader); // TODO: Remove when applications no longer need these shaders
 
@@ -123,54 +123,64 @@ void ShaderFactory::LoadDefaultShaders()
   mDefaultShader->SetProgram( GEOMETRY_TYPE_MESH, SHADER_DEFAULT,
                               "", // Vertex shader defs
                               SHADER_DEF_USE_LIGHTING, // fragment shader defs
-                              MeshColorNoTextureVertex, MeshColorNoTextureFragment );
+                              MeshColorNoTextureVertex, MeshColorNoTextureFragment,
+                              ShaderEffect::FIXED );
 
   mDefaultShader->SetProgram(GEOMETRY_TYPE_MESH, SHADER_EVENLY_LIT,
                              "", // Vertex shader defs
                              "", // fragment shader defs
-                             MeshColorNoTextureVertex, MeshColorNoTextureFragment);
+                             MeshColorNoTextureVertex, MeshColorNoTextureFragment,
+                             ShaderEffect::FIXED );
 
   mDefaultShader->SetProgram(GEOMETRY_TYPE_MESH, SHADER_RIGGED_AND_LIT,
                              SHADER_DEF_USE_BONES,    // vertex shader defs
                              SHADER_DEF_USE_LIGHTING, // fragment shader defs
-                             MeshColorNoTextureVertex, MeshColorNoTextureFragment);
+                             MeshColorNoTextureVertex, MeshColorNoTextureFragment,
+                             ShaderEffect::FLEXIBLE);
 
   mDefaultShader->SetProgram(GEOMETRY_TYPE_MESH, SHADER_RIGGED_AND_EVENLY_LIT,
                              SHADER_DEF_USE_BONES, // Vertex shader defs
                              "",                   // Fragment shader defs
-                             MeshColorNoTextureVertex, MeshColorNoTextureFragment);
+                             MeshColorNoTextureVertex, MeshColorNoTextureFragment,
+                             ShaderEffect::FLEXIBLE);
 
   mDefaultShader->SetProgram(GEOMETRY_TYPE_MESH, SHADER_RIGGED_AND_VERTEX_COLOR,
                              (SHADER_DEF_USE_BONES SHADER_DEF_USE_COLOR), // Vertex shader defs
                              SHADER_DEF_USE_COLOR,                        // Fragment shader defs
-                             MeshColorNoTextureVertex, MeshColorNoTextureFragment);
+                             MeshColorNoTextureVertex, MeshColorNoTextureFragment,
+                             ShaderEffect::FLEXIBLE);
 
   mDefaultShader->SetProgram(GEOMETRY_TYPE_MESH, SHADER_VERTEX_COLOR,
                              SHADER_DEF_USE_COLOR,  // Vertex shader defs
                              SHADER_DEF_USE_COLOR,  // Fragment shader defs
-                             MeshColorNoTextureVertex, MeshColorNoTextureFragment);
+                             MeshColorNoTextureVertex, MeshColorNoTextureFragment,
+                             ShaderEffect::FIXED);
 
   // Textured meshes
   mDefaultShader->SetProgram( GEOMETRY_TYPE_TEXTURED_MESH, SHADER_DEFAULT,
                               "",                      // Vertex shader defs
                               SHADER_DEF_USE_LIGHTING, // fragment shader defs
-                              MeshVertex, MeshFragment );
+                              MeshVertex, MeshFragment,
+                              ShaderEffect::FIXED);
 
 
   mDefaultShader->SetProgram(GEOMETRY_TYPE_TEXTURED_MESH, SHADER_EVENLY_LIT,
                              "",                      // Vertex shader defs
                              "",                      // Fragment shader defs
-                             MeshVertex, MeshFragment);
+                             MeshVertex, MeshFragment,
+                             ShaderEffect::FIXED);
 
   mDefaultShader->SetProgram(GEOMETRY_TYPE_TEXTURED_MESH, SHADER_RIGGED_AND_LIT,
                              SHADER_DEF_USE_BONES,    // Vertex shader defs
                              SHADER_DEF_USE_LIGHTING, // Fragment shader defs
-                             MeshVertex, MeshFragment);
+                             MeshVertex, MeshFragment,
+                             ShaderEffect::FLEXIBLE);
 
   mDefaultShader->SetProgram(GEOMETRY_TYPE_TEXTURED_MESH, SHADER_RIGGED_AND_EVENLY_LIT,
                              SHADER_DEF_USE_BONES, // Vertex shader defs
                              "",                   // Fragment shader defs
-                             MeshVertex, MeshFragment);
+                             MeshVertex, MeshFragment,
+                             ShaderEffect::FLEXIBLE);
 }
 
 void ShaderFactory::LoadTextSubtypeShaders(ShaderEffectPtr shaderEffect)
@@ -180,13 +190,13 @@ void ShaderFactory::LoadTextSubtypeShaders(ShaderEffectPtr shaderEffect)
                              SHADER_DEF_USE_GRADIENT,
                              DistanceFieldFontVertex, DistanceFieldFontFragment);
 
-  shaderEffect->SetProgram(GEOMETRY_TYPE_TEXT, SHADER_GRADIENT_GLOW, DistanceFieldFontGlowVertex, DistanceFieldFontGlowFragment);
+  shaderEffect->SetProgram(GEOMETRY_TYPE_TEXT, SHADER_GRADIENT_GLOW, DistanceFieldFontGlowVertex, DistanceFieldFontGlowFragment, ShaderEffect::FIXED);
 
-  shaderEffect->SetProgram(GEOMETRY_TYPE_TEXT, SHADER_GRADIENT_SHADOW, DistanceFieldFontShadowVertex, DistanceFieldFontShadowFragment);
+  shaderEffect->SetProgram(GEOMETRY_TYPE_TEXT, SHADER_GRADIENT_SHADOW, DistanceFieldFontShadowVertex, DistanceFieldFontShadowFragment, ShaderEffect::FIXED);
 
-  shaderEffect->SetProgram(GEOMETRY_TYPE_TEXT, SHADER_GRADIENT_OUTLINE, DistanceFieldFontOutlineVertex, DistanceFieldFontOutlineFragment);
+  shaderEffect->SetProgram(GEOMETRY_TYPE_TEXT, SHADER_GRADIENT_OUTLINE, DistanceFieldFontOutlineVertex, DistanceFieldFontOutlineFragment, ShaderEffect::FIXED);
 
-  shaderEffect->SetProgram(GEOMETRY_TYPE_TEXT, SHADER_GRADIENT_OUTLINE_GLOW, DistanceFieldFontOutlineGlowVertex, DistanceFieldFontOutlineGlowFragment);
+  shaderEffect->SetProgram(GEOMETRY_TYPE_TEXT, SHADER_GRADIENT_OUTLINE_GLOW, DistanceFieldFontOutlineGlowVertex, DistanceFieldFontOutlineGlowFragment, ShaderEffect::FIXED);
 }
 
 
index c28429b..85b6e49 100644 (file)
@@ -285,6 +285,25 @@ bool RenderTask::GetClearEnabled() const
   return mClearEnabled;
 }
 
+void RenderTask::SetCullMode( bool mode )
+{
+  if ( mCullMode != mode )
+  {
+    mCullMode = mode;
+
+    if ( mSceneObject )
+    {
+      // mSceneObject is being used in a separate thread; queue a message to set the value
+      SetCullModeMessage( mEventToUpdate, *mSceneObject, mCullMode );
+    }
+  }
+}
+
+bool RenderTask::GetCullMode() const
+{
+  return mCullMode;
+}
+
 void RenderTask::SetRefreshRate( unsigned int refreshRate )
 {
   DALI_LOG_TRACE_METHOD_FMT(gLogRender, "this:%p  rate:%d\n", this, refreshRate);
@@ -405,6 +424,7 @@ SceneGraph::RenderTask* RenderTask::CreateSceneObject()
   SetExclusiveMessage( mEventToUpdate, *mSceneObject, mExclusive );
   SetClearColorMessage(  mEventToUpdate, *mSceneObject, mClearColor );
   SetClearEnabledMessage(  mEventToUpdate, *mSceneObject, mClearEnabled );
+  SetCullModeMessage(  mEventToUpdate, *mSceneObject, mCullMode );
   SetRefreshRateMessage(  mEventToUpdate, *mSceneObject, mRefreshRate );
 
   // Caller takes ownership
@@ -721,6 +741,7 @@ RenderTask::RenderTask( EventToUpdate& eventToUpdate, bool isSystemLevel )
   mExclusive( Dali::RenderTask::DEFAULT_EXCLUSIVE ),
   mInputEnabled( Dali::RenderTask::DEFAULT_INPUT_ENABLED ),
   mClearEnabled( Dali::RenderTask::DEFAULT_CLEAR_ENABLED ),
+  mCullMode( Dali::RenderTask::DEFAULT_CULL_MODE ),
   mIsSystemLevel( isSystemLevel )
 {
   DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::RenderTask(this:%p)\n", this);
index 0a549e6..d14746e 100644 (file)
@@ -172,6 +172,16 @@ public:
   bool GetClearEnabled() const;
 
   /**
+   * @copydoc Dali::RenderTask::SetCullMode()
+   */
+  void SetCullMode( bool mode );
+
+  /**
+   * @copydoc Dali::RenderTask::GetCullMode()
+   */
+  bool GetCullMode() const;
+
+  /**
    * @copydoc Dali::RenderTask::SetRefreshRate()
    */
   void SetRefreshRate( unsigned int refreshRate );
@@ -441,6 +451,7 @@ private:
   bool mExclusive     : 1; ///< True if the render-task has exclusive access to the source Nodes.
   bool mInputEnabled  : 1; ///< True if the render-task should be considered for input handling.
   bool mClearEnabled  : 1; ///< True if the render-task should be clear the color buffer.
+  bool mCullMode      : 1; ///< True if the render-task's actors should be culled
   bool mIsSystemLevel : 1; ///< True if the render-task is on the system level task list.
 
   // Default properties
index 3c1cce6..e18e9e2 100644 (file)
@@ -47,13 +47,15 @@ namespace Render
  * @param[in] frameTime The elapsed time between the last two updates.
  * @param[in] viewMatrix The view matrix from the appropriate camera.
  * @param[in] projectionMatrix The projection matrix from the appropriate camera.
+ * @param[in] cullMode True if the renderers should be subjected to clipspace culling
  */
 inline void ProcessRenderList( const RenderList& renderList,
                                Context& context,
                                BufferIndex bufferIndex,
                                float frameTime,
                                const Matrix& viewMatrix,
-                               const Matrix& projectionMatrix )
+                               const Matrix& projectionMatrix,
+                               bool cullMode )
 {
   DALI_PRINT_RENDER_LIST( renderList );
 
@@ -114,7 +116,7 @@ inline void ProcessRenderList( const RenderList& renderList,
     SceneGraph::Renderer* renderer = const_cast< SceneGraph::Renderer* >( item.GetRenderer() );
     const Matrix& modelViewMatrix = item.GetModelViewMatrix();
 
-    renderer->Render( bufferIndex, modelViewMatrix, viewMatrix, projectionMatrix, frameTime );
+    renderer->Render( bufferIndex, modelViewMatrix, viewMatrix, projectionMatrix, frameTime, cullMode );
   }
 }
 
@@ -142,7 +144,7 @@ void ProcessRenderInstruction( const RenderInstruction& instruction,
       if(  renderList &&
           !renderList->IsEmpty() )
       {
-        ProcessRenderList( *renderList, context, bufferIndex, frameTime, *viewMatrix, *projectionMatrix );
+        ProcessRenderList( *renderList, context, bufferIndex, frameTime, *viewMatrix, *projectionMatrix, instruction.mCullMode );
       }
     }
   }
index dc1d4f6..f2e5637 100644 (file)
@@ -133,6 +133,24 @@ void PrintRenderItem( const SceneGraph::RenderItem& item )
   DALI_LOG_RENDER_INFO( "         %s\n", debugString.c_str() );
 }
 
+void PrintRendererCount( unsigned int frameCount, unsigned int rendererCount )
+{
+  if( frameCount % 120 == 30 ) // Print every 2 seconds reg
+  {
+    Debug::LogMessage( Debug::DebugInfo, "ImageRenderer Total # renderers: %u\n", rendererCount );
+  }
+}
+
+void PrintCullCount( unsigned int frameCount, unsigned int culledCount )
+{
+  if( frameCount % 120 == 30 ) // Print every 2 seconds reg
+  {
+    Debug::LogMessage( Debug::DebugInfo, "ImageRenderer # Culled renderers: %u\n", culledCount );
+  }
+}
+
+
+
 } // Render
 
 } // Internal
index e5689e0..d37deaf 100644 (file)
 
 #endif // DALI_PRINT_RENDER_INFO
 
+#undef DALI_PRINT_RENDERERS
+
+// Turn this on to see a snapshot of # renderers and # culled renderers every 2 seconds
+//#define DALI_PRINT_RENDERERS 1
+
+#ifdef DALI_PRINT_RENDERERS
+#define DALI_PRINT_RENDERER_COUNT(x, y)  Render::PrintRendererCount(x, y)
+#define DALI_PRINT_CULL_COUNT(x, y)      Render::PrintCullCount(x, y)
+#else // DALI_PRINT_RENDERERS
+#define DALI_PRINT_RENDERER_COUNT(x, y)
+#define DALI_PRINT_CULL_COUNT(x, y)
+#endif // DALI_PRINT_RENDERERS
+
+
 namespace Dali
 {
 
@@ -89,6 +103,20 @@ void PrintRenderList( const SceneGraph::RenderList& list );
  */
 void PrintRenderItem( const SceneGraph::RenderItem& item );
 
+/**
+ * Print the number of culled renderers
+ * @param[in] frameCount The frame counter
+ * @param[in] culledCount The number of culled renderers
+ */
+void PrintCullCount( unsigned int frameCount, unsigned int culledCount );
+
+/**
+ * Print the number of image renderers
+ * @param[in] frameCount The frame counter
+ * @param[in] rendererCount The number of image renderers
+ */
+void PrintRendererCount( unsigned int frameCount, unsigned int rendererCount );
+
 } // Render
 
 } // Internal
index 0d7544d..714177e 100644 (file)
@@ -38,6 +38,7 @@ RenderInstruction::RenderInstruction()
   mClearColor(),
   mIsViewportSet( false ),
   mIsClearColorSet( false ),
+  mCullMode(false),
   mOffscreenTextureId( 0 ),
   mNextFreeRenderList( 0 )
 {
@@ -101,7 +102,7 @@ void RenderInstruction::Reset( const Matrix*   viewMatrix,
                                const Matrix*   projectionMatrix,
                                unsigned int    offscreenTextureId,
                                const Viewport* viewport,
-                               const Vector4*  clearColor )
+                               const Vector4*  clearColor)
 {
   mViewMatrix = viewMatrix;
   mProjectionMatrix = projectionMatrix;
@@ -109,6 +110,7 @@ void RenderInstruction::Reset( const Matrix*   viewMatrix,
   mIsViewportSet = NULL != viewport;
   mClearColor = clearColor ? *clearColor : Color::BLACK;
   mIsClearColorSet = NULL != clearColor;
+  mCullMode = false;
   mOffscreenTextureId = offscreenTextureId;
   mRenderTracker = NULL;
   mNextFreeRenderList = 0;
index 8539e81..a1ce9ee 100644 (file)
@@ -115,6 +115,7 @@ public: // Data, TODO hide these
   Vector4  mClearColor;                 ///< Optional color to clear with
   bool     mIsViewportSet:1;            ///< Flag to determine whether the viewport is set
   bool     mIsClearColorSet:1;          ///< Flag to determine whether the clear-color is set
+  bool     mCullMode:1;                 ///< True if renderers should be frustum culled
 
   unsigned int mOffscreenTextureId;     ///< Optional offscreen target
 
index d0f3b54..db84631 100644 (file)
@@ -333,7 +333,6 @@ void RenderManager::RemoveRenderTracker( RenderTracker* renderTracker )
   mImpl->RemoveRenderTracker(renderTracker);
 }
 
-
 bool RenderManager::Render( Integration::RenderStatus& status )
 {
   DALI_PRINT_RENDER_START( mImpl->renderBufferIndex );
@@ -345,6 +344,9 @@ bool RenderManager::Render( Integration::RenderStatus& status )
 
   // Increment the frame count at the beginning of each frame
   ++(mImpl->frameCount);
+  mImpl->context.SetFrameCount(mImpl->frameCount);
+  mImpl->context.ClearRendererCount();
+  mImpl->context.ClearCulledCount();
 
   PERF_MONITOR_START(PerformanceMonitor::DRAW_NODES);
 
@@ -427,6 +429,9 @@ bool RenderManager::Render( Integration::RenderStatus& status )
 
   DALI_PRINT_RENDER_END();
 
+  DALI_PRINT_RENDERER_COUNT(mImpl->frameCount, mImpl->context.GetRendererCount());
+  DALI_PRINT_CULL_COUNT(mImpl->frameCount, mImpl->context.GetCulledCount());
+
   return updateRequired;
 }
 
index 671e838..369545a 100644 (file)
@@ -57,7 +57,6 @@ class Program; // to be able to cache programs
 class Context
 {
 public:
-
   /**
    * Size of the VertexAttributeArray enables
    * GLES specification states that there's minimum of 8
@@ -1674,6 +1673,72 @@ public:
 
 #endif // DEBUG_ENABLED
 
+
+  /**
+   * Set the frame count of render thread
+   */
+  inline void SetFrameCount(unsigned int frameCount)
+  {
+    mFrameCount = frameCount;
+  }
+
+  /**
+   * Get the frame count
+   */
+  inline unsigned int GetFrameCount()
+  {
+    return mFrameCount;
+  }
+
+  /**
+   * Increment the count of culled renderers
+   */
+  inline void IncrementCulledCount()
+  {
+    mCulledCount++;
+  }
+
+  /**
+   * Clear the count of culled renderers
+   */
+  inline void ClearCulledCount()
+  {
+    mCulledCount = 0;
+  }
+
+  /**
+   * Get the count of culled renderers in this frame
+   */
+  inline unsigned int GetCulledCount()
+  {
+    return mCulledCount;
+  }
+
+  /**
+   * Increment the count of culled renderers
+   */
+  inline void IncrementRendererCount()
+  {
+    mRendererCount++;
+  }
+
+  /**
+   * Clear the count of image renderers
+   */
+  inline void ClearRendererCount()
+  {
+    mRendererCount = 0;
+  }
+
+  /**
+   * Get the count of image renderers in this frame
+   */
+  inline unsigned int GetRendererCount()
+  {
+    return mRendererCount;
+  }
+
+
 private: // Implementation
 
   /**
@@ -1759,8 +1824,10 @@ private: // Data
 
   Program* mCurrentProgram;
   typedef std::map< std::size_t, Program* > ProgramContainer;
-  ProgramContainer mProgramCache; /// program cache
-
+  ProgramContainer mProgramCache; ///< Cache of shader programs
+  unsigned int mFrameCount;       ///< Number of render frames
+  unsigned int mCulledCount;      ///< Number of culled renderers per frame
+  unsigned int mRendererCount;    ///< Number of image renderers per frame
 };
 
 } // namespace Internal
index ef4bee2..c4d5493 100644 (file)
@@ -219,11 +219,28 @@ bool ImageRenderer::CheckResources()
   return true;
 }
 
-void ImageRenderer::DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color )
+void ImageRenderer::GetGeometryTypes( BufferIndex bufferIndex, GeometryType& outType, ShaderSubTypes& outSubType )
+{
+  outType = GEOMETRY_TYPE_IMAGE;
+  outSubType = SHADER_DEFAULT;
+}
+
+
+void ImageRenderer::DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color, bool cullTest )
 {
   DALI_ASSERT_DEBUG( 0 != mTextureId && "ImageRenderer::DoRender. mTextureId == 0." );
   DALI_ASSERT_DEBUG( NULL != mTexture && "ImageRenderer::DoRender. mTexture == NULL." );
 
+  mContext->IncrementRendererCount();
+  if( cullTest )
+  {
+    if(IsOutsideClipSpace(modelMatrix) )
+    {
+      mContext->IncrementCulledCount();
+      return;
+    }
+  }
+
   if(! mIsMeshGenerated )
   {
     GenerateMeshData( mTexture );
@@ -804,6 +821,138 @@ ImageRenderer::ImageRenderer( RenderDataProvider& dataprovider )
 {
 }
 
+// Frustum culling using clip space and oriented bounding box checks
+bool ImageRenderer::IsOutsideClipSpace(const Matrix& modelMatrix)
+{
+  // First, calculate if the center is inside clip space:
+
+  // Downside is mvp matrix calc per renderer per frame
+  // and up to 4 matrix * vector calls.
+  const Matrix& mvp = mShader->GetMVPMatrix();
+  Vector4 translation = mvp.GetTranslation();
+
+  // Upside is point test is very simple:
+  if( -translation.w <= translation.x  &&  translation.x <= translation.w &&
+      -translation.w <= translation.y  &&  translation.y <= translation.w &&
+      -translation.w <= translation.z  &&  translation.z <= translation.w)
+  {
+    // Definitely inside clip space - don't do any more processing
+    return false;
+  }
+
+  // Transform oriented bounding box to clip space:
+  Vector4 topLeft(    mGeometrySize.x * -0.5f, mGeometrySize.y * -0.5f, 0.0f, 1.0f);
+  Vector4 topRight(   mGeometrySize.x *  0.5f, mGeometrySize.y * -0.5f, 0.0f, 1.0f);
+  Vector4 bottomLeft( mGeometrySize.x * -0.5f, mGeometrySize.y *  0.5f, 0.0f, 1.0f);
+  Vector4 bottomRight(mGeometrySize.x *  0.5f, mGeometrySize.y *  0.5f, 0.0f, 1.0f);
+
+  Vector4 topLeftClip = mvp * topLeft;
+  if( -topLeftClip.w <= topLeftClip.x && topLeftClip.x <= topLeftClip.w &&
+      -topLeftClip.w <= topLeftClip.y && topLeftClip.y <= topLeftClip.w &&
+      -topLeftClip.w <= topLeftClip.z && topLeftClip.z <= topLeftClip.w )
+  {
+    // Definitely inside clip space - don't do any more processing
+    return false;
+  }
+
+  Vector4 bottomRightClip = mvp * bottomRight;
+  if( -bottomRightClip.w <= bottomRightClip.x && bottomRightClip.x <= bottomRightClip.w &&
+      -bottomRightClip.w <= bottomRightClip.y && bottomRightClip.y <= bottomRightClip.w &&
+      -bottomRightClip.w <= bottomRightClip.z && bottomRightClip.z <= bottomRightClip.w )
+  {
+    // Definitely inside clip space - don't do any more processing
+    return false;
+  }
+
+  Vector4 topRightClip = mvp * topRight;
+  if( -topRightClip.w <= topRightClip.x && topRightClip.x <= topRightClip.w &&
+      -topRightClip.w <= topRightClip.y && topRightClip.y <= topRightClip.w &&
+      -topRightClip.w <= topRightClip.z && topRightClip.z <= topRightClip.w )
+  {
+    // Definitely inside clip space - don't do any more processing
+    return false;
+  }
+
+  Vector4 bottomLeftClip = mvp * bottomLeft;
+  if( -bottomLeftClip.w <= bottomLeftClip.x && bottomLeftClip.x <= bottomLeftClip.w &&
+      -bottomLeftClip.w <= bottomLeftClip.y && bottomLeftClip.y <= bottomLeftClip.w &&
+      -bottomLeftClip.w <= bottomLeftClip.z && bottomLeftClip.z <= bottomLeftClip.w )
+  {
+    // Definitely inside clip space - don't do any more processing
+    return false;
+  }
+
+  // Check to see if all four points are outside each plane (AABB would cut this processing
+  // in half)
+
+  unsigned int insideLeftPlaneCount=0;
+  unsigned int insideRightPlaneCount=0;
+  unsigned int insideTopPlaneCount=0;
+  unsigned int insideBottomPlaneCount=0;
+
+  if(-topLeftClip.w <= topLeftClip.x) { insideLeftPlaneCount++; }
+  if(-topRightClip.w <= topRightClip.x){ insideLeftPlaneCount++; }
+  if(-bottomRightClip.w <= bottomRightClip.x) {insideLeftPlaneCount++;}
+  if(-bottomLeftClip.w <= bottomLeftClip.x) {insideLeftPlaneCount++;}
+
+  if( insideLeftPlaneCount == 0 )
+  {
+    return true;
+  }
+
+  if(topLeftClip.x <= topLeftClip.w) { insideRightPlaneCount++;}
+  if(topRightClip.x <= topRightClip.w) { insideRightPlaneCount++; }
+  if(bottomRightClip.x <= bottomRightClip.w) { insideRightPlaneCount++; }
+  if(bottomLeftClip.x <= bottomLeftClip.w ) { insideRightPlaneCount++; }
+
+  if( insideRightPlaneCount == 0 )
+  {
+    return true;
+  }
+
+  if(-topLeftClip.w <= topLeftClip.y ) {insideTopPlaneCount++; }
+  if(-topRightClip.w <= topRightClip.y) {insideTopPlaneCount++; }
+  if(-bottomRightClip.w <= bottomRightClip.y) {insideTopPlaneCount++;}
+  if(-bottomLeftClip.w <= bottomLeftClip.y) { insideTopPlaneCount++;}
+
+  if( insideTopPlaneCount == 0 )
+  {
+    return true;
+  }
+
+  if(topLeftClip.y <= topLeftClip.w) { insideBottomPlaneCount++; }
+  if(topRightClip.y <= topRightClip.w) { insideBottomPlaneCount++; }
+  if(bottomRightClip.y <= bottomRightClip.w) { insideBottomPlaneCount++; }
+  if(bottomLeftClip.y <= bottomLeftClip.w) { insideBottomPlaneCount++; }
+
+  if( insideBottomPlaneCount == 0 )
+  {
+    return true;
+  }
+
+  // Test if any planes are bisected, if they are, then there is likely to
+  // be an intersection into clip space.
+
+  if( insideLeftPlaneCount < 4 )
+  {
+    return false;
+  }
+  if( insideRightPlaneCount < 4 )
+  {
+    return false;
+  }
+  if( insideTopPlaneCount < 4 )
+  {
+    return false;
+  }
+  if( insideBottomPlaneCount < 4 )
+  {
+    return false;
+  }
+
+  return true;
+}
+
 } // namespace SceneGraph
 
 } // namespace Internal
index 0eaea0e..3d59ef6 100644 (file)
@@ -114,9 +114,14 @@ public:
   virtual bool CheckResources();
 
   /**
+   * @copydoc Dali::Internal::SceneGraph::Renderer::GetGeometryTypes()
+   */
+  virtual void GetGeometryTypes( BufferIndex bufferIndex, GeometryType& outType, ShaderSubTypes& outSubType );
+
+  /**
    * @copydoc Dali::Internal::SceneGraph::Renderer::DoRender()
    */
-  virtual void DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color );
+  virtual void DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color, bool cullTest );
 
 protected: // TextureObserver implementation
 
@@ -194,6 +199,11 @@ private:
   // Undefined
   ImageRenderer& operator=(const ImageRenderer& rhs);
 
+  /**
+   * @return true if the renderer is outside clip space and doesn't need rendering
+   */
+  bool IsOutsideClipSpace(const Matrix& modelMatrix);
+
 private:
 
   Texture*    mTexture;
@@ -204,7 +214,6 @@ private:
   Vector4   mBorder;
   PixelArea mPixelArea;
   Vector2   mGeometrySize;
-
   ResourceId  mTextureId;
 
   // flags
index 9f42167..152c3dc 100644 (file)
@@ -120,63 +120,75 @@ bool MeshRenderer::CheckResources()
   return true;
 }
 
-void MeshRenderer::DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color )
+void MeshRenderer::GetGeometryTypes( BufferIndex bufferIndex, GeometryType& outType, ShaderSubTypes& outSubType )
 {
   MeshInfo& meshInfo = mMeshInfo[bufferIndex];
-  Mesh*           mesh              =    meshInfo.mesh;
-  RenderMaterial& material          =  *(meshInfo.material);
-  BoneTransforms& boneTransforms    =    meshInfo.boneTransforms;
-
-  if( ! meshInfo.boneTransforms.transforms.empty() )
-  {
-    ApplyViewToBoneTransforms( meshInfo.boneTransforms, viewMatrix );
-  }
-
-  const int stride = sizeof(Dali::MeshData::Vertex);
-  Dali::MeshData::Vertex *v = 0;
+  Mesh*           mesh     =   meshInfo.mesh;
+  RenderMaterial& material = *(meshInfo.material);
 
-  mesh->UploadVertexData( *mContext, bufferIndex );
-  mesh->BindBuffers( *mContext );
-
-  GeometryType geometryType = GEOMETRY_TYPE_TEXTURED_MESH;
+  outType = GEOMETRY_TYPE_TEXTURED_MESH;
   if( ! material.HasTexture() )
   {
-    geometryType = GEOMETRY_TYPE_MESH;
+    outType = GEOMETRY_TYPE_MESH;
   }
+  outSubType = SHADER_DEFAULT;
 
-  GLsizei numBoneMatrices = (GLsizei)mesh->GetMeshData(Mesh::RENDER_THREAD).GetBoneCount();
-
-  // Select program type
-  ShaderSubTypes shaderType = SHADER_DEFAULT;
-  if( mShader->AreSubtypesRequired( geometryType ) )
+  if( mShader->AreSubtypesRequired( outType ) )
   {
+    GLsizei numBoneMatrices = (GLsizei)mesh->GetMeshData(Mesh::RENDER_THREAD).GetBoneCount();
+
     if( numBoneMatrices )
     {
       if( mesh->GetMeshData(Mesh::RENDER_THREAD).HasColor() )
       {
-        shaderType = SHADER_RIGGED_AND_VERTEX_COLOR;
+        outSubType = SHADER_RIGGED_AND_VERTEX_COLOR;
       }
       else if( mAffectedByLighting )
       {
-        shaderType = SHADER_RIGGED_AND_LIT;
+        outSubType = SHADER_RIGGED_AND_LIT;
       }
       else
       {
-        shaderType = SHADER_RIGGED_AND_EVENLY_LIT;
+        outSubType = SHADER_RIGGED_AND_EVENLY_LIT;
       }
     }
     else
     {
       if( mesh->GetMeshData(Mesh::RENDER_THREAD).HasColor() )
       {
-        shaderType = SHADER_VERTEX_COLOR;
+        outSubType = SHADER_VERTEX_COLOR;
       }
       else if( ! mAffectedByLighting )
       {
-        shaderType = SHADER_EVENLY_LIT;
+        outSubType = SHADER_EVENLY_LIT;
       } // else default
     }
   }
+}
+
+void MeshRenderer::DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color, bool cullTest )
+{
+  MeshInfo& meshInfo = mMeshInfo[bufferIndex];
+  Mesh*           mesh              =    meshInfo.mesh;
+  RenderMaterial& material          =  *(meshInfo.material);
+  BoneTransforms& boneTransforms    =    meshInfo.boneTransforms;
+
+  if( ! meshInfo.boneTransforms.transforms.empty() )
+  {
+    ApplyViewToBoneTransforms( meshInfo.boneTransforms, viewMatrix );
+  }
+
+  const int stride = sizeof(Dali::MeshData::Vertex);
+  Dali::MeshData::Vertex *v = 0;
+
+  mesh->UploadVertexData( *mContext, bufferIndex );
+  mesh->BindBuffers( *mContext );
+
+  GLsizei numBoneMatrices = (GLsizei)mesh->GetMeshData(Mesh::RENDER_THREAD).GetBoneCount();
+
+  GeometryType geometryType = GEOMETRY_TYPE_TEXTURED_MESH;
+  ShaderSubTypes shaderType = SHADER_DEFAULT;
+  GetGeometryTypes( bufferIndex, geometryType, shaderType );
 
   if( geometryType != mGeometryType || shaderType != mShaderType )
   {
index 67acb36..d7af8fb 100644 (file)
@@ -121,9 +121,14 @@ private:
   virtual bool CheckResources();
 
   /**
+   * @copydoc Dali::Internal::SceneGraph::Renderer::GetGeometryTypes()
+   */
+  virtual void GetGeometryTypes( BufferIndex bufferIndex, GeometryType& outType, ShaderSubTypes& outSubType );
+
+  /**
    * @copydoc Dali::Internal::SceneGraph::Renderer::DoRender()
    */
-  virtual void DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color );
+  virtual void DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color, bool cullTest );
 
   /**
    * Apply the view matrix to the bone transforms, and generate inverse transforms (for normal
index 71c610d..57a5b55 100644 (file)
@@ -22,6 +22,7 @@
 // INTERNAL INCLUDES
 #include <dali/internal/render/gl-resources/context.h>
 #include <dali/internal/render/shaders/shader.h>
+#include <dali/internal/render/shaders/program.h>
 #include <dali/internal/render/renderers/render-data-provider.h>
 #include <dali/public-api/actors/blending.h>
 
@@ -74,7 +75,8 @@ void Renderer::Render( BufferIndex bufferIndex,
                        const Matrix& modelViewMatrix,
                        const Matrix& viewMatrix,
                        const Matrix& projectionMatrix,
-                       float frametime )
+                       float frametime,
+                       bool cull)
 {
   DALI_ASSERT_DEBUG( mContext && "Renderer::Render. Renderer not initialised!! (mContext == NULL)." );
   DALI_ASSERT_DEBUG( mShader && "Renderer::Render. Shader not set!!" );
@@ -118,10 +120,21 @@ void Renderer::Render( BufferIndex bufferIndex,
   const Matrix& modelMatrix = mDataProvider.GetModelMatrix( bufferIndex );
   const Vector4& color = mDataProvider.GetRenderColor( bufferIndex );
 
+  // Calculate the MVP matrix first
+  Matrix& modelViewProjectionMatrix = mShader->GetMVPMatrix();
+  Matrix::Multiply( modelViewProjectionMatrix, modelViewMatrix, projectionMatrix );
+
   // Call to over ridden method in the child class
-  // TODO, once MeshRenderer is fixed to render only one mesh, move mShader.Apply here
+  // @todo, once MeshRenderer is fixed to render only one mesh, move mShader.Apply here
   // and we can greatly reduce these parameters. Also then derived renderers can be passed the Program&
-  DoRender( bufferIndex, modelViewMatrix, modelMatrix, viewMatrix, projectionMatrix, color );
+
+  GeometryType geometryType=GEOMETRY_TYPE_IMAGE;
+  ShaderSubTypes subType=SHADER_DEFAULT;
+  GetGeometryTypes( bufferIndex, geometryType, subType );
+  Program& program = mShader->GetProgram( *mContext, geometryType, subType );
+  bool areVerticesFixed = program.AreVerticesFixed();
+
+  DoRender( bufferIndex, modelViewMatrix, modelMatrix, viewMatrix, projectionMatrix, color, cull && areVerticesFixed );
 }
 
 Renderer::Renderer( RenderDataProvider& dataprovider )
index 0e0caae..74b2955 100644 (file)
@@ -103,18 +103,28 @@ public:
   virtual bool RequiresDepthTest() const = 0;
 
   /**
+   * Query the derived type for it's geometry type and subtype
+   * @param[in] bufferIndex The index of the previous update buffer.
+   * @param[out] outType    The geometry type
+   * @param[out] outSubType The geometry subtype
+   */
+  virtual void GetGeometryTypes( BufferIndex bufferIndex, GeometryType& outType, ShaderSubTypes& outSubType ) = 0;
+
+  /**
    * Called to render during RenderManager::Render().
    * @param[in] bufferIndex The index of the previous update buffer.
    * @param[in] modelViewMatrix The model-view matrix.
    * @param[in] viewMatrix The view matrix.
    * @param[in] projectionMatrix The projection matrix.
    * @param[in] frametime The elapsed time between the last two updates.
+   * @param[in] cull Whether to frustum cull this renderer
    */
   void Render( BufferIndex bufferIndex,
                const Matrix& modelViewMatrix,
                const Matrix& viewMatrix,
                const Matrix& projectionMatrix,
-               float frametime );
+               float frametime,
+               bool cull);
 
 protected:
 
@@ -147,8 +157,9 @@ private:
    * @param[in] viewMatrix The view matrix.
    * @param[in] projectionMatrix The projection matrix.
    * @param[in] color to use
+   * @param[in] cullTest Whether to try and cull the renderer.
    */
-  virtual void DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color ) = 0;
+  virtual void DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color, bool cullTest ) = 0;
 
 protected:
 
index fd2847d..9a142ae 100644 (file)
@@ -297,49 +297,59 @@ bool TextRenderer::CheckResources()
   return true;
 }
 
-void TextRenderer::DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color )
+void TextRenderer::GetGeometryTypes( BufferIndex bufferIndex, GeometryType& outType, ShaderSubTypes& outSubType )
 {
-  if ( ! ( mVertexBuffer && mIndexBuffer ) )
-  {
-    // This character has no geometry, must be a white space
-    return;
-  }
-
-  DALI_ASSERT_DEBUG( NULL != mTexture && "TextRenderer::DoRender. mTexture == NULL." );
-
-  DALI_LOG_INFO( gTextFilter, Debug::General, "TextRenderer::DoRender(this: %p) textureId:%d\n", this, mTextureId );
+  outType = GEOMETRY_TYPE_TEXT;
 
   // If we have a color gradient, then we cannot use the default shader.
-  ShaderSubTypes shaderType( SHADER_DEFAULT );
+
+  outSubType = SHADER_DEFAULT;
   if( mTextParameters )
   {
     if( mTextParameters->IsOutlineEnabled() )
     {
       if( mTextParameters->IsGlowEnabled() )
       {
-        shaderType = SHADER_GRADIENT_OUTLINE_GLOW;
+        outSubType = SHADER_GRADIENT_OUTLINE_GLOW;
       }
       else
       {
-        shaderType = SHADER_GRADIENT_OUTLINE;
+        outSubType = SHADER_GRADIENT_OUTLINE;
       }
     }
     else if( mTextParameters->IsGlowEnabled() )
     {
-      shaderType = SHADER_GRADIENT_GLOW;
+      outSubType = SHADER_GRADIENT_GLOW;
     }
     else if( mTextParameters->IsDropShadowEnabled() )
     {
-      shaderType = SHADER_GRADIENT_SHADOW;
+      outSubType = SHADER_GRADIENT_SHADOW;
     }
     else
     {
-      shaderType = SHADER_GRADIENT;
+      outSubType = SHADER_GRADIENT;
     }
   }
+}
+
+void TextRenderer::DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color, bool cullTest )
+{
+  if ( ! ( mVertexBuffer && mIndexBuffer ) )
+  {
+    // This character has no geometry, must be a white space
+    return;
+  }
+
+  DALI_ASSERT_DEBUG( NULL != mTexture && "TextRenderer::DoRender. mTexture == NULL." );
+
+  DALI_LOG_INFO( gTextFilter, Debug::General, "TextRenderer::DoRender(this: %p) textureId:%d\n", this, mTextureId );
+
+  GeometryType geometryType;
+  ShaderSubTypes shaderType;
+  GetGeometryTypes( bufferIndex, geometryType, shaderType );
 
   // Apply shader effect specific program and common uniforms
-  Program& program = mShader->Apply( *mContext, bufferIndex, GEOMETRY_TYPE_TEXT, modelMatrix, viewMatrix, modelViewMatrix, projectionMatrix, color, shaderType );
+  Program& program = mShader->Apply( *mContext, bufferIndex, geometryType, modelMatrix, viewMatrix, modelViewMatrix, projectionMatrix, color, shaderType );
 
   // Set sampler uniform
   GLint samplerLoc = program.GetUniformLocation( Program::UNIFORM_SAMPLER );
index cc5c39b..66b6c4f 100644 (file)
@@ -127,9 +127,14 @@ public:
   virtual bool CheckResources();
 
   /**
+   * @copydoc Dali::Internal::SceneGraph::Renderer::GetGeometryTypes()
+   */
+  virtual void GetGeometryTypes( BufferIndex bufferIndex, GeometryType& outType, ShaderSubTypes& outSubType );
+
+  /**
    * @copydoc Dali::Internal::SceneGraph::Renderer::DoRender()
    */
-  virtual void DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color );
+  virtual void DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color, bool cullTest );
 
 protected: // TextureObserver implementation
   /**
index 96ef256..79932d0 100644 (file)
@@ -118,7 +118,7 @@ const char* gStdUniforms[ Program::UNIFORM_TYPE_LAST ] =
 
 // IMPLEMENTATION
 
-Program* Program::New( const Integration::ResourceId& resourceId, Integration::ShaderData* shaderData, Context& context )
+Program* Program::New( const Integration::ResourceId& resourceId, Integration::ShaderData* shaderData, Context& context, bool fixedVertices )
 {
   size_t shaderHash = shaderData->GetHashValue();
   Program* program = context.GetCachedProgram( shaderHash );
@@ -126,7 +126,7 @@ Program* Program::New( const Integration::ResourceId& resourceId, Integration::S
   if( NULL == program )
   {
     // program not found so create it
-    program = new Program( shaderData, context );
+    program = new Program( shaderData, context, fixedVertices );
 
     program->Load();
 
@@ -431,14 +431,20 @@ void Program::GlContextDestroyed()
   ResetAttribsUniforms();
 }
 
-Program::Program(Integration::ShaderData* shaderData, Context& context )
+bool Program::AreVerticesFixed()
+{
+  return mAreVerticesFixed;
+}
+
+Program::Program(Integration::ShaderData* shaderData, Context& context, bool areVerticesFixed )
 : mContext( context ),
   mGlAbstraction( context.GetAbstraction() ),
   mLinked( false ),
   mVertexShaderId( 0 ),
   mFragmentShaderId( 0 ),
   mProgramId( 0 ),
-  mProgramData(shaderData)
+  mProgramData(shaderData),
+  mAreVerticesFixed(areVerticesFixed)
 {
   // reserve space for standard uniforms
   mUniformLocations.reserve( UNIFORM_TYPE_LAST );
index 266c971..b2633f1 100644 (file)
@@ -137,9 +137,10 @@ public:
    *                        and optionally precompiled binary. If the binary is empty the program bytecode
    *                        is copied into it after compilation and linking)
    * @param [in] context    GL context
+   * @param [in] fixedVertices True if the vertex shader does not change verts
    * @return pointer to the program
    */
-  static Program* New( const Integration::ResourceId& resourceId, Integration::ShaderData* shaderData, Context& context );
+  static Program* New( const Integration::ResourceId& resourceId, Integration::ShaderData* shaderData, Context& context, bool fixedVertices );
 
   /**
    * Takes this program into use
@@ -251,14 +252,20 @@ public:
    */
   void GlContextDestroyed();
 
+  /**
+   * @return true if this program does not change vertex position
+   */
+  bool AreVerticesFixed();
+
 private: // Implementation
 
   /**
    * Constructor, private so no direct instantiation
    * @param[in] shaderData A pointer to a data structure containing the program source and binary
    * @param[in] context    The GL context state cache.
+   * @param[in] areVerticesFixed True if the vertex shader does not move vertices
    */
-  Program( Integration::ShaderData* shaderData, Context& context );
+  Program( Integration::ShaderData* shaderData, Context& context, bool areVerticesFixed );
 
 public:
 
@@ -326,7 +333,7 @@ private:  // Data
   GLint mUniformCacheInt[ MAX_UNIFORM_CACHE_SIZE ];         ///< Value cache for uniforms of single int
   GLfloat mUniformCacheFloat[ MAX_UNIFORM_CACHE_SIZE ];     ///< Value cache for uniforms of single float
   GLfloat mUniformCacheFloat4[ MAX_UNIFORM_CACHE_SIZE ][4]; ///< Value cache for uniforms of four float
-
+  bool mAreVerticesFixed;  ///< True if the program does not change vertex position
 };
 
 } // namespace Internal
index af32e38..70a6c1b 100644 (file)
@@ -231,13 +231,14 @@ void Shader::SetProgram( GeometryType geometryType,
                          ShaderSubTypes subType,
                          Integration::ResourceId resourceId,
                          Integration::ShaderDataPtr shaderData,
-                         Context* context )
+                         Context* context,
+                         bool areVerticesFixed )
 {
   DALI_LOG_TRACE_METHOD_FMT(Debug::Filter::gShader, "%d %d\n", (int)geometryType, resourceId);
 
   bool precompiledBinary = shaderData->HasBinary();
 
-  Program* program = Program::New( resourceId, shaderData.Get(), *context );
+  Program* program = Program::New( resourceId, shaderData.Get(), *context, areVerticesFixed );
 
   ShaderSubTypes theSubType = subType;
   if( subType == SHADER_SUBTYPE_ALL )
@@ -277,6 +278,24 @@ bool Shader::AreSubtypesRequired(GeometryType geometryType)
   return ! mPrograms[ programType ].mUseDefaultForAllSubtypes;
 }
 
+Program& Shader::GetProgram( Context& context,
+                             GeometryType type,
+                             const ShaderSubTypes subType )
+{
+  DALI_ASSERT_DEBUG(type < GEOMETRY_TYPE_LAST);
+  DALI_DEBUG_OSTREAM(debugStream);
+
+  unsigned int programType = GetGeometryTypeIndex( type );
+
+  DALI_ASSERT_DEBUG(!mPrograms[ programType ].mUseDefaultForAllSubtypes || subType == SHADER_DEFAULT);
+  DALI_ASSERT_DEBUG((unsigned int)subType < mPrograms[ programType ].Count());
+  DALI_ASSERT_DEBUG(NULL != mPrograms[ programType ][ subType ]);
+
+  Program& program = *(mPrograms[ programType ][ subType ]);
+  return program;
+}
+
+
 Program& Shader::Apply( Context& context,
                         BufferIndex bufferIndex,
                         GeometryType type,
@@ -351,7 +370,6 @@ Program& Shader::Apply( Context& context,
   loc = program.GetUniformLocation( Program::UNIFORM_MVP_MATRIX );
   if( Program::UNIFORM_UNKNOWN != loc )
   {
-    Matrix::Multiply( mModelViewProjection, modelview, projection );
     DALI_PRINT_UNIFORM( debugStream, bufferIndex, "uMvpMatrix", mModelViewProjection );
     program.SetUniformMatrix4fv( loc, 1, mModelViewProjection.AsFloat() );
   }
index 5cd63f9..bdbb05f 100644 (file)
@@ -257,17 +257,19 @@ public:
 
   /**
    * Set the program for a geometry type and subtype
-   * @param[in] geometryType The type of the object (geometry) that is to be rendered.
-   * @param[in] subType      The subtype, one of ShaderSubTypes.
-   * @param[in] resourceId   The resource ID for the program.
-   * @param[in] shaderData   The program's vertex/fragment source and optionally compiled bytecode
-   * @param[in] context      Reference to the GL context.
+   * @param[in] geometryType  The type of the object (geometry) that is to be rendered.
+   * @param[in] subType       The subtype, one of ShaderSubTypes.
+   * @param[in] resourceId    The resource ID for the program.
+   * @param[in] shaderData    The program's vertex/fragment source and optionally compiled bytecode
+   * @param[in] context       Reference to the GL context.
+   * @param[in] areVerticesFixed True if the vertex shader does not change vertex position
    */
   void SetProgram( GeometryType geometryType,
                    Internal::ShaderSubTypes subType,
                    Integration::ResourceId resourceId,
                    Integration::ShaderDataPtr shaderData,
-                   Context* context );
+                   Context* context,
+                   bool areVerticesFixed );
 
   /**
    * Determine if subtypes are required for the given geometry type
@@ -277,6 +279,13 @@ public:
   bool AreSubtypesRequired(GeometryType geometryType);
 
   /**
+   * Get the program associated with the given type and subtype
+   */
+  Program& GetProgram( Context& context,
+                       GeometryType type,
+                       const ShaderSubTypes subType );
+
+  /**
    * Applies the shader effect specific program and sets the common uniforms
    * @pre The shader has been initialized.
    * @pre This method is not thread-safe, and should only be called from the render-thread.
@@ -308,6 +317,14 @@ public:
    */
   void SetFrameTime( float frametime );
 
+  /**
+   * @return The model view projection matrix
+   */
+  inline Matrix& GetMVPMatrix()
+  {
+    return mModelViewProjection;
+  }
+
 private: // Data
 
   typedef OwnerContainer< UniformMeta* > UniformMetaContainer;
index bfa820b..c23be8c 100644 (file)
@@ -508,6 +508,7 @@ void PrepareRenderInstruction( BufferIndex updateBufferIndex,
   }
 
   instruction.mRenderTracker = renderTracker;
+  instruction.mCullMode = renderTask.GetCullMode();
 
   // inform the render instruction that all renderers have been added and this frame is complete
   instruction.UpdateCompleted();
index 0b9b72e..8c2b6c8 100644 (file)
@@ -586,7 +586,7 @@ void UpdateManager::RemoveShader(Shader* shader)
   DALI_ASSERT_DEBUG(false);
 }
 
-void UpdateManager::SetShaderProgram( Shader* shader, GeometryType geometryType, ShaderSubTypes subType, ResourceId resourceId, size_t shaderHash )
+void UpdateManager::SetShaderProgram( Shader* shader, GeometryType geometryType, ShaderSubTypes subType, ResourceId resourceId, size_t shaderHash, bool fixed )
 {
   DALI_LOG_TRACE_METHOD_FMT(Debug::Filter::gShader, " - (geometryType:%d subType:%d id:%d hash:%d)\n", geometryType, subType, resourceId, shaderHash);
 
@@ -599,13 +599,13 @@ void UpdateManager::SetShaderProgram( Shader* shader, GeometryType geometryType,
   {
     // This is done in the render thread, to allow GL program compilation
     // Will trigger a NotifySaveRequest back to updateManager to forward onto ResourceClient
-    typedef MessageValue5< Shader, GeometryType, Internal::ShaderSubTypes, Integration::ResourceId, Integration::ShaderDataPtr, Context* > DerivedType;
+    typedef MessageValue6< Shader, GeometryType, Internal::ShaderSubTypes, Integration::ResourceId, Integration::ShaderDataPtr, Context*, bool> DerivedType;
 
     // Reserve some memory inside the render queue
     unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
 
     // Construct message in the render queue memory; note that delete should not be called on the return value
-    new (slot) DerivedType( shader, &Shader::SetProgram, geometryType, subType, resourceId, shaderData, &(mImpl->renderManager.GetContext()) );
+    new (slot) DerivedType( shader, &Shader::SetProgram, geometryType, subType, resourceId, shaderData, &(mImpl->renderManager.GetContext()), fixed );
   }
 }
 
index de158b4..ecd97c1 100644 (file)
@@ -303,9 +303,10 @@ public:
    * @param[in] geometryType  The GeometryType to map to the program
    * @param[in] subType       The program subtype
    * @param[in] resourceId    A ResourceManager ticket ID for the program data (source and compiled binary)
-   * @param[in] shaderHash  hash key created with vertex and fragment shader code
+   * @param[in] shaderHash    hash key created with vertex and fragment shader code
+   * @param[in] fixed         True if the vertex shader doesn't alter vertices
    */
-  void SetShaderProgram( Shader* shader, GeometryType geometryType, ShaderSubTypes subType, Integration::ResourceId resourceId, size_t shaderHash );
+  void SetShaderProgram( Shader* shader, GeometryType geometryType, ShaderSubTypes subType, Integration::ResourceId resourceId, size_t shaderHash, bool fixed );
 
   /**
    * Add an animatable mesh
@@ -715,15 +716,16 @@ inline void SetShaderProgramMessage( UpdateManager& manager,
                                      GeometryType geometryType,
                                      ShaderSubTypes subType,
                                      Integration::ResourceId resourceId,
-                                     size_t shaderHash )
+                                     size_t shaderHash,
+                                     bool fixed )
 {
-  typedef MessageValue5< UpdateManager, Shader*, GeometryType, ShaderSubTypes, Integration::ResourceId, size_t > LocalType;
+  typedef MessageValue6< UpdateManager, Shader*, GeometryType, ShaderSubTypes, Integration::ResourceId, size_t, bool > LocalType;
 
   // Reserve some memory inside the message queue
   unsigned int* slot = manager.GetEventToUpdate().ReserveMessageSlot( sizeof( LocalType ) );
 
   // Construct message in the message queue memory; note that delete should not be called on the return value
-  new (slot) LocalType( &manager, &UpdateManager::SetShaderProgram, &shader, geometryType, subType, resourceId, shaderHash );
+  new (slot) LocalType( &manager, &UpdateManager::SetShaderProgram, &shader, geometryType, subType, resourceId, shaderHash, fixed );
 }
 
 // The render thread can safely change the AnimatableMesh
index 27132f8..77ca4bf 100644 (file)
@@ -195,6 +195,16 @@ bool RenderTask::GetClearEnabled() const
   return mClearEnabled;
 }
 
+void RenderTask::SetCullMode( bool mode )
+{
+  mCullMode = mode;
+}
+
+bool RenderTask::GetCullMode() const
+{
+  return mCullMode;
+}
+
 void RenderTask::SetRefreshRate( unsigned int refreshRate )
 {
   DALI_LOG_TRACE_METHOD_FMT(gRenderTaskLogFilter, "this:%p RefreshRate:%d\n", this, refreshRate);
@@ -502,6 +512,7 @@ RenderTask::RenderTask()
   mNotifyTrigger( false ),
   mExclusive( Dali::RenderTask::DEFAULT_EXCLUSIVE ),
   mClearEnabled( Dali::RenderTask::DEFAULT_CLEAR_ENABLED ),
+  mCullMode( Dali::RenderTask::DEFAULT_CULL_MODE ),
   mRenderTarget( NULL ),
   mState( (Dali::RenderTask::DEFAULT_REFRESH_RATE == Dali::RenderTask::REFRESH_ALWAYS)
           ? RENDER_CONTINUOUSLY
index 170b80f..6b9e162 100644 (file)
@@ -213,6 +213,16 @@ public:
   bool GetClearEnabled() const;
 
   /**
+   * @copydoc Dali::RenderTask::SetCullMode()
+   */
+  void SetCullMode( bool mode );
+
+  /**
+   * @copydoc Dali::RenderTask::GetCullMode()
+   */
+  bool GetCullMode() const;
+
+  /**
    * Set the refresh-rate of the RenderTask.
    * @param[in] refreshRate The new refresh rate.
    */
@@ -331,6 +341,7 @@ private:
   bool mNotifyTrigger:1; ///< True if a render once render task has finished renderering
   bool mExclusive: 1; ///< Whether the render task has exclusive access to the source actor (node in the scene graph implementation).
   bool mClearEnabled: 1; ///< Whether previous results are cleared.
+  bool mCullMode: 1; ///< Whether renderers should be frustum culled
 
   FrameBufferTexture* mRenderTarget;
   Viewport mViewport;
@@ -389,6 +400,17 @@ inline void SetClearEnabledMessage( EventToUpdate& eventToUpdate, RenderTask& ta
   new (slot) LocalType( &task, &RenderTask::SetClearEnabled, enabled );
 }
 
+inline void SetCullModeMessage( EventToUpdate& eventToUpdate, RenderTask& task, bool mode )
+{
+  typedef MessageValue1< RenderTask, bool > LocalType;
+
+  // Reserve some memory inside the message queue
+  unsigned int* slot = eventToUpdate.ReserveMessageSlot( sizeof( LocalType ) );
+
+  // Construct message in the message queue memory; note that delete should not be called on the return value
+  new (slot) LocalType( &task, &RenderTask::SetCullMode, mode );
+}
+
 inline void SetRefreshRateMessage( EventToUpdate& eventToUpdate, RenderTask& task, unsigned int refreshRate )
 {
   typedef MessageValue1< RenderTask, unsigned int > LocalType;
index 7f5547b..72e338f 100644 (file)
@@ -47,6 +47,7 @@ const bool         RenderTask::DEFAULT_EXCLUSIVE     = false;
 const bool         RenderTask::DEFAULT_INPUT_ENABLED = true;
 const Vector4      RenderTask::DEFAULT_CLEAR_COLOR   = Vector4( 0.0f, 0.0f, 0.0f, 1.0f ); // cannot use Color::Black because it may or may not be initialized yet
 const bool         RenderTask::DEFAULT_CLEAR_ENABLED = false;
+const bool         RenderTask::DEFAULT_CULL_MODE     = true;
 const unsigned int RenderTask::DEFAULT_REFRESH_RATE  = REFRESH_ALWAYS;
 
 RenderTask::RenderTask()
@@ -195,6 +196,16 @@ bool RenderTask::GetClearEnabled() const
   return GetImplementation(*this).GetClearEnabled();
 }
 
+void RenderTask::SetCullMode( bool mode )
+{
+  GetImplementation(*this).SetCullMode( mode );
+}
+
+bool RenderTask::GetCullMode() const
+{
+  return GetImplementation(*this).GetCullMode();
+}
+
 void RenderTask::SetRefreshRate( unsigned int refreshRate )
 {
   GetImplementation(*this).SetRefreshRate( refreshRate );
@@ -226,4 +237,3 @@ RenderTask::RenderTask( Internal::RenderTask* internal )
 }
 
 } // namespace Dali
-