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