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:
Greg Daniel 2018-11-29 13:30:08 -05:00 committed by Skia Commit-Bot
parent cf37ede8b3
commit 6cd74900da
25 changed files with 580 additions and 114 deletions

View File

@ -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",

View File

@ -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

View File

@ -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;
}
};

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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));

View File

@ -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);

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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;
};

View File

@ -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));

View File

@ -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);

View File

@ -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();
}

View File

@ -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;

View File

@ -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)};
}

View File

@ -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;
};

View 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};
}

View 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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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);

View File

@ -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);