From 7f89750b7b9ced2d7218646fe00501397f895a66 Mon Sep 17 00:00:00 2001 From: PatrickvL Date: Tue, 1 Jun 2021 11:54:02 +0200 Subject: [PATCH] Pass host D3DUsage and D3DFormat along as arguments to the SetHostResource registration function (and only use GetDesc if the caller doesn't have access to those variables). This results in seemingly correct values in g_HostTextureFormats[], but this hits the next hurdle : XboxColorSign isn't always set when it should be, resulting in unintentional signed_to_unsigned mapping for signed host formats like D3DFMT_L6V5U5 (if natively supported). Another area that still needs improvement, is texture component swizzling (we can determine the requirements from kelvin_color_format_map). --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 160 +++++++--------------- src/core/hle/D3D8/XbPixelShader.cpp | 8 +- 2 files changed, 57 insertions(+), 111 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 9422175ca..3f6065f28 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -1135,7 +1135,7 @@ bool HostResourceRequiresUpdate(resource_key_t key, xbox::X_D3DResource* pXboxRe return modified; } -void SetHostResource(xbox::X_D3DResource* pXboxResource, IDirect3DResource* pHostResource, int iTextureStage = -1, DWORD dwSize = 0) +void SetHostResource(xbox::X_D3DResource* pXboxResource, IDirect3DResource* pHostResource, int iTextureStage = -1, DWORD D3DUsage = D3DUSAGE_INVALID, D3DFORMAT PCFormat = D3DFMT_UNKNOWN) { auto key = GetHostResourceKey(pXboxResource, iTextureStage); auto& ResourceCache = GetResourceCache(key); @@ -1149,48 +1149,39 @@ void SetHostResource(xbox::X_D3DResource* pXboxResource, IDirect3DResource* pHos resourceInfo.pHostResource = pHostResource; resourceInfo.dwXboxResourceType = GetXboxCommonResourceType(pXboxResource); resourceInfo.pXboxData = GetDataFromXboxResource(pXboxResource); - resourceInfo.szXboxDataSize = dwSize > 0 ? dwSize : GetXboxResourceSize(pXboxResource); + resourceInfo.szXboxDataSize = GetXboxResourceSize(pXboxResource); resourceInfo.hash = ComputeHash(resourceInfo.pXboxData, resourceInfo.szXboxDataSize); resourceInfo.hashLifeTime = 1ms; resourceInfo.lastUpdate = std::chrono::steady_clock::now(); resourceInfo.nextHashTime = resourceInfo.lastUpdate + resourceInfo.hashLifeTime; resourceInfo.forceRehash = false; - - HRESULT hRet = STATUS_INVALID_PARAMETER; // Default to an error condition, so we can use D3D_OK to check for success - D3DSURFACE_DESC surfaceDesc; - D3DVOLUME_DESC volumeDesc; - UINT Level = 0; // TODO : When should Level every be something other than zero, and if so : what other value? - switch (resourceInfo.dwXboxResourceType) {// TODO : Better check pHostResource class type - case xbox::X_D3DRTYPE_SURFACE: - hRet = ((IDirect3DSurface*)pHostResource)->GetDesc(&surfaceDesc); - break; - case xbox::X_D3DRTYPE_TEXTURE: - hRet = ((IDirect3DTexture*)pHostResource)->GetLevelDesc(Level, &surfaceDesc); - break; - case xbox::X_D3DRTYPE_VOLUMETEXTURE: { - hRet = ((IDirect3DVolumeTexture*)pHostResource)->GetLevelDesc(Level, &volumeDesc); - break; } - case xbox::X_D3DRTYPE_CUBETEXTURE: - hRet = ((IDirect3DCubeTexture*)pHostResource)->GetLevelDesc(Level, &surfaceDesc); - break; - } - - D3DFORMAT hostFormat = D3DFMT_UNKNOWN; - DWORD hostUsage = D3DUSAGE_INVALID; - - if (SUCCEEDED(hRet)) { - if (resourceInfo.dwXboxResourceType == xbox::X_D3DRTYPE_VOLUMETEXTURE) { - hostFormat = volumeDesc.Format; - hostUsage = volumeDesc.Usage; + if (PCFormat == D3DFMT_UNKNOWN) { + HRESULT hRet = STATUS_INVALID_PARAMETER; // Default to an error condition, so we can use D3D_OK to check for success + D3DSURFACE_DESC surfaceDesc; + D3DVOLUME_DESC volumeDesc; + UINT Level = 0; // TODO : When should Level every be something other than zero, and if so : what other value? + switch (resourceInfo.dwXboxResourceType) {// TODO : Better check pHostResource class type + case xbox::X_D3DRTYPE_SURFACE: + hRet = ((IDirect3DSurface*)pHostResource)->GetDesc(&surfaceDesc); + break; + case xbox::X_D3DRTYPE_TEXTURE: + hRet = ((IDirect3DTexture*)pHostResource)->GetLevelDesc(Level, &surfaceDesc); + break; + case xbox::X_D3DRTYPE_VOLUMETEXTURE: { + hRet = ((IDirect3DVolumeTexture*)pHostResource)->GetLevelDesc(Level, &volumeDesc); + break; } + case xbox::X_D3DRTYPE_CUBETEXTURE: + hRet = ((IDirect3DCubeTexture*)pHostResource)->GetLevelDesc(Level, &surfaceDesc); + break; } - else { - hostFormat = surfaceDesc.Format; - hostUsage = surfaceDesc.Usage; + + if (SUCCEEDED(hRet)) { + PCFormat = (resourceInfo.dwXboxResourceType == xbox::X_D3DRTYPE_VOLUMETEXTURE) ? volumeDesc.Format : surfaceDesc.Format; } } - resourceInfo.HostFormat = hostFormat; - resourceInfo.HostUsage = hostUsage; + resourceInfo.HostFormat = PCFormat; + resourceInfo.HostUsage = D3DUsage; } IDirect3DSurface *GetHostSurface(xbox::X_D3DResource *pXboxResource, DWORD D3DUsage = 0) @@ -1256,55 +1247,6 @@ IDirect3DIndexBuffer *GetHostIndexBuffer(xbox::X_D3DResource *pXboxResource) } #endif -void SetHostSurface(xbox::X_D3DResource *pXboxResource, IDirect3DSurface *pHostSurface, int iTextureStage) -{ - assert(pXboxResource != xbox::zeroptr); - assert(GetXboxCommonResourceType(pXboxResource) == X_D3DCOMMON_TYPE_SURFACE); - - SetHostResource(pXboxResource, pHostSurface, iTextureStage); -} - -void SetHostTexture(xbox::X_D3DResource *pXboxResource, IDirect3DTexture *pHostTexture, int iTextureStage) -{ - assert(pXboxResource != xbox::zeroptr); - assert(GetXboxCommonResourceType(pXboxResource) == X_D3DCOMMON_TYPE_TEXTURE); - - SetHostResource(pXboxResource, pHostTexture, iTextureStage); -} - -void SetHostCubeTexture(xbox::X_D3DResource *pXboxResource, IDirect3DCubeTexture *pHostCubeTexture, int iTextureStage) -{ - assert(pXboxResource != xbox::zeroptr); - assert(GetXboxCommonResourceType(pXboxResource) == X_D3DCOMMON_TYPE_TEXTURE); - - SetHostResource(pXboxResource, pHostCubeTexture, iTextureStage); -} - -void SetHostVolumeTexture(xbox::X_D3DResource *pXboxResource, IDirect3DVolumeTexture *pHostVolumeTexture, int iTextureStage) -{ - assert(pXboxResource != xbox::zeroptr); - assert(GetXboxCommonResourceType(pXboxResource) == X_D3DCOMMON_TYPE_TEXTURE); - - SetHostResource(pXboxResource, pHostVolumeTexture, iTextureStage); -} - -void SetHostVolume(xbox::X_D3DResource *pXboxResource, IDirect3DVolume *pHostVolume, int iTextureStage) -{ - assert(pXboxResource != xbox::zeroptr); - assert(GetXboxCommonResourceType(pXboxResource) == X_D3DCOMMON_TYPE_TEXTURE); - - // TODO: IDirect3DVolume9 is not a IDirect3DResource9! - SetHostResource(pXboxResource, (IDirect3DResource*)pHostVolume, iTextureStage); -} - -void SetHostIndexBuffer(xbox::X_D3DResource *pXboxResource, IDirect3DIndexBuffer *pHostIndexBuffer) -{ - assert(pXboxResource != xbox::zeroptr); - assert(GetXboxCommonResourceType(pXboxResource) == X_D3DCOMMON_TYPE_INDEXBUFFER); - - SetHostResource(pXboxResource, pHostIndexBuffer); -} - int XboxD3DPaletteSizeToBytes(const xbox::X_D3DPALETTESIZE Size) { /* @@ -3861,21 +3803,24 @@ xbox::X_D3DSurface* CxbxrImpl_GetBackBuffer2 if(BackBuffer == -1) { static IDirect3DSurface *pCachedPrimarySurface = nullptr; + D3DFORMAT PCFormat = D3DFMT_A8R8G8B8; if(pCachedPrimarySurface == nullptr) { // create a buffer to return // TODO: Verify the surface is always 640x480 - hRet = g_pD3DDevice->CreateOffscreenPlainSurface(640, 480, D3DFMT_A8R8G8B8, /*D3DPool=* /0, &pCachedPrimarySurface, nullptr); + hRet = g_pD3DDevice->CreateOffscreenPlainSurface(640, 480, PCFormat, /*D3DPool=* /0, &pCachedPrimarySurface, nullptr); DEBUG_D3DRESULT(hRet, "g_pD3DDevice->CreateOffscreenPlainSurface"); } - SetHostSurface(pXboxBackBuffer, pCachedPrimarySurface); // No iTextureStage! + int iTextureStage = -1; // No iTextureStage! + SetHostResource(pXboxBackBuffer, (IDirect3DResource*)pCachedPrimarySurface, iTextureStage, 0, PCFormat); + hRet = g_pD3DDevice->GetFrontBuffer(pCachedPrimarySurface); DEBUG_D3DRESULT(hRet, "g_pD3DDevice->GetFrontBuffer"); if (FAILED(hRet)) { EmuLog(LOG_LEVEL::WARNING, "Could not retrieve primary surface, using backbuffer"); - SetHostSurface(pXboxBackBuffer, nullptr); // No iTextureStage! + SetHostResource(pXboxBackBuffer, nullptr); // No iTextureStage! pCachedPrimarySurface->Release(); pCachedPrimarySurface = nullptr; BackBuffer = 0; @@ -3908,7 +3853,7 @@ xbox::X_D3DSurface* CxbxrImpl_GetBackBuffer2 if (FAILED(hRet)) CxbxrAbort("Unable to retrieve back buffer"); - SetHostSurface(pXboxBackBuffer, pCurrentHostBackBuffer); // No iTextureStage! + SetHostResource(pXboxBackBuffer, (IDirect3DResource*)pCurrentHostBackBuffer); // No iTextureStage! TODO : Pass in D3DUsage, PCFormat // Increment reference count pXboxBackBuffer->Common++; // EMUPATCH(D3DResource_AddRef)(pXboxBackBuffer); @@ -5523,6 +5468,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex LOG_FUNC_BEGIN LOG_FUNC_ARG(pResource) + LOG_FUNC_ARG(D3DUsage) LOG_FUNC_ARG(iTextureStage) LOG_FUNC_ARG(dwSize) LOG_FUNC_ARG(ResourceTypeName) @@ -5574,7 +5520,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex DEBUG_D3DRESULT(hRet, "pHostParentTexture->GetCubeMapSurface"); if (hRet == D3D_OK) { - SetHostSurface(pXboxSurface, pNewHostSurface.Get(), iTextureStage); + SetHostResource(pXboxSurface, (IDirect3DResource*)pNewHostSurface.Get(), iTextureStage, D3DUsage); // Note : Final PCFormat argument will be derived from the host resource EmuLog(LOG_LEVEL::DEBUG, "CreateHostResource : Successfully created CubeTexture surface level (Face: %u, Level: %u, pResource: 0x%.08X, pNewHostSurface: 0x%.08X)", CubeMapFace, SurfaceLevel, pResource, pNewHostSurface.Get()); return; @@ -5591,7 +5537,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex DEBUG_D3DRESULT(hRet, "pHostParentTexture->GetSurfaceLevel"); if (hRet == D3D_OK) { - SetHostSurface(pXboxSurface, pNewHostSurface.Get(), iTextureStage); + SetHostResource(pResource, (IDirect3DResource*)pNewHostSurface.Get(), iTextureStage, D3DUsage); // Note : Final PCFormat argument will be derived from the host resource EmuLog(LOG_LEVEL::DEBUG, "CreateHostResource : Successfully created Texture surface level (Level: %u, pResource: 0x%.08X, pNewHostSurface: 0x%.08X)", SurfaceLevel, pResource, pNewHostSurface.Get()); return; @@ -5602,7 +5548,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex EmuLog(LOG_LEVEL::WARNING, "Failed getting host surface level - falling through to regular surface creation"); } - // fall through + [[fallthrough]]; } case xbox::X_D3DRTYPE_VOLUME: { // Note : Use and check for null, since X_D3DRTYPE_SURFACE might fall through here (by design) @@ -5616,7 +5562,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex HRESULT hRet = pParentHostVolumeTexture->GetVolumeLevel(VolumeLevel, pNewHostVolume.GetAddressOf()); DEBUG_D3DRESULT(hRet, "pParentHostVolumeTexture->GetVolumeLevel"); if (hRet == D3D_OK) { - SetHostVolume(pXboxVolume, pNewHostVolume.Get(), iTextureStage); + SetHostResource(pResource, (IDirect3DResource*)pNewHostVolume.Get(), iTextureStage, D3DUsage); // Note : Final PCFormat argument will be derived from the host resource EmuLog(LOG_LEVEL::DEBUG, "CreateHostResource : Successfully created volume level (%u, 0x%.08X, 0x%.08X)", VolumeLevel, pResource, pNewHostVolume.Get()); return; @@ -5624,7 +5570,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex EmuLog(LOG_LEVEL::WARNING, "Failed getting host volume level - falling through to regular volume creation"); } - // fall through + [[fallthrough]]; } case xbox::X_D3DRTYPE_TEXTURE: case xbox::X_D3DRTYPE_VOLUMETEXTURE: @@ -5761,9 +5707,10 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex } else { // Note : This handles both (D3DUsage & D3DUSAGE_RENDERTARGET) and otherwise alike + D3DUsage = D3DUSAGE_RENDERTARGET, // Usage always as render target hRet = g_pD3DDevice->CreateTexture(hostWidth, hostHeight, 1, // Levels - D3DUSAGE_RENDERTARGET, // Usage always as render target + D3DUsage, PCFormat, D3DPool, // D3DPOOL_DEFAULT pNewHostTexture.GetAddressOf(), @@ -5801,7 +5748,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex DXGetErrorString(hRet), DXGetErrorDescription(hRet)); } - SetHostSurface(pResource, pNewHostSurface.Get(), iTextureStage); + SetHostResource(pResource, (IDirect3DResource*)pNewHostSurface.Get(), iTextureStage, D3DUsage, PCFormat); EmuLog(LOG_LEVEL::DEBUG, "CreateHostResource : Successfully created %s (0x%.08X, 0x%.08X)", ResourceTypeName, pResource, pNewHostSurface.Get()); EmuLog(LOG_LEVEL::DEBUG, "CreateHostResource : Width : %d, Height : %d, Format : %d", @@ -5816,7 +5763,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex // So, we need to do this differently - we need to step up to the containing VolumeTexture, // and retrieve and convert all of it's GetVolumeLevel() slices. pNewHostVolume = nullptr; - // SetHostVolume(pResource, pNewHostVolume, iTextureStage); + // SetHostResource(pResource, (IDirect3DResource*)pNewHostVolume, iTextureStage, D3DUsage, PCFormat); // EmuLog(LOG_LEVEL::DEBUG, "CreateHostResource : Successfully created %s (0x%.08X, 0x%.08X)", // ResourceTypeName, pResource, pNewHostVolume); break; @@ -5845,14 +5792,6 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex } } - // Now create our intermediate texture for UpdateTexture, but not for render targets or depth stencils - if (hRet == D3D_OK && (D3DUsage & D3DUSAGE_RENDERTARGET) == 0 && (D3DUsage & D3DUSAGE_DEPTHSTENCIL) == 0) { - hRet = g_pD3DDevice->CreateTexture(hostWidth, hostHeight, dwMipMapLevels, - 0, PCFormat, D3DPOOL_SYSTEMMEM, pIntermediateHostTexture.GetAddressOf(), - nullptr - ); - } - /*if(FAILED(hRet)) { hRet = g_pD3DDevice->CreateTexture @@ -5864,13 +5803,20 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex DEBUG_D3DRESULT(hRet, "g_pD3DDevice->CreateTexture(D3DPOOL_SYSTEMMEM)"); }*/ + // Now create our intermediate texture for UpdateTexture, but not for render targets or depth stencils + if (hRet == D3D_OK && (D3DUsage & D3DUSAGE_RENDERTARGET) == 0 && (D3DUsage & D3DUSAGE_DEPTHSTENCIL) == 0) { + hRet = g_pD3DDevice->CreateTexture(hostWidth, hostHeight, dwMipMapLevels, + 0, PCFormat, D3DPOOL_SYSTEMMEM, pIntermediateHostTexture.GetAddressOf(), + nullptr + ); + } if (hRet != D3D_OK) { CxbxrAbort("CreateTexture Failed!\n\n" "Error: 0x%X\nFormat: %d\nDimensions: %dx%d", hRet, PCFormat, hostWidth, hostHeight); } - SetHostTexture(pResource, pNewHostTexture.Get(), iTextureStage); + SetHostResource(pResource, (IDirect3DResource*)pNewHostTexture.Get(), iTextureStage, D3DUsage, PCFormat); EmuLog(LOG_LEVEL::DEBUG, "CreateHostResource : Successfully created %s (0x%.08X, 0x%.08X)", ResourceTypeName, pResource, pNewHostTexture.Get()); break; @@ -5896,7 +5842,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex DXGetErrorString(hRet), DXGetErrorDescription(hRet)); } - SetHostVolumeTexture(pResource, pNewHostVolumeTexture.Get(), iTextureStage); + SetHostResource(pResource, (IDirect3DResource*)pNewHostVolumeTexture.Get(), iTextureStage, D3DUsage, PCFormat); EmuLog(LOG_LEVEL::DEBUG, "CreateHostResource : Successfully created %s (0x%.08X, 0x%.08X)", ResourceTypeName, pResource, pNewHostVolumeTexture.Get()); break; @@ -5925,7 +5871,7 @@ void CreateHostResource(xbox::X_D3DResource *pResource, DWORD D3DUsage, int iTex DXGetErrorString(hRet), DXGetErrorDescription(hRet)*/); } - SetHostCubeTexture(pResource, pNewHostCubeTexture.Get(), iTextureStage); + SetHostResource(pResource, (IDirect3DResource*)pNewHostCubeTexture.Get(), iTextureStage, D3DUsage, PCFormat); // TODO : Cube face surfaces can be used as a render-target, // so we need to associate host surfaces to each surface of this cube texture // However, we can't do it here: On Xbox, a new Surface is created on every call to @@ -6392,7 +6338,7 @@ void UpdateFixedFunctionVertexShaderState() ffShaderState.PointSprite.PointScaleABC.y = PointScaleEnable ? pointScale_B : 0.0f; ffShaderState.PointSprite.PointScaleABC.z = PointScaleEnable ? pointScale_C : 0.0f; ffShaderState.PointSprite.XboxRenderTargetHeight = PointScaleEnable ? renderTargetHeight : 1.0f; - ffShaderState.PointSprite.RenderUpscaleFactor = g_RenderUpscaleFactor; + ffShaderState.PointSprite.RenderUpscaleFactor = (float)g_RenderUpscaleFactor; // Fog // Determine how the fog depth is transformed into the fog factor diff --git a/src/core/hle/D3D8/XbPixelShader.cpp b/src/core/hle/D3D8/XbPixelShader.cpp index a376657d6..809e53440 100644 --- a/src/core/hle/D3D8/XbPixelShader.cpp +++ b/src/core/hle/D3D8/XbPixelShader.cpp @@ -985,7 +985,7 @@ float CxbxComponentColorSignFromXboxAndHost(bool XboxMarksComponentSigned, bool D3DXCOLOR CxbxCalcColorSign(int stage_nr) { - // Without overrides, just use what the running executable put in COLORSIGN : + // Initially use what the running executable put in COLORSIGN : DWORD XboxColorSign = XboxTextureStates.Get(stage_nr, xbox::X_D3DTSS_COLORSIGN); { // This mimicks behaviour of XDK LazySetShaderStageProgram, which we bypass due to our drawing patches without trampolines. @@ -1006,9 +1006,9 @@ D3DXCOLOR CxbxCalcColorSign(int stage_nr) // Host D3DFMT's with one or more signed components : D3DFMT_V8U8, D3DFMT_Q8W8V8U8, D3DFMT_V16U16, D3DFMT_Q16W16V16U16, D3DFMT_CxV8U8 D3DFORMAT HostTextureFormat = g_HostTextureFormats[stage_nr]; bool HostTextureFormatIsSignedForA = (HostTextureFormat == D3DFMT_Q8W8V8U8); // No need to check for unused formats : D3DFMT_Q16W16V16U16, D3DFMT_CxV8U8, D3DFMT_A2W10V10U10 - bool HostTextureFormatIsSignedForR = (HostTextureFormat == D3DFMT_V8U8) || (HostTextureFormat == D3DFMT_V16U16) || (HostTextureFormat == D3DFMT_L6V5U5) || (HostTextureFormat == D3DFMT_X8L8V8U8) || HostTextureFormatIsSignedForA; - bool HostTextureFormatIsSignedForG = HostTextureFormatIsSignedForR; - bool HostTextureFormatIsSignedForB = HostTextureFormatIsSignedForA; + bool HostTextureFormatIsSignedForR = (HostTextureFormat == D3DFMT_V8U8) || (HostTextureFormat == D3DFMT_V16U16) || (HostTextureFormat == D3DFMT_X8L8V8U8) || HostTextureFormatIsSignedForA; + bool HostTextureFormatIsSignedForG = HostTextureFormatIsSignedForR || (HostTextureFormat == D3DFMT_L6V5U5); + bool HostTextureFormatIsSignedForB = HostTextureFormatIsSignedForA || (HostTextureFormat == D3DFMT_L6V5U5); D3DXCOLOR CxbxColorSign; CxbxColorSign.r = CxbxComponentColorSignFromXboxAndHost(XboxColorSign & xbox::X_D3DTSIGN_RSIGNED, HostTextureFormatIsSignedForR); // Maps to COLORSIGN.r