Browse Source

added multiple windows support for DirectX8

Asad M. Zaman 22 years ago
parent
commit
3ec9017082

+ 3 - 0
panda/src/display/Sources.pp

@@ -28,6 +28,7 @@
     graphicsThreadingModel.I graphicsThreadingModel.h \
     graphicsWindow.h graphicsWindowInputDevice.I  \
     graphicsWindowInputDevice.h \
+    graphicsDevice.h graphicsDevice.i \
     windowProperties.I windowProperties.h \
     hardwareChannel.I  \
     hardwareChannel.h \
@@ -46,6 +47,7 @@
     graphicsStateGuardian.cxx  \
     graphicsThreadingModel.cxx \
     graphicsWindow.cxx graphicsWindowInputDevice.cxx  \
+    graphicsDevice.cxx \
     windowProperties.cxx \
     hardwareChannel.cxx \
     savedFrameBuffer.cxx
@@ -67,6 +69,7 @@
     graphicsStateGuardian.h graphicsWindow.I graphicsWindow.h \
     graphicsThreadingModel.I graphicsThreadingModel.h \
     graphicsWindowInputDevice.I graphicsWindowInputDevice.h \
+    graphicsDevice.I graphicsDevice.h \
     windowProperties.I windowProperties.h \
     hardwareChannel.I hardwareChannel.h \
     lensStack.I lensStack.h \

+ 3 - 0
panda/src/display/config_display.cxx

@@ -63,6 +63,9 @@ const string threading_model = config_display.GetString("threading-model", "");
 // until an explicit call to flip_frame() or the next render_frame().
 const bool auto_flip = config_display.GetBool("auto-flip", true);
 
+// This indicates if you want multiple window support for same GSG
+const bool multiple_windows = config_display.GetBool("multiple-windows", false);
+
 // Set this true to yield the timeslice at the end of the frame to be
 // more polite to other applications that are trying to run.
 const bool yield_timeslice = config_display.GetBool("yield-timeslice", false);

+ 2 - 0
panda/src/display/config_display.h

@@ -37,6 +37,8 @@ extern const string threading_model;
 extern const bool auto_flip;
 extern const bool yield_timeslice;
 
+extern EXPCL_PANDA const bool multiple_windows;
+
 extern EXPCL_PANDA void init_libdisplay();
 
 #endif /* CONFIG_DISPLAY_H */

+ 1 - 0
panda/src/display/display_composite2.cxx

@@ -2,6 +2,7 @@
 #include "frameBufferProperties.cxx"
 #include "graphicsPipeSelection.cxx"
 #include "graphicsThreadingModel.cxx"
+#include "graphicsDevice.cxx"
 #include "hardwareChannel.cxx"
 #include "savedFrameBuffer.cxx"
 #include "windowProperties.cxx"

+ 20 - 0
panda/src/display/graphicsEngine.cxx

