mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-03 14:09:33 +03:00
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:
committed by
Commit Bot
parent
b549be966f
commit
f61272fbf3
@@ -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 = {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user