/*
* Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
* NVIDIA CORPORATION and its licensors retain all intellectual property
* and proprietary rights in and to this software, related documentation
* and any modifications thereto. Any use, reproduction, disclosure or
* distribution of this software and related documentation without an express
* license agreement from NVIDIA CORPORATION is strictly prohibited.
*/
/**
* @file
*
* NVIDIA Multimedia API: DRM Renderer API
*
* @b Description: Helper class for rendering using LibDRM.
*/
#ifndef __NV_DRM_RENDERER_H__
#define __NV_DRM_RENDERER_H__
#include "NvElement.h"
#include
#include
#include
#include
/**
*
* @defgroup l4t_mm_nvdrmrenderer_group DRM Renderer API
*
* @ingroup aa_framework_api_group
* @{
*/
/** Holds a buffer object handle. */
typedef struct _NvDrmBO {
uint32_t bo_handle; /**< Holds DRM buffer index. */
int width; /**< Holds width of the DRM buffer, in pixels. */
int height; /**< Holds height of the DRM buffer, in pixels. */
int pitch; /**< Holds stride/pitch of the DRM buffer. */
uint8_t* data; /**< Holds mapped CPU accessible address. */
} NvDrmBO;
/** Holds information about the frame. */
typedef struct _NvDrmFB {
uint32_t fb_id; /**< Holds the frame ID. */
int width; /**< Holds width of the frame, in pixels. */
int height; /**< Holds height of the frame, in pixels. */
int format; /**< Holds frame format, such as @c DRM_FORMAT_RGB332.
This class supports a subset of the formats defined
in @c drm_fourcc.h, the standard DRM header. */
NvDrmBO bo[4]; /**< Holds DRM buffer handles. */
int num_buffers; /**< Holds the number of DRM buffers, which depends on
the buffer format. */
} NvDrmFB;
/**
* @brief Helper class for rendering using LibDRM.
*
* The renderer requires the file descriptor of a buffer as an input. The caller
* must set the rendering rate in terms of frames per second (FPS).
*
* The caller specifies the width, height connector, and CRTC index.
* Based on the connector and CRTC index, the renderer finds a suitable encoder
* and configures the CRTC mode.
*/
class NvDrmRenderer:public NvElement
{
public:
/**
* Creates a new DRM based renderer named @a name.
*
* @param[in] name Unique name to identity the element instance.
* @param[in] width Width of the window in pixels.
* @param[in] height Height of the window in pixels.
* @param[in] w_x x offset of window location.
* @param[in] w_y y offset of window location.
* @param[in] connector Index of connector to use.
* @param[in] crtc Index of CRTC to use.
* @param[in] metadata Contains HDR metadata.
* @param[in] streamHDR Flag indicating that the current stream has HDR
* metadata, and hence @a metadata is set.
* @returns Reference to the newly created renderer object if successful,
* or NULL if initialization failed.
*/
static NvDrmRenderer *createDrmRenderer(const char *name, uint32_t width,
uint32_t height, uint32_t w_x, uint32_t w_y,
uint32_t connector, uint32_t crtc,
struct drm_tegra_hdr_metadata_smpte_2086 metadata,
bool streamHDR);
~NvDrmRenderer();
/**
* Enqueues a buffer file descriptor for rendering.
*
* This is a non-blocking call. The function waits for the estimated
* rendering time of the next buffer. The estimated rendering time is
* calculated based on the rendering time of the last buffer and the
* rendering rate.
*
* @param[in] fd File descriptor of the exported buffer to render.
* @returns 0 for success, or -1 otherwise.
*/
int enqueBuffer(int fd);
/**
* Dequeues a previously rendered buffer.
*
* This is blocking function that waits until a free buffer is available.
* The renderer retains one buffer, which must not be overwritten
* by any other component. This buffer can be used when the renderer
* is closed or after sending an EOS to the component.
*
* @returns File descriptor of the previously rendered buffer.
*/
int dequeBuffer();
/**
* Sets the rendering rate in terms of frames per second.
*
* \warning @a fps may not be set to zero.
*
* @param[in] fps Rendering rate in frames per second.
* @returns 0 for success, or -1 otherwise.
*/
int setFPS(float fps);
/**
* Enables/disables DRM universal planes client caps,
* such as @c DRM_CLIENT_CAP_UNIVERSAL_PLANES.
*
* @param[in] enable 1 to enable the caps, or 0 to disable them.
* @returns true if successful, or false otherwise.
*/
bool enableUniversalPlanes(int enable);
/**
* Allocates a framebuffer of size (w, h).
*
* @post If the call is successful, the application must remove (free) the
* framebuffer by calling removeFB().
*
* @param[in] width Framebuffer width in pixels.
* @param[in] height Framebuffer height in pixels.
* @param[in] drm_format DRM format of @a _NvDrmBO::bo_handle in @a *fb.
* @param[out] fb A pointer to an \ref NvDrmFB structure that
* contains the framebuffer ID and the buffer
* mapping.
*
* @return 1 if successful, or 0 otherwise.
*/
uint32_t createDumbFB(uint32_t width, uint32_t height, uint32_t drm_format, NvDrmFB *fb);
/**
* Destroys (frees) a framebuffer previously allocated by createDumbFB().
*
* @param fb_id The ID of the framebuffer to destroy.
* @return 0 if the framebuffer is successfully destroyed, or @c -ENOENT
* if the framebuffer is not found.
*/
int removeFB(uint32_t fb_id);
/**
* Close GEM (Graphics Execution Manager) handles.
*
* @param fd FD of the buffer.
* @param bo_handle the gem-handle to be closed.
*
* @return 1 for success, 0 for failure.
*/
int drmUtilCloseGemBo(int fd, uint32_t bo_handle);
/**
* Changes a plane's framebuffer and position.
*
* @note The @a crtc_... and @a src_... parameters accept the special input
* value -1, which indicates that the hardware offset value is not to be
* changed. (Kernel-based DRM drivers return the error code @c -ERANGE when
* given this value.)
*
* @note All @c %setPlane() operations are synced to vblank and are
* blocking.
*
* @param pl_index Plane index of the plane to be changed.
* @param fb_id Framebuffer ID of the framebuffer to display on the
* plane, or -1 to leave the framebuffer unchanged.
* @param crtc_x Offset from left of active display region to show plane.
* @param crtc_y Offset from top of active display region to show plane.
* @param crtc_w Width of output rectangle on display.
* @param crtc_h Height of output rectangle on display.
* @param src_x Clip offset from left of source framebuffer
* (Q16.16 fixed point).
* @param src_y Clip offset from top of source framebuffer
* (Q16.16 fixed point).
* @param src_w Width of source rectangle (Q16.16 fixed point).
* @param src_h Height of source rectangle (Q16.16 fixed point).
* @retval 0 if successful.
* @retval -EINVAL if @a pl_index is invalid.
* @retval -errno otherwise.
*/
int setPlane(uint32_t pl_index,
uint32_t fb_id,
uint32_t crtc_x,
uint32_t crtc_y,
uint32_t crtc_w,
uint32_t crtc_h,
uint32_t src_x,
uint32_t src_y,
uint32_t src_w,
uint32_t src_h);
/**
* Gets total number of planes available.
*
* By default, the count returned includes only "Overlay" type (regular)
* planes -- not "Primary" and "Cursor" planes. If
* @c DRM_CLIENT_CAP_UNIVERSAL_PLANES has been enabled with
* enableUniversalPlanes(), the count returned includes "Primary"
* and "Cursor" planes as well.
*
* @return Count of total planes available.
*/
int getPlaneCount();
/**
* Gets the plane indexes supported by the given
* crtc index.
*
* @param[in] crtc_index Index of crtc for which the
* plane indexes to be found.
* @param[in,out] plane_index Pointer to an array which
* contains plane indexes. This array should be allocated
* by the caller for the size of plane count returned
* by getPlaneCount() API.
*
* @return Count of the indexes written in the given array.
* */
int getPlaneIndex(uint32_t crtc_index,
int32_t* plane_index);
/**
* Gets count of available CRTCs.
*
* @return Count of available CRTCs.
*/
int getCrtcCount();
/**
* Gets count of available encoders.
*
* @return Count of available encoders.
*/
int getEncoderCount();
/**
* Checks whether the DRM renderer supports HDR mode.
*
* @return True if the DRM renderer supports HDR mode, or FALSE otherwise.
*/
bool hdrSupported();
/**
* Sets the HDR metadata retrieved from the decoder.
*
* @return 0 if successful, or -1 otherwise.
*/
int setHDRMetadataSmpte2086(struct drm_tegra_hdr_metadata_smpte_2086);
private:
struct timespec last_render_time; /**< Rendering time of the last buffer. */
int drm_fd; /**< File descriptor of opened DRM device. */
int conn, crtc;
uint32_t width, height;
uint32_t drm_conn_id; /**< DRM connector ID. */
uint32_t drm_enc_id; /**< DRM encoder ID. */
uint32_t drm_crtc_id; /**< DRM CRTC ID. */
uint32_t last_fb;
int activeFd;
int flippedFd;
bool flipPending;
bool renderingStarted;
bool is_nvidia_drm;
uint32_t hdrBlobId;
bool hdrBlobCreated;
std::queue freeBuffers;
std::queue pendingBuffers;
std::unordered_map map_list;
bool stop_thread; /**< Boolean variable used to signal rendering thread
to stop. */
pthread_t render_thread; /**< pthread ID of the rendering thread. */
pthread_mutex_t render_lock; /**< Used for synchronization. */
pthread_cond_t render_cond; /**< Used for synchronization. */
pthread_mutex_t enqueue_lock; /**< Used for synchronization. */
pthread_cond_t enqueue_cond; /**< Used for synchronization. */
pthread_mutex_t dequeue_lock; /**< Used for synchronization. */
pthread_cond_t dequeue_cond; /**< Used for synchronization. */
float fps; /**< Rendering rate in frames per second. */
uint64_t render_time_sec; /**< Seconds part of the time for which
a frame should be displayed. */
uint64_t render_time_nsec; /**< Nanoseconds part of the time for which
a frame should be displayed. */
/**
* Constructor called by the wrapper createDrmRenderer().
*
* \param[in] name A pointer to a unique name that identifies
* the element instance.
* \param[in] width Width of the window in pixels.
* \param[in] height Height of the window in pixels.
* \param[in] w_x X coordinate of the window's upper left corner.
* \param[in] w_y Y coordinate of the window's upper left corner.
* \param[in] connector Index of the connector to use.
* \param[in] crtc Index of the CRTC to use.
* \param[in] metadata A pointer to HDR metadata.
* \param[in] streamHDR TRUE if the current stream has HDR metadata,
* or FALSE otherwise. If TRUE,
* @a metadata must be set.
*/
NvDrmRenderer(const char *name, uint32_t width, uint32_t height,
uint32_t w_x, uint32_t w_y, uint32_t connector, uint32_t crtc,
struct drm_tegra_hdr_metadata_smpte_2086 metadata, bool streamHDR);
/**
* Function executed by the renderThread.
*
* This function is executed repeatedly until signalled to stop
* by the @c stop_thread variable. The function contains a while loop
* which calls renderInternal().
*
* \param[in] arg A pointer to an NvDrmRenderer object.
*/
static void * renderThread(void *arg);
static void * renderThreadOrin(void *arg);
/**
* Callback function for DRM flip event.
*/
static void page_flip_handler(int fd, unsigned int frame,
unsigned int sec, unsigned int usec, void *data);
/**
* Implements the logic of rendering a buffer
* and waiting until the buffer render time.
*
* \param[in] fd Identifier for the buffer to be rendered.
*/
int renderInternal(int fd);
/*
* Returns a DRM buffer_object handle.
*
* \param[in] w Width of the window in pixels.
* \param[in] h Height of the window in pixels.
* \param[in] bpp Bits per pixel in the window.
* \param[in] bo A pointer to a buffer object handle.
* \return An allocated DRM buffer_object handle of size (w,h)
*/
int createDumbBO(int w, int h, int bpp, NvDrmBO *bo);
static const NvElementProfiler::ProfilerField valid_fields =
NvElementProfiler::PROFILER_FIELD_TOTAL_UNITS |
NvElementProfiler::PROFILER_FIELD_FPS |
NvElementProfiler::PROFILER_FIELD_LATE_UNITS;
};
/** @} */
#endif