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