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