我是靠谱客的博主 哭泣草莓,最近开发中收集的这篇文章主要介绍D3D11 texture 创建 NV12 YV12 YUV420 cpu 访问 内存分布 拷贝 map updateresource copyresource,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

nv12 详细介绍:DXGI_FORMAT (dxgiformat.h) - Win32 apps | Microsoft Docs(关于查看msdn文档,对于所有的windows的类型,在vs下鼠标移动到对应的类型或其属性或枚举下,按f1浏览器就能调到对应的官方文档对应的网页,还是相当方便的)
nv12、yuv420、yv12等 显示或者作为shader resource传入shader参考:D3d/opengl texture yuv yuv420p nv12 yv12 等等 显示 以及传入shaderresource_丘上人的博客-CSDN博客_nv12 shader
texture 创建:

//HRESULT hr ;
//UINT pSup;
//hr = g_pd3dDevice->CheckFormatSupport(DXGI_FORMAT_NV12, &pSup); //D3D11 on GeGorce GTX TITAN X device ,don't surpport DXGI_FORMAT_NV12 !!!!
//if (hr != S_OK)
//{
//	MessageBox(NULL, L"Dont support that format", L"Error", MB_OK);
//}
//显存 对 内存对齐要求 比较严苛,这对使用效率及内部显存管理比较重要。 使用图像分辨率2226*1252。
D3D11_TEXTURE2D_DESC desc;
desc.Width = static_cast<UINT>(width);//我设置的是2226(0x8b2)  ,在我机器上内存对齐需要将值改成2240(0x8c0)
desc.Height = static_cast<UINT>(height);//我设置的是1252(0x4e4),在我机器上内存对齐需要将值改成1264(0x4f0)
desc.MipLevels = static_cast<UINT>(1);
desc.ArraySize = static_cast<UINT>(1);
desc.Format = DXGI_FORMAT_NV12;// DXGI_FORMAT_R8G8B8A8_UINT;//DXGI_FORMAT_NV11;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;//表示绑定到pipeline的阶段中,如果只是输出可以使用D3D11_BIND_RENDER_TARGET
desc.CPUAccessFlags = 0;
//usage 
//当Usage 为D3D11_USAGE_IMMUTABLE和D3D11_USAGE_DEFAULT时,不可以设置D3D11_CPU_ACCESS_WRITE或D3D11_CPU_ACCESS_READ,并且必须设置bindflags。这两者是在gpu上申请的内存。(使用gpu device创建的情况时)
//当usage为D3D11_USAGE_IMMUTABLE(不可修改)时,bindflags不能设置为D3D11_BIND_RENDER_TARGET。cpuaccessflags 必须设置为0
//当usage为D3D11_USAGE_DEFUALT时,bindflag可以D3D11_BIND_RENDER_TARGET与D3D11_BIND_SHADER_RESOURCE的组合。
//当Usage为D3D11_USAGE_DYNAMIC时,bindflags必须设置一项(bingflags似乎永远只能设置一项),并
//且必须设置cpuaccessflags为D3D11_CPU_ACCESS_WRITE,经过测试,发现dynamic其实是在gpu上申请了
//内存。(使用gpu device创建的情况时)
//当Usage为D3D11_USAGE_STAGING 时,bindflags必须为0,并且必须设置cpuaccessflags为read或者
//write或者两者的结合,不能为0,经过测试,staging是在普通内存上申请了一块内存。
//对于D3D11_USAGE_STAGIN的资源在pipeline的整个流程所有阶段gpu是无法访问的,显然pipeline阶段显卡访问普通内存是低效的,需要将东西拷贝到显卡内存才行。
//D3D11_CPU_ACCESS_READ 必须用在staging资源上。
//调用接口错误信息可以查看:https://blog.csdn.net/qiushangren/article/details/89280682
//参考:https://blog.csdn.net/sinat_24229853/article/details/48814023
desc.MiscFlags = 0;

D3D11_SUBRESOURCE_DATA sdesc;//texture 初始化参数
sdesc.pSysMem = buffer;//设置用于初始化的内容入口地址,内部会自动拷贝
sdesc.SysMemPitch = width;//一行占用的像素,如果硬盘中存的内容的slice是2304,这里填2304,在创建是会自动截掉多余width的部分。对于这个slice,该值在存入文件中时如果是通过D3Dtexture map函数来存放,可以通过其中的参数来获知。
sdesc.SysMemSlicePitch = width*height+width*height/2;//总共占用的像素。
ID3D11Texture2D* texTemp = nullptr;

//HRESULT hr = device->CreateTexture2D(&desc, NULL, &texTemp);
HRESULT hr = device->CreateTexture2D(&desc,&sdesc,&texTemp);//创建texture

//texTemp->getDesc(&desc);//获取创建时的参数,与初始化时D3D11_SUBRESOURCE_DATA 中的pitch和内部的内存对齐无关。

