* 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 "RenderContextETS.h"
#include <base/util/uid.h>
#include <core/image/intf_image_loader_manager.h>
#include <core/intf_engine.h>
#include <meta/interface/intf_metadata.h>
#include <meta/interface/intf_object_context.h>
#include <scene/ext/intf_render_resource.h>
#include <scene/interface/intf_shader.h>
#include <scene/interface/intf_render_context.h>
#include <scene_adapter/intf_surface_stream.h>
#include <scene_adapter/surface_stream.h>
#include <render/device/intf_gpu_resource_manager.h>
#ifdef __SCENE_ADAPTER__
#include "3d_widget_adapter_log.h"
#endif
META_TYPE(BASE_NS::shared_ptr<CORE_NS::IImageLoaderManager::LoadResult>);
namespace {
SCENE_NS::IRenderResourceManager::Ptr GetResourceManager()
{
auto& obr = META_NS::GetObjectRegistry();
auto data = obr.Create<META_NS::IMetadata>(META_NS::ClassId::Object);
if (!data) {
return {};
}
auto doc = interface_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
auto renderContext = doc->GetProperty<SCENE_NS::IRenderContext::Ptr>("RenderContext")->GetValue();
data->AddProperty(META_NS::ConstructProperty<SCENE_NS::IRenderContext::Ptr>("RenderContext", renderContext));
auto rrmObj = obr.Create(SCENE_NS::ClassId::RenderResourceManager, data);
if (rrmObj) {
return interface_pointer_cast<SCENE_NS::IRenderResourceManager>(rrmObj);
} else {
return {};
}
}
}
namespace OHOS::Render3D {
RenderContextETS::RenderContextETS()
{}
RenderContextETS::~RenderContextETS()
{}
std::shared_ptr<RenderResourcesETS> RenderContextETS::GetResources()
{
if (auto resources = resources_.lock()) {
return resources;
}
auto resources = std::make_shared<RenderResourcesETS>();
resources_ = resources;
return resources;
}
bool RenderContextETS::LoadPlugin(const std::string& name)
{
if (!BASE_NS::IsUidString(name.c_str())) {
WIDGET_LOGE("%{public}s is not a Uid string", name.c_str());
return false;
}
BASE_NS::Uid uid(*(char(*)[37])name.data());
const auto engineQ = META_NS::GetTaskQueueRegistry().GetTaskQueue(ENGINE_THREAD);
return META_NS::AddFutureTaskOrRunDirectly(engineQ, [uid]() {
return Core::GetPluginRegister().LoadPlugins({uid});
}).GetResult();
}
InvokeReturn<std::shared_ptr<ShaderETS>> RenderContextETS::CreateShader(const std::string& name, const std::string& uri)
{
auto renderResourceManager = GetResourceManager();
if (!renderResourceManager) {
return InvokeReturn<std::shared_ptr<ShaderETS>>(nullptr, "render resource manager is not ready");
}
if (uri.empty()) {
return InvokeReturn<std::shared_ptr<ShaderETS>>(nullptr, "Invalid shader uri given");
}
SCENE_NS::IShader::Ptr shader = renderResourceManager->LoadShader(uri.c_str()).GetResult();
return InvokeReturn<std::shared_ptr<ShaderETS>>(std::make_shared<ShaderETS>(shader, name, uri));
}
std::shared_ptr<ImageETS> RenderContextETS::CreateImage(const std::string& name, const std::string& uri)
{
using namespace RENDER_NS;
if (uri.empty()) {
WIDGET_LOGE("Invalid scene resource Image parameters given");
return nullptr;
}
if (auto resources = resources_.lock()) {
if (const auto bitmap = resources->FetchBitmap(uri.c_str())) {
WIDGET_LOGI("Image uri already exist");
return std::make_shared<ImageETS>(name, uri, bitmap);
}
}
auto& obr = META_NS::GetObjectRegistry();
auto doc = interface_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
auto renderContext = doc->GetProperty<SCENE_NS::IRenderContext::Ptr>("RenderContext")->GetValue()->GetRenderer();
using LoadResult = CORE_NS::IImageLoaderManager::LoadResult;
auto loadImage = [uri, renderContext]() {
uint32_t imageLoaderFlags = CORE_NS::IImageLoaderManager::IMAGE_LOADER_GENERATE_MIPS;
auto& imageLoaderMgr = renderContext->GetEngine().GetImageLoaderManager();
return BASE_NS::shared_ptr<LoadResult>{new LoadResult{imageLoaderMgr.LoadImage(uri.c_str(), imageLoaderFlags)}};
};
auto createGpuResource = [uri, renderContext](
BASE_NS::shared_ptr<LoadResult> loadResult) -> SCENE_NS::IBitmap::Ptr {
if (!loadResult->success) {
WIDGET_LOGE("%{public}s", BASE_NS::string{"Failed to load image: "}.append(loadResult->error).c_str());
return {};
}
auto& gpuResourceMgr = renderContext->GetDevice().GetGpuResourceManager();
GpuImageDesc gpuDesc = gpuResourceMgr.CreateGpuImageDesc(loadResult->image->GetImageDesc());
gpuDesc.usageFlags = CORE_IMAGE_USAGE_SAMPLED_BIT | CORE_IMAGE_USAGE_TRANSFER_DST_BIT;
if (gpuDesc.engineCreationFlags & EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_GENERATE_MIPS) {
gpuDesc.usageFlags |= CORE_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
gpuDesc.memoryPropertyFlags = CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
const auto imageHandle = gpuResourceMgr.Create(uri.c_str(), gpuDesc, std::move(loadResult->image));
auto& obr = META_NS::GetObjectRegistry();
auto doc = interface_pointer_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
auto bitmap = META_NS::GetObjectRegistry().Create<SCENE_NS::IBitmap>(SCENE_NS::ClassId::Bitmap, doc);
if (auto m = interface_cast<META_NS::IMetadata>(bitmap)) {
m->AddProperty(META_NS::ConstructProperty<BASE_NS::string>("Uri", uri.c_str()));
}
if (auto i = interface_cast<SCENE_NS::IRenderResource>(bitmap)) {
i->SetRenderHandle(imageHandle);
}
return bitmap;
};
const auto ioQ = META_NS::GetTaskQueueRegistry().GetTaskQueue(IO_QUEUE);
const auto engineQ = META_NS::GetTaskQueueRegistry().GetTaskQueue(ENGINE_THREAD);
auto bitmap = META_NS::AddFutureTaskOrRunDirectly(ioQ, BASE_NS::move(loadImage))
.Then(BASE_NS::move(createGpuResource), engineQ)
.GetResult();
if (!bitmap) {
WIDGET_LOGE("Failed to load image from URI %{public}s", uri.c_str());
return nullptr;
}
GetResources()->StoreBitmap(uri.c_str(), bitmap);
return std::make_shared<ImageETS>(name, uri, bitmap);
}
std::shared_ptr<ImageETS> RenderContextETS::CreateImageStream(const std::string& name, const std::string& uri)
{
std::string internalUri = uri;
auto& obr = META_NS::GetObjectRegistry();
obr.RegisterObjectType<OHOS::Render3D::SurfaceStream>();
auto doc = interface_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
auto createGpuResource = [internalUri]() mutable -> SCENE_NS::IBitmap::Ptr {
auto& obr = META_NS::GetObjectRegistry();
auto doc = interface_pointer_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
auto bitmap = obr.Create<SCENE_NS::IBitmap>(SCENE_NS::ClassId::Bitmap, doc);
internalUri += std::to_string(reinterpret_cast<uintptr_t>(bitmap.get()));
if (auto metadata = interface_cast<META_NS::IMetadata>(bitmap)) {
metadata->AddProperty(META_NS::ConstructProperty<BASE_NS::string>("Uri", internalUri.c_str()));
}
auto surfaceStream = obr.Create<OHOS::Render3D::ISurfaceStream>(OHOS::Render3D::ClassId::SurfaceStream, doc);
if (auto attach = interface_cast<Meta::IAttach>(bitmap); attach && surfaceStream) {
attach->Attach(surfaceStream);
}
return bitmap;
};
const auto engineQ = META_NS::GetTaskQueueRegistry().GetTaskQueue(ENGINE_THREAD);
auto bitmap = META_NS::AddFutureTaskOrRunDirectly(engineQ, BASE_NS::move(createGpuResource)).GetResult();
if (!bitmap) {
WIDGET_LOGE("Failed to load image from URI %{public}s", internalUri.c_str());
return nullptr;
}
GetResources()->StoreBitmap(internalUri.c_str(), bitmap);
return std::make_shared<ImageETS>(name, internalUri, bitmap);
}
bool RenderContextETS::RegisterResourcePath(const std::string& protocol, const std::string& uri)
{
if (protocol.empty() || uri.empty()) {
CORE_LOG_E("Invalid protocol or uri");
return false;
}
auto& obr = META_NS::GetObjectRegistry();
auto doc = interface_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
if (!doc) {
CORE_LOG_E("Get default object context failed");
return false;
}
auto& fileManager = doc->GetProperty<SCENE_NS::IRenderContext::Ptr>("RenderContext")
->GetValue()
->GetRenderer()
->GetEngine()
.GetFileManager();
if (!fileManager.CheckExistence(protocol.c_str())) {
CORE_LOG_E("Protocol %s does not exist", protocol.c_str());
return false;
}
if (!fileManager.RegisterPath(protocol.c_str(), uri.c_str(), false)) {
CORE_LOG_E("Register protocol %s with %s failed", protocol.c_str(), uri.c_str());
return false;
}
return true;
}
}