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