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 &currentImage = 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