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