云渲染、云游戏核心技术之视频hook引擎的OpenGL(一)
云渲染、云游戏核心技术之视频hook引擎的OpenGL(一)
云端共享GPU资源
前言
云渲染客户端 采集的工作
提示:以下是本篇文章正文内容,下面案例可供参考
一、 采集端hook的流程
- 在渲染前一帧的数据拿到 拷贝同享GPU中去,编码从共享GPU中读取数据
在这里面有GPU同享时, 一些理论理解, 在向同享GPU中写入数据时 , GPU是不拷贝的 ,但是GPU读取这块GPU内存时,就会拷贝GPU到新GPU显存
二、hook到视频渲染前回调函数注册
// 拿到窗口销毁时回调地址
wgl_dc_proc = base_get_proc("wglDeleteContext");
// 交换
wgl_slb_proc = base_get_proc("wglSwapLayerBuffers");
// 要显示到屏幕上后一帧数据地址
wgl_sb_proc = base_get_proc("wglSwapBuffers");
// 注册回调函数事务开始
DetourTransactionBegin();
RealSwapBuffers = SwapBuffers;
// 注册回调函数 先处理我们函数, 在我们函数中调用原来的函数
DetourAttach((PVOID *)&RealSwapBuffers, hook_swap_buffers);
if (wgl_dc_proc)
{
RealWglDeleteContext = (PFN_WglDeleteContext)wgl_dc_proc;
DetourAttach((PVOID *)&RealWglDeleteContext,
hook_wgl_delete_context);
}
if (wgl_slb_proc)
{
RealWglSwapLayerBuffers = (PFN_WglSwapLayerBuffers)wgl_slb_proc;
DetourAttach((PVOID *)&RealWglSwapLayerBuffers,
hook_wgl_swap_layer_buffers);
}
if (wgl_sb_proc)
{
RealWglSwapBuffers = (PFN_WglSwapBuffers)wgl_sb_proc;
DetourAttach((PVOID *)&RealWglSwapBuffers,
hook_wgl_swap_buffers);
}
// 注册回调函数事务结束
const LONG error = DetourTransactionCommit();
const bool success = error == NO_ERROR;
三、 共享GPU创建
static inline bool gl_shtex_init_d3d11_tex(void)
{
IDXGIResource* dxgi_res;
HRESULT hr;
D3D11_TEXTURE2D_DESC desc = {0};
desc.Width = data.cx;
desc.Height = data.cy;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = data.format;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
hr = ID3D11Device_CreateTexture2D(data.d3d11_device, &desc, NULL,
&data.d3d11_tex);
if (FAILED(hr)) {
printf("gl_shtex_init_d3d11_tex: failed to create texture" );
return false;
}
//
// 设置D3D11的同享GPU模式
hr = ID3D11Device_QueryInterface(data.d3d11_tex, &GUID_IDXGIResource,
(void**)&dxgi_res);
if (FAILED(hr))
{
printf("gl_shtex_init_d3d11_tex: failed to get IDXGIResource");
return false;
}
//共享GPU模式
hr = IDXGIResource_GetSharedHandle(dxgi_res, &data.handle);
IDXGIResource_Release(dxgi_res);
if (FAILED(hr))
{
printf("gl_shtex_init_d3d11_tex: failed to get shared handle");
return false;
}
return true;
}
四、 拷贝数据到共享GPU中
static void gl_copy_backbuffer(GLuint dst)
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, data.fbo);
if (gl_error("gl_copy_backbuffer", "failed to bind FBO"))
{
return;
}
glBindTexture(GL_TEXTURE_2D, dst);
if (gl_error("gl_copy_backbuffer", "failed to bind texture"))
{
return;
}
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, dst, 0);
if (gl_error("gl_copy_backbuffer", "failed to set frame buffer"))
{
return;
}
glReadBuffer(GL_BACK);
/* darkest dungeon fix */
darkest_dungeon_fix = glGetError() == GL_INVALID_OPERATION && _strcmpi(process_name, "Darkest.exe") == 0 ;
glDrawBuffer(GL_COLOR_ATTACHMENT0);
if (gl_error("gl_copy_backbuffer", "failed to set draw buffer"))
{
return;
}
// 复制GPU数据 位置参数
glBlitFramebuffer(0, data.cy, data.cx, 0, 0, 0, data.cx, data.cy,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
gl_error("gl_copy_backbuffer", "failed to blit");
}
static void gl_shtex_capture(void)
{
GLint last_fbo;
GLint last_tex;
// 1. 加锁 GPU的内存
jimglDXLockObjectsNV(data.gl_device, 1, &data.gl_dxobj);
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &last_fbo);
if (gl_error("gl_shtex_capture", "failed to get last fbo"))
{
return;
}
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
if (gl_error("gl_shtex_capture", "failed to get last texture"))
{
return;
}
// 拷贝GPU到共享GPU中去
gl_copy_backbuffer(data.texture);
glBindTexture(GL_TEXTURE_2D, last_tex);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, last_fbo);
// 拷贝到共享GPU中去了
jimglDXUnlockObjectsNV(data.gl_device, 1, &data.gl_dxobj);
IDXGISwapChain_Present(data.dxgi_swap, 0, 0);
return;
}