Add support for VK_KHR_sampler_ycbcr_conversion

This adds ability for applications to import Android Hardware Buffers
(AHBs) as OpenGL images which in turn can be sampled from and/or
written.

This was specifically tested with the common use case of importing a
buffer created by an media decoder and using that as a texture source to
include that video content on the screen. Tested with:
- Angry Birds 2 video player (for ads) requires YUV conversion.
- Basic Media Decoder example:
    https://github.com/android/media-samples/tree/master/BasicMediaDecoder

Bug: b/155487768
Change-Id: I9255450f81aa4daa2aace7205d4f6c3f225abcca
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2175103
Commit-Queue: Courtney Goeltzenleuchter <courtneygo@google.com>
Reviewed-by: Courtney Goeltzenleuchter <courtneygo@google.com>
Reviewed-by: Tim Van Patten <timvp@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Courtney Goeltzenleuchter
2020-06-17 11:38:37 -06:00
committed by Commit Bot
parent b549be966f
commit f61272fbf3
26 changed files with 448 additions and 69 deletions

View File

@@ -122,11 +122,11 @@ struct FeaturesVk : FeatureSetBase
// Whether the VkDevice supports the VK_FUCHSIA_external_memory
// extension, on which the GL_ANGLE_memory_object_fuchsia extension can be layered.
angle::Feature supportsExternalMemoryFuchsia = {
Feature supportsExternalMemoryFuchsia = {
"supports_external_memory_fuchsia", FeatureCategory::VulkanFeatures,
"VkDevice supports the VK_FUCHSIA_external_memory extension", &members};
angle::Feature supportsFilteringPrecision = {
Feature supportsFilteringPrecision = {
"supports_filtering_precision_google", FeatureCategory::VulkanFeatures,
"VkDevice supports the VK_GOOGLE_sampler_filtering_precision extension", &members};
@@ -172,6 +172,12 @@ struct FeaturesVk : FeatureSetBase
"supports_shader_stencil_export", FeatureCategory::VulkanFeatures,
"VkDevice supports the VK_EXT_shader_stencil_export extension", &members};
// Whether the VkDevice supports the VK_KHR_sampler_ycbcr_conversion extension, which is needed
// to support Ycbcr conversion with external images.
Feature supportsYUVSamplerConversion = {
"supports_yuv_sampler_conversion", FeatureCategory::VulkanFeatures,
"VkDevice supports the VK_KHR_sampler_ycbcr_conversion extension", &members};
// Where VK_EXT_transform_feedback is not support, an emulation path is used.
// http://anglebug.com/3205
Feature emulateTransformFeedback = {

View File

@@ -4,9 +4,9 @@
"src/libANGLE/renderer/angle_format_map.json":
"c79d833aea7007c7d0d51cdaa9b265a6",
"src/libANGLE/renderer/vulkan/gen_vk_format_table.py":
"d8a0f2278c09a49049a73930b9da3719",
"54a7374f93f17da1386600027acca7a3",
"src/libANGLE/renderer/vulkan/vk_format_map.json":
"738c8dc36fbe212669944e88ae918f9c",
"src/libANGLE/renderer/vulkan/vk_format_table_autogen.cpp":
"383749c786e957bdbbbce9d8b5c2441a"
"c7e01cbf1eded87f4ed9f3bc8b7a567c"
}

View File

@@ -64,6 +64,10 @@ extern PFN_vkImportFenceFdKHR vkImportFenceFdKHR;
extern PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR
vkGetPhysicalDeviceExternalSemaphorePropertiesKHR;
// VK_KHR_sampler_ycbcr_conversion
extern PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR;
extern PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR;
# if defined(ANGLE_PLATFORM_FUCHSIA)
// VK_FUCHSIA_imagepipe_surface
extern PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA;

View File

@@ -3748,6 +3748,7 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask();
const gl::ActiveTextureTypeArray &textureTypes = executable->getActiveSamplerTypes();
bool haveImmutableSampler = false;
for (size_t textureUnit : activeTextures)
{
gl::Texture *texture = textures[textureUnit];
@@ -3776,6 +3777,11 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
samplerSerial = samplerVk->getSerial();
}
if (textureVk->getImage().hasImmutableSampler())
{
haveImmutableSampler = true;
}
mActiveTextures[textureUnit].texture = textureVk;
mActiveTextures[textureUnit].sampler = samplerVk;
// Cache serials from sampler and texture, but re-use texture if no sampler bound
@@ -3783,6 +3789,12 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
mActiveTexturesDesc.update(textureUnit, textureVk->getSerial(), samplerSerial);
}
if (haveImmutableSampler)
{
ANGLE_TRY(mExecutable->updatePipelineLayout(context, &mActiveTextures));
invalidateCurrentGraphicsPipeline();
}
return angle::Result::Continue;
}

View File

@@ -97,9 +97,13 @@ egl::Error ImageVk::initialize(const egl::Display *display)
return egl::EglBadAccess();
}
// start with some reasonable alignment that's safe for the case where intendedFormatID is
// FormatID::NONE
size_t alignment = mImage->getFormat().getValidImageCopyBufferAlignment();
// Make sure a staging buffer is ready to use to upload data
mImage->initStagingBuffer(renderer, mImage->getFormat().getImageCopyBufferAlignment(),
vk::kStagingBufferFlags, vk::kStagingBufferSize);
mImage->initStagingBuffer(renderer, alignment, vk::kStagingBufferFlags,
vk::kStagingBufferSize);
mOwnsImage = false;

View File

