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 "surface_draw.h"
17 #include <algorithm>
18 #include <hitrace_meter.h>
19 #include <surface.h>
20 #include <transaction/rs_interfaces.h>
21 #include <ui/rs_surface_extractor.h>
22
23 #include "image/bitmap.h"
24 #include "image_source.h"
25 #include "image_type.h"
26 #include "image_utils.h"
27 #include "render/rs_pixel_map_util.h"
28 #include "surface_capture_future.h"
29 #include "window_manager_hilog.h"
30
31 namespace OHOS {
32 namespace Rosen {
33 namespace {
34 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "SurfaceDraw"};
35 constexpr uint32_t IMAGE_BYTES_STRIDE = 4;
36 } // namespace
37
DrawImage(std::shared_ptr<RSSurfaceNode> surfaceNode,int32_t bufferWidth,int32_t bufferHeight,const std::string & imagePath)38 bool SurfaceDraw::DrawImage(std::shared_ptr<RSSurfaceNode> surfaceNode, int32_t bufferWidth,
39 int32_t bufferHeight, const std::string& imagePath)
40 {
41 sptr<OHOS::Surface> layer = GetLayer(surfaceNode);
42 if (layer == nullptr) {
43 WLOGFE("layer is nullptr");
44 return false;
45 }
46 sptr<OHOS::SurfaceBuffer> buffer = GetSurfaceBuffer(layer, bufferWidth, bufferHeight);
47 if (buffer == nullptr || buffer->GetVirAddr() == nullptr) {
48 return false;
49 }
50 auto addr = static_cast<uint8_t *>(buffer->GetVirAddr());
51 if (!DoDraw(addr, buffer->GetWidth(), buffer->GetHeight(), imagePath)) {
52 WLOGE("draw window pixel failed");
53 return false;
54 }
55 OHOS::BufferFlushConfig flushConfig = {
56 .damage = {
57 .w = buffer->GetWidth(),
58 .h = buffer->GetHeight(),
59 },
60 };
61 OHOS::SurfaceError ret = layer->FlushBuffer(buffer, -1, flushConfig);
62 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
63 WLOGFE("draw pointer FlushBuffer ret:%{public}s", SurfaceErrorStr(ret).c_str());
64 return false;
65 }
66 return true;
67 }
68
DrawImage(std::shared_ptr<RSSurfaceNode> surfaceNode,int32_t bufferWidth,int32_t bufferHeight,std::shared_ptr<Media::PixelMap> pixelMap)69 bool SurfaceDraw::DrawImage(std::shared_ptr<RSSurfaceNode> surfaceNode, int32_t bufferWidth,
70 int32_t bufferHeight, std::shared_ptr<Media::PixelMap> pixelMap)
71 {
72 sptr<OHOS::Surface> layer = GetLayer(surfaceNode);
73 if (layer == nullptr) {
74 WLOGFE("layer is nullptr");
75 return false;
76 }
77 sptr<OHOS::SurfaceBuffer> buffer = GetSurfaceBuffer(layer, bufferWidth, bufferHeight);
78 if (buffer == nullptr || buffer->GetVirAddr() == nullptr) {
79 return false;
80 }
81 auto addr = static_cast<uint8_t *>(buffer->GetVirAddr());
82 if (!DoDraw(addr, buffer->GetWidth(), buffer->GetHeight(), pixelMap)) {
83 WLOGE("draw window pixel failed");
84 return false;
85 }
86 OHOS::BufferFlushConfig flushConfig = {
87 .damage = {
88 .w = buffer->GetWidth(),
89 .h = buffer->GetHeight(),
90 },
91 };
92 OHOS::SurfaceError ret = layer->FlushBuffer(buffer, -1, flushConfig);
93 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
94 WLOGFE("draw pointer FlushBuffer ret:%{public}s", SurfaceErrorStr(ret).c_str());
95 return false;
96 }
97 return true;
98 }
99
DrawColor(std::shared_ptr<RSSurfaceNode> surfaceNode,int32_t bufferWidth,int32_t bufferHeight,uint32_t color)100 bool SurfaceDraw::DrawColor(std::shared_ptr<RSSurfaceNode> surfaceNode, int32_t bufferWidth,
101 int32_t bufferHeight, uint32_t color)
102 {
103 sptr<OHOS::Surface> layer = GetLayer(surfaceNode);
104 if (layer == nullptr) {
105 WLOGFE("layer is nullptr");
106 return false;
107 }
108 sptr<OHOS::SurfaceBuffer> buffer = GetSurfaceBuffer(layer, bufferWidth, bufferHeight);
109 if (buffer == nullptr || buffer->GetVirAddr() == nullptr) {
110 return false;
111 }
112 auto addr = static_cast<uint8_t *>(buffer->GetVirAddr());
113 if (!DoDraw(addr, buffer->GetWidth(), buffer->GetHeight(), color)) {
114 WLOGE("draw window color failed");
115 return false;
116 }
117 OHOS::BufferFlushConfig flushConfig = {
118 .damage = {
119 .w = buffer->GetWidth(),
120 .h = buffer->GetHeight(),
121 },
122 };
123 OHOS::SurfaceError ret = layer->FlushBuffer(buffer, -1, flushConfig);
124 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
125 WLOGFE("draw pointer FlushBuffer ret:%{public}s", SurfaceErrorStr(ret).c_str());
126 return false;
127 }
128 return true;
129 }
130
GetLayer(std::shared_ptr<RSSurfaceNode> surfaceNode)131 sptr<OHOS::Surface> SurfaceDraw::GetLayer(std::shared_ptr<RSSurfaceNode> surfaceNode)
132 {
133 if (surfaceNode == nullptr) {
134 return nullptr;
135 }
136 return surfaceNode->GetSurface();
137 }
138
GetSurfaceBuffer(sptr<OHOS::Surface> layer,int32_t bufferWidth,int32_t bufferHeight)139 sptr<OHOS::SurfaceBuffer> SurfaceDraw::GetSurfaceBuffer(sptr<OHOS::Surface> layer,
140 int32_t bufferWidth, int32_t bufferHeight)
141 {
142 sptr<OHOS::SurfaceBuffer> buffer;
143 int32_t releaseFence = 0;
144 OHOS::BufferRequestConfig config = {
145 .width = bufferWidth,
146 .height = bufferHeight,
147 .strideAlignment = 0x8,
148 .format = GRAPHIC_PIXEL_FMT_RGBA_8888,
149 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
150 };
151
152 OHOS::SurfaceError ret = layer->RequestBuffer(buffer, releaseFence, config);
153 if (ret != OHOS::SURFACE_ERROR_OK) {
154 WLOGFE("request buffer ret:%{public}s", SurfaceErrorStr(ret).c_str());
155 return nullptr;
156 }
157 return buffer;
158 }
159
DecodeImageToPixelMap(const std::string & imagePath)160 std::unique_ptr<OHOS::Media::PixelMap> SurfaceDraw::DecodeImageToPixelMap(const std::string& imagePath)
161 {
162 OHOS::Media::SourceOptions opts;
163 opts.formatHint = "image/png";
164 uint32_t ret = 0;
165 auto imageSource = OHOS::Media::ImageSource::CreateImageSource(imagePath, opts, ret);
166 if (imageSource == nullptr) {
167 WLOGFE("invalid image path.");
168 return nullptr;
169 }
170 std::set<std::string> formats;
171 ret = imageSource->GetSupportedFormats(formats);
172 WLOGFD("get supported format ret:%{public}u", ret);
173
174 OHOS::Media::DecodeOptions decodeOpts;
175 std::unique_ptr<OHOS::Media::PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, ret);
176 if (pixelMap == nullptr) {
177 WLOGFE("pixelMap is nullptr");
178 }
179 return pixelMap;
180 }
181
DrawPixelmap(Drawing::Canvas & canvas,const std::string & imagePath)182 void SurfaceDraw::DrawPixelmap(Drawing::Canvas& canvas, const std::string& imagePath)
183 {
184 std::unique_ptr<OHOS::Media::PixelMap> pixelmap = DecodeImageToPixelMap(imagePath);
185 if (pixelmap == nullptr) {
186 WLOGFE("drawing pixel map is nullptr");
187 return;
188 }
189 Drawing::Pen pen;
190 pen.SetAntiAlias(true);
191 pen.SetColor(Drawing::Color::COLOR_BLUE);
192 Drawing::scalar penWidth = 1;
193 pen.SetWidth(penWidth);
194 canvas.AttachPen(pen);
195 RSPixelMapUtil::DrawPixelMap(canvas, *pixelmap, 0, 0);
196 }
197
DoDraw(uint8_t * addr,uint32_t width,uint32_t height,const std::string & imagePath)198 bool SurfaceDraw::DoDraw(uint8_t* addr, uint32_t width, uint32_t height, const std::string& imagePath)
199 {
200 Drawing::Bitmap bitmap;
201 Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888,
202 Drawing::AlphaType::ALPHATYPE_OPAQUE };
203 bitmap.Build(width, height, format);
204 Drawing::Canvas canvas;
205 canvas.Bind(bitmap);
206 canvas.Clear(Drawing::Color::COLOR_TRANSPARENT);
207 DrawPixelmap(canvas, imagePath);
208 uint32_t addrSize = width * height * IMAGE_BYTES_STRIDE;
209 errno_t ret = memcpy_s(addr, addrSize, bitmap.GetPixels(), addrSize);
210 if (ret != EOK) {
211 WLOGFE("draw failed");
212 return false;
213 }
214 return true;
215 }
216
DoDraw(uint8_t * addr,uint32_t width,uint32_t height,std::shared_ptr<Media::PixelMap> pixelMap)217 bool SurfaceDraw::DoDraw(uint8_t* addr, uint32_t width, uint32_t height, std::shared_ptr<Media::PixelMap> pixelMap)
218 {
219 Drawing::Bitmap bitmap;
220 Drawing::Canvas canvas;
221 Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_OPAQUE };
222 bitmap.Build(width, height, format);
223 canvas.Bind(bitmap);
224 canvas.Clear(Drawing::Color::COLOR_TRANSPARENT);
225
226 Drawing::Image image;
227 Drawing::Bitmap imageBitmap;
228 Drawing::SamplingOptions sampling = Drawing::SamplingOptions(Drawing::FilterMode::NEAREST,
229 Drawing::MipmapMode::NEAREST);
230 imageBitmap.Build(pixelMap->GetWidth(), pixelMap->GetHeight(), format);
231 imageBitmap.SetPixels(const_cast<uint8_t*>(pixelMap->GetPixels()));
232 image.BuildFromBitmap(imageBitmap);
233
234 Drawing::Rect dst(0, 0, width, height);
235 Drawing::Rect src(0, 0, pixelMap->GetWidth(), pixelMap->GetHeight());
236 canvas.DrawImageRect(image, src, dst, sampling);
237
238 uint32_t addrSize = width * height * IMAGE_BYTES_STRIDE;
239 errno_t ret = memcpy_s(addr, addrSize, bitmap.GetPixels(), addrSize);
240 if (ret != EOK) {
241 WLOGFE("draw failed");
242 return false;
243 }
244 return true;
245 }
246
DoDraw(uint8_t * addr,uint32_t width,uint32_t height,uint32_t color)247 bool SurfaceDraw::DoDraw(uint8_t* addr, uint32_t width, uint32_t height, uint32_t color)
248 {
249 Drawing::Bitmap bitmap;
250 Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888,
251 Drawing::AlphaType::ALPHATYPE_OPAQUE };
252 bitmap.Build(width, height, format);
253 Drawing::Canvas canvas;
254 canvas.Bind(bitmap);
255 canvas.Clear(color);
256
257 uint32_t addrSize = width * height * IMAGE_BYTES_STRIDE;
258 errno_t ret = memcpy_s(addr, addrSize, bitmap.GetPixels(), addrSize);
259 if (ret != EOK) {
260 WLOGFE("draw failed");
261 return false;
262 }
263 return true;
264 }
265
DrawImageRect(std::shared_ptr<RSSurfaceNode> surfaceNode,Rect rect,std::shared_ptr<Media::PixelMap> pixelMap,uint32_t color,bool fillWindow)266 bool SurfaceDraw::DrawImageRect(std::shared_ptr<RSSurfaceNode> surfaceNode, Rect rect,
267 std::shared_ptr<Media::PixelMap> pixelMap, uint32_t color, bool fillWindow)
268 {
269 int32_t winHeight = static_cast<int32_t>(rect.height_);
270 int32_t winWidth = static_cast<int32_t>(rect.width_);
271 sptr<OHOS::Surface> layer = GetLayer(surfaceNode);
272 if (layer == nullptr) {
273 WLOGFE("layer is nullptr");
274 return false;
275 }
276 sptr<OHOS::SurfaceBuffer> buffer = GetSurfaceBuffer(layer, winWidth, winHeight);
277 if (buffer == nullptr || buffer->GetVirAddr() == nullptr) {
278 return false;
279 }
280 if (!DoDrawImageRect(buffer, rect, pixelMap, color, fillWindow)) {
281 WLOGE("draw image rect failed.");
282 return false;
283 }
284 OHOS::BufferFlushConfig flushConfig = {
285 .damage = {
286 .w = buffer->GetWidth(),
287 .h = buffer->GetHeight(),
288 },
289 };
290 OHOS::SurfaceError surfaceRet = layer->FlushBuffer(buffer, -1, flushConfig);
291 if (surfaceRet != OHOS::SurfaceError::SURFACE_ERROR_OK) {
292 WLOGFE("draw pointer FlushBuffer ret:%{public}s", SurfaceErrorStr(surfaceRet).c_str());
293 return false;
294 }
295 return true;
296 }
297
DoDrawImageRect(sptr<OHOS::SurfaceBuffer> buffer,const Rect & rect,std::shared_ptr<Media::PixelMap> pixelMap,uint32_t color,bool fillWindow)298 bool SurfaceDraw::DoDrawImageRect(sptr<OHOS::SurfaceBuffer> buffer, const Rect& rect,
299 std::shared_ptr<Media::PixelMap> pixelMap, uint32_t color, bool fillWindow)
300 {
301 int32_t winWidth = static_cast<int32_t>(rect.width_);
302 int32_t winHeight = static_cast<int32_t>(rect.height_);
303 // actual width of the surface buffer after alignment
304 auto bufferStride = buffer->GetStride();
305 int32_t alignWidth = bufferStride / static_cast<int32_t>(IMAGE_BYTES_STRIDE);
306 if (pixelMap == nullptr) {
307 WLOGFE("drawing pixel map failed, because pixel map is nullptr.");
308 return false;
309 }
310 if (pixelMap->GetHeight() <= 0 || pixelMap->GetWidth() <= 0 || winWidth <= 0 || winHeight <= 0) {
311 WLOGFE("drawing pixel map failed, because width or height is invalid.");
312 return false;
313 }
314 Drawing::Bitmap bitmap;
315 Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888,
316 Drawing::AlphaType::ALPHATYPE_OPAQUE };
317 bitmap.Build(alignWidth, winHeight, format);
318 Drawing::Canvas canvas;
319 canvas.Bind(bitmap);
320 canvas.Clear(color);
321 float xAxis = static_cast<float>(winWidth) / pixelMap->GetWidth();
322 float yAxis = static_cast<float>(winHeight) / pixelMap->GetHeight();
323 float axis = std::min(xAxis, yAxis);
324 int scaledPixelMapW = pixelMap->GetWidth();
325 int scaledPixelMapH = pixelMap->GetHeight();
326 if (axis < 1.0) {
327 canvas.Scale(axis, axis);
328 scaledPixelMapW = scaledPixelMapW * axis;
329 scaledPixelMapH = scaledPixelMapH * axis;
330 } else if (fillWindow) {
331 // scale snapshot to whole window
332 canvas.Scale(xAxis, yAxis);
333 scaledPixelMapW = winWidth;
334 scaledPixelMapH = winHeight;
335 }
336 int left = (winWidth - scaledPixelMapW) / 2; // 2 is the left and right boundaries of the win
337 int top = (winHeight - scaledPixelMapH) / 2; // 2 is the top and bottom boundaries of the win
338 WLOGFD("pixelMap width: %{public}d win height: %{public}d left:%{public}d top:%{public}d.",
339 pixelMap->GetWidth(), pixelMap->GetHeight(), left, top);
340 RSPixelMapUtil::DrawPixelMap(canvas, *pixelMap, left, top);
341 // bufferSize is actual size of the surface buffer after alignment
342 int32_t bufferSize = bufferStride * winHeight;
343 uint8_t* bitmapAddr = static_cast<uint8_t*>(bitmap.GetPixels());
344 auto addr = static_cast<uint8_t *>(buffer->GetVirAddr());
345 errno_t ret = memcpy_s(addr, bufferSize, bitmapAddr, bufferSize);
346 if (ret != EOK) {
347 WLOGFE("draw image rect failed, because copy bitmap to buffer failed.");
348 return false;
349 }
350 return true;
351 }
352
GetSurfaceSnapshot(const std::shared_ptr<RSSurfaceNode> surfaceNode,std::shared_ptr<Media::PixelMap> & pixelMap,int32_t timeoutMs,float scaleW,float scaleH)353 bool SurfaceDraw::GetSurfaceSnapshot(const std::shared_ptr<RSSurfaceNode> surfaceNode,
354 std::shared_ptr<Media::PixelMap>&pixelMap, int32_t timeoutMs, float scaleW, float scaleH)
355 {
356 if (surfaceNode == nullptr) {
357 WLOGFE("surfaceNode is null");
358 return false;
359 }
360 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "SurfaceDraw:GetSurfaceSnapshot(%llu)", surfaceNode->GetId());
361 std::shared_ptr<SurfaceCaptureFuture> callback = std::make_shared<SurfaceCaptureFuture>();
362 RSSurfaceCaptureConfig config = {
363 .scaleX = scaleW,
364 .scaleY = scaleH,
365 };
366 if (RSInterfaces::GetInstance().TakeSurfaceCapture(surfaceNode, callback, config)) {
367 pixelMap = callback->GetResult(timeoutMs); // get pixelmap time out ms
368 }
369 if (pixelMap == nullptr) {
370 WLOGE("get surface snapshot timeout.");
371 return false;
372 }
373 return true;
374 }
375
DrawMasking(std::shared_ptr<RSSurfaceNode> surfaceNode,Rect screenRect,Rect transparentRect)376 bool SurfaceDraw::DrawMasking(std::shared_ptr<RSSurfaceNode> surfaceNode, Rect screenRect,
377 Rect transparentRect)
378 {
379 int32_t screenHeight = static_cast<int32_t>(screenRect.height_);
380 int32_t screenWidth = static_cast<int32_t>(screenRect.width_);
381 int32_t transparentHeight = static_cast<int32_t>(transparentRect.height_);
382 int32_t transparentWidth = static_cast<int32_t>(transparentRect.width_);
383 sptr<OHOS::Surface> layer = GetLayer(surfaceNode);
384 if (layer == nullptr) {
385 WLOGFE("layer is nullptr");
386 return false;
387 }
388 sptr<OHOS::SurfaceBuffer> buffer = GetSurfaceBuffer(layer, screenWidth, screenHeight);
389 if (buffer == nullptr || buffer->GetVirAddr() == nullptr) {
390 return false;
391 }
392 auto addr = static_cast<uint8_t *>(buffer->GetVirAddr());
393 Drawing::Bitmap fullbitmap;
394 Drawing::BitmapFormat fullBitmapFormat { Drawing::ColorType::COLORTYPE_RGBA_8888,
395 Drawing::AlphaType::ALPHATYPE_OPAQUE };
396 fullbitmap.Build(screenWidth, screenHeight, fullBitmapFormat);
397 Drawing::Canvas canvas;
398 canvas.Bind(fullbitmap);
399 canvas.Clear(0xFF000000);
400 Drawing::Bitmap transBitmap;
401 Drawing::BitmapFormat transBitmapFormat { Drawing::ColorType::COLORTYPE_RGBA_8888,
402 Drawing::AlphaType::ALPHATYPE_OPAQUE };
403 transBitmap.Build(transparentWidth, transparentHeight, transBitmapFormat);
404 transBitmap.ClearWithColor(0);
405 canvas.DrawBitmap(transBitmap, static_cast<Drawing::scalar>(transparentRect.posX_),
406 static_cast<Drawing::scalar>(transparentRect.posY_));
407
408 uint32_t addrSize = static_cast<uint32_t>(screenWidth * screenHeight * IMAGE_BYTES_STRIDE);
409 errno_t ret = memcpy_s(addr, addrSize, fullbitmap.GetPixels(), addrSize);
410 if (ret != EOK) {
411 WLOGFE("draw failed");
412 return false;
413 }
414 OHOS::BufferFlushConfig flushConfig = {
415 .damage = {
416 .w = buffer->GetWidth(),
417 .h = buffer->GetHeight(),
418 },
419 };
420 OHOS::SurfaceError surfaceRet = layer->FlushBuffer(buffer, -1, flushConfig);
421 if (surfaceRet != OHOS::SurfaceError::SURFACE_ERROR_OK) {
422 WLOGFE("draw masking FlushBuffer ret:%{public}s", SurfaceErrorStr(surfaceRet).c_str());
423 return false;
424 }
425 return true;
426 }
427 } // Rosen
428 } // OHOS