Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
VulkanTexture.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
12#include "src/core/SkMipmap.h"
21
22namespace skgpu::graphite {
23
25 SkISize dimensions,
26 const TextureInfo& info,
27 CreatedImageInfo* outInfo) {
28 SkASSERT(outInfo);
29 const VulkanCaps& caps = sharedContext->vulkanCaps();
30
31 if (dimensions.isEmpty()) {
32 SKGPU_LOG_E("Tried to create VkImage with empty dimensions.");
33 return false;
34 }
35 if (dimensions.width() > caps.maxTextureSize() ||
36 dimensions.height() > caps.maxTextureSize()) {
37 SKGPU_LOG_E("Tried to create VkImage with too large a size.");
38 return false;
39 }
40
41 if ((info.isProtected() == Protected::kYes) != caps.protectedSupport()) {
42 SKGPU_LOG_E("Tried to create %s VkImage in %s Context.",
43 info.isProtected() == Protected::kYes ? "protected" : "unprotected",
44 caps.protectedSupport() ? "protected" : "unprotected");
45 return false;
46 }
47
48 const VulkanTextureSpec& spec = info.vulkanTextureSpec();
49
50 bool isLinear = spec.fImageTiling == VK_IMAGE_TILING_LINEAR;
51 VkImageLayout initialLayout = isLinear ? VK_IMAGE_LAYOUT_PREINITIALIZED
53
54 // Create Image
55 VkSampleCountFlagBits vkSamples;
56 if (!SampleCountToVkSampleCount(info.numSamples(), &vkSamples)) {
57 SKGPU_LOG_E("Failed creating VkImage because we could not covert the number of samples: "
58 "%u to a VkSampleCountFlagBits.", info.numSamples());
59 return false;
60 }
61
62 SkASSERT(!isLinear || vkSamples == VK_SAMPLE_COUNT_1_BIT);
63
64 VkImageCreateFlags createflags = 0;
65 if (info.isProtected() == Protected::kYes && caps.protectedSupport()) {
66 createflags |= VK_IMAGE_CREATE_PROTECTED_BIT;
67 }
68
69 uint32_t numMipLevels = 1;
70 if (info.mipmapped() == Mipmapped::kYes) {
72 }
73
74 uint32_t width = static_cast<uint32_t>(dimensions.fWidth);
75 uint32_t height = static_cast<uint32_t>(dimensions.fHeight);
76
77 const VkImageCreateInfo imageCreateInfo = {
79 nullptr, // pNext
80 createflags, // VkImageCreateFlags
81 VK_IMAGE_TYPE_2D, // VkImageType
82 spec.fFormat, // VkFormat
83 { width, height, 1 }, // VkExtent3D
84 numMipLevels, // mipLevels
85 1, // arrayLayers
86 vkSamples, // samples
87 spec.fImageTiling, // VkImageTiling
88 spec.fImageUsageFlags, // VkImageUsageFlags
89 spec.fSharingMode, // VkSharingMode
90 0, // queueFamilyCount
91 nullptr, // pQueueFamilyIndices
92 initialLayout // initialLayout
93 };
94
95 auto device = sharedContext->device();
96
97 VkImage image = VK_NULL_HANDLE;
100 sharedContext, result, CreateImage(device, &imageCreateInfo, nullptr, &image));
101 if (result != VK_SUCCESS) {
102 SKGPU_LOG_E("Failed call to vkCreateImage with error: %d", result);
103 return false;
104 }
105
106 auto allocator = sharedContext->memoryAllocator();
107 bool forceDedicatedMemory = caps.shouldAlwaysUseDedicatedImageMemory();
108 bool useLazyAllocation =
110
111 auto checkResult = [sharedContext](VkResult result) {
112 return sharedContext->checkVkResult(result);
113 };
115 image,
116 info.isProtected(),
117 forceDedicatedMemory,
118 useLazyAllocation,
119 checkResult,
120 &outInfo->fMemoryAlloc)) {
121 VULKAN_CALL(sharedContext->interface(), DestroyImage(device, image, nullptr));
122 return false;
123 }
124
125 if (useLazyAllocation &&
127 SKGPU_LOG_E("Failed allocate lazy vulkan memory when requested");
129 return false;
130 }
131
134 result,
135 BindImageMemory(
136 device, image, outInfo->fMemoryAlloc.fMemory, outInfo->fMemoryAlloc.fOffset));
137 if (result != VK_SUCCESS) {
139 VULKAN_CALL(sharedContext->interface(), DestroyImage(device, image, nullptr));
140 return false;
141 }
142
143 outInfo->fImage = image;
144 outInfo->fMutableState = sk_make_sp<MutableTextureState>(
146 return true;
147}
148
150 const VulkanResourceProvider* resourceProvider,
151 SkISize dimensions,
152 const TextureInfo& info,
153 skgpu::Budgeted budgeted) {
154 CreatedImageInfo imageInfo;
155 if (!MakeVkImage(sharedContext, dimensions, info, &imageInfo)) {
156 return nullptr;
157 }
158 auto ycbcrConversion = resourceProvider->findOrCreateCompatibleSamplerYcbcrConversion(
159 info.vulkanTextureSpec().fYcbcrConversionInfo);
160
163 info,
164 std::move(imageInfo.fMutableState),
165 imageInfo.fImage,
166 imageInfo.fMemoryAlloc,
168 budgeted,
169 std::move(ycbcrConversion)));
170}
171
173 const VulkanResourceProvider* resourceProvider,
174 SkISize dimensions,
175 const TextureInfo& info,
176 sk_sp<MutableTextureState> mutableState,
177 VkImage image,
178 const VulkanAlloc& alloc) {
179 auto ycbcrConversion = resourceProvider->findOrCreateCompatibleSamplerYcbcrConversion(
180 info.vulkanTextureSpec().fYcbcrConversionInfo);
181
184 info,
185 std::move(mutableState),
186 image,
187 alloc,
190 std::move(ycbcrConversion)));
191}
192
205
207 VkImageLayout newLayout,
208 VkAccessFlags dstAccessMask,
209 VkPipelineStageFlags dstStageMask,
210 bool byRegion,
211 uint32_t newQueueFamilyIndex) const {
212
213 SkASSERT(newLayout == this->currentLayout() ||
214 (VK_IMAGE_LAYOUT_UNDEFINED != newLayout &&
215 VK_IMAGE_LAYOUT_PREINITIALIZED != newLayout));
217 uint32_t currentQueueIndex = this->currentQueueFamilyIndex();
218
220 this->textureInfo().getVulkanTextureInfo(&textureInfo);
221 auto sharedContext = static_cast<const VulkanSharedContext*>(this->sharedContext());
222
223 // Enable the following block on new devices to test that their lazy images stay at 0 memory use
224#if 0
225 auto device = sharedContext->device();
226 if (fAlloc.fFlags & skgpu::VulkanAlloc::kLazilyAllocated_Flag) {
227 VkDeviceSize size;
228 VULKAN_CALL(sharedContext->interface(), GetDeviceMemoryCommitment(device, fAlloc.fMemory, &size));
229
230 SkDebugf("Lazy Image. This: %p, image: %d, size: %d\n", this, fImage, size);
231 }
232#endif
233#ifdef SK_DEBUG
234 if (textureInfo.fSharingMode == VK_SHARING_MODE_CONCURRENT) {
235 if (newQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED) {
236 SkASSERT(currentQueueIndex == VK_QUEUE_FAMILY_IGNORED ||
237 currentQueueIndex == VK_QUEUE_FAMILY_EXTERNAL ||
238 currentQueueIndex == VK_QUEUE_FAMILY_FOREIGN_EXT);
239 } else {
240 SkASSERT(newQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL ||
241 newQueueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT);
242 SkASSERT(currentQueueIndex == VK_QUEUE_FAMILY_IGNORED);
243 }
244 } else {
246 if (newQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED ||
247 currentQueueIndex == sharedContext->queueIndex()) {
248 SkASSERT(currentQueueIndex == VK_QUEUE_FAMILY_IGNORED ||
249 currentQueueIndex == VK_QUEUE_FAMILY_EXTERNAL ||
250 currentQueueIndex == VK_QUEUE_FAMILY_FOREIGN_EXT ||
251 currentQueueIndex == sharedContext->queueIndex());
252 } else if (newQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL ||
253 newQueueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT) {
254 SkASSERT(currentQueueIndex == VK_QUEUE_FAMILY_IGNORED ||
255 currentQueueIndex == sharedContext->queueIndex());
256 }
257 }
258#endif
259
260 if (textureInfo.fSharingMode == VK_SHARING_MODE_EXCLUSIVE) {
261 if (newQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED) {
262 newQueueFamilyIndex = sharedContext->queueIndex();
263 }
264 if (currentQueueIndex == VK_QUEUE_FAMILY_IGNORED) {
265 currentQueueIndex = sharedContext->queueIndex();
266 }
267 }
268
269 // If the old and new layout are the same and the layout is a read only layout, there is no need
270 // to put in a barrier unless we also need to switch queues.
271 if (newLayout == currentLayout && currentQueueIndex == newQueueFamilyIndex &&
275 return;
276 }
277
280
282 uint32_t numMipLevels = 1;
283 SkISize dimensions = this->dimensions();
284 if (this->mipmapped() == Mipmapped::kYes) {
286 }
287 VkImageMemoryBarrier imageMemoryBarrier = {
289 nullptr, // pNext
290 srcAccessMask, // srcAccessMask
291 dstAccessMask, // dstAccessMask
292 currentLayout, // oldLayout
293 newLayout, // newLayout
294 currentQueueIndex, // srcQueueFamilyIndex
295 newQueueFamilyIndex, // dstQueueFamilyIndex
296 fImage, // image
297 { aspectFlags, 0, numMipLevels, 0, 1 } // subresourceRange
298 };
299 SkASSERT(srcAccessMask == imageMemoryBarrier.srcAccessMask);
300 cmdBuffer->addImageMemoryBarrier(this, srcStageMask, dstStageMask, byRegion,
301 &imageMemoryBarrier);
302
305}
306
307VulkanTexture::VulkanTexture(const VulkanSharedContext* sharedContext,
308 SkISize dimensions,
309 const TextureInfo& info,
310 sk_sp<MutableTextureState> mutableState,
311 VkImage image,
312 const VulkanAlloc& alloc,
313 Ownership ownership,
314 skgpu::Budgeted budgeted,
316 : Texture(sharedContext, dimensions, info, std::move(mutableState), ownership, budgeted)
317 , fImage(image)
318 , fMemoryAlloc(alloc)
319 , fSamplerYcbcrConversion(std::move(ycbcrConversion)) {}
320
322 // Need to delete any ImageViews first
323 fImageViews.clear();
324
325 // If the texture is wrapped we don't own this data
326 if (this->ownership() != Ownership::kWrapped) {
327 auto sharedContext = static_cast<const VulkanSharedContext*>(this->sharedContext());
328 VULKAN_CALL(sharedContext->interface(),
329 DestroyImage(sharedContext->device(), fImage, nullptr));
330 skgpu::VulkanMemory::FreeImageMemory(sharedContext->memoryAllocator(), fMemoryAlloc);
331 }
332}
333
337
341
345
368
370 // Currently we assume we will never being doing any explict shader writes (this doesn't include
371 // color attachment or depth/stencil writes). So we will ignore the
372 // VK_MEMORY_OUTPUT_SHADER_WRITE_BIT.
373
374 // We can only directly access the host memory if we are in preinitialized or general layout,
375 // and the image is linear.
376 // TODO: Add check for linear here so we are not always adding host to general, and we should
377 // only be in preinitialized if we are linear
379 if (VK_IMAGE_LAYOUT_GENERAL == layout) {
384 } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
386 } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
390 } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
392 } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
395 // There are no writes that need to be made available
396 flags = 0;
397 }
398 return flags;
399}
400
402 for (int i = 0; i < fImageViews.size(); ++i) {
403 if (fImageViews[i]->usage() == usage) {
404 return fImageViews[i].get();
405 }
406 }
407
408 auto sharedContext = static_cast<const VulkanSharedContext*>(this->sharedContext());
409 VulkanTextureInfo vkTexInfo;
410 this->textureInfo().getVulkanTextureInfo(&vkTexInfo);
411 int miplevels = this->textureInfo().mipmapped() == Mipmapped::kYes
413 this->dimensions().height()) + 1
414 : 1;
415 auto imageView = VulkanImageView::Make(sharedContext,
416 fImage,
417 vkTexInfo.fFormat,
418 usage,
419 miplevels,
420 fSamplerYcbcrConversion);
421 return fImageViews.push_back(std::move(imageView)).get();
422}
423
424
425} // namespace skgpu::graphite
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
#define SKGPU_LOG_E(fmt,...)
Definition Log.h:38
#define SkASSERT(cond)
Definition SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
#define VULKAN_CALL(IFACE, X)
#define VULKAN_CALL_RESULT(SHARED_CONTEXT, RESULT, X)
static int ComputeLevelCount(int baseWidth, int baseHeight)
Definition SkMipmap.cpp:134
bool protectedSupport() const
Definition Caps.h:219
int maxTextureSize() const
Definition Caps.h:134
skgpu::Budgeted budgeted() const
Definition Resource.h:100
const SharedContext * sharedContext() const
Definition Resource.h:187
Ownership ownership() const
Definition Resource.h:98
Mipmapped mipmapped() const
Definition TextureInfo.h:79
Mipmapped mipmapped() const
Definition Texture.h:29
SkISize dimensions() const
Definition Texture.h:31
MutableTextureState * mutableState() const
Definition Texture.cpp:49
const TextureInfo & textureInfo() const
Definition Texture.h:32
bool shouldAlwaysUseDedicatedImageMemory() const
Definition VulkanCaps.h:69
void addImageMemoryBarrier(const Resource *, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, bool byRegion, VkImageMemoryBarrier *barrier)
static std::unique_ptr< const VulkanImageView > Make(const VulkanSharedContext *sharedContext, VkImage image, VkFormat format, Usage usage, uint32_t miplevels, sk_sp< VulkanSamplerYcbcrConversion >)
sk_sp< VulkanSamplerYcbcrConversion > findOrCreateCompatibleSamplerYcbcrConversion(const VulkanYcbcrConversionInfo &ycbcrInfo) const
void updateImageLayout(VkImageLayout)
uint32_t currentQueueFamilyIndex() const
void setImageLayoutAndQueueIndex(VulkanCommandBuffer *, VkImageLayout newLayout, VkAccessFlags dstAccessMask, VkPipelineStageFlags dstStageMask, bool byRegion, uint32_t newQueueFamilyIndex) const
static sk_sp< Texture > Make(const VulkanSharedContext *, const VulkanResourceProvider *, SkISize dimensions, const TextureInfo &, skgpu::Budgeted)
static VkAccessFlags LayoutToSrcAccessMask(const VkImageLayout layout)
static bool MakeVkImage(const VulkanSharedContext *, SkISize dimensions, const TextureInfo &, CreatedImageInfo *outInfo)
static VkPipelineStageFlags LayoutToPipelineSrcStageFlags(const VkImageLayout layout)
static sk_sp< Texture > MakeWrapped(const VulkanSharedContext *, const VulkanResourceProvider *, SkISize dimensions, const TextureInfo &, sk_sp< MutableTextureState >, VkImage, const VulkanAlloc &)
VkImageLayout currentLayout() const
const VulkanImageView * getImageView(VulkanImageView::Usage) const
VkDevice device
Definition main.cc:53
sk_sp< SkImage > image
Definition examples.cpp:29
FlutterSemanticsFlag flags
GAsyncResult * result
uint32_t uint32_t * format
void SetVkImageLayout(MutableTextureState *state, VkImageLayout layout)
SK_API uint32_t GetVkQueueFamilyIndex(const MutableTextureState &state)
SK_API MutableTextureState MakeVulkan(VkImageLayout layout, uint32_t queueFamilyIndex)
void SetVkQueueFamilyIndex(MutableTextureState *state, uint32_t queueFamilyIndex)
SK_API VkImageLayout GetVkImageLayout(const MutableTextureState &state)
void FreeImageMemory(VulkanMemoryAllocator *, const VulkanAlloc &alloc)
bool AllocImageMemory(VulkanMemoryAllocator *, VkImage image, skgpu::Protected isProtected, bool forceDedicatedMemory, bool useLazyAllocation, const std::function< CheckResult > &, VulkanAlloc *alloc)
VkImageAspectFlags vk_format_to_aspect_flags(VkFormat format)
Budgeted
Definition GpuTypes.h:35
static constexpr bool SampleCountToVkSampleCount(uint32_t samples, VkSampleCountFlagBits *vkSamples)
Definition ref_ptr.h:256
int32_t height
int32_t width
static void usage(char *argv0)
bool isEmpty() const
Definition SkSize.h:31
int32_t fHeight
Definition SkSize.h:18
int32_t fWidth
Definition SkSize.h:17
constexpr int32_t width() const
Definition SkSize.h:36
constexpr int32_t height() const
Definition SkSize.h:37
VkAccessFlags srcAccessMask
VkDeviceMemory fMemory
Definition VulkanTypes.h:38
VkDeviceSize fOffset
Definition VulkanTypes.h:39
VkFlags VkPipelineStageFlags
VkImageLayout
@ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
@ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
@ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
@ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
@ VK_IMAGE_LAYOUT_PREINITIALIZED
@ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
@ VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
@ VK_IMAGE_LAYOUT_UNDEFINED
@ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
@ VK_IMAGE_LAYOUT_GENERAL
@ VK_SHARING_MODE_CONCURRENT
@ VK_SHARING_MODE_EXCLUSIVE
VkFlags VkImageAspectFlags
VkFlags VkAccessFlags
uint64_t VkDeviceSize
Definition vulkan_core.h:96
@ VK_IMAGE_CREATE_PROTECTED_BIT
@ VK_IMAGE_TILING_LINEAR
@ VK_IMAGE_ASPECT_COLOR_BIT
@ VK_IMAGE_ASPECT_STENCIL_BIT
@ VK_IMAGE_ASPECT_DEPTH_BIT
@ VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
VkSampleCountFlagBits
@ VK_SAMPLE_COUNT_1_BIT
#define VK_QUEUE_FAMILY_FOREIGN_EXT
@ VK_IMAGE_TYPE_2D
VkFlags VkImageCreateFlags
VkResult
@ VK_SUCCESS
@ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
@ VK_ACCESS_TRANSFER_WRITE_BIT
@ VK_ACCESS_HOST_WRITE_BIT
@ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
#define VK_NULL_HANDLE
Definition vulkan_core.h:46
#define VK_QUEUE_FAMILY_EXTERNAL
VkFormat
@ VK_FORMAT_D24_UNORM_S8_UINT
@ VK_FORMAT_S8_UINT
@ VK_FORMAT_D32_SFLOAT_S8_UINT
@ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
@ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
@ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
@ VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
@ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
@ VK_PIPELINE_STAGE_HOST_BIT
@ VK_PIPELINE_STAGE_TRANSFER_BIT
#define VK_QUEUE_FAMILY_IGNORED
@ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
@ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER