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 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 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 115 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 123 void GrVkSampler::abandonGPUData() const { 124 if (fYcbcrConversion) { 125 fYcbcrConversion->unrefAndAbandon(); 126 } 127 } 128 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