1 /*
2 * Copyright (C) 2023 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 #include "pixel_map_from_surface.h"
17
18 #include "image_log.h"
19 #include "sync_fence.h"
20
21 #undef LOG_DOMAIN
22 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
23
24 #undef LOG_TAG
25 #define LOG_TAG "PixelMap"
26
27 namespace OHOS {
28 namespace Media {
29
PixelMapFromSurface()30 PixelMapFromSurface::PixelMapFromSurface()
31 {}
32
~PixelMapFromSurface()33 PixelMapFromSurface::~PixelMapFromSurface() noexcept
34 {
35 Clear();
36 }
37
Clear()38 void PixelMapFromSurface::Clear() noexcept
39 {
40 if (eglImage_ != EGL_NO_IMAGE_KHR) {
41 if (renderContext_ != nullptr) {
42 eglDestroyImageKHR(renderContext_->GetEGLDisplay(), eglImage_);
43 } else {
44 auto disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
45 eglDestroyImageKHR(disp, eglImage_);
46 }
47 eglImage_ = EGL_NO_IMAGE_KHR;
48 }
49
50 if (texId_ != 0U) {
51 glDeleteTextures(1, &texId_);
52 texId_ = 0U;
53 }
54
55 surfaceBuffer_ = nullptr;
56 if (nativeWindowBuffer_ != nullptr) {
57 DestroyNativeWindowBuffer(nativeWindowBuffer_);
58 nativeWindowBuffer_ = nullptr;
59 }
60 }
61
GetNativeWindowBufferFromSurface(const sptr<Surface> & surface,const Rect & srcRect)62 bool PixelMapFromSurface::GetNativeWindowBufferFromSurface(const sptr<Surface> &surface, const Rect &srcRect)
63 {
64 // private func, surface is not nullptr.
65 sptr<SyncFence> fence;
66 // a 4 * 4 idetity matrix
67 float matrix[16] = {
68 1, 0, 0, 0,
69 0, 1, 0, 0,
70 0, 0, 1, 0,
71 0, 0, 0, 1
72 };
73 int ret = surface->GetLastFlushedBuffer(surfaceBuffer_, fence, matrix);
74 if (ret != OHOS::GSERROR_OK || surfaceBuffer_ == nullptr) {
75 Clear();
76 IMAGE_LOGE(
77 "CreatePixelMapFromSurface: GetLastFlushedBuffer from nativeWindow failed, err: %{public}d",
78 ret);
79 return false;
80 }
81
82 int bufferWidth = surfaceBuffer_->GetWidth();
83 int bufferHeight = surfaceBuffer_->GetHeight();
84 if (srcRect.width > bufferWidth || srcRect.height > bufferHeight ||
85 srcRect.left >= bufferWidth || srcRect.top >= bufferHeight ||
86 srcRect.left + srcRect.width > bufferWidth || srcRect.top + srcRect.height > bufferHeight) {
87 IMAGE_LOGE(
88 "CreatePixelMapFromSurface: invalid argument: srcRect[%{public}d, %{public}d, %{public}d, %{public}d],"
89 "bufferSize:[%{public}d, %{public}d]",
90 srcRect.left, srcRect.top, srcRect.width, srcRect.height,
91 surfaceBuffer_->GetWidth(), surfaceBuffer_->GetHeight());
92 return false;
93 }
94
95 if (fence != nullptr) {
96 fence->Wait(3000); // wait at most 3000ms
97 }
98 nativeWindowBuffer_ = CreateNativeWindowBufferFromSurfaceBuffer(&surfaceBuffer_);
99 return nativeWindowBuffer_ != nullptr;
100 }
101
CreateEGLImage()102 bool PixelMapFromSurface::CreateEGLImage()
103 {
104 EGLint attrs[] = {
105 EGL_IMAGE_PRESERVED,
106 EGL_TRUE,
107 EGL_NONE,
108 };
109 eglImage_ = eglCreateImageKHR(
110 renderContext_->GetEGLDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_OHOS,
111 nativeWindowBuffer_, attrs);
112 if (eglImage_ == EGL_NO_IMAGE_KHR) {
113 Clear();
114 IMAGE_LOGE("%{public}s create egl image fail %{public}d", __func__, eglGetError());
115 return false;
116 }
117 glGenTextures(1, &texId_);
118 glBindTexture(GL_TEXTURE_EXTERNAL_OES, texId_);
119 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
120 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
121 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
122 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
123 static auto glEGLImageTargetTexture2DOESFunc = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(
124 eglGetProcAddress("glEGLImageTargetTexture2DOES"));
125 if (glEGLImageTargetTexture2DOESFunc == nullptr) {
126 Clear();
127 IMAGE_LOGE("%{public}s glEGLImageTargetTexture2DOES func not found: %{public}d",
128 __func__, eglGetError());
129 return false;
130 }
131 glEGLImageTargetTexture2DOESFunc(GL_TEXTURE_EXTERNAL_OES, static_cast<GLeglImageOES>(eglImage_));
132 return true;
133 }
134
DrawImage(const Rect & srcRect)135 bool PixelMapFromSurface::DrawImage(const Rect &srcRect)
136 {
137 GraphicPixelFormat pixelFormat = static_cast<GraphicPixelFormat>(surfaceBuffer_->GetFormat());
138 SkColorType colorType = kRGBA_8888_SkColorType;
139 GLuint glType = GL_RGBA8;
140 int bufferWidth = surfaceBuffer_->GetWidth();
141 int bufferHeight = surfaceBuffer_->GetHeight();
142 if (pixelFormat == GRAPHIC_PIXEL_FMT_BGRA_8888) {
143 colorType = kBGRA_8888_SkColorType;
144 } else if (pixelFormat == GRAPHIC_PIXEL_FMT_YCBCR_P010 || pixelFormat == GRAPHIC_PIXEL_FMT_YCRCB_P010) {
145 colorType = kRGBA_1010102_SkColorType;
146 glType = GL_RGB10_A2;
147 }
148 GrGLTextureInfo grExternalTextureInfo = { GL_TEXTURE_EXTERNAL_OES, texId_, static_cast<GrGLenum>(glType) };
149 auto backendTexturePtr =
150 std::make_shared<GrBackendTexture>(bufferWidth, bufferHeight, GrMipMapped::kNo, grExternalTextureInfo);
151 auto image = SkImage::MakeFromTexture(renderContext_->GetGrContext().get(), *backendTexturePtr,
152 kTopLeft_GrSurfaceOrigin, colorType, kPremul_SkAlphaType, nullptr);
153 if (image == nullptr) {
154 Clear();
155 IMAGE_LOGE("%{public}s create SkImage failed.", __func__);
156 return false;
157 }
158
159 auto imageInfo = SkImageInfo::Make(srcRect.width, srcRect.height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
160 targetSurface_ = SkSurface::MakeRenderTarget(renderContext_->GetGrContext().get(), SkBudgeted::kYes,
161 imageInfo, 0, kTopLeft_GrSurfaceOrigin, nullptr);
162 if (targetSurface_ == nullptr) {
163 Clear();
164 IMAGE_LOGE("%{public}s SkSurface::MakeRenderTarget failed.", __func__);
165 return false;
166 }
167
168 SkCanvas* canvas = targetSurface_->getCanvas();
169 SkPaint paint;
170 paint.setStyle(SkPaint::kFill_Style);
171 SkSamplingOptions sampling(SkFilterMode::kNearest);
172 canvas->drawImageRect(image,
173 SkRect::MakeXYWH(srcRect.left, srcRect.top, srcRect.width, srcRect.height),
174 SkRect::MakeWH(srcRect.width, srcRect.height),
175 sampling, &paint, SkCanvas::kStrict_SrcRectConstraint);
176 canvas->flush();
177 return true;
178 }
179
Create(uint64_t surfaceId,const Rect & srcRect)180 std::unique_ptr<PixelMap> PixelMapFromSurface::Create(uint64_t surfaceId, const Rect &srcRect)
181 {
182 if (srcRect.left < 0 || srcRect.top < 0 || srcRect.width <= 0 || srcRect.height <= 0) {
183 IMAGE_LOGE(
184 "CreatePixelMapFromSurface: invalid argument: srcRect[%{public}d, %{public}d, %{public}d, %{public}d]",
185 srcRect.left, srcRect.top, srcRect.width, srcRect.height);
186 return nullptr;
187 }
188
189 Clear();
190 sptr<Surface> surface = SurfaceUtils::GetInstance()->GetSurface(surfaceId);
191 if (surface == nullptr) {
192 IMAGE_LOGE(
193 "CreatePixelMapFromSurface: can't find surface for surfaceId: %{public}" PRIu64 ".", surfaceId);
194 return nullptr;
195 }
196
197 if (!GetNativeWindowBufferFromSurface(surface, srcRect)) {
198 return nullptr;
199 }
200
201 // init renderContext to do some format convertion if necessary.
202 renderContext_ = std::make_unique<RenderContext>();
203 if (!renderContext_->Init()) {
204 Clear();
205 IMAGE_LOGE("CreatePixelMapFromSurface: init renderContext failed.");
206 return nullptr;
207 }
208
209 if (!CreateEGLImage()) {
210 return nullptr;
211 }
212
213 if (!DrawImage(srcRect)) {
214 return nullptr;
215 }
216
217 InitializationOptions options;
218 options.size.width = srcRect.width;
219 options.size.height = srcRect.height;
220 options.srcPixelFormat = PixelFormat::RGBA_8888;
221 options.pixelFormat = PixelFormat::RGBA_8888;
222 auto pixelMap = PixelMap::Create(options);
223 auto imageInfo = SkImageInfo::Make(srcRect.width, srcRect.height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
224 SkPixmap skPixmap(imageInfo, pixelMap->GetPixel(0, 0), pixelMap->GetRowBytes());
225 targetSurface_->readPixels(skPixmap, 0, 0);
226 return pixelMap;
227 }
228
CreatePixelMapFromSurfaceId(uint64_t surfaceId,const Rect & srcRect)229 std::unique_ptr<PixelMap> CreatePixelMapFromSurfaceId(uint64_t surfaceId, const Rect &srcRect)
230 {
231 auto helper = std::make_unique<PixelMapFromSurface>();
232 return helper->Create(surfaceId, srcRect);
233 }
234 } // namespace Media
235 } // namespace OHOS
236