1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci* Copyright 2016 Google Inc. 3cb93a386Sopenharmony_ci* 4cb93a386Sopenharmony_ci* Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci* found in the LICENSE file. 6cb93a386Sopenharmony_ci*/ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkSampler.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkGpu.h" 11cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkSamplerYcbcrConversion.h" 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_cistatic VkSamplerAddressMode wrap_mode_to_vk_sampler_address(GrSamplerState::WrapMode wrapMode) { 14cb93a386Sopenharmony_ci switch (wrapMode) { 15cb93a386Sopenharmony_ci case GrSamplerState::WrapMode::kClamp: 16cb93a386Sopenharmony_ci return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 17cb93a386Sopenharmony_ci case GrSamplerState::WrapMode::kRepeat: 18cb93a386Sopenharmony_ci return VK_SAMPLER_ADDRESS_MODE_REPEAT; 19cb93a386Sopenharmony_ci case GrSamplerState::WrapMode::kMirrorRepeat: 20cb93a386Sopenharmony_ci return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; 21cb93a386Sopenharmony_ci case GrSamplerState::WrapMode::kClampToBorder: 22cb93a386Sopenharmony_ci return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; 23cb93a386Sopenharmony_ci } 24cb93a386Sopenharmony_ci SkUNREACHABLE; 25cb93a386Sopenharmony_ci} 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_cistatic VkSamplerMipmapMode mipmap_mode_to_vk_sampler_mipmap_mode(GrSamplerState::MipmapMode mm) { 28cb93a386Sopenharmony_ci switch (mm) { 29cb93a386Sopenharmony_ci // There is no disable mode. We use max level to disable mip mapping. 30cb93a386Sopenharmony_ci // It may make more sense to use NEAREST for kNone but Chrome pixel tests seam dependent 31cb93a386Sopenharmony_ci // on subtle rendering differences introduced by switching this. 32cb93a386Sopenharmony_ci case GrSamplerState::MipmapMode::kNone: return VK_SAMPLER_MIPMAP_MODE_LINEAR; 33cb93a386Sopenharmony_ci case GrSamplerState::MipmapMode::kNearest: return VK_SAMPLER_MIPMAP_MODE_NEAREST; 34cb93a386Sopenharmony_ci case GrSamplerState::MipmapMode::kLinear: return VK_SAMPLER_MIPMAP_MODE_LINEAR; 35cb93a386Sopenharmony_ci } 36cb93a386Sopenharmony_ci SkUNREACHABLE; 37cb93a386Sopenharmony_ci} 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ciGrVkSampler* GrVkSampler::Create(GrVkGpu* gpu, GrSamplerState samplerState, 40cb93a386Sopenharmony_ci const GrVkYcbcrConversionInfo& ycbcrInfo) { 41cb93a386Sopenharmony_ci static VkFilter vkMinFilterModes[] = { 42cb93a386Sopenharmony_ci VK_FILTER_NEAREST, 43cb93a386Sopenharmony_ci VK_FILTER_LINEAR, 44cb93a386Sopenharmony_ci VK_FILTER_LINEAR 45cb93a386Sopenharmony_ci }; 46cb93a386Sopenharmony_ci static VkFilter vkMagFilterModes[] = { 47cb93a386Sopenharmony_ci VK_FILTER_NEAREST, 48cb93a386Sopenharmony_ci VK_FILTER_LINEAR, 49cb93a386Sopenharmony_ci VK_FILTER_LINEAR 50cb93a386Sopenharmony_ci }; 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci VkSamplerCreateInfo createInfo; 53cb93a386Sopenharmony_ci memset(&createInfo, 0, sizeof(VkSamplerCreateInfo)); 54cb93a386Sopenharmony_ci createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; 55cb93a386Sopenharmony_ci createInfo.pNext = nullptr; 56cb93a386Sopenharmony_ci createInfo.flags = 0; 57cb93a386Sopenharmony_ci createInfo.magFilter = vkMagFilterModes[static_cast<int>(samplerState.filter())]; 58cb93a386Sopenharmony_ci createInfo.minFilter = vkMinFilterModes[static_cast<int>(samplerState.filter())]; 59cb93a386Sopenharmony_ci createInfo.mipmapMode = mipmap_mode_to_vk_sampler_mipmap_mode(samplerState.mipmapMode()); 60cb93a386Sopenharmony_ci createInfo.addressModeU = wrap_mode_to_vk_sampler_address(samplerState.wrapModeX()); 61cb93a386Sopenharmony_ci createInfo.addressModeV = wrap_mode_to_vk_sampler_address(samplerState.wrapModeY()); 62cb93a386Sopenharmony_ci createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; // Shouldn't matter 63cb93a386Sopenharmony_ci createInfo.mipLodBias = 0.0f; 64cb93a386Sopenharmony_ci createInfo.anisotropyEnable = VK_FALSE; 65cb93a386Sopenharmony_ci createInfo.maxAnisotropy = 1.0f; 66cb93a386Sopenharmony_ci createInfo.compareEnable = VK_FALSE; 67cb93a386Sopenharmony_ci createInfo.compareOp = VK_COMPARE_OP_NEVER; 68cb93a386Sopenharmony_ci // Vulkan doesn't have a direct mapping of GL's nearest or linear filters for minFilter since 69cb93a386Sopenharmony_ci // there is always a mipmapMode. To get the same effect as GL we can set minLod = maxLod = 0.0. 70cb93a386Sopenharmony_ci // This works since our min and mag filters are the same (this forces us to use mag on the 0 71cb93a386Sopenharmony_ci // level mip). If the filters weren't the same we could set min = 0 and max = 0.25 to force 72cb93a386Sopenharmony_ci // the minFilter on mip level 0. 73cb93a386Sopenharmony_ci createInfo.minLod = 0.0f; 74cb93a386Sopenharmony_ci bool useMipMaps = samplerState.mipmapped() == GrMipmapped::kYes; 75cb93a386Sopenharmony_ci createInfo.maxLod = !useMipMaps ? 0.0f : 10000.0f; 76cb93a386Sopenharmony_ci createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; 77cb93a386Sopenharmony_ci createInfo.unnormalizedCoordinates = VK_FALSE; 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci VkSamplerYcbcrConversionInfo conversionInfo; 80cb93a386Sopenharmony_ci GrVkSamplerYcbcrConversion* ycbcrConversion = nullptr; 81cb93a386Sopenharmony_ci if (ycbcrInfo.isValid()) { 82cb93a386Sopenharmony_ci SkASSERT(gpu->vkCaps().supportsYcbcrConversion()); 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ci ycbcrConversion = 85cb93a386Sopenharmony_ci gpu->resourceProvider().findOrCreateCompatibleSamplerYcbcrConversion(ycbcrInfo); 86cb93a386Sopenharmony_ci if (!ycbcrConversion) { 87cb93a386Sopenharmony_ci return nullptr; 88cb93a386Sopenharmony_ci } 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ci conversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO; 91cb93a386Sopenharmony_ci conversionInfo.pNext = nullptr; 92cb93a386Sopenharmony_ci conversionInfo.conversion = ycbcrConversion->ycbcrConversion(); 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci createInfo.pNext = &conversionInfo; 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci VkFormatFeatureFlags flags = ycbcrInfo.fFormatFeatures; 97cb93a386Sopenharmony_ci if (!SkToBool(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT)) { 98cb93a386Sopenharmony_ci createInfo.magFilter = VK_FILTER_NEAREST; 99cb93a386Sopenharmony_ci createInfo.minFilter = VK_FILTER_NEAREST; 100cb93a386Sopenharmony_ci } else if ( 101cb93a386Sopenharmony_ci !(flags & 102cb93a386Sopenharmony_ci VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT)) { 103cb93a386Sopenharmony_ci createInfo.magFilter = ycbcrInfo.fChromaFilter; 104cb93a386Sopenharmony_ci createInfo.minFilter = ycbcrInfo.fChromaFilter; 105cb93a386Sopenharmony_ci } 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci // Required values when using ycbcr conversion 108cb93a386Sopenharmony_ci createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 109cb93a386Sopenharmony_ci createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 110cb93a386Sopenharmony_ci createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 111cb93a386Sopenharmony_ci createInfo.anisotropyEnable = VK_FALSE; 112cb93a386Sopenharmony_ci createInfo.unnormalizedCoordinates = VK_FALSE; 113cb93a386Sopenharmony_ci } 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ci VkSampler sampler; 116cb93a386Sopenharmony_ci VkResult result; 117cb93a386Sopenharmony_ci GR_VK_CALL_RESULT(gpu, result, CreateSampler(gpu->device(), &createInfo, nullptr, &sampler)); 118cb93a386Sopenharmony_ci if (result != VK_SUCCESS) { 119cb93a386Sopenharmony_ci ycbcrConversion->unref(); 120cb93a386Sopenharmony_ci return nullptr; 121cb93a386Sopenharmony_ci } 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci return new GrVkSampler(gpu, sampler, ycbcrConversion, GenerateKey(samplerState, ycbcrInfo)); 124cb93a386Sopenharmony_ci} 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_civoid GrVkSampler::freeGPUData() const { 127cb93a386Sopenharmony_ci SkASSERT(fSampler); 128cb93a386Sopenharmony_ci GR_VK_CALL(fGpu->vkInterface(), DestroySampler(fGpu->device(), fSampler, nullptr)); 129cb93a386Sopenharmony_ci if (fYcbcrConversion) { 130cb93a386Sopenharmony_ci fYcbcrConversion->unref(); 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci} 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ciGrVkSampler::Key GrVkSampler::GenerateKey(GrSamplerState samplerState, 135cb93a386Sopenharmony_ci const GrVkYcbcrConversionInfo& ycbcrInfo) { 136cb93a386Sopenharmony_ci return {samplerState.asIndex(), GrVkSamplerYcbcrConversion::GenerateKey(ycbcrInfo)}; 137cb93a386Sopenharmony_ci} 138