• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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