2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-extension/vector-animation-renderer/vector-animation-renderer-tizen.h>
22 #include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
23 #include <dali/devel-api/common/hash.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/public-api/object/property-array.h>
26 #include <tbm_surface_internal.h>
27 #include <cstring> // for strlen()
30 #include <dali-extension/vector-animation-renderer/vector-animation-plugin-manager.h>
32 // The plugin factories
33 extern "C" DALI_EXPORT_API Dali::VectorAnimationRendererPlugin* CreateVectorAnimationRendererPlugin(void)
35 return new Dali::Plugin::VectorAnimationRendererTizen;
44 const char* const PIXEL_AREA_UNIFORM_NAME("pixelArea");
45 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
47 #if defined(DEBUG_ENABLED)
48 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION");
50 } // unnamed namespace
52 VectorAnimationRendererTizen::VectorAnimationRendererTizen()
61 VectorAnimationRendererTizen::~VectorAnimationRendererTizen()
63 Dali::Mutex::ScopedLock lock(mMutex);
66 DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "this = %p\n", this);
69 bool VectorAnimationRendererTizen::Render(uint32_t frameNumber)
71 Dali::Mutex::ScopedLock lock(mMutex);
75 if(mDecodedBuffers.size() < mTotalFrameNumber)
77 mDecodedBuffers.clear();
78 mDecodedBuffers.resize(mTotalFrameNumber, std::make_pair<std::vector<uint8_t>, bool>(std::vector<uint8_t>(), false));
82 if(!mTbmQueue || !mVectorRenderer || !mTargetSurface)
87 int canDequeue = tbm_surface_queue_can_dequeue(mTbmQueue, 0);
90 // Ignore the previous image which is inserted to the queue.
91 mTargetSurface->IgnoreSourceImage();
94 canDequeue = tbm_surface_queue_can_dequeue(mTbmQueue, 0);
101 tbm_surface_h tbmSurface;
103 if(tbm_surface_queue_dequeue(mTbmQueue, &tbmSurface) != TBM_SURFACE_QUEUE_ERROR_NONE)
105 DALI_LOG_ERROR("Failed to dequeue a tbm_surface [%p]\n", this);
109 tbm_surface_info_s info;
110 int ret = TBM_SURFACE_ERROR_NONE;
112 if(mEnableFixedCache && (frameNumber < mDecodedBuffers.size()) && (!mDecodedBuffers[frameNumber].second))
114 ret = tbm_surface_map(tbmSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &info);
118 ret = tbm_surface_map(tbmSurface, TBM_SURF_OPTION_WRITE, &info);
120 if(ret != TBM_SURFACE_ERROR_NONE)
122 DALI_LOG_ERROR("VectorAnimationRendererTizen::Render: tbm_surface_map is failed! [%d] [%p]\n", ret, this);
123 tbm_surface_queue_cancel_dequeue(mTbmQueue, tbmSurface);
127 unsigned char* buffer = info.planes[0].ptr;
128 if(info.width != mWidth || info.height != mHeight || !buffer)
130 DALI_LOG_ERROR("VectorAnimationRendererTizen::Render: Invalid tbm surface! [%d, %d, %p] [%p]\n", info.width, info.height, buffer, this);
131 tbm_surface_unmap(tbmSurface);
132 tbm_surface_queue_cancel_dequeue(mTbmQueue, tbmSurface);
136 rlottie::Surface surface;
137 bool existing = false;
141 // Need to reset buffer list
146 for(auto&& iter : mBuffers)
148 if(iter.first == tbmSurface)
150 // Find the buffer in the existing list
152 surface = iter.second;
158 if(mEnableFixedCache && (frameNumber < mDecodedBuffers.size()) && mDecodedBuffers[frameNumber].second)
160 const int bufferSize = mWidth * mHeight * Dali::Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888);
161 memcpy(buffer, &mDecodedBuffers[frameNumber].first[0], bufferSize);
167 tbm_surface_internal_ref(tbmSurface);
169 // Create Surface object
170 surface = rlottie::Surface(reinterpret_cast<uint32_t*>(buffer), mWidth, mHeight, static_cast<size_t>(info.planes[0].stride));
173 mBuffers.push_back(SurfacePair(tbmSurface, surface));
176 if(mEnableFixedCache && (frameNumber < mDecodedBuffers.size()))
178 const uint32_t bufferSize = mWidth * mHeight * Dali::Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888);
179 std::vector<uint8_t> rasterizeBuffer(buffer, buffer + bufferSize);
180 mDecodedBuffers[frameNumber].first = std::move(rasterizeBuffer);
181 mDecodedBuffers[frameNumber].second = true;
186 mVectorRenderer->renderSync(frameNumber, surface);
188 tbm_surface_unmap(tbmSurface);
190 tbm_surface_queue_enqueue(mTbmQueue, tbmSurface);
194 mPreviousTextures.push_back(mRenderedTexture); // It is used to destroy the object in the main thread.
196 mRenderedTexture = mTexture;
197 mResourceReady = true;
198 mResourceReadyTriggered = true;
200 VectorAnimationPluginManager::Get().TriggerEvent(*this);
202 DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Resource ready [current = %d] [%p]\n", frameNumber, this);
208 void VectorAnimationRendererTizen::RenderStopped()
212 // Animation is stopped. Free empty buffers
213 mTargetSurface->FreeReleasedBuffers();
216 Dali::Mutex::ScopedLock lock(mMutex);
222 void VectorAnimationRendererTizen::SetShader()
229 Shader shader = mRenderer.GetShader();
231 std::string fragmentShader;
232 std::string vertexShader;
234 // Get the current fragment shader source
235 Property::Value program = shader.GetProperty(Shader::Property::PROGRAM);
236 Property::Map* map = program.GetMap();
239 Property::Value* fragment = map->Find("fragment");
242 fragmentShader = fragment->Get<std::string>();
245 Property::Value* vertex = map->Find("vertex");
248 vertexShader = vertex->Get<std::string>();
252 // Get custom fragment shader prefix
253 mTargetSurface->ApplyNativeFragmentShader(fragmentShader);
255 // Set the modified shader again
256 Shader newShader = Shader::New(vertexShader, fragmentShader);
257 newShader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
259 mRenderer.SetShader(newShader);
261 mShaderChanged = true;
264 void VectorAnimationRendererTizen::ResetBuffers()
266 for(auto&& iter : mBuffers)
268 tbm_surface_internal_unref(iter.first);
273 void VectorAnimationRendererTizen::OnFinalize()
275 mRenderedTexture.Reset();
276 mPreviousTextures.clear();
278 mTargetSurface = nullptr;
282 void VectorAnimationRendererTizen::OnSetSize()
284 mTbmQueue = AnyCast<tbm_surface_queue_h>(mTargetSurface->GetNativeImageSourceQueue());
286 // Reset the previous texture to destroy it in the main thread
287 mPreviousTextures.clear();
290 void VectorAnimationRendererTizen::OnNotify()
292 // Reset the previous texture to destroy it in the main thread
293 mPreviousTextures.clear();
296 void VectorAnimationRendererTizen::PrepareTarget()
298 mTargetSurface = NativeImageSourceQueue::New(mWidth, mHeight, NativeImageSourceQueue::ColorFormat::RGBA8888);
300 mTexture = Texture::New(*mTargetSurface);
303 bool VectorAnimationRendererTizen::IsTargetPrepared()
305 return !!mTargetSurface;
308 bool VectorAnimationRendererTizen::IsRenderReady()
310 return (mResourceReady && mRenderedTexture);
313 Dali::Texture VectorAnimationRendererTizen::GetTargetTexture()
315 return mRenderedTexture;
318 } // namespace Plugin