1 /*
2 * Copyright (c) 2022 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 "nweb_window_adapter.h"
17
18 #include <display_type.h>
19 #include <refbase.h>
20 #include <securec.h>
21 #include <surface.h>
22 #include <ui/rs_surface_node.h>
23
24 #include "graphic_common.h"
25 #include "graphic_common_c.h"
26 #include "nweb_input_event_consumer.h"
27 #include "nweb_log.h"
28 #include "surface_buffer.h"
29 #include "surface_type.h"
30 #include "transaction/rs_interfaces.h"
31 #include "wm_common.h"
32
33 namespace OHOS::NWeb {
34 // static
Instance()35 NWebWindowAdapter &NWebWindowAdapter::Instance()
36 {
37 static NWebWindowAdapter windowAdapter;
38 return windowAdapter;
39 }
40
GetCreateInfo(Rosen::Window * window,const NWebInitArgs & initArgs)41 NWebCreateInfo NWebWindowAdapter::GetCreateInfo(Rosen::Window *window, const NWebInitArgs &initArgs)
42 {
43 NWebCreateInfo createInfo = {
44 .init_args = initArgs,
45 };
46 if (window == nullptr) {
47 return createInfo;
48 }
49 GetSize(window, createInfo);
50 GetRenderInterface(window, createInfo);
51 return createInfo;
52 }
53
GetSize(Rosen::Window * window,NWebCreateInfo & createInfo)54 void NWebWindowAdapter::GetSize(Rosen::Window *window, NWebCreateInfo &createInfo)
55 {
56 createInfo.width = window->GetRect().width_;
57 createInfo.height = window->GetRect().height_;
58 windowInfoMap_[window].width = createInfo.width;
59 windowInfoMap_[window].height = createInfo.height;
60 }
61
GetRenderInterface(Rosen::Window * window,NWebCreateInfo & createInfo)62 void NWebWindowAdapter::GetRenderInterface(Rosen::Window *window, NWebCreateInfo &createInfo)
63 {
64 createInfo.output_render_frame = [window, this] (const char *buffer, uint32_t width, uint32_t height) -> bool {
65 if (windowInfoMap_[window].cachedSurfaceBuffer != nullptr) {
66 WVLOG_I("last cached frame is not consumed, skip this frame output");
67 return false;
68 }
69
70 sptr<Surface> surface = window->GetSurfaceNode()->GetSurface();
71 if (surface == nullptr) {
72 WVLOG_E("surface get from window is nullptr");
73 return false;
74 }
75
76 BufferRequestConfig config = {
77 .width = window->GetRect().width_,
78 .height = window->GetRect().height_,
79 .strideAlignment = sizeof(void *),
80 .format = PIXEL_FMT_RGBA_8888,
81 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
82 .timeout = 0,
83 };
84
85 sptr<SurfaceBuffer> surfaceBuffer;
86 int32_t releaseFence = -1;
87 SurfaceError ret = surface->RequestBuffer(surfaceBuffer, releaseFence, config);
88 if (ret != SURFACE_ERROR_OK) {
89 WVLOG_E("fail to request buffer from surface, errorcode=%{public}d", ret);
90 return false;
91 }
92
93 char *addr = reinterpret_cast<char *>(surfaceBuffer->GetVirAddr());
94 if (addr == nullptr) {
95 WVLOG_E("fail to get buffer addr");
96 surface->CancelBuffer(surfaceBuffer);
97 return false;
98 }
99
100 constexpr uint32_t BITS_PER_PIXEL = 4;
101 uint32_t frameSize = windowInfoMap_[window].width * windowInfoMap_[window].height * BITS_PER_PIXEL;
102 if (windowInfoMap_[window].width != window->GetRect().width_ ||
103 windowInfoMap_[window].height != window->GetRect().height_) {
104 WVLOG_W("nweb output frame size (%{public}u*%{public}u) is different from "
105 "window surface buffer size (%{public}u*%{public}u)",
106 windowInfoMap_[window].width, windowInfoMap_[window].height,
107 window->GetRect().width_, window->GetRect().height_);
108 uint32_t surfaceBufferSize = window->GetRect().width_ * window->GetRect().height_ * BITS_PER_PIXEL;
109 if (surfaceBufferSize < frameSize) {
110 frameSize = surfaceBufferSize;
111 }
112 }
113 if (memcpy_s(addr, frameSize, buffer, frameSize) != EOK) {
114 WVLOG_E("memcpy_s fail, errorcode=%{public}d", ret);
115 return false;
116 }
117
118 windowInfoMap_[window].cachedSurfaceBuffer = surfaceBuffer;
119
120 return true;
121 };
122 }
123
RequestVsync(Rosen::Window * window,std::shared_ptr<NWeb> nweb)124 void NWebWindowAdapter::RequestVsync(Rosen::Window *window, std::shared_ptr<NWeb> nweb)
125 {
126 if (window == nullptr) {
127 return;
128 }
129
130 auto& rsClient = OHOS::Rosen::RSInterfaces::GetInstance();
131 if (receiver_ == nullptr) {
132 receiver_ = rsClient.CreateVSyncReceiver("NWeb_" + std::to_string(::getpid()));
133 if (receiver_ == nullptr) {
134 WVLOG_E("FAIL to CreateVSyncReceiver");
135 return;
136 }
137 }
138 receiver_->Init();
139
140 std::weak_ptr<NWeb> nwebWeak(nweb);
141 VsyncCbInfo *info = new(std::nothrow) VsyncCbInfo { nwebWeak };
142 if (info == nullptr) {
143 return;
144 }
145 Rosen::VSyncReceiver::FrameCallback frameCb = {
146 .userData_ = reinterpret_cast<void *>(info),
147 .callback_ = [window, this] (int64_t time, void *userdata) -> void {
148 VsyncCbInfo *info = reinterpret_cast<VsyncCbInfo *>(userdata);
149 std::weak_ptr<NWeb> nwebWeak = info->nwebWeak;
150 delete info;
151 info = nullptr;
152 if (nwebWeak.expired()) {
153 WVLOG_I("nweb instance has expired, stop request vsync");
154 return;
155 }
156 this->VsyncCb(window, nwebWeak.lock());
157 },
158 };
159
160 int ret = receiver_->RequestNextVSync(frameCb);
161 if (ret != 0) {
162 WVLOG_E("NWebWindowAdapter RequestVsync RequestNextVSync fail, ret=%{public}d", ret);
163 }
164 }
165
VsyncCb(Rosen::Window * window,std::shared_ptr<NWeb> nweb)166 void NWebWindowAdapter::VsyncCb(Rosen::Window *window, std::shared_ptr<NWeb> nweb)
167 {
168 if (window == nullptr) {
169 return;
170 }
171
172 if (windowInfoMap_[window].cachedSurfaceBuffer == nullptr) {
173 RequestVsync(window, nweb);
174 return;
175 }
176
177 sptr<Surface> surface = window->GetSurfaceNode()->GetSurface();
178 if (surface == nullptr) {
179 WVLOG_E("surface get from window is nullptr");
180 RequestVsync(window, nweb);
181 return;
182 }
183
184 BufferFlushConfig flushConfig = {
185 .damage = {
186 .w = window->GetRect().width_,
187 .h = window->GetRect().height_,
188 },
189 .timestamp = 0,
190 };
191
192 SurfaceError ret = surface->FlushBuffer(windowInfoMap_[window].cachedSurfaceBuffer, -1, flushConfig);
193 if (ret == SURFACE_ERROR_OK) {
194 windowInfoMap_[window].cachedSurfaceBuffer = nullptr;
195 } else {
196 WVLOG_E("FAIL flush nweb render frame to window surface, ret=%{public}d", ret);
197 }
198
199 RequestVsync(window, nweb);
200 }
201
RegistEventCb(Rosen::Window * window,std::shared_ptr<NWeb> nweb)202 void NWebWindowAdapter::RegistEventCb(Rosen::Window *window, std::shared_ptr<NWeb> nweb)
203 {
204 if (window == nullptr) {
205 return;
206 }
207
208 std::shared_ptr<Rosen::IInputEventConsumer> inputEventListener =
209 std::make_shared<NWebInputEventConsumer>(nweb);
210
211 window->SetInputEventConsumer(inputEventListener);
212 }
213 } // namespace OHOS::NWeb
214