[d3d] problem with 2 vertex buffers

Started by
6 comments, last by Vincent Torri 16 years, 3 months ago
Hello, and happy new year I want to draw (in 2d) a texture and a rectangle (the latter being yellow) with 2 vertex buffers. Here is the test code:

#include <cstdlib>
#include <cstdio>
 
#include <d3d9.h>
 
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
 
#define D3DFVF_CUSTOMVERTEX_TEX (D3DFVF_XYZRHW | D3DFVF_TEX1)
 
struct D3DVERTEX
{
  float x;
  float y;
  float z;
  float rhw;
  DWORD color;
};
 
struct D3DVERTEX_TEX
{
  float x;
  float y;
  float z;
  float rhw;
  float u;
  float v;
};
 
static int res = 1;
 
int
d3d_init (HWND window,
	  LPDIRECT3D9 *o,
	  LPDIRECT3DDEVICE9 *d)
{
  D3DPRESENT_PARAMETERS pp;
  D3DDISPLAYMODE        dm;
  D3DCAPS9              caps;
  RECT                  rect;
  LPDIRECT3D9           object;
  LPDIRECT3DDEVICE9     device;
  DWORD                 flag;
 
  object = Direct3DCreate9 (D3D_SDK_VERSION);
  if (!object)
    return 0;
 
   if (FAILED (object->GetAdapterDisplayMode (D3DADAPTER_DEFAULT,
					      &dm)))
     goto no_get_adapter;
 
   ZeroMemory (&caps, sizeof(caps));
   if (FAILED (object->GetDeviceCaps (D3DADAPTER_DEFAULT,
				      D3DDEVTYPE_HAL,
				      &caps)))
     goto no_caps;
 
   flag = (caps.VertexProcessingCaps != 0)
     ? D3DCREATE_HARDWARE_VERTEXPROCESSING
     : D3DCREATE_SOFTWARE_VERTEXPROCESSING;
 
   if (!GetClientRect(window, &rect))
     goto no_get_client;
 
   ZeroMemory(&pp, sizeof(pp));
   pp.BackBufferWidth = rect.right - rect.left;
   pp.BackBufferHeight = rect.bottom - rect.top;
   pp.BackBufferFormat = D3DFMT_UNKNOWN;
   pp.BackBufferCount = 1;
   pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
   pp.hDeviceWindow = window;
   pp.Windowed  = TRUE;
   pp.EnableAutoDepthStencil = FALSE;
   pp.FullScreen_RefreshRateInHz = 0;
   pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
 
   if (FAILED(object->CreateDevice (D3DADAPTER_DEFAULT,
				    D3DDEVTYPE_HAL,
				    window,
				    flag,
				    &pp,
				    &device)))
     goto no_device;
 
   if (FAILED (device->SetVertexShader (NULL)))
     goto canot_set_device;
   if (FAILED (device->SetFVF (D3DFVF_CUSTOMVERTEX)))
     goto canot_set_device;
 
   if (FAILED (device->SetRenderState (D3DRS_AMBIENT, RGB (255, 255, 255))))
     goto canot_set_device;
   if (FAILED (device->SetRenderState (D3DRS_LIGHTING, FALSE)))
     goto canot_set_device;
   if (FAILED (device->SetRenderState (D3DRS_CULLMODE, D3DCULL_NONE)))
     goto canot_set_device;
   if (FAILED (device->SetRenderState (D3DRS_ZENABLE, D3DZB_FALSE)))
     goto canot_set_device;
 
   *o = object;
   *d = device;
 
   {
     D3DCAPS9 caps;
     DWORD tc;
 
     device->GetDeviceCaps(&caps);
     tc = caps.TextureCaps;
     printf ("alpha             : %d\n", (tc & D3DPTEXTURECAPS_ALPHA) == D3DPTEXTURECAPS_ALPHA);
     printf ("alpha palette     : %d\n", (tc & D3DPTEXTURECAPS_ALPHAPALETTE) == D3DPTEXTURECAPS_ALPHAPALETTE);
     printf ("cube map          : %d\n", (tc & D3DPTEXTURECAPS_CUBEMAP) == D3DPTEXTURECAPS_CUBEMAP);
     printf ("cube map pow2     : %d\n", (tc & D3DPTEXTURECAPS_CUBEMAP_POW2) == D3DPTEXTURECAPS_CUBEMAP_POW2);
     printf ("mipcube map       : %d\n", (tc & D3DPTEXTURECAPS_MIPCUBEMAP) == D3DPTEXTURECAPS_MIPCUBEMAP);
     printf ("mipmap            : %d\n", (tc & D3DPTEXTURECAPS_MIPMAP) == D3DPTEXTURECAPS_MIPMAP);
     printf ("mipvolumemap      : %d\n", (tc & D3DPTEXTURECAPS_MIPVOLUMEMAP) == D3DPTEXTURECAPS_MIPVOLUMEMAP);
     printf ("non pow2 cond     : %d\n", (tc & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) == D3DPTEXTURECAPS_NONPOW2CONDITIONAL);
     printf ("non proj bump env : %d\n", (tc & D3DPTEXTURECAPS_NOPROJECTEDBUMPENV) == D3DPTEXTURECAPS_NOPROJECTEDBUMPENV);
     printf ("perspective       : %d\n", (tc & D3DPTEXTURECAPS_PERSPECTIVE) == D3DPTEXTURECAPS_PERSPECTIVE);
     printf ("pow2              : %d\n", (tc & D3DPTEXTURECAPS_POW2) == D3DPTEXTURECAPS_POW2);
     printf ("projected         : %d\n", (tc & D3DPTEXTURECAPS_PROJECTED) == D3DPTEXTURECAPS_PROJECTED);
     printf ("square only       : %d\n", (tc & D3DPTEXTURECAPS_SQUAREONLY) == D3DPTEXTURECAPS_SQUAREONLY);
     printf ("repeat not scale  : %d\n", (tc & D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE) == D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE);
     printf ("volume map        : %d\n", (tc & D3DPTEXTURECAPS_VOLUMEMAP) == D3DPTEXTURECAPS_VOLUMEMAP);
     printf ("volume map pow2   : %d\n", (tc & D3DPTEXTURECAPS_VOLUMEMAP_POW2) == D3DPTEXTURECAPS_VOLUMEMAP_POW2);
   }
 
   return 1;
 
 canot_set_device:
   printf ("canot_set_device\n");
   device->Release ();
 no_device:
   printf ("no_device\n");
 no_get_client:
   printf ("no_get_client\n");
 no_caps:
   printf ("no_caps\n");
 no_get_adapter:
   printf ("no_get_adapter\n");
   object->Release ();
 
   return 0;
}
 
