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