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 "memory/rs_tag_tracker.h"
17 #include "native_buffer_utils.h"
18 #include "platform/common/rs_log.h"
19 #include "render_context/render_context.h"
20 namespace OHOS::Rosen {
21 namespace NativeBufferUtils {
DeleteVkImage(void * context)22 void DeleteVkImage(void* context)
23 {
24 VulkanCleanupHelper* cleanupHelper = static_cast<VulkanCleanupHelper*>(context);
25 if (cleanupHelper != nullptr) {
26 cleanupHelper->UnRef();
27 }
28 }
29
GetNativeBufferFormatProperties(const RsVulkanContext & vkContext,VkDevice device,OH_NativeBuffer * nativeBuffer,VkNativeBufferFormatPropertiesOHOS * nbFormatProps,VkNativeBufferPropertiesOHOS * nbProps)30 bool GetNativeBufferFormatProperties(const RsVulkanContext& vkContext, VkDevice device, OH_NativeBuffer* nativeBuffer,
31 VkNativeBufferFormatPropertiesOHOS* nbFormatProps,
32 VkNativeBufferPropertiesOHOS* nbProps)
33 {
34 nbFormatProps->sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_FORMAT_PROPERTIES_OHOS;
35 nbFormatProps->pNext = nullptr;
36
37 nbProps->sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_PROPERTIES_OHOS;
38 nbProps->pNext = nbFormatProps;
39
40 VkResult err = vkContext.vkGetNativeBufferPropertiesOHOS(device, nativeBuffer, nbProps);
41 if (VK_SUCCESS != err) {
42 ROSEN_LOGE("NativeBufferUtils: vkGetNativeBufferPropertiesOHOS Failed ! %d", err);
43 return false;
44 }
45 return true;
46 }
47
CreateVkImage(const RsVulkanContext & vkContext,VkImage * image,const VkNativeBufferFormatPropertiesOHOS & nbFormatProps,const VkExtent3D & imageSize,VkImageUsageFlags usageFlags=0)48 bool CreateVkImage(const RsVulkanContext& vkContext, VkImage* image,
49 const VkNativeBufferFormatPropertiesOHOS& nbFormatProps, const VkExtent3D& imageSize,
50 VkImageUsageFlags usageFlags = 0)
51 {
52 VkExternalFormatOHOS externalFormat;
53 externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_OHOS;
54 externalFormat.pNext = nullptr;
55 externalFormat.externalFormat = 0;
56
57 if (nbFormatProps.format == VK_FORMAT_UNDEFINED) {
58 externalFormat.externalFormat = nbFormatProps.externalFormat;
59 }
60
61 const VkExternalMemoryImageCreateInfo externalMemoryImageInfo {
62 VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, // sType
63 &externalFormat, // pNext
64 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OHOS_NATIVE_BUFFER_BIT_OHOS, // handleTypes
65 };
66
67 VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
68
69 VkImageCreateFlags flags = 0;
70
71 const VkImageCreateInfo imageCreateInfo = {
72 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
73 &externalMemoryImageInfo,
74 flags,
75 VK_IMAGE_TYPE_2D,
76 nbFormatProps.format,
77 imageSize,
78 1,
79 1,
80 VK_SAMPLE_COUNT_1_BIT,
81 tiling,
82 usageFlags,
83 VK_SHARING_MODE_EXCLUSIVE,
84 0,
85 0,
86 VK_IMAGE_LAYOUT_UNDEFINED,
87 };
88
89 VkResult err = vkContext.vkCreateImage(vkContext.GetDevice(), &imageCreateInfo, nullptr, image);
90 if (err != VK_SUCCESS) {
91 ROSEN_LOGE("NativeBufferUtils: vkCreateImage failed");
92 return false;
93 }
94 return true;
95 }
96
AllocateDeviceMemory(const RsVulkanContext & vkContext,VkDeviceMemory * memory,VkImage & image,OH_NativeBuffer * nativeBuffer,VkNativeBufferPropertiesOHOS & nbProps)97 bool AllocateDeviceMemory(const RsVulkanContext& vkContext, VkDeviceMemory* memory, VkImage& image,
98 OH_NativeBuffer* nativeBuffer, VkNativeBufferPropertiesOHOS& nbProps)
99 {
100 VkPhysicalDeviceMemoryProperties2 physicalDeviceMemProps;
101 physicalDeviceMemProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
102 physicalDeviceMemProps.pNext = nullptr;
103
104 uint32_t foundTypeIndex = 0;
105 VkDevice device = vkContext.GetDevice();
106 VkPhysicalDevice physicalDevice = vkContext.GetPhysicalDevice();
107 vkContext.vkGetPhysicalDeviceMemoryProperties2(physicalDevice, &physicalDeviceMemProps);
108 uint32_t memTypeCnt = physicalDeviceMemProps.memoryProperties.memoryTypeCount;
109 bool found = false;
110 for (uint32_t i = 0; i < memTypeCnt; ++i) {
111 if (nbProps.memoryTypeBits & (1 << i)) {
112 const VkPhysicalDeviceMemoryProperties& pdmp = physicalDeviceMemProps.memoryProperties;
113 uint32_t supportedFlags = pdmp.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
114 if (supportedFlags == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
115 foundTypeIndex = i;
116 found = true;
117 break;
118 }
119 }
120 }
121 if (!found) {
122 ROSEN_LOGE("NativeBufferUtils: no fit memory type, memoryTypeBits is %{public}u", nbProps.memoryTypeBits);
123 vkContext.vkDestroyImage(device, image, nullptr);
124 return false;
125 }
126
127 VkImportNativeBufferInfoOHOS nbImportInfo;
128 nbImportInfo.sType = VK_STRUCTURE_TYPE_IMPORT_NATIVE_BUFFER_INFO_OHOS;
129 nbImportInfo.pNext = nullptr;
130 nbImportInfo.buffer = nativeBuffer;
131
132 VkMemoryDedicatedAllocateInfo dedicatedAllocInfo;
133 dedicatedAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
134 dedicatedAllocInfo.pNext = &nbImportInfo;
135 dedicatedAllocInfo.image = image;
136 dedicatedAllocInfo.buffer = VK_NULL_HANDLE;
137
138 VkMemoryAllocateInfo allocInfo = {
139 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, &dedicatedAllocInfo, nbProps.allocationSize, foundTypeIndex,
140 };
141
142 VkResult err = vkContext.vkAllocateMemory(device, &allocInfo, nullptr, memory);
143 if (err != VK_SUCCESS) {
144 vkContext.vkDestroyImage(device, image, nullptr);
145 ROSEN_LOGE("NativeBufferUtils: vkAllocateMemory Fail");
146 return false;
147 }
148 return true;
149 }
150
BindImageMemory(VkDevice device,const RsVulkanContext & vkContext,VkImage & image,VkDeviceMemory & memory)151 bool BindImageMemory(VkDevice device, const RsVulkanContext& vkContext, VkImage& image, VkDeviceMemory& memory)
152 {
153 VkBindImageMemoryInfo bindImageInfo;
154 bindImageInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
155 bindImageInfo.pNext = nullptr;
156 bindImageInfo.image = image;
157 bindImageInfo.memory = memory;
158 bindImageInfo.memoryOffset = 0;
159
160 VkResult err = vkContext.vkBindImageMemory2(device, 1, &bindImageInfo);
161 if (err != VK_SUCCESS) {
162 ROSEN_LOGE("NativeBufferUtils: vkBindImageMemory2 failed");
163 vkContext.vkDestroyImage(device, image, nullptr);
164 vkContext.vkFreeMemory(device, memory, nullptr);
165 return false;
166 }
167 return true;
168 }
169
170 #ifndef USE_ROSEN_DRAWING
MakeFromNativeWindowBuffer(sk_sp<GrDirectContext> skContext,NativeWindowBuffer * nativeWindowBuffer,NativeSurfaceInfo & nativeSurface,int width,int height)171 bool MakeFromNativeWindowBuffer(sk_sp<GrDirectContext> skContext, NativeWindowBuffer* nativeWindowBuffer,
172 NativeSurfaceInfo& nativeSurface, int width, int height)
173 #else
174 bool MakeFromNativeWindowBuffer(std::shared_ptr<Drawing::GPUContext> skContext, NativeWindowBuffer* nativeWindowBuffer,
175 NativeSurfaceInfo& nativeSurface, int width, int height)
176 #endif
177 {
178 OH_NativeBuffer* nativeBuffer = OH_NativeBufferFromNativeWindowBuffer(nativeWindowBuffer);
179 if (nativeBuffer == nullptr) {
180 ROSEN_LOGE("MakeFromNativeWindowBuffer: OH_NativeBufferFromNativeWindowBuffer failed");
181 return false;
182 }
183
184 auto const& vkContext = RsVulkanContext::GetSingleton();
185
186 VkDevice device = vkContext.GetDevice();
187
188 VkNativeBufferFormatPropertiesOHOS nbFormatProps;
189 VkNativeBufferPropertiesOHOS nbProps;
190 if (!GetNativeBufferFormatProperties(vkContext, device, nativeBuffer, &nbFormatProps, &nbProps)) {
191 return false;
192 }
193
194 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
195 if (nbFormatProps.format != VK_FORMAT_UNDEFINED) {
196 usageFlags = usageFlags | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT
197 | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
198 }
199
200 VkImage image;
201 if (!CreateVkImage(vkContext, &image, nbFormatProps, {width, height, 1}, usageFlags)) {
202 return false;
203 }
204
205 VkDeviceMemory memory;
206 if (!AllocateDeviceMemory(vkContext, &memory, image, nativeBuffer, nbProps)) {
207 return false;
208 }
209
210 if (!BindImageMemory(device, vkContext, image, memory)) {
211 return false;
212 }
213
214 auto skColorSpace = RenderContext::ConvertColorGamutToSkColorSpace(nativeSurface.graphicColorGamut);
215 #ifndef USE_ROSEN_DRAWING
216 GrVkImageInfo image_info;
217 image_info.fImage = image;
218 image_info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
219 image_info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
220 image_info.fFormat = nbFormatProps.format;
221 image_info.fImageUsageFlags = usageFlags;
222 image_info.fSampleCount = 1;
223 image_info.fLevelCount = 1;
224
225 GrBackendRenderTarget backend_render_target(width, height, 0, image_info);
226 SkSurfaceProps props(0, SkPixelGeometry::kUnknown_SkPixelGeometry);
227
228 SkColorType colorType = kRGBA_8888_SkColorType;
229
230 if (nbFormatProps.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32) {
231 colorType = kRGBA_1010102_SkColorType;
232 }
233
234 RSTagTracker tagTracker(skContext.get(), RSTagTracker::TAGTYPE::TAG_ACQUIRE_SURFACE);
235
236 nativeSurface.skSurface = SkSurface::MakeFromBackendRenderTarget(
237 skContext.get(), backend_render_target, kTopLeft_GrSurfaceOrigin, colorType,
238 skColorSpace, &props, DeleteVkImage, new VulkanCleanupHelper(RsVulkanContext::GetSingleton(),
239 image, memory));
240 #else
241 Drawing::TextureInfo texture_info;
242 texture_info.SetWidth(width);
243 texture_info.SetHeight(height);
244 std::shared_ptr<Drawing::VKTextureInfo> vkTextureInfo = std::make_shared<Drawing::VKTextureInfo>();
245 vkTextureInfo->vkImage = image;
246 vkTextureInfo->imageTiling = VK_IMAGE_TILING_OPTIMAL;
247 vkTextureInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
248 vkTextureInfo->format = nbFormatProps.format;
249 vkTextureInfo->imageUsageFlags = usageFlags;
250 vkTextureInfo->sampleCount = 1;
251 vkTextureInfo->levelCount = 1;
252 texture_info.SetVKTextureInfo(vkTextureInfo);
253
254 Drawing::ColorType colorType = Drawing::ColorType::COLORTYPE_RGBA_8888;
255 if (nbFormatProps.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32) {
256 colorType = Drawing::ColorType::COLORTYPE_RGBA_1010102;
257 }
258
259 auto skiaColorSpace = std::make_shared<Drawing::SkiaColorSpace>();
260 skiaColorSpace->SetColorSpace(skColorSpace);
261 auto colorSpace = Drawing::ColorSpace::CreateFromImpl(skiaColorSpace);
262 nativeSurface.drawingSurface = Drawing::Surface::MakeFromBackendTexture(
263 skContext.get(),
264 texture_info,
265 Drawing::TextureOrigin::TOP_LEFT,
266 1,
267 colorType,
268 colorSpace,
269 DeleteVkImage,
270 new VulkanCleanupHelper(RsVulkanContext::GetSingleton(),
271 image, memory));
272 #endif
273
274 nativeSurface.image = image;
275 if (nativeSurface.nativeWindowBuffer != nullptr) {
276 NativeObjectUnreference(nativeSurface.nativeWindowBuffer);
277 }
278 NativeObjectReference(nativeWindowBuffer);
279 nativeSurface.nativeWindowBuffer = nativeWindowBuffer;
280
281 return true;
282 }
283
GetYcbcrInfo(VkNativeBufferFormatPropertiesOHOS & nbFormatProps)284 GrVkYcbcrConversionInfo GetYcbcrInfo(VkNativeBufferFormatPropertiesOHOS& nbFormatProps)
285 {
286 GrVkYcbcrConversionInfo ycbcrInfo = {
287 .fFormat = nbFormatProps.format,
288 .fExternalFormat = nbFormatProps.externalFormat,
289 .fYcbcrModel = nbFormatProps.suggestedYcbcrModel,
290 .fYcbcrRange = nbFormatProps.suggestedYcbcrRange,
291 .fXChromaOffset = nbFormatProps.suggestedXChromaOffset,
292 .fYChromaOffset = nbFormatProps.suggestedYChromaOffset,
293 .fChromaFilter = VK_FILTER_NEAREST,
294 .fForceExplicitReconstruction = VK_FALSE,
295 .fFormatFeatures = nbFormatProps.formatFeatures
296 };
297
298 if (VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT & nbFormatProps.formatFeatures) {
299 ycbcrInfo.fChromaFilter = VK_FILTER_LINEAR;
300 }
301 return ycbcrInfo;
302 }
303
304 #ifndef USE_ROSEN_DRAWING
MakeBackendTextureFromNativeBuffer(NativeWindowBuffer * nativeWindowBuffer,int width,int height)305 GrBackendTexture MakeBackendTextureFromNativeBuffer(NativeWindowBuffer* nativeWindowBuffer,
306 int width, int height)
307 #else
308 Drawing::BackendTexture MakeBackendTextureFromNativeBuffer(NativeWindowBuffer* nativeWindowBuffer,
309 int width, int height)
310 #endif
311 {
312 OH_NativeBuffer* nativeBuffer = OH_NativeBufferFromNativeWindowBuffer(nativeWindowBuffer);
313 if (!nativeBuffer) {
314 ROSEN_LOGE("MakeBackendTextureFromNativeBuffer: OH_NativeBufferFromNativeWindowBuffer failed");
315 return {};
316 }
317
318 auto const& vkContext = RsVulkanContext::GetSingleton();
319 VkDevice device = vkContext.GetDevice();
320
321 VkNativeBufferFormatPropertiesOHOS nbFormatProps;
322 VkNativeBufferPropertiesOHOS nbProps;
323 if (!GetNativeBufferFormatProperties(vkContext, device, nativeBuffer, &nbFormatProps, &nbProps)) {
324 return {};
325 }
326
327 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
328 if (nbFormatProps.format != VK_FORMAT_UNDEFINED) {
329 usageFlags = usageFlags | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
330 }
331
332 VkImage image;
333 if (!CreateVkImage(vkContext, &image, nbFormatProps, {width, height, 1}, usageFlags)) {
334 return {};
335 }
336
337 VkDeviceMemory memory;
338 if (!AllocateDeviceMemory(vkContext, &memory, image, nativeBuffer, nbProps)) {
339 return {};
340 }
341
342 if (!BindImageMemory(device, vkContext, image, memory)) {
343 return {};
344 }
345
346 #ifndef USE_ROSEN_DRAWING
347 GrVkAlloc alloc;
348 alloc.fMemory = memory;
349 alloc.fOffset = nbProps.allocationSize;
350
351 GrVkImageInfo imageInfo;
352 imageInfo.fImage = image;
353 imageInfo.fAlloc = alloc;
354 imageInfo.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
355 imageInfo.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
356 imageInfo.fFormat = nbFormatProps.format;
357 imageInfo.fImageUsageFlags = usageFlags;
358 imageInfo.fLevelCount = 1;
359 imageInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
360 imageInfo.fYcbcrConversionInfo = GetYcbcrInfo(nbFormatProps);
361 imageInfo.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
362
363 return GrBackendTexture(width, height, imageInfo);
364 #else
365 Drawing::BackendTexture backendTexture(true);
366 Drawing::TextureInfo textureInfo;
367 textureInfo.SetWidth(width);
368 textureInfo.SetHeight(height);
369
370 std::shared_ptr<Drawing::VKTextureInfo> imageInfo = std::make_shared<Drawing::VKTextureInfo>();
371 imageInfo->vkImage = image;
372 imageInfo->vkAlloc.memory = memory;
373 imageInfo->vkAlloc.size = nbProps.allocationSize;
374 imageInfo->imageTiling = VK_IMAGE_TILING_OPTIMAL;
375 imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
376 imageInfo->format = nbFormatProps.format;
377 imageInfo->imageUsageFlags = usageFlags;
378 imageInfo->levelCount = 1;
379 imageInfo->currentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
380 imageInfo->ycbcrConversionInfo.format = nbFormatProps.format;
381 imageInfo->ycbcrConversionInfo.externalFormat = nbFormatProps.externalFormat;
382 imageInfo->ycbcrConversionInfo.ycbcrModel = nbFormatProps.suggestedYcbcrModel;
383 imageInfo->ycbcrConversionInfo.ycbcrRange = nbFormatProps.suggestedYcbcrRange;
384 imageInfo->ycbcrConversionInfo.xChromaOffset = nbFormatProps.suggestedXChromaOffset;
385 imageInfo->ycbcrConversionInfo.yChromaOffset = nbFormatProps.suggestedYChromaOffset;
386 imageInfo->ycbcrConversionInfo.chromaFilter = VK_FILTER_NEAREST;
387 imageInfo->ycbcrConversionInfo.forceExplicitReconstruction = VK_FALSE;
388 imageInfo->ycbcrConversionInfo.formatFeatures = nbFormatProps.formatFeatures;
389 if (VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT & nbFormatProps.formatFeatures) {
390 imageInfo->ycbcrConversionInfo.chromaFilter = VK_FILTER_LINEAR;
391 }
392 imageInfo->sharingMode = VK_SHARING_MODE_EXCLUSIVE;
393
394 textureInfo.SetVKTextureInfo(imageInfo);
395 backendTexture.SetTextureInfo(textureInfo);
396 return backendTexture;
397 #endif
398 }
399 } // namespace NativeBufferUtils
400 } // namespace OHOS::Rosen
401