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