diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index cb2edd14..463f373b 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -1041,6 +1041,33 @@ bool d3d12_resource_is_cpu_accessible(const struct d3d12_resource *resource) return resource->heap && is_cpu_accessible_heap(&resource->heap->desc.Properties); } +static bool d3d12_resource_validate_box(const struct d3d12_resource *resource, + unsigned int sub_resource_idx, const D3D12_BOX *box) +{ + unsigned int mip_level = sub_resource_idx % resource->desc.MipLevels; + struct d3d12_device *device = resource->device; + const struct vkd3d_format *vkd3d_format; + uint32_t width_mask, height_mask; + uint64_t width, height, depth; + + width = d3d12_resource_desc_get_width(&resource->desc, mip_level); + height = d3d12_resource_desc_get_height(&resource->desc, mip_level); + depth = d3d12_resource_desc_get_depth(&resource->desc, mip_level); + + vkd3d_format = vkd3d_format_from_d3d12_resource_desc(device, &resource->desc, 0); + assert(vkd3d_format); + width_mask = vkd3d_format->block_width - 1; + height_mask = vkd3d_format->block_height - 1; + + return box->left <= width && box->right <= width + && box->top <= height && box->bottom <= height + && box->front <= depth && box->back <= depth + && !(box->left & width_mask) + && !(box->right & width_mask) + && !(box->top & height_mask) + && !(box->bottom & height_mask); +} + /* ID3D12Resource */ static inline struct d3d12_resource *impl_from_ID3D12Resource(ID3D12Resource *iface) { @@ -1282,8 +1309,8 @@ static HRESULT STDMETHODCALLTYPE d3d12_resource_ReadFromSubresource(ID3D12Resour HRESULT hr; TRACE("iface %p, dst_data %p, dst_row_pitch %u, dst_slice_pitch %u, " - "src_sub_resource %u, src_box %p.\n", - iface, dst_data, dst_row_pitch, dst_slice_pitch, src_sub_resource, src_box); + "src_sub_resource %u, src_box %s.\n", + iface, dst_data, dst_row_pitch, dst_slice_pitch, src_sub_resource, debug_d3d12_box(src_box)); if (d3d12_resource_is_buffer(resource)) { @@ -1311,6 +1338,12 @@ static HRESULT STDMETHODCALLTYPE d3d12_resource_ReadFromSubresource(ID3D12Resour if (src_box) { + if (!d3d12_resource_validate_box(resource, src_sub_resource, src_box)) + { + WARN("Invalid box %s.\n", debug_d3d12_box(src_box)); + return E_INVALIDARG; + } + box = *src_box; } else @@ -1323,7 +1356,10 @@ static HRESULT STDMETHODCALLTYPE d3d12_resource_ReadFromSubresource(ID3D12Resour box.back = d3d12_resource_desc_get_depth(&resource->desc, vk_sub_resource.mipLevel); } if (box.right <= box.left || box.bottom <= box.top || box.back <= box.front) + { + WARN("Empty box %s.\n", debug_d3d12_box(src_box)); return S_OK; + } if (!d3d12_resource_is_cpu_accessible(resource)) { diff --git a/tests/d3d12.c b/tests/d3d12.c index cc7113ad..39cbc9e6 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -30465,6 +30465,19 @@ static void test_read_write_subresource(void) 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); todo ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); @@ -30474,6 +30487,10 @@ static void test_read_write_subresource(void) 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); todo ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); @@ -30625,7 +30642,51 @@ static void test_read_write_subresource(void) ID3D12Resource_Release(src_texture); ID3D12Resource_Release(dst_texture); - reset_command_list(command_list, context.allocator); + + /* 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);