HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2013
0414
暇人mod_d3d9vsync(ティアリングを無くしFPS安定化)の更新と、ヘルプ1解決


暇人

リンク

2013/4/14(Sun) 00:51:31|NO.53549

WinXP環境のウィンドウ描画でティアリング(チラツキや波打つ現象)を無くすモジュール
http://hsp.tv/play/pforum.php?mode=pastwch&num=46392
これに修正を加えたものです。(使用サンプルは↑を)

修正箇所
Direct3DCreate9(32 | 0x80000000)はデバッグ時に使うバージョンとかなんとかだったので32に
デバイスロストした時はアクティブになってもリセット可能になるまでタイマーモードのままに
d3d9vsync_set_RefreshRateを追加
初期化時の操作先ウィンドウがbufferだった場合タイマーモードを選択
d3d9vsync実行した時に初期化時の操作先ウィンドウがアクティブじゃなければタイマーモードに移行

命令
d3d9vsync 垂直同期(同期とは言え無いが走査線監視モード時は近い処理)
GetRasterStatus 水平走査線取得
d3d9vsync_logsave d3d9ログ保存
d3d9vsync_GetTime PC起動時からの時間をミリ秒で返す
D3DDV9_Reset D3DDV9リセット
d3d9vsync_set_RefreshRate d3d9vsync_init後にリフレッシュレートが変更された場合の再初期化用
RasterAdjust フルスクリーン時の走査線監視位置修正

読み取り専用変数
d3d9vsync_cpu 1フレームのCPU使用率
d3d9vsync_cpu10
d3d9vsync_ptime 1フレームの処理時間
d3d9vsync_fps 1秒間のフレーム数
d3d9vsync_ftime 1フレームあたりの使用できる時間
d3d9vsync_err



