Jump to content

  • Log In with Google      Sign In   
  • Create Account


Creating a Texture2D array


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
7 replies to this topic

#1 Gavin Williams   Members   -  Reputation: 658

Like
0Likes
Like

Posted 14 June 2012 - 06:20 AM

Hi,

How do I create a Texture2D array in SlimDX ? Or alternatively, can I use photoshops dds exporter to create a dds texture array to load into the Texture2d as i do for normal Textured2D's ?

I have looked at using CopySubresource region() which looks like a good candidate for copying a texture into a texture array because i can select the destination subresource. But there seems to be a catch : MapSubresource requires CPUAccessFlags.Write, so that excludes Default and Immutable, leaving Staging which must be BindFlags.None so i then cant use it as a resource and Dynamic which cannot have an array size of anything but [1]. So it appeares to me as though CopySubresource cant be used for texture arrays !! That seems really weird to me.

What I'm after is :

Texture2D.FromFile(SlimDXDirect3D11.Device device, List<String> sourceFiles);

I know I wont get it, because GOD ! that would be just too easy wouldn't it. No one would dare write a texture loading method so straight forward.

Anyway ...

... I now have the following code, (which will compile but i only see black)

// texture2DArray_G1Brushes ===========================================================
	ImageLoadInformation loadInfo = new ImageLoadInformation();
	loadInfo.CpuAccessFlags = CpuAccessFlags.Read;
	loadInfo.BindFlags = BindFlags.None;
	loadInfo.Depth = 1;
	loadInfo.FilterFlags = FilterFlags.Point;
	loadInfo.FirstMipLevel = 1;
	loadInfo.Format = Format.R8G8B8A8_UNorm;
	loadInfo.Height = 220;
	loadInfo.MipFilterFlags = FilterFlags.None;
	loadInfo.MipLevels = 1;
	loadInfo.OptionFlags = ResourceOptionFlags.None;
	loadInfo.Usage = ResourceUsage.Staging;
	loadInfo.Width = 200;
  
	DataRectangle[] dataRectangleArray = new DataRectangle[2];

	Texture2D tex1 = Texture2D.FromFile(SDXForm.Device11,"Resources/Logo1.dds",loadInfo);
	Single[] fArray = new Single[200*220*4];
	DataStream dataStream = new DataStream(fArray, true, true);
	Texture2D.ToStream(SDXForm.Device11.ImmediateContext, tex1, ImageFileFormat.Dds, dataStream);
	dataRectangleArray[0] = new DataRectangle(200*4, dataStream);

	Texture2D tex2 = Texture2D.FromFile(SDXForm.Device11, "Resources/Logo2.dds", loadInfo);
	Texture2D.ToStream(SDXForm.Device11.ImmediateContext, tex2, ImageFileFormat.Dds, dataStream);
	dataRectangleArray[1] = new DataRectangle(200 * 4, dataStream);

	Texture2DDescription textureDescription = new Texture2DDescription()
	{
		ArraySize = 2,
		BindFlags = BindFlags.ShaderResource,
		CpuAccessFlags = CpuAccessFlags.None,
		Format = SlimDX.DXGI.Format.R8G8B8A8_UNorm,
		Height = 220,
		MipLevels = 1,
		OptionFlags = ResourceOptionFlags.None,
		SampleDescription = new SlimDX.DXGI.SampleDescription(1, 0),
		Usage = ResourceUsage.Immutable,
		Width = 200
	};
  
	texture2DArray_G1Brushes = new Texture2D(SDXForm.Device11, textureDescription, dataRectangleArray);
	AddResource("texture2DArray_G1Brushes", texture2DArray_G1Brushes);

	// srv_G1BrushesArray =================================================================
	ShaderResourceViewDescription shaderResourceDesc = new ShaderResourceViewDescription()
	{
		ArraySize = 2,
		Format = Format.R8G8B8A8_UNorm,
		Dimension = ShaderResourceViewDimension.Texture2DArray,
		MostDetailedMip = 0,
		MipLevels = 1
	};
	srv_G1BrushesArray = new ShaderResourceView(SDXForm.Device11, texture2DArray_G1Brushes, shaderResourceDesc);
	AddResource("srv_G1BrushesArray", srv_G1BrushesArray);