void
d3d_shutdown (LPDIRECT3D9       o,
	      LPDIRECT3DDEVICE9 d)
{
  d->Release ();
  o->Release ();
}
 
LRESULT CALLBACK
window_procedure(HWND hWindow,
		 UINT uMessage,
		 WPARAM wparam,
		 LPARAM lparam)
{
  switch (uMessage) {
  case WM_KEYDOWN:
    {
      switch (wparam) {
      case VK_ESCAPE:
	DestroyWindow (hWindow);
	break;
      }
      return 0;
    }
  case WM_DESTROY:
    res = 0;
    break;
  }
 
  return DefWindowProc(hWindow,uMessage,wparam,lparam);
}
 
HWND
create_window (int width, int height)
{
  WNDCLASS wc;
  RECT       rect;
  HWND       window;
 
  memset (&wc, 0, sizeof (wc));
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = window_procedure;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = GetModuleHandle(NULL);
  wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
  wc.hCursor = LoadCursor (NULL, IDC_ARROW);
  wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
  wc.lpszMenuName =  NULL;
  wc.lpszClassName = "class name";
 
  RegisterClass(&wc);
 
  rect.left = 0;
  rect.top = 0;
  rect.right = width;
  rect.bottom = height;
  if (!AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW | WS_SIZEBOX, FALSE))
    return NULL;
 
  window = CreateWindow(  "class name", "",
			  WS_OVERLAPPEDWINDOW | WS_SIZEBOX,
			  100, 100,
			  rect.right - rect.left,
			  rect.bottom - rect.top,
			  NULL,
			  NULL,
			  GetModuleHandle(NULL),
			  NULL);
  return window;
}
 
