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 #include <surface_utils.h>
17 #include <cinttypes>
18 #include "securec.h"
19 #include "buffer_log.h"
20
21 namespace OHOS {
22 using namespace HiviewDFX;
23 static SurfaceUtils* instance = nullptr;
24 static std::once_flag createFlag_;
25 constexpr uint32_t MATRIX_ARRAY_SIZE = 16;
26
GetInstance()27 SurfaceUtils* SurfaceUtils::GetInstance()
28 {
29 std::call_once(createFlag_, [&]() {
30 instance = new SurfaceUtils();
31 });
32
33 return instance;
34 }
35
~SurfaceUtils()36 SurfaceUtils::~SurfaceUtils()
37 {
38 instance = nullptr;
39 surfaceCache_.clear();
40 nativeWindowCache_.clear();
41 }
42
GetSurface(uint64_t uniqueId)43 sptr<Surface> SurfaceUtils::GetSurface(uint64_t uniqueId)
44 {
45 std::lock_guard<std::mutex> lockGuard(mutex_);
46 auto iter = surfaceCache_.find(uniqueId);
47 if (iter == surfaceCache_.end()) {
48 BLOGE("Cannot find surface, uniqueId: %{public}" PRIu64 ".", uniqueId);
49 return nullptr;
50 }
51 sptr<Surface> surface = iter->second.promote();
52 if (surface == nullptr) {
53 BLOGE("surface is nullptr, uniqueId: %{public}" PRIu64 ".", uniqueId);
54 return nullptr;
55 }
56 return surface;
57 }
58
Add(uint64_t uniqueId,const wptr<Surface> & surface)59 SurfaceError SurfaceUtils::Add(uint64_t uniqueId, const wptr<Surface> &surface)
60 {
61 if (surface == nullptr) {
62 return GSERROR_INVALID_ARGUMENTS;
63 }
64 std::lock_guard<std::mutex> lockGuard(mutex_);
65 if (surfaceCache_.count(uniqueId) == 0) {
66 surfaceCache_[uniqueId] = surface;
67 return GSERROR_OK;
68 }
69 BLOGD("the surface already existed, uniqueId: %{public}" PRIu64, uniqueId);
70 return GSERROR_OK;
71 }
72
Remove(uint64_t uniqueId)73 SurfaceError SurfaceUtils::Remove(uint64_t uniqueId)
74 {
75 std::lock_guard<std::mutex> lockGuard(mutex_);
76 auto iter = surfaceCache_.find(uniqueId);
77 if (iter == surfaceCache_.end()) {
78 BLOGD("Cannot find surface, uniqueId: %{public}" PRIu64 ".", uniqueId);
79 return GSERROR_INVALID_OPERATING;
80 }
81 surfaceCache_.erase(iter);
82 return GSERROR_OK;
83 }
84
MatrixProduct(const std::array<float,MATRIX_ARRAY_SIZE> & lMat,const std::array<float,MATRIX_ARRAY_SIZE> & rMat)85 std::array<float, MATRIX_ARRAY_SIZE> SurfaceUtils::MatrixProduct(const std::array<float, MATRIX_ARRAY_SIZE>& lMat,
86 const std::array<float, MATRIX_ARRAY_SIZE>& rMat)
87 {
88 // Product matrix 4 * 4 = 16
89 return std::array<float, MATRIX_ARRAY_SIZE> {
90 lMat[0] * rMat[0] + lMat[4] * rMat[1] + lMat[8] * rMat[2] + lMat[12] * rMat[3],
91 lMat[1] * rMat[0] + lMat[5] * rMat[1] + lMat[9] * rMat[2] + lMat[13] * rMat[3],
92 lMat[2] * rMat[0] + lMat[6] * rMat[1] + lMat[10] * rMat[2] + lMat[14] * rMat[3],
93 lMat[3] * rMat[0] + lMat[7] * rMat[1] + lMat[11] * rMat[2] + lMat[15] * rMat[3],
94
95 lMat[0] * rMat[4] + lMat[4] * rMat[5] + lMat[8] * rMat[6] + lMat[12] * rMat[7],
96 lMat[1] * rMat[4] + lMat[5] * rMat[5] + lMat[9] * rMat[6] + lMat[13] * rMat[7],
97 lMat[2] * rMat[4] + lMat[6] * rMat[5] + lMat[10] * rMat[6] + lMat[14] * rMat[7],
98 lMat[3] * rMat[4] + lMat[7] * rMat[5] + lMat[11] * rMat[6] + lMat[15] * rMat[7],
99
100 lMat[0] * rMat[8] + lMat[4] * rMat[9] + lMat[8] * rMat[10] + lMat[12] * rMat[11],
101 lMat[1] * rMat[8] + lMat[5] * rMat[9] + lMat[9] * rMat[10] + lMat[13] * rMat[11],
102 lMat[2] * rMat[8] + lMat[6] * rMat[9] + lMat[10] * rMat[10] + lMat[14] * rMat[11],
103 lMat[3] * rMat[8] + lMat[7] * rMat[9] + lMat[11] * rMat[10] + lMat[15] * rMat[11],
104
105 lMat[0] * rMat[12] + lMat[4] * rMat[13] + lMat[8] * rMat[14] + lMat[12] * rMat[15],
106 lMat[1] * rMat[12] + lMat[5] * rMat[13] + lMat[9] * rMat[14] + lMat[13] * rMat[15],
107 lMat[2] * rMat[12] + lMat[6] * rMat[13] + lMat[10] * rMat[14] + lMat[14] * rMat[15],
108 lMat[3] * rMat[12] + lMat[7] * rMat[13] + lMat[11] * rMat[14] + lMat[15] * rMat[15]
109 };
110 }
111
ComputeTransformByMatrix(GraphicTransformType & transform,std::array<float,TRANSFORM_MATRIX_ELE_COUNT> * transformMatrix)112 void SurfaceUtils::ComputeTransformByMatrix(GraphicTransformType& transform,
113 std::array<float, TRANSFORM_MATRIX_ELE_COUNT> *transformMatrix)
114 {
115 const std::array<float, TRANSFORM_MATRIX_ELE_COUNT> rotate90 = {0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
116 const std::array<float, TRANSFORM_MATRIX_ELE_COUNT> rotate180 = {-1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
117 const std::array<float, TRANSFORM_MATRIX_ELE_COUNT> rotate270 = {0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
118 const std::array<float, TRANSFORM_MATRIX_ELE_COUNT> flipH = {-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
119 const std::array<float, TRANSFORM_MATRIX_ELE_COUNT> flipV = {1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
120
121 switch (transform) {
122 case GraphicTransformType::GRAPHIC_ROTATE_NONE:
123 break;
124 case GraphicTransformType::GRAPHIC_ROTATE_90:
125 *transformMatrix = MatrixProduct(*transformMatrix, rotate90);
126 break;
127 case GraphicTransformType::GRAPHIC_ROTATE_180:
128 *transformMatrix = MatrixProduct(*transformMatrix, rotate180);
129 break;
130 case GraphicTransformType::GRAPHIC_ROTATE_270:
131 *transformMatrix = MatrixProduct(*transformMatrix, rotate270);
132 break;
133 case GraphicTransformType::GRAPHIC_FLIP_H:
134 *transformMatrix = MatrixProduct(*transformMatrix, flipH);
135 break;
136 case GraphicTransformType::GRAPHIC_FLIP_V:
137 *transformMatrix = MatrixProduct(*transformMatrix, flipV);
138 break;
139 case GraphicTransformType::GRAPHIC_FLIP_H_ROT90:
140 *transformMatrix = MatrixProduct(flipH, rotate90);
141 break;
142 case GraphicTransformType::GRAPHIC_FLIP_V_ROT90:
143 *transformMatrix = MatrixProduct(flipV, rotate90);
144 break;
145 case GraphicTransformType::GRAPHIC_FLIP_H_ROT180:
146 *transformMatrix = MatrixProduct(flipH, rotate180);
147 break;
148 case GraphicTransformType::GRAPHIC_FLIP_V_ROT180:
149 *transformMatrix = MatrixProduct(flipV, rotate180);
150 break;
151 case GraphicTransformType::GRAPHIC_FLIP_H_ROT270:
152 *transformMatrix = MatrixProduct(flipH, rotate270);
153 break;
154 case GraphicTransformType::GRAPHIC_FLIP_V_ROT270:
155 *transformMatrix = MatrixProduct(flipV, rotate270);
156 break;
157 default:
158 break;
159 }
160 }
161
ComputeTransformMatrix(float matrix[MATRIX_ARRAY_SIZE],uint32_t matrixSize,sptr<SurfaceBuffer> & buffer,GraphicTransformType & transform,const Rect & crop)162 void SurfaceUtils::ComputeTransformMatrix(float matrix[MATRIX_ARRAY_SIZE], uint32_t matrixSize,
163 sptr<SurfaceBuffer>& buffer, GraphicTransformType& transform, const Rect& crop)
164 {
165 if (buffer == nullptr) {
166 return;
167 }
168 float tx = 0.f;
169 float ty = 0.f;
170 float sx = 1.f;
171 float sy = 1.f;
172 std::array<float, TRANSFORM_MATRIX_ELE_COUNT> transformMatrix = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
173 ComputeTransformByMatrix(transform, &transformMatrix);
174
175 float bufferWidth = buffer->GetWidth();
176 float bufferHeight = buffer->GetHeight();
177 bool changeFlag = false;
178 if (crop.w < bufferWidth && bufferWidth != 0) {
179 tx = (float(crop.x) / bufferWidth);
180 sx = (float(crop.w) / bufferWidth);
181 changeFlag = true;
182 }
183 if (crop.h < bufferHeight && bufferHeight != 0) {
184 ty = (float(bufferHeight - crop.y) / bufferHeight);
185 sy = (float(crop.h) / bufferHeight);
186 changeFlag = true;
187 }
188 if (changeFlag) {
189 std::array<float, MATRIX_ARRAY_SIZE> cropMatrix = {sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1};
190 transformMatrix = MatrixProduct(cropMatrix, transformMatrix);
191 }
192
193 auto ret = memcpy_s(matrix, matrixSize * sizeof(float),
194 transformMatrix.data(), sizeof(transformMatrix));
195 if (ret != EOK) {
196 BLOGE("memcpy_s failed, ret: %{public}d", ret);
197 }
198 }
199
ComputeTransformByMatrixV2(GraphicTransformType & transform,std::array<float,TRANSFORM_MATRIX_ELE_COUNT> * transformMatrix)200 void SurfaceUtils::ComputeTransformByMatrixV2(GraphicTransformType& transform,
201 std::array<float, TRANSFORM_MATRIX_ELE_COUNT> *transformMatrix)
202 {
203 const std::array<float, TRANSFORM_MATRIX_ELE_COUNT> rotate90 = {0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1};
204 const std::array<float, TRANSFORM_MATRIX_ELE_COUNT> rotate180 = {-1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1};
205 const std::array<float, TRANSFORM_MATRIX_ELE_COUNT> rotate270 = {0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1};
206 const std::array<float, TRANSFORM_MATRIX_ELE_COUNT> flipH = {-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1};
207 const std::array<float, TRANSFORM_MATRIX_ELE_COUNT> flipV = {1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1};
208
209 switch (transform) {
210 case GraphicTransformType::GRAPHIC_ROTATE_NONE:
211 break;
212 case GraphicTransformType::GRAPHIC_ROTATE_90:
213 *transformMatrix = rotate90;
214 break;
215 case GraphicTransformType::GRAPHIC_ROTATE_180:
216 *transformMatrix = rotate180;
217 break;
218 case GraphicTransformType::GRAPHIC_ROTATE_270:
219 *transformMatrix = rotate270;
220 break;
221 case GraphicTransformType::GRAPHIC_FLIP_H:
222 *transformMatrix = flipH;
223 break;
224 case GraphicTransformType::GRAPHIC_FLIP_V:
225 *transformMatrix = flipV;
226 break;
227 case GraphicTransformType::GRAPHIC_FLIP_H_ROT90:
228 *transformMatrix = MatrixProduct(flipV, rotate90);
229 break;
230 case GraphicTransformType::GRAPHIC_FLIP_V_ROT90:
231 *transformMatrix = MatrixProduct(flipH, rotate90);
232 break;
233 case GraphicTransformType::GRAPHIC_FLIP_H_ROT180:
234 *transformMatrix = flipV;
235 break;
236 case GraphicTransformType::GRAPHIC_FLIP_V_ROT180:
237 *transformMatrix = flipH;
238 break;
239 case GraphicTransformType::GRAPHIC_FLIP_H_ROT270:
240 *transformMatrix = MatrixProduct(flipH, rotate90);
241 break;
242 case GraphicTransformType::GRAPHIC_FLIP_V_ROT270:
243 *transformMatrix = MatrixProduct(flipV, rotate90);
244 break;
245 default:
246 break;
247 }
248 }
249
250 /*
251 * Computes a transformation matrix for buffer rendering with crop and coordinate system conversion.
252 *
253 * The transformation process involves texture coordinate translation, coordinate system
254 * conversion, and scaling operations to achieve proper buffer rendering.
255 *
256 * Texture Coordinate Translation involves converting device coordinates to normalized
257 * texture coordinates [0,1], where:
258 * - tx = crop.x / bufferWidth represents X-axis translation ratio
259 * - ty = (bufferHeight - crop.y - crop.h) / bufferHeight handles Y-axis translation with flip
260 *
261 * Coordinate System Conversion handles the following:
262 * - Device coordinates with origin at top-left and Y-axis down
263 * - OpenGL coordinates with origin at bottom-left and Y-axis up
264 * The Y-axis calculation requires:
265 * - Moving origin from top to bottom using bufferHeight - crop.y
266 * - Accounting for crop region height by subtracting crop.h
267 * - Normalizing to [0,1] range by dividing with bufferHeight
268 *
269 * Scale calculation uses the following factors:
270 * - sx = crop.w / bufferWidth for X-axis scaling
271 * - sy = crop.h / bufferHeight for Y-axis scaling
272 *
273 * The final transformation matrix has the structure:
274 * | sx 0 0 0 | (X-axis scaling)
275 * | 0 sy 0 0 | (Y-axis scaling)
276 * | 0 0 1 0 | (Z-axis unchanged)
277 * | tx ty 0 1 | (Translation)
278 *
279 * @param matrix [out] Output array where the transformation matrix will be stored
280 * @param matrixSize Size of the provided matrix array
281 * @param buffer Source surface buffer containing the image data
282 * @param transform Rotation transformation type to be applied
283 * @param crop Rectangle defining the region of interest for cropping
284 */
ComputeTransformMatrixV2(float matrix[MATRIX_ARRAY_SIZE],uint32_t matrixSize,sptr<SurfaceBuffer> & buffer,GraphicTransformType & transform,const Rect & crop)285 void SurfaceUtils::ComputeTransformMatrixV2(float matrix[MATRIX_ARRAY_SIZE], uint32_t matrixSize,
286 sptr<SurfaceBuffer>& buffer, GraphicTransformType& transform, const Rect& crop)
287 {
288 if (buffer == nullptr) {
289 return;
290 }
291 float tx = 0.f;
292 float ty = 0.f;
293 float sx = 1.f;
294 float sy = 1.f;
295 switch (transform) {
296 case GraphicTransformType::GRAPHIC_ROTATE_90:
297 transform = GraphicTransformType::GRAPHIC_ROTATE_270;
298 break;
299 case GraphicTransformType::GRAPHIC_ROTATE_270:
300 transform = GraphicTransformType::GRAPHIC_ROTATE_90;
301 break;
302 default:
303 break;
304 }
305 std::array<float, TRANSFORM_MATRIX_ELE_COUNT> transformMatrix = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
306 ComputeTransformByMatrixV2(transform, &transformMatrix);
307
308 float bufferWidth = buffer->GetWidth();
309 float bufferHeight = buffer->GetHeight();
310 bool changeFlag = false;
311 if (crop.w < bufferWidth && bufferWidth != 0) {
312 tx = (float(crop.x) / bufferWidth);
313 sx = (float(crop.w) / bufferWidth);
314 changeFlag = true;
315 }
316 if (crop.h < bufferHeight && bufferHeight != 0) {
317 ty = (float(bufferHeight - crop.y - crop.h) / bufferHeight);
318 sy = (float(crop.h) / bufferHeight);
319 changeFlag = true;
320 }
321 if (changeFlag) {
322 std::array<float, MATRIX_ARRAY_SIZE> cropMatrix = {sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1};
323 transformMatrix = MatrixProduct(cropMatrix, transformMatrix);
324 }
325
326 const std::array<float, TRANSFORM_MATRIX_ELE_COUNT> flipV = {1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1};
327 transformMatrix = MatrixProduct(flipV, transformMatrix);
328
329 auto ret = memcpy_s(matrix, matrixSize * sizeof(float),
330 transformMatrix.data(), sizeof(transformMatrix));
331 if (ret != EOK) {
332 BLOGE("memcpy_s failed, ret: %{public}d", ret);
333 }
334 }
335
ComputeBufferMatrix(float matrix[MATRIX_ARRAY_SIZE],uint32_t matrixSize,sptr<SurfaceBuffer> & buffer,GraphicTransformType & transform,const Rect & crop)336 void SurfaceUtils::ComputeBufferMatrix(float matrix[MATRIX_ARRAY_SIZE], uint32_t matrixSize,
337 sptr<SurfaceBuffer>& buffer, GraphicTransformType& transform, const Rect& crop)
338 {
339 ComputeTransformMatrixV2(matrix, matrixSize, buffer, transform, crop);
340 }
341
GetNativeWindow(uint64_t uniqueId)342 void* SurfaceUtils::GetNativeWindow(uint64_t uniqueId)
343 {
344 std::lock_guard<std::mutex> lockGuard(mutex_);
345 auto iter = nativeWindowCache_.find(uniqueId);
346 if (iter == nativeWindowCache_.end()) {
347 BLOGE("Cannot find nativeWindow, uniqueId %{public}" PRIu64 ".", uniqueId);
348 return nullptr;
349 }
350 return iter->second;
351 }
352
AddNativeWindow(uint64_t uniqueId,void * nativeWidow)353 SurfaceError SurfaceUtils::AddNativeWindow(uint64_t uniqueId, void *nativeWidow)
354 {
355 if (nativeWidow == nullptr) {
356 return GSERROR_INVALID_ARGUMENTS;
357 }
358 std::lock_guard<std::mutex> lockGuard(mutex_);
359 if (nativeWindowCache_.count(uniqueId) == 0) {
360 nativeWindowCache_[uniqueId] = nativeWidow;
361 return GSERROR_OK;
362 }
363 BLOGD("the nativeWidow already existed, uniqueId %" PRIu64, uniqueId);
364 return GSERROR_OK;
365 }
366
RemoveNativeWindow(uint64_t uniqueId)367 SurfaceError SurfaceUtils::RemoveNativeWindow(uint64_t uniqueId)
368 {
369 std::lock_guard<std::mutex> lockGuard(mutex_);
370 nativeWindowCache_.erase(uniqueId);
371 return GSERROR_OK;
372 }
373 } // namespace OHOS
374