1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ROSEN_RENDER_SERVICE_BASE_COMMAND_RS_COMMAND_TEMPLATES_H
17 #define ROSEN_RENDER_SERVICE_BASE_COMMAND_RS_COMMAND_TEMPLATES_H
18 
19 #include <cinttypes>
20 #include "command/rs_command.h"
21 #include "command/rs_command_factory.h"
22 #include "transaction/rs_marshalling_helper.h"
23 
24 namespace OHOS {
25 namespace Rosen {
26 class RSUIDirector;
27 
28 // avoiding C++ macros spliting parameters
29 #ifndef ARG
30 #define ARG(...) __VA_ARGS__
31 #endif
32 
33 // Add new RSCommand as alias of template class
34 // Explicit instantiating templates will register the unmarshalling function into RSCommandFactory.
35 // To avoid redundant registry, make sure templates only instantiated once.
36 #ifdef ROSEN_INSTANTIATE_COMMAND_TEMPLATE
37 #define ADD_COMMAND(ALIAS, TYPE)           \
38     using ALIAS = RSCommandTemplate<TYPE>; \
39     template class RSCommandTemplate<TYPE>;
40 #else
41 #define ADD_COMMAND(ALIAS, TYPE) using ALIAS = RSCommandTemplate<TYPE>;
42 #endif
43 
44 template<uint16_t commandType, uint16_t commandSubType, auto processFunc, typename... Params>
45 class RSCommandTemplate : public RSCommand {
46 public:
RSCommandTemplate(const Params &...params)47     RSCommandTemplate(const Params&... params) : params_(params...) {}
RSCommandTemplate(std::tuple<Params...> && params)48     RSCommandTemplate(std::tuple<Params...>&& params) : params_(std::move(params)) {}
49     ~RSCommandTemplate() override = default;
50 
GetType()51     uint16_t GetType() const override
52     {
53         return commandType;
54     }
GetSubType()55     uint16_t GetSubType() const override
56     {
57         return commandSubType;
58     }
59 
GetDrawCmdList()60     std::shared_ptr<Drawing::DrawCmdList> GetDrawCmdList() const override
61     {
62         if constexpr (std::tuple_size<decltype(params_)>::value > 1) {
63             using ptrType = typename std::tuple_element<1, decltype(params_)>::type;
64             if constexpr (std::is_same<std::shared_ptr<Drawing::DrawCmdList>, ptrType>::value) {
65                 return std::get<1>(params_);
66             } else if constexpr (std::is_same<std::shared_ptr<RSRenderModifier>, ptrType>::value) {
67                 auto& modifier = std::get<1>(params_);
68                 if (modifier) {
69                     return modifier->GetPropertyDrawCmdList();
70                 }
71             }
72         }
73         return nullptr;
74     }
75 
GetNodeId()76     NodeId GetNodeId() const override
77     {
78         using idType = typename std::tuple_element<0, decltype(params_)>::type;
79         if (std::is_same<NodeId, idType>::value) {
80             return std::get<0>(params_);
81         }
82         return 0; // invalidId
83     }
84 
Process(RSContext & context)85     void Process(RSContext& context) override
86     {
87         // expand the tuple to function parameters
88         std::apply([&context](auto&... args) { return (*processFunc)(context, args...); }, params_);
89     }
90 
Marshalling(Parcel & parcel)91     bool Marshalling(Parcel& parcel) const override
92     {
93         return RSMarshallingHelper::Marshalling(parcel, commandType) &&
94                RSMarshallingHelper::Marshalling(parcel, commandSubType) &&
95                std::apply([&parcel](const auto&... args) { return RSMarshallingHelper::Marshalling(parcel, args...); },
96                    params_);
97     };
98 
Unmarshalling(Parcel & parcel)99     [[nodiscard]] static RSCommand* Unmarshalling(Parcel& parcel)
100     {
101         std::tuple<Params...> params;
102         if (!std::apply(
103             [&parcel](auto&... args) { return RSMarshallingHelper::Unmarshalling(parcel, args...); }, params)) {
104             return nullptr;
105         }
106         return new RSCommandTemplate(std::move(params));
107     }
108 
109     static inline RSCommandRegister<commandType, commandSubType, Unmarshalling> registry;
110 
111 private:
112     std::tuple<Params...> params_;
113 
114 #ifdef RS_PROFILER_ENABLED
Patch(PatchFunction function)115     void Patch(PatchFunction function) override
116     {
117         PatchParameters(function, params_, std::make_index_sequence<std::tuple_size_v<decltype(params_)>> {});
118     }
119 
120     template<typename T, std::size_t... Index>
PatchParameters(PatchFunction function,T & params,std::index_sequence<Index...>)121     static void PatchParameters(PatchFunction function, T& params, std::index_sequence<Index...>)
122     {
123         (PatchParameter(function, std::get<Index>(params)), ...);
124     }
125 
126     template<typename T>
PatchParameter(PatchFunction function,T & value)127     static void PatchParameter(PatchFunction function, T& value)
128     {
129         if (std::is_same<NodeId, T>::value || std::is_same<AnimationId, T>::value ||
130             std::is_same<PropertyId, T>::value) {
131             auto& id = reinterpret_cast<NodeId&>(value);
132             id = function(id);
133         }
134     }
135 #endif
136 };
137 } // namespace Rosen
138 } // namespace OHOS
139 
140 #endif // ROSEN_RENDER_SERVICE_BASE_COMMAND_RS_COMMAND_TEMPLATES_H
141