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..
User contributions licensed under CC BY-SA 3.0