许可优化
产品
解决方案
服务支持
关于
软件库
当前位置:服务支持 >  软件文章 >  【DirectX3D - 2】渲染YUV图片(离屏表面方式)

【DirectX3D - 2】渲染YUV图片(离屏表面方式)

阅读数 4
点赞 0
article_banner

1. 介绍

目前D3D版本很多(10、11、12), 本文以及后续的实例都将使用D3D9。
使用D3DAPI之前,首先需要安装DXSDK_Jun10.exe,这在前边的文章有介绍。具体安装非常容易,下载安装包一路下一步即可。

本文目的:本文将介绍如何将一帧YUV(NV12)数据渲染显示。
主要方法:创建离屏表面

2. 基本流程

代码流程:

  1. 创建D3D对象
  2. 创建D3D设备
  3. 创建离屏表面
  4. 加载YUV数据,将YUV数据拷贝到离屏表面
  5. 开始渲染

3. 接口介绍

3.1 CreateDevice()

函数原型:

    CreateDevice(THIS_ UINT Adapter,
    D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,
    D3DPRESENT_PARAMETERS* pPresentationParameters,
    IDirect3DDevice9** ppReturnedDeviceInterface);

cpp
  • 1
  • 2
  • 3
  • 4
  • 5
  • 第一个参数:Adapter
    代理模式,即将要使用的显卡适配器的标识号,一般选择 D3DADAPTER_DEFAULT 就ok。

  • 第二个参数:DeviceType
    D3DDEVTYPE_HAL:硬件抽象层,通过显示硬件来完成图形渲染工作
    D3DDEVTYPE_REF:参考光栅器,一般用于测试显卡不支持的D3D功能
    D3DDEVTYPE_SW:用于支持第三方软件

  • 第三个参数:hFocusWindow
    创建的窗口句柄,也即图形将出现的窗口。
    是焦点窗口,当应用程序从前台模式切换到后台模式的时候向Direct3D提示的窗口。

如果是全屏模式,这个窗口指定的焦点窗口必须是最顶层窗口。

对于窗口模式,这个参数可以是NULL(用的是当前显示的窗口),除非PRESENTPARAMETERS的hDeviceWindow参数是一个合法的非NULL值。

交换链有多个后台缓存的时候,每个后台缓存需要各自hDeviceWindow设备窗口,可以共用一个hFocusWindow焦点窗口(一个焦点窗口可以只给一个后台缓存当做自己的设备窗口)。

  • 第四个参数:BehaviorFlags

D3DCREATE_SOFTWARE_VERTEXPROCESSING
由D3D软件进行顶点运算(常用)

D3DCREATE_FPU_PRESERVE
激活双 精度 浮点运算或浮点运算异常 检测,设置该项会降低系统性

D3DCREATE_MULTITHREADED
保证D3D是 多线程 安全的,设置该项 会降低系统性能

D3DCREATE_MIXED_VERTEXPROCESSING
混合方式进行顶点运算

D3DCREATE_HARDWARE_VERTEXPROCESSING
由D3D硬件进行顶点运算

D3DCREATE_PUREDEVICE
禁用D3D的Get*()函数,禁止D3D 使用虚拟设备模拟顶点运算

注意

D3DCREATE_HARDWARE_VERTEXPROCESSING
D3DCREATE_MIXED_VERTEXPROCESSING
D3DCREATE_SOFTWARE_VERTEXPROCESSING
这三个顶点运算时互斥的,且在该函数中必须被指定一个。

后台缓存只用在D3DPRESENT_PARAMETERS中用D3DPRESENTFLAG_LOCKABLE_BACKBUFFER指定了才能被锁定,多重采样纹理的后台缓存和深度缓存不能被锁定。

  • 第五个参数:pPresentationParameters
    渲染参数设定,根据需要创建。

  • 第六个参数:ppReturnedDeviceInterface
    该参数是输出参数,D3D设备,调用这个借口之后,创建成功的D3D设备将使用该参数返回。

3.2 StretchRect()

