diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 05e2a8a4..83f804ad 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -78,14 +78,13 @@ enum parse_state STATE_PREPROC, STATE_PREPROC_INVALID, STATE_REQUIRE, + STATE_RESOURCE, STATE_SAMPLER, STATE_SHADER_INVALID_PIXEL, STATE_SHADER_INVALID_PIXEL_TODO, STATE_SHADER_PIXEL, STATE_SHADER_VERTEX, - STATE_TEXTURE, STATE_TEST, - STATE_VERTEX_BUFFER, }; static bool match_string(const char *line, const char *token, const char **const rest) @@ -314,6 +313,13 @@ static void parse_input_layout_directive(struct shader_runner *runner, const cha element->index = 0; } +void init_resource(struct resource *resource, const struct resource_params *params) +{ + resource->type = params->type; + resource->slot = params->slot; + resource->size = params->data_size; +} + static void set_resource(struct shader_runner *runner, struct resource *resource) { size_t i; @@ -617,8 +623,7 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const goto out; break; - case STATE_TEXTURE: - case STATE_VERTEX_BUFFER: + case STATE_RESOURCE: set_resource(runner, runner->ops->create_resource(runner, ¤t_resource)); free(current_resource.data); break; @@ -766,7 +771,7 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const } else if (sscanf(line, "[texture %u]\n", &index)) { - state = STATE_TEXTURE; + state = STATE_RESOURCE; memset(¤t_resource, 0, sizeof(current_resource)); @@ -776,9 +781,21 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const current_resource.data_type = TEXTURE_DATA_FLOAT; current_resource.texel_size = 16; } + else if (sscanf(line, "[uav %u]\n", &index)) + { + state = STATE_RESOURCE; + + memset(¤t_resource, 0, sizeof(current_resource)); + + current_resource.slot = index; + current_resource.type = RESOURCE_TYPE_UAV; + current_resource.format = DXGI_FORMAT_R32G32B32A32_FLOAT; + current_resource.data_type = TEXTURE_DATA_FLOAT; + current_resource.texel_size = 16; + } else if (sscanf(line, "[vertex buffer %u]\n", &index)) { - state = STATE_VERTEX_BUFFER; + state = STATE_RESOURCE; memset(¤t_resource, 0, sizeof(current_resource)); @@ -844,13 +861,12 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const parse_require_directive(runner, line); break; - case STATE_SAMPLER: - parse_sampler_directive(current_sampler, line); + case STATE_RESOURCE: + parse_resource_directive(¤t_resource, line); break; - case STATE_TEXTURE: - case STATE_VERTEX_BUFFER: - parse_resource_directive(¤t_resource, line); + case STATE_SAMPLER: + parse_sampler_directive(current_sampler, line); break; case STATE_TEST: diff --git a/tests/shader_runner.h b/tests/shader_runner.h index 6ed0109e..60f89458 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -54,6 +54,7 @@ struct sampler enum resource_type { RESOURCE_TYPE_TEXTURE, + RESOURCE_TYPE_UAV, RESOURCE_TYPE_VERTEX_BUFFER, }; @@ -130,6 +131,7 @@ struct shader_runner_ops void fatal_error(const char *format, ...) VKD3D_NORETURN VKD3D_PRINTF_FUNC(1, 2); unsigned int get_vb_stride(const struct shader_runner *runner, unsigned int slot); +void init_resource(struct resource *resource, const struct resource_params *params); void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const struct shader_runner_ops *ops); diff --git a/tests/shader_runner_d3d11.c b/tests/shader_runner_d3d11.c index 6edbdf75..b80a8b65 100644 --- a/tests/shader_runner_d3d11.c +++ b/tests/shader_runner_d3d11.c @@ -44,6 +44,7 @@ struct d3d11_resource ID3D11Resource *resource; ID3D11ShaderResourceView *srv; + ID3D11UnorderedAccessView *uav; }; static struct d3d11_resource *d3d11_resource(struct resource *r) @@ -374,13 +375,12 @@ static struct resource *d3d11_runner_create_resource(struct shader_runner *r, co HRESULT hr; resource = calloc(1, sizeof(*resource)); - - resource->r.slot = params->slot; - resource->r.type = params->type; + init_resource(&resource->r, params); switch (params->type) { case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_UAV: { D3D11_TEXTURE2D_DESC desc = {0}; @@ -391,7 +391,10 @@ static struct resource *d3d11_runner_create_resource(struct shader_runner *r, co desc.Format = params->format; desc.SampleDesc.Count = 1; desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + if (params->type == RESOURCE_TYPE_UAV) + desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; + else + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; resource_data.pSysMem = params->data; resource_data.SysMemPitch = params->width * params->texel_size; @@ -399,8 +402,11 @@ static struct resource *d3d11_runner_create_resource(struct shader_runner *r, co hr = ID3D11Device_CreateTexture2D(device, &desc, &resource_data, (ID3D11Texture2D **)&resource->resource); ok(hr == S_OK, "Failed to create texture, hr %#lx.\n", hr); - hr = ID3D11Device_CreateShaderResourceView(device, resource->resource, NULL, &resource->srv); - ok(hr == S_OK, "Failed to create shader resource view, hr %#lx.\n", hr); + if (params->type == RESOURCE_TYPE_UAV) + hr = ID3D11Device_CreateUnorderedAccessView(device, resource->resource, NULL, &resource->uav); + else + hr = ID3D11Device_CreateShaderResourceView(device, resource->resource, NULL, &resource->srv); + ok(hr == S_OK, "Failed to create view, hr %#lx.\n", hr); break; } @@ -420,14 +426,18 @@ static void d3d11_runner_destroy_resource(struct shader_runner *r, struct resour ID3D11Resource_Release(resource->resource); if (resource->srv) ID3D11ShaderResourceView_Release(resource->srv); + if (resource->uav) + ID3D11UnorderedAccessView_Release(resource->uav); free(resource); } static bool d3d11_runner_draw(struct shader_runner *r, D3D_PRIMITIVE_TOPOLOGY primitive_topology, unsigned int vertex_count) { + ID3D11UnorderedAccessView *uavs[D3D11_PS_CS_UAV_REGISTER_COUNT] = {0}; struct d3d11_shader_runner *runner = d3d11_shader_runner(r); ID3D11DeviceContext *context = runner->immediate_context; + unsigned int min_uav_slot = ARRAY_SIZE(uavs); ID3D11Device *device = runner->device; ID3D10Blob *vs_code, *ps_code; ID3D11Buffer *cb = NULL; @@ -472,6 +482,11 @@ static bool d3d11_runner_draw(struct shader_runner *r, ID3D11DeviceContext_PSSetShaderResources(context, resource->r.slot, 1, &resource->srv); break; + case RESOURCE_TYPE_UAV: + uavs[resource->r.slot] = resource->uav; + min_uav_slot = min(min_uav_slot, resource->r.slot); + break; + case RESOURCE_TYPE_VERTEX_BUFFER: ID3D11DeviceContext_IASetVertexBuffers(context, resource->r.slot, 1, (ID3D11Buffer **)&resource->resource, &stride, &offset); @@ -479,6 +494,10 @@ static bool d3d11_runner_draw(struct shader_runner *r, } } + ID3D11DeviceContext_OMSetRenderTargetsAndUnorderedAccessViews(context, + D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, NULL, NULL, + min_uav_slot, ARRAY_SIZE(uavs) - min_uav_slot, &uavs[min_uav_slot], NULL); + for (i = 0; i < runner->r.sampler_count; ++i) { struct sampler *sampler = &runner->r.samplers[i]; diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index 22c9b226..ec08fea5 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -79,7 +79,7 @@ static ID3D10Blob *compile_shader(const struct d3d12_shader_runner *runner, cons return blob; } -#define MAX_RESOURCE_DESCRIPTORS 256 +#define MAX_RESOURCE_DESCRIPTORS (MAX_RESOURCES * 2) static struct resource *d3d12_runner_create_resource(struct shader_runner *r, const struct resource_params *params) { @@ -90,9 +90,7 @@ static struct resource *d3d12_runner_create_resource(struct shader_runner *r, co struct d3d12_resource *resource; resource = calloc(1, sizeof(*resource)); - resource->r.slot = params->slot; - resource->r.type = params->type; - resource->r.size = params->data_size; + init_resource(&resource->r, params); switch (params->type) { @@ -101,9 +99,6 @@ static struct resource *d3d12_runner_create_resource(struct shader_runner *r, co runner->heap = create_gpu_descriptor_heap(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, MAX_RESOURCE_DESCRIPTORS); - if (params->slot >= MAX_RESOURCE_DESCRIPTORS) - fatal_error("Resource slot %u is too high; please increase MAX_RESOURCE_DESCRIPTORS.\n", params->slot); - resource->resource = create_default_texture(device, params->width, params->height, params->format, 0, D3D12_RESOURCE_STATE_COPY_DEST); resource_data.pData = params->data; @@ -116,6 +111,23 @@ static struct resource *d3d12_runner_create_resource(struct shader_runner *r, co NULL, get_cpu_descriptor_handle(test_context, runner->heap, resource->r.slot)); break; + case RESOURCE_TYPE_UAV: + if (!runner->heap) + runner->heap = create_gpu_descriptor_heap(device, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, MAX_RESOURCE_DESCRIPTORS); + + resource->resource = create_default_texture(device, params->width, params->height, + params->format, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST); + resource_data.pData = params->data; + resource_data.SlicePitch = resource_data.RowPitch = params->width * params->texel_size; + upload_texture_data(resource->resource, &resource_data, 1, test_context->queue, test_context->list); + reset_command_list(test_context->list, test_context->allocator); + transition_resource_state(test_context->list, resource->resource, + D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + ID3D12Device_CreateUnorderedAccessView(device, resource->resource, + NULL, NULL, get_cpu_descriptor_handle(test_context, runner->heap, resource->r.slot + MAX_RESOURCES)); + break; + case RESOURCE_TYPE_VERTEX_BUFFER: resource->resource = create_upload_buffer(device, params->data_size, params->data); break; @@ -192,6 +204,7 @@ static bool d3d12_runner_draw(struct shader_runner *r, switch (resource->r.type) { case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_UAV: range = &resource->descriptor_range; resource->root_index = root_signature_desc.NumParameters++; @@ -201,7 +214,10 @@ static bool d3d12_runner_draw(struct shader_runner *r, root_param->DescriptorTable.pDescriptorRanges = range; root_param->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + if (resource->r.type == RESOURCE_TYPE_UAV) + range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + else + range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; range->NumDescriptors = 1; range->BaseShaderRegister = resource->r.slot; range->RegisterSpace = 0; @@ -281,6 +297,11 @@ static bool d3d12_runner_draw(struct shader_runner *r, get_gpu_descriptor_handle(test_context, runner->heap, resource->r.slot)); break; + case RESOURCE_TYPE_UAV: + ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, resource->root_index, + get_gpu_descriptor_handle(test_context, runner->heap, resource->r.slot + MAX_RESOURCES)); + break; + case RESOURCE_TYPE_VERTEX_BUFFER: vbv.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(resource->resource); vbv.StrideInBytes = get_vb_stride(&runner->r, resource->r.slot); diff --git a/tests/shader_runner_d3d9.c b/tests/shader_runner_d3d9.c index b9ec55b4..417d6875 100644 --- a/tests/shader_runner_d3d9.c +++ b/tests/shader_runner_d3d9.c @@ -222,9 +222,7 @@ static struct resource *d3d9_runner_create_resource(struct shader_runner *r, con void *data; resource = calloc(1, sizeof(*resource)); - resource->r.slot = params->slot; - resource->r.type = params->type; - resource->r.size = params->data_size; + init_resource(&resource->r, params); switch (params->type) { @@ -257,6 +255,10 @@ static struct resource *d3d9_runner_create_resource(struct shader_runner *r, con ok(hr == D3D_OK, "Failed to unmap texture, hr %#lx.\n", hr); break; + case RESOURCE_TYPE_UAV: + fatal_error("UAVs are not supported.\n"); + break; + case RESOURCE_TYPE_VERTEX_BUFFER: hr = IDirect3DDevice9_CreateVertexBuffer(device, params->data_size, D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &resource->vb, NULL); @@ -366,6 +368,10 @@ static bool d3d9_runner_draw(struct shader_runner *r, ok(hr == D3D_OK, "Failed to set texture, hr %#lx.\n", hr); break; + case RESOURCE_TYPE_UAV: + assert(0); + break; + case RESOURCE_TYPE_VERTEX_BUFFER: for (j = 0; j < runner->r.input_element_count; ++j) { diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c index 601eb5a1..f5a0e7ec 100644 --- a/tests/shader_runner_vulkan.c +++ b/tests/shader_runner_vulkan.c @@ -245,17 +245,25 @@ static struct resource *vulkan_runner_create_resource(struct shader_runner *r, c void *data; resource = calloc(1, sizeof(*resource)); - - resource->r.slot = params->slot; - resource->r.type = params->type; + init_resource(&resource->r, params); switch (params->type) { case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_UAV: + { + VkImageUsageFlagBits usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + format = vkd3d_get_vk_format(params->format); - resource->image = create_2d_image(runner, params->width, params->height, - VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, format, &resource->memory); + if (params->type == RESOURCE_TYPE_UAV) + { + layout = VK_IMAGE_LAYOUT_GENERAL; + usage |= VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + } + + resource->image = create_2d_image(runner, params->width, params->height, usage, format, &resource->memory); resource->view = create_2d_image_view(runner, resource->image, format); staging_buffer = create_buffer(runner, params->data_size, @@ -277,14 +285,14 @@ static struct resource *vulkan_runner_create_resource(struct shader_runner *r, c VK_CALL(vkCmdCopyBufferToImage(runner->cmd_buffer, staging_buffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion)); - transition_image_layout(runner, resource->image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + transition_image_layout(runner, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, layout); end_command_buffer(runner); VK_CALL(vkFreeMemory(device, staging_memory, NULL)); VK_CALL(vkDestroyBuffer(device, staging_buffer, NULL)); break; + } case RESOURCE_TYPE_VERTEX_BUFFER: resource->buffer = create_buffer(runner, params->data_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, @@ -383,8 +391,12 @@ static bool compile_shader(const struct vulkan_shader_runner *runner, const char break; case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_UAV: binding = &bindings[interface_info.binding_count++]; - binding->type = VKD3D_SHADER_DESCRIPTOR_TYPE_SRV; + if (resource->r.type == RESOURCE_TYPE_UAV) + binding->type = VKD3D_SHADER_DESCRIPTOR_TYPE_UAV; + else + binding->type = VKD3D_SHADER_DESCRIPTOR_TYPE_SRV; binding->register_space = 0; binding->register_index = resource->r.slot; binding->shader_visibility = VKD3D_SHADER_VISIBILITY_ALL; @@ -557,6 +569,7 @@ static VkPipeline create_pipeline(const struct vulkan_shader_runner *runner, switch (resource->r.type) { case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_UAV: break; case RESOURCE_TYPE_VERTEX_BUFFER: @@ -662,12 +675,16 @@ static VkDescriptorSetLayout create_descriptor_set_layout(struct vulkan_shader_r break; case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_UAV: binding = &bindings[set_desc.bindingCount++]; resource->binding = binding_index++; binding->binding = resource->binding; - binding->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + if (resource->r.type == RESOURCE_TYPE_UAV) + binding->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + else + binding->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; binding->descriptorCount = 1; binding->stageFlags = VK_SHADER_STAGE_ALL; binding->pImmutableSamplers = NULL; @@ -729,6 +746,7 @@ static void bind_resources(struct vulkan_shader_runner *runner, VkPipelineBindPo switch (resource->r.type) { case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_UAV: image_info.imageView = resource->view; image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -739,6 +757,12 @@ static void bind_resources(struct vulkan_shader_runner *runner, VkPipelineBindPo write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; write.pImageInfo = &image_info; + if (resource->r.type == RESOURCE_TYPE_UAV) + { + image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + } + VK_CALL(vkUpdateDescriptorSets(runner->device, 1, &write, 0, NULL)); break; @@ -967,7 +991,7 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) VkInstanceCreateInfo instance_desc = {.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; VkDeviceCreateInfo device_desc = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO}; VkPhysicalDeviceFeatures ret_features, features; - VkDescriptorPoolSize descriptor_pool_sizes[2]; + VkDescriptorPoolSize descriptor_pool_sizes[3]; VkAttachmentDescription attachment_desc = {0}; static const float queue_priority = 1.0f; VkSubpassDescription subpass_desc = {0}; @@ -1049,7 +1073,9 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) } \ features.x = VK_TRUE + ENABLE_FEATURE(fragmentStoresAndAtomics); ENABLE_FEATURE(shaderImageGatherExtended); + ENABLE_FEATURE(shaderStorageImageWriteWithoutFormat); if ((vr = VK_CALL(vkCreateDevice(runner->phys_device, &device_desc, NULL, &device)))) { @@ -1115,6 +1141,8 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner) descriptor_pool_sizes[0].descriptorCount = MAX_RESOURCES; descriptor_pool_sizes[1].type = VK_DESCRIPTOR_TYPE_SAMPLER; descriptor_pool_sizes[1].descriptorCount = MAX_SAMPLERS; + descriptor_pool_sizes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptor_pool_sizes[2].descriptorCount = MAX_RESOURCES; descriptor_pool_desc.maxSets = 1; descriptor_pool_desc.poolSizeCount = ARRAY_SIZE(descriptor_pool_sizes);