• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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