• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <atomic>
26 #include <sync_fence.h>
27 #include <unistd.h>
28 #include <window.h>
29 
30 #include <EGL/egl.h>
31 #include <EGL/eglext.h>
32 #include <GLES/gl.h>
33 #include <GLES/glext.h>
34 
35 namespace OHOS {
36 namespace {
37 // Get a uniqueID in a process
GetProcessUniqueId()38 static int GetProcessUniqueId()
39 {
40     static std::atomic<int> g_counter { 0 };
41     return g_counter.fetch_add(1);
42 }
43 }
44 
SurfaceImage(uint32_t textureId,uint32_t textureTarget)45 SurfaceImage::SurfaceImage(uint32_t textureId, uint32_t textureTarget)
46     : ConsumerSurface("SurfaceImage-" + std::to_string(GetRealPid()) + "-" + std::to_string(GetProcessUniqueId())),
47       textureId_(textureId),
48       textureTarget_(textureTarget),
49       updateSurfaceImage_(false),
50       eglDisplay_(EGL_NO_DISPLAY),
51       eglContext_(EGL_NO_CONTEXT),
52       currentSurfaceImage_(UINT_MAX),
53       currentSurfaceBuffer_(nullptr),
54       currentTimeStamp_(0)
55 {
56     InitSurfaceImage();
57 }
58 
~SurfaceImage()59 SurfaceImage::~SurfaceImage()
60 {
61     for (auto it = imageCacheSeqs_.begin(); it != imageCacheSeqs_.end(); it++) {
62         if (it->second.eglImage_ != EGL_NO_IMAGE_KHR) {
63             eglDestroyImageKHR(eglDisplay_, it->second.eglImage_);
64             it->second.eglImage_ = EGL_NO_IMAGE_KHR;
65         }
66         if (it->second.eglSync_ != EGL_NO_SYNC_KHR) {
67             eglDestroySyncKHR(eglDisplay_, it->second.eglSync_);
68             it->second.eglSync_ = EGL_NO_SYNC_KHR;
69         }
70     }
71 }
72 
InitSurfaceImage()73 void SurfaceImage::InitSurfaceImage()
74 {
75     std::string name = "SurfaceImage-" + std::to_string(GetRealPid()) + "-" + std::to_string(GetProcessUniqueId());
76     auto ret = ConsumerSurface::Init();
77     BLOGI("surfaceimage init");
78     if (ret != SURFACE_ERROR_OK) {
79         BLOGE("init surfaceimage failed");
80     }
81     surfaceImageName_ = name;
82 }
83 
SetDefaultSize(int32_t width,int32_t height)84 SurfaceError SurfaceImage::SetDefaultSize(int32_t width, int32_t height)
85 {
86     return ConsumerSurface::SetDefaultWidthAndHeight(width, height);
87 }
88 
UpdateSurfaceInfo(uint32_t seqNum,sptr<SurfaceBuffer> buffer,const sptr<SyncFence> & acquireFence,int64_t timestamp,Rect damage)89 void SurfaceImage::UpdateSurfaceInfo(uint32_t seqNum, sptr<SurfaceBuffer> buffer, const sptr<SyncFence> &acquireFence,
90                                      int64_t timestamp, Rect damage)
91 {
92     // release old buffer
93     int releaseFence = -1;
94     if (imageCacheSeqs_.count(currentSurfaceImage_) > 0 &&
95         imageCacheSeqs_.at(currentSurfaceImage_).eglSync_ != EGL_NO_SYNC_KHR) {
96         // PLANNING: use eglDupNativeFenceFDOHOS in the future.
97         releaseFence = eglDupNativeFenceFDANDROID(eglDisplay_, imageCacheSeqs_.at(currentSurfaceImage_).eglSync_);
98     }
99     // There is no need to close this fd, because in function ReleaseBuffer it will be closed.
100     ReleaseBuffer(currentSurfaceBuffer_, releaseFence);
101 
102     currentSurfaceImage_ = seqNum;
103     currentSurfaceBuffer_ = buffer;
104     currentTimeStamp_ = timestamp;
105     currentCrop_ = damage;
106     currentTransformType_ = ConsumerSurface::GetTransform();
107     auto utils = SurfaceUtils::GetInstance();
108     utils->ComputeTransformMatrix(currentTransformMatrix_, currentSurfaceBuffer_, currentTransformType_, currentCrop_);
109 
110     // wait on this acquireFence.
111     if (acquireFence != nullptr) {
112         acquireFence->Wait(-1);
113     }
114 }
115 
UpdateSurfaceImage()116 SurfaceError SurfaceImage::UpdateSurfaceImage()
117 {
118     std::lock_guard<std::mutex> lockGuard(opMutex_);
119 
120     // validate egl state
121     SurfaceError ret = ValidateEglState();
122     if (ret != SURFACE_ERROR_OK) {
123         return ret;
124     }
125 
126     // acquire buffer
127     sptr<SurfaceBuffer> buffer = nullptr;
128     sptr<SyncFence> acquireFence = SyncFence::INVALID_FENCE;
129     int64_t timestamp;
130     Rect damage;
131     ret = AcquireBuffer(buffer, acquireFence, timestamp, damage);
132     if (ret != SURFACE_ERROR_OK) {
133         if (ret == SURFACE_ERROR_NO_BUFFER) {
134             BLOGE("AcquireBuffer no buffer");
135         } else {
136             BLOGE("AcquireBuffer failed");
137         }
138         return ret;
139     }
140 
141     ret = UpdateEGLImageAndTexture(eglDisplay_, buffer);
142     if (ret != SURFACE_ERROR_OK) {
143         ReleaseBuffer(buffer, -1);
144         return ret;
145     }
146 
147     uint32_t seqNum = buffer->GetSeqNum();
148     UpdateSurfaceInfo(seqNum, buffer, acquireFence, timestamp, damage);
149     return SURFACE_ERROR_OK;
150 }
151 
AttachContext(uint32_t textureId)152 SurfaceError SurfaceImage::AttachContext(uint32_t textureId)
153 {
154     std::lock_guard<std::mutex> lockGuard(opMutex_);
155     // validate egl state
156     SurfaceError ret = ValidateEglState();
157     if (ret != SURFACE_ERROR_OK) {
158         return ret;
159     }
160 
161     textureId_ = textureId;
162     if (imageCacheSeqs_.count(currentSurfaceImage_) > 0) {
163         const auto &image = imageCacheSeqs_.at(currentSurfaceImage_).eglImage_;
164         glBindTexture(textureTarget_, textureId);
165         glEGLImageTargetTexture2DOES(textureTarget_, static_cast<GLeglImageOES>(image));
166         if (glGetError() != GL_NO_ERROR) {
167             return SURFACE_ERROR_API_FAILED;
168         }
169     }
170 
171     // If there is no EGLImage, we cannot simply return an error.
172     // Developers can call OH_NativeImage_UpdateSurfaceImage later to achieve their purpose.
173     return SURFACE_ERROR_OK;
174 }
175 
DetachContext()176 SurfaceError SurfaceImage::DetachContext()
177 {
178     std::lock_guard<std::mutex> lockGuard(opMutex_);
179     // validate egl state
180     SurfaceError ret = ValidateEglState();
181     if (ret != SURFACE_ERROR_OK) {
182         return ret;
183     }
184 
185     textureId_ = 0;
186     glBindTexture(textureTarget_, 0);
187     return SURFACE_ERROR_OK;
188 }
189 
GetTimeStamp()190 int64_t SurfaceImage::GetTimeStamp()
191 {
192     std::lock_guard<std::mutex> lockGuard(opMutex_);
193     return currentTimeStamp_;
194 }
195 
GetTransformMatrix(float matrix[16])196 SurfaceError SurfaceImage::GetTransformMatrix(float matrix[16])
197 {
198     std::lock_guard<std::mutex> lockGuard(opMutex_);
199     auto ret = memcpy_s(matrix, sizeof(currentTransformMatrix_),
200                         currentTransformMatrix_, sizeof(currentTransformMatrix_));
201     if (ret != EOK) {
202         BLOGE("GetTransformMatrix: currentTransformMatrix_ memcpy_s failed");
203         return SURFACE_ERROR_ERROR;
204     }
205     return SURFACE_ERROR_OK;
206 }
207 
ValidateEglState()208 SurfaceError SurfaceImage::ValidateEglState()
209 {
210     EGLDisplay disp = eglGetCurrentDisplay();
211     EGLContext context = eglGetCurrentContext();
212 
213     if ((eglDisplay_ != disp && eglDisplay_ != EGL_NO_DISPLAY) || (disp == EGL_NO_DISPLAY)) {
214         BLOGE("EGLDisplay is invalid, errno : 0x%{public}x", eglGetError());
215         return SURFACE_ERROR_INIT;
216     }
217     if ((eglContext_ != context && eglContext_ != EGL_NO_CONTEXT) || (context == EGL_NO_CONTEXT)) {
218         BLOGE("EGLContext is invalid, errno : 0x%{public}x", eglGetError());
219         return SURFACE_ERROR_INIT;
220     }
221 
222     eglDisplay_ = disp;
223     eglContext_ = context;
224     return SURFACE_ERROR_OK;
225 }
226 
CreateEGLImage(EGLDisplay disp,const sptr<SurfaceBuffer> & buffer)227 EGLImageKHR SurfaceImage::CreateEGLImage(EGLDisplay disp, const sptr<SurfaceBuffer>& buffer)
228 {
229     sptr<SurfaceBuffer> bufferImpl = buffer;
230     NativeWindowBuffer* nBuffer = CreateNativeWindowBufferFromSurfaceBuffer(&bufferImpl);
231     EGLint attrs[] = {
232         EGL_IMAGE_PRESERVED,
233         EGL_TRUE,
234         EGL_NONE,
235     };
236 
237     EGLImageKHR img = eglCreateImageKHR(disp, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_OHOS, nBuffer, attrs);
238     if (img == EGL_NO_IMAGE_KHR) {
239         EGLint error = eglGetError();
240         BLOGE("failed, error %{public}d", error);
241         eglTerminate(disp);
242     }
243     DestroyNativeWindowBuffer(nBuffer);
244     return img;
245 }
246 
UpdateEGLImageAndTexture(EGLDisplay disp,const sptr<SurfaceBuffer> & buffer)247 SurfaceError SurfaceImage::UpdateEGLImageAndTexture(EGLDisplay disp, const sptr<SurfaceBuffer>& buffer)
248 {
249     // private function, buffer is always valid.
250     uint32_t seqNum = buffer->GetSeqNum();
251     // If there was no eglImage binding to this buffer, we create a new one.
252     if (imageCacheSeqs_.count(seqNum) == 0) {
253         EGLImageKHR eglImage = CreateEGLImage(eglDisplay_, buffer);
254         if (eglImage == EGL_NO_IMAGE_KHR) {
255             return SURFACE_ERROR_INIT;
256         }
257         imageCacheSeqs_[seqNum].eglImage_ = eglImage;
258     }
259 
260     const auto &image = imageCacheSeqs_.at(seqNum).eglImage_;
261     glBindTexture(textureTarget_, textureId_);
262     glEGLImageTargetTexture2DOES(textureTarget_, static_cast<GLeglImageOES>(image));
263     if (glGetError() != GL_NO_ERROR) {
264         return SURFACE_ERROR_API_FAILED;
265     }
266 
267     auto sync = imageCacheSeqs_.at(seqNum).eglSync_;
268     if (sync != EGL_NO_SYNC_KHR) {
269         eglDestroySyncKHR(disp, sync);
270     }
271     sync = eglCreateSyncKHR(disp, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
272     imageCacheSeqs_.at(seqNum).eglSync_ = sync;
273     return SURFACE_ERROR_OK;
274 }
275 
SetOnBufferAvailableListener(void * context,OnBufferAvailableListener listener)276 SurfaceError SurfaceImage::SetOnBufferAvailableListener(void *context, OnBufferAvailableListener listener)
277 {
278     std::lock_guard<std::mutex> lockGuard(opMutex_);
279     if (listener == nullptr) {
280         BLOGE("listener is nullptr");
281         return SURFACE_ERROR_ERROR;
282     }
283 
284     listener_ = listener;
285     context_ = context;
286     return SURFACE_ERROR_OK;
287 }
288 
UnsetOnBufferAvailableListener()289 SurfaceError SurfaceImage::UnsetOnBufferAvailableListener()
290 {
291     std::lock_guard<std::mutex> lockGuard(opMutex_);
292     listener_ = nullptr;
293     context_ = nullptr;
294     return SURFACE_ERROR_OK;
295 }
296 
~SurfaceImageListener()297 SurfaceImageListener::~SurfaceImageListener()
298 {
299     BLOGE("~SurfaceImageListener");
300     surfaceImage_ = nullptr;
301 }
302 
OnBufferAvailable()303 void SurfaceImageListener::OnBufferAvailable()
304 {
305     BLOGD("SurfaceImageListener::OnBufferAvailable");
306     auto surfaceImage = surfaceImage_.promote();
307     if (surfaceImage == nullptr) {
308         BLOGE("surfaceImage promote failed");
309         return;
310     }
311 
312     // check here maybe a messagequeue, flag instead now
313     surfaceImage->OnUpdateBufferAvailableState(true);
314     if (surfaceImage->listener_ != nullptr) {
315         surfaceImage->listener_(surfaceImage->context_);
316     }
317 }
318 } // namespace OHOS
319