diff --git a/panda/src/dxgsg/dxGraphicsStateGuardian.I b/panda/src/dxgsg/dxGraphicsStateGuardian.I index 33d48020ab..4dce57c800 100644 --- a/panda/src/dxgsg/dxGraphicsStateGuardian.I +++ b/panda/src/dxgsg/dxGraphicsStateGuardian.I @@ -284,7 +284,7 @@ call_dxAlphaFunc(D3DCMPFUNC func, DWORD ref) _alpha_func = func; _alpha_func_ref = ref; #ifdef GSG_VERBOSE - dxgsg_cat.debug() << "glAlphaFunc("; + dxgsg_cat.debug() << "dxAlphaFunc("; switch (func) { case D3DCMP_NEVER: dxgsg_cat.debug(false) << "D3DCMP_NEVER, "; diff --git a/panda/src/dxgsg/dxGraphicsStateGuardian.cxx b/panda/src/dxgsg/dxGraphicsStateGuardian.cxx index 36203a8e55..99eabf5883 100644 --- a/panda/src/dxgsg/dxGraphicsStateGuardian.cxx +++ b/panda/src/dxgsg/dxGraphicsStateGuardian.cxx @@ -70,6 +70,7 @@ //#define COUNT_DRAWPRIMS //#define PRINT_TEXSTATS +// #define MAKE_FPSMETER_TRANSPARENT //#define DISABLE_DECALING #define DISABLE_POLYGON_OFFSET_DECALING @@ -196,6 +197,140 @@ Colorf_to_D3DCOLOR(Colorf &cColorf) { #endif //!_X86_ } +void DXGraphicsStateGuardian::SetFPSMeterPosition(RECT &view_rect) { + if(_fpsmeter_verts==NULL) + return; + + DWORD renderWid = view_rect.right - view_rect.left; + DWORD renderHt = view_rect.bottom - view_rect.top; + + // adjust these to match fontsize (these are hacks for default font, probably should get char width from win32) + #define FPSMETER_NUMFONTLETTERS 11 // need 11 letters [0-9.] + #define NUM_FPSMETER_LETTERS 6 // field width used for display + #define FPSMETER_LETTER_WIDTH 9 + #define FPSMETER_LETTER_HEIGHT 12 + + #define FPSMETER_SUFFIX " FPS" + #define FPSMETER_SUFFIXLEN 4 + + float top_offset,left_offset; + float letter_width=FPSMETER_LETTER_WIDTH; + float z = 0.1f; // shouldnt matter since I turn off zfunc and clipping. these values are written into zbuf, but shouldnt matter since its endofframe + float rhw=1.0f; + + top_offset=0.05f * renderHt; + + left_offset = 0.99f*renderWid-letter_width*(NUM_FPSMETER_LETTERS+FPSMETER_SUFFIXLEN); + if(left_offset<0.0f) + left_offset=0.0f; + + float *fltptr= (float*)_fpsmeter_verts; + + // poly color should be irrelevant since fps texblend throws it away + D3DCOLOR fpscolr = D3DRGBA(1.0f,1.0f,1.0f,1.0f); + + #define WRITE_FPSMETER_VERT(x,y,z,w,colr,u,v) { *fltptr = x; fltptr++; \ + *fltptr = y; fltptr++; \ + *fltptr = z; fltptr++; \ + *fltptr = w; fltptr++; \ + (*((DWORD*)fltptr)) = colr; fltptr++; \ + *fltptr = u; fltptr++; \ + *fltptr = v; fltptr++; } + + float u_letter_width = _fps_u_usedwidth/(float)FPSMETER_NUMFONTLETTERS; + float height = FPSMETER_LETTER_HEIGHT; + float cur_xoffset=left_offset; + + // fmt is 3.2, need 12 tris. cant share verts since texcoords differ + + #define WRITE_FPS_SQUARE(x1,y1,x2,y2,u1,v1,u2,v2) \ + float *firstvertptr = fltptr; \ + WRITE_FPSMETER_VERT(x1,y1,z,rhw,fpscolr,u1,v1); \ + WRITE_FPSMETER_VERT(x1,y2,z,rhw,fpscolr,u1,v2); \ + float *thirdvertptr=fltptr; \ + WRITE_FPSMETER_VERT(x2,y2,z,rhw,fpscolr,u2,v2); \ + memcpy(fltptr,thirdvertptr,_fps_vertexsize); \ + fltptr = (float*) (((BYTE*)fltptr) + _fps_vertexsize); \ + WRITE_FPSMETER_VERT(x2,y1,z,rhw,fpscolr,u2,v1); \ + memcpy(fltptr,firstvertptr,_fps_vertexsize); \ + fltptr = (float*) (((BYTE*)fltptr) + _fps_vertexsize); + + for(int i=0;iGetSurfaceDesc(&ddsd); + + // init it to transparent black + if(FAILED( hr = _fpsmeter_font_surf->Lock( NULL, &ddsd, DDLOCK_NOSYSLOCK | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL ))) { + dxgsg_cat.error() << "fps meter creation failed, Lock() failed on texture! hr = " << ConvD3DErrorToString(hr) << "\n"; + dx_show_fps_meter = false; + return; + } + ZeroMemory(ddsd.lpSurface,ddsd.dwWidth*ddsd.dwHeight*2); + _fpsmeter_font_surf->Unlock(NULL); + + // draw text + HDC hDC; + _fpsmeter_font_surf->GetDC(&hDC); + + SetTextColor(hDC, RGB(255,255,128) ); + SetBkMode(hDC, TRANSPARENT ); + + char tstr[2] = {'\0','\0'}; + RECT Rect; + Rect.top = 0; Rect.bottom = FPSMETER_LETTER_HEIGHT-1; + Rect.left = 0; Rect.right = FPSMETER_LETTER_WIDTH; + + for(int i=0;iReleaseDC(hDC); + + // GDI writes 0x00 for alpha, have to make letter pixels opaque again + if(FAILED( hr = _fpsmeter_font_surf->Lock( NULL, &ddsd, DDLOCK_NOSYSLOCK | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL ))) { + dxgsg_cat.error() << "fps meter creation failed, Lock() failed on texture! hr = " << ConvD3DErrorToString(hr) << "\n"; + dx_show_fps_meter = false; + return; + } + + DWORD numpixels=ddsd.dwWidth*ddsd.dwHeight; + + #ifdef MAKE_FPSMETER_TRANSPARENT + WORD *pPixel=(WORD*)ddsd.lpSurface; + for(int ii=numpixels;ii>0;ii--) { + WORD wPixel=*pPixel; + if(wPixel & 0x0FFF) { + *pPixel |= 0xF000; // make written pixels opaque + }/* else { + *pPixel = 0x700F; // otherwise background is translucent blue + }*/ + pPixel++; + } + #endif + _fpsmeter_font_surf->Unlock(NULL); +} + //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian::Constructor // Access: Public @@ -210,7 +345,8 @@ DXGraphicsStateGuardian(GraphicsWindow *win) : GraphicsStateGuardian(win) { _pCurFvfBufPtr = NULL; _pFvfBufBasePtr = new char[VERT_BUFFER_SIZE]; // allocate storage for vertex info. _index_buf = new WORD[D3DMAXNUMVERTICES]; // allocate storage for vertex index info. - + _fpsmeter_verts=NULL; + _fpsmeter_font_surf=NULL; _dx_ready = false; _CurShadeMode = D3DSHADE_FLAT; @@ -366,6 +502,8 @@ init_dx( LPDIRECTDRAW7 context, _d3dDevice = pDevice; _view_rect = viewrect; + assert(_back!=NULL); // dxgsg is always double-buffered right now + #ifdef COUNT_DRAWPRIMS global_pD3DDevice = pDevice; #endif @@ -379,14 +517,7 @@ init_dx( LPDIRECTDRAW7 context, HRESULT hr; - if(dx_show_fps_meter) { - _start_time = timeGetTime(); - _current_fps = 0.0f; - _start_frame_count = _cur_frame_count = 0; - } - _pTexPixFmts = new DDPIXELFORMAT[MAX_DX_TEXPIXFMTS]; - assert(_pTexPixFmts!=NULL); if (pDevice->EnumTextureFormats(EnumTexFmtsCallback, this) != S_OK) { @@ -411,9 +542,9 @@ init_dx( LPDIRECTDRAW7 context, // dx7 doesnt support PLANEMASK renderstate #if(DIRECT3D_VERSION < 0x700) - dxgsg_cat.error() << "dx-decal-type 'offset' not supported by hardware, switching to decal masking\n"; + dxgsg_cat.debug() << "dx-decal-type 'offset' not supported by hardware, switching to decal masking\n"; #else - dxgsg_cat.error() << "dx-decal-type 'offset' not supported by hardware, switching to decal double-draw blend-based masking\n"; + dxgsg_cat.debug() << "dx-decal-type 'offset' not supported by hardware, switching to decal double-draw blend-based masking\n"; #endif #endif #if(DIRECT3D_VERSION < 0x700) @@ -527,6 +658,9 @@ init_dx( LPDIRECTDRAW7 context, enable_line_smooth(false); // enable_multisample(true); + _current_fill_mode = RenderModeProperty::M_filled; + _d3dDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID); + _d3dDevice->SetRenderState(D3DRENDERSTATE_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1); // technically DX7's front-end has no limit on the number of lights, but it's simpler for @@ -633,6 +767,99 @@ init_dx( LPDIRECTDRAW7 context, } #endif + // need to release this better, so init_dx can be called multiple times + + if(dx_show_fps_meter) { + _start_time = timeGetTime(); + _current_fps = 0.0f; + _start_frame_count = _cur_frame_count = 0; + + // create the fpsmeter font texture + DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT ; + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; + ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_HINTSTATIC; + + ddsd.dwTextureStage=0; + ddsd.dwFlags |= DDSD_TEXTURESTAGE; + ddsd.dwMipMapCount = 1; + + // use 4-4-4-4 fmt so blending looks cool + DDPIXELFORMAT *pCurPixFmt; + for(i=0,pCurPixFmt=&_pTexPixFmts[_cNumTexPixFmts-1];i<_cNumTexPixFmts;i++,pCurPixFmt--) { + if((pCurPixFmt->dwRGBBitCount==16) && (pCurPixFmt->dwFlags & DDPF_ALPHAPIXELS) + && (pCurPixFmt->dwRGBAlphaBitMask==0xF000)) + break; + } + + if(i>=_cNumTexPixFmts) { + // if this fails, no 4-4-4-4 fmt, need code to use 5-5-5-1 + dxgsg_cat.error() << "couldnt find 4-4-4-4 tex fmt for fpsmeter font!\n"; + dx_show_fps_meter = false; + return; + } + + memcpy(&ddsd.ddpfPixelFormat,pCurPixFmt,sizeof(DDPIXELFORMAT)); + + DWORD fontareaHeight = FPSMETER_LETTER_HEIGHT; + DWORD fontareaWidth = FPSMETER_LETTER_WIDTH * (FPSMETER_NUMFONTLETTERS + FPSMETER_SUFFIXLEN); + + // this is just the area used for the letters, not the suffix + DWORD letterfontareaWidth = FPSMETER_LETTER_WIDTH * FPSMETER_NUMFONTLETTERS; + + DWORD texdim_x = fontareaWidth; + DWORD texdim_y = fontareaHeight; + + #define ROUND_UP_TO_POW2(val) if(!ISPOW2(val)) { \ + for(int i=31;i>=0;i--) { \ + if(((1< texdim_x) + texdim_x = texdim_y; + texdim_y = texdim_x; + } + + ddsd.dwWidth = texdim_x; + ddsd.dwHeight = texdim_y; + + assert(_fpsmeter_font_surf==NULL); + + PRINTREFCNT(_pDD,"pre-fpsmeter-font-create IDirectDraw7"); + + // Create a new surface for the texture + if(FAILED( hr = _pDD->CreateSurface( &ddsd, &_fpsmeter_font_surf, NULL ) )) { + dxgsg_cat.error() << "CreateSurface() failed for fpsmeter font! hr = " << ConvD3DErrorToString(hr) << "\n"; + dx_show_fps_meter = false; + return; + } + + PRINTREFCNT(_pDD,"post-fpsmeter-font-create IDirectDraw7"); + + FillFPSMeterTexture(); + + // make buffer for fps meter tri data + + _fps_vertexsize = sizeof(D3DVALUE) * 4 + sizeof(D3DCOLOR) + sizeof(float) * 2; + _fpsmeter_fvfflags = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)); + + int numverts=(NUM_FPSMETER_LETTERS+1)*2*3; // +1 for square to hold suffix + + _fpsmeter_verts = (DWORD *) new BYTE[_fps_vertexsize*numverts]; //bugbug remember to release this + + _fps_u_usedwidth = letterfontareaWidth/(float)texdim_x; + _fps_v_usedheight = fontareaHeight/(float)texdim_y; + + SetFPSMeterPosition(_view_rect); + } } //////////////////////////////////////////////////////////////////// @@ -793,6 +1020,26 @@ void DXGraphicsStateGuardian::set_clipper(RECT cliprect) { } #endif +#if defined(_DEBUG) || defined(COUNT_DRAWPRIMS) +typedef enum {DrawPrim,DrawIndexedPrim,DrawPrimStrided} DP_Type; +static const char *DP_Type_Strs[3] = {"DrawPrimitive","DrawIndexedPrimitive","DrawPrimitiveStrided"}; + +void INLINE TestDrawPrimFailure(DP_Type dptype,HRESULT hr,LPDIRECTDRAW7 pDD,DWORD nVerts,DWORD nTris) { + if(FAILED(hr)) { + // loss of exclusive mode is not a real DrawPrim problem, ignore it + HRESULT testcooplvl_hr = pDD->TestCooperativeLevel(); + if((testcooplvl_hr != DDERR_NOEXCLUSIVEMODE)||(testcooplvl_hr != DDERR_EXCLUSIVEMODEALREADYSET)) { + dxgsg_cat.fatal() << DP_Type_Strs[dptype] << "() failed: result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + } + + CountDPs(nVerts,nTris); +} +#else +#define TestDrawPrimFailure(a,b,c,nVerts,nTris) CountDPs(nVerts,nTris); +#endif + //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian::render_frame // Access: Public, Virtual @@ -895,10 +1142,162 @@ render_frame() { } // for (int c = 0; c < max_channel_index; c++) #endif - // Now we're done with the frame processing. Clean up. + // draw new tri-based FPS meter - hr = _d3dDevice->EndScene(); // FPS meter drawing MUST occur after EndScene, since it uses GDI + if(dx_show_fps_meter) { + DO_PSTATS_STUFF(PStatTimer timer(_win->_show_fps_pcollector)); + // compute and write new texture indices here + + char fps_msg[15]; + sprintf(fps_msg, "%6.02f fps", _current_fps); // 6 == NUM_FPSMETER_LETTERS + + #define WRITE_FPS_UV(u,v) {*fltptr=(u); fltptr[1]=(v); fltptr= (float*)(((BYTE*)fltptr)+_fps_vertexsize);} + float u_FPSMETER_LETTER_WIDTH = _fps_u_usedwidth/(float)FPSMETER_NUMFONTLETTERS; + + // write out texcoords + float *fltptr = (float*)_fpsmeter_verts; + fltptr+=5; // skip over 1st XYZ,RHW, and colr (5 DWORDs) + + for(DWORD c=0;c'9'))) { + uval1=0.0f; uval2=0.0f; vval2=0.0f; + } + + WRITE_FPS_UV(uval1,0.0f); + WRITE_FPS_UV(uval1,vval2); + WRITE_FPS_UV(uval2,vval2); + + WRITE_FPS_UV(uval2,vval2); + WRITE_FPS_UV(uval2,0.0f); + WRITE_FPS_UV(uval1,0.0f); + } + + // is this blending fn expensive? if so, can just overwrite everything + + // could a state-block be used here instead? definitely to set up, but to restore? + #ifdef MAKE_FPSMETER_TRANSPARENT + call_dxBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + if(!_blend_enabled) + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, true); + #else + if(_blend_enabled) + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, false); + #endif + + if (_CurShadeMode != D3DSHADE_FLAT) { + _d3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_FLAT); + } + + DWORD saved_zfunc; + _d3dDevice->GetRenderState(D3DRENDERSTATE_ZFUNC,&saved_zfunc); + _d3dDevice->SetRenderState(D3DRENDERSTATE_ZFUNC,D3DCMP_ALWAYS); + + DWORD saved_fill_state; + if(_current_fill_mode != RenderModeProperty::M_filled) { + _d3dDevice->GetRenderState(D3DRENDERSTATE_FILLMODE, &saved_fill_state); + _d3dDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID); + } + + + DWORD saved_clipping_state,saved_cull_state; + _d3dDevice->GetRenderState(D3DRENDERSTATE_CULLMODE, &saved_cull_state); + _d3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); + + _d3dDevice->GetRenderState(D3DRENDERSTATE_CLIPPING, &saved_clipping_state); + _d3dDevice->SetRenderState(D3DRENDERSTATE_CLIPPING, false); + + // ignore lighting state since verts are post-xform + + DWORD saved_magfilter,saved_minfilter,saved_mipfilter; + DWORD saved_colorop,saved_alphaop,saved_colorarg1,saved_alphaarg1; + LPDIRECTDRAWSURFACE7 saved_tex_surf=NULL; + + _d3dDevice->GetTextureStageState(0, D3DTSS_MAGFILTER, &saved_magfilter); + _d3dDevice->GetTextureStageState(0, D3DTSS_MINFILTER, &saved_minfilter); + _d3dDevice->GetTextureStageState(0, D3DTSS_MIPFILTER, &saved_mipfilter); + _d3dDevice->GetTextureStageState( 0, D3DTSS_COLOROP, &saved_colorop); + _d3dDevice->GetTextureStageState( 0, D3DTSS_COLORARG1, &saved_colorarg1); + _d3dDevice->GetTextureStageState( 0, D3DTSS_ALPHAOP, &saved_alphaop); + _d3dDevice->GetTextureStageState( 0, D3DTSS_ALPHAARG1, &saved_alphaarg1); + + if(saved_mipfilter!= D3DTFP_NONE) + _d3dDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTFP_NONE); + + #define FPS_TEXFILTER(X) D3D##X##_POINT + + if(saved_minfilter!=FPS_TEXFILTER(TFN)) + _d3dDevice->SetTextureStageState(0, D3DTSS_MINFILTER, FPS_TEXFILTER(TFN)); + if(saved_magfilter!= FPS_TEXFILTER(TFG)) + _d3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, FPS_TEXFILTER(TFG)); + + if(saved_colorop!=D3DTOP_SELECTARG1) + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + if(saved_colorarg1!=D3DTA_TEXTURE) + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + if(saved_alphaop!=D3DTOP_SELECTARG1) + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + if(saved_alphaarg1!=D3DTA_TEXTURE) + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + + _d3dDevice->GetTexture(0, &saved_tex_surf); + hr = _d3dDevice->SetTexture(0, _fpsmeter_font_surf); + if(FAILED(hr)) { + dxgsg_cat.error() << "SetTexture failed in draw fps meter, result = " << ConvD3DErrorToString(hr) << endl; + exit(1); + } + + DWORD nVerts = (NUM_FPSMETER_LETTERS+1)*2*3; // +1 for suffix square + HRESULT hr = _d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, _fpsmeter_fvfflags, _fpsmeter_verts, nVerts, NULL); + TestDrawPrimFailure(DrawPrim,hr,_pDD,NUM_FPSMETER_LETTERS*2,0); + + #ifdef MAKE_FPSMETER_TRANSPARENT + if(!_blend_enabled) + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, false); + #else + if(_blend_enabled) + _d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, true); + #endif + + _d3dDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, saved_zfunc); + + _d3dDevice->SetRenderState(D3DRENDERSTATE_CLIPPING, saved_clipping_state); + _d3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, saved_cull_state); + + _d3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, saved_magfilter); + _d3dDevice->SetTextureStageState(0, D3DTSS_MINFILTER, saved_minfilter); + _d3dDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, saved_mipfilter); + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, saved_colorop); + _d3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, saved_colorarg1); + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, saved_alphaop); + _d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, saved_alphaarg1); + + if (_CurShadeMode != D3DSHADE_FLAT) { + _d3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, _CurShadeMode); + } + + if(_current_fill_mode != RenderModeProperty::M_filled) { + _d3dDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, saved_fill_state); + } + + _d3dDevice->SetTexture(0, saved_tex_surf); + } + + hr = _d3dDevice->EndScene(); + + // any GDI operations MUST occur after EndScene + + // Now we're done with the frame processing. Clean up. if (_lighting_enabled_this_frame) { // Let's turn off all the lights we had on, and clear the light // cache--to force the lights to be reissued next frame, in case @@ -953,19 +1352,6 @@ render_frame() { _start_frame_count = _cur_frame_count; } - HDC hDC; - - if(SUCCEEDED(_back->GetDC(&hDC))) { - char fps_msg[15]; - sprintf(fps_msg, "%7.02f fps", _current_fps); - SetTextColor(hDC, RGB(255,255,0) ); - SetBkMode(hDC, TRANSPARENT ); - - // 75,8 seem to work well w/default font - TextOutA(hDC, (_view_rect.right-_view_rect.left)-75, 8, fps_msg, strlen(fps_msg)); - _back->ReleaseDC(hDC); - } - _cur_frame_count++; // only used by fps meter right now } @@ -1198,8 +1584,7 @@ render_subgraph(RenderTraverser *traverser, LMatrix4f old_projection_mat = _current_projection_mat; // d3d is left-handed coord system - LMatrix4f projection_mat = - projnode->get_projection()->get_projection_mat(CS_yup_left); + LMatrix4f projection_mat = projnode->get_projection()->get_projection_mat(CS_yup_left); #if 0 dxgsg_cat.spam() << "cur projection matrix: " << projection_mat <<"\n"; @@ -1309,26 +1694,6 @@ typedef enum { FlatVerts,IndexedVerts,MixedFmtVerts } GeomVertFormat; -#if defined(_DEBUG) || defined(COUNT_DRAWPRIMS) -typedef enum {DrawPrim,DrawIndexedPrim,DrawPrimStrided} DP_Type; -static const char *DP_Type_Strs[3] = {"DrawPrimitive","DrawIndexedPrimitive","DrawPrimitiveStrided"}; - -void INLINE TestDrawPrimFailure(DP_Type dptype,HRESULT hr,LPDIRECTDRAW7 pDD,DWORD nVerts,DWORD nTris) { - if(FAILED(hr)) { - // loss of exclusive mode is not a real DrawPrim problem, ignore it - HRESULT testcooplvl_hr = pDD->TestCooperativeLevel(); - if((testcooplvl_hr != DDERR_NOEXCLUSIVEMODE)||(testcooplvl_hr != DDERR_EXCLUSIVEMODEALREADYSET)) { - dxgsg_cat.fatal() << DP_Type_Strs[dptype] << "() failed: result = " << ConvD3DErrorToString(hr) << endl; - exit(1); - } - } - - CountDPs(nVerts,nTris); -} -#else -#define TestDrawPrimFailure(a,b,c,nVerts,nTris) CountDPs(nVerts,nTris); -#endif - #define COPYVERTDATA_2_VERTEXBUFFER(PrimType,NumVertices) { \ DWORD numVertBytes=_pCurFvfBufPtr-_pFvfBufBasePtr; \ memcpy(_pCurrentGeomContext->_pEndofVertData,_pFvfBufBasePtr,numVertBytes); \ @@ -4575,6 +4940,9 @@ issue_render_mode(const RenderModeTransition *attrib) { RenderModeProperty::Mode mode = attrib->get_mode(); + if(mode==_current_fill_mode) + return; + switch (mode) { case RenderModeProperty::M_filled: _d3dDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID); @@ -4582,13 +4950,14 @@ issue_render_mode(const RenderModeTransition *attrib) { case RenderModeProperty::M_wireframe: _d3dDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_WIREFRAME); -// call_glLineWidth(attrib->get_line_width()); break; default: dxgsg_cat.error() << "Unknown render mode " << (int)mode << endl; } + + _current_fill_mode = mode; } //////////////////////////////////////////////////////////////////// @@ -5533,6 +5902,11 @@ free_pointers() { delete [] _pTexPixFmts; _pTexPixFmts = NULL; } + + if(_fpsmeter_verts!=NULL) { + delete [] _fpsmeter_verts; + _fpsmeter_verts = NULL; + } } //////////////////////////////////////////////////////////////////// @@ -5639,6 +6013,10 @@ void DXGraphicsStateGuardian:: dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled) { static bool bAtExitFnEverCalled=false; + if(dxgsg_cat.is_spam()) { + dxgsg_cat.spam() << "dx_cleanup called, bAtExitFnCalled=" << bAtExitFnCalled << ", bAtExitFnEverCalled=" << bAtExitFnEverCalled << endl; + } + bAtExitFnEverCalled = (bAtExitFnEverCalled || bAtExitFnCalled); // for now, I can't trust any of the ddraw/d3d releases during atexit(), @@ -5653,27 +6031,41 @@ dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled) { // msg already delivered to d3d.dll and it's unloaded itself if(!bAtExitFnEverCalled) { + PRINTREFCNT(_pDD,"exit start IDirectDraw7"); + // these 2 calls release ddraw surfaces and vbuffers. unsafe unless not on exit release_all_textures(); release_all_geoms(); + PRINTREFCNT(_pDD,"after release_all_textures IDirectDraw7"); // Do a safe check for releasing the D3DDEVICE. RefCount should be zero. // if we're called from exit(), _d3dDevice may already have been released if (_d3dDevice!=NULL) { - if (0 < (refcnt = _d3dDevice->Release())) { - dxgsg_cat.error() << "dx_cleanup - d3dDevice reference count = " << refcnt << ", should be zero!\n"; - } + _d3dDevice->SetTexture(0,NULL); // should release this stuff internally anyway + RELEASE(_d3dDevice,dxgsg,"d3dDevice",RELEASE_DOWN_TO_ZERO); } - - _d3dDevice = NULL; // clear the pointer in the Gsg - + + PRINTREFCNT(_pDD,"after d3ddevice release IDirectDraw7"); + + RELEASE(_fpsmeter_font_surf,dxgsg,"fpsmeter fontsurf",false); + + PRINTREFCNT(_pDD,"after fpsfont release IDirectDraw7"); + + if((_back!=NULL)&&(_zbuf!=NULL)) + _back->DeleteAttachedSurface(0x0,_zbuf); + // Release the DDraw and D3D objects used by the app - RELEASE(_zbuf); - RELEASE(_back); - RELEASE(_pri); + RELEASE(_zbuf,dxgsg,"zbuffer",false); + + PRINTREFCNT(_pDD,"before releasing d3d obj, IDirectDraw7"); + RELEASE(_d3d,dxgsg,"IDirect3D7 _d3d",false); //RELEASE_DOWN_TO_ZERO); + PRINTREFCNT(_pDD,"after releasing d3d obj, IDirectDraw7"); - RELEASE(_d3d); + RELEASE(_back,dxgsg,"backbuffer",false); + RELEASE(_pri,dxgsg,"primary surface",false); + + PRINTREFCNT(_pDD,"after releasing all surfs, IDirectDraw7"); } // for some reason, DLL_PROCESS_DETACH has not yet been sent to ddraw, so we can still call its fns @@ -5689,20 +6081,24 @@ dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled) { } } - refcnt = _pDD->Release(); - if(bAtExitFnCalled) { - // refcnt may be > 1 - - while (refcnt>1) { - refcnt = _pDD->Release(); - } + // if exit() called, there is definitely no more need for the IDDraw object, + // so we can make sure it's fully released + // note currently this is never called + RELEASE(_pDD,dxgsg,"IDirectDraw7 _pDD", RELEASE_DOWN_TO_ZERO); } else { - if(refcnt>0) - dxgsg_cat.error() << "dx_cleanup - IDDraw Obj reference count = " << refcnt << ", should be zero!\n"; - } + // seems wrong to release to zero, since it might be being used somewhere else? - _pDD = NULL; + // BUGBUG: running w/fpsmeter font surface seems to cause releasing d3ddevice to release fewer + // references to IDDraw7, which leaves IDDraw with a >0 refcnt after our release. Havent figured + // out why, but doesnt seem to cause a problem now since we're exiting... + + RELEASE(_pDD,dxgsg,"IDirectDraw7 _pDD", false); + if(refcnt>0) { + if(dxgsg_cat.is_spam()) + dxgsg_cat.debug() << "dx_cleanup - warning IDDraw7 refcnt = " << refcnt << ", should be zero!\n"; + } + } } } @@ -5724,19 +6120,14 @@ dx_setup_after_resize(RECT viewrect, HWND mwindow) { _back->GetSurfaceDesc(&ddsd_back); _zbuf->GetSurfaceDesc(&ddsd_zbuf); -#if 0 - DWORD refcnt; - refcnt = _zbuf->Release(); _zbuf = NULL; - dxgsg_cat.error() << "zbuf refcnt= "<Release(); _back = NULL; - dxgsg_cat.error() << "back refcnt= "<Release(); _pri = NULL; - dxgsg_cat.error() << "pri refcnt= "<DeleteAttachedSurface(0x0,_zbuf); + + RELEASE(_zbuf,dxgsg,"zbuffer",false); + RELEASE(_back,dxgsg,"backbuffer",false); + RELEASE(_pri,dxgsg,"primary surface",false); assert((_pri == NULL) && (_back == NULL) && (_zbuf == NULL)); _view_rect = viewrect; @@ -5800,14 +6191,12 @@ dx_setup_after_resize(RECT viewrect, HWND mwindow) { // Attach the z-buffer to the back buffer. if ((hr = _back->AddAttachedSurface( _zbuf ) ) != DD_OK) { - dxgsg_cat.fatal() - << "resize() - AddAttachedSurface failed : result = " << ConvD3DErrorToString(hr) << endl; + dxgsg_cat.fatal() << "resize() - AddAttachedSurface failed : result = " << ConvD3DErrorToString(hr) << endl; exit(1); } if ((hr = _d3dDevice->SetRenderTarget(_back,0x0) ) != DD_OK) { - dxgsg_cat.fatal() - << "resize() - SetRenderTarget failed : result = " << ConvD3DErrorToString(hr) << endl; + dxgsg_cat.fatal() << "resize() - SetRenderTarget failed : result = " << ConvD3DErrorToString(hr) << endl; exit(1); } @@ -5819,6 +6208,9 @@ dx_setup_after_resize(RECT viewrect, HWND mwindow) { << "SetViewport failed : result = " << ConvD3DErrorToString(hr) << endl; exit(1); } + + if(dx_show_fps_meter) + SetFPSMeterPosition(_view_rect); } bool refill_tex_callback(TextureContext *tc,void *void_dxgsg_ptr) { @@ -5848,6 +6240,9 @@ HRESULT DXGraphicsStateGuardian::RestoreAllVideoSurfaces(void) { // cant access template in libpanda.dll directly due to vc++ limitations, use traverser to get around it traverse_prepared_textures(refill_tex_callback,this); + if(dx_show_fps_meter) + FillFPSMeterTexture(); + if(dxgsg_cat.is_debug()) dxgsg_cat.debug() << "restore and refill of video surfaces complete...\n"; return S_OK; diff --git a/panda/src/dxgsg/dxGraphicsStateGuardian.h b/panda/src/dxgsg/dxGraphicsStateGuardian.h index 1595067b1d..9f1664fedb 100644 --- a/panda/src/dxgsg/dxGraphicsStateGuardian.h +++ b/panda/src/dxgsg/dxGraphicsStateGuardian.h @@ -32,7 +32,7 @@ #include #include #include - +#include #include #include #include @@ -64,7 +64,43 @@ INLINE ostream &operator << (ostream &out, GLenum v) { ZeroMemory(&var, sizeof(type)); \ var.dwSize = sizeof(type); -#define RELEASE(OBJECT) if(((OBJECT)!=NULL)&&(!IsBadWritePtr((OBJECT),4))) {(OBJECT)->Release(); (OBJECT) = NULL;} +// #define DEBUG_RELEASES + +// this is bDoDownToZero argument to RELEASE() +#define RELEASE_DOWN_TO_ZERO true + +#ifdef DEBUG_RELEASES +#define RELEASE(OBJECT,MODULE,DBGSTR,bDoDownToZero) \ + if(((OBJECT)!=NULL)&&(!IsBadWritePtr((OBJECT),4))) { \ + refcnt = (OBJECT)->Release(); \ + MODULE##_cat.debug() << DBGSTR << " released, refcnt = " << refcnt << endl; \ + if((bDoDownToZero) && (refcnt>0)) { \ + MODULE##_cat.warning() << DBGSTR << " released but still has a non-zero refcnt(" << refcnt << "), multi-releasing it down to zero!\n"; \ + do { \ + refcnt = (OBJECT)->Release(); \ + } while(refcnt>0); \ + } \ + (OBJECT) = NULL; \ + } else { \ + MODULE##_cat.debug() << DBGSTR << " not released, ptr == NULL" << endl; \ + } + +#define PRINTREFCNT(OBJECT,STR) { (OBJECT)->AddRef(); dxgsg_cat.debug() << STR << " refcnt = " << (OBJECT)->Release() << endl; } +#else +#define RELEASE(OBJECT,MODULE,DBGSTR,bDoDownToZero) \ + if(((OBJECT)!=NULL)&&(!IsBadWritePtr((OBJECT),4))) { \ + refcnt=(OBJECT)->Release(); \ + if((bDoDownToZero) && (refcnt>0)) { \ + MODULE##_cat.warning() << DBGSTR << " released but still has a non-zero refcnt(" << refcnt << "), multi-releasing it down to zero!\n"; \ + do { \ + refcnt = (OBJECT)->Release(); \ + } while(refcnt>0); \ + } \ + (OBJECT) = NULL; \ + } + +#define PRINTREFCNT(OBJECT,STR) +#endif //#if defined(NOTIFY_DEBUG) || defined(DO_PSTATS) #ifdef _DEBUG @@ -215,7 +251,7 @@ protected: RECT _view_rect; RECT clip_rect; - HDC _hdc; + HDC _front_hdc; int _cNumTexPixFmts; LPDDPIXELFORMAT _pTexPixFmts; DXTextureContext *_pCurTexContext; @@ -362,6 +398,8 @@ protected: bool _alpha_test_enabled; int _decal_level; + RenderModeProperty::Mode _current_fill_mode; //poinr/wireframe/solid + GraphicsChannel *_panda_gfx_channel; // cache the 1 channel dx supports // Cur Texture State @@ -400,6 +438,13 @@ protected: DWORD _start_frame_count; DWORD _cur_frame_count; float _current_fps; + DWORD *_fpsmeter_verts; + DWORD _fpsmeter_fvfflags; + LPDIRECTDRAWSURFACE7 _fpsmeter_font_surf; + float _fps_u_usedwidth,_fps_v_usedheight; // fraction of fps font texture actually used + DWORD _fps_vertexsize; // size of verts used to render fps meter + void SetFPSMeterPosition(RECT &view_rect); + void FillFPSMeterTexture(void); public: static GraphicsStateGuardian* @@ -414,7 +459,7 @@ public: LPDIRECTDRAW7 GetDDInterface() { return _pDD; } LPDIRECTDRAWSURFACE7 GetBackBuffer() { return _back; } LPDIRECTDRAWSURFACE7 GetZBuffer() { return _zbuf; } - INLINE void Set_HDC(HDC hdc) { _hdc = hdc; } + INLINE void Set_HDC(HDC hdc) { _front_hdc = hdc; } void adjust_view_rect(int x, int y); INLINE void SetDXReady(bool stat) { _dx_ready = stat; } INLINE bool GetDXReady(void) { return _dx_ready;} @@ -436,12 +481,15 @@ public: LPDIRECT3D7 d3d, LPDIRECT3DDEVICE7 d3dDevice, RECT viewrect); - friend HRESULT CALLBACK EnumTexFmtsCallback( LPDDPIXELFORMAT pddpf, VOID* param ); + + friend HRESULT CALLBACK EnumTexFmtsCallback( LPDDPIXELFORMAT pddpf, VOID* param ); private: static TypeHandle _type_handle; }; +#define ISPOW2(X) (((X) & ((X)-1))==0) + #include "dxGraphicsStateGuardian.I" #endif diff --git a/panda/src/dxgsg/dxTextureContext.cxx b/panda/src/dxgsg/dxTextureContext.cxx index d4eca25897..2bfde24c11 100644 --- a/panda/src/dxgsg/dxTextureContext.cxx +++ b/panda/src/dxgsg/dxTextureContext.cxx @@ -1054,8 +1054,6 @@ CreateTexture(LPDIRECT3DDEVICE7 pd3dDevice, int cNumTexPixFmts, LPDDPIXELFORMAT ddsd.dwWidth = dwOrigWidth; ddsd.dwHeight = dwOrigHeight; -#define ISPOW2(X) (((X) & ((X)-1))==0) - if(!ISPOW2(ddsd.dwWidth) || !ISPOW2(ddsd.dwHeight)) { dxgsg_cat.error() << "ERROR: texture dimensions are not a power of 2 for " << _tex->get_name() << "!!!!! \n"; #ifdef _DEBUG @@ -1581,6 +1579,7 @@ CreateTexture(LPDIRECT3DDEVICE7 pd3dDevice, int cNumTexPixFmts, LPDDPIXELFORMAT goto error_exit; } + #ifdef _DEBUG dxgsg_cat.debug() << "CreateTexture: "<< _tex->get_name() <<" converted " << ConvNameStrs[ConvNeeded] << " \n"; #endif @@ -1870,9 +1869,22 @@ DeleteTexture( ) { if(dxgsg_cat.is_spam()) { dxgsg_cat.spam() << "Deleting DX texture for " << _tex->get_name() << "\n"; } - if(_surface) - _surface->Release(); - _surface = NULL; + + ULONG refcnt; + +#ifdef DEBUG_RELEASES + if(_surface) { + LPDIRECTDRAW7 pDD; + _surface->GetDDInterface( (VOID**)&pDD ); + pDD->Release(); + + PRINTREFCNT(pDD,"before DeleteTex, IDDraw7"); + RELEASE(_surface,dxgsg,"texture",false); + PRINTREFCNT(pDD,"after DeleteTex, IDDraw7"); + } +#else + RELEASE(_surface,dxgsg,"texture",false); +#endif } @@ -1885,9 +1897,9 @@ DXTextureContext:: DXTextureContext(Texture *tex) : TextureContext(tex) { //#ifdef NDEBUG -// if(dxgsg_cat.is_spam()) { + if(dxgsg_cat.is_spam()) { dxgsg_cat.spam() << "Creating DX texture [" << tex->get_name() << "], minfilter(" << PandaFilterNameStrs[tex->get_minfilter()] << "), magfilter("<get_magfilter()] << "), anisodeg(" << tex->get_anisotropic_degree() << ")\n"; -// } + } //#endif _surface = NULL; _bHasMipMaps = FALSE; diff --git a/panda/src/wdxdisplay/wdxGraphicsWindow.cxx b/panda/src/wdxdisplay/wdxGraphicsWindow.cxx index 0627eb014c..4e9cf066dc 100644 --- a/panda/src/wdxdisplay/wdxGraphicsWindow.cxx +++ b/panda/src/wdxdisplay/wdxGraphicsWindow.cxx @@ -441,6 +441,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { LPDIRECTDRAWSURFACE7 pddsDummy = NULL, pddsDummyZ = NULL; HRESULT hr; + ULONG refcnt; DX_DECLARE_CLEAN( DDSURFACEDESC2, ddsd ); @@ -483,8 +484,8 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { << "Resize failed to set render target to temporary surface, result = " << ConvD3DErrorToString(hr) << endl; exit(1); } - RELEASE(pddsDummyZ); - RELEASE(pddsDummy); + RELEASE(pddsDummyZ,wdxdisplay,"dummy resize zbuffer",false); + RELEASE(pddsDummy,wdxdisplay,"dummy resize rendertarget buffer",false); } handle_reshape(true); @@ -815,6 +816,7 @@ void wdxGraphicsWindow::config(void) { _window_inactive = false; _return_control_to_app = false; _active_minimized_fullscreen = false; + _bIsLowVidMemCard = false; _hOldForegroundWindow=GetForegroundWindow(); @@ -1015,6 +1017,9 @@ BOOL WINAPI DriverEnumCallback( GUID* pGUID, TCHAR* strDesc,TCHAR* strName, return DDENUMRET_OK; } +//void wdxGraphicsWindow::resize(unsigned int xsize,unsigned int ysize) { +//} + //////////////////////////////////////////////////////////////////// // Function: dx_setup // Description: Set up the DirectX environment. The size of the diff --git a/panda/src/wdxdisplay/wdxGraphicsWindow.h b/panda/src/wdxdisplay/wdxGraphicsWindow.h index f4e679591d..5d2a23a0e7 100644 --- a/panda/src/wdxdisplay/wdxGraphicsWindow.h +++ b/panda/src/wdxdisplay/wdxGraphicsWindow.h @@ -77,6 +77,9 @@ public: virtual void begin_frame( void ); void show_frame(); DXGraphicsStateGuardian *_dxgsg; + +// virtual void resize(unsigned int xsize,unsigned int ysize); +// virtual unsigned int verify_window_sizes(unsigned int numsizes,unsigned int *dimen); protected: ButtonHandle lookup_key(WPARAM wparam) const; @@ -98,6 +101,7 @@ private: HPALETTE _colormap; typedef enum { NotAdjusting,MovingOrResizing,Resizing } WindowAdjustType; WindowAdjustType _WindowAdjustingType; + bool _bIsLowVidMemCard; HCURSOR _hMouseCursor; bool _bSizeIsMaximized; bool _mouse_input_enabled;