Using SharpDX Image effects

1

Forgive the code below, I'm quite out my depth with DirectX and really struggling to conceptualise the different parts. I'm trying to achieve this through SharpDX. I've managed to (in other code) render rectangles, images and text to screen without too much difficulty. However, these all leverage RenderTaget to draw to the canvas. However, effects appear to require the use of a RenderContext which is baffling me.

I've knocked together some code by amalgamating two examples on the SharpDX repo. The first renders a glowing rectangle to screen. The other (renamed DrawImageWithEffect in my code) returns a bitmap which has added effects. The latter works if used directly in the example (saves the image to disk), but I want it just to return a bitmap for further rendering.

The error message occurs at:

d2dRenderTarget.EndDraw()

And reads:

SharpDX.SharpDXException
  HResult=0x88990012
  Message=HRESULT: [0x88990012], Module: [SharpDX.Direct2D1], ApiCode: [D2DERR_WRONG_FACTORY/WrongFactory], Message: Objects used together must be created from the same factory instance.

  Source=SharpDX
  StackTrace:
   at SharpDX.Result.CheckError()
   at SharpDX.Direct2D1.RenderTarget.EndDraw()
   at Tests_SharpDX4.RenderWindow2._Lambda$__18-0() in C:\Users\Steve\Documents\Visual Studio 2017\Projects\Tests_SharpDX4\Tests_SharpDX4\Classes\TestRender5.vb:line 101
   at Tests_SharpDX4.RenderWindow2._Lambda$__R18-1()
   at SharpDX.Windows.RenderLoop.Run(Control form, RenderCallback renderCallback, Boolean useApplicationDoEvents)
   at Tests_SharpDX4.RenderWindow2.Render() in C:\Users\Steve\Documents\Visual Studio 2017\Projects\Tests_SharpDX4\Tests_SharpDX4\Classes\TestRender5.vb:line 92
   at Tests_SharpDX4.Form1.Button1_Click(Object sender, EventArgs e) in C:\Users\Steve\Documents\Visual Studio 2017\Projects\Tests_SharpDX4\Tests_SharpDX4\Form1.vb:line 8
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
   at Tests_SharpDX4.My.MyApplication.Main(String[] Args) in :line 81

Full code (beware - hacky and rough!):

Imports SharpDX
Imports SharpDX.Direct2D1
Imports SharpDX.Direct3D
Imports SharpDX.Direct3D11
Imports SharpDX.DXGI
Imports SharpDX.Windows
Imports SharpDX.Mathematics
Imports SharpDX.IO
Imports D3D11 = SharpDX.Direct3D11
Imports d3d = SharpDX.Direct3D11
Imports D2 = SharpDX.Direct2D1
Imports dxgi = SharpDX.DXGI
Imports wic = SharpDX.WIC
Imports dw = SharpDX.DirectWrite
Imports Factory = SharpDX.DXGI.Factory
Imports AlphaMode = SharpDX.Direct2D1.AlphaMode
Imports Device = SharpDX.Direct3D11.Device


