Merge pull request #375 from PatrickvL/master

Simpler overlay conversion and other tidbits
This commit is contained in:
Luke Usher 2017-04-18 12:13:06 +01:00 committed by GitHub
commit aac42a9af6
6 changed files with 125 additions and 418 deletions

View File

@ -283,7 +283,6 @@ $(SOLUTIONDIR)Export.bat</Command>
<ClInclude Include="..\..\src\CxbxKrnl\HLEDataBase\XOnline.1.0.5849.h" />
<ClInclude Include="..\..\src\CxbxKrnl\HLEIntercept.h" />
<ClInclude Include="..\..\src\CxbxKrnl\LibRc4.h" />
<ClInclude Include="..\..\src\CxbxKrnl\libyuv_extract.h" />
<ClInclude Include="..\..\src\CxbxKrnl\MemoryManager.h" />
<ClInclude Include="..\..\src\CxbxKrnl\nv2a_int.h" />
<ClInclude Include="..\..\src\CxbxKrnl\OOVPA.h" />
@ -544,7 +543,6 @@ $(SOLUTIONDIR)Export.bat</Command>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="..\..\src\CxbxKrnl\LibRc4.cpp" />
<ClCompile Include="..\..\src\CxbxKrnl\libyuv_extract.cpp" />
<ClCompile Include="..\..\src\CxbxKrnl\MemoryManager.cpp" />
<ClCompile Include="..\..\src\CxbxKrnl\ResourceTracker.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

View File

@ -199,9 +199,6 @@
<ClCompile Include="..\..\src\Cxbx\DlgAbout.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="..\..\src\CxbxKrnl\libyuv_extract.cpp">
<Filter>Emulator</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\Cxbx\DlgControllerConfig.h">
@ -552,9 +549,6 @@
<ClInclude Include="..\..\src\Cxbx\DlgAbout.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="..\..\src\CxbxKrnl\libyuv_extract.h">
<Filter>Emulator</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\resource\About.jpg">

View File

