convert SharpDXDirect3D11 Texture2D?
#1
Hi,

I was able to make my forum account work just by simply creating another one hehe. Hopefully that doesn't mess up my account there on the ab4d official website. 

So I am using a DesktopDuplicator as seen here https://github.com/Deathspike/Hansha . Once I get access the Desktop Duplicator in a running program, it outputs:



Code:
   public class ScreenFrame
    {
        public Texture2D texture2D;
        public ScreenFrameRectangle Boundaries;
        public ScreenFrameRectangle[] ModifiedRegions;
        public ScreenFrameRegion[] MovedRegions;
        public byte[] NewPixels;
        public byte[] PreviousPixels;
    }

now with the following line of code next, I am able to copy the contents of the Newpixels to a Bitmap:

Code:
private static void CopyToImage(Bitmap image, ScreenFrame screenFrame)
{
  var imageBoundaries = new System.Drawing.Rectangle(0, 0, screenFrame.Boundaries.Right,
                        screenFrame.Boundaries.Bottom);
  var imageData = image.LockBits(imageBoundaries, ImageLockMode.WriteOnly, image.PixelFormat);
  Marshal.Copy(screenFrame.NewPixels, 0, imageData.Scan0, screenFrame.NewPixels.Length);
  image.UnlockBits(imageData);
}

Following that, I need to convert the Bitmap to a BitmapSource and then from BitmapSource to ImageBrush
and then imageBrush to DiffuseMaterial to apply it to the material of an object.


Code:
BitmapSource bitmapSource = CreateBitmapSource(_bitmap);
ImageBrush _imageBrush = new ImageBrush(bitmapSource);
diffuseMaterial = new DiffuseMaterial(_imageBrush);
floorBox.Material = diffuseMaterial;

It works.

But the function CreateBitmapSource here is overloading the performance like crazy. It really lags and bottlenecks the whole performance:

Code:
private static BitmapSource CreateBitmapSource(Bitmap bitmap)
{
 System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height);

 BitmapData bitmapData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat);

 BitmapSource source = BitmapSource.Create(bitmap.Width, bitmap.Height,bitmap.HorizontalResolution,   bitmap.VerticalResolution, PixelFormats.Pbgra32, null,bitmapData.Scan0, bitmapData.Stride * bitmap.Height,  bitmapData.Stride);
 bitmap.UnlockBits(bitmapData);
 return source;
}

Does anybody have any clues on an alternative?

Thank you!
Steve

I will scour the AB4D samples to find clues about applying textures to an object's material.


EDIT 2018-06-23 - 22h00 - I have found an alternative. But it doesn't fix the lag issue and so I will divide the desktop screen and try to make threads work on them to lower the load. Here is the alternative that I found: 

Code:
BitmapImage _bitmapImage = ToBitmapImage(_bitmap);
ImageBrush brush = new ImageBrush(_bitmapImage);
diffuseMaterial = new DiffuseMaterial(brush);
floorBox.Material = diffuseMaterial;


from here: https://stackoverflow.com/questions/6484...vice-versa
#2
I am sorry for the problems with the forum. I will check the spam filter settings again and see if there is anything I can do to improve that.

Now to your question.
From what you have written I think that you should be able to use the texture2D directly as it is on the GPU without copying it to main memory, converting it to GDI+ bitmap, then to WPF bitmap. And from there in DXEngine back to DirectX shader resource view and sending it back to GPU. There is a lot of overhead especially with sending the image from the gpu and back.

To try this use the following code to first create a ShaderResourceView from the texture2D object:

Code:
var resourceViewDescription = new ShaderResourceViewDescription
{
     Format = [enter format],
     Dimension = SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D,
     Texture2D = new ShaderResourceViewDescription.Texture2DResource
     {
          MipLevels = 1,
          MostDetailedMip = 0
     }
};

var shaderResourceView = new ShaderResourceView(dxViewportView.DXScene.DXDevice.Device, texture2D, resourceViewDescription);

// Do not forget to dispose the shaderResourceView when it is not used any more.
// This can be done with using DisposeList object - for example:
_disposables.Add(shaderResourceView);

Then you can create a DXEngine material that will use that texture:
Code:
var standardMaterial = new StandardMaterial()
{
   // Set ShaderResourceView into array of diffuse textures
  DiffuseTextures = new ShaderResourceView[] { shaderResourceView },

  // When showing texture, the DiffuseColor represents a color mask - each color from texture is multiplied with DiffuseColor (White preserves the original color)
  DiffuseColor = Colors.White.ToColor3()
};

_disposables.Add(standardMaterial);


You can then use the standardMaterial to create a MeshObjectNode or if you are using WPF 3D objects, you can assign it to WPF Material with:

Code:
diffuseMaterial = new DiffuseMaterial();
diffuseMaterial.SetUsedDXMaterial(standardMaterial);

This will use the standardMaterial whenever the DXEngine will render an object with the diffuseMaterial.


I hope that this code will work for you.
Andrej Benedik
#3
Hi Mr. Benedik, Thank you for you fast response.

There is a line of code that gives me an error in the Console. It says that there is an invalid parameter. The device is created at the start of the scene and the scene can display a cube perfectly but it outputs an invalid parameter when I try to create the ShaderResourceView.


Code:
var resourceViewDescription = new ShaderResourceViewDescription
{
    Format = Format.B8G8R8A8_UNorm,
    Dimension = SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D,
    Texture2D = new ShaderResourceViewDescription.Texture2DResource
    {
        MipLevels = 1,
        MostDetailedMip = 0
    }                                        
};

var shaderResourceView = new ShaderResourceView(_currentDXDevice, _desktopFrame.texture2D, resourceViewDescription); //<------ the error is in that line of code?

I scoured the internet a bit for info on that but the info is really hard to find on SharpDX. I am using the 4.0.1.0 SharpDX dll's. I Wonder if that is the problem. I tried creating a Texture2D to see the results like this:

Code:
_Texture2DDescription = new Texture2DDescription
           {
               ArraySize = 1,
               BindFlags = BindFlags.None,
               CpuAccessFlags = CpuAccessFlags.Read,
               Format = Format.B8G8R8A8_UNorm,
               Height = _height,
               MipLevels = 1,
               OptionFlags = ResourceOptionFlags.None,
               SampleDescription = { Count = 1, Quality = 0 },
               Usage = ResourceUsage.Staging,
               Width = _width
           };

//and then I create the Texture2D here
var _desktopImageTexture00 = new Texture2D(_currentDXDevice, _Texture2DDescription);



But to no avail. It says that there is still an invalid parameter... Anyway, if you have any insight on what might be going on?

Steve

EDIT 2018-06-26 - 02h43am - I have found the culprit. I am sending the MainDXViewportView.DXScene.DXDevice.Device to the DesktopDuplication to Acquire the Frame... It seems that using this Device again to create the ShaderResourceView isn't working. I will review this part and try to understand why I can't use the same MainDXViewportView.DXScene.DXDevice.Device. It's probably Something that is easy to understand for others but me, I have no clue. I am in uncharted waters right now. Sorry for not debugging properly and asking questions.
#4
After some thinking, I see that the problem with my recommendation is that the ScreenFrame.texture2D that you got is probably not created in such a way that it can be used use as ShaderResourceView.

To use Texture2D for that, it needs to be create with Texture2DDescription that have:
Usage = ResourceUsage.Default
BindFlags = BindFlags.ShaderResource

If you can control how this Texture2D is created, then try those settings.
Andrej Benedik
  


Forum Jump:


Users browsing this thread:
1 Guest(s)