@@ -176,6 +176,7 @@ make_gsg(GraphicsPipe *pipe, const FrameBufferProperties &properties,
   if (gsg != (GraphicsStateGuardian *)NULL) {
     gsg->_threading_model = threading_model;
     gsg->_pipe = pipe;
+    gsg->_engine = this;
   }
 
   return gsg;
@@ -195,6 +196,7 @@ make_window(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
             const GraphicsThreadingModel &threading_model) {
   if (gsg != (GraphicsStateGuardian *)NULL) {
     nassertr(pipe == gsg->get_pipe(), NULL);
+    nassertr(this == gsg->get_engine(), NULL);
     nassertr(threading_model.get_draw_name() ==
              gsg->get_threading_model().get_draw_name(), NULL);
   }
@@ -294,6 +296,24 @@ remove_all_windows() {
   terminate_threads();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::reset_all_windows
+//       Access: Published
+//  Description: Resets the framebuffer of the current window.  This
+//               is currently used by DirectX 8 only. It calls a
+//               reset_window function on each active window to 
+//               release/create old/new framebuffer
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+reset_all_windows(bool swapchain) {
+  Windows::iterator wi;
+  for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
+    GraphicsWindow *win = (*wi);
+    //    if (win->is_active())
+    win->reset_window(swapchain);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::is_empty
 //       Access: Published

+ 1 - 0
panda/src/display/graphicsEngine.h

@@ -77,6 +77,7 @@ PUBLISHED:
                               const GraphicsThreadingModel &threading_model);
   bool remove_window(GraphicsWindow *window);
   void remove_all_windows();
+  void reset_all_windows(bool swapchain);
   bool is_empty() const;
 
   void render_frame();

+ 11 - 0
panda/src/display/graphicsPipe.I

@@ -78,3 +78,14 @@ INLINE int GraphicsPipe::
 get_display_height() const {
   return _display_height;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsPipe::get_device
+//       Access: Public
+//  Description: Returns a pointer to device object
+////////////////////////////////////////////////////////////////////
+INLINE GraphicsDevice *GraphicsPipe::
+get_device() const {
+  return _device;
+}
+

+ 14 - 0
panda/src/display/graphicsPipe.cxx

@@ -39,6 +39,7 @@ GraphicsPipe() {
 
   _display_width = 0;
   _display_height = 0;
+
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -101,6 +102,19 @@ get_hw_channel(GraphicsWindow *, int) {
   return (HardwareChannel*)0L;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsPipe::make_device
+//       Access: Protected, Virtual
+//  Description: Creates a new device for the pipe. Only DirectX uses
+//               this device, for other api's it is NULL.
+////////////////////////////////////////////////////////////////////
+PT(GraphicsDevice) GraphicsPipe::
+make_device(void *scrn) {
+  // shouldnt this method really be pure virtual?  it's an error for a pipe to not implement it
+  display_cat.error() << "Error: make_device() unimplemented by graphicsPipe!\n";
+  return NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsPipe::make_gsg
 //       Access: Protected, Virtual

+ 11 - 0
panda/src/display/graphicsPipe.h

@@ -28,6 +28,7 @@
 
 class HardwareChannel;
 class GraphicsWindow;
+class GraphicsDevice;
 class GraphicsStateGuardian;
 class FrameBufferProperties;
 
@@ -47,6 +48,11 @@ class FrameBufferProperties;
 //               The GraphicsPipe is used by the GraphicsEngine object
 //               to create and destroy windows; it keeps ownership of
 //               the windows it creates.
+//
+//               M. Asad added new/interim functionality where GraphicsPipe
+//               now contains a device interface to directx/opengl which
+//               will be used to handle multiple windows from same device.
+//
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA GraphicsPipe : public TypedReferenceCount {
 protected:
@@ -84,8 +90,12 @@ protected:
   bool _supports_fullscreen;
   int _display_width;
   int _display_height;
+  PT(GraphicsDevice) _device;
 
 public:
+
+  virtual PT(GraphicsDevice) make_device(void *scrn = NULL);
+
   static TypeHandle get_class_type() {
     return _type_handle;
   }
@@ -98,6 +108,7 @@ public:
     return get_class_type();
   }
   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  INLINE GraphicsDevice *get_device() const;
 
 private:
   static TypeHandle _type_handle;

+ 10 - 0
panda/src/display/graphicsStateGuardian.I

@@ -63,6 +63,16 @@ get_pipe() const {
   return _pipe;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_engine
+//       Access: Public
+//  Description: Returns the graphics engine that created this GSG.
+////////////////////////////////////////////////////////////////////
+INLINE GraphicsEngine *GraphicsStateGuardian::
+get_engine() const {
+  return _engine;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_threading_model
 //       Access: Public

+ 3 - 0
panda/src/display/graphicsStateGuardian.h

@@ -48,6 +48,7 @@
 #include "pvector.h"
 
 class ClearableRegion;
+class GraphicsEngine;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GraphicsStateGuardian
@@ -74,6 +75,7 @@ PUBLISHED:
 public:
   INLINE const FrameBufferProperties &get_properties() const;
   INLINE GraphicsPipe *get_pipe() const;
+  INLINE GraphicsEngine *get_engine() const;
   INLINE const GraphicsThreadingModel &get_threading_model() const;
 
   INLINE void set_scene(SceneSetup *scene_setup);
@@ -333,6 +335,7 @@ private:
 
   FrameBufferProperties _properties;
   PT(GraphicsPipe) _pipe;
+  GraphicsEngine *_engine;
   GraphicsThreadingModel _threading_model;
 
 public:

+ 12 - 0
panda/src/display/graphicsWindow.cxx

@@ -842,6 +842,18 @@ close_window() {
     << "Closing " << get_type() << "\n";
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindow::reset_window
+//       Access: Protected, Virtual
+//  Description: resets the window framebuffer from its derived
+//               children. Does nothing here.
+////////////////////////////////////////////////////////////////////
+void GraphicsWindow::
+reset_window(bool swapchain) {
+  display_cat.info()
+    << "Resetting " << get_type() << "\n";
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindow::open_window
 //       Access: Protected, Virtual

+ 1 - 0
panda/src/display/graphicsWindow.h

@@ -137,6 +137,7 @@ public:
 protected:
   virtual void close_window();
   virtual bool open_window();
+  virtual void reset_window(bool swapchain);
   virtual bool do_reshape_request(int x_origin, int y_origin,
                                   int x_size, int y_size);
 

+ 5 - 1
panda/src/dxgsg8/Sources.pp

@@ -15,12 +15,14 @@
   // need to install these due to external projects that link directly with libpandadx (bartop)  
   #define INSTALL_HEADERS \
     dxgsg8base.h config_dxgsg8.h dxGraphicsStateGuardian8.I dxGraphicsStateGuardian8.h \
-    dxTextureContext8.h dxGeomNodeContext8.h dxGeomNodeContext8.I d3dfont8.h
+    dxTextureContext8.h dxGeomNodeContext8.h dxGeomNodeContext8.I d3dfont8.h \
+    dxGraphicsDevice8.h
 
   // build dxGraphicsStateGuardian separately since its so big
   
   #define SOURCES \
     dxGraphicsStateGuardian8.cxx dxSavedFrameBuffer8.I dxSavedFrameBuffer8.h \
+    dxGraphicsDevice8.h \
     wdxGraphicsPipe8.I wdxGraphicsPipe8.h \
     wdxGraphicsWindow8.I wdxGraphicsWindow8.h \
     $[INSTALL_HEADERS]
@@ -30,6 +32,8 @@
     dxSavedFrameBuffer8.cxx dxTextureContext8.cxx \
     dxGeomNodeContext8.cxx \
     d3dfont8.cxx \
+    dxGraphicsDevice8.cxx \
     wdxGraphicsPipe8.cxx wdxGraphicsWindow8.cxx
 
+
 #end lib_target

+ 156 - 4
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -25,6 +25,7 @@
 #include "geomSphere.h"
 #include "geomIssuer.h"
 #include "graphicsWindow.h"
+#include "graphicsEngine.h"
 #include "graphicsChannel.h"
 #include "lens.h"
 #include "perspectiveLens.h"
@@ -46,6 +47,7 @@
 #include "fogAttrib.h"
 #include "depthOffsetAttrib.h"
 #include "fog.h"
+#include "throw_event.h"
 
 #ifdef DO_PSTATS
 #include "pStatTimer.h"
@@ -962,8 +964,10 @@ do_clear(const RenderBuffer &buffer) {
 
     HRESULT hr = _pD3DDevice->Clear(0, NULL, flags, _d3dcolor_clear_value,
                                          _depth_clear_value, (DWORD)_stencil_clear_value);
-    if(FAILED(hr))
+    if(FAILED(hr)) {
         dxgsg8_cat.error() << "clear_buffer failed:  Clear returned " << D3DERRORSTRING(hr);
+        throw_event("panda3d-render-error");
+    }
     /* The following line will cause the background to always clear to a medium red
     _color_clear_value[0] = .5;
     /* The following lines will cause the background color to cycle from black to red.
@@ -988,7 +992,7 @@ prepare_display_region() {
     
     int l, b, w, h;
     _actual_display_region->get_region_pixels(l, b, w, h);
-    
+
     // Create the viewport
     D3DVIEWPORT8 vp = {l,b,w,h,0.0f,1.0f};
     HRESULT hr = _pD3DDevice->SetViewport( &vp );
@@ -996,6 +1000,7 @@ prepare_display_region() {
       dxgsg8_cat.error()
         << "SetViewport(" << l << ", " << b << ", " << w << ", " << h
         << ") failed" << D3DERRORSTRING(hr);
+      throw_event("panda3d-render-error");
     }
     // Note: for DX9, also change scissor clipping state here
   }
@@ -4547,6 +4552,29 @@ set_context(DXScreenData *pNewContextData) {
     assert(pNewContextData!=NULL);
     _pScrn = pNewContextData;
     _pD3DDevice = _pScrn->pD3DDevice;   //copy this one field for speed of deref
+    _pSwapChain = _pScrn->pSwapChain;   //copy this one field for speed of deref
+ 
+    //    wdxdisplay8_cat.debug() << "SwapChain = "<< _pSwapChain << "\n";
+}
+
+void DXGraphicsStateGuardian8::  
+create_swap_chain(DXScreenData *pNewContextData) {
+    // Instead of creating a device and rendering as d3ddevice->present()
+    // we should render using SwapChain->present(). This is done to support
+    // multiple windows rendering. For that purpose, we need to set additional
+    // swap chains here.
+
+    HRESULT hr;
+    hr = pNewContextData->pD3DDevice->CreateAdditionalSwapChain(&pNewContextData->PresParams, &pNewContextData->pSwapChain);
+    if (FAILED(hr))
+      wdxdisplay8_cat.debug() << "Swapchain creation failed :"<<D3DERRORSTRING(hr)<<"\n";
+    //    set_context(pNewContextData);
+}
+
+void DXGraphicsStateGuardian8::  
+release_swap_chain(DXScreenData *pNewContextData) {
+    // Release the swap chain on this DXScreenData
+    pNewContextData->pSwapChain->Release();
 }
 
 bool refill_tex_callback(TextureContext *tc,void *void_dxgsg_ptr) {
@@ -4623,6 +4651,7 @@ HRESULT DXGraphicsStateGuardian8::ReleaseAllDeviceObjects(void) {
     return S_OK;
 }
 
+#if 0
 ////////////////////////////////////////////////////////////////////
 //     Function: show_frame
 //       Access:
@@ -4666,8 +4695,101 @@ void DXGraphicsStateGuardian8::show_frame(bool bNoNewFrameDrawn) {
     }
   }
 }
+#endif
+
+////////////////////////////////////////////////////////////////////
+//     Function: show_frame
+//       Access:
+//       Description:   redraw primary buffer
+////////////////////////////////////////////////////////////////////
+void DXGraphicsStateGuardian8::show_frame(bool bNoNewFrameDrawn) {
+  //  wdxdisplay8_cat.debug() << "d3ddevice is " << _pD3DDevice << "\n";
+  
+  if(_pD3DDevice==NULL)
+    return;
 
-HRESULT DXGraphicsStateGuardian8::reset_d3d_device(D3DPRESENT_PARAMETERS *pPresParams) {
+  //  DO_PSTATS_STUFF(PStatTimer timer(_win->_swap_pcollector));  // this times just the flip, so it must go here in dxgsg, instead of wdxdisplay, which would time the whole frame
+  HRESULT hr;
+
+  if(bNoNewFrameDrawn) {
+      // a new frame has not been rendered, we just want to display the last thing
+      // that was drawn into backbuf, if backbuf is valid
+      if(_pScrn->PresParams.SwapEffect==D3DSWAPEFFECT_DISCARD) {
+          // in DISCARD mode, old backbufs are not guaranteed to have valid pixels,
+          // so we cant copy back->front here.  just give up.
+          return;
+      } else if(_pScrn->PresParams.SwapEffect==D3DSWAPEFFECT_FLIP) {
+         /* bugbug:  here we should use CopyRects here to copy backbuf to front (except in
+                     the case of frames 1 and 2 where we have no valid data in the backbuffer yet,
+                     for those cases give up and return).
+                     not implemented yet since right now we always do discard mode for fullscrn Present()
+                     for speed.
+          */
+          return;
+      }
+
+      // otherwise we have D3DSWAPEFFECT_COPY, so fall-thru to normal Present()
+      // may work ok as long as backbuf hasnt been touched
+  }
+
+  if (_pSwapChain)
+    hr = _pSwapChain->Present((CONST RECT*)NULL,(CONST RECT*)NULL,(HWND)NULL,NULL);
+  else
+    hr = _pD3DDevice->Present((CONST RECT*)NULL,(CONST RECT*)NULL,(HWND)NULL,NULL);
+
+  if(FAILED(hr)) {
+    if(hr == D3DERR_DEVICELOST) {
+        CheckCooperativeLevel();
+    } else {
+      dxgsg8_cat.error() << "show_frame() - Present() failed" << D3DERRORSTRING(hr);
+      exit(1);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: set_render_target
+//       Access:
+//       Description: Set render target to the backbuffer of
+//                    current swap chain.
+////////////////////////////////////////////////////////////////////
+void DXGraphicsStateGuardian8::set_render_target() {
+  LPDIRECT3DSURFACE8 pBack=NULL, pStencil=NULL;
+
+  if (!_pSwapChain)  //maybe fullscreen mode or main/single window
+    _pD3DDevice->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBack);
+  else
+    _pSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBack);
+
+  //wdxdisplay8_cat.debug() << "swapchain is " << _pSwapChain << "\n";
+  //wdxdisplay8_cat.debug() << "back buffer is " << pBack << "\n";
+
+  _pD3DDevice->GetDepthStencilSurface(&pStencil);
+  _pD3DDevice->SetRenderTarget(pBack,pStencil);
+  pBack->Release();
+  pStencil->Release();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: copy_pres_reset
+//       Access:
+//       Description: copies the PresReset from passed DXScreenData
+////////////////////////////////////////////////////////////////////
+void DXGraphicsStateGuardian8::copy_pres_reset(DXScreenData *pScrn) {
+  memcpy(&_PresReset, &_pScrn->PresParams,sizeof(D3DPRESENT_PARAMETERS));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+//  Function: reset_d3d_device
+//  Access:
+//  Description: This function checks current device's framebuffer dimension against
+//               passed pPresParams backbuffer dimension to determine a device reset
+//               if there is only one window or it is the main window or fullscreen
+//               mode then, it resets the device. Finally it returns the new
+//               DXScreenData through parameter pScrn
+/////////////////////////////////////////////////////////////////////////////////////
+HRESULT DXGraphicsStateGuardian8::
+reset_d3d_device(D3DPRESENT_PARAMETERS *pPresParams, DXScreenData **pScrn) {
   HRESULT hr;
 
   assert(IS_VALID_PTR(pPresParams));
@@ -4683,11 +4805,41 @@ HRESULT DXGraphicsStateGuardian8::reset_d3d_device(D3DPRESENT_PARAMETERS *pPresP
        _pScrn->pD3D8->GetAdapterDisplayMode(_pScrn->CardIDNum, &_pScrn->DisplayMode);
        pPresParams->BackBufferFormat = _pScrn->DisplayMode.Format;
   }
+  // here we have to look at the device's frame buffer dimension
+  // if current window's dimension is bigger than device's frame buffer
+  // we have to reset the device before creating new swapchain.
+  // inorder to reset properly, we need to release all swapchains
+  D3DSURFACE_DESC DeviceDesc;
+  LPDIRECT3DSURFACE8 pDeviceBack;
+  _pD3DDevice->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pDeviceBack);
+  pDeviceBack->GetDesc(&DeviceDesc);
+  pDeviceBack->Release();
+  if ( !(_pScrn->pSwapChain)
+       || (DeviceDesc.Width < pPresParams->BackBufferWidth)
+       || (DeviceDesc.Height < pPresParams->BackBufferHeight) ) {
+
+    get_engine()->reset_all_windows(false);// reset old swapchain by releasing
+
+    _PresReset.BackBufferWidth = pPresParams->BackBufferWidth;
+    _PresReset.BackBufferHeight = pPresParams->BackBufferHeight;
+    hr=_pD3DDevice->Reset(&_PresReset);
+    if (FAILED(hr)) {
+      return hr;
+    }
 
-  hr=_pD3DDevice->Reset(pPresParams);
+    get_engine()->reset_all_windows(true);// reset with new swapchains by creating
+  }
+  // release the old swapchain and create a new one
+  if (_pScrn->pSwapChain) {
+    _pScrn->pSwapChain->Release();
+    _pScrn->pSwapChain = NULL;
+    hr=_pD3DDevice->CreateAdditionalSwapChain(pPresParams,&_pScrn->pSwapChain);
+  }
   if(SUCCEEDED(hr)) {
      if(pPresParams!=&_pScrn->PresParams)
          memcpy(&_pScrn->PresParams,pPresParams,sizeof(D3DPRESENT_PARAMETERS));
+     if (pScrn)
+       *pScrn = _pScrn;
   }
   return hr;
 }

+ 8 - 1
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -152,6 +152,8 @@ public:
   // recreate_tex_callback needs these to be public
   DXScreenData *_pScrn;
   LPDIRECT3DDEVICE8 _pD3DDevice;  // same as pScrn->_pD3DDevice, cached for spd
+  IDirect3DSwapChain8 *_pSwapChain;
+  D3DPRESENT_PARAMETERS _PresReset;  // This is built during reset device
 
 protected:
   virtual void enable_lighting(bool enable);
@@ -337,6 +339,7 @@ public:
   static GraphicsStateGuardian*
   make_DXGraphicsStateGuardian8(const FactoryParams &params);
   void set_context(DXScreenData *pNewContextData);
+  void set_render_target();
 
   static TypeHandle get_class_type(void);
   static void init_type(void);
@@ -355,7 +358,7 @@ public:
 
   void  dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled);
   void reset_panda_gsg(void);
-  HRESULT reset_d3d_device(D3DPRESENT_PARAMETERS *pPresParams);
+  HRESULT reset_d3d_device(D3DPRESENT_PARAMETERS *pPresParams, DXScreenData **pScrn=NULL);
 
   #define DO_REACTIVATE_WINDOW true
   bool CheckCooperativeLevel(bool bDoReactivateWindow = false);
@@ -365,6 +368,10 @@ public:
 
   void support_overlay_window(bool flag);
 
+  void create_swap_chain (DXScreenData *pNewContextData);
+  void release_swap_chain (DXScreenData *pNewContextData);
+  void copy_pres_reset(DXScreenData *pNewContextData);
+
 private:
   static TypeHandle _type_handle;
 };

+ 1 - 0
panda/src/dxgsg8/dxgsg8_composite1.cxx

@@ -6,3 +6,4 @@
 #include "d3dfont8.cxx"
 #include "wdxGraphicsPipe8.cxx"
 #include "wdxGraphicsWindow8.cxx"
+#include "dxGraphicsDevice8.cxx"

+ 1 - 0
panda/src/dxgsg8/dxgsg8base.h

@@ -191,6 +191,7 @@ typedef enum {
 
 typedef struct {
       LPDIRECT3DDEVICE8 pD3DDevice;
+      IDirect3DSwapChain8 *pSwapChain;
       LPDIRECT3D8       pD3D8;  // copied from DXGraphicsPipe8 for convenience
       HWND              hWnd;
       HMONITOR          hMon;

+ 46 - 0
panda/src/dxgsg8/wdxGraphicsPipe8.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "wdxGraphicsPipe8.h"
+#include "dxGraphicsDevice8.h"
 #include "wdxGraphicsWindow8.h"
 #include "config_dxgsg8.h"
 
@@ -750,6 +751,51 @@ search_for_valid_displaymode(DXScreenData &scrn,
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: wdxGraphicsPipew8::make_device
+//       Access: Public, Virtual
+//  Description: Creates a new device.  ??????
+////////////////////////////////////////////////////////////////////
+
+PT(GraphicsDevice) wdxGraphicsPipe8::
+make_device(void *scrn) {
+
+  // FrameBufferProperties really belongs as part of the window/renderbuffer specification
+  // put here because of GLX multithreading requirement
+  PT(DXGraphicsDevice8) device = new DXGraphicsDevice8(this);
+  device->_pScrn = (DXScreenData*) scrn;
+  device->_pD3DDevice = device->_pScrn->pD3DDevice;
+
+  _device = device;
+  wdxdisplay8_cat.error() << "walla: device" << device << "\n";
+
+  return device.p();
+
+/*
+  nassertv(_gsg == (GraphicsStateGuardian *)NULL);
+  _dxgsg = new DXGraphicsStateGuardian8(this);
+  _gsg = _dxgsg;
+
+  // Tell the associated dxGSG about the window handle.
+  _dxgsg->scrn.hWnd = _hWnd;
+
+  if (pD3D8 == NULL) {
+    wdxdisplay8_cat.error()
+      << "Direct3DCreate8 failed!\n";
+    release_gsg();
+    return;
+  }
+
+  if (!choose_adapter(pD3D8)) {
+    wdxdisplay8_cat.error()
+      << "Unable to find suitable rendering device.\n";
+    release_gsg();
+    return;
+  }
+
+  create_screen_buffers_and_device(_dxgsg->scrn, dx_force_16bpp_zbuffer);
+  */
+}
 ////////////////////////////////////////////////////////////////////
 //     Function: wdxGraphicsPipew8::make_gsg
 //       Access: Public, Virtual

+ 1 - 0
panda/src/dxgsg8/wdxGraphicsPipe8.h

@@ -49,6 +49,7 @@ public:
   static PT(GraphicsPipe) pipe_constructor();
 
   virtual PT(GraphicsStateGuardian) make_gsg(const FrameBufferProperties &properties);
+  virtual PT(GraphicsDevice) make_device(void *scrn);
 
   bool find_best_depth_format(DXScreenData &Display, D3DDISPLAYMODE &TestDisplayMode,
                        D3DFORMAT *pBestFmt, bool bWantStencil,

+ 100 - 9
panda/src/dxgsg8/wdxGraphicsWindow8.cxx

@@ -23,6 +23,7 @@
 #include "wdxGraphicsPipe8.h"
 #include "wdxGraphicsWindow8.h"
 #include "config_dxgsg8.h"
+#include "config_display.h"
 
 #include "keyboardButton.h"
 #include "mouseButton.h"
@@ -106,6 +107,8 @@ make_current(void) {
   // (We can't just call reset() when we construct the GSG, because
   // reset() requires having a current context.)
   dxgsg->reset_if_new();
+
+  //  wdxdisplay8_cat.debug() << "this is " << this << "\n";
 }
 
 /* BUGBUG:  need to reinstate these methods ASAP.  they were incorrectly moved from the GraphicsWindow to the GSG
@@ -233,7 +236,9 @@ begin_frame() {
     init_resized_window();
   }
 
-  return WinGraphicsWindow::begin_frame();
+  bool return_val = WinGraphicsWindow::begin_frame();
+  _dxgsg->set_render_target();
+  return return_val;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -249,6 +254,8 @@ begin_frame() {
 void wdxGraphicsWindow8::
 end_flip() {
   if (_dxgsg != (DXGraphicsStateGuardian8 *)NULL && is_active()) {
+    make_current();
+    //    wdxdisplay8_cat.debug() << "current swapchain from end_flip is " << _wcontext.pSwapChain << "\n";
     _dxgsg->show_frame();
   }
 }
@@ -723,6 +730,13 @@ create_screen_buffers_and_device(DXScreenData &Display, bool force_16bpp_zbuffer
   pPresParams->BackBufferWidth = Display.DisplayMode.Width;
   pPresParams->BackBufferHeight = Display.DisplayMode.Height;
 
+#if 0
+  GetClientRect(GetDesktopWindow(), &view_rect);
+  pPresParams->BackBufferWidth = view_rect.right;
+  pPresParams->BackBufferHeight = view_rect.bottom;
+  wdxdisplay8_cat.debug()<<"width "<<view_rect.right<<" and height "<<view_rect.bottom<<"\n";
+#endif
+
   if (_wcontext.bIsTNLDevice) {
     dwBehaviorFlags|=D3DCREATE_HARDWARE_VERTEXPROCESSING;
     // note: we could create a pure device in this case if I eliminated the GetRenderState calls in dxgsg
@@ -801,7 +815,7 @@ create_screen_buffers_and_device(DXScreenData &Display, bool force_16bpp_zbuffer
       pPresParams->SwapEffect = D3DSWAPEFFECT_DISCARD;
     }
 
-    assert((dwRenderWidth==pPresParams->BackBufferWidth)&&(dwRenderHeight==pPresParams->BackBufferHeight));
+    //    assert((dwRenderWidth==pPresParams->BackBufferWidth)&&(dwRenderHeight==pPresParams->BackBufferHeight));
 
     hr = pD3D8->CreateDevice(Display.CardIDNum, D3DDEVTYPE_HAL, _hWnd,
                              dwBehaviorFlags, pPresParams, &Display.pD3DDevice);
@@ -812,6 +826,11 @@ create_screen_buffers_and_device(DXScreenData &Display, bool force_16bpp_zbuffer
     }
   }  // end create windowed buffers
 
+#if 0
+  pPresParams->BackBufferWidth = Display.DisplayMode.Width;
+  pPresParams->BackBufferHeight = Display.DisplayMode.Height;
+#endif
+
   //  ========================================================
 
   PRINT_REFCNT(wdxdisplay8,_wcontext.pD3DDevice);
@@ -1482,7 +1501,6 @@ search_for_device(wdxGraphicsPipe8 *dxpipe, DXDeviceInfo *device_info) {
   return true;
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: wdxGraphicsWindow8::reset_device_resize_window
 //       Access: Private
@@ -1495,18 +1513,20 @@ reset_device_resize_window(UINT new_xsize, UINT new_ysize) {
   assert((new_xsize > 0) && (new_ysize > 0));
   bool bRetval = true;
 
+  DXScreenData *pScrn;
   D3DPRESENT_PARAMETERS d3dpp;
   memcpy(&d3dpp, &_wcontext.PresParams, sizeof(D3DPRESENT_PARAMETERS));
   d3dpp.BackBufferWidth = new_xsize;
   d3dpp.BackBufferHeight = new_ysize;
-  HRESULT hr = _dxgsg->reset_d3d_device(&d3dpp);
+  make_current();
+  HRESULT hr = _dxgsg->reset_d3d_device(&d3dpp, &pScrn);
   
   if (FAILED(hr)) {
     bRetval = false;
     wdxdisplay8_cat.error()
       << "reset_device_resize_window Reset() failed" << D3DERRORSTRING(hr);
     if (hr == D3DERR_OUTOFVIDEOMEMORY) {
-      hr = _dxgsg->reset_d3d_device(&_wcontext.PresParams);
+      hr = _dxgsg->reset_d3d_device(&_wcontext.PresParams, &pScrn);
       if (FAILED(hr)) {
         wdxdisplay8_cat.error()
           << "reset_device_resize_window Reset() failed OutOfVidmem, then failed again doing Reset w/original params:" << D3DERRORSTRING(hr);
@@ -1523,11 +1543,12 @@ reset_device_resize_window(UINT new_xsize, UINT new_ysize) {
       exit(1);
     }
   }
-  
+  // before you init_resized_window you need to copy certain changes to _wcontext
+  _wcontext.pSwapChain = pScrn->pSwapChain;
+  wdxdisplay8_cat.debug() << "swapchain is " << _wcontext.pSwapChain << "\n";
   init_resized_window();
   return bRetval;
 }
-
 ////////////////////////////////////////////////////////////////////
 //     Function: wdxGraphicsWindow8::init_resized_window
 //       Access: Private
@@ -1661,6 +1682,33 @@ is_badvidmem_card(D3DADAPTER_IDENTIFIER8 *pDevID) {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: wdxGraphicsWindow8::reset_window
+//       Access: Public, Virtual
+//  Description: Resets the window framebuffer right now.  Called 
+//               from graphicsEngine. It releases the current swap
+//               chain / creates a new one. If this is the initial
+//               window and swapchain is false, then it calls reset_
+//               main_device to Reset the device.
+////////////////////////////////////////////////////////////////////
+void wdxGraphicsWindow8::
+reset_window(bool swapchain) {
+  DXGraphicsStateGuardian8 *dxgsg;
+  DCAST_INTO_V(dxgsg,_gsg);
+  if (swapchain) {
+    if (_wcontext.pSwapChain) {
+      dxgsg->create_swap_chain(&_wcontext);
+      wdxdisplay8_cat.debug() << "created swapchain " << _wcontext.pSwapChain << "\n";
+    }
+  }
+  else {
+    if (_wcontext.pSwapChain) {
+      dxgsg->release_swap_chain(&_wcontext);
+      wdxdisplay8_cat.debug() << "released swapchain " << _wcontext.pSwapChain << "\n";
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: wdxGraphicsWindow8::open_window
 //       Access: Protected, Virtual
@@ -1670,17 +1718,60 @@ is_badvidmem_card(D3DADAPTER_IDENTIFIER8 *pDevID) {
 ////////////////////////////////////////////////////////////////////
 bool wdxGraphicsWindow8::
 open_window(void) {
+  PT(DXGraphicsDevice8) dxdev;
+  DXGraphicsStateGuardian8 *dxgsg;
+  DCAST_INTO_R(dxgsg,_gsg,false);
+  WindowProperties props;
+
   if(!choose_device()) {
       return false;
   }
+  if (dxgsg->get_pipe()->get_device() && !multiple_windows)
+    return false;
 
+  wdxdisplay8_cat.debug() << "_wcontext.hWnd is " << _wcontext.hWnd << "\n";
   if (!WinGraphicsWindow::open_window()) {
     return false;
   }
-
   _wcontext.hWnd = _hWnd;
-  create_screen_buffers_and_device(_wcontext, dx_force_16bpp_zbuffer);
 
+  wdxdisplay8_cat.debug() << "_wcontext.hWnd is " << _wcontext.hWnd << "\n";
+  
+  // Here check if a device already exists. If so, then this open_window
+  // call may be an extension to create multiple windows on same device
+  // In that case just create an additional swapchain for this window
+
+  if (dxgsg->get_pipe()->get_device() == NULL) {
+    create_screen_buffers_and_device(_wcontext, dx_force_16bpp_zbuffer);
+    dxgsg->get_pipe()->make_device((void*)(&_wcontext));
+    dxgsg->copy_pres_reset(&_wcontext);
+    if (multiple_windows) // then we have no choice but to waist a framebuffer
+      dxgsg->create_swap_chain(&_wcontext);
+  }
+  else {
+
+    // fill in the DXScreenData from dxdevice here and change the reference to hWnd.
+    dxdev = (DXGraphicsDevice8*)dxgsg->get_pipe()->get_device();
+    props = get_properties();
+
+    memcpy(&_wcontext,dxdev->_pScrn,sizeof(DXScreenData));
+    _wcontext.hWnd = _hWnd;
+    _wcontext.PresParams.hDeviceWindow = _hWnd;
+    _wcontext.PresParams.BackBufferWidth = props.get_x_size();
+    _wcontext.PresParams.BackBufferHeight = props.get_y_size();
+
+    wdxdisplay8_cat.debug()<<"device width "<<_wcontext.PresParams.BackBufferWidth<<"\n";
+
+    init_resized_window();
+
+
+    if (wdxdisplay8_cat.is_debug()) {
+      wdxdisplay8_cat.debug() << "Current device is " << dxdev << "\n";
+      
+      dxgsg->create_swap_chain(&_wcontext);
+    }
+  }
+  wdxdisplay8_cat.debug() << "swapchain is " << _wcontext.pSwapChain << "\n";
   return true;
 }
 

+ 1 - 0
panda/src/dxgsg8/wdxGraphicsWindow8.h

@@ -42,6 +42,7 @@ public:
   wdxGraphicsWindow8(GraphicsPipe *pipe, GraphicsStateGuardian *gsg);
   virtual ~wdxGraphicsWindow8();
   virtual bool open_window(void);
+  virtual void reset_window(bool swapchain);
 
   virtual int verify_window_sizes(int numsizes, int *dimen);