无法使用 Direct2D 在其他位图之上绘制位图

Unable to draw bitmaps on top of other bitmap using Direct2D

我想编写一个使用 SharpDX 在背景图像上绘制许多对象的 Direct2D 应用程序。但是在绘制了一定数量的对象之后,Direct2D 将忽略所有其他对象。但是,前提是至少有 1 个对象与背景图像重叠。

这是我的渲染功能的简化版本:

private void Draw()
{
    var zoom = 0.6f;
    var destRect = new RectangleF(0, 0, _windowWidth, _windowHeight);
    RenderTarget2D.DrawBitmap(_backgroundBitmap, destRect, 1.0f, BitmapInterpolationMode.Linear);

    for (var j = 0; j < 10; j++)
    {
        for (var i = 0; i < 100; i++)
        {
            var d = (j % 10);
            destRect = new RectangleF(i * 22 * zoom, j* 40 * zoom, 22 * zoom, 40 * zoom);
            var srcRect = new RectangleF(d * 22, 40, 22, 40);
            RenderTarget2D.DrawBitmap(_digits, destRect, 1.0f, BitmapInterpolationMode.Linear, srcRect);
        }
    }
}

The result is

第 9 行仅绘制了一部分,而第 10 行根本未绘制。

然而,当没有背景图像或没有前景对象接触背景图像时,所有 1000 个对象都会被正确渲染。

Result without background image

更令人困惑的是,当我将行数减少到 3 时,第 3 行不再绘制其所有对象,这在绘制超过 3 行时不会发生。

Result with 3 rows

我的申请有什么问题?

下面是源代码的其余部分(以防相关)...

private void Render()
{
    RenderTarget2D.BeginDraw();
    _deviceContext.Rasterizer.SetViewport(new Viewport(0, 0, _windowWidth, _windowHeight));
    _deviceContext.OutputMerger.SetTargets(_backBufferView);
    Draw();
    _swapChain.Present(0, PresentFlags.None);
    RenderTarget2D.EndDraw();
}

// Initialize DX objects
public void InitDX()
{
    // SwapChain description
    var desc = new SwapChainDescription()
    {
        BufferCount = 1,
        ModeDescription = new ModeDescription(_windowWidth, _windowHeight, new Rational(60, 1), Format.R8G8B8A8_UNorm),
        IsWindowed = true,
        OutputHandle = DisplayHandle,
        SampleDescription = new SampleDescription(1, 0),
        SwapEffect = SwapEffect.Discard,
        Usage = Usage.RenderTargetOutput
    };

    // Create Device and SwapChain
    Factory2D = new SharpDX.Direct2D1.Factory();
    SharpDX.Direct3D11.Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.BgraSupport, new[] { SharpDX.Direct3D.FeatureLevel.Level_10_0 }, desc, out _device, out _swapChain);
    _deviceContext = _device.ImmediateContext;

    // Ignore all windows events
    SharpDX.DXGI.Factory factory = _swapChain.GetParent<SharpDX.DXGI.Factory>();
    factory.MakeWindowAssociation(DisplayHandle, WindowAssociationFlags.IgnoreAll);

    ResizeSwapChain(_windowWidth, _windowHeight);
}

// Resizes the swap-chain
public void ResizeSwapChain(int width, int height)
{
    RenderTarget2D?.Dispose();
    _backBuffer?.Dispose();
    _backBufferView?.Dispose();
    _surface?.Dispose();

    _swapChain.ResizeBuffers(1, width, height, Format.Unknown, SwapChainFlags.AllowModeSwitch);

    _backBuffer = Resource.FromSwapChain<Texture2D>(_swapChain, 0);
    _backBufferView = new RenderTargetView(_device, _backBuffer);
    _surface = _backBuffer.QueryInterface<Surface>();
    var dpi = Factory2D.DesktopDpi;
    RenderTarget2D = new RenderTarget(Factory2D, _surface, new RenderTargetProperties(RenderTargetType.Hardware, new PixelFormat(Format.Unknown, AlphaMode.Premultiplied), dpi.Width, dpi.Height, RenderTargetUsage.None, SharpDX.Direct2D1.FeatureLevel.Level_DEFAULT));
}

// Loads a Direct2D Bitmap from a file
public static Bitmap LoadBitmapFromFile(string file)
{
    var winBitmap = (System.Drawing.Bitmap)System.Drawing.Image.FromFile(file);

    var dxBitmap = CreateDirect2DBitmap(winBitmap, true);
    dxBitmap.Tag = file;
    winBitmap.Dispose();
    return dxBitmap;
}

// Creates a Direct2D from a System.Drawing.Bitmap
public static Bitmap CreateDirect2DBitmap(System.Drawing.Bitmap src, bool swapChannels)
{
    var sourceArea = new System.Drawing.Rectangle(0, 0, src.Width, src.Height);
    var bitmapProperties = new BitmapProperties(new PixelFormat(Format.R8G8B8A8_UNorm, AlphaMode.Premultiplied));
    var size = new Size2(src.Width, src.Height);

    // Transform pixels from BGRA to RGBA
    int stride = src.Width * sizeof(int);
    using (var tempStream = new DataStream(src.Height * stride, true, true))
    {
        // Lock System.Drawing.Bitmap
        var bitmapData = src.LockBits(sourceArea, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);

        // Convert all pixels
        if (swapChannels)
        {
            for (int y = 0; y < src.Height; y++)
            {
                int offset = bitmapData.Stride * y;
                for (int x = 0; x < src.Width; x++)
                {
                    // Not optimized 
                    byte b = Marshal.ReadByte(bitmapData.Scan0, offset++);
                    byte g = Marshal.ReadByte(bitmapData.Scan0, offset++);
                    byte r = Marshal.ReadByte(bitmapData.Scan0, offset++);
                    byte a = Marshal.ReadByte(bitmapData.Scan0, offset++);
                    int rgba = r | (g << 8) | (b << 16) | (a << 24);
                    tempStream.Write(rgba);
                }
            }
        }

        Bitmap result;
        if (swapChannels)
        {
            tempStream.Position = 0;
            result = new Bitmap(RenderTarget2D, size, tempStream, stride, bitmapProperties);
        }
        else
        {
            result = new Bitmap(RenderTarget2D, size, new DataStream(bitmapData.Scan0, stride * src.Height, true, false), stride, bitmapProperties);
        }
        src.UnlockBits(bitmapData);

        return result;
    }
}

我觉得问题是你还没画完就present了。您应该重新排序这些电话:

RenderTarget2D.EndDraw();
_swapChain.Present(0, PresentFlags.None);