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