void
destroy_window (HWND w)
{
  DestroyWindow (w);
}
 
void
line_draw (LPDIRECT3DDEVICE9 device,
           LPDIRECT3DVERTEXBUFFER9 vb_line)
{
  D3DVERTEX *vertex_line;
  void *data;
 
  if (FAILED (vb_line->Lock (0, 0, (void **)&data, 0))) {
    printf ("vb lock failed\n");
    return;
  }
 
  vertex_line = (D3DVERTEX *)data;
 
  vertex_line[0].x = 100.0f;
  vertex_line[0].y = 100.0f;
  vertex_line[0].z = 0.0f;
  vertex_line[0].rhw = 1.0f;
  vertex_line[0].color = D3DCOLOR_ARGB(255, 255, 0, 255);
 
  vertex_line[1].x = 200.0f;
  vertex_line[1].y = 200.0f;
  vertex_line[1].z = 0.0f;
  vertex_line[1].rhw = 1.0f;
  vertex_line[1].color = D3DCOLOR_ARGB(255, 255, 0, 255);
 
  if (FAILED (vb_line->Unlock ())) {
    printf ("vb unlock failed\n");
    return;
  }
 
  device->SetFVF (D3DFVF_CUSTOMVERTEX);
  device->SetStreamSource (0, vb_line, 0, sizeof (D3DVERTEX));
  if (FAILED (device->DrawPrimitive (D3DPT_LINELIST, 0, 1))) {
    printf ("draw pritive failed\n");
  }
}
 
void
triangle_draw (LPDIRECT3DDEVICE9 device,
	       LPDIRECT3DVERTEXBUFFER9 vb_triangle)
{
  D3DVERTEX vertex_triangle[] = {
    { 16.0f, 40.0f,  0.0f, 1.0f, D3DCOLOR_ARGB(255, 255, 0, 0) },
    { 14.0f, 27.0f, 0.0f, 1.0f, D3DCOLOR_ARGB(255, 255, 0, 0) },
    { 18.0f, 35.0f, 0.0f, 1.0f, D3DCOLOR_ARGB(255, 255, 0, 0) }};
  void *data;
 
  if (FAILED (vb_triangle->Lock (0, 0, (void **)&data, 0))) {
    printf ("vb lock failed\n");
    return;
  }
 
  memcpy (data, vertex_triangle, sizeof (vertex_triangle));
 
  if (FAILED (vb_triangle->Unlock ())) {
    printf ("vb unlock failed\n");
    return;
  }
 
  device->SetFVF (D3DFVF_CUSTOMVERTEX);
  device->SetStreamSource (0, vb_triangle, 0, sizeof (D3DVERTEX));
  if (FAILED (device->DrawPrimitive (D3DPT_TRIANGLELIST, 0, 1))) {
    printf ("draw pritive failed\n");
  }
}
 
