Home | History | Annotate | Download | only in vk
      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