1 /*
2 * Copyright (C) 2023 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 "texture_layer.h"
17
18 #include <include/gpu/GrBackendSurface.h>
19 #ifndef NEW_SKIA
20 #include <include/gpu/GrContext.h>
21 #else
22 #include <include/gpu/GrDirectContext.h>
23 #endif
24 #include <include/gpu/gl/GrGLInterface.h>
25 #include <native_buffer.h>
26 #include <render_service_base/include/pipeline/rs_recording_canvas.h>
27 #include <render_service_base/include/property/rs_properties_def.h>
28 #include <render_service_client/core/pipeline/rs_node_map.h>
29 #include <render_service_client/core/transaction/rs_interfaces.h>
30 #include <render_service_client/core/ui/rs_canvas_node.h>
31 #include <render_service_client/core/ui/rs_root_node.h>
32 #include <render_service_client/core/ui/rs_surface_node.h>
33 #include <surface_buffer.h>
34 #include <surface_utils.h>
35 #include <window.h>
36
37 #include "3d_widget_adapter_log.h"
38 #include "graphics_manager.h"
39 #include "offscreen_context_helper.h"
40 #include "widget_trace.h"
41
42 namespace OHOS {
43 namespace Render3D {
44
TextureLayer(int32_t key)45 TextureLayer::TextureLayer(int32_t key) : key_(key)
46 {
47 auto& gfxManager = GraphicsManager::GetInstance();
48 backend_ = gfxManager.GetRenderBackendType(key);
49 if (backend_ == RenderBackend::GLES) {
50 gfxManager.GetOrCreateOffScreenContext(EGL_NO_CONTEXT);
51 }
52 }
53
UpdateRenderFinishFuture(std::shared_future<void> & ftr)54 void TextureLayer::UpdateRenderFinishFuture(std::shared_future<void> &ftr)
55 {
56 std::lock_guard<std::mutex> lk(ftrMut_);
57 image_.ftr_ = ftr;
58 }
59
SetParent(std::shared_ptr<Rosen::RSNode> & parent)60 void TextureLayer::SetParent(std::shared_ptr<Rosen::RSNode>& parent)
61 {
62 parent_ = parent;
63 // delete previous rs node reference
64 RemoveChild();
65
66 if (parent_ && rsNode_) {
67 parent_->AddChild(rsNode_, 0); // second paramenter is added child at the index of parent's children;
68 }
69 }
70
RemoveChild()71 void TextureLayer::RemoveChild()
72 {
73 if (parent_ && rsNode_) {
74 parent_->RemoveChild(rsNode_);
75 }
76 }
77
AllocGLTexture(uint32_t width,uint32_t height)78 void TextureLayer::AllocGLTexture(uint32_t width, uint32_t height)
79 {
80 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
81 GL_UNSIGNED_BYTE, 0);
82 }
83
AllocEglImage(uint32_t width,uint32_t height)84 void TextureLayer::AllocEglImage(uint32_t width, uint32_t height)
85 {
86 OH_NativeBuffer_Config config {
87 .width = width,
88 .height = height,
89 .format = GRAPHIC_PIXEL_FMT_RGBA_8888,
90 .usage = BUFFER_USAGE_MEM_DMA
91 };
92
93 nativeBuffer_ = OH_NativeBuffer_Alloc(&config);
94 if (!nativeBuffer_) {
95 WIDGET_LOGE("native buffer null");
96 return;
97 }
98
99 surfaceBuffer_ = SurfaceBuffer::NativeBufferToSurfaceBuffer(nativeBuffer_);
100 if (!surfaceBuffer_) {
101 WIDGET_LOGE("surface buffer null");
102 FreeNativeBuffer();
103 return;
104 }
105
106 nativeWindowBuffer_ = CreateNativeWindowBufferFromSurfaceBuffer(&surfaceBuffer_);
107 if (!nativeWindowBuffer_) {
108 WIDGET_LOGE("create native window buffer fail");
109 FreeNativeBuffer();
110 return;
111 }
112
113 EGLint attrs[] = {
114 EGL_IMAGE_PRESERVED, EGL_TRUE, EGL_NONE,
115 };
116 auto disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
117 eglImage_ = eglCreateImageKHR(disp, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_OHOS, nativeWindowBuffer_, attrs);
118 if (eglImage_ == EGL_NO_IMAGE_KHR) {
119 WIDGET_LOGE("create egl image fail %d", eglGetError());
120 FreeNativeWindowBuffer();
121 FreeNativeBuffer();
122 return;
123 }
124
125 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(eglImage_));
126 }
127
CreateNativeWindow(uint32_t width,uint32_t height)128 void* TextureLayer::CreateNativeWindow(uint32_t width, uint32_t height)
129 {
130 struct Rosen::RSSurfaceNodeConfig surfaceNodeConfig = { .SurfaceNodeName = std::string("SceneViewer Model") +
131 std::to_string(key_)};
132 rsNode_ = Rosen::RSSurfaceNode::Create(surfaceNodeConfig, false);
133 if (!rsNode_) {
134 WIDGET_LOGE("Create rs node fail");
135 return nullptr;
136 }
137
138 auto surfaceNode = OHOS::Rosen::RSBaseNode::ReinterpretCast<OHOS::Rosen::RSSurfaceNode>(rsNode_);
139 surfaceNode->SetFrameGravity(Rosen::Gravity::RESIZE);
140 if (surface_ == SurfaceType::SURFACE_WINDOW) {
141 surfaceNode->SetHardwareEnabled(true);
142 }
143 if (surface_ == SurfaceType::SURFACE_TEXTURE) {
144 surfaceNode->SetHardwareEnabled(false);
145 }
146
147 producerSurface_ = surfaceNode->GetSurface();
148 if (!producerSurface_) {
149 WIDGET_LOGE("Get producer surface fail");
150 return nullptr;
151 }
152 auto ret = SurfaceUtils::GetInstance()->Add(producerSurface_->GetUniqueId(), producerSurface_);
153 if (ret != SurfaceError::SURFACE_ERROR_OK) {
154 WIDGET_LOGE("add surface error");
155 return nullptr;
156 }
157
158 producerSurface_->SetQueueSize(3); // 3 seems ok
159 producerSurface_->SetUserData("SURFACE_STRIDE_ALIGNMENT", "8");
160 producerSurface_->SetUserData("SURFACE_FORMAT", std::to_string(GRAPHIC_PIXEL_FMT_RGBA_8888));
161 producerSurface_->SetUserData("SURFACE_WIDTH", std::to_string(width));
162 producerSurface_->SetUserData("SURFACE_HEIGHT", std::to_string(height));
163 auto window = CreateNativeWindowFromSurface(&producerSurface_);
164
165 return reinterpret_cast<void *>(window);
166 }
167
ConfigWindow(float offsetX,float offsetY,float width,float height,float scale,bool recreateWindow)168 void TextureLayer::ConfigWindow(float offsetX, float offsetY, float width, float height, float scale,
169 bool recreateWindow)
170 {
171 float widthScale = image_.textureInfo_.widthScale_;
172 float heightScale = image_.textureInfo_.heightScale_;
173 if (surface_ == SurfaceType::SURFACE_WINDOW || surface_ == SurfaceType::SURFACE_TEXTURE) {
174 image_.textureInfo_.recreateWindow_ = recreateWindow;
175
176 if (!image_.textureInfo_.nativeWindow_) {
177 image_.textureInfo_.nativeWindow_ = reinterpret_cast<void *>(CreateNativeWindow(
178 static_cast<uint32_t>(width * widthScale), static_cast<uint32_t>(height * heightScale)));
179 }
180 // need check recreate window flag
181 NativeWindowHandleOpt(reinterpret_cast<OHNativeWindow *>(image_.textureInfo_.nativeWindow_),
182 SET_BUFFER_GEOMETRY, static_cast<uint32_t>(width * scale * widthScale),
183 static_cast<uint32_t>(height * scale * heightScale));
184 rsNode_->SetBounds(offsetX, offsetY, width, height);
185 }
186 }
187
ConfigTexture(float width,float height)188 void TextureLayer::ConfigTexture(float width, float height)
189 {
190 if ((surface_ == SurfaceType::SURFACE_BUFFER) && !image_.textureInfo_.textureId_) {
191 AutoRestore scope;
192
193 GraphicsManager::GetInstance().BindOffScreenContext();
194 glGenTextures(1, &image_.textureInfo_.textureId_);
195
196 glBindTexture(GL_TEXTURE_2D, image_.textureInfo_.textureId_);
197 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
198 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
199 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
200 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
201
202 AllocGLTexture(static_cast<uint32_t>(width), static_cast<uint32_t>(height));
203
204 #if defined(UNIFY_RENDER) && (UNIFY_RENDER == 1)
205 AllocEglImage(static_cast<uint32_t>(width), static_cast<uint32_t>(height));
206 #endif
207 }
208 }
209
OnWindowChange(float offsetX,float offsetY,float width,float height,float scale,bool recreateWindow,SurfaceType surfaceType)210 TextureInfo TextureLayer::OnWindowChange(float offsetX, float offsetY, float width, float height, float scale,
211 bool recreateWindow, SurfaceType surfaceType)
212 {
213 DestroyRenderTarget();
214 surface_ = surfaceType;
215 offsetX_ = offsetX;
216 offsetY_ = offsetY;
217 if (image_.textureInfo_.width_ != static_cast<uint32_t>(width) ||
218 image_.textureInfo_.height_ != static_cast<uint32_t>(height)) {
219 needsRecreateSkImage_ = true;
220 }
221 image_.textureInfo_.width_ = static_cast<uint32_t>(width);
222 image_.textureInfo_.height_ = static_cast<uint32_t>(height);
223
224 ConfigWindow(offsetX, offsetY, width, height, scale, recreateWindow);
225 ConfigTexture(width, height);
226
227 WIDGET_LOGD("TextureLayer OnWindowChange offsetX %f, offsetY %f, width %d, height %d, float scale %f,"
228 "recreateWindow %d window empty %d", offsetX, offsetY, image_.textureInfo_.width_, image_.textureInfo_.height_,
229 scale, recreateWindow, image_.textureInfo_.nativeWindow_ == nullptr);
230 return image_.textureInfo_;
231 }
232
OnWindowChange(const WindowChangeInfo & windowChangeInfo)233 TextureInfo TextureLayer::OnWindowChange(const WindowChangeInfo& windowChangeInfo)
234 {
235 DestroyRenderTarget();
236 surface_ = windowChangeInfo.surfaceType;
237 offsetX_ = (int)windowChangeInfo.offsetX;
238 offsetY_ = (int)windowChangeInfo.offsetY;
239 if (image_.textureInfo_.width_ != static_cast<uint32_t>(windowChangeInfo.width) ||
240 image_.textureInfo_.height_ != static_cast<uint32_t>(windowChangeInfo.height)) {
241 needsRecreateSkImage_ = true;
242 }
243 image_.textureInfo_.width_ = static_cast<uint32_t>(windowChangeInfo.width);
244 image_.textureInfo_.height_ = static_cast<uint32_t>(windowChangeInfo.height);
245
246 image_.textureInfo_.widthScale_ = static_cast<float>(windowChangeInfo.widthScale);
247 image_.textureInfo_.heightScale_ = static_cast<float>(windowChangeInfo.heightScale);
248
249 ConfigWindow(windowChangeInfo.offsetX, windowChangeInfo.offsetY, windowChangeInfo.width,
250 windowChangeInfo.height, windowChangeInfo.scale, windowChangeInfo.recreateWindow);
251 ConfigTexture(windowChangeInfo.width, windowChangeInfo.height);
252
253 WIDGET_LOGD("TextureLayer OnWindowChange-1 offsetX %d, offsetY %d, width %d, height %d, scale %f,widthScale %f,"
254 "heightScale %f, recreateWindow %d window empty %d", offsetX_, offsetY_, image_.textureInfo_.width_,
255 image_.textureInfo_.height_, windowChangeInfo.scale, image_.textureInfo_.widthScale_,
256 image_.textureInfo_.heightScale_, windowChangeInfo.recreateWindow,
257 image_.textureInfo_.nativeWindow_ == nullptr);
258 return image_.textureInfo_;
259 }
260
FreeNativeBuffer()261 void TextureLayer::FreeNativeBuffer()
262 {
263 if (!nativeBuffer_) {
264 return;
265 }
266 OH_NativeBuffer_Unreference(nativeBuffer_);
267 nativeBuffer_ = nullptr;
268 }
269
FreeNativeWindowBuffer()270 void TextureLayer::FreeNativeWindowBuffer()
271 {
272 if (!nativeWindowBuffer_) {
273 return;
274 }
275 DestroyNativeWindowBuffer(nativeWindowBuffer_);
276 nativeWindowBuffer_ = nullptr;
277 }
278
DestroyProducerSurface()279 void TextureLayer::DestroyProducerSurface()
280 {
281 if (!producerSurface_) {
282 return;
283 }
284 auto surfaceUtils = SurfaceUtils::GetInstance();
285 surfaceUtils->Remove(producerSurface_->GetUniqueId());
286 }
287
DestroyNativeWindow()288 void TextureLayer::DestroyNativeWindow()
289 {
290 WIDGET_LOGD("TextureLayer::DestroyNativeWindow");
291 if (!image_.textureInfo_.nativeWindow_) {
292 WIDGET_LOGW("TextureLayer::DestroyNativeWindow invalid window");
293 return;
294 }
295 DestoryNativeWindow(reinterpret_cast<OHNativeWindow *>(image_.textureInfo_.nativeWindow_));
296 image_.textureInfo_.nativeWindow_ = nullptr;
297 }
298
DestroyRenderTarget()299 void TextureLayer::DestroyRenderTarget()
300 {
301 // surface buffer release
302 if (eglImage_ != EGL_NO_IMAGE_KHR) {
303 auto disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
304 eglDestroyImageKHR(disp, eglImage_);
305 eglImage_ = EGL_NO_IMAGE_KHR;
306 }
307
308 FreeNativeWindowBuffer();
309 FreeNativeBuffer();
310
311 if (image_.textureInfo_.textureId_ != 0U) {
312 AutoRestore scope;
313 GraphicsManager::GetInstance().BindOffScreenContext();
314 glDeleteTextures(1, &image_.textureInfo_.textureId_);
315 }
316
317 #if defined(DBG_DRAW_PIXEL) && (DBG_DRAW_PIXEL == 1)
318 if (fbo_ != 0U) {
319 AutoRestore scope;
320 GraphicsManager::GetInstance().BindOffScreenContext();
321 glDeleteFramebuffers(1, fbo_);
322 fbo_ = 0U;
323 }
324
325 if (data_ != nullptr) {
326 delete[] data_;
327 data_ = nullptr;
328 }
329 #endif
330
331 // window release
332 DestroyNativeWindow();
333 DestroyProducerSurface();
334 RemoveChild();
335 rsNode_ = nullptr;
336 parent_ = nullptr;
337 image_.textureInfo_ = {};
338 }
339
~TextureLayer()340 TextureLayer::~TextureLayer()
341 {
342 // explicit release resource before destructor
343 }
344
OnDraw(SkCanvas * canvas)345 void TextureLayer::OnDraw(SkCanvas* canvas)
346 {
347 if (surface_ == SurfaceType::SURFACE_WINDOW || surface_ == SurfaceType::SURFACE_TEXTURE) {
348 return;
349 }
350
351 if (canvas == nullptr) {
352 WIDGET_LOGE("TextureLayer::OnDraw canvas invalid")
353 return;
354 };
355
356 #if defined(UNIFY_RENDER) && (UNIFY_RENDER == 1)
357 onDraw(canvas);
358 #else
359 canvas->drawDrawable(this);
360 #endif
361 }
362
onDraw(SkCanvas * canvas)363 void TextureLayer::onDraw(SkCanvas* canvas)
364 {
365 WIDGET_SCOPED_TRACE("TextureLayer::onDraw");
366 if (canvas == nullptr) {
367 WIDGET_LOGE("TextureLayer::OnDraw canvas invalid")
368 return;
369 };
370 std::lock_guard<std::mutex> lk(ftrMut_);
371 if (image_.ftr_.valid()) {
372 image_.ftr_.get();
373 }
374 #if defined(UNIFY_RENDER) && (UNIFY_RENDER == 1)
375 DrawTextureUnifyRender(canvas);
376 #else
377 DrawTexture(canvas);
378 #endif
379 }
380
381 #if defined(UNIFY_RENDER) && (UNIFY_RENDER == 1)
DrawTextureUnifyRender(SkCanvas * canvas)382 void TextureLayer::DrawTextureUnifyRender(SkCanvas* canvas)
383 {
384 #if defined(DBG_DRAW_PIXEL) && (DBG_DRAW_PIXEL == 1)
385 // DEBUG copy texture to bitmap, no need ipc surfacebuffer
386 ReadPixel();
387 canvas->drawImage(MakePixelImage(), offsetX_, offsetY_);
388 return;
389 #endif
390 #ifndef USE_ROSEN_DRAWING
391 Rosen::RSSurfaceBufferInfo info {
392 surfaceBuffer_, offsetX_, offsetY_, image_.textureInfo_.width_, image_.textureInfo_.height_
393 };
394
395 auto recordingCanvas = static_cast<Rosen::RSRecordingCanvas*>(canvas);
396 recordingCanvas->DrawSurfaceBuffer(info);
397 #endif
398 }
399 #endif
400
DrawTexture(SkCanvas * canvas)401 void TextureLayer::DrawTexture(SkCanvas* canvas)
402 {
403 WIDGET_SCOPED_TRACE("TextureLayer::DrawTexture");
404 if (image_.textureInfo_.textureId_ == 0U) {
405 WIDGET_LOGE("%s invalid texture %d", __func__, __LINE__);
406 return;
407 }
408
409 if (image_.skImage_ == nullptr || needsRecreateSkImage_) {
410 needsRecreateSkImage_ = false;
411 GrGLTextureInfo textureInfo = { GL_TEXTURE_2D, image_.textureInfo_.textureId_, GL_RGBA8_OES };
412 GrBackendTexture backendTexture(image_.textureInfo_.width_, image_.textureInfo_.height_,
413 GrMipMapped::kNo, textureInfo);
414 #ifdef NEW_SKIA
415 image_.skImage_ = SkImage::MakeFromTexture(canvas->recordingContext(), backendTexture, kTopLeft_GrSurfaceOrigin,
416 kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
417 #else
418 image_.skImage_ = SkImage::MakeFromTexture(canvas->getGrContext(), backendTexture, kTopLeft_GrSurfaceOrigin,
419 kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
420 #endif
421 WIDGET_LOGW("%s Create SkImage %d", __func__, __LINE__);
422 }
423
424 canvas->drawImage(image_.skImage_, offsetX_, offsetY_);
425 }
426
427 #if defined(DBG_DRAW_PIXEL) && (DBG_DRAW_PIXEL == 1)
MakePixelImage()428 auto TextureLayer::MakePixelImage()
429 {
430 SkColorType ct = SkColorType::kRGBA_8888_SkColorType;
431 SkAlphaType at = SkAlphaType::kOpaque_SkAlphaType;
432 sk_sp<SkColorSpace> cs = SkColorSpace::MakeSRGB();
433 auto info = SkImageInfo::Make(image_.textureInfo_.width_, image_.textureInfo_.height_, ct, at, cs);
434
435 SkPixmap imagePixmap(info, reinterpret_cast<const void*>(data_), image_.textureInfo_.width_ * 4);
436
437 return SkImage::MakeFromRaster(imagePixmap, nullptr, nullptr);
438 }
439
ReadPixel()440 void TextureLayer::ReadPixel()
441 {
442 AutoRestore scope;
443 GraphicsManager::GetInstance().BindOffScreenContext();
444
445 if (fbo_ == 0) {
446 CreateReadFbo();
447 }
448
449 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
450
451 if (data_ == nullptr) {
452 data_ = new uint8_t[image_.textureInfo_.width_ * image_.textureInfo_.height_ * 4];
453 }
454
455 glReadPixels(0, 0, image_.textureInfo_.width_, image_.textureInfo_.height_, GL_RGBA, GL_UNSIGNED_BYTE, data_);
456
457 glBindFramebuffer(GL_FRAMEBUFFER, 0);
458 }
459
CreateReadFbo()460 void TextureLayer::CreateReadFbo()
461 {
462 glGenFramebuffers(1, &fbo_);
463 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
464 glBindTexture(GL_TEXTURE_2D, image_.textureInfo_.textureId_);
465
466 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, image_.textureInfo_.textureId_, 0);
467
468 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
469 if (status != GL_FRAMEBUFFER_COMPLETE) {
470 WIDGET_LOGE("framebuffer not complete, status %d, fbo_ %d, textureId_ %d",
471 status, fbo_, image_.textureInfo_.textureId_);
472 return;
473 }
474
475 glBindTexture(GL_TEXTURE_2D, 0);
476 glBindFramebuffer(GL_FRAMEBUFFER, 0);
477 }
478 #endif
479
onGetBounds()480 SkRect TextureLayer::onGetBounds()
481 {
482 return SkRect::MakeWH(image_.textureInfo_.width_, image_.textureInfo_.height_);
483 }
484
GetTextureInfo()485 TextureInfo TextureLayer::GetTextureInfo()
486 {
487 return image_.textureInfo_;
488 }
489
490 } // Render3D
491 } // OHOS
492