void
rectangle_draw (LPDIRECT3DDEVICE9 device,
		LPDIRECT3DVERTEXBUFFER9 vb_rectangle)
{
  D3DVERTEX vertex_rectangle[] = {
    { 50.0f, 100.0f, 0.0f, 1.0f, D3DCOLOR_ARGB(255, 255, 255, 0) },
    { 70.0f, 100.0f, 0.0f, 1.0f, D3DCOLOR_ARGB(255, 255, 255, 0) },
    { 70.0f, 200.0f, 0.0f, 1.0f, D3DCOLOR_ARGB(255, 255, 255, 0) },
    { 50.0f, 200.0f, 0.0f, 1.0f, D3DCOLOR_ARGB(255, 255, 255, 0) }};
  void *data;
 
  if (FAILED (vb_rectangle->Lock (0, 0, (void **)&data, 0))) {
    printf ("vb lock failed\n");
    return;
  }
 
  memcpy (data, vertex_rectangle, sizeof (vertex_rectangle));
 
  if (FAILED (vb_rectangle->Unlock ())) {
    printf ("vb unlock failed\n");
    return;
  }
 
  if (FAILED (device->SetFVF (D3DFVF_CUSTOMVERTEX))) {
    printf ("SetFVF failed\n");
    return;
  }
  if (FAILED (device->SetStreamSource (0, vb_rectangle, 0, sizeof (D3DVERTEX)))) {
    printf ("SetStreamSource failed\n");
    return;
  }
  if (FAILED (device->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2))) {
    printf ("draw pritive failed\n");
  }
}
 
void
texture_fill (LPDIRECT3DDEVICE9 device,
              LPDIRECT3DTEXTURE9 texture)
{
  D3DLOCKED_RECT rect;
  void *data;
  unsigned char *tmp;
  int i, j;
 
  static int foo = 0;
  int w;
  int h;
 
  w = 64;
  h = 64;
 
  data = malloc (sizeof (char) * 4 * 64 * 64);
  if (!data) return;
 
  for (tmp = (unsigned char *)data, i = 0; i < 64; i++) {
    for (j = 0; j < 64; j++, tmp += 4) {
      tmp[0] = (i * 2 + foo) % 256;
      tmp[1] = (j + foo) % 256;
      tmp[2] = (w - 1 - j) * 4;
      tmp[3] = 0;
    }
  }
  foo++;
 
  if (FAILED (texture->LockRect (0, &rect, NULL, D3DLOCK_DISCARD))) {
    printf ("texture_draw : tex lock failed\n");
    free (data);
    return;
  }
  memcpy (rect.pBits, data, 4 * 64 * 64);
  free (data);
  if (FAILED (texture->UnlockRect (0))) {
    printf ("texture_draw : tex unlock failed\n");
    return;
  }
}
 
void
texture_draw (LPDIRECT3DDEVICE9 device,
              LPDIRECT3DTEXTURE9 texture,
              LPDIRECT3DVERTEXBUFFER9 vb_tex)
{
  void *data;
  int w;
  int h;
 
  w = 64;
  h = 64;
 
  device->SetTexture (0, texture);
 
  D3DVERTEX_TEX vertex_tex[] = {
    { 0.0f,     0.0f,     0.0f, 1.0f, 0.0f,     0.0f },
    { 0.0f + w, 0.0f,     0.0f, 1.0f, 0.0f + 1, 0.0f },
    { 0.0f + w, 0.0f + h, 0.0f, 1.0f, 0.0f + 1, 0.0f + 1 },
    { 0.0f,     0.0f + h, 0.0f, 1.0f, 0.0f,     0.0f + 1 }};
 
  if (FAILED (vb_tex->Lock (0, 0, (void **)&data, 0))) {
    printf ("vb lock failed\n");
    return;
  }
 
  memcpy (data, vertex_tex, sizeof (vertex_tex));
 
  if (FAILED (vb_tex->Unlock ())) {
    printf ("vb unlock failed\n");
    return;
  }
 
  if (FAILED (device->SetFVF (D3DFVF_CUSTOMVERTEX_TEX))) {
    printf ("SetFVF failed\n");
    return;
  }
  if (FAILED (device->SetStreamSource (0, vb_tex, 0, sizeof (D3DVERTEX_TEX)))) {
    printf ("SetStreamSource failed\n");
    return;
  }
  if (FAILED (device->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2))) {
    printf ("draw pritive failed\n");
  }
}
 
