OpenHarmony dump渲染和合成图层SurfaceBuffer指南

news2024/12/25 22:19:18

      OpenHarmony dump渲染和合成图层SurfaceBuffer指南



引言

  博客停更很久了,提起笔来渐感生疏啊!看来,还是得抽出时间来更新更新啊!好了,感慨也发完了,是时候切入正题了。本篇博客主要以本人在实际项目的开发中,为了定位OpenHarmony显示异常究竟是GPU渲染,合成的问题,还是DC端送显异常的问题而来。这里为了后续的复盘,也为可能有共同需求的朋友所以记录下来,最终发展成为如何dump OpenHarmony渲染和合成图层SurfaceBuffer为png图片。(主要是教大家如何把锅甩给队友)!通过本篇博客,读者将会至少学会如下两点:

  • 通过dump OpenHarmony渲染图层SurfaceBuffer,查看OpenHarmony渲染结果是否正确
  • 通过dump OpenHarmony合成图层SurfaceBuffer,查看OpenHarmony合成结果是否正确

    这里需要注意一点的是,这里的合成指的是GPU(Client)的合成方式!

好了不多说了,直接开干!

能搜寻到这篇博客的,肯定是对OpenHarmony SurfaceBuffer有一定掌握的朋友,所以这里就不会过多解释一些名词和代码逻辑了。总之这是一篇专业性比较强的文章(因为一般的朋友也不会搜这个)!

注意:本篇的介绍是基于OpenHarmony 3.2 release平台为基础的,其中涉及的代码路径如下:

foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_render_service_visitor.cpp
foundation/graphic/graphic_2d/rosen/modules/composer/hdi_backend/src/hdi_backend.cpp



一.自定义逻辑dump OpenHarmony渲染和合成图层SurfaceBuffer指南

由于此篇博客是实战类型的,所以也就不必对小伙伴们吆喝什么的了,这里没有九块九包邮,也没有九块九上车。有的只有是兄弟就砍一刀。


1.1 dump OpenHarmony渲染图层SurfaceBuffer

我们知道OpenHarmony中各个渲染图层是以RSSurfaceRenderNode存在的,所以我们只需要将RSSurfaceRenderNode对应的SurfaceBuffer保存成png图片即可。这里我们直接上我封装好的逻辑代码:

//头文件
#ifndef HDI_BACKEND_UTIL_H
#define HDI_BACKEND_UTIL_H


#include <vector>
#include <iostream>
#include <string>
#include "surface_buffer.h"
#include <unordered_map>
#include <refbase.h>
#include <parameter.h>
#include <parameters.h>
#include "pipeline/rs_surface_render_node.h"
namespace OHOS {
namespace Rosen {

using WriteToPngParam = struct {
    uint32_t width;
    uint32_t height;
    uint32_t stride;
    uint32_t bitDepth;
    const uint8_t *data;
};


class RSBaseRenderUtil {
public:
    static const int ALLSURFACES = 2;
    static bool WriteHdiOutToPng(const sptr<SurfaceBuffer> &buffer, const BufferHandle *bufferHandle);
    static bool WriteSurfaceBufferToPng(const sptr<SurfaceBuffer> &buffer);
    static bool WriteSurfaceRenderNodeToPng(const RSSurfaceRenderNode& node);

private:
    static bool WriteToPng(const std::string &filename, const WriteToPngParam &param);
    
};


} // namespace Rosen
} // namespace OHOS

#endif // HDI_BACKEND_UTIL_H





//具体实现
#include "hdi_backend_util.h"
#include "png.h"
#include "hdi_log.h"
#include <sys/time.h>


