diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c index b6fde8fc627..18b79ce1673 100644 --- a/dlls/d3d8/device.c +++ b/dlls/d3d8/device.c @@ -1244,11 +1244,8 @@ static HRESULT WINAPI IDirect3DDevice8Impl_GetVertexShader(LPDIRECT3DDEVICE8 ifa IWineD3DVertexShader_Release(pShader); *ppShader = (d3d8_shader->handle - This->shader_handles) + (VS_HIGHESTFIXEDFXF + 1); } else { - WARN("(%p) : The shader has been set to NULL\n", This); - - /* TODO: Find out what should be returned, e.g. the FVF */ *ppShader = 0; - hrc = D3DERR_INVALIDCALL; + hrc = D3D_OK; } } else { WARN("(%p) : Call to IWineD3DDevice_GetVertexShader failed %u (device %p)\n", This, hrc, This->WineD3DDevice); @@ -1267,8 +1264,16 @@ static HRESULT WINAPI IDirect3DDevice8Impl_DeleteVertexShader(LPDIRECT3DDEVICE ERR("(%p) : Trying to delete an invalid handle\n", This); return D3DERR_INVALIDCALL; } else { + IWineD3DVertexShader *cur = NULL; shader_handle *handle = &This->shader_handles[pShader - (VS_HIGHESTFIXEDFXF + 1)]; IDirect3DVertexShader8Impl *shader = *handle; + + IWineD3DDevice_GetVertexShader(This->WineD3DDevice, &cur); + if(cur) { + if(cur == shader->wineD3DVertexShader) IDirect3DDevice8_SetVertexShader(iface, 0); + IWineD3DVertexShader_Release(cur); + } + while(IUnknown_Release((IUnknown *)shader)); free_shader_handle(This, handle); } @@ -1450,8 +1455,16 @@ static HRESULT WINAPI IDirect3DDevice8Impl_DeletePixelShader(LPDIRECT3DDEVICE8 i ERR("(%p) : Trying to delete an invalid handle\n", This); return D3DERR_INVALIDCALL; } else { + IWineD3DPixelShader *cur = NULL; shader_handle *handle = &This->shader_handles[pShader - (VS_HIGHESTFIXEDFXF + 1)]; IDirect3DPixelShader8Impl *shader = *handle; + + IWineD3DDevice_GetPixelShader(This->WineD3DDevice, &cur); + if(cur) { + if(cur == shader->wineD3DPixelShader) IDirect3DDevice8_SetPixelShader(iface, 0); + IWineD3DPixelShader_Release(cur); + } + while(IUnknown_Release((IUnknown *)shader)); free_shader_handle(This, handle); } diff --git a/dlls/d3d8/tests/device.c b/dlls/d3d8/tests/device.c index 31cff063cf3..76a6b8b54ae 100644 --- a/dlls/d3d8/tests/device.c +++ b/dlls/d3d8/tests/device.c @@ -24,6 +24,20 @@ static IDirect3D8 *(WINAPI *pDirect3DCreate8)(UINT); +static const DWORD simple_vs[] = {0xFFFE0101, /* vs_1_1 */ + 0x00000009, 0xC0010000, 0x90E40000, 0xA0E40000, /* dp4 oPos.x, v0, c0 */ + 0x00000009, 0xC0020000, 0x90E40000, 0xA0E40001, /* dp4 oPos.y, v0, c1 */ + 0x00000009, 0xC0040000, 0x90E40000, 0xA0E40002, /* dp4 oPos.z, v0, c2 */ + 0x00000009, 0xC0080000, 0x90E40000, 0xA0E40003, /* dp4 oPos.w, v0, c3 */ + 0x0000FFFF}; /* END */ +static const DWORD simple_ps[] = {0xFFFF0101, /* ps_1_1 */ + 0x00000051, 0xA00F0001, 0x3F800000, 0x00000000, 0x00000000, 0x00000000, /* def c1 = 1.0, 0.0, 0.0, 0.0 */ + 0x00000042, 0xB00F0000, /* tex t0 */ + 0x00000008, 0x800F0000, 0xA0E40001, 0xA0E40000, /* dp3 r0, c1, c0 */ + 0x00000005, 0x800F0000, 0x90E40000, 0x80E40000, /* mul r0, v0, r0 */ + 0x00000005, 0x800F0000, 0xB0E40000, 0x80E40000, /* mul r0, t0, r0 */ + 0x0000FFFF}; /* END */ + static int get_refcount(IUnknown *object) { IUnknown_AddRef( object ); @@ -290,20 +304,6 @@ static void test_refcount(void) D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR), /* D3DVSDE_DIFFUSE, Register v5 */ D3DVSD_END() }; - static DWORD simple_vs[] = {0xFFFE0101, /* vs_1_1 */ - 0x00000009, 0xC0010000, 0x90E40000, 0xA0E40000, /* dp4 oPos.x, v0, c0 */ - 0x00000009, 0xC0020000, 0x90E40000, 0xA0E40001, /* dp4 oPos.y, v0, c1 */ - 0x00000009, 0xC0040000, 0x90E40000, 0xA0E40002, /* dp4 oPos.z, v0, c2 */ - 0x00000009, 0xC0080000, 0x90E40000, 0xA0E40003, /* dp4 oPos.w, v0, c3 */ - 0x0000FFFF}; /* END */ - static DWORD simple_ps[] = {0xFFFF0101, /* ps_1_1 */ - 0x00000051, 0xA00F0001, 0x3F800000, 0x00000000, 0x00000000, 0x00000000, /* def c1 = 1.0, 0.0, 0.0, 0.0 */ - 0x00000042, 0xB00F0000, /* tex t0 */ - 0x00000008, 0x800F0000, 0xA0E40001, 0xA0E40000, /* dp3 r0, c1, c0 */ - 0x00000005, 0x800F0000, 0x90E40000, 0x80E40000, /* mul r0, v0, r0 */ - 0x00000005, 0x800F0000, 0xB0E40000, 0x80E40000, /* mul r0, t0, r0 */ - 0x0000FFFF}; /* END */ - pD3d = pDirect3DCreate8( D3D_SDK_VERSION ); ok(pD3d != NULL, "Failed to create IDirect3D8 object\n"); @@ -823,6 +823,125 @@ cleanup: if(hwnd) DestroyWindow(hwnd); } +static void test_shader(void) +{ + HRESULT hr; + HWND hwnd = NULL; + IDirect3D8 *pD3d = NULL; + IDirect3DDevice8 *pDevice = NULL; + D3DPRESENT_PARAMETERS d3dpp; + D3DDISPLAYMODE d3ddm; + DWORD hPixelShader = 0, hVertexShader = 0; + DWORD hPixelShader2 = 0, hVertexShader2 = 0; + DWORD hTempHandle; + + static DWORD dwVertexDecl[] = + { + D3DVSD_STREAM(0), + D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3), + D3DVSD_END() + }; + + pD3d = pDirect3DCreate8( D3D_SDK_VERSION ); + ok(pD3d != NULL, "Failed to create IDirect3D8 object\n"); + hwnd = CreateWindow( "static", "d3d8_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL ); + ok(hwnd != NULL, "Failed to create window\n"); + if (!pD3d || !hwnd) goto cleanup; + + IDirect3D8_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm ); + ZeroMemory( &d3dpp, sizeof(d3dpp) ); + d3dpp.Windowed = TRUE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.BackBufferWidth = 800; + d3dpp.BackBufferHeight = 600; + d3dpp.BackBufferFormat = d3ddm.Format; + + + hr = IDirect3D8_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL /* no NULLREF here */, hwnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice ); + ok(hr == D3D_OK, "IDirect3D8_CreateDevice failed with %s\n", DXGetErrorString8(hr)); + if(!pDevice) goto cleanup; + + /* First create a vertex shader */ + hr = IDirect3DDevice8_CreateVertexShader(pDevice, dwVertexDecl, NULL, &hVertexShader, 0); + ok(hr == D3D_OK, "IDirect3DDevice8_CreateVertexShader returned %s\n", DXGetErrorString8(hr)); + /* Msdn says that the new vertex shader is set immediately. This is wrong, apparently */ + hr = IDirect3DDevice8_GetVertexShader(pDevice, &hTempHandle); + ok(hr == D3D_OK, "IDirect3DDevice8_GetVertexShader returned %s\n", DXGetErrorString8(hr)); + ok(hTempHandle == 0, "Vertex Shader %d is set, expected shader %d\n", hTempHandle, 0); + /* Assign the shader, then verify that GetVertexShader works */ + hr = IDirect3DDevice8_SetVertexShader(pDevice, hVertexShader); + ok(hr == D3D_OK, "IDirect3DDevice8_SetVertexShader returned %s\n", DXGetErrorString8(hr)); + hr = IDirect3DDevice8_GetVertexShader(pDevice, &hTempHandle); + ok(hr == D3D_OK, "IDirect3DDevice8_GetVertexShader returned %s\n", DXGetErrorString8(hr)); + ok(hTempHandle == hVertexShader, "Vertex Shader %d is set, expected shader %d\n", hTempHandle, hVertexShader); + /* Delete the assigned shader. This is supposed to work */ + hr = IDirect3DDevice8_DeleteVertexShader(pDevice, hVertexShader); + ok(hr == D3D_OK, "IDirect3DDevice8_DeleteVertexShader returned %s\n", DXGetErrorString8(hr)); + /* The shader should be unset now */ + hr = IDirect3DDevice8_GetVertexShader(pDevice, &hTempHandle); + ok(hr == D3D_OK, "IDirect3DDevice8_GetVertexShader returned %s\n", DXGetErrorString8(hr)); + ok(hTempHandle == 0, "Vertex Shader %d is set, expected shader %d\n", hTempHandle, 0); + + /* The same with a pixel shader */ + hr = IDirect3DDevice8_CreatePixelShader(pDevice, simple_ps, &hPixelShader); + ok(hr == D3D_OK, "IDirect3DDevice8_CreatePixelShader returned %s\n", DXGetErrorString8(hr)); + /* Msdn says that the new pixel shader is set immediately. This is wrong, apparently */ + hr = IDirect3DDevice8_GetPixelShader(pDevice, &hTempHandle); + ok(hr == D3D_OK, "IDirect3DDevice8_GetPixelShader returned %s\n", DXGetErrorString8(hr)); + ok(hTempHandle == 0, "Pixel Shader %d is set, expected shader %d\n", hTempHandle, 0); + /* Assign the shader, then verify that GetPixelShader works */ + hr = IDirect3DDevice8_SetPixelShader(pDevice, hPixelShader); + ok(hr == D3D_OK, "IDirect3DDevice8_SetPixelShader returned %s\n", DXGetErrorString8(hr)); + hr = IDirect3DDevice8_GetPixelShader(pDevice, &hTempHandle); + ok(hr == D3D_OK, "IDirect3DDevice8_GetPixelShader returned %s\n", DXGetErrorString8(hr)); + ok(hTempHandle == hPixelShader, "Pixel Shader %d is set, expected shader %d\n", hTempHandle, hPixelShader); + /* Delete the assigned shader. This is supposed to work */ + hr = IDirect3DDevice8_DeletePixelShader(pDevice, hPixelShader); + ok(hr == D3D_OK, "IDirect3DDevice8_DeletePixelShader returned %s\n", DXGetErrorString8(hr)); + /* The shader should be unset now */ + hr = IDirect3DDevice8_GetPixelShader(pDevice, &hTempHandle); + ok(hr == D3D_OK, "IDirect3DDevice8_GetPixelShader returned %s\n", DXGetErrorString8(hr)); + ok(hTempHandle == 0, "Pixel Shader %d is set, expected shader %d\n", hTempHandle, 0); + + /* What happens if a non-bound shader is deleted? */ + hr = IDirect3DDevice8_CreateVertexShader(pDevice, dwVertexDecl, NULL, &hVertexShader, 0); + ok(hr == D3D_OK, "IDirect3DDevice8_CreateVertexShader returned %s\n", DXGetErrorString8(hr)); + hr = IDirect3DDevice8_CreateVertexShader(pDevice, dwVertexDecl, NULL, &hVertexShader2, 0); + ok(hr == D3D_OK, "IDirect3DDevice8_CreateVertexShader returned %s\n", DXGetErrorString8(hr)); + + hr = IDirect3DDevice8_SetVertexShader(pDevice, hVertexShader); + ok(hr == D3D_OK, "IDirect3DDevice8_SetVertexShader returned %s\n", DXGetErrorString8(hr)); + hr = IDirect3DDevice8_DeleteVertexShader(pDevice, hVertexShader2); + ok(hr == D3D_OK, "IDirect3DDevice8_DeleteVertexShader returned %s\n", DXGetErrorString8(hr)); + hr = IDirect3DDevice8_GetVertexShader(pDevice, &hTempHandle); + ok(hr == D3D_OK, "IDirect3DDevice8_GetVertexShader returned %s\n", DXGetErrorString8(hr)); + ok(hTempHandle == hVertexShader, "Vertex Shader %d is set, expected shader %d\n", hTempHandle, hVertexShader); + hr = IDirect3DDevice8_DeleteVertexShader(pDevice, hVertexShader); + ok(hr == D3D_OK, "IDirect3DDevice8_DeleteVertexShader returned %s\n", DXGetErrorString8(hr)); + + /* Now for pixel shaders */ + hr = IDirect3DDevice8_CreatePixelShader(pDevice, simple_ps, &hPixelShader); + ok(hr == D3D_OK, "IDirect3DDevice8_CreatePixelShader returned %s\n", DXGetErrorString8(hr)); + hr = IDirect3DDevice8_CreatePixelShader(pDevice, simple_ps, &hPixelShader2); + ok(hr == D3D_OK, "IDirect3DDevice8_CreatePixelShader returned %s\n", DXGetErrorString8(hr)); + + hr = IDirect3DDevice8_SetPixelShader(pDevice, hPixelShader); + ok(hr == D3D_OK, "IDirect3DDevice8_SetPixelShader returned %s\n", DXGetErrorString8(hr)); + hr = IDirect3DDevice8_DeletePixelShader(pDevice, hPixelShader2); + ok(hr == D3D_OK, "IDirect3DDevice8_DeletePixelShader returned %s\n", DXGetErrorString8(hr)); + hr = IDirect3DDevice8_GetPixelShader(pDevice, &hTempHandle); + ok(hr == D3D_OK, "IDirect3DDevice8_GetPixelShader returned %s\n", DXGetErrorString8(hr)); + ok(hTempHandle == hPixelShader, "Pixel Shader %d is set, expected shader %d\n", hTempHandle, hPixelShader); + hr = IDirect3DDevice8_DeletePixelShader(pDevice, hPixelShader); + ok(hr == D3D_OK, "IDirect3DDevice8_DeletePixelShader returned %s\n", DXGetErrorString8(hr)); + +cleanup: + if(pD3d) IDirect3D8_Release(pD3d); + if(pDevice) IDirect3D8_Release(pDevice); + if(hwnd) DestroyWindow(hwnd); +} + START_TEST(device) { HMODULE d3d8_handle = LoadLibraryA( "d3d8.dll" ); @@ -844,5 +963,6 @@ START_TEST(device) test_cursor(); test_states(); test_scene(); + test_shader(); } }