D3D11 CubeMap GenerateMips only update one face.

Started by
4 comments, last by _Camus_ 6 years, 9 months ago

Hello, I would like to generate mipmaps for a RGBA8 texture, however it only works for one face. Here my source:

 


D3D11_TEXTURE2D_DESC desc = { 0 };
	desc.Width = this->x;
	desc.Height = this->y;

	if(cil_props & CIL_CUBE_MAP)
		desc.ArraySize = 6;
	else
		desc.ArraySize = 1;

	if (this->props&TEXT_BASIC_FORMAT::CH_ALPHA)
		desc.Format = DXGI_FORMAT_R8_UNORM;
	else
		desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

	desc.SampleDesc.Count = 1;
	desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;	
	
	desc.MiscFlags = 0;
	if (cil_props & CIL_CUBE_MAP) {
		desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE;		
	}
	desc.MipLevels = 0;
	desc.MiscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS;

	HRESULT hr;
	hr = D3D11Device->CreateTexture2D(&desc, nullptr, Tex.GetAddressOf());

	if (hr != S_OK) {
		this->id = -1;
		return;
	}

	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc{};
	srvDesc.Format = desc.Format;
	if (cil_props & CIL_CUBE_MAP) {
		srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
		srvDesc.Texture2D.MipLevels = -1;
		srvDesc.TextureCube.MipLevels = -1;
	}
	else {
		srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
		srvDesc.Texture2D.MipLevels = -1;
	}


	D3D11Device->CreateShaderResourceView(Tex.Get(), &srvDesc, pSRVTex.GetAddressOf());

	D3D11_SUBRESOURCE_DATA initData[6];
	int bufferSize = this->size/6;
	if (cil_props & CIL_CUBE_MAP) {
		unsigned char *pHead = buffer;
		for (int i = 0; i < 6; i++) {
			initData.pSysMem = pHead;
			initData.SysMemPitch = sizeof(unsigned char) * this->x * 4;
			pHead += bufferSize;
		}
	}else {
		initData[0].pSysMem = buffer;
		initData[0].SysMemPitch = sizeof(unsigned char) * this->x * 4;
	}

	if (cil_props & CIL_CUBE_MAP) {
		for (int i = 0; i < 6; i++) {
			D3D11DeviceContext->UpdateSubresource(Tex.Get(), i, 0, initData.pSysMem, initData.SysMemPitch, size); //size is the size of the entire buffer
		}
	}else {
		D3D11DeviceContext->UpdateSubresource(Tex.Get(), 0, 0, buffer, initData[0].SysMemPitch, 0);
	}


	D3D11DeviceContext->GenerateMips(pSRVTex.Get());

 

This code assume RGBA (32 bpp) and no mipmaps in the buffer. This is how it looks without mipmaps:

 

nomip.thumb.png.81be870adaaa65262456cdfbc1842923.png

This is how it looks with the code above, only one face is updated but curiously, that face alone does have mipmaps:

mipbad.thumb.png.26f8890e23b2ddac162ec0b04e330c46.png

 

Can anyone help me, I can add mipmaps offline but this should work, I would like to handle were the buffer is a cubemap and doesn't have any mipmaps. I tried on Intel and Nvidia, so I guess is not a driver issue, but something I am doing wrong.

 

Thanks!

Advertisement

You seem to be updating subresource 'i' here:


D3D11DeviceContext->UpdateSubresource(Tex.Get(), i, 0, initData[i].pSysMem, initData[i].SysMemPitch, size);

Whereas you should be updating subresource index D3D11CalcSubresource(mip, slice, numMips).

The 6 mips you want to update are not subresources 0,1,2,3,4,5, but rather (0 * numMips), (1 * numMips), (2 * numMips)... etc.

Adam Miles - Principal Software Development Engineer - Microsoft Xbox Advanced Technology Group

2 hours ago, ajmiles said:

You seem to be updating subresource 'i' here:



D3D11DeviceContext->UpdateSubresource(Tex.Get(), i, 0, initData[i].pSysMem, initData[i].SysMemPitch, size);

Whereas you should be updating subresource index D3D11CalcSubresource(mip, slice, numMips).

The 6 mips you want to update are not subresources 0,1,2,3,4,5, but rather (0 * numMips), (1 * numMips), (2 * numMips)... etc.

 

Thank you so much! I was doing it wrong, changed to:


int MipMapCount = 1 + floor(log10((float)max(this->x, this->y)) / log10(2.0));
	if (cil_props & CIL_CUBE_MAP) {
		for (int i = 0; i < 6; i++) {
			for (int j = 0; j < MipMapCount; j++) {
				D3D11DeviceContext->UpdateSubresource(Tex.Get(), D3D11CalcSubresource(j, i, MipMapCount), 0, initData[0].pSysMem, initData[0].SysMemPitch, size);
			}
		}
	}else {
		D3D11DeviceContext->UpdateSubresource(Tex.Get(), 0, 0, buffer, initData[0].SysMemPitch, 0);
	}

And now it's working just fine! 

mipmap.thumb.png.69c106d0ee36b0147590f17eb49a98ee.png

 

Thank you once again!

If you'd like to get rid of the iffy looking calculation for "MipMapCount", just call Tex->GetDesc() and the MipCount field will be populated with the actual mip count (rather than the 0 you filled it in with to create it).

Glad it's working!

Adam Miles - Principal Software Development Engineer - Microsoft Xbox Advanced Technology Group

In fact it was wrong, I was sending the same face all the time and making it for all the mipmaps is not needed. I also followed your advice and used the desc to get the mipmap count! Thanks, this is the working code:

 


D3D11_TEXTURE2D_DESC pDesc;
	Tex->GetDesc(&pDesc);
	int MipMapCount = pDesc.MipLevels;
	if (cil_props & CIL_CUBE_MAP) {
		for (int i = 0; i < 6; i++) {
				D3D11DeviceContext->UpdateSubresource(Tex.Get(), D3D11CalcSubresource(0, i, MipMapCount), 0, initData.pSysMem, initData.SysMemPitch, 0);
		}
	}else {
		D3D11DeviceContext->UpdateSubresource(Tex.Get(), 0, 0, buffer, initData[0].SysMemPitch, 0);
	}

 

And the correct output:

Correct.thumb.png.5e2f3bf12b6ec1b9a797732d24f8ddad.png

 

Again, thanks for the time.

This topic is closed to new replies.

Advertisement