xref: /aosp_15_r20/external/skia/src/gpu/graphite/vk/VulkanSampler.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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