1/*
2 * Copyright (c) 2020-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 "lite_win.h"
17
18#include "gfx_utils/graphic_log.h"
19#include "gfx_utils/pixel_format_utils.h"
20#include "graphic_locker.h"
21#include "graphic_performance.h"
22#include "hals/gfx_engines.h"
23#include "securec.h"
24
25#include "lite_wm.h"
26#ifdef ARM_NEON_OPT
27#include "graphic_neon_utils.h"
28#endif
29
30namespace OHOS {
31#define COLOR_BLEND_RGBA(r1, g1, b1, a1, r2, g2, b2, a2)  \
32    const float A1 = static_cast<float>(a1) / OPA_OPAQUE; \
33    const float A2 = static_cast<float>(a2) / OPA_OPAQUE; \
34    const float a = 1 - (1 - A1) * (1 - A2);              \
35    (r1) = (A2 * (r2) + (1 - A2) * A1 * (r1)) / a;        \
36    (g1) = (A2 * (g2) + (1 - A2) * A1 * (g1)) / a;        \
37    (b1) = (A2 * (b2) + (1 - A2) * A1 * (b1)) / a;        \
38    (a1) = a * OPA_OPAQUE;
39
40#define COLOR_BLEND_RGB(r1, g1, b1, r2, g2, b2, a2)                                    \
41    (r1) = (((r2) * (a2)) / OPA_OPAQUE) + (((r1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE); \
42    (g1) = (((g2) * (a2)) / OPA_OPAQUE) + (((g1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE); \
43    (b1) = (((b2) * (a2)) / OPA_OPAQUE) + (((b1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE);
44
45namespace {
46    static const int16_t DEFAULT_QUEUE_SIZE = 2;
47}
48
49LiteWindow::LiteWindow(const LiteWinConfig& config)
50    : id_(INVALID_WINDOW_ID), pid_(INVALID_PID), isShow_(false), config_(config), surface_(nullptr),
51      backBuf_(nullptr), sid_({}), needUnregister_(false)
52{
53    pthread_mutex_init(&backBufMutex_, nullptr);
54    id_ = LiteWM::GetInstance()->GetUniqueWinId();
55}
56
57LiteWindow::~LiteWindow()
58{
59    if (needUnregister_) {
60        GRAPHIC_LOGI("release svc cookie");
61        if (sid_.cookie != 0) {
62            delete reinterpret_cast<IpcObjectStub*>(sid_.cookie);
63            sid_.cookie = 0;
64        }
65    }
66    if (surface_ != nullptr) {
67        if (backBuf_ != nullptr) {
68            surface_->CancelBuffer(backBuf_);
69        }
70        delete surface_;
71        surface_ = nullptr;
72    }
73
74    LiteWM::GetInstance()->RecycleWinId(id_);
75}
76
77bool LiteWindow::CreateSurface()
78{
79    if (surface_ == nullptr) {
80        surface_ = Surface::CreateSurface();
81        if (surface_ == nullptr) {
82            GRAPHIC_LOGE("CreateSurface failed!");
83            return false;
84        }
85        surface_->SetWidthAndHeight(config_.rect.GetWidth(), config_.rect.GetHeight());
86        surface_->SetQueueSize(DEFAULT_QUEUE_SIZE);
87        surface_->SetFormat(config_.pixelFormat);
88        surface_->SetUsage(BUFFER_CONSUMER_USAGE_HARDWARE);
89
90        if (backBuf_ == nullptr) {
91            backBuf_ = surface_->RequestBuffer();
92        }
93    }
94    return true;
95}
96
97void LiteWindow::ReleaseSurface()
98{
99}
100
101void LiteWindow::ResizeSurface(int16_t width, int16_t height)
102{
103    if (surface_ == nullptr) {
104        return;
105    }
106
107    GraphicLocker lock(backBufMutex_);
108    if (backBuf_ != nullptr) {
109        surface_->CancelBuffer(backBuf_);
110    }
111    surface_->SetWidthAndHeight(width, height);
112    backBuf_ = surface_->RequestBuffer();
113}
114
115void LiteWindow::Update(Rect rect)
116{
117    LiteWM::GetInstance()->UpdateWindowRegion(this, rect);
118}
119
120void LiteWindow::UpdateBackBuf()
121{
122    GraphicLocker lock(backBufMutex_);
123    if (surface_ == nullptr || backBuf_ == nullptr) {
124        return;
125    }
126
127    SurfaceBuffer* acquireBuffer = surface_->AcquireBuffer();
128    if (acquireBuffer != nullptr) {
129        void* acquireBufVirAddr = acquireBuffer->GetVirAddr();
130        void* backBufVirAddr = backBuf_->GetVirAddr();
131        if (acquireBufVirAddr != nullptr && backBufVirAddr != nullptr) {
132            GRAPHIC_LOGI("memcpy, backBuf size=%d, acquireBuffer size=%d",
133                backBuf_->GetSize(), acquireBuffer->GetSize());
134#ifdef ARM_NEON_OPT
135            {
136                DEBUG_PERFORMANCE_TRACE("UpdateBackBuf_neon");
137                NeonMemcpy(backBufVirAddr, backBuf_->GetSize(), acquireBufVirAddr, acquireBuffer->GetSize());
138            }
139#else
140            {
141                DEBUG_PERFORMANCE_TRACE("UpdateBackBuf");
142                if (memcpy_s(backBufVirAddr, backBuf_->GetSize(),
143                    acquireBufVirAddr, acquireBuffer->GetSize()) != EOK) {
144                    GRAPHIC_LOGE("memcpy_s error!");
145                }
146            }
147#endif
148            GRAPHIC_LOGI("memcpy end");
149        }
150        surface_->ReleaseBuffer(acquireBuffer);
151    }
152}
153
154void LiteWindow::FlushWithModeCopy(const Rect& srcRect, const LiteSurfaceData* layerData, int16_t dx, int16_t dy)
155{
156    int16_t x1 = srcRect.GetLeft();
157    int16_t y1 = srcRect.GetTop();
158    int16_t x2 = srcRect.GetRight();
159    int16_t y2 = srcRect.GetBottom();
160
161    uint32_t stride = surface_->GetStride();
162    uint8_t* srcBuf = reinterpret_cast<uint8_t*>(backBuf_->GetVirAddr()) + y1 * stride + x1 * sizeof(ColorType);
163    uint8_t* dstBuf = layerData->virAddr + dy * layerData->stride + dx * sizeof(LayerColorType);
164    int32_t lineSize = static_cast<int32_t>(x2 - x1 + 1) * sizeof(LayerColorType);
165    for (int16_t y = y1; y <= y2; ++y) {
166#ifdef LAYER_PF_ARGB1555
167        ColorType* tmpSrc = reinterpret_cast<ColorType*>(srcBuf);
168        LayerColorType* tmpDst = reinterpret_cast<LayerColorType*>(dstBuf);
169        for (int16_t x = x1; x <= x2; ++x) {
170            *tmpDst++ = PixelFormatUtils::ARGB8888ToARGB1555((tmpSrc++)->full);
171        }
172#elif defined LAYER_PF_ARGB8888
173        if (memcpy_s(dstBuf, lineSize, srcBuf, lineSize) != EOK) {
174            GRAPHIC_LOGE("memcpy_s error!");
175        }
176#endif
177        srcBuf += stride;
178        dstBuf += layerData->stride;
179    }
180}
181
182void LiteWindow::FlushWithModeBlend(const Rect& srcRect, const LiteSurfaceData* layerData, int16_t dx, int16_t dy)
183{
184    int16_t x1 = srcRect.GetLeft();
185    int16_t y1 = srcRect.GetTop();
186    int16_t x2 = srcRect.GetRight();
187    int16_t y2 = srcRect.GetBottom();
188
189    uint32_t stride = surface_->GetStride();
190    uint8_t* srcBuf = reinterpret_cast<uint8_t*>(backBuf_->GetVirAddr()) + y1 * stride + x1 * sizeof(ColorType);
191    uint8_t* dstBuf = layerData->virAddr + dy * layerData->stride + dx * sizeof(LayerColorType);
192    for (int16_t y = y1; y <= y2; ++y) {
193        ColorType* tmpSrc = reinterpret_cast<ColorType*>(srcBuf);
194        LayerColorType* tmpDst = reinterpret_cast<LayerColorType*>(dstBuf);
195        for (int16_t x = x1; x <= x2; ++x) {
196            uint8_t alpha = tmpSrc->alpha * config_.opacity / OPA_OPAQUE;
197#ifdef LAYER_PF_ARGB1555
198            PF_ARGB1555* dst = reinterpret_cast<PF_ARGB1555*>(tmpDst);
199            if (dst->alpha == 0) {
200                if (alpha) {
201                    // ARGB8888 to ARGB1555, R/G/B should right shift 3 bits
202                    dst->red = (tmpSrc->red * alpha / OPA_OPAQUE) >> 3;
203                    dst->green = (tmpSrc->green * alpha / OPA_OPAQUE) >> 3;
204                    dst->blue = (tmpSrc->blue * alpha / OPA_OPAQUE) >> 3;
205                    dst->alpha = 1;
206                }
207            } else {
208                COLOR_BLEND_RGB(dst->red, dst->green, dst->blue,
209                                (tmpSrc->red) >> 3, (tmpSrc->green) >> 3, (tmpSrc->blue) >> 3, alpha);
210            }
211#elif defined LAYER_PF_ARGB8888
212            if (alpha == OPA_OPAQUE) {
213                *tmpDst = tmpSrc->full;
214            } else {
215                Color32* dst = reinterpret_cast<Color32*>(tmpDst);
216                COLOR_BLEND_RGBA(dst->red, dst->green, dst->blue, dst->alpha,
217                                 tmpSrc->red, tmpSrc->green, tmpSrc->blue, alpha);
218            }
219#endif
220            ++tmpSrc;
221            ++tmpDst;
222        }
223        srcBuf += stride;
224        dstBuf += layerData->stride;
225    }
226}
227
228void LiteWindow::Flush(const Rect& srcRect, const LiteSurfaceData* layerData, int16_t dx, int16_t dy)
229{
230    if (layerData == nullptr) {
231        return;
232    }
233
234    GraphicLocker lock(backBufMutex_);
235#if ENABLE_GFX_ENGINES
236    uintptr_t phyaddr = backBuf_->GetPhyAddr();
237    if (IsCoverMode() && phyaddr) {
238        LiteSurfaceData srcData;
239        srcData.width = surface_->GetWidth();
240        srcData.height = surface_->GetHeight();
241        srcData.pixelFormat = (ImagePixelFormat)surface_->GetFormat();
242        srcData.stride = surface_->GetStride();
243        srcData.phyAddr = reinterpret_cast<uint8_t*>(phyaddr);
244        GRAPHIC_LOGD("Hardware composite, width=%d, height=%d, pixelFormat=%d, stride=%d",
245            srcData.width, srcData.height, srcData.pixelFormat, srcData.stride);
246        if (GfxEngines::GetInstance()->GfxBlit(srcData, srcRect, *layerData, dx, dy)) {
247            return;
248        }
249    }
250#endif
251
252    if (config_.compositeMode == LiteWinConfig::COPY) {
253        FlushWithModeCopy(srcRect, layerData, dx, dy);
254    } else if (config_.compositeMode == LiteWinConfig::BLEND) {
255        FlushWithModeBlend(srcRect, layerData, dx, dy);
256    }
257}
258
259Surface* LiteWindow::GetSurface()
260{
261    return surface_;
262}
263
264void LiteWindow::MoveTo(int16_t x, int16_t y)
265{
266    GRAPHIC_LOGI("{%d,%d}=>{%d,%d}", config_.rect.GetLeft(), config_.rect.GetTop(), x, y);
267    LiteWM* liteWM = LiteWM::GetInstance();
268    liteWM->UpdateWindowRegion(this, config_.rect);
269    config_.rect.SetPosition(x, y);
270    liteWM->UpdateWindowRegion(this, config_.rect);
271}
272
273void LiteWindow::Resize(int16_t width, int16_t height)
274{
275    GRAPHIC_LOGI("{%d,%d}=>{%d,%d}", config_.rect.GetWidth(), config_.rect.GetHeight(), width, height);
276    config_.rect.Resize(width, height);
277    ResizeSurface(width, height);
278}
279}
280