可以将一个矩形区域的像素从设备内存的一个Surface转移到另一个Surface上。
StretchRect()函数的原型如下

HRESULT StretchRect(
IDirect3DSurface9 * pSourceSurface,
CONST RECT * pSourceRect,
IDirect3DSurface9 * pDestSurface,
CONST RECT * pDestRect,
D3DTEXTUREFILTERTYPE Filter
);
cpp
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • pSourceSurface
    指向源Surface的指针。
  • pSourceRect
    使用一个 RECT结构体指定源Surface需要复制的区域。如果为NULL的话就是整个区域。
  • pDestSurface
    指向目标Surface的指针。
  • pDestRect
    使用一个 RECT结构体指定目标Surface的区域。
  • Filter
    设置图像大小变换的时候的插值方法。例如:
  • D3DTEXF_POINT
    邻域法。质量较差。
  • D3DTEXF_LINEAR
    线性插值,最常用。
// 以下代码实例了,如何将离屏表面的内存拷贝到后台缓冲区:
IDirect3DDevice9 *m_pDirect3DDevice;
IDirect3DSurface9 *m_pDirect3DSurfaceRender;
IDirect3DSurface9 * pBackBuffer;
m_pDirect3DDevice->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer);
m_pDirect3DDevice->StretchRect(m_pDirect3DSurfaceRender,NULL,pBackBuffer,&m_rtViewport,D3DTEXF_LINEAR);

// 将离屏表面的数据传给了后台缓冲表面。一但传给了后台缓冲表面,就可以用于显示了。
cpp
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3.3 BeginScene、EndScene

在D3D中,需要使用BeginScene和EndScene函数,然后所有的图元绘制代码才能被调用。通过了解,需要注意下下面一些问题:

  1. BeginScene和EndScene必须成对实现。
  2. BeginScene不能连续调用两次否则会出现调用异常。
  3. EndScene属于作用是实际应用所有的绘制命令至显卡,但是它是异步执行的,即它会立即返回,但是不保证绘制命令执行完成。
  4. Present函数会最终等待所有绘制命令结束并将结果从back buffer拷贝到front buffer。
  5. BeginScene和EndScene之间的绘制代码量可以不要太多,当然太少也不好。这样才能保证最后的present不至于等待大量的CPU时间等显卡完成所有的绘制指令。这样可以在present之前多次使用BeginScene/EndScene队,保证CPU和GPU始终基本同时在工作(并行)。
  6. 如果确实存在BeginScene/EndScene之间绘制命令过多,可以在EndScene/Present之间添加一些CPU指令,避免CPU在Present时过多时间空等GPU完成绘制返回。

4. 代码

代码仅作为参考。

/**
 * 函数调用步骤如下:
 *
 * [初始化]
 * Direct3DCreate9():获得IDirect3D9
 * IDirect3D9->CreateDevice():通过IDirect3D9创建Device(设备)。
 * IDirect3DDevice9->CreateOffscreenPlainSurface():通过Device创建一个Surface(离屏表面)。
 *
 * [循环渲染数据]
 * IDirect3DSurface9->LockRect():锁定离屏表面。
 * memcpy():填充数据
 * IDirect3DSurface9->UnLockRect():解锁离屏表面。
 * IDirect3DDevice9->BeginScene():开始绘制。
 * IDirect3DDevice9->GetBackBuffer():获得后备缓冲。
 * IDirect3DDevice9->StretchRect():拷贝Surface数据至后备缓冲。
 * IDirect3DDevice9->EndScene():结束绘制。
 * IDirect3DDevice9->Present():显示出来。
 */

#include <stdio.h>
#include <tchar.h>
#include <d3d9.h>
#include <windows.h>
#include <stdio.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <tchar.h>
#include <time.h> 

#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib, "winmm.lib") 

CRITICAL_SECTION  m_critial;

IDirect3D9* m_pDirect3D9 = NULL;
IDirect3DDevice9* m_pDirect3DDevice = NULL
cpp
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删
相关文章
QR Code
微信扫一扫,欢迎咨询~

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 155-2731-8020
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

手机不正确

公司不为空