1 /*
2 * Copyright (c) 2021 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 #define GL_GLEXT_PROTOTYPES
17 #define EGL_EGLEXT_PROTOTYPES
18
19 #include "surface_image.h"
20
21 #include "securec.h"
22 #include "sandbox_utils.h"
23 #include "surface_utils.h"
24
25 #include <cinttypes>
26 #include <atomic>
27 #include <sync_fence.h>
28 #include <unistd.h>
29 #include <window.h>
30
31 #include <EGL/egl.h>
32 #include <EGL/eglext.h>
33 #include <GLES/gl.h>
34 #include <GLES/glext.h>
35
36 namespace OHOS {
37 namespace {
38 // Get a uniqueID in a process
GetProcessUniqueId()39 static int GetProcessUniqueId()
40 {
41 static std::atomic<int> g_counter { 0 };
42 return g_counter.fetch_add(1, std::memory_order_relaxed);
43 }
44 }
45
SurfaceImage(uint32_t textureId, uint32_t textureTarget)46 SurfaceImage::SurfaceImage(uint32_t textureId, uint32_t textureTarget)
47 : ConsumerSurface("SurfaceImage-" + std::to_string(GetRealPid()) + "-" + std::to_string(GetProcessUniqueId())),
48 textureId_(textureId),
49 textureTarget_(textureTarget),
50 updateSurfaceImage_(false),
51 eglDisplay_(EGL_NO_DISPLAY),
52 eglContext_(EGL_NO_CONTEXT),
53 currentSurfaceImage_(UINT_MAX),
54 currentSurfaceBuffer_(nullptr),
55 currentTimeStamp_(0)
56 {
57 InitSurfaceImage();
58 }
59
SurfaceImage()60 SurfaceImage::SurfaceImage()
61 : ConsumerSurface("SurfaceImageConsumer-" + std::to_string(GetRealPid()) +
62 "-" + std::to_string(GetProcessUniqueId())),
63 currentSurfaceBuffer_(nullptr),
64 currentTimeStamp_(0)
65 {
66 InitSurfaceImage();
67 }
68
~SurfaceImage()69 SurfaceImage::~SurfaceImage()
70 {
71 for (auto it = imageCacheSeqs_.begin(); it != imageCacheSeqs_.end(); it++) {
72 DestroyEGLImage(it->second.eglImage_);
73 DestroyEGLSync(it->second.eglSync_);
74 }
75 }
76
InitSurfaceImage()77 void SurfaceImage::InitSurfaceImage()
78 {
79 std::string name = "SurfaceImage-" + std::to_string(GetRealPid()) + "-" + std::to_string(GetProcessUniqueId());
80 auto ret = ConsumerSurface::Init();
81 uniqueId_ = GetUniqueId();
82 BLOGI("InitSurfaceImage Init ret: %{public}d, uniqueId: %{public}" PRIu64 ".", ret, uniqueId_);
83 surfaceImageName_ = name;
84 }
85
UpdateSurfaceInfo(uint32_t seqNum, sptr<SurfaceBuffer> buffer, const sptr<SyncFence> &acquireFence, int64_t timestamp, Rect damage)86 void SurfaceImage::UpdateSurfaceInfo(uint32_t seqNum, sptr<SurfaceBuffer> buffer, const sptr<SyncFence> &acquireFence,
87 int64_t timestamp, Rect damage)
88 {
89 // release old buffer
90 int releaseFence = -1;
91 auto iter = imageCacheSeqs_.find(currentSurfaceImage_);
92 if (iter != imageCacheSeqs_.end() && iter->second.eglSync_ != EGL_NO_SYNC_KHR) {
93 releaseFence = eglDupNativeFenceFDANDROID(eglDisplay_, iter->second.eglSync_);
94 }
95 // There is no need to close this fd, because in function ReleaseBuffer it will be closed.
96 ReleaseBuffer(currentSurfaceBuffer_, releaseFence);
97
98 currentSurfaceImage_ = seqNum;
99 currentSurfaceBuffer_ = buffer;
100 currentTimeStamp_ = timestamp;
101 currentCrop_ = damage;
102 currentTransformType_ = ConsumerSurface::GetTransform();
103 auto utils = SurfaceUtils::GetInstance();
104 utils->ComputeTransformMatrix(currentTransformMatrix_, TRANSFORM_MATRIX_ELE_COUNT,
105 currentSurfaceBuffer_, currentTransformType_, currentCrop_);
106 utils->ComputeTransformMatrixV2(currentTransformMatrixV2_, TRANSFORM_MATRIX_ELE_COUNT,
107 currentSurfaceBuffer_, currentTransformType_, currentCrop_);
108
109 // wait on this acquireFence.
110 if (acquireFence != nullptr) {
111 acquireFence->Wait(-1);
112 }
113 }
114
UpdateSurfaceImage()115 SurfaceError SurfaceImage::UpdateSurfaceImage()
116 {
117 std::lock_guard<std::mutex> lockGuard(opMutex_);
118
119 // validate egl state
120 SurfaceError ret = ValidateEglState();
121 if (ret != SURFACE_ERROR_OK) {
122 return ret;
123 }
124
125 // acquire buffer
126 sptr<SurfaceBuffer> buffer = nullptr;
127 sptr<SyncFence> acquireFence = SyncFence::InvalidFence();
128 int64_t timestamp = 0;
129 Rect damage;
130 ret = AcquireBuffer(buffer, acquireFence, timestamp, damage);
131 if (ret != SURFACE_ERROR_OK) {
132 return ret;
133 }
134
135 ret = UpdateEGLImageAndTexture(buffer);
136 if (ret != SURFACE_ERROR_OK) {
137 ReleaseBuffer(buffer, -1);
138 return ret;
139 }
140
141 uint32_t seqNum = buffer->GetSeqNum();
142 UpdateSurfaceInfo(seqNum, buffer, acquireFence, timestamp, damage);
143 return SURFACE_ERROR_OK;
144 }
145
AttachContext(uint32_t textureId)146 SurfaceError SurfaceImage::AttachContext(uint32_t textureId)
147 {
148 std::lock_guard<std::mutex> lockGuard(opMutex_);
149 // validate egl state
150 SurfaceError ret = ValidateEglState();
151 if (ret != SURFACE_ERROR_OK) {
152 return ret;
153 }
154
155 textureId_ = textureId;
156 auto iter = imageCacheSeqs_.find(currentSurfaceImage_);
157 if (iter != imageCacheSeqs_.end()) {
158 glBindTexture(textureTarget_, textureId);
159 GLenum error = glGetError();
160 if (error != GL_NO_ERROR) {
161 BLOGE("glBindTexture failed, textureTarget:%{public}d, textureId_:%{public}d, error:%{public}d,"
162 "uniqueId: %{public}" PRIu64 ".", textureTarget_, textureId_, error, uniqueId_);
163 return SURFACE_ERROR_EGL_API_FAILED;
164 }
165 glEGLImageTargetTexture2DOES(textureTarget_, static_cast<GLeglImageOES>(iter->second.eglImage_));
166 error = glGetError();
167 if (error != GL_NO_ERROR) {
168 BLOGE("glEGLImageTargetTexture2DOES failed, textureTarget:%{public}d, error:%{public}d"
169 "uniqueId: %{public}" PRIu64 ".", textureTarget_, error, uniqueId_);
170 return SURFACE_ERROR_EGL_API_FAILED;
171 }
172 }
173
174 // If there is no EGLImage, we cannot simply return an error.
175 // Developers can call OH_NativeImage_UpdateSurfaceImage later to achieve their purpose.
176 return SURFACE_ERROR_OK;
177 }
178
DetachContext()179 SurfaceError SurfaceImage::DetachContext()
180 {
181 std::lock_guard<std::mutex> lockGuard(opMutex_);
182 // validate egl state
183 SurfaceError ret = ValidateEglState();
184 if (ret != SURFACE_ERROR_OK) {
185 return ret;
186 }
187
188 textureId_ = 0;
189 glBindTexture(textureTarget_, 0);
190 GLenum error = glGetError();
191 if (error != GL_NO_ERROR) {
192 BLOGE("glBindTexture failed, textureTarget:%{public}d, textureId:%{public}d, error:%{public}d"
193 "uniqueId: %{public}" PRIu64 ".", textureTarget_, textureId_, error, uniqueId_);
194 return SURFACE_ERROR_EGL_API_FAILED;
195 }
196 return SURFACE_ERROR_OK;
197 }
198
GetTimeStamp()199 int64_t SurfaceImage::GetTimeStamp()
200 {
201 std::lock_guard<std::mutex> lockGuard(opMutex_);
202 return currentTimeStamp_;
203 }
204
GetTransformMatrix(float matrix[16])205 SurfaceError SurfaceImage::GetTransformMatrix(float matrix[16])
206 {
207 std::lock_guard<std::mutex> lockGuard(opMutex_);
208 auto ret = memcpy_s(matrix, sizeof(float) * 16, // 16 is the length of array
209 currentTransformMatrix_, sizeof(currentTransformMatrix_));
210 if (ret != EOK) {
211 BLOGE("memcpy_s failed ret: %{public}d, uniqueId: %{public}" PRIu64 ".", ret, uniqueId_);
212 return SURFACE_ERROR_UNKOWN;
213 }
214 return SURFACE_ERROR_OK;
215 }
216
GetTransformMatrixV2(float matrix[16])217 SurfaceError SurfaceImage::GetTransformMatrixV2(float matrix[16])
218 {
219 std::lock_guard<std::mutex> lockGuard(opMutex_);
220 auto ret = memcpy_s(matrix, sizeof(float) * 16, // 16 is the length of array
221 currentTransformMatrixV2_, sizeof(currentTransformMatrixV2_));
222 if (ret != EOK) {
223 BLOGE("memcpy_s failed ret: %{public}d, uniqueId: %{public}" PRIu64 ".", ret, uniqueId_);
224 return SURFACE_ERROR_UNKOWN;
225 }
226 return SURFACE_ERROR_OK;
227 }
228
ValidateEglState()229 SurfaceError SurfaceImage::ValidateEglState()
230 {
231 EGLDisplay disp = eglGetCurrentDisplay();
232 EGLContext context = eglGetCurrentContext();
233
234 if ((eglDisplay_ != disp && eglDisplay_ != EGL_NO_DISPLAY) || (disp == EGL_NO_DISPLAY)) {
235 BLOGE("EGLDisplay is invalid, errno : 0x%{public}x, uniqueId: %{public}" PRIu64 ".",
236 eglGetError(), uniqueId_);
237 return SURFACE_ERROR_EGL_STATE_UNKONW;
238 }
239 if ((eglContext_ != context && eglContext_ != EGL_NO_CONTEXT) || (context == EGL_NO_CONTEXT)) {
240 BLOGE("EGLContext is invalid, errno : 0x%{public}x, uniqueId: %{public}" PRIu64 ".",
241 eglGetError(), uniqueId_);
242 return SURFACE_ERROR_EGL_STATE_UNKONW;
243 }
244
245 eglDisplay_ = disp;
246 eglContext_ = context;
247 return SURFACE_ERROR_OK;
248 }
249
CreateEGLImage(EGLDisplay disp, const sptr<SurfaceBuffer>& buffer)250 EGLImageKHR SurfaceImage::CreateEGLImage(EGLDisplay disp, const sptr<SurfaceBuffer>& buffer)
251 {
252 sptr<SurfaceBuffer> bufferImpl = buffer;
253 NativeWindowBuffer* nBuffer = CreateNativeWindowBufferFromSurfaceBuffer(&bufferImpl);
254 EGLint attrs[] = {
255 EGL_IMAGE_PRESERVED,
256 EGL_TRUE,
257 EGL_NONE,
258 };
259
260 EGLImageKHR img = eglCreateImageKHR(disp, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_OHOS, nBuffer, attrs);
261 if (img == EGL_NO_IMAGE_KHR) {
262 EGLint error = eglGetError();
263 BLOGE("failed, error %{public}d, uniqueId: %{public}" PRIu64 ".", error, uniqueId_);
264 eglTerminate(disp);
265 }
266 DestroyNativeWindowBuffer(nBuffer);
267 return img;
268 }
269
CheckImageCacheNeedClean(uint32_t seqNum)270 void SurfaceImage::CheckImageCacheNeedClean(uint32_t seqNum)
271 {
272 for (auto it = imageCacheSeqs_.begin(); it != imageCacheSeqs_.end();) {
273 bool result = true;
274 if (seqNum == it->first) {
275 it++;
276 continue;
277 }
278 if (IsSurfaceBufferInCache(it->first, result) == SURFACE_ERROR_OK && !result) {
279 DestroyEGLImage(it->second.eglImage_);
280 DestroyEGLSync(it->second.eglSync_);
281 it = imageCacheSeqs_.erase(it);
282 } else {
283 it++;
284 }
285 }
286 }
287
DestroyEGLImage(EGLImageKHR &eglImage)288 void SurfaceImage::DestroyEGLImage(EGLImageKHR &eglImage)
289 {
290 if (eglImage != EGL_NO_IMAGE_KHR) {
291 eglDestroyImageKHR(eglDisplay_, eglImage);
292 eglImage = EGL_NO_IMAGE_KHR;
293 }
294 }
295
DestroyEGLSync(EGLSyncKHR &eglSync)296 void SurfaceImage::DestroyEGLSync(EGLSyncKHR &eglSync)
297 {
298 if (eglSync != EGL_NO_SYNC_KHR) {
299 eglDestroySyncKHR(eglDisplay_, eglSync);
300 eglSync = EGL_NO_SYNC_KHR;
301 }
302 }
303
DestroyEGLImageBySeq(uint32_t seqNum)304 void SurfaceImage::DestroyEGLImageBySeq(uint32_t seqNum)
305 {
306 auto iter = imageCacheSeqs_.find(seqNum);
307 if (iter != imageCacheSeqs_.end()) {
308 DestroyEGLImage(iter->second.eglImage_);
309 imageCacheSeqs_.erase(seqNum);
310 }
311 }
312
NewBufferDestroyEGLImage(bool isNewBuffer, uint32_t seqNum)313 void SurfaceImage::NewBufferDestroyEGLImage(bool isNewBuffer, uint32_t seqNum)
314 {
315 if (isNewBuffer) {
316 DestroyEGLImageBySeq(seqNum);
317 }
318 }
319
UpdateEGLImageAndTexture(const sptr<SurfaceBuffer>& buffer)320 SurfaceError SurfaceImage::UpdateEGLImageAndTexture(const sptr<SurfaceBuffer>& buffer)
321 {
322 bool isNewBuffer = false;
323 // private function, buffer is always valid.
324 uint32_t seqNum = buffer->GetSeqNum();
325 // If there was no eglImage binding to this buffer, we create a new one.
326 if (imageCacheSeqs_.find(seqNum) == imageCacheSeqs_.end()) {
327 isNewBuffer = true;
328 EGLImageKHR eglImage = CreateEGLImage(eglDisplay_, buffer);
329 if (eglImage == EGL_NO_IMAGE_KHR) {
330 return SURFACE_ERROR_EGL_API_FAILED;
331 }
332 imageCacheSeqs_[seqNum].eglImage_ = eglImage;
333 }
334
335 auto &image = imageCacheSeqs_[seqNum];
336 glBindTexture(textureTarget_, textureId_);
337 GLenum error = glGetError();
338 if (error != GL_NO_ERROR) {
339 NewBufferDestroyEGLImage(isNewBuffer, seqNum);
340 BLOGE("glBindTexture failed, textureTarget:%{public}d, textureId_:%{public}d, error:%{public}d"
341 "uniqueId: %{public}" PRIu64 ".", textureTarget_, textureId_, error, uniqueId_);
342 return SURFACE_ERROR_EGL_API_FAILED;
343 }
344 glEGLImageTargetTexture2DOES(textureTarget_, static_cast<GLeglImageOES>(image.eglImage_));
345 error = glGetError();
346 if (error != GL_NO_ERROR) {
347 NewBufferDestroyEGLImage(isNewBuffer, seqNum);
348 BLOGE("glEGLImageTargetTexture2DOES failed, textureTarget:%{public}d, error:%{public}d"
349 "uniqueId: %{public}" PRIu64 ".", textureTarget_, error, uniqueId_);
350 return SURFACE_ERROR_EGL_API_FAILED;
351 }
352
353 // Create fence object for current image
354 auto iter = imageCacheSeqs_.find(currentSurfaceImage_);
355 if (iter != imageCacheSeqs_.end()) {
356 auto ¤tImage = iter->second;
357 auto preSync = currentImage.eglSync_;
358 if (preSync != EGL_NO_SYNC_KHR) {
359 eglDestroySyncKHR(eglDisplay_, preSync);
360 }
361 currentImage.eglSync_ = eglCreateSyncKHR(eglDisplay_, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
362 glFlush();
363 }
364
365 if (isNewBuffer) {
366 CheckImageCacheNeedClean(seqNum);
367 }
368 return SURFACE_ERROR_OK;
369 }
370
SetOnBufferAvailableListener(void *context, OnBufferAvailableListener listener)371 SurfaceError SurfaceImage::SetOnBufferAvailableListener(void *context, OnBufferAvailableListener listener)
372 {
373 std::lock_guard<std::mutex> lockGuard(opMutex_);
374 if (listener == nullptr) {
375 BLOGE("listener is nullptr, uniqueId: %{public}" PRIu64 ".", uniqueId_);
376 return SURFACE_ERROR_INVALID_PARAM;
377 }
378
379 listener_ = listener;
380 context_ = context;
381 return SURFACE_ERROR_OK;
382 }
383
UnsetOnBufferAvailableListener()384 SurfaceError SurfaceImage::UnsetOnBufferAvailableListener()
385 {
386 std::lock_guard<std::mutex> lockGuard(opMutex_);
387 listener_ = nullptr;
388 context_ = nullptr;
389 return SURFACE_ERROR_OK;
390 }
391
~SurfaceImageListener()392 SurfaceImageListener::~SurfaceImageListener()
393 {
394 BLOGE("~SurfaceImageListener");
395 surfaceImage_ = nullptr;
396 }
397
OnBufferAvailable()398 void SurfaceImageListener::OnBufferAvailable()
399 {
400 BLOGD("enter OnBufferAvailable");
401 auto surfaceImage = surfaceImage_.promote();
402 if (surfaceImage == nullptr) {
403 BLOGE("surfaceImage promote failed");
404 return;
405 }
406
407 // check here maybe a messagequeue, flag instead now
408 surfaceImage->OnUpdateBufferAvailableState(true);
409 if (surfaceImage->listener_ != nullptr) {
410 surfaceImage->listener_(surfaceImage->context_);
411 }
412 }
413
AcquireNativeWindowBuffer(OHNativeWindowBuffer** nativeWindowBuffer, int32_t* fenceFd)414 SurfaceError SurfaceImage::AcquireNativeWindowBuffer(OHNativeWindowBuffer** nativeWindowBuffer, int32_t* fenceFd)
415 {
416 if (nativeWindowBuffer == nullptr || fenceFd == nullptr) {
417 return SURFACE_ERROR_INVALID_PARAM;
418 }
419 std::lock_guard<std::mutex> lockGuard(opMutex_);
420 sptr<SurfaceBuffer> buffer = nullptr;
421 sptr<SyncFence> acquireFence = SyncFence::InvalidFence();
422 int64_t timestamp;
423 Rect damage;
424 SurfaceError ret = AcquireBuffer(buffer, acquireFence, timestamp, damage);
425 if (ret != SURFACE_ERROR_OK) {
426 BLOGE("AcquireBuffer failed: %{public}d, uniqueId: %{public}" PRIu64 ".", ret, uniqueId_);
427 return ret;
428 }
429 currentSurfaceBuffer_ = buffer;
430 currentTimeStamp_ = timestamp;
431 currentCrop_ = damage;
432 currentTransformType_ = ConsumerSurface::GetTransform();
433 auto utils = SurfaceUtils::GetInstance();
434 utils->ComputeTransformMatrixV2(currentTransformMatrixV2_, TRANSFORM_MATRIX_ELE_COUNT,
435 currentSurfaceBuffer_, currentTransformType_, currentCrop_);
436
437 *fenceFd = acquireFence->Dup();
438 OHNativeWindowBuffer *nwBuffer = new(std::nothrow) OHNativeWindowBuffer();
439 if (nwBuffer == nullptr) {
440 return SURFACE_ERROR_NOMEM;
441 }
442 nwBuffer->sfbuffer = buffer;
443 NativeObjectReference(nwBuffer);
444 *nativeWindowBuffer = nwBuffer;
445
446 return SURFACE_ERROR_OK;
447 }
448
ReleaseNativeWindowBuffer(OHNativeWindowBuffer* nativeWindowBuffer, int32_t fenceFd)449 SurfaceError SurfaceImage::ReleaseNativeWindowBuffer(OHNativeWindowBuffer* nativeWindowBuffer, int32_t fenceFd)
450 {
451 if (nativeWindowBuffer == nullptr) {
452 return SURFACE_ERROR_INVALID_PARAM;
453 }
454 std::lock_guard<std::mutex> lockGuard(opMutex_);
455 // There is no need to close this fd, because in function ReleaseBuffer it will be closed.
456 SurfaceError ret = ReleaseBuffer(nativeWindowBuffer->sfbuffer, fenceFd);
457 if (ret != SURFACE_ERROR_OK) {
458 BLOGE("ReleaseBuffer failed: %{public}d, uniqueId: %{public}" PRIu64 ".", ret, uniqueId_);
459 return ret;
460 }
461 NativeObjectUnreference(nativeWindowBuffer);
462 return SURFACE_ERROR_OK;
463 }
464
SetDefaultUsage(uint64_t usage)465 SurfaceError SurfaceImage::SetDefaultUsage(uint64_t usage)
466 {
467 SurfaceError ret = ConsumerSurface::SetDefaultUsage(usage);
468 if (ret != SURFACE_ERROR_OK) {
469 BLOGE("SetDefaultUsage failed: %{public}d, uniqueId: %{public}" PRIu64 ", usage: %{public}" PRIu64 ".", ret,
470 uniqueId_, usage);
471 }
472 return ret;
473 }
474
SetDefaultSize(int32_t width, int32_t height)475 SurfaceError SurfaceImage::SetDefaultSize(int32_t width, int32_t height)
476 {
477 SurfaceError ret = SetDefaultWidthAndHeight(width, height);
478 if (ret != SURFACE_ERROR_OK) {
479 BLOGE("SetDefaultWidthAndHeight failed: %{public}d, uniqueId: %{public}" PRIu64 ", width: %{public}d, "
480 "height: %{public}d", ret, uniqueId_, width, height);
481 }
482 return ret;
483 }
484 } // namespace OHOS
485