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_surface_adapter.h"
17 
18 #include <display_type.h>
19 #include <securec.h>
20 #include <sync_fence.h>
21 
22 #include "graphic_common.h"
23 #include "graphic_common_c.h"
24 #include "nweb_log.h"
25 #include "surface_type.h"
26 
27 namespace {
28 constexpr int BITS_PER_PIXEL = 4;
29 }
30 
31 namespace OHOS::NWeb {
32 class NWebOutputFrameCallbackImpl : public NWebOutputFrameCallback {
33 public:
NWebOutputFrameCallbackImpl(wptr<Surface> surface,NWebSurfaceAdapter * adapter)34     NWebOutputFrameCallbackImpl(wptr<Surface> surface, NWebSurfaceAdapter *adapter) : surface_(surface),
35                                                                                       adapter_(adapter) {}
36     ~NWebOutputFrameCallbackImpl() = default;
37 
Handle(const char * buffer,uint32_t width,uint32_t height)38     bool Handle(const char* buffer, uint32_t width, uint32_t height) override
39     {
40         return adapter_->OutputFrameCallback(buffer, width, height, surface_);
41     }
42 
43 private:
44     wptr<Surface> surface_ = nullptr;
45     NWebSurfaceAdapter *adapter_ = nullptr;
46 };
47 
Instance()48 NWebSurfaceAdapter &NWebSurfaceAdapter::Instance()
49 {
50     static NWebSurfaceAdapter surfaceAdapter;
51     return surfaceAdapter;
52 }
53 
GetCreateInfo(sptr<Surface> surface,std::shared_ptr<NWebEngineInitArgs> initArgs,uint32_t width,uint32_t height,bool incognitoMode)54 std::shared_ptr<NWebCreateInfoImpl> NWebSurfaceAdapter::GetCreateInfo(sptr<Surface> surface,
55     std::shared_ptr<NWebEngineInitArgs> initArgs, uint32_t width, uint32_t height, bool incognitoMode)
56 {
57     std::shared_ptr<NWebCreateInfoImpl> createInfo = std::make_shared<NWebCreateInfoImpl>();
58     createInfo->SetEngineInitArgs(initArgs);
59     createInfo->SetProducerSurface(reinterpret_cast<void *>(&surface));
60 
61     if (surface == nullptr) {
62         return createInfo;
63     }
64 
65     createInfo->SetIsIncognitoMode(incognitoMode);
66     createInfo->SetWidth((width == 0) ? (uint32_t)surface->GetDefaultWidth() : width);
67     createInfo->SetHeight((height == 0) ? (uint32_t)surface->GetDefaultHeight() : height);
68 
69     wptr<Surface> surfaceWeak(surface);
70     createInfo->SetOutputFrameCallback(std::make_shared<NWebOutputFrameCallbackImpl>(surfaceWeak, this));
71     return createInfo;
72 }
73 
OutputFrameCallback(const char * buffer,uint32_t width,uint32_t height,wptr<Surface> surfaceWeak)74 bool NWebSurfaceAdapter::OutputFrameCallback(const char *buffer, uint32_t width, uint32_t height,
75                                              wptr<Surface> surfaceWeak)
76 {
77     sptr<Surface> surface = surfaceWeak.promote();
78     if (surface == nullptr) {
79         WVLOG_E("surface is nullptr or has expired");
80         return false;
81     }
82 
83     sptr<SurfaceBuffer> surfaceBuffer = this->RequestBuffer(surface, width, height);
84     if (surfaceBuffer == nullptr) {
85         return false;
86     }
87 
88     if (!this->CopyFrame(surfaceBuffer, buffer, width, height)) {
89         surface->CancelBuffer(surfaceBuffer);
90         return false;
91     }
92 
93     return this->FlushBuffer(surface, surfaceBuffer, width, height);
94 }
95 
RequestBuffer(sptr<Surface> surface,uint32_t width,uint32_t height)96 sptr<SurfaceBuffer> NWebSurfaceAdapter::RequestBuffer(sptr<Surface> surface, uint32_t width, uint32_t height)
97 {
98     if (surface == nullptr) {
99         return nullptr;
100     }
101 
102     BufferRequestConfig config = {
103         .width = width,
104         .height = height,
105         .strideAlignment = sizeof(void *),
106         .format = PIXEL_FMT_RGBA_8888,
107         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
108         .timeout = 0,
109     };
110 
111     sptr<SurfaceBuffer> surfaceBuffer = nullptr;
112     int32_t releaseFence = -1;
113     SurfaceError ret = surface->RequestBuffer(surfaceBuffer, releaseFence, config);
114     if (ret != SURFACE_ERROR_OK) {
115         WVLOG_E("fail to request buffer from surface, errorcode=%{public}d", ret);
116         return nullptr;
117     }
118 
119     sptr<SyncFence> tempFence = new (std::nothrow) SyncFence(releaseFence);
120     if (tempFence == nullptr) {
121         WVLOG_E("new tempFence failed");
122         return nullptr;
123     }
124     tempFence->Wait(100); // 100 ms
125 
126     return surfaceBuffer;
127 }
128 
CopyFrame(sptr<SurfaceBuffer> surfaceBuffer,const char * src,uint32_t width,uint32_t height)129 bool NWebSurfaceAdapter::CopyFrame(
130     sptr<SurfaceBuffer> surfaceBuffer, const char *src, uint32_t width, uint32_t height)
131 {
132     if (surfaceBuffer == nullptr) {
133         return false;
134     }
135 
136     char *dst = reinterpret_cast<char *>(surfaceBuffer->GetVirAddr());
137     if (dst == nullptr) {
138         WVLOG_E("fail to get buffer addr");
139         return false;
140     }
141 
142     uint32_t srcStride = width * BITS_PER_PIXEL;
143     uint32_t dstStride = (uint32_t)surfaceBuffer->GetStride();
144     uint32_t copiedSize = 0;
145 
146     for (uint32_t currHeight = 0; currHeight < height; ++currHeight) {
147         if (copiedSize + dstStride > surfaceBuffer->GetSize()) {
148             WVLOG_E("copy size overflow, drop this frame(%{public}u*%{public}u)", width, height);
149             return false;
150         }
151         errno_t ret = memcpy_s(dst, static_cast<size_t>(srcStride), src, static_cast<size_t>(srcStride));
152         if (ret != EOK) {
153             WVLOG_E("memcpy_s failed");
154             return false;
155         }
156         src += srcStride;
157         dst += dstStride;
158         copiedSize += dstStride;
159     }
160 
161     return true;
162 }
163 
FlushBuffer(sptr<Surface> surface,sptr<SurfaceBuffer> surfaceBuffer,uint32_t width,uint32_t height)164 bool NWebSurfaceAdapter::FlushBuffer(
165     sptr<Surface> surface, sptr<SurfaceBuffer> surfaceBuffer, uint32_t width, uint32_t height)
166 {
167     if (surface == nullptr) {
168         return false;
169     }
170 
171     BufferFlushConfig flushConfig = {
172         .damage = {
173             .w = width,
174             .h = height,
175         },
176         .timestamp = 0,
177     };
178 
179     SurfaceError ret = surface->FlushBuffer(surfaceBuffer, -1, flushConfig);
180     if (ret != SURFACE_ERROR_OK) {
181         WVLOG_E("FAIL flush nweb render frame, ret=%{public}d", ret);
182         return false;
183     }
184 
185     return true;
186 }
187 } // namespace OHOS::NWeb
188