1 /*
2  * Copyright (c) 2022 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 "modifier/rs_extended_modifier.h"
17 
18 #include <memory>
19 
20 #include "modifier/rs_modifier_type.h"
21 #include "modifier/rs_render_modifier.h"
22 #include "pipeline/rs_node_map.h"
23 #include "pipeline/rs_recording_canvas.h"
24 #include "platform/common/rs_log.h"
25 #if defined(RS_ENABLE_VK)
26 #include "common/rs_optional_trace.h"
27 #include "image/image.h"
28 #include "native_window.h"
29 #include "platform/ohos/backend/native_buffer_utils.h"
30 #include "recording/cmd_list_helper.h"
31 #include "surface_buffer.h"
32 #endif
33 
34 namespace OHOS {
35 namespace Rosen {
36 
37 #if defined(RS_ENABLE_VK)
DmaMemAlloc(const int32_t & width,const int32_t & height,const std::unique_ptr<Media::PixelMap> & pixelMap)38 static sptr<SurfaceBuffer> DmaMemAlloc(const int32_t& width, const int32_t& height,
39     const std::unique_ptr<Media::PixelMap>& pixelMap)
40 {
41 #if defined(_WIN32) || defined(_APPLE) || defined(A_PLATFORM) || defined(IOS_PLATFORM)
42     RS_LOGE("DmaMemAlloc::Unsupport dma mem alloc");
43     return nullptr;
44 #else
45     sptr<SurfaceBuffer> surfaceBuffer = SurfaceBuffer::Create();
46     if (!surfaceBuffer) {
47         return nullptr;
48     }
49     BufferRequestConfig requestConfig = {
50         .width = width,
51         .height = height,
52         .strideAlignment = 0x8, // set 0x8 as default value to alloc SurfaceBufferImpl
53         .format = GRAPHIC_PIXEL_FMT_RGBA_8888, // PixelFormat
54         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_HW_RENDER | BUFFER_USAGE_MEM_MMZ_CACHE | BUFFER_USAGE_MEM_DMA,
55         .timeout = 0,
56         .colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB,
57         .transform = GraphicTransformType::GRAPHIC_ROTATE_NONE,
58     };
59     GSError ret = surfaceBuffer->Alloc(requestConfig);
60     if (ret != GSERROR_OK) {
61         RS_LOGE("DmaMemAlloc::SurfaceBuffer Alloc failed, %{public}s", GSErrorStr(ret).c_str());
62         return nullptr;
63     }
64     void* nativeBuffer = surfaceBuffer.GetRefPtr();
65     if (!nativeBuffer) {
66         return nullptr;
67     }
68     OHOS::RefBase *ref = reinterpret_cast<OHOS::RefBase *>(nativeBuffer);
69     ref->IncStrongRef(ref);
70     int32_t bufferSize = pixelMap->GetByteCount();
71     pixelMap->SetPixelsAddr(surfaceBuffer->GetVirAddr(), nativeBuffer, bufferSize,
72         Media::AllocatorType::DMA_ALLOC, nullptr);
73     return surfaceBuffer;
74 #endif
75 }
76 
CreateSurface(const std::unique_ptr<Media::PixelMap> & pixelMap,int32_t & width,int32_t & height)77 static std::shared_ptr<Drawing::Surface> CreateSurface(const std::unique_ptr<Media::PixelMap>& pixelMap, int32_t& width,
78     int32_t& height)
79 {
80     sptr<SurfaceBuffer> surfaceBufferTmp = DmaMemAlloc(width, height, pixelMap);
81     if (!surfaceBufferTmp) {
82         RS_LOGE("CreateSurface::DmaMemAlloc fail.");
83         return nullptr;
84     }
85 
86     OHNativeWindowBuffer *nativeWindowBufferTmp = CreateNativeWindowBufferFromSurfaceBuffer(&surfaceBufferTmp);
87     if (!nativeWindowBufferTmp) {
88         RS_LOGE("CreateSurface::CreateNativeWindowBufferFromSurfaceBuffer fail");
89         return nullptr;
90     }
91 
92     Drawing::BackendTexture backendTextureTmp = NativeBufferUtils::MakeBackendTextureFromNativeBuffer(
93         nativeWindowBufferTmp, surfaceBufferTmp->GetWidth(), surfaceBufferTmp->GetHeight());
94     if (!backendTextureTmp.IsValid()) {
95         DestroyNativeWindowBuffer(nativeWindowBufferTmp);
96         RS_LOGE("CreateSurface::MakeBackendTextureFromNativeBuffer fail");
97         return nullptr;
98     }
99 
100     auto vkTextureInfo = backendTextureTmp.GetTextureInfo().GetVKTextureInfo();
101     vkTextureInfo->imageUsageFlags = vkTextureInfo->imageUsageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
102     auto cleanUpHelper = new NativeBufferUtils::VulkanCleanupHelper(RsVulkanContext::GetSingleton(),
103         vkTextureInfo->vkImage, vkTextureInfo->vkAlloc.memory);
104     if (!cleanUpHelper) {
105         DestroyNativeWindowBuffer(nativeWindowBufferTmp);
106         RS_LOGE("CreateSurface::construct VulkanCleanupHelper fail.");
107         return nullptr;
108     }
109     auto gpuContext = RsVulkanContext::GetSingleton().CreateDrawingContext();
110     if (!gpuContext) {
111         RS_LOGE("CreateSurface::CreateDrawingContext fail.");
112         delete cleanUpHelper;
113         cleanUpHelper = nullptr;
114         DestroyNativeWindowBuffer(nativeWindowBufferTmp);
115         return nullptr;
116     }
117     std::shared_ptr<Drawing::Surface> drawingSurface = Drawing::Surface::MakeFromBackendTexture(gpuContext.get(),
118         backendTextureTmp.GetTextureInfo(), Drawing::TextureOrigin::TOP_LEFT, 1,
119         Drawing::ColorType::COLORTYPE_RGBA_8888, nullptr, NativeBufferUtils::DeleteVkImage, cleanUpHelper);
120     if (!drawingSurface) {
121         delete cleanUpHelper;
122         cleanUpHelper = nullptr;
123         RS_LOGE("CreateSurface::MakeFromBackendTexture fail.");
124     }
125     DestroyNativeWindowBuffer(nativeWindowBufferTmp);
126     return drawingSurface;
127 }
128 
MakePiexlMapDrawCmdList(std::shared_ptr<Drawing::DrawCmdList> & recording,RSDrawingContext & ctx)129 static std::shared_ptr<Drawing::DrawCmdList> MakePiexlMapDrawCmdList(std::shared_ptr<Drawing::DrawCmdList>& recording,
130     RSDrawingContext& ctx)
131 {
132     static constexpr size_t LONGTEXT_WATER_LINE = 20;
133     static constexpr float OFFSET_COORDANATE = 0.5f;
134     std::shared_ptr<Drawing::DrawCmdList> pixelMapDrawCmdList = nullptr;
135     if (recording->GetOpItemSize() > LONGTEXT_WATER_LINE && recording->CountTextBlobNum() > LONGTEXT_WATER_LINE) {
136         RS_TRACE_NAME("enter long text GPU render.");
137         int32_t width = static_cast<int32_t>(ctx.width + OFFSET_COORDANATE);
138         int32_t height = static_cast<int32_t>(ctx.height + OFFSET_COORDANATE);
139         Media::InitializationOptions options;
140         options.size.width = width;
141         options.size.height = height;
142         options.srcPixelFormat = Media::PixelFormat::RGBA_8888;
143         options.pixelFormat = Media::PixelFormat::RGBA_8888;
144         auto pixelMap = Media::PixelMap::Create(options);
145         if (!pixelMap) {
146             RS_LOGE("MakePiexlMapDrawCmdList::PixelMap Create fail.");
147             return nullptr;
148         }
149         auto drawingSurface = CreateSurface(pixelMap, width, height);
150         if (!drawingSurface) {
151             RS_LOGE("MakePiexlMapDrawCmdList::drawingSurface Create fail.");
152             return nullptr;
153         }
154         auto tmpCanvas = drawingSurface->GetCanvas();
155         recording->Playback(*tmpCanvas, nullptr);
156         drawingSurface->FlushAndSubmit();
157         Drawing::SamplingOptions sampling(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::LINEAR);
158         pixelMapDrawCmdList =
159             std::make_shared<Drawing::DrawCmdList>(width, height, Drawing::DrawCmdList::UnmarshalMode::IMMEDIATE);
160         Drawing::AdaptiveImageInfo adaptiveImageInfo = { 0, 0, {}, 1.0, 0, width, height };
161         auto object = std::make_shared<RSExtendImageObject>(std::move(pixelMap), adaptiveImageInfo);
162         auto objectHandle = Drawing::CmdListHelper::AddImageObjectToCmdList(*pixelMapDrawCmdList, object);
163         Drawing::PaintHandle paintHandle;
164         paintHandle.isAntiAlias = true;
165         paintHandle.style = Drawing::Paint::PaintStyle::PAINT_FILL;
166         pixelMapDrawCmdList->AddDrawOp<Drawing::DrawPixelMapWithParmOpItem::ConstructorHandle>(objectHandle, sampling,
167             paintHandle);
168     }
169     return pixelMapDrawCmdList;
170 }
171 #endif
172 
CreateDrawingContext(NodeId nodeId)173 RSDrawingContext RSExtendedModifierHelper::CreateDrawingContext(NodeId nodeId)
174 {
175     auto node = RSNodeMap::Instance().GetNode<RSCanvasNode>(nodeId);
176     if (!node) {
177         return { nullptr };
178     }
179     auto recordingCanvas = new ExtendRecordingCanvas(node->GetPaintWidth(), node->GetPaintHeight());
180     recordingCanvas->SetIsCustomTextType(node->GetIsCustomTextType());
181     recordingCanvas->SetIsCustomTypeface(node->GetIsCustomTypeface());
182     return { recordingCanvas, node->GetPaintWidth(), node->GetPaintHeight() };
183 }
184 
CreateRenderModifier(RSDrawingContext & ctx,PropertyId id,RSModifierType type)185 std::shared_ptr<RSRenderModifier> RSExtendedModifierHelper::CreateRenderModifier(
186     RSDrawingContext& ctx, PropertyId id, RSModifierType type)
187 {
188     auto renderProperty = std::make_shared<RSRenderProperty<Drawing::DrawCmdListPtr>>(
189         RSExtendedModifierHelper::FinishDrawing(ctx), id);
190     auto renderModifier =  std::make_shared<RSDrawCmdListRenderModifier>(renderProperty);
191     renderModifier->SetType(type);
192     return renderModifier;
193 }
194 
FinishDrawing(RSDrawingContext & ctx)195 std::shared_ptr<Drawing::DrawCmdList> RSExtendedModifierHelper::FinishDrawing(RSDrawingContext& ctx)
196 {
197     auto recordingCanvas = static_cast<ExtendRecordingCanvas*>(ctx.canvas);
198     if (!recordingCanvas) {
199         RS_LOGW("RSExtendedModifierHelper::FinishDrawing recordingCanvas is nullptr");
200         return nullptr;
201     }
202     auto recording = recordingCanvas->GetDrawCmdList();
203     if (!recording) {
204         RS_LOGW("RSExtendedModifierHelper::FinishDrawing recording is nullptr");
205         delete ctx.canvas;
206         ctx.canvas = nullptr;
207         return nullptr;
208     }
209 #if defined(RS_ENABLE_VK)
210     if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN && RSSystemProperties::GetTextBlobAsPixelMap()) {
211         auto pixelMapDrawCmdList = MakePiexlMapDrawCmdList(recording, ctx);
212         if (pixelMapDrawCmdList) {
213             delete ctx.canvas;
214             ctx.canvas = nullptr;
215             return pixelMapDrawCmdList;
216         }
217     }
218 #endif
219     if (RSSystemProperties::GetDrawTextAsBitmap()) {
220         // replace drawOpItem with cached one (generated by CPU)
221         recording->GenerateCache();
222     }
223     delete ctx.canvas;
224     ctx.canvas = nullptr;
225     return recording;
226 }
227 } // namespace Rosen
228 } // namespace OHOS
229