Быстрый код для получения текстур WPF Visual to DirectX (с точки зрения производительности) - PullRequest
4 голосов
/ 24 апреля 2011

Ну, проблема проста, я что-то визуализировал на WPF Visual.Я хочу получить это на DirectX Texture.В настоящее время я использую следующий код для выполнения работы.

var bmp = new System.Windows.Media.Imaging.RenderTargetBitmap(bound.Width, bound.Height, 96, 96, System.Windows.Media.PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
var encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(bmp));
Texture texture = new Texture(dxDevice, bound.Width, bound.Height, 1, Usage.RenderTarget, Format.A8R8G8B8, Pool.Default);
using (MemoryStream ms = new MemoryStream())
{
    encoder.Save(ms);
    ms.Seek(0, SeekOrigin.Begin);
    Surface privateSurface = texture.GetSurfaceLevel(0);
    SurfaceLoader.FromStream(privateSurface, ms, Filter.None, Color.MediumAquamarine.ToArgb());
    ms.Close();
}
return texture; // our prepared texture

Но это несколько медленно, очевидным образом.Ребята, вы можете предложить что-нибудь, что могло бы сделать это быстрее?

[EDIT] Я пытался загрузить данные с помощью CopyPixels (), но выдает исключение D3DXERR_INVALIDDATA.

RenderTargetBitmap bmp = GetBitmap();
// copy into a byte array
int stride = bmp.PixelWidth * 4; 
byte[] data = new byte[bmp.PixelHeight * stride]; 
bmp.CopyPixels(data, stride, 0); 

// create texture
using (MemoryStream ms = new MemoryStream(data))
{
    ms.Seek(0, SeekOrigin.Begin);

    if (dxDevice != null)
    {
        // next line throws D3DXERR_INVALIDDATA exception
        texture = TextureLoader.FromStream(dxDevice, ms);
    }
}

[EDIT] Итак, вот как мне удалось это сделать.

RenderTargetBitmap bmp = GetBitmap();
// copy into a byte array
int stride = bmp.PixelWidth * 4; 
byte[] data = new byte[bmp.PixelHeight * stride]; 
bmp.CopyPixels(data, stride, 0); 

// create texture
Texture texture = new Texture(dxDevice, bound.Width, bound.Height, 1, Usage.SoftwareProcessing, Format.A8R8G8B8, Pool.Managed);
Surface privateSurface = texture.GetSurfaceLevel(0);
var graphicsStream = privateSurface.LockRectangle(LockFlags.None);
graphicsStream.Write(data);
privateSurface.UnlockRectangle();

1 Ответ

2 голосов
/ 24 апреля 2011

Да.Вы все еще можете использовать RenderTargetBitmap.Но вместо того, чтобы кодировать его в PNG и читать в Direct3D, вы можете вызвать CopyPixels на вашем RenderTargetBitmap и затем записать пиксели прямо в вашу текстуру.Должно быть намного быстрее!

// render the visual, just like you did
var bmp = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default, null);
bmp.Render(visual);

// get the pixels
var pixels = new int[width * height];
bmp.CopyPixels(pixels, 4 * width, 0); // each line consists of 4*width bytes.

И теперь, в зависимости от того, какой именно API вы используете (SlimDX? Что-то еще?), Вам нужно заблокировать текстуру и записать данные в массиве pixels втекстура.

...