| /* |
| * Copyright 2023 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "src/gpu/graphite/vk/VulkanSampler.h" |
| |
| #include "include/core/SkSamplingOptions.h" |
| #include "src/gpu/graphite/vk/VulkanCaps.h" |
| #include "src/gpu/graphite/vk/VulkanGraphiteUtilsPriv.h" |
| |
| namespace skgpu::graphite { |
| |
| VulkanSampler::VulkanSampler(const VulkanSharedContext* sharedContext, |
| const SamplerDesc& desc, |
| VkSampler sampler, |
| sk_sp<VulkanYcbcrConversion> ycbcrConversion) |
| : Sampler(sharedContext) |
| , fDesc(desc) |
| , fSampler(sampler) |
| , fYcbcrConversion(ycbcrConversion) {} |
| |
| static VkSamplerAddressMode tile_mode_to_vk_sampler_address(SkTileMode tileMode) { |
| switch (tileMode) { |
| case SkTileMode::kClamp: |
| return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; |
| case SkTileMode::kRepeat: |
| return VK_SAMPLER_ADDRESS_MODE_REPEAT; |
| case SkTileMode::kMirror: |
| return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; |
| case SkTileMode::kDecal: |
| return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; |
| } |
| SkUNREACHABLE; |
| } |
| |
| sk_sp<VulkanSampler> VulkanSampler::Make( |
| const VulkanSharedContext* sharedContext, |
| const SamplerDesc& desc, |
| sk_sp<VulkanYcbcrConversion> ycbcrConversion) { |
| VkSamplerCreateInfo samplerInfo; |
| memset(&samplerInfo, 0, sizeof(VkSamplerCreateInfo)); |
| samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; |
| |
| void* pNext = nullptr; |
| VkSamplerYcbcrConversionInfo conversionInfo; |
| if (ycbcrConversion) { |
| conversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO; |
| conversionInfo.pNext = nullptr; |
| conversionInfo.conversion = ycbcrConversion->ycbcrConversion(); |
| pNext = &conversionInfo; |
| } |
| |
| samplerInfo.pNext = pNext; |
| samplerInfo.flags = 0; |
| |
| VkFilter minMagFilter = [&] { |
| switch (desc.samplingOptions().filter) { |
| case SkFilterMode::kNearest: return VK_FILTER_NEAREST; |
| case SkFilterMode::kLinear: return VK_FILTER_LINEAR; |
| } |
| SkUNREACHABLE; |
| }(); |
| |
| VkSamplerMipmapMode mipmapMode = [&] { |
| switch (desc.samplingOptions().mipmap) { |
| // There is no disable mode. We use max level to disable mip mapping. |
| // It may make more sense to use NEAREST for kNone but Chrome pixel tests have |
| // been dependent on subtle rendering differences introduced by switching this. |
| case SkMipmapMode::kNone: return VK_SAMPLER_MIPMAP_MODE_LINEAR; |
| case SkMipmapMode::kNearest: return VK_SAMPLER_MIPMAP_MODE_NEAREST; |
| case SkMipmapMode::kLinear: return VK_SAMPLER_MIPMAP_MODE_LINEAR; |
| } |
| SkUNREACHABLE; |
| }(); |
| |
| samplerInfo.magFilter = minMagFilter; |
| samplerInfo.minFilter = minMagFilter; |
| samplerInfo.mipmapMode = mipmapMode; |
| samplerInfo.addressModeU = tile_mode_to_vk_sampler_address(desc.tileModeX()); |
| samplerInfo.addressModeV = tile_mode_to_vk_sampler_address(desc.tileModeY()); |
| samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; |
| samplerInfo.mipLodBias = 0; |
| samplerInfo.anisotropyEnable = VK_FALSE; |
| samplerInfo.maxAnisotropy = 1; // TODO: when we start using aniso, need to add to key |
| samplerInfo.compareEnable = VK_FALSE; |
| samplerInfo.compareOp = VK_COMPARE_OP_NEVER; |
| // Vulkan doesn't have a direct mapping to use nearest or linear filters for minFilter since |
| // there is always a mipmapMode. To get the same effect we can set minLod = maxLod = 0.0. |
| // This works since our min and mag filters are the same (this forces us to use mag on the 0 |
| // level mip). If the filters weren't the same we could set min = 0 and max = 0.25 to force |
| // the minFilter on mip level 0. |
| samplerInfo.minLod = 0; |
| samplerInfo.maxLod = (desc.samplingOptions().mipmap == SkMipmapMode::kNone) ? 0.0f |
| : VK_LOD_CLAMP_NONE; |
| samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; |
| samplerInfo.unnormalizedCoordinates = VK_FALSE; |
| |
| VkSampler sampler; |
| VkResult result; |
| VULKAN_CALL_RESULT(sharedContext, |
| result, |
| CreateSampler(sharedContext->device(), &samplerInfo, nullptr, &sampler)); |
| if (result != VK_SUCCESS) { |
| return nullptr; |
| } |
| |
| return sk_sp<VulkanSampler>(new VulkanSampler(sharedContext, |
| desc, |
| sampler, |
| std::move(ycbcrConversion))); |
| } |
| |
| void VulkanSampler::freeGpuData() { |
| const VulkanSharedContext* sharedContext = |
| static_cast<const VulkanSharedContext*>(this->sharedContext()); |
| SkASSERT(fSampler); |
| VULKAN_CALL(sharedContext->interface(), |
| DestroySampler(sharedContext->device(), fSampler, nullptr)); |
| fSampler = VK_NULL_HANDLE; |
| } |
| |
| } // namespace skgpu::graphite |
| |