Sign in to follow this  
Followers 0
CdrTomalak

DX11
Making SlimDX tutorial code compatible with old graphics hardware...

0 posts in this topic

You might have seen me post about this problem before, but basically I have just merged the SlimDX tutorial code with Ron Pentons game framework as per his C# Game Programming book.

The problem is, this won't run on my Dell Latitude D600 ([i]DXGI ERROR UNSUPPORTED)[/i], whilst is fine on my slightly old gaming rig with an Nvidia 9800GT. All it's doing is displaying a triangle.

The quesiton is, how can I alter the code to make it compatible with the ATI Radeon Mobility 9000 graphics hardware on the D600? The specificaiton for this GPU says it doesn't even officically support DirectX9!

Here's the code anyways (excuse the lack of comments - I've stripped most of them out shorten this post).

[CODE]
using System;
using System.ComponentModel;
using SlimDX;
using SlimDX.Windows;
using System.Windows.Forms;
namespace BasicWindow_1
{
public class Game : Form
{
// --------------------------------------------------------------------
// static variables
// --------------------------------------------------------------------
static string gametitle = "Test";
static int screenwidth = 640;
static int screenheight = 480;
static bool windowed = true;
static bool graphicslost = false;
static bool paused = false;
// --------------------------------------------------------------------

// --------------------------------------------------------------------
// Direct3D9 object
// --------------------------------------------------------------------
SlimDX.Direct3D9.Direct3D myD3D;
// --------------------------------------------------------------------

// --------------------------------------------------------------------
// Devices
// --------------------------------------------------------------------

SlimDX.Direct3D11.Device graphics = null;
SlimDX.DXGI.SwapChain swapChain = null;

SlimDX.D3DCompiler.ShaderSignature inputSignature = null;
SlimDX.Direct3D11.VertexShader vertexShader = null;
SlimDX.Direct3D11.PixelShader pixelShader = null;

SlimDX.Direct3D11.RenderTargetView renderTarget = null;

SlimDX.Direct3D11.DeviceContext context = null;

// KEYBOARD ...
SlimDX.DirectInput.DirectInput directInput = null;
SlimDX.DirectInput.Keyboard keyboard = null;

// MOUSE ...
SlimDX.DirectInput.Mouse mouse = null;

// SOUND ...
SlimDX.DirectSound.DirectSound sound = null;


// --------------------------------------------------------------------

// --------------------------------------------------------------------
// Vertex Object
// --------------------------------------------------------------------
SlimDX.DataStream vertices = new DataStream(12 * 3, true, true);
SlimDX.Direct3D11.Buffer vertexBuffer = null; // This is set in init geom.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


// ********************************************************************
// Game Constructor!
public Game()
{
ClientSize = new System.Drawing.Size( screenwidth, screenheight );

Text = gametitle;

}
// ********************************************************************


// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// START: Method InitialiseGraphics
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
public void InitialiseGraphics()
{

var description = new SlimDX.DXGI.SwapChainDescription()
{
BufferCount = 2,
Usage = SlimDX.DXGI.Usage.RenderTargetOutput,
OutputHandle = this.Handle,
IsWindowed = true,
ModeDescription = new SlimDX.DXGI.ModeDescription(0, 0, new SlimDX.Rational(60, 1), SlimDX.DXGI.Format.R8G8B8A8_UNorm),
SampleDescription = new SlimDX.DXGI.SampleDescription(1, 0),
Flags = SlimDX.DXGI.SwapChainFlags.AllowModeSwitch,
SwapEffect = SlimDX.DXGI.SwapEffect.Discard
};

SlimDX.Direct3D11.Device.CreateWithSwapChain(
SlimDX.Direct3D11.DriverType.Hardware,
SlimDX.Direct3D11.DeviceCreationFlags.Debug,
description,
out graphics,
out swapChain
);

// create a view of our render target, which is the backbuffer of the swap chain we just created
using (var resource = SlimDX.Direct3D11.Resource.FromSwapChain<SlimDX.Direct3D11.Texture2D>(swapChain, 0))
renderTarget = new SlimDX.Direct3D11.RenderTargetView(graphics, resource);
// setting a viewport is required if you want to actually see anything
context = graphics.ImmediateContext;
var viewport = new SlimDX.Direct3D11.Viewport(0.0f, 0.0f, this.ClientSize.Width, this.ClientSize.Height);
context.OutputMerger.SetTargets(renderTarget);
context.Rasterizer.SetViewports(viewport);
// load and compile the vertex shader
using (var bytecode = SlimDX.D3DCompiler.ShaderBytecode.CompileFromFile("E:\\MY_AREA\\SharpDevelop_Projects\\SlimDX_StartOver\\BasicWindow_1\\BasicWindow_1\ riangle.fx", "VShader", "vs_4_0", SlimDX.D3DCompiler.ShaderFlags.None, SlimDX.D3DCompiler.EffectFlags.None))
{
inputSignature = SlimDX.D3DCompiler.ShaderSignature.GetInputSignature(bytecode);
vertexShader = new SlimDX.Direct3D11.VertexShader(graphics, bytecode);
}

// load and compile the pixel shader
using (var bytecode = SlimDX.D3DCompiler.ShaderBytecode.CompileFromFile("E:\\MY_AREA\\SharpDevelop_Projects\\SlimDX_StartOver\\BasicWindow_1\\BasicWindow_1\ riangle.fx", "PShader", "ps_4_0", SlimDX.D3DCompiler.ShaderFlags.None, SlimDX.D3DCompiler.EffectFlags.None))
pixelShader = new SlimDX.Direct3D11.PixelShader(graphics, bytecode);


// -----------------------------------------------------------------------
}
// END: Method InitialiseGraphics


// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// ***************** InitializeSound START ****************************
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Initialize the DirectSound subsystem
public void InitialiseSound()
{
// set up a device
sound = new SlimDX.DirectSound.DirectSound();

sound.SetCooperativeLevel( this.Handle, SlimDX.DirectSound.CooperativeLevel.Normal );
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


// ********************************************************************
// *************** InitializeInput START ******************************
// ********************************************************************
// Initialize the DirectInput subsystem
public void InitialiseInput()
{
// set up the keyboard
directInput = new SlimDX.DirectInput.DirectInput();
keyboard = new SlimDX.DirectInput.Keyboard(directInput);

keyboard.SetCooperativeLevel(
this,
SlimDX.DirectInput.CooperativeLevel.Background |
SlimDX.DirectInput.CooperativeLevel.Nonexclusive );
keyboard.Acquire();
// set up the mouse
mouse = new SlimDX.DirectInput.Mouse(directInput);
mouse.SetCooperativeLevel(
this,
SlimDX.DirectInput.CooperativeLevel.Background |
SlimDX.DirectInput.CooperativeLevel.Nonexclusive );
mouse.Acquire();
}
// ********************************************************************

// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Method InitialiseGeometry
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
public void InitialiseGeometry()
{
vertices.Write(new Vector3(0.0f, 0.5f, 0.5f));
vertices.Write(new Vector3(0.5f, -0.5f, 0.5f));
vertices.Write(new Vector3(-0.5f, -0.5f, 0.5f));
vertices.Position = 0; // Rewind the position after we're done.
// create the vertex layout and buffer
var elements = new[] { new SlimDX.Direct3D11.InputElement("POSITION", 0, SlimDX.DXGI.Format.R32G32B32_Float, 0) };
var layout = new SlimDX.Direct3D11.InputLayout(graphics, inputSignature, elements);

// Once we have our vertex data in memory, we need to load it into
// a Direct3D vertex buffer, which can then be passed into the graphics pipeline.
vertexBuffer = new SlimDX.Direct3D11.Buffer(
graphics,
vertices,
12 * 3,
SlimDX.Direct3D11.ResourceUsage.Default,
SlimDX.Direct3D11.BindFlags.VertexBuffer,
SlimDX.Direct3D11.CpuAccessFlags.None,
SlimDX.Direct3D11.ResourceOptionFlags.None,
0);

// configure the Input Assembler portion of the pipeline with the vertex data
context.InputAssembler.InputLayout = layout;
context.InputAssembler.PrimitiveTopology = SlimDX.Direct3D11.PrimitiveTopology.TriangleList;
context.InputAssembler.SetVertexBuffers(0, new SlimDX.Direct3D11.VertexBufferBinding(vertexBuffer, 12, 0));
// set the shaders
context.VertexShader.Set(vertexShader);
context.PixelShader.Set(pixelShader);
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// START: Method RenderFrame
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
public void RenderFrame()
{
// GT 01/06/12:
// From what I can tell, the render frame method
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// END: Method RenderFrame
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// ************** ProcessFrame START **********************************
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Process one iteration of the game loop
protected virtual void ProcessFrame()
{
// process the game only while it's not paused
if( !paused )
{

}
else
System.Threading.Thread.Sleep( 1 );
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Render....
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
protected virtual void Render()
{
if( graphics != null )
{
context.ClearRenderTargetView(renderTarget, new SlimDX.Color4(0.5f, 0.5f, 1.0f));

// draw the triangle
context.Draw(3, 0);
swapChain.Present(0, SlimDX.DXGI.PresentFlags.None);

}
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// ******************** Run START *************************************
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Run the game
public void Run()
{
while( this.Created )
{
// Process one frame of the game
ProcessFrame();
// Render the current scene
// I.e. display graphics to the user in the game form.
Render();
// Handle all events
Application.DoEvents();
}
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


// ********************************************************************
// **************** HANDLE WINDOWS EVENTS *****************************
// ********************************************************************
// Handle windows events
protected override void OnLostFocus( EventArgs e )
{
base.OnLostFocus( e );
Paused = true;
}
protected override void OnKeyDown( KeyEventArgs e )
{
base.OnKeyDown( e );
if( e.KeyCode == System.Windows.Forms.Keys.Escape )
{
this.Close();
}
if ( e.KeyCode == System.Windows.Forms.Keys.P )
{
Paused = !Paused;
}
}
// ********************************************************************
// ********************************************************************
// Property to pause/unpause the game, or get its pause state
public bool Paused
{
get { return paused; }
set
{
// pause the game
if( value == true && paused == false )
{
// TO DO
//
//gametimer.Pause();
paused = true;
}
// unpause the game
if( value == false && paused == true )
{
// TO DO
//
//gametimer.Unpause();
paused = false;
}
}
}
// ********************************************************************

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// START: MAIN
[STAThread]
private static void Main(string[] args)
{
Game game;

try
{
game = new Game();

// Initialise Gfx, Sound, Input, Geometry
game.InitialiseGraphics();
game.InitialiseSound();
game.InitialiseInput();

game.InitialiseGeometry();
game.Show();
game.Run();
}
catch( Exception e )
{
MessageBox.Show( "Error: " + e.Message );
}
}
// END: MAIN
}
}
[/CODE]

EDIT: I might have found something in the SlimDX tutorial. One of the parameters to the SlimDX.Direct3D11.Device.CreateWithSwapChain() method is for Feature Levels:

[i]"The third parameter to the device creation function is an array of feature levels. Feature levels provide a unified method by which Direct3D 11 can run on lower end hardware. Each feature level mandates a specific set of functionality that an adapter must expose, enabling application developers to reliably scale their applications depending on the hardware a user might have. The array allows you to specify a set of feature levels that you’d like Direct3D to try to use. It will try them in order and create a device with the first one that works. You can use the [size=2]Device[/size][size=2].GetSupportedFeatureLevel[/size] method to get the highest feature level currently supported by the primary adapter. If you don’t care to specify a set and just want to use the highest available, you can skip the parameter and use the less generic overload. Once the device has been created, you can access the [size=2]Device[/size][size=2].FeatureLevel[/size] property to see which feature level is currently active. The [url="http://msdn.microsoft.com/en-us/library/ff476148%28VS.85%29.aspx"]10Level9[/url] reference on MSDN gives in-depth details about exactly which portions of the API are available on which feature levels."[/i]

I don't actually use this in my program, but perhaps this is the key to making my program compatible with the old D600?

EDIT: I think I've concluded something, although it's not good.

On my 9800GT rig the following works fine:

[CODE]
SlimDX.Direct3D11.FeatureLevel[] featureLevels = new SlimDX.Direct3D11.FeatureLevel[] { SlimDX.Direct3D11.FeatureLevel.Level_10_0 };
SlimDX.Direct3D11.Device.CreateWithSwapChain(
SlimDX.Direct3D11.DriverType.Hardware,
SlimDX.Direct3D11.DeviceCreationFlags.Debug,
featureLevels,
description,
out graphics,
out swapChain
);
[/CODE]

But when I use FeatureLevel.Level_10_1 or above, I get DXGI ERROR UNSUPPORTED, because this card doesn't support DX11.

I dropped down to FeatureLevel.Level_9_1 on the D600 laptop, but to no avail. Apparently the GPU supports DX8.1 and Shader 1.4, where as the requirements for Level_9_1 are shader model 2.

Oh dear. Still, it was interesting finding out. Edited by CdrTomalak
1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0

  • Similar Content

    • By amadeus12
      I wrote computeshader to blur image.
      But it returns black texture.
      actually I'm not using FX file and effect library.
      I use hlsl file and I bind it to pipeline myself with direct api.
      I have 2 hlsl files which do vertical, horizontal blur.
      here my CPU code which executes computeshader.
      void BoxApp::callComputeShaderandBlur(ID3D11DeviceContext * dc, ID3D11ShaderResourceView * inputSRV, ID3D11UnorderedAccessView * inputUAV, int blurcount)
      {
          for (int i = 0; i < blurcount; i++)
          {
              dc->CSSetShader(m_CSH, 0, 0);
              dc->CSSetShaderResources(0, 1, &inputSRV);
              dc->CSSetUnorderedAccessViews(0, 1, &mBlurOutPutTexUAV, 0);
            
              UINT numGroupsX = (UINT)ceilf(m_Width / 256.0f);
              dc->Dispatch(numGroupsX, m_Height, 1);
             
              dc->CSSetShaderResources(1, 0, 0);
              dc->CSSetUnorderedAccessViews(1, 0, 0, 0);
              dc->CSSetShader(m_CSV, 0, 0);
              dc->CSSetShaderResources(0, 1, &mBlurOutPutTexSRV);
              dc->CSSetUnorderedAccessViews(0, 1, &inputUAV, 0);
              UINT numGroupY = (UINT)ceilf(m_Height / 256.0f);
              dc->Dispatch(m_Width, numGroupY, 1);
              dc->CSSetShaderResources(1, 0, 0);
              dc->CSSetUnorderedAccessViews(1, 0, 0, 0);
          }
          dc->CSSetShaderResources(1, 0, 0);
          dc->CSSetUnorderedAccessViews(1, 0, 0, 0);
          dc->CSSetShader(0, 0, 0);
      }
      If I don't call this function, everything is fine. (I rendered my scene to off screen redertarget and use this texture as quad texture. and render it to real rendertarget. it worked fined)
      That means there's problem in ComputeShader code.
      Every resource and view isn't null pointer, I checked it.
      all HRESULTs are S_OK.
       
      here my 2 shader codes
       
      this is CSH.hlsl
      static float gWeights[11] =
      {
          0.05f, 0.05f, 0.1f, 0.1f, 0.1f, 0.2f, 0.1f, 0.1f, 0.1f, 0.05f, 0.05f,
      };
      static const int gBlurRadius = 5;
      Texture2D gInput;
      RWTexture2D<float4> gOutput;
      #define N 256
      #define CacheSize (N + 2*gBlurRadius)
      groupshared float4 gCache[CacheSize];
      [numthreads(N, 1, 1)]
      void main(int3 groupThreadID : SV_GroupThreadID,
          int3 dispatchThreadID : SV_DispatchThreadID)
      {
          //
          // Fill local thread storage to reduce bandwidth.  To blur 
          // N pixels, we will need to load N + 2*BlurRadius pixels
          // due to the blur radius.
          //
          // This thread group runs N threads.  To get the extra 2*BlurRadius pixels, 
          // have 2*BlurRadius threads sample an extra pixel.
          if (groupThreadID.x < gBlurRadius)
          {
              // Clamp out of bound samples that occur at image borders.
              int x = max(dispatchThreadID.x - gBlurRadius, 0);
              gCache[groupThreadID.x] = gInput[int2(x, dispatchThreadID.y)];
          }
          if (groupThreadID.x >= N - gBlurRadius)
          {
              // Clamp out of bound samples that occur at image borders.
              int x = min(dispatchThreadID.x + gBlurRadius, gInput.Length.x - 1);
              gCache[groupThreadID.x + 2 * gBlurRadius] = gInput[int2(x, dispatchThreadID.y)];
          }
          // Clamp out of bound samples that occur at image borders.
          gCache[groupThreadID.x + gBlurRadius] = gInput[min(dispatchThreadID.xy, gInput.Length.xy - 1)];
          // Wait for all threads to finish.
          GroupMemoryBarrierWithGroupSync();
          //
          // Now blur each pixel.
          //
          float4 blurColor = float4(0, 0, 0, 0);
          [unroll]
          for (int i = -gBlurRadius; i <= gBlurRadius; ++i)
          {
              int k = groupThreadID.x + gBlurRadius + i;
              blurColor += gWeights[i + gBlurRadius] * gCache[k];
          }
          gOutput[dispatchThreadID.xy] = blurColor;
      }
      and this is CSV
       
      static float gWeights[11] =
      {
              0.05f, 0.05f, 0.1f, 0.1f, 0.1f, 0.2f, 0.1f, 0.1f, 0.1f, 0.05f, 0.05f,
      };
      static const int gBlurRadius = 5;
      Texture2D gInput;
      RWTexture2D<float4> gOutput;
      #define N 256
      #define CacheSize (256 + 2*5)
      groupshared float4 gCache[CacheSize];

      [numthreads(1, N, 1)]
      void main(int3 groupThreadID : SV_GroupThreadID,
          int3 dispatchThreadID : SV_DispatchThreadID)
      {
          //
          // Fill local thread storage to reduce bandwidth.  To blur 
          // N pixels, we will need to load N + 2*BlurRadius pixels
          // due to the blur radius.
          //
          // This thread group runs N threads.  To get the extra 2*BlurRadius pixels, 
          // have 2*BlurRadius threads sample an extra pixel.
          if (groupThreadID.y < gBlurRadius)
          {
              // Clamp out of bound samples that occur at image borders.
              int y = max(dispatchThreadID.y - gBlurRadius, 0);
              gCache[groupThreadID.y] = gInput[int2(dispatchThreadID.x, y)];
          }
          if (groupThreadID.y >= N - gBlurRadius)
          {
              // Clamp out of bound samples that occur at image borders.
              int y = min(dispatchThreadID.y + gBlurRadius, gInput.Length.y - 1);
              gCache[groupThreadID.y + 2 * gBlurRadius] = gInput[int2(dispatchThreadID.x, y)];
          }
          // Clamp out of bound samples that occur at image borders.
          gCache[groupThreadID.y + gBlurRadius] = gInput[min(dispatchThreadID.xy, gInput.Length.xy - 1)];

          // Wait for all threads to finish.
          GroupMemoryBarrierWithGroupSync();
          //
          // Now blur each pixel.
          //
          float4 blurColor = float4(0, 0, 0, 0);
          [unroll]
          for (int i = -gBlurRadius; i <= gBlurRadius; ++i)
          {
              int k = groupThreadID.y + gBlurRadius + i;
              blurColor += gWeights[i + gBlurRadius] * gCache[k];
          }
          gOutput[dispatchThreadID.xy] = blurColor;
      }
       
       
      sorry about poor english.
      plz help I'm really sad...
      I spend whole day for this...
      It doesn't work..
      feels bad man..
    • By maxest
      I implemented DX queries after this blog post:
      https://mynameismjp.wordpress.com/2011/10/13/profiling-in-dx11-with-queries/
      Queries work perfectly fine... for as long as I don't use VSync or any other form of Sleep. Why would that happe? I record queries right before my Compute/Dispatch code, record right after and then read the results (spinning on GetData if returns S_FALSE).
      When I don't VSync then my code takes consistent 0.39-0.4 ms. After turning VSync on it starts with something like 0.46 ms, after a second bumps up to 0.61 ms and a few seconds after I get something like 1.2 ms.
      I also used this source:
      http://reedbeta.com/blog/gpu-profiling-101/
      The difference here is that the author uses the disjoint query for the whole Render()  function instead of using one per particular measurement. When I implemented it this way the timings were incosistent (like above 0.46, 0.61, 1.2) regardless of VSync.
    • By Jemme
      Howdy
      Ive got a WPF level editor  and a C++ Directx DLL.

      Here are the main functions:
      public static class Engine { //DX dll //Init [DllImport("Win32Engine.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void Initialize(IntPtr hwnd, int Width, int Height); //Messages / Input [DllImport("Win32Engine.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void HandleMessage(IntPtr hwnd, int msg, int wParam, int lParam); //Load [DllImport("Win32Engine.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void Load(); //Update [DllImport("Win32Engine.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void Update(); //Draw [DllImport("Win32Engine.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void Draw(); //Shutdown [DllImport("Win32Engine.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void ShutDown(); } Okay so what is the proper way to get the window hosted inside a control and the pump the engine?
      At the moment i have it inside a (winfom) panel and use:
       
      protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); HwndSource source = PresentationSource.FromVisual(this) as HwndSource; source.AddHook(WndProc); } private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { Engine.HandleMessage(hwnd, msg, (int)wParam, (int)lParam); Engine.Update(); Engine.Draw(); return IntPtr.Zero; } But there's just a few problems:
      Messages come from everywhere not just the panel (due to using the main window) The input doesn't actually work It's super duper ugly code wise In terms of c++ side the normal enigne (non-editor ) uses this pump:
      while (msg.message != WM_QUIT) { while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); //Input if (msg.message == WM_INPUT) { //Buffer size UINT size = 512; BYTE buffer[512]; GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, (LPVOID)buffer, &size, sizeof(RAWINPUTHEADER)); RAWINPUT *raw = (RAWINPUT*)buffer; if (raw->header.dwType == RIM_TYPEKEYBOARD) { bool keyUp = raw->data.keyboard.Flags & RI_KEY_BREAK; USHORT keyCode = raw->data.keyboard.VKey; if (!keyUp) { Keyboard::SetKeyState(keyCode, true); } else { Keyboard::SetKeyState(keyCode, false); } } } } time->Update(); engine->Update(time->DeltaTime()); engine->Draw(); } Not the nicest loop but works for now for testing and things.

      Now the Editor versions code is:
       
      //Initalize enigne and all sub systems extern "C" { //Hwnd is a panel usually DLLExport void Initialize(int* hwnd, int Width, int Height) { engine = new Engine(); time = new Timer(); time->Update(); if (engine->Initialize(Width, Height,(WINHANDLE)hwnd)) { //WindowMessagePump(); } else { //return a fail? } } } extern "C" { DLLExport void HandleMessage(int* hwnd, int msg, int wParam, int lParam) { //Input if (msg == WM_INPUT) { //Buffer size UINT size = 512; BYTE buffer[512]; GetRawInputData((HRAWINPUT)lParam, RID_INPUT, (LPVOID)buffer, &size, sizeof(RAWINPUTHEADER)); RAWINPUT *raw = (RAWINPUT*)buffer; if (raw->header.dwType == RIM_TYPEKEYBOARD) { bool keyUp = raw->data.keyboard.Flags & RI_KEY_BREAK; USHORT keyCode = raw->data.keyboard.VKey; if (!keyUp) { Keyboard::SetKeyState(keyCode, true); } else { Keyboard::SetKeyState(keyCode, false); } } } } } //Load extern "C" { DLLExport void Load() { engine->Load(); } } //Update extern "C" { DLLExport void Update() { time->Update(); engine->Update(time->DeltaTime()); } } //Draw extern "C" { DLLExport void Draw() { engine->Draw(); } } //ShutDown Engine extern "C" { DLLExport void ShutDown() { engine->ShutDown(); delete time; delete engine; } }  
      Any advice of how to do this properly would be much apprcieated.
      p.s in my opinion the loop should kind of stay the same? but allow the wpf to psuh the message through some how and the loop within c++ calls the update and draw still so :
       
      //Gets message from C# somehow while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); //Input } time->Update(); engine->Update(time->DeltaTime()); engine->Draw(); //returns back to c# ^ some how have that in c++ as the message pump called from wpf 
      Thanks
    • By data2
      I'm an experienced programmer specialized in Computer Graphics, mainly using Direct3D 9.0c, OpenGL and general algorithms. Currently, I am evaluating Direct2D as rendering technology for a professional application dealing with medical image data. As for rendering, it is a x64 desktop application in windowed mode (not fullscreen).
       
      Already with my very initial steps I struggle with a task I thought would be a no-brainer: Rendering a single-channel bitmap on screen.
       
      Running on a Windows 8.1 machine, I create an ID2D1DeviceContext with a Direct3D swap chain buffer surface as render target. The swap chain is created from a HWND and buffer format DXGI_FORMAT_B8G8R8A8_UNORM. Note: See also the code snippets at the end.
       
      Afterwards, I create a bitmap with pixel format DXGI_FORMAT_R8_UNORM and alpha mode D2d1_ALPHA_MODE_IGNORE. When calling DrawBitmap(...) on the device context, a debug break point is triggered with the debug message "D2d DEBUG ERROR - This operation is not compatible with the pixel format of the bitmap".
       
      I know that this output is quite clear. Also, when changing the pixel format to DXGI_FORMAT_R8G8B8A8_UNORM with DXGI_ALPHA_MODE_IGNORE everything works well and I see the bitmap rendered. However, I simply cannot believe that! Graphics cards support single-channel textures ever since - every 3D graphics application can use them without thinking twice. This goes without speaking.
       
      I tried to find anything here and at Google, without success. The only hint I could find was the MSDN Direct2D page with the (supported pixel formats). The documentation suggests - by not mentioning it - that DXGI_FORMAT_R8_UNORM is indeed not supported as bitmap format. I also find posts talking about alpha masks (using DXGI_FORMAT_A8_UNORM), but that's not what I'm after.

      What am I missing that I can't convince Direct2D to create and draw a grayscale bitmap? Or is it really true that Direct2D doesn't support drawing of R8 or R16 bitmaps??
       
      Any help is really appreciated as I don't know how to solve this. If I can't get this trivial basics to work, I think I'd have to stop digging deeper into Direct2D :-(.
       
      And here is the code snippets of relevance. Please note that they might not compile since I ported this on the fly from my C++/CLI code to plain C++. Also, I threw away all error checking and other noise:
       
      Device, Device Context and Swap Chain Creation (D3D and Direct2D):
      // Direct2D factory creation D2D1_FACTORY_OPTIONS options = {}; options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; ID2D1Factory1* d2dFactory; D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, options, &d2dFactory); // Direct3D device creation const auto type = D3D_DRIVER_TYPE_HARDWARE; const auto flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; ID3D11Device* d3dDevice; D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0, D3D11_SDK_VERSION, &d3dDevice, nullptr, nullptr); // Direct2D device creation IDXGIDevice* dxgiDevice; d3dDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice)); ID2D1Device* d2dDevice; d2dFactory->CreateDevice(dxgiDevice, &d2dDevice); // Swap chain creation DXGI_SWAP_CHAIN_DESC1 desc = {}; desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; desc.SampleDesc.Count = 1; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; desc.BufferCount = 2; IDXGIAdapter* dxgiAdapter; dxgiDevice->GetAdapter(&dxgiAdapter); IDXGIFactory2* dxgiFactory; dxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void **>(&dxgiFactory)); IDXGISwapChain1* swapChain; dxgiFactory->CreateSwapChainForHwnd(d3dDevice, hwnd, &swapChainDesc, nullptr, nullptr, &swapChain); // Direct2D device context creation const auto options = D2D1_DEVICE_CONTEXT_OPTIONS_NONE; ID2D1DeviceContext* deviceContext; d2dDevice->CreateDeviceContext(options, &deviceContext); // create render target bitmap from swap chain IDXGISurface* swapChainSurface; swapChain->GetBuffer(0, __uuidof(swapChainSurface), reinterpret_cast<void **>(&swapChainSurface)); D2D1_BITMAP_PROPERTIES1 bitmapProperties; bitmapProperties.dpiX = 0.0f; bitmapProperties.dpiY = 0.0f; bitmapProperties.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW; bitmapProperties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; bitmapProperties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE; bitmapProperties.colorContext = nullptr; ID2D1Bitmap1* swapChainBitmap = nullptr; deviceContext->CreateBitmapFromDxgiSurface(swapChainSurface, &bitmapProperties, &swapChainBitmap); // set swap chain bitmap as render target of D2D device context deviceContext->SetTarget(swapChainBitmap);  
      D2D single-channel Bitmap Creation:
      const D2D1_SIZE_U size = { 512, 512 }; const UINT32 pitch = 512; D2D1_BITMAP_PROPERTIES1 d2dProperties; ZeroMemory(&d2dProperties, sizeof(D2D1_BITMAP_PROPERTIES1)); d2dProperties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE; d2dProperties.pixelFormat.format = DXGI_FORMAT_R8_UNORM; char* sourceData = new char[512*512]; ID2D1Bitmap1* d2dBitmap; deviceContext->DeviceContextPointer->CreateBitmap(size, sourceData, pitch, d2dProperties, &d2dBitmap);  
      Bitmap drawing (FAILING):
      deviceContext->BeginDraw(); D2D1_COLOR_F d2dColor = {}; deviceContext->Clear(d2dColor); // THIS LINE FAILS WITH THE DEBUG BREAKPOINT IF SINGLE CHANNELED deviceContext->DrawBitmap(bitmap, nullptr, 1.0f, D2D1_INTERPOLATION_MODE_LINEAR, nullptr); swapChain->Present(1, 0); deviceContext->EndDraw();