#ifndef EGL_POOL_H
#define EGL_POOL_H
#include "./IBRGPU.h"
#include "./threadsafe_queue.cpp"
class EGL
{
public:
// 是对实际显示设备的抽象
EGLDisplay display;
// 是对用来存储图像的内存区域FrameBuffer 的抽象,包括 Color Buffer, Stencil Buffer ,Depth Buffer。
EGLContext context;
// 存储 OpenGL ES绘图的一些状态信息。
EGLSurface surface;
xverse::ixve *ixveEncode;
xverse::ixve *ixveDecode;
Shader *IBRShader;
Shader *depthShader;
};
/**
* @brief 获取一组EGL参数,并对该组参数进行初始化操作
*/
EGL GetEGL();
class EGLPool
{
public:
EGLPool(int minSize, int maxSize);
EGL GetEGL();
private:
int minSize, maxSize;
gdface::threadsafe_queue<EGL> gQueue;
void initPool();
EGL gen();
void watchCapacity();
xverse::ixve *initXveEncode(struct EncodeParam *encodeParam);
xverse::ixve *initXveDecode();
};
/**
* @brief 初始化EGL池子
* @param minSize 最小容量,如果使用过程中池子的容量减小到小于最小容量,
* 则会继续像池子中添加新对象
* @param maxSize 最大容量,池子会初始化为最大容量数,
* 后续池子的总容量也会小于最大容量
*/
void InitEGLPool(int minSize, int maxSize);
#endif
#include "./IBRGPU.h"
#include "./egl_pool.h"
#include "./threadsafe_queue.cpp"
static EGLPool *globalEGLPool;
/**
* @brief 初始化EGL池子
* @param minSize 最小容量,如果使用过程中池子的容量减小到小于最小容量,
* 则会继续像池子中添加新对象
* @param maxSize 最大容量,池子会初始化为最大容量数,
* 后续池子的总容量也会小于最大容量
*/
void InitEGLPool(int minSize, int maxSize)
{
globalEGLPool = new EGLPool(minSize, maxSize);
}
/**
* @brief 获取一组EGL参数,并对该组参数进行初始化操作
*/
EGL GetEGL()
{
return globalEGLPool->GetEGL();
}
/**
* @param minSize 最小容量,如果使用过程中池子的容量减小到小于最小容量,
* 则会继续像池子中添加新对象
* @param maxSize 最大容量,池子会初始化为最大容量数,
* 后续池子的总容量也会小于最大容量
*/
EGLPool::EGLPool(int minSize, int maxSize)
{
this->minSize = minSize;
this->maxSize = maxSize;
this->initPool();
};
EGL EGLPool::GetEGL()
{
return gQueue.wait_and_pop();
}
/**
* @brief 初始化池子
*/
void EGLPool::initPool()
{
std::cout << "== Init EGLPool == " << maxSize << std::endl;
for (unsigned int i = 0; i < maxSize; i++)
{
gQueue.push(gen());
}
std::cout << "== Init EGLPool finish == " << std::endl;
}
/**
* @brief 维护池子容量平衡
* @details 如果池子的容量减小到小于最小容量,
* 则会继续像池子中添加max-cuurent的对象个数
*/
void EGLPool::watchCapacity()
{
if (this->gQueue.size() < this->minSize)
{
int maxdiffer = this->maxSize - this->gQueue.size();
for (unsigned int i = 0; i < maxdiffer; i++)
{
gQueue.push(gen());
}
}
}
/**
* @brief 初始化EGL,并生成EGL信息
* @return EGL
*/
EGL EGLPool::gen()
{
std::cout << "== Init EGL == " << std::endl;
EGL egl;
// 1.选择显卡 todo 确定具体要多少设备去加载模型
static const int MAX_DEVICES = 10;
EGLDeviceEXT eglDevs[MAX_DEVICES];
EGLint numDev;
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
eglQueryDevicesEXT(MAX_DEVICES, eglDevs, &numDev);
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
// 选择显卡,双显卡0、1可以创建display,会有2、3的额外设备,但是创建出的display为空。
// 2.获取EGLDisplay
egl.display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevs[0], 0);
// 3.初始化与EGLDisplay之间的连接
EGLint major, minor; // major 主版本号,minor次版本号
eglInitialize(egl.display, &major, &minor);
// 3.获取EGLConfig对象
EGLint num_con;
EGLint attrlist[] = {
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_NONE};
EGLConfig config;
eglChooseConfig(egl.display, attrlist, &config, 1, &num_con);
// 后面创建的 surface 和 context 要与这个API相匹配
eglBindAPI(EGL_OPENGL_API);
egl.surface = eglCreatePbufferSurface(egl.display, config, NULL);
// 创建上下文
EGLint contextAttrs[] = {
EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT,
EGL_CONTEXT_MAJOR_VERSION, 4,
EGL_CONTEXT_MINOR_VERSION, 6,
EGL_NONE};
egl.context = eglCreateContext(egl.display, config, EGL_NO_CONTEXT, contextAttrs);
EGLBoolean err1 = eglGetError();
bool res;
res = eglMakeCurrent(egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl.context); //自己创建FBO绘制,可以不绑定surface
// GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLAD
std::cout << "== Init EGL =gladLoadGLLoader1= " << std::endl;
if (!gladLoadGLLoader((GLADloadproc)eglGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
exit(-1);
;
}
std::cout << "== Init EGL =gladLoadGLLoader2= " << std::endl;
if (!gladLoadGLLoader((GLADloadproc)eglGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
exit(-1);
;
}
GetGlobalModel()->setupMesh();
struct EncodeParam encodeParam;
encodeParam.fps = 30;
encodeParam.gop = 32;
string bitrate = "6m";
encodeParam.bitrate = bitrate.data();
egl.ixveEncode = initXveEncode(&encodeParam);
egl.ixveDecode = initXveDecode();
std::cout << "init IBR shader" << std::endl;
egl.IBRShader = new Shader("shader/mesh_based_render_image_shader_Pcf.vert", "shader/mesh_based_render_image_shader_Pcf.frag");
egl.IBRShader->use();
egl.IBRShader->setInt("texture_image_0", 0);
egl.IBRShader->setInt("depthMap_0", 1);
egl.IBRShader->setInt("texture_image_1", 2);
egl.IBRShader->setInt("depthMap_1", 3);
egl.IBRShader->setInt("texture_image_2", 4);
egl.IBRShader->setInt("depthMap_2", 5);
egl.IBRShader->setInt("texture_image_3", 6);
egl.IBRShader->setInt("depthMap_3", 7);
egl.IBRShader->setInt("texture_image_4", 8);
egl.IBRShader->setInt("depthMap_4", 9);
egl.IBRShader->setInt("texture_image_5", 10);
egl.IBRShader->setInt("depthMap_5", 11);
std::cout << "init depth shader" << std::endl;
egl.depthShader = new Shader("shader/mesh_based_depth.vs", "shader/mesh_based_depth.fs");
std::cout << "== Init EGL Finish == " << std::endl;
return egl;
}
xverse::ixve *EGLPool::initXveEncode(struct EncodeParam *encodeParam)
{
xverse::ixve *ixveEncode;
std::cout << "init xve encode " << std::endl;
CreateXVE(&ixveEncode);
xverse::EngineParam engine_param = {
.codec_param =
{
.extra_dpb_size = 0,
.nalu_buf_cnt = 0,
.color_space = xverse::emColorSpace::kColorSpaceNone, // not effective when dxva2/nvenc is used.
.nv_enc_params =
{
.width = uint32_t(1280),
.height = uint32_t(720),
//.fps = 30,
.fps = uint32_t(encodeParam->fps),
.gop = uint32_t(encodeParam->gop),
//.gop = uint32_t(encodeParam->gop),
// .buffer_format = (char *)"iyuv", // todo: use codec_param.color_space instead
.buffer_format = (char *)"abgr", // todo: use codec_param.color_space instead
// .avg_bitrate = (char *)"4m",
.avg_bitrate = encodeParam->bitrate,
},
// .nv_enc_category = xverse::NvEncCategories::kNvEncCateUsingCuda,
.nv_enc_category = xverse::NvEncCategories::kNvEncCateUsingEGL,
.pixve = ixveEncode,
},
.codec_type =
{
// .hard_soft = xverse::emCodecTypeHardSoft::kSoftware,
.hard_soft = xverse::emCodecTypeHardSoft::kHardware,
.enc_dec = xverse::emCodecTypeEncDec::kEncoder,
.standard = xverse::emCodecTypeStd::kH264,
},
.log_level = xverse::emLogLevel::kVerbose,
.log_callback = nullptr,
};
ixveEncode->Open(&engine_param);
std::cout << "init xve encode finished " << std::endl;
return ixveEncode;
}
xverse::ixve *EGLPool::initXveDecode()
{
xverse::ixve *ixveDecode;
std::cout << "init xve decode " << std::endl;
CreateXVE(&ixveDecode);
bool init_cuda_in_sdk = false;
CUcontext cuContext = nullptr;
string log_filename = "/tmp/ibr.log";
if (!init_cuda_in_sdk)
{
std::cout << "init cuda: " << std::endl;
// todo: encapsulate into a utility function
CUresult cuda_res = cuInit(0);
if (cuda_res < 0)
{
std::cout << "error cuinit\n";
}
int nGpu = 0;
cuda_res = cuDeviceGetCount(&nGpu);
if (cuda_res < 0)
{
std::cout << "error cuinit\n";
}
int iGpu = 0;
if (iGpu < 0 || iGpu >= nGpu)
{
std::cout << "GPU ordinal out of range. Should be within [" << 0 << ", " << nGpu - 1 << "]" << std::endl;
}
CUdevice cuDevice = 0;
cuda_res = cuDeviceGet(&cuDevice, iGpu);
if (cuda_res < 0)
{
std::cout << "error cuinit\n";
}
char szDeviceName[80];
cuda_res = cuDeviceGetName(szDeviceName, sizeof(szDeviceName), cuDevice);
if (cuda_res < 0)
{
std::cout << "error cuinit\n";
}
std::cout << "[INFO] GPU in use: " << szDeviceName << std::endl;
cuda_res = cuCtxCreate(&cuContext, 0, cuDevice);
if (cuda_res < 0)
{
std::cout << "error cuinit\n";
}
}
std::cout << "init xve decode: \n";
xverse::EngineParam engine_param = {
.codec_param =
{
.extra_dpb_size = 0,
.nalu_buf_cnt = 0,
.color_space = xverse::emColorSpace::kColorSpaceI420, // not effective when dxva2/NVDEC is used.
.pixve = ixveDecode,
},
.codec_type =
{
.hard_soft = xverse::emCodecTypeHardSoft::kHardware,
.enc_dec = xverse::emCodecTypeEncDec::kDecoder,
.standard = xverse::emCodecTypeStd::kH265,
},
.log_level = xverse::emLogLevel::kVerbose,
.log_callback = nullptr,
.log_filename = log_filename.c_str(),
.init_cuda_inside = init_cuda_in_sdk,
.cu_ctx = (init_cuda_in_sdk ? nullptr : &cuContext),
.nv_dec_output_in_device_mem = 1};
ixveDecode->Open(&engine_param);
std::cout << "init xve decode finished " << std::endl;
return ixveDecode;
}