Panda3D
 All Classes Functions Variables Enumerations
wdxGraphicsBuffer8.cxx
00001 // Filename: wdxGraphicsBuffer8.cxx
00002 // Created by:  drose (08Feb04)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "wdxGraphicsPipe8.h"
00016 #include "wdxGraphicsBuffer8.h"
00017 #include "pStatTimer.h"
00018 
00019 
00020 // ISSUES:
00021   // render to texure format
00022     // can be specified via the DXGraphicsStateGuardian8 member
00023     // _render_to_texture_d3d_format  default = D3DFMT_X8R8G8B8
00024 
00025   // should check texture creation with CheckDepthStencilMatch
00026   // support copy from texture to ram?
00027     // check D3DCAPS2_DYNAMICTEXTURES
00028 
00029 #define FL << "\n" << __FILE__ << " " << __LINE__ << "\n"
00030 
00031 TypeHandle wdxGraphicsBuffer8::_type_handle;
00032 
00033 
00034 ////////////////////////////////////////////////////////////////////
00035 //     Function: wdxGraphicsBuffer8::Constructor
00036 //       Access: Public
00037 //  Description:
00038 ////////////////////////////////////////////////////////////////////
00039 wdxGraphicsBuffer8::
00040 wdxGraphicsBuffer8(GraphicsEngine *engine, GraphicsPipe *pipe,
00041                    const string &name,
00042                    const FrameBufferProperties &fb_prop,
00043                    const WindowProperties &win_prop,
00044                    int flags,
00045                    GraphicsStateGuardian *gsg,
00046                    GraphicsOutput *host):
00047   GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
00048 {
00049   // initialize all class members
00050   _cube_map_index = -1;
00051   _saved_color_buffer = NULL;
00052   _saved_depth_buffer = NULL;
00053   _color_backing_store = NULL;
00054   _depth_backing_store = NULL;
00055 
00056   // is this correct ???
00057   // Since the pbuffer never gets flipped, we get screenshots from the
00058   // same buffer we draw into.
00059   _screenshot_buffer_type = _draw_buffer_type;
00060 
00061   _this = 0;
00062 
00063   if (_gsg) {
00064     // save to GSG list to handle device lost issues
00065     DXGraphicsStateGuardian8 *dxgsg;
00066 
00067     dxgsg = DCAST (DXGraphicsStateGuardian8, _gsg);
00068     _this = new (wdxGraphicsBuffer8 *);
00069     *_this = this;
00070     dxgsg -> _graphics_buffer_list.push_back(_this);
00071   }
00072 }
00073 
00074 ////////////////////////////////////////////////////////////////////
00075 //     Function: wdxGraphicsBuffer8::Destructor
00076 //       Access: Public, Virtual
00077 //  Description:
00078 ////////////////////////////////////////////////////////////////////
00079 wdxGraphicsBuffer8::
00080 ~wdxGraphicsBuffer8() {
00081   this -> close_buffer ( );
00082 
00083   if (_gsg) {
00084     // remove from GSG list
00085     DXGraphicsStateGuardian8 *dxgsg;
00086 
00087     dxgsg = DCAST (DXGraphicsStateGuardian8, _gsg);
00088     if (_this) {
00089       dxgsg -> _graphics_buffer_list.remove(_this);
00090     }
00091     _this = 0;
00092     _gsg.clear();
00093     _gsg = 0;
00094   }
00095 }
00096 
00097 ////////////////////////////////////////////////////////////////////
00098 //     Function: wdxGraphicsBuffer8::begin_frame
00099 //       Access: Public, Virtual
00100 //  Description: This function will be called within the draw thread
00101 //               before beginning rendering for a given frame.  It
00102 //               should do whatever setup is required, and return true
00103 //               if the frame should be rendered, or false if it
00104 //               should be skipped.
00105 ////////////////////////////////////////////////////////////////////
00106 bool wdxGraphicsBuffer8::
00107 begin_frame(FrameMode mode, Thread *current_thread) {
00108 
00109   begin_frame_spam(mode);
00110   if (_gsg == (GraphicsStateGuardian *)NULL) {
00111     return false;
00112   }
00113   if (_dxgsg -> _d3d_device == 0) {
00114     return false;
00115   }
00116 
00117   if (mode == FM_render) {
00118     if (!save_bitplanes()) {
00119       return false;
00120     }
00121     if (!rebuild_bitplanes()) {
00122       restore_bitplanes();
00123       return false;
00124     }
00125     clear_cube_map_selection();
00126   }
00127 
00128   _gsg->set_current_properties(&get_fb_properties());
00129   return _gsg->begin_frame(current_thread);
00130 }
00131 
00132 ////////////////////////////////////////////////////////////////////
00133 //     Function: wdxGraphicsBuffer8::end_frame
00134 //       Access: Public, Virtual
00135 //  Description: This function will be called within the draw thread
00136 //               after rendering is completed for a given frame.  It
00137 //               should do whatever finalization is required.
00138 ////////////////////////////////////////////////////////////////////
00139 void wdxGraphicsBuffer8::
00140 end_frame(FrameMode mode, Thread *current_thread) {
00141 
00142   end_frame_spam(mode);
00143   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00144 
00145   if (mode == FM_render) {
00146     copy_to_textures();
00147   }
00148 
00149   _gsg->end_frame(current_thread);
00150 
00151   if (mode == FM_render) {
00152     trigger_flip();
00153     clear_cube_map_selection();
00154     restore_bitplanes();
00155   }
00156 }
00157 
00158 ////////////////////////////////////////////////////////////////////
00159 //     Function: wdxGraphicsBuffer8::save_bitplanes
00160 //       Access: Public
00161 //  Description: After rendering, d3d_device will need to be restored
00162 //               to its initial state.  This function saves the state.
00163 ////////////////////////////////////////////////////////////////////
00164 bool wdxGraphicsBuffer8::
00165 save_bitplanes() {
00166   HRESULT hr;
00167 
00168   hr = _dxgsg -> _d3d_device -> GetRenderTarget (&_saved_color_buffer);
00169   if (!SUCCEEDED (hr)) {
00170     dxgsg8_cat.error ( ) << "GetRenderTarget " << D3DERRORSTRING(hr) FL;
00171     return false;
00172   }
00173   hr = _dxgsg -> _d3d_device -> GetDepthStencilSurface (&_saved_depth_buffer);
00174   if (!SUCCEEDED (hr)) {
00175     dxgsg8_cat.error ( ) << "GetDepthStencilSurface " << D3DERRORSTRING(hr) FL;
00176     return false;
00177   }
00178   return true;
00179 }
00180 
00181 ////////////////////////////////////////////////////////////////////
00182 //     Function: wdxGraphicsBuffer8::restore_bitplanes
00183 //       Access: Public
00184 //  Description: After rendering, d3d_device will need to be restored
00185 //               to its initial state.  This function restores the state.
00186 ////////////////////////////////////////////////////////////////////
00187 void wdxGraphicsBuffer8::
00188 restore_bitplanes() {
00189   DXGraphicsStateGuardian8 *dxgsg;
00190   DCAST_INTO_V(dxgsg, _gsg);
00191 
00192   HRESULT hr;
00193 
00194   hr = dxgsg -> _d3d_device ->
00195     SetRenderTarget (_saved_color_buffer, _saved_depth_buffer);
00196 
00197   if (!SUCCEEDED (hr)) {
00198     dxgsg8_cat.error ( ) << "SetRenderTarget " << D3DERRORSTRING(hr) FL;
00199   }
00200 
00201   _saved_color_buffer->Release();
00202   _saved_depth_buffer->Release();
00203   _saved_color_buffer = NULL;
00204   _saved_depth_buffer = NULL;
00205 }
00206 
00207 
00208 ////////////////////////////////////////////////////////////////////
00209 //     Function: wdxGraphicsBuffer8::rebuild_bitplanes
00210 //       Access: Public
00211 //  Description: If necessary, reallocates (or allocates) the
00212 //               bitplanes for the buffer.
00213 ////////////////////////////////////////////////////////////////////
00214 bool wdxGraphicsBuffer8::
00215 rebuild_bitplanes() {
00216 
00217   HRESULT hr;
00218   Texture *color_tex = 0;
00219   Texture *depth_tex = 0;
00220   DXTextureContext8 *color_ctx = 0;
00221   DXTextureContext8 *depth_ctx = 0;
00222   IDirect3DTexture8 *color_d3d_tex = 0;
00223   IDirect3DTexture8 *depth_d3d_tex = 0;
00224   IDirect3DCubeTexture8 *color_cube = 0;
00225   IDirect3DCubeTexture8 *depth_cube = 0;
00226   IDirect3DSurface8 *color_surf = 0;
00227   IDirect3DSurface8 *depth_surf = 0;
00228 
00229   // Decide how big the bitplanes should be.
00230 
00231   if ((_host != 0)&&(_creation_flags & GraphicsPipe::BF_size_track_host)) {
00232     if ((_host->get_x_size() != _x_size)||
00233         (_host->get_y_size() != _y_size)) {
00234       set_size_and_recalc(_host->get_x_size(),
00235                           _host->get_y_size());
00236     }
00237   }
00238   int bitplane_x = _x_size;
00239   int bitplane_y = _y_size;
00240   if (Texture::get_textures_power_2() != ATS_none) {
00241     bitplane_x = Texture::up_to_power_2(bitplane_x);
00242     bitplane_y = Texture::up_to_power_2(bitplane_y);
00243   }
00244 
00245   // Find the color and depth textures.  Either may be present,
00246   // or neither.
00247   //
00248   // NOTE: Currently, depth-stencil textures are not implemented,
00249   // but since it's coming soon, we're structuring for it.
00250 
00251   int color_tex_index = -1;
00252   int depth_tex_index = -1;
00253   for (int i=0; i<count_textures(); i++) {
00254     if (get_rtm_mode(i) == RTM_bind_or_copy) {
00255       if ((get_texture(i)->get_format() != Texture::F_depth_stencil)&&
00256           (get_texture(i)->get_format() != Texture::F_depth_component)&&
00257           (color_tex_index < 0)) {
00258         color_tex_index = i;
00259       }
00260     }
00261   }
00262 
00263 
00264   if (color_tex_index < 0) {
00265     // Maintain the backing color surface.
00266     if ((_color_backing_store)&&
00267         ((bitplane_x != _backing_sizex)||(bitplane_y != _backing_sizey))) {
00268       _color_backing_store->Release();
00269       _color_backing_store = NULL;
00270     }
00271     if (!_color_backing_store) {
00272       hr = _dxgsg -> _d3d_device ->
00273         CreateImageSurface(bitplane_x, bitplane_y, _saved_color_desc.Format, &_color_backing_store);
00274       if (!SUCCEEDED(hr)) {
00275         dxgsg8_cat.error ( ) << "CreateImageSurface " << D3DERRORSTRING(hr) FL;
00276       }
00277     }
00278     color_surf = _color_backing_store;
00279   } else {
00280     // Maintain the color texture.
00281     if (_color_backing_store) {
00282       _color_backing_store->Release();
00283       _color_backing_store = NULL;
00284     }
00285     color_tex = get_texture(color_tex_index);
00286     color_tex->set_x_size(bitplane_x);
00287     color_tex->set_y_size(bitplane_y);
00288     color_tex->set_format(Texture::F_rgba);
00289     color_ctx =
00290       DCAST(DXTextureContext8,
00291             color_tex->prepare_now(0, _gsg->get_prepared_objects(), _gsg));
00292     if (color_ctx) {
00293       if (!color_ctx->create_texture(*_dxgsg->_screen)) {
00294         dxgsg8_cat.error()
00295           << "Unable to re-create texture " << *color_ctx->get_texture() << endl;
00296         return false;
00297       }
00298       if (color_tex->get_texture_type() == Texture::TT_2d_texture) {
00299         color_d3d_tex = color_ctx->_d3d_2d_texture;
00300         nassertr(color_d3d_tex != 0, false);
00301         hr = color_d3d_tex -> GetSurfaceLevel(0, &color_surf);
00302         if (!SUCCEEDED(hr)) {
00303           dxgsg8_cat.error ( ) << "GetSurfaceLevel " << D3DERRORSTRING(hr) FL;
00304         }
00305       } else {
00306         color_cube = color_ctx->_d3d_cube_texture;
00307         nassertr(color_cube != 0, false);
00308         if (_cube_map_index >= 0 && _cube_map_index < 6) {
00309           hr = color_cube -> GetCubeMapSurface ((D3DCUBEMAP_FACES) _cube_map_index, 0, &color_surf);
00310           if (!SUCCEEDED(hr)) {
00311             dxgsg8_cat.error ( ) << "GetCubeMapSurface " << D3DERRORSTRING(hr) FL;
00312           }
00313         }
00314       }
00315     }
00316   }
00317 
00318   if (depth_tex_index < 0) {
00319     // Maintain the backing depth surface.
00320     if ((_depth_backing_store)&&
00321         ((bitplane_x != _backing_sizex)||(bitplane_y != _backing_sizey))) {
00322       _depth_backing_store->Release();
00323       _depth_backing_store = NULL;
00324     }
00325     if (!_depth_backing_store) {
00326       hr = _dxgsg -> _d3d_device ->
00327         CreateDepthStencilSurface (bitplane_x, bitplane_y, _saved_depth_desc.Format,
00328                                    _saved_depth_desc.MultiSampleType, &_depth_backing_store);
00329       if (!SUCCEEDED(hr)) {
00330         dxgsg8_cat.error ( ) << "CreateDepthStencilSurface " << D3DERRORSTRING(hr) FL;
00331       }
00332     }
00333     depth_surf = _depth_backing_store;
00334   } else {
00335     // Maintain the depth texture.
00336     if (_depth_backing_store) {
00337       _depth_backing_store->Release();
00338       _depth_backing_store = NULL;
00339     }
00340     depth_tex = get_texture(depth_tex_index);
00341     depth_tex->set_x_size(bitplane_x);
00342     depth_tex->set_y_size(bitplane_y);
00343     depth_tex->set_format(Texture::F_depth_stencil);
00344     depth_ctx =
00345       DCAST(DXTextureContext8,
00346             depth_tex->prepare_now(0, _gsg->get_prepared_objects(), _gsg));
00347     if (depth_ctx) {
00348       if (!depth_ctx->create_texture(*_dxgsg->_screen)) {
00349         dxgsg8_cat.error()
00350           << "Unable to re-create texture " << *color_ctx->get_texture() << endl;
00351         return false;
00352       }
00353       
00354       if (depth_tex->get_texture_type() == Texture::TT_2d_texture) {
00355         depth_d3d_tex = depth_ctx->_d3d_2d_texture;
00356         nassertr(depth_d3d_tex != 0, false);
00357         hr = color_d3d_tex -> GetSurfaceLevel(0, &depth_surf);
00358         if (!SUCCEEDED(hr)) {
00359           dxgsg8_cat.error ( ) << "GetSurfaceLevel " << D3DERRORSTRING(hr) FL;
00360         }
00361       } else {
00362         depth_cube = depth_ctx->_d3d_cube_texture;
00363         nassertr(depth_cube != 0, false);
00364         hr = depth_cube -> GetCubeMapSurface ((D3DCUBEMAP_FACES) _cube_map_index, 0, &depth_surf);
00365         if (!SUCCEEDED(hr)) {
00366           dxgsg8_cat.error ( ) << "GetCubeMapSurface " << D3DERRORSTRING(hr) FL;
00367         }
00368       }
00369     }
00370   }
00371 
00372   _backing_sizex = bitplane_x;
00373   _backing_sizey = bitplane_y;
00374 
00375   // Load up the bitplanes.
00376 
00377   if (color_surf && depth_surf) {
00378     hr = _dxgsg -> _d3d_device -> SetRenderTarget (color_surf, depth_surf);
00379     if (!SUCCEEDED (hr)) {
00380       dxgsg8_cat.error ( ) << "SetRenderTarget " << D3DERRORSTRING(hr) FL;
00381     }
00382   }
00383 
00384   // Decrement the reference counts on these surfaces. The refcounts
00385   // were incremented earlier when we called GetSurfaceLevel.
00386 
00387   if ((color_surf != 0)&&(color_surf != _color_backing_store)) {
00388     color_surf->Release();
00389   }
00390   if ((depth_surf != 0)&&(depth_surf != _depth_backing_store)) {
00391     depth_surf->Release();
00392   }
00393   return true;
00394 }
00395 
00396 ////////////////////////////////////////////////////////////////////
00397 //     Function: wdxGraphicsBuffer8::select_cube_map
00398 //       Access: Public, Virtual
00399 //  Description: Called internally when the window is in
00400 //               render-to-a-texture mode and we are in the process of
00401 //               rendering the six faces of a cube map.  This should
00402 //               do whatever needs to be done to switch the buffer to
00403 //               the indicated face.
00404 ////////////////////////////////////////////////////////////////////
00405 void wdxGraphicsBuffer8::
00406 select_cube_map(int cube_map_index) {
00407   _cube_map_index = cube_map_index;
00408 
00409   HRESULT hr;
00410   Texture *color_tex = 0;
00411   DXTextureContext8 *color_ctx = 0;
00412   IDirect3DCubeTexture8 *color_cube = 0;
00413   IDirect3DSurface8 *color_surf = 0;
00414   int color_tex_index = -1;
00415 
00416   for (int i=0; i<count_textures(); i++) {
00417     if (get_rtm_mode(i) == RTM_bind_or_copy) {
00418       if ((get_texture(i)->get_format() != Texture::F_depth_stencil)&&
00419           (get_texture(i)->get_format() != Texture::F_depth_component)&&
00420           (color_tex_index < 0)) {
00421         color_tex_index = i;
00422       }
00423     }
00424   }
00425 
00426   color_tex = get_texture(color_tex_index);
00427   if (color_tex) {
00428     color_ctx =
00429       DCAST(DXTextureContext8,
00430             color_tex->prepare_now(0, _gsg->get_prepared_objects(), _gsg));
00431     if (!color_ctx->create_texture(*_dxgsg->_screen)) {
00432       dxgsg8_cat.error()
00433         << "Unable to re-create texture " << *color_ctx->get_texture() << endl;
00434       return;
00435     }
00436 
00437     color_cube = color_ctx->_d3d_cube_texture;
00438 
00439     if (color_cube && _cube_map_index >= 0 && _cube_map_index < 6) {
00440       hr = color_cube -> GetCubeMapSurface ((D3DCUBEMAP_FACES) _cube_map_index, 0, &color_surf);
00441       if (!SUCCEEDED(hr)) {
00442         dxgsg8_cat.error ( ) << "GetCubeMapSurface " << D3DERRORSTRING(hr) FL;
00443       }
00444 
00445       hr = _dxgsg -> _d3d_device -> SetRenderTarget (color_surf, 0);
00446       if (!SUCCEEDED (hr)) {
00447         dxgsg8_cat.error ( ) << "SetRenderTarget " << D3DERRORSTRING(hr) FL;
00448       }
00449       else {
00450         color_surf->Release();
00451       }
00452     }
00453   }
00454 }
00455 
00456 ////////////////////////////////////////////////////////////////////
00457 //     Function: wdxGraphicsBuffer8::process_events
00458 //       Access: Public, Virtual
00459 //  Description: Do whatever processing is necessary to ensure that
00460 //               the window responds to user events.  Also, honor any
00461 //               requests recently made via request_properties()
00462 //
00463 //               This function is called only within the window
00464 //               thread.
00465 ////////////////////////////////////////////////////////////////////
00466 void wdxGraphicsBuffer8::
00467 process_events() {
00468   GraphicsBuffer::process_events();
00469 
00470   MSG msg;
00471 
00472   // Handle all the messages on the queue in a row.  Some of these
00473   // might be for another window, but they will get dispatched
00474   // appropriately.
00475   while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
00476     process_1_event();
00477   }
00478 }
00479 
00480 ////////////////////////////////////////////////////////////////////
00481 //     Function: wdxGraphicsBuffer8::close_buffer
00482 //       Access: Protected, Virtual
00483 //  Description: Closes the buffer right now.  Called from the window
00484 //               thread.
00485 ////////////////////////////////////////////////////////////////////
00486 void wdxGraphicsBuffer8::
00487 close_buffer() {
00488 
00489   if (_gsg != (GraphicsStateGuardian *)NULL) {
00490     _gsg.clear();
00491   }
00492 
00493   if (_color_backing_store) {
00494     _color_backing_store->Release();
00495     _color_backing_store = NULL;
00496   }
00497   if (_depth_backing_store) {
00498     _depth_backing_store->Release();
00499     _depth_backing_store = NULL;
00500   }
00501 
00502   _cube_map_index = -1;
00503   _is_valid = false;
00504 }
00505 
00506 ////////////////////////////////////////////////////////////////////
00507 //     Function: wdxGraphicsBuffer8::open_buffer
00508 //       Access: Protected, Virtual
00509 //  Description: Opens the window right now.  Called from the window
00510 //               thread.  Returns true if the window is successfully
00511 //               opened, or false if there was a problem.
00512 ////////////////////////////////////////////////////////////////////
00513 bool wdxGraphicsBuffer8::
00514 open_buffer() {
00515 
00516   // GSG creation/initialization.
00517   if (_gsg == 0) {
00518     // The code below doesn't support creating a GSG on the fly.
00519     // Just error out for now.
00520     //_dxgsg = new DXGraphicsStateGuardian8(_engine, _pipe);
00521     //_gsg = _dxgsg;
00522     return false;
00523   }
00524    
00525   DCAST_INTO_R(_dxgsg, _gsg, false);
00526 
00527   if (!save_bitplanes()) {
00528     return false;
00529   }
00530 
00531   HRESULT hr;
00532   hr = _saved_color_buffer -> GetDesc (&_saved_color_desc);
00533   if (!SUCCEEDED (hr)) {
00534     dxgsg8_cat.error ( ) << "GetDesc " << D3DERRORSTRING(hr) FL;
00535     return false;
00536   }
00537   hr = _saved_depth_buffer -> GetDesc (&_saved_depth_desc);
00538   if (!SUCCEEDED (hr)) {
00539     dxgsg8_cat.error ( ) << "GetDesc " << D3DERRORSTRING(hr) FL;
00540     return false;
00541   }
00542   _fb_properties = _dxgsg->
00543     calc_fb_properties(_saved_color_desc.Format,
00544                        _saved_depth_desc.Format,
00545                        _saved_depth_desc.MultiSampleType);
00546   _fb_properties.set_force_hardware(1); // Wild guess.
00547 
00548   if (!rebuild_bitplanes()) {
00549     restore_bitplanes();
00550     return false;
00551   }
00552 
00553   restore_bitplanes();
00554   return true;
00555 }
00556 
00557 ////////////////////////////////////////////////////////////////////
00558 //     Function: wdxGraphicsBuffer8::process_1_event
00559 //       Access: Private, Static
00560 //  Description: Handles one event from the message queue.
00561 ////////////////////////////////////////////////////////////////////
00562 void wdxGraphicsBuffer8::
00563 process_1_event() {
00564   MSG msg;
00565 
00566   if (!GetMessage(&msg, NULL, 0, 0)) {
00567     // WM_QUIT received.  We need a cleaner way to deal with this.
00568     //    DestroyAllWindows(false);
00569     exit(msg.wParam);  // this will invoke AtExitFn
00570   }
00571 
00572   // Translate virtual key messages
00573   TranslateMessage(&msg);
00574   // Call window_proc
00575   DispatchMessage(&msg);
00576 }
 All Classes Functions Variables Enumerations