Martin Storsjo : d3d9/tests: Add tests for different YUV texture layouts.
Alexandre Julliard
julliard at winehq.org
Mon Feb 17 13:45:16 CST 2014
Module: wine
Branch: master
Commit: 8b2938a23ef0f317d656a5acc13374f5613a4574
URL: http://source.winehq.org/git/wine.git/?a=commit;h=8b2938a23ef0f317d656a5acc13374f5613a4574
Author: Martin Storsjo <martin at martin.st>
Date: Mon Feb 17 14:46:02 2014 +0200
d3d9/tests: Add tests for different YUV texture layouts.
---
dlls/d3d9/tests/visual.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 184 insertions(+)
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
index 13d0ea6..e107471 100644
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -10508,6 +10508,189 @@ static void yuv_color_test(IDirect3DDevice9 *device)
IDirect3D9_Release(d3d);
}
+static void yuv_layout_test(IDirect3DDevice9 *device)
+{
+ HRESULT hr;
+ IDirect3DSurface9 *surface, *target;
+ unsigned int fmt, i, x, y;
+ D3DFORMAT format;
+ const char *fmt_string;
+ D3DLOCKED_RECT lr;
+ IDirect3D9 *d3d;
+ D3DCOLOR color;
+ DWORD ref_color;
+ BYTE *buf, *chroma_buf, *u_buf, *v_buf;
+ UINT width = 20, height = 16;
+ D3DCAPS9 caps;
+ D3DFORMAT skip_once = D3DFMT_UNKNOWN;
+ D3DSURFACE_DESC desc;
+
+ static const struct
+ {
+ DWORD color1, color2;
+ DWORD rgb1, rgb2;
+ }
+ test_data[] =
+ {
+ { 0x000000, 0xffffff, 0x00008800, 0x00ff7dff },
+ { 0xff0000, 0x00ffff, 0x004aff14, 0x00b800ee },
+ { 0x00ff00, 0xff00ff, 0x000024ee, 0x00ffe114 },
+ { 0x0000ff, 0xffff00, 0x00b80000, 0x004affff },
+ { 0xffff00, 0x0000ff, 0x004affff, 0x00b80000 },
+ { 0xff00ff, 0x00ff00, 0x00ffe114, 0x000024ee },
+ { 0x00ffff, 0xff0000, 0x00b800ee, 0x004aff14 },
+ { 0xffffff, 0x000000, 0x00ff7dff, 0x00008800 },
+ };
+
+ static const struct
+ {
+ D3DFORMAT format;
+ const char *str;
+ }
+ formats[] =
+ {
+ { D3DFMT_UYVY, "D3DFMT_UYVY", },
+ { D3DFMT_YUY2, "D3DFMT_YUY2", },
+ { MAKEFOURCC('Y','V','1','2'), "D3DFMT_YV12", },
+ { MAKEFOURCC('N','V','1','2'), "D3DFMT_NV12", },
+ };
+
+ hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
+ ok(SUCCEEDED(hr), "GetDeviceCaps failed, hr %#x.\n", hr);
+ if (caps.TextureCaps & D3DPTEXTURECAPS_POW2
+ && !(caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL))
+ {
+ skip("No NP2 texture support, skipping YUV texture layout test.\n");
+ return;
+ }
+
+ hr = IDirect3DDevice9_GetDirect3D(device, &d3d);
+ ok(hr == D3D_OK, "IDirect3DDevice9_GetDirect3D failed, hr = %#x.\n", hr);
+ hr = IDirect3DDevice9_GetRenderTarget(device, 0, &target);
+ ok(hr == D3D_OK, "IDirect3DDevice9_GetRenderTarget failed, hr = %#x.\n", hr);
+ hr = IDirect3DSurface9_GetDesc(target, &desc);
+ ok(SUCCEEDED(hr), "Failed to get surface description, hr %#x.\n", hr);
+
+ for (fmt = 0; fmt < sizeof(formats) / sizeof(formats[0]); fmt++)
+ {
+ format = formats[fmt].format;
+ fmt_string = formats[fmt].str;
+
+ /* Some (all?) Windows drivers do not support YUV 3D textures, only 2D surfaces in
+ * StretchRect. Thus use StretchRect to draw the YUV surface onto the screen instead
+ * of drawPrimitive. */
+ if (IDirect3D9_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, 0,
+ D3DRTYPE_SURFACE, format) != D3D_OK)
+ {
+ if (skip_once != format)
+ {
+ skip("%s is not supported.\n", fmt_string);
+ skip_once = format;
+ }
+ continue;
+ }
+ if (FAILED(IDirect3D9_CheckDeviceFormatConversion(d3d, 0,
+ D3DDEVTYPE_HAL, format, desc.Format)))
+ {
+ if (skip_once != format)
+ {
+ skip("Driver cannot blit %s surfaces.\n", fmt_string);
+ skip_once = format;
+ }
+ continue;
+ }
+
+ hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, width, height, format, D3DPOOL_DEFAULT, &surface, NULL);
+ ok(hr == D3D_OK, "IDirect3DDevice9_CreateOffscreenPlainSurface failed, hr = %#x.\n", hr);
+
+ for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); i++)
+ {
+ hr = IDirect3DSurface9_LockRect(surface, &lr, NULL, 0);
+ ok(hr == D3D_OK, "IDirect3DSurface9_LockRect failed, hr = %#x.\n", hr);
+ buf = lr.pBits;
+ chroma_buf = buf + lr.Pitch * height;
+ if (format == MAKEFOURCC('Y','V','1','2'))
+ {
+ v_buf = chroma_buf;
+ u_buf = chroma_buf + height / 2 * lr.Pitch/2;
+ }
+ /* Draw the top left quarter of the screen with color1, the rest with color2 */
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < width; x += 2)
+ {
+ DWORD color = (x < width / 2 && y < height / 2) ? test_data[i].color1 : test_data[i].color2;
+ BYTE Y = (color >> 16) & 0xff;
+ BYTE U = (color >> 8) & 0xff;
+ BYTE V = (color >> 0) & 0xff;
+ if (format == D3DFMT_UYVY)
+ {
+ buf[y * lr.Pitch + 2 * x + 0] = U;
+ buf[y * lr.Pitch + 2 * x + 1] = Y;
+ buf[y * lr.Pitch + 2 * x + 2] = V;
+ buf[y * lr.Pitch + 2 * x + 3] = Y;
+ }
+ else if (format == D3DFMT_YUY2)
+ {
+ buf[y * lr.Pitch + 2 * x + 0] = Y;
+ buf[y * lr.Pitch + 2 * x + 1] = U;
+ buf[y * lr.Pitch + 2 * x + 2] = Y;
+ buf[y * lr.Pitch + 2 * x + 3] = V;
+ }
+ else if (format == MAKEFOURCC('Y','V','1','2'))
+ {
+ buf[y * lr.Pitch + x + 0] = Y;
+ buf[y * lr.Pitch + x + 1] = Y;
+ u_buf[(y / 2) * (lr.Pitch / 2) + (x / 2)] = U;
+ v_buf[(y / 2) * (lr.Pitch / 2) + (x / 2)] = V;
+ }
+ else if (format == MAKEFOURCC('N','V','1','2'))
+ {
+ buf[y * lr.Pitch + x + 0] = Y;
+ buf[y * lr.Pitch + x + 1] = Y;
+ chroma_buf[(y / 2) * lr.Pitch + 2 * (x / 2) + 0] = U;
+ chroma_buf[(y / 2) * lr.Pitch + 2 * (x / 2) + 1] = V;
+ }
+ }
+ }
+ hr = IDirect3DSurface9_UnlockRect(surface);
+ ok(hr == D3D_OK, "IDirect3DSurface9_UnlockRect failed, hr = %#x.\n", hr);
+
+ hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0x00000000, 1.0f, 0);
+ ok(hr == D3D_OK, "IDirect3DDevice9_Clear failed with %#x.\n", hr);
+ hr = IDirect3DDevice9_StretchRect(device, surface, NULL, target, NULL, D3DTEXF_POINT);
+ ok(hr == D3D_OK, "IDirect3DDevice9_StretchRect failed with %#x.\n", hr);
+
+ /* Some Windows drivers (mostly Nvidia, but also some VM drivers) insist on doing linear filtering
+ * although we asked for point filtering. To prevent running into precision problems, read at points
+ * with some margin within each quadrant.
+ *
+ * Unfortunately different implementations(Windows-Nvidia and Mac-AMD tested) interpret some colors
+ * vastly differently, so we need a max diff of 18. */
+ for (y = 0; y < 4; y++)
+ {
+ for (x = 0; x < 4; x++)
+ {
+ UINT xcoord = (1 + 2 * x) * 640 / 8;
+ UINT ycoord = (1 + 2 * y) * 480 / 8;
+ ref_color = (y < 2 && x < 2) ? test_data[i].rgb1 : test_data[i].rgb2;
+ color = getPixelColor(device, xcoord, ycoord);
+ ok(color_match(color, ref_color, 18),
+ "Format %s: Got color %#x for pixel (%d/%d)/(%d/%d), pixel %d %d, expected %#x.\n",
+ fmt_string, color, x, 4, y, 4, xcoord, ycoord, ref_color);
+ }
+ }
+ hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+
+ ok(SUCCEEDED(hr), "Present failed with %#x.\n", hr);
+ }
+ IDirect3DSurface9_Release(surface);
+ }
+
+ IDirect3DSurface9_Release(target);
+ IDirect3D9_Release(d3d);
+}
+
static void texop_range_test(IDirect3DDevice9 *device)
{
static const struct {
@@ -15197,6 +15380,7 @@ START_TEST(visual)
tssargtemp_test(device_ptr);
np2_stretch_rect_test(device_ptr);
yuv_color_test(device_ptr);
+ yuv_layout_test(device_ptr);
zwriteenable_test(device_ptr);
alphatest_test(device_ptr);
viewport_test(device_ptr);
More information about the wine-cvs
mailing list