Fix keymap.
[vuplus_xbmc] / xbmc / guilib / D3DResource.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "system.h"
22 #include "D3DResource.h"
23 #include "windowing/WindowingFactory.h"
24 #include "utils/log.h"
25
26 #ifdef HAS_DX
27
28 using namespace std;
29
30 CD3DTexture::CD3DTexture()
31 {
32   m_width = 0;
33   m_height = 0;
34   m_mipLevels = 0;
35   m_usage = 0;
36   m_format = D3DFMT_A8R8G8B8;
37   m_pool = D3DPOOL_DEFAULT;
38   m_texture = NULL;
39   m_data = NULL;
40   m_pitch = 0;
41 }
42
43 CD3DTexture::~CD3DTexture()
44 {
45   Release();
46   delete[] m_data;
47 }
48
49 bool CD3DTexture::Create(UINT width, UINT height, UINT mipLevels, DWORD usage, D3DFORMAT format, D3DPOOL pool)
50 {
51   m_width = width;
52   m_height = height;
53   m_mipLevels = mipLevels;
54   m_usage = usage;
55   m_format = format;
56   m_pool = pool;
57   // create the texture
58   Release();
59   HRESULT hr = D3DXCreateTexture(g_Windowing.Get3DDevice(), m_width, m_height, m_mipLevels, m_usage, m_format, m_pool, &m_texture);
60   if (FAILED(hr))
61   {
62     CLog::Log(LOGERROR, __FUNCTION__" - failed 0x%08X", hr);
63   }
64   else
65   {
66     D3DSURFACE_DESC desc;
67     if( D3D_OK == m_texture->GetLevelDesc(0, &desc))
68     {
69       if(desc.Format != m_format)
70         CLog::Log(LOGWARNING, "CD3DTexture::Create - format changed from %d to %d", m_format, desc.Format);
71       if(desc.Height != m_height || desc.Width != m_width)
72         CLog::Log(LOGWARNING, "CD3DTexture::Create - size changed from %ux%u to %ux%u", m_width, m_height, desc.Width, desc.Height);
73     }
74
75     g_Windowing.Register(this);
76     return true;
77   }
78   return false;
79 }
80
81 void CD3DTexture::Release()
82 {
83   g_Windowing.Unregister(this);
84   SAFE_RELEASE(m_texture);
85 }
86
87 bool CD3DTexture::LockRect(UINT level, D3DLOCKED_RECT *lr, const RECT *rect, DWORD flags)
88 {
89   if (m_texture)
90   {
91     if ((flags & D3DLOCK_DISCARD) && !(m_usage & D3DUSAGE_DYNAMIC))
92       flags &= ~D3DLOCK_DISCARD;
93     return (D3D_OK == m_texture->LockRect(level, lr, rect, flags));
94   }
95   return false;
96 }
97
98 bool CD3DTexture::UnlockRect(UINT level)
99 {
100   if (m_texture)
101     return (D3D_OK == m_texture->UnlockRect(level));
102   return false;
103 }
104
105 bool CD3DTexture::GetLevelDesc(UINT level, D3DSURFACE_DESC *desc)
106 {
107   if (m_texture)
108     return (D3D_OK == m_texture->GetLevelDesc(level, desc));
109   return false;
110 }
111
112 bool CD3DTexture::GetSurfaceLevel(UINT level, LPDIRECT3DSURFACE9 *surface)
113 {
114   if (m_texture)
115     return (D3D_OK == m_texture->GetSurfaceLevel(level, surface));
116   return false;
117 }
118
119 void CD3DTexture::SaveTexture()
120 {
121   if (m_texture)
122   {
123     delete[] m_data;
124     m_data = NULL;
125     if(!(m_usage & D3DUSAGE_RENDERTARGET)
126     && !(m_usage & D3DUSAGE_DEPTHSTENCIL)
127     && !(m_pool == D3DPOOL_DEFAULT && (m_usage & D3DUSAGE_DYNAMIC) == 0))
128     {
129       D3DLOCKED_RECT lr;
130       if (LockRect( 0, &lr, NULL, D3DLOCK_READONLY ))
131       {
132         m_pitch = lr.Pitch;
133         unsigned int memUsage = GetMemoryUsage(lr.Pitch);
134         m_data = new unsigned char[memUsage];
135         memcpy(m_data, lr.pBits, memUsage);
136         UnlockRect(0);
137       }
138     }
139   }
140   SAFE_RELEASE(m_texture);
141 }
142
143 void CD3DTexture::OnDestroyDevice()
144 {
145   SaveTexture();
146 }
147
148 void CD3DTexture::OnLostDevice()
149 {
150   if (m_pool == D3DPOOL_DEFAULT)
151     SaveTexture();
152 }
153
154 void CD3DTexture::RestoreTexture()
155 {
156   // yay, we're back - make a new copy of the texture
157   if (!m_texture)
158   {
159     HRESULT hr = D3DXCreateTexture(g_Windowing.Get3DDevice(), m_width, m_height, m_mipLevels, m_usage, m_format, m_pool, &m_texture);
160     if (FAILED(hr))
161     {
162       CLog::Log(LOGERROR, __FUNCTION__": D3DXCreateTexture failed 0x%08X", hr);
163     }
164     else
165     {
166       // copy the data to the texture
167       D3DLOCKED_RECT lr;
168       if (m_texture && m_data && LockRect(0, &lr, NULL, D3DLOCK_DISCARD ))
169       {
170         if (lr.Pitch == m_pitch)
171           memcpy(lr.pBits, m_data, GetMemoryUsage(lr.Pitch));
172         else
173         {
174           UINT minpitch = ((UINT)lr.Pitch < m_pitch) ? lr.Pitch : m_pitch;
175         
176           for(UINT i = 0; i < m_height; ++i)
177           {
178             // Get pointers to the "rows" of pixels in texture
179             BYTE* pBits = (BYTE*)lr.pBits + i*lr.Pitch;
180             BYTE* pData = m_data + i*m_pitch;
181             memcpy(pBits, pData, minpitch);
182           }
183         }
184         UnlockRect(0);
185       }
186     }
187
188     delete[] m_data;
189     m_data = NULL;
190     m_pitch = 0;
191   }
192 }
193
194 void CD3DTexture::OnCreateDevice()
195 {
196   RestoreTexture();
197 }
198
199 void CD3DTexture::OnResetDevice()
200 {
201   if (m_pool == D3DPOOL_DEFAULT)
202     RestoreTexture();
203 }
204
205
206 unsigned int CD3DTexture::GetMemoryUsage(unsigned int pitch) const
207 {
208   switch (m_format)
209   {
210   case D3DFMT_DXT1:
211   case D3DFMT_DXT3:
212   case D3DFMT_DXT5:
213     return pitch * m_height / 4;
214   default:
215     return pitch * m_height;
216   }
217 }
218
219 CD3DEffect::CD3DEffect()
220 {
221   m_effect = NULL;
222 }
223
224 CD3DEffect::~CD3DEffect()
225 {
226   Release();
227 }
228
229 bool CD3DEffect::Create(const CStdString &effectString, DefinesMap* defines)
230 {
231   Release();
232   m_effectString = effectString;
233   m_defines.clear();
234   if (defines != NULL)
235     m_defines = *defines; //FIXME: is this a copy of all members?
236   if (CreateEffect())
237   {
238     g_Windowing.Register(this);
239     return true;
240   }
241   return false;
242 }
243
244 void CD3DEffect::Release()
245 {
246   g_Windowing.Unregister(this);
247   SAFE_RELEASE(m_effect);
248 }
249
250 void CD3DEffect::OnDestroyDevice()
251 {
252   SAFE_RELEASE(m_effect);
253 }
254
255 void CD3DEffect::OnCreateDevice()
256 {
257   CreateEffect();
258 }
259
260 bool CD3DEffect::SetFloatArray(D3DXHANDLE handle, const float* val, unsigned int count)
261 {
262   if(m_effect)
263     return (D3D_OK == m_effect->SetFloatArray(handle, val, count));
264   return false;
265 }
266
267 bool CD3DEffect::SetMatrix(D3DXHANDLE handle, const D3DXMATRIX* mat)
268 {
269   if (m_effect)
270     return (D3D_OK == m_effect->SetMatrix(handle, mat));
271   return false;
272 }
273
274 bool CD3DEffect::SetTechnique(D3DXHANDLE handle)
275 {
276   if (m_effect)
277     return (D3D_OK == m_effect->SetTechnique(handle));
278   return false;
279 }
280
281 bool CD3DEffect::SetTexture(D3DXHANDLE handle, CD3DTexture &texture)
282 {
283   if (m_effect)
284     return (D3D_OK == m_effect->SetTexture(handle, texture.Get()));
285   return false;
286 }
287
288 bool CD3DEffect::Begin(UINT *passes, DWORD flags)
289 {
290   if (m_effect)
291     return (D3D_OK == m_effect->Begin(passes, flags));
292   return false;
293 }
294
295 bool CD3DEffect::BeginPass(UINT pass)
296 {
297   if (m_effect)
298     return (D3D_OK == m_effect->BeginPass(pass));
299   return false;
300 }
301
302 bool CD3DEffect::EndPass()
303 {
304   if (m_effect)
305     return (D3D_OK == m_effect->EndPass());
306   return false;
307 }
308
309 bool CD3DEffect::End()
310 {
311   if (m_effect)
312     return (D3D_OK == m_effect->End());
313   return false;
314 }
315
316 bool CD3DEffect::CreateEffect()
317 {
318   HRESULT hr;
319   LPD3DXBUFFER pError = NULL;
320
321   std::vector<D3DXMACRO> definemacros;
322
323   for( DefinesMap::const_iterator it = m_defines.begin(); it != m_defines.end(); ++it )
324         {
325                 D3DXMACRO m;
326                 m.Name = it->first.c_str();
327     if (it->second.empty())
328       m.Definition = NULL;
329     else
330                   m.Definition = it->second.c_str();
331                 definemacros.push_back( m );
332         }
333
334   definemacros.push_back(D3DXMACRO());
335         definemacros.back().Name = 0;
336         definemacros.back().Definition = 0;
337
338   hr = D3DXCreateEffect(g_Windowing.Get3DDevice(),  m_effectString, m_effectString.length(), &definemacros[0], NULL, 0, NULL, &m_effect, &pError );
339   if(hr == S_OK)
340     return true;
341   else if(pError)
342   {
343     CStdString error;
344     error.assign((const char*)pError->GetBufferPointer(), pError->GetBufferSize());
345     CLog::Log(LOGERROR, "CD3DEffect::CreateEffect(): %s", error.c_str());
346   }
347   else
348     CLog::Log(LOGERROR, "CD3DEffect::CreateEffect(): call to D3DXCreateEffect() failed with %" PRId32, hr);
349   return false;
350 }
351
352 void CD3DEffect::OnLostDevice()
353 {
354   if (m_effect)
355     m_effect->OnLostDevice();
356 }
357
358 void CD3DEffect::OnResetDevice()
359 {
360   if (m_effect)
361     m_effect->OnResetDevice();
362 }
363
364 CD3DVertexBuffer::CD3DVertexBuffer()
365 {
366   m_length = 0;
367   m_usage = 0;
368   m_fvf = 0;
369   m_pool = D3DPOOL_DEFAULT;
370   m_vertex = NULL;
371   m_data = NULL;
372 }
373
374 CD3DVertexBuffer::~CD3DVertexBuffer()
375 {
376   Release();
377   delete[] m_data;
378 }
379
380 bool CD3DVertexBuffer::Create(UINT length, DWORD usage, DWORD fvf, D3DPOOL pool)
381 {
382   m_length = length;
383   m_usage = usage;
384   m_fvf = fvf;
385   m_pool = pool;
386
387   // create the vertex buffer
388   Release();
389   if (CreateVertexBuffer())
390   {
391     g_Windowing.Register(this);
392     return true;
393   }
394   return false;
395 }
396
397 void CD3DVertexBuffer::Release()
398 {
399   g_Windowing.Unregister(this);
400   SAFE_RELEASE(m_vertex);
401 }
402
403 bool CD3DVertexBuffer::Lock(UINT level, UINT size, void **data, DWORD flags)
404 {
405   if (m_vertex)
406     return (D3D_OK == m_vertex->Lock(level, size, data, flags));
407   return false;
408 }
409
410 bool CD3DVertexBuffer::Unlock()
411 {
412   if (m_vertex)
413     return (D3D_OK == m_vertex->Unlock());
414   return false;
415 }
416
417 void CD3DVertexBuffer::OnDestroyDevice()
418 {
419   if (m_vertex)
420   {
421     delete[] m_data;
422     m_data = NULL;
423     void* data;
424     if (Lock(0, 0, &data, 0))
425     {
426       m_data = new BYTE[m_length];
427       memcpy(m_data, data, m_length);
428       Unlock();
429     }
430   }
431   SAFE_RELEASE(m_vertex);
432 }
433
434 void CD3DVertexBuffer::OnCreateDevice()
435 {
436   // yay, we're back - make a new copy of the vertices
437   if (!m_vertex && m_data && CreateVertexBuffer())
438   {
439     void *data = NULL;
440     if (Lock(0, 0, &data, 0))
441     {
442       memcpy(data, m_data, m_length);
443       Unlock();
444     }
445     delete[] m_data;
446     m_data = NULL;
447   }
448 }
449
450 bool CD3DVertexBuffer::CreateVertexBuffer()
451 {
452   if (D3D_OK == g_Windowing.Get3DDevice()->CreateVertexBuffer(m_length, m_usage, m_fvf, m_pool, &m_vertex, NULL))
453     return true;
454   return false;
455 }
456
457 #endif