@ -53,7 +53,6 @@ namespace xboxkrnl
#include "EmuAlloc.h"
#include "MemoryManager.h"
#include "EmuXTL.h"
#include "libyuv_extract.h" // for YUY2ToARGB
#include <assert.h>
#include <process.h>
@ -1324,7 +1323,7 @@ static void EmuUnswizzleTextureStages()
// break;
//CxbxKrnlCleanup("Temporarily unsupported format for active texture unswizzle (0x%.08X)", SurfaceDesc.Format);
hRet = pTexture->LockRect(v, &LockedRect, NULL, NULL);
hRet = pTexture->LockRect(v, &LockedRect, NULL, 0);
if(FAILED(hRet))
continue;
@ -1336,7 +1335,7 @@ static void EmuUnswizzleTextureStages()
RECT iRect = {0,0,0,0};
POINT iPoint = {0,0};
void *pTemp = malloc(dwHeight*dwPitch);
void *pTemp = malloc(dwPitch*dwHeight);
XTL::EmuUnswizzleRect
(
@ -3210,7 +3209,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_CreateTexture)
*/
D3DLOCKED_RECT LockedRect;
pTexture->EmuTexture8->LockRect(0, &LockedRect, NULL, NULL);
pTexture->EmuTexture8->LockRect(0, &LockedRect, NULL, D3DLOCK_READONLY);
Texture_Data = (DWORD)LockedRect.pBits;
g_DataToTexture.insert(Texture_Data, pTexture);
pTexture->EmuTexture8->UnlockRect(0);
@ -4255,6 +4254,8 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_Clear)
return ret;
}
#define CXBX_SWAP_PRESENT_FORWARD (256 + 4 + 1) // = CxbxPresentForwardMarker + D3DSWAP_FINISH + D3DSWAP_COPY
// ******************************************************************
// * patch: D3DDevice_Present
// ******************************************************************
@ -4266,8 +4267,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_Present)
PVOID pDummy2
)
{
// LOG_FORWARD("D3DDevice_Swap");
DbgPrintf("EmuD3D8: EmuD3DDevice_Present\n"
"(\n"
" pSourceRect : 0x%.08X\n"
@ -4277,7 +4277,27 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_Present)
");\n",
pSourceRect, pDestRect, pDummy1, pDummy2);
HRESULT hRet = S_OK;
return EMUPATCH(D3DDevice_Swap)(CXBX_SWAP_PRESENT_FORWARD); // Xbox present ignores
}
// ******************************************************************
// * patch: D3DDevice_Swap
// ******************************************************************
DWORD WINAPI XTL::EMUPATCH(D3DDevice_Swap)
(
DWORD Flags
)
{
DbgPrintf("EmuD3D8: EmuD3DDevice_Swap\n"
"(\n"
" Flags : 0x%.08X\n"
");\n",
Flags);
// TODO: Ensure this flag is always the same across library versions
if(Flags != 0)
if (Flags != CXBX_SWAP_PRESENT_FORWARD) // Avoid a warning when forwarded
EmuWarning("XTL::EmuD3DDevice_Swap: Flags != 0");
CxbxReleaseBackBufferLock();
@ -4287,8 +4307,10 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_Present)
// g_pDD7->WaitForVerticalBlank( DDWAITVB_BLOCKEND, NULL );
// g_pDD7->WaitForVerticalBlank( DDWAITVB_BLOCKEND, NULL );
hRet = g_pD3DDevice8->Present(pSourceRect, pDestRect, (HWND)pDummy1, (CONST RGNDATA*)pDummy2);
g_pD3DDevice8->Present(0, 0, 0, 0);
if (Flags == CXBX_SWAP_PRESENT_FORWARD) // Only do this when forwarded from Present
{
// Put primitives per frame in the title
/*{
char szString[64];
@ -4300,6 +4322,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_Present)
g_dwPrimPerFrame = 0;
}*/
// TODO : Check if this should be done at Swap-not-Present-time too :
// not really accurate because you definately dont always present on every vblank
g_VBData.Swap = g_VBData.VBlank;
@ -4310,6 +4333,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_Present)
g_VBData.Flags = 2; // D3DVBLANK_SWAPMISSED
g_SwapData.MissedVBlanks++;
}
}
// Handle Swap Callback function
{
@ -4325,58 +4349,13 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_Present)
g_bHackUpdateSoftwareOverlay = FALSE;
DWORD result;
if (Flags == CXBX_SWAP_PRESENT_FORWARD) // Only do this when forwarded from Present
result = S_OK; // Present always returns success
else
result = g_SwapData.Swap; // Swap returns number of swaps
return hRet;
}
// ******************************************************************
// * patch: D3DDevice_Swap
// ******************************************************************
HRESULT WINAPI XTL::EMUPATCH(D3DDevice_Swap)
(
DWORD Flags
)
{
DbgPrintf("EmuD3D8: EmuD3DDevice_Swap\n"
"(\n"
" Flags : 0x%.08X\n"
");\n",
Flags);
// TODO: Ensure this flag is always the same across library versions
if(Flags != 0)
EmuWarning("XTL::EmuD3DDevice_Swap: Flags != 0");
CxbxReleaseBackBufferLock();
// TODO: Make a video option to wait for VBlank before calling Present.
// Makes syncing to 30fps easier (which is the native frame rate for Azurik
// and Halo).
// g_pDD7->WaitForVerticalBlank( DDWAITVB_BLOCKEND, NULL );
// g_pDD7->WaitForVerticalBlank( DDWAITVB_BLOCKEND, NULL );
HRESULT hRet = g_pD3DDevice8->Present(0, 0, 0, 0);
// Handle Swap Callback function
{
g_SwapData.Swap++;
if(g_pSwapCallback != NULL)
{
g_pSwapCallback(&g_SwapData);
}
}
g_bHackUpdateSoftwareOverlay = FALSE;
return hRet;
return result;
}
// ******************************************************************
@ -4838,10 +4817,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DResource_Register)
}
}
RECT iRect = {0,0,0,0};
POINT iPoint = {0,0};
BYTE *pSrc = (BYTE*)pBase;
BYTE *pSrc = (BYTE*)pBase; // TODO : Fix (look at Dxbx) this, as it gives cube textures identical sides
if(( pResource->Data == X_D3DRESOURCE_DATA_BACK_BUFFER)
||( (DWORD)pBase == X_D3DRESOURCE_DATA_BACK_BUFFER))
@ -4868,10 +4844,17 @@ HRESULT WINAPI XTL::EMUPATCH(D3DResource_Register)
// TODO: Fix or handle this situation..?
// This is probably an unallocated resource, mapped into contiguous memory (0x80000000)
}
else if (pSrc == nullptr)
{
// TODO: Fix or handle this situation..?
}
else
{
if (bSwizzled)
{
RECT iRect = { 0,0,0,0 };
POINT iPoint = { 0,0 };
// First we need to unswizzle the texture data
XTL::EmuUnswizzleRect
(
@ -4889,10 +4872,23 @@ HRESULT WINAPI XTL::EMUPATCH(D3DResource_Register)
}
else
{
/* TODO : // Let DirectX convert the surface (including palette formats) :
if(!EmuXBFormatRequiresConversionToARGB) {
D3DXLoadSurfaceFromMemory(
pResource->EmuSurface8,
nullptr, // no destination palette
&destRect,
pSrc, // Source buffer
dwMipPitch, // Source pitch
pCurrentPalette,
&SrcRect,
D3DX_DEFAULT, // D3DX_FILTER_NONE,
0 // No ColorKey?
);
} else {
*/
BYTE *pDest = (BYTE*)LockedRect.pBits;
if (pSrc)
{
if ((DWORD)LockedRect.Pitch == dwMipPitch && dwMipPitch == dwMipWidth*dwBPP)
{
memcpy(pDest, pSrc + dwMipOffs, dwMipWidth*dwMipHeight*dwBPP);
@ -4908,7 +4904,6 @@ HRESULT WINAPI XTL::EMUPATCH(D3DResource_Register)
}
}
}
}
if (CacheFormat != 0) // Do we need to convert to ARGB?
{
@ -6040,27 +6035,6 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_EnableOverlay)
return;
}
XTL::IDirect3DSurface8 *ExtraXRGBSurface = nullptr; // this is our pointer to the memory location containing our copy of the front buffer
void AssureExtraXRGBSurface(XTL::IDirect3DSurface8 *pBackBufferSurface, std::string Caller)
{
XTL::D3DSURFACE_DESC SurfaceDesc;
HRESULT aResult;
// Assure we have a reusable surface (in the correct format) which the back buffer can be converted into :
if (ExtraXRGBSurface == nullptr) {
pBackBufferSurface->GetDesc(&SurfaceDesc);
aResult = g_pD3DDevice8->CreateImageSurface(
SurfaceDesc.Width,
SurfaceDesc.Height,
XTL::D3DFMT_A8R8G8B8, // This format is supported by D3DXSaveSurfaceToFile (D3DFMT_X8R8G8B8 works too)
&ExtraXRGBSurface);
if FAILED(aResult) {
// DbgPrintf("EmuD3D8 : %s could not create a extra buffer!\n", DxbxD3DErrorString(aResult), Caller);
}
}
}
// ******************************************************************
// * patch: D3DDevice_UpdateOverlay
// ******************************************************************
@ -6129,10 +6103,14 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
}
}
RECT SourRect = { 0, 0, (LONG)g_dwOverlayW, (LONG)g_dwOverlayH };
if (SrcRect != NULL)
SourRect = *SrcRect;
// update overlay!
if(g_bSupportsYUY2)
{
RECT SourRect = {0, 0, (LONG)g_dwOverlayW, (LONG)g_dwOverlayH}, DestRect;
RECT DestRect;
MONITORINFO MonitorInfo = {0};
int nTitleHeight = 0;//GetSystemMetrics(SM_CYCAPTION);
@ -6167,72 +6145,53 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
{
IDirect3DSurface8 *pBackBufferSurface = nullptr;
HRESULT hRet = g_pD3DDevice8->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pBackBufferSurface);
// if we obtained the backbuffer, manually translate the YUY2 into the backbuffer format
// if we obtained the backbuffer, load the YUY2 into the backbuffer
if (hRet == D3D_OK) {
IDirect3DSurface8 *pOverlayBufferSurface = nullptr;
D3DLOCKED_RECT LockedRectDest;
// Get backbuffer dimenions; TODO : remember this once, at creation/resize time
D3DSURFACE_DESC BackBufferDesc;
pBackBufferSurface->GetDesc(&BackBufferDesc);
// Determine if the overlay can be written directly to the backbuffer :
bool CanWriteToBackbuffer = false;
if ((BackBufferDesc.Format == D3DFMT_A8R8G8B8) || (BackBufferDesc.Format == D3DFMT_X8R8G8B8)) {
if (DstRect == SrcRect) {
CanWriteToBackbuffer = true;
} else {
if (DstRect != nullptr && SrcRect != nullptr) {
if ((DstRect->left == SrcRect->left)
&& (DstRect->right == SrcRect->right)
&& (DstRect->top == SrcRect->top)
&& (DstRect->bottom == SrcRect->bottom)) {
CanWriteToBackbuffer = true;
}
}
}
}
// If we can write to the back buffer, work with that, else use the screenshotbuffer as temporary surface :
if (CanWriteToBackbuffer) {
pOverlayBufferSurface = pBackBufferSurface;
} else {
AssureExtraXRGBSurface(pBackBufferSurface, "EmuD3DDevice_UpdateOverlay");
pOverlayBufferSurface = ExtraXRGBSurface; // Note : This surface is always in ARGB format
}
// Manually translate the YUY2 formatted input surface into the RGB buffer of the pre-determined output surface :
if (pOverlayBufferSurface->LockRect(&LockedRectDest, DstRect, 0) == D3D_OK) {
// Determine the start of the Xbox overlay buffer and Native destination buffer :
uint08 *pYUY2Input = (uint08*)pSurface->Lock; // TODO : DxbxGetDataFromXboxResource(pSurface);
uint08 *pARGBOutput = (uint08*)LockedRectDest.pBits;
// Limit the width and height of the output to the backbuffer dimensions.
// This will (hopefully) prevent exceptions in Blinx - The Time Sweeper
// (see https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues/285)
uint32 W = min(g_dwOverlayW, BackBufferDesc.Width);
uint32 H = min(g_dwOverlayH, BackBufferDesc.Height);
RECT DestRect = { 0 };
{
// If there's a destination rectangle given, copy that into our local variable :
if (DstRect != NULL)
DestRect = *DstRect;
// full color conversion (YUY2->XRGB)
YUY2ToARGB(pYUY2Input, g_dwOverlayP, pARGBOutput, LockedRectDest.Pitch, W, H);
// Use our (bounded) copy when bounds exceed :
if (DestRect.right > BackBufferDesc.Width) {
DestRect.right = BackBufferDesc.Width;
DstRect = &DestRect;
}
pOverlayBufferSurface->UnlockRect(); // TODO : Could this be done after calling D3DXLoadSurfaceFromSurface (and would that improve performance)?
if (g_dwOverlayH > BackBufferDesc.Height) {
DestRect.bottom = BackBufferDesc.Height;
DstRect = &DestRect;
}
}
if (!CanWriteToBackbuffer) {
// When the overlay could not directly be converted into the back buffer,
// we now have to stretch-copy there (this also does a format-conversion, if needed) :
if (D3DXLoadSurfaceFromSurface(
uint08 *pYUY2Input = (uint08*)pSurface->Lock; // TODO : DxbxGetDataFromXboxResource(pSurface);
// Use D3DXLoadSurfaceFromMemory() to do conversion, stretching and filtering
// avoiding the need for YUY2toARGB() (might become relevant when porting to D3D9 or OpenGL)
// see https://msdn.microsoft.com/en-us/library/windows/desktop/bb172902(v=vs.85).aspx
hRet = D3DXLoadSurfaceFromMemory(
/* pDestSurface = */ pBackBufferSurface,
/* pDestPalette = */ nullptr, // Palette not needed for YUY2
DstRect,
/* pSrcSurface = */ pOverlayBufferSurface,
/* pDestRect = */DstRect, // Either the unmodified original (can be NULL) or a pointer to our local variable
/* pSrcMemory = */ pYUY2Input, // Source buffer
/* SrcFormat = */ D3DFMT_YUY2,
/* SrcPitch = */ g_dwOverlayP,
/* pSrcPalette = */ nullptr, // Palette not needed for YUY2
SrcRect,
/* pSrcRect = */ &SourRect,
/* Filter = */ D3DX_FILTER_POINT, // Dxbx note : D3DX_FILTER_LINEAR gives a smoother image, but 'bleeds' across borders
/* ColorKey = */ ColorKey) != D3D_OK) {
/* ColorKey = */ EnableColorKey ? ColorKey : 0);
if (hRet != D3D_OK) {
DbgPrintf("EmuD3D8 : UpdateOverlay could not convert buffer!\n");
}
}
//DbgPrintf("EmuD3D8 : Error: %s error description: %s\n",
// DXGetErrorString(hRet), DXGetErrorDescription(hRet));
}
pBackBufferSurface->Release();
@ -9702,7 +9661,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_PersistDisplay)()
{
void* ptr = g_MemoryManager.Allocate( BackBufferDesc.Width * BackBufferDesc.Height * dwBytesPerPixel );
if( SUCCEEDED( pBackBuffer->LockRect( &LockedRect, NULL, 0 ) ) )
if( SUCCEEDED( pBackBuffer->LockRect( &LockedRect, NULL, D3DLOCK_READONLY ) ) )
{
CopyMemory( ptr, LockedRect.pBits, BackBufferDesc.Width * BackBufferDesc.Height * dwBytesPerPixel );

View File

@ -669,7 +669,7 @@ HRESULT WINAPI EMUPATCH(D3DDevice_Present)
// ******************************************************************
// * patch: D3DDevice_Swap
// ******************************************************************
HRESULT WINAPI EMUPATCH(D3DDevice_Swap)
DWORD WINAPI EMUPATCH(D3DDevice_Swap)
(
DWORD Flags
);

View File

@ -1,226 +0,0 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include "libyuv_extract.h"
// The following code is an extract of libyuv to keep code size low (this may be revisited later).
// Source : https://github.com/lemenkov/libyuv/commit/7e936044d154b9fe159a67f9562e10b1ef1cb590
/* From libyuv\README.chromium :
Name: libyuv
URL: http://code.google.com/p/libyuv/
Version: 1514
License: BSD
License File: LICENSE
Description:
libyuv is an open source project that includes YUV conversion and scaling functionality.
*/
// From libyuv\include\libyuv\row.h :
// This struct is for Intel color conversion.
struct YuvConstants {
int8 kUVToB[32];
int8 kUVToG[32];
int8 kUVToR[32];
int16 kUVBiasB[16];
int16 kUVBiasG[16];
int16 kUVBiasR[16];
int16 kYToRgb[16];
};
// From libyuv\include\libyuv\row.h :
#if defined(VISUALC_HAS_AVX2)
#define SIMD_ALIGNED(var) __declspec(align(32)) var
#else
#define SIMD_ALIGNED(var) __declspec(align(16)) var
#endif
// From libyuv\source\row_common.cc :
// llvm x86 is poor at ternary operator, so use branchless min/max.
#define USE_BRANCHLESS 1
#if USE_BRANCHLESS
static __inline int32 clamp0(int32 v) {
return ((-(v) >> 31) & (v));
}
static __inline int32 clamp255(int32 v) {
return (((255 - (v)) >> 31) | (v)) & 255;
}
static __inline uint32 Clamp(int32 val) {
int v = clamp0(val);
return (uint32)(clamp255(v));
}
static __inline uint32 Abs(int32 v) {
int m = v >> 31;
return (v + m) ^ m;
}
#else // USE_BRANCHLESS
static __inline int32 clamp0(int32 v) {
return (v < 0) ? 0 : v;
}
static __inline int32 clamp255(int32 v) {
return (v > 255) ? 255 : v;
}
static __inline uint32 Clamp(int32 val) {
int v = clamp0(val);
return (uint32)(clamp255(v));
}
static __inline uint32 Abs(int32 v) {
return (v < 0) ? -v : v;
}
#endif // USE_BRANCHLESS
// From libyuv\source\row_common.cc :
// BT.601 YUV to RGB reference
// R = (Y - 16) * 1.164 - V * -1.596
// G = (Y - 16) * 1.164 - U * 0.391 - V * 0.813
// B = (Y - 16) * 1.164 - U * -2.018
// Y contribution to R,G,B. Scale and bias.
#define YG 18997 /* round(1.164 * 64 * 256 * 256 / 257) */
#define YGB -1160 /* 1.164 * 64 * -16 + 64 / 2 */
// U and V contributions to R,G,B.
#define UB -128 /* max(-128, round(-2.018 * 64)) */
#define UG 25 /* round(0.391 * 64) */
#define VG 52 /* round(0.813 * 64) */
#define VR -102 /* round(-1.596 * 64) */
// Bias values to subtract 16 from Y and 128 from U and V.
#define BB (UB * 128 + YGB)
#define BG (UG * 128 + VG * 128 + YGB)
#define BR (VR * 128 + YGB)
const struct YuvConstants SIMD_ALIGNED(kYuvI601Constants) = {
{ UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0,
UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0 },
{ UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG,
UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG },
{ 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR,
0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR },
{ BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB },
{ BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG },
{ BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR },
{ YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG } };
// C reference code that mimics the YUV assembly.
static __inline void YuvPixel(uint8 y,
uint8 u,
uint8 v,
uint8* b,
uint8* g,
uint8* r,
const struct YuvConstants* yuvconstants) {
int ub = yuvconstants->kUVToB[0];
int ug = yuvconstants->kUVToG[0];
int vg = yuvconstants->kUVToG[1];
int vr = yuvconstants->kUVToR[1];
int bb = yuvconstants->kUVBiasB[0];
int bg = yuvconstants->kUVBiasG[0];
int br = yuvconstants->kUVBiasR[0];
int yg = yuvconstants->kYToRgb[0];
uint32 y1 = (uint32)(y * 0x0101 * yg) >> 16;
*b = Clamp((int32)(-(u * ub) + y1 + bb) >> 6);
*g = Clamp((int32)(-(u * ug + v * vg) + y1 + bg) >> 6);
*r = Clamp((int32)(-(v * vr) + y1 + br) >> 6);
}
void YUY2ToARGBRow_C(const uint8* src_yuy2,
uint8* rgb_buf,
const struct YuvConstants* yuvconstants,
int width) {
int x;
for (x = 0; x < width - 1; x += 2) {
YuvPixel(src_yuy2[0], src_yuy2[1], src_yuy2[3], rgb_buf + 0, rgb_buf + 1,
rgb_buf + 2, yuvconstants);
rgb_buf[3] = 255;
YuvPixel(src_yuy2[2], src_yuy2[1], src_yuy2[3], rgb_buf + 4, rgb_buf + 5,
rgb_buf + 6, yuvconstants);
rgb_buf[7] = 255;
src_yuy2 += 4;
rgb_buf += 8; // Advance 2 pixels.
}
if (width & 1) {
YuvPixel(src_yuy2[0], src_yuy2[1], src_yuy2[3], rgb_buf + 0, rgb_buf + 1,
rgb_buf + 2, yuvconstants);
rgb_buf[3] = 255;
}
}
// Convert YUY2 to ARGB.
LIBYUV_API
int YUY2ToARGB(const uint8* src_yuy2,
int src_stride_yuy2,
uint8* dst_argb,
int dst_stride_argb,
int width,
int height) {
int y;
void(*YUY2ToARGBRow)(const uint8* src_yuy2, uint8* dst_argb,
const struct YuvConstants* yuvconstants, int width) =
YUY2ToARGBRow_C;
if (!src_yuy2 || !dst_argb || width <= 0 || height == 0) {
return -1;
}
// Negative height means invert the image.
if (height < 0) {
height = -height;
src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
src_stride_yuy2 = -src_stride_yuy2;
}
// Coalesce rows.
if (src_stride_yuy2 == width * 2 && dst_stride_argb == width * 4) {
width *= height;
height = 1;
src_stride_yuy2 = dst_stride_argb = 0;
}
#if defined(HAS_YUY2TOARGBROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3)) {
YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3;
if (IS_ALIGNED(width, 16)) {
YUY2ToARGBRow = YUY2ToARGBRow_SSSE3;
}
}
#endif
#if defined(HAS_YUY2TOARGBROW_AVX2)
if (TestCpuFlag(kCpuHasAVX2)) {
YUY2ToARGBRow = YUY2ToARGBRow_Any_AVX2;
if (IS_ALIGNED(width, 32)) {
YUY2ToARGBRow = YUY2ToARGBRow_AVX2;
}
}
#endif
#if defined(HAS_YUY2TOARGBROW_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON;
if (IS_ALIGNED(width, 8)) {
YUY2ToARGBRow = YUY2ToARGBRow_NEON;
}
}
#endif
#if defined(HAS_YUY2TOARGBROW_MSA)
if (TestCpuFlag(kCpuHasMSA)) {
YUY2ToARGBRow = YUY2ToARGBRow_Any_MSA;
if (IS_ALIGNED(width, 8)) {
YUY2ToARGBRow = YUY2ToARGBRow_MSA;
}
}
#endif
for (y = 0; y < height; ++y) {
YUY2ToARGBRow(src_yuy2, dst_argb, &kYuvI601Constants, width);
src_yuy2 += src_stride_yuy2;
dst_argb += dst_stride_argb;
}
return 0;
}

View File

@ -1,18 +0,0 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include "Cxbx.h"
typedef int08 int8;
typedef uint08 uint8;
// From libyuv\include\libyuv\basic_types.h :
#define LIBYUV_API
LIBYUV_API
int YUY2ToARGB(const uint8* src_yuy2,
int src_stride_yuy2,
uint8* dst_argb,
int dst_stride_argb,
int width,
int height);