diff --git a/audit/history.jsonl b/audit/history.jsonl index 00e70685..026a9308 100644 --- a/audit/history.jsonl +++ b/audit/history.jsonl @@ -637,3 +637,4 @@ {"date": "2026-09-30", "unit": "EterLib/GrpTextInstance.cpp", "action": "port", "evidence": "verbatim except Render draw calls -> UIRender commands; port.text, port.app_loop"} {"date": "2026-09-30", "unit": "EterLib/SkyBox.cpp", "action": "port", "evidence": "verbatim except native-terrain gate on Render/RenderCloud and qualified CSkyObject::Destroy in the destructor; port.login_flow (map teardown), live-client sky screenshot matches previous build"} {"date": "2026-09-30", "unit": "EterLib/GrpScreen.cpp", "action": "port", "evidence": "verbatim; 2d draws -> UIRender commands, Show without the web-page rects; D3D8 shim gains TestCooperativeLevel/Reset/Present/GetVertexShader + ID3DXMesh; port.app_loop (3D line/bar draws, device not lost), port.login_flow (picking/projection)"} +{"date": "2026-09-30", "unit": "EterLib/GrpDevice.cpp", "action": "port", "evidence": "verbatim except Create (recording device in place of Direct3DCreate8/detector/CreateDevice, EL3D_ConfirmDevice on its caps); RecordingDevice decodes declaration-only vertex shaders to stream-0 FVFs; GrpScreen Show uses the GrpDevice browser globals; port.app_loop (PT/PNT/PNT2 FVFs, max texture 4096), full ctest, live-client screenshot matches"} diff --git a/audit/port-map/EterLib/GrpDevice.cpp.json b/audit/port-map/EterLib/GrpDevice.cpp.json new file mode 100644 index 00000000..9430d245 --- /dev/null +++ b/audit/port-map/EterLib/GrpDevice.cpp.json @@ -0,0 +1,317 @@ +{ + "reference": "EterLib/GrpDevice.cpp", + "reference_sha256": "dbae65b090d43e24f75f59c03f2d74d180499a155c75e52fe6ddacdb1e8ac72c", + "priority": "P4", + "contracts": [], + "functions": { + "CGraphicDevice::CGraphicDevice": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::CGraphicDevice" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "m_uBackBufferCount": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::CGraphicDevice" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::~CGraphicDevice": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::~CGraphicDevice" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::__Initialize": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::__Initialize" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::RegisterWarningString": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::RegisterWarningString" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::__WarningMessage": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::__WarningMessage" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::MoveWebBrowserRect": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::MoveWebBrowserRect" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::EnableWebBrowserMode": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::EnableWebBrowserMode" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::DisableWebBrowserMode": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::DisableWebBrowserMode" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::ResizeBackBuffer": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::ResizeBackBuffer" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::CreatePNTStreamVertexShader": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::CreatePNTStreamVertexShader", + "src/platform/EterLib/RecordingDevice.cpp:RecordingDevice::CreateVertexShader" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ], + "note": "Verbatim; the recording device turns a declaration-only vertex shader into the FVF of stream 0 (SetVertexShader takes that handle as the FVF it decodes)." + }, + "CGraphicDevice::CreatePNT2StreamVertexShader": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::CreatePNT2StreamVertexShader", + "src/platform/EterLib/RecordingDevice.cpp:RecordingDevice::CreateVertexShader" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ], + "note": "Verbatim; the recording device turns a declaration-only vertex shader into the FVF of stream 0 (SetVertexShader takes that handle as the FVF it decodes)." + }, + "CGraphicDevice::CreatePTStreamVertexShader": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::CreatePTStreamVertexShader", + "src/platform/EterLib/RecordingDevice.cpp:RecordingDevice::CreateVertexShader" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ], + "note": "Verbatim; the recording device turns a declaration-only vertex shader into the FVF of stream 0 (SetVertexShader takes that handle as the FVF it decodes)." + }, + "CGraphicDevice::CreateDoublePNTStreamVertexShader": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::CreateDoublePNTStreamVertexShader", + "src/platform/EterLib/RecordingDevice.cpp:RecordingDevice::CreateVertexShader" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ], + "note": "Verbatim; the recording device turns a declaration-only vertex shader into the FVF of stream 0 (SetVertexShader takes that handle as the FVF it decodes)." + }, + "CGraphicDevice::GetDeviceState": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::GetDeviceState" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::Reset": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::Reset" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "EL3D_ConfirmDevice": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:EL3D_ConfirmDevice" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "GetMaxTextureWidth": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:GetMaxTextureWidth" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "GetMaxTextureHeight": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:GetMaxTextureHeight" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::__IsInDriverBlackList": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::__IsInDriverBlackList" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::Create": { + "status": "ADAPTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::Create" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ], + "note": "40250: GetDC, Direct3DCreate8, D3D_CDisplayModeAutoDetector Build/Find (EL3D_ConfirmDevice per device), driver black list, CreateDevice with a refresh-rate retry, DXT CheckDeviceFormat, SetWindowPos, D3DXCreateSphere/Cylinder, SIS/3dfx caps. Port: MtCreateRecordingDevice in place of the Direct3D object and detection; the present parameters the detector does not choose are set as 40250; EL3D_ConfirmDevice runs on the one device's caps; no debug meshes; no adapter identifier. Invariant: same state manager, matrix stack, screen matrices, stream shaders, default IB/PDT VB and texture-memory/border caps after Create." + }, + "CGraphicDevice::__InitializePDTVertexBufferList": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::__InitializePDTVertexBufferList" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::__DestroyPDTVertexBufferList": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::__DestroyPDTVertexBufferList" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::__CreatePDTVertexBufferList": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::__CreatePDTVertexBufferList" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::__InitializeDefaultIndexBufferList": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::__InitializeDefaultIndexBufferList" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::__DestroyDefaultIndexBufferList": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::__DestroyDefaultIndexBufferList" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::__CreateDefaultIndexBuffer": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::__CreateDefaultIndexBuffer" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::__CreateDefaultIndexBufferList": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::__CreateDefaultIndexBufferList" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::InitBackBufferCount": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::InitBackBufferCount" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + }, + "CGraphicDevice::Destroy": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpDevice.cpp:CGraphicDevice::Destroy" + ], + "test": [ + "tests/port/port_app_loop_test.cpp", + "tests/port/port_login_flow_test.cpp" + ] + } + } +} diff --git a/audit/port-map/EterLib/GrpScreen.cpp.json b/audit/port-map/EterLib/GrpScreen.cpp.json index 743f2f32..1d1ec57f 100644 --- a/audit/port-map/EterLib/GrpScreen.cpp.json +++ b/audit/port-map/EterLib/GrpScreen.cpp.json @@ -357,7 +357,7 @@ "tests/port/port_app_loop_test.cpp", "tests/port/port_login_flow_test.cpp" ], - "note": "40250: Present, or four Present rects around g_rcBrowser while the in-game web page is open. Port: g_isBrowserMode/g_rcBrowser are file statics (false/empty) since PythonApplicationWebPage is DIVERGENT; the rects cast to LONG (32-bit on LP64); the recording device's Present is D3D_OK and the host presents the frame. Invariant: whole back buffer presented." + "note": "40250: Present, or four Present rects around g_rcBrowser while the in-game web page is open. Port: verbatim with the GrpDevice.cpp globals (EnableWebBrowserMode is never called: PythonApplicationWebPage is DIVERGENT); the rects cast to LONG (32-bit on LP64); the recording device's Present is D3D_OK and the host presents the frame. Invariant: whole back buffer presented." }, "CScreen::ProjectPosition": { "status": "PORTED", diff --git a/src/platform/EterLib/GrpDevice.cpp b/src/platform/EterLib/GrpDevice.cpp index 7e913cf6..b9319143 100644 --- a/src/platform/EterLib/GrpDevice.cpp +++ b/src/platform/EterLib/GrpDevice.cpp @@ -1,25 +1,22 @@ -// 40250 EterLib/GrpDevice.cpp over the platform's recording device (RecordingDevice.h): there is no -// Direct3D object, adapter detection or window; Create makes the device, CStateManager, the matrix -// stack and the default buffers as 40250 does. The remaining MT_PLATFORM_STUB() bodies (device reset, -// web-browser mode, driver warnings) have no platform counterpart yet. +// 40250 EterLib/GrpDevice.cpp, verbatim but for CGraphicDevice::Create, which makes the recording device +// (RecordingDevice.h) in place of the Direct3D object, adapter detection and CreateDevice. #include "EterLib/StdAfx.h" #include "EterLib/GrpDevice.h" -#include "EterLib/StateManager.h" #include "EterBase/Stl.h" +#include "EterBase/Debug.h" -#include "CpuBuffer.h" #include "RecordingDevice.h" -#include - -#include "../PlatformStub.h" - bool GRAPHICS_CAPS_CAN_NOT_DRAW_LINE = false; bool GRAPHICS_CAPS_CAN_NOT_DRAW_SHADOW = false; bool GRAPHICS_CAPS_HALF_SIZE_IMAGE = false; bool GRAPHICS_CAPS_CAN_NOT_TEXTURE_ADDRESS_BORDER = false; bool GRAPHICS_CAPS_SOFTWARE_TILING = false; +D3DPRESENT_PARAMETERS g_kD3DPP; +bool g_isBrowserMode=false; +RECT g_rcBrowser; + CGraphicDevice::CGraphicDevice() : m_uBackBufferCount(0) { @@ -31,31 +28,325 @@ CGraphicDevice::~CGraphicDevice() Destroy(); } -void CGraphicDevice::InitBackBufferCount(UINT uBackBufferCount) +void CGraphicDevice::__Initialize() { - m_uBackBufferCount=uBackBufferCount; + ms_iD3DAdapterInfo=D3DADAPTER_DEFAULT; + ms_iD3DDevInfo=D3DADAPTER_DEFAULT; + ms_iD3DModeInfo=D3DADAPTER_DEFAULT; + + ms_lpd3d = NULL; + ms_lpd3dDevice = NULL; + ms_lpd3dMatStack = NULL; + + ms_dwWavingEndTime = 0; + ms_dwFlashingEndTime = 0; + + m_pStateManager = NULL; + + __InitializeDefaultIndexBufferList(); + __InitializePDTVertexBufferList(); } -void CGraphicDevice::Destroy() +void CGraphicDevice::RegisterWarningString(UINT uiMsg, const char * c_szString) { - __DestroyPDTVertexBufferList(); - __DestroyDefaultIndexBufferList(); + m_kMap_strWarningMessage[uiMsg] = c_szString; +} - // PORT: no DC, vertex shader objects or D3DX meshes; the stream "shaders" are FVF codes. - ms_ptVS = 0; - ms_pntVS = 0; - ms_pnt2VS = 0; +void CGraphicDevice::__WarningMessage(HWND hWnd, UINT uiMsg) +{ + if (m_kMap_strWarningMessage.end() == m_kMap_strWarningMessage.find(uiMsg)) + return; + MessageBox(hWnd, m_kMap_strWarningMessage[uiMsg].c_str(), "Warning", MB_OK|MB_TOPMOST); +} - safe_release(ms_lpd3dMatStack); - safe_release(ms_lpd3dDevice); +void CGraphicDevice::MoveWebBrowserRect(const RECT& c_rcWebPage) +{ + g_rcBrowser=c_rcWebPage; +} - if (m_pStateManager) +void CGraphicDevice::EnableWebBrowserMode(const RECT& c_rcWebPage) +{ + if (!ms_lpd3dDevice) + return; + + D3DPRESENT_PARAMETERS& rkD3DPP=ms_d3dPresentParameter; + + g_isBrowserMode=true; + + if (D3DSWAPEFFECT_COPY==rkD3DPP.SwapEffect) + return; + + g_kD3DPP=rkD3DPP; + g_rcBrowser=c_rcWebPage; + + //rkD3DPP.Windowed=TRUE; + rkD3DPP.SwapEffect=D3DSWAPEFFECT_COPY; + rkD3DPP.BackBufferCount = 1; + rkD3DPP.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + + IDirect3DDevice8& rkD3DDev=*ms_lpd3dDevice; + HRESULT hr=rkD3DDev.Reset(&rkD3DPP); + if (FAILED(hr)) + return; + + STATEMANAGER.SetDefaultState(); +} + +void CGraphicDevice::DisableWebBrowserMode() +{ + if (!ms_lpd3dDevice) + return; + + D3DPRESENT_PARAMETERS& rkD3DPP=ms_d3dPresentParameter; + + g_isBrowserMode=false; + + rkD3DPP=g_kD3DPP; + + IDirect3DDevice8& rkD3DDev=*ms_lpd3dDevice; + HRESULT hr=rkD3DDev.Reset(&rkD3DPP); + if (FAILED(hr)) + return; + + STATEMANAGER.SetDefaultState(); +} + +bool CGraphicDevice::ResizeBackBuffer(UINT uWidth, UINT uHeight) +{ + if (!ms_lpd3dDevice) + return false; + + D3DPRESENT_PARAMETERS& rkD3DPP=ms_d3dPresentParameter; + if (rkD3DPP.Windowed) { - delete m_pStateManager; - m_pStateManager = NULL; + if (rkD3DPP.BackBufferWidth!=uWidth || rkD3DPP.BackBufferHeight!=uHeight) + { + rkD3DPP.BackBufferWidth=uWidth; + rkD3DPP.BackBufferHeight=uHeight; + + IDirect3DDevice8& rkD3DDev=*ms_lpd3dDevice; + + HRESULT hr=rkD3DDev.Reset(&rkD3DPP); + if (FAILED(hr)) + { + return false; + } + + STATEMANAGER.SetDefaultState(); + } } - __Initialize(); + return true; +} + +DWORD CGraphicDevice::CreatePNTStreamVertexShader() +{ + assert(ms_lpd3dDevice != NULL); + + DWORD declVector[] = + { + D3DVSD_STREAM(0), + D3DVSD_REG(0, D3DVSDT_FLOAT3), + D3DVSD_REG(3, D3DVSDT_FLOAT3), + D3DVSD_REG(7, D3DVSDT_FLOAT2), + D3DVSD_END() + }; + + DWORD ret; + + if (FAILED(ms_lpd3dDevice->CreateVertexShader(&declVector[0], NULL, &ret, 0))) + return 0; + + return ret; +} + +DWORD CGraphicDevice::CreatePNT2StreamVertexShader() +{ + assert(ms_lpd3dDevice != NULL); + + DWORD declVector[] = + { + D3DVSD_STREAM(0), + D3DVSD_REG(0, D3DVSDT_FLOAT3), + D3DVSD_REG(3, D3DVSDT_FLOAT3), + D3DVSD_REG(7, D3DVSDT_FLOAT2), + D3DVSD_REG(D3DVSDE_TEXCOORD1, D3DVSDT_FLOAT2), +// D3DVSD_STREAM(1), + D3DVSD_END() + }; + + DWORD ret; + + if (FAILED(ms_lpd3dDevice->CreateVertexShader(&declVector[0], NULL, &ret, 0))) + return 0; + + return ret; +} + +DWORD CGraphicDevice::CreatePTStreamVertexShader() +{ + assert(ms_lpd3dDevice != NULL); + + DWORD declVector[] = + { + D3DVSD_STREAM(0), + D3DVSD_REG(0, D3DVSDT_FLOAT3), + D3DVSD_STREAM(1), + D3DVSD_REG(7, D3DVSDT_FLOAT2), + D3DVSD_END() + }; + + DWORD ret; + + if (FAILED(ms_lpd3dDevice->CreateVertexShader(&declVector[0], NULL, &ret, 0))) + return 0; + + return (ret); +} + +DWORD CGraphicDevice::CreateDoublePNTStreamVertexShader() +{ + assert(ms_lpd3dDevice != NULL); + + DWORD declVector[] = + { + D3DVSD_STREAM(0), + D3DVSD_REG(0, D3DVSDT_FLOAT3), + D3DVSD_REG(3, D3DVSDT_FLOAT3), + D3DVSD_REG(7, D3DVSDT_FLOAT2), + D3DVSD_STREAM(1), + D3DVSD_REG(D3DVSDE_POSITION2, D3DVSDT_FLOAT3), + D3DVSD_REG(D3DVSDE_NORMAL2, D3DVSDT_FLOAT3), + D3DVSD_REG(D3DVSDE_TEXCOORD1, D3DVSDT_FLOAT2), + D3DVSD_END() + }; + + DWORD ret; + + if (FAILED(ms_lpd3dDevice->CreateVertexShader(&declVector[0], NULL, &ret, 0))) + return 0; + + return ret; +} + +CGraphicDevice::EDeviceState CGraphicDevice::GetDeviceState() +{ + if (!ms_lpd3dDevice) + return DEVICESTATE_NULL; + + HRESULT hr; + + if (FAILED(hr = ms_lpd3dDevice->TestCooperativeLevel())) + { + if (D3DERR_DEVICELOST == hr) + return DEVICESTATE_BROKEN; + + if (D3DERR_DEVICENOTRESET == hr) + return DEVICESTATE_NEEDS_RESET; + + return DEVICESTATE_BROKEN; + } + + return DEVICESTATE_OK; +} + +bool CGraphicDevice::Reset() +{ + HRESULT hr; + + if (FAILED(hr = ms_lpd3dDevice->Reset(&ms_d3dPresentParameter))) + return false; + + return true; +} + +static LPDIRECT3DSURFACE8 s_lpStencil; +static DWORD s_MaxTextureWidth, s_MaxTextureHeight; + +BOOL EL3D_ConfirmDevice(D3DCAPS8& rkD3DCaps, UINT uBehavior, D3DFORMAT /*eD3DFmt*/) +{ + // PUREDEVICE는 GetTransform / GetViewport 등이 되지 않는다. + if (uBehavior & D3DCREATE_PUREDEVICE) + return FALSE; + + if (uBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING) + { + // DirectionalLight + if (!(rkD3DCaps.VertexProcessingCaps & D3DVTXPCAPS_DIRECTIONALLIGHTS)) + return FALSE; + + // PositionalLight + if (!(rkD3DCaps.VertexProcessingCaps & D3DVTXPCAPS_POSITIONALLIGHTS)) + return FALSE; + + // Software T&L Support - ATI NOT SUPPORT CLIP, USE DIRECTX SOFTWARE PROCESSING CLIPPING + if (GRAPHICS_CAPS_SOFTWARE_TILING) + { + if (!(rkD3DCaps.PrimitiveMiscCaps & D3DPMISCCAPS_CLIPTLVERTS)) + return FALSE; + } + else + { + // Shadow/Terrain + if (!(rkD3DCaps.VertexProcessingCaps & D3DVTXPCAPS_TEXGEN)) + return FALSE; + } + } + + s_MaxTextureWidth = rkD3DCaps.MaxTextureWidth; + s_MaxTextureHeight = rkD3DCaps.MaxTextureHeight; + + return TRUE; +} + +DWORD GetMaxTextureWidth() +{ + return s_MaxTextureWidth; +} + +DWORD GetMaxTextureHeight() +{ + return s_MaxTextureHeight; +} + +bool CGraphicDevice::__IsInDriverBlackList(D3D_CAdapterInfo& rkD3DAdapterInfo) +{ + D3DADAPTER_IDENTIFIER8& rkD3DAdapterIdentifier=rkD3DAdapterInfo.GetIdentifier(); + + char szSrcDriver[256]; + strncpy(szSrcDriver, rkD3DAdapterIdentifier.Driver, sizeof(szSrcDriver)-1); + DWORD dwSrcHighVersion=rkD3DAdapterIdentifier.DriverVersion.QuadPart>>32; + DWORD dwSrcLowVersion=rkD3DAdapterIdentifier.DriverVersion.QuadPart&0xffffffff; + + bool ret=false; + + FILE* fp=fopen("grpblk.txt", "r"); + if (fp) + { + DWORD dwChkHighVersion; + DWORD dwChkLowVersion; + + char szChkDriver[256]; + + char szLine[256]; + while (fgets(szLine, sizeof(szLine)-1, fp)) + { + sscanf(szLine, "%s %x %x", szChkDriver, &dwChkHighVersion, &dwChkLowVersion); + + if (strcmp(szSrcDriver, szChkDriver)==0) + if (dwSrcHighVersion==dwChkHighVersion) + if (dwSrcLowVersion==dwChkLowVersion) + { + ret=true; + break; + } + + szLine[0]='\0'; + } + fclose(fp); + } + + return ret; } int CGraphicDevice::Create(HWND hWnd, int iHres, int iVres, bool Windowed, int /*iBit*/, int iReflashRate) @@ -67,14 +358,29 @@ int CGraphicDevice::Create(HWND hWnd, int iHres, int iVres, bool Windowed, int / ms_iWidth = iHres; ms_iHeight = iVres; - // PORT: in place of Direct3DCreate8, the display-mode detection and CreateDevice: the recording - // device renders through Godot, which supports DXT and has no refresh-rate or T&L failures. ms_hWnd = hWnd; + // PORT: in place of GetDC, Direct3DCreate8, the D3D_CDisplayModeAutoDetector adapter/mode search, the + // driver black list, CreateDevice with its refresh-rate retry, the DXT format checks and the full-screen + // SetWindowPos: the recording device (RecordingDevice.h) renders through the host, which owns the window + // and supports DXT and hardware T&L at any refresh rate. ms_lpd3dDevice = MtCreateRecordingDevice(iHres, iVres); + + ZeroMemory(&ms_d3dPresentParameter, sizeof(ms_d3dPresentParameter)); + + ms_d3dPresentParameter.Windowed = Windowed; + ms_d3dPresentParameter.BackBufferWidth = iHres; + ms_d3dPresentParameter.BackBufferHeight = iVres; + ms_d3dPresentParameter.hDeviceWindow = hWnd; + ms_d3dPresentParameter.BackBufferCount = m_uBackBufferCount; + ms_d3dPresentParameter.SwapEffect = D3DSWAPEFFECT_DISCARD; + + if (!Windowed) + ms_d3dPresentParameter.FullScreen_RefreshRateInHz = iReflashRate; + + ms_d3dPresentParameter.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; + ms_d3dPresentParameter.EnableAutoDepthStencil = TRUE; + ms_dwD3DBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING; - ms_d3dPresentParameter.BackBufferWidth = iHres; - ms_d3dPresentParameter.BackBufferHeight = iVres; - ms_d3dPresentParameter.Windowed = Windowed; if (FAILED((ms_hLastResult = ms_lpd3dDevice->GetDeviceCaps(&ms_d3dCaps)))) { @@ -82,6 +388,10 @@ int CGraphicDevice::Create(HWND hWnd, int iHres, int iVres, bool Windowed, int / return CREATE_GET_DEVICE_CAPS2; } + // PORT: the detector runs EL3D_ConfirmDevice on each device's caps; here on the one device (max texture size). + if (!EL3D_ConfirmDevice(ms_d3dCaps, ms_dwD3DBehavior, ms_d3dPresentParameter.BackBufferFormat)) + return CREATE_DETECT; + ms_lpd3dDevice->GetViewport(&ms_Viewport); m_pStateManager = new CStateManager(ms_lpd3dDevice); @@ -98,8 +408,6 @@ int CGraphicDevice::Create(HWND hWnd, int iHres, int iVres, bool Windowed, int / D3DXMatrixIdentity(&ms_matProj); D3DXMatrixIdentity(&ms_matInverseView); D3DXMatrixIdentity(&ms_matInverseViewYAxis); - D3DXMatrixIdentity(&ms_matWorld); - D3DXMatrixIdentity(&ms_matWorldView); D3DXMatrixIdentity(&ms_matScreen0); D3DXMatrixIdentity(&ms_matScreen1); D3DXMatrixIdentity(&ms_matScreen2); @@ -112,8 +420,10 @@ int CGraphicDevice::Create(HWND hWnd, int iHres, int iVres, bool Windowed, int / ms_matScreen2._11 = (float) iHres / 2; ms_matScreen2._22 = (float) iVres / 2; + + // PORT: no D3DXCreateSphere/D3DXCreateCylinder; ms_lpSphereMesh/ms_lpCylinderMesh stay NULL (debug collision rendering). - // PORT: no D3DXCreateSphere/D3DXCreateCylinder (debug collision rendering) and no Clear. + ms_lpd3dDevice->Clear(0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff000000, 1.0f, 0); if (!__CreateDefaultIndexBufferList()) return false; @@ -138,81 +448,46 @@ int CGraphicDevice::Create(HWND hWnd, int iHres, int iVres, bool Windowed, int / else GRAPHICS_CAPS_CAN_NOT_TEXTURE_ADDRESS_BORDER=true; - // PORT: the SIS/3dfx driver checks have no adapter identifier to test. + // PORT: the SIS/3dfx driver caps have no adapter identifier to test. + return (iRet); } -auto CGraphicDevice::GetDeviceState() -> EDeviceState +void CGraphicDevice::__InitializePDTVertexBufferList() { - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); + for (UINT i=0; iRelease(); + ms_alpd3dPDTVB[i]=NULL; + } + } } -auto CGraphicDevice::Reset() -> bool +bool CGraphicDevice::__CreatePDTVertexBufferList() { - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CGraphicDevice::EnableWebBrowserMode(const RECT &) -> void -{ - MT_PLATFORM_STUB(); -} - -auto CGraphicDevice::DisableWebBrowserMode() -> void -{ - MT_PLATFORM_STUB(); -} - -auto CGraphicDevice::MoveWebBrowserRect(const RECT &) -> void -{ - MT_PLATFORM_STUB(); -} - -auto CGraphicDevice::ResizeBackBuffer(UINT uWidth, UINT uHeight) -> bool -{ - ms_iWidth = uWidth; - ms_iHeight = uHeight; - ms_d3dPresentParameter.BackBufferWidth = uWidth; - ms_d3dPresentParameter.BackBufferHeight = uHeight; + for (UINT i=0; iCreateVertexBuffer( + sizeof(TPDTVertex)*PDT_VERTEX_NUM, + D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, + D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1, + D3DPOOL_SYSTEMMEM, + &ms_alpd3dPDTVB[i]) + )) + return false; + } return true; } -auto CGraphicDevice::RegisterWarningString(UINT, const char *) -> void -{ - MT_PLATFORM_STUB(); -} - -void CGraphicDevice::__Initialize() -{ - ms_iD3DAdapterInfo=D3DADAPTER_DEFAULT; - ms_iD3DDevInfo=D3DADAPTER_DEFAULT; - ms_iD3DModeInfo=D3DADAPTER_DEFAULT; - - ms_lpd3d = NULL; - ms_lpd3dDevice = NULL; - ms_lpd3dMatStack = NULL; - - ms_dwWavingEndTime = 0; - ms_dwFlashingEndTime = 0; - - m_pStateManager = NULL; - - __InitializeDefaultIndexBufferList(); - __InitializePDTVertexBufferList(); -} - -auto CGraphicDevice::__IsInDriverBlackList(D3D_CAdapterInfo &) -> bool -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CGraphicDevice::__WarningMessage(HWND, UINT) -> void -{ - MT_PLATFORM_STUB(); -} - void CGraphicDevice::__InitializeDefaultIndexBufferList() { for (UINT i=0; iRelease(); ms_alpd3dDefIB[i]=NULL; } } +bool CGraphicDevice::__CreateDefaultIndexBuffer(UINT eDefIB, UINT uIdxCount, const WORD* c_awIndices) +{ + assert(ms_alpd3dDefIB[eDefIB]==NULL); + + if (FAILED( + ms_lpd3dDevice->CreateIndexBuffer( + sizeof(WORD)*uIdxCount, + D3DUSAGE_WRITEONLY, + D3DFMT_INDEX16, + D3DPOOL_MANAGED, + &ms_alpd3dDefIB[eDefIB]) + )) return false; + + WORD* dstIndices; + if (FAILED( + ms_alpd3dDefIB[eDefIB]->Lock(0, 0, (BYTE**)&dstIndices, 0) + )) return false; + + memcpy(dstIndices, c_awIndices, sizeof(WORD)*uIdxCount); + + ms_alpd3dDefIB[eDefIB]->Unlock(); + + return true; +} + bool CGraphicDevice::__CreateDefaultIndexBufferList() { static const WORD c_awLineIndices[2] = { 0, 1, }; @@ -268,96 +568,52 @@ bool CGraphicDevice::__CreateDefaultIndexBufferList() return true; } -bool CGraphicDevice::__CreateDefaultIndexBuffer(UINT eDefIB, UINT uIdxCount, const WORD* c_awIndices) +void CGraphicDevice::InitBackBufferCount(UINT uBackBufferCount) { - assert(ms_alpd3dDefIB[eDefIB]==NULL); - - // PORT: a CPU buffer in place of CreateIndexBuffer (CpuBuffer.h). - MtCpuIndexBuffer* pIB = new MtCpuIndexBuffer; - pIB->bytes.resize(sizeof(WORD)*uIdxCount); - pIB->format = D3DFMT_INDEX16; - ms_alpd3dDefIB[eDefIB] = pIB; - - WORD* dstIndices; - if (FAILED( - ms_alpd3dDefIB[eDefIB]->Lock(0, 0, (BYTE**)&dstIndices, 0) - )) return false; - - memcpy(dstIndices, c_awIndices, sizeof(WORD)*uIdxCount); - - ms_alpd3dDefIB[eDefIB]->Unlock(); - - return true; + m_uBackBufferCount=uBackBufferCount; } -void CGraphicDevice::__InitializePDTVertexBufferList() +void CGraphicDevice::Destroy() { - for (UINT i=0; iDeleteVertexShader(ms_ptVS); + ms_ptVS = 0;; + } + + if (ms_pntVS) + { + ms_lpd3dDevice->DeleteVertexShader(ms_pntVS); + ms_pntVS = 0; + } + + if (ms_pnt2VS) + { + ms_lpd3dDevice->DeleteVertexShader(ms_pnt2VS); + ms_pnt2VS = 0; + } + + safe_release(ms_lpSphereMesh); + safe_release(ms_lpCylinderMesh); + + safe_release(ms_lpd3dMatStack); + safe_release(ms_lpd3dDevice); + safe_release(ms_lpd3d); + + if (m_pStateManager) { - // PORT: a CPU buffer in place of CreateVertexBuffer (CpuBuffer.h). - MtCpuVertexBuffer* pVB = new MtCpuVertexBuffer; - pVB->bytes.resize(sizeof(TPDTVertex)*PDT_VERTEX_NUM); - pVB->fvf = D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1; - ms_alpd3dPDTVB[i] = pVB; + delete m_pStateManager; + m_pStateManager = NULL; } - return true; -} -// PORT: the stream vertex shaders are declarations for the fixed-function pipeline; the recording -// device decodes vertices by FVF, so each returns the FVF matching its declaration. PT keeps its -// texture coordinates in stream 1, which the device does not record: stream 0 is position only. -DWORD CGraphicDevice::CreatePTStreamVertexShader() -{ - assert(ms_lpd3dDevice != NULL); - return D3DFVF_XYZ; -} - -DWORD CGraphicDevice::CreatePNTStreamVertexShader() -{ - assert(ms_lpd3dDevice != NULL); - return D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1; -} - -DWORD CGraphicDevice::CreatePNT2StreamVertexShader() -{ - assert(ms_lpd3dDevice != NULL); - return D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2; -} - -auto CGraphicDevice::CreateDoublePNTStreamVertexShader() -> DWORD -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -// 40250 GrpDevice.cpp:298-306; s_MaxTextureWidth/Height come from D3DCAPS8 in __CheckD3DCaps. -// PORT: 4096 is the texture size every Godot renderer on the target GPUs supports. -static DWORD s_MaxTextureWidth = 4096, s_MaxTextureHeight = 4096; - -DWORD GetMaxTextureWidth() -{ - return s_MaxTextureWidth; -} - -DWORD GetMaxTextureHeight() -{ - return s_MaxTextureHeight; + __Initialize(); } diff --git a/src/platform/EterLib/GrpScreen.cpp b/src/platform/EterLib/GrpScreen.cpp index a59f1c32..8a8f4c0e 100644 --- a/src/platform/EterLib/GrpScreen.cpp +++ b/src/platform/EterLib/GrpScreen.cpp @@ -727,10 +727,8 @@ void CScreen::End() STATEMANAGER.EndScene(); } -// PORT: 40250 declares these extern (UserInterface, the in-game web page); PythonApplicationWebPage is -// DIVERGENT here, so the page is never open and Show presents the whole back buffer. -static const bool g_isBrowserMode = false; -static RECT g_rcBrowser = {}; +extern bool g_isBrowserMode; +extern RECT g_rcBrowser; void CScreen::Show(HWND hWnd) { diff --git a/src/platform/EterLib/RecordingDevice.cpp b/src/platform/EterLib/RecordingDevice.cpp index f6c67782..e0e18d90 100644 --- a/src/platform/EterLib/RecordingDevice.cpp +++ b/src/platform/EterLib/RecordingDevice.cpp @@ -299,6 +299,7 @@ public: caps->DevCaps = D3DDEVCAPS_HWTRANSFORMANDLIGHT; caps->VertexShaderVersion = D3DVS_VERSION(1, 1); caps->PrimitiveMiscCaps = D3DPMISCCAPS_CLIPTLVERTS; + caps->VertexProcessingCaps = D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_DIRECTIONALLIGHTS | D3DVTXPCAPS_POSITIONALLIGHTS; caps->MaxActiveLights = 8; caps->MaxTextureBlendStages = 4; caps->MaxSimultaneousTextures = 4; @@ -515,12 +516,38 @@ public: return S_OK; } HRESULT SetPixelShader(DWORD) override { return S_OK; } - // PORT: no programmable vertex shaders; 40250 falls back to its FVF when creation fails. - HRESULT CreateVertexShader(const DWORD*, const DWORD*, DWORD* pHandle, DWORD) override + // PORT: no programmable vertex shaders (a pFunction fails; 40250 falls back to its FVF). A declaration + // alone describes fixed-function input, so its handle is the FVF of stream 0 (the vertices the device + // records): CGraphicDevice's PT/PNT/PNT2 stream shaders. + HRESULT CreateVertexShader(const DWORD* pDeclaration, const DWORD* pFunction, DWORD* pHandle, DWORD) override { if (pHandle) *pHandle = 0; - return E_FAIL; + if (pFunction || !pDeclaration || !pHandle) + return E_FAIL; + DWORD fvf = 0, texCount = 0, stream = 0; + for (const DWORD* token = pDeclaration; *token != D3DVSD_END(); ++token) + { + const DWORD type = (*token & D3DVSD_TOKENTYPEMASK) >> D3DVSD_TOKENTYPESHIFT; + if (type == D3DVSD_TOKEN_STREAM) + stream = *token & 0xF; + else if (type == D3DVSD_TOKEN_STREAMDATA && stream == 0) + { + const DWORD reg = *token & 0x1F; + if (reg == D3DVSDE_POSITION) + fvf |= D3DFVF_XYZ; + else if (reg == D3DVSDE_NORMAL) + fvf |= D3DFVF_NORMAL; + else if (reg == D3DVSDE_DIFFUSE) + fvf |= D3DFVF_DIFFUSE; + else if (reg >= D3DVSDE_TEXCOORD0 && reg <= D3DVSDE_TEXCOORD3) + texCount = std::max(texCount, reg - D3DVSDE_TEXCOORD0 + 1); + else + return E_FAIL; + } + } + *pHandle = fvf | (texCount << D3DFVF_TEXCOUNT_SHIFT); + return S_OK; } HRESULT DeleteVertexShader(DWORD) override { return S_OK; } HRESULT SetVertexShaderConstant(DWORD, const void*, DWORD) override { return S_OK; } diff --git a/src/port/common/D3D8Types.h b/src/port/common/D3D8Types.h index ee08c2ab..fd8bca1b 100644 --- a/src/port/common/D3D8Types.h +++ b/src/port/common/D3D8Types.h @@ -548,6 +548,8 @@ typedef enum _D3DVSD_TOKENTYPE #define D3DVSDE_TEXCOORD1 8 #define D3DVSDE_TEXCOORD2 9 #define D3DVSDE_TEXCOORD3 10 +#define D3DVSDE_POSITION2 11 +#define D3DVSDE_NORMAL2 12 #define D3DFVF_TEXTUREFORMAT2 0 #define D3DFVF_TEXTUREFORMAT1 3 @@ -708,11 +710,17 @@ typedef struct _D3DGAMMARAMP #define D3DPTADDRESSCAPS_BORDER 0x00000008L #define D3DADAPTER_DEFAULT 0 +#define D3DCREATE_PUREDEVICE 0x00000010L #define D3DCREATE_SOFTWARE_VERTEXPROCESSING 0x00000020L #define D3DCREATE_HARDWARE_VERTEXPROCESSING 0x00000040L #define D3DCREATE_MIXED_VERTEXPROCESSING 0x00000080L #define D3DVS_VERSION(_Major, _Minor) (0xFFFE0000 | ((_Major) << 8) | (_Minor)) #define D3DPMISCCAPS_CLIPTLVERTS 0x00000200L +#define D3DVTXPCAPS_TEXGEN 0x00000001L +#define D3DVTXPCAPS_DIRECTIONALLIGHTS 0x00000008L +#define D3DVTXPCAPS_POSITIONALLIGHTS 0x00000010L +#define D3DPRESENTFLAG_LOCKABLE_BACKBUFFER 0x00000001 +#define D3DPRESENT_INTERVAL_IMMEDIATE 0x80000000L // COM interfaces: platform/ owns every instance. The resource hierarchy is kept so the implicit // upcasts 40250 relies on (texture -> base texture) compile; of the resources only the buffers carry @@ -721,6 +729,7 @@ typedef struct _D3DGAMMARAMP struct IDirect3D8 { virtual ~IDirect3D8() = default; + virtual ULONG Release() { return 0; } virtual HRESULT GetAdapterIdentifier(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER8* pIdentifier) = 0; virtual HRESULT GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode) = 0; virtual UINT GetAdapterModeCount(UINT Adapter) = 0; diff --git a/src/port/common/Win32Crt.h b/src/port/common/Win32Crt.h index d1501aaf..a61747db 100644 --- a/src/port/common/Win32Crt.h +++ b/src/port/common/Win32Crt.h @@ -100,8 +100,11 @@ uintptr_t _beginthreadex(void* security, unsigned stack_size, unsigned (*start_a #define MB_OK 0x00000000L #define MB_ICONHAND 0x00000010L #define MB_ICONSTOP MB_ICONHAND +#define MB_TOPMOST 0x00040000L #define IDOK 1 int MessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType); +// user32 ReleaseDC: the host owns the window and hands out no DC, so there is none to release. +inline int ReleaseDC(HWND, HDC) { return 1; } // winmm `timeGetTime`: milliseconds since system start, wrapping at 2^32. DWORD timeGetTime(); diff --git a/tests/port/port_app_loop_test.cpp b/tests/port/port_app_loop_test.cpp index 79bead34..eafddf9e 100644 --- a/tests/port/port_app_loop_test.cpp +++ b/tests/port/port_app_loop_test.cpp @@ -23,6 +23,7 @@ #include "../../src/platform/EterLib/RenderCommands3D.h" #include "EterLib/GrpScreen.h" #include "EterLib/StateManager.h" +#include "EterLib/Util.h" #include "EterPythonLib/PythonGraphic.h" #include // DIK_ESCAPE @@ -33,6 +34,14 @@ #include +// CGraphicDevice::Create's stream "shaders" (CGraphicBase statics). +struct GraphicBaseAccess : CGraphicBase +{ + static DWORD PT() { return ms_ptVS; } + static DWORD PNT() { return ms_pntVS; } + static DWORD PNT2() { return ms_pnt2VS; } +}; + static int g_failures = 0; #define CHECK(cond) \ do { \ @@ -294,6 +303,12 @@ int main(int argc, char** argv) // CScreen's 3D primitives (40250 GrpScreen.cpp, verbatim) go through the device's dynamic PDT stream: // under a perspective projection RenderLine3d is one line-list draw, RenderBar3d a two-triangle strip, // both in the current diffuse colour. The device is lost-free (TestCooperativeLevel is D3D_OK). + // CGraphicDevice::Create (app.Create): the stream vertex shader declarations become the stream-0 FVFs + // the recording device decodes, and EL3D_ConfirmDevice took the max texture size from the caps. + CHECK(GraphicBaseAccess::PT() == D3DFVF_XYZ); + CHECK(GraphicBaseAccess::PNT() == (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)); + CHECK(GraphicBaseAccess::PNT2() == (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX2)); + CHECK(GetMaxTextureWidth() == 4096 && GetMaxTextureHeight() == 4096); { CScreen screen; CHECK(!screen.IsLostDevice() && screen.RestoreDevice());