Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 244dbe4e authored by Tom Murphy's avatar Tom Murphy
Browse files

Extract GPDIFP2 getProducerUsage path to seperate function

Extracting the GPDIFP2 logic to its own function makes it easier to
exit early from the GPDIFP2 path when we need to fall back to the
GetSwapchainGrallocUsage*ANDROID path.

This change also fixes an issue where we would exit getProducerUsage
early instead of falling back to the gralloc paths if GPDIFP2 would
return an error when called with an unsupported format.

Bug: 379230826
Test: atest libvulkan_test
Flag: EXEMPT bugfix
Change-Id: I42f1fe31e5e4a01c472a12854a1f4e989d2786dc
parent 9fd5fdd4
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -22,6 +22,13 @@ package {
    default_applicable_licenses: ["frameworks_native_license"],
}

// Expose internal header files to test testing binary
cc_library_headers {
    name: "libvulkanprivate_headers-testing",
    export_include_dirs: ["."],
    visibility: ["//frameworks/native/vulkan/tests"],
}

ndk_library {
    name: "libvulkan",
    symbol_file: "libvulkan.map.txt",
+7 −0
Original line number Diff line number Diff line
{
  "presubmit": [
    {
      "name": "libvulkan_test"
    }
  ]
}
+119 −96
Original line number Diff line number Diff line
@@ -1413,17 +1413,12 @@ static void DestroySwapchainInternal(VkDevice device,
    allocator->pfnFree(allocator->pUserData, swapchain);
}

static VkResult getProducerUsage(const VkDevice& device,
static VkResult getProducerUsageGPDIFP2(
    const VkPhysicalDevice& pdev,
    const VkSwapchainCreateInfoKHR* create_info,
    const VkSwapchainImageUsageFlagsANDROID swapchain_image_usage,
    bool create_protected_swapchain,
    uint64_t* producer_usage) {
    // Get the physical device to query the appropriate producer usage
    const VkPhysicalDevice& pdev = GetData(device).driver_physical_device;
    const InstanceData& instance_data = GetData(pdev);
    const InstanceDriverTable& instance_dispatch = instance_data.driver;
    if (instance_dispatch.GetPhysicalDeviceImageFormatProperties2 ||
            instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR) {
    // Look through the create_info pNext chain passed to createSwapchainKHR
    // for an image compression control struct.
    // if one is found AND the appropriate extensions are enabled, create a
@@ -1433,11 +1428,13 @@ static VkResult getProducerUsage(const VkDevice& device,
    VkImageCompressionControlEXT image_compression = {};
    const VkSwapchainCreateInfoKHR* create_infos = create_info;
    while (create_infos->pNext) {
            create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(create_infos->pNext);
        create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
            create_infos->pNext);
        switch (create_infos->sType) {
            case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
                const VkImageCompressionControlEXT* compression_infos =
                        reinterpret_cast<const VkImageCompressionControlEXT*>(create_infos);
                    reinterpret_cast<const VkImageCompressionControlEXT*>(
                        create_infos);
                image_compression = *compression_infos;
                image_compression.pNext = nullptr;
                compression_control_pNext = &image_compression;
@@ -1452,7 +1449,8 @@ static VkResult getProducerUsage(const VkDevice& device,
    VkPhysicalDeviceExternalImageFormatInfo external_image_format_info = {
        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
        .pNext = compression_control_pNext,
            .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
        .handleType =
            VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
    };

    // AHB does not have an sRGB format so we can't pass it to GPDIFP
@@ -1469,7 +1467,8 @@ static VkResult getProducerUsage(const VkDevice& device,
        .type = VK_IMAGE_TYPE_2D,
        .tiling = VK_IMAGE_TILING_OPTIMAL,
        .usage = create_info->imageUsage,
            .flags = create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
        .flags =
            create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
    };

    // If supporting mutable format swapchain add the mutable format flag
@@ -1495,12 +1494,12 @@ static VkResult getProducerUsage(const VkDevice& device,
            result);
        return VK_ERROR_SURFACE_LOST_KHR;
    }

    // Determine if USAGE_FRONT_BUFFER is needed.
    // GPDIFP2 has no means of using VkSwapchainImageUsageFlagsANDROID when
    // querying for producer_usage. So androidHardwareBufferUsage will not
    // contain USAGE_FRONT_BUFFER. We need to manually check for usage here.
        if (!(swapchain_image_usage & VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID)) {
    if (!(swapchain_image_usage &
          VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID)) {
        *producer_usage = ahb_usage.androidHardwareBufferUsage;
        return VK_SUCCESS;
    }
@@ -1511,17 +1510,41 @@ static VkResult getProducerUsage(const VkDevice& device,
        .height = create_info->imageExtent.height,
        .layers = create_info->imageArrayLayers,
        .format = create_info->imageFormat,
            .usage = ahb_usage.androidHardwareBufferUsage | AHARDWAREBUFFER_USAGE_FRONT_BUFFER,
        .usage = ahb_usage.androidHardwareBufferUsage |
                 AHARDWAREBUFFER_USAGE_FRONT_BUFFER,
        .stride = 0,  // stride is always ignored when calling isSupported()
    };

        // If FRONT_BUFFER is not supported,
        // then we need to call GetSwapchainGrallocUsageXAndroid below
    // If FRONT_BUFFER is not supported in the GPDIFP2 path
    // then we need to fallback to GetSwapchainGrallocUsageXAndroid
    if (AHardwareBuffer_isSupported(&ahb_desc)) {
        *producer_usage = ahb_usage.androidHardwareBufferUsage;
        *producer_usage |= AHARDWAREBUFFER_USAGE_FRONT_BUFFER;
        return VK_SUCCESS;
    }

    return VK_ERROR_FORMAT_NOT_SUPPORTED;
}

static VkResult getProducerUsage(const VkDevice& device,
                                 const VkSwapchainCreateInfoKHR* create_info,
                                 const VkSwapchainImageUsageFlagsANDROID swapchain_image_usage,
                                 bool create_protected_swapchain,
                                 uint64_t* producer_usage) {
    // Get the physical device to query the appropriate producer usage
    const VkPhysicalDevice& pdev = GetData(device).driver_physical_device;
    const InstanceData& instance_data = GetData(pdev);
    const InstanceDriverTable& instance_dispatch = instance_data.driver;

    if (instance_dispatch.GetPhysicalDeviceImageFormatProperties2 ||
            instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR) {
        VkResult result =
            getProducerUsageGPDIFP2(pdev, create_info, swapchain_image_usage,
                                    create_protected_swapchain, producer_usage);
        if (result == VK_SUCCESS) {
            return VK_SUCCESS;
        }
        // Fall through to gralloc path on error
    }

    uint64_t native_usage = 0;
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ cc_test {

    header_libs: [
        "hwvulkan_headers",
        "libvulkanprivate_headers-testing",
        "vulkan_headers",
    ],

+90 −9
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */

#include <android/log.h>
#include <driver.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <media/NdkImageReader.h>
@@ -29,6 +30,8 @@

namespace android {

namespace libvulkantest {

class AImageReaderVulkanSwapchainTest : public ::testing::Test {
   public:
    AImageReaderVulkanSwapchainTest() {}
@@ -271,7 +274,7 @@ class AImageReaderVulkanSwapchainTest : public ::testing::Test {

        VkResult res =
            vkCreateSwapchainKHR(mDevice, &swapchainInfo, nullptr, &mSwapchain);
        VK_CHECK(res);
        if (res == VK_SUCCESS) {
            LOGI("Swapchain created successfully");

            uint32_t swapchainImageCount = 0;
@@ -282,6 +285,9 @@ class AImageReaderVulkanSwapchainTest : public ::testing::Test {
                                    swapchainImages.data());

            LOGI("Swapchain has %u images", swapchainImageCount);
        } else {
            LOGI("Swapchain creation failed");
        }
    }

    // Image available callback (AImageReader)
@@ -357,4 +363,79 @@ TEST_F(AImageReaderVulkanSwapchainTest, TestHelperMethods) {
    cleanUpSwapchainForTest();
}

// Passing state in these tests requires global state. Wrap each test in an
// anonymous namespace to prevent conflicting names.
namespace {

VKAPI_ATTR VkResult VKAPI_CALL hookedGetPhysicalDeviceImageFormatProperties2KHR(
    VkPhysicalDevice,
    const VkPhysicalDeviceImageFormatInfo2*,
    VkImageFormatProperties2*) {
    return VK_ERROR_SURFACE_LOST_KHR;
}

static PFN_vkGetSwapchainGrallocUsage2ANDROID
    pfnNextGetSwapchainGrallocUsage2ANDROID = nullptr;

static bool g_grallocCalled = false;

VKAPI_ATTR VkResult VKAPI_CALL hookGetSwapchainGrallocUsage2ANDROID(
    VkDevice device,
    VkFormat format,
    VkImageUsageFlags imageUsage,
    VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,
    uint64_t* grallocConsumerUsage,
    uint64_t* grallocProducerUsage) {
    g_grallocCalled = true;
    if (pfnNextGetSwapchainGrallocUsage2ANDROID) {
        return pfnNextGetSwapchainGrallocUsage2ANDROID(
            device, format, imageUsage, swapchainImageUsage,
            grallocConsumerUsage, grallocProducerUsage);
    }

    return VK_ERROR_INITIALIZATION_FAILED;
}

TEST_F(AImageReaderVulkanSwapchainTest, getProducerUsageFallbackTest1) {
    // BUG: 379230826
    // Verify that getProducerUsage falls back to
    // GetSwapchainGrallocUsage*ANDROID if GPDIFP2 fails
    std::vector<const char*> instanceLayers = {};
    std::vector<const char*> deviceLayers = {};
    createVulkanInstance(instanceLayers);

    createAImageReader(640, 480, AIMAGE_FORMAT_PRIVATE, 3);
    getANativeWindowFromReader();
    createVulkanSurface();
    pickPhysicalDeviceAndQueueFamily();

    createDeviceAndGetQueue(deviceLayers);
    auto& pdev = vulkan::driver::GetData(mDevice).driver_physical_device;
    auto& pdevDispatchTable = vulkan::driver::GetData(pdev).driver;
    auto& deviceDispatchTable = vulkan::driver::GetData(mDevice).driver;

    ASSERT_NE(deviceDispatchTable.GetSwapchainGrallocUsage2ANDROID, nullptr);

    pdevDispatchTable.GetPhysicalDeviceImageFormatProperties2 =
        hookedGetPhysicalDeviceImageFormatProperties2KHR;
    deviceDispatchTable.GetSwapchainGrallocUsage2ANDROID =
        hookGetSwapchainGrallocUsage2ANDROID;

    ASSERT_FALSE(g_grallocCalled);

    createSwapchain();

    ASSERT_TRUE(g_grallocCalled);

    ASSERT_NE(mVkInstance, (VkInstance)VK_NULL_HANDLE);
    ASSERT_NE(mPhysicalDev, (VkPhysicalDevice)VK_NULL_HANDLE);
    ASSERT_NE(mDevice, (VkDevice)VK_NULL_HANDLE);
    ASSERT_NE(mSurface, (VkSurfaceKHR)VK_NULL_HANDLE);
    cleanUpSwapchainForTest();
}

}  // namespace

}  // namespace libvulkantest

}  // namespace android