Hi Axel,
Thanks for testing with 3dmark06. I tried to run it without luck yesterday, apparently there is some winetrick that i am missing...
Regarding the linear sampler state. I havent seen any case where setting the filters to LINEAR disables fetch4. From the tests, it only changes slightly the results on R500 AMD by changing the 0.5 texel offset.
My guess, is that all apps that use fetch4 have that into account, and disable it with LODBIAS explicitly.
Sampling a 1x1 L8 texture with fetch4 will return the same value on RGBA, which is similar to a normal sample.
Regarding 3D textures, all implementations behave differently. Since 3D textures have 8 texels, returning the 4 texels used for linear sampling is quite ambiguous.
Intel decides to sample at .xy0 and ignore the Z axis.
Some AMD devices disable fetch4, some others sample at the nearest z coordinate.
In my opinion, we are hitting implementation bugs/corner cases. It is simpler to just keep fetch4 off there. Especially since implementing it is quite difficult.
The tests of 3D textures in wine are just testing that fetch4 is off (no todo, it should be always off).
But on windows, it tests that some of the 4 possibles cases seen on AMD and intel is obtained.
How useful those tests are, i am not sure. I just left them there for reference.
Maybe we should remove those tests on windows, or even add todo in some of the cases for 3d. But in that case, what implementation do we want to follow?
Best regards,
Daniel
Hi,
Apparently 3DMark06 believes somehow that LINEAR disables FETCH4.
It sets MIPFILTER, MINFILTER and MAGFILTER to LINEAR,
and resets ADDRESSV, ADDRESSU and MIPMAPLODBIAS (1, 1, 0 respectively)
then behaves as if FETCH4 was disabled (it later disables it definitely
with the MIPMAPLODBIAS setting).
I don't see any obvious visual glitch, though. The texture sampled with
FETCH4 which isn't meant to be sampled with it (looking at how the
shader values are used) is a D3DFMT_L8 of size 1x1...
I think all this points out that one has to be very careful about FETCH4
corner cases.
Thus I would suggest adding more formats and checks to your code, like
for example INTZ, ATI1, ATI2 ?
For the part "Currently unimplemented on wine due to lack of GL
functionality to cast 3D->2DArray",
shouldn't the test be with a wine_todo rather than a isWin check ?
Axel
On 01/02/2019 01:56, Daniel Ansorregui wrote:
> - Test texld/texldp/texldd/texldb/texldl in PS and FFP
> - Test supported/unsupported texture formats on FFP/texld/texldp
> - Test 3dtextures (Disabled, each platform has different results)
> - Test depth textures DF16/DF24 with fetch4 on PS (FFP is broken on windows)
>
> Signed-off-by: Daniel Ansorregui <mailszeros@gmail.com>
> ---
> dlls/d3d9/tests/visual.c | 644 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 644 insertions(+)
>
> diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
> index c06acb77d4..028fc23078 100644
> --- a/dlls/d3d9/tests/visual.c
> +++ b/dlls/d3d9/tests/visual.c
> @@ -15234,6 +15234,649 @@ done:
> DestroyWindow(window);
> }
>
> +static void fetch4_test(void)
> +{
> + static const DWORD vs_code[] =
> + {
> + 0xfffe0300, /* vs_3_0 */
> + 0x0200001f, 0x80000000, 0x900f0000, /* dcl_position v0 */
> + 0x0200001f, 0x80000005, 0x900f0001, /* dcl_texcoord v1 */
> + 0x0200001f, 0x80000000, 0xe00f0000, /* dcl_position o0 */
> + 0x0200001f, 0x80000005, 0xe00f0001, /* dcl_texcoord o1 */
> + 0x02000001, 0xe00f0000, 0x90e40000, /* mov o0, v0 */
> + 0x02000001, 0xe00f0001, 0x90e40001, /* mov o1, v1 */
> + 0x0000ffff
> + };
> + static const DWORD ps_code_texld[] =
> + {
> + /* Test texld */
> + 0xffff0300, /* ps_3_0 */
> + 0x0200001f, 0x80000005, 0x900f0000, /* dcl_texcoord v0 */
> + 0x0200001f, 0x90000000, 0xa00f0800, /* dcl_2d s0 */
> + 0x03000042, 0x800f0000, 0x90e40000, 0xa0e40800, /* texld r0, v0, s0 */
> + 0x02000001, 0x800f0800, 0x80e40000, /* mov oC0, r0 */
> + 0x0000ffff /* end */
> + };
> + static const DWORD ps_code_texldp[] =
> + {
> + /* Test texldp : AMD and Wine uses the projection on Fetch4, Intel UHD 620 does not apply it */
> + 0xffff0300, /* ps_3_0 */
> + 0x0200001f, 0x80000005, 0x900f0000, /* dcl_texcoord v0 */
> + 0x0200001f, 0x90000000, 0xa00f0800, /* dcl_2d s0 */
> + 0x05000051, 0xa00f0000, 0x00000000, 0x00000000, 0x00000000, 0x40000000, /* def c0, 0.0, 0.0, 0.0, 2.0 */
> + 0x02000001, 0x80030000, 0x90540000, /* mov r0.xy, v0.xyyy */
> + 0x02000001, 0x800c0000, 0xa0fe0000, /* mov r0.zw, c0.zwww */
> + 0x03010042, 0x800f0000, 0x80e40000, 0xa0e40800, /* texldp r0, r0, s0 */
> + 0x02000001, 0x800f0800, 0x80e40000, /* mov oC0, r0 */
> + 0x0000ffff, /* end */
> + };
> + static const DWORD ps_code_texldd[] =
> + {
> + /* Test texldd : Fetch4 uses the same D3D state as LOD bias, therefore disables LOD.
> + * Sampling LOD gradient should be ignored. Same result as texld */
> + /* NOTE: Radeon HD 5700 driver 8.17.10.1404 disables Fetch4 on texldb */
> + 0xffff0300, /* ps_3_0 */
> + 0x0200001f, 0x80000005, 0x900f0000, /* dcl_texcoord v0 */
> + 0x0200001f, 0x90000000, 0xa00f0800, /* dcl_2d s0 */
> + 0x05000051, 0xa00f0000, 0x3f000000, 0x3f000000, 0x3f000000, 0x3f000000, /* def c0, 0.5, 0.5, 0.5, 0.5 */
> + 0x05000051, 0xa00f0001, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, /* def c0, 1.0, 1.0, 1.0, 1.0 */
> + 0x02000001, 0x800f0002, 0xa0e40000, /* mov r2, c0 */
> + 0x0500005d, 0x800f0000, 0x90e40000, 0xa0e40800, 0xa0e40000, 0x80e40002, /* texldd r0, v0, s0, c0, r2 */
> + 0x02000001, 0x800f0800, 0x80e40000, /* mov oC0, r0 */
> + 0x0000ffff, /* end */
> + };
> + static const DWORD ps_code_texldb[] =
> + {
> + /* Test texldb : Fetch4 uses the same D3D state as LOD bias, therefore disables LOD.
> + * Same result as texld */
> + /* NOTE: Radeon HD 5700 driver 8.17.10.1404 disables Fetch4 on texldb */
> + 0xffff0300, /* ps_3_0 */
> + 0x0200001f, 0x80000005, 0x900f0000, /* dcl_texcoord v0 */
> + 0x0200001f, 0x90000000, 0xa00f0800, /* dcl_2d s0 */
> + 0x05000051, 0xa00f0000, 0x00000000, 0x00000000, 0x40a00000, 0x40a00000, /* def c0, 0.0, 0.0, 5.0, 5.0 */
> + 0x03000002, 0x800f0000, 0x90e40000, 0xa0e40000, /* add r0, v0, c0 */
> + 0x03020042, 0x800f0000, 0x80e40000, 0xa0e40800, /* texldb r0, r0, s0 */
> + 0x02000001, 0x800f0800, 0x80e40000, /* mov oC0, r0 */
> + 0x0000ffff, /* end */
> + };
> + static const DWORD ps_code_texldl[] =
> + {
> + /* Test texldl : Fetch4 uses the same D3D state as LOD bias, therefore disables LOD.
> + * The explicit LOD level is then ignored. Same result as texld */
> + /* NOTE: Radeon HD 5700 driver 8.17.10.1404 disables Fetch4 on texldl */
> + 0xffff0300, /* ps_3_0 */
> + 0x0200001f, 0x80000005, 0x900f0000, /* dcl_texcoord v0 */
> + 0x0200001f, 0x90000000, 0xa00f0800, /* dcl_2d s0 */
> + 0x05000051, 0xa00f0000, 0x00000000, 0x00000000, 0x3f000000, 0x3f000000, /* def c0, 0.0, 0.0, 0.5, 0.5 */
> + 0x03000002, 0x800f0000, 0x90e40000, 0xa0e40000, /* add r0, v0, c0 */
> + 0x0300005f, 0x800f0000, 0x80e40000, 0xa0e40800, /* texldl r0, r0, s0 */
> + 0x02000001, 0x800f0800, 0x80e40000, /* mov oC0, r0 */
> + 0x0000ffff, /* end */
> + };
> + static const DWORD ps_code_3d[] =
> + {
> + 0xffff0300, /* ps_3_0 */
> + 0x0200001f, 0x80000005, 0x900f0000, /* dcl_texcoord v0 */
> + 0x0200001f, 0xa0000000, 0xa00f0800, /* dcl_volume s0 */
> + 0x03000042, 0x800f0000, 0x90e40000, 0xa0e40800, /* texld r0, v0, s0 */
> + 0x02000001, 0x800f0800, 0x80e40000, /* mov oC0, r0 */
> + 0x0000ffff /* end */
> + };
> +
> + static const struct
> + {
> + struct vec3 position;
> + struct vec3 texcoord;
> + }
> + quad[] =
> + {
> + /* Tilted on Z axis to get a depth gradient in the depth test */
> + /* NOTE: Using 0.55f-0.6f to avoid rounding errors on depth tests */
> + {{-1.0f, 1.0f, 1.0f}, {0.0f,0.0f,0.6f} },
> + {{ 1.0f, 1.0f, 0.0f}, {1.0f,0.0f,0.6f} },
> + {{-1.0f,-1.0f, 0.0f}, {0.0f,1.0f,0.6f} },
> + {{ 1.0f,-1.0f, 0.0f}, {1.0f,1.0f,0.6f} }
> + };
> +
> + static const struct
> + {
> + UINT x[4], y[4]; /* Matrix Sampling positions */
> + D3DCOLOR color_amd[16]; /* AMD original implementation swizzle with -0.5 texel coord */
> + D3DCOLOR color_intel[16]; /* Intel UHD 620 implementation swizzle with no texel coord correction */
> + /* Wine follows the AMD immplementation, and consider an error the Intel one results
> + * However, the test will accept as valid the intel only if running on windows */
> + D3DCOLOR color_3d_fetch4_off[16];
> + D3DCOLOR color_fetch4_off[16];
> + }
> + expected_colors =
> + {
> + { 40, 200, 360, 520},
> + { 30, 150, 270, 390},
> + /* AMD implementation - Wine implementation */
> + {0x131202f2, 0x1211f2f1, 0x1110f101, 0x10130102,
> + 0x02f204f4, 0xf2f1f4f3, 0xf101f303, 0x01020304,
> + 0x04f42322, 0xf4f32221, 0xf3032120, 0x03042023,
> + 0x23221312, 0x22211211, 0x21201110, 0x20231013},
> + /* Intel UHD 620 implementation */
> + {0x23102013, 0x22132312, 0x21122211, 0x20112110,
> + 0x13011002, 0x120213f2, 0x11f212f1, 0x10f11101,
> + 0x02030104, 0xf20402f4, 0xf1f4f2f3, 0x01f3f103,
> + 0x04200323, 0xf4230422, 0xf322f421, 0x0321f320},
> + /* Fetch4 off on 3D textures */
> + {0xff020202, 0xfff2f2f2, 0xfff1f1f1, 0xff010101,
> + 0xff050505, 0xfff4f4f4, 0xfff3f3f3, 0xff030303,
> + 0xff232323, 0xff222222, 0xff212121, 0xff202020,
> + 0xff131313, 0xff121212, 0xff111111, 0xff101010},
> + /* Fetch4 off on 2D texture */
> + {0x13131313, 0x12121212, 0x11111111, 0x10101010,
> + 0x02020202, 0xf2f2f2f2, 0xf1f1f1f1, 0x01010101,
> + 0x04040404, 0xf4f4f4f4, 0xf3f3f3f3, 0x03030303,
> + 0x23232323, 0x22222222, 0x21212121, 0x20202020}
> + };
> +
> + static const DWORD fetch4_data[] = {0x10111213,
> + 0x01f1f202,
> + 0x03f3f404,
> + 0x20212223};
> +
> + static struct
> + {
> + IDirect3DVertexShader9 *vs;
> + IDirect3DPixelShader9 *ps;
> + const DWORD *ps_code;
> + const char *name;
> + BOOL projection; /* The results should be projected (zoomed by 2) */
> + BOOL allow_off; /* Do not enforce Fetch4 enabled on this one on Windows */
> + }
> + shaders[] =
> + {
> + {NULL, NULL, NULL, "FFP", FALSE, FALSE},
> + {NULL, NULL, ps_code_texld, "texld", FALSE, FALSE},
> + {NULL, NULL, ps_code_texldp, "texldp", TRUE, FALSE},
> + {NULL, NULL, ps_code_texldd, "texldd", FALSE, TRUE},
> + {NULL, NULL, ps_code_texldb, "texldb", FALSE, TRUE},
> + {NULL, NULL, ps_code_texldl, "texldl", FALSE, TRUE},
> + };
> +
> + static const struct
> + {
> + D3DFORMAT format; /* The format of the texture */
> + DWORD data; /* The data we will write to the first line */
> + UINT x, y; /* Where we expect the color to be */
> + BOOL broken_wine; /* Do not check it on wine because is known ot be broken */
> + D3DCOLOR color_amd[3]; /* Wine results. Results on AMD swizzle + texture offset */
> + D3DCOLOR color_intel[3]; /* Results with intel UHD 620, intel swizzle + no texel offset */
> + }
> + format_tests[] =
> + {
> + /* Enabled formats */
> + {D3DFMT_L8, 0xff804010, 360, 270, FALSE,
> + {0x00004010, 0x00004010, 0x10400000},
> + {0x40001000, 0x40001000, 0x40001000}
> + },
> + {D3DFMT_L16, 0xff804010, 360, 270, FALSE,
> + {0x0000ff40, 0x0000ff40, 0x40ff0000},
> + {0xff004000, 0xff004000, 0xff004000}
> + },
> + {D3DFMT_R16F, 0x38003c00, 360, 270, FALSE,
> + {0x000080ff, 0x000080ff, 0xff800000},
> + {0x8000ff00, 0x8000ff00, 0x8000ff00}
> + },
> + {D3DFMT_R32F, 0x3f000000, 360, 270, FALSE,
> + {0x00000080, 0x00000080, 0x80000000},
> + {0x00008000, 0x00008000, 0x00008000}
> + },
> +
> + /* Disabled format on Intel, enabled on AMD, broken on wine
> + * since it is implemented with GL_ALPHA, and fetch4 will fetch RED value */
> + {D3DFMT_A8, 0xff804010, 360, 270, TRUE,
> + {0x00004010, 0x00004010, 0x10400000},
> + {0x00000000, 0x00000000, 0x00000000}
> + },
> +
> + /* Disabled format */
> + {D3DFMT_A8R8G8B8, 0xff804010, 360, 270, FALSE,
> + {0x00000000, 0x00000000, 0xff804010},
> + {0x00000000, 0x00000000, 0xff804010}
> + },
> + };
> +
> + static const struct
> + {
> + D3DCOLOR color_off, color_amd, color_intel;
> + UINT x, y;
> + }
> + expected_depth[][4] =
> + {
> + {
> + /* This is the expected result for shadow samplers */
> + {0xffffffff,0xffffffff,0xffffffff, 20, 15},
> + {0xffffffff,0xffffffff,0xffffffff,260, 15},
> + {0x00000000,0x00000000,0x00000000, 20,255},
> + {0x00000000,0x00000000,0x00000000,260,135},
> + },
> + {
> + /* This is the expected result with DF16 */
> + {0xfffe0000,0xfedfdfbf,0x202000ff, 20, 15},
> + {0xff9f0000,0x9f7f7f5f,0x00bf009f,260, 15},
> + {0xff800000,0x7f5f5f3f,0x9f000080, 20,255},
> + {0xff600000,0x5f3f3f1f,0x80809f60,260,135},
> + },
> + {
> + /* This is the expected result with DF24 */
> + {0xffff0000,0xffdfdfbf,0x202000ff, 20, 15},
> + {0xff9f0000,0x9f7f7f5f,0x00bf009f,260, 15},
> + {0xff800000,0x7f5f5f3f,0x9f000080, 20,255},
> + {0xff600000,0x5f3f3f1f,0x80809f60,260,135},
> + }
> + };
> +
> + static const struct
> + {
> + D3DFORMAT format;
> + const char *name;
> + UINT index;
> + }
> + depth_tests[] =
> + {
> + {D3DFMT_D16_LOCKABLE, "D16_LOCKABLE", 0},
> + {D3DFMT_D32, "D32", 0},
> + {D3DFMT_D15S1, "D15S1", 0},
> + {D3DFMT_D24S8, "D24S8", 0},
> + {D3DFMT_D24X8, "D24X8", 0},
> + {D3DFMT_D24X4S4, "D24X4S4", 0},
> + {D3DFMT_D16, "D16", 0},
> + {D3DFMT_D32F_LOCKABLE, "D32F_LOCKABLE", 0},
> + {D3DFMT_D24FS8, "D24FS8", 0},
> + {MAKEFOURCC('D','F','1','6'), "DF16", 1},
> + {MAKEFOURCC('D','F','2','4'), "DF24", 2},
> + };
> +
> + const BOOL isWin = strcmp(winetest_platform, "wine");
> +
> + IDirect3DSurface9 *original_ds, *original_rt, *rt;
> + IDirect3DVolumeTexture9 *texture3D;
> + IDirect3DPixelShader9 *ps_3d;
> + struct surface_readback rb;
> + IDirect3DVertexShader9 *vs;
> + IDirect3DTexture9 *texture;
> + IDirect3DDevice9 *device;
> + D3DLOCKED_RECT lr;
> + D3DLOCKED_BOX lb;
> + IDirect3D9 *d3d;
> + ULONG refcount;
> + D3DCAPS9 caps;
> + UINT i, j, k;
> + HWND window;
> + HRESULT hr;
> +
> + window = create_window();
> + d3d = Direct3DCreate9(D3D_SDK_VERSION);
> + ok(!!d3d, "Failed to create a D3D object.\n");
> + if (FAILED(IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
> + D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, MAKEFOURCC('D','F','2','4'))))
> + {
> + skip("No DF24 support, skipping FETCH4 test.\n");
> + goto done;
> + }
> + if (!(device = create_device(d3d, window, window, TRUE)))
> + {
> + skip("Failed to create a D3D device, skipping tests.\n");
> + goto done;
> + }
> +
> + hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
> + ok(SUCCEEDED(hr), "GetDeviceCaps failed, hr %#x.\n", hr);
> + if (caps.PixelShaderVersion < D3DPS_VERSION(3, 0))
> + {
> + skip("No pixel shader 3.0 support, skipping FETCH4 test.\n");
> + IDirect3DDevice9_Release(device);
> + goto done;
> + }
> + hr = IDirect3DDevice9_GetRenderTarget(device, 0, &original_rt);
> + ok(SUCCEEDED(hr), "GetRenderTarget failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_GetDepthStencilSurface(device, &original_ds);
> + ok(SUCCEEDED(hr), "GetDepthStencilSurface failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_CreateRenderTarget(device, 8, 8, D3DFMT_A8R8G8B8,
> + D3DMULTISAMPLE_NONE, 0, FALSE, &rt, NULL);
> + ok(SUCCEEDED(hr), "CreateRenderTarget failed, hr %#x.\n", hr);
> +
> + /* Create our texture for FETCH4 shader testing */
> + hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, D3DFMT_L8, D3DPOOL_MANAGED, &texture, NULL);
> + ok(hr == D3D_OK, "Failed to create texture, hr %#x.\n", hr);
> + hr = IDirect3DTexture9_LockRect(texture, 0, &lr, NULL, 0);
> + ok(hr == D3D_OK, "Failed to lock texture, hr %#x.\n", hr);
> + for (i = 0; i < ARRAY_SIZE(fetch4_data); ++i)
> + memcpy((BYTE *)lr.pBits + i*lr.Pitch, &fetch4_data[i], sizeof(fetch4_data[i]));
> + hr = IDirect3DTexture9_UnlockRect(texture, 0);
> + ok(hr == D3D_OK, "Failed to unlock texture, hr %#x.\n", hr);
> +
> + /* Create vertex shader */
> + hr = IDirect3DDevice9_CreateVertexShader(device, vs_code, &vs);
> + ok(hr == D3D_OK, "IDirect3DDevice9_CreateVertexShader returned %08x\n", hr);
> + /* Prepare the pixel shaders */
> + for (i = 0; i < ARRAY_SIZE(shaders); ++i)
> + {
> + if (shaders[i].ps_code)
> + {
> + hr = IDirect3DDevice9_CreatePixelShader(device, shaders[i].ps_code, &shaders[i].ps);
> + ok(SUCCEEDED(hr), "CreatePixelShader failed, hr %#x.\n", hr);
> + /* Copy vertex shader pointer if a PS is present */
> + shaders[i].vs = vs;
> + }
> + }
> + hr = IDirect3DDevice9_CreatePixelShader(device, ps_code_3d, &ps_3d);
> + ok(SUCCEEDED(hr), "CreatePixelShader failed, hr %#x.\n", hr);
> +
> + hr = IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0));
> + ok(SUCCEEDED(hr), "SetFVF failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_TRUE);
> + ok(SUCCEEDED(hr), "SetRenderState failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ZFUNC, D3DCMP_ALWAYS);
> + ok(SUCCEEDED(hr), "SetRenderState failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ZWRITEENABLE, TRUE);
> + ok(SUCCEEDED(hr), "SetRenderState failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
> + ok(SUCCEEDED(hr), "SetRenderState failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetTexture(device, 0, (IDirect3DBaseTexture9 *)texture);
> + ok(hr == D3D_OK, "Failed to set texture, hr %#x.\n", hr);
> +
> + /* According to the spec, FETCH4 is enabled when D3DSAMP_MIPMAPLODBIAS == GET4 and also
> + * D3DSAMP_MAGFILTER == D3DTEXF_POINT. But apparently only GET4 is needed for it to get active.
> + * However, AMD HW r500 samples always as if POINT (nearest filtering) is selected with FETCH4
> + * the driver later on corrected this by adding -0.5 texel coord. */
> + hr = IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MIPMAPLODBIAS, MAKEFOURCC('G','E','T','4'));
> + ok(SUCCEEDED(hr), "SetSamplerState failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
> + ok(SUCCEEDED(hr), "SetSamplerState failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
> + ok(SUCCEEDED(hr), "SetSamplerState failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
> + ok(SUCCEEDED(hr), "SetSamplerState failed, hr %#x.\n", hr);
> +
> + /***********************************************************************
> + * Tests for FFP/PS correctness when using L8 texture with fetch4. *
> + ***********************************************************************/
> +
> + /* Render with fetch4 and test if we obtain proper results for all sampler FFP/PS instructions */
> + for (i = 0; i < ARRAY_SIZE(shaders); ++i)
> + {
> + hr = IDirect3DDevice9_SetVertexShader(device, shaders[i].vs);
> + ok(SUCCEEDED(hr), "Failed to set vertex shader, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetPixelShader(device, shaders[i].ps);
> + ok(SUCCEEDED(hr), "SetPixelShader failed, hr %#x.\n", hr);
> +
> + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 0.0f, 0);
> + ok(SUCCEEDED(hr), "Clear failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_BeginScene(device);
> + ok(SUCCEEDED(hr), "BeginScene failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad, sizeof(*quad));
> + ok(SUCCEEDED(hr), "DrawPrimitiveUP failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_EndScene(device);
> + ok(SUCCEEDED(hr), "EndScene failed, hr %#x.\n", hr);
> +
> + get_rt_readback(original_rt, &rb);
> + for (j = 0; j < ARRAY_SIZE(expected_colors.color_amd); ++j)
> + {
> + UINT x = expected_colors.x[j % 4];
> + UINT y = expected_colors.y[j / 4];
> + D3DCOLOR color = get_readback_color(&rb, x, y);
> + D3DCOLOR color_amd = expected_colors.color_amd[shaders[i].projection ? (j/4/2*4 + (j%4)/2) : j];
> + D3DCOLOR color_intel = expected_colors.color_intel[j];
> + ok(color_match(color, color_amd, 1)
> + || (isWin && (color_match(color, color_intel, 1) || shaders[i].allow_off)),
> + "Test %s Expected color 0x%08x at (%u, %u), got 0x%08x.\n", shaders[i].name,
> + color_amd, x, y, color);
> + }
> + release_surface_readback(&rb);
> +
> + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
> + ok(SUCCEEDED(hr), "Present failed, hr %#x.\n", hr);
> + }
> +
> + /***************************************************************************
> + * Tests for fetch4 enable/disable with different texture formats in FFP/PS. *
> + ***************************************************************************/
> +
> + /* Create the textures to test FETCH4 does work/not work there as expected */
> + for (i = 0; i < ARRAY_SIZE(format_tests); ++i)
> + {
> + IDirect3DTexture9 *tex;
> + hr = IDirect3DDevice9_CreateTexture(device, 2, 2, 1, 0, format_tests[i].format,
> + D3DPOOL_MANAGED, &tex, NULL);
> + ok(hr == D3D_OK, "Failed to create texture, hr %#x.\n", hr);
> + hr = IDirect3DTexture9_LockRect(tex, 0, &lr, NULL, 0);
> + ok(hr == D3D_OK, "Failed to lock texture, hr %#x.\n", hr);
> + memcpy(lr.pBits, &format_tests[i].data, 4);
> + hr = IDirect3DTexture9_UnlockRect(tex, 0);
> + ok(hr == D3D_OK, "Failed to unlock texture, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetTexture(device, 0, (IDirect3DBaseTexture9 *)tex);
> + ok(hr == D3D_OK, "Failed to set texture, hr %#x.\n", hr);
> +
> + /* Test if FETCH4 is enabled/disabled when different textures are used with FFP/texld/texldp */
> + for (j = 0; j < ARRAY_SIZE(format_tests[i].color_amd); ++j)
> + {
> + hr = IDirect3DDevice9_SetVertexShader(device, shaders[j].vs);
> + ok(SUCCEEDED(hr), "Failed to set vertex shader, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetPixelShader(device, shaders[j].ps);
> + ok(SUCCEEDED(hr), "SetPixelShader failed, hr %#x.\n", hr);
> +
> + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 0.0f, 0);
> + ok(SUCCEEDED(hr), "Clear failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_BeginScene(device);
> + ok(SUCCEEDED(hr), "BeginScene failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad, sizeof(*quad));
> + ok(SUCCEEDED(hr), "DrawPrimitiveUP failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_EndScene(device);
> + ok(SUCCEEDED(hr), "EndScene failed, hr %#x.\n", hr);
> +
> + get_rt_readback(original_rt, &rb);
> + D3DCOLOR color = get_readback_color(&rb, format_tests[i].x, format_tests[i].y);
> + D3DCOLOR color_amd = format_tests[i].color_amd[j];
> + D3DCOLOR color_intel = format_tests[i].color_intel[j];
> + todo_wine_if(format_tests[i].broken_wine) ok(color_match(color, color_amd, 1)
> + || (isWin && color_match(color, color_intel, 1)),
> + "Test %d,%s expected color 0x%08x at (%u, %u), got 0x%08x.\n", i, shaders[j].name,
> + color_amd, format_tests[i].x, format_tests[i].y, color);
> + release_surface_readback(&rb);
> +
> + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
> + ok(SUCCEEDED(hr), "Present failed, hr %#x.\n", hr);
> + }
> + IDirect3DTexture9_Release(tex);
> + }
> +
> + /**************************************************
> + * Tests that fetch4 works with 3D textures. *
> + **************************************************/
> +
> + /* Create volume (3D) texture */
> + IDirect3DDevice9_CreateVolumeTexture(device, 4, 4, 2, 1, 0, D3DFMT_L8, D3DPOOL_MANAGED, &texture3D, NULL );
> + ok(hr == D3D_OK, "Failed to create volume texture, hr %#x.\n", hr);
> + hr = IDirect3DVolumeTexture9_LockBox(texture3D, 0, &lb, NULL, 0);
> + ok(hr == D3D_OK, "Failed to lock texture3D, hr %#x.\n", hr);
> + for (i = 0; i < ARRAY_SIZE(fetch4_data); ++i)
> + {
> + memcpy((BYTE *)lb.pBits + i*lb.RowPitch, &fetch4_data[i], sizeof(fetch4_data[i]));
> + /* Shift the lower level, to keep it different */
> + memcpy((BYTE *)lb.pBits + i*lb.RowPitch + lb.SlicePitch, &fetch4_data[(i+1)%4], sizeof(fetch4_data[i]));
> + }
> + hr = IDirect3DVolumeTexture9_UnlockBox(texture3D, 0);
> + ok(hr == D3D_OK, "Failed to unlock texture3D, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetTexture(device, 0, (IDirect3DBaseTexture9 *)texture3D);
> + ok(hr == D3D_OK, "Failed to set texture3D, hr %#x.\n", hr);
> +
> + /* Test FFP and texld with dcl_volume (ps_3d) */
> + for (i = 0; i < 2; ++i)
> + {
> + hr = IDirect3DDevice9_SetVertexShader(device, i ? vs : NULL);
> + ok(SUCCEEDED(hr), "Failed to set vertex shader, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetPixelShader(device, i ? ps_3d : NULL);
> + ok(SUCCEEDED(hr), "SetPixelShader failed, hr %#x.\n", hr);
> +
> + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 0.0f, 0);
> + ok(SUCCEEDED(hr), "Clear failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_BeginScene(device);
> + ok(SUCCEEDED(hr), "BeginScene failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad, sizeof(*quad));
> + ok(SUCCEEDED(hr), "DrawPrimitiveUP failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_EndScene(device);
> + ok(SUCCEEDED(hr), "EndScene failed, hr %#x.\n", hr);
> + get_rt_readback(original_rt, &rb);
> + for (j = 0; j < ARRAY_SIZE(expected_colors.color_amd); ++j)
> + {
> + UINT x = expected_colors.x[j % 4];
> + UINT y = expected_colors.y[j / 4];
> + D3DCOLOR color = get_readback_color(&rb, x, y);
> + D3DCOLOR color_amd = expected_colors.color_amd[j];
> + D3DCOLOR color_intel = expected_colors.color_intel[j];
> + D3DCOLOR color_off = expected_colors.color_3d_fetch4_off[j];
> + D3DCOLOR color_zround = expected_colors.color_amd[(j+4) % ARRAY_SIZE(expected_colors.color_amd)];
> + /* FIXME: Fetch4 on 3D textures have different results based on the vendor/driver
> + * - AMD "HD 5700" rounds to nearest "z" texel, and does fetch4 normally on .xy
> + * - AMD "R500" has fetch4 disabled
> + * - AMD "R580" has fetch4 enabled sampling at .xy0
> + * - Intel UHD 620 sample with fetch4 at .xy0
> + * Currently unimplemented on wine due to lack of GL functionality to cast 3D->2DArray
> + * Wine produces same results as if fetch4 is not enabled (which probably is better)
> + * Test will pass on windows if either one of the allowed results is returned */
> + if(isWin)
> + ok(color_match(color, color_zround, 2) || color_match(color, color_off, 2)
> + || color_match(color, color_intel, 2) || color_match(color, color_amd, 2),
> + "Test 3D %s Expected colors 0x%08x || 0x%08x || 0x%08x || 0x%08x at (%u, %u), got 0x%08x.\n",
> + shaders[i].name, color_amd, color_zround, color_off, color_intel, x, y, color);
> + else
> + ok(color_match(color, color_off, 2),
> + "Test 3D %s Expected color 0x%08x at (%u, %u), got 0x%08x.\n", shaders[i].name,
> + color_off, x, y, color);
> + }
> + release_surface_readback(&rb);
> + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
> + ok(SUCCEEDED(hr), "Present failed, hr %#x.\n", hr);
> + }
> +
> + /********************************************************
> + * Tests for fetch4 enable/disable with depth textures. *
> + ********************************************************/
> +
> + for (i = 0; i < ARRAY_SIZE(depth_tests); ++i)
> + {
> + D3DFORMAT format = depth_tests[i].format;
> + IDirect3DTexture9 *depth_texture;
> + IDirect3DSurface9 *ds;
> +
> + if (FAILED(IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
> + D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, format)))
> + continue;
> +
> + hr = IDirect3DDevice9_CreateTexture(device, 8, 8, 1,
> + D3DUSAGE_DEPTHSTENCIL, format, D3DPOOL_DEFAULT, &depth_texture, NULL);
> + ok(SUCCEEDED(hr), "CreateTexture failed, hr %#x.\n", hr);
> + hr = IDirect3DTexture9_GetSurfaceLevel(depth_texture, 0, &ds);
> + ok(SUCCEEDED(hr), "GetSurfaceLevel failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetDepthStencilSurface(device, ds);
> + ok(SUCCEEDED(hr), "SetDepthStencilSurface failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetRenderTarget(device, 0, rt);
> + ok(SUCCEEDED(hr), "SetRenderTarget failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetVertexShader(device, NULL);
> + ok(SUCCEEDED(hr), "Failed to set vertex shader, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetPixelShader(device, NULL);
> + ok(SUCCEEDED(hr), "SetPixelShader failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetTexture(device, 0, (IDirect3DBaseTexture9 *)texture);
> + ok(hr == D3D_OK, "Failed to set texture3D, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetSamplerState(device, 0,
> + D3DSAMP_MIPMAPLODBIAS, MAKEFOURCC('G','E','T','1'));
> + ok(SUCCEEDED(hr), "SetSamplerState failed, hr %#x.\n", hr);
> +
> + /* Setup the depth/stencil surface. */
> + hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_ZBUFFER, 0, 0.0f, 0);
> + ok(SUCCEEDED(hr), "Clear failed, hr %#x.\n", hr);
> +
> + /* Render to the depth surface */
> + hr = IDirect3DDevice9_BeginScene(device);
> + ok(SUCCEEDED(hr), "BeginScene failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad, sizeof(*quad));
> + ok(SUCCEEDED(hr), "DrawPrimitiveUP failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_EndScene(device);
> + ok(SUCCEEDED(hr), "EndScene failed, hr %#x.\n", hr);
> +
> + hr = IDirect3DDevice9_SetDepthStencilSurface(device, NULL);
> + ok(SUCCEEDED(hr), "SetDepthStencilSurface failed, hr %#x.\n", hr);
> + IDirect3DSurface9_Release(ds);
> + hr = IDirect3DDevice9_SetRenderTarget(device, 0, original_rt);
> + ok(SUCCEEDED(hr), "SetRenderTarget failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetTexture(device, 0, (IDirect3DBaseTexture9 *)depth_texture);
> + ok(SUCCEEDED(hr), "SetTexture failed, hr %#x.\n", hr);
> +
> + /* Set a shader for depth sampling, otherwise windows does not show anything */
> + hr = IDirect3DDevice9_SetVertexShader(device, vs);
> + ok(SUCCEEDED(hr), "Failed to set vertex shader, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_SetPixelShader(device, shaders[1].ps); /* same as texld */
> + ok(SUCCEEDED(hr), "SetPixelShader failed, hr %#x.\n", hr);
> +
> + for (j = 0; j < 2; ++j){
> + hr = IDirect3DDevice9_SetSamplerState(device, 0,
> + D3DSAMP_MIPMAPLODBIAS, MAKEFOURCC('G','E','T', j ? '4' : '1' ));
> + ok(SUCCEEDED(hr), "SetSamplerState failed, hr %#x.\n", hr);
> +
> + /* Do the actual shadow mapping. */
> + hr = IDirect3DDevice9_BeginScene(device);
> + ok(SUCCEEDED(hr), "BeginScene failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad, sizeof(*quad));
> + ok(SUCCEEDED(hr), "DrawPrimitiveUP failed, hr %#x.\n", hr);
> + hr = IDirect3DDevice9_EndScene(device);
> + ok(SUCCEEDED(hr), "EndScene failed, hr %#x.\n", hr);
> +
> + get_rt_readback(original_rt, &rb);
> + for (k = 0; k < ARRAY_SIZE(expected_depth[depth_tests[i].index]); ++k)
> + {
> + UINT x = expected_depth[depth_tests[i].index][k].x;
> + UINT y = expected_depth[depth_tests[i].index][k].y;
> + D3DCOLOR color_off = expected_depth[depth_tests[i].index][k].color_off;
> + D3DCOLOR color_amd = expected_depth[depth_tests[i].index][k].color_amd;
> + D3DCOLOR color_intel = expected_depth[depth_tests[i].index][k].color_intel;
> + D3DCOLOR color = get_readback_color(&rb, x, y);
> + /* When Fetch4 is OFF, ignore G and B channels on windows.
> + * Some implementations will copy R=G=B, some will set them to 0 */
> + if(j == 0)
> + ok((isWin && color_match(color & 0xffff0000, color_off & 0xffff0000, 2))
> + || color_match(color, color_off, 2),
> + "Test OFF Expected color 0x%08x at (%u, %u) for format %s, got 0x%08x.\n",
> + color_off, x, y, depth_tests[i].name, color);
> + else
> + ok(color_match(color, color_amd, 2)
> + || (isWin && color_match(color, color_intel, 2)),
> + "Test ON Expected colors 0x%08x || 0x%08x at (%u, %u) for format %s, got 0x%08x.\n",
> + color_amd, color_intel, x, y, depth_tests[i].name, color);
> + }
> + release_surface_readback(&rb);
> +
> + hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
> + ok(SUCCEEDED(hr), "Present failed, hr %#x.\n", hr);
> + }
> +
> + hr = IDirect3DDevice9_SetTexture(device, 0, NULL);
> + ok(SUCCEEDED(hr), "SetTexture failed, hr %#x.\n", hr);
> + IDirect3DTexture9_Release(depth_texture);
> + }
> +
> + IDirect3DVolumeTexture9_Release(texture3D);
> + IDirect3DTexture9_Release(texture);
> + for (i = 0; i < ARRAY_SIZE(shaders); ++i)
> + if (shaders[i].ps)
> + IDirect3DPixelShader9_Release(shaders[i].ps);
> + IDirect3DPixelShader9_Release(ps_3d);
> + IDirect3DVertexShader9_Release(vs);
> + IDirect3DSurface9_Release(rt);
> + IDirect3DSurface9_Release(original_ds);
> + IDirect3DSurface9_Release(original_rt);
> + refcount = IDirect3DDevice9_Release(device);
> + ok(!refcount, "Device has %u references left.\n", refcount);
> +done:
> + IDirect3D9_Release(d3d);
> + DestroyWindow(window);
> +}
> +
> static void shadow_test(void)
> {
> static const DWORD ps_code[] =
> @@ -24660,6 +25303,7 @@ START_TEST(visual)
> depth_buffer2_test();
> depth_blit_test();
> intz_test();
> + fetch4_test();
> shadow_test();
> fp_special_test();
> depth_bounds_test();