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 31namespace OHOS { 32namespace Rosen { 33namespace { 34constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "SurfaceDraw"}; 35constexpr uint32_t IMAGE_BYTES_STRIDE = 4; 36} // namespace 37 38bool 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 69bool 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 100bool 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 131sptr<OHOS::Surface> SurfaceDraw::GetLayer(std::shared_ptr<RSSurfaceNode> surfaceNode) 132{ 133 if (surfaceNode == nullptr) { 134 return nullptr; 135 } 136 return surfaceNode->GetSurface(); 137} 138 139sptr<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 160std::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 182void 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 198bool 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 217bool 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 247bool 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 266bool 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 298bool 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 353bool 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 376bool 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