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 ×tamp, 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