一、关键字:

虚拟屏、VirtualScreen、PixelFormat。

二、问题描述

系统版本:OpenHarmony 5.0.X

问题现象:虚拟屏PixelFormat默认为RAPHIC_PIXEL_FMT_RGBA_8888,设置其他PixelFormat无法生效。

三、原因分析

1. 虚拟屏的创建过程

创建虚拟屏的过程如下:

img

创建虚拟屏的过程中,没有设置GraphicPixelFormat,默认使用的GraphicPixelFormat为GRAPHIC_PIXEL_FMT_RGBA_8888

// foundation/graphic/graphic_2d/rosen/modules/render_service/core/screen_manager/rs_screen.h
struct VirtualScreenConfigs {
    ScreenId id = INVALID_SCREEN_ID;
    ScreenId mirrorId = INVALID_SCREEN_ID;
    std::string name;
    uint32_t width = 0;
    uint32_t height = 0;
    sptr<Surface> surface = nullptr;
    GraphicPixelFormat pixelFormat = GRAPHIC_PIXEL_FMT_RGBA_8888;
    int32_t flags = 0; // reserve flag.
    std::unordered_set<uint64_t> whiteList = {};
    std::unordered_set<uint64_t> blackListSet = {};
};

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/screen_manager/rs_screen_manager.cpp
ScreenId RSScreenManager::CreateVirtualScreen(
    const std::string &name,
    uint32_t width,
    uint32_t height,
    sptr<Surface> surface,
    ScreenId mirrorId,
    int32_t flags,
    std::vector<NodeId> whiteList)
{
    // ......
    VirtualScreenConfigs configs;
    ScreenId newId = GenerateVirtualScreenIdLocked();
    configs.id = newId;
    configs.mirrorId = mirrorId;
    configs.name = name;
    configs.width = width;
    configs.height = height;
    configs.surface = surface;
    configs.flags = flags;
    configs.whiteList = std::unordered_set<NodeId>(whiteList.begin(), whiteList.end());

    screens_[newId] = std::make_unique<RSScreen>(configs);
    ++currentVirtualScreenNum_;
    RS_LOGD("RSScreenManager %{public}s: create virtual screen(id %{public}" PRIu64 ").", __func__, newId);
    return newId;
}

2. 虚拟屏的渲染过程

虚拟屏的渲染过程如下:

img

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_base_render_util.h
static BufferRequestConfig GetFrameBufferRequestConfig(const ScreenInfo& screenInfo, bool isPhysical = true,
    bool isProtected = false,
    GraphicColorGamut colorGamut = GRAPHIC_COLOR_GAMUT_SRGB,
    GraphicPixelFormat pixelFormat = GRAPHIC_PIXEL_FMT_RGBA_8888);

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_processor.cpp
bool RSProcessor::Init(RSDisplayRenderNode& node, int32_t offsetX, int32_t offsetY, ScreenId mirroredId,
    std::shared_ptr<RSBaseRenderEngine> renderEngine)
{
    // ......

    // set default render frame config
    renderFrameConfig_ = RSBaseRenderUtil::GetFrameBufferRequestConfig(screenInfo_);
    return true;
}

虚拟屏在创建Processor过程中,没有判断是否是物理屏还是虚拟屏,GraphicPixelFormat使用默认值GRAPHIC_PIXEL_FMT_RGBA_8888。

四、方案解决

通过RSInterface设置PixelFormat,在RSVirtualScreenProcessor::Init过程中重新获取PixelFormat。

img

再次调用GetFrameBufferRequestConfig,判断是否为虚拟屏。

--- a/rosen/modules/render_service/core/pipeline/rs_virtual_screen_processor.cpp
+++ b/rosen/modules/render_service/core/pipeline/rs_virtual_screen_processor.cpp
@@ -49,6 +49,7 @@ bool RSVirtualScreenProcessor::Init(RSDisplayRenderNode& node, int32_t offsetX,
         SetMirrorScreenSwap(node);
     }

+    renderFrameConfig_ = RSBaseRenderUtil::GetFrameBufferRequestConfig(screenInfo_, false);
     renderFrameConfig_.usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_MEM_DMA;
Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