• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright 2016 Google Inc.
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 "GrVkSampler.h"
9 
10 #include "GrVkGpu.h"
11 #include "GrVkSamplerYcbcrConversion.h"
12 
wrap_mode_to_vk_sampler_address(GrSamplerState::WrapMode wrapMode)13 static inline VkSamplerAddressMode wrap_mode_to_vk_sampler_address(
14         GrSamplerState::WrapMode wrapMode) {
15     switch (wrapMode) {
16         case GrSamplerState::WrapMode::kClamp:
17             return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
18         case GrSamplerState::WrapMode::kRepeat:
19             return VK_SAMPLER_ADDRESS_MODE_REPEAT;
20         case GrSamplerState::WrapMode::kMirrorRepeat:
21             return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
22         case GrSamplerState::WrapMode::kClampToBorder:
23             return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
24     }
25     SK_ABORT("Unknown wrap mode.");
26     return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
27 }
28 
Create(GrVkGpu * gpu,const GrSamplerState & samplerState,const GrVkYcbcrConversionInfo & ycbcrInfo)29 GrVkSampler* GrVkSampler::Create(GrVkGpu* gpu, const GrSamplerState& samplerState,
30                                  const GrVkYcbcrConversionInfo& ycbcrInfo) {
31     static VkFilter vkMinFilterModes[] = {
32         VK_FILTER_NEAREST,
33         VK_FILTER_LINEAR,
34         VK_FILTER_LINEAR
35     };
36     static VkFilter vkMagFilterModes[] = {
37         VK_FILTER_NEAREST,
38         VK_FILTER_LINEAR,
39         VK_FILTER_LINEAR
40     };
41 
42     VkSamplerCreateInfo createInfo;
43     memset(&createInfo, 0, sizeof(VkSamplerCreateInfo));
44     createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
45     createInfo.pNext = nullptr;
46     createInfo.flags = 0;
47     createInfo.magFilter = vkMagFilterModes[static_cast<int>(samplerState.filter())];
48     createInfo.minFilter = vkMinFilterModes[static_cast<int>(samplerState.filter())];
49     createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
50     createInfo.addressModeU = wrap_mode_to_vk_sampler_address(samplerState.wrapModeX());
51     createInfo.addressModeV = wrap_mode_to_vk_sampler_address(samplerState.wrapModeY());
52     createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; // Shouldn't matter
53     createInfo.mipLodBias = 0.0f;
54     createInfo.anisotropyEnable = VK_FALSE;
55     createInfo.maxAnisotropy = 1.0f;
56     createInfo.compareEnable = VK_FALSE;
57     createInfo.compareOp = VK_COMPARE_OP_NEVER;
58     // Vulkan doesn't have a direct mapping of GL's nearest or linear filters for minFilter since
59     // there is always a mipmapMode. To get the same effect as GL we can set minLod = maxLod = 0.0.
60     // This works since our min and mag filters are the same (this forces us to use mag on the 0
61     // level mip). If the filters weren't the same we could set min = 0 and max = 0.25 to force
62     // the minFilter on mip level 0.
63     createInfo.minLod = 0.0f;
64     bool useMipMaps = GrSamplerState::Filter::kMipMap == samplerState.filter();
65     createInfo.maxLod = !useMipMaps ? 0.0f : 10000.0f;
66     createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
67     createInfo.unnormalizedCoordinates = VK_FALSE;
68 
69     VkSamplerYcbcrConversionInfo conversionInfo;
70     GrVkSamplerYcbcrConversion* ycbcrConversion = nullptr;
71     if (ycbcrInfo.isValid()) {
72         SkASSERT(gpu->vkCaps().supportsYcbcrConversion());
73 
74         ycbcrConversion =
75                 gpu->resourceProvider().findOrCreateCompatibleSamplerYcbcrConversion(ycbcrInfo);
76         if (!ycbcrConversion) {
77             return nullptr;
78         }
79 
80         conversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
81         conversionInfo.pNext = nullptr;
82         conversionInfo.conversion = ycbcrConversion->ycbcrConversion();
83 
84         createInfo.pNext = &conversionInfo;
85 
86         const VkFormatFeatureFlags& flags = ycbcrInfo.fExternalFormatFeatures;
87 
88         if (!SkToBool(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT)) {
89             createInfo.magFilter = VK_FILTER_NEAREST;
90             createInfo.minFilter = VK_FILTER_NEAREST;
91         } else if (
92                 !(flags &
93                   VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT)) {
94             createInfo.magFilter = ycbcrInfo.fChromaFilter;
95             createInfo.minFilter = ycbcrInfo.fChromaFilter;
96         }
97 
98         // Required values when using ycbcr conversion
99         createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
100         createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
101         createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
102         createInfo.anisotropyEnable = VK_FALSE;
103         createInfo.unnormalizedCoordinates = VK_FALSE;
104     }
105 
106     VkSampler sampler;
107     GR_VK_CALL_ERRCHECK(gpu->vkInterface(), CreateSampler(gpu->device(),
108                                                           &createInfo,
109                                                           nullptr,
110                                                           &sampler));
111 
112     return new GrVkSampler(sampler, ycbcrConversion, GenerateKey(samplerState, ycbcrInfo));
113 }
114 
freeGPUData(GrVkGpu * gpu) const115 void GrVkSampler::freeGPUData(GrVkGpu* gpu) const {
116     SkASSERT(fSampler);
117     GR_VK_CALL(gpu->vkInterface(), DestroySampler(gpu->device(), fSampler, nullptr));
118     if (fYcbcrConversion) {
119         fYcbcrConversion->unref(gpu);
120     }
121 }
122 
abandonGPUData() const123 void GrVkSampler::abandonGPUData() const {
124     if (fYcbcrConversion) {
125         fYcbcrConversion->unrefAndAbandon();
126     }
127 }
128 
GenerateKey(const GrSamplerState & samplerState,const GrVkYcbcrConversionInfo & ycbcrInfo)129 GrVkSampler::Key GrVkSampler::GenerateKey(const GrSamplerState& samplerState,
130                                           const GrVkYcbcrConversionInfo& ycbcrInfo) {
131     const int kTileModeXShift = 2;
132     const int kTileModeYShift = 4;
133 
134     SkASSERT(static_cast<int>(samplerState.filter()) <= 3);
135     uint8_t samplerKey = static_cast<uint16_t>(samplerState.filter());
136 
137     SkASSERT(static_cast<int>(samplerState.wrapModeX()) <= 3);
138     samplerKey |= (static_cast<uint8_t>(samplerState.wrapModeX()) << kTileModeXShift);
139 
140     SkASSERT(static_cast<int>(samplerState.wrapModeY()) <= 3);
141     samplerKey |= (static_cast<uint8_t>(samplerState.wrapModeY()) << kTileModeYShift);
142 
143     return {samplerKey, GrVkSamplerYcbcrConversion::GenerateKey(ycbcrInfo)};
144 }
145 
146