diff options
author | CrystalP <CrystalP@xbmc.org> | 2011-01-31 02:47:18 -0500 |
---|---|---|
committer | CrystalP <CrystalP@xbmc.org> | 2011-02-06 20:45:14 -0500 |
commit | 3d246e09f59bbca661570624bde000d62d79408a (patch) | |
tree | ce56c1a3a6819ab9bf701610532bfb6b16997011 | |
parent | 6e2c48f4f4677ed7ae22aa2a8b0edaade9a80fee (diff) |
[WIN32] add nv12 rendering (software and ps)
-rw-r--r-- | system/shaders/yuv2rgb_d3d.fx | 6 | ||||
-rw-r--r-- | xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.cpp | 40 | ||||
-rw-r--r-- | xbmc/cores/VideoRenderers/VideoShaders/WinVideoFilter.h | 4 | ||||
-rw-r--r-- | xbmc/cores/VideoRenderers/WinRenderer.cpp | 102 | ||||
-rw-r--r-- | xbmc/cores/VideoRenderers/WinRenderer.h | 14 |
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 |