Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[d3d8] Wine device tests fixes (Part 4) #4479

Merged
merged 8 commits into from
Nov 23, 2024
79 changes: 64 additions & 15 deletions src/d3d8/d3d8_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -935,15 +935,31 @@ namespace dxvk {
// SetDepthStencilSurface is a separate call
D3D8Surface* zStencil = static_cast<D3D8Surface*>(pNewZStencil);

if (likely(m_depthStencil != zStencil)) {
StateChange();
res = GetD3D9()->SetDepthStencilSurface(D3D8Surface::GetD3D9Nullable(zStencil));
// Depth stencil dimensions can not be lower than
// those of the currently set render target.
if (m_renderTarget != nullptr && zStencil != nullptr) {
K0bin marked this conversation as resolved.
Show resolved Hide resolved
D3DSURFACE_DESC rtDesc;
res = m_renderTarget->GetDesc(&rtDesc);

if (unlikely(FAILED(res))) return res;

D3DSURFACE_DESC dsDesc;
res = zStencil->GetDesc(&dsDesc);

if (unlikely(FAILED(res))) return res;

m_depthStencil = zStencil;
if (unlikely(dsDesc.Width < rtDesc.Width
|| dsDesc.Height < rtDesc.Height))
return D3DERR_INVALIDCALL;
}

StateChange();
res = GetD3D9()->SetDepthStencilSurface(D3D8Surface::GetD3D9Nullable(zStencil));

if (unlikely(FAILED(res))) return res;

m_depthStencil = zStencil;

return D3D_OK;
}

Expand Down Expand Up @@ -1680,16 +1696,29 @@ namespace dxvk {
if (unlikely(pDeclaration == nullptr || pHandle == nullptr))
return D3DERR_INVALIDCALL;

// Validate VS version for non-FF shaders
if (pFunction != nullptr) {
uint32_t majorVersion = (pFunction[0] >> 8) & 0xff;
uint32_t minorVersion = pFunction[0] & 0xff;

if (unlikely(majorVersion != 1 || minorVersion > 1)) {
Logger::err(str::format("D3D8Device::CreateVertexShader: Unsupported VS version ", majorVersion, ".", minorVersion));
return D3DERR_INVALIDCALL;
}
}

D3D8VertexShaderInfo& info = m_vertexShaders.emplace_back();

// Store D3D8 bytecodes in the shader info
if (pDeclaration != nullptr)
for (UINT i = 0; pDeclaration[i+1] != D3DVSD_END(); i++)
info.declaration.push_back(pDeclaration[i]);
for (UINT i = 0; pDeclaration[i] != D3DVSD_END(); i++)
info.declaration.push_back(pDeclaration[i]);
info.declaration.push_back(D3DVSD_END());
K0bin marked this conversation as resolved.
Show resolved Hide resolved

if (pFunction != nullptr)
for (UINT i = 0; pFunction[i+1] != D3DVS_END(); i++)
if (pFunction != nullptr) {
for (UINT i = 0; pFunction[i] != D3DVS_END(); i++)
info.function.push_back(pFunction[i]);
info.function.push_back(D3DVS_END());
}

D3D9VertexShaderCode result = TranslateVertexShader8(pDeclaration, pFunction, m_d3d8Options);

Expand Down Expand Up @@ -1829,6 +1858,9 @@ namespace dxvk {

info->declaration.clear();
info->function.clear();

if (m_currentVertexShader == Handle)
m_currentVertexShader = 0;
}

return D3D_OK;
Expand All @@ -1854,8 +1886,10 @@ namespace dxvk {

// D3D8-specific behavior
if (SizeOfData < ActualSize) {
*pSizeOfData = ActualSize;
return D3DERR_MOREDATA;
// D3DERR_MOREDATA should be returned according to the D3D8 documentation,
// along with a correction to the ActualSize, however tests have shown that
// D3DERR_INVALIDCALL is returned and no size correction is performed.
return D3DERR_INVALIDCALL;
}

memcpy(pData, pInfo->declaration.data(), ActualSize);
Expand All @@ -1882,8 +1916,10 @@ namespace dxvk {

// D3D8-specific behavior
if (SizeOfData < ActualSize) {
*pSizeOfData = ActualSize;
return D3DERR_MOREDATA;
// D3DERR_MOREDATA should be returned according to the D3D8 documentation,
// along with a correction to the ActualSize, however tests have shown that
// D3DERR_INVALIDCALL is returned and no size correction is performed.
return D3DERR_INVALIDCALL;
}

memcpy(pData, pInfo->function.data(), ActualSize);
Expand All @@ -1901,6 +1937,14 @@ namespace dxvk {
if (unlikely(pFunction == nullptr || pHandle == nullptr))
return D3DERR_INVALIDCALL;

uint32_t majorVersion = (pFunction[0] >> 8) & 0xff;
uint32_t minorVersion = pFunction[0] & 0xff;

if (unlikely(majorVersion != 1 || minorVersion > 4)) {
Logger::err(str::format("D3D8Device::CreatePixelShader: Unsupported PS version ", majorVersion, ".", minorVersion));
return D3DERR_INVALIDCALL;
}

d3d9::IDirect3DPixelShader9* pPixelShader;

HRESULT res = GetD3D9()->CreatePixelShader(pFunction, &pPixelShader);
Expand Down Expand Up @@ -1986,6 +2030,9 @@ namespace dxvk {

m_pixelShaders[getShaderIndex(Handle)] = nullptr;

if (m_currentPixelShader == Handle)
m_currentPixelShader = 0;

return D3D_OK;
}

Expand All @@ -2010,8 +2057,10 @@ namespace dxvk {

// D3D8-specific behavior
if (SizeOfData < ActualSize) {
*pSizeOfData = ActualSize;
return D3DERR_MOREDATA;
// D3DERR_MOREDATA should be returned according to the D3D8 documentation,
// along with a correction to the ActualSize, however tests have shown that
// D3DERR_INVALIDCALL is returned and no size correction is performed.
return D3DERR_INVALIDCALL;
}

return pPixelShader->GetFunction(pData, &SizeOfData);
Expand Down
76 changes: 61 additions & 15 deletions src/d3d8/d3d8_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,38 @@ extern "C" {
const D3DCAPS8* pCaps,
BOOL errorReturn,
char** pErrorString) {
dxvk::Logger::warn("D3D8: ValidatePixelShader: Stub");
std::string errorMessage = "";

if (unlikely(pPixelShader == nullptr)) {
errorMessage = "D3D8: ValidatePixelShader: Null pPixelShader";
} else {
uint32_t majorVersion = (pPixelShader[0] >> 8) & 0xff;
uint32_t minorVersion = pPixelShader[0] & 0xff;

if (unlikely(majorVersion != 1 || minorVersion > 4)) {
errorMessage = dxvk::str::format("D3D8: ValidatePixelShader: Unsupported PS version ",
WinterSnowfall marked this conversation as resolved.
Show resolved Hide resolved
majorVersion, ".", minorVersion);
} else if (unlikely(pCaps && pPixelShader[0] > pCaps->PixelShaderVersion)) {
errorMessage = dxvk::str::format("D3D8: ValidatePixelShader: Caps: Unsupported PS version ",
majorVersion, ".", minorVersion);
}
}

if (unlikely(pPixelShader == nullptr))
return E_FAIL;
const size_t errorMessageSize = errorMessage.size() + 1;

#ifdef _WIN32
if (pErrorString != nullptr && errorReturn) {
// Wine tests call HeapFree() on the returned error string,
// so the expectation is for it to be allocated on the heap.
*pErrorString = (char*) HeapAlloc(GetProcessHeap(), 0, errorMessageSize);
if (*pErrorString)
memcpy(*pErrorString, errorMessage.c_str(), errorMessageSize);
}
#endif

if (errorReturn && pErrorString != nullptr) {
const char* errorMessage = "";
*pErrorString = (char *) errorMessage;
if (errorMessageSize > 1) {
dxvk::Logger::warn(errorMessage);
return E_FAIL;
}

return S_OK;
Expand All @@ -38,22 +62,44 @@ extern "C" {
const D3DCAPS8* pCaps,
BOOL errorReturn,
char** pErrorString) {
dxvk::Logger::warn("D3D8: ValidateVertexShader: Stub");
std::string errorMessage = "";

if (unlikely(pVertexShader == nullptr)) {
errorMessage = "D3D8: ValidateVertexShader: Null pVertexShader";
} else {
uint32_t majorVersion = (pVertexShader[0] >> 8) & 0xff;
uint32_t minorVersion = pVertexShader[0] & 0xff;

if (unlikely(majorVersion != 1 || minorVersion > 1)) {
errorMessage = dxvk::str::format("D3D8: ValidateVertexShader: Unsupported VS version ",
majorVersion, ".", minorVersion);
} else if (unlikely(pCaps && pVertexShader[0] > pCaps->VertexShaderVersion)) {
errorMessage = dxvk::str::format("D3D8: ValidateVertexShader: Caps: Unsupported VS version ",
majorVersion, ".", minorVersion);
}
}

if (unlikely(pVertexShader == nullptr))
return E_FAIL;
const size_t errorMessageSize = errorMessage.size() + 1;

if (errorReturn && pErrorString != nullptr) {
const char* errorMessage = "";
*pErrorString = (char *) errorMessage;
#ifdef _WIN32
if (pErrorString != nullptr && errorReturn) {
// Wine tests call HeapFree() on the returned error string,
// so the expectation is for it to be allocated on the heap.
*pErrorString = (char*) HeapAlloc(GetProcessHeap(), 0, errorMessageSize);
if (*pErrorString)
memcpy(*pErrorString, errorMessage.c_str(), errorMessageSize);
}
#endif

if (errorMessageSize > 1) {
dxvk::Logger::warn(errorMessage);
return E_FAIL;
}

return S_OK;
}

DLLEXPORT void __stdcall DebugSetMute() {
dxvk::Logger::debug("D3D8: DebugSetMute: Stub");
}
DLLEXPORT void __stdcall DebugSetMute() {}

DLLEXPORT IDirect3D8* __stdcall Direct3DCreate8(UINT nSDKVersion) {
IDirect3D8* pDirect3D = nullptr;
Expand Down
41 changes: 35 additions & 6 deletions src/d3d9/d3d9_common_texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,38 @@ namespace dxvk {
if (pDesc->Usage & D3DUSAGE_WRITEONLY)
return D3DERR_INVALIDCALL;

constexpr DWORD usageRTOrDS = D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL;

// RENDERTARGET and DEPTHSTENCIL must be default pool
constexpr DWORD incompatibleUsages = D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL;
if (pDesc->Pool != D3DPOOL_DEFAULT && (pDesc->Usage & incompatibleUsages))
if (pDesc->Pool != D3DPOOL_DEFAULT && (pDesc->Usage & usageRTOrDS))
return D3DERR_INVALIDCALL;

// RENDERTARGET and DEPTHSTENCIL in D3DPOOL_DEFAULT
// can not also have DYNAMIC usage
if (pDesc->Pool == D3DPOOL_DEFAULT &&
(pDesc->Usage & usageRTOrDS) &&
(pDesc->Usage & D3DUSAGE_DYNAMIC))
return D3DERR_INVALIDCALL;

const bool isPlainSurface = ResourceType == D3DRTYPE_SURFACE && !(pDesc->Usage & usageRTOrDS);
const bool isDepthStencilFormat = IsDepthStencilFormat(pDesc->Format);

// With the exception of image surfaces (d3d8)
// or plain offscreen surfaces (d3d9), depth stencil
// formats can only be used in D3DPOOL_DEFAULT
if (!isPlainSurface && pDesc->Pool != D3DPOOL_DEFAULT && isDepthStencilFormat)
return D3DERR_INVALIDCALL;

// Depth stencil formats can not have RENDERTARGET
// usage, and nothing except depth stencil formats
// can have DEPTHSTENCIL usage
if (( isDepthStencilFormat && (pDesc->Usage & D3DUSAGE_RENDERTARGET)) ||
(!isDepthStencilFormat && (pDesc->Usage & D3DUSAGE_DEPTHSTENCIL)))
return D3DERR_INVALIDCALL;

// Volume textures can not be used as render targets
if (ResourceType == D3DRTYPE_VOLUMETEXTURE &&
(pDesc->Usage & D3DUSAGE_RENDERTARGET))
return D3DERR_INVALIDCALL;

// Volume textures in D3DPOOL_SCRATCH must not have DYNAMIC usage
Expand All @@ -202,13 +231,13 @@ namespace dxvk {
pDesc->MipLevels = maxMipLevelCount;

if (unlikely(pDesc->Discard)) {
if (!IsDepthStencilFormat(pDesc->Format))
if (!isDepthStencilFormat)
return D3DERR_INVALIDCALL;

if (pDesc->Format == D3D9Format::D32_LOCKABLE
|| pDesc->Format == D3D9Format::D32F_LOCKABLE
|| pDesc->Format == D3D9Format::D16_LOCKABLE
|| pDesc->Format == D3D9Format::S8_LOCKABLE)
|| pDesc->Format == D3D9Format::D32F_LOCKABLE
|| pDesc->Format == D3D9Format::D16_LOCKABLE
|| pDesc->Format == D3D9Format::S8_LOCKABLE)
return D3DERR_INVALIDCALL;
}

Expand Down
Loading