Edited by Gavin Williams, 14 June 2012 - 01:29 PM.


Sponsor:

#2 MJP   Moderators   -  Reputation: 11038

Like
0Likes
Like

Posted 14 June 2012 - 03:12 PM

You don't want to copy in the array slices one by one after you've created the texture. What you want to do is have all of the data for all slices ready in CPU memory, then provide that data as the initialization data when you create your texture array. One way to do this is to load all of the array slices as STAGING resources, map them to get the pointer to their data, and then use those pointers when initializing the IMMUTABLE Texture2D resource for your texture array. Unfortunately I'm not too familar with SlimDX so I'm not sure how exactly to express it with that API, but there should be a way to accomplish this.

#3 Gavin Williams   Members   -  Reputation: 658

Like
0Likes
Like

Posted 14 June 2012 - 10:43 PM

I have tried to provide all the textures at once in a DataRectangle[] , which as far as i can tell, is similar to a subresource in c++, though maybe the DataBox is the equivalent. Same thing. And I have seen an approach in c++ that uses a subresources to successfully load initial data. However, Texture2D does provide for a DataRectangle[] as a parameter, so I was looking at that route. I will continue my search now ...

#4 Gavin Williams   Members   -  Reputation: 658

Like
0Likes
Like

Posted 15 June 2012 - 02:48 AM

Ive had to go back to basics here (again) to try to get a grasp on how DirectX handles resource construction, just to rule out some issues and get a better understanding. So I'm just filling some textures in manually with colors to prove the array is working... and it actually isn't working at all ..

Here is the texture initialization code, including the creation of the Texture2D array :

DataRectangle[] dataRectangleArray = new DataRectangle[2];
float[] sysResource = new float[loadInfo.Width * loadInfo.Height * 4];
int rowPitch = 200 * 16; 	
	// fill in tex 1
	for (int j = 0; j < sysResource.Length; j += 4)
	{
		sysResource[j + 0] = 0; // r
		sysResource[j + 1] = 0; // g
		sysResource[j + 2] = 1; // b
		sysResource[j + 3] = 1; // a
	}
	DataStream dataStream = new DataStream(sysResource, true, true);
	dataRectangleArray[0] = new DataRectangle(rowPitch, dataStream);

	// fill in tex 2
	for (int j = 0; j < sysResource.Length; j += 4)
	{
		sysResource[j + 0] = 1; // r
		sysResource[j + 1] = 0; // g
		sysResource[j + 2] = 0; // b
		sysResource[j + 3] = 1; // a
	}
	dataStream = new DataStream(sysResource, true, true);
	dataRectangleArray[1] = new DataRectangle(rowPitch, dataStream);
		  
	  
	// create texture array - with initial data from dataRectangleArray
	Texture2DDescription textureDescription = new Texture2DDescription()
	{
		ArraySize = 2,
		BindFlags = BindFlags.ShaderResource,
		CpuAccessFlags = CpuAccessFlags.None,
		Format = SlimDX.DXGI.Format.R32G32B32A32_Float,
		Height = 220,
		MipLevels = 1,
		OptionFlags = ResourceOptionFlags.None,
		SampleDescription = new SlimDX.DXGI.SampleDescription(1, 0),
		Usage = ResourceUsage.Immutable,
		Width = 200
	};		
	texture2DArray_G1Brushes = new Texture2D(SDXForm.Device11, textureDescription, dataRectangleArray);
	AddResource("texture2DArray_G1Brushes", texture2DArray_G1Brushes);

	// srv_G1BrushesArray =================================================================
	ShaderResourceViewDescription shaderResourceDesc = new ShaderResourceViewDescription()
			{
				Dimension = ShaderResourceViewDimension.Texture2DArray,			  
				MipLevels = 1,
				MostDetailedMip = 0,
				FirstArraySlice = 0,
				ArraySize = 2,
			};
	srv_G1BrushesArray = new ShaderResourceView(SDXForm.Device11, texture2DArray_G1Brushes, shaderResourceDesc);
	AddResource("srv_G1BrushesArray", srv_G1BrushesArray);

And here is the shader code :

Texture2DArray<float4> gTexture : register (t0);

