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 
30 namespace 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 
45 namespace {
46     static const int16_t DEFAULT_QUEUE_SIZE = 2;
47 }
48 
LiteWindow(const LiteWinConfig & config)49 LiteWindow::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 
~LiteWindow()57 LiteWindow::~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 
CreateSurface()77 bool 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 
ReleaseSurface()97 void LiteWindow::ReleaseSurface()
98 {
99 }
100 
ResizeSurface(int16_t width,int16_t height)101 void 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 
Update(Rect rect)115 void LiteWindow::Update(Rect rect)
116 {
117     LiteWM::GetInstance()->UpdateWindowRegion(this, rect);
118 }
119 
UpdateBackBuf()120 void 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 
FlushWithModeCopy(const Rect & srcRect,const LiteSurfaceData * layerData,int16_t dx,int16_t dy)154 void 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 
FlushWithModeBlend(const Rect & srcRect,const LiteSurfaceData * layerData,int16_t dx,int16_t dy)182 void 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 
Flush(const Rect & srcRect,const LiteSurfaceData * layerData,int16_t dx,int16_t dy)228 void 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 
GetSurface()259 Surface* LiteWindow::GetSurface()
260 {
261     return surface_;
262 }
263 
MoveTo(int16_t x,int16_t y)264 void 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 
Resize(int16_t width,int16_t height)273 void 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