Jump to content
  • Advertisement
Sign in to follow this  
GoodFun

[SlimDX] Problem getting render target data into CPU memory

This topic is 3409 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi there, I'm using SlimDX and DirectX 10. I'm rendering to an 8bit unsigned render target. Once I'm done rendering, I copy the render target over to a CPU readable texture map and try to read it out into an array of byte. I'm using Marshal.Copy and this has been working for a long time. Since I've started to use the November 2008 version of SlimDX, I've encountered cases where the extraction code would fail with a memory access error. This presists through application restarts and even computer reboots, and then suddently goes away again without any change in the code. Does anyone know a better way to get a render target back into CPU accessible memory. It has to be very fast and the speed of Marshal.Copy has been satisfactory. This is what I'm doing to get the Render Target read back into a byte array:
// copy the render target to a CPU accessible texture map
D3D10.Texture2D cpuTexture = new D3D10.Texture2D(device, RenderingDevice.CpuTextureDescription);
device.CopyResource(renderTexture, cpuTexture);

try
{
    // now get the data out of the texture
    DataRectangle data = cpuTexture.Map(0, D3D10.MapMode.Read, D3D10.MapFlags.None);
    // and convert it to a byte array
    result = ExtractByteArray(data.Data.DataPointer, data.Pitch, width, height);
}
catch (Exception ex)
{
    ImgServerForm.AddLog(EventLoggerType.Exception, "Error during FastMap Rendering Layer: " + LayerId.ToString() + " Error: " + ex.ToString());
    Exception newException = new Exception("Error during FastMap Rendering", ex);
    throw newException;
}
finally
{
    cpuTexture.Unmap(0);
}
cpuTexture.Dispose();
renderTarget.Dispose();
renderTexture.Dispose();
This is the extraction method:
private byte[] ExtractByteArray(IntPtr source, int pitch, int width, int height)
{
    // Declare an array to hold the bytes of the bitmap.
    int bytes = width * height;
    byte[] newValues = new byte[bytes];

    // Copy the RGB values into the array.
    for (int y = 0; y < height; y++)
    {
        Marshal.Copy(new IntPtr(source.ToInt32() + y * pitch), newValues, y * width, width);
    }
    // !! This is the line that fails, though I believe it's the Marshal.Copy that causes the issue
    return newValues;
}
These are the render target and cpu texture definitions:
_sampleDescription = new DXGI.SampleDescription();
_sampleDescription.Count = 1;
_sampleDescription.Quality = 0;
_renderTargetDescription = new D3D10.Texture2DDescription();
_renderTargetDescription.ArraySize = 1;
_renderTargetDescription.MipLevels = 1;
_renderTargetDescription.SampleDescription = _sampleDescription;
_renderTargetDescription.Format = DXGI.Format.R8_UInt;
_renderTargetDescription.CpuAccessFlags = D3D10.CpuAccessFlags.None;
_renderTargetDescription.BindFlags = D3D10.BindFlags.RenderTarget;
_renderTargetDescription.Usage = D3D10.ResourceUsage.Default;
_cpuTextureDescription = new D3D10.Texture2DDescription();
_cpuTextureDescription.ArraySize = 1;
_cpuTextureDescription.MipLevels = 1;
_cpuTextureDescription.SampleDescription = _sampleDescription;
_cpuTextureDescription.Format = DXGI.Format.R8_UInt;
_cpuTextureDescription.CpuAccessFlags = D3D10.CpuAccessFlags.Read;
_cpuTextureDescription.BindFlags = D3D10.BindFlags.None;
_cpuTextureDescription.Usage = D3D10.ResourceUsage.Staging;
And last but not least, these are the types of errors I'm receiving when the system doesn't work as it should:
[2009-01-22_00-11-38],Exception,Error during FastMap Rendering Layer:
52 Error: System.OverflowException: Arithmetic operation resulted in an overflow.
   at RenderingServices.DataModel.Layer.ExtractByteArray(IntPtr source, Int32 pitch, Int32 width, Int32 height) in ...\DataModel\Layer.cs:line 414
   at RenderingServices.DataModel.Layer.Render(Device device, Int32 timeSlot, Int32 width, Int32 height, Single left, Single right, Single top, Single bottom, TimeSpan& timeOnCard) in ...\DataModel\Layer.cs:line 237
[2009-01-22_00-11-38],Exception,Unhandled Exception in Rendering Code:
System.Exception: Error during FastMap Rendering ---> System.OverflowException: Arithmetic operation resulted in an overflow.
   at RenderingServices.DataModel.Layer.ExtractByteArray(IntPtr source, Int32 pitch, Int32 width, Int32 height) in ...\DataModel\Layer.cs:line 414
   at RenderingServices.DataModel.Layer.Render(Device device, Int32 timeSlot, Int32 width, Int32 height, Single left, Single right, Single top, Single bottom, TimeSpan& timeOnCard) in ...\DataModel\Layer.cs:line 237
   --- End of inner exception stack trace ---
   at RenderingServices.DataModel.Layer.Render(Device device, Int32 timeSlot, Int32 width, Int32 height, Single left, Single right, Single top, Single bottom, TimeSpan& timeOnCard) in ...\DataModel\Layer.cs:line 258
   at RenderingServices.ImageServer.ImgService.GenerateImageArea(UInt32 clientId, Int32 layerId, Int32 slotNumber, FastMapArea area) in ...\ImageService\ImgService.cs:line 648
If anyone has encountered that problem, I'd be most grateful if you could tell me how to get around it or if someone has a better way to get the texture back into CPU memory in a fast way, that would work too. Thanks Marcel

Share this post


Link to post
Share on other sites
Advertisement
A quick look at the documentation for Marshall.Copy suggests to me that either the count parameter needs to be the number of ints not the number of bytes, or the first parameter needs to be a byte pointer.

Share this post


Link to post
Share on other sites
I just had a look, the IntPtr is just a pointer to a memory address and the length is the number of array elements (Byte[] in my case), so I don't think that is it...

Share this post


Link to post
Share on other sites
what puzzles me most is that most of the time it works, just once in a while it has this issue... and the issue pops up without code changes, and can also disapear again without code changes.

Share this post


Link to post
Share on other sites
Try putting in asserts that some of the values being computed are within int range. I'm particularly suspicious of source.ToInt32() + y * pitch, especially since I thought you were using 64 bit.

Share this post


Link to post
Share on other sites
hmmm, good point, I am using a 64bit OS and 64bit code... you're saying that the int pointer might get truncated???

Share this post


Link to post
Share on other sites
You're the man... that was it... changing the code to use ToInt64 renders right and so far no memory access issues...

I shall go sit in the corner and write 4 million times:
I'm using a 64bit OS, hence I should use 64bit pointers

Thanks, very much appreciated
Marcel

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!