aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCrystalP <CrystalP@xbmc.org>2011-01-31 02:47:18 -0500
committerCrystalP <CrystalP@xbmc.org>2011-02-06 20:45:14 -0500
commit3d246e09f59bbca661570624bde000d62d79408a (patch)
treece56c1a3a6819ab9bf701610532bfb6b16997011
parent6e2c48f4f4677ed7ae22aa2a8b0edaade9a80fee (diff)
[WIN32] add nv12 rendering (software and ps)
-rw-r--r--system/shaders/yuv2rgb_d3d.fx6
-rw-r--r--xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.cpp40
-rw-r--r--xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.h4
-rw-r--r--xbmc/cores/VideoRenderers/WinRenderer.cpp102
-rw-r--r--xbmc/cores/VideoRenderers/WinRenderer.h14
5 files changed, 128 insertions, 38 deletions
diff --git a/system/shaders/yuv2rgb_d3d.fx b/system/shaders/yuv2rgb_d3d.fx
index 833bbadd43..1f39734781 100644
--- a/system/shaders/yuv2rgb_d3d.fx
+++ b/system/shaders/yuv2rgb_d3d.fx
@@ -87,10 +87,16 @@ struct PS_OUTPUT
PS_OUTPUT YUV2RGB( VS_OUTPUT In)
{
PS_OUTPUT OUT;
+#if defined(XBMC_YV12)
float4 YUV = float4(tex2D (YSampler, In.TextureY).x
, tex2D (USampler, In.TextureU).x
, tex2D (VSampler, In.TextureV).x
, 1.0);
+#elif defined(XBMC_NV12)
+ float4 YUV = float4(tex2D (YSampler, In.TextureY).x
+ , tex2D (USampler, In.TextureU).ra
+ , 1.0);
+#endif
OUT.RGBColor = mul(YUV, g_ColorMatrix);
OUT.RGBColor.a = 1.0;
return OUT;
diff --git a/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.cpp b/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.cpp
index 5a29583e55..e0f53d1e76 100644
--- a/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.cpp
+++ b/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.cpp
@@ -192,7 +192,7 @@ bool CWinShader::Execute()
//==================================================================================
-bool CYUV2RGBShader::Create(bool singlepass, unsigned int sourceWidth, unsigned int sourceHeight)
+bool CYUV2RGBShader::Create(bool singlepass, unsigned int sourceWidth, unsigned int sourceHeight, BufferFormat fmt)
{
ReleaseInternal();
@@ -202,6 +202,13 @@ bool CYUV2RGBShader::Create(bool singlepass, unsigned int sourceWidth, unsigned
if (singlepass)
defines["SINGLEPASS"] = "";
+ if (fmt == YV12)
+ defines["XBMC_YV12"] = "";
+ else if (fmt == NV12)
+ defines["XBMC_NV12"] = "";
+ else
+ return false;
+
CStdString effectString = "special://xbmc/system/shaders/yuv2rgb_d3d.fx";
if(!LoadEffect(effectString, &defines))
@@ -213,12 +220,24 @@ bool CYUV2RGBShader::Create(bool singlepass, unsigned int sourceWidth, unsigned
m_sourceWidth = sourceWidth;
m_sourceHeight = sourceHeight;
- if(!m_YUVPlanes[0].Create(m_sourceWidth , m_sourceHeight , 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
- || !m_YUVPlanes[1].Create(m_sourceWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
- || !m_YUVPlanes[2].Create(m_sourceWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT))
+ if (fmt == YV12)
{
- CLog::Log(LOGERROR, __FUNCTION__": Failed to create YUV planes.");
- return false;
+ if(!m_YUVPlanes[0].Create(m_sourceWidth , m_sourceHeight , 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
+ || !m_YUVPlanes[1].Create(m_sourceWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
+ || !m_YUVPlanes[2].Create(m_sourceWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to create YUV planes.");
+ return false;
+ }
+ }
+ else if (fmt == NV12)
+ {
+ if(!m_YUVPlanes[0].Create(m_sourceWidth , m_sourceHeight , 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
+ || !m_YUVPlanes[1].Create(m_sourceWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_A8L8, D3DPOOL_DEFAULT))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to create YUV planes.");
+ return false;
+ }
}
return true;
@@ -233,7 +252,7 @@ void CYUV2RGBShader::Render(CRect sourceRect, CRect destRect,
PrepareParameters(sourceRect, destRect,
contrast, brightness, flags);
UploadToGPU(YUVbuf);
- SetShaderParameters();
+ SetShaderParameters(YUVbuf);
Execute();
}
@@ -299,13 +318,14 @@ void CYUV2RGBShader::PrepareParameters(CRect sourceRect,
flags);
}
-void CYUV2RGBShader::SetShaderParameters()
+void CYUV2RGBShader::SetShaderParameters(YUVBuffer* YUVbuf)
{
m_effect.SetMatrix( "g_ColorMatrix", m_matrix.Matrix());
m_effect.SetTechnique( "YUV2RGB_T" );
m_effect.SetTexture( "g_YTexture", m_YUVPlanes[0] ) ;
m_effect.SetTexture( "g_UTexture", m_YUVPlanes[1] ) ;
- m_effect.SetTexture( "g_VTexture", m_YUVPlanes[2] ) ;
+ if (YUVbuf->GetActivePlanes() == 3)
+ m_effect.SetTexture( "g_VTexture", m_YUVPlanes[2] ) ;
}
void CYUV2RGBShader::ReleaseInternal()
@@ -323,7 +343,7 @@ bool CYUV2RGBShader::UploadToGPU(YUVBuffer* YUVbuf)
const RECT recthalf = { 0, 0, m_sourceWidth / 2, m_sourceHeight / 2};
const POINT point = { 0, 0 };
- for (int i = 0; i<3; i++)
+ for (unsigned int i = 0; i<YUVbuf->GetActivePlanes(); i++)
{
IDirect3DSurface9 *src, *dest;
if(FAILED(YUVbuf->planes[i].texture.Get()->GetSurfaceLevel(0, &src)))
diff --git a/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.h b/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.h
index d74fad4bbb..ea3d992da6 100644
--- a/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.h
+++ b/xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.h
@@ -76,7 +76,7 @@ private:
class CYUV2RGBShader : public CWinShader
{
public:
- virtual bool Create(bool singlepass, unsigned int sourceWidth, unsigned int sourceHeight);
+ virtual bool Create(bool singlepass, unsigned int sourceWidth, unsigned int sourceHeight, BufferFormat fmt);
virtual void Render(CRect sourceRect,
CRect destRect,
float contrast,
@@ -90,7 +90,7 @@ protected:
float contrast,
float brightness,
unsigned int flags);
- virtual void SetShaderParameters();
+ virtual void SetShaderParameters(YUVBuffer* YUVbuf);
virtual void ReleaseInternal();
virtual bool UploadToGPU(YUVBuffer* YUVbuf);
diff --git a/xbmc/cores/VideoRenderers/WinRenderer.cpp b/xbmc/cores/VideoRenderers/WinRenderer.cpp
index 104d283437..357fe341b6 100644
--- a/xbmc/cores/VideoRenderers/WinRenderer.cpp
+++ b/xbmc/cores/VideoRenderers/WinRenderer.cpp
@@ -527,6 +527,10 @@ void CWinRenderer::UpdatePSVideoFilter()
{
SAFE_RELEASE(m_scalerShader)
+ BufferFormat format;
+ if (CONF_FLAGS_FORMAT_MASK(m_flags) == CONF_FLAGS_FORMAT_YV12) format = YV12;
+ else if (CONF_FLAGS_FORMAT_MASK(m_flags) == CONF_FLAGS_FORMAT_NV12) format = NV12;
+
if (m_bUseHQScaler)
{
m_scalerShader = new CConvolutionShader();
@@ -552,7 +556,7 @@ void CWinRenderer::UpdatePSVideoFilter()
if (m_bUseHQScaler)
{
m_colorShader = new CYUV2RGBShader();
- if (!m_colorShader->Create(false, m_sourceWidth, m_sourceHeight))
+ if (!m_colorShader->Create(false, m_sourceWidth, m_sourceHeight, format))
{
m_IntermediateTarget.Release();
SAFE_RELEASE(m_scalerShader)
@@ -564,7 +568,7 @@ void CWinRenderer::UpdatePSVideoFilter()
if (!m_bUseHQScaler) //fallback from HQ scalers and multipass creation above
{
m_colorShader = new CYUV2RGBShader();
- if (!m_colorShader->Create(true, m_sourceWidth, m_sourceHeight))
+ if (!m_colorShader->Create(true, m_sourceWidth, m_sourceHeight, format))
SAFE_RELEASE(m_colorShader);
// we're in big trouble - should fallback on D3D accelerated or sw method
}
@@ -674,35 +678,46 @@ void CWinRenderer::Render(DWORD flags)
void CWinRenderer::RenderSW()
{
+ enum PixelFormat format;
+
+ if (CONF_FLAGS_FORMAT_MASK(m_flags) == CONF_FLAGS_FORMAT_YV12) format = PIX_FMT_YUV420P;
+ else if (CONF_FLAGS_FORMAT_MASK(m_flags) == CONF_FLAGS_FORMAT_NV12) format = PIX_FMT_NV12;
+
// 1. convert yuv to rgb
m_sw_scale_ctx = m_dllSwScale->sws_getCachedContext(m_sw_scale_ctx,
- m_sourceWidth, m_sourceHeight, PIX_FMT_YUV420P,
+ m_sourceWidth, m_sourceHeight, format,
m_sourceWidth, m_sourceHeight, PIX_FMT_BGRA,
SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL);
YUVBuffer* buf = (YUVBuffer*)m_VideoBuffers[m_iYV12RenderBuffer];
- D3DLOCKED_RECT srclr[3];
- if(!(buf->planes[0].texture.LockRect(0, &srclr[0], NULL, D3DLOCK_READONLY))
- || !(buf->planes[1].texture.LockRect(0, &srclr[1], NULL, D3DLOCK_READONLY))
- || !(buf->planes[2].texture.LockRect(0, &srclr[2], NULL, D3DLOCK_READONLY)))
- CLog::Log(LOGERROR, __FUNCTION__" - failed to lock yuv textures into memory");
+ D3DLOCKED_RECT srclr[MAX_PLANES];
+ uint8_t *src[MAX_PLANES];
+ int srcStride[MAX_PLANES];
+
+ for (unsigned int idx = 0; idx < buf->GetActivePlanes(); idx++)
+ {
+ if(!(buf->planes[idx].texture.LockRect(0, &srclr[idx], NULL, D3DLOCK_READONLY)))
+ CLog::Log(LOGERROR, __FUNCTION__" - failed to lock yuv textures into memory");
+ else
+ {
+ src[idx] = (uint8_t*)srclr[idx].pBits;
+ srcStride[idx] = srclr[idx].Pitch;
+ }
+ }
D3DLOCKED_RECT destlr = {0,0};
if (!m_SWTarget.LockRect(0, &destlr, NULL, D3DLOCK_DISCARD))
CLog::Log(LOGERROR, __FUNCTION__" - failed to lock swtarget texture into memory");
- uint8_t *src[] = { (uint8_t*)srclr[0].pBits, (uint8_t*)srclr[1].pBits, (uint8_t*)srclr[2].pBits, 0 };
- int srcStride[] = { srclr[0].Pitch, srclr[1].Pitch, srclr[2].Pitch, 0 };
uint8_t *dst[] = { (uint8_t*) destlr.pBits, 0, 0, 0 };
int dstStride[] = { destlr.Pitch, 0, 0, 0 };
m_dllSwScale->sws_scale(m_sw_scale_ctx, src, srcStride, 0, m_sourceHeight, dst, dstStride);
- if(!(buf->planes[0].texture.UnlockRect(0))
- || !(buf->planes[1].texture.UnlockRect(0))
- || !(buf->planes[2].texture.UnlockRect(0)))
- CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock yuv textures");
+ for (unsigned int idx = 0; idx < buf->GetActivePlanes(); idx++)
+ if(!(buf->planes[idx].texture.UnlockRect(0)))
+ CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock yuv textures");
if (!m_SWTarget.UnlockRect(0))
CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock swtarget texture");
@@ -990,7 +1005,11 @@ bool CWinRenderer::CreateYV12Texture(int index)
{
YUVBuffer *buf = new YUVBuffer();
- if (!buf->Create(m_sourceWidth, m_sourceHeight))
+ BufferFormat format;
+ if (CONF_FLAGS_FORMAT_MASK(m_flags) == CONF_FLAGS_FORMAT_YV12) format = YV12;
+ else if (CONF_FLAGS_FORMAT_MASK(m_flags) == CONF_FLAGS_FORMAT_NV12) format = NV12;
+
+ if (!buf->Create(format, m_sourceWidth, m_sourceHeight))
{
CLog::Log(LOGERROR, __FUNCTION__" - Unable to create YV12 video texture %i", index);
return false;
@@ -1085,8 +1104,9 @@ YUVBuffer::~YUVBuffer()
Release();
}
-bool YUVBuffer::Create(unsigned int width, unsigned int height)
+bool YUVBuffer::Create(BufferFormat format, unsigned int width, unsigned int height)
{
+ m_format = format;
m_width = width;
m_height = height;
@@ -1095,17 +1115,36 @@ bool YUVBuffer::Create(unsigned int width, unsigned int height)
// - Dynamic + D3DPOOL_DEFAULT caused trouble for Intel i3 and some IGP. Bad sync/locking in the driver I suppose
// and Present failed every second time for the second video played.
// - this is what D3D9 does behind the scenes anyway
- if ( !planes[PLANE_Y].texture.Create(m_width , m_height , 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
- || !planes[PLANE_U].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
- || !planes[PLANE_V].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM))
+ switch(m_format)
+ {
+ case YV12:
+ {
+ if ( !planes[PLANE_Y].texture.Create(m_width , m_height , 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
+ || !planes[PLANE_U].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
+ || !planes[PLANE_V].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM))
+ return false;
+ m_activeplanes = 3;
+ break;
+ }
+ case NV12:
+ {
+ if ( !planes[PLANE_Y].texture.Create(m_width , m_height , 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
+ || !planes[PLANE_UV].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_A8L8, D3DPOOL_SYSTEMMEM))
+ return false;
+ m_activeplanes = 2;
+ break;
+ }
+ default:
+ m_activeplanes = 0;
return false;
+ }
return true;
}
void YUVBuffer::Release()
{
- for(unsigned i = 0; i < MAX_PLANES; i++)
+ for(unsigned i = 0; i < m_activeplanes; i++)
{
planes[i].texture.Release();
memset(&planes[i].rect, 0, sizeof(planes[i].rect));
@@ -1114,7 +1153,7 @@ void YUVBuffer::Release()
void YUVBuffer::StartRender()
{
- for(unsigned i = 0; i < MAX_PLANES; i++)
+ for(unsigned i = 0; i < m_activeplanes; i++)
{
if(planes[i].texture.Get() && planes[i].rect.pBits)
if (!planes[i].texture.UnlockRect(0))
@@ -1125,7 +1164,7 @@ void YUVBuffer::StartRender()
void YUVBuffer::StartDecode()
{
- for(unsigned i = 0; i < MAX_PLANES; i++)
+ for(unsigned i = 0; i < m_activeplanes; i++)
{
if(planes[i].texture.Get()
&& planes[i].texture.LockRect(0, &planes[i].rect, NULL, D3DLOCK_DISCARD) == false)
@@ -1138,9 +1177,22 @@ void YUVBuffer::StartDecode()
void YUVBuffer::Clear()
{
- memset(planes[PLANE_Y].rect.pBits, 0, planes[PLANE_Y].rect.Pitch * m_height);
- memset(planes[PLANE_U].rect.pBits, 128, planes[PLANE_U].rect.Pitch * (m_height/2));
- memset(planes[PLANE_V].rect.pBits, 128, planes[PLANE_V].rect.Pitch * (m_height/2));
+ switch(m_format)
+ {
+ case YV12:
+ {
+ memset(planes[PLANE_Y].rect.pBits, 0, planes[PLANE_Y].rect.Pitch * m_height);
+ memset(planes[PLANE_U].rect.pBits, 128, planes[PLANE_U].rect.Pitch * (m_height/2));
+ memset(planes[PLANE_V].rect.pBits, 128, planes[PLANE_V].rect.Pitch * (m_height/2));
+ break;
+ }
+ case NV12:
+ {
+ memset(planes[PLANE_Y].rect.pBits, 0, planes[PLANE_Y].rect.Pitch * m_height);
+ memset(planes[PLANE_UV].rect.pBits, 128, planes[PLANE_U].rect.Pitch * (m_height/2));
+ break;
+ }
+ }
}
//==================================
diff --git a/xbmc/cores/VideoRenderers/WinRenderer.h b/xbmc/cores/VideoRenderers/WinRenderer.h
index 28c2f15a1d..2f98184c06 100644
--- a/xbmc/cores/VideoRenderers/WinRenderer.h
+++ b/xbmc/cores/VideoRenderers/WinRenderer.h
@@ -115,11 +115,20 @@ enum RenderMethod
#define PLANE_Y 0
#define PLANE_U 1
#define PLANE_V 2
+#define PLANE_UV 1
#define FIELD_FULL 0
#define FIELD_TOP 1
#define FIELD_BOT 2
+enum BufferFormat
+{
+ YV12,
+ NV12,
+ YUY2,
+ UYVY
+};
+
struct SVideoBuffer
{
virtual ~SVideoBuffer() {}
@@ -139,17 +148,20 @@ struct SVideoPlane
struct YUVBuffer : SVideoBuffer
{
~YUVBuffer();
- bool Create(unsigned int width, unsigned int height);
+ bool Create(BufferFormat format, unsigned int width, unsigned int height);
virtual void Release();
virtual void StartDecode();
virtual void StartRender();
virtual void Clear();
+ unsigned int GetActivePlanes() { return m_activeplanes; }
SVideoPlane planes[MAX_PLANES];
private:
unsigned int m_width;
unsigned int m_height;
+ BufferFormat m_format;
+ unsigned int m_activeplanes;
};
struct DXVABuffer : SVideoBuffer