Add support for Ycbcr Conversion Samplers in vulkan.
The only thing missing from this CL is that we need to bake the ycbcr conversion samplers into the VkPipeline when we create it. As that is a larger change, that will be broken up into a few follow on CLs. Currently this only supports ycbcr conversion samplers when used with external textures. Bug: skia: Change-Id: I23e95b19469093072589ebbbfb7926ab79dcdea9 Reviewed-on: https://skia-review.googlesource.com/c/164602 Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Jim Van Verth <jvanverth@google.com> Commit-Queue: Greg Daniel <egdaniel@google.com>
This commit is contained in:
parent
cf37ede8b3
commit
6cd74900da
@ -635,6 +635,8 @@ skia_vk_sources = [
|
||||
"$_src/gpu/vk/GrVkResourceProvider.h",
|
||||
"$_src/gpu/vk/GrVkSampler.cpp",
|
||||
"$_src/gpu/vk/GrVkSampler.h",
|
||||
"$_src/gpu/vk/GrVkSamplerYcbcrConversion.cpp",
|
||||
"$_src/gpu/vk/GrVkSamplerYcbcrConversion.h",
|
||||
"$_src/gpu/vk/GrVkSemaphore.cpp",
|
||||
"$_src/gpu/vk/GrVkSemaphore.h",
|
||||
"$_src/gpu/vk/GrVkStencilAttachment.cpp",
|
||||
|
@ -48,9 +48,14 @@ public:
|
||||
}
|
||||
|
||||
static GrBackendFormat MakeVk(VkFormat format) {
|
||||
return GrBackendFormat(format);
|
||||
return GrBackendFormat(format, GrVkYcbcrConversionInfo());
|
||||
}
|
||||
|
||||
// This is used for external textures and the VkFormat is assumed to be VK_FORMAT_UNDEFINED.
|
||||
// This call is only supported on Android since the GrVkYcbcrConvesionInfo contains an android
|
||||
// external format.
|
||||
static GrBackendFormat MakeVk(const GrVkYcbcrConversionInfo& ycbcrInfo);
|
||||
|
||||
#ifdef SK_METAL
|
||||
static GrBackendFormat MakeMtl(GrMTLPixelFormat format) {
|
||||
return GrBackendFormat(format);
|
||||
@ -73,6 +78,8 @@ public:
|
||||
// it returns nullptr
|
||||
const VkFormat* getVkFormat() const;
|
||||
|
||||
const GrVkYcbcrConversionInfo* getVkYcbcrConversionInfo() const;
|
||||
|
||||
#ifdef SK_METAL
|
||||
// If the backend API is Metal, this returns a pointer to a GrMTLPixelFormat. Otherwise
|
||||
// it returns nullptr
|
||||
@ -92,7 +99,7 @@ public:
|
||||
private:
|
||||
GrBackendFormat(GrGLenum format, GrGLenum target);
|
||||
|
||||
GrBackendFormat(const VkFormat vkFormat);
|
||||
GrBackendFormat(const VkFormat vkFormat, const GrVkYcbcrConversionInfo&);
|
||||
|
||||
#ifdef SK_METAL
|
||||
GrBackendFormat(const GrMTLPixelFormat mtlFormat);
|
||||
@ -105,7 +112,10 @@ private:
|
||||
|
||||
union {
|
||||
GrGLenum fGLFormat; // the sized, internal format of the GL resource
|
||||
VkFormat fVkFormat;
|
||||
struct {
|
||||
VkFormat fFormat;
|
||||
GrVkYcbcrConversionInfo fYcbcrConversionInfo;
|
||||
} fVk;
|
||||
#ifdef SK_METAL
|
||||
GrMTLPixelFormat fMtlFormat;
|
||||
#endif
|
||||
|
@ -64,14 +64,73 @@ private:
|
||||
friend class GrVkHeap; // For access to usesSystemHeap
|
||||
bool fUsesSystemHeap;
|
||||
};
|
||||
|
||||
// This struct is used to pass in the necessary information to create a VkSamplerYcbcrConversion
|
||||
// object for an VkExternalFormatANDROID.
|
||||
struct GrVkYcbcrConversionInfo {
|
||||
GrVkYcbcrConversionInfo()
|
||||
: fYcbcrModel(VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY)
|
||||
, fYcbcrRange(VK_SAMPLER_YCBCR_RANGE_ITU_FULL)
|
||||
, fXChromaOffset(VK_CHROMA_LOCATION_COSITED_EVEN)
|
||||
, fYChromaOffset(VK_CHROMA_LOCATION_COSITED_EVEN)
|
||||
, fChromaFilter(VK_FILTER_NEAREST)
|
||||
, fForceExplicitReconstruction(false)
|
||||
, fExternalFormat(0)
|
||||
, fExternalFormatFeatures(0) {}
|
||||
|
||||
GrVkYcbcrConversionInfo(VkSamplerYcbcrModelConversion ycbcrModel,
|
||||
VkSamplerYcbcrRange ycbcrRange,
|
||||
VkChromaLocation xChromaOffset,
|
||||
VkChromaLocation yChromaOffset,
|
||||
VkFilter chromaFilter,
|
||||
VkBool32 forceExplicitReconstruction,
|
||||
uint64_t externalFormat,
|
||||
VkFormatFeatureFlags externalFormatFeatures)
|
||||
: fYcbcrModel(ycbcrModel)
|
||||
, fYcbcrRange(ycbcrRange)
|
||||
, fXChromaOffset(xChromaOffset)
|
||||
, fYChromaOffset(yChromaOffset)
|
||||
, fChromaFilter(chromaFilter)
|
||||
, fForceExplicitReconstruction(forceExplicitReconstruction)
|
||||
, fExternalFormat(externalFormat)
|
||||
, fExternalFormatFeatures(externalFormatFeatures) {}
|
||||
|
||||
bool operator==(const GrVkYcbcrConversionInfo& that) const {
|
||||
return this->fYcbcrModel == that.fYcbcrModel &&
|
||||
this->fYcbcrRange == that.fYcbcrRange &&
|
||||
this->fXChromaOffset == that.fXChromaOffset &&
|
||||
this->fYChromaOffset == that.fYChromaOffset &&
|
||||
this->fChromaFilter == that.fChromaFilter &&
|
||||
this->fForceExplicitReconstruction == that.fForceExplicitReconstruction &&
|
||||
this->fExternalFormat == that.fExternalFormat;
|
||||
// We don't check fExternalFormatFeatures here since all matching external formats must have
|
||||
// the same format features at least in terms of how they effect ycbcr sampler conversion.
|
||||
}
|
||||
|
||||
bool isValid() const { return fExternalFormat != 0; }
|
||||
|
||||
VkSamplerYcbcrModelConversion fYcbcrModel;
|
||||
VkSamplerYcbcrRange fYcbcrRange;
|
||||
VkChromaLocation fXChromaOffset;
|
||||
VkChromaLocation fYChromaOffset;
|
||||
VkFilter fChromaFilter;
|
||||
VkBool32 fForceExplicitReconstruction;
|
||||
// The external format should be compatible to be used in a VkExternalFormatANDROID struct
|
||||
uint64_t fExternalFormat;
|
||||
// The format features here should be those returned by a call to
|
||||
// vkAndroidHardwareBufferFormatPropertiesANDROID
|
||||
VkFormatFeatureFlags fExternalFormatFeatures;
|
||||
};
|
||||
|
||||
struct GrVkImageInfo {
|
||||
VkImage fImage;
|
||||
GrVkAlloc fAlloc;
|
||||
VkImageTiling fImageTiling;
|
||||
VkImageLayout fImageLayout;
|
||||
VkFormat fFormat;
|
||||
uint32_t fLevelCount;
|
||||
uint32_t fCurrentQueueFamily;
|
||||
VkImage fImage;
|
||||
GrVkAlloc fAlloc;
|
||||
VkImageTiling fImageTiling;
|
||||
VkImageLayout fImageLayout;
|
||||
VkFormat fFormat;
|
||||
uint32_t fLevelCount;
|
||||
uint32_t fCurrentQueueFamily;
|
||||
GrVkYcbcrConversionInfo fYcbcrConversionInfo;
|
||||
|
||||
GrVkImageInfo()
|
||||
: fImage(VK_NULL_HANDLE)
|
||||
@ -80,18 +139,21 @@ struct GrVkImageInfo {
|
||||
, fImageLayout(VK_IMAGE_LAYOUT_UNDEFINED)
|
||||
, fFormat(VK_FORMAT_UNDEFINED)
|
||||
, fLevelCount(0)
|
||||
, fCurrentQueueFamily(VK_QUEUE_FAMILY_IGNORED) {}
|
||||
, fCurrentQueueFamily(VK_QUEUE_FAMILY_IGNORED)
|
||||
, fYcbcrConversionInfo() {}
|
||||
|
||||
GrVkImageInfo(VkImage image, GrVkAlloc alloc, VkImageTiling imageTiling, VkImageLayout layout,
|
||||
VkFormat format, uint32_t levelCount,
|
||||
uint32_t currentQueueFamily = VK_QUEUE_FAMILY_IGNORED)
|
||||
uint32_t currentQueueFamily = VK_QUEUE_FAMILY_IGNORED,
|
||||
GrVkYcbcrConversionInfo ycbcrConversionInfo = GrVkYcbcrConversionInfo())
|
||||
: fImage(image)
|
||||
, fAlloc(alloc)
|
||||
, fImageTiling(imageTiling)
|
||||
, fImageLayout(layout)
|
||||
, fFormat(format)
|
||||
, fLevelCount(levelCount)
|
||||
, fCurrentQueueFamily(currentQueueFamily) {}
|
||||
, fCurrentQueueFamily(currentQueueFamily)
|
||||
, fYcbcrConversionInfo(ycbcrConversionInfo) {}
|
||||
|
||||
GrVkImageInfo(const GrVkImageInfo& info, VkImageLayout layout)
|
||||
: fImage(info.fImage)
|
||||
@ -100,7 +162,8 @@ struct GrVkImageInfo {
|
||||
, fImageLayout(layout)
|
||||
, fFormat(info.fFormat)
|
||||
, fLevelCount(info.fLevelCount)
|
||||
, fCurrentQueueFamily(info.fCurrentQueueFamily) {}
|
||||
, fCurrentQueueFamily(info.fCurrentQueueFamily)
|
||||
, fYcbcrConversionInfo(info.fYcbcrConversionInfo) {}
|
||||
|
||||
// This gives a way for a client to update the layout of the Image if they change the layout
|
||||
// while we're still holding onto the wrapped texture. They will first need to get a handle
|
||||
@ -110,7 +173,9 @@ struct GrVkImageInfo {
|
||||
bool operator==(const GrVkImageInfo& that) const {
|
||||
return fImage == that.fImage && fAlloc == that.fAlloc &&
|
||||
fImageTiling == that.fImageTiling && fImageLayout == that.fImageLayout &&
|
||||
fFormat == that.fFormat && fLevelCount == that.fLevelCount;
|
||||
fFormat == that.fFormat && fLevelCount == that.fLevelCount &&
|
||||
fCurrentQueueFamily == that.fCurrentQueueFamily &&
|
||||
fYcbcrConversionInfo == that.fYcbcrConversionInfo;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -63,20 +63,36 @@ const GrGLenum* GrBackendFormat::getGLTarget() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GrBackendFormat::GrBackendFormat(VkFormat vkFormat)
|
||||
GrBackendFormat GrBackendFormat::MakeVk(const GrVkYcbcrConversionInfo& ycbcrInfo) {
|
||||
#ifdef SK_BUILD_FOR_ANDROID
|
||||
return GrBackendFormat(VK_FORMAT_UNDEFINED, ycbcrInfo);
|
||||
#else
|
||||
return GrBackendFormat();
|
||||
#endif
|
||||
}
|
||||
|
||||
GrBackendFormat::GrBackendFormat(VkFormat vkFormat, const GrVkYcbcrConversionInfo& ycbcrInfo)
|
||||
: fBackend(GrBackendApi::kVulkan)
|
||||
#ifdef SK_VULKAN
|
||||
, fValid(true)
|
||||
#else
|
||||
, fValid(false)
|
||||
#endif
|
||||
, fVkFormat(vkFormat)
|
||||
, fTextureType(GrTextureType::k2D) {
|
||||
fVk.fFormat = vkFormat;
|
||||
fVk.fYcbcrConversionInfo = ycbcrInfo;
|
||||
}
|
||||
|
||||
const VkFormat* GrBackendFormat::getVkFormat() const {
|
||||
if (this->isValid() && GrBackendApi::kVulkan == fBackend) {
|
||||
return &fVkFormat;
|
||||
return &fVk.fFormat;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const GrVkYcbcrConversionInfo* GrBackendFormat::getVkYcbcrConversionInfo() const {
|
||||
if (this->isValid() && GrBackendApi::kVulkan == fBackend) {
|
||||
return &fVk.fYcbcrConversionInfo;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -194,6 +194,27 @@ bool GrVkCaps::canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* s
|
||||
srcConfig, SkToBool(src->asTextureProxy()));
|
||||
}
|
||||
|
||||
template<typename T> T* get_extension_feature_struct(const VkPhysicalDeviceFeatures2& features,
|
||||
VkStructureType type) {
|
||||
// All Vulkan structs that could be part of the features chain will start with the
|
||||
// structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
|
||||
// so we can get access to the pNext for the next struct.
|
||||
struct CommonVulkanHeader {
|
||||
VkStructureType sType;
|
||||
void* pNext;
|
||||
};
|
||||
|
||||
void* pNext = features.pNext;
|
||||
while (pNext) {
|
||||
CommonVulkanHeader* header = static_cast<CommonVulkanHeader*>(pNext);
|
||||
if (header->sType == type) {
|
||||
return static_cast<T*>(pNext);
|
||||
}
|
||||
pNext = header->pNext;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GrVkCaps::init(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface,
|
||||
VkPhysicalDevice physDev, const VkPhysicalDeviceFeatures2& features,
|
||||
const GrVkExtensions& extensions) {
|
||||
@ -263,6 +284,24 @@ void GrVkCaps::init(const GrContextOptions& contextOptions, const GrVkInterface*
|
||||
}
|
||||
#endif
|
||||
|
||||
auto ycbcrFeatures =
|
||||
get_extension_feature_struct<VkPhysicalDeviceSamplerYcbcrConversionFeatures>(
|
||||
features,
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES);
|
||||
if (ycbcrFeatures && ycbcrFeatures->samplerYcbcrConversion &&
|
||||
fSupportsAndroidHWBExternalMemory &&
|
||||
(physicalDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
|
||||
(extensions.hasExtension(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, 1) &&
|
||||
this->supportsMaintenance1() &&
|
||||
this->supportsBindMemory2() &&
|
||||
this->supportsMemoryRequirements2() &&
|
||||
this->supportsPhysicalDeviceProperties2()))) {
|
||||
fSupportsYcbcrConversion = true;
|
||||
}
|
||||
// We always push back the default GrVkYcbcrConversionInfo so that the case of no conversion
|
||||
// will return a key of 0.
|
||||
fYcbcrInfos.push_back(GrVkYcbcrConversionInfo());
|
||||
|
||||
this->initGrCaps(vkInterface, physDev, properties, memoryProperties, features, extensions);
|
||||
this->initShaderCaps(properties, features);
|
||||
|
||||
@ -376,27 +415,6 @@ int get_max_sample_count(VkSampleCountFlags flags) {
|
||||
return 64;
|
||||
}
|
||||
|
||||
template<typename T> T* get_extension_feature_struct(const VkPhysicalDeviceFeatures2& features,
|
||||
VkStructureType type) {
|
||||
// All Vulkan structs that could be part of the features chain will start with the
|
||||
// structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
|
||||
// so we can get access to the pNext for the next struct.
|
||||
struct CommonVulkanHeader {
|
||||
VkStructureType sType;
|
||||
void* pNext;
|
||||
};
|
||||
|
||||
void* pNext = features.pNext;
|
||||
while (pNext) {
|
||||
CommonVulkanHeader* header = static_cast<CommonVulkanHeader*>(pNext);
|
||||
if (header->sType == type) {
|
||||
return static_cast<T*>(pNext);
|
||||
}
|
||||
pNext = header->pNext;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GrVkCaps::initGrCaps(const GrVkInterface* vkInterface,
|
||||
VkPhysicalDevice physDev,
|
||||
const VkPhysicalDeviceProperties& properties,
|
||||
@ -828,6 +846,10 @@ GrBackendFormat GrVkCaps::onCreateFormatFromBackendTexture(
|
||||
const GrBackendTexture& backendTex) const {
|
||||
GrVkImageInfo vkInfo;
|
||||
SkAssertResult(backendTex.getVkImageInfo(&vkInfo));
|
||||
if (vkInfo.fYcbcrConversionInfo.isValid()) {
|
||||
SkASSERT(vkInfo.fFormat == VK_FORMAT_UNDEFINED);
|
||||
return GrBackendFormat::MakeVk(vkInfo.fYcbcrConversionInfo);
|
||||
}
|
||||
return GrBackendFormat::MakeVk(vkInfo.fFormat);
|
||||
}
|
||||
|
||||
|
@ -130,6 +130,9 @@ public:
|
||||
// Returns true if the device supports importing Android hardware buffers into Vulkan memory.
|
||||
bool supportsAndroidHWBExternalMemory() const { return fSupportsAndroidHWBExternalMemory; }
|
||||
|
||||
// Returns true if it supports ycbcr conversion for samplers
|
||||
bool supportsYcbcrConversion() const { return fSupportsYcbcrConversion; }
|
||||
|
||||
/**
|
||||
* Helpers used by canCopySurface. In all cases if the SampleCnt parameter is zero that means
|
||||
* the surface is not a render target, otherwise it is the number of samples in the render
|
||||
@ -194,6 +197,8 @@ private:
|
||||
void initConfigTable(const GrVkInterface*, VkPhysicalDevice, const VkPhysicalDeviceProperties&);
|
||||
void initStencilFormat(const GrVkInterface* iface, VkPhysicalDevice physDev);
|
||||
|
||||
uint8_t getYcbcrKeyFromYcbcrInfo(const GrVkYcbcrConversionInfo& info);
|
||||
|
||||
void applyDriverCorrectnessWorkarounds(const VkPhysicalDeviceProperties&);
|
||||
|
||||
struct ConfigInfo {
|
||||
@ -221,6 +226,8 @@ private:
|
||||
|
||||
StencilFormat fPreferredStencilFormat;
|
||||
|
||||
SkSTArray<1, GrVkYcbcrConversionInfo> fYcbcrInfos;
|
||||
|
||||
bool fMustDoCopiesFromOrigin = false;
|
||||
bool fMustSubmitCommandsBeforeCopyOp = false;
|
||||
bool fMustSleepOnTearDown = false;
|
||||
@ -238,6 +245,8 @@ private:
|
||||
bool fSupportsExternalMemory = false;
|
||||
bool fSupportsAndroidHWBExternalMemory = false;
|
||||
|
||||
bool fSupportsYcbcrConversion = false;
|
||||
|
||||
typedef GrCaps INHERITED;
|
||||
};
|
||||
|
||||
|
@ -261,7 +261,8 @@ bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu,
|
||||
|
||||
GrSamplerState samplerState = GrSamplerState::ClampNearest();
|
||||
|
||||
GrVkSampler* sampler = resourceProv.findOrCreateCompatibleSampler(samplerState);
|
||||
GrVkSampler* sampler = resourceProv.findOrCreateCompatibleSampler(
|
||||
samplerState, GrVkYcbcrConversionInfo());
|
||||
|
||||
VkDescriptorImageInfo imageInfo;
|
||||
memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
|
||||
|
@ -870,15 +870,17 @@ bool GrVkGpu::updateBuffer(GrVkBuffer* buffer, const void* src,
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool check_backend_texture(const GrBackendTexture& backendTex,
|
||||
GrPixelConfig config) {
|
||||
GrVkImageInfo info;
|
||||
if (!backendTex.getVkImageInfo(&info)) {
|
||||
static bool check_image_info(const GrVkCaps& caps,
|
||||
const GrVkImageInfo& info,
|
||||
GrPixelConfig config) {
|
||||
if (VK_NULL_HANDLE == info.fImage || VK_NULL_HANDLE == info.fAlloc.fMemory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (VK_NULL_HANDLE == info.fImage || VK_NULL_HANDLE == info.fAlloc.fMemory) {
|
||||
return false;
|
||||
if (info.fYcbcrConversionInfo.isValid()) {
|
||||
if (!caps.supportsYcbcrConversion() || info.fFormat != VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SkASSERT(GrVkFormatPixelConfigPairIsValid(info.fFormat, config));
|
||||
@ -887,7 +889,12 @@ static bool check_backend_texture(const GrBackendTexture& backendTex,
|
||||
|
||||
sk_sp<GrTexture> GrVkGpu::onWrapBackendTexture(const GrBackendTexture& backendTex,
|
||||
GrWrapOwnership ownership, bool purgeImmediately) {
|
||||
if (!check_backend_texture(backendTex, backendTex.config())) {
|
||||
GrVkImageInfo imageInfo;
|
||||
if (!backendTex.getVkImageInfo(&imageInfo)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!check_image_info(this->vkCaps(), imageInfo, backendTex.config())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -898,10 +905,6 @@ sk_sp<GrTexture> GrVkGpu::onWrapBackendTexture(const GrBackendTexture& backendTe
|
||||
surfDesc.fConfig = backendTex.config();
|
||||
surfDesc.fSampleCnt = 1;
|
||||
|
||||
GrVkImageInfo imageInfo;
|
||||
if (!backendTex.getVkImageInfo(&imageInfo)) {
|
||||
return nullptr;
|
||||
}
|
||||
sk_sp<GrVkImageLayout> layout = backendTex.getGrVkImageLayout();
|
||||
SkASSERT(layout);
|
||||
return GrVkTexture::MakeWrappedTexture(this, surfDesc, ownership, purgeImmediately,
|
||||
@ -911,7 +914,12 @@ sk_sp<GrTexture> GrVkGpu::onWrapBackendTexture(const GrBackendTexture& backendTe
|
||||
sk_sp<GrTexture> GrVkGpu::onWrapRenderableBackendTexture(const GrBackendTexture& backendTex,
|
||||
int sampleCnt,
|
||||
GrWrapOwnership ownership) {
|
||||
if (!check_backend_texture(backendTex, backendTex.config())) {
|
||||
GrVkImageInfo imageInfo;
|
||||
if (!backendTex.getVkImageInfo(&imageInfo)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!check_image_info(this->vkCaps(), imageInfo, backendTex.config())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -922,10 +930,6 @@ sk_sp<GrTexture> GrVkGpu::onWrapRenderableBackendTexture(const GrBackendTexture&
|
||||
surfDesc.fConfig = backendTex.config();
|
||||
surfDesc.fSampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config());
|
||||
|
||||
GrVkImageInfo imageInfo;
|
||||
if (!backendTex.getVkImageInfo(&imageInfo)) {
|
||||
return nullptr;
|
||||
}
|
||||
sk_sp<GrVkImageLayout> layout = backendTex.getGrVkImageLayout();
|
||||
SkASSERT(layout);
|
||||
|
||||
|
@ -48,6 +48,7 @@ public:
|
||||
return GrBackendFormat::MakeVk(this->imageFormat());
|
||||
}
|
||||
uint32_t mipLevels() const { return fInfo.fLevelCount; }
|
||||
GrVkYcbcrConversionInfo ycbcrConversionInfo() const { return fInfo.fYcbcrConversionInfo; }
|
||||
const Resource* resource() const { return fResource; }
|
||||
bool isLinearTiled() const {
|
||||
return SkToBool(VK_IMAGE_TILING_LINEAR == fInfo.fImageTiling);
|
||||
|
@ -7,16 +7,37 @@
|
||||
|
||||
#include "GrVkImageView.h"
|
||||
#include "GrVkGpu.h"
|
||||
#include "GrVkSamplerYcbcrConversion.h"
|
||||
#include "GrVkUtil.h"
|
||||
|
||||
const GrVkImageView* GrVkImageView::Create(const GrVkGpu* gpu, VkImage image, VkFormat format,
|
||||
Type viewType, uint32_t miplevels) {
|
||||
VkImageView imageView;
|
||||
const GrVkImageView* GrVkImageView::Create(GrVkGpu* gpu, VkImage image, VkFormat format,
|
||||
Type viewType, uint32_t miplevels,
|
||||
const GrVkYcbcrConversionInfo& ycbcrInfo) {
|
||||
|
||||
void* pNext = nullptr;
|
||||
VkSamplerYcbcrConversionInfo conversionInfo;
|
||||
GrVkSamplerYcbcrConversion* ycbcrConversion = nullptr;
|
||||
|
||||
if (ycbcrInfo.isValid()) {
|
||||
SkASSERT(gpu->vkCaps().supportsYcbcrConversion() && format == VK_FORMAT_UNDEFINED);
|
||||
|
||||
ycbcrConversion =
|
||||
gpu->resourceProvider().findOrCreateCompatibleSamplerYcbcrConversion(ycbcrInfo);
|
||||
if (!ycbcrConversion) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
conversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
|
||||
conversionInfo.pNext = nullptr;
|
||||
conversionInfo.conversion = ycbcrConversion->ycbcrConversion();
|
||||
pNext = &conversionInfo;
|
||||
}
|
||||
|
||||
VkImageView imageView;
|
||||
// Create the VkImageView
|
||||
VkImageViewCreateInfo viewInfo = {
|
||||
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType
|
||||
NULL, // pNext
|
||||
pNext, // pNext
|
||||
0, // flags
|
||||
image, // image
|
||||
VK_IMAGE_VIEW_TYPE_2D, // viewType
|
||||
@ -37,9 +58,20 @@ const GrVkImageView* GrVkImageView::Create(const GrVkGpu* gpu, VkImage image, Vk
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new GrVkImageView(imageView);
|
||||
return new GrVkImageView(imageView, ycbcrConversion);
|
||||
}
|
||||
|
||||
void GrVkImageView::freeGPUData(const GrVkGpu* gpu) const {
|
||||
GR_VK_CALL(gpu->vkInterface(), DestroyImageView(gpu->device(), fImageView, nullptr));
|
||||
|
||||
if (fYcbcrConversion) {
|
||||
fYcbcrConversion->unref(gpu);
|
||||
}
|
||||
}
|
||||
|
||||
void GrVkImageView::abandonGPUData() const {
|
||||
if (fYcbcrConversion) {
|
||||
fYcbcrConversion->unrefAndAbandon();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,9 @@
|
||||
#include "GrTypes.h"
|
||||
#include "GrVkResource.h"
|
||||
|
||||
class GrVkSamplerYcbcrConversion;
|
||||
struct GrVkYcbcrConversionInfo;
|
||||
|
||||
class GrVkImageView : public GrVkResource {
|
||||
public:
|
||||
enum Type {
|
||||
@ -20,8 +23,9 @@ public:
|
||||
kStencil_Type
|
||||
};
|
||||
|
||||
static const GrVkImageView* Create(const GrVkGpu* gpu, VkImage image, VkFormat format,
|
||||
Type viewType, uint32_t miplevels);
|
||||
static const GrVkImageView* Create(GrVkGpu* gpu, VkImage image, VkFormat format,
|
||||
Type viewType, uint32_t miplevels,
|
||||
const GrVkYcbcrConversionInfo& ycbcrInfo);
|
||||
|
||||
VkImageView imageView() const { return fImageView; }
|
||||
|
||||
@ -32,14 +36,17 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
GrVkImageView(VkImageView imageView) : INHERITED(), fImageView(imageView) {}
|
||||
GrVkImageView(VkImageView imageView, GrVkSamplerYcbcrConversion* ycbcrConversion)
|
||||
: INHERITED(), fImageView(imageView), fYcbcrConversion(ycbcrConversion) {}
|
||||
|
||||
GrVkImageView(const GrVkImageView&);
|
||||
GrVkImageView& operator=(const GrVkImageView&);
|
||||
|
||||
void freeGPUData(const GrVkGpu* gpu) const override;
|
||||
void abandonGPUData() const override;
|
||||
|
||||
VkImageView fImageView;
|
||||
GrVkSamplerYcbcrConversion* fYcbcrConversion;
|
||||
|
||||
typedef GrVkResource INHERITED;
|
||||
};
|
||||
|
@ -243,7 +243,8 @@ void GrVkPipelineState::setAndBindTextures(GrVkGpu* gpu,
|
||||
GrVkTexture* texture = samplerBindings[i].fTexture;
|
||||
|
||||
const GrVkImageView* textureView = texture->textureView();
|
||||
GrVkSampler* sampler = gpu->resourceProvider().findOrCreateCompatibleSampler(state);
|
||||
GrVkSampler* sampler = gpu->resourceProvider().findOrCreateCompatibleSampler(
|
||||
state, texture->ycbcrConversionInfo());
|
||||
|
||||
VkDescriptorImageInfo imageInfo;
|
||||
memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
|
||||
|
@ -148,7 +148,8 @@ GrVkRenderTarget::MakeWrappedRenderTarget(GrVkGpu* gpu,
|
||||
|
||||
// Create Resolve attachment view
|
||||
resolveAttachmentView = GrVkImageView::Create(gpu, info.fImage, pixelFormat,
|
||||
GrVkImageView::kColor_Type, 1);
|
||||
GrVkImageView::kColor_Type, 1,
|
||||
GrVkYcbcrConversionInfo());
|
||||
if (!resolveAttachmentView) {
|
||||
GrVkImage::DestroyImageInfo(gpu, &msInfo);
|
||||
return nullptr;
|
||||
@ -161,7 +162,8 @@ GrVkRenderTarget::MakeWrappedRenderTarget(GrVkGpu* gpu,
|
||||
|
||||
// Get color attachment view
|
||||
const GrVkImageView* colorAttachmentView = GrVkImageView::Create(gpu, colorImage, pixelFormat,
|
||||
GrVkImageView::kColor_Type, 1);
|
||||
GrVkImageView::kColor_Type, 1,
|
||||
GrVkYcbcrConversionInfo());
|
||||
if (!colorAttachmentView) {
|
||||
if (desc.fSampleCnt > 1) {
|
||||
resolveAttachmentView->unref(gpu);
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "GrVkGpu.h"
|
||||
#include "GrVkPipeline.h"
|
||||
#include "GrVkRenderTarget.h"
|
||||
#include "GrVkSampler.h"
|
||||
#include "GrVkUniformBuffer.h"
|
||||
#include "GrVkUtil.h"
|
||||
|
||||
@ -166,10 +165,14 @@ GrVkDescriptorPool* GrVkResourceProvider::findOrCreateCompatibleDescriptorPool(
|
||||
return new GrVkDescriptorPool(fGpu, type, count);
|
||||
}
|
||||
|
||||
GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(const GrSamplerState& params) {
|
||||
GrVkSampler* sampler = fSamplers.find(GrVkSampler::GenerateKey(params));
|
||||
GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(
|
||||
const GrSamplerState& params, const GrVkYcbcrConversionInfo& ycbcrInfo) {
|
||||
GrVkSampler* sampler = fSamplers.find(GrVkSampler::GenerateKey(params, ycbcrInfo));
|
||||
if (!sampler) {
|
||||
sampler = GrVkSampler::Create(fGpu, params);
|
||||
sampler = GrVkSampler::Create(fGpu, params, ycbcrInfo);
|
||||
if (!sampler) {
|
||||
return nullptr;
|
||||
}
|
||||
fSamplers.add(sampler);
|
||||
}
|
||||
SkASSERT(sampler);
|
||||
@ -177,6 +180,22 @@ GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(const GrSampler
|
||||
return sampler;
|
||||
}
|
||||
|
||||
GrVkSamplerYcbcrConversion* GrVkResourceProvider::findOrCreateCompatibleSamplerYcbcrConversion(
|
||||
const GrVkYcbcrConversionInfo& ycbcrInfo) {
|
||||
GrVkSamplerYcbcrConversion* ycbcrConversion =
|
||||
fYcbcrConversions.find(GrVkSamplerYcbcrConversion::GenerateKey(ycbcrInfo));
|
||||
if (!ycbcrConversion) {
|
||||
ycbcrConversion = GrVkSamplerYcbcrConversion::Create(fGpu, ycbcrInfo);
|
||||
if (!ycbcrConversion) {
|
||||
return nullptr;
|
||||
}
|
||||
fYcbcrConversions.add(ycbcrConversion);
|
||||
}
|
||||
SkASSERT(ycbcrConversion);
|
||||
ycbcrConversion->ref();
|
||||
return ycbcrConversion;
|
||||
}
|
||||
|
||||
GrVkPipelineState* GrVkResourceProvider::findOrCreateCompatiblePipelineState(
|
||||
const GrPipeline& pipeline, const GrPrimitiveProcessor& proc, GrPrimitiveType primitiveType,
|
||||
VkRenderPass compatibleRenderPass) {
|
||||
@ -349,7 +368,7 @@ void GrVkResourceProvider::destroyResources(bool deviceLost) {
|
||||
fRenderPassArray.reset();
|
||||
|
||||
// Iterate through all store GrVkSamplers and unref them before resetting the hash.
|
||||
SkTDynamicHash<GrVkSampler, uint8_t>::Iter iter(&fSamplers);
|
||||
SkTDynamicHash<GrVkSampler, GrVkSampler::Key>::Iter iter(&fSamplers);
|
||||
for (; !iter.done(); ++iter) {
|
||||
(*iter).unref(fGpu);
|
||||
}
|
||||
@ -408,7 +427,7 @@ void GrVkResourceProvider::abandonResources() {
|
||||
fRenderPassArray.reset();
|
||||
|
||||
// Iterate through all store GrVkSamplers and unrefAndAbandon them before resetting the hash.
|
||||
SkTDynamicHash<GrVkSampler, uint8_t>::Iter iter(&fSamplers);
|
||||
SkTDynamicHash<GrVkSampler, GrVkSampler::Key>::Iter iter(&fSamplers);
|
||||
for (; !iter.done(); ++iter) {
|
||||
(*iter).unrefAndAbandon();
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include "GrVkPipelineStateBuilder.h"
|
||||
#include "GrVkRenderPass.h"
|
||||
#include "GrVkResource.h"
|
||||
#include "GrVkSampler.h"
|
||||
#include "GrVkSamplerYcbcrConversion.h"
|
||||
#include "GrVkUtil.h"
|
||||
#include "SkLRUCache.h"
|
||||
#include "SkTArray.h"
|
||||
@ -31,7 +33,6 @@ class GrVkPipeline;
|
||||
class GrVkPipelineState;
|
||||
class GrVkPrimaryCommandBuffer;
|
||||
class GrVkRenderTarget;
|
||||
class GrVkSampler;
|
||||
class GrVkSecondaryCommandBuffer;
|
||||
class GrVkUniformHandler;
|
||||
|
||||
@ -97,9 +98,15 @@ public:
|
||||
// of our cache of GrVkDescriptorPools.
|
||||
GrVkDescriptorPool* findOrCreateCompatibleDescriptorPool(VkDescriptorType type, uint32_t count);
|
||||
|
||||
// Finds or creates a compatible GrVkSampler based on the GrSamplerState.
|
||||
// The refcount is incremented and a pointer returned.
|
||||
GrVkSampler* findOrCreateCompatibleSampler(const GrSamplerState&);
|
||||
// Finds or creates a compatible GrVkSampler based on the GrSamplerState and
|
||||
// GrVkYcbcrConversionInfo. The refcount is incremented and a pointer returned.
|
||||
GrVkSampler* findOrCreateCompatibleSampler(const GrSamplerState&,
|
||||
const GrVkYcbcrConversionInfo& ycbcrInfo);
|
||||
|
||||
// Finds or creates a compatible GrVkSamplerYcbcrConversion based on the GrSamplerState and
|
||||
// GrVkYcbcrConversionInfo. The refcount is incremented and a pointer returned.
|
||||
GrVkSamplerYcbcrConversion* findOrCreateCompatibleSamplerYcbcrConversion(
|
||||
const GrVkYcbcrConversionInfo& ycbcrInfo);
|
||||
|
||||
GrVkPipelineState* findOrCreateCompatiblePipelineState(const GrPipeline&,
|
||||
const GrPrimitiveProcessor&,
|
||||
@ -252,7 +259,10 @@ private:
|
||||
|
||||
// Stores GrVkSampler objects that we've already created so we can reuse them across multiple
|
||||
// GrVkPipelineStates
|
||||
SkTDynamicHash<GrVkSampler, uint8_t> fSamplers;
|
||||
SkTDynamicHash<GrVkSampler, GrVkSampler::Key> fSamplers;
|
||||
|
||||
// Stores GrVkSamplerYcbcrConversion objects that we've already created so we can reuse them.
|
||||
SkTDynamicHash<GrVkSamplerYcbcrConversion, GrVkSamplerYcbcrConversion::Key> fYcbcrConversions;
|
||||
|
||||
// Cache of GrVkPipelineStates
|
||||
PipelineStateCache* fPipelineStateCache;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "GrVkSampler.h"
|
||||
|
||||
#include "GrVkGpu.h"
|
||||
#include "GrVkSamplerYcbcrConversion.h"
|
||||
|
||||
static inline VkSamplerAddressMode wrap_mode_to_vk_sampler_address(
|
||||
GrSamplerState::WrapMode wrapMode) {
|
||||
@ -23,7 +24,8 @@ static inline VkSamplerAddressMode wrap_mode_to_vk_sampler_address(
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
}
|
||||
|
||||
GrVkSampler* GrVkSampler::Create(const GrVkGpu* gpu, const GrSamplerState& samplerState) {
|
||||
GrVkSampler* GrVkSampler::Create(GrVkGpu* gpu, const GrSamplerState& samplerState,
|
||||
const GrVkYcbcrConversionInfo& ycbcrInfo) {
|
||||
static VkFilter vkMinFilterModes[] = {
|
||||
VK_FILTER_NEAREST,
|
||||
VK_FILTER_LINEAR,
|
||||
@ -38,7 +40,7 @@ GrVkSampler* GrVkSampler::Create(const GrVkGpu* gpu, const GrSamplerState& sampl
|
||||
VkSamplerCreateInfo createInfo;
|
||||
memset(&createInfo, 0, sizeof(VkSamplerCreateInfo));
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
createInfo.pNext = 0;
|
||||
createInfo.pNext = nullptr;
|
||||
createInfo.flags = 0;
|
||||
createInfo.magFilter = vkMagFilterModes[static_cast<int>(samplerState.filter())];
|
||||
createInfo.minFilter = vkMinFilterModes[static_cast<int>(samplerState.filter())];
|
||||
@ -62,32 +64,80 @@ GrVkSampler* GrVkSampler::Create(const GrVkGpu* gpu, const GrSamplerState& sampl
|
||||
createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||
createInfo.unnormalizedCoordinates = VK_FALSE;
|
||||
|
||||
VkSamplerYcbcrConversionInfo conversionInfo;
|
||||
GrVkSamplerYcbcrConversion* ycbcrConversion = nullptr;
|
||||
if (ycbcrInfo.isValid()) {
|
||||
SkASSERT(gpu->vkCaps().supportsYcbcrConversion());
|
||||
|
||||
ycbcrConversion =
|
||||
gpu->resourceProvider().findOrCreateCompatibleSamplerYcbcrConversion(ycbcrInfo);
|
||||
if (!ycbcrConversion) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
conversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
|
||||
conversionInfo.pNext = nullptr;
|
||||
conversionInfo.conversion = ycbcrConversion->ycbcrConversion();
|
||||
|
||||
createInfo.pNext = &conversionInfo;
|
||||
|
||||
const VkFormatFeatureFlags& flags = ycbcrInfo.fExternalFormatFeatures;
|
||||
|
||||
if (!SkToBool(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT)) {
|
||||
createInfo.magFilter = VK_FILTER_NEAREST;
|
||||
createInfo.minFilter = VK_FILTER_NEAREST;
|
||||
} else if (
|
||||
!(flags &
|
||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT)) {
|
||||
createInfo.magFilter = ycbcrInfo.fChromaFilter;
|
||||
createInfo.minFilter = ycbcrInfo.fChromaFilter;
|
||||
}
|
||||
|
||||
// Required values when using ycbcr conversion
|
||||
createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
createInfo.anisotropyEnable = VK_FALSE;
|
||||
createInfo.unnormalizedCoordinates = VK_FALSE;
|
||||
}
|
||||
|
||||
VkSampler sampler;
|
||||
GR_VK_CALL_ERRCHECK(gpu->vkInterface(), CreateSampler(gpu->device(),
|
||||
&createInfo,
|
||||
nullptr,
|
||||
&sampler));
|
||||
|
||||
return new GrVkSampler(sampler, GenerateKey(samplerState));
|
||||
return new GrVkSampler(sampler, ycbcrConversion, GenerateKey(samplerState, ycbcrInfo));
|
||||
}
|
||||
|
||||
void GrVkSampler::freeGPUData(const GrVkGpu* gpu) const {
|
||||
SkASSERT(fSampler);
|
||||
GR_VK_CALL(gpu->vkInterface(), DestroySampler(gpu->device(), fSampler, nullptr));
|
||||
if (fYcbcrConversion) {
|
||||
fYcbcrConversion->unref(gpu);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t GrVkSampler::GenerateKey(const GrSamplerState& samplerState) {
|
||||
void GrVkSampler::abandonGPUData() const {
|
||||
if (fYcbcrConversion) {
|
||||
fYcbcrConversion->unrefAndAbandon();
|
||||
}
|
||||
}
|
||||
|
||||
GrVkSampler::Key GrVkSampler::GenerateKey(const GrSamplerState& samplerState,
|
||||
const GrVkYcbcrConversionInfo& ycbcrInfo) {
|
||||
const int kTileModeXShift = 2;
|
||||
const int kTileModeYShift = 4;
|
||||
|
||||
SkASSERT(static_cast<int>(samplerState.filter()) <= 3);
|
||||
uint8_t key = static_cast<uint8_t>(samplerState.filter());
|
||||
uint8_t samplerKey = static_cast<uint16_t>(samplerState.filter());
|
||||
|
||||
SkASSERT(static_cast<int>(samplerState.wrapModeX()) <= 3);
|
||||
key |= (static_cast<uint8_t>(samplerState.wrapModeX()) << kTileModeXShift);
|
||||
samplerKey |= (static_cast<uint8_t>(samplerState.wrapModeX()) << kTileModeXShift);
|
||||
|
||||
SkASSERT(static_cast<int>(samplerState.wrapModeY()) <= 3);
|
||||
key |= (static_cast<uint8_t>(samplerState.wrapModeY()) << kTileModeYShift);
|
||||
samplerKey |= (static_cast<uint8_t>(samplerState.wrapModeY()) << kTileModeYShift);
|
||||
|
||||
return key;
|
||||
return {samplerKey, GrVkSamplerYcbcrConversion::GenerateKey(ycbcrInfo)};
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrVkSampler_DEFINED
|
||||
#define GrVkSampler_DEFINED
|
||||
@ -11,22 +11,43 @@
|
||||
#include "GrVkVulkan.h"
|
||||
|
||||
#include "GrVkResource.h"
|
||||
#include "GrVkSamplerYcbcrConversion.h"
|
||||
#include "SkOpts.h"
|
||||
#include "vk/GrVkTypes.h"
|
||||
|
||||
class GrSamplerState;
|
||||
class GrVkGpu;
|
||||
|
||||
|
||||
class GrVkSampler : public GrVkResource {
|
||||
public:
|
||||
static GrVkSampler* Create(const GrVkGpu* gpu, const GrSamplerState&);
|
||||
static GrVkSampler* Create(GrVkGpu* gpu, const GrSamplerState&, const GrVkYcbcrConversionInfo&);
|
||||
|
||||
VkSampler sampler() const { return fSampler; }
|
||||
|
||||
// Helpers for hashing GrVkSampler
|
||||
static uint8_t GenerateKey(const GrSamplerState&);
|
||||
struct Key {
|
||||
Key(uint16_t samplerKey, const GrVkSamplerYcbcrConversion::Key& ycbcrKey) {
|
||||
// We must memset here since the GrVkSamplerYcbcrConversion has a 64 bit value which may
|
||||
// force alignment padding to occur in the middle of the Key struct.
|
||||
memset(this, 0, sizeof(Key));
|
||||
fSamplerKey = samplerKey;
|
||||
fYcbcrKey = ycbcrKey;
|
||||
}
|
||||
uint16_t fSamplerKey;
|
||||
GrVkSamplerYcbcrConversion::Key fYcbcrKey;
|
||||
|
||||
static const uint8_t& GetKey(const GrVkSampler& sampler) { return sampler.fKey; }
|
||||
static uint32_t Hash(const uint16_t& key) { return key; }
|
||||
bool operator==(const Key& that) const {
|
||||
return this->fSamplerKey == that.fSamplerKey &&
|
||||
this->fYcbcrKey == that.fYcbcrKey;
|
||||
}
|
||||
};
|
||||
|
||||
// Helpers for hashing GrVkSampler
|
||||
static Key GenerateKey(const GrSamplerState&, const GrVkYcbcrConversionInfo&);
|
||||
|
||||
static const Key& GetKey(const GrVkSampler& sampler) { return sampler.fKey; }
|
||||
static uint32_t Hash(const Key& key) {
|
||||
return SkOpts::hash(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
|
||||
}
|
||||
|
||||
#ifdef SK_TRACE_VK_RESOURCES
|
||||
void dumpInfo() const override {
|
||||
@ -35,12 +56,15 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
GrVkSampler(VkSampler sampler, uint16_t key) : INHERITED(), fSampler(sampler), fKey(key) {}
|
||||
GrVkSampler(VkSampler sampler, GrVkSamplerYcbcrConversion* ycbcrConversion, Key key)
|
||||
: INHERITED(), fSampler(sampler), fYcbcrConversion(ycbcrConversion), fKey(key) {}
|
||||
|
||||
void freeGPUData(const GrVkGpu* gpu) const override;
|
||||
void abandonGPUData() const override;
|
||||
|
||||
VkSampler fSampler;
|
||||
uint8_t fKey;
|
||||
VkSampler fSampler;
|
||||
GrVkSamplerYcbcrConversion* fYcbcrConversion;
|
||||
Key fKey;
|
||||
|
||||
typedef GrVkResource INHERITED;
|
||||
};
|
||||
|
101
src/gpu/vk/GrVkSamplerYcbcrConversion.cpp
Normal file
101
src/gpu/vk/GrVkSamplerYcbcrConversion.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrVkSamplerYcbcrConversion.h"
|
||||
|
||||
#include "GrVkGpu.h"
|
||||
|
||||
GrVkSamplerYcbcrConversion* GrVkSamplerYcbcrConversion::Create(
|
||||
const GrVkGpu* gpu, const GrVkYcbcrConversionInfo& info) {
|
||||
if (!gpu->vkCaps().supportsYcbcrConversion()) {
|
||||
return nullptr;
|
||||
}
|
||||
// We only support creating ycbcr conversion for external formats;
|
||||
SkASSERT(info.fExternalFormat);
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
const VkFormatFeatureFlags& featureFlags = info.fExternalFormatFeatures;
|
||||
if (info.fXChromaOffset == VK_CHROMA_LOCATION_MIDPOINT ||
|
||||
info.fYChromaOffset == VK_CHROMA_LOCATION_MIDPOINT) {
|
||||
SkASSERT(featureFlags & VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT);
|
||||
}
|
||||
if (info.fXChromaOffset == VK_CHROMA_LOCATION_COSITED_EVEN ||
|
||||
info.fYChromaOffset == VK_CHROMA_LOCATION_COSITED_EVEN) {
|
||||
SkASSERT(featureFlags & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT);
|
||||
}
|
||||
if (info.fChromaFilter == VK_FILTER_LINEAR) {
|
||||
SkASSERT(featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT);
|
||||
}
|
||||
if (info.fForceExplicitReconstruction) {
|
||||
SkASSERT(featureFlags &
|
||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SK_BUILD_FOR_ANDROID
|
||||
VkExternalFormatANDROID externalFormat;
|
||||
externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
|
||||
externalFormat.pNext = nullptr;
|
||||
externalFormat.externalFormat = info.fExternalFormat;
|
||||
|
||||
VkSamplerYcbcrConversionCreateInfo ycbcrCreateInfo;
|
||||
memset(&ycbcrCreateInfo, 0, sizeof(VkSamplerYcbcrConversionCreateInfo));
|
||||
ycbcrCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO;
|
||||
ycbcrCreateInfo.pNext = &externalFormat;
|
||||
ycbcrCreateInfo.format = VK_FORMAT_UNDEFINED;
|
||||
ycbcrCreateInfo.ycbcrModel = info.fYcbcrModel;
|
||||
ycbcrCreateInfo.ycbcrRange = info.fYcbcrRange;
|
||||
// Componets is ignored for external format conversions;
|
||||
// ycbcrCreateInfo.components = {0, 0, 0, 0};
|
||||
ycbcrCreateInfo.xChromaOffset = info.fXChromaOffset;
|
||||
ycbcrCreateInfo.yChromaOffset = info.fYChromaOffset;
|
||||
ycbcrCreateInfo.chromaFilter = info.fChromaFilter;
|
||||
ycbcrCreateInfo.forceExplicitReconstruction = info.fForceExplicitReconstruction;
|
||||
|
||||
VkSamplerYcbcrConversion conversion;
|
||||
GR_VK_CALL(gpu->vkInterface(), CreateSamplerYcbcrConversion(gpu->device(), &ycbcrCreateInfo,
|
||||
nullptr, &conversion));
|
||||
if (conversion == VK_NULL_HANDLE) {
|
||||
return nullptr;
|
||||
}
|
||||
return new GrVkSamplerYcbcrConversion(conversion, GenerateKey(info));
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GrVkSamplerYcbcrConversion::freeGPUData(const GrVkGpu* gpu) const {
|
||||
SkASSERT(fYcbcrConversion);
|
||||
GR_VK_CALL(gpu->vkInterface(), DestroySamplerYcbcrConversion(gpu->device(), fYcbcrConversion,
|
||||
nullptr));
|
||||
}
|
||||
|
||||
GrVkSamplerYcbcrConversion::Key GrVkSamplerYcbcrConversion::GenerateKey(
|
||||
const GrVkYcbcrConversionInfo& ycbcrInfo) {
|
||||
SkASSERT(static_cast<int>(ycbcrInfo.fYcbcrModel <= 7));
|
||||
static const int kRangeShift = 3;
|
||||
SkASSERT(static_cast<int>(ycbcrInfo.fYcbcrRange) <= 1);
|
||||
static const int kXChromaOffsetShift = kRangeShift + 1;
|
||||
SkASSERT(static_cast<int>(ycbcrInfo.fXChromaOffset) <= 1);
|
||||
static const int kYChromaOffsetShift = kXChromaOffsetShift + 1;
|
||||
SkASSERT(static_cast<int>(ycbcrInfo.fXChromaOffset) <= 1);
|
||||
static const int kChromaFilterShift = kYChromaOffsetShift + 1;
|
||||
SkASSERT(static_cast<int>(ycbcrInfo.fChromaFilter) <= 1);
|
||||
static const int kReconShift = kChromaFilterShift + 1;
|
||||
SkASSERT(static_cast<int>(ycbcrInfo.fForceExplicitReconstruction) <= 1);
|
||||
GR_STATIC_ASSERT(kReconShift <= 7);
|
||||
|
||||
uint8_t ycbcrKey = static_cast<uint8_t>(ycbcrInfo.fYcbcrModel);
|
||||
ycbcrKey |= (static_cast<uint8_t>(ycbcrInfo.fYcbcrRange) << kRangeShift);
|
||||
ycbcrKey |= (static_cast<uint8_t>(ycbcrInfo.fXChromaOffset) << kXChromaOffsetShift);
|
||||
ycbcrKey |= (static_cast<uint8_t>(ycbcrInfo.fYChromaOffset) << kYChromaOffsetShift);
|
||||
ycbcrKey |= (static_cast<uint8_t>(ycbcrInfo.fChromaFilter) << kChromaFilterShift);
|
||||
ycbcrKey |= (static_cast<uint8_t>(ycbcrInfo.fForceExplicitReconstruction) << kReconShift);
|
||||
|
||||
return {ycbcrInfo.fExternalFormat, ycbcrKey};
|
||||
}
|
||||
|
71
src/gpu/vk/GrVkSamplerYcbcrConversion.h
Normal file
71
src/gpu/vk/GrVkSamplerYcbcrConversion.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrVkSamplerYcbcrConverison_DEFINED
|
||||
#define GrVkSamplerYcbcrConverison_DEFINED
|
||||
|
||||
#include "GrVkVulkan.h"
|
||||
|
||||
#include "GrVkResource.h"
|
||||
|
||||
#include "SkOpts.h"
|
||||
#include "vk/GrVkTypes.h"
|
||||
|
||||
class GrVkGpu;
|
||||
|
||||
class GrVkSamplerYcbcrConversion : public GrVkResource {
|
||||
public:
|
||||
static GrVkSamplerYcbcrConversion* Create(const GrVkGpu* gpu, const GrVkYcbcrConversionInfo&);
|
||||
|
||||
VkSamplerYcbcrConversion ycbcrConversion() const { return fYcbcrConversion; }
|
||||
|
||||
struct Key {
|
||||
Key() : fExternalFormat(0), fConversionKey(0) {}
|
||||
Key(uint64_t externalFormat, uint8_t conversionKey)
|
||||
: fExternalFormat(externalFormat), fConversionKey(conversionKey) {}
|
||||
|
||||
uint64_t fExternalFormat;
|
||||
uint8_t fConversionKey;
|
||||
|
||||
bool operator==(const Key& that) const {
|
||||
return this->fExternalFormat == that.fExternalFormat &&
|
||||
this->fConversionKey == that.fConversionKey;
|
||||
}
|
||||
};
|
||||
|
||||
// Helpers for hashing GrVkSamplerYcbcrConversion
|
||||
static Key GenerateKey(const GrVkYcbcrConversionInfo& ycbcrInfo);
|
||||
|
||||
static const Key& GetKey(const GrVkSamplerYcbcrConversion& ycbcrConversion) {
|
||||
return ycbcrConversion.fKey;
|
||||
}
|
||||
static uint32_t Hash(const Key& key) {
|
||||
return SkOpts::hash(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
|
||||
}
|
||||
|
||||
#ifdef SK_TRACE_VK_RESOURCES
|
||||
void dumpInfo() const override {
|
||||
SkDebugf("GrVkSamplerYcbcrConversion: %d (%d refs)\n", fYcbcrConversion, this->getRefCnt());
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
GrVkSamplerYcbcrConversion(VkSamplerYcbcrConversion ycbcrConversion, Key key)
|
||||
: INHERITED()
|
||||
, fYcbcrConversion(ycbcrConversion)
|
||||
, fKey(key) {}
|
||||
|
||||
void freeGPUData(const GrVkGpu* gpu) const override;
|
||||
|
||||
VkSamplerYcbcrConversion fYcbcrConversion;
|
||||
Key fKey;
|
||||
|
||||
typedef GrVkResource INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -51,7 +51,8 @@ GrVkStencilAttachment* GrVkStencilAttachment::Create(GrVkGpu* gpu,
|
||||
|
||||
const GrVkImageView* imageView = GrVkImageView::Create(gpu, info.fImage,
|
||||
format.fInternalFormat,
|
||||
GrVkImageView::kStencil_Type, 1);
|
||||
GrVkImageView::kStencil_Type, 1,
|
||||
GrVkYcbcrConversionInfo());
|
||||
if (!imageView) {
|
||||
GrVkImage::DestroyImageInfo(gpu, &info);
|
||||
return nullptr;
|
||||
|
@ -76,9 +76,9 @@ sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu, SkBudgeted budgeted
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const GrVkImageView* imageView = GrVkImageView::Create(gpu, info.fImage, info.fFormat,
|
||||
GrVkImageView::kColor_Type,
|
||||
info.fLevelCount);
|
||||
const GrVkImageView* imageView = GrVkImageView::Create(
|
||||
gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
|
||||
info.fYcbcrConversionInfo);
|
||||
if (!imageView) {
|
||||
GrVkImage::DestroyImageInfo(gpu, &info);
|
||||
return nullptr;
|
||||
@ -98,9 +98,9 @@ sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu,
|
||||
// Wrapped textures require both image and allocation (because they can be mapped)
|
||||
SkASSERT(VK_NULL_HANDLE != info.fImage && VK_NULL_HANDLE != info.fAlloc.fMemory);
|
||||
|
||||
const GrVkImageView* imageView = GrVkImageView::Create(gpu, info.fImage, info.fFormat,
|
||||
GrVkImageView::kColor_Type,
|
||||
info.fLevelCount);
|
||||
const GrVkImageView* imageView = GrVkImageView::Create(
|
||||
gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
|
||||
info.fYcbcrConversionInfo);
|
||||
if (!imageView) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -100,9 +100,9 @@ sk_sp<GrVkTextureRenderTarget> GrVkTextureRenderTarget::Make(GrVkGpu* gpu,
|
||||
bool isWrapped) {
|
||||
VkImage image = info.fImage;
|
||||
// Create the texture ImageView
|
||||
const GrVkImageView* imageView = GrVkImageView::Create(gpu, image, info.fFormat,
|
||||
GrVkImageView::kColor_Type,
|
||||
info.fLevelCount);
|
||||
const GrVkImageView* imageView = GrVkImageView::Create(
|
||||
gpu, image, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
|
||||
info.fYcbcrConversionInfo);
|
||||
if (!imageView) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -141,7 +141,7 @@ sk_sp<GrVkTextureRenderTarget> GrVkTextureRenderTarget::Make(GrVkGpu* gpu,
|
||||
// Create resolve attachment view.
|
||||
resolveAttachmentView = GrVkImageView::Create(gpu, image, pixelFormat,
|
||||
GrVkImageView::kColor_Type,
|
||||
info.fLevelCount);
|
||||
info.fLevelCount, GrVkYcbcrConversionInfo());
|
||||
if (!resolveAttachmentView) {
|
||||
GrVkImage::DestroyImageInfo(gpu, &msInfo);
|
||||
imageView->unref(gpu);
|
||||
@ -154,7 +154,8 @@ sk_sp<GrVkTextureRenderTarget> GrVkTextureRenderTarget::Make(GrVkGpu* gpu,
|
||||
}
|
||||
|
||||
const GrVkImageView* colorAttachmentView = GrVkImageView::Create(gpu, colorImage, pixelFormat,
|
||||
GrVkImageView::kColor_Type, 1);
|
||||
GrVkImageView::kColor_Type, 1,
|
||||
GrVkYcbcrConversionInfo());
|
||||
if (!colorAttachmentView) {
|
||||
if (desc.fSampleCnt > 1) {
|
||||
resolveAttachmentView->unref(gpu);
|
||||
@ -251,7 +252,8 @@ bool GrVkTextureRenderTarget::updateForMipmap(GrVkGpu* gpu, const GrVkImageInfo&
|
||||
newInfo.fImage,
|
||||
pixelFormat,
|
||||
GrVkImageView::kColor_Type,
|
||||
newInfo.fLevelCount);
|
||||
newInfo.fLevelCount,
|
||||
GrVkYcbcrConversionInfo());
|
||||
if (!resolveAttachmentView) {
|
||||
return false;
|
||||
}
|
||||
@ -262,7 +264,8 @@ bool GrVkTextureRenderTarget::updateForMipmap(GrVkGpu* gpu, const GrVkImageInfo&
|
||||
newInfo.fImage,
|
||||
pixelFormat,
|
||||
GrVkImageView::kColor_Type,
|
||||
1);
|
||||
1,
|
||||
GrVkYcbcrConversionInfo());
|
||||
if (!colorAttachmentView) {
|
||||
return false;
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ bool GrPixelConfigToVkFormat(GrPixelConfig config, VkFormat* format) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
bool GrVkFormatPixelConfigPairIsValid(VkFormat format, GrPixelConfig config) {
|
||||
switch (format) {
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
@ -113,6 +114,7 @@ bool GrVkFormatPixelConfigPairIsValid(VkFormat format, GrPixelConfig config) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GrVkFormatIsSupported(VkFormat format) {
|
||||
switch (format) {
|
||||
|
@ -36,10 +36,12 @@ bool GrPixelConfigToVkFormat(GrPixelConfig config, VkFormat* format);
|
||||
|
||||
bool GrVkFormatIsSupported(VkFormat);
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
/**
|
||||
* Returns true if the passed in VkFormat and GrPixelConfig are compatible with each other.
|
||||
*/
|
||||
bool GrVkFormatPixelConfigPairIsValid(VkFormat, GrPixelConfig);
|
||||
#endif
|
||||
|
||||
bool GrSampleCountToVkSampleCount(uint32_t samples, VkSampleCountFlagBits* vkSamples);
|
||||
|
||||
|
@ -352,6 +352,17 @@ static void setup_extension_features(GrVkGetProc getProc, VkInstance inst, VkPhy
|
||||
tailPNext = &blend->pNext;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceSamplerYcbcrConversionFeatures* ycbcrFeature = nullptr;
|
||||
if (physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
|
||||
extensions->hasExtension(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, 1)) {
|
||||
ycbcrFeature = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*) sk_malloc_throw(
|
||||
sizeof(VkPhysicalDeviceSamplerYcbcrConversionFeatures));
|
||||
ycbcrFeature->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
|
||||
ycbcrFeature->pNext = nullptr;
|
||||
*tailPNext = ycbcrFeature;
|
||||
tailPNext = &ycbcrFeature->pNext;
|
||||
}
|
||||
|
||||
if (physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
|
||||
ACQUIRE_VK_PROC_LOCAL(GetPhysicalDeviceFeatures2, inst, VK_NULL_HANDLE);
|
||||
grVkGetPhysicalDeviceFeatures2(physDev, features);
|
||||
|
Loading…
Reference in New Issue
Block a user