blob: 0efdb0e6f404a09a59be016129c6deb52bd287a6 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <ddk/protocol/display/controller.h>
#include <fbl/ref_counted.h>
#include <fbl/ref_ptr.h>
#include <lib/zx/vmo.h>
#include <zircon/listnode.h>
#include <atomic>
#include "fence.h"
#include "fuchsia/hardware/display/c/fidl.h"
#include "id-map.h"
namespace display {
class Controller;
typedef struct image_node {
list_node_t link;
fbl::RefPtr<class Image> self;
} image_node_t;
class Image : public fbl::RefCounted<Image>, public IdMappable<fbl::RefPtr<Image>> {
public:
Image(Controller* controller, const image_t& info, zx::vmo vmo);
~Image();
image_t& info() { return info_; }
// Marks the image as in use.
bool Acquire();
// Marks the image as not in use. Should only be called before PrepareFences.
void DiscardAcquire();
// Called to set this image's fences and prepare the image to be displayed.
void PrepareFences(fbl::RefPtr<FenceReference>&& wait,
fbl::RefPtr<FenceReference>&& signal);
// Called to immediately retire the image if StartPresent hasn't been called yet.
void EarlyRetire();
// Called when the image is passed to the display hardware.
void StartPresent();
// Called when another image is presented after this one.
void StartRetire();
// Called on vsync after StartRetire has been called.
void OnRetire();
// Called on all waiting images when any fence fires.
void OnFenceReady(FenceReference* fence);
// Called to reset fences when client releases the image. Releasing fences
// is independent of the rest of the image lifecycle.
void ResetFences();
bool IsReady() const { return wait_fence_ == nullptr; }
bool HasSameConfig(const image_t& config) const {
for (uint32_t i = 0; i < countof(info_.planes); i++) {
if (info_.planes[i].bytes_per_row != config.planes[i].bytes_per_row ||
info_.planes[i].byte_offset != config.planes[i].byte_offset) {
return false;
}
}
return info_.width == config.width
&& info_.height == config.height
&& info_.pixel_format == config.pixel_format
&& info_.type == config.type;
}
bool HasSameConfig(const Image& other) const { return HasSameConfig(other.info_); }
const zx::vmo& vmo() { return vmo_; }
void set_z_index(uint32_t z_index) { z_index_ = z_index; }
uint32_t z_index() const { return z_index_; }
// The node alternates between a client's waiting image list and the controller's
// presented image list. The presented image list is protected with the controller mutex,
// and the waiting list is only accessed on the loop and thus is not generally
// protected. However, transfers between the lists are protected by the controller mutex.
image_node_t node = {
.link = LIST_INITIAL_CLEARED_VALUE,
.self = nullptr,
};
private:
image_t info_;
Controller* const controller_;
// z_index is set/read by controller.cpp under its lock
uint32_t z_index_;
// Only ever accessed on loop thread, so no synchronization
fbl::RefPtr<FenceReference> wait_fence_ = nullptr;
// signal_fence_ is only accessed on the loop. armed_signal_fence_ is accessed
// under the controller mutex. See comment in ::OnRetire for more details.
fbl::RefPtr<FenceReference> signal_fence_ = nullptr;
fbl::RefPtr<FenceReference> armed_signal_fence_ = nullptr;
// Flag which indicates that the image is currently in some display configuration.
std::atomic_bool in_use_ = {};
// Flag indicating that the image is being managed by the display hardware. Only
// accessed under the controller mutex.
bool presenting_ = false;
// Flag indicating that the image has started the process of retiring and will be free after
// the next vsync. This is distinct from presenting_ due to multiplexing the display between
// multiple clients. Only accessed under the controller mutex.
bool retiring_ = false;
const zx::vmo vmo_;
};
} // namespace display