Public Class RenderWindow2
    Implements IDisposable

    'Redner Form
    Dim form As RenderForm = New RenderForm("SharpDX - MiniTri Direct2D - Direct3D 10 Sample")

    'Swapchain description
    Dim desc = New SwapChainDescription() With {
            .BufferCount = 1,
            .ModeDescription = New ModeDescription(form.ClientSize.Width, form.ClientSize.Height, New Rational(60, 1), Format.R8G8B8A8_UNorm),
            .IsWindowed = True,
            .OutputHandle = form.Handle,
            .SampleDescription = New SampleDescription(1, 0),
            .SwapEffect = SwapEffect.Discard,
            .Usage = Usage.RenderTargetOutput
        }

    Dim device As Device
    Dim swapChain As SwapChain

    Dim d2dFactory = New SharpDX.Direct2D1.Factory()

    Dim backBuffer As Texture2D
    Dim renderView As RenderTargetView
    Dim factory As Factory

    Dim surface As Surface

    Dim d2dRenderTarget As RenderTarget

    Dim stopwatch As Stopwatch = New Stopwatch()
    Dim solidColorBrush As SolidColorBrush

    Dim width As Integer = form.ClientSize.Width
    Dim height As Integer = form.ClientSize.Height
    Dim rectangleGeometry = New RoundedRectangleGeometry(d2dFactory, New RoundedRectangle() With {
            .RadiusX = 32,
            .RadiusY = 32,
            .Rect = New SharpDX.RectangleF(128, 128, width - 128 * 2, height - 128 * 2)
        })

    Dim bm As Bitmap1


    Public Sub New()

        Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.BgraSupport, New SharpDX.Direct3D.FeatureLevel() {SharpDX.Direct3D.FeatureLevel.Level_10_0}, desc, device, swapChain)

        factory = swapChain.GetParent(Of Factory)()
        factory.MakeWindowAssociation(form.Handle, WindowAssociationFlags.IgnoreAll)
        backBuffer = Texture2D.FromSwapChain(Of Texture2D)(swapChain, 0)
        renderView = New RenderTargetView(device, backBuffer)

        surface = backBuffer.QueryInterface(Of Surface)()
        d2dRenderTarget = New RenderTarget(d2dFactory, surface, New RenderTargetProperties(New PixelFormat(Format.Unknown, AlphaMode.Premultiplied)))

        solidColorBrush = New SolidColorBrush(d2dRenderTarget, Color.White)

        stopwatch.Start()

        LoadResources()

    End Sub

    Private Sub LoadResources()

        bm = DrawImageWithEffect("arcademachine.png")

    End Sub

    Public Sub Render()

        RenderLoop.Run(form, Function()
                                 d2dRenderTarget.BeginDraw()

                                 d2dRenderTarget.Clear(Color.DarkBlue)
                                 solidColorBrush.Color = New Color4(1, 1, 1, CSng(Math.Abs(Math.Cos(stopwatch.ElapsedMilliseconds * 0.001))))
                                 d2dRenderTarget.FillGeometry(rectangleGeometry, solidColorBrush, Nothing)

                                 d2dRenderTarget.DrawBitmap(bm, 1, BitmapInterpolationMode.Linear)

                                 d2dRenderTarget.EndDraw()
                                 swapChain.Present(0, PresentFlags.None)
                             End Function)
    End Sub

    Public Function DrawImageWithEffect(inputPath As String) As Bitmap1

        ' This sample represents a method of offline image processing.
        ' It requires references to DirectX 11.1, so it will run only on Windows 7 Platform Update Or above.
        ' It references SharpDX from Win8Desktop-net40 folder.
        ' The same method Is applicable in Windows 8 modern apps.
        ' This code skips all sanity checks to focus on feature demonstration. In production apps do Not forget to check
        ' for parameters correctness And feature support.

        ' The sample does the following
        ' 1. Initializes references to all needed devices And factories
        ' 2. Loads an input image And stores its size to be used in the output image
        ' 3. Prepares an effect graph to process the image
        ' 4. Prepares some text to draw it over image (useful for any kind of annotations, watermarks, etc).
        ' 5. Initializes the render target - here can be any compatible surface.
        ' 6. Draws the prepared effect graph And text.
        ' 7. Saves the image in the output file.
        ' 8. Disposes everything.
        ' 9. Starts the default associated program to display the result.

        Dim outputPath = "Output.png"
        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' INITIALIZATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        ' initialize the D3D device which will allow to render to image any graphics - 3D Or 2D
        Dim defaultDevice = device
        Dim d3dDevice = defaultDevice.QueryInterface(Of Direct3D11.Device1)()
        Dim dxgiDevice = d3dDevice.QueryInterface(Of dxgi.Device)()
        Dim d2dDevice = New D2.Device(dxgiDevice)

        'Dim imagingFactory = New wic.ImagingFactory2()
        Dim imagingFactory = New wic.ImagingFactory2()


        ' initialize the DeviceContext - it will be the D2D render target and will allow all rendering operations
        Dim d2dContext = New D2.DeviceContext(d2dDevice, D2.DeviceContextOptions.None)
        Dim dwFactory = New dw.Factory()

        ' specify a pixel format that is supported by both D2D and WIC
        Dim d2PixelFormat = New D2.PixelFormat(dxgi.Format.R8G8B8A8_UNorm, D2.AlphaMode.Premultiplied)
        Dim wicPixelFormat = wic.PixelFormat.Format32bppPRGBA

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' IMAGE LOADING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        Dim decoder = New wic.PngBitmapDecoder(imagingFactory)
        Dim inputStream = New wic.WICStream(imagingFactory, inputPath, SharpDX.IO.NativeFileAccess.Read)
        decoder.Initialize(inputStream, wic.DecodeOptions.CacheOnLoad)

        ' decode the loaded image to a format that can be consumed by D2D
        Dim formatConverter = New wic.FormatConverter(imagingFactory)
        formatConverter.Initialize(decoder.GetFrame(0), wicPixelFormat)

        ' load the base image into a D2D Bitmap
        'var inputBitmap = d2.Bitmap1.FromWicBitmap(d2dContext, formatConverter, New d2.BitmapProperties1(d2PixelFormat));

        ' store the image size - output will be of the same size
        Dim inputImageSize = formatConverter.Size
        Dim pixelWidth = inputImageSize.Width
        Dim pixelHeight = inputImageSize.Height

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' EFFECT SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        ' Effect 1  BitmapSource -take decoded image data And get a BitmapSource from it
        Dim bitmapSourceEffect = New D2.Effects.BitmapSource(d2dContext)
        bitmapSourceEffect.WicBitmapSource = formatConverter

        ' Effect 2 : GaussianBlur - give the bitmapsource a gaussian blurred effect
        Dim gaussianBlurEffect = New D2.Effects.GaussianBlur(d2dContext)
        gaussianBlurEffect.SetInput(0, bitmapSourceEffect.Output, True)
        gaussianBlurEffect.StandardDeviation = 5.0F

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' OVERLAY TEXT SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        Dim textFormat = New dw.TextFormat(dwFactory, "Arial", 15.0F)

        ' draw a long text to show the automatic line wrapping
        Dim textToDraw = "MAGO WOZ ERE"

        ' create the text layout - this improves the drawing performance for static text
        ' as the glyph positions are precalculated
        Dim textLayout = New dw.TextLayout(dwFactory, textToDraw, textFormat, 300.0F, 1000.0F)
        Dim textBrush = New D2.SolidColorBrush(d2dContext, New Interop.RawColor4(0, 0, 0.8, 1))

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' RENDER TARGET SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        ' create the d2d bitmap description using default flags (from SharpDX samples) And 96 DPI
        Dim d2dBitmapProps = New D2.BitmapProperties1(d2PixelFormat, 96, 96, D2.BitmapOptions.Target Or D2.BitmapOptions.CannotDraw)
        Dim d2dRenderTarget = New D2.Bitmap1(d2dContext, New SharpDX.Size2(pixelWidth, pixelHeight), d2dBitmapProps)

        ' the render target
        d2dContext.Target = d2dRenderTarget

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' DRAWING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        ' slow preparations - fast drawing
        d2dContext.BeginDraw()
        d2dContext.DrawImage(gaussianBlurEffect)
        d2dContext.DrawTextLayout(New Vector2(5.0F, 5.0F), textLayout, textBrush)
        d2dContext.EndDraw()

        ' MY EDIT:
        Return d2dRenderTarget

        ' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' IMAGE SAVING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        ' delete the output file if it already exists

        If System.IO.File.Exists(outputPath) Then System.IO.File.Delete(outputPath)

        ' use the appropiate overload to write either to stream or to a file
        Dim stream = New wic.WICStream(imagingFactory, outputPath, NativeFileAccess.Write)
        'Dim st2 = New wic.WICStream(imagingFactory,)
        ' select the image encoding format HERE

        Dim encoder = New wic.PngBitmapEncoder(imagingFactory)
        encoder.Initialize(stream)
        Dim bitmapFrameEncode = New wic.BitmapFrameEncode(encoder)
        bitmapFrameEncode.Initialize()
        bitmapFrameEncode.SetSize(pixelWidth, pixelHeight)
        bitmapFrameEncode.SetPixelFormat(wicPixelFormat)

        ' this is the trick to write D2D1 bitmap to WIC
        Dim imageEncoder = New wic.ImageEncoder(imagingFactory, d2dDevice)
        imageEncoder.WriteFrame(d2dRenderTarget, bitmapFrameEncode, New wic.ImageParameters(d2PixelFormat, 96, 96, 0, 0, pixelWidth, pixelHeight))
        bitmapFrameEncode.Commit()
        encoder.Commit()

        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ' CLEANUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        ' dispose everything And free used resources

        bitmapFrameEncode.Dispose()
        encoder.Dispose()
        stream.Dispose()
        textBrush.Dispose()
        textLayout.Dispose()
        textFormat.Dispose()
        formatConverter.Dispose()
        gaussianBlurEffect.Dispose()
        bitmapSourceEffect.Dispose()
        d2dRenderTarget.Dispose()
        inputStream.Dispose()
        decoder.Dispose()
        d2dContext.Dispose()
        dwFactory.Dispose()
        imagingFactory.Dispose()
        d2dDevice.Dispose()
        dxgiDevice.Dispose()
        d3dDevice.Dispose()
        defaultDevice.Dispose()
        'System.Diagnostics.Process.Start(outputPath)
    End Function


#Region "IDisposable Support"
    Private disposedValue As Boolean ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not disposedValue Then
            If disposing Then
                ' TODO: dispose managed state (managed objects).
                renderView.Dispose()
                backBuffer.Dispose()
                device.ImmediateContext.ClearState()
                device.ImmediateContext.Flush()
                device.Dispose()
                device.Dispose()
                swapChain.Dispose()
                factory.Dispose()
            End If

            ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
            ' TODO: set large fields to null.
        End If
        disposedValue = True
    End Sub

    ' TODO: override Finalize() only if Dispose(disposing As Boolean) above has code to free unmanaged resources.
    'Protected Overrides Sub Finalize()
    '    ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
    '    Dispose(False)
    '    MyBase.Finalize()
    'End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
        Dispose(True)
        ' TODO: uncomment the following line if Finalize() is overridden above.
        ' GC.SuppressFinalize(Me)
    End Sub
#End Region
End Class

I'm tearing my hair out here with DX - would really appreciate some guidance..

vb.net
winforms
directx
sharpdx
imaging
asked on Stack Overflow Oct 7, 2018 by stigzler • edited Oct 8, 2018 by Jimi

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0