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