1
\$\begingroup\$

I want to get access to a texture's pixel color data on the CPU. When trying to map the texture, I get E_INVALIDARG in return from ID3D11DeviceContext::Map.

ID3D11ShaderResourceView* resourceView; //represents my texture, already loaded up
//...

//Getting the resources of the texture view...
ID3D11Resource* res = nullptr;
ID3D11Texture2D* tex = nullptr;
resourceView->GetResource(&res);
res->QueryInterface(&tex);
D3D11_TEXTURE2D_DESC desc;
tex->GetDesc(&desc); //Correct data gets filled out
D3D11_RESOURCE_DIMENSION dim;
res->GetType(&dim); //value gets set as Texture2D which it should

D3D11_MAPPED_SUBRESOURCE mappedResource;
HRESULT h;
h = context->Map(tex,0,D3D11_MAP_READ,0,&mappedResource); //This always fails
h = context->Map(res,0,D3D11_MAP_READ,0,&mappedResource); //This also fails

The idea is that I keep only shaderResourceViews for my textures, because that is all I needed until now, and get the relevant resources here.

I tried mapping as WRITE_DISCARD also, but to no success. I am really confused, because I never had any problem with mapping constant buffers and vertex buffers. I seem to be certainly missing something?
By the way, I am using Wic Texture loader and DDS Texture loader for the DirectXTex toolkit, and tried this code for png, dds textures, with and without mip-maps.

\$\endgroup\$
4
\$\begingroup\$

It might help if you explained what you are doing with that texture exactly... In general, there are lots of good performance reasons why you can't easily access texture data in Direct3D resources from the CPU...

You can't map D3D11_USAGE_DEFAULT textures as they are allowed to be placed into memory that is potentially inaccessible the CPU, and is therefore the fastest for the GPU to access.

You can't map D3D11_USAGE_IMMUTABLE at all, and can only initialize them with initData at creation time.

You can map D3D11_USAGE_DYNAMIC textures, but there's a performance penalty for both the GPU and CPU to read them. Generally you use them with only D3D11_CPU_ACCESS_WRITE and not try to read them from the CPU.

You can of course map D3D11_USAGE_STAGING since they are only accessible by the CPU, so they can't be rendered.

Both DirectXTex and DirectX Tool Kit's texture loaders have an Ex version that would allow you to specify a usage other than D3D11_USAGE_DEFAULT and to provide D3D11_CPU_ACCESS_READ which is required to access the pixels with Map

You could also create a second D3D11_USAGE_STAGING resource and then CopyResource from the original to the staging resource, and then you can Map the staging resource. Note that this is what DirectX Tool Kit's ScreenGrab and DirectXTex's CaptureTexture are doing.

It's also worth noting that if you really want to access the texture's pixel color data, you do not want to use D3D11_MAP_WRITE_DISCARD as the whole purpose of that flag is to tell the driver that you don't actually care about any existing data from the CPU side--this allows the driver to just give you back a pointer to some other memory of the same size while continuing to use any existing copy for rendering without slowing things down--this is called 'buffer renaming'.

BTW, be sure to read this post as to why there are texture functions in both DirectXTex & DirectX Tool Kit.

PS: If you get an HRESULT like E_INVALIDARG, if you enable the Debug Device you will get diagnostic output that tells you why...

\$\endgroup\$
  • \$\begingroup\$ Thank you, this should help a lot! I want to read two textures, lerp between them and upload the result to a third one. The problem is the default usage of the loaded ones which I didn't notice... \$\endgroup\$ – János Turánszki Jun 17 '15 at 6:34
  • \$\begingroup\$ @JánosTuránszki It would probably be a lot faster, if you lerp between the two textures via render to texture on the GPU. \$\endgroup\$ – Tobias B Jun 17 '15 at 7:02
  • \$\begingroup\$ Loading the two textures and then blending them into a render target would be the fastest thing to do there... \$\endgroup\$ – Chuck Walbourn Jun 17 '15 at 7:02
  • \$\begingroup\$ I intend to test both. I want to test on the CPU because it is a small texture (4096 pixels). \$\endgroup\$ – János Turánszki Jun 17 '15 at 9:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.