290 lines
12 KiB
C
290 lines
12 KiB
C
|
/*
|
||
|
* Copyright 2016-2017 Józef Kucia for CodeWeavers
|
||
|
* Copyright 2020-2021 Philip Rebohle for Valve Corporation
|
||
|
* Copyright 2020-2021 Joshua Ashton for Valve Corporation
|
||
|
* Copyright 2020-2021 Hans-Kristian Arntzen for Valve Corporation
|
||
|
*
|
||
|
* 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
|
||
|
*/
|
||
|
|
||
|
#define VKD3D_DBG_CHANNEL VKD3D_DBG_CHANNEL_API
|
||
|
#include "d3d12_crosstest.h"
|
||
|
|
||
|
void test_clock_calibration(void)
|
||
|
{
|
||
|
#ifndef _WIN32
|
||
|
skip("Clock calibration tests cannot pass on native Linux. Skipping.\n");
|
||
|
#else
|
||
|
uint64_t cpu_times[2], gpu_times[2];
|
||
|
struct test_context context;
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (!init_test_context(&context, NULL))
|
||
|
return;
|
||
|
|
||
|
hr = ID3D12CommandQueue_GetClockCalibration(context.queue, &gpu_times[0], &cpu_times[0]);
|
||
|
ok(hr == S_OK, "Failed retrieve calibrated timestamps, hr %#x.\n", hr);
|
||
|
|
||
|
vkd3d_sleep(100);
|
||
|
|
||
|
hr = ID3D12CommandQueue_GetClockCalibration(context.queue, &gpu_times[1], &cpu_times[1]);
|
||
|
ok(hr == S_OK, "Failed retrieve calibrated timestamps, hr %#x.\n", hr);
|
||
|
|
||
|
ok(gpu_times[1] > gpu_times[0], "Inconsistent GPU timestamps.\n");
|
||
|
ok(cpu_times[1] > cpu_times[0], "Inconsistent CPU timestamps.\n");
|
||
|
|
||
|
destroy_test_context(&context);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void test_open_heap_from_address(void)
|
||
|
{
|
||
|
#ifdef _WIN32
|
||
|
ID3D12Resource *readback_resource;
|
||
|
struct test_context context;
|
||
|
struct resource_readback rb;
|
||
|
D3D12_HEAP_DESC heap_desc;
|
||
|
ID3D12Resource *resource;
|
||
|
unsigned int heap_size;
|
||
|
ID3D12Device3 *device3;
|
||
|
ID3D12Device *device;
|
||
|
HANDLE file_handle;
|
||
|
ID3D12Heap *heap;
|
||
|
unsigned int i;
|
||
|
uint32_t *addr;
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (!init_test_context(&context, NULL))
|
||
|
return;
|
||
|
|
||
|
device = context.device;
|
||
|
hr = ID3D12Device_QueryInterface(device, &IID_ID3D12Device3, (void **)&device3);
|
||
|
ok(hr == S_OK, "Failed to query ID3D12Device3, hr #%x.\n", hr);
|
||
|
|
||
|
/* Simple case, import directly from VirtualAlloc. */
|
||
|
{
|
||
|
heap_size = 64 * 1024;
|
||
|
addr = VirtualAlloc(NULL, heap_size, MEM_COMMIT, PAGE_READWRITE);
|
||
|
ok(!!addr, "Failed to VirtualAllocate.\n");
|
||
|
|
||
|
for (i = 0; i < heap_size / sizeof(uint32_t); i++)
|
||
|
addr[i] = i;
|
||
|
|
||
|
hr = ID3D12Device3_OpenExistingHeapFromAddress(device3, addr, &IID_ID3D12Heap, (void **)&heap);
|
||
|
ok(hr == S_OK, "Failed to open heap from address: hr #%x.\n", hr);
|
||
|
|
||
|
if (heap)
|
||
|
{
|
||
|
heap_desc = ID3D12Heap_GetDesc(heap);
|
||
|
ok(heap_desc.SizeInBytes == heap_size, "Expected heap size of %u, but got %u.\n", heap_size, (unsigned int)heap_desc.SizeInBytes);
|
||
|
ok(!!(heap_desc.Flags & D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER), "Expected Heap desc to have SHARED_CROSS_ADAPTER flag set.\n");
|
||
|
ok(!!(heap_desc.Flags & D3D12_HEAP_FLAG_SHARED), "Expected heap desc to have SHARED flag set.\n");
|
||
|
|
||
|
resource = create_placed_buffer(device, heap, 0, heap_size, D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||
|
ok(!!resource, "Failed to create resource.\n");
|
||
|
readback_resource = create_default_buffer(device, heap_size, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_DEST);
|
||
|
ID3D12GraphicsCommandList_CopyResource(context.list, readback_resource, resource);
|
||
|
transition_resource_state(context.list, readback_resource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||
|
get_buffer_readback_with_command_list(readback_resource, DXGI_FORMAT_UNKNOWN, &rb, context.queue, context.list);
|
||
|
reset_command_list(context.list, context.allocator);
|
||
|
ok(!memcmp(rb.data, addr, heap_size), "Expected exact copy.\n");
|
||
|
release_resource_readback(&rb);
|
||
|
ID3D12Heap_Release(heap);
|
||
|
ID3D12Resource_Release(readback_resource);
|
||
|
ID3D12Resource_Release(resource);
|
||
|
}
|
||
|
VirtualFree(addr, 0, MEM_RELEASE);
|
||
|
}
|
||
|
|
||
|
/* Import at offset, which should fail. */
|
||
|
{
|
||
|
heap_size = 64 * 1024;
|
||
|
addr = VirtualAlloc(NULL, heap_size, MEM_COMMIT, PAGE_READWRITE);
|
||
|
ok(!!addr, "Failed to VirtualAllocate.\n");
|
||
|
hr = ID3D12Device3_OpenExistingHeapFromAddress(device3, addr + 1024, &IID_ID3D12Heap, (void **)&heap);
|
||
|
ok(hr == E_INVALIDARG, "Should not be able to open heap at offset from VirtualAlloc.\n");
|
||
|
}
|
||
|
|
||
|
/* HANDLE variant. */
|
||
|
{
|
||
|
heap_size = 256 * 1024;
|
||
|
file_handle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, heap_size, "foobar");
|
||
|
ok(!!file_handle, "Failed to open file mapping.\n");
|
||
|
|
||
|
addr = MapViewOfFile(file_handle, FILE_MAP_ALL_ACCESS, 0, 0, heap_size);
|
||
|
ok(!!addr, "Failed to map view of file.\n");
|
||
|
for (i = 0; i < heap_size / sizeof(uint32_t); i++)
|
||
|
addr[i] = i;
|
||
|
|
||
|
hr = ID3D12Device3_OpenExistingHeapFromFileMapping(device3, file_handle, &IID_ID3D12Heap, (void **)&heap);
|
||
|
ok(hr == S_OK, "Failed to open heap from file mapping: hr #%x.\n", hr);
|
||
|
|
||
|
if (heap)
|
||
|
{
|
||
|
heap_desc = ID3D12Heap_GetDesc(heap);
|
||
|
ok(heap_desc.SizeInBytes == heap_size, "Expected heap size of %u, but got %u.\n", heap_size, (unsigned int)heap_desc.SizeInBytes);
|
||
|
ok(!!(heap_desc.Flags & D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER), "Expected Heap desc to have SHARED_CROSS_ADAPTER flag set.\n");
|
||
|
ok(!!(heap_desc.Flags & D3D12_HEAP_FLAG_SHARED), "Expected heap desc to have SHARED flag set.\n");
|
||
|
|
||
|
resource = create_placed_buffer(device, heap, 0, heap_size, D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||
|
ok(!!resource, "Failed to create resource.\n");
|
||
|
readback_resource = create_default_buffer(device, heap_size, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_DEST);
|
||
|
ID3D12GraphicsCommandList_CopyResource(context.list, readback_resource, resource);
|
||
|
transition_resource_state(context.list, readback_resource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||
|
get_buffer_readback_with_command_list(readback_resource, DXGI_FORMAT_UNKNOWN, &rb, context.queue, context.list);
|
||
|
reset_command_list(context.list, context.allocator);
|
||
|
for (i = 0; i < heap_size / sizeof(uint32_t); i++)
|
||
|
{
|
||
|
uint32_t v = get_readback_uint(&rb, i, 0, 0);
|
||
|
ok(v == i, "Expected %u, got %u.\n", i, v);
|
||
|
}
|
||
|
release_resource_readback(&rb);
|
||
|
ID3D12Heap_Release(heap);
|
||
|
ID3D12Resource_Release(readback_resource);
|
||
|
ID3D12Resource_Release(resource);
|
||
|
}
|
||
|
|
||
|
UnmapViewOfFile(addr);
|
||
|
CloseHandle(file_handle);
|
||
|
}
|
||
|
|
||
|
ID3D12Device3_Release(device3);
|
||
|
destroy_test_context(&context);
|
||
|
#else
|
||
|
skip("Cannot test OpenExistingHeapFrom* on non-native Win32 platforms.\n");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void test_write_watch(void)
|
||
|
{
|
||
|
#ifndef _WIN32
|
||
|
skip("WRITE_WATCH tests cannot pass on native Linux. Skipping.\n");
|
||
|
#else
|
||
|
D3D12_HEAP_PROPERTIES heap_properties;
|
||
|
D3D12_RESOURCE_DESC resource_desc;
|
||
|
struct test_context_desc desc;
|
||
|
void **dirty_addresses = NULL;
|
||
|
struct test_context context;
|
||
|
ULONG_PTR address_count;
|
||
|
ID3D12Resource *buffer;
|
||
|
size_t mapping_size;
|
||
|
DWORD page_size;
|
||
|
char *map_ptr;
|
||
|
UINT result;
|
||
|
HRESULT hr;
|
||
|
|
||
|
mapping_size = 64 * 1024;
|
||
|
|
||
|
memset(&desc, 0, sizeof(desc));
|
||
|
desc.no_render_target = true;
|
||
|
desc.no_pipeline = true;
|
||
|
desc.no_root_signature = true;
|
||
|
if (!init_test_context(&context, &desc))
|
||
|
return;
|
||
|
|
||
|
memset(&heap_properties, 0, sizeof(heap_properties));
|
||
|
|
||
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||
|
resource_desc.Alignment = 0;
|
||
|
resource_desc.Width = mapping_size;
|
||
|
resource_desc.Height = 1;
|
||
|
resource_desc.DepthOrArraySize = 1;
|
||
|
resource_desc.MipLevels = 1;
|
||
|
resource_desc.Format = DXGI_FORMAT_UNKNOWN;
|
||
|
resource_desc.SampleDesc.Count = 1;
|
||
|
resource_desc.SampleDesc.Quality = 0;
|
||
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||
|
|
||
|
buffer = NULL;
|
||
|
heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||
|
hr = ID3D12Device_CreateCommittedResource(context.device, &heap_properties,
|
||
|
D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH, &resource_desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||
|
NULL, &IID_ID3D12Resource, (void **)&buffer);
|
||
|
ok(hr == E_INVALIDARG, "Got hr %#x, expected %#x.\n", hr, E_INVALIDARG);
|
||
|
if (buffer)
|
||
|
ID3D12Resource_Release(buffer);
|
||
|
|
||
|
buffer = NULL;
|
||
|
heap_properties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||
|
hr = ID3D12Device_CreateCommittedResource(context.device, &heap_properties,
|
||
|
D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH, &resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ,
|
||
|
NULL, &IID_ID3D12Resource, (void **)&buffer);
|
||
|
ok(hr == S_OK, "Got hr %#x, expected %#x.\n", hr, S_OK);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
skip("Failed to create write watch buffer.\n");
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
/* Do some basic write watch testing... */
|
||
|
hr = ID3D12Resource_Map(buffer, 0, NULL, (void**) &map_ptr);
|
||
|
ok(hr == S_OK, "Got hr %#x, expected %#x.\n", hr, S_OK);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
skip("Failed to map write watch resource.\n");
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
result = ResetWriteWatch((void*) map_ptr, mapping_size);
|
||
|
ok(!result, "Failed to ResetWriteWatch %#x.\n", GetLastError());
|
||
|
if (result)
|
||
|
{
|
||
|
skip("Failed to ResetWriteWatch, skipping the rest of the WRITE_WATCH tests.\n");
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
page_size = 0x1000;
|
||
|
address_count = mapping_size / (DWORD_PTR)page_size;
|
||
|
dirty_addresses = malloc(sizeof(void*) * address_count);
|
||
|
|
||
|
/* Dirty it a bit, in some pages... */
|
||
|
map_ptr[0 * page_size] = 'a';
|
||
|
map_ptr[1 * page_size] = 'b';
|
||
|
map_ptr[5 * page_size] = 'c';
|
||
|
map_ptr[9 * page_size] = 'd';
|
||
|
|
||
|
result = GetWriteWatch(WRITE_WATCH_FLAG_RESET, (void*) map_ptr, mapping_size, dirty_addresses, &address_count, &page_size);
|
||
|
ok(!result, "Failed to GetWriteWatch %#x.\n", GetLastError());
|
||
|
if (result)
|
||
|
{
|
||
|
skip("Failed to GetWriteWatch, skipping the rest of the WRITE_WATCH tests.\n");
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
ok(address_count == 4, "Expected address_count of %p, got %p\n", 4, address_count);
|
||
|
ok(page_size == 0x1000, "Expected page_size of %u, got %u\n", 0x1000, page_size);
|
||
|
ok(dirty_addresses[0] == (void*)&map_ptr[0 * page_size], "Expected dirty address 0 to be %p, got %p\n",
|
||
|
(void*)&map_ptr[0 * page_size], dirty_addresses[0]);
|
||
|
ok(dirty_addresses[1] == (void*)&map_ptr[1 * page_size], "Expected dirty address 1 to be %p, got %p\n",
|
||
|
(void*)&map_ptr[1 * page_size], dirty_addresses[1]);
|
||
|
ok(dirty_addresses[2] == (void*)&map_ptr[5 * page_size], "Expected dirty address 2 to be %p, got %p\n",
|
||
|
(void*)&map_ptr[5 * page_size], dirty_addresses[2]);
|
||
|
ok(dirty_addresses[3] == (void*)&map_ptr[9 * page_size], "Expected dirty address 3 to be %p, got %p\n",
|
||
|
(void*)&map_ptr[9 * page_size], dirty_addresses[3]);
|
||
|
|
||
|
done:
|
||
|
free(dirty_addresses);
|
||
|
|
||
|
if (buffer)
|
||
|
ID3D12Resource_Release(buffer);
|
||
|
|
||
|
destroy_test_context(&context);
|
||
|
#endif
|
||
|
}
|
||
|
|