首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

DirectX9(D3D9)游戏开发:高光时刻录制和共享纹理的踩坑

编程知识
2024年08月04日 09:13

共享纹理

老游戏使用directx9无法直接与cc高光sdk(d3d11)对接,但是d3d9ex有共享纹理,我们通过共享纹理把游戏画面共享给cc录制,记录一些踩坑的笔记。

共享纹理示例:

// 初始化Direct3D
void initD3D9(HWND hWnd)
{
    hr = d3d9exdev->GetRenderTarget(0, &g_d3d9RenderSurface);
    D3DSURFACE_DESC desc;
    g_d3d9RenderSurface->GetDesc(&desc);
    //关于格式说明:图像的格式必须与desc.format的格式一致,否则共享纹理的画面是黑色的,并且pool要使用default
    hr = d3d9exdev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT,
        &g_d3d9SharedSurface, &g_d3d9SharedHandle);
    if (FAILED(hr))
    {
        OutputDebugStringA("CreateOffscreenPlainSurface failed\n");
    }
}
// 渲染一帧
void RenderD3D9(void)
{
    hr = d3d9exdev->StretchRect(g_d3d9RenderSurface, NULL, g_d3d9SharedSurface, NULL, D3DTEXF_NONE);
    if (FAILED(hr))
    {
        OutputDebugStringA("GetRenderTargetData failed\n");
    }
}
//g_d3d9SharedHandle就是共享纹理的句柄,传给sdk进行录制
long long sharedHandleAddress = reinterpret_cast<long long>(g_d3d9SharedHandle);

创建d3d9ex

只有d3d9ex才能共享纹理,d3d9无法共享纹理

LPDIRECT3D9EX d3d9ex = nullptr;
Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9ex);

VS中正常,编译出的exe出错

在与cc联调的过程中碰到一个问题:从vs中启动共享纹理正常,而打包出来的exe共享纹理是黑色的。

最后通过各种排查,各种换方法,才定位到问题,我们游戏加载的d3d9.dll非微软原版的!

把我们游戏的d3d9.dll,发给CC测试发现:游戏进程CreateOffscreenPlainSurface创建的纹理在录制sdk无法打开

image-20240701125253381

那为什么从vs里启动就是正常的呢?

在vs中启动从模块窗口中可以看到加载的是系统的dll

image-20240701130544013

编译出来的exe相同dll加载的位置已经变了!

image-20240702101140384

尝试删掉或替换游戏目录下的d3d9.dll,测试结果如下表:

d3d9.dll 独立进程 同进程
替换d3d9.dll为微软原版
删除d3d9.dll

windows dll加载的顺序

打包应用系统按以下顺序搜索:

  1. DLL 重定向。
  2. API 集。
  3. 桌面应用仅 (UWP 应用) 。 SxS 清单重定向。
  4. Loaded-module 列表。
  5. 已知 DLL。
  6. 进程的包依赖项关系图。 这是应用程序的包,以及应用程序包清单的 节中指定的任何依赖项。 依赖项按它们在清单中的出现顺序进行搜索。
  7. 调用进程从加载的文件夹 (可执行文件的文件夹) 。
  8. 系统文件夹 (%SystemRoot%\system32) 。

附官方文档:Dynamic-link library search order - Win32 apps | Microsoft Learn

为什么要替换微软的d3d9.dll?

我们有部分集显玩家的地表会出问题,所以游戏内有个设置使用vulkan,勾选后会使用dxvk,不过这个dll也被命名为d3d9.dll,但是在内服为了截帧所以默认替换了游戏目录下的d3d9.dll

doitsujin/dxvk: Vulkan-based implementation of D3D9, D3D10 and D3D11 for Linux / Wine (github.com)

关闭编译优化导致录像闪屏

在我本地打包出来的游戏录像偶尔闪烁,而QA跑打包机打出来的游戏则录像视频特别闪,游戏内画面正常只有录像出现闪屏。

经过对比发现,我本地有两个工程的vs c++编译优化关闭了,也就是:项目 - 属性 - C/C++ - 优化:【最大优化O2】改成【已禁用】

image-20240703111252668

于是尝试打开我本地工程的c++优化,果然视频也会闪屏,那为什么这个优化会导致闪屏呢?

因为关闭优化后游戏运行速度变慢,游戏变慢就变成同步了从而掩盖了共享纹理的问题。而游戏是多线程的,对纹理的访问是非同步的就会闪烁。

最终解决办法

Moo::rc().device();获取D3D设备,而不是游戏初始化通过CreateDeviceEx创建的pD3D9Ex,因为引擎里对D3D9Ex进行了封装,默认就开启了D3D9Ex,并且 Moo::rc().device()处理了多线程的同步问题