float4 PShader(PSIN input) : SV_Target
{
	float4 color = gTexture.Sample(PointSampler, float3(input.texcoord, 0));
	return color;
}

And unexpectedly I'm getting a red texture ! But clearly it should be blue from this code ! So could anyone point out what I'm doing wrong in that regard ? By the way, it acutally doesn't matter what number i put into the sample shader in the z postion 0 - 500, it doesn't change anything, I would expect it to at least have the decency to crash on me.

Oh, and can anyone confirm that rowPitch = texture.width * format.width ? So for a texture 200 pixels across and Format.R32G32B32A32_Float, rowPitch = 200*16

Edited by Gavin Williams, 15 June 2012 - 06:44 AM.


#5 Gavin Williams   Members   -  Reputation: 658

Like
0Likes
Like

Posted 15 June 2012 - 07:48 AM

At http://www.rastertek.../dx11tut17.html, the author Craig uses a different approach to a texture array,
	// Set shader texture array resource in the pixel shader.
	deviceContext->PSSetShaderResources(0, 2, textureArray);
but i suspect that all he's doing is loading the textures into consecutive registers, and not utilizing texture array capabilities at all, can someone confirm this ? Because his way looks a lot easier, just by providing an array of ShaderResourcesViews.

Edit : http://code.google.com/p/slimdx/issues/detail?id=848 seems to confirm this

Edited by Gavin Williams, 15 June 2012 - 09:06 AM.


#6 Mike.Popoloski   Crossbones+   -  Reputation: 2901

Like
1Likes
Like

Posted 15 June 2012 - 09:48 AM

I believe your problem is that you're expecting DataStream to create a copy of the data you give it; it does not. It essentially creates a pointer to the data, so after creating the first array slice you go on and overwrite all the data and fill it with red instead, which is why your texture is ending up red no matter what you do.

You can either create separate managed arrays for the data, or you can use the DataStream overload that takes an integer instead of an array. This will allocate the given number of bytes in native memory (avoiding the GC overhead for the large data arrays typically used by textures) and let you write into it with the provided Write() functions. If you do it this way, make sure you rewind the stream to the start by setting Position = 0 before passing it to D3D.
Mike Popoloski | Journal | SlimDX

#7 Gavin Williams   Members   -  Reputation: 658

Like
0Likes
Like

Posted 15 June 2012 - 11:31 AM

You are absolutely right. Thank you. Putting it all in a for-loop fixed it. Code follows :

		    DataRectangle[] dataRectangleArray = new DataRectangle[textureFiles.Count];
		    for(int i = 0; i < textureFiles.Count; i++)
		    {
			    float[] sysResource = new float[loadInfo.Width * loadInfo.Height * 4];
			    int rowPitch = 200 * 16;

			    FillArrayWithColorData(ref sysResource);

			    DataStream dataStream = new DataStream(sysResource, true, true);
			    dataRectangleArray[i] = new DataRectangle(rowPitch, dataStream);
		    }

I'll also try out the DataStream method to avoid the array and then look at getting actual textures in.

#8 Gavin Williams   Members   -  Reputation: 658

Like
0Likes
Like

Posted 15 June 2012 - 04:30 PM

Well I finally got it working, a few kinks to work out, but textures are 'mostly loading'. here's the core code of the copy operation :

 DataStream dataStream = new DataStream(width * height * formatWidth, true, true);
			    DataBox databox = SDXForm.Device11.ImmediateContext.MapSubresource(singleTexture, 0,0, MapMode.Read, SlimDX.Direct3D11.MapFlags.None);
			    // copy databox into dataStream
			    dataStream.Position = 0;
			    databox.Data.Position = 0;
			    byte[] buffer = new byte[formatWidth];
			    while (dataStream.Position < dataStream.Length)
			    {
				    databox.Data.Read(buffer,0,formatWidth);
				    dataStream.Write(buffer, 0, formatWidth);
			    }
			    dataStream.Position = 0;
			    databox.Data.Position = 0;
			    
			    dataRectangleArray[i] = new DataRectangle(rowPitch, dataStream);
			    SDXForm.Device11.ImmediateContext.UnmapSubresource(singleTexture, 0)





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS