From 8a37fe59c9b77bc32c6998721d335cc1c41c44db Mon Sep 17 00:00:00 2001 From: taeyoon Date: Tue, 24 Nov 2015 15:00:36 +0900 Subject: [PATCH] NativeImageSource with tbm_surface for tizen 3.0 wayland - NativeImageSource uses XPixmap or Ecore Pixmap type in x windows system. - Tizen 3.0 wayland doesn't support the pixmap type. -> Replaces pixmap to tbm_surface. -> Adds handling fragment shader code into ImageRenderer for tbm_surface -> Adds UTCs for various scenarios of ImageView (NativeImage vs. Regular image) Change-Id: Ibe3747dcf5711f11770ae1e54d1ca37577d7ca6f --- automated-tests/src/dali-toolkit/CMakeLists.txt | 1 + .../dali-toolkit-test-utils/test-native-image.cpp | 1 + .../dali-toolkit-test-utils/test-native-image.h | 11 + .../src/dali-toolkit/utc-Dali-ImageView.cpp | 319 +++++++++++++++++++++ .../controls/renderers/image/image-renderer.cpp | 129 ++++++++- .../controls/renderers/image/image-renderer.h | 16 ++ 6 files changed, 475 insertions(+), 2 deletions(-) diff --git a/automated-tests/src/dali-toolkit/CMakeLists.txt b/automated-tests/src/dali-toolkit/CMakeLists.txt index e0e2601..10ef2a0 100644 --- a/automated-tests/src/dali-toolkit/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit/CMakeLists.txt @@ -79,6 +79,7 @@ LIST(APPEND TC_SOURCES dali-toolkit-test-utils/test-gl-sync-abstraction.cpp dali-toolkit-test-utils/test-render-controller.cpp dali-toolkit-test-utils/test-trace-call-stack.cpp + dali-toolkit-test-utils/test-native-image.cpp ) diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.cpp index d143d35..d8ad2ba 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.cpp @@ -31,6 +31,7 @@ TestNativeImagePointer TestNativeImage::New(int width, int height) TestNativeImage::TestNativeImage(int width, int height) : mWidth(width), mHeight(height), mExtensionCreateCalls(0), mExtensionDestroyCalls(0), mTargetTextureCalls(0) { + mExtension = new TestNativeImageExtension(); } TestNativeImage::~TestNativeImage() diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.h index 4a39cb1..8dc6431 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.h @@ -20,12 +20,21 @@ // INTERNAL INCLUDES #include +#include namespace Dali { class TestNativeImage; typedef IntrusivePtr TestNativeImagePointer; +class DALI_IMPORT_API TestNativeImageExtension: public Dali::NativeImageInterface::Extension +{ +public: + inline const char* GetCustomFragmentPreFix(){return "#extension GL_OES_EGL_image_external:require\n";} + inline const char* GetCustomSamplerTypename(){return "samplerExternalOES";} + +}; + class DALI_IMPORT_API TestNativeImage : public Dali::NativeImageInterface { public: @@ -38,6 +47,7 @@ public: inline virtual unsigned int GetWidth() const {return mWidth;}; inline virtual unsigned int GetHeight() const {return mHeight;}; inline virtual bool RequiresBlending() const {return true;}; + inline virtual Dali::NativeImageInterface::Extension* GetExtension() {return mExtension;} private: TestNativeImage(int width, int height); @@ -49,6 +59,7 @@ public: int mExtensionCreateCalls; int mExtensionDestroyCalls; int mTargetTextureCalls; + TestNativeImageExtension* mExtension; }; } // Dali diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp index cc62d54..32d987f 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp @@ -24,6 +24,9 @@ #include #include +#include +#include + using namespace Dali; using namespace Toolkit; @@ -39,6 +42,35 @@ void utc_dali_toolkit_image_view_cleanup(void) namespace { + +const char* VERTEX_SHADER = DALI_COMPOSE_SHADER( + attribute mediump vec2 aPosition;\n + varying mediump vec2 vTexCoord;\n + uniform mediump mat4 uMvpMatrix;\n + uniform mediump vec3 uSize;\n + \n + void main()\n + {\n + mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n + vertexPosition.xyz *= uSize;\n + vertexPosition = uMvpMatrix * vertexPosition;\n + \n + vTexCoord = aPosition + vec2(0.5);\n + gl_Position = vertexPosition;\n + }\n +); + +const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER( + varying mediump vec2 vTexCoord;\n + uniform sampler2D sTexture;\n + uniform lowp vec4 uColor;\n + \n + void main()\n + {\n + gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n + }\n +); + const char* TEST_IMAGE_FILE_NAME = "gallery_image_01.jpg"; const char* TEST_IMAGE_FILE_NAME2 = "gallery_image_02.jpg"; @@ -650,3 +682,290 @@ int UtcDaliImageViewResourceUrlP(void) END_TEST; } + +// Scenarios 1: ImageView from regular image +int UtcDaliImageViewSetImageBufferImage(void) +{ + ToolkitTestApplication application; + + ImageView imageView = ImageView::New(); + Stage::GetCurrent().Add( imageView ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + gl.EnableTextureCallTrace( true ); + + std::vector< GLuint > ids; + ids.push_back( 23 ); + application.GetGlAbstraction().SetNextTextureIds( ids ); + + int width = 300; + int height = 400; + BufferImage image = CreateBufferImage( width, height, Color::WHITE ); + + imageView.SetImage( image ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") ); + + std::stringstream params; + params << GL_TEXTURE_2D << ", " << 23; + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", params.str()) ); + + END_TEST; +} + +// Scenarios 2: ImageView from Native image +int UtcDaliImageViewSetImageNativeImage(void) +{ + ToolkitTestApplication application; + + ImageView imageView = ImageView::New(); + Stage::GetCurrent().Add( imageView ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + gl.EnableTextureCallTrace( true ); + + std::vector< GLuint > ids; + ids.push_back( 23 ); + application.GetGlAbstraction().SetNextTextureIds( ids ); + + int width = 200; + int height = 500; + TestNativeImagePointer nativeImageInterface = TestNativeImage::New( width, height ); + NativeImage nativeImage = NativeImage::New( *(nativeImageInterface.Get()) ); + + imageView.SetImage( nativeImage ); + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") ); + + std::stringstream params; + params << GL_TEXTURE_2D << ", " << 23; + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", params.str()) ); + + END_TEST; +} + +// Scenarios 3: ImageView initially from regular image but then SetImage called with Native image +int UtcDaliImageViewSetImageBufferImageToNativeImage(void) +{ + ToolkitTestApplication application; + + int width = 300; + int height = 400; + BufferImage image = CreateBufferImage( width, height, Color::WHITE ); + + ImageView imageView = ImageView::New( image ); + Stage::GetCurrent().Add( imageView ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + gl.EnableTextureCallTrace( true ); + + std::vector< GLuint > ids; + ids.push_back( 23 ); + application.GetGlAbstraction().SetNextTextureIds( ids ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") ); + + std::stringstream params; + params << GL_TEXTURE_2D << ", " << 23; + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", params.str()) ); + + width = 200; + height = 500; + TestNativeImagePointer nativeImageInterface = TestNativeImage::New( width, height ); + NativeImage nativeImage = NativeImage::New( *(nativeImageInterface.Get()) ); + imageView.SetImage( nativeImage ); + + ids.clear(); + ids.push_back( 24 ); + application.GetGlAbstraction().SetNextTextureIds( ids ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") ); + + std::stringstream nextTextureParams; + nextTextureParams << GL_TEXTURE_2D << ", " << 24; + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", nextTextureParams.str()) ); + + END_TEST; +} + +// Scenarios 4: ImageView initially from Native image but then SetImage called with regular image +int UtcDaliImageViewSetImageNativeImageToBufferImage(void) +{ + ToolkitTestApplication application; + + int width = 300; + int height = 400; + TestNativeImagePointer nativeImageInterface = TestNativeImage::New( width, height ); + NativeImage nativeImage = NativeImage::New( *(nativeImageInterface.Get()) ); + + ImageView imageView = ImageView::New( nativeImage ); + Stage::GetCurrent().Add( imageView ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + gl.EnableTextureCallTrace( true ); + + std::vector< GLuint > ids; + ids.push_back( 23 ); + application.GetGlAbstraction().SetNextTextureIds( ids ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") ); + + std::stringstream params; + params << GL_TEXTURE_2D << ", " << 23; + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", params.str()) ); + + width = 200; + height = 500; + BufferImage image = CreateBufferImage( width, height, Color::WHITE ); + imageView.SetImage( image ); + + ids.clear(); + ids.push_back( 24 ); + application.GetGlAbstraction().SetNextTextureIds( ids ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") ); + + std::stringstream nextTextureParams; + nextTextureParams << GL_TEXTURE_2D << ", " << 24; + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", nextTextureParams.str()) ); + + END_TEST; +} + +// Scenarios 5: ImageView from Native image with custom shader +int UtcDaliImageViewSetImageNativeImageWithCustomShader(void) +{ + ToolkitTestApplication application; + + int width = 300; + int height = 400; + + Property::Map customShader; + customShader.Insert( "vertexShader", VERTEX_SHADER ); + customShader.Insert( "fragmentShader", FRAGMENT_SHADER ); + + Property::Array shaderHints; + shaderHints.PushBack( "requiresSelfDepthTest" ); + shaderHints.PushBack( "outputIsTransparent" ); + shaderHints.PushBack( "outputIsOpaque" ); + shaderHints.PushBack( "modifiesGeometry" ); + + customShader.Insert( "hints", shaderHints ); + + Property::Map map; + map.Insert( "rendererType", "imageRenderer" ); + map.Insert( "shader", customShader ); + + TestNativeImagePointer nativeImageInterface = TestNativeImage::New( width, height ); + NativeImage nativeImage = NativeImage::New( *(nativeImageInterface.Get()) ); + + ImageView imageView = ImageView::New( nativeImage ); + imageView.SetProperty( ImageView::Property::IMAGE, map ); + Stage::GetCurrent().Add( imageView ); + + imageView.SetProperty( ImageView::Property::IMAGE, map ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + gl.EnableTextureCallTrace( true ); + + std::vector< GLuint > ids; + ids.push_back( 23 ); + application.GetGlAbstraction().SetNextTextureIds( ids ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") ); + + std::stringstream params; + params << GL_TEXTURE_2D << ", " << 23; + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", params.str()) ); + + END_TEST; +} + +// Scenarios 6: ImageView initially from regular image with custom shader but then SetImage called with Native +int UtcDaliImageViewSetImageBufferImageWithCustomShaderToNativeImage(void) +{ + ToolkitTestApplication application; + + int width = 300; + int height = 400; + + Property::Map customShader; + customShader.Insert( "vertexShader", VERTEX_SHADER ); + customShader.Insert( "fragmentShader", FRAGMENT_SHADER ); + + Property::Array shaderHints; + shaderHints.PushBack( "requiresSelfDepthTest" ); + shaderHints.PushBack( "outputIsTransparent" ); + shaderHints.PushBack( "outputIsOpaque" ); + shaderHints.PushBack( "modifiesGeometry" ); + + customShader.Insert( "hints", shaderHints ); + + Property::Map map; + map.Insert( "rendererType", "imageRenderer" ); + map.Insert( "shader", customShader ); + + BufferImage image = CreateBufferImage( width, height, Color::WHITE ); + + ImageView imageView = ImageView::New( image ); + imageView.SetProperty( ImageView::Property::IMAGE, map ); + Stage::GetCurrent().Add( imageView ); + + imageView.SetProperty( ImageView::Property::IMAGE, map ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + gl.EnableTextureCallTrace( true ); + + std::vector< GLuint > ids; + ids.push_back( 23 ); + application.GetGlAbstraction().SetNextTextureIds( ids ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") ); + + std::stringstream params; + params << GL_TEXTURE_2D << ", " << 23; + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", params.str()) ); + + TestNativeImagePointer nativeImageInterface = TestNativeImage::New( width, height ); + NativeImage nativeImage = NativeImage::New( *(nativeImageInterface.Get()) ); + imageView.SetImage( nativeImage ); + + ids.clear(); + ids.push_back( 24 ); + application.GetGlAbstraction().SetNextTextureIds( ids ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") ); + + std::stringstream nativeImageParams; + nativeImageParams << GL_TEXTURE_2D << ", " << 24; + DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", nativeImageParams.str()) ); + + + END_TEST; +} diff --git a/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp b/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp index 7862d53..b9fcec9 100644 --- a/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp +++ b/dali-toolkit/internal/controls/renderers/image/image-renderer.cpp @@ -21,6 +21,7 @@ // EXTERNAL HEADER #include // for strncasecmp #include +#include #include // INTERNAL HEADER @@ -79,6 +80,8 @@ const std::string ALPHA_BLENDING_UNIFORM_NAME = "uAlphaBlending"; const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f); +const char* DEFAULT_SAMPLER_TYPENAME = "sampler2D"; + const char* VERTEX_SHADER = DALI_COMPOSE_SHADER( attribute mediump vec2 aPosition;\n uniform mediump mat4 uMvpMatrix;\n @@ -110,6 +113,7 @@ const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER( }\n ); + Geometry GenerateGeometry( const Vector< Vector2 >& vertices, const Vector< unsigned int >& indices ) { Property::Map vertexFormat; @@ -207,7 +211,9 @@ ImageRenderer::ImageRenderer( RendererFactoryCache& factoryCache, ImageAtlasMana mDesiredSize(), mFittingMode( FittingMode::DEFAULT ), mSamplingMode( SamplingMode::DEFAULT ), - mIsAlphaPreMultiplied( false ) + mIsAlphaPreMultiplied( false ), + mNativeFragmentShaderCode( ), + mNativeImageFlag( false ) { } @@ -336,6 +342,13 @@ void ImageRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap } } + NativeImage nativeImage = NativeImage::DownCast( mImage ); + + if( nativeImage ) + { + SetNativeFragmentShaderCode( nativeImage ); + } + // if actor is on stage, create new renderer and apply to actor if( actor && actor.OnStage() ) { @@ -387,9 +400,17 @@ Renderer ImageRenderer::CreateRenderer() const Geometry geometry; Shader shader; + // If mImage is nativeImage with custom sampler or prefix, mNativeFragmentShaderCode will be applied. + // Renderer can't be shared between NativeImage and other image types. + if( !mNativeFragmentShaderCode.empty() ) + { + return CreateNativeImageRenderer(); + } + if( !mImpl->mCustomShader ) { geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) ); + shader = GetImageShader(mFactoryCache); } else @@ -417,6 +438,45 @@ Renderer ImageRenderer::CreateRenderer() const return Renderer::New( geometry, material ); } +Renderer ImageRenderer::CreateNativeImageRenderer() const +{ + Geometry geometry; + Shader shader; + + if( !mImpl->mCustomShader ) + { + geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) ); + + shader = Shader::New( VERTEX_SHADER, mNativeFragmentShaderCode ); + shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT ); + shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT ); + shader.RegisterProperty( ALPHA_BLENDING_UNIFORM_NAME, 1.f ); + } + else + { + geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize ); + if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() ) + { + shader = Shader::New( VERTEX_SHADER, mNativeFragmentShaderCode ); + } + else + { + shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader, + mNativeFragmentShaderCode, + mImpl->mCustomShader->mHints ); + if( mImpl->mCustomShader->mVertexShader.empty() ) + { + shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT ); + shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT ); + shader.RegisterProperty( ALPHA_BLENDING_UNIFORM_NAME, 1.f ); + } + } + } + + Material material = Material::New( shader ); + return Renderer::New( geometry, material ); +} + void ImageRenderer::InitializeRenderer( const std::string& imageUrl ) { if( imageUrl.empty() ) @@ -669,11 +729,35 @@ void ImageRenderer::SetImage( Actor& actor, const Image& image ) { if( mImage != image ) { + NativeImage newNativeImage = NativeImage::DownCast( image ); + bool newRendererFlag = true; + + if( newNativeImage && !mNativeImageFlag ) + { + SetNativeFragmentShaderCode( newNativeImage ); + } + + if( ( newNativeImage && mNativeImageFlag ) || ( !newNativeImage && !mNativeImageFlag ) ) + { + newRendererFlag = false; + } + + if( newNativeImage ) + { + mNativeImageFlag = true; + } + else + { + mNativeFragmentShaderCode.clear(); + mNativeImageFlag = false; + } + mImage = image; if( mImpl->mRenderer ) { - if( GetIsFromCache() ) // if renderer is from cache, remove the old one + // if renderer is from cache, remove the old one, and create new renderer + if( GetIsFromCache() ) { //remove old renderer if( actor ) @@ -693,6 +777,20 @@ void ImageRenderer::SetImage( Actor& actor, const Image& image ) SetOnStage(actor); } } + // if input image is nativeImage and mImage is regular image or the reverse, remove the old one, and create new renderer + else if( newRendererFlag ) + { + //remove old renderer + if( actor ) + { + actor.RemoveRenderer( mImpl->mRenderer ); + } + + if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor + { + SetOnStage(actor); + } + } else // if renderer is not from cache, reuse the same renderer and only change the texture { ApplyImageToSampler( image ); @@ -787,6 +885,33 @@ void ImageRenderer::CleanCache(const std::string& url) } } +void ImageRenderer::SetNativeFragmentShaderCode( Dali::NativeImage& nativeImage ) +{ + const char* fragmentPreFix = nativeImage.GetCustomFragmentPreFix(); + const char* customSamplerTypename = nativeImage.GetCustomSamplerTypename(); + + if( fragmentPreFix ) + { + mNativeFragmentShaderCode = fragmentPreFix; + mNativeFragmentShaderCode += "\n"; + } + + if( mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty() ) + { + mNativeFragmentShaderCode += mImpl->mCustomShader->mFragmentShader; + } + else + { + mNativeFragmentShaderCode += FRAGMENT_SHADER; + } + + if( customSamplerTypename ) + { + mNativeFragmentShaderCode.replace( mNativeFragmentShaderCode.find( DEFAULT_SAMPLER_TYPENAME ), strlen( DEFAULT_SAMPLER_TYPENAME ), customSamplerTypename ); + } + +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/renderers/image/image-renderer.h b/dali-toolkit/internal/controls/renderers/image/image-renderer.h index 4b73fc6..b208b44 100644 --- a/dali-toolkit/internal/controls/renderers/image/image-renderer.h +++ b/dali-toolkit/internal/controls/renderers/image/image-renderer.h @@ -30,6 +30,8 @@ namespace Dali { +class NativeImage; + namespace Toolkit { @@ -200,6 +202,13 @@ private: Renderer CreateRenderer() const; /** + * @brief Creates the Dali::Renderer for NativeImage with custom sampler type and prefix, initializing it + * + * @return Returns the created Dali::Renderer + */ + Renderer CreateNativeImageRenderer() const; + + /** * Callback function of image resource loading succeed * @param[in] image The Image content that we attempted to load from mImageUrl */ @@ -216,6 +225,11 @@ private: */ void CleanCache(const std::string& url); + /** + * Set shader code for nativeimage if it exists + */ + void SetNativeFragmentShaderCode( Dali::NativeImage& nativeImage ); + private: Image mImage; ImageAtlasManager& mAtlasManager; @@ -226,6 +240,8 @@ private: Dali::SamplingMode::Type mSamplingMode; bool mIsAlphaPreMultiplied; + std::string mNativeFragmentShaderCode; + bool mNativeImageFlag; }; } // namespace Internal -- 2.7.4