Panda3D
|
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 }