//mod_d3d9vsync v1.0 for HSP3 2013/04/13 #module "mod_d3d9vsync" #uselib "d3d9" #cfunc Direct3DCreate9 "Direct3DCreate9" int #usecom IDirect3D9 "{81BDCBCA-64D4-426d-AE8D-AD0147F4275C}" #comfunc D3D9_GetAdapterDisplayMode 8 int, int #comfunc D3D9_GetDeviceCaps 14 int ,int,int,int #comfunc D3D9_CreateDevice 16 int, int, int, int, int, int #usecom IDirect3DDevice9 "{D0223B96-BF7A-43fd-92BD-A43B0D82B9EB}" #comfunc D3D9_TestCooperativeLevel 3 #comfunc IDirect3DDevice9_GetRasterStatus 19 int,int #comfunc _D3DDV9_Reset 16 int #define D3DDEVTYPE_HAL 1 #define D3DDEVTYPE_REF 2 #define D3DDEVTYPE_SW 3 #define D3DDEVTYPE_NULLREF 4 #define D3DSWAPEFFECT_DISCARD 1 #define D3DSWAPEFFECT_FLIP 2 #define D3DSWAPEFFECT_COPY 3 #define D3DSWAPEFFECT_FORCE_DWORD 0xFFFFFFF #define D3DCREATE_HARDWARE_VERTEXPROCESSING 0x00000040 #define D3DCREATE_SOFTWARE_VERTEXPROCESSING 0x00000020 #define DDCAPS_READSCANLINE 0x00020000 #define D3DCREATE_FPU_PRESERVE 0x00000002 #define D3DCREATE_MULTITHREADED 0x00000004 #define D3D_SDK_VERSION 32 #define ctype D3DPS_VERSION(%1,%2) (0xFFFF0000|((%1)<<8)|(%2)) #define ctype D3DVS_VERSION(%1,%2) (0xFFFE0000|((%1)<<8)|(%2)) #define ctype D3DVP_VERSION(%1) (((((%1))>>8)&$ff)),((%1&$ff)) #uselib "KERNEL32.DLL" #func _Sleep "Sleep" sptr #uselib "winmm.dll" #cfunc _timeGetTime "timeGetTime" #func _timeBeginPeriod "timeBeginPeriod" sptr #func _timeEndPeriod "timeEndPeriod" sptr #define global d3d9vsync_GetTime _timeGetTime@mod_d3d9vsync() //PC起動時からの時間をミリ秒で返す #define global D3D9WIN_ID 9999 //D3D9_CreateDevice用ウィンドウID #define global d3d9vsync_cpu cpu@mod_d3d9vsync //1フレームのCPU使用率 #define global d3d9vsync_cpu10 cpu10@mod_d3d9vsync //10フレームのCPU平均使用率 #define global d3d9vsync_ptime Processing_time@mod_d3d9vsync //1フレームの処理時間 #define global d3d9vsync_fps fps@mod_d3d9vsync //1秒間のフレーム数 #define global d3d9vsync_ftime fps_time@mod_d3d9vsync //1フレームあたりの使用できる時間 #define global d3d9vsync_err d3d9err@mod_d3d9vsync //D3DERR //d3d9vsync_set_RefreshRate 現在のリフレッシュレート //d3d9vsync_init後にリフレッシュレートが変更された場合の最初期化用 #define global d3d9vsync_set_RefreshRate(%1=-1) _d3d9vsync_set_RefreshRate %1 #deffunc _d3d9vsync_set_RefreshRate int RR if RR>0 {set_RefreshRate=RR:D3DDV9_Reset}else{set_RefreshRate=RefreshRate} return RefreshRate //D3DDV9_Reset //D3DDV9リセット #deffunc D3DDV9_Reset if (vsyncoff\2)=0 { D3D9_GetAdapterDisplayMode objd3d, 0, varptr(D3DFORMAT) if D3DFORMAT(2)>0 {RefreshRate=D3DFORMAT(2)}else{RefreshRate=set_RefreshRate} _D3DDV9_Reset objd3ddv,varptr(d3dpp) vsyncon=bak_vsyncon vsyncoff=0 if (set_fps = RefreshRate) {vsyncon=0}else{if vsyncon=0 {vsyncoff=2} } gosub *timeinit } return //RasterAdjust 修正値 //フルスクリーン時の走査線監視位置修正 修正値省略時20(最終ラインより20手前の走査線を監視,リフレッシュレート60でY解像度1080の場合) //修正値を省略した場合statに現在の設定値が返る #define global RasterAdjust(%1=Raster_adjust@mod_d3d9vsync) _RasterAdjust %1 #deffunc _RasterAdjust int p1 Raster_adjust=p1 return Raster_adjust //d3d9vsync_init フレームレート , 走査線監視モード優先フラグ //d3d9各種初期化 フレームレート省略時60(0以下を指定するとリフレッシュレートが使われる) //リフレッシュレート優先フラグ:1の時フレームレートとリフレッシュレートが違っても走査線監視モードを設定 #define global d3d9vsync_init(%1=60,%2=0) vsyncon@mod_d3d9vsync=%2:_d3d9vsync_init %1 #deffunc _d3d9vsync_init int _set_fps bak_ID = ginfo(3) Target_ID=bak_ID mref BMSCR,67 if (BMSCR(17) = 1) {} if set_RefreshRate<=0 {set_RefreshRate=60} bak_vsyncon=vsyncon desktop_sizey=ginfo(21) if set_fps {d3d9vsync_end}//再初期化された場合d3d9vsync_endを実行 _timeBeginPeriod 1 : tBP=1 RefreshRate=set_RefreshRate //とりあえずリフレッシュレート60にしとく if _set_fps<=0 {set_fps=60}else{set_fps=_set_fps} Raster_adjust=20 //フルスクリーン時の走査線監視位置修正値 Sleep_adjust_full=1 //フルスクリーン時スリープ修正値 dim D3DFORMAT, 4 dim D3DCAPS9,128 dim RasterStatus,2 d3dpp = 0, 0, D3DFORMAT(3), 1, 0, 0, D3DSWAPEFFECT_DISCARD, 0, 1, 0, 0, 0, 0, 0 p = 0 d3d9err=0 vsyncoff=0 if (BMSCR(17) = 1) {vsyncoff=1: gosub *timeinit: return -6 } //現在の操作先がbufferだった if varptr(Direct3DCreate9) = 0 {vsyncoff=1: gosub *timeinit: return -1 } //Direct3DCreate9が無いのでタイマーモードを設定して初期化終了 newcom objd3d, , -1, Direct3DCreate9(D3D_SDK_VERSION) D3D9_GetAdapterDisplayMode objd3d, 0, varptr(D3DFORMAT) if D3DFORMAT(2)>0 {RefreshRate=D3DFORMAT(2)}//リフレッシュレートが読み取れない場合60を設定 if _set_fps<=0 {set_fps=RefreshRate}//フレームレートに0以下が指定されたのでリフレッシュレートをフレームレートに D3D9_GetDeviceCaps objd3d,0,D3DDEVTYPE_HAL,varptr(D3DCAPS9) if stat<0 { D3D9_GetDeviceCaps objd3d,0,D3DDEVTYPE_REF,varptr(D3DCAPS9)//そもそもD3DDEVTYPE_REFだとDDCAPS_READSCANLINEに対応してないかも if stat<0 {d3d9err=stat:vsyncoff=1: gosub *timeinit: return -2} //D3D9_GetDeviceCapsが失敗した } if (D3DCAPS9(2)&DDCAPS_READSCANLINE) = 0 {vsyncoff=1: gosub *timeinit: return -3} //水平走査線取得非対応の場合タイマーモードを設定 FPUtes=str(9876543210.98745+1) FPU=(peek(FPUtes,15) = '5') //現在のFPU精度をテスト、小数点以下の'5'を読み取れなかったら単精度 bgscr D3D9WIN_ID,1,1,2 BF_SV=D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE*FPU //大抵初期化できるSOFTWAREにする D3D9_CreateDevice objd3d, 0, D3DCAPS9 , hWnd, BF_SV, varptr(d3dpp), varptr(p) d3d9err=stat gsel bak_ID if d3d9err<0{ vsyncoff=1:gosub *timeinit: return -4} //D3D9_CreateDeviceが失敗した newcom objd3ddv, , -1, p if vsyncon=0 {//走査線監視モード優先フラグOFF if set_fps ! RefreshRate {//指定フレームレートとリフレッシュレートが違う場合タイマーモードを設定 vsyncoff=2: gosub *timeinit: return -5 //タイマーモード選択 } }else{ //走査線監視モード優先フラグON 指定フレームレートとリフレッシュレートが違ったらタイマーモード+走査線監視モードを設定 if (set_fps = RefreshRate) {vsyncon=0}//同じなら通常の走査線監視モードを設定 } gosub *timeinit return RefreshRate *timeinit Refresh_time=1000.0/RefreshRate fps_time=1000.0/set_fps timA=_timeGetTime() Start_tim=timA timB=timA timC=timA fs_tim=0.0 cpu10=0.0 cpu=0.0 Processing_time=0 Processing_time10=0 return //GetRasterStatus 垂直帰線期間フラグ, 水平走査線数 //水平走査線取得 #deffunc GetRasterStatus var V,var R //水平走査線取得 if (vsyncoff\2)=0 { IDirect3DDevice9_GetRasterStatus objd3ddv,0,varptr(RasterStatus) V=RasterStatus //1=垂直帰線期間中 R=RasterStatus(1) //現在の走査線、上が1の時0になる(環境によるかも知れない) } return #define D3DERR_DEVICELOST -2005530520 #define D3DERR_DEVICENOTRESET -2005530519 //d3d9vsync 走査線監視フラグ //垂直同期 フラグに1を指定するとタイマーモード(省略時は0走査線監視モード) #deffunc d3d9vsync int _vsyncoff fps_cnt++ mref BMSCR,67 if ginfo(2)<0 or (ginfo(3) ! Target_ID) or (BMSCR(17) = 1) or (desktop_sizey ! ginfo(21)) {//非アクティブになった、解像度が変更された、初期化時のウィンドウと違った、操作先がbufferだった Reset_f=1 //D3DDV9リセット準備フラグセット }else{ if Reset_f=1 { //リセット準備フラグが立ってから1フレーム経過した Reset_f=2 //リセットフラグセット(アクティブになってから1フレーム待つため) }else{ if Reset_f=2 {//リセットフラグが立っている D3D9_TestCooperativeLevel objd3ddv if D3DERR_DEVICENOTRESET=stat or stat=0 {//リセットが可能 D3DDV9_Reset Reset_f=0 } } } } to=t Rasterok_f=0 Processing_time10+Processing_time if (fps_cnt\10)=0 {cpu10=(double(Processing_time10)*10)/fps_time:Processing_time10=0} cpu=double(Processing_time*100)/fps_time desktop_sizey=ginfo(21) adjust=((60.0/double(RefreshRate))*(double(desktop_sizey)/1080))//解像度とリフレッシュレートによって1ラインの時間が変るので係数を出す Raster_ms=double(desktop_sizey)/Refresh_time//1msで移動する走査線数 if (ginfo(7)<ginfo(21)) and (ginfo(7)>0) {WinRaster=ginfo(7)}else{WinRaster=ginfo(21)}//ウィンドウ下部位置とデスクトップYサイズを比較して低い方をラスター比較位置にする dup Raster,RasterStatus(1) WinUpRaster=limit(ginfo(5)-adjust*10,0,ginfo(5)) if (_vsyncoff | vsyncoff | Reset_f)=0 and vsyncon=0 { //水平走査線監視処理ON if ginfo(13)>=ginfo(21) {Sleep_adjust=Sleep_adjust_full } //フルスクリーン時スリープ修正値 timA = _timeGetTime() Processing_time = timA - timB //前回監視開始からの現在までの経過時間(監視期間も含まれるからメイン処理時間より1ms程度余分になる) sleep_tim=limit(fps_time-((timA - timC))-Sleep_adjust,0,fps_time)//スリープ時間(前回監視位置を超えたらSleep_adjust分短く) if sleep_tim>0 {_Sleep sleep_tim}//スリープ timB=_timeGetTime() if ginfo(13)>=ginfo(21) {//ウィンドウサイズがデスクトップサイズ以上(フルスクリーンとして処理開始) _WinRaster=WinRaster-(adjust*Raster_adjust) IDirect3DDevice9_GetRasterStatus objd3ddv,0,varptr(RasterStatus) if RasterStatus=1 or Raster=0 or (Raster>=_WinRaster) { }else{ Raster_bak=Raster repeat IDirect3DDevice9_GetRasterStatus objd3ddv,0,varptr(RasterStatus) if RasterStatus=1 or Raster=0 or (Raster>=_WinRaster) {Rasterok_f=1:break} if (cnt\100)=99 {if Raster_bak=Raster{break}else{Raster_bak=Raster}}//無限ループ回避策(100回ループしても同じ走査線数だったら抜ける)多分必要ないだろうけど・・・ loop } }else{ IDirect3DDevice9_GetRasterStatus objd3ddv,0,varptr(RasterStatus) if Raster>=WinRaster { Sleep_adjust=limit((Raster+Raster_ms-WinRaster)/Raster_ms,1,fps_time)//スリープ終了後すぐに監視位置を越えてるので次回のスリープを短くする修正値 }else{ Sleep_adjust=0 Raster_bak=Raster repeat IDirect3DDevice9_GetRasterStatus objd3ddv,0,varptr(RasterStatus) if (RasterStatus=1 or Raster=0 or Raster>=WinRaster) {Rasterok_f=1:break} if (cnt\100)=99 {if Raster_bak=Raster{break}else{Raster_bak=Raster}} loop } } fs_tim=0.0 timC=_timeGetTime() Start_tim=timC }else{ //タイマー処理ON fs_tim+fps_time //1フレームの時間を足して次フレームスタート時間にする if fs_tim > 50 {Start_tim+50:fs_tim-50} //HSPDX使用時は単精度になるから桁数を抑える timB=_timeGetTime() sms=fs_tim-(timB-Start_tim) //次フレームスタート時間からスタートからの時間を引いてスリープ時間にする(結果が負なら1フレームの時間を越えた) if sms < 0 {fs_tim-sms} //1フレームの時間以上使用したからオーバー分をフレームスタート時間に加算 _Sleep limit(sms,0,fps_time+1) //小数点以下のスリープは出来ないから最大スリープ時間を+1する if (vsyncoff\2)=0 and Reset_f=0 {gosub *GetRaster}//GetRasterStatusが使えるなら使う Processing_time=timB-timC//1フレームのスリープ時間を抜いた時間(処理に掛かった時間) timC=_timeGetTime() } t=timC/1000 if t ! to {d3d9vsync_fps=fps_cnt-fps_cnt_old:fps_cnt_old=fps_cnt} return Rasterok_f //これが1の場合スリープ時間が少なかった(水平走査線取得に対応してる場合) *GetRaster IDirect3DDevice9_GetRasterStatus objd3ddv,0,varptr(RasterStatus) if (Raster<=WinUpRaster or Raster>=WinRaster) {//メインウィンドウ外なら抜ける return }else{ if _vsyncoff>0 or vsyncon=0 {Rasterok_f=1:return }//タイマーモードなのですぐに抜ける Raster_bak=Raster repeat IDirect3DDevice9_GetRasterStatus objd3ddv,0,varptr(RasterStatus) if (Raster<=_WinRaster or Raster>=WinRaster) {Rasterok_f=1:break} if (cnt\100)=99 {if Raster_bak=Raster{break}else{Raster_bak=Raster}} loop } return //d3d9vsync_end //d3d9vsync終了処理 #deffunc d3d9vsync_end onexit if tBP {_timeEndPeriod 1:tEP=0} if vartype(objd3ddv)=6 {delcom objd3ddv:objd3ddv=0} if vartype(objd3d)=6 {delcom objd3d:objd3d=0} return //d3d9vsync_logsave //ログ保存 #deffunc d3d9vsync_logsave D3DCAPS9_log="-------------------------------\n D3DDISPLAYMODE\n-------------------------------\n" repeat 4 D3DCAPS9_log+=strf("%2d : %d\n",cnt,D3DFORMAT(cnt)) loop D3DCAPS9_log+"\n-------------------------------\n D3DCAPS9\n-------------------------------\n" repeat 76 if cnt=62 {D3DCAPS9_log+"D3DVSHADERCAPS2_0 VS20Caps{\n"} if cnt=66 {D3DCAPS9_log+"D3DPSHADERCAPS2_0 PS20Caps{\n"} D3DCAPS9_log+=strf("%2d : %s",cnt,str(D3DCAPS9(cnt))) if cnt=49 {D3DCAPS9_log+strf(" VertexShaderVersion(%d,%d)",D3DVP_VERSION(D3DCAPS9(cnt)))} if cnt=51 {D3DCAPS9_log+strf(" PixelShaderVersion(%d,%d)",D3DVP_VERSION(D3DCAPS9(cnt)))} if cnt=65 or cnt=69 {D3DCAPS9_log+"\n }\n"}else{D3DCAPS9_log+"\n"} loop D3DCAPS9_log+"\n-------------------------------\n D3DPRESENT_PARAMETERS\n-------------------------------\n" repeat 14 D3DCAPS9_log+=strf("%2d : %d\n",cnt,d3dpp(cnt)) loop notesel D3DCAPS9_log notesave "d3d9vsync.log" return #global



この記事に返信する


暇人

リンク

2013/4/14(Sun) 01:41:28|NO.53550

mod_d3d9vsync用ヘルプファイル
http://ux.getuploader.com/himajin130414/download/1/mod_d3d9vsync.hs


ここにヘルプ内容書こうとしたけどダメだった・・・



ONION software Copyright 1997-2023(c) All rights reserved.