• 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 #include <atomic>
21 #include <sync_fence.h>
22 #include <unistd.h>
23 #include <window.h>
24 
25 #include <EGL/egl.h>
26 #include <EGL/eglext.h>
27 #include <GLES/gl.h>
28 #include <GLES/glext.h>
29 
30 namespace OHOS {
31 namespace {
32 // Get a uniqueID in a process
GetProcessUniqueId()33 static int GetProcessUniqueId()
34 {
35     static std::atomic<int> g_counter { 0 };
36     return g_counter.fetch_add(1);
37 }
38 }
39 
SurfaceImage(uint32_t textureId,uint32_t textureTarget)40 SurfaceImage::SurfaceImage(uint32_t textureId, uint32_t textureTarget)
41     : ConsumerSurface("SurfaceImage-" + std::to_string(getpid()) + "-" + std::to_string(GetProcessUniqueId())),
42       textureId_(textureId),
43       textureTarget_(textureTarget),
44       updateSurfaceImage_(false),
45       eglDisplay_(EGL_NO_DISPLAY),
46       eglContext_(EGL_NO_CONTEXT),
47       currentSurfaceImage_(-1), // -1 invalid
48       currentSurfaceBuffer_(nullptr),
49       currentSurfaceBufferFence_(-1), // -1 invalid
50       currentTimeStamp_(0)
51 {
52     InitSurfaceImage();
53 }
54 
~SurfaceImage()55 SurfaceImage::~SurfaceImage()
56 {
57 }
58 
InitSurfaceImage()59 void SurfaceImage::InitSurfaceImage()
60 {
61     std::string name = "SurfaceImage-" + std::to_string(getpid()) + "-" + std::to_string(GetProcessUniqueId());
62     auto ret = ConsumerSurface::Init();
63     SLOGI("surfaceimage init");
64     if (ret != SURFACE_ERROR_OK) {
65         SLOGE("init surfaceimage failed");
66     }
67     surfaceImageName_ = name;
68 }
69 
SetDefaultSize(int32_t width,int32_t height)70 SurfaceError SurfaceImage::SetDefaultSize(int32_t width, int32_t height)
71 {
72     return ConsumerSurface::SetDefaultWidthAndHeight(width, height);
73 }
74 
UpdateSurfaceImage()75 SurfaceError SurfaceImage::UpdateSurfaceImage()
76 {
77     std::lock_guard<std::mutex> lockGuard(opMutex_);
78     SLOGI();
79 
80     SurfaceError ret;
81     // validate egl state
82     ret = ValidateEglState();
83     if (ret != SURFACE_ERROR_OK) {
84         return ret;
85     }
86 
87     // acquire buffer
88     sptr<SurfaceBuffer> buffer = nullptr;
89     int32_t fence;
90     int64_t timestamp;
91     Rect damage;
92 
93     ret = AcquireBuffer(buffer, fence, timestamp, damage);
94     if (ret != SURFACE_ERROR_OK) {
95         if (ret == SURFACE_ERROR_NO_BUFFER) {
96             glBindTexture(textureTarget_, textureId_);
97             SLOGE("AcquireBuffer no buffer");
98         } else {
99             SLOGE("AcquireBuffer failed");
100         }
101         return ret;
102     }
103 
104     auto bufferImpl = SurfaceBufferImpl::FromBase(buffer);
105 
106     int32_t seqNum = bufferImpl->GetSeqNum();
107     SLOGI("seqNum %{public}d", seqNum);
108     EGLImageKHR img = imageCacheSeqs_[seqNum].eglImage_;
109     glBindTexture(textureTarget_, textureId_);
110     glEGLImageTargetTexture2DOES(textureTarget_, static_cast<GLeglImageOES>(img));
111 
112     while (glGetError() != GL_NO_ERROR) {
113         SLOGE("glEGLImageTargetTexture2DOES error");
114         ret = SURFACE_ERROR_API_FAILED;
115     }
116 
117     if (ret == SURFACE_ERROR_OK) {
118         ret = WaitReleaseEGLSync(eglDisplay_);
119     }
120 
121     if (ret != SURFACE_ERROR_OK) {
122         ReleaseBuffer(buffer, -1);
123         return ret;
124     }
125 
126     if (currentSurfaceImage_ != -1 && seqNum != currentSurfaceImage_) {
127         ret = ReleaseBuffer(currentSurfaceBuffer_, -1);
128         if (ret != SURFACE_ERROR_OK) {
129             SLOGE("release currentSurfaceBuffer_ failed %{public}d", ret);
130         }
131     }
132 
133     currentSurfaceImage_ = seqNum;
134     currentSurfaceBuffer_ = buffer;
135     currentSurfaceBufferFence_ = fence;
136     currentTimeStamp_ = timestamp;
137 
138     ret = WaitOnFence();
139     return ret;
140 }
141 
AttachContext()142 SurfaceError SurfaceImage::AttachContext()
143 {
144     std::lock_guard<std::mutex> lockGuard(opMutex_);
145     if (isAttached) {
146         SLOGI("SurfaceImage is already attached");
147         return SURFACE_ERROR_OK;
148     }
149     if (imageCacheSeqs_[currentSurfaceImage_].eglImage_ == EGL_NO_IMAGE_KHR) {
150         SLOGE("AttachContext failed, no eglImage");
151         return SURFACE_ERROR_ERROR;
152     }
153 
154     EGLImageKHR img = imageCacheSeqs_[currentSurfaceImage_].eglImage_;
155     EGLDisplay disp = eglGetCurrentDisplay();
156     EGLContext context = eglGetCurrentContext();
157     if (disp == EGL_NO_DISPLAY || context == EGL_NO_CONTEXT) {
158         SLOGE("AttachContext failed, EGLDisplay or EGLContext is invalid");
159         return SURFACE_ERROR_INIT;
160     }
161 
162     glBindTexture(textureTarget_, textureId_);
163     glEGLImageTargetTexture2DOES(textureTarget_, static_cast<GLeglImageOES>(img));
164     eglDisplay_ = disp;
165     eglContext_ = context;
166 
167     isAttached = true;
168     return SURFACE_ERROR_OK;
169 }
170 
DetachContext()171 SurfaceError SurfaceImage::DetachContext()
172 {
173     std::lock_guard<std::mutex> lockGuard(opMutex_);
174     if (!isAttached) {
175         SLOGI("SurfaceImage is already detached");
176         return SURFACE_ERROR_OK;
177     }
178     EGLDisplay disp = eglGetCurrentDisplay();
179     EGLContext context = eglGetCurrentContext();
180 
181     if ((eglDisplay_ != disp && eglDisplay_ != EGL_NO_DISPLAY) || (disp == EGL_NO_DISPLAY)) {
182         SLOGE("EGLDisplay is invalid, errno : 0x%{public}x", eglGetError());
183         return SURFACE_ERROR_INIT;
184     }
185     if ((eglContext_ != context && eglContext_ != EGL_NO_CONTEXT) || (context == EGL_NO_CONTEXT)) {
186         SLOGE("EGLContext is invalid, errno : 0x%{public}x", eglGetError());
187         return SURFACE_ERROR_INIT;
188     }
189 
190     SurfaceError ret = WaitReleaseEGLSync(eglDisplay_);
191     if (ret == SURFACE_ERROR_OK) {
192         glDeleteTextures(1, &textureId_);
193     } else {
194         return ret;
195     }
196 
197     eglDisplay_ = EGL_NO_DISPLAY;
198     eglContext_ = EGL_NO_CONTEXT;
199 
200     isAttached = false;
201     return SURFACE_ERROR_OK;
202 }
203 
GetTimeStamp()204 int64_t SurfaceImage::GetTimeStamp()
205 {
206     std::lock_guard<std::mutex> lockGuard(opMutex_);
207     return currentTimeStamp_;
208 }
209 
AcquireBuffer(sptr<SurfaceBuffer> & buffer,int32_t & fence,int64_t & timestamp,Rect & damage)210 SurfaceError SurfaceImage::AcquireBuffer(sptr<SurfaceBuffer>& buffer, int32_t &fence,
211                                          int64_t &timestamp, Rect &damage)
212 {
213     SurfaceError ret = ConsumerSurface::AcquireBuffer(buffer, fence, timestamp, damage);
214     if (ret != SURFACE_ERROR_OK) {
215         SLOGE("AcquireBuffer error");
216         return ret;
217     }
218     // get seq num
219     auto bufferImpl = SurfaceBufferImpl::FromBase(buffer);
220     int32_t seqNum = bufferImpl->GetSeqNum();
221 
222     if (buffer != nullptr) {
223         if (imageCacheSeqs_[seqNum].eglImage_ != EGL_NO_IMAGE_KHR) {
224             eglDestroyImageKHR(eglDisplay_, imageCacheSeqs_[seqNum].eglImage_);
225             imageCacheSeqs_[seqNum].eglImage_ = EGL_NO_IMAGE_KHR;
226         }
227     }
228 
229     // create image
230     if (imageCacheSeqs_[seqNum].eglImage_ == EGL_NO_IMAGE_KHR) {
231         EGLImageKHR eglImage = CreateEGLImage(eglDisplay_, buffer);
232         if (eglImage == EGL_NO_IMAGE_KHR) {
233             return SURFACE_ERROR_INIT;
234         }
235         imageCacheSeqs_[seqNum].eglImage_ = eglImage;
236     }
237     return SURFACE_ERROR_OK;
238 }
239 
ReleaseBuffer(sptr<SurfaceBuffer> & buffer,int32_t fence)240 SurfaceError SurfaceImage::ReleaseBuffer(sptr<SurfaceBuffer>& buffer, int32_t fence)
241 {
242     SurfaceError error = ConsumerSurface::ReleaseBuffer(buffer, fence);
243     if (error != SURFACE_ERROR_OK) {
244         SLOGE("ReleaseBuffer error");
245         return error;
246     }
247     auto bufferImpl = SurfaceBufferImpl::FromBase(buffer);
248     int32_t seqNum = bufferImpl->GetSeqNum();
249 
250     imageCacheSeqs_[seqNum].eglSync_ = EGL_NO_SYNC_KHR;
251     return SURFACE_ERROR_OK;
252 }
253 
ValidateEglState()254 SurfaceError SurfaceImage::ValidateEglState()
255 {
256     EGLDisplay disp = eglGetCurrentDisplay();
257     EGLContext context = eglGetCurrentContext();
258 
259     if ((eglDisplay_ != disp && eglDisplay_ != EGL_NO_DISPLAY) || (disp == EGL_NO_DISPLAY)) {
260         SLOGE("EGLDisplay is invalid, errno : 0x%{public}x", eglGetError());
261         return SURFACE_ERROR_INIT;
262     }
263     if ((eglContext_ != context && eglContext_ != EGL_NO_CONTEXT) || (context == EGL_NO_CONTEXT)) {
264         SLOGE("EGLContext is invalid, errno : 0x%{public}x", eglGetError());
265         return SURFACE_ERROR_INIT;
266     }
267 
268     eglDisplay_ = disp;
269     eglContext_ = context;
270     return SURFACE_ERROR_OK;
271 }
272 
CreateEGLImage(EGLDisplay disp,const sptr<SurfaceBuffer> & buffer)273 EGLImageKHR SurfaceImage::CreateEGLImage(EGLDisplay disp, const sptr<SurfaceBuffer>& buffer)
274 {
275     sptr<SurfaceBufferImpl> bufferImpl = SurfaceBufferImpl::FromBase(buffer);
276     NativeWindowBuffer* nBuffer = CreateNativeWindowBufferFromSurfaceBuffer(&bufferImpl);
277     EGLint attrs[] = {
278         EGL_IMAGE_PRESERVED,
279         EGL_TRUE,
280         EGL_NONE,
281     };
282 
283     EGLImageKHR img = eglCreateImageKHR(disp, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_OHOS, nBuffer, attrs);
284     if (img == EGL_NO_IMAGE_KHR) {
285         EGLint error = eglGetError();
286         SLOGE("failed, error %{public}d", error);
287         eglTerminate(disp);
288     }
289     return img;
290 }
291 
WaitReleaseEGLSync(EGLDisplay disp)292 SurfaceError SurfaceImage::WaitReleaseEGLSync(EGLDisplay disp)
293 {
294     // check fence extension
295     EGLSyncKHR fence = imageCacheSeqs_[currentSurfaceImage_].eglSync_;
296     if (fence != EGL_NO_SYNC_KHR) {
297         EGLint ret = eglClientWaitSyncKHR(disp, fence, 0, 1000000000);
298         if (ret == EGL_FALSE) {
299             SLOGE("eglClientWaitSyncKHR error 0x%{public}x", eglGetError());
300             return SURFACE_ERROR_ERROR;
301         } else if (ret == EGL_TIMEOUT_EXPIRED_KHR) {
302             SLOGE("eglClientWaitSyncKHR timeout");
303             return SURFACE_ERROR_ERROR;
304         }
305         eglDestroySyncKHR(disp, fence);
306     }
307     fence = eglCreateSyncKHR(disp, EGL_SYNC_FENCE_KHR, NULL);
308     if (fence == EGL_NO_SYNC_KHR) {
309         SLOGE("eglCreateSyncKHR error 0x%{public}x", eglGetError());
310         return SURFACE_ERROR_ERROR;
311     }
312     glFlush();
313     imageCacheSeqs_[currentSurfaceImage_].eglSync_ = fence;
314     return SURFACE_ERROR_OK;
315 }
316 
WaitOnFence()317 SurfaceError SurfaceImage::WaitOnFence()
318 {
319     // check ret error code
320     EGLDisplay disp = eglGetCurrentDisplay();
321     EGLContext context = eglGetCurrentContext();
322     if ((eglDisplay_ != disp && eglDisplay_ != EGL_NO_DISPLAY) || (disp == EGL_NO_DISPLAY)) {
323         SLOGE("EGLDisplay is invalid, errno : 0x%{public}x", eglGetError());
324         return SURFACE_ERROR_INIT;
325     }
326     if ((eglContext_ != context && eglContext_ != EGL_NO_CONTEXT) || (context == EGL_NO_CONTEXT)) {
327         SLOGE("EGLContext is invalid, errno : 0x%{public}x", eglGetError());
328         return SURFACE_ERROR_INIT;
329     }
330 
331     // check EGL_FENCE_KHR
332     if (currentSurfaceBufferFence_ != -1) {
333         SLOGE("currentSurfaceBufferFence_ fd - %{public}d", currentSurfaceBufferFence_);
334         sptr<SyncFence> fence = new SyncFence(currentSurfaceBufferFence_);
335         fence->Wait(-1);
336     }
337     return SURFACE_ERROR_OK;
338 }
339 
~SurfaceImageListener()340 SurfaceImageListener::~SurfaceImageListener()
341 {
342     SLOGE("~SurfaceImageListener");
343     surfaceImage_ = nullptr;
344 }
345 
OnBufferAvailable()346 void SurfaceImageListener::OnBufferAvailable()
347 {
348     SLOGE("SurfaceImageListener::OnBufferAvailable");
349     auto surfaceImage = surfaceImage_.promote();
350     if (surfaceImage == nullptr) {
351         SLOGE("surfaceImage promote failed");
352         return;
353     }
354 
355     // check here maybe a messagequeue, flag instead now
356     surfaceImage->OnUpdateBufferAvailableState(true);
357 }
358 } // namespace OHOS