394 lines
9.3 KiB
C++
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;
|
|
}
|