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