From: Conor McCarthy cmccarthy@codeweavers.com
Based in part on vkd3d-proton patches by Philip Rebohle and Hans-Kristian Arntzen. --- include/vkd3d_d3d12.idl | 4 +- libs/vkd3d/device.c | 28 ++- libs/vkd3d/state.c | 388 +++++++++++++++++++++++++++++++------ libs/vkd3d/vkd3d_private.h | 38 +++- 4 files changed, 395 insertions(+), 63 deletions(-)
diff --git a/include/vkd3d_d3d12.idl b/include/vkd3d_d3d12.idl index 9b1b494c8..cdd3acecd 100644 --- a/include/vkd3d_d3d12.idl +++ b/include/vkd3d_d3d12.idl @@ -2129,11 +2129,11 @@ typedef struct D3D12_PIPELINE_STATE_STREAM_DESC void *pPipelineStateSubobjectStream; } D3D12_PIPELINE_STATE_STREAM_DESC;
-struct D3D12_RT_FORMAT_ARRAY +typedef struct D3D12_RT_FORMAT_ARRAY { DXGI_FORMAT RTFormats[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT]; UINT NumRenderTargets; -}; +} D3D12_RT_FORMAT_ARRAY;
typedef enum D3D12_PIPELINE_STATE_SUBOBJECT_TYPE { diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index ec5a921c3..998df40c7 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -2620,13 +2620,17 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateGraphicsPipelineState(ID3D12 const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc, REFIID riid, void **pipeline_state) { struct d3d12_device *device = impl_from_ID3D12Device5(iface); + struct d3d12_pipeline_state_desc pipeline_desc; struct d3d12_pipeline_state *object; HRESULT hr;
TRACE("iface %p, desc %p, riid %s, pipeline_state %p.\n", iface, desc, debugstr_guid(riid), pipeline_state);
- if (FAILED(hr = d3d12_pipeline_state_create_graphics(device, desc, &object))) + if (FAILED(hr = pipeline_state_desc_from_d3d12_graphics_desc(&pipeline_desc, desc))) + return hr; + + if (FAILED(hr = d3d12_pipeline_state_create_graphics(device, &pipeline_desc, &object))) return hr;
return return_interface(&object->ID3D12PipelineState_iface, @@ -2637,13 +2641,17 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateComputePipelineState(ID3D12D const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc, REFIID riid, void **pipeline_state) { struct d3d12_device *device = impl_from_ID3D12Device5(iface); + struct d3d12_pipeline_state_desc pipeline_desc; struct d3d12_pipeline_state *object; HRESULT hr;
TRACE("iface %p, desc %p, riid %s, pipeline_state %p.\n", iface, desc, debugstr_guid(riid), pipeline_state);
- if (FAILED(hr = d3d12_pipeline_state_create_compute(device, desc, &object))) + if (FAILED(hr = pipeline_state_desc_from_d3d12_compute_desc(&pipeline_desc, desc))) + return hr; + + if (FAILED(hr = d3d12_pipeline_state_create_compute(device, &pipeline_desc, &object))) return hr;
return return_interface(&object->ID3D12PipelineState_iface, @@ -3964,9 +3972,21 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_SetResidencyPriority(ID3D12Device5 static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePipelineState(ID3D12Device5 *iface, const D3D12_PIPELINE_STATE_STREAM_DESC *desc, REFIID iid, void **pipeline_state) { - FIXME("iface %p, desc %p, iid %s, pipeline_state %p stub!\n", iface, desc, debugstr_guid(iid), pipeline_state); + struct d3d12_device *device = impl_from_ID3D12Device5(iface); + struct d3d12_pipeline_state_desc pipeline_desc; + struct d3d12_pipeline_state *object; + VkPipelineBindPoint bind_point; + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, desc %p, iid %s, pipeline_state %p.\n", iface, desc, debugstr_guid(iid), pipeline_state); + + if (FAILED(hr = pipeline_state_desc_from_d3d12_stream_desc(&pipeline_desc, desc, &bind_point))) + return hr; + + if (FAILED(hr = d3d12_pipeline_state_create(device, bind_point, &pipeline_desc, &object))) + return hr; + + return return_interface(&object->ID3D12PipelineState_iface, &IID_ID3D12PipelineState, iid, pipeline_state); }
static HRESULT STDMETHODCALLTYPE d3d12_device_OpenExistingHeapFromAddress(ID3D12Device5 *iface, diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 2545c0f04..f6dd3917a 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -1736,6 +1736,241 @@ void vkd3d_render_pass_cache_cleanup(struct vkd3d_render_pass_cache *cache, cache->render_passes = NULL; }
+static void d3d12_promote_depth_stencil_desc(D3D12_DEPTH_STENCIL_DESC1 *dst, const D3D12_DEPTH_STENCIL_DESC *src) +{ + dst->DepthEnable = src->DepthEnable; + dst->DepthWriteMask = src->DepthWriteMask; + dst->DepthFunc = src->DepthFunc; + dst->StencilEnable = src->StencilEnable; + dst->StencilReadMask = src->StencilReadMask; + dst->StencilWriteMask = src->StencilWriteMask; + dst->FrontFace = src->FrontFace; + dst->BackFace = src->BackFace; + dst->DepthBoundsTestEnable = FALSE; +} + +static void d3d12_init_pipeline_state_desc(struct d3d12_pipeline_state_desc *desc) +{ + D3D12_DEPTH_STENCIL_DESC1 *ds_state = &desc->depth_stencil_state; + D3D12_RASTERIZER_DESC *rs_state = &desc->rasterizer_state; + D3D12_BLEND_DESC *blend_state = &desc->blend_state; + DXGI_SAMPLE_DESC *sample_desc = &desc->sample_desc; + + memset(desc, 0, sizeof(*desc)); + ds_state->DepthEnable = TRUE; + ds_state->DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; + ds_state->DepthFunc = D3D12_COMPARISON_FUNC_LESS; + ds_state->StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK; + ds_state->StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK; + ds_state->FrontFace.StencilFunc = ds_state->BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS; + ds_state->FrontFace.StencilDepthFailOp = ds_state->BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP; + ds_state->FrontFace.StencilPassOp = ds_state->BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP; + ds_state->FrontFace.StencilFailOp = ds_state->BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP; + + rs_state->FillMode = D3D12_FILL_MODE_SOLID; + rs_state->CullMode = D3D12_CULL_MODE_BACK; + rs_state->DepthClipEnable = TRUE; + rs_state->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; + + blend_state->RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + + sample_desc->Count = 1; + sample_desc->Quality = 0; + + desc->sample_mask = D3D12_DEFAULT_SAMPLE_MASK; +} + +HRESULT pipeline_state_desc_from_d3d12_graphics_desc(struct d3d12_pipeline_state_desc *desc, + const D3D12_GRAPHICS_PIPELINE_STATE_DESC *d3d12_desc) +{ + memset(desc, 0, sizeof(*desc)); + desc->root_signature = d3d12_desc->pRootSignature; + desc->vs = d3d12_desc->VS; + desc->ps = d3d12_desc->PS; + desc->ds = d3d12_desc->DS; + desc->hs = d3d12_desc->HS; + desc->gs = d3d12_desc->GS; + desc->stream_output = d3d12_desc->StreamOutput; + desc->blend_state = d3d12_desc->BlendState; + desc->sample_mask = d3d12_desc->SampleMask; + desc->rasterizer_state = d3d12_desc->RasterizerState; + d3d12_promote_depth_stencil_desc(&desc->depth_stencil_state, &d3d12_desc->DepthStencilState); + desc->input_layout = d3d12_desc->InputLayout; + desc->strip_cut_value = d3d12_desc->IBStripCutValue; + desc->primitive_topology_type = d3d12_desc->PrimitiveTopologyType; + desc->rtv_formats.NumRenderTargets = d3d12_desc->NumRenderTargets; + memcpy(desc->rtv_formats.RTFormats, d3d12_desc->RTVFormats, sizeof(desc->rtv_formats.RTFormats)); + desc->dsv_format = d3d12_desc->DSVFormat; + desc->sample_desc = d3d12_desc->SampleDesc; + desc->node_mask = d3d12_desc->NodeMask; + desc->cached_pso = d3d12_desc->CachedPSO; + desc->flags = d3d12_desc->Flags; + return S_OK; +} + +HRESULT pipeline_state_desc_from_d3d12_compute_desc(struct d3d12_pipeline_state_desc *desc, + const D3D12_COMPUTE_PIPELINE_STATE_DESC *d3d12_desc) +{ + memset(desc, 0, sizeof(*desc)); + desc->root_signature = d3d12_desc->pRootSignature; + desc->cs = d3d12_desc->CS; + desc->node_mask = d3d12_desc->NodeMask; + desc->cached_pso = d3d12_desc->CachedPSO; + desc->flags = d3d12_desc->Flags; + return S_OK; +} + +static VkShaderStageFlags pipeline_state_desc_get_shader_stages(const struct d3d12_pipeline_state_desc *desc) +{ + VkShaderStageFlags result = 0; + + if (desc->vs.BytecodeLength && desc->vs.pShaderBytecode) + result |= VK_SHADER_STAGE_VERTEX_BIT; + if (desc->hs.BytecodeLength && desc->hs.pShaderBytecode) + result |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + if (desc->ds.BytecodeLength && desc->ds.pShaderBytecode) + result |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + if (desc->gs.BytecodeLength && desc->gs.pShaderBytecode) + result |= VK_SHADER_STAGE_GEOMETRY_BIT; + if (desc->ps.BytecodeLength && desc->ps.pShaderBytecode) + result |= VK_SHADER_STAGE_FRAGMENT_BIT; + if (desc->cs.BytecodeLength && desc->cs.pShaderBytecode) + result |= VK_SHADER_STAGE_COMPUTE_BIT; + + /* If we use rasterizer discard, force fragment shader to not exist. + * See VUID-VkGraphicsPipelineCreateInfo-pStages-06894. */ + if (desc->stream_output.NumEntries && + desc->stream_output.RasterizedStream == D3D12_SO_NO_RASTERIZED_STREAM) + { + result &= ~VK_SHADER_STAGE_FRAGMENT_BIT; + } + + return result; +} + +#define DCL_SUBOBJECT_INFO(type, field) {__alignof__(type), sizeof(type), offsetof(struct d3d12_pipeline_state_desc, field)} + +HRESULT pipeline_state_desc_from_d3d12_stream_desc(struct d3d12_pipeline_state_desc *desc, + const D3D12_PIPELINE_STATE_STREAM_DESC *d3d12_desc, VkPipelineBindPoint *vk_bind_point) +{ + VkShaderStageFlags defined_stages, disallowed_stages; + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE subobject_type; + const char *stream_ptr, *stream_end; + uint64_t defined_subobjects = 0; + uint64_t subobject_bit; + char *desc_char; + size_t i, size; + + static const struct + { + size_t alignment; + size_t size; + size_t dst_offset; + } + subobject_info[] = + { + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE] = DCL_SUBOBJECT_INFO(ID3D12RootSignature *, root_signature), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS] = DCL_SUBOBJECT_INFO(D3D12_SHADER_BYTECODE, vs), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS] = DCL_SUBOBJECT_INFO(D3D12_SHADER_BYTECODE, ps), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS] = DCL_SUBOBJECT_INFO(D3D12_SHADER_BYTECODE, ds), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS] = DCL_SUBOBJECT_INFO(D3D12_SHADER_BYTECODE, hs), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS] = DCL_SUBOBJECT_INFO(D3D12_SHADER_BYTECODE, gs), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS] = DCL_SUBOBJECT_INFO(D3D12_SHADER_BYTECODE, cs), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT] = DCL_SUBOBJECT_INFO(D3D12_STREAM_OUTPUT_DESC, stream_output), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND] = DCL_SUBOBJECT_INFO(D3D12_BLEND_DESC, blend_state), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK] = DCL_SUBOBJECT_INFO(UINT, sample_mask), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER] = DCL_SUBOBJECT_INFO(D3D12_RASTERIZER_DESC, rasterizer_state), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL] = DCL_SUBOBJECT_INFO(D3D12_DEPTH_STENCIL_DESC, depth_stencil_state), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT] = DCL_SUBOBJECT_INFO(D3D12_INPUT_LAYOUT_DESC, input_layout), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE] = DCL_SUBOBJECT_INFO(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, strip_cut_value), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY] = DCL_SUBOBJECT_INFO(D3D12_PRIMITIVE_TOPOLOGY_TYPE, primitive_topology_type), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS] = DCL_SUBOBJECT_INFO(D3D12_RT_FORMAT_ARRAY, rtv_formats), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT] = DCL_SUBOBJECT_INFO(DXGI_FORMAT, dsv_format), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC] = DCL_SUBOBJECT_INFO(DXGI_SAMPLE_DESC, sample_desc), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK] = DCL_SUBOBJECT_INFO(UINT, node_mask), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO] = DCL_SUBOBJECT_INFO(D3D12_CACHED_PIPELINE_STATE, cached_pso), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS] = DCL_SUBOBJECT_INFO(D3D12_PIPELINE_STATE_FLAGS, flags), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1] = DCL_SUBOBJECT_INFO(D3D12_DEPTH_STENCIL_DESC1, depth_stencil_state), + [D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING] = DCL_SUBOBJECT_INFO(D3D12_VIEW_INSTANCING_DESC, view_instancing_desc), + }; + + /* Initialize defaults for undefined subobjects */ + d3d12_init_pipeline_state_desc(desc); + + /* Structs are packed, but padded so that their size + * is always a multiple of the size of a pointer. */ + stream_ptr = d3d12_desc->pPipelineStateSubobjectStream; + stream_end = stream_ptr + d3d12_desc->SizeInBytes; + desc_char = (char *)desc; + + while (stream_ptr < stream_end) + { + if (stream_ptr + sizeof(subobject_type) > stream_end) + { + WARN("Invalid pipeline state stream.\n"); + return E_INVALIDARG; + } + + subobject_type = *(const D3D12_PIPELINE_STATE_SUBOBJECT_TYPE *)stream_ptr; + subobject_bit = 1ull << subobject_type; + + if (defined_subobjects & subobject_bit) + { + WARN("Duplicate pipeline subobject type %u.\n", subobject_type); + return E_INVALIDARG; + } + + defined_subobjects |= subobject_bit; + + if (subobject_type >= ARRAY_SIZE(subobject_info)) + { + FIXME("Unhandled pipeline subobject type %#x.\n", subobject_type); + return E_INVALIDARG; + } + + i = align(sizeof(subobject_type), subobject_info[subobject_type].alignment); + size = subobject_info[subobject_type].size; + + if (stream_ptr + i + size > stream_end) + { + WARN("Invalid pipeline state stream.\n"); + return E_INVALIDARG; + } + + memcpy(&desc_char[subobject_info[subobject_type].dst_offset], &stream_ptr[i], size); + stream_ptr += align(i + size, sizeof(void *)); + } + + /* Deduce pipeline type from specified shaders */ + defined_stages = pipeline_state_desc_get_shader_stages(desc); + + if (defined_stages & VK_SHADER_STAGE_VERTEX_BIT) + { + disallowed_stages = VK_SHADER_STAGE_COMPUTE_BIT; + *vk_bind_point = VK_PIPELINE_BIND_POINT_GRAPHICS; + } + else if (defined_stages & VK_SHADER_STAGE_COMPUTE_BIT) + { + disallowed_stages = VK_SHADER_STAGE_VERTEX_BIT; + *vk_bind_point = VK_PIPELINE_BIND_POINT_COMPUTE; + } + else + { + WARN("Cannot deduce pipeline type from shader stages %#x.\n", defined_stages); + return E_INVALIDARG; + } + + if (defined_stages & disallowed_stages) + { + WARN("Invalid combination of shader stages %#x.\n", defined_stages); + return E_INVALIDARG; + } + + return S_OK; +} + +#undef DCL_SUBOBJECT_INFO + struct vkd3d_pipeline_key { D3D12_PRIMITIVE_TOPOLOGY topology; @@ -2193,7 +2428,7 @@ static HRESULT d3d12_pipeline_state_find_and_init_uav_counters(struct d3d12_pipe }
static HRESULT d3d12_pipeline_state_init_compute(struct d3d12_pipeline_state *state, - struct d3d12_device *device, const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc) + struct d3d12_device *device, const struct d3d12_pipeline_state_desc *desc) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; struct vkd3d_shader_interface_info shader_interface; @@ -2208,14 +2443,14 @@ static HRESULT d3d12_pipeline_state_init_compute(struct d3d12_pipeline_state *st
memset(&state->uav_counters, 0, sizeof(state->uav_counters));
- if (!(root_signature = unsafe_impl_from_ID3D12RootSignature(desc->pRootSignature))) + if (!(root_signature = unsafe_impl_from_ID3D12RootSignature(desc->root_signature))) { WARN("Root signature is NULL.\n"); return E_INVALIDARG; }
if (FAILED(hr = d3d12_pipeline_state_find_and_init_uav_counters(state, device, root_signature, - &desc->CS, VK_SHADER_STAGE_COMPUTE_BIT))) + &desc->cs, VK_SHADER_STAGE_COMPUTE_BIT))) return hr;
memset(&target_info, 0, sizeof(target_info)); @@ -2256,7 +2491,7 @@ static HRESULT d3d12_pipeline_state_init_compute(struct d3d12_pipeline_state *st
vk_pipeline_layout = state->uav_counters.vk_pipeline_layout ? state->uav_counters.vk_pipeline_layout : root_signature->vk_pipeline_layout; - if (FAILED(hr = vkd3d_create_compute_pipeline(device, &desc->CS, &shader_interface, + if (FAILED(hr = vkd3d_create_compute_pipeline(device, &desc->cs, &shader_interface, vk_pipeline_layout, &state->u.compute.vk_pipeline))) { WARN("Failed to create Vulkan compute pipeline, hr %#x.\n", hr); @@ -2278,7 +2513,7 @@ static HRESULT d3d12_pipeline_state_init_compute(struct d3d12_pipeline_state *st }
HRESULT d3d12_pipeline_state_create_compute(struct d3d12_device *device, - const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc, struct d3d12_pipeline_state **state) + const struct d3d12_pipeline_state_desc *desc, struct d3d12_pipeline_state **state) { struct d3d12_pipeline_state *object; HRESULT hr; @@ -2457,7 +2692,7 @@ static void vk_stencil_op_state_from_d3d12(struct VkStencilOpState *vk_desc, }
static void ds_desc_from_d3d12(struct VkPipelineDepthStencilStateCreateInfo *vk_desc, - const D3D12_DEPTH_STENCIL_DESC *d3d12_desc) + const D3D12_DEPTH_STENCIL_DESC1 *d3d12_desc) { memset(vk_desc, 0, sizeof(*vk_desc)); vk_desc->sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; @@ -2738,12 +2973,12 @@ static VkLogicOp vk_logic_op_from_d3d12(D3D12_LOGIC_OP op) }
static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *state, - struct d3d12_device *device, const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc) + struct d3d12_device *device, const struct d3d12_pipeline_state_desc *desc) { unsigned int ps_output_swizzle[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT]; struct d3d12_graphics_pipeline_state *graphics = &state->u.graphics; const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; - const D3D12_STREAM_OUTPUT_DESC *so_desc = &desc->StreamOutput; + const D3D12_STREAM_OUTPUT_DESC *so_desc = &desc->stream_output; VkVertexInputBindingDivisorDescriptionEXT *binding_divisor; const struct vkd3d_vulkan_info *vk_info = &device->vk_info; uint32_t instance_divisors[D3D12_VS_INPUT_REGISTER_COUNT]; @@ -2787,11 +3022,11 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s } shader_stages[] = { - {VK_SHADER_STAGE_VERTEX_BIT, offsetof(D3D12_GRAPHICS_PIPELINE_STATE_DESC, VS)}, - {VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, offsetof(D3D12_GRAPHICS_PIPELINE_STATE_DESC, HS)}, - {VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, offsetof(D3D12_GRAPHICS_PIPELINE_STATE_DESC, DS)}, - {VK_SHADER_STAGE_GEOMETRY_BIT, offsetof(D3D12_GRAPHICS_PIPELINE_STATE_DESC, GS)}, - {VK_SHADER_STAGE_FRAGMENT_BIT, offsetof(D3D12_GRAPHICS_PIPELINE_STATE_DESC, PS)}, + {VK_SHADER_STAGE_VERTEX_BIT, offsetof(struct d3d12_pipeline_state_desc, vs)}, + {VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, offsetof(struct d3d12_pipeline_state_desc, hs)}, + {VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, offsetof(struct d3d12_pipeline_state_desc, ds)}, + {VK_SHADER_STAGE_GEOMETRY_BIT, offsetof(struct d3d12_pipeline_state_desc, gs)}, + {VK_SHADER_STAGE_FRAGMENT_BIT, offsetof(struct d3d12_pipeline_state_desc, ps)}, };
state->ID3D12PipelineState_iface.lpVtbl = &d3d12_pipeline_state_vtbl; @@ -2802,26 +3037,26 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s
memset(&input_signature, 0, sizeof(input_signature));
- for (i = desc->NumRenderTargets; i < ARRAY_SIZE(desc->RTVFormats); ++i) + for (i = desc->rtv_formats.NumRenderTargets; i < ARRAY_SIZE(desc->rtv_formats.RTFormats); ++i) { - if (desc->RTVFormats[i] != DXGI_FORMAT_UNKNOWN) + if (desc->rtv_formats.RTFormats[i] != DXGI_FORMAT_UNKNOWN) { WARN("Format must be set to DXGI_FORMAT_UNKNOWN for inactive render targets.\n"); return E_INVALIDARG; } }
- if (!(root_signature = unsafe_impl_from_ID3D12RootSignature(desc->pRootSignature))) + if (!(root_signature = unsafe_impl_from_ID3D12RootSignature(desc->root_signature))) { WARN("Root signature is NULL.\n"); return E_INVALIDARG; }
- sample_count = vk_samples_from_dxgi_sample_desc(&desc->SampleDesc); - if (desc->SampleDesc.Count != 1 && desc->SampleDesc.Quality) - WARN("Ignoring sample quality %u.\n", desc->SampleDesc.Quality); + sample_count = vk_samples_from_dxgi_sample_desc(&desc->sample_desc); + if (desc->sample_desc.Count != 1 && desc->sample_desc.Quality) + WARN("Ignoring sample quality %u.\n", desc->sample_desc.Quality);
- rt_count = desc->NumRenderTargets; + rt_count = desc->rtv_formats.NumRenderTargets; if (rt_count > ARRAY_SIZE(graphics->blend_attachments)) { FIXME("NumRenderTargets %zu > %zu, ignoring extra formats.\n", @@ -2829,40 +3064,40 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s rt_count = ARRAY_SIZE(graphics->blend_attachments); }
- graphics->om_logic_op_enable = desc->BlendState.RenderTarget[0].LogicOpEnable + graphics->om_logic_op_enable = desc->blend_state.RenderTarget[0].LogicOpEnable && device->feature_options.OutputMergerLogicOp; graphics->om_logic_op = graphics->om_logic_op_enable - ? vk_logic_op_from_d3d12(desc->BlendState.RenderTarget[0].LogicOp) + ? vk_logic_op_from_d3d12(desc->blend_state.RenderTarget[0].LogicOp) : VK_LOGIC_OP_COPY; - if (desc->BlendState.RenderTarget[0].LogicOpEnable && !graphics->om_logic_op_enable) + if (desc->blend_state.RenderTarget[0].LogicOpEnable && !graphics->om_logic_op_enable) WARN("The device does not support output merger logic ops. Ignoring logic op %#x.\n", - desc->BlendState.RenderTarget[0].LogicOp); + desc->blend_state.RenderTarget[0].LogicOp);
graphics->null_attachment_mask = 0; for (i = 0; i < rt_count; ++i) { const D3D12_RENDER_TARGET_BLEND_DESC *rt_desc;
- if (desc->RTVFormats[i] == DXGI_FORMAT_UNKNOWN) + if (desc->rtv_formats.RTFormats[i] == DXGI_FORMAT_UNKNOWN) { graphics->null_attachment_mask |= 1u << i; ps_output_swizzle[i] = VKD3D_SHADER_NO_SWIZZLE; graphics->rtv_formats[i] = VK_FORMAT_UNDEFINED; } - else if ((format = vkd3d_get_format(device, desc->RTVFormats[i], false))) + else if ((format = vkd3d_get_format(device, desc->rtv_formats.RTFormats[i], false))) { ps_output_swizzle[i] = vkd3d_get_rt_format_swizzle(format); graphics->rtv_formats[i] = format->vk_format; } else { - WARN("Invalid RTV format %#x.\n", desc->RTVFormats[i]); + WARN("Invalid RTV format %#x.\n", desc->rtv_formats.RTFormats[i]); hr = E_INVALIDARG; goto fail; }
- rt_desc = &desc->BlendState.RenderTarget[desc->BlendState.IndependentBlendEnable ? i : 0]; - if (desc->BlendState.IndependentBlendEnable && rt_desc->LogicOpEnable) + rt_desc = &desc->blend_state.RenderTarget[desc->blend_state.IndependentBlendEnable ? i : 0]; + if (desc->blend_state.IndependentBlendEnable && rt_desc->LogicOpEnable) { WARN("IndependentBlendEnable must be FALSE when logic operations are enabled.\n"); hr = E_INVALIDARG; @@ -2881,8 +3116,8 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s graphics->rtv_formats[i] = VK_FORMAT_UNDEFINED; graphics->rt_count = rt_count;
- ds_desc_from_d3d12(&graphics->ds_desc, &desc->DepthStencilState); - if (desc->DSVFormat == DXGI_FORMAT_UNKNOWN + ds_desc_from_d3d12(&graphics->ds_desc, &desc->depth_stencil_state); + if (desc->dsv_format == DXGI_FORMAT_UNKNOWN && graphics->ds_desc.depthTestEnable && !graphics->ds_desc.depthWriteEnable && graphics->ds_desc.depthCompareOp == VK_COMPARE_OP_ALWAYS && !graphics->ds_desc.stencilTestEnable) { @@ -2893,13 +3128,13 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s graphics->dsv_format = VK_FORMAT_UNDEFINED; if (graphics->ds_desc.depthTestEnable || graphics->ds_desc.stencilTestEnable) { - if (desc->DSVFormat == DXGI_FORMAT_UNKNOWN) + if (desc->dsv_format == DXGI_FORMAT_UNKNOWN) { WARN("DSV format is DXGI_FORMAT_UNKNOWN.\n"); graphics->dsv_format = VK_FORMAT_UNDEFINED; graphics->null_attachment_mask |= dsv_attachment_mask(graphics); } - else if ((format = vkd3d_get_format(device, desc->DSVFormat, true))) + else if ((format = vkd3d_get_format(device, desc->dsv_format, true))) { if (!(format->vk_aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) FIXME("Format %#x is not depth/stencil format.\n", format->dxgi_format); @@ -2908,12 +3143,12 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s } else { - WARN("Invalid DSV format %#x.\n", desc->DSVFormat); + WARN("Invalid DSV format %#x.\n", desc->dsv_format); hr = E_INVALIDARG; goto fail; }
- if (!desc->PS.pShaderBytecode) + if (!desc->ps.pShaderBytecode) { if (FAILED(hr = create_shader_stage(device, &graphics->stages[graphics->stage_count], VK_SHADER_STAGE_FRAGMENT_BIT, &default_ps, NULL))) @@ -2936,7 +3171,7 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s ps_target_info.extension_count = vk_info->shader_extension_count; ps_target_info.parameters = ps_shader_parameters; ps_target_info.parameter_count = ARRAY_SIZE(ps_shader_parameters); - ps_target_info.dual_source_blending = is_dual_source_blending(&desc->BlendState.RenderTarget[0]); + ps_target_info.dual_source_blending = is_dual_source_blending(&desc->blend_state.RenderTarget[0]); ps_target_info.output_swizzles = ps_output_swizzle; ps_target_info.output_swizzle_count = rt_count;
@@ -2946,11 +3181,11 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s hr = E_INVALIDARG; goto fail; } - if (ps_target_info.dual_source_blending && desc->BlendState.IndependentBlendEnable) + if (ps_target_info.dual_source_blending && desc->blend_state.IndependentBlendEnable) { - for (i = 1; i < ARRAY_SIZE(desc->BlendState.RenderTarget); ++i) + for (i = 1; i < ARRAY_SIZE(desc->blend_state.RenderTarget); ++i) { - if (desc->BlendState.RenderTarget[i].BlendEnable) + if (desc->blend_state.RenderTarget[i].BlendEnable) { WARN("Blend enable cannot be set for render target %u when dual source blending is used.\n", i); hr = E_INVALIDARG; @@ -2992,9 +3227,9 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s xfb_info.buffer_strides = so_desc->pBufferStrides; xfb_info.buffer_stride_count = so_desc->NumStrides;
- if (desc->GS.pShaderBytecode) + if (desc->gs.pShaderBytecode) xfb_stage = VK_SHADER_STAGE_GEOMETRY_BIT; - else if (desc->DS.pShaderBytecode) + else if (desc->ds.pShaderBytecode) xfb_stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; else xfb_stage = VK_SHADER_STAGE_VERTEX_BIT; @@ -3046,7 +3281,7 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: - if (desc->PrimitiveTopologyType != D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH) + if (desc->primitive_topology_type != D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH) { WARN("D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH must be used with tessellation shaders.\n"); hr = E_INVALIDARG; @@ -3088,7 +3323,7 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s ++graphics->stage_count; }
- graphics->attribute_count = desc->InputLayout.NumElements; + graphics->attribute_count = desc->input_layout.NumElements; if (graphics->attribute_count > ARRAY_SIZE(graphics->attributes)) { FIXME("InputLayout.NumElements %zu > %zu, ignoring extra elements.\n", @@ -3104,13 +3339,13 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s goto fail; }
- if (FAILED(hr = compute_input_layout_offsets(device, &desc->InputLayout, aligned_offsets))) + if (FAILED(hr = compute_input_layout_offsets(device, &desc->input_layout, aligned_offsets))) goto fail;
graphics->instance_divisor_count = 0; for (i = 0, j = 0, mask = 0; i < graphics->attribute_count; ++i) { - const D3D12_INPUT_ELEMENT_DESC *e = &desc->InputLayout.pInputElementDescs[i]; + const D3D12_INPUT_ELEMENT_DESC *e = &desc->input_layout.pInputElementDescs[i]; const struct vkd3d_shader_signature_element *signature_element;
/* TODO: DXGI_FORMAT_UNKNOWN will succeed here, which may not match @@ -3194,30 +3429,30 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s graphics->attribute_count = j; vkd3d_shader_free_shader_signature(&input_signature);
- switch (desc->IBStripCutValue) + switch (desc->strip_cut_value) { case D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED: case D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF: case D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF: - graphics->index_buffer_strip_cut_value = desc->IBStripCutValue; + graphics->index_buffer_strip_cut_value = desc->strip_cut_value; break; default: - WARN("Invalid index buffer strip cut value %#x.\n", desc->IBStripCutValue); + WARN("Invalid index buffer strip cut value %#x.\n", desc->strip_cut_value); hr = E_INVALIDARG; goto fail; }
is_dsv_format_unknown = graphics->null_attachment_mask & dsv_attachment_mask(graphics);
- rs_desc_from_d3d12(&graphics->rs_desc, &desc->RasterizerState); + rs_desc_from_d3d12(&graphics->rs_desc, &desc->rasterizer_state); have_attachment = graphics->rt_count || graphics->dsv_format || is_dsv_format_unknown; - if ((!have_attachment && !(desc->PS.pShaderBytecode && desc->PS.BytecodeLength)) + if ((!have_attachment && !(desc->ps.pShaderBytecode && desc->ps.BytecodeLength)) || (graphics->xfb_enabled && so_desc->RasterizedStream == D3D12_SO_NO_RASTERIZED_STREAM)) graphics->rs_desc.rasterizerDiscardEnable = VK_TRUE;
rs_stream_info_from_d3d12(&graphics->rs_stream_info, &graphics->rs_desc, so_desc, vk_info); if (vk_info->EXT_depth_clip_enable) - rs_depth_clip_info_from_d3d12(&graphics->rs_depth_clip_info, &graphics->rs_desc, &desc->RasterizerState); + rs_depth_clip_info_from_d3d12(&graphics->rs_depth_clip_info, &graphics->rs_desc, &desc->rasterizer_state);
graphics->ms_desc.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; graphics->ms_desc.pNext = NULL; @@ -3226,16 +3461,23 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s graphics->ms_desc.sampleShadingEnable = VK_FALSE; graphics->ms_desc.minSampleShading = 0.0f; graphics->ms_desc.pSampleMask = NULL; - if (desc->SampleMask != ~0u) + if (desc->sample_mask != ~0u) { assert(DIV_ROUND_UP(sample_count, 32) <= ARRAY_SIZE(graphics->sample_mask)); - graphics->sample_mask[0] = desc->SampleMask; + graphics->sample_mask[0] = desc->sample_mask; graphics->sample_mask[1] = 0xffffffffu; graphics->ms_desc.pSampleMask = graphics->sample_mask; } - graphics->ms_desc.alphaToCoverageEnable = desc->BlendState.AlphaToCoverageEnable; + graphics->ms_desc.alphaToCoverageEnable = desc->blend_state.AlphaToCoverageEnable; graphics->ms_desc.alphaToOneEnable = VK_FALSE;
+ if (desc->view_instancing_desc.ViewInstanceCount) + { + FIXME("View instancing is not supported yet.\n"); + hr = E_INVALIDARG; + goto fail; + } + /* We defer creating the render pass for pipelines wth DSVFormat equal to * DXGI_FORMAT_UNKNOWN. We take the actual DSV format from the bound DSV. */ if (is_dsv_format_unknown) @@ -3269,7 +3511,7 @@ fail: }
HRESULT d3d12_pipeline_state_create_graphics(struct d3d12_device *device, - const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc, struct d3d12_pipeline_state **state) + const struct d3d12_pipeline_state_desc *desc, struct d3d12_pipeline_state **state) { struct d3d12_pipeline_state *object; HRESULT hr; @@ -3290,6 +3532,42 @@ HRESULT d3d12_pipeline_state_create_graphics(struct d3d12_device *device, return S_OK; }
+HRESULT d3d12_pipeline_state_create(struct d3d12_device *device, VkPipelineBindPoint bind_point, + const struct d3d12_pipeline_state_desc *desc, struct d3d12_pipeline_state **state) +{ + struct d3d12_pipeline_state *object; + HRESULT hr; + + if (!(object = vkd3d_calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + switch (bind_point) + { + case VK_PIPELINE_BIND_POINT_COMPUTE: + hr = d3d12_pipeline_state_init_compute(object, device, desc); + break; + + case VK_PIPELINE_BIND_POINT_GRAPHICS: + hr = d3d12_pipeline_state_init_graphics(object, device, desc); + break; + + default: + WARN("Invalid bind point %u.", bind_point); + hr = E_INVALIDARG; + } + + if (FAILED(hr)) + { + vkd3d_free(object); + return hr; + } + + TRACE("Created pipeline state %p.\n", object); + + *state = object; + return S_OK; +} + static enum VkPrimitiveTopology vk_topology_from_d3d12_topology(D3D12_PRIMITIVE_TOPOLOGY topology) { switch (topology) diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 2e9845dfa..f5ba6d11a 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -1312,10 +1312,44 @@ static inline bool d3d12_pipeline_state_has_unknown_dsv_format(struct d3d12_pipe return false; }
+struct d3d12_pipeline_state_desc +{ + ID3D12RootSignature *root_signature; + D3D12_SHADER_BYTECODE vs; + D3D12_SHADER_BYTECODE ps; + D3D12_SHADER_BYTECODE ds; + D3D12_SHADER_BYTECODE hs; + D3D12_SHADER_BYTECODE gs; + D3D12_SHADER_BYTECODE cs; + D3D12_STREAM_OUTPUT_DESC stream_output; + D3D12_BLEND_DESC blend_state; + unsigned int sample_mask; + D3D12_RASTERIZER_DESC rasterizer_state; + D3D12_DEPTH_STENCIL_DESC1 depth_stencil_state; + D3D12_INPUT_LAYOUT_DESC input_layout; + D3D12_INDEX_BUFFER_STRIP_CUT_VALUE strip_cut_value; + D3D12_PRIMITIVE_TOPOLOGY_TYPE primitive_topology_type; + D3D12_RT_FORMAT_ARRAY rtv_formats; + DXGI_FORMAT dsv_format; + DXGI_SAMPLE_DESC sample_desc; + D3D12_VIEW_INSTANCING_DESC view_instancing_desc; + unsigned int node_mask; + D3D12_CACHED_PIPELINE_STATE cached_pso; + D3D12_PIPELINE_STATE_FLAGS flags; +}; + +HRESULT pipeline_state_desc_from_d3d12_graphics_desc(struct d3d12_pipeline_state_desc *desc, + const D3D12_GRAPHICS_PIPELINE_STATE_DESC *d3d12_desc); +HRESULT pipeline_state_desc_from_d3d12_compute_desc(struct d3d12_pipeline_state_desc *desc, + const D3D12_COMPUTE_PIPELINE_STATE_DESC *d3d12_desc); +HRESULT pipeline_state_desc_from_d3d12_stream_desc(struct d3d12_pipeline_state_desc *desc, + const D3D12_PIPELINE_STATE_STREAM_DESC *d3d12_desc, VkPipelineBindPoint *vk_bind_point); HRESULT d3d12_pipeline_state_create_compute(struct d3d12_device *device, - const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc, struct d3d12_pipeline_state **state); + const struct d3d12_pipeline_state_desc *desc, struct d3d12_pipeline_state **state); HRESULT d3d12_pipeline_state_create_graphics(struct d3d12_device *device, - const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc, struct d3d12_pipeline_state **state); + const struct d3d12_pipeline_state_desc *desc, struct d3d12_pipeline_state **state); +HRESULT d3d12_pipeline_state_create(struct d3d12_device *device, VkPipelineBindPoint bind_point, + const struct d3d12_pipeline_state_desc *desc, struct d3d12_pipeline_state **state); VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_state *state, D3D12_PRIMITIVE_TOPOLOGY topology, const uint32_t *strides, VkFormat dsv_format, VkRenderPass *vk_render_pass); struct d3d12_pipeline_state *unsafe_impl_from_ID3D12PipelineState(ID3D12PipelineState *iface);
From: Conor McCarthy cmccarthy@codeweavers.com
Based on vkd3d-proton patches by Hans-Kristian Arntzen and Philip Rebohle. --- tests/d3d12.c | 571 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 571 insertions(+)
diff --git a/tests/d3d12.c b/tests/d3d12.c index 8f100a5e7..e6d05c130 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -3180,6 +3180,576 @@ static void test_create_graphics_pipeline_state(void) ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount); }
+union d3d12_root_signature_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + ID3D12RootSignature *root_signature; + }; + void *dummy_align; +}; + +union d3d12_shader_bytecode_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_SHADER_BYTECODE shader_bytecode; + }; + void *dummy_align; +}; + +union d3d12_stream_output_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_STREAM_OUTPUT_DESC stream_output_desc; + }; + void *dummy_align; +}; + +union d3d12_blend_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_BLEND_DESC blend_desc; + }; + void *dummy_align; +}; + +union d3d12_sample_mask_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + UINT sample_mask; + }; + void *dummy_align; +}; + +union d3d12_rasterizer_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_RASTERIZER_DESC rasterizer_desc; + }; + void *dummy_align; +}; + +union d3d12_depth_stencil_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_DEPTH_STENCIL_DESC depth_stencil_desc; + }; + void *dummy_align; +}; + +union d3d12_input_layout_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_INPUT_LAYOUT_DESC input_layout; + }; + void *dummy_align; +}; + +union d3d12_ib_strip_cut_value_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_INDEX_BUFFER_STRIP_CUT_VALUE strip_cut_value; + }; + void *dummy_align; +}; + +union d3d12_primitive_topology_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_PRIMITIVE_TOPOLOGY_TYPE primitive_topology_type; + }; + void *dummy_align; +}; + +union d3d12_render_target_formats_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_RT_FORMAT_ARRAY render_target_formats; + }; + void *dummy_align; +}; + +union d3d12_depth_stencil_format_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + DXGI_FORMAT depth_stencil_format; + }; + void *dummy_align; +}; + +union d3d12_sample_desc_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + DXGI_SAMPLE_DESC sample_desc; + }; + void *dummy_align; +}; + +union d3d12_node_mask_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + UINT node_mask; + }; + void *dummy_align; +}; + +union d3d12_cached_pso_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_CACHED_PIPELINE_STATE cached_pso; + }; + void *dummy_align; +}; + +union d3d12_flags_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_PIPELINE_STATE_FLAGS flags; + }; + void *dummy_align; +}; + +union d3d12_depth_stencil1_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_DEPTH_STENCIL_DESC1 depth_stencil_desc; + }; + void *dummy_align; +}; + +union d3d12_view_instancing_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_VIEW_INSTANCING_DESC view_instancing_desc; + }; + void *dummy_align; +}; + +static void test_create_pipeline_state(void) +{ + D3D12_ROOT_SIGNATURE_DESC root_signature_desc; + ID3D12RootSignature *root_signature; + ID3D12PipelineState *pipeline_state; + ID3D12Device2 *device2; + ID3D12Device *device; + unsigned int i; + ULONG refcount; + HRESULT hr; + + static const DWORD cs_code[] = + { +#if 0 + [numthreads(1, 1, 1)] + void main() { } +#endif + 0x43425844, 0x1acc3ad0, 0x71c7b057, 0xc72c4306, 0xf432cb57, 0x00000001, 0x00000074, 0x00000003, + 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, + 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x00000020, 0x00050050, 0x00000008, 0x0100086a, + 0x0400009b, 0x00000001, 0x00000001, 0x00000001, 0x0100003e, + }; + + static const DWORD vs_code[] = + { +#if 0 + float4 main(float4 pos : POS) : SV_POSITION { + return pos; + } +#endif + 0x43425844, 0xd0f999d3, 0x5250b8b9, 0x32f55488, 0x0498c795, 0x00000001, 0x000000d4, 0x00000003, + 0x0000002c, 0x00000058, 0x0000008c, 0x4e475349, 0x00000024, 0x00000001, 0x00000008, 0x00000020, + 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x00534f50, 0x4e47534f, 0x0000002c, + 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, + 0x505f5653, 0x5449534f, 0x004e4f49, 0x58454853, 0x00000040, 0x00010050, 0x00000010, 0x0100086a, + 0x0300005f, 0x001010f2, 0x00000000, 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x05000036, + 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x0100003e, + }; + + static const DWORD ps_code[] = + { +#if 0 + float4 main() : SV_TARGET { + return float4(1.0f, 1.0f, 1.0f, 1.0f); + } +#endif + 0x43425844, 0x29b14cf3, 0xb991cf90, 0x9e455ffc, 0x4675b046, 0x00000001, 0x000000b4, 0x00000003, + 0x0000002c, 0x0000003c, 0x00000070, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, + 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003, 0x00000000, + 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x58454853, 0x0000003c, 0x00000050, 0x0000000f, + 0x0100086a, 0x03000065, 0x001020f2, 0x00000000, 0x08000036, 0x001020f2, 0x00000000, 0x00004002, + 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x0100003e, + }; + + static const union d3d12_root_signature_subobject root_signature_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE, + NULL, /* fill in dynamically */ + }}; + + static const union d3d12_shader_bytecode_subobject vs_subobject = {{ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS, { vs_code, sizeof(vs_code) } }}; + static const union d3d12_shader_bytecode_subobject ps_subobject = {{ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS, { ps_code, sizeof(ps_code) } }}; + static const union d3d12_shader_bytecode_subobject cs_subobject = {{ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS, { cs_code, sizeof(cs_code) } }}; + + static const D3D12_SO_DECLARATION_ENTRY so_entries[] = + { + { 0, "SV_POSITION", 0, 0, 4, 0 }, + }; + + static const UINT so_strides[] = { 16u }; + + static const union d3d12_stream_output_subobject stream_output_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT, + { so_entries, ARRAY_SIZE(so_entries), + so_strides, ARRAY_SIZE(so_strides), + D3D12_SO_NO_RASTERIZED_STREAM }, + }}; + + static const union d3d12_blend_subobject blend_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND, + { FALSE, TRUE, + {{ FALSE, FALSE, + D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, + D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, + D3D12_LOGIC_OP_NOOP, 0xf }}, + } + }}; + + static const union d3d12_sample_mask_subobject sample_mask_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK, + 0xffffffffu + }}; + + static const union d3d12_rasterizer_subobject rasterizer_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER, + { D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_BACK, + FALSE, 0, 0.0f, 0.0f, TRUE, FALSE, FALSE, 0, + D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF }, + }}; + + static const union d3d12_depth_stencil_subobject depth_stencil_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL, + { TRUE, D3D12_DEPTH_WRITE_MASK_ALL, D3D12_COMPARISON_FUNC_LESS_EQUAL, TRUE, 0xff, 0xff, + { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_INCR, D3D12_COMPARISON_FUNC_EQUAL }, + { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_INCR, D3D12_COMPARISON_FUNC_EQUAL } }, + }}; + + static const D3D12_INPUT_ELEMENT_DESC input_elements[] = + { + { "POS", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + }; + + static const union d3d12_input_layout_subobject input_layout_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT, + { input_elements, ARRAY_SIZE(input_elements) }, + }}; + + static const union d3d12_ib_strip_cut_value_subobject ib_strip_cut_value_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE, + D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF, + }}; + + static const union d3d12_primitive_topology_subobject primitive_topology_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY, + D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, + }}; + + static const union d3d12_render_target_formats_subobject render_target_formats_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS, + { { DXGI_FORMAT_R8G8B8A8_UNORM }, 1 }, + }}; + + static const union d3d12_depth_stencil_format_subobject depth_stencil_format_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT, + }}; + + static const union d3d12_sample_desc_subobject sample_desc_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC, + { 1, 0 }, + }}; + + static const union d3d12_node_mask_subobject node_mask_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK, + 0x0, + }}; + + static const union d3d12_cached_pso_subobject cached_pso_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO, + { NULL, 0 }, + }}; + + static const union d3d12_flags_subobject flags_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS, + D3D12_PIPELINE_STATE_FLAG_NONE, + }}; + + static const union d3d12_depth_stencil1_subobject depth_stencil1_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1, + { TRUE, D3D12_DEPTH_WRITE_MASK_ALL, D3D12_COMPARISON_FUNC_LESS_EQUAL, TRUE, 0xff, 0xff, + { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_INCR, D3D12_COMPARISON_FUNC_EQUAL }, + { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_INCR, D3D12_COMPARISON_FUNC_EQUAL } }, + }}; + + static const union d3d12_view_instancing_subobject view_instancing_subobject = + {{ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING, + { 0, NULL, D3D12_VIEW_INSTANCING_FLAG_NONE }, + }}; + + struct + { + union d3d12_root_signature_subobject root_signature; + union d3d12_shader_bytecode_subobject vertex_shader; + union d3d12_shader_bytecode_subobject pixel_shader; + union d3d12_blend_subobject blend; + union d3d12_sample_mask_subobject sample_mask; + union d3d12_rasterizer_subobject rasterizer; + union d3d12_depth_stencil1_subobject depth_stencil; + union d3d12_input_layout_subobject input_layout; + union d3d12_ib_strip_cut_value_subobject strip_cut; + union d3d12_primitive_topology_subobject primitive_topology; + union d3d12_render_target_formats_subobject render_target_formats; + union d3d12_depth_stencil_format_subobject depth_stencil_format; + union d3d12_sample_desc_subobject sample_desc; + union d3d12_node_mask_subobject node_mask; + union d3d12_cached_pso_subobject cached_pso; + union d3d12_flags_subobject flags; + union d3d12_view_instancing_subobject view_instancing; + } + pipeline_desc_1 = + { + root_signature_subobject, + vs_subobject, + ps_subobject, + blend_subobject, + sample_mask_subobject, + rasterizer_subobject, + depth_stencil1_subobject, + input_layout_subobject, + ib_strip_cut_value_subobject, + primitive_topology_subobject, + render_target_formats_subobject, + depth_stencil_format_subobject, + sample_desc_subobject, + node_mask_subobject, + cached_pso_subobject, + flags_subobject, + view_instancing_subobject, + }; + + struct + { + union d3d12_root_signature_subobject root_signature; + union d3d12_shader_bytecode_subobject compute_shader; + } + pipeline_desc_2 = + { + root_signature_subobject, cs_subobject, + }; + + struct + { + union d3d12_root_signature_subobject root_signature; + union d3d12_shader_bytecode_subobject vertex_shader; + union d3d12_stream_output_subobject stream_output; + union d3d12_input_layout_subobject input_layout; + } + pipeline_desc_3 = + { + root_signature_subobject, vs_subobject, stream_output_subobject, + input_layout_subobject, + }; + + struct + { + union d3d12_root_signature_subobject root_signature; + } + pipeline_desc_4 = + { + root_signature_subobject, + }; + + struct + { + union d3d12_root_signature_subobject root_signature; + union d3d12_shader_bytecode_subobject cs; + union d3d12_shader_bytecode_subobject vs; + } + pipeline_desc_5 = + { + root_signature_subobject, cs_subobject, vs_subobject, + }; + + struct + { + union d3d12_root_signature_subobject root_signature; + union d3d12_shader_bytecode_subobject cs; + union d3d12_shader_bytecode_subobject ps; + union d3d12_rasterizer_subobject rasterizer; + } + pipeline_desc_6 = + { + root_signature_subobject, cs_subobject, ps_subobject, + rasterizer_subobject, + }; + + struct + { + union d3d12_root_signature_subobject root_signature; + union d3d12_depth_stencil_subobject depth_stencil; + union d3d12_depth_stencil_format_subobject depth_stencil_format; + union d3d12_input_layout_subobject input_layout; + union d3d12_shader_bytecode_subobject vertex_shader; + } + pipeline_desc_7 = + { + root_signature_subobject, depth_stencil_subobject, depth_stencil_format_subobject, + input_layout_subobject, vs_subobject, + }; + + struct + { + union d3d12_root_signature_subobject root_signature; + union d3d12_shader_bytecode_subobject cs; + union d3d12_shader_bytecode_subobject cs2; + } + pipeline_desc_8 = + { + root_signature_subobject, cs_subobject, cs_subobject, + }; + + struct + { + union d3d12_root_signature_subobject root_signature; + union d3d12_shader_bytecode_subobject vs; + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE extra_type; + } + pipeline_desc_9 = + { + root_signature_subobject, vs_subobject, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL + }; + + struct + { + D3D12_PIPELINE_STATE_STREAM_DESC stream_desc; + HRESULT expected_result; + } + tests[] = { + { { sizeof(pipeline_desc_1), &pipeline_desc_1 }, S_OK }, + { { sizeof(pipeline_desc_2), &pipeline_desc_2 }, S_OK }, + { { sizeof(pipeline_desc_3), &pipeline_desc_3 }, S_OK }, + { { sizeof(pipeline_desc_4), &pipeline_desc_4 }, E_INVALIDARG }, + { { sizeof(pipeline_desc_5), &pipeline_desc_5 }, E_INVALIDARG }, + { { sizeof(pipeline_desc_6), &pipeline_desc_6 }, S_OK }, + { { sizeof(pipeline_desc_7), &pipeline_desc_7 }, S_OK }, + { { sizeof(pipeline_desc_8), &pipeline_desc_8 }, E_INVALIDARG }, + { { sizeof(pipeline_desc_9), &pipeline_desc_9 }, E_INVALIDARG }, + }; + + if (!(device = create_device())) + { + skip("Failed to create device.\n"); + return; + } + + if (ID3D12Device_QueryInterface(device, &IID_ID3D12Device2, (void **)&device2)) + { + skip("ID3D12Device2 not supported.\n"); + ID3D12Device_Release(device); + return; + } + + root_signature_desc.NumParameters = 0; + root_signature_desc.pParameters = NULL; + root_signature_desc.NumStaticSamplers = 0; + root_signature_desc.pStaticSamplers = NULL; + root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT | + D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + hr = create_root_signature(device, &root_signature_desc, &root_signature); + ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + union d3d12_root_signature_subobject *rs_subobject; + vkd3d_test_push_context("Test %u", i); + + /* Assign root signature. To keep things simple, assume that the root + * signature is always the first element in each pipeline stream */ + rs_subobject = tests[i].stream_desc.pPipelineStateSubobjectStream; + + if (rs_subobject && rs_subobject->type == D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE) + rs_subobject->root_signature = root_signature; + + hr = ID3D12Device2_CreatePipelineState(device2, &tests[i].stream_desc, &IID_ID3D12PipelineState, (void **)&pipeline_state); + ok(hr == tests[i].expected_result, "Got unexpected return value %#x.\n", hr); + + if (hr == S_OK) + { + refcount = ID3D12PipelineState_Release(pipeline_state); + ok(!refcount, "ID3D12PipelineState has %u references left.\n", (unsigned int)refcount); + } + + vkd3d_test_pop_context(); + } + + refcount = ID3D12RootSignature_Release(root_signature); + ok(!refcount, "ID3D12RootSignature has %u references left.\n", (unsigned int)refcount); + refcount = ID3D12Device2_Release(device2); + ok(refcount == 1, "ID3D12Device2 has %u references left.\n", (unsigned int)refcount); + refcount = ID3D12Device_Release(device); + ok(!refcount, "ID3D12Device has %u references left.\n", (unsigned int)refcount); +} + static void test_create_fence(void) { ID3D12Device *device, *tmp_device; @@ -36997,6 +37567,7 @@ START_TEST(d3d12) run_test(test_root_signature_limits); run_test(test_create_compute_pipeline_state); run_test(test_create_graphics_pipeline_state); + run_test(test_create_pipeline_state); run_test(test_create_fence); run_test(test_object_interface); run_test(test_multithread_private_data);
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d/device.c | 4 +--- libs/vkd3d/state.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 998df40c7..b6c3d11a5 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -1522,9 +1522,7 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, device->feature_options1.ExpandedComputeResourceStates = TRUE; device->feature_options1.Int64ShaderOps = features->shaderInt64;
- /* Depth bounds test is enabled in D3D12_DEPTH_STENCIL_DESC1, which is not - * supported. */ - device->feature_options2.DepthBoundsTestSupported = FALSE; + device->feature_options2.DepthBoundsTestSupported = features->depthBounds; /* d3d12_command_list_SetSamplePositions() is not implemented. */ device->feature_options2.ProgrammableSamplePositionsTier = D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED;
diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index f6dd3917a..479d93f6a 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -2708,7 +2708,7 @@ static void ds_desc_from_d3d12(struct VkPipelineDepthStencilStateCreateInfo *vk_ vk_desc->depthWriteEnable = VK_FALSE; vk_desc->depthCompareOp = VK_COMPARE_OP_NEVER; } - vk_desc->depthBoundsTestEnable = VK_FALSE; + vk_desc->depthBoundsTestEnable = d3d12_desc->DepthBoundsTestEnable; if ((vk_desc->stencilTestEnable = d3d12_desc->StencilEnable)) { vk_stencil_op_state_from_d3d12(&vk_desc->front, &d3d12_desc->FrontFace, @@ -3117,6 +3117,12 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s graphics->rt_count = rt_count;
ds_desc_from_d3d12(&graphics->ds_desc, &desc->depth_stencil_state); + if (graphics->ds_desc.depthBoundsTestEnable && !device->feature_options2.DepthBoundsTestSupported) + { + WARN("Depth bounds test not supported by device.\n"); + hr = E_INVALIDARG; + goto fail; + } if (desc->dsv_format == DXGI_FORMAT_UNKNOWN && graphics->ds_desc.depthTestEnable && !graphics->ds_desc.depthWriteEnable && graphics->ds_desc.depthCompareOp == VK_COMPARE_OP_ALWAYS && !graphics->ds_desc.stencilTestEnable) @@ -3126,7 +3132,8 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s }
graphics->dsv_format = VK_FORMAT_UNDEFINED; - if (graphics->ds_desc.depthTestEnable || graphics->ds_desc.stencilTestEnable) + if (graphics->ds_desc.depthTestEnable || graphics->ds_desc.stencilTestEnable + || graphics->ds_desc.depthBoundsTestEnable) { if (desc->dsv_format == DXGI_FORMAT_UNKNOWN) {
-struct D3D12_RT_FORMAT_ARRAY +typedef struct D3D12_RT_FORMAT_ARRAY { DXGI_FORMAT RTFormats[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT]; UINT NumRenderTargets; -}; +} D3D12_RT_FORMAT_ARRAY;
That should be a separate change.
- if (FAILED(hr = d3d12_pipeline_state_create_graphics(device, desc, &object))) + if (FAILED(hr = pipeline_state_desc_from_d3d12_graphics_desc(&pipeline_desc, desc))) + return hr; + + if (FAILED(hr = d3d12_pipeline_state_create_graphics(device, &pipeline_desc, &object))) return hr;
It seems a fair bit nicer to keep d3d12_device_CreateGraphicsPipelineState() the way it is, and then do the conversion from D3D12_GRAPHICS_PIPELINE_STATE_DESC to d3d12_pipeline_state_desc inside d3d12_pipeline_state_create_graphics(). Likewise for d3d12_pipeline_state_create_compute() and d3d12_pipeline_state_create().
This commit can probably also be split a little; for example, the d3d12_pipeline_state_init_compute() changes don't depend on the d3d12_pipeline_state_init_graphics() changes, and the d3d12_pipeline_state_init_graphics() changes don't depend on pipeline_state_desc_from_d3d12_stream_desc().
+static void d3d12_promote_depth_stencil_desc(D3D12_DEPTH_STENCIL_DESC1 *dst, const D3D12_DEPTH_STENCIL_DESC *src) +{ + dst->DepthEnable = src->DepthEnable; + dst->DepthWriteMask = src->DepthWriteMask; + dst->DepthFunc = src->DepthFunc; + dst->StencilEnable = src->StencilEnable; + dst->StencilReadMask = src->StencilReadMask; + dst->StencilWriteMask = src->StencilWriteMask; + dst->FrontFace = src->FrontFace; + dst->BackFace = src->BackFace; + dst->DepthBoundsTestEnable = FALSE; +}
We'd typically implement that as something like this:
```c memcpy(dst, src, sizeof(*src)); dst->DepthBoundsTestEnable = FALSE; ```
and then likely just inline it in pipeline_state_desc_from_d3d12_graphics_desc() where we could drop the "DepthBoundsTestEnable" assignment because "desc" was zero-initialised.
+static VkShaderStageFlags pipeline_state_desc_get_shader_stages(const struct d3d12_pipeline_state_desc *desc) +{ + VkShaderStageFlags result = 0; + + if (desc->vs.BytecodeLength && desc->vs.pShaderBytecode) + result |= VK_SHADER_STAGE_VERTEX_BIT; + if (desc->hs.BytecodeLength && desc->hs.pShaderBytecode) + result |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + if (desc->ds.BytecodeLength && desc->ds.pShaderBytecode) + result |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + if (desc->gs.BytecodeLength && desc->gs.pShaderBytecode) + result |= VK_SHADER_STAGE_GEOMETRY_BIT; + if (desc->ps.BytecodeLength && desc->ps.pShaderBytecode) + result |= VK_SHADER_STAGE_FRAGMENT_BIT; + if (desc->cs.BytecodeLength && desc->cs.pShaderBytecode) + result |= VK_SHADER_STAGE_COMPUTE_BIT; + + /* If we use rasterizer discard, force fragment shader to not exist. + * See VUID-VkGraphicsPipelineCreateInfo-pStages-06894. */ + if (desc->stream_output.NumEntries && + desc->stream_output.RasterizedStream == D3D12_SO_NO_RASTERIZED_STREAM) + { + result &= ~VK_SHADER_STAGE_FRAGMENT_BIT; + }
How would we trigger that? We use this to set "defined_stages" in pipeline_state_desc_from_d3d12_stream_desc(), but that never checks VK_SHADER_STAGE_FRAGMENT_BIT. In fact, it only really seems to care about VK_SHADER_STAGE_VERTEX_BIT and VK_SHADER_STAGE_COMPUTE_BIT.
+#define DCL_SUBOBJECT_INFO(type, field) {__alignof__(type), sizeof(type), offsetof(struct d3d12_pipeline_state_desc, field)}
I don't think we need this outside subject_info[]. I.e., we can do something like this:
```c static const struct { ... } subobject_info[] = { #define DCL_SUBOBJECT_INFO(type, field) ... ... #undef DCL_SUBOBJECT_INFO }; ```
+ const char *stream_ptr, *stream_end;
uint8_t, probably.
+ /* Structs are packed, but padded so that their size + * is always a multiple of the size of a pointer. */ + stream_ptr = d3d12_desc->pPipelineStateSubobjectStream; + stream_end = stream_ptr + d3d12_desc->SizeInBytes; + desc_char = (char *)desc;
I.e., "Stream packets are aligned to the size of pointers.", right? In any case, this doesn't necessarily seem like the ideal place for this comment; it would seem more appropriate right before we align(i + size, ...) in the loop further below.
+ subobject_type = *(const D3D12_PIPELINE_STATE_SUBOBJECT_TYPE *)stream_ptr; + subobject_bit = 1ull << subobject_type;
This only works for subobject types smaller than 64, of course. In principle that's fine, but we only validate the subobject type a few lines later, which is a little ugly.
+ if (stream_ptr + i + size > stream_end) + { + WARN("Invalid pipeline state stream.\n"); + return E_INVALIDARG; + }
It's probably fine in practice, but this kind of thing is always a bit of a trigger when reviewing code. It seems nicer to use vkd3d_bound_range(), here and in the similar comparison at the start of the loop.
+union d3d12_root_signature_subobject +{ + struct + { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + ID3D12RootSignature *root_signature; + }; + void *dummy_align; +};
Do we need "dummy_align"? Could we use DECLSPEC_ALIGN? Could we make these unions local to test_create_pipeline_state()? I don't think we need them at the top level, right?
The placement of "{" and "}" is a bit unusual in a few places in the test. For example in the tests[] declaration.