texture初始化参数(D3D11_SUBRESOURCE_DATA)为何要这么设计: 主要是考虑内存对齐,考虑如下的情况,红色区域是有效像素,而白色加红色的大区域是内存所占空间。而图片在内存中一般就是按像素(rgba或者类似dds中的压缩格式)一行一行从左到右连续存储的。有的为了高效而设置了一行像素的内存对齐(比如align(64bit)、align(128bit))往外补了几个字节。windows中大部分操作像素内存的接口都是为了兼容内存对齐这个目的设计的。

关于显存与内存之间的数据传输及内存管理可参考:资源从内存上传到显存时,在 DX11 中都对应哪些过程? - 知乎
D3d底层对存储访问管理有很高效率的流水线形式的优化方式。


如果希望cpu中转(cpu能访问),可通过ID3D11DeviceContext->map来访问,需要对texture创建参数做如下两步:
1、设置desc的Usage 为D3D11_USAGE_DYNAMIC 或者D3D11_USAGE_STAGING,即大于等于D3D11_USAGE_DYNAMIC表示为cpu可访问的texture。
2、设置CPUAccessFlags 的属性D3D11_CPU_ACCESS_READ,D3D11_CPU_ACCESS_WRITE。设置cpu访问的权限。


texture 的拷贝,在D3d11中可以通过ID3D11DeviceContext->updateresource,或ID3D11DeviceContext->copyresource等等来操作。这几个函数对source texture和dest texture的属性没有限制!!! 当然dest 肯定不能为immutable。具体使用参考官方文档。及调试时出现的错误信息(信息很明确)。(异步拷贝 , pipeline stall , d3d11 flush )

//texture 拷贝。tex 是按tex1的属性来创建的并设置了其cpu可访问性和可修改性属性,只能在创建的时候设置texture的属性。
//copy 方式经过测试两幅4096*4096*4的图像src与dest均为dynamic或default类型时拷贝时间为10的-5级别s(应该是内部有并行操作,
//这时间比内存到内存的memcpy都快)。说明优化很棒,采用了异步调用进行拷贝的。其中有一方为staging类型时,为0.0001s(在我电脑上0到100000的累加平均耗时在0.000269
//,最小为0.000249). dest 不能为immutable
dctx->CopyResource(tex1, tex);

//dctx->CopySubresourceRegion(tex1, 0, 0, 0, 0, tex, 0, NULL);

//dctx->UpdateSubresource(tex1,0,NULL,tex,0,0);

//通过tex->GetDesc(&desc); 检测到tex(源)的分辨率为2240*1264
//texture map
D3D11_MAPPED_SUBRESOURCE mappedResource;//用于存放map返回的参数。
mappedResource.DepthPitch = 0;
mappedResource.RowPitch = 0;
mappedResource.pData = 0;
//注意参数访问性的设置及对应的要求https://docs.microsoft.com/zh-cn/windows/desktop/api/d3d11/ne-d3d11-d3d11_map
if ((ret = dctx->Map(tex1, 0, D3D11_MAP_READ, 0, &mappedResource)) == 0)//_DISCARD
{//mapppedResource的rowpitch为2304(0x900,我显卡位宽为256,实际位对齐),depthpitch为4368384(2304*1264+2304/2*1264)------(y+uv)
//可以断定,获取出来的pitch与创建时用的参数是不一致的,这里考虑到了内存对齐。也就是类似将实际申请的内存的地址拿出来了。
    bool needSave = false;
    if(needSave){
	    FILE *file= fopen("./ttt");
        fwrite((char*)mappedResource.pData,1,mappedResource.DepthPitch,file);
        fclose(file);
    }
    dctx->Unmap(tex1, 0);
}

最近使用了里面的Arraysize参数,发现ArraySize对不同的bindflags有不同的取值范围,(在gtx1080Ti上)对于D3D11_BIND_RENDER_TARGET和D3D11_BIND_SGADER_RESOURCE,只能为1和2;否则报错如下

D3D11 ERROR: ID3D11Device::CreateTexture2D: Texture arrays larger then 2 are not allowed for planar formats. [ STATE_CREATION ERROR #101: CREATETEXTURE2D_INVALIDDIMENSIONS]


对于D3D11_BIND_DECODE可以有很多(1到2048)(该值根据显卡性能来确定,具体参考msdn)

​​​​​​​D3D11 ERROR: ID3D11Device::CreateTexture2D: The Dimensions are invalid. For feature level D3D_FEATURE_LEVEL_11_0, the Width (value = 1920) must be between 1 and 16384, inclusively. The Height (value = 1080) must be between 1 and 16384, inclusively. And, the ArraySize (value = 10000) must be between 1 and 2048, inclusively. [ STATE_CREATION ERROR #101: CREATETEXTURE2D_INVALIDDIMENSIONS]

最后

以上就是哭泣草莓为你收集整理的D3D11 texture 创建 NV12 YV12 YUV420 cpu 访问 内存分布 拷贝 map updateresource copyresource的全部内容,希望文章能够帮你解决D3D11 texture 创建 NV12 YV12 YUV420 cpu 访问 内存分布 拷贝 map updateresource copyresource所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(33)

评论列表共有 0 条评论

立即
投稿
返回
顶部