在SharpDX中调整DXGI资源或Texture2D的大小 [英] Resizing a DXGI Resource or Texture2D in SharpDX

查看:285
本文介绍了在SharpDX中调整DXGI资源或Texture2D的大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想调整在SharpDX中使用桌面复制API捕获的屏幕的大小。我正在使用屏幕捕获示例代码从SharpDX样本存储库中,相关部分如下:。

I want to resize a screen captured using the Desktop Duplication API in SharpDX. I am using the Screen Capture sample code from the SharpDX Samples repository, relevant portion follows:.

SharpDX.DXGI.Resource screenResource;
OutputDuplicateFrameInformation duplicateFrameInformation;

// Try to get duplicated frame within given time
duplicatedOutput.AcquireNextFrame(10000, out duplicateFrameInformation, out screenResource);

if (i > 0)
{
    // copy resource into memory that can be accessed by the CPU
    using (var screenTexture2D = screenResource.QueryInterface<Texture2D>()) 
    device.ImmediateContext.CopyResource(screenTexture2D, screenTexture);

    // Get the desktop capture texture
    var mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.Read, MapFlags.None);

    System.Diagnostics.Debug.WriteLine(watch.Elapsed);

    // Create Drawing.Bitmap
    var bitmap = new System.Drawing.Bitmap(width, height, PixelFormat.Format32bppArgb);
    var boundsRect = new System.Drawing.Rectangle(0, 0, width, height);

    // Copy pixels from screen capture Texture to GDI bitmap
    var mapDest = bitmap.LockBits(boundsRect, ImageLockMode.WriteOnly, bitmap.PixelFormat);
    var sourcePtr = mapSource.DataPointer;
    var destPtr = mapDest.Scan0;
    for (int y = 0; y < height; y++)
    {
        // Iterate and write to bitmap...

在处理为字节数组之前,我想将图像调整为比实际屏幕尺寸小得多的尺寸。我不需要保存图像,只需获取字节数即可。我想相对快速有效地做到这一点(例如,如果可能的话,利用GPU)。

I would like to resize the image much smaller than the actual screen size before processing it as a byte array. I do not need to save the image, just get at the bytes. I would like to do this relatively quickly and efficiently (e.g. leveraging GPU if possible).

CopyResource期间,我无法扩展,因为输出尺寸必须与输入尺寸相同。我可以从我的 screenTexture2D 执行另一个副本以进行缩放吗?如何精确地缩放资源-是否使用交换链,矩阵变换或其他方法?

I'm not able to scale during CopyResource, as the output dimensions are required to be the same as the input dimensions. Can I perform another copy from my screenTexture2D to scale? How exactly do I scale the resource - do I use a Swap Chain, Matrix transform, or something else?

推荐答案

可以从屏幕上精细调整为2的幂,您可以通过以下方式实现:

If you are fine resizing to a power of two from the screen, you can do it by:


  • 使用创建较小的纹理RenderTarget / ShaderResource 的用法,以及选项 GenerateMipMaps ,相同大小的屏幕,mipcount> 1(2表示大小/ 2,3表示大小/ 4 ...等。)

  • 将屏幕纹理的第一个mipmap复制到较小的纹理

  • DeviceContext.GenerateMipMaps 在较小纹理上

  • 将较小纹理(1:/ 2、2:/ 4 ...等)的选定mimap复制到临时纹理(也应该声明为较小的值,即与将要使用的mipmap相同)

  • Create a smaller texture with RenderTarget/ShaderResource usage, and options GenerateMipMaps, same size of screen, mipcount > 1 (2 for having size /2, 3 for having /4...etc.).
  • Copy the first mipmap of the screen texture to the smaller texture
  • DeviceContext.GenerateMipMaps on the smaller texture
  • Copy the selected mimap of the smaller texture (1: /2, 2: /4...etc.) to the staging texture (that should also be declared smaller, i.e. same size as the mipmap that is going to be used)

对原始内容的快速破解生成/ 2纹理的代码如下:

A quick hack on the original code to generate a /2 texture would be like this:

    [STAThread]
    private static void Main()
    {
        // # of graphics card adapter
        const int numAdapter = 0;

        // # of output device (i.e. monitor)
        const int numOutput = 0;

        const string outputFileName = "ScreenCapture.bmp";

        // Create DXGI Factory1
        var factory = new Factory1();
        var adapter = factory.GetAdapter1(numAdapter);

        // Create device from Adapter
        var device = new Device(adapter);

        // Get DXGI.Output
        var output = adapter.GetOutput(numOutput);
        var output1 = output.QueryInterface<Output1>();

        // Width/Height of desktop to capture
        int width = output.Description.DesktopBounds.Width;
        int height = output.Description.DesktopBounds.Height;

        // Create Staging texture CPU-accessible
        var textureDesc = new Texture2DDescription
                              {
                                  CpuAccessFlags = CpuAccessFlags.Read,
                                  BindFlags = BindFlags.None,
                                  Format = Format.B8G8R8A8_UNorm,
                                  Width = width/2,
                                  Height = height/2,
                                  OptionFlags = ResourceOptionFlags.None,
                                  MipLevels = 1,
                                  ArraySize = 1,
                                  SampleDescription = { Count = 1, Quality = 0 },
                                  Usage = ResourceUsage.Staging
                              };
        var stagingTexture = new Texture2D(device, textureDesc);

        // Create Staging texture CPU-accessible
        var smallerTextureDesc = new Texture2DDescription
        {
            CpuAccessFlags = CpuAccessFlags.None,
            BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
            Format = Format.B8G8R8A8_UNorm,
            Width = width,
            Height = height,
            OptionFlags = ResourceOptionFlags.GenerateMipMaps,
            MipLevels = 4,
            ArraySize = 1,
            SampleDescription = { Count = 1, Quality = 0 },
            Usage = ResourceUsage.Default
        };
        var smallerTexture = new Texture2D(device, smallerTextureDesc);
        var smallerTextureView = new ShaderResourceView(device, smallerTexture);

        // Duplicate the output
        var duplicatedOutput = output1.DuplicateOutput(device);

        bool captureDone = false;
        for (int i = 0; !captureDone; i++)
        {
            try
            {
                SharpDX.DXGI.Resource screenResource;
                OutputDuplicateFrameInformation duplicateFrameInformation;

                // Try to get duplicated frame within given time
                duplicatedOutput.AcquireNextFrame(10000, out duplicateFrameInformation, out screenResource);

                if (i > 0)
                {
                    // copy resource into memory that can be accessed by the CPU
                    using (var screenTexture2D = screenResource.QueryInterface<Texture2D>())
                        device.ImmediateContext.CopySubresourceRegion(screenTexture2D, 0, null, smallerTexture, 0);

                    // Generates the mipmap of the screen
                    device.ImmediateContext.GenerateMips(smallerTextureView);

                    // Copy the mipmap 1 of smallerTexture (size/2) to the staging texture
                    device.ImmediateContext.CopySubresourceRegion(smallerTexture, 1, null, stagingTexture, 0);

                    // Get the desktop capture texture
                    var mapSource = device.ImmediateContext.MapSubresource(stagingTexture, 0, MapMode.Read, MapFlags.None);

                    // Create Drawing.Bitmap
                    var bitmap = new System.Drawing.Bitmap(width/2, height/2, PixelFormat.Format32bppArgb);
                    var boundsRect = new System.Drawing.Rectangle(0, 0, width/2, height/2);

                    // Copy pixels from screen capture Texture to GDI bitmap
                    var mapDest = bitmap.LockBits(boundsRect, ImageLockMode.WriteOnly, bitmap.PixelFormat);
                    var sourcePtr = mapSource.DataPointer;
                    var destPtr = mapDest.Scan0;
                    for (int y = 0; y < height/2; y++)
                    {
                        // Copy a single line 
                        Utilities.CopyMemory(destPtr, sourcePtr, width/2 * 4);

                        // Advance pointers
                        sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch);
                        destPtr = IntPtr.Add(destPtr, mapDest.Stride);
                    }

                    // Release source and dest locks
                    bitmap.UnlockBits(mapDest);
                    device.ImmediateContext.UnmapSubresource(stagingTexture, 0);

                    // Save the output
                    bitmap.Save(outputFileName);

                    // Capture done
                    captureDone = true;
                }

                screenResource.Dispose();
                duplicatedOutput.ReleaseFrame();

            }
            catch (SharpDXException e)
            {
                if (e.ResultCode.Code != SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
                {
                    throw e;
                }
            }
        }

        // Display the texture using system associated viewer
        System.Diagnostics.Process.Start(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, outputFileName)));

        // TODO: We should cleanp up all allocated COM objects here
    }

这篇关于在SharpDX中调整DXGI资源或Texture2D的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