1 /*
2 * Copyright (C) 2024 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 #include "pixel_map_gl_post_proc_program.h"
16
17 #include <atomic>
18 #include <cstdint>
19 #include <memory>
20 #include <string>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/time.h>
26 #include <sys/mman.h>
27 #include <iostream>
28
29 #include "native_buffer.h"
30 #include "pixel_map_gl_shader.h"
31 #include "securec.h"
32 #include "sync_fence.h"
33 #include "image_utils.h"
34 #include <fstream>
35 #include <sstream>
36 #undef LOG_DOMAIN
37 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
38
39 #undef LOG_TAG
40 #define LOG_TAG "PixelMapGLPostProcProgram"
41 #define PI 3.1415926
42
43 namespace OHOS {
44 namespace Media {
45 using namespace GlCommon;
46 std::once_flag shaderInitFlag[PixelMapGlShader::SHADER_MAX];
47 std::mutex g_shaderMtx;
48 std::condition_variable g_shaderCv;
49 std::atomic<int> g_shaderCount = 0;
50 std::atomic<int> g_shaderFailCount = 0;
51
PixelMapGLPostProcProgram()52 PixelMapGLPostProcProgram::PixelMapGLPostProcProgram()
53 {
54 }
55
~PixelMapGLPostProcProgram()56 PixelMapGLPostProcProgram::~PixelMapGLPostProcProgram() noexcept
57 {
58 Clear();
59 IMAGE_LOGE("slr_gpu ~PixelMapGLPostProcProgram()");
60 }
61
SetGPUTransformData(GPUTransformData & transformData)62 void PixelMapGLPostProcProgram::SetGPUTransformData(GPUTransformData &transformData)
63 {
64 this->transformData_ = transformData;
65 }
66
Clear()67 void PixelMapGLPostProcProgram::Clear() noexcept
68 {
69 if (renderContext_ != nullptr && renderContext_->eglContext_ != EGL_NO_CONTEXT) {
70 renderContext_->MakeCurrentSimple(true);
71 if (rotateShader_) {
72 rotateShader_->Clear();
73 rotateShader_.reset();
74 }
75 if (slrShader_) {
76 slrShader_->Clear();
77 slrShader_.reset();
78 }
79 if (lapShader_) {
80 lapShader_->Clear();
81 lapShader_.reset();
82 }
83 if (vertexShader_) {
84 vertexShader_->Clear();
85 vertexShader_.reset();
86 }
87 renderContext_->MakeCurrentSimple(false);
88 }
89 }
90
BuildShader()91 bool PixelMapGLPostProcProgram::BuildShader()
92 {
93 ImageTrace imageTrace("PixelMapGLPostProcProgram::BuildShader");
94 static PixelMapGlContext renderContextAll(true);
95 for (int i = PixelMapGlShader::SHADER_ROTATE; i < PixelMapGlShader::SHADER_MAX; i++) {
96 std::call_once(shaderInitFlag[i], [&]() {
97 auto shader = PixelMapGlShader::ShaderFactory::GetInstance().Get(PixelMapGlShader::ShaderType(i));
98 g_shaderCount++;
99 if (!shader || !shader->LoadProgram()) {
100 g_shaderFailCount++;
101 }
102 std::unique_lock<std::mutex> lock(g_shaderMtx);
103 g_shaderCv.notify_all();
104 });
105 }
106 {
107 std::unique_lock<std::mutex> lock(g_shaderMtx);
108 g_shaderCv.wait(lock, [] {
109 return g_shaderCount == PixelMapGlShader::SHADER_MAX - PixelMapGlShader::SHADER_ROTATE;
110 });
111 }
112 return g_shaderFailCount == 0;
113 }
114
Init()115 bool PixelMapGLPostProcProgram::Init()
116 {
117 if (renderContext_ == nullptr) {
118 ImageTrace imageTrace("OpenGL context create");
119 renderContext_ = make_unique<PixelMapGlContext>();
120 if (!renderContext_->InitEGLContext()) {
121 IMAGE_LOGE("slr_gpu CreatePixelMapFromSurface: init renderContext failed.");
122 return false;
123 }
124 return InitGLResource();
125 }
126 return true;
127 }
128
CreateNormalImage(const uint8_t * data,GLuint & imageTexId)129 bool PixelMapGLPostProcProgram::CreateNormalImage(const uint8_t *data, GLuint &imageTexId)
130 {
131 const Size &sourceSize = transformData_.sourceInfo_.size;
132 int perPixelSize = transformData_.sourceInfo_.pixelBytes;
133 if (data == nullptr) {
134 return false;
135 }
136 if (imageTexId != 0) {
137 glDeleteTextures(1, &imageTexId);
138 }
139 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
140 glGenTextures(1, &imageTexId);
141 glBindTexture(GL_TEXTURE_2D, imageTexId);
142 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
143 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
144 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sourceSize.width, sourceSize.height, 0,
145 transformData_.glFormat, GL_UNSIGNED_BYTE, NULL);
146 if (perPixelSize * sourceSize.width == transformData_.sourceInfo_.stride) {
147 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, sourceSize.width, sourceSize.height,
148 transformData_.glFormat, GL_UNSIGNED_BYTE, data);
149 } else {
150 GLuint pbo = 0;
151 glGenBuffers(1, &pbo);
152 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
153 glBufferData(GL_PIXEL_UNPACK_BUFFER,
154 sourceSize.width * sourceSize.height * perPixelSize, NULL, GL_STREAM_DRAW);
155 char *mapPointer = (char *)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0,
156 sourceSize.width * sourceSize.height * perPixelSize, GL_MAP_WRITE_BIT);
157 if (mapPointer == NULL) {
158 return false;
159 }
160 for (int i = 0; i < sourceSize.height; i++) {
161 if (memcpy_s(mapPointer + sourceSize.width * perPixelSize * i,
162 sourceSize.width * perPixelSize * (sourceSize.height - i),
163 data + perPixelSize * i, sourceSize.width * perPixelSize) != 0) {
164 IMAGE_LOGE("slr_gpu %{public}s memcpy_s failed", __func__);
165 return false;
166 }
167 }
168 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
169 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sourceSize.width, sourceSize.height, 0,
170 transformData_.glFormat, GL_UNSIGNED_BYTE, NULL);
171 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
172 glDeleteBuffers(1, &pbo);
173 }
174 GLenum err = glGetError();
175 if (err != GL_NO_ERROR) {
176 IMAGE_LOGE("slr_gpu %{public}s failed gl error: %{public}x", __func__, err);
177 return false;
178 }
179 return true;
180 }
181
CreateEGLImage(OHNativeWindowBuffer * nativeBuffer,EGLImageKHR & eglImage,GLuint & imageTexId)182 bool PixelMapGLPostProcProgram::CreateEGLImage(OHNativeWindowBuffer *nativeBuffer,
183 EGLImageKHR &eglImage, GLuint &imageTexId)
184 {
185 if (nativeBuffer == nullptr) {
186 return false;
187 }
188 static EGLint attrs[] = {
189 EGL_IMAGE_PRESERVED,
190 EGL_TRUE,
191 EGL_NONE,
192 };
193 eglImage = eglCreateImageKHR(
194 renderContext_->GetEGLDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_OHOS,
195 nativeBuffer, attrs);
196 if (eglImage == EGL_NO_IMAGE_KHR) {
197 IMAGE_LOGE("slr_gpu %{public}s create egl image fail %{public}d", __func__, eglGetError());
198 return false;
199 }
200 if (imageTexId != 0) {
201 glDeleteTextures(1, &imageTexId);
202 }
203 glGenTextures(1, &imageTexId);
204 glBindTexture(GL_TEXTURE_EXTERNAL_OES, imageTexId);
205 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
206 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
207 static auto glEGLImageTargetTexture2DOESFunc = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(
208 eglGetProcAddress("glEGLImageTargetTexture2DOES"));
209 if (glEGLImageTargetTexture2DOESFunc == nullptr) {
210 IMAGE_LOGE("slr_gpu %{public}s glEGLImageTargetTexture2DOES func not found: %{public}d",
211 __func__, eglGetError());
212 return false;
213 }
214 glEGLImageTargetTexture2DOESFunc(GL_TEXTURE_EXTERNAL_OES, static_cast<GLeglImageOES>(eglImage));
215 return true;
216 }
217
UseEGLImageCreateNormalImage(GLuint & imageTexId)218 bool PixelMapGLPostProcProgram::UseEGLImageCreateNormalImage(GLuint &imageTexId)
219 {
220 GLuint eglImageTexId = imageTexId;
221 Size &sourceSize = transformData_.sourceInfo_.size;
222 GLuint tempFbo[NUM_2];
223 glGenFramebuffers(NUM_2, tempFbo);
224 glBindFramebuffer(GL_READ_FRAMEBUFFER, tempFbo[0]);
225 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_EXTERNAL_OES, eglImageTexId, 0);
226 IMAGE_LOGD("readfbo status %{public}x", glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
227
228 glGenTextures(1, &imageTexId);
229 glBindTexture(GL_TEXTURE_2D, imageTexId);
230 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
231 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
232 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sourceSize.width, sourceSize.height, 0,
233 transformData_.glFormat, GL_UNSIGNED_BYTE, NULL);
234
235 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tempFbo[1]);
236 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, imageTexId, 0);
237 IMAGE_LOGD("drawfbo status %{public}x", glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
238
239 glBlitFramebuffer(0, 0, sourceSize.width, sourceSize.height, 0, 0, sourceSize.width,
240 sourceSize.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
241 eglDestroyImageKHR(renderContext_->GetEGLDisplay(), eglImage_);
242 glDeleteTextures(1, &eglImageTexId);
243 glDeleteFramebuffers(NUM_2, tempFbo);
244 eglImage_ = EGL_NO_IMAGE_KHR;
245 GLenum err = glGetError();
246 if (err != GL_NO_ERROR) {
247 IMAGE_LOGE("slr_gpu %{public}s failed gl error: %{public}x", __func__, err);
248 return false;
249 }
250 return true;
251 }
252
GLMakecurrent(bool needCurrent)253 bool PixelMapGLPostProcProgram::GLMakecurrent(bool needCurrent)
254 {
255 if (!renderContext_) {
256 IMAGE_LOGE("slr_gpu GLMakecurrent renderContext_ == nullptr");
257 return false;
258 }
259 return renderContext_->MakeCurrentSimple(needCurrent);
260 }
261
InitGLResource()262 bool PixelMapGLPostProcProgram::InitGLResource()
263 {
264 vertexShader_ = std::make_shared<PixelMapGlShader::VertexShader>();
265 if (!vertexShader_->LoadProgram()) {
266 return false;
267 }
268 rotateShader_ = std::make_shared<PixelMapGlShader::RotateShader>();
269 if (!rotateShader_->LoadProgram()) {
270 return false;
271 }
272 slrShader_ = std::make_shared<PixelMapGlShader::SLRShader>();
273 if (!slrShader_->LoadProgram()) {
274 return false;
275 }
276 lapShader_ = std::make_shared<PixelMapGlShader::LapShader>();
277 if (!lapShader_->LoadProgram()) {
278 return false;
279 }
280 return true;
281 }
282
BuildProcTexture(bool needThumb,bool needUpload,GLuint & readTexId)283 bool PixelMapGLPostProcProgram::BuildProcTexture(bool needThumb, bool needUpload, GLuint &readTexId)
284 {
285 OHNativeWindowBuffer *nativeBuffer = nullptr;
286 const uint8_t *normalBuffer = nullptr;
287 if (!transformData_.isDma) {
288 normalBuffer = transformData_.sourceInfo_.addr;
289 if (!CreateNormalImage(normalBuffer, readTexId)) {
290 return false;
291 }
292 } else {
293 void *surfaceBuffer = transformData_.sourceInfo_.context;
294 nativeBuffer = CreateNativeWindowBufferFromSurfaceBuffer(&surfaceBuffer);
295 if (!CreateEGLImage(nativeBuffer, eglImage_, readTexId)) {
296 DestroyNativeWindowBuffer(nativeBuffer);
297 return false;
298 }
299 DestroyNativeWindowBuffer(nativeBuffer);
300 if (!UseEGLImageCreateNormalImage(readTexId)) {
301 return false;
302 }
303 }
304 GLenum err = glGetError();
305 if (err != GL_NO_ERROR) {
306 IMAGE_LOGE("slr_gpu %{public}s failed gl error: %{public}d %{public}x", __func__, __LINE__, err);
307 return false;
308 }
309 return true;
310 }
311
DestroyProcTexture()312 void PixelMapGLPostProcProgram::DestroyProcTexture()
313 {
314 glBindTexture(GL_TEXTURE_2D, 0);
315 glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
316 if (eglImage_ != EGL_NO_IMAGE_KHR) {
317 eglDestroyImageKHR(renderContext_->GetEGLDisplay(), eglImage_);
318 }
319 eglImage_ = EGL_NO_IMAGE_KHR;
320 return;
321 }
322
GenProcEndData(char * lcdData)323 bool PixelMapGLPostProcProgram::GenProcEndData(char *lcdData)
324 {
325 ImageTrace imageTrace("GenProcEndData");
326 switch (transformData_.transformationType) {
327 case TransformationType::SCALE :
328 if (!(BuildProcTexture(false, true, slrShader_->GetReadTexId()) &&
329 ResizeScaleWithGL() && ReadEndData(lcdData, lapShader_->GetWriteTexId()))) {
330 return false;
331 }
332 break;
333 case TransformationType::ROTATE :
334 if (!(BuildProcTexture(false, true, rotateShader_->GetReadTexId()) &&
335 ResizeRotateWithGL() && ReadEndData(lcdData, rotateShader_->GetWriteTexId()))) {
336 return false;
337 }
338 break;
339 default:
340 break;
341 }
342
343 DestroyProcTexture();
344 return true;
345 }
346
GenProcDmaEndData(void * surfaceBuffer)347 bool PixelMapGLPostProcProgram::GenProcDmaEndData(void *surfaceBuffer)
348 {
349 ImageTrace imageTrace("GenProcEndData-surface");
350 switch (transformData_.transformationType) {
351 case TransformationType::SCALE :
352 if (!(BuildProcTexture(false, true, slrShader_->GetReadTexId()) &&
353 ResizeScaleWithGL() && ReadEndDMAData(surfaceBuffer, lapShader_->GetWriteFbo()))) {
354 return false;
355 }
356 break;
357 case TransformationType::ROTATE :
358 if (!(BuildProcTexture(false, true, rotateShader_->GetReadTexId()) &&
359 ResizeRotateWithGL() && ReadEndDMAData(surfaceBuffer, rotateShader_->GetWriteFbo()))) {
360 return false;
361 }
362 break;
363 default:
364 break;
365 }
366 DestroyProcTexture();
367 return true;
368 }
369
ResizeScaleWithGL()370 bool PixelMapGLPostProcProgram::ResizeScaleWithGL()
371 {
372 ImageTrace imageTrace("ResizeScaleWithGL");
373 ((PixelMapGlShader::SLRShader*)(slrShader_.get()))->SetEglImage(eglImage_);
374 ((PixelMapGlShader::SLRShader*)(slrShader_.get()))->SetParams(transformData_);
375 if (!slrShader_->Use()) {
376 return false;
377 }
378 ((PixelMapGlShader::LapShader*)(lapShader_.get()))->SetParams(transformData_);
379 lapShader_->GetReadTexId() = slrShader_->GetWriteTexId();
380 if (!lapShader_->Use()) {
381 return false;
382 }
383 GLenum err = glGetError();
384 if (err != GL_NO_ERROR) {
385 IMAGE_LOGE("slr_gpu 3 %{public}s failed gl error: %{public}x", __func__, err);
386 return false;
387 }
388 return true;
389 }
390
ResizeRotateWithGL()391 bool PixelMapGLPostProcProgram::ResizeRotateWithGL()
392 {
393 ImageTrace imageTrace("ResizeRotateWithGL");
394 rotateShader_->SetParams(transformData_);
395 if (!rotateShader_->Use()) {
396 return false;
397 }
398 return true;
399 }
400
ReadEndData(char * targetData,GLuint & writeTexId)401 bool PixelMapGLPostProcProgram::ReadEndData(char *targetData, GLuint &writeTexId)
402 {
403 ImageTrace imageTrace("ReadEndData");
404 if (targetData == nullptr) {
405 return false;
406 }
407 Size &targetSize = transformData_.targetInfo_.size;
408 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, writeTexId, 0);
409 if (targetSize.width * NUM_4 >= transformData_.targetInfo_.stride) {
410 glReadPixels(0, 0, targetSize.width, targetSize.height, GL_RGBA, GL_UNSIGNED_BYTE, targetData);
411 } else {
412 GLuint pbo = 0;
413 glGenBuffers(1, &pbo);
414 glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
415 glBufferData(GL_PIXEL_PACK_BUFFER, targetSize.width * targetSize.height * NUM_4, NULL, GL_STREAM_READ);
416 glReadPixels(0, 0, targetSize.width, targetSize.height, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
417 char *mapPointer = (char *)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0,
418 targetSize.width * targetSize.height * NUM_4, GL_MAP_READ_BIT);
419 if (mapPointer == NULL) {
420 return false;
421 }
422 for (int i = 0; i < targetSize.height; i++) {
423 if (memcpy_s(targetData + transformData_.targetInfo_.stride * i,
424 targetSize.width * NUM_4 * (targetSize.height - i),
425 mapPointer + targetSize.width * NUM_4 * i, targetSize.width * NUM_4) != 0) {
426 IMAGE_LOGE("slr_gpu %{public}s memcpy_s fail", __func__);
427 return false;
428 }
429 }
430 glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
431 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
432 glDeleteBuffers(1, &pbo);
433 }
434
435 glFinish();
436 GLenum err = glGetError();
437 if (err != GL_NO_ERROR) {
438 IMAGE_LOGE("slr_gpu %{public}s fail %{public}x", __func__, err);
439 return false;
440 }
441 return true;
442 }
443
ReadEndDMAData(void * surfaceBuffer,GLuint & writeFbo)444 bool PixelMapGLPostProcProgram::ReadEndDMAData(void *surfaceBuffer, GLuint &writeFbo)
445 {
446 ImageTrace imageTrace("ReadEndDMAData ");
447 OHNativeWindowBuffer *nativeBuffer = CreateNativeWindowBufferFromSurfaceBuffer(&surfaceBuffer);
448 EGLImage endEglImage;
449 GLuint endReadTexId = 0U;
450 if (!CreateEGLImage(nativeBuffer, endEglImage, endReadTexId)) {
451 IMAGE_LOGE("slr_gpu ReadEndDMAData CreateEGLImage fail %{public}d", eglGetError());
452 return false;
453 }
454 GLuint endFbo;
455 glGenFramebuffers(1, &endFbo);
456 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, endFbo);
457 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_EXTERNAL_OES, endReadTexId, 0);
458 glBindFramebuffer(GL_READ_FRAMEBUFFER, writeFbo);
459 Size &targetSize = transformData_.targetInfo_.size;
460 glBlitFramebuffer(0, 0, targetSize.width, targetSize.height, 0, 0,
461 targetSize.width, targetSize.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
462 eglDestroyImageKHR(renderContext_->GetEGLDisplay(), endEglImage);
463 glDeleteTextures(1, &endReadTexId);
464 glDeleteFramebuffers(1, &endFbo);
465 DestroyNativeWindowBuffer(nativeBuffer);
466 glFinish();
467 GLenum err = glGetError();
468 if (err != GL_NO_ERROR) {
469 IMAGE_LOGE("slr_gpu %{public}s failed gl error: %{public}x", __func__, err);
470 return false;
471 }
472 return true;
473 }
474
Execute()475 bool PixelMapGLPostProcProgram::Execute()
476 {
477 if (!GLMakecurrent(true)) {
478 IMAGE_LOGE("slr_gpu GenProcEndData cannot makecurent with opengl");
479 return false;
480 }
481 bool ret = true;
482 if (transformData_.isDma) {
483 ret = GenProcDmaEndData(transformData_.targetInfo_.context);
484 } else {
485 ret = GenProcEndData((char*)transformData_.targetInfo_.outdata);
486 }
487 if (!GLMakecurrent(false)) {
488 IMAGE_LOGE("slr_gpu GenProcEndData Unbinding failed");
489 return false;
490 }
491 return ret;
492 }
493 } // namespace Media
494 } //