mirror of
https://github.com/openharmony/ace_ace_engine.git
synced 2026-07-19 14:43:36 -04:00
@@ -87,6 +87,10 @@ if (disable_gpu || enable_rosen_backend) {
|
||||
defines += [ "GPU_DISABLED" ]
|
||||
}
|
||||
|
||||
if (disable_gpu) {
|
||||
defines += [ "UPLOAD_GPU_DISABLED" ]
|
||||
}
|
||||
|
||||
if (form_components_support) {
|
||||
defines += [ "FORM_SUPPORTED" ]
|
||||
}
|
||||
|
||||
@@ -52,7 +52,10 @@ template("ace_ohos_standard_source_set") {
|
||||
configs = [ "$ace_root:ace_config" ]
|
||||
|
||||
if (defined(config.enable_rosen_backend) && config.enable_rosen_backend) {
|
||||
configs += [ "//foundation/graphic/standard/rosen/modules/render_service_client:render_service_client_config" ]
|
||||
configs += [
|
||||
"//foundation/graphic/standard/rosen/modules/render_service_base:export_config",
|
||||
"//foundation/graphic/standard/rosen/modules/render_service_client:render_service_client_config",
|
||||
]
|
||||
}
|
||||
|
||||
include_dirs = [
|
||||
|
||||
@@ -184,6 +184,13 @@ void AceAbility::OnStart(const Want& want)
|
||||
ImageCache::SetCacheFileInfo();
|
||||
});
|
||||
OHOS::sptr<OHOS::Rosen::Window> window = Ability::GetWindow();
|
||||
std::shared_ptr<OHOS::Rosen::RSUIDirector> rsUiDirector;
|
||||
if (SystemProperties::GetRosenBackendEnabled()) {
|
||||
rsUiDirector = OHOS::Rosen::RSUIDirector::Create();
|
||||
rsUiDirector->SetRSSurfaceNode(window->GetSurfaceNode());
|
||||
rsUiDirector->Init();
|
||||
}
|
||||
|
||||
// register surface change callback and window mode change callback
|
||||
OHOS::sptr<OHOS::Rosen::IWindowChangeListener> thisAbility(this);
|
||||
window->RegisterWindowChangeListener(thisAbility);
|
||||
@@ -330,23 +337,20 @@ void AceAbility::OnStart(const Want& want)
|
||||
|
||||
Ace::Platform::UIEnvCallback callback = nullptr;
|
||||
#ifdef ENABLE_ROSEN_BACKEND
|
||||
callback = [window, id = abilityId_](const OHOS::Ace::RefPtr<OHOS::Ace::PipelineContext>& context) mutable {
|
||||
if (SystemProperties::GetRosenBackendEnabled()) {
|
||||
auto rsUiDirector = OHOS::Rosen::RSUIDirector::Create();
|
||||
if (rsUiDirector != nullptr) {
|
||||
rsUiDirector->SetRSSurfaceNode(window->GetSurfaceNode());
|
||||
rsUiDirector->SetUITaskRunner(
|
||||
[taskExecutor = Platform::AceContainer::GetContainer(id)->GetTaskExecutor(), id](
|
||||
const std::function<void()>& task) {
|
||||
ContainerScope scope(id);
|
||||
taskExecutor->PostTask(task, TaskExecutor::TaskType::UI);
|
||||
});
|
||||
if (context != nullptr) {
|
||||
context->SetRSUIDirector(rsUiDirector);
|
||||
}
|
||||
rsUiDirector->Init();
|
||||
LOGI("Init Rosen Backend");
|
||||
callback = [window, id = abilityId_, flutterAceView, rsUiDirector](
|
||||
const OHOS::Ace::RefPtr<OHOS::Ace::PipelineContext>& context) mutable {
|
||||
if (rsUiDirector) {
|
||||
rsUiDirector->SetUITaskRunner(
|
||||
[taskExecutor = Platform::AceContainer::GetContainer(id)->GetTaskExecutor(), id](
|
||||
const std::function<void()>& task) {
|
||||
ContainerScope scope(id);
|
||||
taskExecutor->PostTask(task, TaskExecutor::TaskType::UI);
|
||||
});
|
||||
if (context != nullptr) {
|
||||
context->SetRSUIDirector(rsUiDirector);
|
||||
}
|
||||
flutterAceView->InitIOManager(Platform::AceContainer::GetContainer(id)->GetTaskExecutor());
|
||||
LOGI("Init Rosen Backend");
|
||||
} else {
|
||||
LOGI("not Init Rosen Backend");
|
||||
}
|
||||
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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.
|
||||
*/
|
||||
|
||||
#ifndef FOUNDATION_ACE_ADAPTER_OHOS_CPP_ACE_ROSEN_SYNC_TASK_H
|
||||
#define FOUNDATION_ACE_ADAPTER_OHOS_CPP_ACE_ROSEN_SYNC_TASK_H
|
||||
|
||||
#include "render_service_client/core/ui/rs_ui_director.h"
|
||||
#include "transaction/rs_transaction_proxy.h"
|
||||
|
||||
namespace OHOS::Ace::Platform {
|
||||
|
||||
class AceRosenSyncTask : public Rosen::RSSyncTask {
|
||||
public:
|
||||
explicit AceRosenSyncTask(std::function<void()>&& task, unsigned long long timeoutNS = 50e6)
|
||||
: Rosen::RSSyncTask(timeoutNS), task_(std::move(task))
|
||||
{}
|
||||
virtual ~AceRosenSyncTask() = default;
|
||||
|
||||
#ifdef ROSEN_OHOS
|
||||
bool CheckHeader(Parcel& parcel) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadFromParcel(Parcel& parcel) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Marshalling(Parcel& parcel) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif // ROSEN_OHOS
|
||||
|
||||
void Process(Rosen::RSContext& context) override
|
||||
{
|
||||
if (task_) {
|
||||
task_();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void()> task_;
|
||||
};
|
||||
} // namespace OHOS::Ace::Platform
|
||||
|
||||
#endif // FOUNDATION_ACE_ADAPTER_OHOS_CPP_ACE_ROSEN_SYNC_TASK_H
|
||||
@@ -15,12 +15,21 @@
|
||||
|
||||
#include "adapter/ohos/entrance/flutter_ace_view.h"
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
#include "flutter/fml/synchronization/waitable_event.h"
|
||||
#include "flutter/shell/common/shell_io_manager.h"
|
||||
#include "flutter/shell/gpu/gpu_surface_gl_delegate.h"
|
||||
#include "key_event.h"
|
||||
#include "pointer_event.h"
|
||||
|
||||
#if defined(ENABLE_ROSEN_BACKEND) and !defined(UPLOAD_GPU_DISABLED)
|
||||
#include "adapter/ohos/entrance/ace_rosen_sync_task.h"
|
||||
#endif
|
||||
|
||||
#include "base/log/ace_trace.h"
|
||||
#include "base/log/dump_log.h"
|
||||
#include "base/log/event_report.h"
|
||||
#include "base/log/log.h"
|
||||
@@ -700,4 +709,82 @@ std::unique_ptr<PlatformWindow> FlutterAceView::GetPlatformWindow()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FlutterAceView::InitIOManager(RefPtr<TaskExecutor> taskExecutor)
|
||||
{
|
||||
#if defined(ENABLE_ROSEN_BACKEND) and !defined(UPLOAD_GPU_DISABLED)
|
||||
ACE_SCOPED_TRACE("InitIOManager");
|
||||
EGLContext shareContext = nullptr;
|
||||
EGLSurface surface = nullptr;
|
||||
auto callback = [&shareContext, &surface]() {
|
||||
ACE_SCOPED_TRACE("create egl ");
|
||||
EGLContext context = eglGetCurrentContext();
|
||||
if (context == EGL_NO_CONTEXT) {
|
||||
LOGE("eglGetCurrentContext failed errorCode = [%{public}d]", eglGetError());
|
||||
return;
|
||||
}
|
||||
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
if (display == EGL_NO_DISPLAY) {
|
||||
LOGE("eglGetDisplay failed errorCode = [%{public}d]", eglGetError());
|
||||
return;
|
||||
}
|
||||
EGLint attributes[] = {
|
||||
// clang-format off
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_ALPHA_SIZE, 8,
|
||||
EGL_DEPTH_SIZE, 0,
|
||||
EGL_STENCIL_SIZE, 0,
|
||||
EGL_NONE, // termination sentinel
|
||||
// clang-format on
|
||||
};
|
||||
EGLint config_count = 0;
|
||||
EGLConfig egl_config = nullptr;
|
||||
if (eglChooseConfig(display, attributes, &egl_config, 1, &config_count) != EGL_TRUE) {
|
||||
LOGE("Get EGLConfig failed errorCode = [%{public}d]", eglGetError());
|
||||
return;
|
||||
}
|
||||
EGLint contextAttr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
|
||||
shareContext = eglCreateContext(display, egl_config, context, contextAttr);
|
||||
if (shareContext == EGL_NO_CONTEXT) {
|
||||
LOGE("eglCreateContext failed errorCode = [%{public}d]", eglGetError());
|
||||
return;
|
||||
}
|
||||
const EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
|
||||
surface = eglCreatePbufferSurface(display, egl_config, attribs);
|
||||
if (surface == EGL_NO_SURFACE) {
|
||||
LOGE("eglCreatePbufferSurface failed errorCode = [%{public}d]", eglGetError());
|
||||
return;
|
||||
}
|
||||
LOGI("create egl success");
|
||||
};
|
||||
auto task = std::make_shared<AceRosenSyncTask>(std::move(callback));
|
||||
Rosen::RSTransactionProxy::GetInstance()->ExecuteSynchronousTask(task);
|
||||
|
||||
if (shareContext == EGL_NO_CONTEXT || surface == EGL_NO_SURFACE) {
|
||||
LOGW("create egl env failed, image should not upload to gpu.");
|
||||
return;
|
||||
}
|
||||
auto state = flutter::UIDartState::Current()->GetStateById(instanceId_);
|
||||
if (state == nullptr) {
|
||||
LOGE("state is nullptr");
|
||||
return;
|
||||
}
|
||||
fml::WeakPtr<flutter::ShellIOManager> ioManager = state->GetIOManager();
|
||||
taskExecutor->PostSyncTask(
|
||||
[surface, shareContext, ioManager]() {
|
||||
ACE_SCOPED_TRACE("create resource_context ");
|
||||
if (eglMakeCurrent(eglGetDisplay(EGL_DEFAULT_DISPLAY), surface, surface, shareContext) == EGL_TRUE) {
|
||||
sk_sp<GrContext> resource_context = flutter::ShellIOManager::CreateCompatibleResourceLoadingContext(
|
||||
GrBackend::kOpenGL_GrBackend, flutter::GPUSurfaceGLDelegate::GetDefaultPlatformGLInterface());
|
||||
|
||||
ioManager->NotifyResourceContextAvailable(resource_context);
|
||||
}
|
||||
},
|
||||
TaskExecutor::TaskType::IO);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace OHOS::Ace::Platform
|
||||
@@ -131,6 +131,8 @@ public:
|
||||
bool Dump(const std::vector<std::string>& params) override;
|
||||
const void* GetNativeWindowById(uint64_t textureId) override;
|
||||
|
||||
void InitIOManager(RefPtr<TaskExecutor> taskExecutor);
|
||||
|
||||
private:
|
||||
void NotifySurfaceChanged(int width, int height, WindowSizeChangeReason type)
|
||||
{
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "adapter/ohos/entrance/plugin_utils_impl.h"
|
||||
#include "base/geometry/rect.h"
|
||||
#include "base/log/log.h"
|
||||
#include "base/log/ace_trace.h"
|
||||
#include "base/subwindow/subwindow_manager.h"
|
||||
#include "base/utils/system_properties.h"
|
||||
#include "core/common/ace_engine.h"
|
||||
@@ -238,6 +239,7 @@ std::string UIContentImpl::GetContentInfo() const
|
||||
|
||||
void UIContentImpl::CommonInitialize(OHOS::Rosen::Window* window, const std::string& contentInfo, NativeValue* storage)
|
||||
{
|
||||
ACE_FUNCTION_TRACE();
|
||||
window_ = window;
|
||||
startUrl_ = contentInfo;
|
||||
if (!window_) {
|
||||
@@ -267,6 +269,13 @@ void UIContentImpl::CommonInitialize(OHOS::Rosen::Window* window, const std::str
|
||||
ImageCache::SetCacheFileInfo();
|
||||
});
|
||||
|
||||
std::shared_ptr<OHOS::Rosen::RSUIDirector> rsUiDirector;
|
||||
if (SystemProperties::GetRosenBackendEnabled()) {
|
||||
rsUiDirector = OHOS::Rosen::RSUIDirector::Create();
|
||||
rsUiDirector->SetRSSurfaceNode(window->GetSurfaceNode());
|
||||
rsUiDirector->Init();
|
||||
}
|
||||
|
||||
int32_t deviceWidth = 0;
|
||||
int32_t deviceHeight = 0;
|
||||
float density = 1.0f;
|
||||
@@ -477,11 +486,10 @@ void UIContentImpl::CommonInitialize(OHOS::Rosen::Window* window, const std::str
|
||||
|
||||
Ace::Platform::UIEnvCallback callback = nullptr;
|
||||
#ifdef ENABLE_ROSEN_BACKEND
|
||||
callback = [window, id = instanceId_, container](const OHOS::Ace::RefPtr<OHOS::Ace::PipelineContext>& context) {
|
||||
if (SystemProperties::GetRosenBackendEnabled()) {
|
||||
auto rsUiDirector = OHOS::Rosen::RSUIDirector::Create();
|
||||
if (rsUiDirector != nullptr) {
|
||||
rsUiDirector->SetRSSurfaceNode(window->GetSurfaceNode());
|
||||
callback = [window, id = instanceId_, container, flutterAceView, rsUiDirector](
|
||||
const OHOS::Ace::RefPtr<OHOS::Ace::PipelineContext>& context) {
|
||||
if (rsUiDirector) {
|
||||
ACE_SCOPED_TRACE("OHOS::Rosen::RSUIDirector::Create()");
|
||||
rsUiDirector->SetUITaskRunner(
|
||||
[taskExecutor = container->GetTaskExecutor(), id](const std::function<void()>& task) {
|
||||
ContainerScope scope(id);
|
||||
@@ -491,9 +499,8 @@ void UIContentImpl::CommonInitialize(OHOS::Rosen::Window* window, const std::str
|
||||
if (context != nullptr) {
|
||||
context->SetRSUIDirector(rsUiDirector);
|
||||
}
|
||||
rsUiDirector->Init();
|
||||
flutterAceView->InitIOManager(container->GetTaskExecutor());
|
||||
LOGI("UIContent Init Rosen Backend");
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -234,7 +234,7 @@ void RosenRenderImage::ImageDataPaintSuccess(const fml::RefPtr<flutter::CanvasIm
|
||||
return;
|
||||
}
|
||||
UpdateLoadSuccessState();
|
||||
image_ = image->image();
|
||||
image_ = image;
|
||||
skiaDom_ = nullptr;
|
||||
svgDom_ = nullptr;
|
||||
if (imageDataNotReady_) {
|
||||
@@ -453,7 +453,9 @@ void RosenRenderImage::ProcessPixmapForPaint()
|
||||
skImage = SkImage::MakeFromRaster(imagePixmap, nullptr, nullptr);
|
||||
#endif
|
||||
}
|
||||
image_ = std::move(skImage);
|
||||
auto canvasImage = flutter::CanvasImage::Create();
|
||||
canvasImage->set_image(flutter::SkiaGPUObject<SkImage>(skImage, renderTaskHolder_->unrefQueue));
|
||||
image_ = canvasImage;
|
||||
if (!VerifySkImageDataFromPixmap(pixmap)) {
|
||||
LOGE("pixmap paint failed due to SkImage data verification fail. rawImageSize: %{public}s",
|
||||
rawImageSize_.ToString().c_str());
|
||||
@@ -601,7 +603,7 @@ void RosenRenderImage::Paint(RenderContext& context, const Offset& offset)
|
||||
ApplyInterpolation(paint);
|
||||
sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();
|
||||
if (image_) {
|
||||
colorSpace = image_->refColorSpace();
|
||||
colorSpace = image_->image()->refColorSpace();
|
||||
}
|
||||
#ifdef USE_SYSTEM_SKIA
|
||||
paint.setColor4f(paint.getColor4f(), colorSpace.get());
|
||||
@@ -697,7 +699,7 @@ void RosenRenderImage::CanvasDrawImageRect(
|
||||
if (GetBackgroundImageFlag()) {
|
||||
return;
|
||||
}
|
||||
if (!image_) {
|
||||
if (!image_ || !image_->image()) {
|
||||
imageDataNotReady_ = true;
|
||||
LOGI("image data is not ready, rawImageSize_: %{public}s, image source: %{private}s",
|
||||
rawImageSize_.ToString().c_str(), sourceInfo_.ToString().c_str());
|
||||
@@ -711,7 +713,7 @@ void RosenRenderImage::CanvasDrawImageRect(
|
||||
if (GetAdaptiveFrameRectFlag()) {
|
||||
recordingCanvas->translate(imageRenderPosition_.GetX() * -1, imageRenderPosition_.GetY() * -1);
|
||||
Rosen::RsImageInfo rsImageInfo(fitNum, repeatNum, radius, scale_);
|
||||
recordingCanvas->DrawImageWithParm(image_, rsImageInfo, paint);
|
||||
recordingCanvas->DrawImageWithParm(image_->image(), rsImageInfo, paint);
|
||||
return;
|
||||
}
|
||||
bool isLoading = ((imageLoadingStatus_ == ImageLoadingStatus::LOADING) ||
|
||||
@@ -738,7 +740,7 @@ void RosenRenderImage::CanvasDrawImageRect(
|
||||
SkRect::MakeXYWH(realDstRect.Left() - imageRenderPosition_.GetX(),
|
||||
realDstRect.Top() - imageRenderPosition_.GetY(),
|
||||
realDstRect.Width(), realDstRect.Height());
|
||||
canvas->drawImageRect(image_, skSrcRect, skDstRect, &paint);
|
||||
canvas->drawImageRect(image_->image(), skSrcRect, skDstRect, &paint);
|
||||
LOGD("dstRect params: %{public}s", realDstRect.ToString().c_str());
|
||||
LOGD("scaledSrcRect params: %{public}s", scaledSrcRect.ToString().c_str());
|
||||
#endif
|
||||
@@ -779,14 +781,14 @@ void RosenRenderImage::DrawImageOnCanvas(const Rect& srcRect, const Rect& dstRec
|
||||
|
||||
recordingCanvas->save();
|
||||
recordingCanvas->concat(sampleMatrix);
|
||||
recordingCanvas->drawImageRect(image_, skSrcRect, skDstRect, &paint, SkCanvas::kFast_SrcRectConstraint);
|
||||
recordingCanvas->drawImageRect(image_->image(), skSrcRect, skDstRect, &paint, SkCanvas::kFast_SrcRectConstraint);
|
||||
recordingCanvas->restore();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool RosenRenderImage::VerifySkImageDataFromPixmap(const RefPtr<PixelMap>& pixmap) const
|
||||
{
|
||||
if (!image_) {
|
||||
if (!image_ || !image_->image()) {
|
||||
LOGE("image data made from pixmap is null");
|
||||
return false;
|
||||
}
|
||||
@@ -818,7 +820,7 @@ void RosenRenderImage::PaintBgImage(const std::shared_ptr<RSNode>& rsNode)
|
||||
if (!GetBackgroundImageFlag()) {
|
||||
return;
|
||||
}
|
||||
if (currentDstRectList_.empty() || !image_) {
|
||||
if (currentDstRectList_.empty() || !image_ || !image_->image()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -827,7 +829,7 @@ void RosenRenderImage::PaintBgImage(const std::shared_ptr<RSNode>& rsNode)
|
||||
}
|
||||
#ifdef OHOS_PLATFORM
|
||||
auto rosenImage = std::make_shared<Rosen::RSImage>();
|
||||
rosenImage->SetImage(image_);
|
||||
rosenImage->SetImage(image_->image());
|
||||
rosenImage->SetImageRepeat(static_cast<int>(imageRepeat_));
|
||||
rsNode->SetBgImageWidth(imageRenderSize_.Width());
|
||||
rsNode->SetBgImageHeight(imageRenderSize_.Height());
|
||||
@@ -1164,10 +1166,10 @@ void RosenRenderImage::ClearRenderObject()
|
||||
|
||||
bool RosenRenderImage::IsSourceWideGamut() const
|
||||
{
|
||||
if (sourceInfo_.IsSvg() || !image_) {
|
||||
if (sourceInfo_.IsSvg() || !image_ || !image_->image()) {
|
||||
return false;
|
||||
}
|
||||
return ImageProvider::IsWideGamut(image_->refColorSpace());
|
||||
return ImageProvider::IsWideGamut(image_->image()->refColorSpace());
|
||||
}
|
||||
|
||||
bool RosenRenderImage::RetryLoading()
|
||||
|
||||
@@ -120,7 +120,7 @@ private:
|
||||
|
||||
sk_sp<SkSVGDOM> skiaDom_;
|
||||
RefPtr<SvgDom> svgDom_;
|
||||
sk_sp<SkImage> image_;
|
||||
fml::RefPtr<flutter::CanvasImage> image_;
|
||||
bool loadSvgAfterLayout_ = false;
|
||||
bool loadSvgOnPaint_ = false; // only load svg trees without box and bind
|
||||
SkVector radii_[4] = { { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 } };
|
||||
|
||||
@@ -260,7 +260,7 @@ void ImageProvider::UploadImageToGPUForRender(
|
||||
LOGW("renderTaskHolder has been released.");
|
||||
return;
|
||||
}
|
||||
#if defined(DUMP_DRAW_CMD) || defined(GPU_DISABLED)
|
||||
#ifdef UPLOAD_GPU_DISABLED
|
||||
// If want to dump draw command or gpu disabled, should use CPU image.
|
||||
callback({ image, renderTaskHolder->unrefQueue });
|
||||
#else
|
||||
|
||||
@@ -199,13 +199,13 @@ void PipelineContext::FlushPipelineWithoutAnimation()
|
||||
FlushPostAnimation();
|
||||
FlushLayout();
|
||||
FlushRender();
|
||||
FlushMessages();
|
||||
FlushRenderFinish();
|
||||
FlushWindowBlur();
|
||||
FlushFocus();
|
||||
FireVisibleChangeEvent();
|
||||
ProcessPostFlush();
|
||||
ClearDeactivateElements();
|
||||
FlushMessages();
|
||||
}
|
||||
|
||||
void PipelineContext::FlushMessages()
|
||||
|
||||
Reference in New Issue
Block a user