HRESULT DXUTCreate3DEnvironment9( IDirect3DDevice9* pd3dDeviceFromApp )
{
hr = pD3D9Ex->CreateDeviceEx( pNewDeviceSettings->d3d9.AdapterOrdinal, pNewDeviceSettings->d3d9.DeviceType, \
            DXUTGetHWNDFocus(), pNewDeviceSettings->d3d9.BehaviorFlags, \
            &pNewDeviceSettings->d3d9.pp, NULL, &pd3dDevice9Ex);
}

使用process explorer查看程序的句柄和加载的dll

菜单点击 View - Lower Pane View - 勾选DLLS和Handles ,并且勾选 View - Show Lower Pane,然后选中某个进程后,在底部就会出现dll tab页,里面显示了当前进程加载了那些dll

image-20240702142239030

From:https://www.cnblogs.com/zhaoqingqing/p/18341086
本文地址: http://shuzixingkong.net/article/762
0评论
提交 加载更多评论
其他文章 数值分析方法
数值分析方法 数值方法可以用近似方法来理解 对于一些得不到解析解否则解析解计算难度太大的问题,如何用较少的计算得到相对较好(满足精度要求)的数值解、近似解。 数值分析最基本的立足点是容许误差 例子: 近似计算基本方法: 离散化(e.g. 数值积分) 递推法(将一个复杂的计算过程转化为简单过程的多次重
数值分析方法 数值分析方法 数值分析方法
WPF【无限滚动图片浏览】自定义控件
自定义控件 自定义控件是我比较陌生的一个主题。我好久没练习过wpf了,需要巩固记忆。我想了一会儿,打开动漫之家,忽然觉得这个看漫画的图片浏览控件有意思。于是特地花了一天做了这个图片控件。我原本以为很容易,但实际上并不简单。这个图片浏览控件比我想象中要难许多,有技术上的难题,也有逻辑上的难题。好在最后
WPF【无限滚动图片浏览】自定义控件 WPF【无限滚动图片浏览】自定义控件 WPF【无限滚动图片浏览】自定义控件
【JavaScript】前端算法题 40道题+解析
最近练习了一些前端算法题,现在做个总结,以下题目都是个人写法,并不是标准答案,如有错误欢迎指出,有对某道题有新的想法的友友也可以在评论区发表想法,互相学习🤭
全网最适合入门的面向对象编程教程:31 Python的内置数据类型-对象Object和类型Type
Python 中的对象和类型是一个非常重要的概念。在 Python 中,一切都是对象,包括数字、字符串、列表等,每个对象都有自己的类型。
全网最适合入门的面向对象编程教程:31 Python的内置数据类型-对象Object和类型Type 全网最适合入门的面向对象编程教程:31 Python的内置数据类型-对象Object和类型Type 全网最适合入门的面向对象编程教程:31 Python的内置数据类型-对象Object和类型Type
使用 addRouteMiddleware 动态添加中间
title: 使用 addRouteMiddleware 动态添加中间 date: 2024/8/4 updated: 2024/8/4 author: cmdragon excerpt: 摘要:文章介绍了Nuxt3中addRouteMiddleware的使用方法,该功能允许开发者动态添加路由中间件
使用 addRouteMiddleware 动态添加中间 使用 addRouteMiddleware 动态添加中间
FFmpeg开发笔记(四十四)毕业设计可做的几个拉满颜值的音视频APP
​一年一度的毕业季就要到了,毕业设计算是大学生毕业前的最后一个大作业,尤其是计算机相关专业的毕业设计,通常要通过编程开发一个软件,比如开发一个图书馆管理系统,开发一个电商APP等等。 一个好的毕业设计可以给作者加分,可以评优,还能获得编程开发的实战经验,所以很有必要认真去做毕业设计。那么就计算机相关
使用PasteSpider实现类似Jenkins的功能,让你的2G服务器也可以飞起
或许你接触过Jenkins, 在我理解就是拉取源码,然后构建成镜像,最后启动容器! 但是这个功能对于小内存的服务器来说就是奢望了! 今天介绍一个新版本,把你这个遗憾弥补下! 在PasteSpider中,也是支持拉取源码,然后编译发布的!!! 以下案例使用svn作为源码管理 如果你使用git作为源码管
使用PasteSpider实现类似Jenkins的功能,让你的2G服务器也可以飞起 使用PasteSpider实现类似Jenkins的功能,让你的2G服务器也可以飞起 使用PasteSpider实现类似Jenkins的功能,让你的2G服务器也可以飞起
Rust项目的代码组织
学习一种编程语言时,常常优先关注在语言的语法和标准库上,希望能够尽快用上新语言来开发,我自己学习新的开发语言时也是这样。 不过,想用一种新的语言去开发实际的项目,或者自己做点小工具的话,除了语言本身之外,了解它在项目中如何组织代码也是至关重要的。毕竟在实际项目中,不可能像学习语言时那样,常常只有一个
Rust项目的代码组织 Rust项目的代码组织 Rust项目的代码组织