11 Replies Latest reply on May 31, 2015 1:19 PM by Arch_D_Robison

    Simple demo of HD 4400 and HD 4600 screen tearing under Windows 8.1 + DirectX 9

    Arch_D_Robison

      Summary

      I've getting screen tearing on both HD 4400 and HD 4600 machines running Windows 8.1 when using DirectX 9.  I've reduced the problem to a short demo program, and made the source code available.  The demo, on failing machines, shows red on the screen that should be all blue.  More so if the program is compiled in "Release" mode, hence my suspicion of a timing issue.   

       

      Details

      The HD 4400 machine has a BIOS and graphics driver up to date as of 2014-Aug-12.  I have not seen the problem on machines with discrete graphics cards running Windows XP or Windows 7.  Alas I don't have a HD 4400/4600 machine running Windows 7, so I don't know know if the root cause is Windows 8.1 or the Intel graphics.

       

      The program uses DirectX 9 and double buffering, in a way that I've used successfully for nearly a decade, and I believe is vanilla code.  The source code and executable are available from my personal web site (RedFlicker - Blonzonics) along with instructions for running the program.  Here is what the program does:

      1. Fill a buffer with RED pixels.
      2. Overwrite the buffer with BLUE pixels.
      3. Ship the buffer to the screen.
      4. Repeat.

      By my understanding, the screen should always show BLUE pixels, because the RED pixels are totally overwritten before the buffer is displayed.  But the top of the screen shows RED pixels sometimes, as if the buffer is being prematurely displayed, (or is delayed in being not displayed after buffer swapping?)  Possibilities:

      • I've been using DirectX 9 incorrectly for nearly a decade, and never noticed until Windows 8.1/HD 4x00 showed up.
      • DIrectX 9 + Windows 8.1 has a bug.
      • Intel's driver or hardware has a bug.

      What's the best way to attempt to resolve this issue?

       

      P.S. Gory Details for DirectX 9 Experts

      More details follow, of possible interest to DirectX experts who might spot something wrong in my code.  Below is how I am updating and displaying the buffer (from lines 244-268 of RedFlicker.cpp in the source code from the website):

      static void UpdateAndDraw( HWND hwnd ) {
          HRESULT hr;
          Device->BeginScene();
          IDirect3DSurface9* backBuffer=0;
          hr = Device->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&backBuffer);
          Assert(hr==D3D_OK);
          D3DSURFACE_DESC desc;
          hr = backBuffer->GetDesc(&desc);
          Assert(hr==D3D_OK);
          D3DLOCKED_RECT lockedRect;
          hr = backBuffer->LockRect(&lockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_DISCARD);
          Assert(hr==D3D_OK);
      
          FillWithCheckerBoard(desc, lockedRect, 0xFF0000);
          FillWithCheckerBoard(desc, lockedRect, 0x0000FF);
      
          hr = backBuffer->UnlockRect();
          Assert(hr==D3D_OK);
          backBuffer->Release();
          Device->EndScene();
          hr = Device->Present( 0, 0, 0, 0 );
          if( hr!=D3D_OK ) {
              Decode(hr);
        }
      }
      

       

      Here is the routine that sets up the "present" parameters:

      static void SetPresentParameters( D3DPRESENT_PARAMETERS& present ) {
          ZeroMemory( &present, sizeof(D3DPRESENT_PARAMETERS) );
          present.BackBufferCount           = 2;
          present.SwapEffect                = D3DSWAPEFFECT_DISCARD;
          present.BackBufferFormat          = D3DFMT_X8R8G8B8;
          present.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
          present.Windowed                  = !ExclusiveMode;
      
      
          if( ExclusiveMode ) {
              present.BackBufferHeight = DisplayHeight;
              present.BackBufferWidth = DisplayWidth;
          }
      }
      

       

      The "present" parameters are transmitted to DirectX in this routine:

      static bool InitializeDirectX( HWND hwnd ) {
          HRESULT hr;
      
          // Create the Direct3D interface object.
          d3d = Direct3DCreate9( D3D_SDK_VERSION );
          Assert(d3d!=NULL);
      
          // Get device capabilities
          D3DCAPS9 displayCaps;
          hr = d3d->GetDeviceCaps(0,D3DDEVTYPE_HAL,&displayCaps);
          Assert(hr==D3D_OK);
      
          // Get resolution of current display mode
          D3DDISPLAYMODE displayMode;
          hr = d3d->GetAdapterDisplayMode(0,&displayMode);
          Assert(hr==D3D_OK);
          DisplayHeight = displayMode.Height;
          DisplayWidth = displayMode.Width;
      
          // Create the device
          D3DPRESENT_PARAMETERS present;
          SetPresentParameters(present);
          hr = d3d->CreateDevice( 
              D3DADAPTER_DEFAULT, 
              D3DDEVTYPE_HAL, 
              hwnd, 
              D3DCREATE_SOFTWARE_VERTEXPROCESSING,
              &present,
              &Device
          );
          if ( hr!=D3D_OK  ) {
              char buffer[200];
              sprintf_s(buffer,200,"Internal error: d3d->CreateDevice returned %s\n",Decode(hr));
              MessageBoxA(hwnd,buffer,NULL,MB_OK|MB_ICONWARNING);
              return false;
          }
         
          return true;
      }
      

      The source code download has the full source (360 lines) and a VS2013 solution for compiling it.