efl/legacy/evas/src/modules/engines/direct3d/evas_direct3d_device.cpp

394 lines
9.3 KiB
C++

//#define ENABLE_LOG_PRINTF
#include "evas_direct3d_device.h"
#include "evas_direct3d_vertex_buffer_cache.h"
D3DDevice::D3DDevice()
{
ResetParams();
}
bool D3DDevice::Init(HWND window, int depth, bool fullscreen)
{
D3DPRESENT_PARAMETERS pp;
D3DDISPLAYMODE dm;
D3DCAPS9 caps;
RECT rect;
DWORD flag;
HRESULT hr;
if (window == NULL)
return false;
Destroy();
_object = Direct3DCreate9(D3D_SDK_VERSION);
if (_object == NULL)
return false;
if (FAILED(hr = _object->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dm)))
{
ERR("GetAdapterDisplayMode failed: %x", hr);
Destroy();
return false;
}
if (FAILED(hr = _object->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps)))
{
ERR("GetDeviceCaps failed: %x", hr);
Destroy();
return false;
}
if (!GetClientRect(window, &rect))
{
ERR("GetClientRect failed: %x", GetLastError());
Destroy();
return false;
}
if (SUCCEEDED(_object->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
dm.Format, 0, D3DRTYPE_TEXTURE, (depth == 16) ? D3DFMT_R5G6B5 : D3DFMT_A8R8G8B8)))
{
dm.Format = (depth == 16) ? D3DFMT_R5G6B5 : D3DFMT_A8R8G8B8;
}
flag = (caps.VertexProcessingCaps != 0) ?
(D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE) :
D3DCREATE_SOFTWARE_VERTEXPROCESSING;
ZeroMemory(&pp, sizeof(pp));
if (!fullscreen)
{
pp.BackBufferWidth = rect.right - rect.left;
pp.BackBufferHeight = rect.bottom - rect.top;
}
else
{
pp.BackBufferWidth = ::GetSystemMetrics(SM_CXSCREEN);
pp.BackBufferHeight = ::GetSystemMetrics(SM_CYSCREEN);
}
pp.BackBufferFormat = dm.Format;
pp.BackBufferCount = 1;
pp.MultiSampleType = D3DMULTISAMPLE_NONE;
pp.MultiSampleQuality = 0;
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
pp.hDeviceWindow = window;
pp.Windowed = fullscreen ? FALSE : TRUE;
//pp.EnableAutoDepthStencil = TRUE;
//pp.AutoDepthStencilFormat = D3DFMT_D16;
pp.FullScreen_RefreshRateInHz = 0;
pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
if (FAILED(hr = _object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
window, flag, &pp, &_device)))
{
WRN("CreateDevice failed: %x", hr);
Destroy();
return false;
}
LPDIRECT3DSURFACE9 backbuffer = NULL;
_device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
backbuffer->GetDesc(&_backbuffer_desc);
backbuffer->Release();
switch (dm.Format) {
case D3DFMT_A8R8G8B8:
case D3DFMT_X8R8G8B8:
_depth = 32;
break;
case D3DFMT_R5G6B5:
_depth = 16;
break;
default:
WRN("No supported format found");
Destroy();
return false;
}
//_render_to_texture = false;
_d3dpp = pp;
_device_lost = FALSE;
_scene_rendering = FALSE;
_width = rect.right - rect.left;
_height = rect.bottom - rect.top;
_window = window;
if (FAILED(CreateRenderTarget()))
{
ERR("Failed to create render target");
Destroy();
return false;
}
Log("initialized");
return true;
}
bool D3DDevice::Reset(int width, int height, int fullscreen)
{
D3DPRESENT_PARAMETERS pp = _d3dpp;
_d3dpp.BackBufferWidth = (width > 0) ? width : _d3dpp.BackBufferWidth;
_d3dpp.BackBufferHeight = (height > 0) ? height : _d3dpp.BackBufferHeight;
_d3dpp.Windowed = (fullscreen == 1) ? FALSE : ((fullscreen == 0) ? TRUE : _d3dpp.Windowed);
if (FAILED(ResetDevice()))
{
WRN("Couldnt restore device");
_d3dpp = pp;
return SUCCEEDED(ResetDevice());
}
_width = _d3dpp.BackBufferWidth;
_height = _d3dpp.BackBufferHeight;
return true;
}
void D3DDevice::Destroy()
{
//if (_render_target != NULL)
//{
// _render_target->Release();
// _render_target = NULL;
//}
if (_render_target_data != NULL)
{
_render_target_data->Release();
_render_target_data = NULL;
}
if (_device != NULL)
{
int num = _device->Release();
assert(num == 0);
}
if (_object != NULL)
_object->Release();
ResetParams();
INF("uninitialized");
}
void D3DDevice::ResetParams()
{
_window = NULL;
_object = NULL;
_device = NULL;
_width = 0;
_height = 0;
_rot = 0;
_depth = 0;
_device_lost = false;
_scene_rendering = false;
ZeroMemory(&_d3dpp, sizeof(_d3dpp));
ZeroMemory(&_backbuffer_desc, sizeof(_backbuffer_desc));
//_render_target = NULL;
_render_target_data = NULL;
_render_data_updated = false;
_render_data.Resize();
//_original_render_target = NULL;
//_render_to_texture = false;
}
HRESULT D3DDevice::RestoreDevice()
{
Log("restore");
assert(_device != NULL);
HRESULT hr = S_OK;
// Test the cooperative level to see if it's okay to render
if (SUCCEEDED(hr = _device->TestCooperativeLevel()))
{
_device_lost = FALSE;
DBG("render test ok");
return S_OK;
}
// If the device was lost, do not render until we get it back
if (hr == D3DERR_DEVICELOST)
return E_FAIL;
// Check if the device needs to be reset.
if (hr == D3DERR_DEVICENOTRESET)
{
if (FAILED(hr = ResetDevice()))
return hr;
}
return hr;
}
HRESULT D3DDevice::ResetDevice()
{
DBG("reset");
HRESULT hr = S_OK;
_scene_rendering = FALSE;
// Release all video memory objects
// Bad to call such, make better
D3DVertexBufferCache::Current()->Uninitialize();
//if (_render_target != NULL)
//{
// _render_target->Release();
// _render_target = NULL;
//}
if (_render_target_data != NULL)
{
_render_target_data->Release();
_render_target_data = NULL;
}
// Reset the device
if (FAILED(hr = _device->Reset(&_d3dpp)))
{
ERR("D3DDevice: Reset of the device failed! Error (%X)", (DWORD)hr);
return hr;
}
// Store render target surface desc
LPDIRECT3DSURFACE9 backbuffer = NULL;
_device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
if (backbuffer != NULL)
{
backbuffer->GetDesc(&_backbuffer_desc);
backbuffer->Release();
}
// Initialize the app's device-dependent objects
hr = CreateRenderTarget();
if (FAILED(hr))
{
WRN("Restoration of device objects failed");
// Invalidate objects
return E_FAIL;
}
DBG("Device objects were successfuly restored");
_textures.Set(NULL);
//_device_objects_restored = true;
return S_OK;
}
bool D3DDevice::Begin()
{
if (FAILED(RestoreDevice()))
return false;
//if (_render_to_texture && _render_target != NULL)
//{
// if (FAILED(_device->GetRenderTarget(0, &_original_render_target)))
// return false;
// if (FAILED(_device->SetRenderTarget(0, _render_target)))
// return false;
//}
HRESULT hr;
if (FAILED(hr = _device->BeginScene()))
{
WRN("Cannot begin scene: %X", (DWORD)hr);
return false;
}
//static const D3DVIEWPORT9 vp = {0, 0, _width, _height, 0.f, 1.f};
//_device->SetViewport(&vp);
//_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
//_device->Clear(0, NULL, D3DCLEAR_TARGET /*| D3DCLEAR_ZBUFFER*/, 0xff8080ff, 1.f, 0);
return true;
}
bool D3DDevice::End()
{
_device->EndScene();
_device->Present(NULL, NULL, NULL, NULL);
_render_data_updated = false;
//if (_render_to_texture && _render_target != NULL && _original_render_target != NULL)
//{
// if (FAILED(_device->SetRenderTarget(0, _original_render_target)))
// return false;
//}
return true;
}
TArray<DWORD> &D3DDevice::GetRenderData()
{
if (_render_data_updated)
return _render_data;
_render_data.Allocate(0);
if (_render_target_data == NULL)
return _render_data;
LPDIRECT3DSURFACE9 surf = NULL;
HRESULT hr;
if (FAILED(_device->GetRenderTarget(0, &surf)))
return _render_data;
if (FAILED(hr = _device->GetRenderTargetData(surf, _render_target_data)))
{
WRN("Failed to get render target data (%X)", (DWORD)hr);
surf->Release();
return _render_data;
}
D3DLOCKED_RECT lr;
if (FAILED(_render_target_data->LockRect(&lr, NULL, D3DLOCK_READONLY)))
{
surf->Release();
return _render_data;
}
_render_data.Allocate(_width * _height);
for (int i = 0; i < _height; i++)
{
CopyMemory(&_render_data[i * _width], (BYTE *)lr.pBits + i * lr.Pitch,
_width * sizeof(DWORD));
}
_render_target_data->UnlockRect();
_render_data_updated = true;
surf->Release();
return _render_data;
}
HRESULT D3DDevice::SetTexture(DWORD stage, LPDIRECT3DTEXTURE9 tex)
{
if (stage >= 8)
return E_FAIL;
if (_textures.Length() <= (int)stage)
_textures.Allocate(stage + 1);
if (_textures[stage] != tex)
{
_textures[stage] = tex;
return _device->SetTexture(stage, tex);
}
return S_OK;
}
HRESULT D3DDevice::CreateRenderTarget()
{
if (_device == NULL)
return E_FAIL;
//if (_render_target != NULL &&
if (_render_target_data != NULL)
return S_OK;
//if (FAILED(_device->CreateRenderTarget(_width, _height, _backbuffer_desc.Format,
// D3DMULTISAMPLE_NONE, 0, FALSE, &_render_target, NULL)))
//{
// return E_FAIL;
//}
if (FAILED(_device->CreateOffscreenPlainSurface(_backbuffer_desc.Width,
_backbuffer_desc.Height, _backbuffer_desc.Format, D3DPOOL_SYSTEMMEM,
&_render_target_data, NULL)))
{
return E_FAIL;
}
return S_OK;
}