3393 lines
142 KiB
C
3393 lines
142 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_create_committed_resource(void)
|
|
{
|
|
D3D12_GPU_VIRTUAL_ADDRESS gpu_address;
|
|
D3D12_HEAP_PROPERTIES heap_properties;
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
ID3D12Device *device, *tmp_device;
|
|
D3D12_CLEAR_VALUE clear_value;
|
|
D3D12_RESOURCE_STATES state;
|
|
ID3D12Resource *resource;
|
|
unsigned int i;
|
|
ULONG refcount;
|
|
HRESULT hr;
|
|
|
|
static const struct
|
|
{
|
|
D3D12_HEAP_TYPE heap_type;
|
|
D3D12_RESOURCE_FLAGS flags;
|
|
}
|
|
invalid_buffer_desc_tests[] =
|
|
{
|
|
/* Render target or unordered access resources are not allowed with UPLOAD or READBACK. */
|
|
{D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET},
|
|
{D3D12_HEAP_TYPE_READBACK, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET},
|
|
{D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS},
|
|
{D3D12_HEAP_TYPE_READBACK, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS},
|
|
{D3D12_HEAP_TYPE_DEFAULT, D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS},
|
|
{D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS},
|
|
{D3D12_HEAP_TYPE_READBACK, D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS},
|
|
};
|
|
|
|
if (!(device = create_device()))
|
|
{
|
|
skip("Failed to create device.\n");
|
|
return;
|
|
}
|
|
|
|
memset(&heap_properties, 0, sizeof(heap_properties));
|
|
heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 32;
|
|
resource_desc.Height = 32;
|
|
resource_desc.DepthOrArraySize = 1;
|
|
resource_desc.MipLevels = 1;
|
|
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
resource_desc.SampleDesc.Count = 1;
|
|
resource_desc.SampleDesc.Quality = 0;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
|
|
clear_value.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
clear_value.Color[0] = 1.0f;
|
|
clear_value.Color[1] = 0.0f;
|
|
clear_value.Color[2] = 0.0f;
|
|
clear_value.Color[3] = 1.0f;
|
|
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clear_value,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == S_OK, "Failed to create committed resource, hr %#x.\n", hr);
|
|
|
|
refcount = get_refcount(device);
|
|
ok(refcount == 2, "Got unexpected refcount %u.\n", (unsigned int)refcount);
|
|
hr = ID3D12Resource_GetDevice(resource, &IID_ID3D12Device, (void **)&tmp_device);
|
|
ok(hr == S_OK, "Failed to get device, hr %#x.\n", hr);
|
|
refcount = get_refcount(device);
|
|
ok(refcount == 3, "Got unexpected refcount %u.\n", (unsigned int)refcount);
|
|
refcount = ID3D12Device_Release(tmp_device);
|
|
ok(refcount == 2, "Got unexpected refcount %u.\n", (unsigned int)refcount);
|
|
|
|
check_interface(resource, &IID_ID3D12Object, true);
|
|
check_interface(resource, &IID_ID3D12DeviceChild, true);
|
|
check_interface(resource, &IID_ID3D12Pageable, true);
|
|
check_interface(resource, &IID_ID3D12Resource, true);
|
|
|
|
gpu_address = ID3D12Resource_GetGPUVirtualAddress(resource);
|
|
ok(!gpu_address, "Got unexpected GPU virtual address %#"PRIx64".\n", gpu_address);
|
|
|
|
refcount = ID3D12Resource_Release(resource);
|
|
ok(!refcount, "ID3D12Resource has %u references left.\n", (unsigned int)refcount);
|
|
|
|
resource_desc.MipLevels = 0;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clear_value,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == S_OK, "Failed to create committed resource, hr %#x.\n", hr);
|
|
resource_desc = ID3D12Resource_GetDesc(resource);
|
|
ok(resource_desc.MipLevels == 6, "Got unexpected miplevels %u.\n", resource_desc.MipLevels);
|
|
ID3D12Resource_Release(resource);
|
|
resource_desc.MipLevels = 10;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clear_value,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == S_OK, "Failed to create committed resource, hr %#x.\n", hr);
|
|
resource_desc = ID3D12Resource_GetDesc(resource);
|
|
ok(resource_desc.MipLevels == 10, "Got unexpected miplevels %u.\n", resource_desc.MipLevels);
|
|
ID3D12Resource_Release(resource);
|
|
resource_desc.MipLevels = 1;
|
|
|
|
resource_desc.SampleDesc.Count = 0;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clear_value,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
resource_desc.SampleDesc.Count = 1;
|
|
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
|
&clear_value, &IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* For D3D12_RESOURCE_STATE_RENDER_TARGET the D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET flag is required. */
|
|
resource_desc.Flags = 0;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
todo ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
if (SUCCEEDED(hr))
|
|
ID3D12Resource_Release(resource);
|
|
|
|
/* A texture cannot be created on a UPLOAD heap. */
|
|
heap_properties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
|
resource = (void *)(uintptr_t)0xdeadbeef;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
ok(!resource, "Got unexpected pointer %p.\n", resource);
|
|
|
|
resource = (void *)(uintptr_t)0xdeadbeef;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
|
&IID_ID3D12Device, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
ok(!resource, "Got unexpected pointer %p.\n", resource);
|
|
|
|
/* A texture cannot be created on a READBACK heap. */
|
|
heap_properties.Type = D3D12_HEAP_TYPE_READBACK;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
resource_desc.Format = DXGI_FORMAT_BC1_UNORM;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == S_OK, "Failed to create committed resource, hr %#x.\n", hr);
|
|
ID3D12Resource_Release(resource);
|
|
|
|
resource_desc.Height = 31;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
resource_desc.Width = 31;
|
|
resource_desc.Height = 32;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
resource_desc.Width = 30;
|
|
resource_desc.Height = 30;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
resource_desc.Width = 2;
|
|
resource_desc.Height = 2;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D;
|
|
resource_desc.Width = 32;
|
|
resource_desc.Height = 1;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
heap_properties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 32;
|
|
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;
|
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == S_OK, "Failed to create committed resource, hr %#x.\n", hr);
|
|
|
|
check_interface(resource, &IID_ID3D12Object, true);
|
|
check_interface(resource, &IID_ID3D12DeviceChild, true);
|
|
check_interface(resource, &IID_ID3D12Pageable, true);
|
|
check_interface(resource, &IID_ID3D12Resource, true);
|
|
|
|
gpu_address = ID3D12Resource_GetGPUVirtualAddress(resource);
|
|
ok(gpu_address, "Got unexpected GPU virtual address %#"PRIx64".\n", gpu_address);
|
|
|
|
refcount = ID3D12Resource_Release(resource);
|
|
ok(!refcount, "ID3D12Resource has %u references left.\n", (unsigned int)refcount);
|
|
|
|
resource_desc.MipLevels = 0;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, &clear_value,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Failed to create committed resource, hr %#x.\n", hr);
|
|
resource_desc.MipLevels = 1;
|
|
|
|
/* The clear value must be NULL for buffers. */
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, &clear_value,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* For D3D12_HEAP_TYPE_UPLOAD the state must be D3D12_RESOURCE_STATE_GENERIC_READ. */
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COPY_SOURCE, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
heap_properties.Type = D3D12_HEAP_TYPE_READBACK;
|
|
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == S_OK, "Failed to create committed resource, hr %#x.\n", hr);
|
|
|
|
gpu_address = ID3D12Resource_GetGPUVirtualAddress(resource);
|
|
ok(gpu_address, "Got unexpected GPU virtual address %#"PRIx64".\n", gpu_address);
|
|
|
|
refcount = ID3D12Resource_Release(resource);
|
|
ok(!refcount, "ID3D12Resource has %u references left.\n", (unsigned int)refcount);
|
|
|
|
/* For D3D12_HEAP_TYPE_READBACK the state must be D3D12_RESOURCE_STATE_COPY_DEST. */
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COPY_SOURCE, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(invalid_buffer_desc_tests); ++i)
|
|
{
|
|
memset(&heap_properties, 0, sizeof(heap_properties));
|
|
heap_properties.Type = invalid_buffer_desc_tests[i].heap_type;
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 32;
|
|
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;
|
|
resource_desc.Flags = invalid_buffer_desc_tests[i].flags;
|
|
|
|
if (invalid_buffer_desc_tests[i].heap_type == D3D12_HEAP_TYPE_UPLOAD)
|
|
state = D3D12_RESOURCE_STATE_GENERIC_READ;
|
|
else
|
|
state = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, state, NULL, &IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Test %u: Got unexpected hr %#x.\n", i, hr);
|
|
}
|
|
|
|
refcount = ID3D12Device_Release(device);
|
|
ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount);
|
|
}
|
|
|
|
void test_create_heap(void)
|
|
{
|
|
D3D12_FEATURE_DATA_ARCHITECTURE architecture;
|
|
D3D12_FEATURE_DATA_D3D12_OPTIONS options;
|
|
D3D12_HEAP_DESC desc, result_desc;
|
|
ID3D12Device *device, *tmp_device;
|
|
bool is_pool_L1_supported;
|
|
HRESULT hr, expected_hr;
|
|
unsigned int i, j;
|
|
ID3D12Heap *heap;
|
|
ULONG refcount;
|
|
|
|
static const struct
|
|
{
|
|
uint64_t alignment;
|
|
HRESULT expected_hr;
|
|
}
|
|
tests[] =
|
|
{
|
|
{D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT, S_OK},
|
|
{D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT, S_OK},
|
|
{2 * D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT, E_INVALIDARG},
|
|
{2 * D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT, E_INVALIDARG},
|
|
{D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT, E_INVALIDARG},
|
|
};
|
|
static const struct
|
|
{
|
|
D3D12_HEAP_FLAGS flags;
|
|
const char *name;
|
|
}
|
|
heap_flags[] =
|
|
{
|
|
{D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS, "buffers"},
|
|
{D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES, "textures"},
|
|
{D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES, "rt_ds_textures"},
|
|
};
|
|
static const struct
|
|
{
|
|
D3D12_CPU_PAGE_PROPERTY page_property;
|
|
D3D12_MEMORY_POOL pool_preference;
|
|
HRESULT expected_hr;
|
|
}
|
|
custom_tests[] =
|
|
{
|
|
{D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_UNKNOWN, E_INVALIDARG},
|
|
{D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE, D3D12_MEMORY_POOL_UNKNOWN, E_INVALIDARG},
|
|
{D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE, D3D12_MEMORY_POOL_UNKNOWN, E_INVALIDARG},
|
|
{D3D12_CPU_PAGE_PROPERTY_WRITE_BACK, D3D12_MEMORY_POOL_UNKNOWN, E_INVALIDARG},
|
|
{D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_L0, E_INVALIDARG},
|
|
{D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE, D3D12_MEMORY_POOL_L0, S_OK},
|
|
{D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE, D3D12_MEMORY_POOL_L0, S_OK},
|
|
{D3D12_CPU_PAGE_PROPERTY_WRITE_BACK, D3D12_MEMORY_POOL_L0, S_OK},
|
|
{D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_L1, E_INVALIDARG},
|
|
{D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE, D3D12_MEMORY_POOL_L1, S_OK},
|
|
{D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE, D3D12_MEMORY_POOL_L1, E_INVALIDARG},
|
|
{D3D12_CPU_PAGE_PROPERTY_WRITE_BACK, D3D12_MEMORY_POOL_L1, E_INVALIDARG},
|
|
};
|
|
|
|
if (!(device = create_device()))
|
|
{
|
|
skip("Failed to create device.\n");
|
|
return;
|
|
}
|
|
|
|
desc.SizeInBytes = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
memset(&desc.Properties, 0, sizeof(desc.Properties));
|
|
desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
desc.Alignment = 0;
|
|
desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES;
|
|
hr = ID3D12Device_CreateHeap(device, &desc, &IID_ID3D12Heap, (void **)&heap);
|
|
ok(hr == S_OK, "Failed to create heap, hr %#x.\n", hr);
|
|
|
|
refcount = get_refcount(device);
|
|
ok(refcount == 2, "Got unexpected refcount %u.\n", (unsigned int)refcount);
|
|
hr = ID3D12Heap_GetDevice(heap, &IID_ID3D12Device, (void **)&tmp_device);
|
|
ok(hr == S_OK, "Failed to get device, hr %#x.\n", hr);
|
|
refcount = get_refcount(device);
|
|
ok(refcount == 3, "Got unexpected refcount %u.\n", (unsigned int)refcount);
|
|
refcount = ID3D12Device_Release(tmp_device);
|
|
ok(refcount == 2, "Got unexpected refcount %u.\n", (unsigned int)refcount);
|
|
|
|
check_interface(heap, &IID_ID3D12Object, true);
|
|
check_interface(heap, &IID_ID3D12DeviceChild, true);
|
|
check_interface(heap, &IID_ID3D12Pageable, true);
|
|
check_interface(heap, &IID_ID3D12Heap, true);
|
|
|
|
result_desc = ID3D12Heap_GetDesc(heap);
|
|
check_heap_desc(&result_desc, &desc);
|
|
|
|
refcount = ID3D12Heap_Release(heap);
|
|
ok(!refcount, "ID3D12Heap has %u references left.\n", (unsigned int)refcount);
|
|
|
|
desc.SizeInBytes = 0;
|
|
hr = ID3D12Device_CreateHeap(device, &desc, &IID_ID3D12Heap, (void **)&heap);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
desc.SizeInBytes = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES | D3D12_HEAP_FLAG_ALLOW_DISPLAY;
|
|
hr = ID3D12Device_CreateHeap(device, &desc, &IID_ID3D12Heap, (void **)&heap);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
heap = (void *)(uintptr_t)0xdeadbeef;
|
|
desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES | D3D12_HEAP_FLAG_ALLOW_DISPLAY;
|
|
hr = ID3D12Device_CreateHeap(device, &desc, &IID_ID3D12Heap, (void **)&heap);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
ok(!heap, "Got unexpected pointer %p.\n", heap);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(tests); ++i)
|
|
{
|
|
for (j = 0; j < ARRAY_SIZE(heap_flags); ++j)
|
|
{
|
|
vkd3d_test_set_context("Test %u, %u", i, j);
|
|
|
|
desc.SizeInBytes = 10 * tests[i].alignment;
|
|
desc.Alignment = tests[i].alignment;
|
|
desc.Flags = heap_flags[j].flags;
|
|
hr = ID3D12Device_CreateHeap(device, &desc, &IID_ID3D12Heap, (void **)&heap);
|
|
ok(hr == tests[i].expected_hr, "Test %u, %s: Got hr %#x, expected %#x.\n",
|
|
i, heap_flags[j].name, hr, tests[i].expected_hr);
|
|
if (FAILED(hr))
|
|
continue;
|
|
|
|
result_desc = ID3D12Heap_GetDesc(heap);
|
|
check_heap_desc(&result_desc, &desc);
|
|
|
|
refcount = ID3D12Heap_Release(heap);
|
|
ok(!refcount, "ID3D12Heap has %u references left.\n", (unsigned int)refcount);
|
|
}
|
|
}
|
|
vkd3d_test_set_context(NULL);
|
|
|
|
hr = ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options));
|
|
ok(hr == S_OK, "Failed to check feature support, hr %#x.\n", hr);
|
|
if (options.ResourceHeapTier < D3D12_RESOURCE_HEAP_TIER_2)
|
|
{
|
|
skip("Resource heap tier %u.\n", options.ResourceHeapTier);
|
|
goto done;
|
|
}
|
|
|
|
desc.SizeInBytes = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
desc.Flags = D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES;
|
|
hr = ID3D12Device_CreateHeap(device, &desc, &IID_ID3D12Heap, (void **)&heap);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
result_desc = ID3D12Heap_GetDesc(heap);
|
|
check_heap_desc(&result_desc, &desc);
|
|
refcount = ID3D12Heap_Release(heap);
|
|
ok(!refcount, "ID3D12Heap has %u references left.\n", (unsigned int)refcount);
|
|
|
|
memset(&architecture, 0, sizeof(architecture));
|
|
hr = ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_ARCHITECTURE, &architecture, sizeof(architecture));
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
for (i = D3D12_HEAP_TYPE_DEFAULT; i < D3D12_HEAP_TYPE_CUSTOM; ++i)
|
|
{
|
|
vkd3d_test_set_context("Test %u\n", i);
|
|
desc.Properties = ID3D12Device_GetCustomHeapProperties(device, 1, i);
|
|
ok(desc.Properties.Type == D3D12_HEAP_TYPE_CUSTOM, "Got unexpected heap type %#x.\n", desc.Properties.Type);
|
|
|
|
switch (i)
|
|
{
|
|
case D3D12_HEAP_TYPE_DEFAULT:
|
|
ok(desc.Properties.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
|
|
"Got unexpected CPUPageProperty %#x.\n", desc.Properties.CPUPageProperty);
|
|
ok(desc.Properties.MemoryPoolPreference == (architecture.UMA
|
|
? D3D12_MEMORY_POOL_L0 : D3D12_MEMORY_POOL_L1),
|
|
"Got unexpected MemoryPoolPreference %#x.\n", desc.Properties.MemoryPoolPreference);
|
|
break;
|
|
|
|
case D3D12_HEAP_TYPE_UPLOAD:
|
|
ok(desc.Properties.CPUPageProperty == (architecture.CacheCoherentUMA
|
|
? D3D12_CPU_PAGE_PROPERTY_WRITE_BACK : D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE),
|
|
"Got unexpected CPUPageProperty %#x.\n", desc.Properties.CPUPageProperty);
|
|
ok(desc.Properties.MemoryPoolPreference == D3D12_MEMORY_POOL_L0,
|
|
"Got unexpected MemoryPoolPreference %#x.\n", desc.Properties.MemoryPoolPreference);
|
|
break;
|
|
|
|
case D3D12_HEAP_TYPE_READBACK:
|
|
ok(desc.Properties.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
|
|
"Got unexpected CPUPageProperty %#x.\n", desc.Properties.CPUPageProperty);
|
|
ok(desc.Properties.MemoryPoolPreference == D3D12_MEMORY_POOL_L0,
|
|
"Got unexpected MemoryPoolPreference %#x.\n", desc.Properties.MemoryPoolPreference);
|
|
break;
|
|
|
|
default:
|
|
ok(0, "Invalid heap type %#x.\n", i);
|
|
continue;
|
|
}
|
|
|
|
hr = ID3D12Device_CreateHeap(device, &desc, &IID_ID3D12Heap, (void **)&heap);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
result_desc = ID3D12Heap_GetDesc(heap);
|
|
check_heap_desc(&result_desc, &desc);
|
|
ID3D12Heap_Release(heap);
|
|
}
|
|
vkd3d_test_set_context(NULL);
|
|
|
|
is_pool_L1_supported = is_memory_pool_L1_supported(device);
|
|
desc.Properties.Type = D3D12_HEAP_TYPE_CUSTOM;
|
|
desc.Properties.CreationNodeMask = 1;
|
|
desc.Properties.VisibleNodeMask = 1;
|
|
for (i = 0; i < ARRAY_SIZE(custom_tests); ++i)
|
|
{
|
|
vkd3d_test_set_context("Test %u", i);
|
|
|
|
desc.Properties.CPUPageProperty = custom_tests[i].page_property;
|
|
desc.Properties.MemoryPoolPreference = custom_tests[i].pool_preference;
|
|
hr = ID3D12Device_CreateHeap(device, &desc, &IID_ID3D12Heap, (void **)&heap);
|
|
expected_hr = (custom_tests[i].pool_preference != D3D12_MEMORY_POOL_L1 || is_pool_L1_supported) ? custom_tests[i].expected_hr : E_INVALIDARG;
|
|
ok(hr == expected_hr, "Test %u, page_property %u, pool_preference %u: Got hr %#x, expected %#x.\n",
|
|
i, custom_tests[i].page_property, custom_tests[i].pool_preference, hr, expected_hr);
|
|
if (FAILED(hr))
|
|
continue;
|
|
|
|
result_desc = ID3D12Heap_GetDesc(heap);
|
|
check_heap_desc(&result_desc, &desc);
|
|
|
|
refcount = ID3D12Heap_Release(heap);
|
|
ok(!refcount, "ID3D12Heap has %u references left.\n", (unsigned int)refcount);
|
|
}
|
|
vkd3d_test_set_context(NULL);
|
|
|
|
done:
|
|
refcount = ID3D12Device_Release(device);
|
|
ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount);
|
|
}
|
|
|
|
void test_create_placed_resource_size(void)
|
|
{
|
|
D3D12_RESOURCE_ALLOCATION_INFO info;
|
|
unsigned int mip_sizes[11], i;
|
|
D3D12_HEAP_DESC heap_desc;
|
|
D3D12_RESOURCE_DESC desc;
|
|
ID3D12Resource *resource;
|
|
ID3D12Device *device;
|
|
ID3D12Heap *heap;
|
|
HRESULT hr;
|
|
|
|
if (!(device = create_device()))
|
|
{
|
|
skip("Failed to create device.\n");
|
|
return;
|
|
}
|
|
|
|
memset(&desc, 0, sizeof(desc));
|
|
desc.Format = DXGI_FORMAT_R11G11B10_FLOAT;
|
|
desc.DepthOrArraySize = 1;
|
|
desc.Width = 540;
|
|
desc.Height = 540;
|
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
desc.SampleDesc.Count = 1;
|
|
desc.SampleDesc.Quality = 0;
|
|
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS | D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
|
|
for (i = 1; i < ARRAY_SIZE(mip_sizes); i++)
|
|
{
|
|
desc.MipLevels = i;
|
|
info = ID3D12Device_GetResourceAllocationInfo(device, 0, 1, &desc);
|
|
mip_sizes[i] = info.SizeInBytes;
|
|
#if 0
|
|
/* RADV fails this check, but native driver does not.
|
|
* It is probably legal for a driver to have non-monotonic resource sizes here. */
|
|
if (i > 1)
|
|
ok(mip_sizes[i] >= mip_sizes[i - 1], "Resource size is not monotonically increasing (%u < %u).\n", mip_sizes[i], mip_sizes[i - 1]);
|
|
#endif
|
|
}
|
|
|
|
memset(&heap_desc, 0, sizeof(heap_desc));
|
|
heap_desc.Alignment = 0;
|
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
heap_desc.SizeInBytes = mip_sizes[ARRAY_SIZE(mip_sizes) - 1];
|
|
hr = ID3D12Device_CreateHeap(device, &heap_desc, &IID_ID3D12Heap, (void **)&heap);
|
|
ok(SUCCEEDED(hr), "Failed to create heap, hr #%x.\n", hr);
|
|
|
|
hr = ID3D12Device_CreatePlacedResource(device, heap, 0, &desc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void **)&resource);
|
|
ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);
|
|
|
|
ID3D12Resource_Release(resource);
|
|
ID3D12Heap_Release(heap);
|
|
|
|
heap_desc.SizeInBytes = 64 * 1024;
|
|
hr = ID3D12Device_CreateHeap(device, &heap_desc, &IID_ID3D12Heap, (void **)&heap);
|
|
ok(SUCCEEDED(hr), "Failed to create heap, hr #%x.\n", hr);
|
|
|
|
/* Runtime validates range, this must fail. */
|
|
hr = ID3D12Device_CreatePlacedResource(device, heap, 0, &desc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Unexpected result, hr #%x.\n", hr);
|
|
|
|
ID3D12Heap_Release(heap);
|
|
ID3D12Device_Release(device);
|
|
}
|
|
|
|
void test_create_placed_resource(void)
|
|
{
|
|
D3D12_GPU_VIRTUAL_ADDRESS gpu_address;
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
ID3D12Device *device, *tmp_device;
|
|
D3D12_CLEAR_VALUE clear_value;
|
|
D3D12_RESOURCE_STATES state;
|
|
D3D12_HEAP_DESC heap_desc;
|
|
ID3D12Resource *resource;
|
|
ID3D12Heap *heap;
|
|
unsigned int i;
|
|
ULONG refcount;
|
|
HRESULT hr;
|
|
|
|
static const struct
|
|
{
|
|
D3D12_HEAP_TYPE heap_type;
|
|
D3D12_RESOURCE_FLAGS flags;
|
|
}
|
|
invalid_buffer_desc_tests[] =
|
|
{
|
|
/* Render target or unordered access resources are not allowed with UPLOAD or READBACK. */
|
|
{D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET},
|
|
{D3D12_HEAP_TYPE_READBACK, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET},
|
|
{D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS},
|
|
{D3D12_HEAP_TYPE_READBACK, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS},
|
|
};
|
|
|
|
if (!(device = create_device()))
|
|
{
|
|
skip("Failed to create device.\n");
|
|
return;
|
|
}
|
|
|
|
heap_desc.SizeInBytes = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
memset(&heap_desc.Properties, 0, sizeof(heap_desc.Properties));
|
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
heap_desc.Alignment = 0;
|
|
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
|
|
hr = ID3D12Device_CreateHeap(device, &heap_desc, &IID_ID3D12Heap, (void **)&heap);
|
|
ok(hr == S_OK, "Failed to create heap, hr %#x.\n", hr);
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 32;
|
|
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;
|
|
resource_desc.Flags = 0;
|
|
|
|
clear_value.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
clear_value.Color[0] = 1.0f;
|
|
clear_value.Color[1] = 0.0f;
|
|
clear_value.Color[2] = 0.0f;
|
|
clear_value.Color[3] = 1.0f;
|
|
|
|
refcount = get_refcount(heap);
|
|
ok(refcount == 1, "Got unexpected refcount %u.\n", (unsigned int)refcount);
|
|
|
|
hr = ID3D12Device_CreatePlacedResource(device, heap, 0,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == S_OK, "Failed to create placed resource, hr %#x.\n", hr);
|
|
|
|
refcount = get_refcount(heap);
|
|
ok(refcount == 1, "Got unexpected refcount %u.\n", (unsigned int)refcount);
|
|
|
|
refcount = get_refcount(device);
|
|
ok(refcount == 3, "Got unexpected refcount %u.\n", (unsigned int)refcount);
|
|
hr = ID3D12Resource_GetDevice(resource, &IID_ID3D12Device, (void **)&tmp_device);
|
|
ok(hr == S_OK, "Failed to get device, hr %#x.\n", hr);
|
|
refcount = get_refcount(device);
|
|
ok(refcount == 4, "Got unexpected refcount %u.\n", (unsigned int)refcount);
|
|
refcount = ID3D12Device_Release(tmp_device);
|
|
ok(refcount == 3, "Got unexpected refcount %u.\n", (unsigned int)refcount);
|
|
|
|
check_interface(resource, &IID_ID3D12Object, true);
|
|
check_interface(resource, &IID_ID3D12DeviceChild, true);
|
|
check_interface(resource, &IID_ID3D12Pageable, true);
|
|
check_interface(resource, &IID_ID3D12Resource, true);
|
|
|
|
gpu_address = ID3D12Resource_GetGPUVirtualAddress(resource);
|
|
ok(gpu_address, "Got unexpected GPU virtual address %#"PRIx64".\n", gpu_address);
|
|
|
|
refcount = ID3D12Resource_Release(resource);
|
|
ok(!refcount, "ID3D12Resource has %u references left.\n", (unsigned int)refcount);
|
|
|
|
/* The clear value must be NULL for buffers. */
|
|
hr = ID3D12Device_CreatePlacedResource(device, heap, 0,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, &clear_value,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* Textures are disallowed on ALLOW_ONLY_HEAPS */
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
|
|
hr = ID3D12Device_CreatePlacedResource(device, heap, 0,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, &clear_value,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
ID3D12Heap_Release(heap);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(invalid_buffer_desc_tests); ++i)
|
|
{
|
|
heap_desc.SizeInBytes = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
memset(&heap_desc.Properties, 0, sizeof(heap_desc.Properties));
|
|
heap_desc.Properties.Type = invalid_buffer_desc_tests[i].heap_type;
|
|
heap_desc.Alignment = 0;
|
|
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
|
|
hr = ID3D12Device_CreateHeap(device, &heap_desc, &IID_ID3D12Heap, (void **)&heap);
|
|
ok(hr == S_OK, "Test %u: Failed to create heap, hr %#x.\n", i, hr);
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 32;
|
|
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;
|
|
resource_desc.Flags = invalid_buffer_desc_tests[i].flags;
|
|
|
|
if (invalid_buffer_desc_tests[i].heap_type == D3D12_HEAP_TYPE_UPLOAD)
|
|
state = D3D12_RESOURCE_STATE_GENERIC_READ;
|
|
else
|
|
state = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
|
|
hr = ID3D12Device_CreatePlacedResource(device, heap, 0,
|
|
&resource_desc, state, &clear_value, &IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Test %u: Got unexpected hr %#x.\n", i, hr);
|
|
|
|
ID3D12Heap_Release(heap);
|
|
}
|
|
|
|
refcount = ID3D12Device_Release(device);
|
|
ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount);
|
|
}
|
|
|
|
void test_create_reserved_resource(void)
|
|
{
|
|
D3D12_GPU_VIRTUAL_ADDRESS gpu_address;
|
|
D3D12_HEAP_PROPERTIES heap_properties;
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
D3D12_CLEAR_VALUE clear_value;
|
|
D3D12_HEAP_FLAGS heap_flags;
|
|
ID3D12Resource *resource;
|
|
bool standard_swizzle;
|
|
ID3D12Device *device;
|
|
ULONG refcount;
|
|
HRESULT hr;
|
|
void *ptr;
|
|
|
|
if (!(device = create_device()))
|
|
{
|
|
skip("Failed to create device.\n");
|
|
return;
|
|
}
|
|
|
|
if (get_tiled_resources_tier(device) == D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED)
|
|
{
|
|
skip("Tiled resources are not supported.\n");
|
|
goto done;
|
|
}
|
|
|
|
standard_swizzle = is_standard_swizzle_64kb_supported(device);
|
|
trace("Standard swizzle 64KB: %#x.\n", standard_swizzle);
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 32;
|
|
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;
|
|
resource_desc.Flags = 0;
|
|
|
|
hr = ID3D12Device_CreateReservedResource(device,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == S_OK, "Failed to create reserved resource, hr %#x.\n", hr);
|
|
|
|
check_interface(resource, &IID_ID3D12Object, true);
|
|
check_interface(resource, &IID_ID3D12DeviceChild, true);
|
|
check_interface(resource, &IID_ID3D12Pageable, true);
|
|
check_interface(resource, &IID_ID3D12Resource, true);
|
|
|
|
gpu_address = ID3D12Resource_GetGPUVirtualAddress(resource);
|
|
ok(gpu_address, "Got unexpected GPU virtual address %#"PRIx64".\n", gpu_address);
|
|
|
|
heap_flags = 0xdeadbeef;
|
|
hr = ID3D12Resource_GetHeapProperties(resource, &heap_properties, &heap_flags);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
ok(heap_flags == 0xdeadbeef, "Got unexpected heap flags %#x.\n", heap_flags);
|
|
|
|
/* Map() is not allowed on reserved resources */
|
|
hr = ID3D12Resource_Map(resource, 0, NULL, &ptr);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
refcount = ID3D12Resource_Release(resource);
|
|
ok(!refcount, "ID3D12Resource has %u references left.\n", (unsigned int)refcount);
|
|
|
|
/* The clear value must be NULL for buffers. */
|
|
clear_value.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
clear_value.Color[0] = 1.0f;
|
|
clear_value.Color[1] = 0.0f;
|
|
clear_value.Color[2] = 0.0f;
|
|
clear_value.Color[3] = 1.0f;
|
|
|
|
hr = ID3D12Device_CreateReservedResource(device,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, &clear_value,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* D3D12_TEXTURE_LAYOUT_ROW_MAJOR must be used for buffers. */
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
|
|
hr = ID3D12Device_CreateReservedResource(device,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
hr = ID3D12Device_CreateReservedResource(device,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE must be used for textures. */
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 64;
|
|
resource_desc.Height = 64;
|
|
resource_desc.DepthOrArraySize = 1;
|
|
resource_desc.MipLevels = 4;
|
|
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
resource_desc.SampleDesc.Count = 1;
|
|
resource_desc.SampleDesc.Quality = 0;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
|
|
resource_desc.Flags = 0;
|
|
|
|
hr = ID3D12Device_CreateReservedResource(device,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == S_OK, "Failed to create reserved resource, hr %#x.\n", hr);
|
|
refcount = ID3D12Resource_Release(resource);
|
|
ok(!refcount, "ID3D12Resource has %u references left.\n", (unsigned int)refcount);
|
|
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
hr = ID3D12Device_CreateReservedResource(device,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
resource_desc.MipLevels = 1;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
hr = ID3D12Device_CreateReservedResource(device,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_STANDARD_SWIZZLE;
|
|
hr = ID3D12Device_CreateReservedResource(device,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == (standard_swizzle ? S_OK : E_INVALIDARG) || broken(use_warp_device), "Got unexpected hr %#x.\n", hr);
|
|
if (SUCCEEDED(hr))
|
|
ID3D12Resource_Release(resource);
|
|
|
|
/* Depth-Stencil formats not allowed */
|
|
resource_desc.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
|
|
hr = ID3D12Device_CreateReservedResource(device,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
if (SUCCEEDED(hr))
|
|
ID3D12Resource_Release(resource);
|
|
|
|
/* More than one layer not allowed if some mips may be packed */
|
|
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UINT;
|
|
resource_desc.DepthOrArraySize = 4;
|
|
resource_desc.MipLevels = 10;
|
|
hr = ID3D12Device_CreateReservedResource(device,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
if (SUCCEEDED(hr))
|
|
ID3D12Resource_Release(resource);
|
|
|
|
/* 1D not allowed */
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D;
|
|
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UINT;
|
|
resource_desc.Height = 1;
|
|
resource_desc.DepthOrArraySize = 1;
|
|
resource_desc.MipLevels = 1;
|
|
hr = ID3D12Device_CreateReservedResource(device,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
if (SUCCEEDED(hr))
|
|
ID3D12Resource_Release(resource);
|
|
|
|
done:
|
|
refcount = ID3D12Device_Release(device);
|
|
ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount);
|
|
}
|
|
|
|
void test_map_resource(void)
|
|
{
|
|
D3D12_HEAP_PROPERTIES heap_properties;
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
ID3D12Resource *resource;
|
|
ID3D12Device *device;
|
|
ULONG refcount;
|
|
void *data;
|
|
HRESULT hr;
|
|
|
|
if (!(device = create_device()))
|
|
{
|
|
skip("Failed to create device.\n");
|
|
return;
|
|
}
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 32;
|
|
resource_desc.Height = 32;
|
|
resource_desc.DepthOrArraySize = 1;
|
|
resource_desc.MipLevels = 1;
|
|
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
resource_desc.SampleDesc.Count = 1;
|
|
resource_desc.SampleDesc.Quality = 0;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
resource_desc.Flags = 0;
|
|
|
|
memset(&heap_properties, 0, sizeof(heap_properties));
|
|
heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == S_OK, "Failed to create texture, hr %#x.\n", hr);
|
|
|
|
/* Resources on a DEFAULT heap cannot be mapped. */
|
|
data = (void *)(uintptr_t)0xdeadbeef;
|
|
hr = ID3D12Resource_Map(resource, 0, NULL, &data);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
ok(data == (void *)(uintptr_t)0xdeadbeef, "Pointer was modified %p.\n", data);
|
|
|
|
ID3D12Resource_Release(resource);
|
|
|
|
heap_properties.Type = D3D12_HEAP_TYPE_CUSTOM;
|
|
heap_properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE;
|
|
heap_properties.MemoryPoolPreference = D3D12_MEMORY_POOL_L0;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
if (FAILED(hr))
|
|
{
|
|
skip("Failed to create texture on custom heap.\n");
|
|
}
|
|
else
|
|
{
|
|
/* The data pointer must be NULL for the UNKNOWN layout. */
|
|
data = (void *)(uintptr_t)0xdeadbeef;
|
|
hr = ID3D12Resource_Map(resource, 0, NULL, &data);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
ok(data == (void *)(uintptr_t)0xdeadbeef, "Pointer was modified %p.\n", data);
|
|
|
|
/* Texture on custom heaps can be mapped, but the address doesn't get disclosed to applications */
|
|
hr = ID3D12Resource_Map(resource, 0, NULL, NULL);
|
|
todo ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
ID3D12Resource_Unmap(resource, 0, NULL);
|
|
|
|
ID3D12Resource_Release(resource);
|
|
}
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
resource_desc.Height = 1;
|
|
resource_desc.Format = DXGI_FORMAT_UNKNOWN;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
|
|
memset(&heap_properties, 0, sizeof(heap_properties));
|
|
heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == S_OK, "Failed to create committed resource, hr %#x.\n", hr);
|
|
|
|
/* Resources on a DEFAULT heap cannot be mapped. */
|
|
data = (void *)(uintptr_t)0xdeadbeef;
|
|
hr = ID3D12Resource_Map(resource, 0, NULL, &data);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
ok(data == (void *)(uintptr_t)0xdeadbeef, "Pointer was modified %p.\n", data);
|
|
|
|
ID3D12Resource_Release(resource);
|
|
|
|
heap_properties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
|
&IID_ID3D12Resource, (void **)&resource);
|
|
ok(hr == S_OK, "Failed to create committed resource, hr %#x.\n", hr);
|
|
|
|
data = NULL;
|
|
hr = ID3D12Resource_Map(resource, 0, NULL, &data);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
ok(data, "Got NULL pointer.\n");
|
|
ID3D12Resource_Unmap(resource, 0, NULL);
|
|
|
|
data = (void *)(uintptr_t)0xdeadbeef;
|
|
hr = ID3D12Resource_Map(resource, 1, NULL, &data);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
ok(data == (void *)(uintptr_t)0xdeadbeef, "Pointer was modified %p.\n", data);
|
|
|
|
data = NULL;
|
|
hr = ID3D12Resource_Map(resource, 0, NULL, &data);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
ok(data, "Got NULL pointer.\n");
|
|
ID3D12Resource_Unmap(resource, 1, NULL);
|
|
ID3D12Resource_Unmap(resource, 0, NULL);
|
|
|
|
/* Passing NULL to Map should map, but not disclose the CPU VA to caller. */
|
|
hr = ID3D12Resource_Map(resource, 0, NULL, NULL);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
ID3D12Resource_Unmap(resource, 0, NULL);
|
|
|
|
ID3D12Resource_Release(resource);
|
|
|
|
refcount = ID3D12Device_Release(device);
|
|
ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount);
|
|
}
|
|
|
|
void test_map_placed_resources(void)
|
|
{
|
|
D3D12_ROOT_SIGNATURE_DESC root_signature_desc;
|
|
ID3D12GraphicsCommandList *command_list;
|
|
ID3D12Heap *upload_heap, *readback_heap;
|
|
D3D12_ROOT_PARAMETER root_parameters[2];
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
ID3D12Resource *readback_buffer;
|
|
struct test_context_desc desc;
|
|
struct resource_readback rb;
|
|
struct test_context context;
|
|
ID3D12Resource *uav_buffer;
|
|
D3D12_HEAP_DESC heap_desc;
|
|
ID3D12CommandQueue *queue;
|
|
ID3D12Resource *cb[4];
|
|
uint32_t *cb_data[4];
|
|
ID3D12Device *device;
|
|
D3D12_RANGE range;
|
|
unsigned int i;
|
|
uint32_t *ptr;
|
|
HRESULT hr;
|
|
|
|
STATIC_ASSERT(ARRAY_SIZE(cb) == ARRAY_SIZE(cb_data));
|
|
|
|
static const DWORD ps_code[] =
|
|
{
|
|
#if 0
|
|
uint offset;
|
|
uint value;
|
|
|
|
RWByteAddressBuffer u;
|
|
|
|
void main()
|
|
{
|
|
u.Store(offset, value);
|
|
}
|
|
#endif
|
|
0x43425844, 0x0dcbdd90, 0x7dad2857, 0x4ee149ee, 0x72a13d21, 0x00000001, 0x000000a4, 0x00000003,
|
|
0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
|
|
0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x00000050, 0x00000050, 0x00000014, 0x0100086a,
|
|
0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x0300009d, 0x0011e000, 0x00000000, 0x090000a6,
|
|
0x0011e012, 0x00000000, 0x0020800a, 0x00000000, 0x00000000, 0x0020801a, 0x00000000, 0x00000000,
|
|
0x0100003e,
|
|
};
|
|
static const D3D12_SHADER_BYTECODE ps = {ps_code, sizeof(ps_code)};
|
|
static const uint32_t expected_values[] = {0xdead, 0xbeef, 0xfeed, 0xc0de};
|
|
|
|
memset(&desc, 0, sizeof(desc));
|
|
desc.no_root_signature = true;
|
|
if (!init_test_context(&context, &desc))
|
|
return;
|
|
device = context.device;
|
|
command_list = context.list;
|
|
queue = context.queue;
|
|
|
|
root_parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV;
|
|
root_parameters[0].Descriptor.ShaderRegister = 0;
|
|
root_parameters[0].Descriptor.RegisterSpace = 0;
|
|
root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
|
root_parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
root_parameters[1].Descriptor.ShaderRegister = 0;
|
|
root_parameters[1].Descriptor.RegisterSpace = 0;
|
|
root_parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
|
root_signature_desc.NumParameters = ARRAY_SIZE(root_parameters);
|
|
root_signature_desc.pParameters = root_parameters;
|
|
root_signature_desc.NumStaticSamplers = 0;
|
|
root_signature_desc.pStaticSamplers = NULL;
|
|
root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
|
|
hr = create_root_signature(device, &root_signature_desc, &context.root_signature);
|
|
ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr);
|
|
|
|
context.pipeline_state = create_pipeline_state(device, context.root_signature, 0, NULL, &ps, NULL);
|
|
|
|
heap_desc.SizeInBytes = ARRAY_SIZE(cb) * D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
memset(&heap_desc.Properties, 0, sizeof(heap_desc.Properties));
|
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
|
heap_desc.Alignment = 0;
|
|
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
|
|
hr = ID3D12Device_CreateHeap(device, &heap_desc, &IID_ID3D12Heap, (void **)&upload_heap);
|
|
ok(hr == S_OK, "Failed to create heap, hr %#x.\n", hr);
|
|
|
|
heap_desc.SizeInBytes = 1024;
|
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_READBACK;
|
|
hr = ID3D12Device_CreateHeap(device, &heap_desc, &IID_ID3D12Heap, (void **)&readback_heap);
|
|
ok(hr == S_OK, "Failed to create heap, hr %#x.\n", hr);
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
|
|
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;
|
|
resource_desc.Flags = 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(cb); ++i)
|
|
{
|
|
hr = ID3D12Device_CreatePlacedResource(device, upload_heap,
|
|
i * D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
|
|
&resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
|
&IID_ID3D12Resource, (void **)&cb[i]);
|
|
ok(hr == S_OK, "Failed to create placed resource %u, hr %#x.\n", i, hr);
|
|
}
|
|
|
|
resource_desc.Width = 1024;
|
|
hr = ID3D12Device_CreatePlacedResource(device, readback_heap, 0,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL,
|
|
&IID_ID3D12Resource, (void **)&readback_buffer);
|
|
ok(hr == S_OK, "Failed to create placed resource, hr %#x.\n", hr);
|
|
|
|
uav_buffer = create_default_buffer(device, resource_desc.Width,
|
|
D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(cb); ++i)
|
|
{
|
|
hr = ID3D12Resource_Map(cb[i], 0, NULL, (void **)&cb_data[i]);
|
|
ok(hr == S_OK, "Failed to map buffer %u, hr %#x.\n", i, hr);
|
|
}
|
|
|
|
hr = ID3D12Resource_Map(cb[0], 0, NULL, (void **)&ptr);
|
|
ok(hr == S_OK, "Failed to map buffer, hr %#x.\n", hr);
|
|
ok(ptr == cb_data[0], "Got map ptr %p, expected %p.\n", ptr, cb_data[0]);
|
|
cb_data[0][0] = 0;
|
|
cb_data[0][1] = expected_values[0];
|
|
ID3D12Resource_Unmap(cb[0], 0, NULL);
|
|
ID3D12Resource_Unmap(cb[0], 0, NULL);
|
|
cb_data[0] = NULL;
|
|
|
|
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
|
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
|
|
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
|
|
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
|
|
ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
|
|
ID3D12GraphicsCommandList_SetGraphicsRootUnorderedAccessView(command_list, 0,
|
|
ID3D12Resource_GetGPUVirtualAddress(uav_buffer));
|
|
|
|
ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 1,
|
|
ID3D12Resource_GetGPUVirtualAddress(cb[0]));
|
|
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
|
|
|
|
ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 1,
|
|
ID3D12Resource_GetGPUVirtualAddress(cb[2]));
|
|
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
|
|
cb_data[2][0] = 4;
|
|
cb_data[2][1] = expected_values[1];
|
|
|
|
ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 1,
|
|
ID3D12Resource_GetGPUVirtualAddress(cb[1]));
|
|
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
|
|
cb_data[1][0] = 8;
|
|
cb_data[1][1] = expected_values[2];
|
|
|
|
ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 1,
|
|
ID3D12Resource_GetGPUVirtualAddress(cb[3]));
|
|
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
|
|
cb_data[3][0] = 12;
|
|
cb_data[3][1] = expected_values[3];
|
|
range.Begin = 0;
|
|
range.End = 2 * sizeof(uint32_t);
|
|
ID3D12Resource_Unmap(cb[3], 0, &range);
|
|
cb_data[3] = NULL;
|
|
|
|
transition_resource_state(command_list, uav_buffer,
|
|
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
|
ID3D12GraphicsCommandList_CopyResource(command_list, readback_buffer, uav_buffer);
|
|
|
|
get_buffer_readback_with_command_list(readback_buffer, DXGI_FORMAT_R32_UINT, &rb, queue, command_list);
|
|
for (i = 0; i < ARRAY_SIZE(expected_values); ++i)
|
|
{
|
|
unsigned int value = get_readback_uint(&rb, i, 0, 0);
|
|
ok(value == expected_values[i], "Got %#x, expected %#x at %u.\n", value, expected_values[i], i);
|
|
}
|
|
release_resource_readback(&rb);
|
|
|
|
ID3D12Resource_Release(uav_buffer);
|
|
ID3D12Resource_Release(readback_buffer);
|
|
ID3D12Heap_Release(upload_heap);
|
|
ID3D12Heap_Release(readback_heap);
|
|
for (i = 0; i < ARRAY_SIZE(cb); ++i)
|
|
ID3D12Resource_Release(cb[i]);
|
|
destroy_test_context(&context);
|
|
}
|
|
|
|
#define check_copyable_footprints(a, b, c, d, e, f, g, h) \
|
|
check_copyable_footprints_(__LINE__, a, b, c, d, e, f, g, h)
|
|
static void check_copyable_footprints_(unsigned int line, const D3D12_RESOURCE_DESC *desc,
|
|
unsigned int sub_resource_idx, unsigned int sub_resource_count, uint64_t base_offset,
|
|
const D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts, const UINT *row_counts,
|
|
const uint64_t *row_sizes, uint64_t *total_size)
|
|
{
|
|
unsigned int miplevel, width, height, depth, row_count, row_size, row_pitch, layers, plane, num_planes;
|
|
uint64_t offset, size, total;
|
|
unsigned int i;
|
|
|
|
layers = desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? 1 : desc->DepthOrArraySize;
|
|
num_planes = format_num_planes(desc->Format);
|
|
offset = total = 0;
|
|
|
|
for (i = 0; i < sub_resource_count; ++i)
|
|
{
|
|
miplevel = (sub_resource_idx + i) % desc->MipLevels;
|
|
plane = (sub_resource_idx + i) / (desc->MipLevels * layers);
|
|
width = align(max(1, desc->Width >> miplevel), format_block_width(desc->Format));
|
|
height = align(max(1, desc->Height >> miplevel), format_block_height(desc->Format));
|
|
depth = desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? desc->DepthOrArraySize : 1;
|
|
depth = max(1, depth >> miplevel);
|
|
row_count = height / format_block_height(desc->Format);
|
|
row_size = (width / format_block_width(desc->Format)) * format_size_planar(desc->Format, plane);
|
|
|
|
/* For whatever reason, depth-stencil images actually have 512 byte row alignment, not 256.
|
|
* Both WARP and NV driver have this behavior, so it might be an undocumented requirement.
|
|
* This function is likely part of the core runtime though ... */
|
|
row_pitch = align(row_size, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT * num_planes);
|
|
|
|
if (layouts)
|
|
{
|
|
const D3D12_PLACED_SUBRESOURCE_FOOTPRINT *l = &layouts[i];
|
|
const D3D12_SUBRESOURCE_FOOTPRINT *f = &l->Footprint;
|
|
DXGI_FORMAT footprint_format;
|
|
|
|
footprint_format = format_to_footprint_format(desc->Format, plane);
|
|
ok_(line)(l->Offset == base_offset + offset,
|
|
"Got offset %"PRIu64", expected %"PRIu64".\n", l->Offset, base_offset + offset);
|
|
ok_(line)(f->Format == footprint_format, "Got format %#x, expected %#x.\n", f->Format, footprint_format);
|
|
ok_(line)(f->Width == width, "Got width %u, expected %u.\n", f->Width, width);
|
|
ok_(line)(f->Height == height, "Got height %u, expected %u.\n", f->Height, height);
|
|
ok_(line)(f->Depth == depth, "Got depth %u, expected %u.\n", f->Depth, depth);
|
|
ok_(line)(f->RowPitch == row_pitch, "Got row pitch %u, expected %u.\n", f->RowPitch, row_pitch);
|
|
}
|
|
|
|
if (row_counts)
|
|
ok_(line)(row_counts[i] == row_count, "Got row count %u, expected %u.\n", row_counts[i], row_count);
|
|
|
|
if (row_sizes)
|
|
ok_(line)(row_sizes[i] == row_size, "Got row size %"PRIu64", expected %u.\n", row_sizes[i], row_size);
|
|
|
|
size = max(0, row_count - 1) * row_pitch + row_size;
|
|
size = max(0, depth - 1) * align(size, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT * num_planes) + size;
|
|
|
|
total = offset + size;
|
|
offset = align(total, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
|
|
}
|
|
|
|
if (total_size)
|
|
ok_(line)(*total_size == total, "Got total size %"PRIu64", expected %"PRIu64".\n", *total_size, total);
|
|
}
|
|
|
|
void test_get_copyable_footprints_planar(void)
|
|
{
|
|
D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprints[2 * 2 * 3];
|
|
UINT64 row_sizes[ARRAY_SIZE(footprints)];
|
|
UINT row_counts[ARRAY_SIZE(footprints)];
|
|
D3D12_RESOURCE_DESC desc;
|
|
ID3D12Device *device;
|
|
UINT64 total_bytes;
|
|
unsigned int i;
|
|
|
|
/* All of these formats will have R32_TYPELESS + R8_TYPELESS placements. */
|
|
static const DXGI_FORMAT planar_formats[] =
|
|
{
|
|
DXGI_FORMAT_D32_FLOAT_S8X24_UINT,
|
|
DXGI_FORMAT_D24_UNORM_S8_UINT,
|
|
DXGI_FORMAT_R24G8_TYPELESS,
|
|
DXGI_FORMAT_R32G8X24_TYPELESS,
|
|
};
|
|
|
|
if (!(device = create_device()))
|
|
{
|
|
skip("Failed to create device.\n");
|
|
return;
|
|
}
|
|
|
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
desc.Width = 130;
|
|
desc.Height = 119;
|
|
desc.DepthOrArraySize = 2;
|
|
desc.MipLevels = 3;
|
|
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
desc.SampleDesc.Count = 1;
|
|
desc.SampleDesc.Quality = 0;
|
|
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
|
desc.Alignment = 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(planar_formats); i++)
|
|
{
|
|
vkd3d_test_set_context("Test %u", i);
|
|
desc.Format = planar_formats[i];
|
|
ID3D12Device_GetCopyableFootprints(device, &desc, 0, ARRAY_SIZE(footprints), 0,
|
|
footprints, row_counts, row_sizes, &total_bytes);
|
|
check_copyable_footprints(&desc, 0, ARRAY_SIZE(footprints), 0, footprints, row_counts, row_sizes, &total_bytes);
|
|
}
|
|
vkd3d_test_set_context(NULL);
|
|
|
|
ID3D12Device_Release(device);
|
|
}
|
|
|
|
void test_get_copyable_footprints(void)
|
|
{
|
|
D3D12_PLACED_SUBRESOURCE_FOOTPRINT layouts[10];
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
UINT64 row_sizes[10], total_size;
|
|
unsigned int sub_resource_count;
|
|
unsigned int i, j, k, l;
|
|
ID3D12Device *device;
|
|
UINT row_counts[10];
|
|
ULONG refcount;
|
|
|
|
static const struct
|
|
{
|
|
D3D12_RESOURCE_DIMENSION dimension;
|
|
unsigned int width;
|
|
unsigned int height;
|
|
unsigned int depth_or_array_size;
|
|
unsigned int miplevel_count;
|
|
bool test_with_compressed;
|
|
}
|
|
resources[] =
|
|
{
|
|
{D3D12_RESOURCE_DIMENSION_BUFFER, 4, 1, 1, 1, false},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE1D, 4, 1, 1, 1, false},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE1D, 4, 1, 1, 2, false},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE1D, 3, 1, 1, 1, false},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE1D, 4, 1, 2, 1, false},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE2D, 4, 4, 1, 1, true},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE2D, 4, 4, 2, 1, true},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE2D, 4, 4, 1, 2, true},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE2D, 3, 1, 1, 2, false},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE2D, 3, 2, 1, 2, false},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE2D, 3, 1, 1, 1, false},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE2D, 3, 2, 1, 1, false},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE3D, 4, 4, 1, 1, true},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE3D, 4, 4, 2, 1, true},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE3D, 4, 4, 2, 2, true},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE3D, 8, 8, 8, 4, true},
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE3D, 3, 2, 2, 2, false},
|
|
};
|
|
static const struct
|
|
{
|
|
DXGI_FORMAT format;
|
|
bool is_compressed;
|
|
}
|
|
formats[] =
|
|
{
|
|
{DXGI_FORMAT_R32G32B32A32_FLOAT, false},
|
|
{DXGI_FORMAT_R32G32B32A32_UINT, false},
|
|
{DXGI_FORMAT_R32_UINT, false},
|
|
{DXGI_FORMAT_R8G8B8A8_UNORM, false},
|
|
{DXGI_FORMAT_BC1_UNORM, true},
|
|
{DXGI_FORMAT_BC2_UNORM, true},
|
|
{DXGI_FORMAT_BC3_UNORM, true},
|
|
{DXGI_FORMAT_BC4_UNORM, true},
|
|
{DXGI_FORMAT_BC5_UNORM, true},
|
|
{DXGI_FORMAT_BC6H_UF16, true},
|
|
{DXGI_FORMAT_BC6H_SF16, true},
|
|
{DXGI_FORMAT_BC7_UNORM, true},
|
|
};
|
|
static const uint64_t base_offsets[] =
|
|
{
|
|
0, 1, 2, 30, 255, 512, 513, 600, 4096, 4194304, ~(uint64_t)0,
|
|
};
|
|
static const struct
|
|
{
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
unsigned int sub_resource_idx;
|
|
unsigned int sub_resource_count;
|
|
}
|
|
invalid_descs[] =
|
|
{
|
|
{
|
|
{D3D12_RESOURCE_DIMENSION_BUFFER, 0, 3, 2, 1, 1, DXGI_FORMAT_R32_UINT,
|
|
{1, 0}, D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE}, 0, 1,
|
|
},
|
|
{
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE1D, 0, 4, 2, 1, 1, DXGI_FORMAT_R32_UINT,
|
|
{1, 0}, D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE}, 0, 1,
|
|
},
|
|
{
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE2D, 0, 4, 4, 1, 1, DXGI_FORMAT_R32_UINT,
|
|
{1, 0}, D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE}, 0, 2,
|
|
},
|
|
{
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE2D, 0, 3, 1, 1, 2, DXGI_FORMAT_BC1_UNORM,
|
|
{1, 0}, D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE}, 0, 2,
|
|
},
|
|
{
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE2D, 0, 3, 1, 1, 1, DXGI_FORMAT_BC1_UNORM,
|
|
{1, 0}, D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE}, 0, 1,
|
|
},
|
|
{
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE2D, 0, 3, 1, 1, 2, DXGI_FORMAT_BC7_UNORM,
|
|
{1, 0}, D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE}, 0, 2,
|
|
},
|
|
{
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE2D, 0, 3, 1, 1, 1, DXGI_FORMAT_BC7_UNORM,
|
|
{1, 0}, D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE}, 0, 1,
|
|
},
|
|
{
|
|
{D3D12_RESOURCE_DIMENSION_TEXTURE3D, 3, 2, 2, 2, 2, DXGI_FORMAT_BC1_UNORM,
|
|
{1, 0}, D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE}, 0, 1,
|
|
},
|
|
};
|
|
|
|
if (!(device = create_device()))
|
|
{
|
|
skip("Failed to create device.\n");
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(resources); ++i)
|
|
{
|
|
const bool is_buffer = resources[i].dimension == D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
|
|
resource_desc.Dimension = resources[i].dimension;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = resources[i].width;
|
|
resource_desc.Height = resources[i].height;
|
|
resource_desc.DepthOrArraySize = resources[i].depth_or_array_size;
|
|
resource_desc.MipLevels = resources[i].miplevel_count;
|
|
|
|
for (j = 0; j < ARRAY_SIZE(formats); ++j)
|
|
{
|
|
if (formats[j].is_compressed && !resources[i].test_with_compressed)
|
|
continue;
|
|
if (is_buffer && j > 0)
|
|
continue;
|
|
|
|
if (is_buffer)
|
|
resource_desc.Format = DXGI_FORMAT_UNKNOWN;
|
|
else
|
|
resource_desc.Format = formats[j].format;
|
|
|
|
resource_desc.SampleDesc.Count = 1;
|
|
resource_desc.SampleDesc.Quality = 0;
|
|
resource_desc.Layout = is_buffer ? D3D12_TEXTURE_LAYOUT_ROW_MAJOR : D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
|
|
sub_resource_count = resource_desc.MipLevels;
|
|
if (resources[i].dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D)
|
|
sub_resource_count *= resource_desc.DepthOrArraySize;
|
|
assert(sub_resource_count <= ARRAY_SIZE(layouts));
|
|
|
|
for (k = 0; k < ARRAY_SIZE(base_offsets); ++k)
|
|
{
|
|
vkd3d_test_set_context("resource %u, format %#x, offset %#"PRIx64,
|
|
i, resource_desc.Format, base_offsets[k]);
|
|
|
|
memset(layouts, 0, sizeof(layouts));
|
|
memset(row_counts, 0, sizeof(row_counts));
|
|
memset(row_sizes, 0, sizeof(row_sizes));
|
|
total_size = 0;
|
|
ID3D12Device_GetCopyableFootprints(device, &resource_desc, 0, sub_resource_count, base_offsets[k],
|
|
layouts, row_counts, row_sizes, &total_size);
|
|
check_copyable_footprints(&resource_desc, 0, sub_resource_count, base_offsets[k],
|
|
layouts, row_counts, row_sizes, &total_size);
|
|
|
|
memset(layouts, 0, sizeof(layouts));
|
|
ID3D12Device_GetCopyableFootprints(device, &resource_desc, 0, sub_resource_count, base_offsets[k],
|
|
layouts, NULL, NULL, NULL);
|
|
check_copyable_footprints(&resource_desc, 0, sub_resource_count, base_offsets[k],
|
|
layouts, NULL, NULL, NULL);
|
|
memset(row_counts, 0, sizeof(row_counts));
|
|
ID3D12Device_GetCopyableFootprints(device, &resource_desc, 0, sub_resource_count, base_offsets[k],
|
|
NULL, row_counts, NULL, NULL);
|
|
check_copyable_footprints(&resource_desc, 0, sub_resource_count, base_offsets[k],
|
|
NULL, row_counts, NULL, NULL);
|
|
memset(row_sizes, 0, sizeof(row_sizes));
|
|
ID3D12Device_GetCopyableFootprints(device, &resource_desc, 0, sub_resource_count, base_offsets[k],
|
|
NULL, NULL, row_sizes, NULL);
|
|
check_copyable_footprints(&resource_desc, 0, sub_resource_count, base_offsets[k],
|
|
NULL, NULL, row_sizes, NULL);
|
|
total_size = 0;
|
|
ID3D12Device_GetCopyableFootprints(device, &resource_desc, 0, sub_resource_count, base_offsets[k],
|
|
NULL, NULL, NULL, &total_size);
|
|
check_copyable_footprints(&resource_desc, 0, sub_resource_count, base_offsets[k],
|
|
NULL, NULL, NULL, &total_size);
|
|
|
|
for (l = 0; l < sub_resource_count; ++l)
|
|
{
|
|
vkd3d_test_set_context("resource %u, format %#x, offset %#"PRIx64", sub-resource %u",
|
|
i, resource_desc.Format, base_offsets[k], l);
|
|
|
|
memset(layouts, 0, sizeof(layouts));
|
|
memset(row_counts, 0, sizeof(row_counts));
|
|
memset(row_sizes, 0, sizeof(row_sizes));
|
|
total_size = 0;
|
|
ID3D12Device_GetCopyableFootprints(device, &resource_desc, l, 1, base_offsets[k],
|
|
layouts, row_counts, row_sizes, &total_size);
|
|
check_copyable_footprints(&resource_desc, l, 1, base_offsets[k],
|
|
layouts, row_counts, row_sizes, &total_size);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
vkd3d_test_set_context(NULL);
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 512;
|
|
resource_desc.Height = 512;
|
|
resource_desc.DepthOrArraySize = 1;
|
|
resource_desc.MipLevels = 1;
|
|
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
resource_desc.SampleDesc.Count = 4;
|
|
resource_desc.SampleDesc.Quality = 0;
|
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
memset(layouts, 0, sizeof(layouts));
|
|
memset(row_counts, 0, sizeof(row_counts));
|
|
memset(row_sizes, 0, sizeof(row_sizes));
|
|
total_size = 0;
|
|
ID3D12Device_GetCopyableFootprints(device, &resource_desc, 0, 1, 0,
|
|
layouts, row_counts, row_sizes, &total_size);
|
|
check_copyable_footprints(&resource_desc, 0, 1, 0,
|
|
layouts, row_counts, row_sizes, &total_size);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(invalid_descs); ++i)
|
|
{
|
|
resource_desc = invalid_descs[i].resource_desc;
|
|
|
|
memset(layouts, 0, sizeof(layouts));
|
|
memset(row_counts, 0, sizeof(row_counts));
|
|
memset(row_sizes, 0, sizeof(row_sizes));
|
|
total_size = 0;
|
|
ID3D12Device_GetCopyableFootprints(device, &resource_desc,
|
|
invalid_descs[i].sub_resource_idx, invalid_descs[i].sub_resource_count, 0,
|
|
layouts, row_counts, row_sizes, &total_size);
|
|
|
|
for (j = 0; j < invalid_descs[i].sub_resource_count; ++j)
|
|
{
|
|
const D3D12_PLACED_SUBRESOURCE_FOOTPRINT *l = &layouts[j];
|
|
|
|
ok(l->Offset == ~(uint64_t)0, "Got offset %"PRIu64".\n", l->Offset);
|
|
ok(l->Footprint.Format == ~(DXGI_FORMAT)0, "Got format %#x.\n", l->Footprint.Format);
|
|
ok(l->Footprint.Width == ~0u, "Got width %u.\n", l->Footprint.Width);
|
|
ok(l->Footprint.Height == ~0u, "Got height %u.\n", l->Footprint.Height);
|
|
ok(l->Footprint.Depth == ~0u, "Got depth %u.\n", l->Footprint.Depth);
|
|
ok(l->Footprint.RowPitch == ~0u, "Got row pitch %u.\n", l->Footprint.RowPitch);
|
|
|
|
ok(row_counts[j] == ~0u, "Got row count %u.\n", row_counts[j]);
|
|
ok(row_sizes[j] == ~(uint64_t)0, "Got row size %"PRIu64".\n", row_sizes[j]);
|
|
}
|
|
|
|
ok(total_size == ~(uint64_t)0, "Got total size %"PRIu64".\n", total_size);
|
|
}
|
|
|
|
refcount = ID3D12Device_Release(device);
|
|
ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount);
|
|
}
|
|
|
|
void test_resource_allocation_info(void)
|
|
{
|
|
D3D12_RESOURCE_ALLOCATION_INFO1 res_info[2];
|
|
D3D12_RESOURCE_ALLOCATION_INFO info, info1;
|
|
D3D12_RESOURCE_DESC desc[2];
|
|
ID3D12Device4 *device4;
|
|
ID3D12Device *device;
|
|
unsigned int i, j;
|
|
ULONG refcount;
|
|
|
|
static const unsigned int alignments[] =
|
|
{
|
|
0,
|
|
D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT,
|
|
D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
|
|
D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT,
|
|
};
|
|
static const unsigned int buffer_sizes[] =
|
|
{
|
|
1,
|
|
16,
|
|
256,
|
|
1024,
|
|
D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT,
|
|
D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT + 1,
|
|
D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
|
|
D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT + 1,
|
|
D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT,
|
|
D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT + 1,
|
|
};
|
|
static const struct
|
|
{
|
|
unsigned int width;
|
|
unsigned int height;
|
|
unsigned int array_size;
|
|
unsigned int miplevels;
|
|
DXGI_FORMAT format;
|
|
}
|
|
texture_tests[] =
|
|
{
|
|
{ 4, 4, 1, 1, DXGI_FORMAT_R8_UINT},
|
|
{ 8, 8, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM},
|
|
{16, 16, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM},
|
|
{16, 16, 1024, 1, DXGI_FORMAT_R8G8B8A8_UNORM},
|
|
{256, 512, 1, 10, DXGI_FORMAT_BC1_UNORM},
|
|
{256, 512, 64, 1, DXGI_FORMAT_BC1_UNORM},
|
|
|
|
{1024, 1024, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM},
|
|
{1024, 1024, 1, 2, DXGI_FORMAT_R8G8B8A8_UNORM},
|
|
{1024, 1024, 1, 3, DXGI_FORMAT_R8G8B8A8_UNORM},
|
|
{1024, 1024, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM},
|
|
{260, 512, 1, 1, DXGI_FORMAT_BC1_UNORM},
|
|
};
|
|
|
|
if (!(device = create_device()))
|
|
{
|
|
skip("Failed to create device.\n");
|
|
return;
|
|
}
|
|
|
|
if (FAILED(ID3D12Device_QueryInterface(device, &IID_ID3D12Device4, (void**)&device4)))
|
|
skip("GetResourceAllocationInfo1 not supported by device.\n");
|
|
|
|
desc[0].Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
desc[0].Alignment = 0;
|
|
desc[0].Width = 32;
|
|
desc[0].Height = 1;
|
|
desc[0].DepthOrArraySize = 1;
|
|
desc[0].MipLevels = 1;
|
|
desc[0].Format = DXGI_FORMAT_UNKNOWN;
|
|
desc[0].SampleDesc.Count = 1;
|
|
desc[0].SampleDesc.Quality = 0;
|
|
desc[0].Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
desc[0].Flags = 0;
|
|
|
|
desc[1] = desc[0];
|
|
desc[1].Width = 120000;
|
|
|
|
info = ID3D12Device_GetResourceAllocationInfo(device, 0, 2, &desc[0]);
|
|
check_alignment(info.SizeInBytes, info.Alignment);
|
|
|
|
if (device4)
|
|
{
|
|
uint64_t offset = 0;
|
|
|
|
info1 = ID3D12Device4_GetResourceAllocationInfo1(device4, 0, 2, &desc[0], NULL);
|
|
ok(info1.SizeInBytes == info.SizeInBytes, "Got unexpected size %"PRIu64".\n", info1.SizeInBytes);
|
|
ok(info1.Alignment == info.Alignment, "Got unexpected alignment %"PRIu64".\n", info1.Alignment);
|
|
|
|
info1 = ID3D12Device4_GetResourceAllocationInfo1(device4, 0, 2, &desc[0], &res_info[0]);
|
|
ok(info1.SizeInBytes == info.SizeInBytes, "Got unexpected size %"PRIu64".\n", info1.SizeInBytes);
|
|
ok(info1.Alignment == info.Alignment, "Got unexpected alignment %"PRIu64".\n", info1.Alignment);
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
info = ID3D12Device_GetResourceAllocationInfo(device, 0, 1, &desc[i]);
|
|
offset = align(offset, info.Alignment);
|
|
|
|
ok(res_info[i].Offset == offset, "Got unexpected resource offset %"PRIu64".\n", res_info[i].Offset);
|
|
ok(res_info[i].SizeInBytes == info.SizeInBytes, "Got unexpected resource size %"PRIu64".\n", res_info[i].SizeInBytes);
|
|
ok(res_info[i].Alignment == info.Alignment, "Got unexpected resource alignment %"PRIu64".\n", res_info[i].Alignment);
|
|
|
|
offset = res_info[i].Offset + res_info[i].SizeInBytes;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(alignments); ++i)
|
|
{
|
|
for (j = 0; j < ARRAY_SIZE(buffer_sizes); ++j)
|
|
{
|
|
desc[0].Alignment = alignments[i];
|
|
desc[0].Width = buffer_sizes[j];
|
|
info = ID3D12Device_GetResourceAllocationInfo(device, 0, 1, &desc[0]);
|
|
if (!desc[0].Alignment || desc[0].Alignment == D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT)
|
|
{
|
|
check_alignment(info.SizeInBytes, info.Alignment);
|
|
}
|
|
else
|
|
{
|
|
ok(info.SizeInBytes == ~(uint64_t)0,
|
|
"Got unexpected size %"PRIu64".\n", info.SizeInBytes);
|
|
ok(info.Alignment == D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
|
|
"Got unexpected alignment %"PRIu64".\n", info.Alignment);
|
|
}
|
|
}
|
|
}
|
|
|
|
desc[1].Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
desc[1].SampleDesc.Count = 1;
|
|
desc[1].SampleDesc.Quality = 0;
|
|
desc[1].Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
desc[1].Flags = 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(texture_tests); ++i)
|
|
{
|
|
desc[1].Width = texture_tests[i].width;
|
|
desc[1].Height = texture_tests[i].height;
|
|
desc[1].DepthOrArraySize = texture_tests[i].array_size;
|
|
desc[1].MipLevels = texture_tests[i].miplevels;
|
|
desc[1].Format = texture_tests[i].format;
|
|
|
|
desc[1].Alignment = 0;
|
|
info = ID3D12Device_GetResourceAllocationInfo(device, 0, 1, &desc[1]);
|
|
ok(info.Alignment >= D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
|
|
"Got unexpected alignment %"PRIu64".\n", info.Alignment);
|
|
check_alignment(info.SizeInBytes, info.Alignment);
|
|
|
|
desc[1].Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
info = ID3D12Device_GetResourceAllocationInfo(device, 0, 1, &desc[1]);
|
|
ok(info.Alignment >= D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
|
|
"Got unexpected alignment %"PRIu64".\n", info.Alignment);
|
|
check_alignment(info.SizeInBytes, info.Alignment);
|
|
|
|
desc[1].Alignment = D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
info = ID3D12Device_GetResourceAllocationInfo(device, 0, 1, &desc[1]);
|
|
ok(info.Alignment >= D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT,
|
|
"Got unexpected alignment %"PRIu64".\n", info.Alignment);
|
|
if (i < 6)
|
|
{
|
|
check_alignment(info.SizeInBytes, info.Alignment);
|
|
}
|
|
else
|
|
{
|
|
ok(info.SizeInBytes == ~(uint64_t)0,
|
|
"Got unexpected size %"PRIu64".\n", info.SizeInBytes);
|
|
ok(info.Alignment >= D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
|
|
"Got unexpected alignment %"PRIu64".\n", info.Alignment);
|
|
}
|
|
}
|
|
|
|
if (device4)
|
|
ID3D12Device4_Release(device4);
|
|
|
|
refcount = ID3D12Device_Release(device);
|
|
ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount);
|
|
}
|
|
|
|
void test_suballocate_small_textures(void)
|
|
{
|
|
D3D12_GPU_VIRTUAL_ADDRESS gpu_address;
|
|
D3D12_RESOURCE_ALLOCATION_INFO info;
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
ID3D12Resource *textures[10];
|
|
D3D12_HEAP_DESC heap_desc;
|
|
ID3D12Device *device;
|
|
ID3D12Heap *heap;
|
|
unsigned int i;
|
|
ULONG refcount;
|
|
HRESULT hr;
|
|
|
|
if (!(device = create_device()))
|
|
{
|
|
skip("Failed to create device.\n");
|
|
return;
|
|
}
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 32;
|
|
resource_desc.Height = 32;
|
|
resource_desc.DepthOrArraySize = 1;
|
|
resource_desc.MipLevels = 1;
|
|
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
resource_desc.SampleDesc.Count = 1;
|
|
resource_desc.SampleDesc.Quality = 0;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
resource_desc.Flags = 0;
|
|
|
|
resource_desc.Alignment = D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
|
|
info = ID3D12Device_GetResourceAllocationInfo(device, 0, 1, &resource_desc);
|
|
trace("Size %"PRIu64", alignment %"PRIu64".\n", info.SizeInBytes, info.Alignment);
|
|
check_alignment(info.SizeInBytes, info.Alignment);
|
|
if (info.Alignment != D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT)
|
|
{
|
|
resource_desc.Alignment = 0;
|
|
info = ID3D12Device_GetResourceAllocationInfo(device, 0, 1, &resource_desc);
|
|
trace("Size %"PRIu64", alignment %"PRIu64".\n", info.SizeInBytes, info.Alignment);
|
|
check_alignment(info.SizeInBytes, info.Alignment);
|
|
}
|
|
|
|
ok(info.Alignment >= D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT, "Got alignment %"PRIu64".\n", info.Alignment);
|
|
|
|
heap_desc.SizeInBytes = ARRAY_SIZE(textures) * info.SizeInBytes;
|
|
memset(&heap_desc.Properties, 0, sizeof(heap_desc.Properties));
|
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
heap_desc.Alignment = 0;
|
|
heap_desc.Flags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
|
|
hr = ID3D12Device_CreateHeap(device, &heap_desc, &IID_ID3D12Heap, (void **)&heap);
|
|
ok(hr == S_OK, "Failed to create heap, hr %#x.\n", hr);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(textures); ++i)
|
|
{
|
|
hr = ID3D12Device_CreatePlacedResource(device, heap, i * info.SizeInBytes,
|
|
&resource_desc, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
|
|
NULL, &IID_ID3D12Resource, (void **)&textures[i]);
|
|
ok(hr == S_OK, "Failed to create placed resource %u, hr %#x.\n", i, hr);
|
|
|
|
check_interface(textures[i], &IID_ID3D12Object, true);
|
|
check_interface(textures[i], &IID_ID3D12DeviceChild, true);
|
|
check_interface(textures[i], &IID_ID3D12Pageable, true);
|
|
check_interface(textures[i], &IID_ID3D12Resource, true);
|
|
|
|
gpu_address = ID3D12Resource_GetGPUVirtualAddress(textures[i]);
|
|
ok(!gpu_address, "Got unexpected GPU virtual address %#"PRIx64".\n", gpu_address);
|
|
}
|
|
|
|
refcount = get_refcount(heap);
|
|
ok(refcount == 1, "Got unexpected refcount %u.\n", (unsigned int)refcount);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(textures); ++i)
|
|
{
|
|
refcount = ID3D12Resource_Release(textures[i]);
|
|
ok(!refcount, "ID3D12Resource has %u references left.\n", (unsigned int)refcount);
|
|
}
|
|
|
|
refcount = ID3D12Heap_Release(heap);
|
|
ok(!refcount, "ID3D12Heap has %u references left.\n", (unsigned int)refcount);
|
|
refcount = ID3D12Device_Release(device);
|
|
ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount);
|
|
}
|
|
|
|
void test_read_subresource_rt(void)
|
|
{
|
|
const FLOAT white[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
D3D12_CPU_DESCRIPTOR_HANDLE desc_handle;
|
|
D3D12_HEAP_PROPERTIES heap_properties;
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
ID3D12DescriptorHeap *desc_heap;
|
|
struct test_context_desc desc;
|
|
struct test_context context;
|
|
ID3D12Resource *resource;
|
|
uint32_t pixels[4 * 4];
|
|
ID3D12Device *device;
|
|
D3D12_RECT rect;
|
|
uint32_t pixel;
|
|
uint32_t x, y;
|
|
D3D12_BOX box;
|
|
HRESULT hr;
|
|
|
|
memset(&desc, 0, sizeof(desc));
|
|
desc.no_pipeline = true;
|
|
desc.no_render_target = true;
|
|
desc.no_render_target = true;
|
|
if (!init_test_context(&context, &desc))
|
|
return;
|
|
|
|
device = context.device;
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 4;
|
|
resource_desc.Height = 4;
|
|
resource_desc.DepthOrArraySize = 1;
|
|
resource_desc.MipLevels = 1;
|
|
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
resource_desc.SampleDesc.Count = 1;
|
|
resource_desc.SampleDesc.Quality = 0;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
|
|
memset(&heap_properties, 0, sizeof(heap_properties));
|
|
heap_properties.Type = D3D12_HEAP_TYPE_CUSTOM;
|
|
heap_properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK;
|
|
heap_properties.MemoryPoolPreference = D3D12_MEMORY_POOL_L0;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&resource);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
skip("Cannot create CPU accessible render target. Skipping test.\n");
|
|
destroy_test_context(&context);
|
|
return;
|
|
}
|
|
|
|
pixel = 0x80808080;
|
|
ID3D12Resource_Map(resource, 0, NULL, NULL);
|
|
for (y = 0; y < 4; y++)
|
|
{
|
|
for (x = 0; x < 4; x++)
|
|
{
|
|
set_box(&box, x, y, 0, x + 1, y + 1, 1);
|
|
ID3D12Resource_WriteToSubresource(resource, 0, &box, &pixel,
|
|
sizeof(uint32_t), sizeof(uint32_t));
|
|
}
|
|
}
|
|
ID3D12Resource_Unmap(resource, 0, NULL);
|
|
|
|
desc_heap = create_cpu_descriptor_heap(device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1);
|
|
desc_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap);
|
|
ID3D12Device_CreateRenderTargetView(device, resource, NULL, desc_handle);
|
|
transition_resource_state(context.list, resource,
|
|
D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
|
|
|
for (x = 0; x < 4; x++)
|
|
{
|
|
set_rect(&rect, x, x, x + 1, x + 1);
|
|
ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, desc_handle, white, 1, &rect);
|
|
}
|
|
|
|
transition_resource_state(context.list, resource,
|
|
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COMMON);
|
|
|
|
ID3D12GraphicsCommandList_Close(context.list);
|
|
exec_command_list(context.queue, context.list);
|
|
wait_queue_idle(device, context.queue);
|
|
|
|
ID3D12Resource_Map(resource, 0, NULL, NULL);
|
|
set_box(&box, 0, 0, 0, 4, 4, 1);
|
|
ID3D12Resource_ReadFromSubresource(resource, pixels,
|
|
4 * sizeof(uint32_t), 16 * sizeof(uint32_t), 0, &box);
|
|
ID3D12Resource_Unmap(resource, 0, NULL);
|
|
|
|
for (y = 0; y < 4; y++)
|
|
{
|
|
for (x = 0; x < 4; x++)
|
|
{
|
|
uint32_t expected = x == y ? UINT32_MAX : pixel;
|
|
ok(pixels[y * 4 + x] == expected, "Pixel %u, %u: %#x != %#x\n", x, y, pixels[y * 4 + x], expected);
|
|
}
|
|
}
|
|
|
|
ID3D12DescriptorHeap_Release(desc_heap);
|
|
ID3D12Resource_Release(resource);
|
|
|
|
destroy_test_context(&context);
|
|
}
|
|
|
|
/* Reduced test case which runs on more implementations. */
|
|
void test_read_write_subresource_2d(void)
|
|
{
|
|
D3D12_TEXTURE_COPY_LOCATION src_location, dst_location;
|
|
uint32_t *dst_buffer, *zero_buffer, *ptr;
|
|
ID3D12GraphicsCommandList *command_list;
|
|
D3D12_HEAP_PROPERTIES heap_properties;
|
|
D3D12_SUBRESOURCE_DATA texture_data;
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
struct test_context_desc desc;
|
|
struct test_context context;
|
|
struct resource_readback rb;
|
|
ID3D12Resource *src_texture;
|
|
ID3D12Resource *dst_texture;
|
|
ID3D12CommandQueue *queue;
|
|
ID3D12Resource *rb_buffer;
|
|
unsigned int buffer_size;
|
|
unsigned int slice_pitch;
|
|
unsigned int row_pitch;
|
|
uint32_t got, expected;
|
|
unsigned int x, y, i;
|
|
ID3D12Device *device;
|
|
D3D12_BOX box;
|
|
HRESULT hr;
|
|
|
|
memset(&desc, 0, sizeof(desc));
|
|
desc.no_render_target = true;
|
|
if (!init_test_context(&context, &desc))
|
|
return;
|
|
device = context.device;
|
|
command_list = context.list;
|
|
queue = context.queue;
|
|
|
|
row_pitch = 128 * sizeof(unsigned int);
|
|
slice_pitch = row_pitch * 100;
|
|
buffer_size = slice_pitch * 1;
|
|
|
|
/* Buffers are not supported */
|
|
rb_buffer = create_readback_buffer(device, buffer_size);
|
|
dst_buffer = malloc(buffer_size);
|
|
ok(dst_buffer, "Failed to allocate memory.\n");
|
|
zero_buffer = malloc(buffer_size);
|
|
ok(zero_buffer, "Failed to allocate memory.\n");
|
|
memset(zero_buffer, 0, buffer_size);
|
|
|
|
set_box(&box, 0, 0, 0, 1, 1, 1);
|
|
hr = ID3D12Resource_WriteToSubresource(rb_buffer, 0, &box, dst_buffer, row_pitch, slice_pitch);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
hr = ID3D12Resource_ReadFromSubresource(rb_buffer, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
ID3D12Resource_Release(rb_buffer);
|
|
|
|
/* Only texture on custom heaps is legal for ReadFromSubresource/WriteToSubresource */
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 128;
|
|
resource_desc.Height = 100;
|
|
resource_desc.DepthOrArraySize = 1;
|
|
resource_desc.MipLevels = 1;
|
|
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
resource_desc.SampleDesc.Count = 1;
|
|
resource_desc.SampleDesc.Quality = 0;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
resource_desc.Flags = 0;
|
|
|
|
memset(&heap_properties, 0, sizeof(heap_properties));
|
|
heap_properties.Type = D3D12_HEAP_TYPE_CUSTOM;
|
|
heap_properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK;
|
|
heap_properties.MemoryPoolPreference = D3D12_MEMORY_POOL_L0;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&src_texture);
|
|
if (FAILED(hr))
|
|
{
|
|
skip("Failed to create texture on custom heap.\n");
|
|
goto done;
|
|
}
|
|
|
|
/* Invalid box */
|
|
set_box(&box, 0, 0, 0, 128, 100, 2);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
set_box(&box, 0, 0, 2, 128, 100, 2);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
set_box(&box, 128, 0, 0, 129, 100, 1);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* NULL box */
|
|
hr = ID3D12Resource_WriteToSubresource(src_texture, 0, NULL, dst_buffer, row_pitch, slice_pitch);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, NULL);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* Empty box */
|
|
set_box(&box, 128, 100, 1, 128, 100, 1);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
set_box(&box, 0, 0, 0, 0, 0, 0);
|
|
hr = ID3D12Resource_WriteToSubresource(src_texture, 0, &box, dst_buffer, row_pitch, slice_pitch);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
for (i = 0; i < 2; ++i)
|
|
{
|
|
vkd3d_test_set_context("Test %u", i);
|
|
|
|
for (y = 0; y < 100; ++y)
|
|
{
|
|
for (x = 0; x < 128; ++x)
|
|
{
|
|
ptr = &dst_buffer[y * 128 + x];
|
|
if (x < 2 && y < 2) /* Region 1 */
|
|
*ptr = (y + 1) << 8 | (x + 1);
|
|
else if (2 <= x && x < 11 && 2 <= y && y < 13) /* Region 2 */
|
|
*ptr = (y + 2) << 8 | (x + 2);
|
|
else
|
|
*ptr = 0xdeadbeef;
|
|
}
|
|
}
|
|
|
|
if (i)
|
|
{
|
|
hr = ID3D12Resource_WriteToSubresource(src_texture, 0, NULL, zero_buffer, row_pitch, slice_pitch);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* Write region 1 */
|
|
set_box(&box, 0, 0, 0, 2, 2, 1);
|
|
hr = ID3D12Resource_WriteToSubresource(src_texture, 0, &box, dst_buffer, row_pitch, slice_pitch);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* Write region 2 */
|
|
set_box(&box, 2, 2, 0, 11, 13, 1);
|
|
hr = ID3D12Resource_WriteToSubresource(src_texture, 0, &box, &dst_buffer[2 * 128 + 2],
|
|
row_pitch, slice_pitch);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
}
|
|
else
|
|
{
|
|
/* Upload the test data */
|
|
transition_resource_state(command_list, src_texture,
|
|
D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST);
|
|
texture_data.pData = dst_buffer;
|
|
texture_data.RowPitch = row_pitch;
|
|
texture_data.SlicePitch = slice_pitch;
|
|
upload_texture_data(src_texture, &texture_data, 1, queue, command_list);
|
|
reset_command_list(command_list, context.allocator);
|
|
transition_resource_state(command_list, src_texture,
|
|
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON);
|
|
}
|
|
|
|
memset(dst_buffer, 0, buffer_size);
|
|
|
|
/* Read region 1 */
|
|
set_box(&box, 0, 0, 0, 2, 2, 1);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* Read region 2 */
|
|
set_box(&box, 2, 2, 0, 11, 13, 1);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, &dst_buffer[2 * 128 + 2], row_pitch,
|
|
slice_pitch, 0, &box);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
for (y = 0; y < 100; ++y)
|
|
{
|
|
for (x = 0; x < 128; ++x)
|
|
{
|
|
if (x < 2 && y < 2) /* Region 1 */
|
|
expected = (y + 1) << 8 | (x + 1);
|
|
else if (2 <= x && x < 11 && 2 <= y && y < 13) /* Region 2 */
|
|
expected = (y + 2) << 8 | (x + 2);
|
|
else /* Untouched */
|
|
expected = 0;
|
|
|
|
got = dst_buffer[y * 128 + x];
|
|
if (got != expected)
|
|
break;
|
|
}
|
|
if (got != expected)
|
|
break;
|
|
}
|
|
ok(got == expected, "Got unexpected value 0x%08x at (%u, %u), expected 0x%08x.\n", got, x, y, expected);
|
|
}
|
|
vkd3d_test_set_context(NULL);
|
|
|
|
/* Test layout is the same */
|
|
dst_texture = create_default_texture2d(device, 128, 100, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0,
|
|
D3D12_RESOURCE_STATE_COPY_DEST);
|
|
memset(dst_buffer, 0, buffer_size);
|
|
texture_data.pData = dst_buffer;
|
|
texture_data.RowPitch = row_pitch;
|
|
texture_data.SlicePitch = slice_pitch;
|
|
upload_texture_data(dst_texture, &texture_data, 1, queue, command_list);
|
|
reset_command_list(command_list, context.allocator);
|
|
|
|
src_location.pResource = src_texture;
|
|
src_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
src_location.SubresourceIndex = 0;
|
|
dst_location.pResource = dst_texture;
|
|
dst_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
dst_location.SubresourceIndex = 0;
|
|
set_box(&box, 0, 0, 0, 128, 100, 1);
|
|
ID3D12GraphicsCommandList_CopyTextureRegion(command_list, &dst_location, 0, 0, 0, &src_location, &box);
|
|
|
|
transition_resource_state(command_list, dst_texture,
|
|
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
|
get_texture_readback_with_command_list(dst_texture, 0, &rb, queue, command_list);
|
|
for (y = 0; y < 100; ++y)
|
|
{
|
|
for (x = 0; x < 128; ++x)
|
|
{
|
|
if (x < 2 && y < 2) /* Region 1 */
|
|
expected = (y + 1) << 8 | (x + 1);
|
|
else if (2 <= x && x < 11 && 2 <= y && y < 13) /* Region 2 */
|
|
expected = (y + 2) << 8 | (x + 2);
|
|
else /* Untouched */
|
|
expected = 0;
|
|
|
|
got = get_readback_uint(&rb, x, y, 0);
|
|
if (got != expected)
|
|
break;
|
|
}
|
|
if (got != expected)
|
|
break;
|
|
}
|
|
ok(got == expected, "Got unexpected value 0x%08x at (%u, %u), expected 0x%08x.\n", got, x, y, expected);
|
|
release_resource_readback(&rb);
|
|
|
|
ID3D12Resource_Release(src_texture);
|
|
ID3D12Resource_Release(dst_texture);
|
|
|
|
done:
|
|
free(dst_buffer);
|
|
free(zero_buffer);
|
|
destroy_test_context(&context);
|
|
}
|
|
|
|
void test_read_write_subresource(void)
|
|
{
|
|
D3D12_TEXTURE_COPY_LOCATION src_location, dst_location;
|
|
uint32_t *dst_buffer, *zero_buffer, *ptr;
|
|
ID3D12GraphicsCommandList *command_list;
|
|
D3D12_HEAP_PROPERTIES heap_properties;
|
|
D3D12_SUBRESOURCE_DATA texture_data;
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
struct test_context_desc desc;
|
|
struct test_context context;
|
|
struct resource_readback rb;
|
|
ID3D12Resource *src_texture;
|
|
ID3D12Resource *dst_texture;
|
|
ID3D12CommandQueue *queue;
|
|
ID3D12Resource *rb_buffer;
|
|
unsigned int buffer_size;
|
|
unsigned int slice_pitch;
|
|
unsigned int x, y, z, i;
|
|
unsigned int row_pitch;
|
|
uint32_t got, expected;
|
|
ID3D12Device *device;
|
|
D3D12_BOX box;
|
|
HRESULT hr;
|
|
|
|
memset(&desc, 0, sizeof(desc));
|
|
desc.no_render_target = true;
|
|
if (!init_test_context(&context, &desc))
|
|
return;
|
|
device = context.device;
|
|
command_list = context.list;
|
|
queue = context.queue;
|
|
|
|
row_pitch = 128 * sizeof(unsigned int);
|
|
slice_pitch = row_pitch * 100;
|
|
buffer_size = slice_pitch * 64;
|
|
|
|
/* Buffers are not supported */
|
|
rb_buffer = create_readback_buffer(device, buffer_size);
|
|
dst_buffer = malloc(buffer_size);
|
|
ok(dst_buffer, "Failed to allocate memory.\n");
|
|
zero_buffer = malloc(buffer_size);
|
|
ok(zero_buffer, "Failed to allocate memory.\n");
|
|
memset(zero_buffer, 0, buffer_size);
|
|
|
|
set_box(&box, 0, 0, 0, 1, 1, 1);
|
|
hr = ID3D12Resource_WriteToSubresource(rb_buffer, 0, &box, dst_buffer, row_pitch, slice_pitch);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
hr = ID3D12Resource_ReadFromSubresource(rb_buffer, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
ID3D12Resource_Release(rb_buffer);
|
|
|
|
/* Only texture on custom heaps is legal for ReadFromSubresource/WriteToSubresource */
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 128;
|
|
resource_desc.Height = 100;
|
|
resource_desc.DepthOrArraySize = 64;
|
|
resource_desc.MipLevels = 1;
|
|
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
resource_desc.SampleDesc.Count = 1;
|
|
resource_desc.SampleDesc.Quality = 0;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
resource_desc.Flags = 0;
|
|
|
|
memset(&heap_properties, 0, sizeof(heap_properties));
|
|
heap_properties.Type = D3D12_HEAP_TYPE_CUSTOM;
|
|
heap_properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK;
|
|
heap_properties.MemoryPoolPreference = D3D12_MEMORY_POOL_L0;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&src_texture);
|
|
if (FAILED(hr))
|
|
{
|
|
skip("Failed to create texture on custom heap.\n");
|
|
goto done;
|
|
}
|
|
|
|
/* Invalid box */
|
|
set_box(&box, 0, 0, 0, 128, 100, 65);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
set_box(&box, 0, 0, 65, 128, 100, 65);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
set_box(&box, 128, 0, 0, 128, 100, 65);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* NULL box */
|
|
hr = ID3D12Resource_WriteToSubresource(src_texture, 0, NULL, dst_buffer, row_pitch, slice_pitch);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, NULL);
|
|
todo_if(is_nvidia_device(device))
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* Empty box */
|
|
set_box(&box, 128, 100, 64, 128, 100, 64);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
set_box(&box, 0, 0, 0, 0, 0, 0);
|
|
hr = ID3D12Resource_WriteToSubresource(src_texture, 0, &box, dst_buffer, row_pitch, slice_pitch);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
for (i = 0; i < 2; ++i)
|
|
{
|
|
vkd3d_test_set_context("Test %u", i);
|
|
|
|
for (z = 0; z < 64; ++z)
|
|
{
|
|
for (y = 0; y < 100; ++y)
|
|
{
|
|
for (x = 0; x < 128; ++x)
|
|
{
|
|
ptr = &dst_buffer[z * 128 * 100 + y * 128 + x];
|
|
if (x < 2 && y< 2 && z < 2) /* Region 1 */
|
|
*ptr = (z + 1) << 16 | (y + 1) << 8 | (x + 1);
|
|
else if (2 <= x && x < 11 && 2 <= y && y < 13 && 2 <= z && z < 17) /* Region 2 */
|
|
*ptr = (z + 2) << 16 | (y + 2) << 8 | (x + 2);
|
|
else
|
|
*ptr = 0xdeadbeef;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i)
|
|
{
|
|
hr = ID3D12Resource_WriteToSubresource(src_texture, 0, NULL, zero_buffer, row_pitch, slice_pitch);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* Write region 1 */
|
|
set_box(&box, 0, 0, 0, 2, 2, 2);
|
|
hr = ID3D12Resource_WriteToSubresource(src_texture, 0, &box, dst_buffer, row_pitch, slice_pitch);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* Write region 2 */
|
|
set_box(&box, 2, 2, 2, 11, 13, 17);
|
|
hr = ID3D12Resource_WriteToSubresource(src_texture, 0, &box, &dst_buffer[2 * 128 * 100 + 2 * 128 + 2],
|
|
row_pitch, slice_pitch);
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
}
|
|
else
|
|
{
|
|
/* Upload the test data */
|
|
transition_resource_state(command_list, src_texture,
|
|
D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST);
|
|
texture_data.pData = dst_buffer;
|
|
texture_data.RowPitch = row_pitch;
|
|
texture_data.SlicePitch = slice_pitch;
|
|
upload_texture_data(src_texture, &texture_data, 1, queue, command_list);
|
|
reset_command_list(command_list, context.allocator);
|
|
transition_resource_state(command_list, src_texture,
|
|
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON);
|
|
}
|
|
|
|
memset(dst_buffer, 0, buffer_size);
|
|
|
|
/* Read region 1 */
|
|
set_box(&box, 0, 0, 0, 2, 2, 2);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
todo_if(is_nvidia_device(device))
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* Read region 2 */
|
|
set_box(&box, 2, 2, 2, 11, 13, 17);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, &dst_buffer[2 * 128 * 100 + 2 * 128 + 2], row_pitch,
|
|
slice_pitch, 0, &box);
|
|
todo_if(is_nvidia_device(device))
|
|
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
|
|
|
|
for (z = 0; z < 64; ++z)
|
|
{
|
|
for (y = 0; y < 100; ++y)
|
|
{
|
|
for (x = 0; x < 128; ++x)
|
|
{
|
|
if (x < 2 && y < 2 && z < 2) /* Region 1 */
|
|
expected = (z + 1) << 16 | (y + 1) << 8 | (x + 1);
|
|
else if (2 <= x && x < 11 && 2 <= y && y < 13 && 2 <= z && z < 17) /* Region 2 */
|
|
expected = (z + 2) << 16 | (y + 2) << 8 | (x + 2);
|
|
else /* Untouched */
|
|
expected = 0;
|
|
|
|
got = dst_buffer[z * 128 * 100 + y * 128 + x];
|
|
if (got != expected)
|
|
break;
|
|
}
|
|
if (got != expected)
|
|
break;
|
|
}
|
|
if (got != expected)
|
|
break;
|
|
}
|
|
todo_if(is_nvidia_device(device))
|
|
ok(got == expected, "Got unexpected value 0x%08x at (%u, %u, %u), expected 0x%08x.\n", got, x, y, z, expected);
|
|
}
|
|
vkd3d_test_set_context(NULL);
|
|
|
|
/* Test layout is the same */
|
|
dst_texture = create_default_texture3d(device, 128, 100, 64, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0,
|
|
D3D12_RESOURCE_STATE_COPY_DEST);
|
|
memset(dst_buffer, 0, buffer_size);
|
|
texture_data.pData = dst_buffer;
|
|
texture_data.RowPitch = row_pitch;
|
|
texture_data.SlicePitch = slice_pitch;
|
|
upload_texture_data(dst_texture, &texture_data, 1, queue, command_list);
|
|
reset_command_list(command_list, context.allocator);
|
|
|
|
src_location.pResource = src_texture;
|
|
src_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
src_location.SubresourceIndex = 0;
|
|
dst_location.pResource = dst_texture;
|
|
dst_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
dst_location.SubresourceIndex = 0;
|
|
set_box(&box, 0, 0, 0, 128, 100, 64);
|
|
ID3D12GraphicsCommandList_CopyTextureRegion(command_list, &dst_location, 0, 0, 0, &src_location, &box);
|
|
|
|
transition_resource_state(command_list, dst_texture,
|
|
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
|
get_texture_readback_with_command_list(dst_texture, 0, &rb, queue, command_list);
|
|
for (z = 0; z < 64; ++z)
|
|
{
|
|
for (y = 0; y < 100; ++y)
|
|
{
|
|
for (x = 0; x < 128; ++x)
|
|
{
|
|
if (x < 2 && y < 2 && z < 2) /* Region 1 */
|
|
expected = (z + 1) << 16 | (y + 1) << 8 | (x + 1);
|
|
else if (2 <= x && x < 11 && 2 <= y && y < 13 && 2 <= z && z < 17) /* Region 2 */
|
|
expected = (z + 2) << 16 | (y + 2) << 8 | (x + 2);
|
|
else /* Untouched */
|
|
expected = 0;
|
|
|
|
got = get_readback_uint(&rb, x, y, z);
|
|
if (got != expected)
|
|
break;
|
|
}
|
|
if (got != expected)
|
|
break;
|
|
}
|
|
if (got != expected)
|
|
break;
|
|
}
|
|
ok(got == expected, "Got unexpected value 0x%08x at (%u, %u, %u), expected 0x%08x.\n", got, x, y, z, expected);
|
|
release_resource_readback(&rb);
|
|
|
|
ID3D12Resource_Release(src_texture);
|
|
ID3D12Resource_Release(dst_texture);
|
|
|
|
/* Invalid box */
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
resource_desc.Alignment = 0;
|
|
resource_desc.Width = 64;
|
|
resource_desc.Height = 32;
|
|
resource_desc.DepthOrArraySize = 1;
|
|
resource_desc.MipLevels = 1;
|
|
resource_desc.Format = DXGI_FORMAT_BC1_UNORM;
|
|
resource_desc.SampleDesc.Count = 1;
|
|
resource_desc.SampleDesc.Quality = 0;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
resource_desc.Flags = 0;
|
|
|
|
memset(&heap_properties, 0, sizeof(heap_properties));
|
|
heap_properties.Type = D3D12_HEAP_TYPE_CUSTOM;
|
|
heap_properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK;
|
|
heap_properties.MemoryPoolPreference = D3D12_MEMORY_POOL_L0;
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_properties, D3D12_HEAP_FLAG_NONE,
|
|
&resource_desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&src_texture);
|
|
ok(hr == S_OK, "Failed to create resource, hr %#x.\n", hr);
|
|
|
|
/* Unaligned coordinates for BC format */
|
|
set_box(&box, 0, 0, 0, 2, 2, 1);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
set_box(&box, 2, 2, 0, 4, 4, 1);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
set_box(&box, 2, 2, 0, 6, 6, 1);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
/* Invalid coordinates for resource dimensions */
|
|
set_box(&box, 0, 0, 0, 64, 32, 2);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
set_box(&box, 0, 0, 0, 68, 32, 1);
|
|
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
|
|
|
|
ID3D12Resource_Release(src_texture);
|
|
|
|
done:
|
|
free(dst_buffer);
|
|
free(zero_buffer);
|
|
destroy_test_context(&context);
|
|
}
|
|
|
|
struct suballocation_thread_data
|
|
{
|
|
struct test_context *context;
|
|
unsigned int seed;
|
|
};
|
|
|
|
void test_stress_suballocation_thread(void *userdata)
|
|
{
|
|
struct suballocation_thread_data *thread_data = userdata;
|
|
struct test_context *context = thread_data->context;
|
|
|
|
#define SUBALLOC_TEST_NUM_BUFFERS 128
|
|
#define SUBALLOC_TEST_NUM_ITERATIONS 64
|
|
ID3D12Resource *readback_buffers[SUBALLOC_TEST_NUM_BUFFERS] = { NULL };
|
|
ID3D12Resource *buffers[SUBALLOC_TEST_NUM_BUFFERS] = { NULL };
|
|
UINT reference_values[SUBALLOC_TEST_NUM_BUFFERS] = { 0 };
|
|
ID3D12Heap *heaps[SUBALLOC_TEST_NUM_BUFFERS] = { NULL };
|
|
D3D12_ROOT_SIGNATURE_DESC root_signature_desc;
|
|
D3D12_ROOT_PARAMETER root_parameters[2];
|
|
ID3D12PipelineState *pipeline_state;
|
|
ID3D12RootSignature *root_signature;
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
ID3D12CommandAllocator *allocator;
|
|
ID3D12GraphicsCommandList *list;
|
|
ID3D12Heap *dummy_heaps[2];
|
|
D3D12_HEAP_DESC heap_desc;
|
|
unsigned int iter, i;
|
|
UINT reference_value;
|
|
ID3D12Fence *fence;
|
|
UINT64 fence_value;
|
|
bool clear_buffer;
|
|
unsigned int seed;
|
|
bool alloc_heap;
|
|
bool keep_alive;
|
|
UINT alloc_size;
|
|
HRESULT hr;
|
|
|
|
static const DWORD cs_code[] =
|
|
{
|
|
#if 0
|
|
RWStructuredBuffer<uint> Buf : register(u0);
|
|
cbuffer CBuf : register(b0) { uint clear_value; };
|
|
|
|
[numthreads(64, 1, 1)]
|
|
void main(uint thr : SV_DispatchThreadID)
|
|
{
|
|
Buf[thr] = clear_value;
|
|
}
|
|
#endif
|
|
0x43425844, 0x687983cd, 0xe75a9b58, 0xa77e1917, 0x78d96804, 0x00000001, 0x000000c0, 0x00000003,
|
|
0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
|
|
0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x0000006c, 0x00050050, 0x0000001b, 0x0100086a,
|
|
0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x0400009e, 0x0011e000, 0x00000000, 0x00000004,
|
|
0x0200005f, 0x00020012, 0x0400009b, 0x00000040, 0x00000001, 0x00000001, 0x090000a8, 0x0011e012,
|
|
0x00000000, 0x0002000a, 0x00004001, 0x00000000, 0x0020800a, 0x00000000, 0x00000000, 0x0100003e,
|
|
};
|
|
|
|
seed = thread_data->seed;
|
|
|
|
#ifdef _WIN32
|
|
/* rand_r() doesn't exist, but rand() does and is MT safe on Win32. */
|
|
#define rand_r(x) rand()
|
|
srand(seed);
|
|
#endif
|
|
|
|
root_signature_desc.NumParameters = 2;
|
|
root_signature_desc.Flags = 0;
|
|
root_signature_desc.NumStaticSamplers = 0;
|
|
root_signature_desc.pStaticSamplers = NULL;
|
|
root_signature_desc.pParameters = root_parameters;
|
|
|
|
root_parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV;
|
|
root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
|
root_parameters[0].Descriptor.RegisterSpace = 0;
|
|
root_parameters[0].Descriptor.ShaderRegister = 0;
|
|
|
|
root_parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
|
|
root_parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
|
root_parameters[1].Constants.RegisterSpace = 0;
|
|
root_parameters[1].Constants.ShaderRegister = 0;
|
|
root_parameters[1].Constants.Num32BitValues = 1;
|
|
|
|
hr = create_root_signature(context->device, &root_signature_desc, &root_signature);
|
|
ok(SUCCEEDED(hr), "Failed to create root signature.\n");
|
|
|
|
pipeline_state = create_compute_pipeline_state(context->device, root_signature,
|
|
shader_bytecode(cs_code, sizeof(cs_code)));
|
|
|
|
hr = ID3D12Device_CreateCommandAllocator(context->device, D3D12_COMMAND_LIST_TYPE_DIRECT, &IID_ID3D12CommandAllocator, (void **)&allocator);
|
|
ok(SUCCEEDED(hr), "Failed to create command allocator.\n");
|
|
hr = ID3D12Device_CreateCommandList(context->device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, allocator, NULL, &IID_ID3D12GraphicsCommandList, (void **)&list);
|
|
ok(SUCCEEDED(hr), "Failed to create command list.\n");
|
|
ID3D12GraphicsCommandList_Close(list);
|
|
|
|
ID3D12Device_CreateFence(context->device, 0, D3D12_FENCE_FLAG_NONE, &IID_ID3D12Fence, (void **)&fence);
|
|
fence_value = 0;
|
|
reference_value = 0;
|
|
|
|
hr = wait_for_fence(fence, fence_value);
|
|
ok(SUCCEEDED(hr), "Failed to wait for fence.\n");
|
|
|
|
/* Stress test internal implementation details. Perform many smaller allocations and verify that the allocation works as expected. */
|
|
|
|
for (iter = 0; iter < SUBALLOC_TEST_NUM_ITERATIONS; iter++)
|
|
{
|
|
reset_command_list(list, allocator);
|
|
fence_value++;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(heaps); i++)
|
|
{
|
|
/* Randomly allocate heaps and place a buffer on top of it. */
|
|
alloc_heap = rand_r(&seed) % 2 == 0;
|
|
/* Ensures we sometimes hit dedicated allocation paths. (2 MiB limit). */
|
|
alloc_size = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT * (1 + rand_r(&seed) % 40);
|
|
keep_alive = rand_r(&seed) % 2 == 0;
|
|
|
|
if (buffers[i] && keep_alive)
|
|
{
|
|
/* To test chunk allocator, make sure we don't free *everything* every iteration.
|
|
Just transition back to UAV state. */
|
|
transition_resource_state(list, buffers[i], D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
|
/* If we reuse the buffer, always test explicit clear since we tested zero memory once already previous iteration. */
|
|
reference_values[i] = ++reference_value;
|
|
}
|
|
else
|
|
{
|
|
clear_buffer = rand_r(&seed) % 2 == 0;
|
|
if (clear_buffer)
|
|
reference_values[i] = ++reference_value;
|
|
else
|
|
reference_values[i] = 0; /* Test zero memory behavior. */
|
|
|
|
if (heaps[i])
|
|
ID3D12Heap_Release(heaps[i]);
|
|
if (buffers[i])
|
|
ID3D12Resource_Release(buffers[i]);
|
|
if (readback_buffers[i])
|
|
ID3D12Resource_Release(readback_buffers[i]);
|
|
|
|
heaps[i] = NULL;
|
|
buffers[i] = NULL;
|
|
readback_buffers[i] = NULL;
|
|
|
|
memset(&heap_desc, 0, sizeof(heap_desc));
|
|
heap_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
|
|
heap_desc.SizeInBytes = alloc_size;
|
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
|
|
/* If we're clearing ourselves, this should be moot. Check that it doesn't cause issues. */
|
|
if (clear_buffer && rand_r(&seed) % 2 == 0)
|
|
heap_desc.Flags |= D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
|
|
|
|
if (alloc_heap)
|
|
{
|
|
hr = ID3D12Device_CreateHeap(context->device, &heap_desc, &IID_ID3D12Heap, (void **)&heaps[i]);
|
|
ok(SUCCEEDED(hr), "Failed to allocate heap.\n");
|
|
}
|
|
|
|
memset(&resource_desc, 0, sizeof(resource_desc));
|
|
resource_desc.Width = alloc_size;
|
|
resource_desc.DepthOrArraySize = 1;
|
|
resource_desc.Height = 1;
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
resource_desc.Format = DXGI_FORMAT_UNKNOWN;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
resource_desc.SampleDesc.Count = 1;
|
|
resource_desc.MipLevels = 1;
|
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
|
if (alloc_heap)
|
|
hr = ID3D12Device_CreatePlacedResource(context->device, heaps[i], 0, &resource_desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, &IID_ID3D12Resource, (void **)&buffers[i]);
|
|
else
|
|
hr = ID3D12Device_CreateCommittedResource(context->device, &heap_desc.Properties, D3D12_HEAP_FLAG_NONE, &resource_desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, &IID_ID3D12Resource, (void **)&buffers[i]);
|
|
ok(SUCCEEDED(hr), "Failed to create buffer.\n");
|
|
|
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_READBACK;
|
|
hr = ID3D12Device_CreateCommittedResource(context->device, &heap_desc.Properties, D3D12_HEAP_FLAG_NONE, &resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, &IID_ID3D12Resource, (void **)&readback_buffers[i]);
|
|
ok(SUCCEEDED(hr), "Failed to create readback buffer.\n");
|
|
}
|
|
|
|
if (reference_values[i] != 0)
|
|
{
|
|
ID3D12GraphicsCommandList_SetComputeRootSignature(list, root_signature);
|
|
ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(list, 0, ID3D12Resource_GetGPUVirtualAddress(buffers[i]));
|
|
ID3D12GraphicsCommandList_SetComputeRoot32BitConstants(list, 1, 1, &reference_values[i], 0);
|
|
ID3D12GraphicsCommandList_SetPipelineState(list, pipeline_state);
|
|
ID3D12GraphicsCommandList_Dispatch(list, ID3D12Resource_GetDesc(buffers[i]).Width / (4 * 64), 1, 1);
|
|
}
|
|
|
|
transition_resource_state(list, buffers[i], D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
|
ID3D12GraphicsCommandList_CopyResource(list, readback_buffers[i], buffers[i]);
|
|
}
|
|
|
|
/* Create a heap which needs to be zeroed.
|
|
* Test that we can safely free the heap after zero memory is flushed.
|
|
* For the first one, we free before ExecuteCommandLists, this should never attempt clearing memory.
|
|
* For the second one, we have flushed, so we expect a CPU stall where we wait for zeromemory to complete. */
|
|
alloc_size = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT * (1 + rand_r(&seed) % 20);
|
|
memset(&heap_desc, 0, sizeof(heap_desc));
|
|
heap_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
|
|
heap_desc.SizeInBytes = alloc_size;
|
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
hr = ID3D12Device_CreateHeap(context->device, &heap_desc, &IID_ID3D12Heap, (void **)&dummy_heaps[0]);
|
|
ok(SUCCEEDED(hr), "Failed to allocate heap.\n");
|
|
hr = ID3D12Device_CreateHeap(context->device, &heap_desc, &IID_ID3D12Heap, (void **)&dummy_heaps[1]);
|
|
ok(SUCCEEDED(hr), "Failed to allocate heap.\n");
|
|
|
|
ID3D12GraphicsCommandList_Close(list);
|
|
ID3D12Heap_Release(dummy_heaps[0]);
|
|
ID3D12CommandQueue_ExecuteCommandLists(context->queue, 1, (ID3D12CommandList *const *)&list);
|
|
ID3D12Heap_Release(dummy_heaps[1]);
|
|
|
|
ID3D12CommandQueue_Signal(context->queue, fence, fence_value);
|
|
wait_for_fence(fence, fence_value);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(readback_buffers); i++)
|
|
{
|
|
bool found_error = false;
|
|
UINT j, words, *mapped;
|
|
UINT last_value = 0;
|
|
|
|
words = ID3D12Resource_GetDesc(readback_buffers[i]).Width / 4;
|
|
last_value = 0;
|
|
hr = ID3D12Resource_Map(readback_buffers[i], 0, NULL, (void **)&mapped);
|
|
ok(SUCCEEDED(hr), "Failed to map readback buffer.\n");
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
for (j = 0; j < words && !found_error; j++)
|
|
{
|
|
last_value = mapped[j];
|
|
found_error = mapped[j] != reference_values[i];
|
|
}
|
|
ok(!found_error, "Expected all words to be %u, but got %u.\n", reference_values[i], last_value);
|
|
ID3D12Resource_Unmap(readback_buffers[i], 0, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(heaps); i++)
|
|
if (heaps[i])
|
|
ID3D12Heap_Release(heaps[i]);
|
|
for (i = 0; i < ARRAY_SIZE(buffers); i++)
|
|
if (buffers[i])
|
|
ID3D12Resource_Release(buffers[i]);
|
|
for (i = 0; i < ARRAY_SIZE(readback_buffers); i++)
|
|
if (readback_buffers[i])
|
|
ID3D12Resource_Release(readback_buffers[i]);
|
|
|
|
ID3D12PipelineState_Release(pipeline_state);
|
|
ID3D12RootSignature_Release(root_signature);
|
|
ID3D12GraphicsCommandList_Release(list);
|
|
ID3D12CommandAllocator_Release(allocator);
|
|
ID3D12Fence_Release(fence);
|
|
#undef rand_r
|
|
}
|
|
|
|
void test_stress_fallback_render_target_allocation_device(void)
|
|
{
|
|
D3D12_RESOURCE_ALLOCATION_INFO alloc_info;
|
|
struct test_context context;
|
|
D3D12_HEAP_DESC heap_desc;
|
|
D3D12_RESOURCE_DESC desc;
|
|
ID3D12Resource *resource;
|
|
ID3D12Heap *heaps[1024];
|
|
unsigned int i;
|
|
HRESULT hr;
|
|
|
|
if (!init_compute_test_context(&context))
|
|
return;
|
|
|
|
/* Spam allocate enough that we should exhaust VRAM and require fallbacks to system memory.
|
|
* Verify that we don't collapse in such a situation.
|
|
* Render targets hit some particular edge cases on NV that we should focus on testing. */
|
|
|
|
memset(&desc, 0, sizeof(desc));
|
|
desc.Width = 2048;
|
|
desc.Height = 2048;
|
|
desc.DepthOrArraySize = 1;
|
|
desc.MipLevels = 1;
|
|
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
desc.SampleDesc.Count = 1;
|
|
|
|
alloc_info = ID3D12Device_GetResourceAllocationInfo(context.device, 0, 1, &desc);
|
|
|
|
memset(&heap_desc, 0, sizeof(heap_desc));
|
|
heap_desc.SizeInBytes = alloc_info.SizeInBytes;
|
|
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
|
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
memset(heaps, 0, sizeof(heaps));
|
|
|
|
for (i = 0; i < ARRAY_SIZE(heaps); i++)
|
|
{
|
|
hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void**)&heaps[i]);
|
|
ok(SUCCEEDED(hr), "Failed to create heap, hr #%x.\n", hr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = ID3D12Device_CreatePlacedResource(context.device, heaps[i], 0, &desc,
|
|
D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void**)&resource);
|
|
ok(SUCCEEDED(hr), "Failed to place resource, hr #%x.\n", hr);
|
|
if (SUCCEEDED(hr))
|
|
ID3D12Resource_Release(resource);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(heaps); i++)
|
|
if (heaps[i])
|
|
ID3D12Heap_Release(heaps[i]);
|
|
|
|
destroy_test_context(&context);
|
|
}
|
|
|
|
void test_stress_suballocation_rebar(void)
|
|
{
|
|
ID3D12Resource *resources_suballocate[4096];
|
|
ID3D12Resource *resources_direct[1024];
|
|
struct test_context context;
|
|
unsigned int i;
|
|
|
|
if (!init_compute_test_context(&context))
|
|
return;
|
|
|
|
/* Spam allocate enough that we should either exhaust small BAR, or our budget.
|
|
* Verify that we don't collapse in such a situation. */
|
|
|
|
for (i = 0; i < ARRAY_SIZE(resources_suballocate); i++)
|
|
{
|
|
resources_suballocate[i] = create_upload_buffer(context.device, 256 * 1024, NULL);
|
|
ok(!!resources_suballocate[i], "Failed to create buffer.\n");
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(resources_suballocate); i++)
|
|
if (resources_suballocate[i])
|
|
ID3D12Resource_Release(resources_suballocate[i]);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(resources_direct); i++)
|
|
{
|
|
resources_direct[i] = create_upload_buffer(context.device, 2 * 1024 * 1024, NULL);
|
|
ok(!!resources_direct[i], "Failed to create buffer.\n");
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(resources_direct); i++)
|
|
if (resources_direct[i])
|
|
ID3D12Resource_Release(resources_direct[i]);
|
|
|
|
destroy_test_context(&context);
|
|
}
|
|
|
|
void test_stress_suballocation(void)
|
|
{
|
|
struct suballocation_thread_data data;
|
|
struct test_context_desc desc;
|
|
struct test_context context;
|
|
|
|
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;
|
|
|
|
data.context = &context;
|
|
data.seed = 42;
|
|
test_stress_suballocation_thread(&data);
|
|
|
|
destroy_test_context(&context);
|
|
}
|
|
|
|
void test_stress_suballocation_multithread(void)
|
|
{
|
|
struct suballocation_thread_data data[8];
|
|
struct test_context_desc desc;
|
|
struct test_context context;
|
|
HANDLE threads[8];
|
|
unsigned int i;
|
|
|
|
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;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
data[i].context = &context;
|
|
data[i].seed = 42 + i;
|
|
threads[i] = create_thread(test_stress_suballocation_thread, &data[i]);
|
|
}
|
|
|
|
for (i = 0; i < 8; i++)
|
|
ok(join_thread(threads[i]), "Failed to join thread %u.\n", i);
|
|
|
|
destroy_test_context(&context);
|
|
}
|
|
|
|
void test_placed_image_alignment(void)
|
|
{
|
|
ID3D12Resource *readback_buffers[4096] = { NULL };
|
|
D3D12_TEXTURE_COPY_LOCATION copy_dst, copy_src;
|
|
D3D12_RESOURCE_ALLOCATION_INFO alloc_info;
|
|
D3D12_DESCRIPTOR_HEAP_DESC desc_heap_desc;
|
|
ID3D12Resource *images[4096] = { NULL };
|
|
D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle;
|
|
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc;
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
D3D12_RESOURCE_BARRIER barrier;
|
|
struct test_context_desc desc;
|
|
struct test_context context;
|
|
ID3D12DescriptorHeap *rtvs;
|
|
D3D12_HEAP_DESC heap_desc;
|
|
unsigned int i, j;
|
|
D3D12_BOX src_box;
|
|
ID3D12Heap *heap;
|
|
HRESULT hr;
|
|
|
|
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;
|
|
|
|
/* Verifies that we don't screw up when using GPUs which require > 64k alignment for RTs (Polaris and older).
|
|
* We verify this by ensuring we don't get any fake internal allocations.
|
|
* If we do, we will certainly OOM the GPU since we're placing ~64 GB worth of textures. */
|
|
|
|
memset(&resource_desc, 0, sizeof(resource_desc));
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
resource_desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
resource_desc.Width = 1024;
|
|
resource_desc.Height = 1024;
|
|
resource_desc.MipLevels = 1;
|
|
resource_desc.DepthOrArraySize = 1;
|
|
resource_desc.SampleDesc.Count = 1;
|
|
resource_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
alloc_info = ID3D12Device_GetResourceAllocationInfo(context.device, 0, 1, &resource_desc);
|
|
ok(alloc_info.Alignment <= D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT, "Requirement alignment %u is > 64KiB.\n", alloc_info.Alignment);
|
|
|
|
memset(&heap_desc, 0, sizeof(heap_desc));
|
|
heap_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
heap_desc.SizeInBytes = alloc_info.SizeInBytes + D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT * ARRAY_SIZE(images);
|
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
|
|
|
|
memset(&desc_heap_desc, 0, sizeof(desc_heap_desc));
|
|
desc_heap_desc.NumDescriptors = ARRAY_SIZE(images);
|
|
desc_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
|
hr = ID3D12Device_CreateDescriptorHeap(context.device, &desc_heap_desc, &IID_ID3D12DescriptorHeap, (void **)&rtvs);
|
|
ok(SUCCEEDED(hr), "Failed to create RTV heap.\n");
|
|
|
|
hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void **)&heap);
|
|
ok(SUCCEEDED(hr), "Failed to create heap.\n");
|
|
|
|
for (i = 0; i < ARRAY_SIZE(images); i++)
|
|
{
|
|
hr = ID3D12Device_CreatePlacedResource(context.device, heap, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT * i, &resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, &IID_ID3D12Resource, (void **)&images[i]);
|
|
ok(SUCCEEDED(hr), "Failed to create placed resource.\n");
|
|
|
|
cpu_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(rtvs);
|
|
cpu_handle.ptr += i * ID3D12Device_GetDescriptorHandleIncrementSize(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
|
|
|
memset(&rtv_desc, 0, sizeof(rtv_desc));
|
|
rtv_desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
|
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
|
ID3D12Device_CreateRenderTargetView(context.device, images[i], &rtv_desc, cpu_handle);
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(images); i++)
|
|
readback_buffers[i] = create_readback_buffer(context.device, 16);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(images); i++)
|
|
{
|
|
const FLOAT color[] = { i, i + 1, i + 2, i + 3 };
|
|
const RECT rect = { 0, 0, 1, 1 };
|
|
|
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_ALIASING;
|
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barrier.Aliasing.pResourceAfter = images[i];
|
|
barrier.Aliasing.pResourceBefore = NULL;
|
|
ID3D12GraphicsCommandList_ResourceBarrier(context.list, 1, &barrier);
|
|
ID3D12GraphicsCommandList_DiscardResource(context.list, images[i], NULL);
|
|
cpu_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(rtvs);
|
|
cpu_handle.ptr += i * ID3D12Device_GetDescriptorHandleIncrementSize(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
|
ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, cpu_handle, color, 1, &rect);
|
|
transition_resource_state(context.list, images[i], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
|
|
|
copy_dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
|
copy_dst.pResource = readback_buffers[i];
|
|
copy_dst.PlacedFootprint.Offset = 0;
|
|
copy_dst.PlacedFootprint.Footprint.Width = 1;
|
|
copy_dst.PlacedFootprint.Footprint.Height = 1;
|
|
copy_dst.PlacedFootprint.Footprint.Depth = 1;
|
|
copy_dst.PlacedFootprint.Footprint.RowPitch = 1024; /* Needs to be large on D3D12. Doesn't matter here. */
|
|
copy_dst.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
|
|
|
copy_src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
copy_src.SubresourceIndex = 0;
|
|
copy_src.pResource = images[i];
|
|
|
|
src_box.left = 0;
|
|
src_box.right = 1;
|
|
src_box.top = 0;
|
|
src_box.bottom = 1;
|
|
src_box.front = 0;
|
|
src_box.back = 1;
|
|
|
|
ID3D12GraphicsCommandList_CopyTextureRegion(context.list, ©_dst, 0, 0, 0, ©_src, &src_box);
|
|
}
|
|
|
|
ID3D12GraphicsCommandList_Close(context.list);
|
|
ID3D12CommandQueue_ExecuteCommandLists(context.queue, 1, (ID3D12CommandList *const *)&context.list);
|
|
wait_queue_idle(context.device, context.queue);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(readback_buffers); i++)
|
|
{
|
|
float *mapped = NULL;
|
|
hr = ID3D12Resource_Map(readback_buffers[i], 0, NULL, (void **)&mapped);
|
|
ok(SUCCEEDED(hr), "Failed to map buffer.\n");
|
|
if (mapped)
|
|
{
|
|
for (j = 0; j < 4; j++)
|
|
ok(mapped[j] == (float)(i + j), "Readback data for component %u is unxpected (%f != %f).\n", j, mapped[j], (float)(i + j));
|
|
ID3D12Resource_Unmap(readback_buffers[i], 0, NULL);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(images); i++)
|
|
{
|
|
ID3D12Resource_Release(images[i]);
|
|
ID3D12Resource_Release(readback_buffers[i]);
|
|
}
|
|
ID3D12DescriptorHeap_Release(rtvs);
|
|
ID3D12Heap_Release(heap);
|
|
destroy_test_context(&context);
|
|
}
|
|
|
|
void test_map_texture_validation(void)
|
|
{
|
|
D3D12_RESOURCE_ALLOCATION_INFO alloc_info;
|
|
D3D12_HEAP_PROPERTIES heap_props;
|
|
struct test_context context;
|
|
D3D12_HEAP_DESC heap_desc;
|
|
bool todo_host_visible_rt;
|
|
D3D12_RESOURCE_DESC desc;
|
|
ID3D12Resource *resource;
|
|
ID3D12Device *device;
|
|
ID3D12Heap *heap;
|
|
void *mapped_ptr;
|
|
unsigned int i;
|
|
HRESULT hr;
|
|
|
|
struct test
|
|
{
|
|
D3D12_HEAP_FLAGS heap_flags;
|
|
D3D12_TEXTURE_LAYOUT layout;
|
|
D3D12_RESOURCE_DIMENSION dimension;
|
|
UINT mip_levels;
|
|
UINT depth_or_array_size;
|
|
D3D12_RESOURCE_FLAGS flags;
|
|
D3D12_CPU_PAGE_PROPERTY page_property;
|
|
HRESULT heap_creation_hr;
|
|
HRESULT creation_hr;
|
|
HRESULT map_hr_with_ppdata;
|
|
HRESULT map_hr_without_ppdata;
|
|
bool custom_heap;
|
|
bool is_todo;
|
|
};
|
|
|
|
/* Various weird cases all come together to make mapping ROW_MAJOR textures impossible in D3D12. */
|
|
static const struct test tests[] =
|
|
{
|
|
/* MipLevel 2 not allowed. */
|
|
{ D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER | D3D12_HEAP_FLAG_SHARED,
|
|
D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
|
2, 1, D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER,
|
|
D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
|
|
E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, true },
|
|
|
|
/* LayerCount 2 not allowed. */
|
|
{ D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER | D3D12_HEAP_FLAG_SHARED,
|
|
D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
|
1, 2, D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER,
|
|
D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
|
|
E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, true },
|
|
|
|
/* Need SHARED resource flag. */
|
|
{ D3D12_HEAP_FLAG_NONE,
|
|
D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
|
1, 1, D3D12_RESOURCE_FLAG_NONE,
|
|
D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
|
|
S_OK, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, true },
|
|
|
|
/* WRITE_BACK not allowed. */
|
|
{ D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER | D3D12_HEAP_FLAG_SHARED,
|
|
D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
|
1, 1, D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER,
|
|
D3D12_CPU_PAGE_PROPERTY_WRITE_BACK,
|
|
E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, true },
|
|
|
|
/* OK, but cannot map. */
|
|
{ D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER | D3D12_HEAP_FLAG_SHARED,
|
|
D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
|
1, 1, D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER,
|
|
D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
|
|
S_OK, S_OK, E_INVALIDARG, E_INVALIDARG, true, true },
|
|
|
|
/* 1D texture not allowed. */
|
|
{ D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER | D3D12_HEAP_FLAG_SHARED,
|
|
D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE1D,
|
|
1, 1, D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER,
|
|
D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
|
|
S_OK, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, true },
|
|
|
|
/* 3D texture not allowed. */
|
|
{ D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER | D3D12_HEAP_FLAG_SHARED,
|
|
D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE3D,
|
|
1, 1, D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER,
|
|
D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
|
|
S_OK, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, true },
|
|
|
|
/* UPLOAD heap not allowed. */
|
|
{ D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER | D3D12_HEAP_FLAG_SHARED,
|
|
D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
|
1, 1, D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER,
|
|
D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
|
E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, false },
|
|
|
|
/* UPLOAD heap not allowed. */
|
|
{ D3D12_HEAP_FLAG_NONE,
|
|
D3D12_TEXTURE_LAYOUT_UNKNOWN,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
|
2, 2, D3D12_RESOURCE_FLAG_NONE,
|
|
D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
|
S_OK, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, false },
|
|
|
|
/* Allowed, but cannot get concrete pointer.
|
|
* TODO: 1D linear not supported in general. */
|
|
{ D3D12_HEAP_FLAG_NONE,
|
|
D3D12_TEXTURE_LAYOUT_UNKNOWN,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE1D,
|
|
1, 1, D3D12_RESOURCE_FLAG_NONE,
|
|
D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE,
|
|
S_OK, S_OK, E_INVALIDARG, S_OK, true, true },
|
|
|
|
/* Allowed, but cannot get concrete pointer. */
|
|
{ D3D12_HEAP_FLAG_NONE,
|
|
D3D12_TEXTURE_LAYOUT_UNKNOWN,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
|
1, 1, D3D12_RESOURCE_FLAG_NONE,
|
|
D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE,
|
|
S_OK, S_OK, E_INVALIDARG, S_OK, true, true },
|
|
|
|
/* Allowed, but cannot get concrete pointer.
|
|
* TODO: Mipmapped linear not supported in general. */
|
|
{ D3D12_HEAP_FLAG_NONE,
|
|
D3D12_TEXTURE_LAYOUT_UNKNOWN,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
|
2, 2, D3D12_RESOURCE_FLAG_NONE,
|
|
D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE,
|
|
S_OK, S_OK, E_INVALIDARG, S_OK, true, true },
|
|
|
|
/* Allowed, but cannot map 3D with mip levels > 1.
|
|
* TODO: 3D linear not supported in general. */
|
|
{ D3D12_HEAP_FLAG_NONE,
|
|
D3D12_TEXTURE_LAYOUT_UNKNOWN,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE3D,
|
|
2, 2, D3D12_RESOURCE_FLAG_NONE,
|
|
D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE,
|
|
S_OK, S_OK, E_INVALIDARG, E_INVALIDARG, true, true },
|
|
|
|
/* Allowed.
|
|
* TODO: 3D linear not supported in general. */
|
|
{ D3D12_HEAP_FLAG_NONE,
|
|
D3D12_TEXTURE_LAYOUT_UNKNOWN,
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE3D,
|
|
1, 2, D3D12_RESOURCE_FLAG_NONE,
|
|
D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE,
|
|
S_OK, S_OK, E_INVALIDARG, S_OK, true, true },
|
|
};
|
|
|
|
if (!init_compute_test_context(&context))
|
|
return;
|
|
|
|
device = context.device;
|
|
|
|
memset(&desc, 0, sizeof(desc));
|
|
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
desc.Width = 64;
|
|
desc.Height = 1;
|
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
desc.SampleDesc.Count = 1;
|
|
|
|
memset(&heap_props, 0, sizeof(heap_props));
|
|
heap_props.Type = D3D12_HEAP_TYPE_CUSTOM;
|
|
heap_props.MemoryPoolPreference = D3D12_MEMORY_POOL_L0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(tests); i++)
|
|
{
|
|
vkd3d_test_set_context("Test %u", i);
|
|
heap_props.CPUPageProperty = tests[i].page_property;
|
|
desc.MipLevels = tests[i].mip_levels;
|
|
desc.DepthOrArraySize = tests[i].depth_or_array_size;
|
|
desc.Flags = tests[i].flags;
|
|
desc.Layout = tests[i].layout;
|
|
desc.Dimension = tests[i].dimension;
|
|
|
|
if (tests[i].custom_heap)
|
|
{
|
|
heap_props.Type = D3D12_HEAP_TYPE_CUSTOM;
|
|
heap_props.MemoryPoolPreference = D3D12_MEMORY_POOL_L0;
|
|
}
|
|
else
|
|
{
|
|
heap_props.Type = D3D12_HEAP_TYPE_UPLOAD;
|
|
heap_props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
}
|
|
|
|
alloc_info = ID3D12Device_GetResourceAllocationInfo(device, 0, 1, &desc);
|
|
|
|
if (alloc_info.SizeInBytes != UINT64_MAX)
|
|
{
|
|
memset(&heap_desc, 0, sizeof(heap_desc));
|
|
heap_desc.Properties = heap_props;
|
|
heap_desc.Flags = tests[i].heap_flags;
|
|
|
|
/* According to docs (https://docs.microsoft.com/en-us/windows/win32/direct3d12/shared-heaps),
|
|
* with SHARED_CROSS_ADAPTER, a heap must be created with ALLOW_ALL_BUFFERS_AND_TEXTURES.
|
|
* Unsure if this particular case requires HEAP_TIER_2? */
|
|
if (!(heap_desc.Flags & D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER))
|
|
heap_desc.Flags |= D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
|
|
heap_desc.SizeInBytes = alloc_info.SizeInBytes;
|
|
hr = ID3D12Device_CreateHeap(device, &heap_desc, &IID_ID3D12Heap, (void**)&heap);
|
|
|
|
/* We cannot successfully create host visible linear RT on all implementations. */
|
|
todo_host_visible_rt = !(heap_desc.Flags & D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES) &&
|
|
heap_desc.Properties.CPUPageProperty != D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE;
|
|
todo_if(tests[i].is_todo || todo_host_visible_rt)
|
|
ok(hr == tests[i].heap_creation_hr, "Unexpected hr %#x.\n", hr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = ID3D12Device_CreatePlacedResource(device, heap, 0, &desc, D3D12_RESOURCE_STATE_GENERIC_READ,
|
|
NULL, &IID_ID3D12Resource, (void**)&resource);
|
|
todo_if(tests[i].is_todo) ok(hr == tests[i].creation_hr, "Unexpected hr %#x.\n", hr);
|
|
if (SUCCEEDED(hr))
|
|
ID3D12Resource_Release(resource);
|
|
ID3D12Heap_Release(heap);
|
|
}
|
|
}
|
|
|
|
hr = ID3D12Device_CreateCommittedResource(device, &heap_props, tests[i].heap_flags,
|
|
&desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &IID_ID3D12Resource,
|
|
(void**)&resource);
|
|
todo_if(tests[i].is_todo) ok(hr == tests[i].creation_hr, "Unexpected hr %#x.\n", hr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = ID3D12Resource_Map(resource, 0, NULL, &mapped_ptr);
|
|
ok(hr == tests[i].map_hr_with_ppdata, "Unexpected hr %#x.\n", hr);
|
|
if (SUCCEEDED(hr))
|
|
ID3D12Resource_Unmap(resource, 0, NULL);
|
|
|
|
hr = ID3D12Resource_Map(resource, 0, NULL, NULL);
|
|
ok(hr == tests[i].map_hr_without_ppdata, "Unexpected hr %#x.\n", hr);
|
|
if (SUCCEEDED(hr))
|
|
ID3D12Resource_Unmap(resource, 0, NULL);
|
|
ID3D12Resource_Release(resource);
|
|
}
|
|
}
|
|
vkd3d_test_set_context(NULL);
|
|
destroy_test_context(&context);
|
|
}
|
|
|
|
void test_aliasing_barrier_edge_cases(void)
|
|
{
|
|
const FLOAT color[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
|
|
D3D12_RESOURCE_ALLOCATION_INFO alloc_info;
|
|
D3D12_CPU_DESCRIPTOR_HANDLE rtv[3];
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
D3D12_RESOURCE_BARRIER barrier;
|
|
struct test_context_desc desc;
|
|
ID3D12Resource *resources[3];
|
|
struct test_context context;
|
|
ID3D12DescriptorHeap *rtvs;
|
|
D3D12_HEAP_DESC heap_desc;
|
|
ID3D12Heap *heap;
|
|
unsigned int i;
|
|
HRESULT hr;
|
|
|
|
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(&resource_desc, 0, sizeof(resource_desc));
|
|
resource_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
resource_desc.Width = 2048;
|
|
resource_desc.Height = 2048;
|
|
resource_desc.DepthOrArraySize = 1;
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
resource_desc.SampleDesc.Count = 1;
|
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
resource_desc.MipLevels = 1;
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
|
|
alloc_info = ID3D12Device_GetResourceAllocationInfo(context.device, 0, 1, &resource_desc);
|
|
|
|
memset(&heap_desc, 0, sizeof(heap_desc));
|
|
heap_desc.SizeInBytes = alloc_info.SizeInBytes;
|
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
|
|
hr = ID3D12Device_CreateHeap(context.device, &heap_desc, &IID_ID3D12Heap, (void**)&heap);
|
|
ok(SUCCEEDED(hr), "Failed to create heap, hr #%x.\n", hr);
|
|
|
|
rtvs = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, ARRAY_SIZE(resources));
|
|
for (i = 0; i < ARRAY_SIZE(resources); i++)
|
|
{
|
|
D3D12_CPU_DESCRIPTOR_HANDLE h = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(rtvs);
|
|
h.ptr += i * ID3D12Device_GetDescriptorHandleIncrementSize(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
|
hr = ID3D12Device_CreatePlacedResource(context.device, heap, 0, &resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET,
|
|
NULL, &IID_ID3D12Resource, (void**)&resources[i]);
|
|
ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);
|
|
ID3D12Device_CreateRenderTargetView(context.device, resources[i], NULL, h);
|
|
rtv[i] = h;
|
|
}
|
|
|
|
/* D3D12 validation does not complain about any of this, and it works on native drivers, somehow ...
|
|
* It's somewhat clear from this that aliasing barrier on its own should not modify any image layout,
|
|
* we should only consider global memory barriers here. */
|
|
ID3D12GraphicsCommandList_ClearRenderTargetView(context.list, rtv[0], color, 0, NULL);
|
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_ALIASING;
|
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barrier.Aliasing.pResourceBefore = resources[2];
|
|
barrier.Aliasing.pResourceAfter = resources[1];
|
|
ID3D12GraphicsCommandList_ResourceBarrier(context.list, 1, &barrier);
|
|
transition_resource_state(context.list, resources[0], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
|
check_sub_resource_uint(resources[0], 0, context.queue, context.list, 0x00ff0000, 0);
|
|
|
|
ID3D12DescriptorHeap_Release(rtvs);
|
|
for (i = 0; i < ARRAY_SIZE(resources); i++)
|
|
ID3D12Resource_Release(resources[i]);
|
|
ID3D12Heap_Release(heap);
|
|
|
|
destroy_test_context(&context);
|
|
}
|