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
21namespace OHOS {
22using namespace HiviewDFX;
23static SurfaceUtils* instance = nullptr;
24static std::once_flag createFlag_;
25constexpr uint32_t MATRIX_ARRAY_SIZE = 16;
26
27SurfaceUtils* SurfaceUtils::GetInstance()
28{
29    std::call_once(createFlag_, [&]() {
30        instance = new SurfaceUtils();
31    });
32
33    return instance;
34}
35
36SurfaceUtils::~SurfaceUtils()
37{
38    instance = nullptr;
39    surfaceCache_.clear();
40    nativeWindowCache_.clear();
41}
42
43sptr<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
59SurfaceError 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
73SurfaceError 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
85std::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
112void 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
162void SurfaceUtils::ComputeTransformMatrix(float matrix[MATRIX_ARRAY_SIZE], uint32_t matrixSize,
163    sptr<SurfaceBuffer>& buffer, GraphicTransformType& transform, 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
200void 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
250void SurfaceUtils::ComputeTransformMatrixV2(float matrix[MATRIX_ARRAY_SIZE], uint32_t matrixSize,
251    sptr<SurfaceBuffer>& buffer, GraphicTransformType& transform, Rect& crop)
252{
253    if (buffer == nullptr) {
254        return;
255    }
256    float tx = 0.f;
257    float ty = 0.f;
258    float sx = 1.f;
259    float sy = 1.f;
260    switch (transform) {
261        case GraphicTransformType::GRAPHIC_ROTATE_90:
262            transform = GraphicTransformType::GRAPHIC_ROTATE_270;
263            break;
264        case GraphicTransformType::GRAPHIC_ROTATE_270:
265            transform = GraphicTransformType::GRAPHIC_ROTATE_90;
266            break;
267        default:
268            break;
269    }
270    std::array<float, TRANSFORM_MATRIX_ELE_COUNT> transformMatrix = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
271    ComputeTransformByMatrixV2(transform, &transformMatrix);
272
273    float bufferWidth = buffer->GetWidth();
274    float bufferHeight = buffer->GetHeight();
275    bool changeFlag = false;
276    if (crop.w < bufferWidth && bufferWidth != 0) {
277        tx = (float(crop.x) / bufferWidth);
278        sx = (float(crop.w) / bufferWidth);
279        changeFlag = true;
280    }
281    if (crop.h < bufferHeight && bufferHeight != 0) {
282        ty = (float(bufferHeight - crop.y) / bufferHeight);
283        sy = (float(crop.h) / bufferHeight);
284        changeFlag = true;
285    }
286    if (changeFlag) {
287        std::array<float, MATRIX_ARRAY_SIZE> cropMatrix = {sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1};
288        transformMatrix = MatrixProduct(cropMatrix, transformMatrix);
289    }
290
291    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};
292    transformMatrix = MatrixProduct(flipV, transformMatrix);
293
294    auto ret = memcpy_s(matrix, matrixSize * sizeof(float),
295                        transformMatrix.data(), sizeof(transformMatrix));
296    if (ret != EOK) {
297        BLOGE("memcpy_s failed, ret: %{public}d", ret);
298    }
299}
300
301void* SurfaceUtils::GetNativeWindow(uint64_t uniqueId)
302{
303    std::lock_guard<std::mutex> lockGuard(mutex_);
304    auto iter = nativeWindowCache_.find(uniqueId);
305    if (iter == nativeWindowCache_.end()) {
306        BLOGE("Cannot find nativeWindow, uniqueId %{public}" PRIu64 ".", uniqueId);
307        return nullptr;
308    }
309    return iter->second;
310}
311
312SurfaceError SurfaceUtils::AddNativeWindow(uint64_t uniqueId, void *nativeWidow)
313{
314    if (nativeWidow == nullptr) {
315        return GSERROR_INVALID_ARGUMENTS;
316    }
317    std::lock_guard<std::mutex> lockGuard(mutex_);
318    if (nativeWindowCache_.count(uniqueId) == 0) {
319        nativeWindowCache_[uniqueId] = nativeWidow;
320        return GSERROR_OK;
321    }
322    BLOGD("the nativeWidow already existed, uniqueId %" PRIu64, uniqueId);
323    return GSERROR_OK;
324}
325
326SurfaceError SurfaceUtils::RemoveNativeWindow(uint64_t uniqueId)
327{
328    std::lock_guard<std::mutex> lockGuard(mutex_);
329    nativeWindowCache_.erase(uniqueId);
330    return GSERROR_OK;
331}
332} // namespace OHOS
333