blob: 00d8af59c1c9c399c67b481fa2ba64816f7e9ccc [file] [log] [blame]
// Copyright 2019 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.
#ifndef SRC_MEDIA_DRIVERS_AMLOGIC_ENCODER_DEVICE_CTX_H_
#define SRC_MEDIA_DRIVERS_AMLOGIC_ENCODER_DEVICE_CTX_H_
#include <fuchsia/hardware/mediacodec/c/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/device-protocol/pdev.h>
#include <lib/device-protocol/platform-device.h>
#include <lib/fidl-utils/bind.h>
#include <lib/sync/completion.h>
#include <zircon/fidl.h>
#include <zircon/types.h>
#include <memory>
#include <thread>
#include <unordered_map>
#include <ddk/driver.h>
#include <ddk/platform-defs.h>
#include <ddk/protocol/amlogiccanvas.h>
#include <ddk/protocol/platform/device.h>
#include <ddk/protocol/sysmem.h>
#include <ddktl/device.h>
#include <ddktl/protocol/empty-protocol.h>
#include "ddktl/protocol/amlogiccanvas.h"
#include "ddktl/protocol/platform/device.h"
#include "ddktl/protocol/sysmem.h"
#include "fuchsia/media/cpp/fidl.h"
#include "lib/mmio/mmio.h"
#include "lib/zx/interrupt.h"
#include "src/media/drivers/amlogic_encoder/internal_buffer.h"
#include "src/media/drivers/amlogic_encoder/local_codec_factory.h"
#include "src/media/drivers/amlogic_encoder/registers.h"
#include "src/media/drivers/amlogic_encoder/scoped_canvas.h"
constexpr uint32_t kInitialQuant = 26;
constexpr uint32_t kCanvasMinWidthAlignment = 32;
constexpr uint32_t kCanvasMinHeightAlignment = 16;
constexpr uint32_t kPictureMinAlignment = 16;
constexpr uint32_t kDefaultGopSize = 8;
constexpr uint32_t kDefaultBitRate = 200000;
constexpr uint32_t kDefaultFrameRate = 30;
enum InputFormat {
kNv12 = 3,
};
enum NoiseReductionMode {
kDisabled = 0,
kSNROnly = 1,
kTNROnly = 2,
k3DNR = 3,
};
enum class SocType {
kUnknown,
// These should be ordered from oldest to newest.
kG12A = 2, // S905D2
kG12B = 3, // T931
};
// Returns true if |a| is newer than or the same as |b|.
inline bool IsDeviceAtLeast(SocType a, SocType b) {
return static_cast<int>(a) >= static_cast<int>(b);
}
class DeviceCtx;
using DeviceType = ddk::Device<DeviceCtx, ddk::UnbindableNew, ddk::Messageable>;
// Manages context for the device's lifetime.
class DeviceCtx : public DeviceType, public ddk::EmptyProtocol<ZX_PROTOCOL_MEDIA_CODEC> {
public:
// Creates and binds an instance of `DeviceCtx`. If successful, returns ZX_OK
// and a bound instance of `DeviceCtx`, otherwise an error status and
// `nullptr`.
static std::unique_ptr<DeviceCtx> Create(zx_device_t* parent);
explicit DeviceCtx(zx_device_t* parent, ddk::PDevProtocolClient pdev,
ddk::AmlogicCanvasProtocolClient canvas, ddk::SysmemProtocolClient sysmem,
CbusRegisterIo cbus, DosRegisterIo dosbus, AoRegisterIo aobus,
HiuRegisterIo hiubus, zx::interrupt interrupt, zx::bti bti)
: DeviceType(parent),
pdev_(pdev),
canvas_(canvas),
sysmem_(sysmem),
cbus_(std::move(cbus)),
dosbus_(std::move(dosbus)),
aobus_(std::move(aobus)),
hiubus_(std::move(hiubus)),
bti_(std::move(bti)),
interrupt_handle_(std::move(interrupt)),
loop_(&kAsyncLoopConfigNoAttachToCurrentThread),
codec_admission_control_(std::make_unique<CodecAdmissionControl>(loop_.dispatcher())) {}
DeviceCtx(const DeviceCtx&) = delete;
DeviceCtx& operator=(const DeviceCtx&) = delete;
~DeviceCtx() { ShutDown(); }
// init and add device
zx_status_t Bind();
// media codec FIDL implementation
void GetCodecFactory(zx::channel request);
// Methods required by the ddk.
void DdkRelease();
void DdkUnbindNew(ddk::UnbindTxn txn);
zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn);
zx::unowned_bti bti() { return zx::unowned_bti(bti_); }
// This gets started connecting to sysmem, but returns an InterfaceHandle
// instead of InterfacePtr so that the caller can bind to the dispatcher.
fidl::InterfaceHandle<fuchsia::sysmem::Allocator> ConnectToSysmem();
// encoder control
zx_status_t EncoderInit(const fuchsia::media::FormatDetails& format_details);
zx_status_t UpdateEncoderSettings(const fuchsia::media::FormatDetails& format_details);
zx_status_t EnsureFwLoaded();
zx_status_t StopEncoder();
zx_status_t SetInputBuffer(const CodecBuffer* buffer);
void SetOutputBuffer(const CodecBuffer* buffer);
// Fills current output buffer with encoded NAL's. Will include SPS/PPS headers for each IDR.
zx_status_t EncodeFrame(uint32_t* output_len);
private:
void ShutDown();
zx_status_t PowerOn();
void InterruptInit();
zx_status_t BufferAlloc();
zx_status_t CanvasInit();
// populates firmware_ptr_ and firmware_size_
zx_status_t ParseFirmwarePackage();
zx_status_t LoadFirmware();
zx_status_t ParseFirmwarePackage(uintptr_t* firmware);
void FrameReset(bool idr);
zx_status_t EncodeSPSPPS();
void Start();
void Reset();
void Config(bool idr);
void ReferenceBuffersConfig();
void OutputBufferConfig(zx_paddr_t phys, size_t size);
void InputBufferConfig(zx_paddr_t phys, size_t size);
zx_status_t CanvasConfig(zx_handle_t vmo, uint32_t height, uint32_t bytes_per_row,
uint32_t offset, ScopedCanvasId* canvas_id_out, uint32_t alloc_flag);
void SetInputFormat();
void IeMeParameterInit(HcodecIeMeMbType::MbType mb_type);
void QuantTableInit();
zx_status_t CanvasInitReference(InternalBuffer* buf, ScopedCanvasId* y_canvas,
ScopedCanvasId* uv_canvas, uint32_t* packed_canvas_ids);
zx_status_t EncodeCmd(EncoderStatus cmd, uint32_t* output_len);
ddk::PDevProtocolClient pdev_;
ddk::AmlogicCanvasProtocolClient canvas_;
ddk::SysmemProtocolClient sysmem_;
SocType soc_type_ = SocType::kUnknown;
CbusRegisterIo cbus_;
DosRegisterIo dosbus_;
AoRegisterIo aobus_;
HiuRegisterIo hiubus_;
zx::bti bti_;
zx::vmo firmware_package_vmo_;
uintptr_t firmware_package_ptr_ = 0;
uint64_t firmware_package_size_ = 0;
// points into firmware_package_ptr_ at parsed out location
uintptr_t firmware_ptr_ = 0;
uint32_t firmware_size_ = 0;
bool firmware_loaded_ = false;
EncoderStatus hw_status_;
zx::interrupt interrupt_handle_;
std::thread interrupt_thread_;
sync_completion_t interrupt_sync_;
fuchsia::sysmem::AllocatorSyncPtr sysmem_sync_ptr_;
// working buffers for encoder
std::optional<InternalBuffer> dec0_;
std::optional<InternalBuffer> dec1_;
std::optional<InternalBuffer> assit_;
std::optional<InternalBuffer> scale_buff_;
std::optional<InternalBuffer> dump_info_;
std::optional<InternalBuffer> cbr_info_;
std::optional<InternalBuffer> sps_pps_data_;
uint32_t sps_pps_size_ = 0;
const CodecBuffer* input_buffer_ = nullptr;
const CodecBuffer* output_buffer_ = nullptr;
async::Loop loop_;
thrd_t loop_thread_;
// FIDL interfaces
std::unordered_map<LocalCodecFactory*, std::unique_ptr<LocalCodecFactory>> codec_factories_;
std::unique_ptr<CodecAdmissionControl> codec_admission_control_;
std::unique_ptr<CodecImpl> codec_instance_;
// Encoding settings
uint32_t gop_size_ = kDefaultGopSize;
uint32_t bit_rate_ = kDefaultBitRate;
uint32_t frame_rate_ = kDefaultFrameRate;
// Picture info
uint32_t encoder_width_;
uint32_t encoder_height_;
uint32_t rows_per_slice_;
// reset to 0 for IDR
uint16_t idr_pic_id_ = 0;
// increment each frame
uint32_t frame_number_ = 0;
// reset to 0 for IDR and imcrement by 2 for NON-IDR
uint32_t pic_order_cnt_lsb_ = 0;
NoiseReductionMode noise_reduction_;
InputFormat input_format_;
uint32_t me_weight_ = HcodecMeWeight::kMeWeightOffset;
uint32_t i4_weight_ = HcodecIeWeight::kI4MbWeightOffset;
uint32_t i16_weight_ = HcodecIeWeight::kI16MbWeightOffset;
uint32_t quant_table_i4_[8] = {};
uint32_t quant_table_i16_[8] = {};
uint32_t quant_table_me_[8] = {};
ScopedCanvasId input_y_canvas_;
ScopedCanvasId input_uv_canvas_;
ScopedCanvasId dec0_y_canvas_;
ScopedCanvasId dec0_uv_canvas_;
ScopedCanvasId dec1_y_canvas_;
ScopedCanvasId dec1_uv_canvas_;
uint32_t dblk_buf_canvas_;
uint32_t ref_buf_canvas_;
uint32_t input_canvas_ids_;
};
#endif // SRC_MEDIA_DRIVERS_AMLOGIC_ENCODER_DEVICE_CTX_H_