首页 > 解决方案 > 在 Vulkan 中显示来自 ImageReader 的纹理

问题描述

我想知道是否可以使用 vulkan 显示来自 ImageReader 的纹理内容。

这就是创建 ImageReader 的方式

mReader = ImageReader.newInstance(1920, 1080, ImageFormat.PRIVATE, MAX_IMAGE_SIZE + 1);

图像包含安全内容。在 Vulkan 方面,我尝试获取硬件缓冲区并实例化图像,但验证层抱怨:

(ERROR / SPEC): msgNum: 0 - vkAllocateMemory: AHardwareBuffer_Desc 的格式 (2141391878) 和/或用法 (0x20002900) 与 Vulkan 不兼容。Vulkan 规范规定:如果 buffer 不为 NULL,则它必须是有效的 Android 硬件缓冲区对象,其 AHardwareBuffer_Desc::format 和 AHardwareBuffer_Desc::usage 与 Vulkan 兼容,如 Android 硬件缓冲区中所述。( https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01881 )

问题是 AHardwareBuffer 不是我创建的,是由 ImageReader 类创建的。

这是 C++ 端的代码:


VkAndroidHardwareBufferFormatPropertiesANDROID hardwareBufferFormat{
        .sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID,
        .pNext = nullptr,
    };

    VkAndroidHardwareBufferPropertiesANDROID hardwareBufferProperties{
        .sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
        .pNext = &hardwareBufferFormat,
    };

    vkGetAndroidHardwareBufferPropertiesANDROID(mLogicalDevice, buffer, &hardwareBufferProperties);

    LOGD("Size %lu MemType %s format 0x%X extFormat 0x%lX flags 0x%X",
         hardwareBufferProperties.allocationSize,
         GetMemoryTypeString(hardwareBufferProperties.memoryTypeBits).c_str(),
         hardwareBufferFormat.format, hardwareBufferFormat.externalFormat,
         hardwareBufferFormat.formatFeatures);
    LOGD("Flags: \n%s", GetFeatureFlagBitsString(hardwareBufferFormat.formatFeatures).c_str());

    LOGD("AHardwareBuffer format in vulkan is %d", hardwareBufferFormat.format);

    //VkFormat fmt = vk_format_from_android(hardwareBufferFormat.format, 0 );
    AHardwareBuffer_Desc hardwareBufferDesc{};
    AHardwareBuffer_describe(buffer, &hardwareBufferDesc);

    // Width and Height must be same as per spec
    mTexture.width = hardwareBufferDesc.width;
    mTexture.height = hardwareBufferDesc.height;
    mTexture.mipLevels = 1;
    mTexture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

    LOGD("Image width x height %dx%d", mTexture.width, mTexture.height);

    VkExternalFormatANDROID externalFormatAndroid{
        .sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
        .pNext = nullptr,
        .externalFormat = hardwareBufferFormat.externalFormat,
    };

    VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo{
        .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
        .pNext = &externalFormatAndroid,
        .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
    };

    VkAndroidHardwareBufferUsageANDROID hardwareBufferUsage {};
    VkImageFormatProperties2 properties {}; 
    VkPhysicalDeviceImageFormatInfo2 deviceImageFormat {};

    VkImageCreateInfo imageCreateInfo{
        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
        .pNext = &externalMemoryImageCreateInfo,
        .flags = 0,
        .imageType = VK_IMAGE_TYPE_2D,
        .format = VK_FORMAT_UNDEFINED,
        .extent = {mTexture.width, mTexture.height, 1},
        .mipLevels = mTexture.mipLevels,
        .arrayLayers = hardwareBufferDesc.layers,
        .samples = VK_SAMPLE_COUNT_1_BIT,
        .tiling = VK_IMAGE_TILING_OPTIMAL,
        .usage = VK_IMAGE_USAGE_SAMPLED_BIT,
        .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
        .queueFamilyIndexCount = 0,
        .pQueueFamilyIndices = nullptr,
        .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED,
    };

    CHECK_VK_RESULT(vkCreateImage(mLogicalDevice, &imageCreateInfo, nullptr, &mTexture.image));

    // AHardwareBuffer_Desc::format and AHardwareBuffer_Desc::usage must be valid and compatible
    // with Vulkan
    VkImportAndroidHardwareBufferInfoANDROID hardwareBufferInfo{
        .sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID,
        .pNext = nullptr,
        .buffer = buffer};

    VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo{
        .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
        .pNext = &hardwareBufferInfo,
        .image = mTexture.image,
        .buffer = VK_NULL_HANDLE,
    };

    /* TODO: Double check memoryTypeBits and using VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT */
    uint32_t mem_index = GetMemoryType(hardwareBufferProperties.memoryTypeBits,  0);
    if (mem_index < 0) {
        LOGE("Could not find matching memory type!");
        return VK_ERROR_INITIALIZATION_FAILED;
    }

    VkMemoryAllocateInfo memoryAllocateInfo{
        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
        .pNext = &memoryDedicatedAllocateInfo,
        .allocationSize = hardwareBufferProperties.allocationSize,
        .memoryTypeIndex = mem_index};

    // THIS IS WHERE THE VALIDATION THROWS ERROR
    CHECK_VK_RESULT(
        vkAllocateMemory(mLogicalDevice, &memoryAllocateInfo, nullptr, &mTexture.deviceMemory))

我知道正在处理私有内存,但规范似乎要求(即使是未知的内存格式)AHardwareBuffer_desc 格式必须是在 Vulkan 中具有等价物的东西;在我看来这是不合理的,因为在这种情况下,格式可能是专有的。

谢谢!

标签: androidc++exoplayervulkandecoder

解决方案


推荐阅读