diff --git a/configure.ac b/configure.ac index 27c03a6c..d13b4407 100644 --- a/configure.ac +++ b/configure.ac @@ -79,6 +79,7 @@ AS_IF([test "x$with_spirv_tools" = "xyes"], PKG_CHECK_MODULES([XCB], [xcb xcb-keysyms]) dnl Check for functions +VKD3D_CHECK_BUILTIN_CLZ VKD3D_CHECK_BUILTIN_POPCOUNT VKD3D_CHECK_SYNC_ADD_AND_FETCH_FUNC VKD3D_CHECK_SYNC_SUB_AND_FETCH_FUNC diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h index ce8f32e1..2e3873b8 100644 --- a/include/private/vkd3d_common.h +++ b/include/private/vkd3d_common.h @@ -50,6 +50,38 @@ static inline unsigned int vkd3d_popcount(unsigned int v) #endif } +/* Undefined for x == 0. */ +static inline unsigned int vkd3d_log2i(unsigned int x) +{ +#ifdef HAVE_BUILTIN_CLZ + return __builtin_clz(x) ^ 0x1f; +#else + static const unsigned int l[] = + { + ~0u, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + }; + unsigned int i; + + return (i = x >> 16) ? (x = i >> 8) ? l[x] + 24 + : l[i] + 16 : (i = x >> 8) ? l[i] + 8 : l[x]; +#endif +} + #ifndef _WIN32 # if HAVE_SYNC_ADD_AND_FETCH static inline LONG InterlockedIncrement(LONG volatile *x) diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index 72848a44..264578bd 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -103,14 +103,16 @@ HRESULT vkd3d_create_buffer(struct d3d12_device *device, } static HRESULT vkd3d_create_image(struct d3d12_resource *resource, struct d3d12_device *device, - const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags, - const D3D12_RESOURCE_DESC *desc) + const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; const struct vkd3d_format *format; + const D3D12_RESOURCE_DESC *desc; VkImageCreateInfo image_info; VkResult vr; + desc = &resource->desc; + if (!(format = vkd3d_format_from_d3d12_resource_desc(desc, 0))) { WARN("Invalid DXGI format %#x.\n", desc->Format); @@ -606,6 +608,30 @@ struct d3d12_resource *unsafe_impl_from_ID3D12Resource(ID3D12Resource *iface) return impl_from_ID3D12Resource(iface); } +static HRESULT validate_buffer_desc(const D3D12_RESOURCE_DESC *desc) +{ + if (desc->MipLevels != 1) + { + WARN("Invalid miplevel count %u for buffer.\n", desc->MipLevels); + return E_INVALIDARG; + } + + return S_OK; +} + +static HRESULT validate_texture_desc(D3D12_RESOURCE_DESC *desc) +{ + if (!desc->MipLevels) + { + unsigned int size = max(desc->Width, desc->Height); + if (desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) + size = max(size, desc->DepthOrArraySize); + desc->MipLevels = vkd3d_log2i(size) + 1; + } + + return S_OK; +} + static HRESULT d3d12_committed_resource_init(struct d3d12_resource *resource, struct d3d12_device *device, const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags, const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state, @@ -658,8 +684,10 @@ static HRESULT d3d12_committed_resource_init(struct d3d12_resource *resource, st switch (desc->Dimension) { case D3D12_RESOURCE_DIMENSION_BUFFER: - if (FAILED(hr = vkd3d_create_buffer(device, heap_properties, heap_flags, desc, - &resource->u.vk_buffer))) + if (FAILED(hr = validate_buffer_desc(&resource->desc))) + return hr; + if (FAILED(hr = vkd3d_create_buffer(device, heap_properties, heap_flags, + &resource->desc, &resource->u.vk_buffer))) return hr; if (!(resource->gpu_address = vkd3d_gpu_va_allocator_allocate(&device->gpu_va_allocator, desc->Width, resource))) @@ -679,8 +707,10 @@ static HRESULT d3d12_committed_resource_init(struct d3d12_resource *resource, st case D3D12_RESOURCE_DIMENSION_TEXTURE1D: case D3D12_RESOURCE_DIMENSION_TEXTURE2D: case D3D12_RESOURCE_DIMENSION_TEXTURE3D: + if (FAILED(hr = validate_texture_desc(&resource->desc))) + return hr; resource->flags |= VKD3D_RESOURCE_INITIAL_STATE_TRANSITION; - if (FAILED(hr = vkd3d_create_image(resource, device, heap_properties, heap_flags, desc))) + if (FAILED(hr = vkd3d_create_image(resource, device, heap_properties, heap_flags))) return hr; if (FAILED(hr = vkd3d_allocate_image_memory(resource, device, heap_properties, heap_flags))) { diff --git a/m4/check-builtin-functions.m4 b/m4/check-builtin-functions.m4 index c09eb474..2b24a802 100644 --- a/m4/check-builtin-functions.m4 +++ b/m4/check-builtin-functions.m4 @@ -18,6 +18,16 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([int main(void) { return __sync_sub_and_fetch((in [Define to 1 if you have __sync_sub_and_fetch.])], [AC_MSG_RESULT([no])])]) +dnl VKD3D_CHECK_BUILTIN_CLZ +AC_DEFUN([VKD3D_CHECK_BUILTIN_CLZ], +[AC_MSG_CHECKING([for __builtin_clz]) +AC_LINK_IFELSE([AC_LANG_SOURCE([int main(void) { return __builtin_clz(0); }])], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_BUILTIN_CLZ], + [1], + [Define to 1 if you have __builtin_clz.])], + [AC_MSG_RESULT([no])])]) + dnl VKD3D_CHECK_BUILTIN_POPCOUNT AC_DEFUN([VKD3D_CHECK_BUILTIN_POPCOUNT], [AC_MSG_CHECKING([for __builtin_popcount]) diff --git a/tests/d3d12.c b/tests/d3d12.c index dfc9257b..55116204 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -2213,6 +2213,24 @@ static void test_create_committed_resource(void) 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(SUCCEEDED(hr), "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(SUCCEEDED(hr), "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; + 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); @@ -2291,6 +2309,13 @@ static void test_create_committed_resource(void) 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,