From: Conor McCarthy cmccarthy@codeweavers.com
Signed-off-by: Józef Kucia jkucia@codeweavers.com --- This supersedes patch 168255.
Version 2: * Use correct width and height when src_box is NULL and miplevel != 0. * Return E_NOTIMPL when image aspect != VK_IMAGE_ASPECT_COLOR_BIT (image aspect must be one bit for vkGetImageSubresourceLayout(), also the code is not tested with depth-stencil images). * Minor simplifications and cosmetic changes. * Add todo_if() for Nvidia. --- libs/vkd3d/resource.c | 99 ++++++++++++++++++++++++++++++++++++++++--- tests/d3d12.c | 13 +++--- 2 files changed, 102 insertions(+), 10 deletions(-)
diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index 0842859f12d1..cb2edd1439cf 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -1269,12 +1269,101 @@ static HRESULT STDMETHODCALLTYPE d3d12_resource_ReadFromSubresource(ID3D12Resour void *dst_data, UINT dst_row_pitch, UINT dst_slice_pitch, UINT src_sub_resource, const D3D12_BOX *src_box) { - FIXME("iface %p, dst_data %p, dst_row_pitch %u, dst_slice_pitch %u, " - "src_sub_resource %u, src_box %p stub!\n", - iface, dst_data, dst_row_pitch, dst_slice_pitch, - src_sub_resource, src_box); + struct d3d12_resource *resource = impl_from_ID3D12Resource(iface); + const struct vkd3d_vk_device_procs *vk_procs; + VkImageSubresource vk_sub_resource; + const struct vkd3d_format *format; + VkSubresourceLayout vk_layout; + struct d3d12_device *device; + BYTE *src_data, *src, *dst; + unsigned int y, z; + D3D12_BOX box; + size_t size; + HRESULT hr;
- return E_NOTIMPL; + 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); + + if (d3d12_resource_is_buffer(resource)) + { + WARN("Buffers are not supported.\n"); + return E_INVALIDARG; + } + + device = resource->device; + vk_procs = &device->vk_procs; + + if (!(format = vkd3d_format_from_d3d12_resource_desc(device, &resource->desc, 0))) + { + ERR("Invalid DXGI format %#x.\n", resource->desc.Format); + return E_INVALIDARG; + } + if (format->vk_aspect_mask != VK_IMAGE_ASPECT_COLOR_BIT) + { + FIXME("Not supported for format %#x.\n", format->dxgi_format); + return E_NOTIMPL; + } + + vk_sub_resource.arrayLayer = src_sub_resource / resource->desc.MipLevels; + vk_sub_resource.mipLevel = src_sub_resource % resource->desc.MipLevels; + vk_sub_resource.aspectMask = format->vk_aspect_mask; + + if (src_box) + { + box = *src_box; + } + else + { + box.left = 0; + box.top = 0; + box.front = 0; + box.right = d3d12_resource_desc_get_width(&resource->desc, vk_sub_resource.mipLevel); + box.bottom = d3d12_resource_desc_get_height(&resource->desc, vk_sub_resource.mipLevel); + 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) + return S_OK; + + if (!d3d12_resource_is_cpu_accessible(resource)) + { + FIXME_ONCE("Not implemented for this resource type.\n"); + return E_NOTIMPL; + } + if (!(resource->flags & VKD3D_RESOURCE_LINEAR_TILING)) + { + FIXME_ONCE("Not implemented for image tiling other than VK_IMAGE_TILING_LINEAR.\n"); + return E_NOTIMPL; + } + + VK_CALL(vkGetImageSubresourceLayout(device->vk_device, resource->u.vk_image, &vk_sub_resource, &vk_layout)); + TRACE("Offset %#"PRIx64", size %#"PRIx64", row pitch %#"PRIx64", depth pitch %#"PRIx64".\n", + vk_layout.offset, vk_layout.size, vk_layout.rowPitch, vk_layout.depthPitch); + + if (FAILED(hr = d3d12_heap_map(resource->heap, resource->heap_offset, resource, (void **)&src_data))) + { + WARN("Failed to map resource %p, hr %#x.\n", resource, hr); + return hr; + } + + src_data += vk_layout.offset; + src_data += box.left / format->block_width * format->byte_count * format->block_byte_count; + size = (box.right - box.left) / format->block_width * format->byte_count * format->block_byte_count; + for (z = box.front; z < box.back; ++z) + { + dst = dst_data + (z - box.front) * dst_slice_pitch; + src = src_data + z * vk_layout.depthPitch + box.top / format->block_height * vk_layout.rowPitch; + for (y = box.top; y < box.bottom; y += format->block_height) + { + memcpy(dst, src, size); + dst += dst_row_pitch; + src += vk_layout.rowPitch; + } + } + + d3d12_heap_unmap(resource->heap, resource); + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d3d12_resource_GetHeapProperties(ID3D12Resource *iface, diff --git a/tests/d3d12.c b/tests/d3d12.c index 95eb90d89438..63375b0078c8 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -30434,7 +30434,7 @@ static void test_read_write_subresource(void) todo ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
hr = ID3D12Resource_ReadFromSubresource(rb_buffer, dst_buffer, row_pitch, slice_pitch, 0, &box); - todo ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
ID3D12Resource_Release(rb_buffer);
@@ -30468,7 +30468,8 @@ static void test_read_write_subresource(void) todo ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, NULL); - todo ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + todo_if(is_nvidia_device(device)) + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
/* Empty box */ set_box(&box, 0, 0, 0, 0, 0, 0); @@ -30476,7 +30477,7 @@ static void test_read_write_subresource(void) todo ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
hr = ID3D12Resource_ReadFromSubresource(src_texture, dst_buffer, row_pitch, slice_pitch, 0, &box); - todo ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
for (z = 0; z < 64; ++z) { @@ -30511,13 +30512,15 @@ static void test_read_write_subresource(void) /* 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 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + 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 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + todo_if(is_nvidia_device(device)) + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
for (z = 0; z < 64; ++z) {