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