• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "native_avcodec_base.h"
17 #include <sstream>
18 #include <EGL/egl.h>
19 #include <GLES3/gl3.h>
20 #include <GLES3/gl31.h>
21 #include "external_window.h"
22 #include "native_averrors.h"
23 #include "graphics_render_engine_impl.h"
24 #include "render/graphics/base/gl_utils.h"
25 #include "render/graphics/base/render_context.h"
26 #include "render/graphics/base/render_surface.h"
27 #include "render/graphics/base/task/render_task.h"
28 #include "render/graphics/base/math/render_matrix.h"
29 #include "render/graphics/base/shader_pass/shader_pass_surface.h"
30 #include "render/graphics/base/shader_pass/shader_pass_on_screen.h"
31 #include "render/graphics/effect/image_effect_render.h"
32 #include "media_log.h"
33 
34 namespace OHOS {
35 namespace Media {
36 namespace {
37 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_VIDEOEDITOR, "Render"};
38 }
GraphicsRenderEngineImpl(uint64_t id)39 GraphicsRenderEngineImpl::GraphicsRenderEngineImpl(uint64_t id) : id_(id)
40 {
41     MEDIA_LOGD("construct.");
42 }
43 
~GraphicsRenderEngineImpl()44 GraphicsRenderEngineImpl::~GraphicsRenderEngineImpl()
45 {
46     MEDIA_LOGD("destroy begin.");
47     Destroy();
48 }
49 
Destroy()50 void GraphicsRenderEngineImpl::Destroy()
51 {
52     std::lock_guard<std::recursive_mutex> guard(renderMutex_);
53     if (surface_ != nullptr) {
54         delete surface_;
55         surface_ = nullptr;
56         MEDIA_LOGI("Destroy graphics render surface");
57     }
58     if (!ready_) {
59         MEDIA_LOGW("graphics render engine[id=%{public}" PRIu64 "] is not ready, need not destroy.", id_);
60         return;
61     }
62     ready_ = false;
63     if (renderThread_) {
64         auto task =
65             std::make_shared<RenderTask<>>([this]() { this->ReleaseThread(); }, COMMON_TASK_TAG, RequestTaskId());
66         renderThread_->ClearTaskQueue();
67         renderThread_->AddTask(task);
68         task->Wait();
69         delete renderThread_;
70         renderThread_ = nullptr;
71     }
72     MEDIA_LOGI("[Render] Engine %{public}" PRIu64 " destroy end!", id_);
73 }
74 
Init(OHNativeWindow * outputWindow)75 VEFError GraphicsRenderEngineImpl::Init(OHNativeWindow* outputWindow)
76 {
77     MEDIA_LOGI("init graphics engine.");
78     if (ready_) {
79         MEDIA_LOGW("[Render] graphics engine [id = %{public}" PRIu64 "] has been initialized,"
80         " please do not initialize again.", id_);
81         return VEFError::ERR_OK;
82     }
83 
84     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
85     if (!eglInitialize(display, nullptr, nullptr)) {
86         MEDIA_LOGE("unable to initialize display");
87         return VEFError::ERR_INTERNAL_ERROR;
88     }
89     MEDIA_LOGI("eglInitialize initialize finish");
90 
91     VEFError ret = InitExportEngine(outputWindow);
92     if (ret != VEFError::ERR_OK) {
93         MEDIA_LOGE("init export engine failed with error: %{public}d.", ret);
94         return ret;
95     }
96 
97     auto func = []() {};
98     renderThread_ = new (std::nothrow) RenderThread<>(RENDER_QUEUE_SIZE, func);
99     if (renderThread_ == nullptr) {
100         MEDIA_LOGE("create render thread failed.");
101         return VEFError::ERR_INTERNAL_ERROR;
102     }
103 
104     renderThread_->Start();
105     VEFError error = VEFError::ERR_OK;
106     auto task = std::make_shared<RenderTask<>>(
107         [this, &error]() {
108             error = this->InitThread();
109             if (error != VEFError::ERR_OK) {
110                 return;
111             }
112             error = this->InitSurfaceTexture();
113             if (error != VEFError::ERR_OK) {
114                 return;
115             }
116 
117             shaderPassSurface_ = std::make_shared<ShaderPassSurface>(context_.get());
118             shaderPassOnScreen_ = std::make_shared<ShaderPassOnScreen>(context_.get());
119             shaderPassRotate_ = std::make_shared<ShaderPassRotate>(context_.get());
120             ready_ = true;
121         },
122         COMMON_TASK_TAG, RequestTaskId());
123     renderThread_->AddTask(task);
124     task->Wait();
125 
126     MEDIA_LOGI("initEnv finish");
127     return VEFError::ERR_OK;
128 }
129 
StartRender()130 VEFError GraphicsRenderEngineImpl::StartRender()
131 {
132     MEDIA_LOGI("StartRender engine");
133     return VEFError::ERR_OK;
134 }
135 
UnInit()136 VEFError GraphicsRenderEngineImpl::UnInit()
137 {
138     if (renderThread_ != nullptr) {
139         delete renderThread_;
140         renderThread_ = nullptr;
141         MEDIA_LOGI("uninit graphics engine");
142     }
143     if (surface_ != nullptr) {
144         delete surface_;
145         surface_ = nullptr;
146         MEDIA_LOGI("unInit graphics surface");
147     }
148     return VEFError::ERR_OK;
149 }
150 
StopRender()151 VEFError GraphicsRenderEngineImpl::StopRender()
152 {
153     MEDIA_LOGI("StopRender engine");
154     if (ready_) {
155         renderThread_->ClearTaskQueue();
156         auto task =
157             std::make_shared<RenderTask<>>([this]() { this->ReleaseThread(); }, COMMON_TASK_TAG, RequestTaskId());
158         renderThread_->AddTask(task);
159         task->Wait();
160     }
161     return VEFError::ERR_OK;
162 }
163 
InitExportEngine(OHNativeWindow * window)164 VEFError GraphicsRenderEngineImpl::InitExportEngine(OHNativeWindow* window)
165 {
166     MEDIA_LOGI("[Render] InitExportEngine %{public}" PRIu64 "begin", id_);
167     if (window == nullptr) {
168         MEDIA_LOGE("init export engine failed, the window is nullptr.");
169         return VEFError::ERR_INVALID_PARAM;
170     }
171 
172     exportWindow_ = window;
173     surface_ = new (std::nothrow) RenderSurface(std::string());
174     if (surface_ == nullptr) {
175         MEDIA_LOGE("create RenderSurface object failed.");
176         return VEFError::ERR_OOM;
177     }
178 
179     surface_->SetAttrib(attribute_);
180     surface_->Create(window);
181 
182     MEDIA_LOGI("[Render] InitExportEngine %{public}" PRIu64 "success", id_);
183     return VEFError::ERR_OK;
184 }
185 
GetThreadId() const186 std::string GraphicsRenderEngineImpl::GetThreadId() const
187 {
188     std::ostringstream stream;
189     stream << std::this_thread::get_id();
190     return stream.str();
191 }
192 
InitThread()193 VEFError GraphicsRenderEngineImpl::InitThread()
194 {
195     std::string threadID = GetThreadId();
196     MEDIA_LOGI("init render thread [%{public}s].", threadID.c_str());
197 
198     auto context = std::make_shared<RenderContext>();
199     if (!context->Init()) {
200         MEDIA_LOGE("init render context failed");
201         return VEFError::ERR_INTERNAL_ERROR;
202     }
203     if (!context->MakeCurrent(surface_)) {
204         MEDIA_LOGE("make egl context to current context failed");
205         return VEFError::ERR_INTERNAL_ERROR;
206     }
207     context_ = context;
208     MEDIA_LOGI("init render thread [%{public}s] success.", threadID.c_str());
209     return VEFError::ERR_OK;
210 }
211 
ReleaseThread()212 void GraphicsRenderEngineImpl::ReleaseThread()
213 {
214     std::string threadId = GetThreadId();
215     MEDIA_LOGD("ReleaseThread: %{public}s", threadId.c_str());
216 }
217 
RequestTaskId()218 uint64_t GraphicsRenderEngineImpl::RequestTaskId()
219 {
220     return currentTaskId_.fetch_add(1);
221 }
222 
InitSurfaceTexture()223 VEFError GraphicsRenderEngineImpl::InitSurfaceTexture()
224 {
225     MEDIA_LOGI("init render surface texture.");
226     VEFError result = VEFError::ERR_INTERNAL_ERROR;
227     GLuint oesTexId = GL_NONE;
228     do {
229         auto surfaceTexture = std::make_shared<SurfaceTexture>();
230         if (!context_->MakeCurrent(surface_)) {
231             MEDIA_LOGE("make egl context to current context failed.");
232             break;
233         }
234         oesTexId = GLUtils::CreateTexNoStorage(GL_TEXTURE_EXTERNAL_OES);
235         if (oesTexId == GL_NONE) {
236             MEDIA_LOGE("create oes texture object failed.");
237             break;
238         }
239         surfaceTexture->nativeTexId_ = oesTexId;
240         auto nativeImage = OH_NativeImage_Create(oesTexId, GL_TEXTURE_EXTERNAL_OES);
241         if (nativeImage == nullptr) {
242             MEDIA_LOGE("create nativeImage object failed.");
243             break;
244         }
245         surfaceTexture->nativeImage_ =
246             std::shared_ptr<OH_NativeImage>(nativeImage, [](OH_NativeImage* image) { OH_NativeImage_Destroy(&image); });
247         surfaceTexture->nativeWindow_ = OH_NativeImage_AcquireNativeWindow(surfaceTexture->nativeImage_.get());
248         if (surfaceTexture->nativeWindow_ == nullptr) {
249             MEDIA_LOGE("OH_NativeImage_AcquireNativeWindow failed.");
250             break;
251         }
252         OH_OnFrameAvailableListener listener;
253         listener.context = surfaceTexture.get();
254         listener.onFrameAvailable = SurfaceTexture::OnFrameAvailable;
255         int32_t error = OH_NativeImage_SetOnFrameAvailableListener(surfaceTexture->nativeImage_.get(), listener);
256         if (error != 0) {
257             MEDIA_LOGE("OH_NativeImage_SetOnFrameAvailableListener failed with error:%{public}d.", error);
258             break;
259         }
260         surfaceTexture_ = surfaceTexture;
261         result = VEFError::ERR_OK;
262         MEDIA_LOGI("init render surface texture success.");
263     } while (false);
264     if (result != VEFError::ERR_OK) {
265         GLUtils::DeleteTexture(oesTexId);
266     }
267     return result;
268 }
269 
GetInputWindow()270 OHNativeWindow* GraphicsRenderEngineImpl::GetInputWindow()
271 {
272     if (surfaceTexture_ != nullptr) {
273         return surfaceTexture_->nativeWindow_;
274     }
275     return nullptr;
276 }
277 
Render(uint64_t index,const std::shared_ptr<GraphicsRenderInfo> & effectInfo,const RenderResultCallback & cb)278 VEFError GraphicsRenderEngineImpl::Render(uint64_t index, const std::shared_ptr<GraphicsRenderInfo>& effectInfo,
279     const RenderResultCallback& cb)
280 {
281     std::lock_guard<std::recursive_mutex> guard(renderMutex_);
282     if (ready_) {
283         MEDIA_LOGD("render frame[index = %{public}" PRIu64 "]", index);
284     } else {
285         MEDIA_LOGE("render engine not ready render frame[index = %{public}" PRIu64 "]failed", index);
286         return VEFError::ERR_INTERNAL_ERROR;
287     }
288     auto taskId = RequestTaskId();
289     auto launchTime = std::chrono::high_resolution_clock::now();
290     auto task = std::make_shared<RenderTask<>>(
291         [this, taskId, launchTime, index, effectInfo, cb]() {
292             auto beginTime = std::chrono::high_resolution_clock::now();
293             this->context_->MakeCurrent(surface_);
294             auto renderTexture = this->RenderFrame(effectInfo);
295             auto renderEndTime = std::chrono::high_resolution_clock::now();
296             this->DrawFrame(index, renderTexture);
297             auto drawEndtime = std::chrono::high_resolution_clock::now();
298             std::chrono::duration<double, std::milli> queueDelay = beginTime - launchTime;
299             std::chrono::duration<double, std::milli> renderTime = renderEndTime - beginTime;
300             std::chrono::duration<double, std::milli> drawtime = drawEndtime - renderEndTime;
301             MEDIA_LOGD("renderTime: %{public}lf frawTime: %{public}lf,"
302                 " queueDelay: %{public}lf, TaskId: %{public}" PRIu64 ","
303                 "ExternId:  %{public}" PRIu64 ".", renderTime.count(), drawtime.count(),
304                 queueDelay.count(), taskId, index);
305             cb(GraphicsRenderResult::SUCCESS);
306         },
307         EXPORT_TASK_TAG, taskId);
308 
309     renderThread_->AddTask(task);
310     return VEFError::ERR_OK;
311 }
312 
RenderFrame(const std::shared_ptr<GraphicsRenderInfo> & graphicsRenderInfo)313 RenderTexturePtr GraphicsRenderEngineImpl::RenderFrame(const std::shared_ptr<GraphicsRenderInfo>& graphicsRenderInfo)
314 {
315     surfaceTexture_->AwaitNativeImage();
316     GLUtils::CheckError(__FILE_NAME__, __LINE__);
317     if (auto ret = OH_NativeImage_UpdateSurfaceImage(surfaceTexture_->nativeImage_.get()); ret != 0) {
318         MEDIA_LOGE("RenderFrame OH_NativeImage_UpdateSurfaceImage failed with error:%{public}d.", ret);
319     }
320     GLint bufferW = -1;
321     GLint bufferH = -1;
322     glBindTexture(GL_TEXTURE_EXTERNAL_OES, surfaceTexture_->nativeTexId_);
323     glGetTexLevelParameteriv(GL_TEXTURE_EXTERNAL_OES, 0, GL_TEXTURE_WIDTH, &bufferW);
324     glGetTexLevelParameteriv(GL_TEXTURE_EXTERNAL_OES, 0, GL_TEXTURE_HEIGHT, &bufferH);
325     glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
326     int32_t rotation = graphicsRenderInfo->rotation_;
327     Mat4x4 matrix = GLUtils::GetOesSamplingMatrix({ bufferW, bufferH }, { bufferW, bufferH }, rotation, false);
328     SurfaceDataPtr surfaceData = shaderPassSurface_->GetRenderEffectData();
329     surfaceData->nativeTexId = surfaceTexture_->nativeTexId_;
330     surfaceData->uTexMatrix = matrix;
331     const int32_t rotation90 = 90;
332     const int32_t rotation270 = 270;
333     if (rotation == rotation90 || rotation == rotation270) {
334         surfaceData->outputWidth_ = bufferH;
335         surfaceData->outputHeight_ = bufferW;
336     } else {
337         surfaceData->outputWidth_ = bufferW;
338         surfaceData->outputHeight_ = bufferH;
339     }
340     auto outputRenderTexture = shaderPassSurface_->Render();
341     outputRenderTexture = RenderEffects(outputRenderTexture, graphicsRenderInfo);
342     if (rotation != 0) {
343         Mat4x4 rotateMatrix = GLUtils::GetOesSamplingMatrix(
344             {bufferW, bufferH},
345             { bufferW, bufferH },
346             -rotation,
347             false);
348         SurfaceDataPtr rotateSurfaceData = shaderPassRotate_->GetRenderEffectData();
349         rotateSurfaceData->inputTexture_ = outputRenderTexture;
350         rotateSurfaceData->outputWidth_ = bufferW;
351         rotateSurfaceData->outputHeight_ = bufferH;
352         rotateSurfaceData->uTexMatrix = rotateMatrix;
353         auto outputTexture = shaderPassRotate_->Render();
354         return outputTexture;
355     } else {
356         return outputRenderTexture;
357     }
358 }
359 
RenderEffects(const RenderTexturePtr & inputTexture,const std::shared_ptr<GraphicsRenderInfo> & graphicsRenderInfo)360 RenderTexturePtr GraphicsRenderEngineImpl::RenderEffects(const RenderTexturePtr& inputTexture,
361     const std::shared_ptr<GraphicsRenderInfo>& graphicsRenderInfo)
362 {
363     if (graphicsRenderInfo == nullptr) {
364         MEDIA_LOGD("renderInfo is nullptr, not need render effect.");
365         return inputTexture;
366     }
367     int32_t colorRange = graphicsRenderInfo->colorRange_;
368     auto outputRenderTexture = inputTexture;
369     for (const auto& effectInfo : graphicsRenderInfo->effectInfoList_) {
370         if (effectInfo->type != EffectType::IMAGE_EFFECT) {
371             MEDIA_LOGE("effectType [%{public}d] is not supported.", effectInfo->type);
372             continue;
373         }
374         auto it = imageEffectRenderList_.find(effectInfo->id);
375         if (it != imageEffectRenderList_.end()) {
376             outputRenderTexture = it->second->Render(context_.get(), surface_, outputRenderTexture, colorRange);
377         } else {
378 #ifdef IMAGE_EFFECT_SUPPORT
379             auto imageEffectRender = std::make_shared<ImageEffectRender>(effectInfo->imageEffect);
380             imageEffectRenderList_[effectInfo->id] = imageEffectRender;
381             outputRenderTexture = imageEffectRender->Render(context_.get(), surface_, outputRenderTexture, colorRange);
382 #endif
383         }
384     }
385 
386     return outputRenderTexture;
387 }
388 
DrawFrame(uint64_t pts,const RenderTexturePtr & renderTexture)389 void GraphicsRenderEngineImpl::DrawFrame(uint64_t pts, const RenderTexturePtr& renderTexture)
390 {
391     auto retCode = OH_NativeWindow_NativeWindowHandleOpt(exportWindow_, SET_UI_TIMESTAMP, pts);
392     if (retCode != AV_ERR_OK) {
393         MEDIA_LOGE("set native window opt faild, retcode = %{public}d", retCode);
394     }
395     RenderEffectDataPtr renderEffectData = shaderPassOnScreen_->GetRenderEffectData();
396     if (renderTexture == nullptr) {
397         MEDIA_LOGE("DrawFrame param renderTexture is nullptr.");
398         return;
399     }
400     renderEffectData->inputTexture_ = renderTexture;
401     renderEffectData->outputWidth_ = renderTexture->Width();
402     renderEffectData->outputHeight_ = renderTexture->Height();
403     shaderPassOnScreen_->Render();
404     context_->SwapBuffers(surface_);
405 }
406 }
407 }