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