[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>
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
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);
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},
{"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}
};
--- /dev/null
+/*
+ * 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;
+}
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();
}
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 );
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)
*(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)
*/
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
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
*/
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
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
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
/**
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.
/**
* 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&)
}
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,
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.
}
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()
*/
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
* @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.
* @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.
{
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
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)
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);
}
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);
SetExclusiveMessage( mEventToUpdate, *mSceneObject, mExclusive );
SetClearColorMessage( mEventToUpdate, *mSceneObject, mClearColor );
SetClearEnabledMessage( mEventToUpdate, *mSceneObject, mClearEnabled );
+ SetCullModeMessage( mEventToUpdate, *mSceneObject, mCullMode );
SetRefreshRateMessage( mEventToUpdate, *mSceneObject, mRefreshRate );
// Caller takes ownership
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);
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 );
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
* @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 );
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 );
}
}
if( renderList &&
!renderList->IsEmpty() )
{
- ProcessRenderList( *renderList, context, bufferIndex, frameTime, *viewMatrix, *projectionMatrix );
+ ProcessRenderList( *renderList, context, bufferIndex, frameTime, *viewMatrix, *projectionMatrix, instruction.mCullMode );
}
}
}
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
#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
{
*/
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
mClearColor(),
mIsViewportSet( false ),
mIsClearColorSet( false ),
+ mCullMode(false),
mOffscreenTextureId( 0 ),
mNextFreeRenderList( 0 )
{
const Matrix* projectionMatrix,
unsigned int offscreenTextureId,
const Viewport* viewport,
- const Vector4* clearColor )
+ const Vector4* clearColor)
{
mViewMatrix = viewMatrix;
mProjectionMatrix = projectionMatrix;
mIsViewportSet = NULL != viewport;
mClearColor = clearColor ? *clearColor : Color::BLACK;
mIsClearColorSet = NULL != clearColor;
+ mCullMode = false;
mOffscreenTextureId = offscreenTextureId;
mRenderTracker = NULL;
mNextFreeRenderList = 0;
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
mImpl->RemoveRenderTracker(renderTracker);
}
-
bool RenderManager::Render( Integration::RenderStatus& status )
{
DALI_PRINT_RENDER_START( mImpl->renderBufferIndex );
// 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);
DALI_PRINT_RENDER_END();
+ DALI_PRINT_RENDERER_COUNT(mImpl->frameCount, mImpl->context.GetRendererCount());
+ DALI_PRINT_CULL_COUNT(mImpl->frameCount, mImpl->context.GetCulledCount());
+
return updateRequired;
}
class Context
{
public:
-
/**
* Size of the VertexAttributeArray enables
* GLES specification states that there's minimum of 8
#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
/**
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
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 );
{
}
+// 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
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
// 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;
Vector4 mBorder;
PixelArea mPixelArea;
Vector2 mGeometrySize;
-
ResourceId mTextureId;
// flags
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 )
{
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
// 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>
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!!" );
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 )
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:
* @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:
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 );
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
/**
// 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 );
if( NULL == program )
{
// program not found so create it
- program = new Program( shaderData, context );
+ program = new Program( shaderData, context, fixedVertices );
program->Load();
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 );
* 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
*/
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:
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
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 )
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,
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() );
}
/**
* 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
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.
*/
void SetFrameTime( float frametime );
+ /**
+ * @return The model view projection matrix
+ */
+ inline Matrix& GetMVPMatrix()
+ {
+ return mModelViewProjection;
+ }
+
private: // Data
typedef OwnerContainer< UniformMeta* > UniformMetaContainer;
}
instruction.mRenderTracker = renderTracker;
+ instruction.mCullMode = renderTask.GetCullMode();
// inform the render instruction that all renderers have been added and this frame is complete
instruction.UpdateCompleted();
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);
{
// 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 );
}
}
* @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
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
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);
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
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.
*/
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;
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;
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()
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 );
}
} // namespace Dali
-