1 /*
2 * Copyright (C) 2024 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 #include "SamplerJS.h"
17
18 #include <meta/api/make_callback.h>
19 #include <meta/api/util.h>
20 #include <meta/interface/intf_task_queue.h>
21 #include <meta/interface/intf_task_queue_registry.h>
22 #include <meta/interface/property/property_events.h>
23 #include <scene/interface/intf_node.h>
24 #include <scene/interface/intf_postprocess.h>
25 #include <scene/interface/intf_scene.h>
26 #include <scene/interface/intf_texture.h>
27 #include <render/intf_render_context.h>
28
29 using IntfPtr = BASE_NS::shared_ptr<CORE_NS::IInterface>;
30 using IntfWeakPtr = BASE_NS::weak_ptr<CORE_NS::IInterface>;
31
RegisterEnums(NapiApi::Object exports)32 void SamplerJS::RegisterEnums(NapiApi::Object exports)
33 {
34 napi_value v;
35 auto env = exports.GetEnv();
36 NapiApi::Object SceneFilter(env);
37 NapiApi::Object SceneSamplerAddressMode(env);
38
39 using SCENE_NS::SamplerFilter;
40 using SCENE_NS::SamplerAddressMode;
41
42 #define DECL_ENUM(enu, type, value) \
43 { \
44 napi_create_uint32(enu.GetEnv(), static_cast<uint32_t>(type::value), &v); \
45 enu.Set(#value, v); \
46 }
47 DECL_ENUM(SceneFilter, SamplerFilter, NEAREST);
48 DECL_ENUM(SceneFilter, SamplerFilter, LINEAR);
49
50 DECL_ENUM(SceneSamplerAddressMode, SamplerAddressMode, REPEAT);
51 DECL_ENUM(SceneSamplerAddressMode, SamplerAddressMode, MIRRORED_REPEAT);
52 DECL_ENUM(SceneSamplerAddressMode, SamplerAddressMode, CLAMP_TO_EDGE);
53 // Do not declare CLAMP_TO_BORDER or MIRROR_CLAMP_TO_EDGE as they are not part of SamplerAddressMode in
54 // sceneResources.d.ts
55 #undef DECL_ENUM
56 exports.Set("SamplerFilter", SceneFilter);
57 exports.Set("SamplerAddressMode", SceneSamplerAddressMode);
58 }
59
60 constexpr auto DEFAULT_FILTER = SCENE_NS::SamplerFilter::NEAREST;
61 constexpr auto DEFAULT_ADDESS_MODE = SCENE_NS::SamplerAddressMode::REPEAT;
62
ConvertToFilter(uint32_t value)63 SCENE_NS::SamplerFilter SamplerJS::ConvertToFilter(uint32_t value)
64 {
65 static constexpr auto MAX_FILTER = static_cast<uint32_t>(SCENE_NS::SamplerFilter::LINEAR);
66 if (value <= MAX_FILTER) {
67 return static_cast<SCENE_NS::SamplerFilter>(value);
68 }
69 return DEFAULT_FILTER;
70 }
71
ConvertFromFilter(SCENE_NS::SamplerFilter value)72 uint32_t SamplerJS::ConvertFromFilter(SCENE_NS::SamplerFilter value)
73 {
74 return static_cast<uint32_t>(value);
75 }
76
ConvertToAddressMode(uint32_t value)77 SCENE_NS::SamplerAddressMode SamplerJS::ConvertToAddressMode(uint32_t value)
78 {
79 static constexpr auto MAX_ADDRESS_MDOE = static_cast<uint32_t>(SCENE_NS::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE);
80 if (value <= MAX_ADDRESS_MDOE) {
81 return static_cast<SCENE_NS::SamplerAddressMode>(value);
82 }
83 return DEFAULT_ADDESS_MODE;
84 }
85
ConvertFromAddressMode(SCENE_NS::SamplerAddressMode value)86 uint32_t SamplerJS::ConvertFromAddressMode(SCENE_NS::SamplerAddressMode value)
87 {
88 return static_cast<uint32_t>(value);
89 }
90
Init(napi_env env,napi_value exports)91 void SamplerJS::Init(napi_env env, napi_value exports)
92 {
93 using namespace NapiApi;
94
95 BASE_NS::vector<napi_property_descriptor> node_props;
96
97 node_props.emplace_back(
98 GetSetProperty<uint32_t, SamplerJS, &SamplerJS::GetMagFilter, &SamplerJS::SetMagFilter>("magFilter"));
99 node_props.emplace_back(
100 GetSetProperty<uint32_t, SamplerJS, &SamplerJS::GetMinFilter, &SamplerJS::SetMinFilter>("minFilter"));
101 node_props.emplace_back(
102 GetSetProperty<uint32_t, SamplerJS, &SamplerJS::GetMipMapMode, &SamplerJS::SetMipMapMode>("mipMapMode"));
103 node_props.emplace_back(
104 GetSetProperty<uint32_t, SamplerJS, &SamplerJS::GetAddressModeU, &SamplerJS::SetAddressModeU>("addressModeU"));
105 node_props.emplace_back(
106 GetSetProperty<uint32_t, SamplerJS, &SamplerJS::GetAddressModeV, &SamplerJS::SetAddressModeV>("addressModeV"));
107 node_props.emplace_back(
108 GetSetProperty<uint32_t, SamplerJS, &SamplerJS::GetAddressModeW, &SamplerJS::SetAddressModeW>("addressModeW"));
109
110 node_props.push_back(MakeTROMethod<NapiApi::FunctionContext<>, SamplerJS, &SamplerJS::Dispose>("destroy"));
111
112 napi_value func;
113 auto status = napi_define_class(env, "Sampler", NAPI_AUTO_LENGTH, BaseObject::ctor<SamplerJS>(),
114 nullptr, node_props.size(), node_props.data(), &func);
115
116 NapiApi::MyInstanceState* mis;
117 NapiApi::MyInstanceState::GetInstance(env, reinterpret_cast<void**>(&mis));
118 if (mis) {
119 mis->StoreCtor("Sampler", func);
120 }
121
122 NapiApi::Object exp1(env, exports);
123 napi_value eType1, v1;
124 napi_create_object(env, &eType1);
125 }
126
Dispose(NapiApi::FunctionContext<> & ctx)127 napi_value SamplerJS::Dispose(NapiApi::FunctionContext<>& ctx)
128 {
129 LOG_V("SamplerJS::Dispose");
130 DisposeNative(nullptr);
131 return {};
132 }
DisposeNative(void *)133 void SamplerJS::DisposeNative(void*)
134 {
135 if (!disposed_) {
136 disposed_ = true;
137 LOG_V("SamplerJS::DisposeNative");
138 UnsetNativeObject();
139 }
140 }
Finalize(napi_env env)141 void SamplerJS::Finalize(napi_env env)
142 {
143 DisposeNative(nullptr);
144 BaseObject::Finalize(env);
145 }
GetInstanceImpl(uint32_t id)146 void* SamplerJS::GetInstanceImpl(uint32_t id)
147 {
148 if (id == SamplerJS::ID)
149 return this;
150 return nullptr;
151 }
152
CreateRawJsObject(napi_env env)153 napi_value SamplerJS::CreateRawJsObject(napi_env env)
154 {
155 // Ei ky tmmnen. Sit ku tn assignaa kohdilleen, ni joo se tekee jotain vissiin.
156 // mutta tn kautta ei voi en muuttaa mitn. Tytyy tehd sama bind ja unbind ku postproc-kamoissa.
157 auto sampler = NapiApi::Object { env };
158 for (auto&& propName : { "magFilter", "minFilter", "mipMapMode" }) {
159 sampler.Set(propName, NapiApi::Value<uint32_t>(env, static_cast<uint32_t>(DEFAULT_FILTER)));
160 }
161 for (auto&& propName : { "addressModeU", "addressModeV", "addressModeW" }) {
162 sampler.Set(propName, NapiApi::Value<uint32_t>(env, static_cast<uint32_t>(DEFAULT_ADDESS_MODE)));
163 }
164
165 // According to the API, Sampler isn't a SceneResource, so it shouldn't have destroy (or other props).
166 // Add it anyway, to remain compatible with SamplerJS.
167 napi_value destroyFunc;
168 // If nullptr isn't ok for cb, use this no-op: [](napi_env, napi_callback_info) { return napi_value {}; }
169 napi_create_function(
170 env, "destroy", NAPI_AUTO_LENGTH, [](napi_env, napi_callback_info) { return napi_value {}; }, nullptr,
171 &destroyFunc);
172 sampler.Set("destroy", destroyFunc);
173 return sampler.ToNapiValue();
174 }
175
SamplerJS(napi_env e,napi_callback_info i)176 SamplerJS::SamplerJS(napi_env e, napi_callback_info i) : BaseObject(e, i)
177 {
178 LOG_V("Sampler ++");
179 if (!GetSampler()) {
180 LOG_E("Cannot finish creating a texture sampler: Native sampler object missing");
181 assert(false);
182 }
183 }
184
~SamplerJS()185 SamplerJS::~SamplerJS()
186 {
187 LOG_V("Sampler --");
188 DisposeNative(nullptr);
189 }
190
GetSampler() const191 SCENE_NS::ISampler::Ptr SamplerJS::GetSampler() const
192 {
193 return GetNativeObject<SCENE_NS::ISampler>();
194 }
195
GetMagFilter(NapiApi::FunctionContext<> & ctx)196 napi_value SamplerJS::GetMagFilter(NapiApi::FunctionContext<>& ctx)
197 {
198 auto sampler = GetSampler();
199 auto filter = sampler ? META_NS::GetValue(sampler->MagFilter()) : DEFAULT_FILTER;
200 return ctx.GetNumber(ConvertFromFilter(filter));
201 }
202
SetMagFilter(NapiApi::FunctionContext<uint32_t> & ctx)203 void SamplerJS::SetMagFilter(NapiApi::FunctionContext<uint32_t>& ctx)
204 {
205 if (auto sampler = GetSampler()) {
206 auto value = ConvertToFilter(ctx.Arg<0>());
207 META_NS::SetValue(sampler->MagFilter(), value);
208 }
209 }
210
GetMinFilter(NapiApi::FunctionContext<> & ctx)211 napi_value SamplerJS::GetMinFilter(NapiApi::FunctionContext<>& ctx)
212 {
213 auto sampler = GetSampler();
214 auto filter = sampler ? META_NS::GetValue(sampler->MinFilter()) : DEFAULT_FILTER;
215 return ctx.GetNumber(ConvertFromFilter(filter));
216 }
217
SetMinFilter(NapiApi::FunctionContext<uint32_t> & ctx)218 void SamplerJS::SetMinFilter(NapiApi::FunctionContext<uint32_t>& ctx)
219 {
220 if (auto sampler = GetSampler()) {
221 auto value = ConvertToFilter(ctx.Arg<0>());
222 META_NS::SetValue(sampler->MinFilter(), value);
223 }
224 }
225
GetMipMapMode(NapiApi::FunctionContext<> & ctx)226 napi_value SamplerJS::GetMipMapMode(NapiApi::FunctionContext<>& ctx)
227 {
228 auto sampler = GetSampler();
229 auto filter = sampler ? META_NS::GetValue(sampler->MipMapMode()) : DEFAULT_FILTER;
230 return ctx.GetNumber(ConvertFromFilter(filter));
231 }
232
SetMipMapMode(NapiApi::FunctionContext<uint32_t> & ctx)233 void SamplerJS::SetMipMapMode(NapiApi::FunctionContext<uint32_t>& ctx)
234 {
235 if (auto sampler = GetSampler()) {
236 auto value = ConvertToFilter(ctx.Arg<0>());
237 META_NS::SetValue(sampler->MipMapMode(), value);
238 }
239 }
240
GetAddressModeU(NapiApi::FunctionContext<> & ctx)241 napi_value SamplerJS::GetAddressModeU(NapiApi::FunctionContext<>& ctx)
242 {
243 auto sampler = GetSampler();
244 auto mode = sampler ? META_NS::GetValue(sampler->AddressModeU()) : DEFAULT_ADDESS_MODE;
245 return ctx.GetNumber(ConvertFromAddressMode(mode));
246 }
247
SetAddressModeU(NapiApi::FunctionContext<uint32_t> & ctx)248 void SamplerJS::SetAddressModeU(NapiApi::FunctionContext<uint32_t>& ctx)
249 {
250 if (auto sampler = GetSampler()) {
251 auto value = ConvertToAddressMode(ctx.Arg<0>());
252 META_NS::SetValue(sampler->AddressModeU(), value);
253 }
254 }
255
GetAddressModeV(NapiApi::FunctionContext<> & ctx)256 napi_value SamplerJS::GetAddressModeV(NapiApi::FunctionContext<>& ctx)
257 {
258 auto sampler = GetSampler();
259 auto mode = sampler ? META_NS::GetValue(sampler->AddressModeV()) : DEFAULT_ADDESS_MODE;
260 return ctx.GetNumber(ConvertFromAddressMode(mode));
261 }
262
SetAddressModeV(NapiApi::FunctionContext<uint32_t> & ctx)263 void SamplerJS::SetAddressModeV(NapiApi::FunctionContext<uint32_t>& ctx)
264 {
265 if (auto sampler = GetSampler()) {
266 auto value = ConvertToAddressMode(ctx.Arg<0>());
267 META_NS::SetValue(sampler->AddressModeV(), value);
268 }
269 }
270
GetAddressModeW(NapiApi::FunctionContext<> & ctx)271 napi_value SamplerJS::GetAddressModeW(NapiApi::FunctionContext<>& ctx)
272 {
273 auto sampler = GetSampler();
274 auto mode = sampler ? META_NS::GetValue(sampler->AddressModeW()) : DEFAULT_ADDESS_MODE;
275 return ctx.GetNumber(ConvertFromAddressMode(mode));
276 }
277
SetAddressModeW(NapiApi::FunctionContext<uint32_t> & ctx)278 void SamplerJS::SetAddressModeW(NapiApi::FunctionContext<uint32_t>& ctx)
279 {
280 if (auto sampler = GetSampler()) {
281 auto value = ConvertToAddressMode(ctx.Arg<0>());
282 META_NS::SetValue(sampler->AddressModeW(), value);
283 }
284 }
285