Panda3D

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     if (_one_shot) {
00154       prepare_for_deletion();
00155     }
00156     clear_cube_map_selection();
00157     restore_bitplanes();
00158   }
00159 }
00160 
00161 ////////////////////////////////////////////////////////////////////
00162 //     Function: wdxGraphicsBuffer8::save_bitplanes
00163 //       Access: Public
00164 //  Description: After rendering, d3d_device will need to be restored
00165 //               to its initial state.  This function saves the state.
00166 ////////////////////////////////////////////////////////////////////
00167 bool wdxGraphicsBuffer8::
00168 save_bitplanes() {
00169   HRESULT hr;
00170 
00171   hr = _dxgsg -> _d3d_device -> GetRenderTarget (&_saved_color_buffer);
00172   if (!SUCCEEDED (hr)) {
00173     dxgsg8_cat.error ( ) << "GetRenderTarget " << D3DERRORSTRING(hr) FL;
00174     return false;
00175   }
00176   hr = _dxgsg -> _d3d_device -> GetDepthStencilSurface (&_saved_depth_buffer);
00177   if (!SUCCEEDED (hr)) {
00178     dxgsg8_cat.error ( ) << "GetDepthStencilSurface " << D3DERRORSTRING(hr) FL;
00179     return false;
00180   }
00181   return true;
00182 }
00183 
00184 ////////////////////////////////////////////////////////////////////
00185 //     Function: wdxGraphicsBuffer8::restore_bitplanes
00186 //       Access: Public
00187 //  Description: After rendering, d3d_device will need to be restored
00188 //               to its initial state.  This function restores the state.
00189 ////////////////////////////////////////////////////////////////////
00190 void wdxGraphicsBuffer8::
00191 restore_bitplanes() {
00192   DXGraphicsStateGuardian8 *dxgsg;
00193   DCAST_INTO_V(dxgsg, _gsg);
00194 
00195   HRESULT hr;
00196 
00197   hr = dxgsg -> _d3d_device ->
00198     SetRenderTarget (_saved_color_buffer, _saved_depth_buffer);
00199 
00200   if (!SUCCEEDED (hr)) {
00201     dxgsg8_cat.error ( ) << "SetRenderTarget " << D3DERRORSTRING(hr) FL;
00202   }
00203 
00204   _saved_color_buffer->Release();
00205   _saved_depth_buffer->Release();
00206   _saved_color_buffer = NULL;
00207   _saved_depth_buffer = NULL;
00208 }
00209 
00210 
00211 ////////////////////////////////////////////////////////////////////
00212 //     Function: wdxGraphicsBuffer8::rebuild_bitplanes
00213 //       Access: Public
00214 //  Description: If necessary, reallocates (or allocates) the
00215 //               bitplanes for the buffer.
00216 ////////////////////////////////////////////////////////////////////
00217 bool wdxGraphicsBuffer8::
00218 rebuild_bitplanes() {
00219 
00220   HRESULT hr;
00221   Texture *color_tex = 0;
00222   Texture *depth_tex = 0;
00223   DXTextureContext8 *color_ctx = 0;
00224   DXTextureContext8 *depth_ctx = 0;
00225   IDirect3DTexture8 *color_d3d_tex = 0;
00226   IDirect3DTexture8 *depth_d3d_tex = 0;
00227   IDirect3DCubeTexture8 *color_cube = 0;
00228   IDirect3DCubeTexture8 *depth_cube = 0;
00229   IDirect3DSurface8 *color_surf = 0;
00230   IDirect3DSurface8 *depth_surf = 0;
00231 
00232   // Decide how big the bitplanes should be.
00233 
00234   if ((_host != 0)&&(_creation_flags & GraphicsPipe::BF_size_track_host)) {
00235     if ((_host->get_x_size() != _x_size)||
00236         (_host->get_y_size() != _y_size)) {
00237       set_size_and_recalc(_host->get_x_size(),
00238                           _host->get_y_size());
00239     }
00240   }
00241   int bitplane_x = _x_size;
00242   int bitplane_y = _y_size;
00243   if (Texture::get_textures_power_2() != ATS_none) {
00244     bitplane_x = Texture::up_to_power_2(bitplane_x);
00245     bitplane_y = Texture::up_to_power_2(bitplane_y);
00246   }
00247 
00248   // Find the color and depth textures.  Either may be present,
00249   // or neither.
00250   //
00251   // NOTE: Currently, depth-stencil textures are not implemented,
00252   // but since it's coming soon, we're structuring for it.
00253 
00254   int color_tex_index = -1;
00255   int depth_tex_index = -1;
00256   for (int i=0; i<count_textures(); i++) {
00257     if (get_rtm_mode(i) == RTM_bind_or_copy) {
00258       if ((get_texture(i)->get_format() != Texture::F_depth_stencil)&&
00259           (get_texture(i)->get_format() != Texture::F_depth_component)&&
00260           (color_tex_index < 0)) {
00261         color_tex_index = i;
00262       } else {
00263         _textures[i]._rtm_mode = RTM_copy_texture;
00264       }
00265     }
00266   }
00267 
00268 
00269   if (color_tex_index < 0) {
00270     // Maintain the backing color surface.
00271     if ((_color_backing_store)&&
00272         ((bitplane_x != _backing_sizex)||(bitplane_y != _backing_sizey))) {
00273       _color_backing_store->Release();
00274       _color_backing_store = NULL;
00275     }
00276     if (!_color_backing_store) {
00277       hr = _dxgsg -> _d3d_device ->
00278         CreateImageSurface(bitplane_x, bitplane_y, _saved_color_desc.Format, &_color_backing_store);
00279       if (!SUCCEEDED(hr)) {
00280         dxgsg8_cat.error ( ) << "CreateImageSurface " << D3DERRORSTRING(hr) FL;
00281       }
00282     }
00283     color_surf = _color_backing_store;
00284   } else {
00285     // Maintain the color texture.
00286     if (_color_backing_store) {
00287       _color_backing_store->Release();
00288       _color_backing_store = NULL;
00289     }
00290     color_tex = get_texture(color_tex_index);
00291     color_tex->set_x_size(bitplane_x);
00292     color_tex->set_y_size(bitplane_y);
00293     color_tex->set_format(Texture::F_rgba);
00294     color_ctx =
00295       DCAST(DXTextureContext8,
00296             color_tex->prepare_now(_gsg->get_prepared_objects(), _gsg));
00297     if (color_ctx) {
00298       if (!color_ctx->create_texture(*_dxgsg->_screen)) {
00299         dxgsg8_cat.error()
00300           << "Unable to re-create texture " << *color_ctx->get_texture() << endl;
00301         return false;
00302       }
00303       if (color_tex->get_texture_type() == Texture::TT_2d_texture) {
00304         color_d3d_tex = color_ctx->_d3d_2d_texture;
00305         nassertr(color_d3d_tex != 0, false);
00306         hr = color_d3d_tex -> GetSurfaceLevel(0, &color_surf);
00307         if (!SUCCEEDED(hr)) {
00308           dxgsg8_cat.error ( ) << "GetSurfaceLevel " << D3DERRORSTRING(hr) FL;
00309         }
00310       } else {
00311         color_cube = color_ctx->_d3d_cube_texture;
00312         nassertr(color_cube != 0, false);
00313         if (_cube_map_index >= 0 && _cube_map_index < 6) {
00314           hr = color_cube -> GetCubeMapSurface ((D3DCUBEMAP_FACES) _cube_map_index, 0, &color_surf);
00315           if (!SUCCEEDED(hr)) {
00316             dxgsg8_cat.error ( ) << "GetCubeMapSurface " << D3DERRORSTRING(hr) FL;
00317           }
00318         }
00319       }
00320     }
00321   }
00322 
00323   if (depth_tex_index < 0) {
00324     // Maintain the backing depth surface.
00325     if ((_depth_backing_store)&&
00326         ((bitplane_x != _backing_sizex)||(bitplane_y != _backing_sizey))) {
00327       _depth_backing_store->Release();
00328       _depth_backing_store = NULL;
00329     }
00330     if (!_depth_backing_store) {
00331       hr = _dxgsg -> _d3d_device ->
00332         CreateDepthStencilSurface (bitplane_x, bitplane_y, _saved_depth_desc.Format,
00333                                    _saved_depth_desc.MultiSampleType, &_depth_backing_store);
00334       if (!SUCCEEDED(hr)) {
00335         dxgsg8_cat.error ( ) << "CreateDepthStencilSurface " << D3DERRORSTRING(hr) FL;
00336       }
00337     }
00338     depth_surf = _depth_backing_store;
00339   } else {
00340     // Maintain the depth texture.
00341     if (_depth_backing_store) {
00342       _depth_backing_store->Release();
00343       _depth_backing_store = NULL;
00344     }
00345     depth_tex = get_texture(depth_tex_index);
00346     depth_tex->set_x_size(bitplane_x);
00347     depth_tex->set_y_size(bitplane_y);
00348     depth_tex->set_format(Texture::F_depth_stencil);
00349     depth_ctx =
00350       DCAST(DXTextureContext8,
00351             depth_tex->prepare_now(_gsg->get_prepared_objects(), _gsg));
00352     if (depth_ctx) {
00353       if (!depth_ctx->create_texture(*_dxgsg->_screen)) {
00354         dxgsg8_cat.error()
00355           << "Unable to re-create texture " << *color_ctx->get_texture() << endl;
00356         return false;
00357       }
00358       
00359       if (depth_tex->get_texture_type() == Texture::TT_2d_texture) {
00360         depth_d3d_tex = depth_ctx->_d3d_2d_texture;
00361         nassertr(depth_d3d_tex != 0, false);
00362         hr = color_d3d_tex -> GetSurfaceLevel(0, &depth_surf);
00363         if (!SUCCEEDED(hr)) {
00364           dxgsg8_cat.error ( ) << "GetSurfaceLevel " << D3DERRORSTRING(hr) FL;
00365         }
00366       } else {
00367         depth_cube = depth_ctx->_d3d_cube_texture;
00368         nassertr(depth_cube != 0, false);
00369         hr = depth_cube -> GetCubeMapSurface ((D3DCUBEMAP_FACES) _cube_map_index, 0, &depth_surf);
00370         if (!SUCCEEDED(hr)) {
00371           dxgsg8_cat.error ( ) << "GetCubeMapSurface " << D3DERRORSTRING(hr) FL;
00372         }
00373       }
00374     }
00375   }
00376 
00377   _backing_sizex = bitplane_x;
00378   _backing_sizey = bitplane_y;
00379 
00380   // Load up the bitplanes.
00381 
00382   if (color_surf && depth_surf) {
00383     hr = _dxgsg -> _d3d_device -> SetRenderTarget (color_surf, depth_surf);
00384     if (!SUCCEEDED (hr)) {
00385       dxgsg8_cat.error ( ) << "SetRenderTarget " << D3DERRORSTRING(hr) FL;
00386     }
00387   }
00388 
00389   // Decrement the reference counts on these surfaces. The refcounts
00390   // were incremented earlier when we called GetSurfaceLevel.
00391 
00392   if ((color_surf != 0)&&(color_surf != _color_backing_store)) {
00393     color_surf->Release();
00394   }
00395   if ((depth_surf != 0)&&(depth_surf != _depth_backing_store)) {
00396     depth_surf->Release();
00397   }
00398   return true;
00399 }
00400 
00401 ////////////////////////////////////////////////////////////////////
00402 //     Function: wdxGraphicsBuffer8::select_cube_map
00403 //       Access: Public, Virtual
00404 //  Description: Called internally when the window is in
00405 //               render-to-a-texture mode and we are in the process of
00406 //               rendering the six faces of a cube map.  This should
00407 //               do whatever needs to be done to switch the buffer to
00408 //               the indicated face.
00409 ////////////////////////////////////////////////////////////////////
00410 void wdxGraphicsBuffer8::
00411 select_cube_map(int cube_map_index) {
00412   _cube_map_index = cube_map_index;
00413 
00414   HRESULT hr;
00415   Texture *color_tex = 0;
00416   DXTextureContext8 *color_ctx = 0;
00417   IDirect3DCubeTexture8 *color_cube = 0;
00418   IDirect3DSurface8 *color_surf = 0;
00419   int color_tex_index = -1;
00420 
00421   for (int i=0; i<count_textures(); i++) {
00422     if (get_rtm_mode(i) == RTM_bind_or_copy) {
00423       if ((get_texture(i)->get_format() != Texture::F_depth_stencil)&&
00424           (get_texture(i)->get_format() != Texture::F_depth_component)&&
00425           (color_tex_index < 0)) {
00426         color_tex_index = i;
00427       } else {
00428         _textures[i]._rtm_mode = RTM_copy_texture;
00429       }
00430     }
00431   }
00432 
00433   color_tex = get_texture(color_tex_index);
00434   if (color_tex) {
00435     color_ctx =
00436       DCAST(DXTextureContext8,
00437             color_tex->prepare_now(_gsg->get_prepared_objects(), _gsg));
00438     if (!color_ctx->create_texture(*_dxgsg->_screen)) {
00439       dxgsg8_cat.error()
00440         << "Unable to re-create texture " << *color_ctx->get_texture() << endl;
00441       return;
00442     }
00443 
00444     color_cube = color_ctx->_d3d_cube_texture;
00445 
00446     if (color_cube && _cube_map_index >= 0 && _cube_map_index < 6) {
00447       hr = color_cube -> GetCubeMapSurface ((D3DCUBEMAP_FACES) _cube_map_index, 0, &color_surf);
00448       if (!SUCCEEDED(hr)) {
00449         dxgsg8_cat.error ( ) << "GetCubeMapSurface " << D3DERRORSTRING(hr) FL;
00450       }
00451 
00452       hr = _dxgsg -> _d3d_device -> SetRenderTarget (color_surf, 0);
00453       if (!SUCCEEDED (hr)) {
00454         dxgsg8_cat.error ( ) << "SetRenderTarget " << D3DERRORSTRING(hr) FL;
00455       }
00456       else {
00457         color_surf->Release();
00458       }
00459     }
00460   }
00461 }
00462 
00463 ////////////////////////////////////////////////////////////////////
00464 //     Function: wdxGraphicsBuffer8::process_events
00465 //       Access: Public, Virtual
00466 //  Description: Do whatever processing is necessary to ensure that
00467 //               the window responds to user events.  Also, honor any
00468 //               requests recently made via request_properties()
00469 //
00470 //               This function is called only within the window
00471 //               thread.
00472 ////////////////////////////////////////////////////////////////////
00473 void wdxGraphicsBuffer8::
00474 process_events() {
00475   GraphicsBuffer::process_events();
00476 
00477   MSG msg;
00478 
00479   // Handle all the messages on the queue in a row.  Some of these
00480   // might be for another window, but they will get dispatched
00481   // appropriately.
00482   while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
00483     process_1_event();
00484   }
00485 }
00486 
00487 ////////////////////////////////////////////////////////////////////
00488 //     Function: wdxGraphicsBuffer8::close_buffer
00489 //       Access: Protected, Virtual
00490 //  Description: Closes the buffer right now.  Called from the window
00491 //               thread.
00492 ////////////////////////////////////////////////////////////////////
00493 void wdxGraphicsBuffer8::
00494 close_buffer() {
00495 
00496   if (_gsg != (GraphicsStateGuardian *)NULL) {
00497     _gsg.clear();
00498   }
00499 
00500   if (_color_backing_store) {
00501     _color_backing_store->Release();
00502     _color_backing_store = NULL;
00503   }
00504   if (_depth_backing_store) {
00505     _depth_backing_store->Release();
00506     _depth_backing_store = NULL;
00507   }
00508 
00509   _active = false;
00510   _cube_map_index = -1;
00511   _is_valid = false;
00512 }
00513 
00514 ////////////////////////////////////////////////////////////////////
00515 //     Function: wdxGraphicsBuffer8::open_buffer
00516 //       Access: Protected, Virtual
00517 //  Description: Opens the window right now.  Called from the window
00518 //               thread.  Returns true if the window is successfully
00519 //               opened, or false if there was a problem.
00520 ////////////////////////////////////////////////////////////////////
00521 bool wdxGraphicsBuffer8::
00522 open_buffer() {
00523 
00524   // GSG creation/initialization.
00525   if (_gsg == 0) {
00526     // The code below doesn't support creating a GSG on the fly.
00527     // Just error out for now.
00528     //_dxgsg = new DXGraphicsStateGuardian8(_engine, _pipe);
00529     //_gsg = _dxgsg;
00530     return false;
00531   }
00532    
00533   DCAST_INTO_R(_dxgsg, _gsg, false);
00534 
00535   if (!save_bitplanes()) {
00536     return false;
00537   }
00538 
00539   HRESULT hr;
00540   hr = _saved_color_buffer -> GetDesc (&_saved_color_desc);
00541   if (!SUCCEEDED (hr)) {
00542     dxgsg8_cat.error ( ) << "GetDesc " << D3DERRORSTRING(hr) FL;
00543     return false;
00544   }
00545   hr = _saved_depth_buffer -> GetDesc (&_saved_depth_desc);
00546   if (!SUCCEEDED (hr)) {
00547     dxgsg8_cat.error ( ) << "GetDesc " << D3DERRORSTRING(hr) FL;
00548     return false;
00549   }
00550   _fb_properties = _dxgsg->
00551     calc_fb_properties(_saved_color_desc.Format,
00552                        _saved_depth_desc.Format,
00553                        _saved_depth_desc.MultiSampleType);
00554   _fb_properties.set_force_hardware(1); // Wild guess.
00555 
00556   if (!rebuild_bitplanes()) {
00557     restore_bitplanes();
00558     return false;
00559   }
00560 
00561   restore_bitplanes();
00562   return true;
00563 }
00564 
00565 ////////////////////////////////////////////////////////////////////
00566 //     Function: wdxGraphicsBuffer8::process_1_event
00567 //       Access: Private, Static
00568 //  Description: Handles one event from the message queue.
00569 ////////////////////////////////////////////////////////////////////
00570 void wdxGraphicsBuffer8::
00571 process_1_event() {
00572   MSG msg;
00573 
00574   if (!GetMessage(&msg, NULL, 0, 0)) {
00575     // WM_QUIT received.  We need a cleaner way to deal with this.
00576     //    DestroyAllWindows(false);
00577     exit(msg.wParam);  // this will invoke AtExitFn
00578   }
00579 
00580   // Translate virtual key messages
00581   TranslateMessage(&msg);
00582   // Call window_proc
00583   DispatchMessage(&msg);
00584 }
 All Classes Functions Variables Enumerations