* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <memory>
#include <cmath>
#include <surface_buffer.h>
#include <surface_utils.h>
#include <native_buffer.h>
#include <iconsumer_surface.h>
#include <window.h>
#include <scene/ext/intf_ecs_context.h>
#include <scene/ext/intf_internal_scene.h>
#include <scene/ext/intf_render_resource.h>
#include "texture_info.h"
#include "ohos/3d_widget_adapter_log.h"
#include "scene_adapter/intf_scene_adapter.h"
#include "scene_adapter/intf_offscreen_scene.h"
#include <meta/interface/intf_object.h>
#include <scene/interface/intf_scene.h>
using namespace testing;
using namespace testing::ext;
namespace OHOS::Render3D {
class OffscreenRenderUT : public ::testing::Test {
public:
static void SetUpTestCase()
{}
static void TearDownTestCase()
{}
void SetUp()
{}
void TearDown()
{}
};
static constexpr BASE_NS::Uid UID_DOTFIELD_PLUGIN{"8430021d-a57f-d9ff-7770-c24fb3f6321c"};
static uint32_t g_width = 512;
static uint32_t g_height = 512;
using CameraIntrinsics = OHOS::Render3D::OffscreenCameraIntrinsics;
using CameraConfigs = OHOS::Render3D::OffscreenCameraConfigs;
using OHOS::Render3D::IOffScreenScene;
class OffscreenRenderSession : public OHOS::Rosen::IConsumerListenerClazz {
public:
void OnBufferAvailable() override
{
EXPECT_NE(consumerSurface_, nullptr);
OHOS::sptr<OHOS::SurfaceBuffer> buffer;
int32_t fence = -1;
int64_t timestamp = 0;
OHOS::Rect damage;
auto success = consumerSurface_->AcquireBuffer(buffer, fence, timestamp, damage);
EXPECT_NE(buffer, nullptr);
EXPECT_EQ(success, OHOS::SURFACE_ERROR_OK);
OH_NativeBuffer* nativeBuffer = buffer->SurfaceBufferToNativaBuffer();
EXPECT_NE(nativeBuffer, nullptr);
consumerSurface_->ReleaseBuffer(buffer, fence);
}
OHOS::sptr<OHOS::IConsumerSurface> consumerSurface_;
OHOS::sptr<OHOS::ISurface> producerSurface_;
void RenderFrame(int i)
{
CameraIntrinsics intr{
0.3,
0.05,
10
};
camConfigs_.position_ = OHOS::Render3D::Vector3f({0.1 * i, -1, 2});
camConfigs_.rotation_ = OHOS::Render3D::Vector4f({0.0, 0.0, 0.0, 1});
camConfigs_.intrinsics_ = intr;
bool ret = offscreenScene_->SetCameraConfigs(camConfigs_);
EXPECT_TRUE(ret);
offscreenScene_->RenderFrame();
}
void ConfigRender()
{
consumerSurface_ = OHOS::IConsumerSurface::Create("OffscreenRenderSurfaceConsumer");
EXPECT_NE(consumerSurface_, nullptr);
auto producer = consumerSurface_->GetProducer();
EXPECT_NE(producer, nullptr);
auto producerSurface_ = OHOS::Surface::CreateSurfaceAsProducer(producer);
auto utils = OHOS::SurfaceUtils::GetInstance();
EXPECT_NE(utils, nullptr);
this->offscreenBufferWidth_ = g_width;
this->offscreenBufferHeight_ = g_height;
producerSurface_->SetQueueSize(5);
producerSurface_->SetUserData("SURFACE_STRIDE_ALIGNMENT", "8");
producerSurface_->SetUserData("SURFACE_FORMAT", std::to_string(GRAPHIC_PIXEL_FMT_RGBA_8888));
producerSurface_->SetUserData("SURFACE_WIDTH", std::to_string(offscreenBufferWidth_));
producerSurface_->SetUserData("SURFACE_HEIGHT", std::to_string(offscreenBufferHeight_));
utils->Add(producerSurface_->GetUniqueId(), producerSurface_);
consumerSurface_->RegisterConsumerListener(this);
this->producerSurfaceId_ = producerSurface_->GetUniqueId();
OHOS::Render3D::WindowChangeInfo info;
info.width = static_cast<float>(offscreenBufferWidth_);
info.height = static_cast<float>(offscreenBufferHeight_);
info.producerSurfaceId = this->producerSurfaceId_;
CameraIntrinsics intr{
1,
0.0001,
10000
};
camConfigs_.position_ = OHOS::Render3D::Vector3f({-0.5, 2, 1});
camConfigs_.rotation_ = OHOS::Render3D::Vector4f({0.0, 0.0, 0.0, 1});
camConfigs_.intrinsics_ = intr;
std::string str{UID_DOTFIELD_PLUGIN};
offscreenScene_->LoadPluginByUid(str);
offscreenScene_->CreateCamera(camConfigs_);
offscreenScene_->OnWindowChange(info);
}
uint64_t producerSurfaceId_ = 0;
uint32_t offscreenBufferWidth_ = 0;
uint32_t offscreenBufferHeight_ = 0;
OHOS::Render3D::OffscreenCameraConfigs camConfigs_;
BASE_NS::shared_ptr<IOffScreenScene> offscreenScene_;
OffscreenRenderSession()
{
offscreenScene_ = OHOS::Render3D::GetOffscreenSceneInstance();
}
~OffscreenRenderSession()
{
offscreenScene_->Deinit(true);
}
};
* @tc.name: LoadPluginsAndInit001
* @tc.desc: test LoadPluginsAndInit001
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, LoadPluginByUid, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid = "invalid UID";
EXPECT_FALSE(offScreenScene->LoadPluginByUid(uid));
std::string uid2{UID_DOTFIELD_PLUGIN};
EXPECT_TRUE(offScreenScene->LoadPluginByUid(uid2));
}
* @tc.name: CameraConfig
* @tc.desc: Verify CreateCamera and SetCameraConfig and EngineTickFrame
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, CameraConfig, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid{UID_DOTFIELD_PLUGIN};
bool ret = offScreenScene->LoadPluginByUid(uid);
EXPECT_TRUE(ret);
EXPECT_EQ(offScreenScene->GetCamera(), nullptr);
OffscreenCameraConfigs p;
bool ret2 = offScreenScene->SetCameraConfigs(p);
EXPECT_FALSE(ret2);
offScreenScene->CreateCamera(p);
EXPECT_NE(offScreenScene->GetCamera(), nullptr);
auto far1 = offScreenScene->GetCamera()->FarPlane()->GetValue();
OffscreenCameraConfigs p2;
p2.intrinsics_.far_ = 10000;
offScreenScene->SetCameraConfigs(p2);
auto far2 = offScreenScene->GetCamera()->FarPlane()->GetValue();
EXPECT_NE(far1, far2);
bool ret3 = offScreenScene->EngineTickFrame(offScreenScene->GetEcs());
EXPECT_TRUE(ret3);
}
* @tc.name: OffscreenRender
* @tc.desc: Verify offscreen render with buffer queue
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenRender, TestSize.Level1)
{
OffscreenRenderSession renderSession;
renderSession.ConfigRender();
const int frameCount = 5;
for (int i = 0; i < frameCount; ++i) {
renderSession.RenderFrame(i);
}
}
* @tc.name: OffscreenSceneGetSceneObj001
* @tc.desc: test GetSceneObj returns null before LoadPluginByUid [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneGetSceneObj001, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
auto sceneObj = offScreenScene->GetSceneObj();
EXPECT_EQ(sceneObj, nullptr);
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneGetSceneObj002
* @tc.desc: test GetSceneObj returns valid after LoadPluginByUid [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneGetSceneObj002, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid{UID_DOTFIELD_PLUGIN};
bool ret = offScreenScene->LoadPluginByUid(uid);
EXPECT_TRUE(ret);
{
auto sceneObj = offScreenScene->GetSceneObj();
EXPECT_NE(sceneObj, nullptr);
}
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneGetCamera001
* @tc.desc: test GetCamera returns null before CreateCamera [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneGetCamera001, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid{UID_DOTFIELD_PLUGIN};
offScreenScene->LoadPluginByUid(uid);
auto camera = offScreenScene->GetCamera();
EXPECT_EQ(camera, nullptr);
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneGetCamera002
* @tc.desc: test GetCamera returns valid after CreateCamera [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneGetCamera002, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid{UID_DOTFIELD_PLUGIN};
offScreenScene->LoadPluginByUid(uid);
OffscreenCameraConfigs p;
offScreenScene->CreateCamera(p);
auto camera = offScreenScene->GetCamera();
EXPECT_NE(camera, nullptr);
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneSetCameraConfigs001
* @tc.desc: test SetCameraConfigs before CreateCamera [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneSetCameraConfigs001, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid{UID_DOTFIELD_PLUGIN};
offScreenScene->LoadPluginByUid(uid);
OffscreenCameraConfigs p;
bool ret = offScreenScene->SetCameraConfigs(p);
EXPECT_FALSE(ret);
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneSetCameraConfigs002
* @tc.desc: test SetCameraConfigs after CreateCamera [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneSetCameraConfigs002, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid{UID_DOTFIELD_PLUGIN};
offScreenScene->LoadPluginByUid(uid);
OffscreenCameraConfigs p1;
p1.intrinsics_.fov_ = 0.5f;
p1.intrinsics_.near_ = 0.1f;
p1.intrinsics_.far_ = 100.0f;
offScreenScene->CreateCamera(p1);
OffscreenCameraConfigs p2;
p2.intrinsics_.fov_ = 0.8f;
p2.intrinsics_.near_ = 0.2f;
p2.intrinsics_.far_ = 200.0f;
bool ret = offScreenScene->SetCameraConfigs(p2);
EXPECT_TRUE(ret);
auto camera = offScreenScene->GetCamera();
EXPECT_NE(camera, nullptr);
EXPECT_EQ(camera->FoV()->GetValue(), 0.8f);
EXPECT_EQ(camera->NearPlane()->GetValue(), 0.2f);
EXPECT_EQ(camera->FarPlane()->GetValue(), 200.0f);
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneRenderFrame001
* @tc.desc: test RenderFrame before CreateCamera [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneRenderFrame001, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid{UID_DOTFIELD_PLUGIN};
offScreenScene->LoadPluginByUid(uid);
bool ret = offScreenScene->RenderFrame();
EXPECT_TRUE(ret);
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneDeinit001
* @tc.desc: test Deinit without engine deinit [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneDeinit001, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid{UID_DOTFIELD_PLUGIN};
offScreenScene->LoadPluginByUid(uid);
OffscreenCameraConfigs p;
offScreenScene->CreateCamera(p);
{
auto sceneObjBefore = offScreenScene->GetSceneObj();
EXPECT_NE(sceneObjBefore, nullptr);
}
offScreenScene->Deinit(false);
{
auto sceneObjAfter = offScreenScene->GetSceneObj();
EXPECT_EQ(sceneObjAfter, nullptr);
}
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneDeinit002
* @tc.desc: test Deinit with engine deinit [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneDeinit002, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid{UID_DOTFIELD_PLUGIN};
offScreenScene->LoadPluginByUid(uid);
OffscreenCameraConfigs p;
offScreenScene->CreateCamera(p);
offScreenScene->Deinit(true);
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneOnWindowChange001
* @tc.desc: test OnWindowChange before LoadPluginByUid [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneOnWindowChange001, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
OHOS::Render3D::WindowChangeInfo info;
info.width = 512;
info.height = 512;
bool ret = offScreenScene->OnWindowChange(info);
EXPECT_TRUE(ret);
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneOnWindowChange002
* @tc.desc: test OnWindowChange after LoadPluginByUid [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneOnWindowChange002, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid{UID_DOTFIELD_PLUGIN};
offScreenScene->LoadPluginByUid(uid);
OHOS::Render3D::WindowChangeInfo info;
info.width = 1024;
info.height = 768;
bool ret = offScreenScene->OnWindowChange(info);
EXPECT_TRUE(ret);
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneGetEcs001
* @tc.desc: test GetEcs returns null before LoadPluginByUid [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneGetEcs001, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
auto ecs = offScreenScene->GetEcs();
EXPECT_EQ(ecs, nullptr);
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneGetEcs002
* @tc.desc: test GetEcs returns valid after LoadPluginByUid [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneGetEcs002, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid{UID_DOTFIELD_PLUGIN};
offScreenScene->LoadPluginByUid(uid);
{
auto ecs = offScreenScene->GetEcs();
EXPECT_NE(ecs, nullptr);
}
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneEngineTickFrame001
* @tc.desc: test EngineTickFrame with valid ecs [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneEngineTickFrame001, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid{UID_DOTFIELD_PLUGIN};
offScreenScene->LoadPluginByUid(uid);
{
auto ecs = offScreenScene->GetEcs();
EXPECT_NE(ecs, nullptr);
bool ret = offScreenScene->EngineTickFrame(ecs);
EXPECT_TRUE(ret);
}
offScreenScene->Deinit(true);
}
* @tc.name: OffscreenSceneCameraConfigsDump
* @tc.desc: test OffscreenCameraConfigs Dump method [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneCameraConfigsDump, TestSize.Level1)
{
OffscreenCameraConfigs p;
p.position_ = OHOS::Render3D::Vector3f({1.0f, 2.0f, 3.0f});
p.rotation_ = OHOS::Render3D::Vector4f({0.0f, 0.0f, 0.0f, 1.0f});
p.clearColor_ = OHOS::Render3D::Vector4f({0.5f, 0.5f, 0.5f, 1.0f});
p.intrinsics_.fov_ = 0.8f;
p.intrinsics_.near_ = 0.1f;
p.intrinsics_.far_ = 100.0f;
std::string dump = p.Dump();
EXPECT_FALSE(dump.empty());
EXPECT_NE(dump.find("OffscreenCamera:"), std::string::npos);
}
* @tc.name: OffscreenSceneCreateCameraDifferentConfigs
* @tc.desc: test CreateCamera with different configurations [AUTO-GENERATED]
* @tc.type: FUNC
*/
HWTEST_F(OffscreenRenderUT, OffscreenSceneCreateCameraDifferentConfigs, TestSize.Level1)
{
auto offScreenScene = GetOffscreenSceneInstance();
EXPECT_NE(offScreenScene, nullptr);
std::string uid{UID_DOTFIELD_PLUGIN};
offScreenScene->LoadPluginByUid(uid);
OffscreenCameraConfigs p;
p.position_ = OHOS::Render3D::Vector3f({5.0f, 10.0f, 15.0f});
p.rotation_ = OHOS::Render3D::Vector4f({0.0f, 1.0f, 0.0f, 0.0f});
p.clearColor_ = OHOS::Render3D::Vector4f({1.0f, 0.0f, 0.0f, 1.0f});
p.intrinsics_.fov_ = 1.2f;
p.intrinsics_.near_ = 0.01f;
p.intrinsics_.far_ = 1000.0f;
bool ret = offScreenScene->CreateCamera(p);
EXPECT_TRUE(ret);
auto camera = offScreenScene->GetCamera();
EXPECT_NE(camera, nullptr);
auto pos = interface_pointer_cast<SCENE_NS::INode>(camera)->Position()->GetValue();
EXPECT_LT(std::fabs(pos.x - 5.0f), Rosen::EPSILON);
EXPECT_LT(std::fabs(pos.y - 10.0f), Rosen::EPSILON);
EXPECT_LT(std::fabs(pos.z - 15.0f), Rosen::EPSILON);
EXPECT_EQ(camera->FoV()->GetValue(), 1.2f);
EXPECT_EQ(camera->NearPlane()->GetValue(), 0.01f);
EXPECT_EQ(camera->FarPlane()->GetValue(), 1000.0f);
offScreenScene->Deinit(true);
}
}