int
main ()
{
  LPDIRECT3D9       object;
  LPDIRECT3DDEVICE9 device;
  LPDIRECT3DVERTEXBUFFER9 vb_line;
  LPDIRECT3DVERTEXBUFFER9 vb_triangle;
  LPDIRECT3DVERTEXBUFFER9 vb_rectangle;
  LPDIRECT3DVERTEXBUFFER9 vb_tex;
  LPDIRECT3DTEXTURE9 texture;
  HWND window;
 
  window = create_window (800, 600);
  if (!window) {
    printf ("window init failed\n");
    return EXIT_FAILURE;
  }
 
  ShowWindow(window, SW_SHOWNORMAL);
  UpdateWindow(window);
 
  if (!d3d_init (window, &object, &device)) {
    printf ("d3d init failed\n");
    return EXIT_FAILURE;
  }
 
  if (FAILED(device->CreateVertexBuffer (sizeof (D3DVERTEX) * 2,
					 D3DUSAGE_WRITEONLY,
					 D3DFVF_CUSTOMVERTEX,
					 D3DPOOL_MANAGED,
					 &vb_line, NULL))) {
    printf ("vertex buffer create failed\n");
    d3d_shutdown (object, device);
    destroy_window (window);
    return EXIT_FAILURE;
  }
 
  if (FAILED(device->CreateVertexBuffer (sizeof (D3DVERTEX) * 3,
					 D3DUSAGE_WRITEONLY,
					 D3DFVF_CUSTOMVERTEX,
					 D3DPOOL_MANAGED,
					 &vb_triangle, NULL))) {
    printf ("vertex buffer create failed\n");
    d3d_shutdown (object, device);
    destroy_window (window);
    return EXIT_FAILURE;
  }
 
  if (FAILED(device->CreateVertexBuffer (sizeof (D3DVERTEX) * 4,
					 D3DUSAGE_WRITEONLY,
					 D3DFVF_CUSTOMVERTEX,
					 D3DPOOL_MANAGED,
					 &vb_rectangle, NULL))) {
    printf ("vertex buffer create failed\n");
    d3d_shutdown (object, device);
    destroy_window (window);
    return EXIT_FAILURE;
  }
 
  if (FAILED(device->CreateVertexBuffer (sizeof (D3DVERTEX_TEX) * 4,
					 D3DUSAGE_WRITEONLY,
					 D3DFVF_CUSTOMVERTEX,
					 D3DPOOL_MANAGED,
					 &vb_tex, NULL))) {
    printf ("vertex buffer create failed\n");
    d3d_shutdown (object, device);
    destroy_window (window);
    return EXIT_FAILURE;
  }
 
  if (FAILED (device->CreateTexture (64, 64, 1, D3DUSAGE_DYNAMIC,
                                     D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
                                     &texture, NULL))) {
    printf ("texture create failed\n");
    d3d_shutdown (object, device);
    destroy_window (window);
    return EXIT_FAILURE;
  }
 
  while (res) {
    MSG msg;
 
    if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {
      TranslateMessage (&msg);
      DispatchMessage (&msg);
    }
 
    device->Clear (0, NULL, D3DCLEAR_TARGET,
		   D3DCOLOR_XRGB (0, 0, 0),
		   0.0f, 0);
    device->BeginScene ();
 
    rectangle_draw (device, vb_rectangle);
//     triangle_draw (device, vb_triangle);
//     line_draw (device, vb_line);
    texture_fill (device, texture);
    texture_draw (device, texture, vb_tex);
 
    device->EndScene ();
    device->Present (NULL, NULL, NULL, NULL);
  }
 
  d3d_shutdown (object, device);
  destroy_window (window);
 
  return EXIT_SUCCESS;
}

