/*
* Copyright 2008 Henri Verbeet for CodeWeavers
* Copyright 2015 Józef Kucia for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <assert.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#define COBJMACROS
#include "initguid.h"
#include "d3d11_4.h"
#include "wine/heap.h"
#include "wine/test.h"
#define BITS_NNAN 0xffc00000
#define BITS_NAN 0x7fc00000
#define BITS_NINF 0xff800000
#define BITS_INF 0x7f800000
#define BITS_N1_0 0xbf800000
#define BITS_1_0 0x3f800000
#define SWAPCHAIN_FLAG_SHADER_INPUT 0x1
static unsigned int use_adapter_idx;
static BOOL enable_debug_layer;
static BOOL use_warp_adapter;
static BOOL use_mt = TRUE;
static struct test_entry
{
union
{
void (*test)(void);
void (*test_fl)(D3D_FEATURE_LEVEL fl);
} u;
D3D_FEATURE_LEVEL fl;
} *mt_tests;
size_t mt_tests_size, mt_test_count;
struct format_support
{
DXGI_FORMAT format;
D3D_FEATURE_LEVEL fl_required;
D3D_FEATURE_LEVEL fl_optional;
};
static const struct format_support display_format_support[] =
{
{DXGI_FORMAT_R8G8B8A8_UNORM, D3D_FEATURE_LEVEL_9_1},
{DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3D_FEATURE_LEVEL_9_1},
{DXGI_FORMAT_B8G8R8A8_UNORM, D3D_FEATURE_LEVEL_9_1},
{DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, D3D_FEATURE_LEVEL_9_1},
{DXGI_FORMAT_R16G16B16A16_FLOAT, D3D_FEATURE_LEVEL_10_0},
{DXGI_FORMAT_R10G10B10A2_UNORM, D3D_FEATURE_LEVEL_10_0},
{DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0},
};
struct vec2
{
float x, y;
};
struct vec3
{
float x, y, z;
};
struct vec4
{
float x, y, z, w;
};
struct ivec4
{
int x, y, z, w;
};
struct uvec4
{
unsigned int x, y, z, w;
};
struct device_desc
{
const D3D_FEATURE_LEVEL *feature_level;
UINT flags;
};
struct swapchain_desc
{
BOOL windowed;
unsigned buffer_count;
unsigned int width, height;
DXGI_SWAP_EFFECT swap_effect;
DWORD flags;
};
static void queue_test_entry(const struct test_entry *t)
{
if (mt_test_count >= mt_tests_size)
{
mt_tests_size = max(16, mt_tests_size * 2);
mt_tests = heap_realloc(mt_tests, mt_tests_size * sizeof(*t));
}
mt_tests[mt_test_count++] = *t;
}
static void queue_test_fl(void (*test)(const D3D_FEATURE_LEVEL fl), D3D_FEATURE_LEVEL fl)
{
struct test_entry t;
t.u.test_fl = test;
t.fl = fl;
queue_test_entry(&t);
}
static void queue_test(void (*test)(void))
{
struct test_entry t;
t.u.test = test;
t.fl = 0;
queue_test_entry(&t);
}
static void run_mt_test(const struct test_entry *t)
{
if (t->fl)
t->u.test_fl(t->fl);
else
t->u.test();
}
static DWORD WINAPI thread_func(void *ctx)
{
LONG *i = ctx, j;
while (*i < mt_test_count)
{
j = *i;
if (InterlockedCompareExchange(i, j + 1, j) == j)
run_mt_test(&mt_tests[j]);
}
return 0;
}
static void run_queued_tests(void)
{
unsigned int thread_count, i;
HANDLE *threads;
SYSTEM_INFO si;
LONG test_idx;
if (!use_mt)
{
for (i = 0; i < mt_test_count; ++i)
{
run_mt_test(&mt_tests[i]);
}
return;
}
GetSystemInfo(&si);
thread_count = si.dwNumberOfProcessors;
threads = heap_calloc(thread_count, sizeof(*threads));
for (i = 0, test_idx = 0; i < thread_count; ++i)
{
threads[i] = CreateThread(NULL, 0, thread_func, &test_idx, 0, NULL);
ok(!!threads[i], "Failed to create thread %u.\n", i);
}
WaitForMultipleObjects(thread_count, threads, TRUE, INFINITE);
for (i = 0; i < thread_count; ++i)
{
CloseHandle(threads[i]);
}
heap_free(threads);
}
static void set_box(D3D11_BOX *box, UINT left, UINT top, UINT front, UINT right, UINT bottom, UINT back)
{
box->left = left;
box->top = top;
box->front = front;
box->right = right;
box->bottom = bottom;
box->back = back;
}
static ULONG get_refcount(void *iface)
{
IUnknown *unknown = iface;
IUnknown_AddRef(unknown);
return IUnknown_Release(unknown);
}
#define check_interface(a, b, c, d) check_interface_(__LINE__, a, b, c, d)
static HRESULT check_interface_(unsigned int line, void *iface, REFIID riid, BOOL supported, BOOL is_broken)
{
HRESULT hr, expected_hr, broken_hr;
IUnknown *unknown = iface, *out;
if (supported)
{
expected_hr = S_OK;
broken_hr = E_NOINTERFACE;
}
else
{
expected_hr = E_NOINTERFACE;
broken_hr = S_OK;
}
hr = IUnknown_QueryInterface(unknown, riid, (void **)&out);
ok_(__FILE__, line)(hr == expected_hr || broken(is_broken && hr == broken_hr),
"Got hr %#x, expected %#x.\n", hr, expected_hr);
if (SUCCEEDED(hr))
IUnknown_Release(out);
return hr;
}
static BOOL compare_float(float f, float g, unsigned int ulps)
{
int x = *(int *)&f;
int y = *(int *)&g;
if (x < 0)
x = INT_MIN - x;
if (y < 0)
y = INT_MIN - y;
if (abs(x - y) > ulps)
return FALSE;
return TRUE;
}
static BOOL compare_vec4(const struct vec4 *v1, const struct vec4 *v2, unsigned int ulps)
{
return compare_float(v1->x, v2->x, ulps)
&& compare_float(v1->y, v2->y, ulps)
&& compare_float(v1->z, v2->z, ulps)
&& compare_float(v1->w, v2->w, ulps);
}
static BOOL compare_uvec4(const struct uvec4* v1, const struct uvec4 *v2)
{
return v1->x == v2->x && v1->y == v2->y && v1->z == v2->z && v1->w == v2->w;
}
static BOOL compare_color(DWORD c1, DWORD c2, BYTE max_diff)
{
if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff)
return FALSE;
c1 >>= 8; c2 >>= 8;
if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff)
return FALSE;
c1 >>= 8; c2 >>= 8;
if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff)
return FALSE;
c1 >>= 8; c2 >>= 8;
if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff)
return FALSE;
return TRUE;
}
struct srv_desc
{
DXGI_FORMAT format;
D3D11_SRV_DIMENSION dimension;
unsigned int miplevel_idx;
unsigned int miplevel_count;
unsigned int layer_idx;
unsigned int layer_count;
};
static void get_srv_desc(D3D11_SHADER_RESOURCE_VIEW_DESC *d3d11_desc, const struct srv_desc *desc)
{
d3d11_desc->Format = desc->format;
d3d11_desc->ViewDimension = desc->dimension;
if (desc->dimension == D3D11_SRV_DIMENSION_TEXTURE1D)
{
U(*d3d11_desc).Texture1D.MostDetailedMip = desc->miplevel_idx;
U(*d3d11_desc).Texture1D.MipLevels = desc->miplevel_count;
}
else if (desc->dimension == D3D11_SRV_DIMENSION_TEXTURE1DARRAY)
{
U(*d3d11_desc).Texture1DArray.MostDetailedMip = desc->miplevel_idx;
U(*d3d11_desc).Texture1DArray.MipLevels = desc->miplevel_count;
U(*d3d11_desc).Texture1DArray.FirstArraySlice = desc->layer_idx;
U(*d3d11_desc).Texture1DArray.ArraySize = desc->layer_count;
}
else if (desc->dimension == D3D11_SRV_DIMENSION_TEXTURE2D)
{
U(*d3d11_desc).Texture2D.MostDetailedMip = desc->miplevel_idx;
U(*d3d11_desc).Texture2D.MipLevels = desc->miplevel_count;
}
else if (desc->dimension == D3D11_S