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

Commit 1612a4ed authored by Chris Forbes's avatar Chris Forbes Committed by Android (Google) Code Review
Browse files

Merge "Break QueuePresentKHR into more manageable pieces"

parents 95c2b195 4cd01fb2
Loading
Loading
Loading
Loading
+181 −172
Original line number Diff line number Diff line
@@ -243,6 +243,11 @@ enum { MAX_TIMING_INFOS = 10 };
// syncronous requests to Surface Flinger):
enum { MIN_NUM_FRAMES_AGO = 5 };

bool IsSharedPresentMode(VkPresentModeKHR mode) {
    return mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
        mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR;
}

struct Swapchain {
    Swapchain(Surface& surface_,
              uint32_t num_images_,
@@ -254,9 +259,7 @@ struct Swapchain {
          pre_transform(pre_transform_),
          frame_timestamps_enabled(false),
          acquire_next_image_timeout(-1),
          shared(present_mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
                 present_mode ==
                     VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
          shared(IsSharedPresentMode(present_mode)) {
        ANativeWindow* window = surface.window.get();
        native_window_get_refresh_cycle_duration(
            window,
@@ -1796,127 +1799,33 @@ static VkResult WorstPresentResult(VkResult a, VkResult b) {
    return a != VK_SUCCESS ? a : b;
}

VKAPI_ATTR
VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
    ATRACE_CALL();

    ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
             "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
             present_info->sType);

    VkDevice device = GetData(queue).driver_device;
    const auto& dispatch = GetData(queue).driver;
    VkResult final_result = VK_SUCCESS;

    // Look at the pNext chain for supported extension structs:
    const VkPresentRegionsKHR* present_regions = nullptr;
    const VkPresentTimesInfoGOOGLE* present_times = nullptr;
    const VkPresentRegionsKHR* next =
        reinterpret_cast<const VkPresentRegionsKHR*>(present_info->pNext);
    while (next) {
        switch (next->sType) {
            case VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR:
                present_regions = next;
                break;
            case VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE:
                present_times =
                    reinterpret_cast<const VkPresentTimesInfoGOOGLE*>(next);
                break;
            default:
                ALOGV("QueuePresentKHR ignoring unrecognized pNext->sType = %x",
                      next->sType);
                break;
// KHR_incremental_present aspect of QueuePresentKHR
static void SetSwapchainSurfaceDamage(ANativeWindow *window, const VkPresentRegionKHR *pRegion) {
    std::vector<android_native_rect_t> rects(pRegion->rectangleCount);
    for (auto i = 0u; i < pRegion->rectangleCount; i++) {
        auto const& rect = pRegion->pRectangles[i];
        if (rect.layer > 0) {
            ALOGV("vkQueuePresentKHR ignoring invalid layer (%u); using layer 0 instead",
                rect.layer);
        }
        next = reinterpret_cast<const VkPresentRegionsKHR*>(next->pNext);
    }
    ALOGV_IF(
        present_regions &&
            present_regions->swapchainCount != present_info->swapchainCount,
        "VkPresentRegions::swapchainCount != VkPresentInfo::swapchainCount");
    ALOGV_IF(present_times &&
                 present_times->swapchainCount != present_info->swapchainCount,
             "VkPresentTimesInfoGOOGLE::swapchainCount != "
             "VkPresentInfo::swapchainCount");
    const VkPresentRegionKHR* regions =
        (present_regions) ? present_regions->pRegions : nullptr;
    const VkPresentTimeGOOGLE* times =
        (present_times) ? present_times->pTimes : nullptr;
    const VkAllocationCallbacks* allocator = &GetData(device).allocator;
    android_native_rect_t* rects = nullptr;
    uint32_t nrects = 0;

    for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
        Swapchain& swapchain =
            *SwapchainFromHandle(present_info->pSwapchains[sc]);
        uint32_t image_idx = present_info->pImageIndices[sc];
        Swapchain::Image& img = swapchain.images[image_idx];
        const VkPresentRegionKHR* region =
            (regions && !swapchain.mailbox_mode) ? &regions[sc] : nullptr;
        const VkPresentTimeGOOGLE* time = (times) ? &times[sc] : nullptr;
        VkResult swapchain_result = VK_SUCCESS;
        VkResult result;
        int err;

        int fence = -1;
        result = dispatch.QueueSignalReleaseImageANDROID(
            queue, present_info->waitSemaphoreCount,
            present_info->pWaitSemaphores, img.image, &fence);
        if (result != VK_SUCCESS) {
            ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
            swapchain_result = result;
        rects[i].left = rect.offset.x;
        rects[i].bottom = rect.offset.y;
        rects[i].right = rect.offset.x + rect.extent.width;
        rects[i].top = rect.offset.y + rect.extent.height;
    }
    native_window_set_surface_damage(window, rects.data(), rects.size());
}
        if (img.release_fence >= 0)
            close(img.release_fence);
        img.release_fence = fence < 0 ? -1 : dup(fence);

        if (swapchain.surface.swapchain_handle ==
            present_info->pSwapchains[sc]) {
// GOOGLE_display_timing aspect of QueuePresentKHR
static void SetSwapchainFrameTimestamp(Swapchain &swapchain, const VkPresentTimeGOOGLE *pTime) {
    ANativeWindow *window = swapchain.surface.window.get();
            if (swapchain_result == VK_SUCCESS) {
                if (region) {
                    // Process the incremental-present hint for this swapchain:
                    uint32_t rcount = region->rectangleCount;
                    if (rcount > nrects) {
                        android_native_rect_t* new_rects =
                            static_cast<android_native_rect_t*>(
                                allocator->pfnReallocation(
                                    allocator->pUserData, rects,
                                    sizeof(android_native_rect_t) * rcount,
                                    alignof(android_native_rect_t),
                                    VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
                        if (new_rects) {
                            rects = new_rects;
                            nrects = rcount;
                        } else {
                            rcount = 0;  // Ignore the hint for this swapchain
                        }
                    }
                    for (uint32_t r = 0; r < rcount; ++r) {
                        if (region->pRectangles[r].layer > 0) {
                            ALOGV(
                                "vkQueuePresentKHR ignoring invalid layer "
                                "(%u); using layer 0 instead",
                                region->pRectangles[r].layer);
                        }
                        int x = region->pRectangles[r].offset.x;
                        int y = region->pRectangles[r].offset.y;
                        int width = static_cast<int>(
                            region->pRectangles[r].extent.width);
                        int height = static_cast<int>(
                            region->pRectangles[r].extent.height);
                        android_native_rect_t* cur_rect = &rects[r];
                        cur_rect->left = x;
                        cur_rect->top = y + height;
                        cur_rect->right = x + width;
                        cur_rect->bottom = y;
                    }
                    native_window_set_surface_damage(window, rects, rcount);
                }
                if (time) {

    // We don't know whether the app will actually use GOOGLE_display_timing
    // with a particular swapchain until QueuePresent; enable it on the BQ
    // now if needed
    if (!swapchain.frame_timestamps_enabled) {
                        ALOGV(
                            "Calling "
                            "native_window_enable_frame_timestamps(true)");
        ALOGV("Calling native_window_enable_frame_timestamps(true)");
        native_window_enable_frame_timestamps(window, true);
        swapchain.frame_timestamps_enabled = true;
    }
@@ -1924,7 +1833,7 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
    // Record the nativeFrameId so it can be later correlated to
    // this present.
    uint64_t nativeFrameId = 0;
                    err = native_window_get_next_frame_id(
    int err = native_window_get_next_frame_id(
            window, &nativeFrameId);
    if (err != android::OK) {
        ALOGE("Failed to get next native frame ID.");
@@ -1932,20 +1841,63 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {

    // Add a new timing record with the user's presentID and
    // the nativeFrameId.
                    swapchain.timing.emplace_back(time, nativeFrameId);
                    while (swapchain.timing.size() > MAX_TIMING_INFOS) {
                        swapchain.timing.erase(swapchain.timing.begin());
    swapchain.timing.emplace_back(pTime, nativeFrameId);
    if (swapchain.timing.size() > MAX_TIMING_INFOS) {
        swapchain.timing.erase(
            swapchain.timing.begin(),
            swapchain.timing.begin() + swapchain.timing.size() - MAX_TIMING_INFOS);
    }
                    if (time->desiredPresentTime) {
                        // Set the desiredPresentTime:
    if (pTime->desiredPresentTime) {
        ALOGV(
                            "Calling "
                            "native_window_set_buffers_timestamp(%" PRId64 ")",
                            time->desiredPresentTime);
            "Calling native_window_set_buffers_timestamp(%" PRId64 ")",
            pTime->desiredPresentTime);
        native_window_set_buffers_timestamp(
            window,
                            static_cast<int64_t>(time->desiredPresentTime));
            static_cast<int64_t>(pTime->desiredPresentTime));
    }
}

static VkResult PresentOneSwapchain(
        VkQueue queue,
        Swapchain& swapchain,
        uint32_t imageIndex,
        const VkPresentRegionKHR *pRegion,
        const VkPresentTimeGOOGLE *pTime,
        uint32_t waitSemaphoreCount,
        const VkSemaphore *pWaitSemaphores) {

    VkDevice device = GetData(queue).driver_device;
    const auto& dispatch = GetData(queue).driver;

    Swapchain::Image& img = swapchain.images[imageIndex];
    VkResult swapchain_result = VK_SUCCESS;
    VkResult result;
    int err;

    // XXX: long standing issue: QueueSignalReleaseImageANDROID consumes the
    // wait semaphores, so this doesn't actually work for the multiple swapchain
    // case.
    int fence = -1;
    result = dispatch.QueueSignalReleaseImageANDROID(
        queue, waitSemaphoreCount,
        pWaitSemaphores, img.image, &fence);
    if (result != VK_SUCCESS) {
        ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
        swapchain_result = result;
    }
    if (img.release_fence >= 0)
        close(img.release_fence);
    img.release_fence = fence < 0 ? -1 : dup(fence);

    if (swapchain.surface.swapchain_handle == HandleFromSwapchain(&swapchain)) {
        ANativeWindow* window = swapchain.surface.window.get();
        if (swapchain_result == VK_SUCCESS) {

            if (pRegion) {
                SetSwapchainSurfaceDamage(window, pRegion);
            }
            if (pTime) {
                SetSwapchainFrameTimestamp(swapchain, pTime);
            }

            err = window->queueBuffer(window, img.buffer.get(), fence);
@@ -2011,15 +1963,72 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
        swapchain_result = VK_ERROR_OUT_OF_DATE_KHR;
    }

    return swapchain_result;
}

VKAPI_ATTR
VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
    ATRACE_CALL();

    ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
             "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
             present_info->sType);

    VkResult final_result = VK_SUCCESS;

    // Look at the pNext chain for supported extension structs:
    const VkPresentRegionsKHR* present_regions = nullptr;
    const VkPresentTimesInfoGOOGLE* present_times = nullptr;
    const VkPresentRegionsKHR* next =
        reinterpret_cast<const VkPresentRegionsKHR*>(present_info->pNext);
    while (next) {
        switch (next->sType) {
            case VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR:
                present_regions = next;
                break;
            case VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE:
                present_times =
                    reinterpret_cast<const VkPresentTimesInfoGOOGLE*>(next);
                break;
            default:
                ALOGV("QueuePresentKHR ignoring unrecognized pNext->sType = %x",
                      next->sType);
                break;
        }
        next = reinterpret_cast<const VkPresentRegionsKHR*>(next->pNext);
    }
    ALOGV_IF(
        present_regions &&
            present_regions->swapchainCount != present_info->swapchainCount,
        "VkPresentRegions::swapchainCount != VkPresentInfo::swapchainCount");
    ALOGV_IF(present_times &&
                 present_times->swapchainCount != present_info->swapchainCount,
             "VkPresentTimesInfoGOOGLE::swapchainCount != "
             "VkPresentInfo::swapchainCount");
    const VkPresentRegionKHR* regions =
        (present_regions) ? present_regions->pRegions : nullptr;
    const VkPresentTimeGOOGLE* times =
        (present_times) ? present_times->pTimes : nullptr;

    for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
        Swapchain& swapchain =
            *SwapchainFromHandle(present_info->pSwapchains[sc]);

        VkResult swapchain_result = PresentOneSwapchain(
            queue,
            swapchain,
            present_info->pImageIndices[sc],
            (regions && !swapchain.mailbox_mode) ? &regions[sc] : nullptr,
            times ? &times[sc] : nullptr,
            present_info->waitSemaphoreCount,
            present_info->pWaitSemaphores);

        if (present_info->pResults)
            present_info->pResults[sc] = swapchain_result;

        if (swapchain_result != final_result)
            final_result = WorstPresentResult(final_result, swapchain_result);
    }
    if (rects) {
        allocator->pfnFree(allocator->pUserData, rects);
    }

    return final_result;
}