Here is basically what I do: * I define 2 customized vertex buffers (one for the rectangle, one for the texture * I create the texture and 2 vertex buffers (one for the rectangle and one for the texture) * I display the rectangle, then the texture I did a small animation for the texture. Some of the code (non-specific d3d parts) are not optimzed (it's just a test program for me). Problem: the rectangle, which should always be yellow, has changing color (around yellow and red or pink) If I don't display the texture, then the rectangle is yellow. Does someone see where the problem is ? Thank you PS: If someone see if some parts of the d3d specific code can be optimized for 2d rendering, then I would be glad to know :)
Advertisement
I can't see anything obvious in your code (there is a lot of it to read!) but your description sounds like a textbook example of a 'corrupt' pipeline state.

You need to ensure the D3D pipeline is configured correctly for each and every Draw() call you issue, if you forget to clean up and/or reset a state then you get leaks between calls. For example, your 2nd call to render textured geometry might well be using a partial configuration state from the 1st call to render the triangle.

Your description sounds like a leaked SetFVF() call. It could well be drawing your triangle using the 'U' texture coordinate as colour or something like that...

If you can't spot the issue, try using PIX - it's perfect for this sort of thing [smile]

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

how can I "close" a SetFVF call (if there's a "leak") ?

basically, about FVF, I do that:

// rectangledevice->SetFVF (D3DFVF_CUSTOMVERTEX);device->SetStreamSource (0, vb_rectangle, 0, sizeof (D3DVERTEX));device->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);// texturedevice->SetFVF (D3DFVF_CUSTOMVERTEX_TEX);device->SetStreamSource (0, vb_tex, 0, sizeof (D3DVERTEX_TEX));device->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);// rectangledevice->SetFVF (D3DFVF_CUSTOMVERTEX);device->SetStreamSource (0, vb_rectangle, 0, sizeof (D3DVERTEX));device->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);// texturedevice->SetFVF (D3DFVF_CUSTOMVERTEX_TEX);device->SetStreamSource (0, vb_tex, 0, sizeof (D3DVERTEX_TEX));device->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);etc...


is it good ?
Should I use only 1 custom vertex ? (I guess that, in that case, the color should be white (255, 255, 255, 255 in ARGB)

thank you for mentionning PIX. It will help me also for other purposes.

thanks
Your code looks fine for SetFVF(), but as with all leaks it could well be some obscure runtime-only execution flow that is doing things that you're not necessarily expecting.

Or I could be wrong and it could be another state configuration; which is where PIX will really become useful.

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

I answer myself: I had to add device->SetTexture(0, NULL); before the Lock of the vertex buffer of the rectangle.
After adding the SetTexture call and using the debug mode, with DebugView, I get those messages:

[1944] D3D9 Helper: Enhanced D3DDebugging disabled; Application was not compiled with D3D_DEBUG_INFO [1944] Direct3D9: (INFO) :======================= Hal HWVP device selected [1944] [1944] Direct3D9: (INFO) :HalDevice Driver Style 9 [1944] [1944] Direct3D9: :DoneExclusiveMode[1944] [1944] Direct3D9: (WARN) :Ignoring redundant SetRenderState - 7 [1944] [1944] Direct3D9: (ERROR) :Current vertex shader declaration doesn't match VB's FVF [1944] [1944] Direct3D9: (ERROR) :DrawPrimitive failed.


the DrawPrimitive call is the one of the texture.

Does someone see the problem ?

thank you
Seems fairly self-explanatory to me [smile]:

Current vertex shader declaration doesn't match VB's FVF

Basically you've configured the pipeline to expect binary data in a particular format, but the buffer you've then told it to read it in is saying its stored in a different format. Therefore it doesn't know what to do with it and fails the call.

Check your SetVertexDeclaration(), SetFVF() and CreateVertexBuffer() calls to ensure all declarations match up.

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

indeed, the creation of the vertex buffer is not correct. Thanks !

This topic is closed to new replies.

Advertisement