[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / cores / VideoRenderers / WinRenderer.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.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 #ifdef HAS_DX
22
23 #include "WinRenderer.h"
24 #include "Util.h"
25 #include "settings/Settings.h"
26 #include "settings/GUISettings.h"
27 #include "guilib/Texture.h"
28 #include "windowing/WindowingFactory.h"
29 #include "settings/AdvancedSettings.h"
30 #include "threads/SingleLock.h"
31 #include "utils/log.h"
32 #include "filesystem/File.h"
33 #include "utils/MathUtils.h"
34 #include "VideoShaders/WinVideoFilter.h"
35 #include "DllSwScale.h"
36 #include "guilib/LocalizeStrings.h"
37 #include "dialogs/GUIDialogKaiToast.h"
38 #include "win32/WIN32Util.h"
39 #include "cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h"
40
41 typedef struct {
42   RenderMethod  method;
43   const char   *name;
44 } RenderMethodDetail;
45
46 static RenderMethodDetail RenderMethodDetails[] = {
47     { RENDER_SW     , "Software" },
48     { RENDER_PS     , "Pixel Shaders" },
49     { RENDER_DXVA   , "DXVA" },
50     { RENDER_INVALID, NULL }
51 };
52
53 static RenderMethodDetail *FindRenderMethod(RenderMethod m)
54 {
55   for (unsigned i = 0; RenderMethodDetails[i].method != RENDER_INVALID; i++) {
56     if (RenderMethodDetails[i].method == m)
57       return &RenderMethodDetails[i];
58   }
59   return NULL;
60 }
61
62 CWinRenderer::CWinRenderer()
63 {
64   m_iYV12RenderBuffer = 0;
65   m_NumYV12Buffers = 0;
66
67   m_colorShader = NULL;
68   m_scalerShader = NULL;
69   m_extended_format = 0;
70
71   m_iRequestedMethod = RENDER_METHOD_AUTO;
72
73   m_renderMethod = RENDER_PS;
74   m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
75   m_scalingMethodGui = (ESCALINGMETHOD)-1;
76   m_TextureFilter = D3DTEXF_POINT;
77
78   m_bUseHQScaler = false;
79   m_bFilterInitialized = false;
80
81   for (int i = 0; i<NUM_BUFFERS; i++)
82     m_VideoBuffers[i] = NULL;
83
84   m_sw_scale_ctx = NULL;
85   m_dllSwScale = NULL;
86 }
87
88 CWinRenderer::~CWinRenderer()
89 {
90   UnInit();
91 }
92
93 static enum PixelFormat PixelFormatFromFormat(ERenderFormat format)
94 {
95   if      (format == RENDER_FMT_YUV420P)   return PIX_FMT_YUV420P;
96   else if (format == RENDER_FMT_YUV420P10) return PIX_FMT_YUV420P10;
97   else if (format == RENDER_FMT_YUV420P10) return PIX_FMT_YUV420P16;
98   else if (format == RENDER_FMT_NV12)      return PIX_FMT_NV12;
99   else if (format == RENDER_FMT_UYVY422)   return PIX_FMT_UYVY422;
100   else if (format == RENDER_FMT_YUYV422)   return PIX_FMT_YUYV422;
101   else return PIX_FMT_NONE;
102 }
103
104 void CWinRenderer::ManageTextures()
105 {
106   int neededbuffers = 2;
107
108   if( m_NumYV12Buffers < neededbuffers )
109   {
110     for(int i = m_NumYV12Buffers; i<neededbuffers;i++)
111       CreateYV12Texture(i);
112
113     m_NumYV12Buffers = neededbuffers;
114   }
115   else if( m_NumYV12Buffers > neededbuffers )
116   {
117     m_NumYV12Buffers = neededbuffers;
118     m_iYV12RenderBuffer = m_iYV12RenderBuffer % m_NumYV12Buffers;
119
120     for(int i = m_NumYV12Buffers-1; i>=neededbuffers;i--)
121       DeleteYV12Texture(i);
122   }
123 }
124
125 void CWinRenderer::SelectRenderMethod()
126 {
127   // Set rendering to dxva before trying it, in order to open the correct processor immediately, when deinterlacing method is auto.
128
129   // Force dxva renderer after dxva decoding: PS and SW renderers have performance issues after dxva decode.
130   if (g_advancedSettings.m_DXVAForceProcessorRenderer && m_format == RENDER_FMT_DXVA)
131   {
132     CLog::Log(LOGNOTICE, "D3D: rendering method forced to DXVA2 processor");
133     m_renderMethod = RENDER_DXVA;
134     if (!m_processor.Open(m_sourceWidth, m_sourceHeight, m_iFlags, m_format, m_extended_format))
135     {
136       CLog::Log(LOGNOTICE, "D3D: unable to open DXVA2 processor");
137       m_processor.Close();
138       m_renderMethod = RENDER_INVALID;
139     }
140   }
141   else
142   {
143     CLog::Log(LOGDEBUG, __FUNCTION__": Requested render method: %d", m_iRequestedMethod);
144
145     switch(m_iRequestedMethod)
146     {
147       case RENDER_METHOD_DXVA:
148         m_renderMethod = RENDER_DXVA;
149         if (m_processor.Open(m_sourceWidth, m_sourceHeight, m_iFlags, m_format, m_extended_format))
150             break;
151         else
152         {
153           CLog::Log(LOGNOTICE, "D3D: unable to open DXVA2 processor");
154           m_processor.Close();
155         }
156       // Drop through to pixel shader
157       case RENDER_METHOD_AUTO:
158       case RENDER_METHOD_D3D_PS:
159         // Try the pixel shaders support
160         if (m_deviceCaps.PixelShaderVersion >= D3DPS_VERSION(2, 0))
161         {
162           CTestShader shader;
163           if (shader.Create())
164           {
165             m_renderMethod = RENDER_PS;
166             break;
167           }
168           else
169           {
170             CLog::Log(LOGNOTICE, "D3D: unable to load test shader - D3D installation is most likely incomplete");
171             CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, "DirectX", g_localizeStrings.Get(2101));
172           }
173         }
174         else
175         {
176           CLog::Log(LOGNOTICE, "D3D: graphics adapter does not support Pixel Shaders 2.0");
177         }
178         CLog::Log(LOGNOTICE, "D3D: falling back to SW mode");
179       // drop through to software
180       case RENDER_METHOD_SOFTWARE:
181       default:
182         // So we'll do the color conversion in software.
183         m_renderMethod = RENDER_SW;
184         break;
185     }
186   }
187
188   RenderMethodDetail *rmdet = FindRenderMethod(m_renderMethod);
189   CLog::Log(LOGDEBUG, __FUNCTION__": Selected render method %d: %s", m_renderMethod, rmdet != NULL ? rmdet->name : "unknown");
190 }
191
192 bool CWinRenderer::UpdateRenderMethod()
193 {
194   if (m_SWTarget.Get())
195     m_SWTarget.Release();
196
197   if (m_renderMethod == RENDER_SW)
198   {
199     m_dllSwScale = new DllSwScale();
200
201     if (!m_dllSwScale->Load())
202       CLog::Log(LOGERROR,"CDVDDemuxFFmpeg::Open - failed to load ffmpeg libraries");
203
204     if(!m_SWTarget.Create(m_sourceWidth, m_sourceHeight, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT))
205     {
206       CLog::Log(LOGNOTICE, __FUNCTION__": Failed to create sw render target.");
207       return false;
208     }
209   }
210   return true;
211 }
212
213 bool CWinRenderer::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation)
214 {
215   if(m_sourceWidth  != width
216   || m_sourceHeight != height)
217   {
218     m_sourceWidth       = width;
219     m_sourceHeight      = height;
220     // need to recreate textures
221     m_NumYV12Buffers    = 0;
222     m_iYV12RenderBuffer = 0;
223     // reinitialize the filters/shaders
224     m_bFilterInitialized = false;
225   }
226
227   m_fps = fps;
228   m_iFlags = flags;
229   m_format = format;
230   m_extended_format = extended_format;
231
232   // calculate the input frame aspect ratio
233   CalculateFrameAspectRatio(d_width, d_height);
234   ChooseBestResolution(fps);
235   m_destWidth = g_settings.m_ResInfo[m_resolution].iWidth;
236   m_destHeight = g_settings.m_ResInfo[m_resolution].iHeight;
237   SetViewMode(g_settings.m_currentVideoSettings.m_ViewMode);
238   ManageDisplay();
239
240   m_bConfigured = true;
241
242   SelectRenderMethod();
243   UpdateRenderMethod();
244
245   return true;
246 }
247
248 int CWinRenderer::NextYV12Texture()
249 {
250   if(m_NumYV12Buffers)
251     return (m_iYV12RenderBuffer + 1) % m_NumYV12Buffers;
252   else
253     return -1;
254 }
255
256 bool CWinRenderer::AddVideoPicture(DVDVideoPicture* picture)
257 {
258   if (m_renderMethod == RENDER_DXVA)
259   {
260     int source = NextYV12Texture();
261     if(source < 0)
262       return false;
263
264     DXVABuffer *buf = (DXVABuffer*)m_VideoBuffers[source];
265     buf->id = m_processor.Add(picture);
266     return true;
267   }
268   return false;
269 }
270
271 int CWinRenderer::GetImage(YV12Image *image, int source, bool readonly)
272 {
273   /* take next available buffer */
274   if( source == AUTOSOURCE )
275     source = NextYV12Texture();
276
277   if( source < 0 )
278     return -1;
279
280   YUVBuffer *buf = (YUVBuffer*)m_VideoBuffers[source];
281
282   image->cshift_x = 1;
283   image->cshift_y = 1;
284   image->height = m_sourceHeight;
285   image->width = m_sourceWidth;
286   image->flags = 0;
287   if(m_format == RENDER_FMT_YUV420P10
288   || m_format == RENDER_FMT_YUV420P16)
289     image->bpp = 2;
290   else
291     image->bpp = 1;
292
293   for(int i=0;i<3;i++)
294   {
295     image->stride[i] = buf->planes[i].rect.Pitch;
296     image->plane[i]  = (BYTE*)buf->planes[i].rect.pBits;
297   }
298
299   return source;
300 }
301
302 void CWinRenderer::ReleaseImage(int source, bool preserve)
303 {
304   // no need to release anything here since we're using system memory
305 }
306
307 void CWinRenderer::Reset()
308 {
309 }
310
311 void CWinRenderer::Update(bool bPauseDrawing)
312 {
313   if (!m_bConfigured) return;
314   ManageDisplay();
315 }
316
317 void CWinRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
318 {
319   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
320
321   if (clear)
322     pD3DDevice->Clear( 0L, NULL, D3DCLEAR_TARGET, m_clearColour, 1.0f, 0L );
323
324   if(alpha < 255)
325     pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
326   else
327     pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
328
329   if (!m_bConfigured) return;
330   ManageTextures();
331
332   CSingleLock lock(g_graphicsContext);
333
334   ManageDisplay();
335
336   Render(flags);
337 }
338
339 void CWinRenderer::FlipPage(int source)
340 {
341   if(source == AUTOSOURCE)
342     source = NextYV12Texture();
343
344   if (m_VideoBuffers[m_iYV12RenderBuffer] != NULL)
345     m_VideoBuffers[m_iYV12RenderBuffer]->StartDecode();
346
347   if( source >= 0 && source < m_NumYV12Buffers )
348     m_iYV12RenderBuffer = source;
349   else
350     m_iYV12RenderBuffer = 0;
351
352   if (m_VideoBuffers[m_iYV12RenderBuffer] != NULL)
353     m_VideoBuffers[m_iYV12RenderBuffer]->StartRender();
354
355 #ifdef MP_DIRECTRENDERING
356   __asm wbinvd
357 #endif
358
359   return;
360 }
361
362 unsigned int CWinRenderer::PreInit()
363 {
364   CSingleLock lock(g_graphicsContext);
365   m_bConfigured = false;
366   UnInit();
367   m_resolution = g_guiSettings.m_LookAndFeelResolution;
368   if ( m_resolution == RES_WINDOW )
369     m_resolution = RES_DESKTOP;
370
371   // setup the background colour
372   m_clearColour = (g_advancedSettings.m_videoBlackBarColour & 0xff) * 0x010101;
373
374   g_Windowing.Get3DDevice()->GetDeviceCaps(&m_deviceCaps);
375
376   m_iRequestedMethod = g_guiSettings.GetInt("videoplayer.rendermethod");
377
378   if ((g_advancedSettings.m_DXVAForceProcessorRenderer || m_iRequestedMethod == RENDER_METHOD_DXVA) && !m_processor.PreInit())
379     CLog::Log(LOGNOTICE, "CWinRenderer::Preinit - could not init DXVA2 processor - skipping");
380
381   m_formats.push_back(RENDER_FMT_YUV420P);
382   if(g_Windowing.IsTextureFormatOk(D3DFMT_L16, 0))
383   {
384     m_formats.push_back(RENDER_FMT_YUV420P10);
385     m_formats.push_back(RENDER_FMT_YUV420P16);
386   }
387   m_formats.push_back(RENDER_FMT_NV12);
388   m_formats.push_back(RENDER_FMT_YUYV422);
389   m_formats.push_back(RENDER_FMT_UYVY422);
390
391
392   return 0;
393 }
394
395 void CWinRenderer::UnInit()
396 {
397   CSingleLock lock(g_graphicsContext);
398
399   if (m_SWTarget.Get())
400     m_SWTarget.Release();
401
402   if (m_IntermediateTarget.Get())
403     m_IntermediateTarget.Release();
404
405   SAFE_DELETE(m_colorShader);
406   SAFE_DELETE(m_scalerShader);
407   
408   m_bConfigured = false;
409   m_bFilterInitialized = false;
410
411   for(int i = 0; i < NUM_BUFFERS; i++)
412     DeleteYV12Texture(i);
413
414   m_NumYV12Buffers = 0;
415
416   if (m_sw_scale_ctx)
417   {
418     m_dllSwScale->sws_freeContext(m_sw_scale_ctx);
419     m_sw_scale_ctx = NULL;
420   }
421   SAFE_DELETE(m_dllSwScale);
422
423   m_processor.UnInit();
424 }
425
426 bool CWinRenderer::CreateIntermediateRenderTarget()
427 {
428   // Initialize a render target for intermediate rendering - same size as the video source
429   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
430   D3DFORMAT format = D3DFMT_X8R8G8B8;
431   DWORD usage = D3DUSAGE_RENDERTARGET;
432
433   if      (g_Windowing.IsTextureFormatOk(D3DFMT_A2R10G10B10, usage)) format = D3DFMT_A2R10G10B10;
434   else if (g_Windowing.IsTextureFormatOk(D3DFMT_A2B10G10R10, usage)) format = D3DFMT_A2B10G10R10;
435   else if (g_Windowing.IsTextureFormatOk(D3DFMT_A8R8G8B8, usage))    format = D3DFMT_A8R8G8B8;
436   else if (g_Windowing.IsTextureFormatOk(D3DFMT_A8B8G8R8, usage))    format = D3DFMT_A8B8G8R8;
437   else if (g_Windowing.IsTextureFormatOk(D3DFMT_X8R8G8B8, usage))    format = D3DFMT_X8R8G8B8;
438   else if (g_Windowing.IsTextureFormatOk(D3DFMT_X8B8G8R8, usage))    format = D3DFMT_X8B8G8R8;
439   else if (g_Windowing.IsTextureFormatOk(D3DFMT_R8G8B8, usage))      format = D3DFMT_R8G8B8;
440
441   CLog::Log(LOGDEBUG, __FUNCTION__": format %i", format);
442
443   if(!m_IntermediateTarget.Create(m_sourceWidth, m_sourceHeight, 1, usage, format, D3DPOOL_DEFAULT))
444   {
445     CLog::Log(LOGERROR, __FUNCTION__": render target creation failed. Going back to bilinear scaling.", format);
446     return false;
447   }
448   return true;
449 }
450
451 void CWinRenderer::SelectSWVideoFilter()
452 {
453   switch (m_scalingMethod)
454   {
455   case VS_SCALINGMETHOD_AUTO:
456   case VS_SCALINGMETHOD_LINEAR:
457     if (Supports(VS_SCALINGMETHOD_LINEAR))
458     {
459       m_TextureFilter = D3DTEXF_LINEAR;
460       break;
461     }
462     // fall through for fallback
463   case VS_SCALINGMETHOD_NEAREST:
464   default:
465     m_TextureFilter = D3DTEXF_POINT;
466     break;
467   }
468 }
469
470 void CWinRenderer::SelectPSVideoFilter()
471 {
472   m_bUseHQScaler = false;
473
474   switch (m_scalingMethod)
475   {
476   case VS_SCALINGMETHOD_NEAREST:
477   case VS_SCALINGMETHOD_LINEAR:
478     break;
479
480   case VS_SCALINGMETHOD_CUBIC:
481   case VS_SCALINGMETHOD_LANCZOS2:
482   case VS_SCALINGMETHOD_SPLINE36_FAST:
483   case VS_SCALINGMETHOD_LANCZOS3_FAST:
484     m_bUseHQScaler = true;
485     break;
486
487   case VS_SCALINGMETHOD_SPLINE36:
488   case VS_SCALINGMETHOD_LANCZOS3:
489     m_bUseHQScaler = true;
490     break;
491
492   case VS_SCALINGMETHOD_SINC8:
493   case VS_SCALINGMETHOD_NEDI:
494     CLog::Log(LOGERROR, "D3D: TODO: This scaler has not yet been implemented");
495     break;
496
497   case VS_SCALINGMETHOD_BICUBIC_SOFTWARE:
498   case VS_SCALINGMETHOD_LANCZOS_SOFTWARE:
499   case VS_SCALINGMETHOD_SINC_SOFTWARE:
500     CLog::Log(LOGERROR, "D3D: TODO: Software scaling has not yet been implemented");
501     break;
502
503   default:
504     break;
505   }
506
507   if (m_scalingMethod == VS_SCALINGMETHOD_AUTO)
508   {
509     bool scaleSD = m_sourceHeight < 720 && m_sourceWidth < 1280;
510     bool scaleUp = (int)m_sourceHeight < g_graphicsContext.GetHeight() && (int)m_sourceWidth < g_graphicsContext.GetWidth();
511     bool scaleFps = m_fps < (g_advancedSettings.m_videoAutoScaleMaxFps + 0.01f);
512
513     if (Supports(VS_SCALINGMETHOD_LANCZOS3_FAST) && scaleSD && scaleUp && scaleFps)
514     {
515       m_scalingMethod = VS_SCALINGMETHOD_LANCZOS3_FAST;
516       m_bUseHQScaler = true;
517     }
518   }
519 }
520
521 void CWinRenderer::UpdatePSVideoFilter()
522 {
523   SAFE_DELETE(m_scalerShader);
524
525   if (m_bUseHQScaler)
526   {
527     // First try the more efficient two pass convolution scaler
528     m_scalerShader = new CConvolutionShaderSeparable();
529
530     if (!m_scalerShader->Create(m_scalingMethod))
531     {
532       SAFE_DELETE(m_scalerShader);
533       CLog::Log(LOGNOTICE, __FUNCTION__": two pass convolution shader init problem, falling back to one pass.");
534     }
535
536     // Fallback on the one pass version
537     if (m_scalerShader == NULL)
538     {
539       m_scalerShader = new CConvolutionShader1Pass();
540
541       if (!m_scalerShader->Create(m_scalingMethod))
542       {
543         SAFE_DELETE(m_scalerShader);
544         CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(34400), g_localizeStrings.Get(34401));
545         m_bUseHQScaler = false;
546       }
547     }
548   }
549
550   if(m_IntermediateTarget.Get())
551     m_IntermediateTarget.Release();
552
553   if (m_bUseHQScaler && !CreateIntermediateRenderTarget())
554   {
555     SAFE_DELETE(m_scalerShader);
556     m_bUseHQScaler = false;
557   }
558
559   SAFE_DELETE(m_colorShader);
560
561   if (m_bUseHQScaler)
562   {
563     m_colorShader = new CYUV2RGBShader();
564     if (!m_colorShader->Create(m_sourceWidth, m_sourceHeight, m_format))
565     {
566       // Try again after disabling the HQ scaler and freeing its resources
567       m_IntermediateTarget.Release();
568       SAFE_DELETE(m_scalerShader);
569       SAFE_DELETE(m_colorShader);
570       m_bUseHQScaler = false;
571     }
572   }
573
574   if (!m_bUseHQScaler) //fallback from HQ scalers and multipass creation above
575   {
576     m_colorShader = new CYUV2RGBShader();
577     if (!m_colorShader->Create(m_sourceWidth, m_sourceHeight, m_format))
578       SAFE_DELETE(m_colorShader);
579     // we're in big trouble - should fallback on D3D accelerated or sw method
580   }
581 }
582
583 void CWinRenderer::UpdateVideoFilter()
584 {
585   if (m_scalingMethodGui == g_settings.m_currentVideoSettings.m_ScalingMethod && m_bFilterInitialized)
586     return;
587
588   m_bFilterInitialized = true;
589
590   m_scalingMethodGui = g_settings.m_currentVideoSettings.m_ScalingMethod;
591   m_scalingMethod    = m_scalingMethodGui;
592
593   if (!Supports(m_scalingMethod))
594   {
595     CLog::Log(LOGWARNING, __FUNCTION__" - chosen scaling method %d is not supported by renderer", (int)m_scalingMethod);
596     m_scalingMethod = VS_SCALINGMETHOD_AUTO;
597   }
598
599   switch(m_renderMethod)
600   {
601   case RENDER_SW:
602     SelectSWVideoFilter();
603     break;
604
605   case RENDER_PS:
606     SelectPSVideoFilter();
607     UpdatePSVideoFilter();
608     break;
609
610   case RENDER_DXVA:
611     // Everything already setup, nothing to do.
612     break;
613
614   default:
615     return;
616   }
617 }
618
619 void CWinRenderer::Render(DWORD flags)
620 {
621   if (m_renderMethod == RENDER_DXVA)
622   {
623     CWinRenderer::RenderProcessor(flags);
624     return;
625   }
626
627   UpdateVideoFilter();
628
629   // Optimize later? we could get by with bilinear under some circumstances
630   /*if(!m_bUseHQScaler
631     || !g_graphicsContext.IsFullScreenVideo()
632     || g_graphicsContext.IsCalibrating()
633     || (m_destRect.Width() == m_sourceWidth && m_destRect.Height() == m_sourceHeight))
634     */
635   CSingleLock lock(g_graphicsContext);
636
637   // Don't need a stencil/depth buffer and a buffer smaller than the render target causes D3D complaints and nVidia issues
638   // Save & restore when we're done.
639   LPDIRECT3DSURFACE9 pZBuffer;
640   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
641   pD3DDevice->GetDepthStencilSurface(&pZBuffer);
642   pD3DDevice->SetDepthStencilSurface(NULL);
643
644   if (m_renderMethod == RENDER_SW)
645     RenderSW();
646   else if (m_renderMethod == RENDER_PS)
647     RenderPS();
648
649   pD3DDevice->SetDepthStencilSurface(pZBuffer);
650   pZBuffer->Release();
651 }
652
653 void CWinRenderer::RenderSW()
654 {
655   enum PixelFormat format = PixelFormatFromFormat(m_format);
656
657   // 1. convert yuv to rgb
658   m_sw_scale_ctx = m_dllSwScale->sws_getCachedContext(m_sw_scale_ctx,
659                                                       m_sourceWidth, m_sourceHeight, format,
660                                                       m_sourceWidth, m_sourceHeight, PIX_FMT_BGRA,
661                                                       SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL);
662
663   YUVBuffer* buf = (YUVBuffer*)m_VideoBuffers[m_iYV12RenderBuffer];
664
665   D3DLOCKED_RECT   srclr[MAX_PLANES];
666   uint8_t         *src[MAX_PLANES];
667   int              srcStride[MAX_PLANES];
668
669   for (unsigned int idx = 0; idx < buf->GetActivePlanes(); idx++)
670   {
671     if(!(buf->planes[idx].texture.LockRect(0, &srclr[idx], NULL, D3DLOCK_READONLY)))
672       CLog::Log(LOGERROR, __FUNCTION__" - failed to lock yuv textures into memory");
673     else
674     {
675       src[idx] = (uint8_t*)srclr[idx].pBits;
676       srcStride[idx] = srclr[idx].Pitch;
677     }
678   }
679   
680   D3DLOCKED_RECT destlr = {0,0};
681   if (!m_SWTarget.LockRect(0, &destlr, NULL, D3DLOCK_DISCARD))
682     CLog::Log(LOGERROR, __FUNCTION__" - failed to lock swtarget texture into memory");
683
684   uint8_t *dst[]  = { (uint8_t*) destlr.pBits, 0, 0, 0 };
685   int dstStride[] = { destlr.Pitch, 0, 0, 0 };
686
687   m_dllSwScale->sws_scale(m_sw_scale_ctx, src, srcStride, 0, m_sourceHeight, dst, dstStride);
688
689   for (unsigned int idx = 0; idx < buf->GetActivePlanes(); idx++)
690     if(!(buf->planes[idx].texture.UnlockRect(0)))
691       CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock yuv textures");
692
693   if (!m_SWTarget.UnlockRect(0))
694     CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock swtarget texture");
695
696   // 2. scale to display
697
698   // Don't know where this martian comes from but it can happen in the initial frames of a video
699   if ((m_destRect.x1 < 0 && m_destRect.x2 < 0) || (m_destRect.y1 < 0 && m_destRect.y2 < 0))
700     return;
701
702   ScaleFixedPipeline();
703 }
704
705 /*
706 Code kept for reference, as a basis to re-enable StretchRect and 
707 do the color conversion with it.
708 See IDirect3D9::CheckDeviceFormat() for support of non-standard fourcc textures
709 and IDirect3D9::CheckDeviceFormatConversion for color conversion support
710
711 void CWinRenderer::ScaleStretchRect()
712 {
713   // Test HW scaler support. StretchRect is slightly faster than drawing a quad.
714   // If linear filtering is not supported, drop back to quads, as most HW has linear filtering for quads.
715   //if(m_deviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES
716   //&& m_deviceCaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR
717   //&& m_deviceCaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)
718   //{
719   //  m_StretchRectSupported = true;
720   //}
721
722   CRect sourceRect = m_sourceRect;
723   CRect destRect = m_destRect;
724
725   D3DSURFACE_DESC desc;
726   if (FAILED(target->GetDesc(&desc)))
727     CLog::Log(LOGERROR, "CWinRenderer::Render - failed to get back buffer description");
728   CRect tgtRect(0, 0, desc.Width, desc.Height);
729
730   // Need to manipulate the coordinates since StretchRect doesn't accept off-screen coordinates.
731   CWIN32Util::CropSource(sourceRect, destRect, tgtRect);
732
733   RECT srcRect = { sourceRect.x1, sourceRect.y1, sourceRect.x2, sourceRect.y2 };
734   IDirect3DSurface9* source;
735   if(!m_SWTarget.GetSurfaceLevel(0, &source))
736     CLog::Log(LOGERROR, "CWinRenderer::Render - failed to get source");
737
738   RECT dstRect = { destRect.x1, destRect.y1, destRect.x2, destRect.y2 };
739   IDirect3DSurface9* target;
740   if(FAILED(g_Windowing.Get3DDevice()->GetRenderTarget(0, &target)))
741     CLog::Log(LOGERROR, "CWinRenderer::Render - failed to get back buffer");
742
743   HRESULT hr;
744   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
745
746   if(FAILED(hr = pD3DDevice->StretchRect(source, &srcRect, target, &dstRect, m_TextureFilter)))
747     CLog::Log(LOGERROR, __FUNCTION__" - StretchRect failed (0x%08X)", hr);
748
749   target->Release();
750   source->Release();
751 }
752 */
753
754 void CWinRenderer::ScaleFixedPipeline()
755 {
756   HRESULT hr;
757   IDirect3DDevice9 *pD3DDev = g_Windowing.Get3DDevice();
758   D3DSURFACE_DESC srcDesc;
759   if (FAILED(hr = m_SWTarget.Get()->GetLevelDesc(0, &srcDesc)))
760     CLog::Log(LOGERROR, __FUNCTION__": GetLevelDesc failed. %s", CRenderSystemDX::GetErrorDescription(hr).c_str());
761
762   float srcWidth  = (float)srcDesc.Width;
763   float srcHeight = (float)srcDesc.Height;
764
765   bool cbcontrol          = (g_settings.m_currentVideoSettings.m_Contrast != 50.0f || g_settings.m_currentVideoSettings.m_Brightness != 50.0f);
766   unsigned int contrast   = (unsigned int)(g_settings.m_currentVideoSettings.m_Contrast *.01f * 255.0f); // we have to divide by two here/multiply by two later
767   unsigned int brightness = (unsigned int)(g_settings.m_currentVideoSettings.m_Brightness * .01f * 255.0f);
768
769   D3DCOLOR diffuse  = D3DCOLOR_ARGB(255, contrast, contrast, contrast);
770   D3DCOLOR specular = D3DCOLOR_ARGB(255, brightness, brightness, brightness);
771
772   struct VERTEX
773   {
774     FLOAT x,y,z,rhw;
775     D3DCOLOR diffuse;
776     D3DCOLOR specular;
777     FLOAT tu, tv;
778   };
779
780   VERTEX vertex[] =
781   {
782     {m_destRect.x1, m_destRect.y1, 0.0f, 1.0f, diffuse, specular, m_sourceRect.x1 / srcWidth, m_sourceRect.y1 / srcHeight},
783     {m_destRect.x2, m_destRect.y1, 0.0f, 1.0f, diffuse, specular, m_sourceRect.x2 / srcWidth, m_sourceRect.y1 / srcHeight},
784     {m_destRect.x2, m_destRect.y2, 0.0f, 1.0f, diffuse, specular, m_sourceRect.x2 / srcWidth, m_sourceRect.y2 / srcHeight},
785     {m_destRect.x1, m_destRect.y2, 0.0f, 1.0f, diffuse, specular, m_sourceRect.x1 / srcWidth, m_sourceRect.y2 / srcHeight},
786   };
787
788   // Compensate for D3D coordinates system
789   for(int i = 0; i < sizeof(vertex)/sizeof(vertex[0]); i++)
790   {
791     vertex[i].x -= 0.5f;
792     vertex[i].y -= 0.5f;
793   };
794
795   pD3DDev->SetTexture(0, m_SWTarget.Get());
796
797   if (!cbcontrol)
798   {
799     hr = pD3DDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
800     hr = pD3DDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
801     hr = pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
802     hr = pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
803     hr = pD3DDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
804     hr = pD3DDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
805   }
806   else
807   {
808     hr = pD3DDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE2X );
809     hr = pD3DDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
810     hr = pD3DDev->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
811     hr = pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
812     hr = pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
813
814     hr = pD3DDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_ADDSIGNED );
815     hr = pD3DDev->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_CURRENT );
816     hr = pD3DDev->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_SPECULAR );
817     hr = pD3DDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
818     hr = pD3DDev->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT );
819
820     hr = pD3DDev->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_DISABLE );
821     hr = pD3DDev->SetTextureStageState( 2, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
822   }
823
824   hr = pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
825   hr = pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE);
826   hr = pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE);
827   hr = pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE);
828   hr = pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
829   hr = pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
830   hr = pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
831   hr = pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA|D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED); 
832
833   hr = pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, m_TextureFilter);
834   hr = pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, m_TextureFilter);
835   hr = pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
836   hr = pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
837
838   hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1);
839
840   if (FAILED(hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, vertex, sizeof(VERTEX))))
841     CLog::Log(LOGERROR, __FUNCTION__": DrawPrimitiveUP failed. %s", CRenderSystemDX::GetErrorDescription(hr).c_str());
842
843   pD3DDev->SetTexture(0, NULL);
844 }
845
846 void CWinRenderer::RenderPS()
847 {
848   if (!m_bUseHQScaler)
849   {
850     Stage1();
851   }
852   else
853   {
854     Stage1();
855     Stage2();
856   }
857 }
858
859 void CWinRenderer::Stage1()
860 {
861   if (!m_bUseHQScaler)
862   {
863       m_colorShader->Render(m_sourceRect, m_destRect,
864                             g_settings.m_currentVideoSettings.m_Contrast,
865                             g_settings.m_currentVideoSettings.m_Brightness,
866                             m_iFlags,
867                             (YUVBuffer*)m_VideoBuffers[m_iYV12RenderBuffer]);
868   }
869   else
870   {
871     // Switch the render target to the temporary destination
872     LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
873     LPDIRECT3DSURFACE9 newRT, oldRT;
874     m_IntermediateTarget.GetSurfaceLevel(0, &newRT);
875     pD3DDevice->GetRenderTarget(0, &oldRT);
876     pD3DDevice->SetRenderTarget(0, newRT);
877
878     CRect srcRect(0.0f, 0.0f, m_sourceWidth, m_sourceHeight);
879     CRect rtRect(0.0f, 0.0f, m_sourceWidth, m_sourceHeight);
880
881     m_colorShader->Render(srcRect, rtRect,
882                           g_settings.m_currentVideoSettings.m_Contrast,
883                           g_settings.m_currentVideoSettings.m_Brightness,
884                           m_iFlags,
885                           (YUVBuffer*)m_VideoBuffers[m_iYV12RenderBuffer]);
886
887     // Restore the render target
888     pD3DDevice->SetRenderTarget(0, oldRT);
889
890     oldRT->Release();
891     newRT->Release();
892   }
893 }
894
895 void CWinRenderer::Stage2()
896 {
897   m_scalerShader->Render(m_IntermediateTarget, m_sourceWidth, m_sourceHeight, m_destWidth, m_destHeight, m_sourceRect, m_destRect);
898 }
899
900 void CWinRenderer::RenderProcessor(DWORD flags)
901 {
902   CSingleLock lock(g_graphicsContext);
903   HRESULT hr;
904
905   DXVABuffer *image = (DXVABuffer*)m_VideoBuffers[m_iYV12RenderBuffer];
906
907   IDirect3DSurface9* target;
908   if(FAILED(hr = g_Windowing.Get3DDevice()->GetRenderTarget(0, &target)))
909   {
910     CLog::Log(LOGERROR, "CWinRenderer::RenderSurface - failed to get render target. %s", CRenderSystemDX::GetErrorDescription(hr).c_str());
911     return;
912   }
913
914   m_processor.Render(m_sourceRect, m_destRect, target, image->id, flags);
915
916   target->Release();
917 }
918
919 bool CWinRenderer::RenderCapture(CRenderCapture* capture)
920 {
921   if (!m_bConfigured || m_NumYV12Buffers == 0)
922     return false;
923
924   bool succeeded = false;
925
926   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
927
928   CRect saveSize = m_destRect;
929   saveRotatedCoords();//backup current m_rotatedDestCoords
930
931   m_destRect.SetRect(0, 0, (float)capture->GetWidth(), (float)capture->GetHeight());
932   syncDestRectToRotatedPoints();//syncs the changed destRect to m_rotatedDestCoords
933
934   LPDIRECT3DSURFACE9 oldSurface;
935   pD3DDevice->GetRenderTarget(0, &oldSurface);
936
937   capture->BeginRender();
938   if (capture->GetState() != CAPTURESTATE_FAILED)
939   {
940     pD3DDevice->BeginScene();
941     Render(0);
942     pD3DDevice->EndScene();
943     capture->EndRender();
944     succeeded = true;
945   }
946
947   pD3DDevice->SetRenderTarget(0, oldSurface);
948   oldSurface->Release();
949
950   m_destRect = saveSize;
951   restoreRotatedCoords();//restores the previous state of the rotated dest coords
952
953   return succeeded;
954 }
955
956 //********************************************************************************************************
957 // YV12 Texture creation, deletion, copying + clearing
958 //********************************************************************************************************
959 void CWinRenderer::DeleteYV12Texture(int index)
960 {
961   CSingleLock lock(g_graphicsContext);
962   if (m_VideoBuffers[index] != NULL)
963     SAFE_DELETE(m_VideoBuffers[index]);
964   m_NumYV12Buffers = 0;
965 }
966
967 bool CWinRenderer::CreateYV12Texture(int index)
968 {
969   CSingleLock lock(g_graphicsContext);
970   DeleteYV12Texture(index);
971
972   if (m_renderMethod == RENDER_DXVA)
973   {
974     m_VideoBuffers[index] = new DXVABuffer();
975   }
976   else
977   {
978     YUVBuffer *buf = new YUVBuffer();
979
980     if (!buf->Create(m_format, m_sourceWidth, m_sourceHeight))
981     {
982       CLog::Log(LOGERROR, __FUNCTION__" - Unable to create YV12 video texture %i", index);
983       return false;
984     }
985     m_VideoBuffers[index] = buf;
986   }
987
988   SVideoBuffer *buf = m_VideoBuffers[index];
989
990   buf->StartDecode();
991   buf->Clear();
992
993   if(index == m_iYV12RenderBuffer)
994     buf->StartRender();
995
996   CLog::Log(LOGDEBUG, "created video buffer %i", index);
997   return true;
998 }
999
1000 bool CWinRenderer::Supports(EDEINTERLACEMODE mode)
1001 {
1002   if(mode == VS_DEINTERLACEMODE_OFF
1003   || mode == VS_DEINTERLACEMODE_AUTO
1004   || mode == VS_DEINTERLACEMODE_FORCE)
1005     return true;
1006
1007   return false;
1008 }
1009
1010 bool CWinRenderer::Supports(EINTERLACEMETHOD method)
1011 {
1012   if(method == VS_INTERLACEMETHOD_AUTO)
1013     return true;
1014
1015   if (m_renderMethod == RENDER_DXVA)
1016   {
1017     if(method == VS_INTERLACEMETHOD_DXVA_BOB
1018     || method == VS_INTERLACEMETHOD_DXVA_BEST)
1019       return true;
1020   }
1021
1022   if(m_format != RENDER_FMT_DXVA
1023   && (   method == VS_INTERLACEMETHOD_DEINTERLACE
1024       || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF
1025       || method == VS_INTERLACEMETHOD_SW_BLEND))
1026     return true;
1027
1028   return false;
1029 }
1030
1031 bool CWinRenderer::Supports(ERENDERFEATURE feature)
1032 {
1033   if(feature == RENDERFEATURE_BRIGHTNESS)
1034     return true;
1035
1036   if(feature == RENDERFEATURE_CONTRAST)
1037     return true;
1038
1039   if (feature == RENDERFEATURE_STRETCH         ||
1040       feature == RENDERFEATURE_NONLINSTRETCH   ||
1041       feature == RENDERFEATURE_CROP            ||
1042       feature == RENDERFEATURE_ZOOM            ||
1043       feature == RENDERFEATURE_VERTICAL_SHIFT  ||
1044       feature == RENDERFEATURE_PIXEL_RATIO     ||
1045       feature == RENDERFEATURE_POSTPROCESS)
1046     return true;
1047
1048
1049   return false;
1050 }
1051
1052 bool CWinRenderer::Supports(ESCALINGMETHOD method)
1053 {
1054   if (m_renderMethod == RENDER_DXVA)
1055   {
1056     if(method == VS_SCALINGMETHOD_DXVA_HARDWARE)
1057       return true;
1058     return false;
1059   }
1060   else if(m_renderMethod == RENDER_PS)
1061   {
1062     if(m_deviceCaps.PixelShaderVersion >= D3DPS_VERSION(2, 0)
1063     && (   method == VS_SCALINGMETHOD_AUTO
1064         || method == VS_SCALINGMETHOD_LINEAR))
1065         return true;
1066
1067     if(m_deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0))
1068     {
1069       if(method == VS_SCALINGMETHOD_CUBIC
1070       || method == VS_SCALINGMETHOD_LANCZOS2
1071       || method == VS_SCALINGMETHOD_SPLINE36_FAST
1072       || method == VS_SCALINGMETHOD_LANCZOS3_FAST
1073       || method == VS_SCALINGMETHOD_SPLINE36
1074       || method == VS_SCALINGMETHOD_LANCZOS3)
1075         return true;
1076     }
1077   }
1078   else if(m_renderMethod == RENDER_SW)
1079   {
1080     if(method == VS_SCALINGMETHOD_AUTO
1081     || method == VS_SCALINGMETHOD_NEAREST)
1082       return true;
1083     if(method == VS_SCALINGMETHOD_LINEAR
1084     && m_deviceCaps.TextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR
1085     && m_deviceCaps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)
1086       return true;
1087   }
1088   return false;
1089 }
1090
1091 EINTERLACEMETHOD CWinRenderer::AutoInterlaceMethod()
1092 {
1093   if (m_renderMethod == RENDER_DXVA)
1094     return VS_INTERLACEMETHOD_DXVA_BOB;
1095   else
1096     return VS_INTERLACEMETHOD_DEINTERLACE_HALF;
1097 }
1098
1099 //============================================
1100
1101 YUVBuffer::~YUVBuffer()
1102 {
1103   Release();
1104 }
1105
1106 bool YUVBuffer::Create(ERenderFormat format, unsigned int width, unsigned int height)
1107 {
1108   m_format = format;
1109   m_width = width;
1110   m_height = height;
1111
1112   // Create the buffers in system memory and copy to D3DPOOL_DEFAULT:
1113   // - helps with lost devices. A buffer can be locked for dvdplayer without interfering.
1114   // - Dynamic + D3DPOOL_DEFAULT caused trouble for Intel i3 and some IGP. Bad sync/locking in the driver  I suppose
1115   // and Present failed every second time for the second video played.
1116   // - this is what D3D9 does behind the scenes anyway
1117   switch(m_format)
1118   {
1119   case RENDER_FMT_YUV420P10:
1120   case RENDER_FMT_YUV420P16:
1121     {
1122       if ( !planes[PLANE_Y].texture.Create(m_width    , m_height    , 1, 0, D3DFMT_L16, D3DPOOL_SYSTEMMEM)
1123         || !planes[PLANE_U].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L16, D3DPOOL_SYSTEMMEM)
1124         || !planes[PLANE_V].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L16, D3DPOOL_SYSTEMMEM))
1125         return false;
1126       m_activeplanes = 3;
1127       break;
1128     }
1129   case RENDER_FMT_YUV420P:
1130     {
1131       if ( !planes[PLANE_Y].texture.Create(m_width    , m_height    , 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
1132         || !planes[PLANE_U].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
1133         || !planes[PLANE_V].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM))
1134         return false;
1135       m_activeplanes = 3;
1136       break;
1137     }
1138   case RENDER_FMT_NV12:
1139     {
1140       if ( !planes[PLANE_Y].texture.Create(m_width    , m_height    , 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
1141         || !planes[PLANE_UV].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_A8L8, D3DPOOL_SYSTEMMEM))
1142         return false;
1143       m_activeplanes = 2;
1144       break;
1145     }
1146   case RENDER_FMT_YUYV422:
1147     {
1148       if ( !planes[PLANE_Y].texture.Create(m_width >> 1    , m_height    , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM))
1149         return false;
1150       m_activeplanes = 1;
1151       break;
1152     }
1153   case RENDER_FMT_UYVY422:
1154     {
1155       if ( !planes[PLANE_Y].texture.Create(m_width >> 1    , m_height    , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM))
1156         return false;
1157       m_activeplanes = 1;
1158       break;
1159     }
1160   default:
1161     m_activeplanes = 0;
1162     return false;
1163   }
1164
1165   return true;
1166 }
1167
1168 void YUVBuffer::Release()
1169 {
1170   for(unsigned i = 0; i < m_activeplanes; i++)
1171   {
1172     planes[i].texture.Release();
1173     memset(&planes[i].rect, 0, sizeof(planes[i].rect));
1174   }
1175 }
1176
1177 void YUVBuffer::StartRender()
1178 {
1179   for(unsigned i = 0; i < m_activeplanes; i++)
1180   {
1181     if(planes[i].texture.Get() && planes[i].rect.pBits)
1182       if (!planes[i].texture.UnlockRect(0))
1183         CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock texture %d", i);
1184     memset(&planes[i].rect, 0, sizeof(planes[i].rect));
1185   }
1186 }
1187
1188 void YUVBuffer::StartDecode()
1189 {
1190   for(unsigned i = 0; i < m_activeplanes; i++)
1191   {
1192     if(planes[i].texture.Get()
1193     && planes[i].texture.LockRect(0, &planes[i].rect, NULL, D3DLOCK_DISCARD) == false)
1194     {
1195       memset(&planes[i].rect, 0, sizeof(planes[i].rect));
1196       CLog::Log(LOGERROR, __FUNCTION__" - failed to lock texture %d into memory", i);
1197     }
1198   }
1199 }
1200
1201 void YUVBuffer::Clear()
1202 {
1203   // Set Y to 0 and U,V to 128 (RGB 0,0,0) to avoid visual artifacts at the start of playback
1204
1205   switch(m_format)
1206   {
1207   case RENDER_FMT_YUV420P16:
1208     {
1209       wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0,     planes[PLANE_Y].rect.Pitch *  m_height    / 2);
1210       wmemset((wchar_t*)planes[PLANE_U].rect.pBits, 32768, planes[PLANE_U].rect.Pitch * (m_height/2) / 2);
1211       wmemset((wchar_t*)planes[PLANE_V].rect.pBits, 32768, planes[PLANE_V].rect.Pitch * (m_height/2) / 2);
1212       break;
1213     }
1214   case RENDER_FMT_YUV420P10:
1215     {
1216       wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0,   planes[PLANE_Y].rect.Pitch *  m_height    / 2);
1217       wmemset((wchar_t*)planes[PLANE_U].rect.pBits, 512, planes[PLANE_U].rect.Pitch * (m_height/2) / 2);
1218       wmemset((wchar_t*)planes[PLANE_V].rect.pBits, 512, planes[PLANE_V].rect.Pitch * (m_height/2) / 2);
1219       break;
1220     }
1221   case RENDER_FMT_YUV420P:
1222     {
1223       memset(planes[PLANE_Y].rect.pBits, 0,   planes[PLANE_Y].rect.Pitch *  m_height);
1224       memset(planes[PLANE_U].rect.pBits, 128, planes[PLANE_U].rect.Pitch * (m_height/2));
1225       memset(planes[PLANE_V].rect.pBits, 128, planes[PLANE_V].rect.Pitch * (m_height/2));
1226       break;
1227     }
1228   case RENDER_FMT_NV12:
1229     {
1230       memset(planes[PLANE_Y].rect.pBits, 0,   planes[PLANE_Y].rect.Pitch *  m_height);
1231       memset(planes[PLANE_UV].rect.pBits, 128, planes[PLANE_U].rect.Pitch * (m_height/2));
1232       break;
1233     }
1234   // YUY2, UYVY: wmemset to set a 16bit pattern, byte-swapped because x86 is LE
1235   case RENDER_FMT_YUYV422:
1236     {
1237       wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0x8000, planes[PLANE_Y].rect.Pitch / 2 * m_height);
1238       break;
1239     }
1240   case RENDER_FMT_UYVY422:
1241     {
1242       wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0x0080, planes[PLANE_Y].rect.Pitch / 2 * m_height);
1243       break;
1244     }
1245
1246   }
1247 }
1248
1249 //==================================
1250
1251 DXVABuffer::~DXVABuffer()
1252 {
1253   Release();
1254 }
1255
1256 void DXVABuffer::Release()
1257 {
1258   id = 0;
1259 }
1260
1261 void DXVABuffer::StartDecode()
1262 {
1263   Release();
1264 }
1265 #endif