namespace OHOS {
namespace Rosen {

bool RSBaseRenderUtil::WriteToPng(const std::string &filename, const WriteToPngParam &param)
{
    HLOGI("RSBaseRenderUtil::WriteToPng filename = %s{public}", filename.c_str());
    png_structp pngStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    if (pngStruct == nullptr) {
        return false;
    }
    png_infop pngInfo = png_create_info_struct(pngStruct);
    if (pngInfo == nullptr) {
        png_destroy_write_struct(&pngStruct, nullptr);
        return false;
    }

    FILE *fp = fopen(filename.c_str(), "wb");
    if (fp == nullptr) {
        png_destroy_write_struct(&pngStruct, &pngInfo);
        return false;
    }
    png_init_io(pngStruct, fp);

    // set png header
    png_set_IHDR(pngStruct, pngInfo,
        param.width, param.height,
        param.bitDepth,
        PNG_COLOR_TYPE_RGBA,
        PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_BASE,
        PNG_FILTER_TYPE_BASE);
    png_set_packing(pngStruct); // set packing info
    png_write_info(pngStruct, pngInfo); // write to header

    for (uint32_t i = 0; i < param.height; i++) {
        png_write_row(pngStruct, param.data + (i * param.stride));
    }
    png_write_end(pngStruct, pngInfo);

    // free
    png_destroy_write_struct(&pngStruct, &pngInfo);
    int ret = fclose(fp);
    return ret == 0;
}


bool RSBaseRenderUtil::WriteHdiOutToPng(const sptr<SurfaceBuffer> &buffer, const BufferHandle *bufferHandle)
{
    if((std::atoi((system::GetParameter("rosen.dump.surfacebuffer", "0")).c_str()) == ALLSURFACES) )
    {
        HLOGE("allow WriteHdiOutToPng");
        {
            if (bufferHandle == nullptr) {
                return false;
            }
            struct timeval now;
            gettimeofday(&now, nullptr);
            constexpr int secToUsec = 1000 * 1000;
            int64_t nowVal =  static_cast<int64_t>(now.tv_sec) * secToUsec + static_cast<int64_t>(now.tv_usec);
            std::string filename = "/data/hdioutput/hdi_output_layer_" +
                std::to_string(nowVal) + ".png";

            WriteToPngParam param;
            param.width = static_cast<uint32_t>(bufferHandle->width);
            param.height = static_cast<uint32_t>(bufferHandle->height);
            param.data = (uint8_t*)(buffer->GetVirAddr());
            param.stride = static_cast<uint32_t>(bufferHandle->stride);
            param.bitDepth = 8;
            
            WriteToPng(filename, param);
            
        }
    }
    return false;
}


bool RSBaseRenderUtil::WriteSurfaceBufferToPng(const sptr<SurfaceBuffer> &buffer)
{
    if((std::atoi((system::GetParameter("rosen.dump.surfacebuffer", "0")).c_str()) == ALLSURFACES) )
    {
        HLOGE("allow WriteHdiOutToPng");
        {
            BufferHandle *bufferHandle = buffer->GetBufferHandle();
            if (bufferHandle == nullptr) {
                return false;
            }
            struct timeval now;
            gettimeofday(&now, nullptr);
            constexpr int secToUsec = 1000 * 1000;
            int64_t nowVal =  static_cast<int64_t>(now.tv_sec) * secToUsec + static_cast<int64_t>(now.tv_usec);
            std::string filename = "/data/hdioutput/hdi_output_layer_" +
                std::to_string(nowVal) + ".png";

            WriteToPngParam param;
            param.width = static_cast<uint32_t>(bufferHandle->width);
            param.height = static_cast<uint32_t>(bufferHandle->height);
            param.data = (uint8_t*)(buffer->GetVirAddr());
            param.stride = static_cast<uint32_t>(bufferHandle->stride);
            param.bitDepth = 8;
            
            WriteToPng(filename, param);
            
        }
    }
    return false;
}


bool RSBaseRenderUtil::WriteSurfaceRenderNodeToPng(const RSSurfaceRenderNode& node)
{
    if((std::atoi((system::GetParameter("rosen.dump.rendernode", "0")).c_str()) == ALLSURFACES))
    {
        sptr<SurfaceBuffer> buffer = node.GetBuffer();
        if (buffer == nullptr) {
            return false;
        }
        BufferHandle *bufferHandle =  buffer->GetBufferHandle();
        if (bufferHandle == nullptr) {
            return false;
        }

        struct timeval now;
        gettimeofday(&now, nullptr);
        constexpr int secToUsec = 1000 * 1000;
        int64_t nowVal =  static_cast<int64_t>(now.tv_sec) * secToUsec + static_cast<int64_t>(now.tv_usec);
        std::string filename = "/data/SurfaceRenderNode_" +
            node.GetName() + "_"  +
            std::to_string(node.GetId()) + "_" +
            std::to_string(nowVal) + ".png";

        WriteToPngParam param;
        param.width = static_cast<uint32_t>(bufferHandle->width);
        param.height = static_cast<uint32_t>(bufferHandle->height);
        param.data = (uint8_t*)(buffer->GetVirAddr());
        param.stride = static_cast<uint32_t>(bufferHandle->stride);
        param.bitDepth = 8;

        return WriteToPng(filename, param);      
    }

    return false;
}

}// namespace Rosen
} // namespace OHOS