@@ -245,7 +245,7 @@ angle::Result MemoryObjectVk::createImage(ContextVk *contextVk,
VkMemoryPropertyFlags flags = 0;
ANGLE_TRY(image->initExternalMemory(contextVk, renderer->getMemoryProperties(),
externalMemoryRequirements, importMemoryInfo,
externalMemoryRequirements, nullptr, importMemoryInfo,
renderer->getQueueFamilyIndex(), flags));
return angle::Result::Continue;

View File

@@ -446,9 +446,11 @@ void ProgramExecutableVk::addImageDescriptorSetDesc(const gl::ProgramExecutable
}
}
void ProgramExecutableVk::addTextureDescriptorSetDesc(const gl::ProgramState &programState,
bool useOldRewriteStructSamplers,
vk::DescriptorSetLayoutDesc *descOut)
void ProgramExecutableVk::addTextureDescriptorSetDesc(
const gl::ProgramState &programState,
bool useOldRewriteStructSamplers,
const gl::ActiveTextureArray<vk::TextureUnit> *activeTextures,
vk::DescriptorSetLayoutDesc *descOut)
{
const std::vector<gl::SamplerBinding> &samplerBindings = programState.getSamplerBindings();
const std::vector<gl::LinkedUniform> &uniforms = programState.getUniforms();
@@ -493,8 +495,25 @@ void ProgramExecutableVk::addTextureDescriptorSetDesc(const gl::ProgramState &pr
ShaderInterfaceVariableInfo &info = mVariableInfoMap[shaderType][samplerName];
VkShaderStageFlags activeStages = gl_vk::kShaderStageMap[shaderType];
descOut->update(info.binding, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, arraySize,
activeStages, nullptr);
// TODO: https://issuetracker.google.com/issues/158215272: how do we handle array of
// immutable samplers?
GLuint textureUnit = samplerBinding.boundTextureUnits[0];
if (activeTextures &&
((*activeTextures)[textureUnit].texture->getImage().hasImmutableSampler()))
{
ASSERT(samplerBinding.boundTextureUnits.size() == 1);
// Always take the texture's sampler, that's only way to get to yuv conversion for
// externalFormat
const vk::Sampler &immutableSampler =
(*activeTextures)[textureUnit].texture->getSampler();
descOut->update(info.binding, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, arraySize,
activeStages, &immutableSampler);
}
else
{
descOut->update(info.binding, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, arraySize,
activeStages, nullptr);
}
}
}
}
@@ -610,7 +629,11 @@ angle::Result ProgramExecutableVk::getComputePipeline(ContextVk *contextVk,
return shaderProgram->getComputePipeline(contextVk, getPipelineLayout(), pipelineOut);
}
angle::Result ProgramExecutableVk::createPipelineLayout(const gl::Context *glContext)
// updatePipelineLayout is used to create the DescriptorSetLayout(s) and PipelineLayout and update
// them when we discover that an immutable sampler is in use.
angle::Result ProgramExecutableVk::updatePipelineLayout(
const gl::Context *glContext,
gl::ActiveTextureArray<vk::TextureUnit> *activeTextures)
{
const gl::State &glState = glContext->getState();
ContextVk *contextVk = vk::GetImpl(glContext);
@@ -621,13 +644,12 @@ angle::Result ProgramExecutableVk::createPipelineLayout(const gl::Context *glCon
gl::ShaderMap<const gl::ProgramState *> programStates;
fillProgramStateMap(contextVk, &programStates);
reset(contextVk);
// Store a reference to the pipeline and descriptor set layouts. This will create them if they
// don't already exist in the cache.
// Default uniforms and transform feedback:
vk::DescriptorSetLayoutDesc uniformsAndXfbSetDesc;
mNumDefaultUniformDescriptors = 0;
for (const gl::ShaderType shaderType : linkedShaderStages)
{
const std::string uniformBlockName = kDefaultUniformNames[shaderType];
@@ -693,7 +715,7 @@ angle::Result ProgramExecutableVk::createPipelineLayout(const gl::Context *glCon
const gl::ProgramState *programState = programStates[shaderType];
ASSERT(programState);
addTextureDescriptorSetDesc(*programState, contextVk->useOldRewriteStructSamplers(),
&texturesSetDesc);
activeTextures, &texturesSetDesc);
}
ANGLE_TRY(renderer->getDescriptorSetLayout(contextVk, texturesSetDesc,
@@ -721,6 +743,22 @@ angle::Result ProgramExecutableVk::createPipelineLayout(const gl::Context *glCon
ANGLE_TRY(renderer->getPipelineLayout(contextVk, pipelineLayoutDesc, mDescriptorSetLayouts,
&mPipelineLayout));
return angle::Result::Continue;
}
angle::Result ProgramExecutableVk::createPipelineLayout(const gl::Context *glContext)
{
ContextVk *contextVk = vk::GetImpl(glContext);
RendererVk *renderer = contextVk->getRenderer();
const gl::ProgramExecutable &glExecutable = getGlExecutable();
const gl::ShaderBitSet &linkedShaderStages = glExecutable.getLinkedShaderStages();
gl::ShaderMap<const gl::ProgramState *> programStates;
fillProgramStateMap(contextVk, &programStates);
reset(contextVk);
ANGLE_TRY(updatePipelineLayout(glContext, nullptr));
// Initialize descriptor pools.
std::array<VkDescriptorPoolSize, 2> uniformAndXfbSetSize = {
{{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
@@ -1302,6 +1340,10 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex
textureVk->getReadImageViewAndRecordUse(contextVk).getHandle();
}
if (textureVk->getImage().hasImmutableSampler())
{
imageInfos[arrayElement].sampler = textureVk->getSampler().getHandle();
}
ShaderInterfaceVariableInfoMap &variableInfoMap = mVariableInfoMap[shaderType];
const std::string samplerName =
contextVk->getRenderer()->getFeatures().forceOldRewriteStructSamplers.enabled

View File

@@ -137,6 +137,8 @@ class ProgramExecutableVk
const vk::PipelineLayout &getPipelineLayout() const { return mPipelineLayout.get(); }
angle::Result createPipelineLayout(const gl::Context *glContext);
angle::Result updatePipelineLayout(const gl::Context *glContext,
gl::ActiveTextureArray<vk::TextureUnit> *activeTextures);
angle::Result updateTexturesDescriptorSet(ContextVk *contextVk);
angle::Result updateShaderResourcesDescriptorSet(ContextVk *contextVk,
@@ -182,6 +184,7 @@ class ProgramExecutableVk
vk::DescriptorSetLayoutDesc *descOut);
void addTextureDescriptorSetDesc(const gl::ProgramState &programState,
bool useOldRewriteStructSamplers,
const gl::ActiveTextureArray<vk::TextureUnit> *activeTextures,
vk::DescriptorSetLayoutDesc *descOut);
void updateDefaultUniformsDescriptorSet(

View File

@@ -492,6 +492,7 @@ void RendererVk::onDestroy()
mPipelineCache.destroy(mDevice);
mSamplerCache.destroy(this);
mYuvConversionCache.destroy(this);
mTheNullBuffer.destroy(this);
mAllocator.destroy();
@@ -886,6 +887,10 @@ void RendererVk::queryDeviceExtensionFeatures(const ExtensionNameList &deviceExt
mExternalSemaphoreProperties = {};
mExternalSemaphoreProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES;
mSamplerYcbcrConversionFeatures = {};
mSamplerYcbcrConversionFeatures.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
if (!vkGetPhysicalDeviceProperties2KHR || !vkGetPhysicalDeviceFeatures2KHR)
{
return;
@@ -935,6 +940,12 @@ void RendererVk::queryDeviceExtensionFeatures(const ExtensionNameList &deviceExt
vk::AddToPNextChain(&deviceProperties, &mExternalMemoryHostProperties);
}
// Query Ycbcr conversion properties
if (ExtensionFound(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, deviceExtensionNames))
{
vk::AddToPNextChain(&deviceFeatures, &mSamplerYcbcrConversionFeatures);
}
// Query subgroup properties
vk::AddToPNextChain(&deviceProperties, &mSubgroupProperties);
@@ -972,6 +983,13 @@ void RendererVk::queryDeviceExtensionFeatures(const ExtensionNameList &deviceExt
mIndexTypeUint8Features.pNext = nullptr;
mSubgroupProperties.pNext = nullptr;
mExternalMemoryHostProperties.pNext = nullptr;
mLineRasterizationFeatures.pNext = nullptr;
mProvokingVertexFeatures.pNext = nullptr;
mVertexAttributeDivisorFeatures.pNext = nullptr;
mVertexAttributeDivisorProperties.pNext = nullptr;
mTransformFeedbackFeatures.pNext = nullptr;
mIndexTypeUint8Features.pNext = nullptr;
mSamplerYcbcrConversionFeatures.pNext = nullptr;
}
angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex)
@@ -1274,6 +1292,12 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
#endif // !defined(ANGLE_SHARED_LIBVULKAN)
}
if (getFeatures().supportsYUVSamplerConversion.enabled)
{
enabledDeviceExtensions.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
vk::AddToPNextChain(&createInfo, &mSamplerYcbcrConversionFeatures);
}
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.flags = 0;
createInfo.queueCreateInfoCount = 1;
@@ -1325,6 +1349,10 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
{
InitTransformFeedbackEXTFunctions(mDevice);
}
if (getFeatures().supportsYUVSamplerConversion.enabled)
{
InitSamplerYcbcrKHRFunctions(mDevice);
}
#endif // !defined(ANGLE_SHARED_LIBVULKAN)
// Initialize the vulkan pipeline cache.
@@ -1730,6 +1758,9 @@ void RendererVk::initFeatures(DisplayVk *displayVk, const ExtensionNameList &dev
// Currently disabled by default: http://anglebug.com/4324
ANGLE_FEATURE_CONDITION(&mFeatures, enableCommandProcessingThread, false);
ANGLE_FEATURE_CONDITION(&mFeatures, supportsYUVSamplerConversion,
mSamplerYcbcrConversionFeatures.samplerYcbcrConversion != VK_FALSE);
angle::PlatformMethods *platform = ANGLEPlatformCurrent();
platform->overrideFeaturesVk(platform, &mFeatures);

View File

@@ -247,6 +247,7 @@ class RendererVk : angle::NonCopyable
bool enableDebugUtils() const { return mEnableDebugUtils; }
SamplerCache &getSamplerCache() { return mSamplerCache; }
SamplerYcbcrConversionCache &getYuvConversionCache() { return mYuvConversionCache; }
vk::ActiveHandleCounter &getActiveHandleCounts() { return mActiveHandleCounts; }
// Queue commands to worker thread for processing
@@ -309,6 +310,7 @@ class RendererVk : angle::NonCopyable
VkPhysicalDeviceExternalMemoryHostPropertiesEXT mExternalMemoryHostProperties;
VkExternalFenceProperties mExternalFenceProperties;
VkExternalSemaphoreProperties mExternalSemaphoreProperties;
VkPhysicalDeviceSamplerYcbcrConversionFeatures mSamplerYcbcrConversionFeatures;
std::vector<VkQueueFamilyProperties> mQueueFamilyProperties;
std::mutex mQueueMutex;
angle::PackedEnumMap<egl::ContextPriority, VkQueue> mQueues;
@@ -382,6 +384,7 @@ class RendererVk : angle::NonCopyable
vk::Allocator mAllocator;
SamplerCache mSamplerCache;
SamplerYcbcrConversionCache mYuvConversionCache;
vk::ActiveHandleCounter mActiveHandleCounts;
// Vulkan does not allow binding a null vertex buffer. We use a dummy as a placeholder.

View File

@@ -39,7 +39,7 @@ angle::Result SamplerVk::syncState(const gl::Context *context, const bool dirty)
mSampler.reset();
}
vk::SamplerDesc desc(mState, false);
vk::SamplerDesc desc(mState, false, 0);
ANGLE_TRY(renderer->getSamplerCache().getSampler(contextVk, desc, &mSampler));
// Regenerate the serial on a sampler change.

View File

@@ -210,9 +210,9 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initializeWithExternalMemory(
image.getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
VkMemoryPropertyFlags flags = 0;
ANGLE_TRY(image.initExternalMemory(displayVk, renderer->getMemoryProperties(),
externalMemoryRequirements, &importMemoryHostPointerInfo,
VK_QUEUE_FAMILY_EXTERNAL, flags));
ANGLE_TRY(image.initExternalMemory(
displayVk, renderer->getMemoryProperties(), externalMemoryRequirements, nullptr,
&importMemoryHostPointerInfo, VK_QUEUE_FAMILY_EXTERNAL, flags));
return angle::Result::Continue;
}

View File

@@ -1884,7 +1884,8 @@ angle::Result TextureVk::syncState(const gl::Context *context,
mImage->getLevelCount(), layerCount));
}
vk::SamplerDesc samplerDesc(mState.getSamplerState(), mState.isStencilMode());
vk::SamplerDesc samplerDesc(mState.getSamplerState(), mState.isStencilMode(),
mImage->getExternalFormat());
ANGLE_TRY(renderer->getSamplerCache().getSampler(contextVk, samplerDesc, &mSampler));
// Regenerate the serial on a sampler change.

View File

@@ -413,7 +413,7 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
// reallocated independently of |mImage| on state changes.
vk::ImageViewHelper mImageViews;
// |mSampler| contains the relevant Vulkan sampler states reprensenting the OpenGL Texture
// |mSampler| contains the relevant Vulkan sampler states representing the OpenGL Texture
// sampling states for the Texture.
vk::BindingPointer<vk::Sampler> mSampler;

View File

@@ -70,7 +70,18 @@ egl::Error HardwareBufferImageSiblingVkAndroid::ValidateHardwareBuffer(RendererV
return egl::EglBadParameter() << "Failed to query AHardwareBuffer properties";
}
if (!HasFullTextureFormatSupport(renderer, bufferFormatProperties.format))
if (bufferFormatProperties.format == VK_FORMAT_UNDEFINED)
{
ASSERT(bufferFormatProperties.externalFormat != 0);
// We must have an external format, check that it supports texture sampling
if (!(bufferFormatProperties.formatFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
{
return egl::EglBadParameter()
<< "Sampling from AHardwareBuffer externalFormat 0x" << std::hex
<< bufferFormatProperties.externalFormat << " is unsupported ";
}
}
else if (!HasFullTextureFormatSupport(renderer, bufferFormatProperties.format))
{
return egl::EglBadParameter()
<< "AHardwareBuffer format does not support enough features to use as a texture.";
@@ -151,18 +162,35 @@ angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk
ANGLE_VK_TRY(displayVk, vkGetAndroidHardwareBufferPropertiesANDROID(device, hardwareBuffer,
&bufferProperties));
const vk::Format &vkFormat = renderer->getFormat(internalFormat);
const angle::Format &imageFormat = vkFormat.actualImageFormat();
VkExternalFormatANDROID externalFormat = {};
externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
externalFormat.externalFormat = 0;
const vk::Format &vkFormat = renderer->getFormat(internalFormat);
const vk::Format &externalVkFormat = renderer->getFormat(angle::FormatID::NONE);
const angle::Format &imageFormat = vkFormat.actualImageFormat();
bool isDepthOrStencilFormat = imageFormat.hasDepthOrStencilBits();
// Query AHB description and do the following -
// 1. Derive VkImageTiling mode based on AHB usage flags
// 2. Map AHB usage flags to VkImageUsageFlags
AHardwareBuffer_Desc ahbDescription;
AHardwareBuffer_describe(hardwareBuffer, &ahbDescription);
VkImageTiling imageTilingMode = AhbDescUsageToVkImageTiling(ahbDescription);
VkImageUsageFlags usage = AhbDescUsageToVkImageUsage(ahbDescription, isDepthOrStencilFormat);
if (bufferFormatProperties.format == VK_FORMAT_UNDEFINED)
{
externalFormat.externalFormat = bufferFormatProperties.externalFormat;
// VkImageCreateInfo struct: If the pNext chain includes a VkExternalFormatANDROID structure
// whose externalFormat member is not 0, usage must not include any usages except
// VK_IMAGE_USAGE_SAMPLED_BIT
usage = VK_IMAGE_USAGE_SAMPLED_BIT;
}
VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
externalMemoryImageCreateInfo.pNext = &externalFormat;
externalMemoryImageCreateInfo.handleTypes =
@@ -173,19 +201,12 @@ angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk
mImage = new vk::ImageHelper();
// Query AHB description and do the following -
// 1. Derive VkImageTiling mode based on AHB usage flags
// 2. Map AHB usage flags to VkImageUsageFlags
AHardwareBuffer_Desc ahbDescription;
AHardwareBuffer_describe(hardwareBuffer, &ahbDescription);
VkImageTiling imageTilingMode = AhbDescUsageToVkImageTiling(ahbDescription);
VkImageUsageFlags usage = AhbDescUsageToVkImageUsage(
ahbDescription, (imageFormat.depthBits > 0 || imageFormat.stencilBits > 0));
mImage->setTilingMode(imageTilingMode);
ANGLE_TRY(mImage->initExternal(
displayVk, gl::TextureType::_2D, vkExtents, vkFormat, 1, usage, vk::kVkImageCreateFlagsNone,
vk::ImageLayout::ExternalPreInitialized, &externalMemoryImageCreateInfo, 0, 0, 1, 1));
displayVk, gl::TextureType::_2D, vkExtents,
bufferFormatProperties.format == VK_FORMAT_UNDEFINED ? externalVkFormat : vkFormat, 1,
usage, vk::kVkImageCreateFlagsNone, vk::ImageLayout::ExternalPreInitialized,
&externalMemoryImageCreateInfo, 0, 0, 1, 1));
VkImportAndroidHardwareBufferInfoANDROID importHardwareBufferInfo = {};
importHardwareBufferInfo.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
@@ -203,9 +224,35 @@ angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk
externalMemoryRequirements.memoryTypeBits = bufferProperties.memoryTypeBits;
VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
ANGLE_TRY(mImage->initExternalMemory(displayVk, renderer->getMemoryProperties(),
externalMemoryRequirements, &dedicatedAllocInfo,
VK_QUEUE_FAMILY_FOREIGN_EXT, flags));
if (bufferFormatProperties.format == VK_FORMAT_UNDEFINED)
{
// Note from Vulkan spec: Since GL_OES_EGL_image_external does not require the same sampling
// and conversion calculations as Vulkan does, achieving identical results between APIs may
// not be possible on some implementations.
ANGLE_VK_CHECK(displayVk, renderer->getFeatures().supportsYUVSamplerConversion.enabled,
VK_ERROR_FEATURE_NOT_PRESENT);
ASSERT(externalFormat.pNext == nullptr);
VkSamplerYcbcrConversionCreateInfo yuvConversionInfo = {};
yuvConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO;
yuvConversionInfo.pNext = &externalFormat;
yuvConversionInfo.format = VK_FORMAT_UNDEFINED;
yuvConversionInfo.xChromaOffset = bufferFormatProperties.suggestedXChromaOffset;
yuvConversionInfo.yChromaOffset = bufferFormatProperties.suggestedYChromaOffset;
yuvConversionInfo.ycbcrModel = bufferFormatProperties.suggestedYcbcrModel;
yuvConversionInfo.ycbcrRange = bufferFormatProperties.suggestedYcbcrRange;
yuvConversionInfo.chromaFilter = VK_FILTER_LINEAR;
yuvConversionInfo.components = bufferFormatProperties.samplerYcbcrConversionComponents;
ANGLE_TRY(mImage->initExternalMemory(
displayVk, renderer->getMemoryProperties(), externalMemoryRequirements,
&yuvConversionInfo, &dedicatedAllocInfo, VK_QUEUE_FAMILY_FOREIGN_EXT, flags));
}
else
{
ANGLE_TRY(mImage->initExternalMemory(
displayVk, renderer->getMemoryProperties(), externalMemoryRequirements, nullptr,
&dedicatedAllocInfo, VK_QUEUE_FAMILY_FOREIGN_EXT, flags));
}
constexpr uint32_t kColorRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
constexpr uint32_t kDepthStencilRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;

View File

@@ -144,7 +144,7 @@ def gen_format_case(angle, internal_format, vk_json_data):
args = dict(
format_id=angle, internal_format=internal_format, image_template="", buffer_template="")
if ((angle not in vk_map) and (angle not in vk_fallbacks)) or angle == 'NONE':
if ((angle not in vk_map) and (angle not in vk_fallbacks)):
return empty_format_entry_template.format(**args)
# get_formats returns override format (if any) + fallbacks

View File

@@ -14,6 +14,7 @@
#include "common/vulkan/vk_google_filtering_precision.h"
#include "libANGLE/BlobCache.h"
#include "libANGLE/VertexAttribute.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/ProgramVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
@@ -1741,9 +1742,11 @@ SamplerDesc::SamplerDesc(const SamplerDesc &other) = default;
SamplerDesc &SamplerDesc::operator=(const SamplerDesc &rhs) = default;
SamplerDesc::SamplerDesc(const gl::SamplerState &samplerState, bool stencilMode)
SamplerDesc::SamplerDesc(const gl::SamplerState &samplerState,
bool stencilMode,
uint64_t externalFormat)
{
update(samplerState, stencilMode);
update(samplerState, stencilMode, externalFormat);
}
void SamplerDesc::reset()
@@ -1752,6 +1755,7 @@ void SamplerDesc::reset()
mMaxAnisotropy = 0.0f;
mMinLod = 0.0f;
mMaxLod = 0.0f;
mExternalFormat = 0;
mMagFilter = 0;
mMinFilter = 0;
mMipmapMode = 0;
@@ -1760,16 +1764,23 @@ void SamplerDesc::reset()
mAddressModeW = 0;
mCompareEnabled = 0;
mCompareOp = 0;
mReserved = 0;
mReserved[0] = 0;
mReserved[1] = 0;
mReserved[2] = 0;
}
void SamplerDesc::update(const gl::SamplerState &samplerState, bool stencilMode)
void SamplerDesc::update(const gl::SamplerState &samplerState,
bool stencilMode,
uint64_t externalFormat)
{
mMipLodBias = 0.0f;
mMaxAnisotropy = samplerState.getMaxAnisotropy();
mMinLod = samplerState.getMinLod();
mMaxLod = samplerState.getMaxLod();
// GL has no notion of external format, this must be provided from metadata from the image
mExternalFormat = externalFormat;
bool compareEnable = samplerState.getCompareMode() == GL_COMPARE_REF_TO_TEXTURE;
VkCompareOp compareOp = gl_vk::GetCompareOp(samplerState.getCompareFunc());
// When sampling from stencil, deqp tests expect texture compare to have no effect
@@ -1799,7 +1810,9 @@ void SamplerDesc::update(const gl::SamplerState &samplerState, bool stencilMode)
mMaxLod = 0.25f;
}
mReserved = 0;
mReserved[0] = 0;
mReserved[1] = 0;
mReserved[2] = 0;
}
angle::Result SamplerDesc::init(ContextVk *contextVk, vk::Sampler *sampler) const
@@ -1841,6 +1854,25 @@ angle::Result SamplerDesc::init(ContextVk *contextVk, vk::Sampler *sampler) cons
vk::AddToPNextChain(&createInfo, &filteringInfo);
}
VkSamplerYcbcrConversionInfo yuvConversionInfo = {};
if (mExternalFormat)
{
ASSERT((contextVk->getRenderer()->getFeatures().supportsYUVSamplerConversion.enabled));
yuvConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
yuvConversionInfo.pNext = nullptr;
yuvConversionInfo.conversion =
contextVk->getRenderer()->getYuvConversionCache().getYuvConversionFromExternalFormat(
mExternalFormat);
vk::AddToPNextChain(&createInfo, &yuvConversionInfo);
// Vulkan spec requires these settings:
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;
}
ANGLE_VK_TRY(contextVk, sampler->init(contextVk->getDevice(), createInfo));
return angle::Result::Continue;
@@ -2167,6 +2199,73 @@ angle::Result PipelineLayoutCache::getPipelineLayout(
return angle::Result::Continue;
}
// YuvConversionCache implementation
SamplerYcbcrConversionCache::SamplerYcbcrConversionCache() = default;
SamplerYcbcrConversionCache::~SamplerYcbcrConversionCache()
{
ASSERT(mPayload.empty());
}
void SamplerYcbcrConversionCache::destroy(RendererVk *renderer)
{
VkDevice device = renderer->getDevice();
for (auto &iter : mPayload)
{
vk::RefCountedSamplerYcbcrConversion &yuvSampler = iter.second;
ASSERT(!yuvSampler.isReferenced());
yuvSampler.get().destroy(device);
renderer->getActiveHandleCounts().onDeallocate(vk::HandleType::SamplerYcbcrConversion);
}
mPayload.clear();
}
angle::Result SamplerYcbcrConversionCache::getYuvConversion(
vk::Context *context,
uint64_t externalFormat,
const VkSamplerYcbcrConversionCreateInfo &yuvConversionCreateInfo,
vk::BindingPointer<vk::SamplerYcbcrConversion> *yuvConversionOut)
{
const auto iter = mPayload.find(externalFormat);
if (iter != mPayload.end())
{
vk::RefCountedSamplerYcbcrConversion &yuvConversion = iter->second;
yuvConversionOut->set(&yuvConversion);
return angle::Result::Continue;
}
vk::SamplerYcbcrConversion wrappedYuvConversion;
ANGLE_VK_TRY(context, wrappedYuvConversion.init(context->getDevice(), yuvConversionCreateInfo));
auto insertedItem = mPayload.emplace(
externalFormat, vk::RefCountedSamplerYcbcrConversion(std::move(wrappedYuvConversion)));
vk::RefCountedSamplerYcbcrConversion &insertedYuvConversion = insertedItem.first->second;
yuvConversionOut->set(&insertedYuvConversion);
context->getRenderer()->getActiveHandleCounts().onAllocate(
vk::HandleType::SamplerYcbcrConversion);
return angle::Result::Continue;
}
VkSamplerYcbcrConversion SamplerYcbcrConversionCache::getYuvConversionFromExternalFormat(
uint64_t externalFormat) const
{
const auto iter = mPayload.find(externalFormat);
if (iter != mPayload.end())
{
const vk::RefCountedSamplerYcbcrConversion &yuvConversion = iter->second;
return yuvConversion.get().getHandle();
}
// Should never get here if we have a valid externalFormat.
UNREACHABLE();
return VK_NULL_HANDLE;
}
// SamplerCache implementation.
SamplerCache::SamplerCache() = default;

View File

@@ -26,9 +26,10 @@ enum class ImageLayout;
using RenderPassAndSerial = ObjectAndSerial<RenderPass>;
using PipelineAndSerial = ObjectAndSerial<Pipeline>;
using RefCountedDescriptorSetLayout = RefCounted<DescriptorSetLayout>;
using RefCountedPipelineLayout = RefCounted<PipelineLayout>;
using RefCountedSampler = RefCounted<Sampler>;
using RefCountedDescriptorSetLayout = RefCounted<DescriptorSetLayout>;
using RefCountedPipelineLayout = RefCounted<PipelineLayout>;
using RefCountedSampler = RefCounted<Sampler>;
using RefCountedSamplerYcbcrConversion = RefCounted<SamplerYcbcrConversion>;
// Helper macro that casts to a bitfield type then verifies no bits were dropped.
#define SetBitField(lhs, rhs) \
@@ -609,13 +610,13 @@ class SamplerDesc final
{
public:
SamplerDesc();
explicit SamplerDesc(const gl::SamplerState &samplerState, bool stencilMode);
SamplerDesc(const gl::SamplerState &samplerState, bool stencilMode, uint64_t externalFormat);
~SamplerDesc();
SamplerDesc(const SamplerDesc &other);
SamplerDesc &operator=(const SamplerDesc &rhs);
void update(const gl::SamplerState &samplerState, bool stencilMode);
void update(const gl::SamplerState &samplerState, bool stencilMode, uint64_t externalFormat);
void reset();
angle::Result init(ContextVk *contextVk, vk::Sampler *sampler) const;
@@ -630,6 +631,14 @@ class SamplerDesc final
float mMinLod;
float mMaxLod;
// If the sampler needs to convert the image content (e.g. from YUV to RGB) then mExternalFormat
// will be non-zero and match the external format as returned from
// vkGetAndroidHardwareBufferPropertiesANDROID.
// The externalFormat is guaranteed to be unique and any image with the same externalFormat can
// use the same conversion sampler. Thus externalFormat works as a Serial() used elsewhere in
// ANGLE.
uint64_t mExternalFormat;
// 16 bits for modes + states.
// 1 bit per filter (only 2 possible values in GL: linear/nearest)
uint16_t mMagFilter : 1;
@@ -649,12 +658,11 @@ class SamplerDesc final
// Border color and unnormalized coordinates implicitly set to contants.
// 16 extra bits reserved for future use.
uint16_t mReserved;
// 48 extra bits reserved for future use.
uint16_t mReserved[3];
};
// Total size: 160 bits == 20 bytes.
static_assert(sizeof(SamplerDesc) == 20, "Unexpected SamplerDesc size");
static_assert(sizeof(SamplerDesc) == 32, "Unexpected SamplerDesc size");
// Disable warnings about struct padding.
ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
@@ -1051,6 +1059,26 @@ class SamplerCache final : angle::NonCopyable
std::unordered_map<vk::SamplerDesc, vk::RefCountedSampler> mPayload;
};
// YuvConversion Cache
class SamplerYcbcrConversionCache final : angle::NonCopyable
{
public:
SamplerYcbcrConversionCache();
~SamplerYcbcrConversionCache();
void destroy(RendererVk *render);
angle::Result getYuvConversion(
vk::Context *context,
uint64_t externalFormat,
const VkSamplerYcbcrConversionCreateInfo &yuvConversionCreateInfo,
vk::BindingPointer<vk::SamplerYcbcrConversion> *yuvConversionOut);
VkSamplerYcbcrConversion getYuvConversionFromExternalFormat(uint64_t externalFormat) const;
private:
std::unordered_map<uint64_t, vk::RefCountedSamplerYcbcrConversion> mPayload;
};
// Some descriptor set and pipeline layout constants.
//
// The set/binding assignment is done as following:

View File

@@ -1145,7 +1145,15 @@ void Format::initialize(RendererVk *renderer, const angle::Format &angleFormat)
break;
case angle::FormatID::NONE:
// This format is not implemented in Vulkan.
internalFormat = GL_NONE;
actualImageFormatID = angle::FormatID::NONE;
vkImageFormat = VK_FORMAT_UNDEFINED;
imageInitializerFunction = nullptr;
actualBufferFormatID = angle::FormatID::NONE;
vkBufferFormat = VK_FORMAT_UNDEFINED;
vkBufferFormatIsPacked = false;
vertexLoadFunction = nullptr;
vertexLoadRequiresConversion = false;
break;
case angle::FormatID::PVRTC1_RGBA_2BPP_UNORM_BLOCK:

View File

@@ -189,6 +189,13 @@ size_t Format::getImageCopyBufferAlignment() const
return alignment;
}
size_t Format::getValidImageCopyBufferAlignment() const
{
constexpr size_t kMinimumAlignment = 16;
return (intendedFormatID == angle::FormatID::NONE) ? kMinimumAlignment
: getImageCopyBufferAlignment();
}
bool Format::hasEmulatedImageChannels() const
{
const angle::Format &angleFmt = intendedFormat();

View File

@@ -84,6 +84,7 @@ struct Format final : private angle::NonCopyable
// Returns buffer alignment for image-copy operations (to or from a buffer).
size_t getImageCopyBufferAlignment() const;
size_t getValidImageCopyBufferAlignment() const;
// Returns true if the Image format has more channels than the ANGLE format.
bool hasEmulatedImageChannels() const;

View File

@@ -2469,6 +2469,8 @@ ImageHelper::ImageHelper(ImageHelper &&other)
mCurrentQueueFamilyIndex(other.mCurrentQueueFamilyIndex),
mLastNonShaderReadOnlyLayout(other.mLastNonShaderReadOnlyLayout),
mCurrentShaderReadStageMask(other.mCurrentShaderReadStageMask),
mYuvConversionSampler(std::move(other.mYuvConversionSampler)),
mExternalFormat(other.mExternalFormat),
mBaseLevel(other.mBaseLevel),
mMaxLevel(other.mMaxLevel),
mLayerCount(other.mLayerCount),
@@ -2503,6 +2505,7 @@ void ImageHelper::resetCachedProperties()
mLayerCount = 0;
mLevelCount = 0;
mCurrentSingleClearValue.reset();
mExternalFormat = 0;
}
void ImageHelper::initStagingBuffer(RendererVk *renderer,
@@ -2582,6 +2585,9 @@ angle::Result ImageHelper::initExternal(Context *context,
mCurrentLayout = initialLayout;
mYuvConversionSampler.reset();
mExternalFormat = 0;
ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
stageClearIfEmulatedFormat(context);
@@ -2736,18 +2742,34 @@ angle::Result ImageHelper::initMemory(Context *context,
return angle::Result::Continue;
}
angle::Result ImageHelper::initExternalMemory(Context *context,
const MemoryProperties &memoryProperties,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
uint32_t currentQueueFamilyIndex,
angle::Result ImageHelper::initExternalMemory(
Context *context,
const MemoryProperties &memoryProperties,
const VkMemoryRequirements &memoryRequirements,
const VkSamplerYcbcrConversionCreateInfo *samplerYcbcrConversionCreateInfo,
const void *extraAllocationInfo,
uint32_t currentQueueFamilyIndex,
VkMemoryPropertyFlags flags)
VkMemoryPropertyFlags flags)
{
// TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162
ANGLE_TRY(AllocateImageMemoryWithRequirements(context, flags, memoryRequirements,
extraAllocationInfo, &mImage, &mDeviceMemory));
mCurrentQueueFamilyIndex = currentQueueFamilyIndex;
#ifdef VK_USE_PLATFORM_ANDROID_KHR
if (samplerYcbcrConversionCreateInfo)
{
const VkExternalFormatANDROID *vkExternalFormat =
reinterpret_cast<const VkExternalFormatANDROID *>(
samplerYcbcrConversionCreateInfo->pNext);
ASSERT(vkExternalFormat->sType == VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID);
mExternalFormat = vkExternalFormat->externalFormat;
ANGLE_TRY(context->getRenderer()->getYuvConversionCache().getYuvConversion(
context, mExternalFormat, *samplerYcbcrConversionCreateInfo, &mYuvConversionSampler));
}
#endif
return angle::Result::Continue;
}
@@ -2797,9 +2819,8 @@ angle::Result ImageHelper::initLayerImageViewImpl(
viewInfo.image = mImage.getHandle();
viewInfo.viewType = gl_vk::GetImageViewType(textureType);
viewInfo.format = imageFormat;
ASSERT(viewInfo.format != VK_FORMAT_UNDEFINED);
if (swizzleMap.swizzleRequired())
if (swizzleMap.swizzleRequired() && !mYuvConversionSampler.valid())
{
viewInfo.components.r = gl_vk::GetSwizzle(swizzleMap.swizzleRed);
viewInfo.components.g = gl_vk::GetSwizzle(swizzleMap.swizzleGreen);
@@ -2821,6 +2842,15 @@ angle::Result ImageHelper::initLayerImageViewImpl(
viewInfo.pNext = imageViewUsageCreateInfo;
VkSamplerYcbcrConversionInfo yuvConversionInfo = {};
if (mYuvConversionSampler.valid())
{
ASSERT((context->getRenderer()->getFeatures().supportsYUVSamplerConversion.enabled));
yuvConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
yuvConversionInfo.pNext = nullptr;
yuvConversionInfo.conversion = mYuvConversionSampler.get().getHandle();
vk::AddToPNextChain(&viewInfo, &yuvConversionInfo);
}
ANGLE_VK_TRY(context, imageViewOut->init(context->getDevice(), viewInfo));
return angle::Result::Continue;
}

View File

@@ -1060,12 +1060,14 @@ class ImageHelper final : public Resource, public angle::Subject
angle::Result initMemory(Context *context,
const MemoryProperties &memoryProperties,
VkMemoryPropertyFlags flags);
angle::Result initExternalMemory(Context *context,
const MemoryProperties &memoryProperties,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
uint32_t currentQueueFamilyIndex,
VkMemoryPropertyFlags flags);
angle::Result initExternalMemory(
Context *context,
const MemoryProperties &memoryProperties,
const VkMemoryRequirements &memoryRequirements,
const VkSamplerYcbcrConversionCreateInfo *samplerYcbcrConversionCreateInfo,
const void *extraAllocationInfo,
uint32_t currentQueueFamilyIndex,
VkMemoryPropertyFlags flags);
angle::Result initLayerImageView(Context *context,
gl::TextureType textureType,
VkImageAspectFlags aspectMask,
@@ -1387,6 +1389,8 @@ class ImageHelper final : public Resource, public angle::Subject
GLuint *inputSkipBytes);
void onWrite() { mCurrentSingleClearValue.reset(); }
bool hasImmutableSampler() { return mExternalFormat != 0; }
uint64_t getExternalFormat() const { return mExternalFormat; }
private:
enum class UpdateSource
@@ -1523,6 +1527,10 @@ class ImageHelper final : public Resource, public angle::Subject
ImageLayout mLastNonShaderReadOnlyLayout;
VkPipelineStageFlags mCurrentShaderReadStageMask;
// For imported images
vk::BindingPointer<vk::SamplerYcbcrConversion> mYuvConversionSampler;
uint64_t mExternalFormat;
// Cached properties.
uint32_t mBaseLevel;
uint32_t mMaxLevel;

View File

@@ -775,6 +775,10 @@ PFN_vkImportFenceFdKHR vkImportFenceFdKHR = nullptr;
PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR
vkGetPhysicalDeviceExternalSemaphorePropertiesKHR = nullptr;
// VK_KHR_sampler_ycbcr_conversion
PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR = nullptr;
PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR = nullptr;
# if defined(ANGLE_PLATFORM_FUCHSIA)
// VK_FUCHSIA_imagepipe_surface
PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA = nullptr;
@@ -835,6 +839,13 @@ void InitTransformFeedbackEXTFunctions(VkDevice device)
GET_DEVICE_FUNC(vkCmdDrawIndirectByteCountEXT);
}
// VK_KHR_sampler_ycbcr_conversion
void InitSamplerYcbcrKHRFunctions(VkDevice device)
{
GET_DEVICE_FUNC(vkCreateSamplerYcbcrConversionKHR);
GET_DEVICE_FUNC(vkDestroySamplerYcbcrConversionKHR);
}
# if defined(ANGLE_PLATFORM_FUCHSIA)
void InitImagePipeSurfaceFUCHSIAFunctions(VkInstance instance)
{

View File

@@ -482,6 +482,12 @@ class BindingPointer final : angle::NonCopyable
~BindingPointer() { reset(); }
BindingPointer(BindingPointer &&other)
{
set(other.mRefCounted);
other.reset();
}
void set(RefCounted<T> *refCounted)
{
if (mRefCounted)
@@ -685,6 +691,7 @@ void InitDebugUtilsEXTFunctions(VkInstance instance);
void InitDebugReportEXTFunctions(VkInstance instance);
void InitGetPhysicalDeviceProperties2KHRFunctions(VkInstance instance);
void InitTransformFeedbackEXTFunctions(VkDevice device);
void InitSamplerYcbcrKHRFunctions(VkDevice device);
# if defined(ANGLE_PLATFORM_FUCHSIA)
// VK_FUCHSIA_imagepipe_surface

View File

@@ -48,6 +48,7 @@ namespace vk
FUNC(QueryPool) \
FUNC(RenderPass) \
FUNC(Sampler) \
FUNC(SamplerYcbcrConversion) \
FUNC(Semaphore) \
FUNC(ShaderModule)
@@ -606,6 +607,15 @@ class Sampler final : public WrappedObject<Sampler, VkSampler>
VkResult init(VkDevice device, const VkSamplerCreateInfo &createInfo);
};
class SamplerYcbcrConversion final
: public WrappedObject<SamplerYcbcrConversion, VkSamplerYcbcrConversion>
{
public:
SamplerYcbcrConversion() = default;
void destroy(VkDevice device);
VkResult init(VkDevice device, const VkSamplerYcbcrConversionCreateInfo &createInfo);
};
class Event final : public WrappedObject<Event, VkEvent>
{
public:
@@ -1698,6 +1708,23 @@ ANGLE_INLINE VkResult Sampler::init(VkDevice device, const VkSamplerCreateInfo &
return vkCreateSampler(device, &createInfo, nullptr, &mHandle);
}
// SamplerYuvConversion implementation.
ANGLE_INLINE void SamplerYcbcrConversion::destroy(VkDevice device)
{
if (valid())
{
vkDestroySamplerYcbcrConversionKHR(device, mHandle, nullptr);
mHandle = VK_NULL_HANDLE;
}
}
ANGLE_INLINE VkResult
SamplerYcbcrConversion::init(VkDevice device, const VkSamplerYcbcrConversionCreateInfo &createInfo)
{
ASSERT(!valid());
return vkCreateSamplerYcbcrConversionKHR(device, &createInfo, nullptr, &mHandle);
}
// Event implementation.
ANGLE_INLINE void Event::destroy(VkDevice device)
{