1 /*
2 * Copyright 2023 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
8 #include "src/gpu/graphite/vk/VulkanSampler.h"
9
10 #include "include/core/SkSamplingOptions.h"
11 #include "src/gpu/graphite/vk/VulkanCaps.h"
12 #include "src/gpu/graphite/vk/VulkanGraphiteUtilsPriv.h"
13
14 namespace skgpu::graphite {
15
VulkanSampler(const VulkanSharedContext * sharedContext,const SamplerDesc & desc,VkSampler sampler,sk_sp<VulkanYcbcrConversion> ycbcrConversion)16 VulkanSampler::VulkanSampler(const VulkanSharedContext* sharedContext,
17 const SamplerDesc& desc,
18 VkSampler sampler,
19 sk_sp<VulkanYcbcrConversion> ycbcrConversion)
20 : Sampler(sharedContext)
21 , fDesc(desc)
22 , fSampler(sampler)
23 , fYcbcrConversion(ycbcrConversion) {}
24
tile_mode_to_vk_sampler_address(SkTileMode tileMode)25 static VkSamplerAddressMode tile_mode_to_vk_sampler_address(SkTileMode tileMode) {
26 switch (tileMode) {
27 case SkTileMode::kClamp:
28 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
29 case SkTileMode::kRepeat:
30 return VK_SAMPLER_ADDRESS_MODE_REPEAT;
31 case SkTileMode::kMirror:
32 return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
33 case SkTileMode::kDecal:
34 return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
35 }
36 SkUNREACHABLE;
37 }
38
Make(const VulkanSharedContext * sharedContext,const SamplerDesc & desc,sk_sp<VulkanYcbcrConversion> ycbcrConversion)39 sk_sp<VulkanSampler> VulkanSampler::Make(
40 const VulkanSharedContext* sharedContext,
41 const SamplerDesc& desc,
42 sk_sp<VulkanYcbcrConversion> ycbcrConversion) {
43 VkSamplerCreateInfo samplerInfo;
44 memset(&samplerInfo, 0, sizeof(VkSamplerCreateInfo));
45 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
46
47 void* pNext = nullptr;
48 VkSamplerYcbcrConversionInfo conversionInfo;
49 if (ycbcrConversion) {
50 conversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
51 conversionInfo.pNext = nullptr;
52 conversionInfo.conversion = ycbcrConversion->ycbcrConversion();
53 pNext = &conversionInfo;
54 }
55
56 samplerInfo.pNext = pNext;
57 samplerInfo.flags = 0;
58
59 VkFilter minMagFilter = [&] {
60 switch (desc.samplingOptions().filter) {
61 case SkFilterMode::kNearest: return VK_FILTER_NEAREST;
62 case SkFilterMode::kLinear: return VK_FILTER_LINEAR;
63 }
64 SkUNREACHABLE;
65 }();
66
67 VkSamplerMipmapMode mipmapMode = [&] {
68 switch (desc.samplingOptions().mipmap) {
69 // There is no disable mode. We use max level to disable mip mapping.
70 // It may make more sense to use NEAREST for kNone but Chrome pixel tests have
71 // been dependent on subtle rendering differences introduced by switching this.
72 case SkMipmapMode::kNone: return VK_SAMPLER_MIPMAP_MODE_LINEAR;
73 case SkMipmapMode::kNearest: return VK_SAMPLER_MIPMAP_MODE_NEAREST;
74 case SkMipmapMode::kLinear: return VK_SAMPLER_MIPMAP_MODE_LINEAR;
75 }
76 SkUNREACHABLE;
77 }();
78
79 samplerInfo.magFilter = minMagFilter;
80 samplerInfo.minFilter = minMagFilter;
81 samplerInfo.mipmapMode = mipmapMode;
82 samplerInfo.addressModeU = tile_mode_to_vk_sampler_address(desc.tileModeX());
83 samplerInfo.addressModeV = tile_mode_to_vk_sampler_address(desc.tileModeY());
84 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
85 samplerInfo.mipLodBias = 0;
86 samplerInfo.anisotropyEnable = VK_FALSE;
87 samplerInfo.maxAnisotropy = 1; // TODO: when we start using aniso, need to add to key
88 samplerInfo.compareEnable = VK_FALSE;
89 samplerInfo.compareOp = VK_COMPARE_OP_NEVER;
90 // Vulkan doesn't have a direct mapping to use nearest or linear filters for minFilter since
91 // there is always a mipmapMode. To get the same effect we can set minLod = maxLod = 0.0.
92 // This works since our min and mag filters are the same (this forces us to use mag on the 0
93 // level mip). If the filters weren't the same we could set min = 0 and max = 0.25 to force
94 // the minFilter on mip level 0.
95 samplerInfo.minLod = 0;
96 samplerInfo.maxLod = (desc.samplingOptions().mipmap == SkMipmapMode::kNone) ? 0.0f
97 : VK_LOD_CLAMP_NONE;
98 samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
99 samplerInfo.unnormalizedCoordinates = VK_FALSE;
100
101 VkSampler sampler;
102 VkResult result;
103 VULKAN_CALL_RESULT(sharedContext,
104 result,
105 CreateSampler(sharedContext->device(), &samplerInfo, nullptr, &sampler));
106 if (result != VK_SUCCESS) {
107 return nullptr;
108 }
109
110 return sk_sp<VulkanSampler>(new VulkanSampler(sharedContext,
111 desc,
112 sampler,
113 std::move(ycbcrConversion)));
114 }
115
freeGpuData()116 void VulkanSampler::freeGpuData() {
117 const VulkanSharedContext* sharedContext =
118 static_cast<const VulkanSharedContext*>(this->sharedContext());
119 SkASSERT(fSampler);
120 VULKAN_CALL(sharedContext->interface(),
121 DestroySampler(sharedContext->device(), fSampler, nullptr));
122 fSampler = VK_NULL_HANDLE;
123 }
124
125 } // namespace skgpu::graphite
126
127