接下来我们要做的就是在OpenHarmony的处理逻辑中,调用什么的源码进行dump,具体操作步骤如下:

  • 在rs_render_service_visitor.cpp中引入上述头文件,并且在下面引入dump

    //foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_render_service_visitor.cpp
    void RSRenderServiceVisitor::ProcessSurfaceRenderNode(RSSurfaceRenderNode& node)
    {
    	...
    	//不一定要在这个地方,只需要是渲染后对对应的RSSurfaceRenderNode操作即可
        RSBaseRenderUtil::WriteSurfaceRenderNodeToPng(node);
        ...
    }
    
  • 当我们想要dump时候,只需要将对应parma打开即可

    rosen.dump.rendernode
    
  • 接着就可以在data目录下看到生成的png图片
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


1.2 dump OpenHarmony合成图层SurfaceBuffer

这块我们可以在hdi_backend.cpp的如下方法中添加相关的逻辑,如下:

int32_t HdiBackend::SetScreenClientInfo(const FrameBufferEntry &fbEntry, const OutputPtr &output)
{
	...
    RSBaseRenderUtil::WriteSurfaceBufferToPng(fbEntry.buffer);
    ...
}

这当然上述仅仅是提供了一种思路,具体的上述源码逻辑用在什么地方,读者可以根据自己的需要自行调整。这里我们简单测试一下,看看生成的dump文件如下:

在这里插入图片描述

在这里插入图片描述




二.OpenHarmony dump渲染和合成图层SurfaceBuffer指南小结和注意事项

到这里dump的相关逻辑就告一段落了,细心的朋友也许会发现dump渲染和合成的图层代码逻辑基本完全一致。是的,这是因为无论是渲染的图层还是合成之后的图层它们都是通过SurfaceBuffer来进行存储指向的。

其中,我们引用上述封装好的dump函数时候,我们在对应的BUILD.gn中必须,引入如下的库和头文件,如下

  deps = [
   "//foundation/graphic/graphic_2d:libsurface",
	"//foundation/graphic/graphic_2d/rosen/modules/render_service_base:librender_service_base",
  ]

  public_deps = [
    "//foundation/graphic/graphic_2d/utils:buffer_handle",
    "//third_party/libpng:libpng",
  ]
  external_deps = [ "init:libbegetutil" ]
  include_dirs = [
    "//drivers/peripheral/display/interfaces/include",
    "//third_party/libpng",
  ]

这里我们简单总结下dump OpenHarmony中各种图层SurfaceBuffer内容的思路:

  • 首先要获取各种图层所指向的GraphicBuffer
  • 获取GraphicBuffer的存储地址(通常是通过内存映射过来的)
  • 然后将获取到的地址中的内容,以一定的格式进行存储,通常是GRB888格式(也可以进行相关的封装)

这里重点补充一下,关于dump SurfaceBuffer获取的信息大小,格式,以及存储计算规则是否正确可以通过hidumper -s RenderService -a allInfo 进行查看,如下:

# hidumper  -s RenderService

-------------------------------[ability]-------------------------------


----------------------------------RenderService---------------------------------
------Graphic2D--RenderSerice ------
Usage:
 h                             |help text for the tool
screen                         |dump all screen infomation in the system
surface                        |dump all surface information
composer fps                   |dump the fps info of composer
[surface name] fps             |dump the fps info of surface
composer fpsClear                   |clear the fps info of composer
[surface name] fpsClear             |clear the fps info of surface
nodeNotOnTree                  |dump nodeNotOnTree info
allSurfacesMem                 |dump surface mem info
RSTree                         |dump RSTree info
EventParamList                 |dump EventParamList info
allInfo                        |dump all info


# hidumper  -s RenderService -a allInfo                                        


-------------------------------[ability]-------------------------------


----------------------------------RenderService---------------------------------
-- ScreenInfo
screen[0]: id=2, powerstatus=POWER_STATUS_ON, backlight=-1, screenType=EXTERNAL_TYPE
  supportedMode[0]: 720x400, refreshrate=70
  supportedMode[1]: 640x480, refreshrate=60
  supportedMode[2]: 640x480, refreshrate=75
  supportedMode[3]: 800x600, refreshrate=60
  supportedMode[4]: 800x600, refreshrate=75
  supportedMode[5]: 1024x768, refreshrate=60
  supportedMode[6]: 1152x864, refreshrate=75
  supportedMode[7]: 1280x1024, refreshrate=60
  supportedMode[8]: 1280x1024, refreshrate=75
  supportedMode[9]: 1920x1080, refreshrate=60
  activeMode: 1920x1080, refreshrate=60
  capability: name=Unknown, phywidth=530, phyheight=300,supportlayers=0, virtualDispCount=0, propCount=0, type=INVILID_DISP_INTF, supportWriteBack=false

-- LayerInfo

 surface [ScreenLockWindow] NodeId[2954937499653] LayerId[2]://锁屏界面
 zOrder = 0, visibleNum = 1, transformType = 0 <no rotation>, compositionType = 0 <client composistion>, blendType = 3 <SRC_OVER blending>, layerAlpha = [enGlobalAlpha(1), enPixelAlpha(0), alpha0(0), alpha1(0), gAlpha(255)].
 layerRect = [0, 0, 1920, 1080], visibleRegion = [0, 0, 1920, 1080], dirtyRegion = [0, 0, 1920, 1080], cropRect = [0, 0, 1920, 1080].
    BufferQueue:
      default-size = [1920x1080], FIFO = 3, name = ScreenLockWindow, uniqueId = 2954937499653, usedBufferListLen = 3, freeBufferListLen = 2, dirtyBufferListLen = 0, totalBuffersMemSize = 24300.00(KiB).
      bufferQueueCache:
        sequence = 8, state = 0 <released>, timestamp = 780011576923, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB).
        sequence = 9, state = 0 <released>, timestamp = 840016378613, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB).
        sequence = 13, state = 3 <acquired>, timestamp = 900011540119, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB).

FrameBufferSurface
    BufferQueue:
      default-size = [0x0], FIFO = 3, name = FrameBuffer, uniqueId = 2954937499648, usedBufferListLen = 2, freeBufferListLen = 1, dirtyBufferListLen = 0, totalBuffersMemSize = 16200.00(KiB).
      bufferQueueCache:
        sequence = 2, state = 3 <acquired>, timestamp = 900046439, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 73, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB).
        sequence = 4, state = 0 <released>, timestamp = 840051447, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 73, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB).

-- Node Not On Tree

 node Id[6597069766667]:
    BufferQueue:
      default-size = [0x0], FIFO = 3, name = SystemUi_BannerNotice, uniqueId = 2954937499659, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB).
      bufferQueueCache:

 node Id[6597069766666]:
    BufferQueue:
      default-size = [0x0], FIFO = 3, name = SystemUi_DropdownPanel, uniqueId = 2954937499658, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB).
      bufferQueueCache:

 node Id[6597069766658]:
    BufferQueue:
      default-size = [0x0], FIFO = 3, name = SystemUi_VolumePanel, uniqueId = 2954937499654, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB).
      bufferQueueCache:

 node Id[7146825580544]:
    BufferQueue:
      default-size = [0x0], FIFO = 3, name = imeWindow, uniqueId = 2954937499652, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB).
      bufferQueueCache:

 node Id[6962141986820]:
    BufferQueue:
      default-size = [0x0], FIFO = 3, name = RecentView, uniqueId = 2954937499651, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB).
      bufferQueueCache:

-- All Surfaces Memory Size
the memory size of all surfaces buffer is : 94680.00 KiB.
    BufferQueue:
      default-size = [0x0], FIFO = 3, name = SystemUi_DropdownPanel, uniqueId = 2954937499658, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB).
      bufferQueueCache:
    BufferQueue:
      default-size = [1920x32], FIFO = 3, name = SystemUi_PrivacyIndicator, uniqueId = 2954937499657, usedBufferListLen = 3, freeBufferListLen = 1, dirtyBufferListLen = 0, totalBuffersMemSize = 720.00(KiB).
      bufferQueueCache:
        sequence = 12, state = 1 <requested>, timestamp = 40645170158, damageRect = [0, 0, 1920, 32], config = [1920x32, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 32, bufferMemSize = 240.00(KiB).
        sequence = 14, state = 3 <acquired>, timestamp = 40912469187, damageRect = [0, 0, 1920, 32], config = [1920x32, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 32, bufferMemSize = 240.00(KiB).
        sequence = 17, state = 0 <released>, timestamp = 40827680126, damageRect = [0, 0, 1920, 32], config = [1920x32, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 32, bufferMemSize = 240.00(KiB).
    BufferQueue:
      default-size = [1920x1080], FIFO = 3, name = EntryView, uniqueId = 2954937499650, usedBufferListLen = 3, freeBufferListLen = 2, dirtyBufferListLen = 0, totalBuffersMemSize = 24300.00(KiB).
      bufferQueueCache:
        sequence = 5, state = 0 <released>, timestamp = 31794906265, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB).
        sequence = 6, state = 0 <released>, timestamp = 32561536655, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB).
        sequence = 7, state = 3 <acquired>, timestamp = 32644867137, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB).
    BufferQueue:
      default-size = [1920x108], FIFO = 3, name = SystemUi_NavigationBar, uniqueId = 2954937499656, usedBufferListLen = 3, freeBufferListLen = 2, dirtyBufferListLen = 0, totalBuffersMemSize = 2430.00(KiB).
      bufferQueueCache:
        sequence = 11, state = 0 <released>, timestamp = 40827680126, damageRect = [0, 0, 1920, 108], config = [1920x108, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 108, bufferMemSize = 810.00(KiB).
        sequence = 16, state = 0 <released>, timestamp = 40912469187, damageRect = [0, 0, 1920, 108], config = [1920x108, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 108, bufferMemSize = 810.00(KiB).
        sequence = 19, state = 3 <acquired>, timestamp = 60012066524, damageRect = [0, 0, 1920, 108], config = [1920x108, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 108, bufferMemSize = 810.00(KiB).
    BufferQueue:
      default-size = [0x0], FIFO = 3, name = SystemUi_VolumePanel, uniqueId = 2954937499654, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB).
      bufferQueueCache:
    BufferQueue:
      default-size = [1920x1080], FIFO = 3, name = ScreenLockWindow, uniqueId = 2954937499653, usedBufferListLen = 3, freeBufferListLen = 2, dirtyBufferListLen = 0, totalBuffersMemSize = 24300.00(KiB).
      bufferQueueCache:
        sequence = 8, state = 0 <released>, timestamp = 780011576923, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB).
        sequence = 9, state = 0 <released>, timestamp = 840016378613, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB).
        sequence = 13, state = 3 <acquired>, timestamp = 900011540119, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB).
    BufferQueue:
      default-size = [0x0], FIFO = 3, name = imeWindow, uniqueId = 2954937499652, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB).
      bufferQueueCache:
    BufferQueue:
      default-size = [0x0], FIFO = 3, name = RecentView, uniqueId = 2954937499651, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB).
      bufferQueueCache:
    BufferQueue:
      default-size = [1920x108], FIFO = 3, name = SystemUi_StatusBar, uniqueId = 2954937499655, usedBufferListLen = 3, freeBufferListLen = 2, dirtyBufferListLen = 0, totalBuffersMemSize = 2430.00(KiB).
      bufferQueueCache:
        sequence = 10, state = 0 <released>, timestamp = 40827680126, damageRect = [0, 0, 1920, 108], config = [1920x108, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 108, bufferMemSize = 810.00(KiB).
        sequence = 15, state = 3 <acquired>, timestamp = 60012066524, damageRect = [0, 0, 1920, 108], config = [1920x108, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 108, bufferMemSize = 810.00(KiB).
        sequence = 18, state = 0 <released>, timestamp = 40912469187, damageRect = [0, 0, 1920, 108], config = [1920x108, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 108, bufferMemSize = 810.00(KiB).

-- RenderServiceTreeDump: 
Animating Node: [];
| BASE_NODE[0], isOnTheTree: 1, children[2963527434241 ]
  | DISPLAY_NODE[2963527434241], isOnTheTree: 1, children[6597069766656 6597069766661 6597069766664 6597069766665 6962141986816 ]
    | SURFACE_NODE[6597069766656], isOnTheTree: 1, hasConsumer: 1, Name [ScreenLockWindow], parent [2963527434241], { Region Size 1: [0, 0, 1920, 1080] }, SurfaceBgAlpha[ 255 ], children[]
    | SURFACE_NODE[6597069766661], isOnTheTree: 1, hasConsumer: 1, Name [SystemUi_StatusBar], parent [2963527434241], { Region Size 0:  }, SurfaceBgAlpha[ 0 ], children[]
    | SURFACE_NODE[6597069766664], isOnTheTree: 1, hasConsumer: 1, Name [SystemUi_NavigationBar], parent [2963527434241], { Region Size 0:  }, SurfaceBgAlpha[ 0 ], children[]
    | SURFACE_NODE[6597069766665], isOnTheTree: 1, hasConsumer: 1, Name [SystemUi_PrivacyIndicator], parent [2963527434241], { Region Size 0:  }, SurfaceBgAlpha[ 0 ], children[]
    | SURFACE_NODE[6962141986816], isOnTheTree: 1, hasConsumer: 1, Name [EntryView], parent [2963527434241], { Region Size 0:  }, SurfaceBgAlpha[ 0 ], children[]

-- EventParamListDump: 
rosen.RsDFXEvent.RS_COMPOSITION_TIMEOUT.timeOutThresholdMs: 100
rosen.RsDFXEvent.RS_COMPOSITION_TIMEOUT.eventIntervalMs: 60000
-- QosDump: 
QOS is disabled




三.写在最后

至此OpenHarmony dump渲染和合成图层SurfaceBuffer指南整个就完成了,读者是感到意犹未尽呢,还是想说一句尼玛,瞎扯淡呢!
好了,OpenHarmony dump渲染和合成图层SurfaceBuffer指南就告一段落了,各位青山不改绿水长流,各位江湖见!当然各位读者的点赞和关注是我写作路上前进的最大动力了,如果有啥不对或者不爽的也可以踩一踩也无妨!你们的鼓励和批评是博主前进路上最大的动力。

各位读友,千万不要喷我,因为我这也是第一次深入到OpenHarmony显示这块的源码逻辑,为啥我深入到了这块,因为入职了一家原厂。所以我现在是菜鸟一杯,如果有对OpenHarmony graphic刚兴趣的朋友,也可以联系我,一起学习进步!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/543622.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Excel技巧之 【提取文件夹内的全部文件名】

在工作中&#xff0c;有时候需要将所有文档的名字提取出来做成表格。 这种情况&#xff0c;你是一个一个复制粘贴么&#xff1f;nonono&#xff01; 如果你是复制粘贴的&#xff0c;一定要试试下面的方法&#xff0c;可以快速提取文件名。 具体步骤&#xff1a; 1. 将所有的…

chatgpt赋能Python-python3_5怎么算

Python3|5是如何计算的&#xff1f; 介绍 Python是一种高级编程语言&#xff0c;许多开发人员喜欢使用它来构建各种应用程序&#xff0c;从网站到机器学习应用程序。然而&#xff0c;在使用Python编写代码时&#xff0c;很多人都会遇到一个问题&#xff1a;Python3|5计算是如…

粪菌移植——一种治疗人体疾病的新型疗法

谷禾健康 粪菌移植是一项近年来备受关注的医疗技术&#xff0c;它涉及将健康捐赠者的粪便物质转移至患有疾病或障碍患者的胃肠道。 简单来说就是选择健康合适的人粪便&#xff0c;通过科学方法提取出有用的微生物&#xff0c;去除有害与无用的部分&#xff0c;然后制成制剂&…

Redis缓存实战

一 Redis缓存简介 二 Redis缓存入门 在我们查询数据一般都是直接查询数据库&#xff0c;返回给前端。为了提高效率实际项目中会将基础数据等热点数据放入redis缓存中。 发起请求&#xff0c;先访问redis缓存&#xff0c;缓存中有直接将数据返回&#xff1b;缓存没有命中&…

玩转Netty,从“Hello World”开始

大家好&#xff0c;我是老三&#xff0c;之前里&#xff0c;我们讨论了Java的三种IO模型&#xff0c;提到了网络通信框架Netty&#xff0c;它简化和优化了NIO的使用&#xff0c;这期&#xff0c;我们正式开始走近Netty。 为什么要用Netty? 首先当然是NIO的使用&#xff0c;本…

知行之桥EDI系统2023版功能介绍——日志页面

在知行之桥EDI系统2023版中&#xff0c;除了在此前的文章中曾经介绍过的概览页面之外&#xff0c;还新增了日志页面。日志页面基于旧版本的状态页面进行了功能优化&#xff0c;为用户展示了消息、交易日志、应用程序日志、访问日志以及审计日志五种类型&#xff0c;每种日志类型…

MySQL 复合查询 内外连接

目录 基本查询回顾 多表查询 自连接 group by可以带多个 子查询 在from子句中使用子查询 合并查询 表的内连和外连 内连接 外连接 左外连接 右外连接 关于自连接和内连接&#xff08;chatgpt&#xff09; 基本查询回顾 查询工资高于 500 或岗位为 MANAGER 的雇员…

虚拟键盘:十六进制值和鼠标或键盘等效项。 代码按数字顺序列出

Virtual-Key Codes (Winuser.h) - Win32 apps | Microsoft Learn 虚拟键码 (Winuser.h) - Win32 apps | Microsoft Learn Value说明0x01鼠标左键0x02鼠标右键0x03控制中断处理0x04中间鼠标按钮 (三键鼠标)0x05X1 鼠标按钮0x06X2 鼠标按钮0x07Undefined0x08BACKSPACE 密钥0x09T…

注册阿里云OSS步骤

注册阿里云OSS步骤 阿里云是阿里巴巴集团旗下全球领先的云计算公司&#xff0c;也是国内最大的云服务提供商 。 云服务指的就是通过互联网对外提供的各种各样的服务&#xff0c;比如像&#xff1a;语音服务、短信服务、邮件服务、视频直播服务、文字识别服务、对象存储服务等等…

【SAM】CAN SAM COUNT ANYTHING? AN EMPIRICAL STUDY ON SAM COUNTING

论文链接&#xff1a; 代码链接&#xff1a; 目的 探索SAM在few-shot setting的object counting的能力。 结论 它目前落后于最先进的few-shot object counting方法&#xff0c;特别是对于小而拥挤的物体。两个主要原因。首先&#xff0c;SAM倾向于使用单个掩码分割同一类别…

javaIO流之序列流

目录 简介一、ObjectOutputStream二、ObjectInputStream三、Kryo四、小结 简介 Java 的序列流&#xff08;ObjectInputStream 和 ObjectOutputStream&#xff09;是一种可以将 Java 对象序列化和反序列化的流。 序列化是指将一个对象转换为一个字节序列&#xff08;包含对象的…

《算法训练营》贪心入门 + 10题

&#x1f442; 梦寻古镇 - 羽翼深蓝Wings - 单曲 - 网易云音乐 &#x1f442; 如果我有一个男朋友 - 于娜懿 - 单曲 - 网易云音乐 &#x1f442; 对酒&#xff08;女生版&#xff09; - 浅影阿 - 单曲 - 网易云音乐 &#x1f442; 知我&#xff08;抒情版&#xff09; - 尘a…

分享一个程序员接私活、兼职的平台

分享一个程序员接私活、兼职的平台 1、技术方向满足任一即可2、技术要求3、最后 1、技术方向满足任一即可 Python&#xff1a;熟练掌握Python编程语言&#xff0c;能够使用Python进行数据处理、机器学习和深度学习等相关工作。 MATLAB&#xff1a;熟练掌握MATLAB编程语言&…

API接口设计方案

API&#xff08;Application Programming Interface&#xff09;接口是一种用于与应用程序进行交互的标准化接口&#xff0c;它允许第三方应用程序通过网络调用应用程序的功能。设计API接口是开发人员在开发软件系统时的重要任务之一&#xff0c;因为API接口的质量和易用性直接…

UML的14种图

目录 1.UML 2.0包括14种图&#xff0c;分别列举如下&#xff1a; 2.活动图、用例图 3.部署图、顺序图 4.类图、协作图 5. 状态图、构件图 6.UML结构图和行为图 7.最后推荐一个图片转文字网站 8.最后推荐一个抖音去水印在线工具 9.最后推荐一个PPT模板下载网站 1.UML 2…

基于移动端vue的项目中webpack升级注意事项

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

Android应用-开发框架设计

目录 1. &#x1f4c2; 简介 1.1 背景 1.2 专业术语 2. &#x1f531; 总体设计思想 2.1 分层&#xff1a;组件化设计框架 2.2 分类&#xff1a;应用开发架构图 3. ⚛️ 框架详细设计 3.1 组件化框架外形 3.2 业务模块化 3.3 代码编程框架 4. &#x1f4a0; 框架其他…

streamlit

正常在学习一个新框架之前&#xff0c; 肯定要先调研下这个框架究竟能做些什么事吧&#xff1f; 但对于 streamlit 来说&#xff0c;请你相信我&#xff0c;这是一个你可以无脑去学习的框架&#xff0c;我之所以这么说&#xff0c;是因为我相信终有一天&#xff0c;你一定能用…

【算法学习系列】04 - 由01不等概率随机实现01等概率随机

文章目录 约定条件说明解决方案思路说明实现代码 验证方案 约定条件说明 存在函数 unequalP_01() 不等概率返回 0 和 1。只能通过函数 unequalP_01() 来实现 01 等概率随机函数 equalP_01() 解决方案 为了能够验证最后的等概率随机&#xff0c;这里先把函数 unequalP_01() 实现…

美颜SDK设计思路与架构分析:如何实现高可定制化

当下&#xff0c;美颜SDK也成为了移动应用开发中的必备工具之一。在实际应用中&#xff0c;不同的应用场景需要不同的美颜效果&#xff0c;因此如何实现高可定制化的美颜SDK就成为了一个重要的技术问题。 一、美颜SDK的设计思路 美颜SDK的设计思路需要考虑以下几个方面&…