blob: c26f63a08f7eb86e36bb8d5a357d46e7bd102a57 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/ui/lib/escher/vk/sampler.h"
#include "src/ui/lib/escher/impl/vulkan_utils.h"
#include "src/ui/lib/escher/resources/resource_recycler.h"
#include "src/ui/lib/escher/util/image_utils.h"
#include "vulkan/vulkan.hpp"
namespace escher {
const ResourceTypeInfo Sampler::kTypeInfo("Sampler", ResourceType::kResource,
ResourceType::kSampler);
Sampler::Sampler(ResourceRecycler* resource_recycler, vk::Format format, vk::Filter filter,
bool use_unnormalized_coordinates)
: Resource(resource_recycler), is_immutable_(false) {
auto device = resource_recycler->vulkan_context().device;
// TODO(fxbug.dev/24595): eG8B8R82Plane420Unorm/eG8B8G8R8422Unorm is not enough to assume NV12,
// but they're currently the only formats we support at the sampler level.
if (image_utils::IsYuvFormat(format)) {
FX_DCHECK(resource_recycler->caps().allow_ycbcr);
// Check chroma filter support.
auto physical_device = resource_recycler->vulkan_context().physical_device;
auto format_properties = physical_device.getFormatProperties(format);
vk::SamplerYcbcrConversionCreateInfo ycbcr_create_info;
ycbcr_create_info.pNext = nullptr;
ycbcr_create_info.format = format;
ycbcr_create_info.ycbcrModel = vk::SamplerYcbcrModelConversion::eYcbcr709;
ycbcr_create_info.ycbcrRange = vk::SamplerYcbcrRange::eItuNarrow;
ycbcr_create_info.components = {
VK_COMPONENT_SWIZZLE_IDENTITY, // R
VK_COMPONENT_SWIZZLE_IDENTITY, // G
VK_COMPONENT_SWIZZLE_IDENTITY, // B
VK_COMPONENT_SWIZZLE_IDENTITY, // A
};
if (format_properties.optimalTilingFeatures &
vk::FormatFeatureFlagBits::eCositedChromaSamples) {
ycbcr_create_info.xChromaOffset = vk::ChromaLocation::eCositedEven;
ycbcr_create_info.yChromaOffset = vk::ChromaLocation::eCositedEven;
} else if (format_properties.optimalTilingFeatures &
vk::FormatFeatureFlagBits::eMidpointChromaSamples) {
ycbcr_create_info.xChromaOffset = vk::ChromaLocation::eMidpoint;
ycbcr_create_info.yChromaOffset = vk::ChromaLocation::eMidpoint;
} else {
FX_LOGS(ERROR) << "The potential features of format [" << vk::to_string(format) << "] don't "
<< "support eCositedChromaSamples or eMidpointChromaSamples!";
FX_NOTREACHED();
}
// If the chroma filter is not supported by the device, we would like to
// make it fall back to eNearest for YUV images.
if (filter == vk::Filter::eLinear &&
!(format_properties.optimalTilingFeatures &
vk::FormatFeatureFlagBits::eSampledImageYcbcrConversionLinearFilter)) {
FX_LOGS(INFO) << "The Vulkan physical device doesn't support linear filter on YCbCr images. "
<< "Set YCbCr chroma filter to eNearest as a fallback.";
ycbcr_create_info.chromaFilter = vk::Filter::eNearest;
// We would like to keep the choice of filter in VkSamplerCreateInfo for
// non-YUV images if it is supported by the device, otherwise we also make
// it fall back to eNearest.
if (!(format_properties.optimalTilingFeatures &
vk::FormatFeatureFlagBits::eSampledImageYcbcrConversionSeparateReconstructionFilter)) {
FX_LOGS(INFO) << "The Vulkan physical device cannot use separated reconstruction filters "
<< "for non-YUV images. Set non-YUV filters to eNearest.";
filter = vk::Filter::eNearest;
}
} else {
ycbcr_create_info.chromaFilter = filter;
}
ycbcr_create_info.forceExplicitReconstruction = VK_FALSE;
ycbcr_conversion_ = ESCHER_CHECKED_VK_RESULT(device.createSamplerYcbcrConversionKHR(
ycbcr_create_info, nullptr, resource_recycler->vulkan_context().loader));
is_immutable_ = true;
}
vk::SamplerCreateInfo sampler_info;
sampler_info.pNext = GetExtensionData();
sampler_info.magFilter = filter;
sampler_info.minFilter = filter;
sampler_info.anisotropyEnable = false;
sampler_info.maxAnisotropy = 1.0;
sampler_info.unnormalizedCoordinates = use_unnormalized_coordinates;
sampler_info.compareEnable = VK_FALSE;
sampler_info.compareOp = vk::CompareOp::eAlways;
sampler_info.mipLodBias = 0.0f;
sampler_info.minLod = 0.0f;
sampler_info.maxLod = 0.0f;
if (use_unnormalized_coordinates) {
sampler_info.mipmapMode = vk::SamplerMipmapMode::eNearest;
} else {
sampler_info.mipmapMode = vk::SamplerMipmapMode::eLinear;
}
sampler_info.addressModeU = vk::SamplerAddressMode::eClampToEdge;
sampler_info.addressModeV = vk::SamplerAddressMode::eClampToEdge;
sampler_info.addressModeW = vk::SamplerAddressMode::eClampToEdge;
sampler_ = ESCHER_CHECKED_VK_RESULT(vk_device().createSampler(sampler_info));
}
Sampler::~Sampler() {
if (is_immutable_) {
vk_device().destroySamplerYcbcrConversionKHR(ycbcr_conversion_.conversion, nullptr,
vulkan_context().loader);
}
vk_device().destroySampler(sampler_);
}
} // namespace escher