/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
}
END_TEST;
-}
\ No newline at end of file
+}
+
+int UtcDaliControlOffScreenRendering(void)
+{
+ ToolkitTestApplication application;
+
+ Control control = Control::New();
+ control.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+ control.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ application.GetScene().Add(control);
+ control.SetBackgroundColor(Color::RED);
+ DALI_TEST_EQUALS(control.GetProperty(DevelControl::Property::OFFSCREEN_RENDERING).Get<int>(), (int)DevelControl::OffScreenRenderingType::NONE, TEST_LOCATION);
+
+ control.SetProperty(DevelControl::Property::OFFSCREEN_RENDERING, DevelControl::OffScreenRenderingType::REFRESH_ALWAYS);
+ DALI_TEST_EQUALS(control.GetProperty(DevelControl::Property::OFFSCREEN_RENDERING).Get<int>(), (int)DevelControl::OffScreenRenderingType::REFRESH_ALWAYS, TEST_LOCATION);
+ control.SetProperty(DevelControl::Property::OFFSCREEN_RENDERING, DevelControl::OffScreenRenderingType::REFRESH_ONCE);
+ DALI_TEST_EQUALS(control.GetProperty(DevelControl::Property::OFFSCREEN_RENDERING).Get<int>(), (int)DevelControl::OffScreenRenderingType::REFRESH_ONCE, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ control.SetProperty(DevelControl::Property::OFFSCREEN_RENDERING, DevelControl::OffScreenRenderingType::NONE);
+ DALI_TEST_EQUALS(control.GetProperty(DevelControl::Property::OFFSCREEN_RENDERING).Get<int>(), (int)DevelControl::OffScreenRenderingType::NONE, TEST_LOCATION);
+
+ control.Unparent(); // Disconnect fron scene.
+ application.GetScene().Add(control);
+
+ END_TEST;
+}
/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
/// @brief AccessibilityAction signal type.
typedef Signal<bool(const Dali::Accessibility::ActionInfo&)> AccessibilityActionSignalType;
+enum OffScreenRenderingType
+{
+ NONE,
+ REFRESH_ONCE,
+ REFRESH_ALWAYS
+};
+constexpr unsigned int OffScreenRenderingTypeCount = 3u;
+
enum State
{
NORMAL,
* @details Name "accessibilityIsModal", type Property::BOOLEAN.
*/
ACCESSIBILITY_IS_MODAL,
+
+ /**
+ * @brief Whether to draw on offscreen of not.
+ * @details Name "offscreenRendering", type Property::BOOLEAN
+ * @note Default is false.
+ */
+ OFFSCREEN_RENDERING
};
} // namespace Property
const PropertyRegistration Control::Impl::PROPERTY_28(typeRegistration, "accessibilityScrollable", Toolkit::DevelControl::Property::ACCESSIBILITY_SCROLLABLE, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
const PropertyRegistration Control::Impl::PROPERTY_29(typeRegistration, "accessibilityStates", Toolkit::DevelControl::Property::ACCESSIBILITY_STATES, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
const PropertyRegistration Control::Impl::PROPERTY_30(typeRegistration, "accessibilityIsModal", Toolkit::DevelControl::Property::ACCESSIBILITY_IS_MODAL, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_31(typeRegistration, "offScreenRendering", Toolkit::DevelControl::Property::OFFSCREEN_RENDERING, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
// clang-format on
mPanGestureDetector(),
mTapGestureDetector(),
mLongPressGestureDetector(),
+ mOffScreenRenderingContext(nullptr),
+ mOffScreenRenderingType(DevelControl::OffScreenRenderingType::NONE),
mTooltip(NULL),
mInputMethodContext(),
mIdleCallback(nullptr),
mDispatchKeyEvents(true),
mProcessorRegistered(false)
{
- mAccessibilityData = new AccessibilityData(mControlImpl);
- mVisualData = new VisualData(*this);
+ mAccessibilityData = std::make_unique<AccessibilityData>(mControlImpl);
+ mVisualData = std::make_unique<VisualData>(*this);
}
Control::Impl::~Impl()
// Removes the callback from the callback manager in case the control is destroyed before the callback is executed.
Adaptor::Get().RemoveIdle(mIdleCallback);
}
-
- delete mAccessibilityData;
- delete mVisualData;
}
Control::Impl& Control::Impl::Get(Internal::Control& internalControl)
return mVisualData->IsResourceReady();
}
+void Control::Impl::OnSceneConnection()
+{
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::OnSceneConnection number of registered visuals(%d)\n", mVisualData->mVisuals.Size());
+
+ Actor self = mControlImpl.Self();
+
+ for(RegisteredVisualContainer::Iterator iter = mVisualData->mVisuals.Begin(); iter != mVisualData->mVisuals.End(); iter++)
+ {
+ // Check whether the visual is empty and enabled
+ if((*iter)->visual && (*iter)->enabled)
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::OnSceneConnection Setting visual(%d) on scene\n", (*iter)->index);
+ Toolkit::GetImplementation((*iter)->visual).SetOnScene(self);
+ }
+ }
+
+ if(mOffScreenRenderingContext) // mOffScreenRenderingType != NONE
+ {
+ mOffScreenRenderingContext->Enable(Toolkit::Control(mControlImpl.GetOwner()), mOffScreenRenderingType);
+ }
+}
+
void Control::Impl::OnSceneDisconnection()
{
Actor self = mControlImpl.Self();
mVisualData->ClearScene(self);
+
+ if(mOffScreenRenderingContext)
+ {
+ mOffScreenRenderingContext->Disable(Toolkit::Control(mControlImpl.GetOwner()));
+ }
}
void Control::Impl::EnableReadyTransitionOverriden(Toolkit::Visual::Base& visual, bool enable)
}
break;
}
+
+ case Toolkit::DevelControl::Property::OFFSCREEN_RENDERING:
+ {
+ int32_t offscreenRenderingType;
+ if(value.Get(offscreenRenderingType))
+ {
+ controlImpl.mImpl->SetOffScreenRendering(offscreenRenderingType);
+ }
+ break;
+ }
}
}
}
value = controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.isModal;
break;
}
+
+ case Toolkit::DevelControl::Property::OFFSCREEN_RENDERING:
+ {
+ value = controlImpl.mImpl->mOffScreenRenderingType;
+ break;
+ }
}
}
}
}
+void Control::Impl::SetOffScreenRendering(int32_t offScreenRenderingType)
+{
+ // Validate input
+ {
+ constexpr int32_t count = static_cast<int32_t>(DevelControl::OffScreenRenderingTypeCount);
+ if(0 > offScreenRenderingType || offScreenRenderingType >= count)
+ {
+ DALI_LOG_ERROR("Failed to set offscreen rendering. Type index is out of bound.\n");
+ return;
+ }
+ }
+
+ mOffScreenRenderingType = static_cast<DevelControl::OffScreenRenderingType>(offScreenRenderingType);
+ Dali::Toolkit::Control handle(mControlImpl.GetOwner());
+
+ // Disable
+ if(mOffScreenRenderingType == DevelControl::OffScreenRenderingType::NONE)
+ {
+ if(mOffScreenRenderingContext)
+ {
+ mOffScreenRenderingContext->Disable(handle);
+ mOffScreenRenderingContext.reset();
+ }
+ }
+ // Enable
+ else
+ {
+ if(mOffScreenRenderingContext)
+ {
+ mOffScreenRenderingContext->Disable(handle);
+ }
+ else
+ {
+ Dali::Toolkit::Control handle(mControlImpl.GetOwner());
+ mOffScreenRenderingContext = std::make_unique<OffScreenRenderingContext>();
+ }
+ mOffScreenRenderingContext->Enable(handle, mOffScreenRenderingType);
+ }
+}
+
void Control::Impl::Process(bool postProcessor)
{
// Call ApplyFittingMode
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/internal/controls/render-effects/offscreen-rendering-context.h>
#include <dali-toolkit/internal/controls/tooltip/tooltip.h>
#include <dali-toolkit/public-api/controls/control-impl.h>
#include <dali-toolkit/public-api/controls/render-effects/render-effect.h>
*/
bool IsResourceReady() const;
+ /**
+ * @copydoc CustomActorImpl::OnSceneConnection()
+ */
+ void OnSceneConnection();
+
/**
* @copydoc CustomActorImpl::OnSceneDisconnection()
*/
*/
void RegisterProcessorOnce();
+ /**
+ * Set off-screen rendering.
+ * @param[in] offScreenRenderingType enum OffScreenRenderingType
+ */
+ void SetOffScreenRendering(int32_t offScreenRenderingType);
+
protected: // From processor-interface
/**
* @copydoc Dali::Integration::Processor::Process()
DevelControl::State mState;
std::string mSubStateName;
- AccessibilityData* mAccessibilityData;
- VisualData* mVisualData;
+ std::unique_ptr<AccessibilityData> mAccessibilityData;
+ std::unique_ptr<VisualData> mVisualData;
int mLeftFocusableActorId; ///< Actor ID of Left focusable control.
int mRightFocusableActorId; ///< Actor ID of Right focusable control.
TapGestureDetector mTapGestureDetector;
LongPressGestureDetector mLongPressGestureDetector;
+ // Off screen rendering context
+ std::unique_ptr<OffScreenRenderingContext> mOffScreenRenderingContext;
+ DevelControl::OffScreenRenderingType mOffScreenRenderingType;
+
// Tooltip
TooltipPtr mTooltip;
static const PropertyRegistration PROPERTY_28;
static const PropertyRegistration PROPERTY_29;
static const PropertyRegistration PROPERTY_30;
+ static const PropertyRegistration PROPERTY_31;
};
} // namespace Internal
--- /dev/null
+/*
+ * Copyright (c) 2024 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/controls/render-effects/offscreen-rendering-context.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/control/control-renderers.h>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
+
+// EXTERNAL INCLUDES
+#include <integration-api/debug.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+bool OffScreenRenderingContext::IsEnabled()
+{
+ return mCamera && mRenderer;
+}
+
+void OffScreenRenderingContext::Enable(Toolkit::Control control, DevelControl::OffScreenRenderingType type)
+{
+ if(type == DevelControl::OffScreenRenderingType::NONE)
+ {
+ return;
+ }
+
+ // Create resources
+ if(!IsEnabled())
+ {
+ Integration::SceneHolder sceneHolder = Integration::SceneHolder::Get(control);
+ if(DALI_UNLIKELY(!sceneHolder))
+ {
+ DALI_LOG_ERROR("Could not enable offscreen rendering. The control is not connected to a scene.\n");
+ return;
+ }
+ mSceneHolder = sceneHolder;
+
+ const Size size = control.GetProperty<Size>(Actor::Property::SIZE);
+
+ mCamera = CameraActor::New(size);
+ mCamera.SetInvertYAxis(true);
+ mCamera.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+ mCamera.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+ mCamera.SetType(Camera::FREE_LOOK);
+ mCamera.SetPerspectiveProjection(size);
+ control.Add(mCamera);
+
+ mFrameBuffer = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
+ Texture texture = Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, size.width, size.height);
+ mFrameBuffer.AttachColorTexture(texture);
+
+ RenderTaskList taskList = sceneHolder.GetRenderTaskList();
+ mRenderTask = taskList.CreateTask();
+ mRenderTask.SetSourceActor(control);
+ mRenderTask.SetCameraActor(mCamera);
+ mRenderTask.SetExclusive(true);
+ mRenderTask.SetInputEnabled(false);
+ mRenderTask.SetFrameBuffer(mFrameBuffer);
+ mRenderTask.SetClearEnabled(true);
+ mRenderTask.SetClearColor(sceneHolder.GetBackgroundColor());
+
+ mRenderer = CreateRenderer(SHADER_CONTROL_RENDERERS_VERT, SHADER_CONTROL_RENDERERS_FRAG);
+ SetRendererTexture(mRenderer, mFrameBuffer);
+
+ control.GetImplementation().SetCacheRenderer(mRenderer);
+ control.GetImplementation().SetOffScreenRenderableType(OffScreenRenderable::Type::FORWARD);
+ }
+
+ // Set refresh rate
+ if(type == DevelControl::OffScreenRenderingType::REFRESH_ALWAYS)
+ {
+ mRenderTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
+ }
+ else if(type == DevelControl::OffScreenRenderingType::REFRESH_ONCE)
+ {
+ mRenderTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
+ }
+}
+
+void OffScreenRenderingContext::Disable(Toolkit::Control control)
+{
+ if(IsEnabled())
+ {
+ if(DALI_LIKELY(control))
+ {
+ control.GetImplementation().RemoveCacheRenderer();
+
+ mCamera.Unparent();
+ control.GetImplementation().SetOffScreenRenderableType(OffScreenRenderable::Type::NONE);
+ }
+
+ auto sceneHolder = mSceneHolder.GetHandle();
+ if(DALI_LIKELY(sceneHolder))
+ {
+ RenderTaskList taskList = sceneHolder.GetRenderTaskList();
+ taskList.RemoveTask(mRenderTask);
+ }
+ mSceneHolder.Reset();
+
+ mFrameBuffer.Reset();
+ mRenderTask.Reset();
+ mCamera.Reset();
+ mRenderer.Reset();
+ }
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_INTERNAL_OFFSCREEN_RENDERING_CONTEXT
+#define DALI_TOOLKIT_INTERNAL_OFFSCREEN_RENDERING_CONTEXT
+
+/*
+ * Copyright (c) 2024 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/scene-holder.h>
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/object/weak-handle.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/rendering/frame-buffer.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <integration-api/adaptor-framework/scene-holder.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+class OffScreenRenderingContext
+{
+public:
+ OffScreenRenderingContext() = default;
+ void Enable(Toolkit::Control control, DevelControl::OffScreenRenderingType type);
+ void Disable(Toolkit::Control control);
+
+private:
+ bool IsEnabled();
+
+private:
+ RenderTask mRenderTask;
+ CameraActor mCamera;
+ FrameBuffer mFrameBuffer;
+ Renderer mRenderer;
+
+ WeakHandle<Integration::SceneHolder> mSceneHolder;
+};
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+#endif //DALI_TOOLKIT_INTERNAL_OFFSCREEN_RENDERING_CONTEXT
${toolkit_src_dir}/controls/alignment/alignment-impl.cpp
${toolkit_src_dir}/controls/render-effects/render-effect-impl.cpp
${toolkit_src_dir}/controls/render-effects/blur-effect-impl.cpp
+ ${toolkit_src_dir}/controls/render-effects/offscreen-rendering-context.cpp
${toolkit_src_dir}/controls/bloom-view/bloom-view-impl.cpp
${toolkit_src_dir}/controls/bubble-effect/bubble-emitter-impl.cpp
${toolkit_src_dir}/controls/bubble-effect/bubble-renderer.cpp
void Control::OnSceneConnection(int depth)
{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::OnSceneConnection number of registered visuals(%d)\n", mImpl->mVisualData->mVisuals.Size());
-
- Actor self(Self());
-
- for(RegisteredVisualContainer::Iterator iter = mImpl->mVisualData->mVisuals.Begin(); iter != mImpl->mVisualData->mVisuals.End(); iter++)
- {
- // Check whether the visual is empty and enabled
- if((*iter)->visual && (*iter)->enabled)
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::OnSceneConnection Setting visual(%d) on scene\n", (*iter)->index);
- Toolkit::GetImplementation((*iter)->visual).SetOnScene(self);
- }
- }
+ mImpl->OnSceneConnection();
// The clipping renderer is only created if required.
CreateClippingRenderer(*this);