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 <cmath>
17#include <vector>
18#include <fcntl.h>
19#include <unistd.h>
20#include "display_test.h"
21#include "buffer_handle.h"
22
23#include "v1_2/display_composer_type.h"
24#include "v1_0/include/idisplay_buffer.h"
25
26namespace OHOS {
27namespace HDI {
28namespace Display {
29namespace TEST {
30using namespace OHOS::HDI::Display::Composer::V1_0;
31using namespace OHOS::HDI::Display::Buffer::V1_0;
32
33const uint8_t BITS_PER_BYTE = 8;
34
35static uint32_t BGRAToRGBA(uint32_t bgra)
36{
37    uint32_t rgba = 0;
38    const uint32_t COLOR_RED = 0x0000ff00;
39    const uint32_t COLOR_GREEN = 0x00ff0000;
40    const uint32_t COLOR_BLUE = 0xff000000;
41    const uint32_t ALPHA = 0x000000ff;
42    const int32_t TWO_BYTE_OFFSET = 16;
43
44    rgba |= (bgra & COLOR_RED) << TWO_BYTE_OFFSET; // get red then move to rgba
45    rgba |= (bgra & COLOR_GREEN);                  // get green
46    rgba |= (bgra & COLOR_BLUE) >> TWO_BYTE_OFFSET; // get blue then move to rgba
47    rgba |= (bgra & ALPHA);                  // get alpha
48
49    return rgba;
50}
51
52static int32_t GetPixelFormatBpp(Composer::V1_0::PixelFormat format)
53{
54    const int32_t BPP_RGBA_8888 = 32;
55    switch (format) {
56        case Composer::V1_0::PIXEL_FMT_RGBA_8888:
57            return BPP_RGBA_8888;
58        case Composer::V1_0::PIXEL_FMT_BGRA_8888:
59            return BPP_RGBA_8888;
60        default:
61            return -1;
62    }
63}
64
65void SaveFile(const char *fileName, uint8_t *data, int size)
66{
67    if (fileName != nullptr && data != nullptr) {
68        int fileFd = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
69        if (fileFd <= 0) {
70            DISPLAY_TEST_LOGE("Open file failed %{public}d", fileFd);
71            return;
72        }
73
74        int hasWriten = write(fileFd, data, size);
75        DISPLAY_TEST_LOGD("SaveFile hasWriten %{public}d", hasWriten);
76        close(fileFd);
77    } else {
78        DISPLAY_TEST_LOGE("SaveFile failed");
79    }
80}
81
82static uint32_t ConverToRGBA(Composer::V1_0::PixelFormat fmt, uint32_t color)
83{
84    switch (fmt) {
85        case Composer::V1_0::PIXEL_FMT_BGRA_8888:
86            return BGRAToRGBA(color);
87        case Composer::V1_0::PIXEL_FMT_RGBA_8888:
88            return color;
89        default:
90            DISPLAY_TEST_LOGE("the fmt can not convert %{public}d", fmt);
91    }
92    return color;
93}
94
95uint32_t GetPixelValue(const BufferHandle &handle, int x, int y)
96{
97    const int32_t PIXEL_BYTES = 4;
98    int32_t bpp = GetPixelFormatBpp((Composer::V1_0::PixelFormat)handle.format);
99    DISPLAY_TEST_CHK_RETURN((bpp <= 0), 0, DISPLAY_TEST_LOGE("CheckPixel do not support format %{public}d",
100        handle.format));
101    DISPLAY_TEST_CHK_RETURN((handle.virAddr == nullptr), 0,
102        DISPLAY_TEST_LOGE("CheckPixel viraddr is null must map it"));
103    DISPLAY_TEST_CHK_RETURN((x < 0 || x >= handle.width), 0,
104        DISPLAY_TEST_LOGE("CheckPixel invalid parameter x:%{public}d width:%{public}d", x, handle.width));
105    DISPLAY_TEST_CHK_RETURN((y < 0 || y >= handle.height), 0,
106        DISPLAY_TEST_LOGE("CheckPixel invalid parameter y:%{public}d height:%{public}d", y, handle.height));
107
108    int32_t position = y * handle.width + x;
109    if ((position * PIXEL_BYTES) > handle.size) {
110        DISPLAY_TEST_LOGE("the pixel position outside\n");
111    }
112    uint32_t *pixel = reinterpret_cast<uint32_t *>(handle.virAddr) + position;
113    DISPLAY_TEST_CHK_RETURN((pixel == nullptr), DISPLAY_FAILURE, DISPLAY_TEST_LOGE("get pixel failed"));
114
115    return *pixel;
116}
117
118uint32_t GetUint32(uint32_t value)
119{
120    uint32_t dst;
121    uint8_t *data = reinterpret_cast<uint8_t *>(&dst);
122    for (uint8_t i = 0; i < sizeof(uint32_t); i++) {
123        *(data + i) = (value >> ((sizeof(uint32_t) - i - 1) * BITS_PER_BYTE)) & 0xff;
124    }
125    return dst;
126}
127
128uint32_t CheckPixel(const BufferHandle &handle, int x, int y, uint32_t color)
129{
130    const int32_t PIXEL_BYTES = 4;
131    int32_t bpp = GetPixelFormatBpp(static_cast<Composer::V1_0::PixelFormat>(handle.format));
132    DISPLAY_TEST_CHK_RETURN((bpp <= 0), 0, DISPLAY_TEST_LOGE("CheckPixel do not support format %{public}d",
133        handle.format));
134    DISPLAY_TEST_CHK_RETURN((handle.virAddr == nullptr), 0,
135        DISPLAY_TEST_LOGE("CheckPixel viraddr is null must map it"));
136    DISPLAY_TEST_CHK_RETURN((x < 0 || x >= handle.width), 0,
137        DISPLAY_TEST_LOGE("CheckPixel invalid parameter x:%{public}d width:%{public}d", x, handle.width));
138    DISPLAY_TEST_CHK_RETURN((y < 0 || y >= handle.height), 0,
139        DISPLAY_TEST_LOGE("CheckPixel invalid parameter y:%{public}d height:%{public}d", y, handle.height));
140
141    int32_t position = y * handle.width + x;
142    if ((position * PIXEL_BYTES) > handle.size) {
143        DISPLAY_TEST_LOGE("the pixel position outside\n");
144    }
145    uint32_t *pixel = reinterpret_cast<uint32_t *>(handle.virAddr) + position;
146    DISPLAY_TEST_CHK_RETURN((pixel == nullptr), DISPLAY_FAILURE, DISPLAY_TEST_LOGE("get pixel failed"));
147
148    uint32_t checkColor = ConverToRGBA(static_cast<Composer::V1_0::PixelFormat>(handle.format), GetUint32(*pixel));
149    if (checkColor != color) {
150        DISPLAY_TEST_LOGD("x:%{public}d y:%{public}d width:%{public}d", x, y, handle.width);
151        SaveFile("/data/display_test_bitmap_", static_cast<uint8_t *>(handle.virAddr), handle.size);
152        return DISPLAY_FAILURE;
153    }
154    return DISPLAY_SUCCESS;
155}
156
157void SetUint32(uint32_t &dst, uint32_t value)
158{
159    uint8_t *data = reinterpret_cast<uint8_t *>(&dst);
160    if (data != nullptr) {
161        for (uint8_t i = 0; i < sizeof(uint32_t); i++) {
162            *(data + i) = (value >> ((sizeof(uint32_t) - i - 1) * BITS_PER_BYTE)) & 0xff;
163        }
164    } else {
165        DISPLAY_TEST_LOGE("SetUint32 failed");
166    }
167}
168
169void SetPixel(const BufferHandle &handle, int x, int y, uint32_t color)
170{
171    const int32_t PIXEL_BYTES = 4;
172    const int32_t BPP = 32;
173    DISPLAY_TEST_CHK_RETURN_NOT_VALUE((BPP <= 0),
174        DISPLAY_TEST_LOGE("CheckPixel do not support format %{public}d", handle.format));
175    DISPLAY_TEST_CHK_RETURN_NOT_VALUE((handle.virAddr == nullptr),
176        DISPLAY_TEST_LOGE("CheckPixel viraddr is null must map it"));
177    DISPLAY_TEST_CHK_RETURN_NOT_VALUE((x < 0 || x >= handle.width),
178        DISPLAY_TEST_LOGE("CheckPixel invalid parameter x:%{public}d width:%{public}d", x, handle.width));
179    DISPLAY_TEST_CHK_RETURN_NOT_VALUE((y < 0 || y >= handle.height),
180        DISPLAY_TEST_LOGE("CheckPixel invalid parameter y:%{public}d height:%{public}d", y, handle.height));
181
182    int32_t position = y * handle.stride / PIXEL_BYTES + x;
183    if ((position * PIXEL_BYTES) > handle.size) {
184        DISPLAY_TEST_LOGE("the pixel position outside\n");
185    }
186    uint32_t *pixel = reinterpret_cast<uint32_t *>(handle.virAddr) + position;
187    DISPLAY_TEST_CHK_RETURN_NOT_VALUE((pixel == nullptr), DISPLAY_TEST_LOGE("get pixel failed"));
188
189    SetUint32(*pixel, color);
190}
191
192void ClearColor(const BufferHandle &handle, uint32_t color)
193{
194    for (int32_t x = 0; x < handle.width; x++) {
195        for (int32_t y = 0; y < handle.height; y++) {
196            SetPixel(handle, x, y, color);
197        }
198    }
199}
200
201void ClearColorRect(const BufferHandle &handle, uint32_t color, const IRect &rect)
202{
203    DISPLAY_TEST_LOGD("x %{public}d, y %{public}d w %{public}d h %{public}d color %x ", rect.x, rect.y, rect.w, rect.h,
204        color);
205    for (int32_t x = 0; x < rect.w; x++) {
206        for (int32_t y = 0; y < rect.h; y++) {
207            SetPixel(handle, x + rect.x, y + rect.y, color);
208        }
209    }
210}
211
212std::vector<IRect> SplitBuffer(const BufferHandle &handle, std::vector<uint32_t> &colors)
213{
214    std::vector<IRect> splitRects;
215    if (colors.empty()) {
216        DISPLAY_TEST_LOGD("the colors empty");
217    }
218    const uint32_t ROW_NUM = sqrt(colors.size());
219    const uint32_t COL_NUM = ROW_NUM;
220    if (ROW_NUM == 0) {
221        DISPLAY_TEST_LOGD("ROW_NUM is zero");
222        return splitRects;
223    }
224
225    const uint32_t CELL_WIDTH = handle.width / ROW_NUM;
226    const uint32_t CELL_HEIGHT = handle.height / COL_NUM;
227    IRect rect = { 0, 0, CELL_WIDTH, CELL_HEIGHT };
228    DISPLAY_TEST_LOGD("ROW_NUM %{public}u, COL_NUM %{public}u CELL_WIDTH %{public}u CELL_HEIGHT %{public}u",
229        ROW_NUM, COL_NUM, CELL_WIDTH, CELL_HEIGHT);
230    uint32_t count = 0;
231    for (uint32_t x = 0; x < ROW_NUM; x++) {
232        for (uint32_t y = 0; y < COL_NUM; y++) {
233            rect.x = x * CELL_WIDTH;
234            rect.y = y * CELL_HEIGHT;
235            ClearColorRect(handle, colors[count++], rect);
236            splitRects.push_back(rect);
237        }
238    }
239    SaveFile("/data/splitbuffer_data_", static_cast<uint8_t *>(handle.virAddr), handle.size);
240    return splitRects;
241}
242} // OHOS
243} // HDI
244} // Display
245} // TEST
246