This commit is contained in:
elwrcl committed 2026-06-06 13:25:15 +03:00
1 parent 04d4dc8b09
commit 818cab85dc
12511 files changed
+6156641

No files matched your search

+14
View File
@@ -0,0 +1,14 @@
[[deqp]]
deqp = "/deqp/external/vulkancts/modules/vulkan/deqp-vk.exe"
deqp_args = [
"--deqp-surface-width=256",
"--deqp-surface-height=256",
"--deqp-surface-type=pbuffer",
"--deqp-gl-config-name=rgba8888d24s8ms0",
"--deqp-visibility=hidden",
]
caselists = ["/deqp/mustpass/vk-main.txt"]
skips = ["./_install/warp-skips.txt"]
flakes = ["./_install/warp-flakes.txt"]
renderer_check = 'Microsoft Direct3D12 \(Microsoft Basic Render Driver\)'
tests_per_group = 5000
+87
View File
@@ -0,0 +1,87 @@
.windows-docker-tags:
tags:
- windows
- docker
- "2022"
- mesa
.windows-shell-tags:
tags:
- windows
- shell
- "2022"
- mesa
# Unfortunately YAML doesn't let us concatenate arrays, so we have to do the
# rules duplication manually
.windows-build-rules:
rules:
- !reference [.scheduled_pipeline-rules, rules]
- !reference [.build-rules, rules]
- !reference [.microsoft-farm-rules, rules]
- !reference [.zink-common-rules, rules]
- !reference [.vulkan-rules, rules]
- !reference [.softpipe-rules, rules]
- !reference [.lavapipe-rules, rules]
- changes: &d3d12_file_list
- src/gallium/drivers/d3d12/**/*
- src/gallium/frontends/wgl/*
- src/gallium/winsys/d3d12/wgl/*
- src/gallium/targets/libgl-gdi/*
- src/gallium/targets/libgl-d3d12/*
when: on_success
- changes:
- src/microsoft/**/*
- src/gallium/frontends/va/*
- src/gallium/targets/va/*
when: on_success
- !reference [.radv-rules, rules]
.glon12-test-rules:
rules:
- !reference [.test, rules]
- !reference [.microsoft-farm-rules, rules]
- !reference [.gl-rules, rules]
- changes: *d3d12_file_list
when: on_success
- changes:
- src/microsoft/compiler/*
when: on_success
.spirv2dxil-test-rules:
rules:
- !reference [.test, rules]
- !reference [.microsoft-farm-rules, rules]
- !reference [.core-rules, rules]
- changes: &spirv2dxil_file_list
- src/microsoft/ci/*
- src/microsoft/compiler/*
- src/microsoft/spirv_to_dxil/*
when: on_success
.dozen-test-rules:
rules:
- !reference [.test, rules]
- !reference [.microsoft-farm-rules, rules]
- !reference [.vulkan-rules, rules]
- changes:
*spirv2dxil_file_list
when: on_success
- changes:
- src/microsoft/vulkan/*
when: on_success
.dozen-manual-rules:
stage: layered-backends-nightly
extends: .no-auto-retry
rules:
- !reference [.test, rules]
- !reference [.microsoft-farm-manual-rules, rules]
- !reference [.vulkan-manual-rules, rules]
- changes:
*spirv2dxil_file_list
when: manual
- changes:
- src/microsoft/vulkan/*
when: manual
+59
View File
@@ -0,0 +1,59 @@
include:
- local: 'src/microsoft/ci/gitlab-ci-inc.yml'
test-spirv2dxil-windows:
extends:
- .use-windows_test_msvc
- .spirv2dxil-test-rules
stage: layered-backends
timeout: 15m
dependencies:
- windows-msvc
needs:
- job: windows-msvc
- job: windows_test_msvc
optional: true
variables:
GIT_STRATEGY: none # testing doesn't build anything from source
script:
- . _install/spirv2dxil_run.ps1
artifacts:
when: on_failure
name: "${CI_PROJECT_NAME}_${CI_JOB_NAME_SLUG}"
paths:
- spirv2dxil_results.txt
test-dozen-deqp:
extends:
- .use-windows_test_msvc
- .dozen-test-rules
stage: layered-backends
timeout: 15m
dependencies:
- windows-msvc
needs:
- job: windows-msvc
- job: windows_test_msvc
optional: true
variables:
GIT_STRATEGY: none # testing doesn't build anything from source
DZN_AGILITY_RELATIVE_PATH: "D3D12\\"
DZN_AGILITY_SDK_VERSION: 619
DEQP_FRACTION: 4
script:
- . _install/deqp_runner_run.ps1
artifacts:
when: on_failure
name: "${CI_PROJECT_NAME}_${CI_JOB_NAME_SLUG}"
paths:
- results/
reports:
junit: results/junit.xml
test-dozen-deqp-full:
extends:
- test-dozen-deqp
- .dozen-manual-rules
timeout: 1h
variables:
DEQP_FRACTION: 1
File diff suppressed because it is too large. Load diff
+16
View File
@@ -0,0 +1,16 @@
# The CTS expects OpKill to terminate shaders while the spec allows it to be implemented
# as OpDemoteToHelperInvocation. Wait for pending CTS fix.
dEQP-VK.graphicsfuzz.while-inside-switch,Fail
# Appeared after decreasing the fraction
dEQP-VK.api.driver_properties.conformance_version,Fail
dEQP-VK.info.device_extensions,Fail
dEQP-VK.wsi.win32.swapchain.create.composite_alpha,Fail
dEQP-VK.wsi.win32.swapchain.simulate_oom.composite_alpha,Fail
# Seen in https://gitlab.freedesktop.org/mesa/mesa/-/pipelines/1364513
dEQP-VK.api.device_init.create_instance_name_version.basic,Crash
dEQP-VK.api.info.extension_core_versions.extension_core_versions,Fail
# WARP bug in fp64 ffma code, running on hw or a WARP update fixes it
dEQP-VK.glsl.builtin.precision_double.mix.compute.vec3,Fail
+4
View File
@@ -0,0 +1,4 @@
dEQP-VK.query_pool.concurrent_queries.primary_command_buffer
dEQP-VK.memory.mapping.suballocation.full.variable.implicit_unmap
dEQP-VK.ubo.3_level_array.std430.row_major_mat4.fragment_comp_access
dEQP-VK.api.command_buffers.record_many_draws_secondary_2
+7
View File
@@ -0,0 +1,7 @@
# If the Windows runner becomes sluggish due to external load, such as
# gstreamer, it can cause the tests to exceed their time limit.
dEQP-VK.api.object_management.multithreaded_per_thread_resources.device_group
dEQP-VK.ubo.3_level_array.scalar.column_major_mat4.both_comp_access
dEQP-VK.ubo.3_level_array.std140.row_major_mat4.both
dEQP-VK.memory.pipeline_barrier.host_write_uniform_buffer.1048576
dEQP-VK.api.device_init.create_instance_device_intentional_alloc_fail.*
File diff suppressed because it is too large. Load diff
+179
View File
@@ -0,0 +1,179 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef CLC_COMPILER_H
#define CLC_COMPILER_H
#include "clc/clc.h"
#include "dxil_versions.h"
#ifdef __cplusplus
extern "C" {
#endif
#define CLC_MAX_CONSTS 32
#define CLC_MAX_BINDINGS_PER_ARG 3
#define CLC_MAX_SAMPLERS 16
struct clc_printf_info {
unsigned num_args;
unsigned *arg_sizes;
char *str;
};
struct clc_dxil_metadata {
struct {
unsigned offset;
unsigned size;
union {
struct {
unsigned buf_ids[CLC_MAX_BINDINGS_PER_ARG];
unsigned num_buf_ids;
} image;
struct {
unsigned sampler_id;
} sampler;
struct {
unsigned buf_id;
} globconstptr;
struct {
unsigned sharedmem_offset;
} localptr;
};
} *args;
unsigned kernel_inputs_cbv_id;
unsigned kernel_inputs_buf_size;
unsigned work_properties_cbv_id;
size_t num_uavs;
size_t num_srvs;
size_t num_samplers;
struct {
void *data;
size_t size;
unsigned uav_id;
} consts[CLC_MAX_CONSTS];
size_t num_consts;
struct {
unsigned sampler_id;
unsigned addressing_mode;
unsigned normalized_coords;
unsigned filter_mode;
} const_samplers[CLC_MAX_SAMPLERS];
size_t num_const_samplers;
size_t local_mem_size;
size_t priv_mem_size;
uint16_t local_size[3];
uint16_t local_size_hint[3];
struct {
unsigned info_count;
struct clc_printf_info *infos;
int uav_id;
} printf;
};
struct clc_dxil_object {
const struct clc_kernel_info *kernel;
struct clc_dxil_metadata metadata;
struct {
void *data;
size_t size;
} binary;
};
struct clc_runtime_arg_info {
union {
struct {
unsigned size;
} localptr;
struct {
unsigned normalized_coords;
unsigned addressing_mode; /* See SPIR-V spec for value meanings */
unsigned linear_filtering;
} sampler;
};
};
struct clc_runtime_kernel_conf {
uint16_t local_size[3];
struct clc_runtime_arg_info *args;
unsigned lower_bit_size;
unsigned support_global_work_id_offsets;
unsigned support_workgroup_id_offsets;
enum dxil_shader_model max_shader_model;
enum dxil_validator_version validator_version;
};
struct clc_libclc_dxil_options {
unsigned optimize;
};
struct clc_libclc *
clc_libclc_new_dxil(const struct clc_logger *logger,
const struct clc_libclc_dxil_options *dxil_options);
bool
clc_spirv_to_dxil(struct clc_libclc *lib,
const struct clc_binary *linked_spirv,
const struct clc_parsed_spirv *parsed_data,
const char *entrypoint,
const struct clc_runtime_kernel_conf *conf,
const struct clc_spirv_specialization_consts *consts,
const struct clc_logger *logger,
struct clc_dxil_object *out_dxil);
void clc_free_dxil_object(struct clc_dxil_object *dxil);
/* This struct describes the layout of data expected in the CB bound at global_work_offset_cbv_id */
struct clc_work_properties_data {
/* Returned from get_global_offset(), and added into get_global_id() */
unsigned global_offset_x;
unsigned global_offset_y;
unsigned global_offset_z;
/* Returned from get_work_dim() */
unsigned work_dim;
/* The number of work groups being launched (i.e. the parameters to Dispatch).
* If the requested global size doesn't fit in a single Dispatch, these values should
* indicate the total number of groups that *should* have been launched. */
unsigned group_count_total_x;
unsigned group_count_total_y;
unsigned group_count_total_z;
unsigned padding;
/* If the requested global size doesn't fit in a single Dispatch, subsequent dispatches
* should fill out these offsets to indicate how many groups have already been launched */
unsigned group_id_offset_x;
unsigned group_id_offset_y;
unsigned group_id_offset_z;
};
uint64_t clc_compiler_get_version(void);
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large. Load diff
+268
View File
@@ -0,0 +1,268 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "util/u_math.h"
#include "nir.h"
#include "glsl_types.h"
#include "nir_builder.h"
#include "nir_deref.h"
#include "clc_nir.h"
#include "clc_compiler.h"
#include "../compiler/dxil_nir.h"
static nir_def *
load_ubo(nir_builder *b, nir_intrinsic_instr *intr, nir_variable *var, unsigned offset)
{
return nir_load_ubo(b,
intr->def.num_components,
intr->def.bit_size,
nir_imm_int(b, var->data.binding),
nir_imm_int(b, offset),
.align_mul = 256,
.align_offset = offset,
.range_base = offset,
.range = intr->def.bit_size * intr->def.num_components / 8);
}
static bool
is_clc_system_value(const nir_instr *instr, const void *state)
{
if (instr->type != nir_instr_type_intrinsic)
return false;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
switch (intr->intrinsic) {
case nir_intrinsic_load_base_global_invocation_id:
case nir_intrinsic_load_work_dim:
case nir_intrinsic_load_num_workgroups:
case nir_intrinsic_load_base_workgroup_id:
return true;
default:
return false;
}
}
static nir_def *
lower_clc_system_value(nir_builder *b, nir_instr *instr, void *state)
{
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
nir_variable *var = (nir_variable *)state;
switch (intr->intrinsic) {
case nir_intrinsic_load_base_global_invocation_id:
return load_ubo(b, intr, var, offsetof(struct clc_work_properties_data, global_offset_x));
case nir_intrinsic_load_work_dim:
return load_ubo(b, intr, var, offsetof(struct clc_work_properties_data, work_dim));
case nir_intrinsic_load_num_workgroups:
return load_ubo(b, intr, var, offsetof(struct clc_work_properties_data, group_count_total_x));
case nir_intrinsic_load_base_workgroup_id:
return load_ubo(b, intr, var, offsetof(struct clc_work_properties_data, group_id_offset_x));
default:
return NULL;
}
}
bool
clc_nir_lower_system_values(nir_shader *nir, nir_variable *var)
{
return nir_shader_lower_instructions(nir, is_clc_system_value, lower_clc_system_value, var);
}
static bool
is_load_kernel_input(const nir_instr *instr, const void *state)
{
return instr->type == nir_instr_type_intrinsic &&
nir_instr_as_intrinsic(instr)->intrinsic == nir_intrinsic_load_kernel_input;
}
static nir_def *
lower_load_kernel_input(nir_builder *b, nir_instr *instr, void *state)
{
nir_variable *var = (nir_variable *)state;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
unsigned bit_size = intr->def.bit_size;
enum glsl_base_type base_type;
switch (bit_size) {
case 64:
base_type = GLSL_TYPE_UINT64;
break;
case 32:
base_type = GLSL_TYPE_UINT;
break;
case 16:
base_type = GLSL_TYPE_UINT16;
break;
case 8:
base_type = GLSL_TYPE_UINT8;
break;
default:
UNREACHABLE("invalid bit size");
}
const struct glsl_type *type =
glsl_vector_type(base_type, intr->def.num_components);
nir_def *ptr = nir_vec2(b, nir_imm_int(b, var->data.binding),
nir_u2uN(b, intr->src[0].ssa, 32));
nir_deref_instr *deref = nir_build_deref_cast(b, ptr, nir_var_mem_ubo, type,
bit_size / 8);
deref->cast.align_mul = nir_intrinsic_align_mul(intr);
deref->cast.align_offset = nir_intrinsic_align_offset(intr);
return nir_load_deref(b, deref);
}
bool
clc_nir_lower_kernel_input_loads(nir_shader *nir, nir_variable *var)
{
return nir_shader_lower_instructions(nir, is_load_kernel_input, lower_load_kernel_input, var);
}
static nir_variable *
add_printf_var(struct nir_shader *nir, unsigned uav_id)
{
/* This size is arbitrary. Minimum required per spec is 1MB */
const unsigned max_printf_size = 1 * 1024 * 1024;
const unsigned printf_array_size = max_printf_size / sizeof(unsigned);
nir_variable *var =
nir_variable_create(nir, nir_var_mem_ssbo,
glsl_array_type(glsl_uint_type(), printf_array_size, sizeof(unsigned)),
"printf");
var->data.binding = uav_id;
return var;
}
bool
clc_lower_printf_base(nir_shader *nir, unsigned uav_id)
{
nir_variable *printf_var = NULL;
nir_def *printf_deref = NULL;
nir_foreach_function_impl(impl, nir) {
nir_builder b = nir_builder_at(nir_before_impl(impl));
bool progress = false;
nir_foreach_block(block, impl) {
nir_foreach_instr_safe(instr, block) {
if (instr->type != nir_instr_type_intrinsic)
continue;
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
if (intrin->intrinsic != nir_intrinsic_load_printf_buffer_address)
continue;
if (!printf_var) {
printf_var = add_printf_var(nir, uav_id);
nir_deref_instr *deref = nir_build_deref_var(&b, printf_var);
printf_deref = &deref->def;
}
nir_def_rewrite_uses(&intrin->def, printf_deref);
progress = true;
}
}
nir_progress(progress, impl,
nir_metadata_loop_analysis | nir_metadata_block_index | nir_metadata_dominance);
}
return printf_var != NULL;
}
/* Find patterns of:
* - deref_var for one of the kernel inputs
* - load_deref to get a pointer to global/constant memory
* - cast the pointer into a deref
* - use a basic deref chain that terminates in a load/store/atomic
*
* When this pattern is found, replace the load_deref with a constant value,
* based on which kernel argument is being loaded from. This can only be done
* for chains that terminate in a pointer access, since the presence of null
* pointers should be detected by actually performing the load and inspecting
* the resulting pointer value.
*/
static bool
lower_deref_base_to_constant(nir_builder *b, nir_intrinsic_instr *intr, void *context)
{
switch (intr->intrinsic) {
case nir_intrinsic_load_deref:
case nir_intrinsic_store_deref:
case nir_intrinsic_deref_atomic:
case nir_intrinsic_deref_atomic_swap:
break;
default:
return false;
}
nir_deref_instr *deref = nir_src_as_deref(intr->src[0]);
if (!nir_deref_mode_must_be(deref, nir_var_mem_global | nir_var_mem_constant))
return false;
nir_deref_path path;
nir_deref_path_init(&path, deref, NULL);
bool ret = false;
if (path.path[0]->deref_type != nir_deref_type_cast)
goto done;
if (!nir_deref_mode_must_be(path.path[0], nir_var_mem_global | nir_var_mem_constant))
goto done;
nir_instr *cast_src = nir_def_instr(path.path[0]->parent.ssa);
if (cast_src->type != nir_instr_type_intrinsic)
goto done;
nir_intrinsic_instr *cast_src_intr = nir_instr_as_intrinsic(cast_src);
if (cast_src_intr->intrinsic != nir_intrinsic_load_deref)
goto done;
nir_deref_instr *load_deref_src = nir_src_as_deref(cast_src_intr->src[0]);
if (load_deref_src->deref_type != nir_deref_type_var ||
load_deref_src->modes != nir_var_uniform)
goto done;
nir_variable *var = load_deref_src->var;
ret = true;
b->cursor = nir_before_instr(&path.path[0]->instr);
nir_def *original_offset = nir_unpack_64_2x32_split_x(b, &cast_src_intr->def);
nir_def *constant_ptr = nir_pack_64_2x32_split(b, original_offset, nir_imm_int(b, var->data.binding));
nir_deref_instr *new_path = nir_build_deref_cast_with_alignment(b, constant_ptr, path.path[0]->modes, path.path[0]->type, path.path[0]->cast.ptr_stride,
path.path[0]->cast.align_mul, path.path[0]->cast.align_offset);
for (unsigned i = 1; path.path[i]; ++i) {
b->cursor = nir_after_instr(&path.path[i]->instr);
new_path = nir_build_deref_follower(b, new_path, path.path[i]);
}
nir_src_rewrite(&intr->src[0], &new_path->def);
done:
nir_deref_path_finish(&path);
return ret;
}
bool
clc_nir_lower_global_pointers_to_constants(nir_shader *nir)
{
return nir_shader_intrinsics_pass(nir, lower_deref_base_to_constant,
nir_metadata_control_flow |
nir_metadata_loop_analysis, NULL);
}
+36
View File
@@ -0,0 +1,36 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef CLC_NIR_H
#define CLC_NIR_H
#include <stdbool.h>
#include "nir.h"
bool
clc_nir_lower_system_values(nir_shader *nir, nir_variable *var);
bool clc_nir_lower_kernel_input_loads(nir_shader *nir, nir_variable *var);
bool clc_lower_printf_base(nir_shader *nir, unsigned uav_id);
bool clc_nir_lower_global_pointers_to_constants(nir_shader *nir);
#endif
+18
View File
@@ -0,0 +1,18 @@
EXPORTS
clc_libclc_new_dxil
clc_free_libclc
clc_libclc_serialize
clc_libclc_free_serialized
clc_libclc_deserialize
clc_compile_c_to_spir
clc_free_spir
clc_compile_spir_to_spirv
clc_free_spirv
clc_compile_c_to_spirv
clc_link_spirv
clc_parse_spirv
clc_free_parsed_spirv
clc_specialize_spirv
clc_spirv_to_dxil
clc_free_dxil_object
clc_compiler_get_version
+916
View File
@@ -0,0 +1,916 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdexcept>
#include <unknwn.h>
#include <directx/d3d12.h>
#include <dxgi1_4.h>
#include <gtest/gtest.h>
#include <wrl.h>
#include <dxguids/dxguids.h>
#include "util/u_debug.h"
#include "clc_compiler.h"
#include "compute_test.h"
#include "dxil_validator.h"
#include <spirv-tools/libspirv.hpp>
#if (defined(_WIN32) && defined(_MSC_VER))
inline D3D12_CPU_DESCRIPTOR_HANDLE
GetCPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
{
return heap->GetCPUDescriptorHandleForHeapStart();
}
inline D3D12_GPU_DESCRIPTOR_HANDLE
GetGPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
{
return heap->GetGPUDescriptorHandleForHeapStart();
}
inline D3D12_HEAP_PROPERTIES
GetCustomHeapProperties(ID3D12Device *dev, D3D12_HEAP_TYPE type)
{
return dev->GetCustomHeapProperties(0, type);
}
#else
inline D3D12_CPU_DESCRIPTOR_HANDLE
GetCPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
{
D3D12_CPU_DESCRIPTOR_HANDLE ret;
heap->GetCPUDescriptorHandleForHeapStart(&ret);
return ret;
}
inline D3D12_GPU_DESCRIPTOR_HANDLE
GetGPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
{
D3D12_GPU_DESCRIPTOR_HANDLE ret;
heap->GetGPUDescriptorHandleForHeapStart(&ret);
return ret;
}
inline D3D12_HEAP_PROPERTIES
GetCustomHeapProperties(ID3D12Device *dev, D3D12_HEAP_TYPE type)
{
D3D12_HEAP_PROPERTIES ret;
dev->GetCustomHeapProperties(&ret, 0, type);
return ret;
}
#endif
using std::runtime_error;
using Microsoft::WRL::ComPtr;
enum compute_test_debug_flags {
COMPUTE_DEBUG_EXPERIMENTAL_SHADERS = 1 << 0,
COMPUTE_DEBUG_USE_HW_D3D = 1 << 1,
COMPUTE_DEBUG_OPTIMIZE_LIBCLC = 1 << 2,
COMPUTE_DEBUG_SERIALIZE_LIBCLC = 1 << 3,
};
static const struct debug_named_value compute_debug_options[] = {
{ "experimental_shaders", COMPUTE_DEBUG_EXPERIMENTAL_SHADERS, "Enable experimental shaders" },
{ "use_hw_d3d", COMPUTE_DEBUG_USE_HW_D3D, "Use a hardware D3D device" },
{ "optimize_libclc", COMPUTE_DEBUG_OPTIMIZE_LIBCLC, "Optimize the clc_libclc before using it" },
{ "serialize_libclc", COMPUTE_DEBUG_SERIALIZE_LIBCLC, "Serialize and deserialize the clc_libclc" },
DEBUG_NAMED_VALUE_END
};
DEBUG_GET_ONCE_FLAGS_OPTION(debug_compute, "COMPUTE_TEST_DEBUG", compute_debug_options, 0)
static void warning_callback(void *priv, const char *msg)
{
fprintf(stderr, "WARNING: %s\n", msg);
}
static void error_callback(void *priv, const char *msg)
{
fprintf(stderr, "ERROR: %s\n", msg);
}
static const struct clc_logger logger = {
NULL,
error_callback,
warning_callback,
};
void
ComputeTest::enable_d3d12_debug_layer()
{
HMODULE hD3D12Mod = LoadLibrary("D3D12.DLL");
if (!hD3D12Mod) {
fprintf(stderr, "D3D12: failed to load D3D12.DLL\n");
return;
}
typedef HRESULT(WINAPI * PFN_D3D12_GET_DEBUG_INTERFACE)(REFIID riid,
void **ppFactory);
PFN_D3D12_GET_DEBUG_INTERFACE D3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(hD3D12Mod, "D3D12GetDebugInterface");
if (!D3D12GetDebugInterface) {
fprintf(stderr, "D3D12: failed to load D3D12GetDebugInterface from D3D12.DLL\n");
return;
}
ID3D12Debug *debug;
if (FAILED(D3D12GetDebugInterface(__uuidof(ID3D12Debug), (void **)& debug))) {
fprintf(stderr, "D3D12: D3D12GetDebugInterface failed\n");
return;
}
debug->EnableDebugLayer();
}
IDXGIFactory4 *
ComputeTest::get_dxgi_factory()
{
static const GUID IID_IDXGIFactory4 = {
0x1bc6ea02, 0xef36, 0x464f,
{ 0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a }
};
typedef HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY)(REFIID riid,
void **ppFactory);
PFN_CREATE_DXGI_FACTORY CreateDXGIFactory;
HMODULE hDXGIMod = LoadLibrary("DXGI.DLL");
if (!hDXGIMod)
throw runtime_error("Failed to load DXGI.DLL");
CreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(hDXGIMod, "CreateDXGIFactory");
if (!CreateDXGIFactory)
throw runtime_error("Failed to load CreateDXGIFactory from DXGI.DLL");
IDXGIFactory4 *factory = NULL;
HRESULT hr = CreateDXGIFactory(IID_IDXGIFactory4, (void **)&factory);
if (FAILED(hr))
throw runtime_error("CreateDXGIFactory failed");
return factory;
}
IDXGIAdapter1 *
ComputeTest::choose_adapter(IDXGIFactory4 *factory)
{
IDXGIAdapter1 *ret;
if (debug_get_option_debug_compute() & COMPUTE_DEBUG_USE_HW_D3D) {
for (unsigned i = 0; SUCCEEDED(factory->EnumAdapters1(i, &ret)); i++) {
DXGI_ADAPTER_DESC1 desc;
ret->GetDesc1(&desc);
if (!(desc.Flags & D3D_DRIVER_TYPE_SOFTWARE))
return ret;
}
throw runtime_error("Failed to enum hardware adapter");
} else {
if (FAILED(factory->EnumWarpAdapter(__uuidof(IDXGIAdapter1),
(void **)& ret)))
throw runtime_error("Failed to enum warp adapter");
return ret;
}
}
ID3D12Device *
ComputeTest::create_device(IDXGIAdapter1 *adapter)
{
typedef HRESULT(WINAPI *PFN_D3D12CREATEDEVICE)(IUnknown *, D3D_FEATURE_LEVEL, REFIID, void **);
PFN_D3D12CREATEDEVICE D3D12CreateDevice;
HMODULE hD3D12Mod = LoadLibrary("D3D12.DLL");
if (!hD3D12Mod)
throw runtime_error("failed to load D3D12.DLL");
if (debug_get_option_debug_compute() & COMPUTE_DEBUG_EXPERIMENTAL_SHADERS) {
typedef HRESULT(WINAPI *PFN_D3D12ENABLEEXPERIMENTALFEATURES)(UINT, const IID *, void *, UINT *);
PFN_D3D12ENABLEEXPERIMENTALFEATURES D3D12EnableExperimentalFeatures;
D3D12EnableExperimentalFeatures = (PFN_D3D12ENABLEEXPERIMENTALFEATURES)
GetProcAddress(hD3D12Mod, "D3D12EnableExperimentalFeatures");
if (FAILED(D3D12EnableExperimentalFeatures(1, &D3D12ExperimentalShaderModels, NULL, NULL)))
throw runtime_error("failed to enable experimental shader models");
}
D3D12CreateDevice = (PFN_D3D12CREATEDEVICE)GetProcAddress(hD3D12Mod, "D3D12CreateDevice");
if (!D3D12CreateDevice)
throw runtime_error("failed to load D3D12CreateDevice from D3D12.DLL");
ID3D12Device *dev;
if (FAILED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_12_0,
__uuidof(ID3D12Device), (void **)& dev)))
throw runtime_error("D3D12CreateDevice failed");
return dev;
}
ComPtr<ID3D12RootSignature>
ComputeTest::create_root_signature(const ComputeTest::Resources &resources)
{
D3D12_ROOT_PARAMETER1 root_param;
root_param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
root_param.DescriptorTable.NumDescriptorRanges = resources.ranges.size();
root_param.DescriptorTable.pDescriptorRanges = resources.ranges.data();
root_param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
D3D12_ROOT_SIGNATURE_DESC1 root_sig_desc;
root_sig_desc.NumParameters = 1;
root_sig_desc.pParameters = &root_param;
root_sig_desc.NumStaticSamplers = 0;
root_sig_desc.pStaticSamplers = NULL;
root_sig_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
D3D12_VERSIONED_ROOT_SIGNATURE_DESC versioned_desc;
versioned_desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
versioned_desc.Desc_1_1 = root_sig_desc;
ID3DBlob *sig, *error;
if (FAILED(D3D12SerializeVersionedRootSignature(&versioned_desc,
&sig, &error)))
throw runtime_error("D3D12SerializeVersionedRootSignature failed");
ComPtr<ID3D12RootSignature> ret;
if (FAILED(dev->CreateRootSignature(0,
sig->GetBufferPointer(),
sig->GetBufferSize(),
__uuidof(ID3D12RootSignature),
(void **)& ret)))
throw runtime_error("CreateRootSignature failed");
return ret;
}
ComPtr<ID3D12PipelineState>
ComputeTest::create_pipeline_state(ComPtr<ID3D12RootSignature> &root_sig,
const struct clc_dxil_object &dxil)
{
D3D12_COMPUTE_PIPELINE_STATE_DESC pipeline_desc = { root_sig.Get() };
pipeline_desc.CS.pShaderBytecode = dxil.binary.data;
pipeline_desc.CS.BytecodeLength = dxil.binary.size;
ComPtr<ID3D12PipelineState> pipeline_state;
if (FAILED(dev->CreateComputePipelineState(&pipeline_desc,
__uuidof(ID3D12PipelineState),
(void **)& pipeline_state)))
throw runtime_error("Failed to create pipeline state");
return pipeline_state;
}
ComPtr<ID3D12Resource>
ComputeTest::create_buffer(int size, D3D12_HEAP_TYPE heap_type)
{
D3D12_RESOURCE_DESC desc;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
desc.Width = size;
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Flags = heap_type == D3D12_HEAP_TYPE_DEFAULT ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : D3D12_RESOURCE_FLAG_NONE;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
D3D12_HEAP_PROPERTIES heap_pris = GetCustomHeapProperties(dev, heap_type);
ComPtr<ID3D12Resource> res;
if (FAILED(dev->CreateCommittedResource(&heap_pris,
D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON,
NULL, __uuidof(ID3D12Resource), (void **)&res)))
throw runtime_error("CreateCommittedResource failed");
return res;
}
ComPtr<ID3D12Resource>
ComputeTest::create_upload_buffer_with_data(const void *data, size_t size)
{
auto upload_res = create_buffer(size, D3D12_HEAP_TYPE_UPLOAD);
void *ptr = NULL;
D3D12_RANGE res_range = { 0, (SIZE_T)size };
if (FAILED(upload_res->Map(0, &res_range, (void **)&ptr)))
throw runtime_error("Failed to map upload-buffer");
assert(ptr);
memcpy(ptr, data, size);
upload_res->Unmap(0, &res_range);
return upload_res;
}
ComPtr<ID3D12Resource>
ComputeTest::create_sized_buffer_with_data(size_t buffer_size,
const void *data,
size_t data_size)
{
auto upload_res = create_upload_buffer_with_data(data, data_size);
auto res = create_buffer(buffer_size, D3D12_HEAP_TYPE_DEFAULT);
resource_barrier(res, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST);
cmdlist->CopyBufferRegion(res.Get(), 0, upload_res.Get(), 0, data_size);
resource_barrier(res, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON);
execute_cmdlist();
return res;
}
void
ComputeTest::get_buffer_data(ComPtr<ID3D12Resource> res,
void *buf, size_t size)
{
auto readback_res = create_buffer(align(size, 4), D3D12_HEAP_TYPE_READBACK);
resource_barrier(res, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_SOURCE);
cmdlist->CopyResource(readback_res.Get(), res.Get());
resource_barrier(res, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COMMON);
execute_cmdlist();
void *ptr = NULL;
D3D12_RANGE res_range = { 0, size };
if (FAILED(readback_res->Map(0, &res_range, &ptr)))
throw runtime_error("Failed to map readback-buffer");
memcpy(buf, ptr, size);
D3D12_RANGE empty_range = { 0, 0 };
readback_res->Unmap(0, &empty_range);
}
void
ComputeTest::resource_barrier(ComPtr<ID3D12Resource> &res,
D3D12_RESOURCE_STATES state_before,
D3D12_RESOURCE_STATES state_after)
{
D3D12_RESOURCE_BARRIER barrier;
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = res.Get();
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = state_before;
barrier.Transition.StateAfter = state_after;
cmdlist->ResourceBarrier(1, &barrier);
}
void
ComputeTest::execute_cmdlist()
{
if (FAILED(cmdlist->Close()))
throw runtime_error("Closing ID3D12GraphicsCommandList failed");
ID3D12CommandList *cmdlists[] = { cmdlist };
cmdqueue->ExecuteCommandLists(1, cmdlists);
cmdqueue_fence->SetEventOnCompletion(fence_value, event);
cmdqueue->Signal(cmdqueue_fence, fence_value);
fence_value++;
WaitForSingleObject(event, INFINITE);
if (FAILED(cmdalloc->Reset()))
throw runtime_error("resetting ID3D12CommandAllocator failed");
if (FAILED(cmdlist->Reset(cmdalloc, NULL)))
throw runtime_error("resetting ID3D12GraphicsCommandList failed");
}
void
ComputeTest::create_uav_buffer(ComPtr<ID3D12Resource> res,
size_t width, size_t byte_stride,
D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle)
{
D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc;
uav_desc.Format = DXGI_FORMAT_R32_TYPELESS;
uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
uav_desc.Buffer.FirstElement = 0;
uav_desc.Buffer.NumElements = DIV_ROUND_UP(width * byte_stride, 4);
uav_desc.Buffer.StructureByteStride = 0;
uav_desc.Buffer.CounterOffsetInBytes = 0;
uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
dev->CreateUnorderedAccessView(res.Get(), NULL, &uav_desc, cpu_handle);
}
void
ComputeTest::create_cbv(ComPtr<ID3D12Resource> res, size_t size,
D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle)
{
D3D12_CONSTANT_BUFFER_VIEW_DESC cbv_desc;
cbv_desc.BufferLocation = res ? res->GetGPUVirtualAddress() : 0;
cbv_desc.SizeInBytes = size;
dev->CreateConstantBufferView(&cbv_desc, cpu_handle);
}
ComPtr<ID3D12Resource>
ComputeTest::add_uav_resource(ComputeTest::Resources &resources,
unsigned spaceid, unsigned resid,
const void *data, size_t num_elems,
size_t elem_size)
{
size_t size = align(elem_size * num_elems, 4);
D3D12_CPU_DESCRIPTOR_HANDLE handle;
ComPtr<ID3D12Resource> res;
handle = GetCPUDescriptorHandleForHeapStart(uav_heap);
handle = offset_cpu_handle(handle, resources.descs.size() * uav_heap_incr);
if (size) {
if (data)
res = create_buffer_with_data(data, size);
else
res = create_buffer(size, D3D12_HEAP_TYPE_DEFAULT);
resource_barrier(res, D3D12_RESOURCE_STATE_COMMON,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
}
create_uav_buffer(res, num_elems, elem_size, handle);
resources.add(res, D3D12_DESCRIPTOR_RANGE_TYPE_UAV, spaceid, resid);
return res;
}
ComPtr<ID3D12Resource>
ComputeTest::add_cbv_resource(ComputeTest::Resources &resources,
unsigned spaceid, unsigned resid,
const void *data, size_t size)
{
unsigned aligned_size = align(size, 256);
D3D12_CPU_DESCRIPTOR_HANDLE handle;
ComPtr<ID3D12Resource> res;
handle = GetCPUDescriptorHandleForHeapStart(uav_heap);
handle = offset_cpu_handle(handle, resources.descs.size() * uav_heap_incr);
if (size) {
assert(data);
res = create_sized_buffer_with_data(aligned_size, data, size);
}
create_cbv(res, aligned_size, handle);
resources.add(res, D3D12_DESCRIPTOR_RANGE_TYPE_CBV, spaceid, resid);
return res;
}
void
ComputeTest::run_shader_with_raw_args(Shader shader,
const CompileArgs &compile_args,
const std::vector<RawShaderArg *> &args)
{
if (args.size() < 1)
throw runtime_error("no inputs");
static HMODULE hD3D12Mod = LoadLibrary("D3D12.DLL");
if (!hD3D12Mod)
throw runtime_error("Failed to load D3D12.DLL");
D3D12SerializeVersionedRootSignature = (PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)GetProcAddress(hD3D12Mod, "D3D12SerializeVersionedRootSignature");
if (args.size() != shader.dxil->kernel->num_args)
throw runtime_error("incorrect number of inputs");
struct clc_runtime_kernel_conf conf = {};
// Older WARP and some hardware doesn't support int64, so for these tests, unconditionally lower away int64
// A more complex runtime can be smarter about detecting when this needs to be done
conf.lower_bit_size = 64;
conf.max_shader_model = SHADER_MODEL_6_2;
conf.validator_version = DXIL_VALIDATOR_1_4;
if (!shader.dxil->metadata.local_size[0])
conf.local_size[0] = compile_args.x;
else
conf.local_size[0] = shader.dxil->metadata.local_size[0];
if (!shader.dxil->metadata.local_size[1])
conf.local_size[1] = compile_args.y;
else
conf.local_size[1] = shader.dxil->metadata.local_size[1];
if (!shader.dxil->metadata.local_size[2])
conf.local_size[2] = compile_args.z;
else
conf.local_size[2] = shader.dxil->metadata.local_size[2];
if (compile_args.x % conf.local_size[0] ||
compile_args.y % conf.local_size[1] ||
compile_args.z % conf.local_size[2])
throw runtime_error("invalid global size must be a multiple of local size");
std::vector<struct clc_runtime_arg_info> argsinfo(args.size());
conf.args = argsinfo.data();
conf.support_global_work_id_offsets =
compile_args.work_props.global_offset_x != 0 ||
compile_args.work_props.global_offset_y != 0 ||
compile_args.work_props.global_offset_z != 0;
conf.support_workgroup_id_offsets =
compile_args.work_props.group_id_offset_x != 0 ||
compile_args.work_props.group_id_offset_y != 0 ||
compile_args.work_props.group_id_offset_z != 0;
for (unsigned i = 0; i < shader.dxil->kernel->num_args; ++i) {
RawShaderArg *arg = args[i];
size_t size = arg->get_elem_size() * arg->get_num_elems();
switch (shader.dxil->kernel->args[i].address_qualifier) {
case CLC_KERNEL_ARG_ADDRESS_LOCAL:
argsinfo[i].localptr.size = size;
break;
default:
break;
}
}
configure(shader, &conf);
validate(shader);
std::shared_ptr<struct clc_dxil_object> &dxil = shader.dxil;
std::vector<uint8_t> argsbuf(dxil->metadata.kernel_inputs_buf_size);
std::vector<ComPtr<ID3D12Resource>> argres(shader.dxil->kernel->num_args);
clc_work_properties_data work_props = compile_args.work_props;
if (!conf.support_workgroup_id_offsets) {
work_props.group_count_total_x = compile_args.x / conf.local_size[0];
work_props.group_count_total_y = compile_args.y / conf.local_size[1];
work_props.group_count_total_z = compile_args.z / conf.local_size[2];
}
if (work_props.work_dim == 0)
work_props.work_dim = 3;
Resources resources;
for (unsigned i = 0; i < dxil->kernel->num_args; ++i) {
RawShaderArg *arg = args[i];
size_t size = arg->get_elem_size() * arg->get_num_elems();
void *slot = argsbuf.data() + dxil->metadata.args[i].offset;
switch (dxil->kernel->args[i].address_qualifier) {
case CLC_KERNEL_ARG_ADDRESS_CONSTANT:
case CLC_KERNEL_ARG_ADDRESS_GLOBAL: {
assert(dxil->metadata.args[i].size == sizeof(uint64_t));
uint64_t *ptr_slot = (uint64_t *)slot;
if (arg->get_data())
*ptr_slot = (uint64_t)dxil->metadata.args[i].globconstptr.buf_id << 32;
else
*ptr_slot = ~0ull;
break;
}
case CLC_KERNEL_ARG_ADDRESS_LOCAL: {
assert(dxil->metadata.args[i].size == sizeof(uint64_t));
uint64_t *ptr_slot = (uint64_t *)slot;
*ptr_slot = dxil->metadata.args[i].localptr.sharedmem_offset;
break;
}
case CLC_KERNEL_ARG_ADDRESS_PRIVATE: {
assert(size == dxil->metadata.args[i].size);
memcpy(slot, arg->get_data(), size);
break;
}
default:
assert(0);
}
}
for (unsigned i = 0; i < dxil->kernel->num_args; ++i) {
RawShaderArg *arg = args[i];
if (dxil->kernel->args[i].address_qualifier == CLC_KERNEL_ARG_ADDRESS_GLOBAL ||
dxil->kernel->args[i].address_qualifier == CLC_KERNEL_ARG_ADDRESS_CONSTANT) {
argres[i] = add_uav_resource(resources, 0,
dxil->metadata.args[i].globconstptr.buf_id,
arg->get_data(), arg->get_num_elems(),
arg->get_elem_size());
}
}
if (dxil->metadata.printf.uav_id > 0) {
static constexpr uint32_t printf_initial_data[1024 * 1024 / 4] = { sizeof(uint32_t) };
add_uav_resource(resources, 0, dxil->metadata.printf.uav_id, printf_initial_data, ARRAY_SIZE(printf_initial_data), sizeof(printf_initial_data[0]));
}
for (unsigned i = 0; i < dxil->metadata.num_consts; ++i)
add_uav_resource(resources, 0, dxil->metadata.consts[i].uav_id,
dxil->metadata.consts[i].data,
dxil->metadata.consts[i].size / 4, 4);
if (argsbuf.size())
add_cbv_resource(resources, 0, dxil->metadata.kernel_inputs_cbv_id,
argsbuf.data(), argsbuf.size());
add_cbv_resource(resources, 0, dxil->metadata.work_properties_cbv_id,
&work_props, sizeof(work_props));
auto root_sig = create_root_signature(resources);
auto pipeline_state = create_pipeline_state(root_sig, *dxil);
cmdlist->SetDescriptorHeaps(1, &uav_heap);
cmdlist->SetComputeRootSignature(root_sig.Get());
cmdlist->SetComputeRootDescriptorTable(0, GetGPUDescriptorHandleForHeapStart(uav_heap));
cmdlist->SetPipelineState(pipeline_state.Get());
cmdlist->Dispatch(compile_args.x / conf.local_size[0],
compile_args.y / conf.local_size[1],
compile_args.z / conf.local_size[2]);
for (auto &range : resources.ranges) {
if (range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV) {
for (unsigned i = range.OffsetInDescriptorsFromTableStart;
i < range.NumDescriptors; i++) {
if (!resources.descs[i].Get())
continue;
resource_barrier(resources.descs[i],
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
D3D12_RESOURCE_STATE_COMMON);
}
}
}
execute_cmdlist();
for (unsigned i = 0; i < args.size(); i++) {
if (!(args[i]->get_direction() & SHADER_ARG_OUTPUT))
continue;
assert(dxil->kernel->args[i].address_qualifier == CLC_KERNEL_ARG_ADDRESS_GLOBAL);
get_buffer_data(argres[i], args[i]->get_data(),
args[i]->get_elem_size() * args[i]->get_num_elems());
}
ComPtr<ID3D12InfoQueue> info_queue;
dev->QueryInterface(info_queue.ReleaseAndGetAddressOf());
if (info_queue)
{
EXPECT_EQ(0, info_queue->GetNumStoredMessages());
for (unsigned i = 0; i < info_queue->GetNumStoredMessages(); ++i) {
SIZE_T message_size = 0;
info_queue->GetMessageA(i, nullptr, &message_size);
D3D12_MESSAGE* message = (D3D12_MESSAGE*)malloc(message_size);
info_queue->GetMessageA(i, message, &message_size);
FAIL() << message->pDescription;
free(message);
}
}
}
void
ComputeTest::SetUp()
{
static struct clc_libclc *compiler_ctx_g = nullptr;
if (!compiler_ctx_g) {
clc_libclc_dxil_options options = { };
options.optimize = (debug_get_option_debug_compute() & COMPUTE_DEBUG_OPTIMIZE_LIBCLC) != 0;
compiler_ctx_g = clc_libclc_new_dxil(&logger, &options);
if (!compiler_ctx_g)
throw runtime_error("failed to create CLC compiler context");
if (debug_get_option_debug_compute() & COMPUTE_DEBUG_SERIALIZE_LIBCLC) {
void *serialized = nullptr;
size_t serialized_size = 0;
clc_libclc_serialize(compiler_ctx_g, &serialized, &serialized_size);
if (!serialized)
throw runtime_error("failed to serialize CLC compiler context");
clc_free_libclc(compiler_ctx_g);
compiler_ctx_g = nullptr;
compiler_ctx_g = clc_libclc_deserialize(serialized, serialized_size);
if (!compiler_ctx_g)
throw runtime_error("failed to deserialize CLC compiler context");
clc_libclc_free_serialized(serialized);
}
}
compiler_ctx = compiler_ctx_g;
enable_d3d12_debug_layer();
factory = get_dxgi_factory();
if (!factory)
throw runtime_error("failed to create DXGI factory");
adapter = choose_adapter(factory);
if (!adapter)
throw runtime_error("failed to choose adapter");
dev = create_device(adapter);
if (!dev)
throw runtime_error("failed to create device");
if (FAILED(dev->CreateFence(0, D3D12_FENCE_FLAG_NONE,
__uuidof(cmdqueue_fence),
(void **)&cmdqueue_fence)))
throw runtime_error("failed to create fence\n");
D3D12_COMMAND_QUEUE_DESC queue_desc;
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE;
queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queue_desc.NodeMask = 0;
if (FAILED(dev->CreateCommandQueue(&queue_desc,
__uuidof(cmdqueue),
(void **)&cmdqueue)))
throw runtime_error("failed to create command queue");
if (FAILED(dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COMPUTE,
__uuidof(cmdalloc), (void **)&cmdalloc)))
throw runtime_error("failed to create command allocator");
if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COMPUTE,
cmdalloc, NULL, __uuidof(cmdlist), (void **)&cmdlist)))
throw runtime_error("failed to create command list");
D3D12_DESCRIPTOR_HEAP_DESC heap_desc;
heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
heap_desc.NumDescriptors = 1000;
heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
heap_desc.NodeMask = 0;
if (FAILED(dev->CreateDescriptorHeap(&heap_desc,
__uuidof(uav_heap), (void **)&uav_heap)))
throw runtime_error("failed to create descriptor heap");
uav_heap_incr = dev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
event = CreateEvent(NULL, false, false, NULL);
if (!event)
throw runtime_error("Failed to create event");
fence_value = 1;
}
void
ComputeTest::TearDown()
{
CloseHandle(event);
uav_heap->Release();
cmdlist->Release();
cmdalloc->Release();
cmdqueue->Release();
cmdqueue_fence->Release();
dev->Release();
adapter->Release();
factory->Release();
}
PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE ComputeTest::D3D12SerializeVersionedRootSignature;
bool
validate_module(const struct clc_dxil_object &dxil)
{
struct dxil_validator *val = dxil_create_validator(NULL);
char *err;
bool res = dxil_validate_module(val, dxil.binary.data,
dxil.binary.size, &err);
if (!res && err)
fprintf(stderr, "D3D12: validation failed: %s", err);
dxil_destroy_validator(val);
return res;
}
static void
dump_blob(const char *path, const struct clc_dxil_object &dxil)
{
FILE *fp = fopen(path, "wb");
if (fp) {
fwrite(dxil.binary.data, 1, dxil.binary.size, fp);
fclose(fp);
printf("D3D12: wrote '%s'...\n", path);
}
}
ComputeTest::Shader
ComputeTest::compile(const std::vector<const char *> &sources,
const std::vector<const char *> &compile_args,
bool create_library)
{
struct clc_compile_args args = {
};
args.args = compile_args.data();
args.num_args = (unsigned)compile_args.size();
args.features.images = true;
args.features.images_read_write = true;
args.features.int64 = true;
ComputeTest::Shader shader;
std::vector<Shader> shaders;
args.source.name = "obj.cl";
for (unsigned i = 0; i < sources.size(); i++) {
args.source.value = sources[i];
clc_binary spirv{};
if (!clc_compile_c_to_spirv(&args, &logger, &spirv, NULL))
throw runtime_error("failed to compile object!");
Shader shader;
shader.obj = std::shared_ptr<clc_binary>(new clc_binary(spirv), [](clc_binary *spirv)
{
clc_free_spirv(spirv);
delete spirv;
});
shaders.push_back(shader);
}
if (shaders.size() == 1 && create_library)
return shaders[0];
return link(shaders, create_library);
}
ComputeTest::Shader
ComputeTest::link(const std::vector<Shader> &sources,
bool create_library)
{
std::vector<const clc_binary*> objs;
for (auto& source : sources)
objs.push_back(&*source.obj);
struct clc_linker_args link_args = {};
link_args.in_objs = objs.data();
link_args.num_in_objs = (unsigned)objs.size();
link_args.create_library = create_library;
clc_binary spirv{};
if (!clc_link_spirv(&link_args, &logger, &spirv))
throw runtime_error("failed to link objects!");
ComputeTest::Shader shader;
shader.obj = std::shared_ptr<clc_binary>(new clc_binary(spirv), [](clc_binary *spirv)
{
clc_free_spirv(spirv);
delete spirv;
});
if (!link_args.create_library)
configure(shader, NULL);
return shader;
}
ComputeTest::Shader
ComputeTest::assemble(const char *source)
{
spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
std::vector<uint32_t> binary;
if (!tools.Assemble(source, strlen(source), &binary))
throw runtime_error("failed to assemble");
ComputeTest::Shader shader;
shader.obj = std::shared_ptr<clc_binary>(new clc_binary{}, [](clc_binary *spirv)
{
free(spirv->data);
delete spirv;
});
shader.obj->size = binary.size() * 4;
shader.obj->data = malloc(shader.obj->size);
memcpy(shader.obj->data, binary.data(), shader.obj->size);
configure(shader, NULL);
return shader;
}
void
ComputeTest::configure(Shader &shader,
const struct clc_runtime_kernel_conf *conf)
{
if (!shader.metadata) {
shader.metadata = std::shared_ptr<clc_parsed_spirv>(new clc_parsed_spirv{}, [](clc_parsed_spirv *metadata)
{
clc_free_parsed_spirv(metadata);
delete metadata;
});
if (!clc_parse_spirv(shader.obj.get(), NULL, shader.metadata.get()))
throw runtime_error("failed to parse spirv!");
}
std::unique_ptr<clc_dxil_object> dxil(new clc_dxil_object{});
if (!clc_spirv_to_dxil(compiler_ctx, shader.obj.get(), shader.metadata.get(), "main_test", conf, nullptr, &logger, dxil.get()))
throw runtime_error("failed to compile kernel!");
shader.dxil = std::shared_ptr<clc_dxil_object>(dxil.release(), [](clc_dxil_object *dxil)
{
clc_free_dxil_object(dxil);
delete dxil;
});
}
void
ComputeTest::validate(ComputeTest::Shader &shader)
{
dump_blob("unsigned.cso", *shader.dxil);
if (!validate_module(*shader.dxil))
throw runtime_error("failed to validate module!");
dump_blob("signed.cso", *shader.dxil);
}
+355
View File
@@ -0,0 +1,355 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdexcept>
#include <directx/d3d12.h>
#include <dxgi1_4.h>
#include <gtest/gtest.h>
#include <wrl.h>
#include "clc_compiler.h"
using std::runtime_error;
using Microsoft::WRL::ComPtr;
inline D3D12_CPU_DESCRIPTOR_HANDLE
offset_cpu_handle(D3D12_CPU_DESCRIPTOR_HANDLE handle, UINT offset)
{
handle.ptr += offset;
return handle;
}
inline size_t
align(size_t value, unsigned alignment)
{
assert(alignment > 0);
return ((value + (alignment - 1)) / alignment) * alignment;
}
class ComputeTest : public ::testing::Test {
protected:
struct Shader {
std::shared_ptr<struct clc_binary> obj;
std::shared_ptr<struct clc_parsed_spirv> metadata;
std::shared_ptr<struct clc_dxil_object> dxil;
};
static void
enable_d3d12_debug_layer();
static IDXGIFactory4 *
get_dxgi_factory();
static IDXGIAdapter1 *
choose_adapter(IDXGIFactory4 *factory);
static ID3D12Device *
create_device(IDXGIAdapter1 *adapter);
struct Resources {
void add(ComPtr<ID3D12Resource> res,
D3D12_DESCRIPTOR_RANGE_TYPE type,
unsigned spaceid,
unsigned resid)
{
descs.push_back(res);
if(!ranges.empty() &&
ranges.back().RangeType == type &&
ranges.back().RegisterSpace == spaceid &&
ranges.back().BaseShaderRegister + ranges.back().NumDescriptors == resid) {
ranges.back().NumDescriptors++;
return;
}
D3D12_DESCRIPTOR_RANGE1 range;
range.RangeType = type;
range.NumDescriptors = 1;
range.BaseShaderRegister = resid;
range.RegisterSpace = spaceid;
range.OffsetInDescriptorsFromTableStart = descs.size() - 1;
range.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS;
ranges.push_back(range);
}
std::vector<D3D12_DESCRIPTOR_RANGE1> ranges;
std::vector<ComPtr<ID3D12Resource>> descs;
};
ComPtr<ID3D12RootSignature>
create_root_signature(const Resources &resources);
ComPtr<ID3D12PipelineState>
create_pipeline_state(ComPtr<ID3D12RootSignature> &root_sig,
const struct clc_dxil_object &dxil);
ComPtr<ID3D12Resource>
create_buffer(int size, D3D12_HEAP_TYPE heap_type);
ComPtr<ID3D12Resource>
create_upload_buffer_with_data(const void *data, size_t size);
ComPtr<ID3D12Resource>
create_sized_buffer_with_data(size_t buffer_size, const void *data,
size_t data_size);
ComPtr<ID3D12Resource>
create_buffer_with_data(const void *data, size_t size)
{
return create_sized_buffer_with_data(size, data, size);
}
void
get_buffer_data(ComPtr<ID3D12Resource> res,
void *buf, size_t size);
void
resource_barrier(ComPtr<ID3D12Resource> &res,
D3D12_RESOURCE_STATES state_before,
D3D12_RESOURCE_STATES state_after);
void
execute_cmdlist();
void
create_uav_buffer(ComPtr<ID3D12Resource> res,
size_t width, size_t byte_stride,
D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle);
void create_cbv(ComPtr<ID3D12Resource> res, size_t size,
D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle);
ComPtr<ID3D12Resource>
add_uav_resource(Resources &resources, unsigned spaceid, unsigned resid,
const void *data = NULL, size_t num_elems = 0,
size_t elem_size = 0);
ComPtr<ID3D12Resource>
add_cbv_resource(Resources &resources, unsigned spaceid, unsigned resid,
const void *data, size_t size);
void
SetUp() override;
void
TearDown() override;
Shader
compile(const std::vector<const char *> &sources,
const std::vector<const char *> &compile_args = {},
bool create_library = false);
Shader
link(const std::vector<Shader> &sources,
bool create_library = false);
Shader
assemble(const char *source);
void
configure(Shader &shader,
const struct clc_runtime_kernel_conf *conf);
void
validate(Shader &shader);
template <typename T>
Shader
specialize(Shader &shader, uint32_t id, T const& val)
{
Shader new_shader;
new_shader.obj = std::shared_ptr<clc_binary>(new clc_binary{}, [](clc_binary *spirv)
{
clc_free_spirv(spirv);
delete spirv;
});
if (!shader.metadata)
configure(shader, NULL);
clc_spirv_specialization spec;
spec.id = id;
memcpy(&spec.value, &val, sizeof(val));
clc_spirv_specialization_consts consts;
consts.specializations = &spec;
consts.num_specializations = 1;
if (!clc_specialize_spirv(shader.obj.get(), shader.metadata.get(), &consts, new_shader.obj.get()))
throw runtime_error("failed to specialize");
configure(new_shader, NULL);
return new_shader;
}
enum ShaderArgDirection {
SHADER_ARG_INPUT = 1,
SHADER_ARG_OUTPUT = 2,
SHADER_ARG_INOUT = SHADER_ARG_INPUT | SHADER_ARG_OUTPUT,
};
class RawShaderArg {
public:
RawShaderArg(enum ShaderArgDirection dir) : dir(dir) { }
virtual size_t get_elem_size() const = 0;
virtual size_t get_num_elems() const = 0;
virtual const void *get_data() const = 0;
virtual void *get_data() = 0;
enum ShaderArgDirection get_direction() { return dir; }
private:
enum ShaderArgDirection dir;
};
class NullShaderArg : public RawShaderArg {
public:
NullShaderArg() : RawShaderArg(SHADER_ARG_INPUT) { }
size_t get_elem_size() const override { return 0; }
size_t get_num_elems() const override { return 0; }
const void *get_data() const override { return NULL; }
void *get_data() override { return NULL; }
};
template <typename T>
class ShaderArg : public std::vector<T>, public RawShaderArg
{
public:
ShaderArg(const T &v, enum ShaderArgDirection dir = SHADER_ARG_INOUT) :
std::vector<T>({ v }), RawShaderArg(dir) { }
ShaderArg(const std::vector<T> &v, enum ShaderArgDirection dir = SHADER_ARG_INOUT) :
std::vector<T>(v), RawShaderArg(dir) { }
ShaderArg(const std::initializer_list<T> v, enum ShaderArgDirection dir = SHADER_ARG_INOUT) :
std::vector<T>(v), RawShaderArg(dir) { }
ShaderArg<T>& operator =(const T &v)
{
this->clear();
this->push_back(v);
return *this;
}
operator T&() { return this->at(0); }
operator const T&() const { return this->at(0); }
ShaderArg<T>& operator =(const std::vector<T> &v)
{
*this = v;
return *this;
}
ShaderArg<T>& operator =(std::initializer_list<T> v)
{
*this = v;
return *this;
}
size_t get_elem_size() const override { return sizeof(T); }
size_t get_num_elems() const override { return this->size(); }
const void *get_data() const override { return this->data(); }
void *get_data() override { return this->data(); }
};
struct CompileArgs
{
unsigned x, y, z;
std::vector<const char *> compiler_command_line;
clc_work_properties_data work_props;
};
private:
void gather_args(std::vector<RawShaderArg *> &args) { }
template <typename T, typename... Rest>
void gather_args(std::vector<RawShaderArg *> &args, T &arg, Rest&... rest)
{
args.push_back(&arg);
gather_args(args, rest...);
}
void run_shader_with_raw_args(Shader shader,
const CompileArgs &compile_args,
const std::vector<RawShaderArg *> &args);
protected:
template <typename... Args>
void run_shader(Shader shader,
const CompileArgs &compile_args,
Args&... args)
{
std::vector<RawShaderArg *> raw_args;
gather_args(raw_args, args...);
run_shader_with_raw_args(shader, compile_args, raw_args);
}
template <typename... Args>
void run_shader(const std::vector<const char *> &sources,
unsigned x, unsigned y, unsigned z,
Args&... args)
{
std::vector<RawShaderArg *> raw_args;
gather_args(raw_args, args...);
CompileArgs compile_args = { x, y, z };
run_shader_with_raw_args(compile(sources), compile_args, raw_args);
}
template <typename... Args>
void run_shader(const std::vector<const char *> &sources,
const CompileArgs &compile_args,
Args&... args)
{
std::vector<RawShaderArg *> raw_args;
gather_args(raw_args, args...);
run_shader_with_raw_args(
compile(sources, compile_args.compiler_command_line),
compile_args, raw_args);
}
template <typename... Args>
void run_shader(const char *source,
unsigned x, unsigned y, unsigned z,
Args&... args)
{
std::vector<RawShaderArg *> raw_args;
gather_args(raw_args, args...);
CompileArgs compile_args = { x, y, z };
run_shader_with_raw_args(compile({ source }), compile_args, raw_args);
}
IDXGIFactory4 *factory;
IDXGIAdapter1 *adapter;
ID3D12Device *dev;
ID3D12Fence *cmdqueue_fence;
ID3D12CommandQueue *cmdqueue;
ID3D12CommandAllocator *cmdalloc;
ID3D12GraphicsCommandList *cmdlist;
ID3D12DescriptorHeap *uav_heap;
struct clc_libclc *compiler_ctx;
UINT uav_heap_incr;
int fence_value;
HANDLE event;
static PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE D3D12SerializeVersionedRootSignature;
};
+33
View File
@@ -0,0 +1,33 @@
# Copyright © Microsoft Corporation
# SPDX-License-Identifier: MIT
files_libclc_compiler = files(
'clc_compiler.c',
'clc_nir.c',
)
libclc_compiler = shared_library(
'clon12compiler',
[files_libclc_compiler, sha1_h],
vs_module_defs : 'clon12compiler.def',
include_directories : [inc_include, inc_src, inc_spirv],
dependencies: [idep_mesaclc, idep_nir_headers, dep_version, idep_mesautil,
idep_libdxil_compiler, idep_nir, idep_vtn],
install : true,
name_prefix : '' # otherwise mingw will create libclon12compiler.dll
)
if dep_dxheaders.found() and host_machine.system() == 'windows' and with_tests
clc_compiler_test = executable('clc_compiler_test',
['clc_compiler_test.cpp', 'compute_test.cpp'],
link_with : [libclc_compiler],
dependencies : [idep_gtest, idep_mesautil, idep_libdxil_compiler, dep_dxheaders,
dep_spirv_tools, idep_compiler],
include_directories : [inc_include, inc_src, inc_spirv],
)
if build_machine.system() == 'windows'
test('clc_compiler_test', clc_compiler_test, timeout: 180, protocol : 'gtest')
endif
endif
+772
View File
@@ -0,0 +1,772 @@
///////////////////////////////////////////////////////////////////////////////
// //
// dxcapi.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// Provides declarations for the DirectX Compiler API entry point. //
// //
///////////////////////////////////////////////////////////////////////////////
#ifndef __DXC_API__
#define __DXC_API__
#ifdef _WIN32
#ifndef DXC_API_IMPORT
#define DXC_API_IMPORT __declspec(dllimport)
#endif
#else
#ifndef DXC_API_IMPORT
#define DXC_API_IMPORT __attribute__ ((visibility ("default")))
#endif
#endif
#include <stdint.h>
#ifndef CROSS_PLATFORM_UUIDOF
// Warning: This macro exists in WinAdapter.h as well
#if defined(_MSC_VER)
#define CROSS_PLATFORM_UUIDOF(iface, spec) \
struct __declspec(uuid(spec)) iface;
#else /* defined(_MSC_VER) */
#if defined(__MINGW32__)
#include <guiddef.h>
#include <sal.h>
#ifndef _Maybenull_
#define _Maybenull_
#endif
#ifndef _In_count_
#define _In_count_(x)
#endif
#ifndef _In_opt_count_
#define _In_opt_count_(x)
#endif
#ifndef _In_bytecount_
#define _In_bytecount_(x)
#endif
#endif /* defined(__MINGW32__) */
#ifndef __CRT_UUID_DECL
#define __CRT_UUID_DECL(type, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
extern "C++" \
{ \
template <> \
struct __mesa_emulated_uuidof_s<type> \
{ \
static constexpr IID __uuid_inst = { \
l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}}; \
}; \
template <> \
constexpr const GUID &__mesa_emulated_uuidof<type>() \
{ \
return __mesa_emulated_uuidof_s<type>::__uuid_inst; \
} \
template <> \
constexpr const GUID &__mesa_emulated_uuidof<type *>() \
{ \
return __mesa_emulated_uuidof_s<type>::__uuid_inst; \
} \
}
#define __uuidof(T) __mesa_emulated_uuidof<typename std::decay<T>::type>()
#endif /*__CRT_UUID_DECL */
constexpr uint8_t __nybble_from_hex(char c) {
return ((c >= '0' && c <= '9')
? (c - '0')
: ((c >= 'a' && c <= 'f')
? (c - 'a' + 10)
: ((c >= 'A' && c <= 'F') ? (c - 'A' + 10)
: /* Should be an error */ -1)));
}
constexpr uint8_t __byte_from_hexstr(const char str[2], unsigned offset) {
return __nybble_from_hex(str[offset + 0]) << 4 | __nybble_from_hex(str[offset + 1]);
}
constexpr unsigned short __short_from_hexstr_be(const char str[4], unsigned offset)
{
unsigned short hi = __byte_from_hexstr(str, offset + 0);
unsigned short lo = __byte_from_hexstr(str, offset + 2);
return (hi << 8) | lo;
}
constexpr unsigned int __word_from_hexstr_be(const char str[8], unsigned offset)
{
unsigned int hi = __short_from_hexstr_be(str, offset + 0);
unsigned int lo = __short_from_hexstr_be(str, offset + 4);
return (hi << 16) | lo;
}
#define CROSS_PLATFORM_UUIDOF(iface, spec) \
struct iface; \
__CRT_UUID_DECL( \
iface, \
__word_from_hexstr_be(spec, 0), \
__short_from_hexstr_be(spec, 9), \
__short_from_hexstr_be(spec, 14), \
__byte_from_hexstr(spec, 19), __byte_from_hexstr(spec, 21), \
__byte_from_hexstr(spec, 24), __byte_from_hexstr(spec, 26), \
__byte_from_hexstr(spec, 28), __byte_from_hexstr(spec, 30), \
__byte_from_hexstr(spec, 32), __byte_from_hexstr(spec, 34))
#endif /* defined(_MSC_VER) */
#endif /* CROSS_PLATFORM_UUIDOF */
#ifndef _WIN32
CROSS_PLATFORM_UUIDOF(INoMarshal, "ECC8691B-C1DB-4DC0-855E-65F6C551AF49")
struct INoMarshal : public IUnknown {};
CROSS_PLATFORM_UUIDOF(IMalloc, "00000002-0000-0000-C000-000000000046")
struct IMalloc : public IUnknown {
virtual void *Alloc(size_t size);
virtual void *Realloc(void *ptr, size_t size);
virtual void Free(void *ptr);
virtual HRESULT QueryInterface(REFIID riid, void **ppvObject);
};
CROSS_PLATFORM_UUIDOF(ISequentialStream, "0C733A30-2A1C-11CE-ADE5-00AA0044773D")
struct ISequentialStream : public IUnknown {
virtual HRESULT Read(void *pv, ULONG cb, ULONG *pcbRead) = 0;
virtual HRESULT Write(const void *pv, ULONG cb, ULONG *pcbWritten) = 0;
};
CROSS_PLATFORM_UUIDOF(IStream, "0000000c-0000-0000-C000-000000000046")
struct IStream : public ISequentialStream {
virtual HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
ULARGE_INTEGER *plibNewPosition) = 0;
virtual HRESULT SetSize(ULARGE_INTEGER libNewSize) = 0;
virtual HRESULT CopyTo(IStream *pstm, ULARGE_INTEGER cb,
ULARGE_INTEGER *pcbRead,
ULARGE_INTEGER *pcbWritten) = 0;
virtual HRESULT Commit(DWORD grfCommitFlags) = 0;
virtual HRESULT Revert(void) = 0;
virtual HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
DWORD dwLockType) = 0;
virtual HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
DWORD dwLockType) = 0;
virtual HRESULT Stat(STATSTG *pstatstg, DWORD grfStatFlag) = 0;
virtual HRESULT Clone(IStream **ppstm) = 0;
};
#endif
struct IMalloc;
struct IDxcIncludeHandler;
typedef HRESULT (__stdcall *DxcCreateInstanceProc)(
_In_ REFCLSID rclsid,
_In_ REFIID riid,
_Out_ LPVOID* ppv
);
typedef HRESULT(__stdcall *DxcCreateInstance2Proc)(
_In_ IMalloc *pMalloc,
_In_ REFCLSID rclsid,
_In_ REFIID riid,
_Out_ LPVOID* ppv
);
/// <summary>
/// Creates a single uninitialized object of the class associated with a specified CLSID.
/// </summary>
/// <param name="rclsid">
/// The CLSID associated with the data and code that will be used to create the object.
/// </param>
/// <param name="riid">
/// A reference to the identifier of the interface to be used to communicate
/// with the object.
/// </param>
/// <param name="ppv">
/// Address of pointer variable that receives the interface pointer requested
/// in riid. Upon successful return, *ppv contains the requested interface
/// pointer. Upon failure, *ppv contains NULL.</param>
/// <remarks>
/// While this function is similar to CoCreateInstance, there is no COM involvement.
/// </remarks>
extern "C"
DXC_API_IMPORT HRESULT __stdcall DxcCreateInstance(
_In_ REFCLSID rclsid,
_In_ REFIID riid,
_Out_ LPVOID* ppv
);
extern "C"
DXC_API_IMPORT HRESULT __stdcall DxcCreateInstance2(
_In_ IMalloc *pMalloc,
_In_ REFCLSID rclsid,
_In_ REFIID riid,
_Out_ LPVOID* ppv
);
// For convenience, equivalent definitions to CP_UTF8 and CP_UTF16.
#define DXC_CP_UTF8 65001
#define DXC_CP_UTF16 1200
// Use DXC_CP_ACP for: Binary; ANSI Text; Autodetect UTF with BOM
#define DXC_CP_ACP 0
// This flag indicates that the shader hash was computed taking into account source information (-Zss)
#define DXC_HASHFLAG_INCLUDES_SOURCE 1
// Hash digest type for ShaderHash
typedef struct DxcShaderHash {
UINT32 Flags; // DXC_HASHFLAG_*
BYTE HashDigest[16];
} DxcShaderHash;
#define DXC_FOURCC(ch0, ch1, ch2, ch3) ( \
(UINT32)(UINT8)(ch0) | (UINT32)(UINT8)(ch1) << 8 | \
(UINT32)(UINT8)(ch2) << 16 | (UINT32)(UINT8)(ch3) << 24 \
)
#define DXC_PART_PDB DXC_FOURCC('I', 'L', 'D', 'B')
#define DXC_PART_PDB_NAME DXC_FOURCC('I', 'L', 'D', 'N')
#define DXC_PART_PRIVATE_DATA DXC_FOURCC('P', 'R', 'I', 'V')
#define DXC_PART_ROOT_SIGNATURE DXC_FOURCC('R', 'T', 'S', '0')
#define DXC_PART_DXIL DXC_FOURCC('D', 'X', 'I', 'L')
#define DXC_PART_REFLECTION_DATA DXC_FOURCC('S', 'T', 'A', 'T')
#define DXC_PART_SHADER_HASH DXC_FOURCC('H', 'A', 'S', 'H')
#define DXC_PART_INPUT_SIGNATURE DXC_FOURCC('I', 'S', 'G', '1')
#define DXC_PART_OUTPUT_SIGNATURE DXC_FOURCC('O', 'S', 'G', '1')
#define DXC_PART_PATCH_CONSTANT_SIGNATURE DXC_FOURCC('P', 'S', 'G', '1')
// Some option arguments are defined here for continuity with D3DCompile interface
#define DXC_ARG_DEBUG L"-Zi"
#define DXC_ARG_SKIP_VALIDATION L"-Vd"
#define DXC_ARG_SKIP_OPTIMIZATIONS L"-Od"
#define DXC_ARG_PACK_MATRIX_ROW_MAJOR L"-Zpr"
#define DXC_ARG_PACK_MATRIX_COLUMN_MAJOR L"-Zpc"
#define DXC_ARG_AVOID_FLOW_CONTROL L"-Gfa"
#define DXC_ARG_PREFER_FLOW_CONTROL L"-Gfp"
#define DXC_ARG_ENABLE_STRICTNESS L"-Ges"
#define DXC_ARG_ENABLE_BACKWARDS_COMPATIBILITY L"-Gec"
#define DXC_ARG_IEEE_STRICTNESS L"-Gis"
#define DXC_ARG_OPTIMIZATION_LEVEL0 L"-O0"
#define DXC_ARG_OPTIMIZATION_LEVEL1 L"-O1"
#define DXC_ARG_OPTIMIZATION_LEVEL2 L"-O2"
#define DXC_ARG_OPTIMIZATION_LEVEL3 L"-O3"
#define DXC_ARG_WARNINGS_ARE_ERRORS L"-WX"
#define DXC_ARG_RESOURCES_MAY_ALIAS L"-res_may_alias"
#define DXC_ARG_ALL_RESOURCES_BOUND L"-all_resources_bound"
#define DXC_ARG_DEBUG_NAME_FOR_SOURCE L"-Zss"
#define DXC_ARG_DEBUG_NAME_FOR_BINARY L"-Zsb"
// IDxcBlob is an alias of ID3D10Blob and ID3DBlob
CROSS_PLATFORM_UUIDOF(IDxcBlob, "8BA5FB08-5195-40e2-AC58-0D989C3A0102")
struct IDxcBlob : public IUnknown {
public:
virtual LPVOID STDMETHODCALLTYPE GetBufferPointer(void) = 0;
virtual SIZE_T STDMETHODCALLTYPE GetBufferSize(void) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcBlobEncoding, "7241d424-2646-4191-97c0-98e96e42fc68")
struct IDxcBlobEncoding : public IDxcBlob {
public:
virtual HRESULT STDMETHODCALLTYPE GetEncoding(_Out_ BOOL *pKnown,
_Out_ UINT32 *pCodePage) = 0;
};
// Notes on IDxcBlobUtf16 and IDxcBlobUtf8
// These guarantee null-terminated text and the stated encoding.
// GetBufferSize() will return the size in bytes, including null-terminator
// GetStringLength() will return the length in characters, excluding the null-terminator
// Name strings will use IDxcBlobUtf16, while other string output blobs,
// such as errors/warnings, preprocessed HLSL, or other text will be based
// on the -encoding option.
// The API will use this interface for output name strings
CROSS_PLATFORM_UUIDOF(IDxcBlobUtf16, "A3F84EAB-0FAA-497E-A39C-EE6ED60B2D84")
struct IDxcBlobUtf16 : public IDxcBlobEncoding {
public:
virtual LPCWSTR STDMETHODCALLTYPE GetStringPointer(void) = 0;
virtual SIZE_T STDMETHODCALLTYPE GetStringLength(void) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcBlobUtf8, "3DA636C9-BA71-4024-A301-30CBF125305B")
struct IDxcBlobUtf8 : public IDxcBlobEncoding {
public:
virtual LPCSTR STDMETHODCALLTYPE GetStringPointer(void) = 0;
virtual SIZE_T STDMETHODCALLTYPE GetStringLength(void) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcIncludeHandler, "7f61fc7d-950d-467f-b3e3-3c02fb49187c")
struct IDxcIncludeHandler : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE LoadSource(
_In_z_ LPCWSTR pFilename, // Candidate filename.
_COM_Outptr_result_maybenull_ IDxcBlob **ppIncludeSource // Resultant source object for included file, nullptr if not found.
) = 0;
};
// Structure for supplying bytes or text input to Dxc APIs.
// Use Encoding = 0 for non-text bytes, ANSI text, or unknown with BOM.
typedef struct DxcBuffer {
LPCVOID Ptr;
SIZE_T Size;
UINT Encoding;
} DxcText;
struct DxcDefine {
LPCWSTR Name;
_Maybenull_ LPCWSTR Value;
};
CROSS_PLATFORM_UUIDOF(IDxcCompilerArgs, "73EFFE2A-70DC-45F8-9690-EFF64C02429D")
struct IDxcCompilerArgs : public IUnknown {
// Pass GetArguments() and GetCount() to Compile
virtual LPCWSTR* STDMETHODCALLTYPE GetArguments() = 0;
virtual UINT32 STDMETHODCALLTYPE GetCount() = 0;
// Add additional arguments or defines here, if desired.
virtual HRESULT STDMETHODCALLTYPE AddArguments(
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments to add
_In_ UINT32 argCount // Number of arguments to add
) = 0;
virtual HRESULT STDMETHODCALLTYPE AddArgumentsUTF8(
_In_opt_count_(argCount)LPCSTR *pArguments, // Array of pointers to UTF-8 arguments to add
_In_ UINT32 argCount // Number of arguments to add
) = 0;
virtual HRESULT STDMETHODCALLTYPE AddDefines(
_In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount // Number of defines
) = 0;
};
//////////////////////////
// Legacy Interfaces
/////////////////////////
// NOTE: IDxcUtils replaces IDxcLibrary
CROSS_PLATFORM_UUIDOF(IDxcLibrary, "e5204dc7-d18c-4c3c-bdfb-851673980fe7")
struct IDxcLibrary : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE SetMalloc(_In_opt_ IMalloc *pMalloc) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobFromBlob(
_In_ IDxcBlob *pBlob, UINT32 offset, UINT32 length, _COM_Outptr_ IDxcBlob **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobFromFile(
_In_z_ LPCWSTR pFileName, _In_opt_ UINT32* codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobWithEncodingFromPinned(
_In_bytecount_(size) LPCVOID pText, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobWithEncodingOnHeapCopy(
_In_bytecount_(size) LPCVOID pText, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobWithEncodingOnMalloc(
_In_bytecount_(size) LPCVOID pText, IMalloc *pIMalloc, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateIncludeHandler(
_COM_Outptr_ IDxcIncludeHandler **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateStreamFromBlobReadOnly(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IStream **ppStream) = 0;
virtual HRESULT STDMETHODCALLTYPE GetBlobAsUtf8(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE GetBlobAsUtf16(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
};
// NOTE: IDxcResult replaces IDxcOperationResult
CROSS_PLATFORM_UUIDOF(IDxcOperationResult, "CEDB484A-D4E9-445A-B991-CA21CA157DC2")
struct IDxcOperationResult : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetStatus(_Out_ HRESULT *pStatus) = 0;
// GetResult returns the main result of the operation.
// This corresponds to:
// DXC_OUT_OBJECT - Compile() with shader or library target
// DXC_OUT_DISASSEMBLY - Disassemble()
// DXC_OUT_HLSL - Compile() with -P
// DXC_OUT_ROOT_SIGNATURE - Compile() with rootsig_* target
virtual HRESULT STDMETHODCALLTYPE GetResult(_COM_Outptr_result_maybenull_ IDxcBlob **ppResult) = 0;
// GetErrorBuffer Corresponds to DXC_OUT_ERRORS.
virtual HRESULT STDMETHODCALLTYPE GetErrorBuffer(_COM_Outptr_result_maybenull_ IDxcBlobEncoding **ppErrors) = 0;
};
// NOTE: IDxcCompiler3 replaces IDxcCompiler and IDxcCompiler2
CROSS_PLATFORM_UUIDOF(IDxcCompiler, "8c210bf3-011f-4422-8d70-6f9acb8db617")
struct IDxcCompiler : public IUnknown {
// Compile a single entry point to the target shader model
virtual HRESULT STDMETHODCALLTYPE Compile(
_In_ IDxcBlob *pSource, // Source text to compile
_In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
_In_opt_z_ LPCWSTR pEntryPoint, // entry point name
_In_z_ LPCWSTR pTargetProfile, // shader profile to compile
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_count_(defineCount)
const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount, // Number of defines
_In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
_COM_Outptr_ IDxcOperationResult **ppResult // Compiler output status, buffer, and errors
) = 0;
// Preprocess source text
virtual HRESULT STDMETHODCALLTYPE Preprocess(
_In_ IDxcBlob *pSource, // Source text to preprocess
_In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_count_(defineCount)
const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount, // Number of defines
_In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
_COM_Outptr_ IDxcOperationResult **ppResult // Preprocessor output status, buffer, and errors
) = 0;
// Disassemble a program.
virtual HRESULT STDMETHODCALLTYPE Disassemble(
_In_ IDxcBlob *pSource, // Program to disassemble.
_COM_Outptr_ IDxcBlobEncoding **ppDisassembly // Disassembly text.
) = 0;
};
// NOTE: IDxcCompiler3 replaces IDxcCompiler and IDxcCompiler2
CROSS_PLATFORM_UUIDOF(IDxcCompiler2, "A005A9D9-B8BB-4594-B5C9-0E633BEC4D37")
struct IDxcCompiler2 : public IDxcCompiler {
// Compile a single entry point to the target shader model with debug information.
virtual HRESULT STDMETHODCALLTYPE CompileWithDebug(
_In_ IDxcBlob *pSource, // Source text to compile
_In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
_In_opt_z_ LPCWSTR pEntryPoint, // Entry point name
_In_z_ LPCWSTR pTargetProfile, // Shader profile to compile
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_count_(defineCount)
const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount, // Number of defines
_In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
_COM_Outptr_ IDxcOperationResult **ppResult, // Compiler output status, buffer, and errors
_Outptr_opt_result_z_ LPWSTR *ppDebugBlobName,// Suggested file name for debug blob. (Must be HeapFree()'d!)
_COM_Outptr_opt_ IDxcBlob **ppDebugBlob // Debug blob
) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcLinker, "F1B5BE2A-62DD-4327-A1C2-42AC1E1E78E6")
struct IDxcLinker : public IUnknown {
public:
// Register a library with name to ref it later.
virtual HRESULT RegisterLibrary(
_In_opt_ LPCWSTR pLibName, // Name of the library.
_In_ IDxcBlob *pLib // Library blob.
) = 0;
// Links the shader and produces a shader blob that the Direct3D runtime can
// use.
virtual HRESULT STDMETHODCALLTYPE Link(
_In_opt_ LPCWSTR pEntryName, // Entry point name
_In_ LPCWSTR pTargetProfile, // shader profile to link
_In_count_(libCount)
const LPCWSTR *pLibNames, // Array of library names to link
_In_ UINT32 libCount, // Number of libraries to link
_In_opt_count_(argCount) const LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_COM_Outptr_
IDxcOperationResult **ppResult // Linker output status, buffer, and errors
) = 0;
};
/////////////////////////
// Latest interfaces. Please use these
////////////////////////
// NOTE: IDxcUtils replaces IDxcLibrary
CROSS_PLATFORM_UUIDOF(IDxcUtils, "4605C4CB-2019-492A-ADA4-65F20BB7D67F")
struct IDxcUtils : public IUnknown {
// Create a sub-blob that holds a reference to the outer blob and points to its memory.
virtual HRESULT STDMETHODCALLTYPE CreateBlobFromBlob(
_In_ IDxcBlob *pBlob, UINT32 offset, UINT32 length, _COM_Outptr_ IDxcBlob **ppResult) = 0;
// For codePage, use 0 (or DXC_CP_ACP) for raw binary or ANSI code page
// Creates a blob referencing existing memory, with no copy.
// User must manage the memory lifetime separately.
// (was: CreateBlobWithEncodingFromPinned)
virtual HRESULT STDMETHODCALLTYPE CreateBlobFromPinned(
_In_bytecount_(size) LPCVOID pData, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
// Create blob, taking ownership of memory allocated with supplied allocator.
// (was: CreateBlobWithEncodingOnMalloc)
virtual HRESULT STDMETHODCALLTYPE MoveToBlob(
_In_bytecount_(size) LPCVOID pData, IMalloc *pIMalloc, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
////
// New blobs and copied contents are allocated with the current allocator
// Copy blob contents to memory owned by the new blob.
// (was: CreateBlobWithEncodingOnHeapCopy)
virtual HRESULT STDMETHODCALLTYPE CreateBlob(
_In_bytecount_(size) LPCVOID pData, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
// (was: CreateBlobFromFile)
virtual HRESULT STDMETHODCALLTYPE LoadFile(
_In_z_ LPCWSTR pFileName, _In_opt_ UINT32* pCodePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateReadOnlyStreamFromBlob(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IStream **ppStream) = 0;
// Create default file-based include handler
virtual HRESULT STDMETHODCALLTYPE CreateDefaultIncludeHandler(
_COM_Outptr_ IDxcIncludeHandler **ppResult) = 0;
// Convert or return matching encoded text blobs
virtual HRESULT STDMETHODCALLTYPE GetBlobAsUtf8(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobUtf8 **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE GetBlobAsUtf16(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobUtf16 **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDxilContainerPart(
_In_ const DxcBuffer *pShader,
_In_ UINT32 DxcPart,
_Outptr_result_nullonfailure_ void **ppPartData,
_Out_ UINT32 *pPartSizeInBytes) = 0;
// Create reflection interface from serialized Dxil container, or DXC_PART_REFLECTION_DATA.
// TBD: Require part header for RDAT? (leaning towards yes)
virtual HRESULT STDMETHODCALLTYPE CreateReflection(
_In_ const DxcBuffer *pData, REFIID iid, void **ppvReflection) = 0;
virtual HRESULT STDMETHODCALLTYPE BuildArguments(
_In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
_In_opt_z_ LPCWSTR pEntryPoint, // Entry point name. (-E)
_In_z_ LPCWSTR pTargetProfile, // Shader profile to compile. (-T)
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_count_(defineCount)
const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount, // Number of defines
_COM_Outptr_ IDxcCompilerArgs **ppArgs // Arguments you can use with Compile() method
) = 0;
// Takes the shader PDB and returns the hash and the container inside it
virtual HRESULT STDMETHODCALLTYPE GetPDBContents(
_In_ IDxcBlob *pPDBBlob, _COM_Outptr_ IDxcBlob **ppHash, _COM_Outptr_ IDxcBlob **ppContainer) = 0;
};
// For use with IDxcResult::[Has|Get]Output dxcOutKind argument
// Note: text outputs returned from version 2 APIs are UTF-8 or UTF-16 based on -encoding option
typedef enum DXC_OUT_KIND {
DXC_OUT_NONE = 0,
DXC_OUT_OBJECT = 1, // IDxcBlob - Shader or library object
DXC_OUT_ERRORS = 2, // IDxcBlobUtf8 or IDxcBlobUtf16
DXC_OUT_PDB = 3, // IDxcBlob
DXC_OUT_SHADER_HASH = 4, // IDxcBlob - DxcShaderHash of shader or shader with source info (-Zsb/-Zss)
DXC_OUT_DISASSEMBLY = 5, // IDxcBlobUtf8 or IDxcBlobUtf16 - from Disassemble
DXC_OUT_HLSL = 6, // IDxcBlobUtf8 or IDxcBlobUtf16 - from Preprocessor or Rewriter
DXC_OUT_TEXT = 7, // IDxcBlobUtf8 or IDxcBlobUtf16 - other text, such as -ast-dump or -Odump
DXC_OUT_REFLECTION = 8, // IDxcBlob - RDAT part with reflection data
DXC_OUT_ROOT_SIGNATURE = 9, // IDxcBlob - Serialized root signature output
DXC_OUT_EXTRA_OUTPUTS = 10,// IDxcExtraResults - Extra outputs
DXC_OUT_FORCE_DWORD = 0xFFFFFFFF
} DXC_OUT_KIND;
CROSS_PLATFORM_UUIDOF(IDxcResult, "58346CDA-DDE7-4497-9461-6F87AF5E0659")
struct IDxcResult : public IDxcOperationResult {
virtual BOOL STDMETHODCALLTYPE HasOutput(_In_ DXC_OUT_KIND dxcOutKind) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOutput(_In_ DXC_OUT_KIND dxcOutKind,
_In_ REFIID iid, _COM_Outptr_opt_result_maybenull_ void **ppvObject,
_COM_Outptr_ IDxcBlobUtf16 **ppOutputName) = 0;
virtual UINT32 GetNumOutputs() = 0;
virtual DXC_OUT_KIND GetOutputByIndex(UINT32 Index) = 0;
virtual DXC_OUT_KIND PrimaryOutput() = 0;
};
// Special names for extra output that should get written to specific streams
#define DXC_EXTRA_OUTPUT_NAME_STDOUT L"*stdout*"
#define DXC_EXTRA_OUTPUT_NAME_STDERR L"*stderr*"
CROSS_PLATFORM_UUIDOF(IDxcExtraOutputs, "319b37a2-a5c2-494a-a5de-4801b2faf989")
struct IDxcExtraOutputs : public IUnknown {
virtual UINT32 STDMETHODCALLTYPE GetOutputCount() = 0;
virtual HRESULT STDMETHODCALLTYPE GetOutput(_In_ UINT32 uIndex,
_In_ REFIID iid, _COM_Outptr_opt_result_maybenull_ void **ppvObject,
_COM_Outptr_opt_result_maybenull_ IDxcBlobUtf16 **ppOutputType,
_COM_Outptr_opt_result_maybenull_ IDxcBlobUtf16 **ppOutputName) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcCompiler3, "228B4687-5A6A-4730-900C-9702B2203F54")
struct IDxcCompiler3 : public IUnknown {
// Compile a single entry point to the target shader model,
// Compile a library to a library target (-T lib_*),
// Compile a root signature (-T rootsig_*), or
// Preprocess HLSL source (-P)
virtual HRESULT STDMETHODCALLTYPE Compile(
_In_ const DxcBuffer *pSource, // Source text to compile
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
_In_ REFIID riid, _Out_ LPVOID *ppResult // IDxcResult: status, buffer, and errors
) = 0;
// Disassemble a program.
virtual HRESULT STDMETHODCALLTYPE Disassemble(
_In_ const DxcBuffer *pObject, // Program to disassemble: dxil container or bitcode.
_In_ REFIID riid, _Out_ LPVOID *ppResult // IDxcResult: status, disassembly text, and errors
) = 0;
};
static const UINT32 DxcValidatorFlags_Default = 0;
static const UINT32 DxcValidatorFlags_InPlaceEdit = 1; // Validator is allowed to update shader blob in-place.
static const UINT32 DxcValidatorFlags_RootSignatureOnly = 2;
static const UINT32 DxcValidatorFlags_ModuleOnly = 4;
static const UINT32 DxcValidatorFlags_ValidMask = 0x7;
CROSS_PLATFORM_UUIDOF(IDxcValidator, "A6E82BD2-1FD7-4826-9811-2857E797F49A")
struct IDxcValidator : public IUnknown {
// Validate a shader.
virtual HRESULT STDMETHODCALLTYPE Validate(
_In_ IDxcBlob *pShader, // Shader to validate.
_In_ UINT32 Flags, // Validation flags.
_COM_Outptr_ IDxcOperationResult **ppResult // Validation output status, buffer, and errors
) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcContainerBuilder, "334b1f50-2292-4b35-99a1-25588d8c17fe")
struct IDxcContainerBuilder : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE Load(_In_ IDxcBlob *pDxilContainerHeader) = 0; // Loads DxilContainer to the builder
virtual HRESULT STDMETHODCALLTYPE AddPart(_In_ UINT32 fourCC, _In_ IDxcBlob *pSource) = 0; // Part to add to the container
virtual HRESULT STDMETHODCALLTYPE RemovePart(_In_ UINT32 fourCC) = 0; // Remove the part with fourCC
virtual HRESULT STDMETHODCALLTYPE SerializeContainer(_Out_ IDxcOperationResult **ppResult) = 0; // Builds a container of the given container builder state
};
CROSS_PLATFORM_UUIDOF(IDxcAssembler, "091f7a26-1c1f-4948-904b-e6e3a8a771d5")
struct IDxcAssembler : public IUnknown {
// Assemble dxil in ll or llvm bitcode to DXIL container.
virtual HRESULT STDMETHODCALLTYPE AssembleToContainer(
_In_ IDxcBlob *pShader, // Shader to assemble.
_COM_Outptr_ IDxcOperationResult **ppResult // Assembly output status, buffer, and errors
) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcContainerReflection, "d2c21b26-8350-4bdc-976a-331ce6f4c54c")
struct IDxcContainerReflection : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE Load(_In_ IDxcBlob *pContainer) = 0; // Container to load.
virtual HRESULT STDMETHODCALLTYPE GetPartCount(_Out_ UINT32 *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetPartKind(UINT32 idx, _Out_ UINT32 *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetPartContent(UINT32 idx, _COM_Outptr_ IDxcBlob **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE FindFirstPartKind(UINT32 kind, _Out_ UINT32 *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetPartReflection(UINT32 idx, REFIID iid, void **ppvObject) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcOptimizerPass, "AE2CD79F-CC22-453F-9B6B-B124E7A5204C")
struct IDxcOptimizerPass : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetOptionName(_COM_Outptr_ LPWSTR *ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDescription(_COM_Outptr_ LPWSTR *ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOptionArgCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOptionArgName(UINT32 argIndex, _COM_Outptr_ LPWSTR *ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOptionArgDescription(UINT32 argIndex, _COM_Outptr_ LPWSTR *ppResult) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcOptimizer, "25740E2E-9CBA-401B-9119-4FB42F39F270")
struct IDxcOptimizer : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetAvailablePassCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetAvailablePass(UINT32 index, _COM_Outptr_ IDxcOptimizerPass** ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE RunOptimizer(IDxcBlob *pBlob,
_In_count_(optionCount) LPCWSTR *ppOptions, UINT32 optionCount,
_COM_Outptr_ IDxcBlob **pOutputModule,
_COM_Outptr_opt_ IDxcBlobEncoding **ppOutputText) = 0;
};
static const UINT32 DxcVersionInfoFlags_None = 0;
static const UINT32 DxcVersionInfoFlags_Debug = 1; // Matches VS_FF_DEBUG
static const UINT32 DxcVersionInfoFlags_Internal = 2; // Internal Validator (non-signing)
CROSS_PLATFORM_UUIDOF(IDxcVersionInfo, "b04f5b50-2059-4f12-a8ff-a1e0cde1cc7e")
struct IDxcVersionInfo : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetVersion(_Out_ UINT32 *pMajor, _Out_ UINT32 *pMinor) = 0;
virtual HRESULT STDMETHODCALLTYPE GetFlags(_Out_ UINT32 *pFlags) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcVersionInfo2, "fb6904c4-42f0-4b62-9c46-983af7da7c83")
struct IDxcVersionInfo2 : public IDxcVersionInfo {
virtual HRESULT STDMETHODCALLTYPE GetCommitInfo(_Out_ UINT32 *pCommitCount, _Out_ char **pCommitHash) = 0;
};
// Note: __declspec(selectany) requires 'extern'
// On Linux __declspec(selectany) is removed and using 'extern' results in link error.
#ifdef _MSC_VER
#define CLSID_SCOPE __declspec(selectany) extern
#else
#define CLSID_SCOPE
#endif
CLSID_SCOPE const CLSID CLSID_DxcCompiler = {
0x73e22d93,
0xe6ce,
0x47f3,
{0xb5, 0xbf, 0xf0, 0x66, 0x4f, 0x39, 0xc1, 0xb0}};
// {EF6A8087-B0EA-4D56-9E45-D07E1A8B7806}
CLSID_SCOPE const GUID CLSID_DxcLinker = {
0xef6a8087,
0xb0ea,
0x4d56,
{0x9e, 0x45, 0xd0, 0x7e, 0x1a, 0x8b, 0x78, 0x6}};
// {CD1F6B73-2AB0-484D-8EDC-EBE7A43CA09F}
CLSID_SCOPE const CLSID CLSID_DxcDiaDataSource = {
0xcd1f6b73,
0x2ab0,
0x484d,
{0x8e, 0xdc, 0xeb, 0xe7, 0xa4, 0x3c, 0xa0, 0x9f}};
// {3E56AE82-224D-470F-A1A1-FE3016EE9F9D}
CLSID_SCOPE const CLSID CLSID_DxcCompilerArgs = {
0x3e56ae82,
0x224d,
0x470f,
{0xa1, 0xa1, 0xfe, 0x30, 0x16, 0xee, 0x9f, 0x9d}};
// {6245D6AF-66E0-48FD-80B4-4D271796748C}
CLSID_SCOPE const GUID CLSID_DxcLibrary = {
0x6245d6af,
0x66e0,
0x48fd,
{0x80, 0xb4, 0x4d, 0x27, 0x17, 0x96, 0x74, 0x8c}};
CLSID_SCOPE const GUID CLSID_DxcUtils = CLSID_DxcLibrary;
// {8CA3E215-F728-4CF3-8CDD-88AF917587A1}
CLSID_SCOPE const GUID CLSID_DxcValidator = {
0x8ca3e215,
0xf728,
0x4cf3,
{0x8c, 0xdd, 0x88, 0xaf, 0x91, 0x75, 0x87, 0xa1}};
// {D728DB68-F903-4F80-94CD-DCCF76EC7151}
CLSID_SCOPE const GUID CLSID_DxcAssembler = {
0xd728db68,
0xf903,
0x4f80,
{0x94, 0xcd, 0xdc, 0xcf, 0x76, 0xec, 0x71, 0x51}};
// {b9f54489-55b8-400c-ba3a-1675e4728b91}
CLSID_SCOPE const GUID CLSID_DxcContainerReflection = {
0xb9f54489,
0x55b8,
0x400c,
{0xba, 0x3a, 0x16, 0x75, 0xe4, 0x72, 0x8b, 0x91}};
// {AE2CD79F-CC22-453F-9B6B-B124E7A5204C}
CLSID_SCOPE const GUID CLSID_DxcOptimizer = {
0xae2cd79f,
0xcc22,
0x453f,
{0x9b, 0x6b, 0xb1, 0x24, 0xe7, 0xa5, 0x20, 0x4c}};
// {94134294-411f-4574-b4d0-8741e25240d2}
CLSID_SCOPE const GUID CLSID_DxcContainerBuilder = {
0x94134294,
0x411f,
0x4574,
{0xb4, 0xd0, 0x87, 0x41, 0xe2, 0x52, 0x40, 0xd2}};
#endif
+104
View File
@@ -0,0 +1,104 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_buffer.h"
#include <assert.h>
void
dxil_buffer_init(struct dxil_buffer *b, unsigned abbrev_width)
{
blob_init(&b->blob);
b->buf = 0;
b->buf_bits = 0;
b->abbrev_width = abbrev_width;
}
void
dxil_buffer_finish(struct dxil_buffer *b)
{
blob_finish(&b->blob);
}
static bool
flush_dword(struct dxil_buffer *b)
{
assert(b->buf_bits >= 32 && b->buf_bits < 64);
uint32_t lower_bits = b->buf & UINT32_MAX;
if (!blob_write_bytes(&b->blob, &lower_bits, sizeof(lower_bits)))
return false;
b->buf >>= 32;
b->buf_bits -= 32;
return true;
}
bool
dxil_buffer_emit_bits(struct dxil_buffer *b, uint32_t data, unsigned width)
{
assert(b->buf_bits < 32);
assert(width > 0 && width <= 32);
assert((data & ~((UINT64_C(1) << width) - 1)) == 0);
b->buf |= ((uint64_t)data) << b->buf_bits;
b->buf_bits += width;
if (b->buf_bits >= 32)
return flush_dword(b);
return true;
}
bool
dxil_buffer_emit_vbr_bits(struct dxil_buffer *b, uint64_t data,
unsigned width)
{
assert(width > 1 && width <= 32);
uint32_t tag = UINT32_C(1) << (width - 1);
uint32_t max = tag - 1;
while (data > max) {
uint32_t value = (data & max) | tag;
data >>= width - 1;
if (!dxil_buffer_emit_bits(b, value, width))
return false;
}
return dxil_buffer_emit_bits(b, data, width);
}
bool
dxil_buffer_align(struct dxil_buffer *b)
{
assert(b->buf_bits < 32);
if (b->buf_bits) {
b->buf_bits = 32;
return flush_dword(b);
}
return true;
}
+60
View File
@@ -0,0 +1,60 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_BUFFER_H
#define DXIL_BUFFER_H
#include "util/blob.h"
struct dxil_buffer {
struct blob blob;
uint64_t buf;
unsigned buf_bits;
unsigned abbrev_width;
};
void
dxil_buffer_init(struct dxil_buffer *b, unsigned abbrev_width);
void
dxil_buffer_finish(struct dxil_buffer *b);
bool
dxil_buffer_emit_bits(struct dxil_buffer *b, uint32_t data, unsigned width);
bool
dxil_buffer_emit_vbr_bits(struct dxil_buffer *b, uint64_t data,
unsigned width);
bool
dxil_buffer_align(struct dxil_buffer *b);
static inline bool
dxil_buffer_emit_abbrev_id(struct dxil_buffer *b, uint32_t id)
{
return dxil_buffer_emit_bits(b, id, b->abbrev_width);
}
#endif
+129
View File
@@ -0,0 +1,129 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_buffer.h"
#include <assert.h>
#include <stdio.h>
static void
init()
{
struct dxil_buffer buf;
dxil_buffer_init(&buf, 2);
assert(!buf.buf);
assert(!buf.buf_bits);
}
static void
assert_blob_data(const struct dxil_buffer *m, const uint8_t *data,
size_t len)
{
if (m->blob.size != len) {
fprintf(stderr, "blob-size mismatch, expected %zd, got %zd",
len, m->blob.size);
abort();
}
for (size_t i = 0; i < len; ++i) {
if (m->blob.data[i] != data[i]) {
fprintf(stderr, "blob-data mismatch at index %zd, "
"expected 0x%02x, got 0x%02x", i,
data[i], m->blob.data[i]);
abort();
}
}
}
#define ASSERT_BLOB_DATA(m, data) \
assert_blob_data(m, data, sizeof(data))
static void
align()
{
struct dxil_buffer buf;
dxil_buffer_init(&buf, 2);
assert_blob_data(&buf, NULL, 0);
dxil_buffer_init(&buf, 2);
dxil_buffer_emit_bits(&buf, 0xbeef, 16);
dxil_buffer_align(&buf);
assert(!buf.buf);
assert(!buf.buf_bits);
uint8_t expected0[] = { 0xef, 0xbe, 0x00, 0x00 };
ASSERT_BLOB_DATA(&buf, expected0);
dxil_buffer_align(&buf);
ASSERT_BLOB_DATA(&buf, expected0);
}
static void
emit_bits()
{
struct dxil_buffer buf;
dxil_buffer_init(&buf, 2);
dxil_buffer_emit_bits(&buf, 0xbeef, 16);
dxil_buffer_align(&buf);
assert(!buf.buf);
assert(!buf.buf_bits);
uint8_t expected0[] = { 0xef, 0xbe, 0x00, 0x00 };
ASSERT_BLOB_DATA(&buf, expected0);
dxil_buffer_init(&buf, 2);
dxil_buffer_emit_bits(&buf, 0xdead, 16);
dxil_buffer_emit_bits(&buf, 0xbeef, 16);
assert(!buf.buf);
assert(!buf.buf_bits);
uint8_t expected1[] = { 0xad, 0xde, 0xef, 0xbe };
ASSERT_BLOB_DATA(&buf, expected1);
dxil_buffer_init(&buf, 2);
dxil_buffer_emit_bits(&buf, 0x1111111, 28);
dxil_buffer_emit_bits(&buf, 0x22222222, 32);
dxil_buffer_align(&buf);
uint8_t expected2[] = { 0x11, 0x11, 0x11, 0x21, 0x22, 0x22, 0x22, 0x02 };
ASSERT_BLOB_DATA(&buf, expected2);
}
static void
emit_vbr_bits()
{
struct dxil_buffer buf;
dxil_buffer_init(&buf, 2);
dxil_buffer_emit_vbr_bits(&buf, 0x1a, 8);
dxil_buffer_emit_vbr_bits(&buf, 0x1a, 6);
dxil_buffer_emit_vbr_bits(&buf, 0x00, 2);
dxil_buffer_emit_vbr_bits(&buf, 0x0a, 4);
dxil_buffer_emit_vbr_bits(&buf, 0x04, 2);
dxil_buffer_emit_vbr_bits(&buf, 0x00, 2);
uint8_t expected[] = { 0x1a, 0x1a, 0x1a, 0x1a };
ASSERT_BLOB_DATA(&buf, expected);
}
int
main()
{
init();
align();
emit_bits();
emit_vbr_bits();
return 0;
}
+395
View File
@@ -0,0 +1,395 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_container.h"
#include "dxil_module.h"
#include "util/u_debug.h"
#include <assert.h>
const uint32_t DXIL_DXBC = DXIL_FOURCC('D', 'X', 'B', 'C');
void
dxil_container_init(struct dxil_container *c)
{
blob_init(&c->parts);
c->num_parts = 0;
}
void
dxil_container_finish(struct dxil_container *c)
{
blob_finish(&c->parts);
}
static bool
add_part_header(struct dxil_container *c,
enum dxil_part_fourcc fourcc,
uint32_t part_size)
{
assert(c->parts.size < UINT_MAX);
unsigned offset = (unsigned)c->parts.size;
if (!blob_write_bytes(&c->parts, &fourcc, sizeof(fourcc)) ||
!blob_write_bytes(&c->parts, &part_size, sizeof(part_size)))
return false;
assert(c->num_parts < DXIL_MAX_PARTS);
c->part_offsets[c->num_parts++] = offset;
return true;
}
static bool
add_part(struct dxil_container *c,
enum dxil_part_fourcc fourcc,
const void *part_data, uint32_t part_size)
{
return add_part_header(c, fourcc, part_size) &&
blob_write_bytes(&c->parts, part_data, part_size);
}
bool
dxil_container_add_features(struct dxil_container *c,
const struct dxil_features *features)
{
/* DXIL feature info is a bitfield packed into a uint64_t. */
static_assert(sizeof(struct dxil_features) <= sizeof(uint64_t),
"Expected dxil_features to fit into a uint64_t");
uint64_t bits = 0;
memcpy(&bits, features, sizeof(struct dxil_features));
return add_part(c, DXIL_SFI0, &bits, sizeof(uint64_t));
}
typedef struct {
struct {
const char *name;
uint32_t offset;
} entries[DXIL_SHADER_MAX_IO_ROWS];
uint32_t num_entries;
} name_offset_cache_t;
static uint32_t
get_semantic_name_offset(name_offset_cache_t *cache, const char *name,
struct _mesa_string_buffer *buf, uint32_t buf_offset,
bool validator_7)
{
uint32_t offset = buf->length + buf_offset;
/* DXC doesn't de-duplicate arbitrary semantic names until validator 1.7, only SVs. */
if (validator_7 || strncmp(name, "SV_", 3) == 0) {
/* consider replacing this with a binary search using rb_tree */
for (unsigned i = 0; i < cache->num_entries; ++i) {
if (!strcmp(name, cache->entries[i].name))
return cache->entries[i].offset;
}
cache->entries[cache->num_entries].name = name;
cache->entries[cache->num_entries].offset = offset;
++cache->num_entries;
}
_mesa_string_buffer_append_len(buf, name, strlen(name) + 1);
return offset;
}
static uint32_t
collect_semantic_names(unsigned num_records,
struct dxil_signature_record *io_data,
struct _mesa_string_buffer *buf,
uint32_t buf_offset,
bool validator_7)
{
name_offset_cache_t cache;
cache.num_entries = 0;
for (unsigned i = 0; i < num_records; ++i) {
struct dxil_signature_record *io = &io_data[i];
uint32_t offset = get_semantic_name_offset(&cache, io->name, buf, buf_offset, validator_7);
for (unsigned j = 0; j < io->num_elements; ++j)
io->elements[j].semantic_name_offset = offset;
}
if (validator_7 && buf->length % sizeof(uint32_t) != 0) {
unsigned padding_to_add = sizeof(uint32_t) - (buf->length % sizeof(uint32_t));
char padding[sizeof(uint32_t)] = { 0 };
_mesa_string_buffer_append_len(buf, padding, padding_to_add);
}
return buf_offset + buf->length;
}
bool
dxil_container_add_io_signature(struct dxil_container *c,
enum dxil_part_fourcc part,
unsigned num_records,
struct dxil_signature_record *io_data,
bool validator_7)
{
struct {
uint32_t param_count;
uint32_t param_offset;
} header;
header.param_count = 0;
uint32_t fixed_size = sizeof(header);
header.param_offset = fixed_size;
bool retval = true;
for (unsigned i = 0; i < num_records; ++i) {
/* TODO:
* - Here we need to check whether the value is actually part of the
* signature */
fixed_size += sizeof(struct dxil_signature_element) * io_data[i].num_elements;
header.param_count += io_data[i].num_elements;
}
struct _mesa_string_buffer *names =
_mesa_string_buffer_create(NULL, 1024);
uint32_t last_offset = collect_semantic_names(num_records, io_data,
names, fixed_size,
validator_7);
if (!add_part_header(c, part, last_offset) ||
!blob_write_bytes(&c->parts, &header, sizeof(header))) {
retval = false;
goto cleanup;
}
/* write all parts */
for (unsigned i = 0; i < num_records; ++i)
for (unsigned j = 0; j < io_data[i].num_elements; ++j) {
if (!blob_write_bytes(&c->parts, &io_data[i].elements[j],
sizeof(io_data[i].elements[j]))) {
retval = false;
goto cleanup;
}
}
/* write all names */
if (!blob_write_bytes(&c->parts, names->buf, names->length))
retval = false;
cleanup:
_mesa_string_buffer_destroy(names);
return retval;
}
bool
dxil_container_add_state_validation(struct dxil_container *c,
const struct dxil_module *m,
struct dxil_validation_state *state)
{
uint32_t psv_size = m->minor_validator >= 8 ?
sizeof(struct dxil_psv_runtime_info_3) : m->minor_validator >= 6 ?
sizeof(struct dxil_psv_runtime_info_2) : sizeof(struct dxil_psv_runtime_info_1);
uint32_t resource_bind_info_size = m->minor_validator >= 6 ?
sizeof(struct dxil_resource_v1) : sizeof(struct dxil_resource_v0);
uint32_t dxil_pvs_sig_size = sizeof(struct dxil_psv_signature_element);
uint32_t resource_count = state->num_resources;
struct dxil_psv_runtime_info_3 *psv3 = &state->state;
struct dxil_psv_runtime_info_2 *psv2 = &psv3->psv2;
struct dxil_psv_runtime_info_1 *psv1 = &psv2->psv1;
uint32_t size = psv_size + 2 * sizeof(uint32_t);
if (resource_count > 0) {
size += sizeof (uint32_t) +
resource_bind_info_size * resource_count;
}
uint32_t string_table_size = (m->sem_string_table->length + 3) & ~3u;
size += sizeof(uint32_t) + string_table_size;
size += sizeof(uint32_t) + m->sem_index_table.size * sizeof(uint32_t);
if (m->num_sig_inputs || m->num_sig_outputs || m->num_sig_patch_consts) {
size += sizeof(uint32_t);
}
size += dxil_pvs_sig_size * m->num_sig_inputs;
size += dxil_pvs_sig_size * m->num_sig_outputs;
size += dxil_pvs_sig_size * m->num_sig_patch_consts;
psv1->sig_input_vectors = (uint8_t)m->num_psv_inputs;
for (unsigned i = 0; i < 4; ++i)
psv1->sig_output_vectors[i] = (uint8_t)m->num_psv_outputs[i];
if (psv1->uses_view_id) {
for (unsigned i = 0; i < 4; ++i)
size += m->dependency_table_dwords_per_input[i] * sizeof(uint32_t);
}
for (unsigned i = 0; i < 4; ++i)
size += m->io_dependency_table_size[i] * sizeof(uint32_t);
if (!add_part_header(c, DXIL_PSV0, size))
return false;
if (!blob_write_bytes(&c->parts, &psv_size, sizeof(psv_size)))
return false;
if (!blob_write_bytes(&c->parts, &state->state, psv_size))
return false;
if (!blob_write_bytes(&c->parts, &resource_count, sizeof(resource_count)))
return false;
if (resource_count > 0) {
if (!blob_write_bytes(&c->parts, &resource_bind_info_size, sizeof(resource_bind_info_size)) ||
!blob_write_bytes(&c->parts, state->resources.v0, resource_bind_info_size * state->num_resources))
return false;
}
uint32_t fill = 0;
if (!blob_write_bytes(&c->parts, &string_table_size, sizeof(string_table_size)) ||
!blob_write_bytes(&c->parts, m->sem_string_table->buf, m->sem_string_table->length) ||
!blob_write_bytes(&c->parts, &fill, string_table_size - m->sem_string_table->length))
return false;
if (!blob_write_bytes(&c->parts, &m->sem_index_table.size, sizeof(uint32_t)))
return false;
if (m->sem_index_table.size > 0) {
if (!blob_write_bytes(&c->parts, m->sem_index_table.data,
m->sem_index_table.size * sizeof(uint32_t)))
return false;
}
if (m->num_sig_inputs || m->num_sig_outputs || m->num_sig_patch_consts) {
if (!blob_write_bytes(&c->parts, &dxil_pvs_sig_size, sizeof(dxil_pvs_sig_size)))
return false;
if (!blob_write_bytes(&c->parts, &m->psv_inputs, dxil_pvs_sig_size * m->num_sig_inputs))
return false;
if (!blob_write_bytes(&c->parts, &m->psv_outputs, dxil_pvs_sig_size * m->num_sig_outputs))
return false;
if (!blob_write_bytes(&c->parts, &m->psv_patch_consts, dxil_pvs_sig_size * m->num_sig_patch_consts))
return false;
}
/* This was a bug in the DXIL validation logic prior to 1.8. When replicating these I/O dependency
* tables from the metadata to the container, the pointer is advanced for each stream,
* and then copied for all streams... meaning that the first streams have zero data, since the
* pointer is advanced and then never written to. The last stream (that has data) then has the
* data from all streams written to it. However, if any stream before the last one has a larger
* size, this will cause corruption, since it's writing to the smaller space that was allocated
* for the last stream. We assume that never happens, and just zero all earlier streams. */
if (m->shader_kind == DXIL_GEOMETRY_SHADER && m->minor_validator < 8) {
bool zero_view_id_deps = false, zero_io_deps = false;
for (int i = 3; i >= 0; --i) {
if (psv1->uses_view_id && m->dependency_table_dwords_per_input[i]) {
if (zero_view_id_deps)
memset(m->viewid_dependency_table[i], 0, sizeof(uint32_t) * m->dependency_table_dwords_per_input[i]);
zero_view_id_deps = true;
}
if (m->io_dependency_table_size[i]) {
if (zero_io_deps)
memset(m->io_dependency_table[i], 0, sizeof(uint32_t) * m->io_dependency_table_size[i]);
zero_io_deps = true;
}
}
}
if (psv1->uses_view_id) {
for (unsigned i = 0; i < 4; ++i)
if (!blob_write_bytes(&c->parts, m->viewid_dependency_table[i],
sizeof(uint32_t) * m->dependency_table_dwords_per_input[i]))
return false;
}
for (unsigned i = 0; i < 4; ++i)
if (!blob_write_bytes(&c->parts, m->io_dependency_table[i],
sizeof(uint32_t) * m->io_dependency_table_size[i]))
return false;
return true;
}
bool
dxil_container_add_module(struct dxil_container *c,
const struct dxil_module *m)
{
assert(m->buf.buf_bits == 0); // make sure the module is fully flushed
uint32_t version = (m->shader_kind << 16) |
(m->major_version << 4) |
m->minor_version;
uint32_t size = 6 * sizeof(uint32_t) + m->buf.blob.size;
assert(size % sizeof(uint32_t) == 0);
uint32_t uint32_size = size / sizeof(uint32_t);
uint32_t magic = 0x4C495844;
uint32_t dxil_version = 1 << 8; // I have no idea...
uint32_t bitcode_offset = 16;
uint32_t bitcode_size = m->buf.blob.size;
return add_part_header(c, DXIL_DXIL, size) &&
blob_write_bytes(&c->parts, &version, sizeof(version)) &&
blob_write_bytes(&c->parts, &uint32_size, sizeof(uint32_size)) &&
blob_write_bytes(&c->parts, &magic, sizeof(magic)) &&
blob_write_bytes(&c->parts, &dxil_version, sizeof(dxil_version)) &&
blob_write_bytes(&c->parts, &bitcode_offset, sizeof(bitcode_offset)) &&
blob_write_bytes(&c->parts, &bitcode_size, sizeof(bitcode_size)) &&
blob_write_bytes(&c->parts, m->buf.blob.data, m->buf.blob.size);
}
bool
dxil_container_write(struct dxil_container *c, struct blob *blob)
{
assert(blob->size == 0);
if (!blob_write_bytes(blob, &DXIL_DXBC, sizeof(DXIL_DXBC)))
return false;
const uint8_t unsigned_digest[16] = { 0 }; // null-digest means unsigned
if (!blob_write_bytes(blob, unsigned_digest, sizeof(unsigned_digest)))
return false;
uint16_t major_version = 1;
uint16_t minor_version = 0;
if (!blob_write_bytes(blob, &major_version, sizeof(major_version)) ||
!blob_write_bytes(blob, &minor_version, sizeof(minor_version)))
return false;
size_t header_size = 32 + 4 * c->num_parts;
size_t size = header_size + c->parts.size;
assert(size <= UINT32_MAX);
uint32_t container_size = (uint32_t)size;
if (!blob_write_bytes(blob, &container_size, sizeof(container_size)))
return false;
uint32_t part_offsets[DXIL_MAX_PARTS];
for (int i = 0; i < c->num_parts; ++i) {
size_t offset = header_size + c->part_offsets[i];
assert(offset <= UINT32_MAX);
part_offsets[i] = (uint32_t)offset;
}
if (!blob_write_bytes(blob, &c->num_parts, sizeof(c->num_parts)) ||
!blob_write_bytes(blob, part_offsets, sizeof(uint32_t) * c->num_parts) ||
!blob_write_bytes(blob, c->parts.data, c->parts.size))
return false;
return true;
}
+135
View File
@@ -0,0 +1,135 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_CONTAINER_H
#define DXIL_CONTAINER_H
#ifdef __cplusplus
extern "C" {
#endif
#include "util/blob.h"
#include "dxil_signature.h"
#define DXIL_MAX_PARTS 8
struct dxil_container {
struct blob parts;
unsigned part_offsets[DXIL_MAX_PARTS];
unsigned num_parts;
};
enum dxil_resource_type {
DXIL_RES_INVALID = 0,
DXIL_RES_SAMPLER = 1,
DXIL_RES_CBV = 2,
DXIL_RES_SRV_TYPED = 3,
DXIL_RES_SRV_RAW = 4,
DXIL_RES_SRV_STRUCTURED = 5,
DXIL_RES_UAV_TYPED = 6,
DXIL_RES_UAV_RAW = 7,
DXIL_RES_UAV_STRUCTURED,
DXIL_RES_UAV_STRUCTURED_WITH_COUNTER,
DXIL_RES_NUM_ENTRIES /* should always be last */
};
#define DXIL_FOURCC(ch0, ch1, ch2, ch3) ( \
(uint32_t)(ch0) | (uint32_t)(ch1) << 8 | \
(uint32_t)(ch2) << 16 | (uint32_t)(ch3) << 24)
enum dxil_part_fourcc {
DXIL_RDEF = DXIL_FOURCC('R', 'D', 'E', 'F'),
DXIL_ISG1 = DXIL_FOURCC('I', 'S', 'G', '1'),
DXIL_OSG1 = DXIL_FOURCC('O', 'S', 'G', '1'),
DXIL_PSG1 = DXIL_FOURCC('P', 'S', 'G', '1'),
DXIL_STAT = DXIL_FOURCC('S', 'T', 'A', 'T'),
DXIL_ILDB = DXIL_FOURCC('I', 'L', 'D', 'B'),
DXIL_ILDN = DXIL_FOURCC('I', 'L', 'D', 'N'),
DXIL_SFI0 = DXIL_FOURCC('S', 'F', 'I', '0'),
DXIL_PRIV = DXIL_FOURCC('P', 'R', 'I', 'V'),
DXIL_RTS0 = DXIL_FOURCC('R', 'T', 'S', '0'),
DXIL_DXIL = DXIL_FOURCC('D', 'X', 'I', 'L'),
DXIL_PSV0 = DXIL_FOURCC('P', 'S', 'V', '0'),
DXIL_RDAT = DXIL_FOURCC('R', 'D', 'A', 'T'),
DXIL_HASH = DXIL_FOURCC('H', 'A', 'S', 'H'),
};
struct dxil_resource_v0 {
uint32_t resource_type;
uint32_t space;
uint32_t lower_bound;
uint32_t upper_bound;
};
struct dxil_resource_v1 {
struct dxil_resource_v0 v0;
uint32_t resource_kind;
uint32_t resource_flags;
};
struct dxil_validation_state {
struct dxil_psv_runtime_info_3 state;
union {
const struct dxil_resource_v0 *v0;
const struct dxil_resource_v1 *v1;
} resources;
uint32_t num_resources;
};
void
dxil_container_init(struct dxil_container *c);
void
dxil_container_finish(struct dxil_container *c);
struct dxil_features;
bool
dxil_container_add_features(struct dxil_container *c,
const struct dxil_features *features);
bool
dxil_container_add_io_signature(struct dxil_container *c,
enum dxil_part_fourcc part,
unsigned num_records,
struct dxil_signature_record *io,
bool validator_7);
bool
dxil_container_add_state_validation(struct dxil_container *c,
const struct dxil_module *m,
struct dxil_validation_state *state);
bool
dxil_container_add_module(struct dxil_container *c,
const struct dxil_module *m);
bool
dxil_container_write(struct dxil_container *c, struct blob *blob);
#ifdef __cplusplus
}
#endif
#endif
+808
View File
@@ -0,0 +1,808 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_dump.h"
#include "dxil_internal.h"
#define DIXL_DUMP_DECL
#include "dxil_dump_decls.h"
#include "dxil_module.h"
#include "util/string_buffer.h"
#include "util/list.h"
#include <stdio.h>
struct dxil_dumper {
struct _mesa_string_buffer *buf;
int current_indent;
};
struct dxil_dumper *dxil_dump_create(void)
{
struct dxil_dumper *d = calloc(1, sizeof(struct dxil_dumper));
d->buf = _mesa_string_buffer_create(NULL, 1024);
d->current_indent = 0;
return d;
}
void dxil_dump_free(struct dxil_dumper *d)
{
_mesa_string_buffer_destroy(d->buf);
d->buf = 0;
free(d);
}
void dxil_dump_buf_to_file(struct dxil_dumper *d, FILE *f)
{
assert(f);
assert(d);
assert(d->buf);
fprintf(f, "%s", d->buf->buf);
}
static
void dxil_dump_indention_inc(struct dxil_dumper *d)
{
++d->current_indent;
}
static
void dxil_dump_indention_dec(struct dxil_dumper *d)
{
--d->current_indent;
assert(d->current_indent >= 0);
}
static
void dxil_dump_indent(struct dxil_dumper *d)
{
for (int i = 0; i < 2 * d->current_indent; ++i)
_mesa_string_buffer_append_char(d->buf, ' ');
}
void
dxil_dump_module(struct dxil_dumper *d, struct dxil_module *m)
{
assert(m);
assert(d);
_mesa_string_buffer_printf(d->buf, "DXIL MODULE:\n");
dump_metadata(d, m);
dump_shader_info(d, &m->info);
dump_types(d, &m->type_list);
dump_gvars(d, &m->gvar_list);
dump_funcs(d, &m->func_list);
dump_attr_set_list(d, &m->attr_set_list);
dump_constants(d, &m->const_list);
struct dxil_func_def *func_def;
LIST_FOR_EACH_ENTRY(func_def, &m->func_def_list, head) {
dump_instrs(d, &func_def->instr_list);
}
dump_mdnodes(d, &m->mdnode_list);
dump_named_nodes(d, &m->md_named_node_list);
dump_io_signatures(d->buf, m);
dump_psv(d->buf, m);
_mesa_string_buffer_printf(d->buf, "END DXIL MODULE\n");
}
static void
dump_metadata(struct dxil_dumper *d, struct dxil_module *m)
{
_mesa_string_buffer_printf(d->buf, "Shader: %s\n",
dump_shader_string(m->shader_kind));
_mesa_string_buffer_printf(d->buf, "Version: %d.%d\n",
m->major_version, m->minor_version);
dump_features(d->buf, &m->feats);
}
static void
dump_shader_info(struct dxil_dumper *d, struct dxil_shader_info *info)
{
_mesa_string_buffer_append(d->buf, "Shader Info:\n");
if (info->has_out_position)
_mesa_string_buffer_append(d->buf, " has_out_position\n");
}
static const char *
dump_shader_string(enum dxil_shader_kind kind)
{
#define SHADER_STR(X) case DXIL_ ## X ## _SHADER: return #X
switch (kind) {
SHADER_STR(VERTEX);
SHADER_STR(PIXEL);
SHADER_STR(GEOMETRY);
SHADER_STR(COMPUTE);
default:
return "UNSUPPORTED";
}
#undef SHADER_STR
}
static void
dump_features(struct _mesa_string_buffer *buf, struct dxil_features *feat)
{
_mesa_string_buffer_printf(buf, "Features:\n");
#define PRINT_FEAT(F) if (feat->F) _mesa_string_buffer_printf(buf, " %s\n", #F)
PRINT_FEAT(doubles);
PRINT_FEAT(cs_4x_raw_sb);
PRINT_FEAT(uavs_at_every_stage);
PRINT_FEAT(use_64uavs);
PRINT_FEAT(min_precision);
PRINT_FEAT(dx11_1_double_extensions);
PRINT_FEAT(dx11_1_shader_extensions);
PRINT_FEAT(dx9_comparison_filtering);
PRINT_FEAT(tiled_resources);
PRINT_FEAT(stencil_ref);
PRINT_FEAT(inner_coverage);
PRINT_FEAT(typed_uav_load_additional_formats);
PRINT_FEAT(rovs);
PRINT_FEAT(array_layer_from_vs_or_ds);
PRINT_FEAT(wave_ops);
PRINT_FEAT(int64_ops);
PRINT_FEAT(view_id);
PRINT_FEAT(barycentrics);
PRINT_FEAT(native_low_precision);
PRINT_FEAT(shading_rate);
PRINT_FEAT(raytracing_tier_1_1);
PRINT_FEAT(sampler_feedback);
#undef PRINT_FEAT
}
static void
dump_types(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "Types:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_type, type, list, head) {
dxil_dump_indent(d);
dump_type(d, type);
_mesa_string_buffer_append(d->buf, "\n");
}
dxil_dump_indention_dec(d);
}
static void dump_type_name(struct dxil_dumper *d, const struct dxil_type *type)
{
if (!type) {
_mesa_string_buffer_append(d->buf, "(type error)");
return;
}
switch (type->type) {
case TYPE_VOID:
_mesa_string_buffer_append(d->buf, "void");
break;
case TYPE_INTEGER:
_mesa_string_buffer_printf(d->buf, "int%d", type->int_bits);
break;
case TYPE_FLOAT:
_mesa_string_buffer_printf(d->buf, "float%d", type->float_bits);
break;
case TYPE_POINTER:
dump_type_name(d, type->ptr_target_type);
_mesa_string_buffer_append(d->buf, "*");
break;
case TYPE_STRUCT:
_mesa_string_buffer_printf(d->buf, "struct %s", type->struct_def.name);
break;
case TYPE_ARRAY:
dump_type_name(d, type->array_or_vector_def.elem_type);
_mesa_string_buffer_printf(d->buf, "[%zu]", type->array_or_vector_def.num_elems);
break;
case TYPE_FUNCTION:
_mesa_string_buffer_append(d->buf, "(");
dump_type_name(d, type->function_def.ret_type);
_mesa_string_buffer_append(d->buf, ")(");
for (size_t i = 0; i < type->function_def.args.num_types; ++i) {
if (i > 0)
_mesa_string_buffer_append(d->buf, ", ");
dump_type_name(d, type->function_def.args.types[i]);
}
_mesa_string_buffer_append(d->buf, ")");
break;
case TYPE_VECTOR:
_mesa_string_buffer_append(d->buf, "vector<");
dump_type_name(d, type->array_or_vector_def.elem_type);
_mesa_string_buffer_printf(d->buf, ", %zu>", type->array_or_vector_def.num_elems);
break;
default:
_mesa_string_buffer_printf(d->buf, "unknown type %d", type->type);
}
}
static void
dump_type(struct dxil_dumper *d, const struct dxil_type *type)
{
switch (type->type) {
case TYPE_STRUCT:
_mesa_string_buffer_printf(d->buf, "struct %s {\n", type->struct_def.name);
dxil_dump_indention_inc(d);
for (size_t i = 0; i < type->struct_def.elem.num_types; ++i) {
dxil_dump_indent(d);
dump_type(d, type->struct_def.elem.types[i]);
_mesa_string_buffer_append(d->buf, "\n");
}
dxil_dump_indention_dec(d);
dxil_dump_indent(d);
_mesa_string_buffer_append(d->buf, "}\n");
break;
default:
dump_type_name(d, type);
break;
}
}
static void
dump_gvars(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "Global variables:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_gvar, gvar, list, head) {
dxil_dump_indent(d);
_mesa_string_buffer_printf(d->buf, "address_space(%d) ", gvar->as);
if (gvar->constant)
_mesa_string_buffer_append(d->buf, "const ");
if (gvar->align)
_mesa_string_buffer_append(d->buf, "align ");
if (gvar->initializer)
_mesa_string_buffer_printf(d->buf, "init_id:%d\n", gvar->initializer->id);
dump_type_name(d, gvar->type);
_mesa_string_buffer_printf(d->buf, " val_id:%d\n", gvar->value.id);
}
dxil_dump_indention_dec(d);
}
static void
dump_funcs(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "Functions:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_func, func, list, head) {
dxil_dump_indent(d);
if (func->decl)
_mesa_string_buffer_append(d->buf, "declare ");
_mesa_string_buffer_append(d->buf, func->name);
_mesa_string_buffer_append_char(d->buf, ' ');
dump_type_name(d, func->type);
if (func->attr_set)
_mesa_string_buffer_printf(d->buf, " #%d", func->attr_set);
_mesa_string_buffer_append_char(d->buf, '\n');
}
dxil_dump_indention_dec(d);
}
static void
dump_attr_set_list(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "Attribute set:\n");
dxil_dump_indention_inc(d);
int attr_id = 1;
list_for_each_entry(struct attrib_set, attr, list, head) {
_mesa_string_buffer_printf(d->buf, " #%d: {", attr_id++);
for (unsigned i = 0; i < attr->num_attrs; ++i) {
if (i > 0)
_mesa_string_buffer_append_char(d->buf, ' ');
if (attr->attrs[i].type == DXIL_ATTR_ENUM) {
const char *value = "";
switch (attr->attrs[i].key.kind) {
case DXIL_ATTR_KIND_NONE: value = "none"; break;
case DXIL_ATTR_KIND_NO_UNWIND: value = "nounwind"; break;
case DXIL_ATTR_KIND_READ_NONE: value = "readnone"; break;
case DXIL_ATTR_KIND_READ_ONLY: value = "readonly"; break;
case DXIL_ATTR_KIND_NO_DUPLICATE: value = "noduplicate"; break;
}
_mesa_string_buffer_append(d->buf, value);
} else if (attr->attrs[i].type == DXIL_ATTR_STRING) {
_mesa_string_buffer_append_char(d->buf, '"');
_mesa_string_buffer_append(d->buf, attr->attrs[i].key.str);
_mesa_string_buffer_append_char(d->buf, '"');
} else if (attr->attrs[i].type == DXIL_ATTR_STRING_VALUE) {
_mesa_string_buffer_append_char(d->buf, '"');
_mesa_string_buffer_append(d->buf, attr->attrs[i].key.str);
_mesa_string_buffer_append(d->buf, "\"=\"");
_mesa_string_buffer_append(d->buf, attr->attrs[i].value.str);
_mesa_string_buffer_append_char(d->buf, '"');
}
}
_mesa_string_buffer_append(d->buf, "}\n");
}
dxil_dump_indention_dec(d);
}
static void
dump_constants(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "Constants:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_const, cnst, list, head) {
_mesa_string_buffer_append_char(d->buf, ' ');
dump_value(d, &cnst->value);
_mesa_string_buffer_append(d->buf, " = ");
dump_type_name(d, cnst->value.type);
if (!cnst->undef) {
switch (cnst->value.type->type) {
case TYPE_FLOAT:
_mesa_string_buffer_printf(d->buf, " %10.5f\n", cnst->float_value);
break;
case TYPE_INTEGER:
_mesa_string_buffer_printf(d->buf, " %" PRIdMAX "\n", cnst->int_value);
break;
case TYPE_ARRAY:
_mesa_string_buffer_append(d->buf, "{");
for (unsigned i = 0;
i < cnst->value.type->array_or_vector_def.num_elems; i++) {
_mesa_string_buffer_printf(d->buf, " %%%d",
cnst->array_values[i]->id);
dump_type_name(d, cnst->value.type);
if (i != cnst->value.type->array_or_vector_def.num_elems - 1)
_mesa_string_buffer_append(d->buf, ",");
_mesa_string_buffer_append(d->buf, " ");
}
_mesa_string_buffer_append(d->buf, "}\n");
break;
case TYPE_STRUCT:
_mesa_string_buffer_append(d->buf, "{");
for (unsigned i = 0;
i < cnst->value.type->struct_def.elem.num_types; i++) {
_mesa_string_buffer_printf(d->buf, " %%%d",
cnst->struct_values[i]->id);
dump_type_name(d, cnst->struct_values[i]->type);
if (i != cnst->value.type->struct_def.elem.num_types - 1)
_mesa_string_buffer_append(d->buf, ",");
_mesa_string_buffer_append(d->buf, " ");
}
_mesa_string_buffer_append(d->buf, "}\n");
break;
default:
UNREACHABLE("Unsupported const type");
}
} else
_mesa_string_buffer_append(d->buf, " undef\n");
}
dxil_dump_indention_dec(d);
}
static void
dump_instrs(struct dxil_dumper *d, struct list_head *list)
{
_mesa_string_buffer_append(d->buf, "Shader body:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_instr, instr, list, head) {
dxil_dump_indent(d);
if (instr->has_value) {
dump_value(d, &instr->value);
_mesa_string_buffer_append(d->buf, " = ");
} else {
_mesa_string_buffer_append_char(d->buf, ' ');
}
switch (instr->type) {
case INSTR_BINOP: dump_instr_binop(d, &instr->binop); break;
case INSTR_CMP: dump_instr_cmp(d, &instr->cmp);break;
case INSTR_SELECT:dump_instr_select(d, &instr->select); break;
case INSTR_CAST: dump_instr_cast(d, &instr->cast); break;
case INSTR_CALL: dump_instr_call(d, &instr->call); break;
case INSTR_RET: dump_instr_ret(d, &instr->ret); break;
case INSTR_EXTRACTVAL: dump_instr_extractval(d, &instr->extractval); break;
case INSTR_BR: dump_instr_branch(d, &instr->br); break;
case INSTR_PHI: dump_instr_phi(d, &instr->phi); break;
case INSTR_ALLOCA: dump_instr_alloca(d, &instr->alloca); break;
case INSTR_GEP: dump_instr_gep(d, &instr->gep); break;
case INSTR_LOAD: dump_instr_load(d, &instr->load); break;
case INSTR_STORE: dump_instr_store(d, &instr->store); break;
case INSTR_ATOMICRMW: dump_instr_atomicrmw(d, &instr->atomicrmw); break;
default:
_mesa_string_buffer_printf(d->buf, "unknown instruction type %d", instr->type);
}
_mesa_string_buffer_append(d->buf, "\n");
}
dxil_dump_indention_dec(d);
}
static void
dump_instr_binop(struct dxil_dumper *d, struct dxil_instr_binop *binop)
{
const char *str = binop->opcode < DXIL_BINOP_INSTR_COUNT ?
binop_strings[binop->opcode] : "INVALID";
_mesa_string_buffer_printf(d->buf, "%s ", str);
dump_instr_print_operands(d, 2, binop->operands);
}
static void
dump_instr_cmp(struct dxil_dumper *d, struct dxil_instr_cmp *cmp)
{
const char *str = cmp->pred < DXIL_CMP_INSTR_COUNT ?
pred_strings[cmp->pred] : "INVALID";
_mesa_string_buffer_printf(d->buf, "%s ", str);
dump_instr_print_operands(d, 2, cmp->operands);
}
static void
dump_instr_select(struct dxil_dumper *d, struct dxil_instr_select *select)
{
_mesa_string_buffer_append(d->buf, "sel ");
dump_instr_print_operands(d, 3, select->operands);
}
static void
dump_instr_cast(struct dxil_dumper *d, struct dxil_instr_cast *cast)
{
const char *str = cast->opcode < DXIL_CAST_INSTR_COUNT ?
cast_opcode_strings[cast->opcode] : "INVALID";
_mesa_string_buffer_printf(d->buf, "%s.", str);
dump_type_name(d, cast->type);
_mesa_string_buffer_append_char(d->buf, ' ');
dump_value(d, cast->value);
}
static void
dump_instr_call(struct dxil_dumper *d, struct dxil_instr_call *call)
{
assert(call->num_args == call->func->type->function_def.args.num_types);
struct dxil_type **func_arg_types = call->func->type->function_def.args.types;
_mesa_string_buffer_printf(d->buf, "%s(", call->func->name);
for (unsigned i = 0; i < call->num_args; ++i) {
if (i > 0)
_mesa_string_buffer_append(d->buf, ", ");
dump_type_name(d, func_arg_types[i]);
_mesa_string_buffer_append_char(d->buf, ' ');
dump_value(d, call->args[i]);
}
_mesa_string_buffer_append_char(d->buf, ')');
}
static void
dump_instr_ret(struct dxil_dumper *d, struct dxil_instr_ret *ret)
{
_mesa_string_buffer_append(d->buf, "ret ");
if (ret->value)
dump_value(d, ret->value);
}
static void
dump_instr_extractval(struct dxil_dumper *d, struct dxil_instr_extractval *extr)
{
_mesa_string_buffer_append(d->buf, "extractvalue ");
dump_type_name(d, extr->type);
dump_value(d, extr->src);
_mesa_string_buffer_printf(d->buf, ", %d", extr->idx);
}
static void
dump_instr_branch(struct dxil_dumper *d, struct dxil_instr_br *br)
{
_mesa_string_buffer_append(d->buf, "branch ");
if (br->cond)
dump_value(d, br->cond);
else
_mesa_string_buffer_append(d->buf, " (uncond)");
_mesa_string_buffer_printf(d->buf, " %d %d", br->succ[0], br->succ[1]);
}
static void
dump_instr_phi(struct dxil_dumper *d, struct dxil_instr_phi *phi)
{
_mesa_string_buffer_append(d->buf, "phi ");
dump_type_name(d, phi->type);
struct dxil_phi_src *src = phi->incoming;
for (unsigned i = 0; i < phi->num_incoming; ++i, ++src) {
if (i > 0)
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, src->value);
_mesa_string_buffer_printf(d->buf, "(%d)", src->block);
}
}
static void
dump_instr_alloca(struct dxil_dumper *d, struct dxil_instr_alloca *alloca)
{
_mesa_string_buffer_append(d->buf, "alloca ");
dump_type_name(d, alloca->alloc_type);
_mesa_string_buffer_append(d->buf, ", ");
dump_type_name(d, alloca->size_type);
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, alloca->size);
unsigned align_mask = (1 << 6 ) - 1;
unsigned align = alloca->align & align_mask;
_mesa_string_buffer_printf(d->buf, ", %d", 1 << (align - 1));
}
static void
dump_instr_gep(struct dxil_dumper *d, struct dxil_instr_gep *gep)
{
_mesa_string_buffer_append(d->buf, "getelementptr ");
if (gep->inbounds)
_mesa_string_buffer_append(d->buf, "inbounds ");
dump_type_name(d, gep->source_elem_type);
_mesa_string_buffer_append(d->buf, ", ");
for (unsigned i = 0; i < gep->num_operands; ++i) {
if (i > 0)
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, gep->operands[i]);
}
}
static void
dump_instr_load(struct dxil_dumper *d, struct dxil_instr_load *load)
{
_mesa_string_buffer_append(d->buf, "load ");
if (load->is_volatile)
_mesa_string_buffer_append(d->buf, " volatile");
dump_type_name(d, load->type);
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, load->ptr);
_mesa_string_buffer_printf(d->buf, ", %d", load->align);
}
static void
dump_instr_store(struct dxil_dumper *d, struct dxil_instr_store *store)
{
_mesa_string_buffer_append(d->buf, "store ");
if (store->is_volatile)
_mesa_string_buffer_append(d->buf, " volatile");
dump_value(d, store->value);
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, store->ptr);
_mesa_string_buffer_printf(d->buf, ", %d", store->align);
}
static const char *rmworder_str[] = {
[DXIL_ATOMIC_ORDERING_NOTATOMIC] = "not-atomic",
[DXIL_ATOMIC_ORDERING_UNORDERED] = "unordered",
[DXIL_ATOMIC_ORDERING_MONOTONIC] = "monotonic",
[DXIL_ATOMIC_ORDERING_ACQUIRE] = "acquire",
[DXIL_ATOMIC_ORDERING_RELEASE] = "release",
[DXIL_ATOMIC_ORDERING_ACQREL] = "acqrel",
[DXIL_ATOMIC_ORDERING_SEQCST] = "seqcst",
};
static const char *rmwsync_str[] = {
[DXIL_SYNC_SCOPE_SINGLETHREAD] = "single-thread",
[DXIL_SYNC_SCOPE_CROSSTHREAD] = "cross-thread",
};
static const char *rmwop_str[] = {
[DXIL_RMWOP_XCHG] = "xchg",
[DXIL_RMWOP_ADD] = "add",
[DXIL_RMWOP_SUB] = "sub",
[DXIL_RMWOP_AND] = "and",
[DXIL_RMWOP_NAND] = "nand",
[DXIL_RMWOP_OR] = "or",
[DXIL_RMWOP_XOR] = "xor",
[DXIL_RMWOP_MAX] = "max",
[DXIL_RMWOP_MIN] = "min",
[DXIL_RMWOP_UMAX] = "umax",
[DXIL_RMWOP_UMIN] = "umin",
};
static void
dump_instr_atomicrmw(struct dxil_dumper *d, struct dxil_instr_atomicrmw *rmw)
{
_mesa_string_buffer_printf(d->buf, "atomicrmw.%s ", rmwop_str[rmw->op]);
if (rmw->is_volatile)
_mesa_string_buffer_append(d->buf, " volatile");
dump_value(d, rmw->value);
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, rmw->ptr);
_mesa_string_buffer_printf(d->buf, ", ordering(%s)", rmworder_str[rmw->ordering]);
_mesa_string_buffer_printf(d->buf, ", sync_scope(%s)", rmwsync_str[rmw->syncscope]);
}
static void
dump_instr_print_operands(struct dxil_dumper *d, int num,
const struct dxil_value *val[])
{
for (int i = 0; i < num; ++i) {
if (i > 0)
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, val[i]);
}
}
static void
dump_value(struct dxil_dumper *d, const struct dxil_value *val)
{
if (val->id < 10)
_mesa_string_buffer_append(d->buf, " ");
if (val->id < 100)
_mesa_string_buffer_append(d->buf, " ");
_mesa_string_buffer_printf(d->buf, "%%%d", val->id);
dump_type_name(d, val->type);
}
static void
dump_mdnodes(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "MD-Nodes:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_mdnode, node, list, head) {
dump_mdnode(d, node);
}
dxil_dump_indention_dec(d);
}
static void
dump_mdnode(struct dxil_dumper *d, const struct dxil_mdnode *node)
{
dxil_dump_indent(d);
switch (node->type) {
case MD_STRING:
_mesa_string_buffer_printf(d->buf, "S:%s\n", node->string);
break;
case MD_VALUE:
_mesa_string_buffer_append(d->buf, "V:");
dump_type_name(d, node->value.type);
_mesa_string_buffer_append_char(d->buf, ' ');
dump_value(d, node->value.value);
_mesa_string_buffer_append_char(d->buf, '\n');
break;
case MD_NODE:
_mesa_string_buffer_append(d->buf, " \\\n");
dxil_dump_indention_inc(d);
for (size_t i = 0; i < node->node.num_subnodes; ++i) {
if (node->node.subnodes[i])
dump_mdnode(d, node->node.subnodes[i]);
else {
dxil_dump_indent(d);
_mesa_string_buffer_append(d->buf, "(nullptr)\n");
}
}
dxil_dump_indention_dec(d);
break;
}
}
static void
dump_named_nodes(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "Named Nodes:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_named_node, node, list, head) {
dxil_dump_indent(d);
_mesa_string_buffer_printf(d->buf, "%s:\n", node->name);
dxil_dump_indention_inc(d);
for (size_t i = 0; i < node->num_subnodes; ++i) {
if (node->subnodes[i])
dump_mdnode(d, node->subnodes[i]);
else {
dxil_dump_indent(d);
_mesa_string_buffer_append(d->buf, "(nullptr)\n");
}
}
dxil_dump_indention_dec(d);
}
dxil_dump_indention_dec(d);
}
static void
mask_to_string(uint32_t mask, char str[5])
{
const char *mc = "xyzw";
for (int i = 0; i < 4 && mask; ++i) {
str[i] = (mask & (1 << i)) ? mc[i] : '_';
}
str[4] = 0;
}
static void dump_io_signatures(struct _mesa_string_buffer *buf, struct dxil_module *m)
{
_mesa_string_buffer_append(buf, "\nInput signature:\n");
dump_io_signature(buf, m->num_sig_inputs, m->inputs);
_mesa_string_buffer_append(buf, "\nOutput signature:\n");
dump_io_signature(buf, m->num_sig_outputs, m->outputs);
}
static void dump_io_signature(struct _mesa_string_buffer *buf, unsigned num,
struct dxil_signature_record *io)
{
_mesa_string_buffer_append(buf, " SEMANTIC-NAME Index Mask Reg SysValue Format\n");
_mesa_string_buffer_append(buf, "----------------------------------------------\n");
for (unsigned i = 0; i < num; ++i, ++io) {
for (unsigned j = 0; j < io->num_elements; ++j) {
char mask[5] = "";
mask_to_string(io->elements[j].mask, mask);
_mesa_string_buffer_printf(buf, "%-15s %3d %4s %3d %-8s %-7s\n",
io->name, io->elements[j].semantic_index,
mask, io->elements[j].reg, io->sysvalue,
component_type_as_string(io->elements[j].comp_type));
}
}
}
static const char *component_type_as_string(uint32_t type)
{
return (type < DXIL_PROG_SIG_COMP_TYPE_COUNT) ?
dxil_type_strings[type] : "invalid";
}
static void dump_psv(struct _mesa_string_buffer *buf,
struct dxil_module *m)
{
_mesa_string_buffer_append(buf, "\nPipeline State Validation\nInputs:\n");
dump_psv_io(buf, m, m->num_sig_inputs, m->psv_inputs);
_mesa_string_buffer_append(buf, "\nOutputs:\n");
dump_psv_io(buf, m, m->num_sig_outputs, m->psv_outputs);
}
static void dump_psv_io(struct _mesa_string_buffer *buf, struct dxil_module *m,
unsigned num, struct dxil_psv_signature_element *io)
{
_mesa_string_buffer_append(buf, " SEMANTIC-NAME Rows Cols Kind Comp-Type Interp dynmask+stream Indices\n");
_mesa_string_buffer_append(buf, "----------------------------------------------\n");
for (unsigned i = 0; i < num; ++i, ++io) {
_mesa_string_buffer_printf(buf, "%-14s %d+%d %d+%d %4d %-7s %-4d %-9d [",
m->sem_string_table->buf + io->semantic_name_offset,
(int)io->start_row, (int)io->rows,
(int)((io->cols_and_start & 0xf) >> 4),
(int)(io->cols_and_start & 0xf),
(int)io->semantic_kind,
component_type_as_string(io->component_type),
(int)io->interpolation_mode,
(int)io->dynamic_mask_and_stream);
for (int k = 0; k < io->rows; ++k) {
if (k > 0)
_mesa_string_buffer_append(buf, ", ");
_mesa_string_buffer_printf(buf,"%d ", m->sem_index_table.data[io->start_row + k]);
}
_mesa_string_buffer_append(buf, "]\n");
}
}
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_DUMP_H
#define DXIL_DUMP_H
#include <stdio.h>
struct dxil_module;
struct _mesa_string_buffer;
#ifdef __cplusplus
extern "C" {
#endif
struct dxil_dumper;
struct dxil_dumper *dxil_dump_create(void);
void dxil_dump_free(struct dxil_dumper *d);
void dxil_dump_buf_to_file(struct dxil_dumper *d, FILE *f);
void
dxil_dump_module(struct dxil_dumper *d, struct dxil_module *m);
#ifdef __cplusplus
}
#endif
#endif // DXIL_DUMP_H
+179
View File
@@ -0,0 +1,179 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DIXL_DUMP_DECL
#error This header can only be included from dxil_dump.c
#endif
#include "dxil_module.h"
static void
dump_metadata(struct dxil_dumper *buf, struct dxil_module *m);
static void
dump_shader_info(struct dxil_dumper *buf, struct dxil_shader_info *info);
static const char *
dump_shader_string(enum dxil_shader_kind kind);
static void
dump_features(struct _mesa_string_buffer *buf, struct dxil_features *feat);
static void
dump_types(struct dxil_dumper *buf, struct list_head *list);
static void
dump_gvars(struct dxil_dumper *buf, struct list_head *list);
static void
dump_constants(struct dxil_dumper *buf, struct list_head *list);
static void
dump_funcs(struct dxil_dumper *buf, struct list_head *list);
static void
dump_attr_set_list(struct dxil_dumper *buf, struct list_head *list);
static void
dump_instrs(struct dxil_dumper *buf, struct list_head *list);
static void
dump_mdnodes(struct dxil_dumper *buf, struct list_head *list);
static void
dump_mdnode(struct dxil_dumper *d, const struct dxil_mdnode *node);
static void
dump_named_nodes(struct dxil_dumper *d, struct list_head *list);
static void
dump_type(struct dxil_dumper *buf, const struct dxil_type *type);
static void
dump_instr_binop(struct dxil_dumper *d, struct dxil_instr_binop *binop);
static void
dump_instr_cmp(struct dxil_dumper *d, struct dxil_instr_cmp *cmp);
static void
dump_instr_select(struct dxil_dumper *d, struct dxil_instr_select *select);
static void
dump_instr_cast(struct dxil_dumper *d, struct dxil_instr_cast *cast);
static void
dump_instr_call(struct dxil_dumper *d, struct dxil_instr_call *call);
static void
dump_instr_ret(struct dxil_dumper *d, struct dxil_instr_ret *ret);
static void
dump_instr_extractval(struct dxil_dumper *d, struct dxil_instr_extractval *ret);
static void
dump_instr_branch(struct dxil_dumper *d, struct dxil_instr_br *br);
static void
dump_instr_phi(struct dxil_dumper *d, struct dxil_instr_phi *phi);
static void
dump_instr_alloca(struct dxil_dumper *d, struct dxil_instr_alloca *alloca);
static void
dump_instr_gep(struct dxil_dumper *d, struct dxil_instr_gep *gep);
static void
dump_instr_load(struct dxil_dumper *d, struct dxil_instr_load *store);
static void
dump_instr_store(struct dxil_dumper *d, struct dxil_instr_store *store);
static void
dump_instr_atomicrmw(struct dxil_dumper *d, struct dxil_instr_atomicrmw *rmw);
static void
dump_instr_print_operands(struct dxil_dumper *d, int num,
const struct dxil_value *val[]);
static void dump_io_signatures(struct _mesa_string_buffer *buf,
struct dxil_module *m);
static void
dump_io_signature(struct _mesa_string_buffer *buf, unsigned num,
struct dxil_signature_record *io);
static const char *component_type_as_string(uint32_t type);
static void dump_psv(struct _mesa_string_buffer *buf,
struct dxil_module *m);
static void dump_psv_io(struct _mesa_string_buffer *buf, struct dxil_module *m,
unsigned num, struct dxil_psv_signature_element *io);
static void
dump_value(struct dxil_dumper *d, const struct dxil_value *val);
static const char *binop_strings[DXIL_BINOP_INSTR_COUNT] = {
[DXIL_BINOP_ADD] = "add",
[DXIL_BINOP_SUB] = "sub",
[DXIL_BINOP_MUL] = "mul",
[DXIL_BINOP_UDIV] = "udiv",
[DXIL_BINOP_SDIV] = "sdiv",
[DXIL_BINOP_UREM] = "urem",
[DXIL_BINOP_SREM] = "srem",
[DXIL_BINOP_SHL] = "shl",
[DXIL_BINOP_LSHR] = "lshr",
[DXIL_BINOP_ASHR] = "ashr",
[DXIL_BINOP_AND] = "and",
[DXIL_BINOP_OR] = "or",
[DXIL_BINOP_XOR]= "xor"
};
static const char *pred_strings[DXIL_CMP_INSTR_COUNT] = {
[DXIL_FCMP_FALSE] = "FALSE",
[DXIL_FCMP_OEQ] = "ord-fEQ",
[DXIL_FCMP_OGT] = "ord-fGT",
[DXIL_FCMP_OGE] = "ord-fGE",
[DXIL_FCMP_OLT] = "ord-fLT",
[DXIL_FCMP_OLE] = "ord-fLE",
[DXIL_FCMP_ONE] = "ord-fNE",
[DXIL_FCMP_ORD] = "ord-fRD",
[DXIL_FCMP_UNO] = "unord-fNO",
[DXIL_FCMP_UEQ] = "unord-fEQ",
[DXIL_FCMP_UGT] = "unord-fGT",
[DXIL_FCMP_UGE] = "unord-fGE",
[DXIL_FCMP_ULT] = "unord-fLT",
[DXIL_FCMP_ULE] = "unord-fLE",
[DXIL_FCMP_UNE] = "unord-fNE",
[DXIL_FCMP_TRUE] = "TRUE",
[DXIL_ICMP_EQ] = "iEQ",
[DXIL_ICMP_NE] = "iNE",
[DXIL_ICMP_UGT] = "uiGT",
[DXIL_ICMP_UGE] = "uiGE",
[DXIL_ICMP_ULT] = "uiLT",
[DXIL_ICMP_ULE] = "uiLE",
[DXIL_ICMP_SGT] = "iGT",
[DXIL_ICMP_SGE] = "iGE",
[DXIL_ICMP_SLT] = "iLT",
[DXIL_ICMP_SLE] = "iLE"
};
static const char *cast_opcode_strings[DXIL_CAST_INSTR_COUNT] = {
[DXIL_CAST_TRUNC] = "trunc",
[DXIL_CAST_ZEXT] = "zext",
[DXIL_CAST_SEXT] = "sext",
[DXIL_CAST_FPTOUI] = "ftoui",
[DXIL_CAST_FPTOSI] = "ftoi",
[DXIL_CAST_UITOFP] = "uitof",
[DXIL_CAST_SITOFP] = "itof",
[DXIL_CAST_FPTRUNC] = "ftrunc",
[DXIL_CAST_FPEXT] = "fext",
[DXIL_CAST_PTRTOINT] = "ptrtoint",
[DXIL_CAST_INTTOPTR] = "inttoptr",
[DXIL_CAST_BITCAST] = "bitcast",
[DXIL_CAST_ADDRSPACECAST] = "addrspacecast",
};
static const char *dxil_type_strings[DXIL_PROG_SIG_COMP_TYPE_COUNT] = {
[DXIL_PROG_SIG_COMP_TYPE_UNKNOWN] = "unknown",
[DXIL_PROG_SIG_COMP_TYPE_UINT32] = "uint32",
[DXIL_PROG_SIG_COMP_TYPE_SINT32] = "int32",
[DXIL_PROG_SIG_COMP_TYPE_FLOAT32] = "float32",
[DXIL_PROG_SIG_COMP_TYPE_UINT16] = "uint16",
[DXIL_PROG_SIG_COMP_TYPE_SINT16] = "int16",
[DXIL_PROG_SIG_COMP_TYPE_FLOAT16] = "float16",
[DXIL_PROG_SIG_COMP_TYPE_UINT64] = "uint64",
[DXIL_PROG_SIG_COMP_TYPE_SINT64] = "int64",
[DXIL_PROG_SIG_COMP_TYPE_FLOAT64] = "float64"
};
+193
View File
@@ -0,0 +1,193 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_enums.h"
#include "glsl_types.h"
#include "nir.h"
#include "util/u_debug.h"
enum dxil_prog_sig_comp_type dxil_get_prog_sig_comp_type(const struct glsl_type *type)
{
type = glsl_without_array(type);
switch (glsl_get_base_type(type)) {
case GLSL_TYPE_UINT: return DXIL_PROG_SIG_COMP_TYPE_UINT32;
case GLSL_TYPE_INT: return DXIL_PROG_SIG_COMP_TYPE_SINT32;
case GLSL_TYPE_FLOAT: return DXIL_PROG_SIG_COMP_TYPE_FLOAT32;
case GLSL_TYPE_FLOAT16: return DXIL_PROG_SIG_COMP_TYPE_FLOAT16;
case GLSL_TYPE_DOUBLE: return DXIL_PROG_SIG_COMP_TYPE_UINT32;
case GLSL_TYPE_UINT16: return DXIL_PROG_SIG_COMP_TYPE_UINT16;
case GLSL_TYPE_INT16: return DXIL_PROG_SIG_COMP_TYPE_SINT16;
case GLSL_TYPE_UINT64: return DXIL_PROG_SIG_COMP_TYPE_UINT32;
case GLSL_TYPE_INT64: return DXIL_PROG_SIG_COMP_TYPE_SINT32;
case GLSL_TYPE_BOOL: return DXIL_PROG_SIG_COMP_TYPE_UINT32;
/* For structs, just emit them as float registers. This way, they can be
* interpolated or not, and it doesn't matter, and it avoids linking issues
* that we'd see if the type here tried to depend on (e.g.) interp mode. */
case GLSL_TYPE_STRUCT: return DXIL_PROG_SIG_COMP_TYPE_FLOAT32;
default:
debug_printf("unexpected type: %s\n", glsl_get_type_name(type));
return DXIL_PROG_SIG_COMP_TYPE_UNKNOWN;
}
}
enum dxil_component_type dxil_get_comp_type_from_prog_sig_type(enum dxil_prog_sig_comp_type type)
{
switch (type) {
case DXIL_PROG_SIG_COMP_TYPE_UINT32: return DXIL_COMP_TYPE_U32;
case DXIL_PROG_SIG_COMP_TYPE_SINT32: return DXIL_COMP_TYPE_I32;
case DXIL_PROG_SIG_COMP_TYPE_FLOAT32: return DXIL_COMP_TYPE_F32;
case DXIL_PROG_SIG_COMP_TYPE_UINT16: return DXIL_COMP_TYPE_U16;
case DXIL_PROG_SIG_COMP_TYPE_SINT16: return DXIL_COMP_TYPE_I16;
case DXIL_PROG_SIG_COMP_TYPE_FLOAT16: return DXIL_COMP_TYPE_F16;
default:
debug_printf("unexpected signature type\n");
UNREACHABLE("unexpected signature type");
}
}
enum dxil_component_type dxil_get_comp_type(const struct glsl_type *type)
{
type = glsl_without_array(type);
enum glsl_base_type base_type = glsl_get_base_type(type);
if (glsl_type_is_texture(type) || glsl_type_is_image(type))
base_type = glsl_get_sampler_result_type(type);
switch (base_type) {
case GLSL_TYPE_UINT: return DXIL_COMP_TYPE_U32;
case GLSL_TYPE_INT: return DXIL_COMP_TYPE_I32;
case GLSL_TYPE_FLOAT: return DXIL_COMP_TYPE_F32;
case GLSL_TYPE_FLOAT16: return DXIL_COMP_TYPE_F16;
case GLSL_TYPE_DOUBLE: return DXIL_COMP_TYPE_F64;
case GLSL_TYPE_UINT16: return DXIL_COMP_TYPE_U16;
case GLSL_TYPE_INT16: return DXIL_COMP_TYPE_I16;
case GLSL_TYPE_UINT64: return DXIL_COMP_TYPE_U64;
case GLSL_TYPE_INT64: return DXIL_COMP_TYPE_I64;
case GLSL_TYPE_BOOL: return DXIL_COMP_TYPE_I1;
default:
debug_printf("type: %s\n", glsl_get_type_name(type));
UNREACHABLE("unexpected glsl type");
}
}
enum dxil_resource_kind dxil_sampler_dim_to_resource_kind(enum glsl_sampler_dim dim, bool is_array)
{
switch (dim) {
case GLSL_SAMPLER_DIM_1D:
return is_array ? DXIL_RESOURCE_KIND_TEXTURE1D_ARRAY
: DXIL_RESOURCE_KIND_TEXTURE1D;
case GLSL_SAMPLER_DIM_2D:
case GLSL_SAMPLER_DIM_EXTERNAL:
return is_array ? DXIL_RESOURCE_KIND_TEXTURE2D_ARRAY
: DXIL_RESOURCE_KIND_TEXTURE2D;
case GLSL_SAMPLER_DIM_SUBPASS:
return DXIL_RESOURCE_KIND_TEXTURE2D_ARRAY;
case GLSL_SAMPLER_DIM_3D:
return DXIL_RESOURCE_KIND_TEXTURE3D;
case GLSL_SAMPLER_DIM_CUBE:
return is_array ? DXIL_RESOURCE_KIND_TEXTURECUBE_ARRAY
: DXIL_RESOURCE_KIND_TEXTURECUBE;
case GLSL_SAMPLER_DIM_RECT:
return DXIL_RESOURCE_KIND_TEXTURE2D;
case GLSL_SAMPLER_DIM_BUF:
return DXIL_RESOURCE_KIND_TYPED_BUFFER;
case GLSL_SAMPLER_DIM_MS:
return is_array ? DXIL_RESOURCE_KIND_TEXTURE2DMS_ARRAY
: DXIL_RESOURCE_KIND_TEXTURE2DMS;
case GLSL_SAMPLER_DIM_SUBPASS_MS:
return DXIL_RESOURCE_KIND_TEXTURE2DMS_ARRAY;
default:
UNREACHABLE("unexpected sampler type");
}
}
enum dxil_resource_kind dxil_get_resource_kind(const struct glsl_type *type)
{
type = glsl_without_array(type);
/* This looks weird, we strip the arrays but then we still test whether it's
* an array, key is the first refers to sampler[] and the second to samplerArray */
bool is_array = glsl_sampler_type_is_array(type);
if (glsl_type_is_texture(type) || glsl_type_is_image(type))
return dxil_sampler_dim_to_resource_kind(glsl_get_sampler_dim(type), is_array);
debug_printf("type: %s\n", glsl_get_type_name(type));
UNREACHABLE("unexpected glsl type");
}
enum dxil_input_primitive dxil_get_input_primitive(enum mesa_prim primitive)
{
switch (primitive) {
case MESA_PRIM_POINTS:
return DXIL_INPUT_PRIMITIVE_POINT;
case MESA_PRIM_LINES:
return DXIL_INPUT_PRIMITIVE_LINE;
case MESA_PRIM_LINES_ADJACENCY:
return DXIL_INPUT_PRIMITIVE_LINES_ADJENCY;
case MESA_PRIM_TRIANGLES:
return DXIL_INPUT_PRIMITIVE_TRIANGLE;
case MESA_PRIM_TRIANGLES_ADJACENCY:
return DXIL_INPUT_PRIMITIVE_TRIANGLES_ADJENCY;
default:
UNREACHABLE("unhandled primitive topology");
}
}
enum dxil_primitive_topology dxil_get_primitive_topology(enum mesa_prim topology)
{
switch (topology) {
case MESA_PRIM_POINTS:
return DXIL_PRIMITIVE_TOPOLOGY_POINT_LIST;
case MESA_PRIM_LINES:
return DXIL_PRIMITIVE_TOPOLOGY_LINE_LIST;
case MESA_PRIM_LINE_STRIP:
return DXIL_PRIMITIVE_TOPOLOGY_LINE_STRIP;
case MESA_PRIM_TRIANGLE_STRIP:
return DXIL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
default:
UNREACHABLE("unhandled primitive topology");
}
}
static const char *overload_str[DXIL_NUM_OVERLOADS] = {
[DXIL_NONE] = "",
[DXIL_I1] = "i1",
[DXIL_I16] = "i16",
[DXIL_I32] = "i32",
[DXIL_I64] = "i64",
[DXIL_F16] = "f16",
[DXIL_F32] = "f32",
[DXIL_F64] = "f64",
};
const char *dxil_overload_suffix( enum overload_type overload)
{
assert(overload < DXIL_NUM_OVERLOADS);
return overload_str[overload];
}
+401
View File
@@ -0,0 +1,401 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DIXL_ENUMS_H
#define DIXL_ENUMS_H
#include <stdbool.h>
#include "shader_enums.h"
enum dxil_signature_kind {
DXIL_SIG_INVALID = 0,
DXIL_SIG_INPUT,
DXIL_SIG_OUTPUT,
DXIL_SIG_PATCH_CONST_OR_PRIM
};
/* These enums are taken from
* DirectXShaderCompiler/lib/dxc/DXIL/DxilConstants.h
*/
enum dxil_semantic_kind {
DXIL_SEM_ARBITRARY,
DXIL_SEM_VERTEX_ID,
DXIL_SEM_INSTANCE_ID,
DXIL_SEM_POSITION,
DXIL_SEM_RENDERTARGET_ARRAY_INDEX,
DXIL_SEM_VIEWPORT_ARRAY_INDEX,
DXIL_SEM_CLIP_DISTANCE,
DXIL_SEM_CULL_DISTANCE,
DXIL_SEM_OUTPUT_CONTROL_POINT_ID,
DXIL_SEM_DOMAIN_LOCATION,
DXIL_SEM_PRIMITIVE_ID,
DXIL_SEM_GS_INSTANCE_ID,
DXIL_SEM_SAMPLE_INDEX,
DXIL_SEM_IS_FRONT_FACE,
DXIL_SEM_COVERAGE,
DXIL_SEM_INNER_COVERAGE,
DXIL_SEM_TARGET,
DXIL_SEM_DEPTH,
DXIL_SEM_DEPTH_LE,
DXIL_SEM_DEPTH_GE,
DXIL_SEM_STENCIL_REF,
DXIL_SEM_DISPATCH_THREAD_ID,
DXIL_SEM_GROUP_ID,
DXIL_SEM_GROUP_INDEX,
DXIL_SEM_GROUP_THREAD_ID,
DXIL_SEM_TESS_FACTOR,
DXIL_SEM_INSIDE_TESS_FACTOR,
DXIL_SEM_VIEW_ID,
DXIL_SEM_BARYCENTRICS,
DXIL_SEM_SHADING_RATE,
DXIL_SEM_CULL_PRIMITIVE,
DXIL_SEM_INVALID
};
enum dxil_prog_sig_semantic {
DXIL_PROG_SEM_UNDEFINED = 0,
DXIL_PROG_SEM_POSITION = 1,
DXIL_PROG_SEM_CLIP_DISTANCE = 2,
DXIL_PROG_SEM_CULL_DISTANCE = 3,
DXIL_PROG_SEM_RENDERTARGET_ARRAY_INDEX = 4,
DXIL_PROG_SEM_VIEWPORT_ARRAY_INDEX = 5,
DXIL_PROG_SEM_VERTEX_ID = 6,
DXIL_PROG_SEM_PRIMITIVE_ID = 7,
DXIL_PROG_SEM_INSTANCE_ID = 8,
DXIL_PROG_SEM_IS_FRONTFACE = 9,
DXIL_PROG_SEM_SAMPLE_INDEX = 10,
DXIL_PROG_SEM_FINAL_QUAD_EDGE_TESSFACTOR = 11,
DXIL_PROG_SEM_FINAL_QUAD_INSIDE_EDGE_TESSFACTOR = 12,
DXIL_PROG_SEM_FINAL_TRI_EDGE_TESSFACTOR = 13,
DXIL_PROG_SEM_FINAL_TRI_INSIDE_EDGE_TESSFACTOR = 14,
DXIL_PROG_SEM_FINAL_LINE_DETAIL_TESSFACTOR = 15,
DXIL_PROG_SEM_FINAL_LINE_DENSITY_TESSFACTOR = 16,
DXIL_PROG_SEM_BARYCENTRICS = 23,
DXIL_PROG_SEM_SHADING_RATE = 24,
DXIL_PROG_SEM_CULL_PRIMITIVE = 25,
DXIL_PROG_SEM_TARGET = 64,
DXIL_PROG_SEM_DEPTH = 65,
DXIL_PROG_SEM_COVERAGE = 66,
DXIL_PROG_SEM_DEPTH_GE = 67,
DXIL_PROG_SEM_DEPTH_LE = 68,
DXIL_PROG_SEM_STENCIL_REF = 69,
DXIL_PROG_SEM_INNER_COVERAGE = 70
};
enum dxil_prog_sig_comp_type {
DXIL_PROG_SIG_COMP_TYPE_UNKNOWN = 0,
DXIL_PROG_SIG_COMP_TYPE_UINT32 = 1,
DXIL_PROG_SIG_COMP_TYPE_SINT32 = 2,
DXIL_PROG_SIG_COMP_TYPE_FLOAT32 = 3,
DXIL_PROG_SIG_COMP_TYPE_UINT16 = 4,
DXIL_PROG_SIG_COMP_TYPE_SINT16 = 5,
DXIL_PROG_SIG_COMP_TYPE_FLOAT16 = 6,
DXIL_PROG_SIG_COMP_TYPE_UINT64 = 7,
DXIL_PROG_SIG_COMP_TYPE_SINT64 = 8,
DXIL_PROG_SIG_COMP_TYPE_FLOAT64 = 9,
DXIL_PROG_SIG_COMP_TYPE_COUNT
};
enum dxil_sig_point_kind {
DXIL_SIG_POINT_VSIN, // Ordinary Vertex Shader input from Input Assembler
DXIL_SIG_POINT_VSOUT, // Ordinary Vertex Shader output that may feed Rasterizer
DXIL_SIG_POINT_PCIN, // Patch Constant function non-patch inputs
DXIL_SIG_POINT_HSIN, // Hull Shader function non-patch inputs
DXIL_SIG_POINT_HSCPIN, // Hull Shader patch inputs - Control Points
DXIL_SIG_POINT_HSCPOut, // Hull Shader function output - Control Point
DXIL_SIG_POINT_PCOUT, // Patch Constant function output - Patch Constant data passed to Domain Shader
DXIL_SIG_POINT_DSIN, // Domain Shader regular input - Patch Constant data plus system values
DXIL_SIG_POINT_DSCPIN, // Domain Shader patch input - Control Points
DXIL_SIG_POINT_DSOUT, // Domain Shader output - vertex data that may feed Rasterizer
DXIL_SIG_POINT_GSVIN, // Geometry Shader vertex input - qualified with primitive type
DXIL_SIG_POINT_GSIN, // Geometry Shader non-vertex inputs (system values)
DXIL_SIG_POINT_GSOUT, // Geometry Shader output - vertex data that may feed Rasterizer
DXIL_SIG_POINT_PSIN, // Pixel Shader input
DXIL_SIG_POINT_PSOUT, // Pixel Shader output
DXIL_SIG_POINT_CSIN, // Compute Shader input
DXIL_SIG_POINT_MSIN, // Mesh Shader input
DXIL_SIG_POINT_MSOUT, // Mesh Shader vertices output
DXIL_SIG_POINT_MSPOUT, // Mesh Shader primitives output
DXIL_SIG_POINT_ASIN, // Amplification Shader input
DXIL_SIG_POINT_INVALID
};
enum dxil_min_precision {
DXIL_MIN_PREC_DEFAULT = 0,
DXIL_MIN_PREC_FLOAT16 = 1,
DXIL_MIN_PREC_FLOAT2_8 = 2,
DXIL_MIN_PREC_RESERVED = 3,
DXIL_MIN_PREC_SINT16 = 4,
DXIL_MIN_PREC_UINT16 = 5,
DXIL_MIN_PREC_ANY16 = 0xf0,
DXIL_MIN_PREC_ANY10 = 0xf1
};
enum dxil_semantic_interpret_kind {
DXIL_SEM_INTERP_NA, // Not Available
DXIL_SEM_INTERP_SV, // Normal System Value
DXIL_SEM_INTERP_SGV, // System Generated Value (sorted last)
DXIL_SEM_INTERP_ARB, // Treated as Arbitrary
DXIL_SEM_INTERP_NOT_IN_SIG, // Not included in signature (intrinsic access)
DXIL_SEM_INTERP_NOT_PACKED, // Included in signature, but does not contribute to packing
DXIL_SEM_INTERP_TARGET, // Special handling for SV_Target
DXIL_SEM_INTERP_TESSFACTOR, // Special handling for tessellation factors
DXIL_SEM_INTERP_SHADOW, // Shadow element must be added to a signature for compatibility
DXIL_SEM_INTERP_CLIPCULL, // Special packing rules for SV_ClipDistance or SV_CullDistance
DXIL_SEM_INTERP_INVALID
};
enum dxil_component_type {
DXIL_COMP_TYPE_INVALID = 0,
DXIL_COMP_TYPE_I1 = 1,
DXIL_COMP_TYPE_I16 = 2,
DXIL_COMP_TYPE_U16 = 3,
DXIL_COMP_TYPE_I32 = 4,
DXIL_COMP_TYPE_U32 = 5,
DXIL_COMP_TYPE_I64 = 6,
DXIL_COMP_TYPE_U64 = 7,
DXIL_COMP_TYPE_F16 = 8,
DXIL_COMP_TYPE_F32 = 9,
DXIL_COMP_TYPE_F64 = 10,
DXIL_COMP_TYPE_SNORMF16 = 11,
DXIL_COMP_TYPE_UNORMF16 = 12,
DXIL_COMP_TYPE_SNORMF32 = 13,
DXIL_COMP_TYPE_UNORMF32 = 14,
DXIL_COMP_TYPE_SNORMF64 = 15,
DXIL_COMP_TYPE_UNORMF64 = 16
};
enum dxil_interpolation_mode {
DXIL_INTERP_UNDEFINED = 0,
DXIL_INTERP_CONSTANT = 1,
DXIL_INTERP_LINEAR = 2,
DXIL_INTERP_LINEAR_CENTROID = 3,
DXIL_INTERP_LINEAR_NOPERSPECTIVE = 4,
DXIL_INTERP_LINEAR_NOPERSPECTIVE_CENTROID = 5,
DXIL_INTERP_LINEAR_SAMPLE = 6,
DXIL_INTERP_LINEAR_NOPERSPECTIVE_SAMPLE = 7,
DXIL_INTERP_INVALID = 8
};
enum overload_type {
DXIL_NONE,
DXIL_I1,
DXIL_I16,
DXIL_I32,
DXIL_I64,
DXIL_F16,
DXIL_F32,
DXIL_F64,
DXIL_NUM_OVERLOADS
};
enum dxil_resource_class {
DXIL_RESOURCE_CLASS_SRV = 0,
DXIL_RESOURCE_CLASS_UAV = 1,
DXIL_RESOURCE_CLASS_CBV = 2,
DXIL_RESOURCE_CLASS_SAMPLER = 3
};
enum dxil_resource_kind {
DXIL_RESOURCE_KIND_INVALID = 0,
DXIL_RESOURCE_KIND_TEXTURE1D = 1,
DXIL_RESOURCE_KIND_TEXTURE2D = 2,
DXIL_RESOURCE_KIND_TEXTURE2DMS = 3,
DXIL_RESOURCE_KIND_TEXTURE3D = 4,
DXIL_RESOURCE_KIND_TEXTURECUBE = 5,
DXIL_RESOURCE_KIND_TEXTURE1D_ARRAY = 6,
DXIL_RESOURCE_KIND_TEXTURE2D_ARRAY = 7,
DXIL_RESOURCE_KIND_TEXTURE2DMS_ARRAY = 8,
DXIL_RESOURCE_KIND_TEXTURECUBE_ARRAY = 9,
DXIL_RESOURCE_KIND_TYPED_BUFFER = 10,
DXIL_RESOURCE_KIND_RAW_BUFFER = 11,
DXIL_RESOURCE_KIND_STRUCTURED_BUFFER = 12,
DXIL_RESOURCE_KIND_CBUFFER = 13,
DXIL_RESOURCE_KIND_SAMPLER = 14,
DXIL_RESOURCE_KIND_TBUFFER = 15,
};
enum dxil_sampler_kind {
DXIL_SAMPLER_KIND_DEFAULT = 0,
DXIL_SAMPLER_KIND_COMPARISON = 1,
DXIL_SAMPLER_KIND_MONO = 2,
DXIL_SAMPLER_KIND_INVALID = 3,
};
enum dxil_attr_kind {
DXIL_ATTR_KIND_NONE = 0,
DXIL_ATTR_KIND_NO_DUPLICATE = 12,
DXIL_ATTR_KIND_NO_UNWIND = 18,
DXIL_ATTR_KIND_READ_NONE = 20,
DXIL_ATTR_KIND_READ_ONLY = 21,
};
enum dxil_input_primitive {
DXIL_INPUT_PRIMITIVE_UNDEFINED = 0,
DXIL_INPUT_PRIMITIVE_POINT = 1,
DXIL_INPUT_PRIMITIVE_LINE = 2,
DXIL_INPUT_PRIMITIVE_TRIANGLE = 3,
DXIL_INPUT_PRIMITIVE_LINES_ADJENCY = 6,
DXIL_INPUT_PRIMITIVE_TRIANGLES_ADJENCY = 7,
};
enum dxil_primitive_topology {
DXIL_PRIMITIVE_TOPOLOGY_UNDEFINED = 0,
DXIL_PRIMITIVE_TOPOLOGY_POINT_LIST = 1,
DXIL_PRIMITIVE_TOPOLOGY_LINE_LIST = 2,
DXIL_PRIMITIVE_TOPOLOGY_LINE_STRIP = 3,
DXIL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 4,
DXIL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 5,
};
enum dxil_shader_tag {
DXIL_SHADER_TAG_FLAGS = 0,
DXIL_SHADER_TAG_GS_STATE = 1,
DXIL_SHADER_TAG_DS_STATE = 2,
DXIL_SHADER_TAG_HS_STATE = 3,
DXIL_SHADER_TAG_NUM_THREADS = 4,
DXIL_SHADER_TAG_WAVE_SIZE = 11,
DXIL_SHADER_TAG_WAVE_SIZE_RANGE = 23,
};
enum dxil_barrier_mode {
DXIL_BARRIER_MODE_SYNC_THREAD_GROUP = 1,
DXIL_BARRIER_MODE_UAV_FENCE_GLOBAL = 2,
DXIL_BARRIER_MODE_UAV_FENCE_THREAD_GROUP = 4,
DXIL_BARRIER_MODE_GROUPSHARED_MEM_FENCE = 8,
};
enum dxil_address_space {
DXIL_AS_DEFAULT = 0,
DXIL_AS_DEVMEM = 1,
DXIL_AS_CBUF = 2,
DXIL_AS_GROUPSHARED = 3,
};
enum dxil_rmw_op {
DXIL_RMWOP_XCHG = 0,
DXIL_RMWOP_ADD = 1,
DXIL_RMWOP_SUB = 2,
DXIL_RMWOP_AND = 3,
DXIL_RMWOP_NAND = 4,
DXIL_RMWOP_OR = 5,
DXIL_RMWOP_XOR = 6,
DXIL_RMWOP_MAX = 7,
DXIL_RMWOP_MIN = 8,
DXIL_RMWOP_UMAX = 9,
DXIL_RMWOP_UMIN = 10,
};
enum dxil_atomic_ordering {
DXIL_ATOMIC_ORDERING_NOTATOMIC = 0,
DXIL_ATOMIC_ORDERING_UNORDERED = 1,
DXIL_ATOMIC_ORDERING_MONOTONIC = 2,
DXIL_ATOMIC_ORDERING_ACQUIRE = 3,
DXIL_ATOMIC_ORDERING_RELEASE = 4,
DXIL_ATOMIC_ORDERING_ACQREL = 5,
DXIL_ATOMIC_ORDERING_SEQCST = 6,
};
enum dxil_sync_scope {
DXIL_SYNC_SCOPE_SINGLETHREAD = 0,
DXIL_SYNC_SCOPE_CROSSTHREAD = 1,
};
enum dxil_tessellator_domain {
DXIL_TESSELLATOR_DOMAIN_UNDEFINED = 0,
DXIL_TESSELLATOR_DOMAIN_ISOLINE = 1,
DXIL_TESSELLATOR_DOMAIN_TRI = 2,
DXIL_TESSELLATOR_DOMAIN_QUAD = 3,
};
enum dxil_tessellator_output_primitive {
DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_UNDEFINED = 0,
DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_POINT = 1,
DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_LINE = 2,
DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_TRIANGLE_CW = 3,
DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_TRIANGLE_CCW = 4,
};
enum dxil_tessellator_partitioning {
DXIL_TESSELLATOR_PARTITIONING_UNDEFINED = 0,
DXIL_TESSELLATOR_PARTITIONING_INTEGER = 1,
DXIL_TESSELLATOR_PARTITIONING_POW2 = 2,
DXIL_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD = 3,
DXIL_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN = 4,
};
enum dxil_signature_element_extended_properties {
DXIL_SIGNATURE_ELEMENT_OUTPUT_STREAM = 0,
DXIL_SIGNATURE_ELEMENT_GLOBAL_SYMBOL = 1,
DXIL_SIGNATURE_ELEMENT_DYNAMIC_INDEX_COMPONENT_MASK = 2,
DXIL_SIGNATURE_ELEMENT_USAGE_COMPONENT_MASK = 3,
};
enum dxil_quad_op_kind {
QUAD_READ_ACROSS_X = 0,
QUAD_READ_ACROSS_Y = 1,
QUAD_READ_ACROSS_DIAGONAL = 2,
};
enum dxil_wave_op_kind {
DXIL_WAVE_OP_SUM = 0,
DXIL_WAVE_OP_PRODUCT = 1,
DXIL_WAVE_OP_MIN = 2,
DXIL_WAVE_OP_MAX = 3,
};
enum dxil_wave_bit_op_kind {
DXIL_WAVE_BIT_OP_AND = 0,
DXIL_WAVE_BIT_OP_OR = 1,
DXIL_WAVE_BIT_OP_XOR = 2,
};
#ifdef __cplusplus
extern "C" {
#endif
struct glsl_type;
enum glsl_sampler_dim;
enum dxil_component_type dxil_get_comp_type(const struct glsl_type *type);
enum dxil_prog_sig_comp_type dxil_get_prog_sig_comp_type(const struct glsl_type *type);
enum dxil_component_type dxil_get_comp_type_from_prog_sig_type(enum dxil_prog_sig_comp_type type);
enum dxil_resource_kind dxil_sampler_dim_to_resource_kind(enum glsl_sampler_dim dim, bool is_array);
enum dxil_resource_kind dxil_get_resource_kind(const struct glsl_type *type);
enum dxil_primitive_topology dxil_get_primitive_topology(enum mesa_prim topology);
enum dxil_input_primitive dxil_get_input_primitive(enum mesa_prim primitive);
const char *dxil_overload_suffix( enum overload_type overload);
#ifdef __cplusplus
}
#endif
#endif // DXIL_ENUMS_H
+287
View File
@@ -0,0 +1,287 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_function.h"
#include "dxil_module.h"
#define MAX_FUNC_PARAMS 18
struct predefined_func_descr {
const char *base_name;
const char *retval_descr;
const char *param_descr;
enum dxil_attr_kind attr;
};
static struct predefined_func_descr predefined_funcs[] = {
{"dx.op.atomicBinOp", "O", "i@iiiii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.cbufferLoad", "O", "i@ii", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.cbufferLoadLegacy", "B", "i@i", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.createHandle", "@", "iciib", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.storeOutput", "v", "iiicO", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.loadInput", "O", "iiici", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.tertiary", "O", "iOOO", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.quaternary", "O", "iOOOO", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.threadId", "i", "ii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.threadIdInGroup", "i", "ii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.flattenedThreadIdInGroup", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.groupId", "i", "ii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.unary", "O", "iO", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.unaryBits", "i", "iO", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.isSpecialFloat", "b", "iO", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.binary", "O", "iOO", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.bufferStore", "v", "i@iiOOOOc", DXIL_ATTR_KIND_NONE},
{"dx.op.rawBufferStore", "v", "i@iiOOOOci", DXIL_ATTR_KIND_NONE},
{"dx.op.bufferLoad", "R", "i@ii", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.rawBufferLoad", "R", "i@iici", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.attributeAtVertex", "O", "iiicc", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.sample", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleBias", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleLevel", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleGrad", "R", "i@@ffffiiifffffff", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleCmp", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleCmpLevel", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleCmpLevelZero", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleCmpBias", "R", "i@@ffffiiifff", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleCmpGrad", "R", "i@@ffffiiiffffffff", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.textureLoad", "R", "i@iiiiiii", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.textureGather", "R", "i@@ffffiii", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.textureGatherCmp", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.discard", "v", "ib", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.sampleIndex", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.emitStream", "v", "ic", DXIL_ATTR_KIND_NONE},
{"dx.op.cutStream", "v", "ic", DXIL_ATTR_KIND_NONE},
{"dx.op.getDimensions", "D", "i@i", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.calculateLOD", "f", "i@@fffb", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.barrier", "v", "ii", DXIL_ATTR_KIND_NO_DUPLICATE},
{"dx.op.atomicCompareExchange", "O", "i@iiiii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.textureStore", "v", "i@iiiOOOOc", DXIL_ATTR_KIND_NONE},
{"dx.op.primitiveID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.outputControlPointID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.gsInstanceID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.viewID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.domainLocation", "f", "ic", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.legacyF16ToF32", "f", "ii", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.legacyF32ToF16", "i", "if", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.makeDouble", "g", "iii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.splitDouble", "G", "ig", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.texture2DMSGetSamplePosition", "S", "i@i", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.renderTargetGetSamplePosition", "S", "ii", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.evalSnapped", "O", "iiicii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.evalCentroid", "O", "iiic", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.evalSampleIndex", "O", "iiici", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.coverage", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.storePatchConstant", "v", "iiicO", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.loadPatchConstant", "O", "iiic", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.loadOutputControlPoint", "O", "iiici", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.createHandleFromBinding", "@", "i#ib", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.createHandleFromHeap", "@", "iibb", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.annotateHandle", "@", "i@P", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.isHelperLane", "b", "i", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.waveIsFirstLane", "b", "i", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveGetLaneIndex", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.waveGetLaneCount", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.waveReadLaneFirst", "O", "iO", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveReadLaneAt", "O", "iOi", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveAnyTrue", "b", "ib", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveAllTrue", "b", "ib", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveActiveAllEqual", "b", "iO", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveActiveBallot", "F", "ib", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveActiveOp", "O", "iOcc", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveActiveBit", "O", "iOc", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.wavePrefixOp", "O", "iOcc", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.quadReadLaneAt", "O", "iOi", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.quadOp", "O", "iOc", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.dot4AddPacked", "i", "iiii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.startVertexLocation", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.startInstanceLocation", "i", "i", DXIL_ATTR_KIND_READ_NONE},
};
struct func_descr {
const char *name;
enum overload_type overload;
};
struct func_rb_node {
struct rb_node node;
const struct dxil_func *func;
struct func_descr descr;
};
static inline
const struct func_rb_node *
func_rb_node(const struct rb_node *n)
{
return (const struct func_rb_node *)n;
}
static int
func_compare_to_name_and_overload(const struct rb_node *node, const void *data)
{
const struct func_descr *descr = (const struct func_descr *)data;
const struct func_rb_node *f = func_rb_node(node);
if (f->descr.overload < descr->overload)
return -1;
if (f->descr.overload > descr->overload)
return 1;
return strcmp(f->descr.name, descr->name);
}
static const struct dxil_func *
allocate_function_from_predefined(struct dxil_module *mod,
const char *name,
enum overload_type overload)
{
for (unsigned i = 0; i < ARRAY_SIZE(predefined_funcs); ++i) {
if (!strcmp(predefined_funcs[i].base_name, name)) {
return dxil_alloc_func(mod, name, overload,
predefined_funcs[i].retval_descr,
predefined_funcs[i].param_descr,
predefined_funcs[i].attr);
}
}
UNREACHABLE("Invalid function name");
}
const struct dxil_func *
dxil_get_function(struct dxil_module *mod,
const char *name, enum overload_type overload)
{
struct func_descr descr = { name, overload };
const struct rb_node *node = rb_tree_search(mod->functions, &descr,
func_compare_to_name_and_overload);
if (node)
return func_rb_node(node)->func;
return allocate_function_from_predefined(mod, name, overload);
}
static int func_compare_name(const struct rb_node *lhs, const struct rb_node *rhs)
{
const struct func_rb_node *node = func_rb_node(rhs);
return func_compare_to_name_and_overload(lhs, &node->descr);
}
static void
dxil_add_function(struct rb_tree *functions, const struct dxil_func *func,
const char *name, enum overload_type overload)
{
struct func_rb_node *f = rzalloc(functions, struct func_rb_node);
f->func = func;
f->descr.name = name;
f->descr.overload = overload;
rb_tree_insert(functions, &f->node, func_compare_name);
}
static const struct dxil_type *
get_type_from_string(struct dxil_module *mod, const char *param_descr,
enum overload_type overload, int *idx)
{
assert(param_descr);
char type_id = param_descr[(*idx)++];
assert(*idx <= (int)strlen(param_descr));
switch (type_id) {
case DXIL_FUNC_PARAM_INT64: return dxil_module_get_int_type(mod, 64);
case DXIL_FUNC_PARAM_INT32: return dxil_module_get_int_type(mod, 32);
case DXIL_FUNC_PARAM_INT16: return dxil_module_get_int_type(mod, 16);
case DXIL_FUNC_PARAM_INT8: return dxil_module_get_int_type(mod, 8);
case DXIL_FUNC_PARAM_BOOL: return dxil_module_get_int_type(mod, 1);
case DXIL_FUNC_PARAM_FLOAT64: return dxil_module_get_float_type(mod, 64);
case DXIL_FUNC_PARAM_FLOAT32: return dxil_module_get_float_type(mod, 32);
case DXIL_FUNC_PARAM_FLOAT16: return dxil_module_get_float_type(mod, 16);
case DXIL_FUNC_PARAM_HANDLE: return dxil_module_get_handle_type(mod);
case DXIL_FUNC_PARAM_VOID: return dxil_module_get_void_type(mod);
case DXIL_FUNC_PARAM_FROM_OVERLOAD: return dxil_get_overload_type(mod, overload);
case DXIL_FUNC_PARAM_RESRET: return dxil_module_get_resret_type(mod, overload);
case DXIL_FUNC_PARAM_DIM: return dxil_module_get_dimret_type(mod);
case DXIL_FUNC_PARAM_SAMPLE_POS: return dxil_module_get_samplepos_type(mod);
case DXIL_FUNC_PARAM_CBUF_RET: return dxil_module_get_cbuf_ret_type(mod, overload);
case DXIL_FUNC_PARAM_SPLIT_DOUBLE: return dxil_module_get_split_double_ret_type(mod);
case DXIL_FUNC_PARAM_RES_BIND: return dxil_module_get_res_bind_type(mod);
case DXIL_FUNC_PARAM_RES_PROPS: return dxil_module_get_res_props_type(mod);
case DXIL_FUNC_PARAM_POINTER: {
const struct dxil_type *target = get_type_from_string(mod, param_descr, overload, idx);
return dxil_module_get_pointer_type(mod, target);
}
case DXIL_FUNC_PARAM_FOURI32: return dxil_module_get_fouri32_type(mod);
default:
assert(0 && "unknown type identifier");
}
return NULL;
}
const struct dxil_func *
dxil_alloc_func_with_rettype(struct dxil_module *mod, const char *name,
enum overload_type overload,
const struct dxil_type *retval_type,
const char *param_descr,
enum dxil_attr_kind attr)
{
assert(param_descr);
const struct dxil_type *arg_types[MAX_FUNC_PARAMS];
int index = 0;
unsigned num_params = 0;
while (param_descr[num_params]) {
const struct dxil_type *t = get_type_from_string(mod, param_descr, overload, &index);
if (!t)
return NULL;
assert(num_params < MAX_FUNC_PARAMS);
arg_types[num_params++] = t;
}
const struct dxil_type *func_type =
dxil_module_add_function_type(mod, retval_type,
arg_types, num_params);
if (!func_type) {
fprintf(stderr, "%s: Func type allocation failed\n", __func__);
return NULL;
}
char full_name[100];
snprintf(full_name, sizeof (full_name), "%s%s%s", name,
overload == DXIL_NONE ? "" : ".", dxil_overload_suffix(overload));
const struct dxil_func *func = dxil_add_function_decl(mod, full_name, func_type, attr);
if (func)
dxil_add_function(mod->functions, func, name, overload);
return func;
}
const struct dxil_func *
dxil_alloc_func(struct dxil_module *mod, const char *name, enum overload_type overload,
const char *retval_type_descr,
const char *param_descr, enum dxil_attr_kind attr)
{
int index = 0;
const struct dxil_type *retval_type = get_type_from_string(mod, retval_type_descr, overload, &index);
assert(retval_type_descr[index] == 0);
return dxil_alloc_func_with_rettype(mod, name, overload, retval_type,
param_descr, attr);
}
+97
View File
@@ -0,0 +1,97 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_FUNCTION_H
#define DXIL_FUNCTION_H
#define DXIL_FUNC_PARAM_INT64 'l'
#define DXIL_FUNC_PARAM_INT32 'i'
#define DXIL_FUNC_PARAM_INT16 'h'
#define DXIL_FUNC_PARAM_INT8 'c'
#define DXIL_FUNC_PARAM_BOOL 'b'
#define DXIL_FUNC_PARAM_FLOAT64 'g'
#define DXIL_FUNC_PARAM_FLOAT32 'f'
#define DXIL_FUNC_PARAM_FLOAT16 'e'
#define DXIL_FUNC_PARAM_HANDLE '@'
#define DXIL_FUNC_PARAM_POINTER '*'
#define DXIL_FUNC_PARAM_VOID 'v'
#define DXIL_FUNC_PARAM_FROM_OVERLOAD 'O'
#define DXIL_FUNC_PARAM_RESRET 'R'
#define DXIL_FUNC_PARAM_CBUF_RET 'B'
#define DXIL_FUNC_PARAM_DIM 'D'
#define DXIL_FUNC_PARAM_SPLIT_DOUBLE 'G'
#define DXIL_FUNC_PARAM_SAMPLE_POS 'S'
#define DXIL_FUNC_PARAM_RES_BIND '#'
#define DXIL_FUNC_PARAM_RES_PROPS 'P'
#define DXIL_FUNC_PARAM_FOURI32 'F'
#include "dxil_module.h"
#include "util/rb_tree.h"
const char *dxil_overload_suffix( enum overload_type overload);
const struct dxil_type *
dxil_get_overload_type(struct dxil_module *mod, enum overload_type overload);
/* These functions implement a generic method for declaring functions
* The input parameters types are given as a string using the characters
* given above as identifyer for the types. Only scalars and pointers to
* scalars are implemented at this point.
*
* Examples:
*
* Call: dxil_alloc_func(mod, "storeData.f32", "v", "icf");
* Result function: void storeData.f32(int32, int8, float32)
*
* Call: dxil_alloc_func(mod, "storeData.f32", "e", "*icf");
* Result function: float16 storeData.f32(int32 *, int8, float32)
*
* Call: dxil_alloc_func(mod, "storeData.f32", "*h", "b*f");
* Result function: float16 storeData.f32(bool *, float32 *)
*
*/
const struct dxil_func *
dxil_alloc_func(struct dxil_module *mod, const char *name, enum overload_type overload,
const char *retval_type_descr, const char *param_descr, enum dxil_attr_kind attr);
/* For specifically constructed return types one can also create the return type
* seperately and pass it as paramaer
*/
const struct dxil_func *
dxil_alloc_func_with_rettype(struct dxil_module *mod, const char *name, enum overload_type overload,
const struct dxil_type *retval_type, const char *param_descr,
enum dxil_attr_kind attr);
/* This call should be the usual entry point to allocate a new function type.
* 'name' must either be in the list of predefined functions, or a function
* with 'name' and 'overload' must already be allocated by using one of the above
* function calls. The allocated functions are searched for by using an rb_tree, so
* the search complexity should be O(log(n)).
*/
const struct dxil_func *
dxil_get_function(struct dxil_module *mod, const char *name,
enum overload_type overload);
#endif // DXIL_FUNCTION_H
+310
View File
@@ -0,0 +1,310 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_INTERNAL_H
#define DXIL_INTERNAL_H
#include "dxil_module.h"
#include "util/list.h"
#include <stdint.h>
// Malloc.h defines a macro for alloca. Let's at least make sure that all includers
// of this header have the same definition of alloca.
#include <malloc.h>
struct dxil_type_list {
struct dxil_type **types;
size_t num_types;
};
struct dxil_type {
enum type_type {
TYPE_VOID,
TYPE_INTEGER,
TYPE_FLOAT,
TYPE_POINTER,
TYPE_STRUCT,
TYPE_ARRAY,
TYPE_VECTOR,
TYPE_FUNCTION
} type;
union {
unsigned int_bits;
unsigned float_bits;
const struct dxil_type *ptr_target_type;
struct {
const char *name;
struct dxil_type_list elem;
} struct_def;
struct {
const struct dxil_type *ret_type;
struct dxil_type_list args;
} function_def;
struct {
const struct dxil_type *elem_type;
size_t num_elems;
} array_or_vector_def;
};
struct list_head head;
unsigned id;
};
struct dxil_value {
int id;
const struct dxil_type *type;
};
struct dxil_gvar {
const char *name;
const struct dxil_type *type;
bool constant;
enum dxil_address_space as;
int align;
const struct dxil_value *initializer;
struct dxil_value value;
struct list_head head;
};
struct dxil_func {
char *name;
const struct dxil_type *type;
bool decl;
unsigned attr_set;
struct dxil_value value;
struct list_head head;
};
struct dxil_attrib {
enum {
DXIL_ATTR_ENUM,
DXIL_ATTR_ENUM_VALUE,
DXIL_ATTR_STRING = 3,
DXIL_ATTR_STRING_VALUE,
} type;
union {
enum dxil_attr_kind kind;
const char *str;
} key;
union {
uint64_t integer;
const char *str;
} value;
};
struct attrib_set {
struct dxil_attrib attrs[2];
unsigned num_attrs;
struct list_head head;
};
struct dxil_instr_binop {
enum dxil_bin_opcode opcode;
const struct dxil_value *operands[2];
enum dxil_opt_flags flags;
};
struct dxil_instr_cmp {
enum dxil_cmp_pred pred;
const struct dxil_value *operands[2];
};
struct dxil_instr_select {
const struct dxil_value *operands[3];
};
struct dxil_instr_cast {
enum dxil_cast_opcode opcode;
const struct dxil_type *type;
const struct dxil_value *value;
};
struct dxil_instr_call {
const struct dxil_func *func;
struct dxil_value **args;
size_t num_args;
};
struct dxil_instr_ret {
struct dxil_value *value;
};
struct dxil_instr_extractval {
const struct dxil_value *src;
const struct dxil_type *type;
unsigned int idx;
};
struct dxil_instr_br {
const struct dxil_value *cond;
unsigned succ[2];
};
struct dxil_instr_phi {
const struct dxil_type *type;
struct dxil_phi_src {
const struct dxil_value *value;
unsigned block;
} *incoming;
size_t num_incoming;
};
struct dxil_instr_alloca {
const struct dxil_type *alloc_type;
const struct dxil_type *size_type;
const struct dxil_value *size;
unsigned align;
};
struct dxil_instr_gep {
bool inbounds;
const struct dxil_type *source_elem_type;
struct dxil_value **operands;
size_t num_operands;
};
struct dxil_instr_load {
const struct dxil_value *ptr;
const struct dxil_type *type;
unsigned align;
bool is_volatile;
};
struct dxil_instr_store {
const struct dxil_value *value, *ptr;
unsigned align;
bool is_volatile;
};
struct dxil_instr_atomicrmw {
const struct dxil_value *value, *ptr;
enum dxil_rmw_op op;
bool is_volatile;
enum dxil_atomic_ordering ordering;
enum dxil_sync_scope syncscope;
};
struct dxil_instr_cmpxchg {
const struct dxil_value *cmpval, *newval, *ptr;
bool is_volatile;
enum dxil_atomic_ordering ordering;
enum dxil_sync_scope syncscope;
};
struct dxil_instr {
enum instr_type {
INSTR_BINOP,
INSTR_CMP,
INSTR_SELECT,
INSTR_CAST,
INSTR_BR,
INSTR_PHI,
INSTR_CALL,
INSTR_RET,
INSTR_EXTRACTVAL,
INSTR_ALLOCA,
INSTR_GEP,
INSTR_LOAD,
INSTR_STORE,
INSTR_ATOMICRMW,
INSTR_CMPXCHG,
} type;
union {
struct dxil_instr_binop binop;
struct dxil_instr_cmp cmp;
struct dxil_instr_select select;
struct dxil_instr_cast cast;
struct dxil_instr_call call;
struct dxil_instr_ret ret;
struct dxil_instr_extractval extractval;
struct dxil_instr_phi phi;
struct dxil_instr_br br;
struct dxil_instr_alloca alloca;
struct dxil_instr_gep gep;
struct dxil_instr_load load;
struct dxil_instr_store store;
struct dxil_instr_atomicrmw atomicrmw;
struct dxil_instr_cmpxchg cmpxchg;
};
bool has_value;
struct dxil_value value;
struct list_head head;
};
struct dxil_const {
struct dxil_value value;
bool undef;
union {
intmax_t int_value;
double float_value;
const struct dxil_value **array_values;
const struct dxil_value **struct_values;
const struct dxil_value **vector_values;
};
struct list_head head;
};
struct dxil_mdnode {
enum mdnode_type {
MD_STRING,
MD_VALUE,
MD_NODE
} type;
union {
char *string;
struct {
const struct dxil_type *type;
const struct dxil_value *value;
} value;
struct {
const struct dxil_mdnode **subnodes;
size_t num_subnodes;
} node;
};
struct list_head head;
unsigned id;
};
struct dxil_named_node {
char *name;
const struct dxil_mdnode **subnodes;
size_t num_subnodes;
struct list_head head;
};
#endif // DXIL_INTERNAL_H
File diff suppressed because it is too large. Load diff
+587
View File
@@ -0,0 +1,587 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/*
* See the DirectX Shader Compiler for documentation for DXIL details:
* https://github.com/Microsoft/DirectXShaderCompiler/blob/master/docs/DXIL.rst
*/
#ifndef DXIL_MODULE_H
#define DXIL_MODULE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "dxil_buffer.h"
#include "dxil_signature.h"
#include "util/list.h"
#define DXIL_SHADER_MAX_IO_ROWS 128
enum dxil_shader_kind {
DXIL_PIXEL_SHADER = 0,
DXIL_VERTEX_SHADER = 1,
DXIL_GEOMETRY_SHADER = 2,
DXIL_HULL_SHADER = 3,
DXIL_DOMAIN_SHADER = 4,
DXIL_COMPUTE_SHADER = 5,
};
extern int debug_dxil;
enum dxil_debug_flags {
DXIL_DEBUG_VERBOSE = 1 << 0,
DXIL_DEBUG_DUMP_BLOB = 1 << 1,
DXIL_DEBUG_TRACE = 1 << 2,
DXIL_DEBUG_DUMP_MODULE = 1 << 3,
};
enum dxil_bin_opcode {
DXIL_BINOP_ADD = 0,
DXIL_BINOP_SUB = 1,
DXIL_BINOP_MUL = 2,
DXIL_BINOP_UDIV = 3,
DXIL_BINOP_SDIV = 4,
DXIL_BINOP_UREM = 5,
DXIL_BINOP_SREM = 6,
DXIL_BINOP_SHL = 7,
DXIL_BINOP_LSHR = 8,
DXIL_BINOP_ASHR = 9,
DXIL_BINOP_AND = 10,
DXIL_BINOP_OR = 11,
DXIL_BINOP_XOR = 12,
DXIL_BINOP_INSTR_COUNT
};
enum dxil_cast_opcode {
DXIL_CAST_TRUNC = 0,
DXIL_CAST_ZEXT = 1,
DXIL_CAST_SEXT = 2,
DXIL_CAST_FPTOUI = 3,
DXIL_CAST_FPTOSI = 4,
DXIL_CAST_UITOFP = 5,
DXIL_CAST_SITOFP = 6,
DXIL_CAST_FPTRUNC = 7,
DXIL_CAST_FPEXT = 8,
DXIL_CAST_PTRTOINT = 9,
DXIL_CAST_INTTOPTR = 10,
DXIL_CAST_BITCAST = 11,
DXIL_CAST_ADDRSPACECAST = 12,
DXIL_CAST_INSTR_COUNT
};
enum dxil_cmp_pred {
DXIL_FCMP_FALSE = 0,
DXIL_FCMP_OEQ = 1,
DXIL_FCMP_OGT = 2,
DXIL_FCMP_OGE = 3,
DXIL_FCMP_OLT = 4,
DXIL_FCMP_OLE = 5,
DXIL_FCMP_ONE = 6,
DXIL_FCMP_ORD = 7,
DXIL_FCMP_UNO = 8,
DXIL_FCMP_UEQ = 9,
DXIL_FCMP_UGT = 10,
DXIL_FCMP_UGE = 11,
DXIL_FCMP_ULT = 12,
DXIL_FCMP_ULE = 13,
DXIL_FCMP_UNE = 14,
DXIL_FCMP_TRUE = 15,
DXIL_ICMP_EQ = 32,
DXIL_ICMP_NE = 33,
DXIL_ICMP_UGT = 34,
DXIL_ICMP_UGE = 35,
DXIL_ICMP_ULT = 36,
DXIL_ICMP_ULE = 37,
DXIL_ICMP_SGT = 38,
DXIL_ICMP_SGE = 39,
DXIL_ICMP_SLT = 40,
DXIL_ICMP_SLE = 41,
DXIL_CMP_INSTR_COUNT
};
enum dxil_opt_flags {
DXIL_UNSAFE_ALGEBRA = (1 << 0),
DXIL_NO_NANS = (1 << 1),
DXIL_NO_INFS = (1 << 2),
DXIL_NO_SIGNED_ZEROS = (1 << 3),
DXIL_ALLOW_RECIPROCAL = (1 << 4)
};
struct dxil_features {
uint64_t doubles : 1,
cs_4x_raw_sb : 1,
uavs_at_every_stage : 1,
use_64uavs : 1,
min_precision : 1,
dx11_1_double_extensions : 1,
dx11_1_shader_extensions : 1,
dx9_comparison_filtering : 1,
tiled_resources : 1,
stencil_ref : 1,
inner_coverage : 1,
typed_uav_load_additional_formats : 1,
rovs : 1,
array_layer_from_vs_or_ds : 1,
wave_ops : 1,
int64_ops : 1,
view_id : 1,
barycentrics : 1,
native_low_precision : 1,
shading_rate : 1,
raytracing_tier_1_1 : 1,
sampler_feedback : 1,
atomic_int64_typed : 1,
atomic_int64_tgsm : 1,
derivatives_in_mesh_or_amp : 1,
resource_descriptor_heap_indexing : 1,
sampler_descriptor_heap_indexing : 1,
unnamed : 1,
atomic_int64_heap_resource : 1,
advanced_texture_ops : 1,
writable_msaa : 1,
sample_cmp_bias_gradient : 1,
extended_command_info : 1;
};
struct dxil_shader_info {
unsigned has_out_position:1;
unsigned has_out_depth:1;
unsigned has_per_sample_input:1;
};
struct dxil_func_def {
struct list_head head;
const struct dxil_func *func;
struct list_head instr_list;
int *basic_block_ids; /* maps from "user" ids to LLVM ids */
size_t num_basic_block_ids;
unsigned curr_block;
};
struct dxil_module {
void *ralloc_ctx;
enum dxil_shader_kind shader_kind;
unsigned major_version, minor_version;
unsigned major_validator, minor_validator;
struct dxil_features feats;
unsigned raw_and_structured_buffers : 1;
struct dxil_shader_info info;
struct dxil_buffer buf;
/* The number of entries in the arrays below */
unsigned num_sig_inputs;
unsigned num_sig_outputs;
unsigned num_sig_patch_consts;
/* The number of "vectors" of elements. This is used to determine the sizes
* of the dependency tables.
*/
unsigned num_psv_inputs;
unsigned num_psv_outputs[4];
unsigned num_psv_patch_consts;
struct dxil_signature_record inputs[DXIL_SHADER_MAX_IO_ROWS];
struct dxil_signature_record outputs[DXIL_SHADER_MAX_IO_ROWS];
struct dxil_signature_record patch_consts[DXIL_SHADER_MAX_IO_ROWS];
/* This array is indexed using var->data.driver_location, which
* is not a direct match to IO rows, since a row is a vec4, and
* variables can occupy less than that, and several vars can
* be packed in a row. Hence the x4, but I doubt we can end up
* with more than 80x4 variables in practice. Maybe this array
* should be allocated dynamically based on on the maximum
* driver_location across all input vars.
*/
uint8_t input_mappings[DXIL_SHADER_MAX_IO_ROWS * 4];
uint8_t output_mappings[DXIL_SHADER_MAX_IO_ROWS * 4];
uint8_t patch_mappings[DXIL_SHADER_MAX_IO_ROWS * 4];
struct dxil_psv_signature_element psv_inputs[DXIL_SHADER_MAX_IO_ROWS];
struct dxil_psv_signature_element psv_outputs[DXIL_SHADER_MAX_IO_ROWS];
struct dxil_psv_signature_element psv_patch_consts[DXIL_SHADER_MAX_IO_ROWS];
struct _mesa_string_buffer *sem_string_table;
struct dxil_psv_sem_index_table sem_index_table;
/* These tables are a bitmask per input, with one bit per output
* to indicate whether or not that input contributes to the output.
* Each input's bitmask size is rounded up to a uint32 (DWORD),
* so a bitbask for one output component is the same as for 8 output vec4s.
* Sizes are in number of uint32s.
* Meaning of each array entry depends on shader stage.
* GS: [i] = output stream index
* HS: [0] = control point outputs, [1] = patch constant outputs
* DS: [0] = control point inputs, [1] = patch constant inputs (only for io table)
* PS/VS: only 0 is used. */
uint32_t *serialized_dependency_table;
uint32_t *viewid_dependency_table[4];
uint32_t *io_dependency_table[4];
uint32_t dependency_table_dwords_per_input[4];
uint32_t io_dependency_table_size[4];
uint32_t serialized_dependency_table_size;
struct {
unsigned abbrev_width;
intptr_t offset;
} blocks[16];
size_t num_blocks;
struct list_head type_list;
struct list_head gvar_list;
struct list_head func_list;
struct list_head func_def_list;
struct list_head attr_set_list;
struct list_head const_list;
struct list_head mdnode_list;
struct list_head md_named_node_list;
const struct dxil_type *void_type;
const struct dxil_type *int1_type, *int8_type, *int16_type,
*int32_type, *int64_type;
const struct dxil_type *float16_type, *float32_type, *float64_type;
struct rb_tree *functions;
struct dxil_func_def *cur_emitting_func;
};
struct dxil_instr;
struct dxil_value;
void
dxil_module_init(struct dxil_module *m, void *ralloc_ctx);
void
dxil_module_release(struct dxil_module *m);
const struct dxil_value *
dxil_add_global_var(struct dxil_module *m, const char *name,
const struct dxil_type *type,
enum dxil_address_space as, int align,
const struct dxil_value *value);
const struct dxil_value *
dxil_add_global_ptr_var(struct dxil_module *m, const char *name,
const struct dxil_type *type,
enum dxil_address_space as, int align,
const struct dxil_value *value);
struct dxil_func_def *
dxil_add_function_def(struct dxil_module *m, const char *name,
const struct dxil_type *type, unsigned num_blocks,
const char *const *attr_keys, const char *const *attr_values);
const struct dxil_func *
dxil_add_function_decl(struct dxil_module *m, const char *name,
const struct dxil_type *type,
enum dxil_attr_kind attr);
const struct dxil_type *
dxil_module_get_void_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_int_type(struct dxil_module *m, unsigned bit_size);
const struct dxil_type *
dxil_module_get_float_type(struct dxil_module *m, unsigned bit_size);
const struct dxil_type *
dxil_module_get_pointer_type(struct dxil_module *m,
const struct dxil_type *target);
const struct dxil_type *
dxil_get_overload_type(struct dxil_module *mod, enum overload_type overload);
const struct dxil_type *
dxil_module_get_handle_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_cbuf_ret_type(struct dxil_module *mod, enum overload_type overload);
const struct dxil_type *
dxil_module_get_split_double_ret_type(struct dxil_module *mod);
const struct dxil_type *
dxil_module_get_res_type(struct dxil_module *m, enum dxil_resource_kind kind,
enum dxil_component_type comp_type, unsigned num_comps,
bool readwrite);
const struct dxil_type *
dxil_module_get_resret_type(struct dxil_module *m, enum overload_type overload);
const struct dxil_type *
dxil_module_get_dimret_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_samplepos_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_res_bind_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_res_props_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_fouri32_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_struct_type(struct dxil_module *m,
const char *name,
const struct dxil_type **elem_types,
size_t num_elem_types);
const struct dxil_type *
dxil_module_get_array_type(struct dxil_module *m,
const struct dxil_type *elem_type,
size_t num_elems);
const struct dxil_type *
dxil_module_get_vector_type(struct dxil_module *m,
const struct dxil_type *elem_type,
size_t num_elems);
const struct dxil_type *
dxil_module_add_function_type(struct dxil_module *m,
const struct dxil_type *ret_type,
const struct dxil_type **arg_types,
size_t num_arg_types);
nir_alu_type
dxil_type_to_nir_type(const struct dxil_type *type);
bool
dxil_value_type_equal_to(const struct dxil_value *value,
const struct dxil_type *lhs);
bool
dxil_value_type_bitsize_equal_to(const struct dxil_value *value, unsigned bitsize);
const struct dxil_type *
dxil_value_get_type(const struct dxil_value *value);
const struct dxil_value *
dxil_module_get_int1_const(struct dxil_module *m, bool value);
const struct dxil_value *
dxil_module_get_int8_const(struct dxil_module *m, int8_t value);
const struct dxil_value *
dxil_module_get_int16_const(struct dxil_module *m, int16_t value);
const struct dxil_value *
dxil_module_get_int32_const(struct dxil_module *m, int32_t value);
const struct dxil_value *
dxil_module_get_int64_const(struct dxil_module *m, int64_t value);
const struct dxil_value *
dxil_module_get_int_const(struct dxil_module *m, intmax_t value,
unsigned bit_size);
const struct dxil_value *
dxil_module_get_float16_const(struct dxil_module *m, uint16_t);
const struct dxil_value *
dxil_module_get_float_const(struct dxil_module *m, float value);
const struct dxil_value *
dxil_module_get_double_const(struct dxil_module *m, double value);
const struct dxil_value *
dxil_module_get_array_const(struct dxil_module *m, const struct dxil_type *type,
const struct dxil_value **values);
const struct dxil_value *
dxil_module_get_vector_const(struct dxil_module *m, const struct dxil_type *type,
const struct dxil_value **values);
const struct dxil_value *
dxil_module_get_struct_const(struct dxil_module *m, const struct dxil_type *type,
const struct dxil_value **values);
const struct dxil_value *
dxil_module_get_undef(struct dxil_module *m, const struct dxil_type *type);
const struct dxil_value *
dxil_module_get_res_bind_const(struct dxil_module *m,
uint32_t lower_bound,
uint32_t upper_bound,
uint32_t space,
uint8_t class);
const struct dxil_value *
dxil_module_get_res_props_const(struct dxil_module *m,
enum dxil_resource_class class,
const struct dxil_mdnode *mdnode);
const struct dxil_value *
dxil_module_get_srv_res_props_const(struct dxil_module *m,
const nir_tex_instr *tex);
const struct dxil_value *
dxil_module_get_sampler_res_props_const(struct dxil_module *m,
bool is_shadow);
const struct dxil_value *
dxil_module_get_uav_res_props_const(struct dxil_module *m,
nir_intrinsic_instr *intr);
const struct dxil_value *
dxil_module_get_buffer_res_props_const(struct dxil_module *m,
enum dxil_resource_class class,
enum dxil_resource_kind kind);
const struct dxil_mdnode *
dxil_get_metadata_string(struct dxil_module *m, const char *str);
const struct dxil_mdnode *
dxil_get_metadata_value(struct dxil_module *m, const struct dxil_type *type,
const struct dxil_value *value);
const struct dxil_mdnode *
dxil_get_metadata_func(struct dxil_module *m, const struct dxil_func *func);
const struct dxil_mdnode *
dxil_get_metadata_int1(struct dxil_module *m, bool value);
const struct dxil_mdnode *
dxil_get_metadata_int8(struct dxil_module *m, int8_t value);
const struct dxil_mdnode *
dxil_get_metadata_int32(struct dxil_module *m, int32_t value);
const struct dxil_mdnode *
dxil_get_metadata_int64(struct dxil_module *m, int64_t value);
const struct dxil_mdnode *
dxil_get_metadata_float32(struct dxil_module *m, float value);
const struct dxil_mdnode *
dxil_get_metadata_node(struct dxil_module *m,
const struct dxil_mdnode *subnodes[],
size_t num_subnodes);
bool
dxil_add_metadata_named_node(struct dxil_module *m, const char *name,
const struct dxil_mdnode *subnodes[],
size_t num_subnodes);
const struct dxil_value *
dxil_emit_binop(struct dxil_module *m, enum dxil_bin_opcode opcode,
const struct dxil_value *op0, const struct dxil_value *op1,
enum dxil_opt_flags flags);
const struct dxil_value *
dxil_emit_cmp(struct dxil_module *m, enum dxil_cmp_pred pred,
const struct dxil_value *op0, const struct dxil_value *op1);
const struct dxil_value *
dxil_emit_select(struct dxil_module *m,
const struct dxil_value *op0,
const struct dxil_value *op1,
const struct dxil_value *op2);
const struct dxil_value *
dxil_emit_extractval(struct dxil_module *m, const struct dxil_value *src,
const unsigned int index);
const struct dxil_value *
dxil_emit_cast(struct dxil_module *m, enum dxil_cast_opcode opcode,
const struct dxil_type *type,
const struct dxil_value *value);
bool
dxil_emit_branch(struct dxil_module *m, const struct dxil_value *cond,
unsigned true_block, unsigned false_block);
const struct dxil_value *
dxil_instr_get_return_value(struct dxil_instr *instr);
struct dxil_instr *
dxil_emit_phi(struct dxil_module *m, const struct dxil_type *type);
bool
dxil_phi_add_incoming(struct dxil_instr *instr,
const struct dxil_value *incoming_values[],
const unsigned incoming_blocks[],
size_t num_incoming);
const struct dxil_value *
dxil_emit_call(struct dxil_module *m,
const struct dxil_func *func,
const struct dxil_value **args, size_t num_args);
bool
dxil_emit_call_void(struct dxil_module *m,
const struct dxil_func *func,
const struct dxil_value **args, size_t num_args);
bool
dxil_emit_ret_void(struct dxil_module *m);
const struct dxil_value *
dxil_emit_alloca(struct dxil_module *m, const struct dxil_type *alloc_type,
const struct dxil_value *size,
unsigned int align);
const struct dxil_value *
dxil_emit_gep_inbounds(struct dxil_module *m,
const struct dxil_value **operands,
size_t num_operands);
const struct dxil_value *
dxil_emit_load(struct dxil_module *m, const struct dxil_value *ptr,
unsigned align,
bool is_volatile);
bool
dxil_emit_store(struct dxil_module *m, const struct dxil_value *value,
const struct dxil_value *ptr, unsigned align,
bool is_volatile);
const struct dxil_value *
dxil_emit_cmpxchg(struct dxil_module *m, const struct dxil_value *cmpval,
const struct dxil_value *newval,
const struct dxil_value *ptr, bool is_volatile,
enum dxil_atomic_ordering ordering,
enum dxil_sync_scope syncscope);
const struct dxil_value *
dxil_emit_atomicrmw(struct dxil_module *m, const struct dxil_value *value,
const struct dxil_value *ptr, enum dxil_rmw_op op,
bool is_volatile, enum dxil_atomic_ordering ordering,
enum dxil_sync_scope syncscope);
bool
dxil_emit_module(struct dxil_module *m);
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large. Load diff
+103
View File
@@ -0,0 +1,103 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_NIR_H
#define DXIL_NIR_H
#include <stdbool.h>
#include "nir.h"
#include "nir_builder.h"
#ifdef __cplusplus
extern "C" {
#endif
bool dxil_nir_lower_8bit_conv(nir_shader *shader);
bool dxil_nir_lower_16bit_conv(nir_shader *shader);
bool dxil_nir_algebraic(nir_shader *shader);
bool dxil_nir_lower_fquantize2f16(nir_shader *shader);
bool dxil_nir_lower_constant_to_temp(nir_shader *shader);
bool dxil_nir_flatten_var_arrays(nir_shader *shader, nir_variable_mode modes);
bool dxil_nir_lower_var_bit_size(nir_shader *shader, nir_variable_mode modes,
unsigned min_bit_size, unsigned max_bit_size);
bool dxil_nir_remove_oob_array_accesses(nir_shader *shader);
bool dxil_nir_scratch_and_shared_to_dxil(nir_shader *shader);
bool dxil_nir_lower_deref_ssbo(nir_shader *shader);
bool dxil_nir_opt_alu_deref_srcs(nir_shader *shader);
bool dxil_nir_lower_upcast_phis(nir_shader *shader, unsigned min_bit_size);
bool dxil_nir_split_clip_cull_distance(nir_shader *shader);
bool dxil_nir_lower_double_math(nir_shader *shader);
bool dxil_nir_lower_system_values_to_zero(nir_shader *shader,
gl_system_value* system_value,
uint32_t count);
bool dxil_nir_lower_system_values(nir_shader *shader);
bool dxil_nir_split_typed_samplers(nir_shader *shader);
bool dxil_nir_lower_sysval_to_load_input(nir_shader *s, nir_variable **sysval_vars);
bool dxil_nir_lower_vs_vertex_conversion(nir_shader *s, enum pipe_format target_formats[]);
void
dxil_sort_by_driver_location(nir_shader* s, nir_variable_mode modes);
void
dxil_sort_ps_outputs(nir_shader* s);
void
dxil_reassign_driver_locations(nir_shader* s, nir_variable_mode modes,
uint64_t other_stage_mask, const BITSET_WORD *other_stage_frac_mask);
bool dxil_nir_split_tess_ctrl(nir_shader *nir, nir_function **patch_const_func);
bool dxil_nir_fixup_tess_level_for_domain(nir_shader *nir);
bool dxil_nir_set_tcs_patches_in(nir_shader *nir, unsigned num_control_points);
bool dxil_nir_lower_ubo_array_one_to_static(nir_shader *s);
bool dxil_nir_fix_io_uint_type(nir_shader *s, uint64_t in_mask, uint64_t out_mask);
bool dxil_nir_lower_discard_and_terminate(nir_shader* s);
bool dxil_nir_ensure_position_writes(nir_shader *s);
bool dxil_nir_lower_sample_pos(nir_shader *s);
bool dxil_nir_lower_subgroup_id(nir_shader *s);
bool dxil_nir_lower_num_subgroups(nir_shader *s);
bool dxil_nir_split_unaligned_loads_stores(nir_shader *shader, nir_variable_mode modes);
bool dxil_nir_lower_unsupported_subgroup_scan(nir_shader *s);
bool dxil_nir_forward_front_face(nir_shader *s);
bool dxil_nir_move_consts(nir_shader *s);
struct dxil_module;
bool dxil_nir_analyze_io_dependencies(struct dxil_module *mod, nir_shader *s);
bool dxil_nir_guess_image_formats(nir_shader *s);
bool dxil_nir_lower_coherent_loads_and_stores(nir_shader *s);
bool dxil_nir_kill_undefined_varyings(nir_shader *shader, uint64_t prev_stage_written_mask,
uint32_t prev_stage_patch_written_mask, const BITSET_WORD *prev_stage_frac_output_mask);
bool dxil_nir_kill_unused_outputs(nir_shader *shader, uint64_t next_stage_read_mask,
uint32_t next_stage_patch_read_mask, const BITSET_WORD *next_stage_frac_input_mask);
void dxil_nir_propagate_interp_to_outputs(nir_shader *prev_stage_nir,
const nir_shader *fs_nir);
/* Synthesize placeholder TES inputs mirroring TCS outputs the consumer
* doesn't already declare, so DXIL signature shapes match. */
bool dxil_nir_pad_tes_input_signature(nir_shader *tes, const nir_shader *tcs);
#ifdef __cplusplus
}
#endif
#endif /* DXIL_NIR_H */
@@ -0,0 +1,127 @@
#
# Copyright (C) 2020 Microsoft Corporation
#
# Copyright (C) 2018 Alyssa Rosenzweig
#
# Copyright (C) 2016 Intel Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
import argparse
import sys
import math
a = 'a'
b = 'b'
c = 'c'
# The nir_lower_bit_size() pass gets rid of all 8bit ALUs but insert new u2u8
# and i2i8 operations to convert the result back to the original type after the
# arithmetic operation is done. Those u2u8 and i2i8 operations, as any other
# 8bit operations, are not supported by DXIL and needs to be discarded. The
# dxil_nir_lower_8bit_conv() pass is here for that.
# Similarly, some hardware doesn't support 16bit values
no_8bit_conv = []
no_16bit_conv = []
def remove_unsupported_casts(arr, bit_size, mask, max_unsigned_float, min_signed_float, max_signed_float):
for outer_op_type in ('u2u', 'i2i', 'u2f', 'i2f'):
for outer_op_sz in (16, 32, 64):
if outer_op_sz == bit_size:
continue
outer_op = outer_op_type + str(int(outer_op_sz))
for inner_op_type in ('u2u', 'i2i'):
inner_op = inner_op_type + str(int(bit_size))
for src_sz in (16, 32, 64):
if (src_sz == bit_size):
continue
# Coming from integral, truncate appropriately
orig_seq = (outer_op, (inner_op, 'a@' + str(int(src_sz))))
if (outer_op[0] == 'u'):
new_seq = ('iand', a, mask)
else:
shift = src_sz - bit_size
new_seq = ('ishr', ('ishl', a, shift), shift)
# Make sure the destination is the right type/size
if outer_op_sz != src_sz or outer_op[2] != inner_op[0]:
new_seq = (outer_op, new_seq)
arr += [(orig_seq, new_seq)]
for inner_op_type in ('f2u', 'f2i'):
inner_op = inner_op_type + str(int(bit_size))
if (outer_op[2] == 'f'):
# From float and to float, just truncate via min/max, and ensure the right float size
for src_sz in (16, 32, 64):
if (src_sz == bit_size):
continue
orig_seq = (outer_op, (inner_op, 'a@' + str(int(src_sz))))
if (outer_op[0] == 'u'):
new_seq = ('fmin', ('fmax', a, 0.0), max_unsigned_float)
else:
new_seq = ('fmin', ('fmax', a, min_signed_float), max_signed_float)
if outer_op_sz != src_sz:
new_seq = ('f2f' + str(int(outer_op_sz)), new_seq)
arr += [(orig_seq, new_seq)]
else:
# From float to integral, convert to integral type first, then truncate
orig_seq = (outer_op, (inner_op, a))
float_conv = ('f2' + inner_op[2] + str(int(outer_op_sz)), a)
if (outer_op[0] == 'u'):
new_seq = ('iand', float_conv, mask)
else:
shift = outer_op_sz - bit_size
new_seq = ('ishr', ('ishl', float_conv, shift), shift)
arr += [(orig_seq, new_seq)]
remove_unsupported_casts(no_8bit_conv, 8, 0xff, 255.0, -128.0, 127.0)
remove_unsupported_casts(no_16bit_conv, 16, 0xffff, 65535.0, -32768.0, 32767.0)
algebraic_ops = [
(('b2b32', 'a'), ('b2i32', 'a')),
(('b2b1', 'a'), ('ine', ('b2i32', a), 0)),
]
no_16bit_conv += [
(('f2f32', ('u2u16', 'a@32')), ('unpack_half_x_dxil', a)),
(('u2u32', ('f2f16_rtz', 'a@32')), ('pack_half_2x16_split', 'a', 0)),
]
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--import-path', required=True)
args = parser.parse_args()
sys.path.insert(0, args.import_path)
run()
def run():
import nir_algebraic # pylint: disable=import-error
print('#include "dxil_nir.h"')
print(nir_algebraic.AlgebraicPass("dxil_nir_lower_8bit_conv",
no_8bit_conv).render())
print(nir_algebraic.AlgebraicPass("dxil_nir_lower_16bit_conv",
no_16bit_conv).render())
print(nir_algebraic.AlgebraicPass("dxil_nir_algebraic",
algebraic_ops).render())
if __name__ == '__main__':
main()
@@ -0,0 +1,556 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "dxil_nir_lower_int_cubemaps.h"
#include "nir_builder.h"
#include "nir_builtin_builder.h"
static bool
type_needs_lowering(const struct glsl_type *type, bool lower_samplers)
{
type = glsl_without_array(type);
if (!glsl_type_is_image(type) && !glsl_type_is_sampler(type))
return false;
if (glsl_get_sampler_dim(type) != GLSL_SAMPLER_DIM_CUBE)
return false;
if (glsl_type_is_image(type))
return true;
return lower_samplers && glsl_base_type_is_integer(glsl_get_sampler_result_type(type));
}
static bool
lower_int_cubmap_to_array_filter(const nir_instr *instr,
const void *options)
{
bool lower_samplers = *(bool *)options;
if (instr->type == nir_instr_type_intrinsic) {
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
switch (intr->intrinsic) {
case nir_intrinsic_image_atomic:
case nir_intrinsic_image_atomic_swap:
case nir_intrinsic_image_load:
case nir_intrinsic_image_size:
case nir_intrinsic_image_store:
case nir_intrinsic_image_deref_atomic:
case nir_intrinsic_image_deref_atomic_swap:
case nir_intrinsic_image_deref_load:
case nir_intrinsic_image_deref_size:
case nir_intrinsic_image_deref_store:
return nir_intrinsic_image_dim(intr) == GLSL_SAMPLER_DIM_CUBE;
default:
return false;
}
} else if (instr->type == nir_instr_type_deref) {
nir_deref_instr *deref = nir_instr_as_deref(instr);
return type_needs_lowering(deref->type, lower_samplers);
} else if (instr->type == nir_instr_type_tex && lower_samplers) {
nir_tex_instr *tex = nir_instr_as_tex(instr);
if (tex->sampler_dim != GLSL_SAMPLER_DIM_CUBE)
return false;
switch (tex->op) {
case nir_texop_tex:
case nir_texop_txb:
case nir_texop_txd:
case nir_texop_txl:
case nir_texop_txs:
case nir_texop_lod:
case nir_texop_tg4:
break;
default:
return false;
}
int sampler_deref = nir_tex_instr_src_index(tex, nir_tex_src_sampler_deref);
assert(sampler_deref >= 0);
nir_deref_instr *deref = nir_def_as_deref(tex->src[sampler_deref].src.ssa);
nir_variable *cube = nir_deref_instr_get_variable(deref);
return glsl_base_type_is_integer(glsl_get_sampler_result_type(cube->type));
}
return false;
}
typedef struct {
bool image;
nir_def *rx;
nir_def *ry;
nir_def *rz;
nir_def *arx;
nir_def *ary;
nir_def *arz;
nir_def *array;
} coord_t;
/* This is taken from from sp_tex_sample:convert_cube */
static nir_def *
evaluate_face_x(nir_builder *b, coord_t *coord)
{
nir_def *sign = nir_fsign(b, coord->rx);
nir_def *positive = nir_fge_imm(b, coord->rx, 0.0);
nir_def *ima = nir_fdiv(b, nir_imm_float(b, -0.5), coord->arx);
nir_def *x = nir_fadd_imm(b, nir_fmul(b, nir_fmul(b, sign, ima), coord->rz), 0.5);
nir_def *y = nir_fadd_imm(b, nir_fmul(b, ima, coord->ry), 0.5);
nir_def *face = nir_bcsel(b, positive, nir_imm_float(b, 0.0), nir_imm_float(b, 1.0));
if (coord->array)
face = nir_fadd(b, face, coord->array);
return coord->image ?
nir_vec4(b, x,y, face, nir_undef(b, 1, 32)) :
nir_vec3(b, x,y, face);
}
static nir_def *
evaluate_face_y(nir_builder *b, coord_t *coord)
{
nir_def *sign = nir_fsign(b, coord->ry);
nir_def *positive = nir_fge_imm(b, coord->ry, 0.0);
nir_def *ima = nir_fdiv(b, nir_imm_float(b, 0.5), coord->ary);
nir_def *x = nir_fadd_imm(b, nir_fmul(b, ima, coord->rx), 0.5);
nir_def *y = nir_fadd_imm(b, nir_fmul(b, nir_fmul(b, sign, ima), coord->rz), 0.5);
nir_def *face = nir_bcsel(b, positive, nir_imm_float(b, 2.0), nir_imm_float(b, 3.0));
if (coord->array)
face = nir_fadd(b, face, coord->array);
return coord->image ?
nir_vec4(b, x,y, face, nir_undef(b, 1, 32)) :
nir_vec3(b, x,y, face);
}
static nir_def *
evaluate_face_z(nir_builder *b, coord_t *coord)
{
nir_def *sign = nir_fsign(b, coord->rz);
nir_def *positive = nir_fge_imm(b, coord->rz, 0.0);
nir_def *ima = nir_fdiv(b, nir_imm_float(b, -0.5), coord->arz);
nir_def *x = nir_fadd_imm(b, nir_fmul(b, nir_fmul(b, sign, ima), nir_fneg(b, coord->rx)), 0.5);
nir_def *y = nir_fadd_imm(b, nir_fmul(b, ima, coord->ry), 0.5);
nir_def *face = nir_bcsel(b, positive, nir_imm_float(b, 4.0), nir_imm_float(b, 5.0));
if (coord->array)
face = nir_fadd(b, face, coord->array);
return coord->image ?
nir_vec4(b, x,y, face, nir_undef(b, 1, 32)) :
nir_vec3(b, x,y, face);
}
static nir_def *
create_array_tex_from_cube_tex(nir_builder *b, nir_tex_instr *tex, nir_def *coord, nir_texop op)
{
nir_tex_instr *array_tex;
array_tex = nir_tex_instr_create(b->shader, tex->num_srcs);
array_tex->op = op;
array_tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
array_tex->is_array = true;
array_tex->is_shadow = tex->is_shadow;
array_tex->is_new_style_shadow = tex->is_new_style_shadow;
array_tex->texture_index = tex->texture_index;
array_tex->sampler_index = tex->sampler_index;
array_tex->dest_type = tex->dest_type;
array_tex->coord_components = 3;
array_tex->can_speculate = tex->can_speculate;
nir_src coord_src = nir_src_for_ssa(coord);
for (unsigned i = 0; i < tex->num_srcs; i++) {
nir_src *psrc = (tex->src[i].src_type == nir_tex_src_coord) ?
&coord_src : &tex->src[i].src;
array_tex->src[i].src = nir_src_for_ssa(psrc->ssa);
array_tex->src[i].src_type = tex->src[i].src_type;
}
nir_def_init(&array_tex->instr, &array_tex->def,
nir_tex_instr_dest_size(array_tex), 32);
nir_builder_instr_insert(b, &array_tex->instr);
return &array_tex->def;
}
static nir_def *
handle_cube_edge(nir_builder *b, nir_def *x, nir_def *y, nir_def *face, nir_def *array_slice_cube_base, nir_def *tex_size)
{
enum cube_remap
{
cube_remap_zero = 0,
cube_remap_x,
cube_remap_y,
cube_remap_tex_size,
cube_remap_tex_size_minus_x,
cube_remap_tex_size_minus_y,
cube_remap_size,
};
struct cube_remap_table
{
enum cube_remap remap_x;
enum cube_remap remap_y;
uint32_t remap_face;
};
static const struct cube_remap_table cube_remap_neg_x[6] =
{
{cube_remap_tex_size, cube_remap_y, 4},
{cube_remap_tex_size, cube_remap_y, 5},
{cube_remap_y, cube_remap_zero, 1},
{cube_remap_tex_size_minus_y, cube_remap_tex_size, 1},
{cube_remap_tex_size, cube_remap_y, 1},
{cube_remap_tex_size, cube_remap_y, 0},
};
static const struct cube_remap_table cube_remap_pos_x[6] =
{
{cube_remap_zero, cube_remap_y, 5},
{cube_remap_zero, cube_remap_y, 4},
{cube_remap_tex_size_minus_y, cube_remap_zero, 0},
{cube_remap_y, cube_remap_tex_size, 0},
{cube_remap_zero, cube_remap_y, 0},
{cube_remap_zero, cube_remap_y, 1},
};
static const struct cube_remap_table cube_remap_neg_y[6] =
{
{cube_remap_tex_size, cube_remap_tex_size_minus_x, 2},
{cube_remap_zero, cube_remap_x, 2},
{cube_remap_tex_size_minus_x, cube_remap_zero, 5},
{cube_remap_x, cube_remap_tex_size, 4},
{cube_remap_x, cube_remap_tex_size, 2},
{cube_remap_tex_size_minus_x, cube_remap_zero, 2},
};
static const struct cube_remap_table cube_remap_pos_y[6] =
{
{cube_remap_tex_size, cube_remap_x, 3},
{cube_remap_zero, cube_remap_tex_size_minus_x, 3},
{cube_remap_x, cube_remap_zero, 4},
{cube_remap_tex_size_minus_x, cube_remap_tex_size, 5},
{cube_remap_x, cube_remap_zero, 3},
{cube_remap_tex_size_minus_x, cube_remap_tex_size, 3},
};
static const struct cube_remap_table* remap_tables[4] = {
cube_remap_neg_x,
cube_remap_pos_x,
cube_remap_neg_y,
cube_remap_pos_y
};
nir_def *zero = nir_imm_int(b, 0);
/* Doesn't matter since the texture is square */
tex_size = nir_channel(b, tex_size, 0);
nir_def *x_on = nir_iand(b, nir_ige(b, x, zero), nir_ige(b, tex_size, x));
nir_def *y_on = nir_iand(b, nir_ige(b, y, zero), nir_ige(b, tex_size, y));
nir_def *one_on = nir_ixor(b, x_on, y_on);
/* If the sample did not fall off the face in either dimension, then set output = input */
nir_def *x_result = x;
nir_def *y_result = y;
nir_def *face_result = face;
/* otherwise, if the sample fell off the face in either the X or the Y direction, remap to the new face */
nir_def *remap_predicates[4] =
{
nir_iand(b, one_on, nir_ilt(b, x, zero)),
nir_iand(b, one_on, nir_ilt(b, tex_size, x)),
nir_iand(b, one_on, nir_ilt(b, y, zero)),
nir_iand(b, one_on, nir_ilt(b, tex_size, y)),
};
nir_def *remap_array[cube_remap_size];
remap_array[cube_remap_zero] = zero;
remap_array[cube_remap_x] = x;
remap_array[cube_remap_y] = y;
remap_array[cube_remap_tex_size] = tex_size;
remap_array[cube_remap_tex_size_minus_x] = nir_isub(b, tex_size, x);
remap_array[cube_remap_tex_size_minus_y] = nir_isub(b, tex_size, y);
/* For each possible way the sample could have fallen off */
for (unsigned i = 0; i < 4; i++) {
const struct cube_remap_table* remap_table = remap_tables[i];
/* For each possible original face */
for (unsigned j = 0; j < 6; j++) {
nir_def *predicate = nir_iand(b, remap_predicates[i], nir_ieq_imm(b, face, j));
x_result = nir_bcsel(b, predicate, remap_array[remap_table[j].remap_x], x_result);
y_result = nir_bcsel(b, predicate, remap_array[remap_table[j].remap_y], y_result);
face_result = nir_bcsel(b, predicate, remap_array[remap_table[j].remap_face], face_result);
}
}
return nir_vec3(b, x_result, y_result, nir_iadd(b, face_result, array_slice_cube_base));
}
static nir_def *
handle_cube_gather(nir_builder *b, nir_tex_instr *tex, nir_def *coord)
{
nir_def *tex_size = nir_get_texture_size(b, tex);
/* nir_get_texture_size puts the cursor before the tex op */
b->cursor = nir_after_def(coord);
nir_def *const_05 = nir_imm_float(b, 0.5f);
nir_def *texel_coords = nir_fmul(b, nir_trim_vector(b, coord, 2),
nir_i2f32(b, nir_trim_vector(b, tex_size, 2)));
nir_def *x_orig = nir_channel(b, texel_coords, 0);
nir_def *y_orig = nir_channel(b, texel_coords, 1);
nir_def *x_pos = nir_f2i32(b, nir_fadd(b, x_orig, const_05));
nir_def *x_neg = nir_f2i32(b, nir_fsub(b, x_orig, const_05));
nir_def *y_pos = nir_f2i32(b, nir_fadd(b, y_orig, const_05));
nir_def *y_neg = nir_f2i32(b, nir_fsub(b, y_orig, const_05));
nir_def *coords[4][2] = {
{ x_neg, y_pos },
{ x_pos, y_pos },
{ x_pos, y_neg },
{ x_neg, y_neg },
};
nir_def *array_slice_2d = nir_f2i32(b, nir_channel(b, coord, 2));
nir_def *face = nir_imod_imm(b, array_slice_2d, 6);
nir_def *array_slice_cube_base = nir_isub(b, array_slice_2d, face);
nir_def *channels[4];
for (unsigned i = 0; i < 4; ++i) {
nir_def *final_coord = handle_cube_edge(b, coords[i][0], coords[i][1], face, array_slice_cube_base, tex_size);
nir_def *sampled_val = create_array_tex_from_cube_tex(b, tex, final_coord, nir_texop_txf);
channels[i] = nir_channel(b, sampled_val, tex->component);
}
return nir_vec(b, channels, 4);
}
static nir_def *
lower_cube_coords(nir_builder *b, nir_def *coord, bool is_array, bool is_image)
{
coord_t coords;
coords.image = is_image;
coords.rx = nir_channel(b, coord, 0);
coords.ry = nir_channel(b, coord, 1);
coords.rz = nir_channel(b, coord, 2);
coords.arx = nir_fabs(b, coords.rx);
coords.ary = nir_fabs(b, coords.ry);
coords.arz = nir_fabs(b, coords.rz);
coords.array = NULL;
if (is_array)
coords.array = nir_fmul_imm(b, nir_channel(b, coord, 3), 6.0f);
nir_def *use_face_x = nir_iand(b,
nir_fge(b, coords.arx, coords.ary),
nir_fge(b, coords.arx, coords.arz));
nir_if *use_face_x_if = nir_push_if(b, use_face_x);
nir_def *face_x_coord = evaluate_face_x(b, &coords);
nir_if *use_face_x_else = nir_push_else(b, use_face_x_if);
nir_def *use_face_y = nir_iand(b,
nir_fge(b, coords.ary, coords.arx),
nir_fge(b, coords.ary, coords.arz));
nir_if *use_face_y_if = nir_push_if(b, use_face_y);
nir_def *face_y_coord = evaluate_face_y(b, &coords);
nir_if *use_face_y_else = nir_push_else(b, use_face_y_if);
nir_def *face_z_coord = evaluate_face_z(b, &coords);
nir_pop_if(b, use_face_y_else);
nir_def *face_y_or_z_coord = nir_if_phi(b, face_y_coord, face_z_coord);
nir_pop_if(b, use_face_x_else);
// This contains in xy the normalized sample coordinates, and in z the face index
nir_def *coord_and_face = nir_if_phi(b, face_x_coord, face_y_or_z_coord);
return coord_and_face;
}
static nir_def *
lower_cube_sample(nir_builder *b, nir_tex_instr *tex)
{
int coord_index = nir_tex_instr_src_index(tex, nir_tex_src_coord);
assert(coord_index >= 0);
/* Evaluate the face and the xy coordinates for a 2D tex op */
nir_def *coord = tex->src[coord_index].src.ssa;
nir_def *coord_and_face = lower_cube_coords(b, coord, tex->is_array, false);
if (tex->op == nir_texop_tg4)
return handle_cube_gather(b, tex, coord_and_face);
else
return create_array_tex_from_cube_tex(b, tex, coord_and_face, tex->op);
}
static nir_def *
lower_cube_image_load_store_atomic(nir_builder *b, nir_intrinsic_instr *intr)
{
b->cursor = nir_before_instr(&intr->instr);
nir_intrinsic_set_image_array(intr, true);
nir_intrinsic_set_image_dim(intr, GLSL_SAMPLER_DIM_2D);
return NIR_LOWER_INSTR_PROGRESS;
}
static nir_def *
lower_cube_txs(nir_builder *b, nir_tex_instr *tex)
{
b->cursor = nir_after_instr(&tex->instr);
if (!tex->is_array)
return nir_trim_vector(b, &tex->def, 2);
nir_def *array_dim = nir_channel(b, &tex->def, 2);
nir_def *cube_array_dim = nir_idiv(b, array_dim, nir_imm_int(b, 6));
return nir_vec3(b, nir_channel(b, &tex->def, 0),
nir_channel(b, &tex->def, 1),
cube_array_dim);
}
static nir_def *
lower_cube_image_size(nir_builder *b, nir_intrinsic_instr *intr)
{
b->cursor = nir_after_instr(&intr->instr);
if (!nir_intrinsic_image_array(intr))
return nir_trim_vector(b, &intr->def, 2);
nir_def *array_dim = nir_channel(b, &intr->def, 2);
nir_def *cube_array_dim = nir_idiv(b, array_dim, nir_imm_int(b, 6));
return nir_vec3(b, nir_channel(b, &intr->def, 0),
nir_channel(b, &intr->def, 1),
cube_array_dim);
}
static const struct glsl_type *
make_2darray_sampler_from_cubemap(const struct glsl_type *type)
{
return glsl_get_sampler_dim(type) == GLSL_SAMPLER_DIM_CUBE ?
glsl_sampler_type(
GLSL_SAMPLER_DIM_2D,
false, true,
glsl_get_sampler_result_type(type)) : type;
}
static const struct glsl_type *
make_2darray_image_from_cubemap(const struct glsl_type *type)
{
return glsl_get_sampler_dim(type) == GLSL_SAMPLER_DIM_CUBE ?
glsl_image_type(
GLSL_SAMPLER_DIM_2D,
true,
glsl_get_sampler_result_type(type)) : type;
}
static const struct glsl_type *
make_2darray_from_cubemap_with_array(const struct glsl_type *type, bool is_image)
{
if (glsl_type_is_array(type)) {
const struct glsl_type *new_type = glsl_without_array(type);
return new_type != type ? glsl_array_type(make_2darray_from_cubemap_with_array(glsl_without_array(type), is_image),
glsl_get_length(type), 0) : type;
} else if (is_image)
return make_2darray_image_from_cubemap(type);
else
return make_2darray_sampler_from_cubemap(type);
}
static nir_def *
lower_int_cubemap_to_array_tex(nir_builder *b, nir_tex_instr *tex)
{
switch (tex->op) {
case nir_texop_tex:
case nir_texop_txb:
case nir_texop_txd:
case nir_texop_txl:
case nir_texop_lod:
case nir_texop_tg4:
return lower_cube_sample(b, tex);
case nir_texop_txs:
return lower_cube_txs(b, tex);
default:
UNREACHABLE("Unsupported cupe map texture operation");
}
}
static nir_def *
lower_cube_image_intrinsic(nir_builder *b, nir_intrinsic_instr *intr)
{
if (intr->intrinsic == nir_intrinsic_image_size ||
intr->intrinsic == nir_intrinsic_image_deref_size)
return lower_cube_image_size(b, intr);
else
return lower_cube_image_load_store_atomic(b, intr);
}
static nir_def *
lower_cube_image_deref(nir_builder *b, nir_deref_instr *deref)
{
deref->type = make_2darray_from_cubemap_with_array(
deref->type,
glsl_type_is_image(glsl_without_array(deref->type)));
return NIR_LOWER_INSTR_PROGRESS;
}
static nir_def *
lower_int_cubmap_to_array_impl(nir_builder *b, nir_instr *instr,
void *options)
{
bool lower_samplers = *(bool *)options;
if (instr->type == nir_instr_type_tex && lower_samplers)
return lower_int_cubemap_to_array_tex(b, nir_instr_as_tex(instr));
else if (instr->type == nir_instr_type_intrinsic)
return lower_cube_image_intrinsic(b, nir_instr_as_intrinsic(instr));
else if (instr->type == nir_instr_type_deref)
return lower_cube_image_deref(b, nir_instr_as_deref(instr));
return NULL;
}
bool
dxil_nir_lower_int_cubemaps(nir_shader *s, bool lower_samplers)
{
bool result =
nir_shader_lower_instructions(s,
lower_int_cubmap_to_array_filter,
lower_int_cubmap_to_array_impl,
&lower_samplers);
if (result) {
nir_foreach_variable_with_modes_safe(var, s, nir_var_uniform | nir_var_image) {
if (!type_needs_lowering(var->type, lower_samplers))
continue;
bool is_image = glsl_type_is_image(glsl_without_array(var->type));
var->type = make_2darray_from_cubemap_with_array(var->type, is_image);
}
}
return result;
}
@@ -0,0 +1,40 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef DXIL_NIR_LOWER_INT_CUBEMAPS_H
#define DXIL_NIR_LOWER_INT_CUBEMAPS_H
#include "nir.h"
#ifdef __cplusplus
extern "C" {
#endif
bool
dxil_nir_lower_int_cubemaps(nir_shader *s, bool lower_samplers);
#ifdef __cplusplus
}
#endif
#endif // DXIL_NIR_LOWER_INT_CUBEMAPS_H
@@ -0,0 +1,575 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "dxil_nir_lower_int_samplers.h"
#include "nir_builder.h"
#include "nir_builtin_builder.h"
typedef struct {
unsigned n_texture_states;
dxil_wrap_sampler_state* wrap_states;
dxil_texture_swizzle_state* tex_swizzles;
float max_bias;
} sampler_states;
static bool
lower_sample_to_txf_for_integer_tex_filter(const nir_instr *instr,
const void *_options)
{
if (instr->type != nir_instr_type_tex)
return false;
nir_tex_instr *tex = nir_instr_as_tex(instr);
if (tex->op != nir_texop_tex &&
tex->op != nir_texop_txb &&
tex->op != nir_texop_txl &&
tex->op != nir_texop_txd)
return false;
return (tex->dest_type & (nir_type_int | nir_type_uint));
}
static nir_def *
dx_get_texture_lod(nir_builder *b, nir_tex_instr *tex)
{
nir_tex_instr *tql;
unsigned num_srcs = 0;
for (unsigned i = 0; i < tex->num_srcs; i++) {
if (tex->src[i].src_type == nir_tex_src_coord ||
tex->src[i].src_type == nir_tex_src_texture_deref ||
tex->src[i].src_type == nir_tex_src_sampler_deref ||
tex->src[i].src_type == nir_tex_src_texture_offset ||
tex->src[i].src_type == nir_tex_src_sampler_offset ||
tex->src[i].src_type == nir_tex_src_texture_handle ||
tex->src[i].src_type == nir_tex_src_sampler_handle)
num_srcs++;
}
tql = nir_tex_instr_create(b->shader, num_srcs);
tql->op = nir_texop_lod;
unsigned coord_components = tex->coord_components;
if (tex->is_array)
--coord_components;
tql->coord_components = coord_components;
tql->sampler_dim = tex->sampler_dim;
tql->is_shadow = tex->is_shadow;
tql->is_new_style_shadow = tex->is_new_style_shadow;
tql->texture_index = tex->texture_index;
tql->sampler_index = tex->sampler_index;
tql->can_speculate = tex->can_speculate;
tql->dest_type = nir_type_float32;
/* The coordinate needs special handling because we might have
* to strip the array index. Don't clutter the code with an additional
* check for is_array though, in the worst case we create an additional
* move the the optimization will remove later again. */
int coord_index = nir_tex_instr_src_index(tex, nir_tex_src_coord);
nir_def *ssa_src = nir_trim_vector(b, tex->src[coord_index].src.ssa,
coord_components);
tql->src[0].src = nir_src_for_ssa(ssa_src);
tql->src[0].src_type = nir_tex_src_coord;
unsigned idx = 1;
for (unsigned i = 0; i < tex->num_srcs; i++) {
if (tex->src[i].src_type == nir_tex_src_texture_deref ||
tex->src[i].src_type == nir_tex_src_sampler_deref ||
tex->src[i].src_type == nir_tex_src_texture_offset ||
tex->src[i].src_type == nir_tex_src_sampler_offset ||
tex->src[i].src_type == nir_tex_src_texture_handle ||
tex->src[i].src_type == nir_tex_src_sampler_handle) {
tql->src[idx].src = nir_src_for_ssa(tex->src[i].src.ssa);
tql->src[idx].src_type = tex->src[i].src_type;
idx++;
}
}
nir_def_init(&tql->instr, &tql->def, 2, 32);
nir_builder_instr_insert(b, &tql->instr);
/* DirectX LOD only has a value in x channel */
return nir_channel(b, &tql->def, 0);
}
typedef struct {
nir_def *coords;
nir_def *use_border_color;
} wrap_result_t;
typedef struct {
nir_def *lod;
nir_def *size;
int ncoord_comp;
wrap_result_t wrap[3];
} wrap_lower_param_t;
static void
wrap_clamp_to_edge(nir_builder *b, wrap_result_t *wrap_params, nir_def *size)
{
/* clamp(coord, 0, size - 1) */
wrap_params->coords = nir_fmin(b, nir_fadd_imm(b, size, -1.0f),
nir_fmax(b, wrap_params->coords, nir_imm_float(b, 0.0f)));
}
static void
wrap_repeat(nir_builder *b, wrap_result_t *wrap_params, nir_def *size)
{
/* mod(coord, size)
* This instruction must be exact, otherwise certain sizes result in
* incorrect sampling */
wrap_params->coords = nir_fmod(b, wrap_params->coords, size);
nir_def_as_alu(wrap_params->coords)->fp_math_ctrl |= nir_fp_exact;
}
static nir_def *
mirror(nir_builder *b, nir_def *coord)
{
/* coord if >= 0, otherwise -(1 + coord) */
return nir_bcsel(b, nir_fge_imm(b, coord, 0.0f), coord,
nir_fneg(b, nir_fadd_imm(b, coord, 1.0f)));
}
static void
wrap_mirror_repeat(nir_builder *b, wrap_result_t *wrap_params, nir_def *size)
{
/* (size − 1) − mirror(mod(coord, 2 * size) − size) */
nir_def *coord_mod2size = nir_fmod(b, wrap_params->coords, nir_fmul_imm(b, size, 2.0f));
nir_def_as_alu(coord_mod2size)->fp_math_ctrl |= nir_fp_exact;
nir_def *a = nir_fsub(b, coord_mod2size, size);
wrap_params->coords = nir_fsub(b, nir_fadd_imm(b, size, -1.0f), mirror(b, a));
}
static void
wrap_mirror_clamp_to_edge(nir_builder *b, wrap_result_t *wrap_params, nir_def *size)
{
/* clamp(mirror(coord), 0, size - 1) */
wrap_params->coords = nir_fmin(b, nir_fadd_imm(b, size, -1.0f),
nir_fmax(b, mirror(b, wrap_params->coords), nir_imm_float(b, 0.0f)));
}
static void
wrap_clamp(nir_builder *b, wrap_result_t *wrap_params, nir_def *size)
{
nir_def *is_low = nir_flt_imm(b, wrap_params->coords, 0.0);
nir_def *is_high = nir_fge(b, wrap_params->coords, size);
wrap_params->use_border_color = nir_ior(b, is_low, is_high);
}
static void
wrap_mirror_clamp(nir_builder *b, wrap_result_t *wrap_params, nir_def *size)
{
/* We have to take care of the boundaries */
nir_def *is_low = nir_flt(b, wrap_params->coords, nir_fmul_imm(b, size, -1.0));
nir_def *is_high = nir_flt(b, nir_fmul_imm(b, size, 2.0), wrap_params->coords);
wrap_params->use_border_color = nir_ior(b, is_low, is_high);
/* Within the boundaries this acts like mirror_repeat */
wrap_mirror_repeat(b, wrap_params, size);
}
static wrap_result_t
wrap_coords(nir_builder *b, nir_def *coords, enum dxil_tex_wrap wrap,
nir_def *size)
{
wrap_result_t result = {coords, nir_imm_false(b)};
switch (wrap) {
case DXIL_TEX_WRAP_CLAMP_TO_EDGE:
wrap_clamp_to_edge(b, &result, size);
break;
case DXIL_TEX_WRAP_REPEAT:
wrap_repeat(b, &result, size);
break;
case DXIL_TEX_WRAP_MIRROR_REPEAT:
wrap_mirror_repeat(b, &result, size);
break;
case DXIL_TEX_WRAP_MIRROR_CLAMP:
case DXIL_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
wrap_mirror_clamp_to_edge(b, &result, size);
break;
case DXIL_TEX_WRAP_CLAMP:
case DXIL_TEX_WRAP_CLAMP_TO_BORDER:
wrap_clamp(b, &result, size);
break;
case DXIL_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
wrap_mirror_clamp(b, &result, size);
break;
}
return result;
}
static nir_def *
load_bordercolor(nir_builder *b, nir_tex_instr *tex, const dxil_wrap_sampler_state *active_state,
const dxil_texture_swizzle_state *tex_swizzle)
{
int ndest_comp = tex->def.num_components;
unsigned swizzle[4] = {
tex_swizzle->swizzle_r,
tex_swizzle->swizzle_g,
tex_swizzle->swizzle_b,
tex_swizzle->swizzle_a
};
/* Avoid any possible float conversion issues */
uint32_t border_color[4];
memcpy(border_color, active_state->border_color, sizeof(border_color));
STATIC_ASSERT(sizeof(border_color) == sizeof(active_state->border_color));
nir_const_value const_value[4];
for (int i = 0; i < ndest_comp; ++i) {
switch (swizzle[i]) {
case PIPE_SWIZZLE_0:
const_value[i] = nir_const_value_for_uint(0, 32);
break;
case PIPE_SWIZZLE_1:
const_value[i] = nir_const_value_for_uint(1, 32);
break;
case PIPE_SWIZZLE_X:
case PIPE_SWIZZLE_Y:
case PIPE_SWIZZLE_Z:
case PIPE_SWIZZLE_W:
const_value[i] = nir_const_value_for_uint(border_color[swizzle[i]], 32);
break;
default:
UNREACHABLE("Unexpected swizzle value");
}
}
return nir_build_imm(b, ndest_comp, 32, const_value);
}
static nir_tex_instr *
create_txf_from_tex(nir_builder *b, nir_tex_instr *tex)
{
nir_tex_instr *txf;
unsigned num_srcs = 0;
for (unsigned i = 0; i < tex->num_srcs; i++) {
if (tex->src[i].src_type == nir_tex_src_texture_deref ||
tex->src[i].src_type == nir_tex_src_texture_offset ||
tex->src[i].src_type == nir_tex_src_texture_handle)
num_srcs++;
}
txf = nir_tex_instr_create(b->shader, num_srcs);
txf->op = nir_texop_txf;
txf->coord_components = tex->coord_components;
txf->sampler_dim = tex->sampler_dim;
txf->is_array = tex->is_array;
txf->is_shadow = tex->is_shadow;
txf->is_new_style_shadow = tex->is_new_style_shadow;
txf->texture_index = tex->texture_index;
txf->sampler_index = tex->sampler_index;
txf->can_speculate = tex->can_speculate;
txf->dest_type = tex->dest_type;
unsigned idx = 0;
for (unsigned i = 0; i < tex->num_srcs; i++) {
if (tex->src[i].src_type == nir_tex_src_texture_deref ||
tex->src[i].src_type == nir_tex_src_texture_offset ||
tex->src[i].src_type == nir_tex_src_texture_handle) {
txf->src[idx].src = nir_src_for_ssa(tex->src[i].src.ssa);
txf->src[idx].src_type = tex->src[i].src_type;
idx++;
}
}
nir_def_init(&txf->instr, &txf->def, nir_tex_instr_dest_size(txf), 32);
nir_builder_instr_insert(b, &txf->instr);
return txf;
}
static nir_def *
load_texel(nir_builder *b, nir_tex_instr *tex, wrap_lower_param_t *params)
{
nir_def *texcoord = NULL;
/* Put coordinates back together */
switch (tex->coord_components) {
case 1:
texcoord = params->wrap[0].coords;
break;
case 2:
texcoord = nir_vec2(b, params->wrap[0].coords, params->wrap[1].coords);
break;
case 3:
texcoord = nir_vec3(b, params->wrap[0].coords, params->wrap[1].coords, params->wrap[2].coords);
break;
default:
;
}
texcoord = nir_f2i32(b, texcoord);
nir_tex_instr *load = create_txf_from_tex(b, tex);
nir_tex_instr_add_src(load, nir_tex_src_lod, params->lod);
nir_tex_instr_add_src(load, nir_tex_src_coord, texcoord);
b->cursor = nir_after_instr(&load->instr);
return &load->def;
}
typedef struct {
const dxil_wrap_sampler_state *aws;
float max_bias;
nir_def *size;
int ncoord_comp;
} lod_params;
static nir_def *
evalute_active_lod(nir_builder *b, nir_tex_instr *tex, lod_params *params)
{
static nir_def *lod = NULL;
/* Later we use min_lod for clamping the LOD to a legal value */
float min_lod = MAX2(params->aws->min_lod, 0.0f);
/* Evaluate the LOD to be used for the texel fetch */
if (unlikely(tex->op == nir_texop_txl)) {
int lod_index = nir_tex_instr_src_index(tex, nir_tex_src_lod);
/* if we have an explicite LOD, take it */
lod = tex->src[lod_index].src.ssa;
} else if (unlikely(tex->op == nir_texop_txd)) {
int ddx_index = nir_tex_instr_src_index(tex, nir_tex_src_ddx);
int ddy_index = nir_tex_instr_src_index(tex, nir_tex_src_ddy);
assert(ddx_index >= 0 && ddy_index >= 0);
nir_def *grad = nir_fmax(b,
tex->src[ddx_index].src.ssa,
tex->src[ddy_index].src.ssa);
nir_def *r = nir_fmul(b, grad, nir_i2f32(b, params->size));
nir_def *rho = nir_channel(b, r, 0);
for (int i = 1; i < params->ncoord_comp; ++i)
rho = nir_fmax(b, rho, nir_channel(b, r, i));
lod = nir_flog2(b, rho);
} else if (b->shader->info.stage == MESA_SHADER_FRAGMENT){
lod = dx_get_texture_lod(b, tex);
} else {
/* Only fragment shaders provide the gradient information to evaluate a LOD,
* so force 0 otherwise */
lod = nir_imm_float(b, 0.0);
}
/* Evaluate bias according to OpenGL (4.6 (Compatibility Profile) October 22, 2019),
* sec. 8.14.1, eq. (8.9)
*
* lod' = lambda + CLAMP(bias_texobj + bias_texunit + bias_shader)
*
* bias_texobj is the value of TEXTURE_LOD_BIAS for the bound texture object. ...
* bias_textunt is the value of TEXTURE_LOD_BIAS for the current texture unit, ...
* bias shader is the value of the optional bias parameter in the texture
* lookup functions available to fragment shaders. ... The sum of these values
* is clamped to the range [−bias_max, bias_max] where bias_max is the value
* of the implementation defined constant MAX_TEXTURE_LOD_BIAS.
* In core contexts the value bias_texunit is dropped from above equation.
*
* Gallium provides the value lod_bias as the sum of bias_texobj and bias_texunit
* in compatibility contexts and as bias_texobj in core contexts, hence the
* implementation here is the same in both cases.
*/
nir_def *lod_bias = nir_imm_float(b, params->aws->lod_bias);
if (unlikely(tex->op == nir_texop_txb)) {
int bias_index = nir_tex_instr_src_index(tex, nir_tex_src_bias);
lod_bias = nir_fadd(b, lod_bias, tex->src[bias_index].src.ssa);
}
lod = nir_fadd(b, lod, nir_fclamp(b, lod_bias,
nir_imm_float(b, -params->max_bias),
nir_imm_float(b, params->max_bias)));
/* Clamp lod according to ibid. eq. (8.10) */
lod = nir_fmax(b, lod, nir_imm_float(b, min_lod));
/* If the max lod is > max_bias = log2(max_texture_size), the lod will be clamped
* by the number of levels, no need to clamp it againt the max_lod first. */
if (params->aws->max_lod <= params->max_bias)
lod = nir_fmin(b, lod, nir_imm_float(b, params->aws->max_lod));
/* Pick nearest LOD */
lod = nir_f2i32(b, nir_fround_even(b, lod));
/* cap actual lod by number of available levels */
return nir_imin(b, lod, nir_imm_int(b, params->aws->last_level));
}
static nir_def *
lower_sample_to_txf_for_integer_tex_impl(nir_builder *b, nir_instr *instr,
void *options)
{
sampler_states *states = (sampler_states *)options;
wrap_lower_param_t params = {0};
nir_tex_instr *tex = nir_instr_as_tex(instr);
const static dxil_wrap_sampler_state default_wrap_state = {
{ 0, 0, 0, 1 },
0,
FLT_MIN, FLT_MAX,
0,
{ 0, 0, 0 },
1,
0,
0,
0
};
const dxil_wrap_sampler_state *active_wrap_state = tex->sampler_index < states->n_texture_states ? &states->wrap_states[tex->sampler_index] : &default_wrap_state;
b->cursor = nir_before_instr(instr);
int coord_index = nir_tex_instr_src_index(tex, nir_tex_src_coord);
nir_def *old_coord = tex->src[coord_index].src.ssa;
params.ncoord_comp = tex->coord_components;
if (tex->is_array)
params.ncoord_comp -= 1;
/* This helper to get the texture size always uses LOD 0, and DirectX doesn't support
* giving another LOD when querying the texture size */
nir_def *size0 = nir_get_texture_size(b, tex);
params.lod = nir_imm_int(b, 0);
if (active_wrap_state->last_level > 0) {
lod_params p = {
.aws = active_wrap_state,
.max_bias = states->max_bias,
.size = size0,
.ncoord_comp = params.ncoord_comp
};
params.lod = evalute_active_lod(b, tex, &p);
/* Evaluate actual level size*/
params.size = nir_i2f32(b, nir_imax(b, nir_ishr(b, size0, params.lod),
nir_imm_int(b, 1)));
} else {
params.size = nir_i2f32(b, size0);
}
nir_def *new_coord = old_coord;
if (!active_wrap_state->is_nonnormalized_coords) {
/* Evaluate the integer lookup coordinates for the requested LOD, don't touch the
* array index */
if (!tex->is_array) {
new_coord = nir_fmul(b, params.size, old_coord);
} else {
nir_def *array_index = nir_channel(b, old_coord, params.ncoord_comp);
int mask = (1 << params.ncoord_comp) - 1;
nir_def *coord = nir_fmul(b, nir_channels(b, params.size, mask),
nir_channels(b, old_coord, mask));
switch (params.ncoord_comp) {
case 1:
new_coord = nir_vec2(b, coord, array_index);
break;
case 2:
new_coord = nir_vec3(b, nir_channel(b, coord, 0),
nir_channel(b, coord, 1),
array_index);
break;
default:
UNREACHABLE("unsupported number of non-array coordinates");
}
}
}
nir_def *coord_help[3];
for (int i = 0; i < params.ncoord_comp; ++i)
coord_help[i] = nir_ffloor(b, nir_channel(b, new_coord, i));
// Note: array index needs to be rounded to nearest before clamp rather than floored
if (tex->is_array)
coord_help[params.ncoord_comp] = nir_fround_even(b, nir_channel(b, new_coord, params.ncoord_comp));
/* Correct the texture coordinates for the offsets. */
int offset_index = nir_tex_instr_src_index(tex, nir_tex_src_offset);
if (offset_index >= 0) {
nir_def *offset = tex->src[offset_index].src.ssa;
for (int i = 0; i < params.ncoord_comp; ++i)
coord_help[i] = nir_fadd(b, coord_help[i], nir_i2f32(b, nir_channel(b, offset, i)));
}
nir_def *use_border_color = nir_imm_false(b);
if (!active_wrap_state->skip_boundary_conditions) {
for (int i = 0; i < params.ncoord_comp; ++i) {
params.wrap[i] = wrap_coords(b, coord_help[i], active_wrap_state->wrap[i], nir_channel(b, params.size, i));
use_border_color = nir_ior(b, use_border_color, params.wrap[i].use_border_color);
}
if (tex->is_array)
params.wrap[params.ncoord_comp] =
wrap_coords(b, coord_help[params.ncoord_comp],
DXIL_TEX_WRAP_CLAMP_TO_EDGE,
nir_i2f32(b, nir_channel(b, size0, params.ncoord_comp)));
} else {
/* When we emulate a cube map by using a texture array, the coordinates are always
* in range, and we don't have to take care of boundary conditions */
for (unsigned i = 0; i < 3; ++i) {
params.wrap[i].coords = coord_help[i];
params.wrap[i].use_border_color = nir_imm_false(b);
}
}
const dxil_texture_swizzle_state one2one = {
PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W
};
nir_if *border_if = nir_push_if(b, use_border_color);
const dxil_texture_swizzle_state *swizzle = (states->tex_swizzles && tex->sampler_index < states->n_texture_states) ?
&states->tex_swizzles[tex->sampler_index]:
&one2one;
nir_def *border_color = load_bordercolor(b, tex, active_wrap_state, swizzle);
nir_if *border_else = nir_push_else(b, border_if);
nir_def *sampler_color = load_texel(b, tex, &params);
nir_pop_if(b, border_else);
return nir_if_phi(b, border_color, sampler_color);
}
/* Sampling from integer textures is not allowed in DirectX, so we have
* to use texel fetches. For this we have to scale the coordiantes
* to be integer based, and evaluate the LOD the texel fetch has to be
* applied on, and take care of the boundary conditions .
*/
bool
dxil_lower_sample_to_txf_for_integer_tex(nir_shader *s,
unsigned n_texture_states,
dxil_wrap_sampler_state *wrap_states,
dxil_texture_swizzle_state *tex_swizzles,
float max_bias)
{
sampler_states states = { n_texture_states, wrap_states, tex_swizzles, max_bias};
bool result =
nir_shader_lower_instructions(s,
lower_sample_to_txf_for_integer_tex_filter,
lower_sample_to_txf_for_integer_tex_impl,
&states);
return result;
}
@@ -0,0 +1,75 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef DXIL_NIR_LOWER_INT_SAMPLERS_H
#define DXIL_NIR_LOWER_INT_SAMPLERS_H
#include "nir.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
unsigned swizzle_r:3;
unsigned swizzle_g:3;
unsigned swizzle_b:3;
unsigned swizzle_a:3;
} dxil_texture_swizzle_state;
enum dxil_tex_wrap {
DXIL_TEX_WRAP_REPEAT,
DXIL_TEX_WRAP_CLAMP,
DXIL_TEX_WRAP_CLAMP_TO_EDGE,
DXIL_TEX_WRAP_CLAMP_TO_BORDER,
DXIL_TEX_WRAP_MIRROR_REPEAT,
DXIL_TEX_WRAP_MIRROR_CLAMP,
DXIL_TEX_WRAP_MIRROR_CLAMP_TO_EDGE,
DXIL_TEX_WRAP_MIRROR_CLAMP_TO_BORDER,
};
typedef struct {
float border_color[4];
float lod_bias;
float min_lod, max_lod;
int last_level;
uint8_t wrap[3]; /* enum dxil_tex_wrap */
uint8_t is_int_sampler:1;
uint8_t is_nonnormalized_coords:1;
uint8_t is_linear_filtering:1;
uint8_t skip_boundary_conditions:1;
uint8_t unused:4;
} dxil_wrap_sampler_state;
bool
dxil_lower_sample_to_txf_for_integer_tex(nir_shader *s,
unsigned n_texture_states,
dxil_wrap_sampler_state *wrap_states,
dxil_texture_swizzle_state *tex_swizzles,
float max_bias);
#ifdef __cplusplus
}
#endif
#endif // DXIL_NIR_LOWER_INT_SAMPLERS_H
@@ -0,0 +1,167 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "dxil_nir.h"
#include "nir_builder.h"
#include "nir_builtin_builder.h"
static enum pipe_format
get_input_target_format(nir_variable *var, const void *options)
{
enum pipe_format *target_formats = (enum pipe_format *)options;
return target_formats[var->data.driver_location];
}
static bool
lower_vs_vertex_conversion_filter(const nir_instr *instr, const void *options)
{
if (instr->type != nir_instr_type_intrinsic)
return false;
nir_intrinsic_instr *inst = nir_instr_as_intrinsic(instr);
if (inst->intrinsic != nir_intrinsic_load_deref)
return false;
nir_variable *var = nir_intrinsic_get_var(inst, 0);
return (var->data.mode == nir_var_shader_in) &&
(get_input_target_format(var, options) != PIPE_FORMAT_NONE);
}
typedef nir_def *
(*shift_right_func)(nir_builder *build, nir_def *src0, nir_def *src1);
/* decoding the signed vs unsigned scaled format is handled
* by applying the signed or unsigned shift right function
* accordingly */
static nir_def *
from_10_10_10_2_scaled(nir_builder *b, nir_def *src,
nir_def *lshift, shift_right_func shr)
{
nir_def *rshift = nir_imm_ivec4(b, 22, 22, 22, 30);
return nir_i2f32(b, shr(b, nir_ishl(b, src, lshift), rshift));
}
static nir_def *
from_10_10_10_2_snorm(nir_builder *b, nir_def *src, nir_def *lshift)
{
nir_def *split = from_10_10_10_2_scaled(b, src, lshift, nir_ishr);
nir_def *scale_rgb = nir_imm_vec4(b,
1.0f / 0x1ff,
1.0f / 0x1ff,
1.0f / 0x1ff,
1.0f);
return nir_fmul(b, split, scale_rgb);
}
static nir_def *
from_10_10_10_2_unorm(nir_builder *b, nir_def *src, nir_def *lshift)
{
nir_def *split = from_10_10_10_2_scaled(b, src, lshift, nir_ushr);
nir_def *scale_rgb = nir_imm_vec4(b,
1.0f / 0x3ff,
1.0f / 0x3ff,
1.0f / 0x3ff,
1.0f / 3.0f);
return nir_fmul(b, split, scale_rgb);
}
inline static nir_def *
lshift_rgba(nir_builder *b)
{
return nir_imm_ivec4(b, 22, 12, 2, 0);
}
inline static nir_def *
lshift_bgra(nir_builder *b)
{
return nir_imm_ivec4(b, 2, 12, 22, 0);
}
static nir_def *
lower_vs_vertex_conversion_impl(nir_builder *b, nir_instr *instr, void *options)
{
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
nir_variable *var = nir_intrinsic_get_var(intr, 0);
enum pipe_format fmt = get_input_target_format(var, options);
if (!util_format_has_alpha(fmt)) {
/* these formats need the alpha channel replaced with 1: */
assert(fmt == PIPE_FORMAT_R8G8B8_SINT ||
fmt == PIPE_FORMAT_R8G8B8_UINT ||
fmt == PIPE_FORMAT_R16G16B16_SINT ||
fmt == PIPE_FORMAT_R16G16B16_UINT);
if (intr->def.num_components == 3)
return NULL;
return nir_vector_insert_imm(b, &intr->def, nir_imm_int(b, 1), 3);
} else {
nir_def *src = nir_channel(b, &intr->def, 0);
switch (fmt) {
case PIPE_FORMAT_R10G10B10A2_SNORM:
return from_10_10_10_2_snorm(b, src, lshift_rgba(b));
case PIPE_FORMAT_B10G10R10A2_SNORM:
return from_10_10_10_2_snorm(b, src, lshift_bgra(b));
case PIPE_FORMAT_B10G10R10A2_UNORM:
return from_10_10_10_2_unorm(b, src, lshift_bgra(b));
case PIPE_FORMAT_R10G10B10A2_SSCALED:
return from_10_10_10_2_scaled(b, src, lshift_rgba(b), nir_ishr);
case PIPE_FORMAT_B10G10R10A2_SSCALED:
return from_10_10_10_2_scaled(b, src, lshift_bgra(b), nir_ishr);
case PIPE_FORMAT_R10G10B10A2_USCALED:
return from_10_10_10_2_scaled(b, src, lshift_rgba(b), nir_ushr);
case PIPE_FORMAT_B10G10R10A2_USCALED:
return from_10_10_10_2_scaled(b, src, lshift_bgra(b), nir_ushr);
case PIPE_FORMAT_R8G8B8A8_USCALED:
case PIPE_FORMAT_R16G16B16A16_USCALED:
return nir_u2f32(b, &intr->def);
case PIPE_FORMAT_R8G8B8A8_SSCALED:
case PIPE_FORMAT_R16G16B16A16_SSCALED:
return nir_i2f32(b, &intr->def);
default:
UNREACHABLE("Unsupported emulated vertex format");
}
}
}
/* Lower emulated vertex attribute input
* The vertex attributes are passed as R32_UINT that needs to be converted
* to one of the RGB10A2 formats that need to be emulated.
*
* @param target_formats contains the per attribute format to convert to
* or PIPE_FORMAT_NONE if no conversion is needed
*/
bool
dxil_nir_lower_vs_vertex_conversion(nir_shader *s,
enum pipe_format target_formats[])
{
assert(s->info.stage == MESA_SHADER_VERTEX);
bool result =
nir_shader_lower_instructions(s,
lower_vs_vertex_conversion_filter,
lower_vs_vertex_conversion_impl,
target_formats);
return result;
}
+409
View File
@@ -0,0 +1,409 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "nir.h"
#include "nir_builder.h"
#include "nir_control_flow.h"
#include "dxil_nir.h"
static bool
is_memory_barrier_tcs_patch(const nir_intrinsic_instr *intr)
{
if (intr->intrinsic == nir_intrinsic_barrier &&
nir_intrinsic_memory_modes(intr) & nir_var_shader_out) {
assert(nir_intrinsic_memory_modes(intr) == nir_var_shader_out);
assert(nir_intrinsic_memory_scope(intr) == SCOPE_WORKGROUP || nir_intrinsic_memory_scope(intr) == SCOPE_INVOCATION);
return true;
} else {
return false;
}
}
static void
remove_hs_intrinsics(nir_function_impl *impl)
{
nir_foreach_block(block, impl) {
nir_foreach_instr_safe(instr, block) {
if (instr->type != nir_instr_type_intrinsic)
continue;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
if (intr->intrinsic == nir_intrinsic_load_output ||
intr->intrinsic == nir_intrinsic_load_per_vertex_output) {
nir_builder b = nir_builder_at(nir_before_instr(&intr->instr));
nir_def_rewrite_uses(&intr->def, nir_undef(&b, intr->def.num_components, intr->def.bit_size));
} else if (intr->intrinsic != nir_intrinsic_store_output &&
!is_memory_barrier_tcs_patch(intr)) {
continue;
}
nir_instr_remove(instr);
}
}
nir_progress(true, impl, nir_metadata_control_flow);
}
static void
add_instr_and_srcs_to_set(struct set *instr_set, nir_instr *instr);
static bool
add_srcs_to_set(nir_src *src, void *state)
{
add_instr_and_srcs_to_set(state, nir_def_instr(src->ssa));
return true;
}
static void
add_instr_and_srcs_to_set(struct set *instr_set, nir_instr *instr)
{
bool was_already_found = false;
_mesa_set_search_or_add(instr_set, instr, &was_already_found);
if (!was_already_found)
nir_foreach_src(instr, add_srcs_to_set, instr_set);
}
static void
prune_patch_function_to_intrinsic_and_srcs(nir_function_impl *impl)
{
struct set *instr_set = _mesa_pointer_set_create(NULL);
/* Do this in two phases:
* 1. Find all instructions that contribute to a store_output and add them to
* the set. Also, add instructions that contribute to control flow.
* 2. Erase every instruction that isn't in the set
*/
nir_foreach_block(block, impl) {
nir_if *following_if = nir_block_get_following_if(block);
if (following_if) {
add_instr_and_srcs_to_set(instr_set, nir_def_instr(following_if->condition.ssa));
}
nir_foreach_instr_safe(instr, block) {
if (instr->type == nir_instr_type_intrinsic) {
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
if (intr->intrinsic != nir_intrinsic_store_output &&
!is_memory_barrier_tcs_patch(intr))
continue;
} else if (instr->type != nir_instr_type_jump)
continue;
add_instr_and_srcs_to_set(instr_set, instr);
}
}
nir_foreach_block_reverse(block, impl) {
nir_foreach_instr_reverse_safe(instr, block) {
struct set_entry *entry = _mesa_set_search(instr_set, instr);
if (!entry)
nir_instr_remove(instr);
}
}
_mesa_set_destroy(instr_set, NULL);
}
static nir_cursor
get_cursor_for_instr_without_cf(nir_instr *instr)
{
nir_block *block = instr->block;
if (block->cf_node.parent->type == nir_cf_node_function)
return nir_before_instr(instr);
do {
block = nir_cf_node_as_block(nir_cf_node_prev(block->cf_node.parent));
} while (block->cf_node.parent->type != nir_cf_node_function);
return nir_after_block_before_jump(block);
}
struct tcs_patch_loop_state {
nir_def *deref, *count;
nir_cursor begin_cursor, end_cursor, insert_cursor;
nir_loop *loop;
};
static void
start_tcs_loop(nir_builder *b, struct tcs_patch_loop_state *state, nir_deref_instr *loop_var_deref)
{
if (!loop_var_deref)
return;
nir_store_deref(b, loop_var_deref, nir_imm_int(b, 0), 1);
state->loop = nir_push_loop(b);
state->count = nir_load_deref(b, loop_var_deref);
nir_break_if(b, nir_ige_imm(b, state->count, b->impl->function->shader->info.tess.tcs_vertices_out));
state->insert_cursor = b->cursor;
nir_store_deref(b, loop_var_deref, nir_iadd_imm(b, state->count, 1), 1);
nir_pop_loop(b, state->loop);
}
static void
end_tcs_loop(nir_builder *b, struct tcs_patch_loop_state *state)
{
if (!state->loop)
return;
nir_cf_list extracted;
nir_cf_extract(&extracted, state->begin_cursor, state->end_cursor);
nir_cf_reinsert(&extracted, state->insert_cursor);
*state = (struct tcs_patch_loop_state ){ 0 };
}
/* In HLSL/DXIL, the hull (tesselation control) shader is split into two:
* 1. The main hull shader, which runs once per output control point.
* 2. A patch constant function, which runs once overall.
* In GLSL/NIR, these are combined. Each invocation must write to the output
* array with a constant gl_InvocationID, which is (apparently) lowered to an
* if/else ladder in nir. Each invocation must write the same value to patch
* constants - or else undefined behavior strikes. NIR uses store_output to
* write the patch constants, and store_per_vertex_output to write the control
* point values.
*
* We clone the NIR function to produce 2: one with the store_output intrinsics
* removed, which becomes the main shader (only writes control points), and one
* with everything that doesn't contribute to store_output removed, which becomes
* the patch constant function.
*
* For the patch constant function, if the expressions rely on gl_InvocationID,
* then we need to run the resulting logic in a loop, using the loop counter to
* replace gl_InvocationID. This loop can be terminated when a barrier is hit. If
* gl_InvocationID is used again after the barrier, then another loop needs to begin.
*/
bool
dxil_nir_split_tess_ctrl(nir_shader *nir, nir_function **patch_const_func)
{
assert(nir->info.stage == MESA_SHADER_TESS_CTRL);
assert(exec_list_length(&nir->functions) == 1);
nir_function_impl *entrypoint = nir_shader_get_entrypoint(nir);
*patch_const_func = nir_function_create(nir, "PatchConstantFunc");
nir_function_impl *patch_const_func_impl = nir_function_impl_clone(nir, entrypoint);
nir_function_set_impl(*patch_const_func, patch_const_func_impl);
remove_hs_intrinsics(entrypoint);
prune_patch_function_to_intrinsic_and_srcs(patch_const_func_impl);
/* Kill dead references to the invocation ID from the patch const func so we don't
* insert unnecessarily loops
*/
bool progress;
do {
progress = false;
progress |= nir_opt_dead_cf(nir);
progress |= nir_opt_dce(nir);
} while (progress);
/* Now, the patch constant function needs to be split into blocks and loops.
* The series of instructions up to the first block containing a load_invocation_id
* will run sequentially. Then a loop is inserted so load_invocation_id will load the
* loop counter. This loop continues until a barrier is reached, when the loop
* is closed and the process begins again.
*
* First, sink load_invocation_id so that each use has its own local load.
* This ensures the load sits in the same pre/post-barrier region as its
* use, which the loop-wrapping pass below relies on — even for single-use
* loads whose use sits across a barrier.
*/
nir_builder b = nir_builder_create(patch_const_func_impl);
nir_foreach_block(block, patch_const_func_impl) {
nir_foreach_instr_safe(instr, block) {
if (instr->type != nir_instr_type_intrinsic)
continue;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
if (intr->intrinsic != nir_intrinsic_load_invocation_id ||
list_is_empty(&intr->def.uses))
continue;
nir_foreach_use_including_if_safe(src, &intr->def) {
b.cursor = nir_before_src(src);
nir_src_rewrite(src, nir_load_invocation_id(&b));
}
nir_instr_remove(instr);
}
}
/* Now replace those invocation ID loads with loads of a local variable that's used as a loop counter */
nir_variable *loop_var = NULL;
nir_deref_instr *loop_var_deref = NULL;
struct tcs_patch_loop_state state = { 0 };
nir_foreach_block_safe(block, patch_const_func_impl) {
nir_foreach_instr_safe(instr, block) {
if (instr->type != nir_instr_type_intrinsic)
continue;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
switch (intr->intrinsic) {
case nir_intrinsic_load_invocation_id: {
if (!loop_var) {
loop_var = nir_local_variable_create(patch_const_func_impl, glsl_int_type(), "PatchConstInvocId");
b.cursor = nir_before_impl(patch_const_func_impl);
loop_var_deref = nir_build_deref_var(&b, loop_var);
}
if (!state.loop) {
b.cursor = state.begin_cursor = get_cursor_for_instr_without_cf(instr);
start_tcs_loop(&b, &state, loop_var_deref);
}
nir_def_rewrite_uses(&intr->def, state.count);
break;
}
case nir_intrinsic_barrier:
if (!is_memory_barrier_tcs_patch(intr))
break;
/* The GL tessellation spec says:
* The barrier() function may only be called inside the main entry point of the tessellation control shader
* and may not be called in potentially divergent flow control. In particular, barrier() may not be called
* inside a switch statement, in either sub-statement of an if statement, inside a do, for, or while loop,
* or at any point after a return statement in the function main().
*
* Therefore, we should be at function-level control flow.
*/
assert(nir_cursors_equal(nir_before_instr(instr), get_cursor_for_instr_without_cf(instr)));
state.end_cursor = nir_before_instr(instr);
end_tcs_loop(&b, &state);
nir_instr_remove(instr);
break;
default:
break;
}
}
}
state.end_cursor = nir_after_block_before_jump(nir_impl_last_block(patch_const_func_impl));
end_tcs_loop(&b, &state);
//TODO: this isn't correct if the def isn't loop invariant
/* If we have more than one loop, SSA needs to be repaired for one loop to use defs from another. */
if (loop_var)
nir_repair_ssa_impl(patch_const_func_impl);
nir_progress(true, patch_const_func_impl, nir_metadata_none);
nir_progress(true, entrypoint, nir_metadata_none);
return true;
}
struct remove_tess_level_accesses_data {
unsigned location;
unsigned size;
};
static bool
remove_tess_level_accesses(nir_builder *b, nir_instr *instr, void *_data)
{
struct remove_tess_level_accesses_data *data = _data;
if (instr->type != nir_instr_type_intrinsic)
return false;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
if (intr->intrinsic != nir_intrinsic_store_output &&
intr->intrinsic != nir_intrinsic_load_input)
return false;
nir_io_semantics io = nir_intrinsic_io_semantics(intr);
if (io.location != data->location)
return false;
if (nir_intrinsic_component(intr) < data->size)
return false;
if (intr->intrinsic == nir_intrinsic_store_output) {
assert(nir_src_num_components(intr->src[0]) == 1);
nir_instr_remove(instr);
} else {
b->cursor = nir_after_instr(instr);
assert(intr->def.num_components == 1);
nir_def_rewrite_uses(&intr->def, nir_undef(b, 1, intr->def.bit_size));
}
return true;
}
/* Update the types of the tess level variables and remove writes to removed components.
* GL always has a 4-component outer tess level and 2-component inner, while D3D requires
* the number of components to vary based on the primitive mode.
* The 4 and 2 is for quads, while triangles are 3 and 1, and lines are 2 and 0.
*/
bool
dxil_nir_fixup_tess_level_for_domain(nir_shader *nir)
{
bool progress = false;
if (nir->info.tess._primitive_mode != TESS_PRIMITIVE_QUADS) {
nir_foreach_variable_with_modes_safe(var, nir, nir_var_shader_out | nir_var_shader_in) {
unsigned new_array_size = 4;
unsigned old_array_size = glsl_array_size(var->type);
if (var->data.location == VARYING_SLOT_TESS_LEVEL_OUTER) {
new_array_size = nir->info.tess._primitive_mode == TESS_PRIMITIVE_TRIANGLES ? 3 : 2;
assert(var->data.compact && (old_array_size == 4 || old_array_size == new_array_size));
} else if (var->data.location == VARYING_SLOT_TESS_LEVEL_INNER) {
new_array_size = nir->info.tess._primitive_mode == TESS_PRIMITIVE_TRIANGLES ? 1 : 0;
assert(var->data.compact && (old_array_size == 2 || old_array_size == new_array_size));
} else
continue;
if (new_array_size == old_array_size)
continue;
progress = true;
if (new_array_size)
var->type = glsl_array_type(glsl_float_type(), new_array_size, 0);
else {
exec_node_remove(&var->node);
ralloc_free(var);
}
struct remove_tess_level_accesses_data pass_data = {
.location = var->data.location,
.size = new_array_size
};
nir_shader_instructions_pass(nir, remove_tess_level_accesses,
nir_metadata_control_flow, &pass_data);
}
}
return progress;
}
static bool
tcs_update_deref_input_types(nir_builder *b, nir_instr *instr, void *data)
{
if (instr->type != nir_instr_type_deref)
return false;
nir_deref_instr *deref = nir_instr_as_deref(instr);
if (deref->deref_type != nir_deref_type_var)
return false;
nir_variable *var = deref->var;
deref->type = var->type;
return true;
}
bool
dxil_nir_set_tcs_patches_in(nir_shader *nir, unsigned num_control_points)
{
bool progress = false;
nir_foreach_variable_with_modes(var, nir, nir_var_shader_in) {
if (nir_is_arrayed_io(var, MESA_SHADER_TESS_CTRL)) {
var->type = glsl_array_type(glsl_get_array_element(var->type), num_control_points, 0);
progress = true;
}
}
if (progress)
nir_shader_instructions_pass(nir, tcs_update_deref_input_types, nir_metadata_all, NULL);
return progress;
}
+897
View File
@@ -0,0 +1,897 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_signature.h"
#include "dxil_enums.h"
#include "dxil_module.h"
#include "glsl_types.h"
#include "nir_to_dxil.h"
#include "util/u_debug.h"
#include <string.h>
struct semantic_info {
enum dxil_semantic_kind kind;
char name[64];
int index;
enum dxil_prog_sig_comp_type comp_type;
uint8_t sig_comp_type;
int32_t start_row;
int32_t rows;
uint8_t start_col;
uint8_t cols;
uint8_t interpolation;
uint8_t stream;
const char *sysvalue_name;
};
static bool
is_depth_output(enum dxil_semantic_kind kind)
{
return kind == DXIL_SEM_DEPTH || kind == DXIL_SEM_DEPTH_GE ||
kind == DXIL_SEM_DEPTH_LE || kind == DXIL_SEM_STENCIL_REF;
}
static uint8_t
get_interpolation(nir_variable *var)
{
if (var->data.patch)
return DXIL_INTERP_UNDEFINED;
if (glsl_type_is_integer(glsl_without_array_or_matrix(var->type)) ||
glsl_type_is_64bit(glsl_without_array_or_matrix(var->type)))
return DXIL_INTERP_CONSTANT;
if (var->data.sample) {
if (var->data.location == VARYING_SLOT_POS)
return DXIL_INTERP_LINEAR_NOPERSPECTIVE_SAMPLE;
switch (var->data.interpolation) {
case INTERP_MODE_NONE: return DXIL_INTERP_LINEAR_SAMPLE;
case INTERP_MODE_FLAT: return DXIL_INTERP_CONSTANT;
case INTERP_MODE_NOPERSPECTIVE: return DXIL_INTERP_LINEAR_NOPERSPECTIVE_SAMPLE;
case INTERP_MODE_SMOOTH: return DXIL_INTERP_LINEAR_SAMPLE;
}
} else if (unlikely(var->data.centroid)) {
if (var->data.location == VARYING_SLOT_POS)
return DXIL_INTERP_LINEAR_NOPERSPECTIVE_CENTROID;
switch (var->data.interpolation) {
case INTERP_MODE_NONE: return DXIL_INTERP_LINEAR_CENTROID;
case INTERP_MODE_FLAT: return DXIL_INTERP_CONSTANT;
case INTERP_MODE_NOPERSPECTIVE: return DXIL_INTERP_LINEAR_NOPERSPECTIVE_CENTROID;
case INTERP_MODE_SMOOTH: return DXIL_INTERP_LINEAR_CENTROID;
}
} else {
if (var->data.location == VARYING_SLOT_POS)
return DXIL_INTERP_LINEAR_NOPERSPECTIVE;
switch (var->data.interpolation) {
case INTERP_MODE_NONE: return DXIL_INTERP_LINEAR;
case INTERP_MODE_FLAT: return DXIL_INTERP_CONSTANT;
case INTERP_MODE_NOPERSPECTIVE: return DXIL_INTERP_LINEAR_NOPERSPECTIVE;
case INTERP_MODE_SMOOTH: return DXIL_INTERP_LINEAR;
}
}
return DXIL_INTERP_LINEAR;
}
static const char *
in_sysvalue_name(nir_variable *var)
{
switch (var->data.location) {
case VARYING_SLOT_POS:
return "POS";
case VARYING_SLOT_FACE:
return "FACE";
case VARYING_SLOT_LAYER:
return "RTINDEX";
default:
return "NONE";
}
}
/*
* The signatures are written into the stream in two pieces:
* DxilProgramSignatureElement is a fixes size structure that gets dumped
* to the stream in order of the registers and each contains an offset
* to the semantic name string. Then these strings are dumped into the stream.
*/
static unsigned
get_additional_semantic_info(nir_shader *s, nir_variable *var, struct semantic_info *info,
unsigned next_row, unsigned clip_size)
{
const struct glsl_type *type = var->type;
if (nir_is_arrayed_io(var, s->info.stage))
type = glsl_get_array_element(type);
info->comp_type = dxil_get_prog_sig_comp_type(type);
info->sig_comp_type = dxil_get_comp_type_from_prog_sig_type(info->comp_type);
bool is_depth = is_depth_output(info->kind);
bool is_gs_input = s->info.stage == MESA_SHADER_GEOMETRY &&
(var->data.mode & (nir_var_shader_in | nir_var_system_value));
info->stream = var->data.stream;
info->rows = 1;
if (info->kind == DXIL_SEM_TARGET) {
info->start_row = info->index;
info->cols = 4;
} else if (is_depth ||
(info->kind == DXIL_SEM_PRIMITIVE_ID && is_gs_input) ||
info->kind == DXIL_SEM_COVERAGE ||
info->kind == DXIL_SEM_SAMPLE_INDEX) {
// This turns into a 'N/A' mask in the disassembly
info->start_row = -1;
info->cols = 1;
} else if (info->kind == DXIL_SEM_TESS_FACTOR ||
info->kind == DXIL_SEM_INSIDE_TESS_FACTOR) {
assert(var->data.compact);
info->start_row = next_row;
info->rows = glsl_get_aoa_size(type);
info->cols = 1;
next_row += info->rows;
} else if (var->data.compact) {
info->start_row = next_row;
next_row++;
assert(glsl_type_is_array(type) && info->kind == DXIL_SEM_CLIP_DISTANCE);
unsigned num_floats = glsl_get_aoa_size(type);
unsigned start_offset = (var->data.location - VARYING_SLOT_CLIP_DIST0) * 4 +
var->data.location_frac;
if (start_offset >= clip_size) {
info->kind = DXIL_SEM_CULL_DISTANCE;
snprintf(info->name, 64, "SV_CullDistance");
}
info->cols = num_floats;
info->start_col = (uint8_t)var->data.location_frac;
} else {
info->start_row = next_row;
info->rows = glsl_count_vec4_slots(type, false, false);
if (glsl_type_is_array(type))
type = glsl_get_array_element(type);
next_row += info->rows;
info->start_col = (uint8_t)var->data.location_frac;
info->cols = MIN2(glsl_get_component_slots(type), 4);
}
return next_row;
}
typedef void (*semantic_info_proc)(nir_variable *var, struct semantic_info *info, mesa_shader_stage stage);
static void
get_semantic_vs_in_name(nir_variable *var, struct semantic_info *info, mesa_shader_stage stage)
{
strcpy(info->name, "TEXCOORD");
info->index = var->data.driver_location;
info->kind = DXIL_SEM_ARBITRARY;
}
static void
get_semantic_sv_name(nir_variable *var, struct semantic_info *info, mesa_shader_stage stage)
{
if (stage != MESA_SHADER_VERTEX)
info->interpolation = get_interpolation(var);
switch (var->data.location) {
case SYSTEM_VALUE_VERTEX_ID_ZERO_BASE:
info->kind = DXIL_SEM_VERTEX_ID;
break;
case SYSTEM_VALUE_INSTANCE_ID:
info->kind = DXIL_SEM_INSTANCE_ID;
break;
case SYSTEM_VALUE_PRIMITIVE_ID:
info->kind = DXIL_SEM_PRIMITIVE_ID;
break;
case SYSTEM_VALUE_SAMPLE_ID:
info->kind = DXIL_SEM_SAMPLE_INDEX;
break;
default:
UNREACHABLE("unsupported system value");
}
strncpy(info->name, var->name, ARRAY_SIZE(info->name) - 1);
}
static void
get_semantic_ps_outname(nir_variable *var, struct semantic_info *info)
{
info->kind = DXIL_SEM_INVALID;
switch (var->data.location) {
case FRAG_RESULT_COLOR:
snprintf(info->name, 64, "%s", "SV_Target");
info->index = var->data.index;
info->kind = DXIL_SEM_TARGET;
break;
case FRAG_RESULT_DATA0:
case FRAG_RESULT_DATA1:
case FRAG_RESULT_DATA2:
case FRAG_RESULT_DATA3:
case FRAG_RESULT_DATA4:
case FRAG_RESULT_DATA5:
case FRAG_RESULT_DATA6:
case FRAG_RESULT_DATA7:
snprintf(info->name, 64, "%s", "SV_Target");
info->index = var->data.location - FRAG_RESULT_DATA0;
if (var->data.location == FRAG_RESULT_DATA0 &&
var->data.index > 0)
info->index = var->data.index;
info->kind = DXIL_SEM_TARGET;
break;
case FRAG_RESULT_DEPTH:
snprintf(info->name, 64, "%s", "SV_Depth");
info->kind = DXIL_SEM_DEPTH;
break;
case FRAG_RESULT_STENCIL:
snprintf(info->name, 64, "%s", "SV_StencilRef");
info->kind = DXIL_SEM_STENCIL_REF; //??
break;
case FRAG_RESULT_SAMPLE_MASK:
snprintf(info->name, 64, "%s", "SV_Coverage");
info->kind = DXIL_SEM_COVERAGE; //??
break;
default:
snprintf(info->name, 64, "%s", "UNDEFINED");
break;
}
}
static void
get_semantic_name(nir_variable *var, struct semantic_info *info,
const struct glsl_type *type)
{
info->kind = DXIL_SEM_INVALID;
info->interpolation = get_interpolation(var);
switch (var->data.location) {
case VARYING_SLOT_POS:
assert(glsl_get_components(type) == 4);
snprintf(info->name, 64, "%s", "SV_Position");
info->kind = DXIL_SEM_POSITION;
break;
case VARYING_SLOT_FACE:
assert(glsl_get_components(type) == 1);
snprintf(info->name, 64, "%s", "SV_IsFrontFace");
info->kind = DXIL_SEM_IS_FRONT_FACE;
break;
case VARYING_SLOT_PRIMITIVE_ID:
assert(glsl_get_components(type) == 1);
snprintf(info->name, 64, "%s", "SV_PrimitiveID");
info->kind = DXIL_SEM_PRIMITIVE_ID;
break;
case VARYING_SLOT_CLIP_DIST1:
info->index = 1;
FALLTHROUGH;
case VARYING_SLOT_CLIP_DIST0:
assert(var->data.location == VARYING_SLOT_CLIP_DIST1 || info->index == 0);
snprintf(info->name, 64, "%s", "SV_ClipDistance");
info->kind = DXIL_SEM_CLIP_DISTANCE;
break;
case VARYING_SLOT_TESS_LEVEL_INNER:
assert(glsl_get_components(type) <= 2);
snprintf(info->name, 64, "%s", "SV_InsideTessFactor");
info->kind = DXIL_SEM_INSIDE_TESS_FACTOR;
break;
case VARYING_SLOT_TESS_LEVEL_OUTER:
assert(glsl_get_components(type) <= 4);
snprintf(info->name, 64, "%s", "SV_TessFactor");
info->kind = DXIL_SEM_TESS_FACTOR;
break;
case VARYING_SLOT_VIEWPORT:
assert(glsl_get_components(type) == 1);
snprintf(info->name, 64, "%s", "SV_ViewportArrayIndex");
info->kind = DXIL_SEM_VIEWPORT_ARRAY_INDEX;
break;
case VARYING_SLOT_LAYER:
assert(glsl_get_components(type) == 1);
snprintf(info->name, 64, "%s", "SV_RenderTargetArrayIndex");
info->kind = DXIL_SEM_RENDERTARGET_ARRAY_INDEX;
break;
default: {
info->index = var->data.driver_location;
strcpy(info->name, "TEXCOORD");
info->kind = DXIL_SEM_ARBITRARY;
}
}
}
static void
get_semantic_in_name(nir_variable *var, struct semantic_info *info, mesa_shader_stage stage)
{
const struct glsl_type *type = var->type;
if (nir_is_arrayed_io(var, stage) &&
glsl_type_is_array(type))
type = glsl_get_array_element(type);
get_semantic_name(var, info, type);
info->sysvalue_name = in_sysvalue_name(var);
}
static enum dxil_prog_sig_semantic
prog_semantic_from_kind(enum dxil_semantic_kind kind, unsigned num_vals, unsigned start_val)
{
switch (kind) {
case DXIL_SEM_ARBITRARY: return DXIL_PROG_SEM_UNDEFINED;
case DXIL_SEM_VERTEX_ID: return DXIL_PROG_SEM_VERTEX_ID;
case DXIL_SEM_INSTANCE_ID: return DXIL_PROG_SEM_INSTANCE_ID;
case DXIL_SEM_POSITION: return DXIL_PROG_SEM_POSITION;
case DXIL_SEM_COVERAGE: return DXIL_PROG_SEM_COVERAGE;
case DXIL_SEM_INNER_COVERAGE: return DXIL_PROG_SEM_INNER_COVERAGE;
case DXIL_SEM_PRIMITIVE_ID: return DXIL_PROG_SEM_PRIMITIVE_ID;
case DXIL_SEM_SAMPLE_INDEX: return DXIL_PROG_SEM_SAMPLE_INDEX;
case DXIL_SEM_IS_FRONT_FACE: return DXIL_PROG_SEM_IS_FRONTFACE;
case DXIL_SEM_RENDERTARGET_ARRAY_INDEX: return DXIL_PROG_SEM_RENDERTARGET_ARRAY_INDEX;
case DXIL_SEM_VIEWPORT_ARRAY_INDEX: return DXIL_PROG_SEM_VIEWPORT_ARRAY_INDEX;
case DXIL_SEM_CLIP_DISTANCE: return DXIL_PROG_SEM_CLIP_DISTANCE;
case DXIL_SEM_CULL_DISTANCE: return DXIL_PROG_SEM_CULL_DISTANCE;
case DXIL_SEM_BARYCENTRICS: return DXIL_PROG_SEM_BARYCENTRICS;
case DXIL_SEM_SHADING_RATE: return DXIL_PROG_SEM_SHADING_RATE;
case DXIL_SEM_CULL_PRIMITIVE: return DXIL_PROG_SEM_CULL_PRIMITIVE;
case DXIL_SEM_TARGET: return DXIL_PROG_SEM_TARGET;
case DXIL_SEM_DEPTH: return DXIL_PROG_SEM_DEPTH;
case DXIL_SEM_DEPTH_LE: return DXIL_PROG_SEM_DEPTH_LE;
case DXIL_SEM_DEPTH_GE: return DXIL_PROG_SEM_DEPTH_GE;
case DXIL_SEM_STENCIL_REF: return DXIL_PROG_SEM_STENCIL_REF;
case DXIL_SEM_TESS_FACTOR:
switch (num_vals) {
case 4: return DXIL_PROG_SEM_FINAL_QUAD_EDGE_TESSFACTOR;
case 3: return DXIL_PROG_SEM_FINAL_TRI_EDGE_TESSFACTOR;
case 2: return start_val == 0 ?
DXIL_PROG_SEM_FINAL_LINE_DENSITY_TESSFACTOR :
DXIL_PROG_SEM_FINAL_LINE_DETAIL_TESSFACTOR;
default:
UNREACHABLE("Invalid row count for tess factor");
}
case DXIL_SEM_INSIDE_TESS_FACTOR:
switch (num_vals) {
case 2: return DXIL_PROG_SEM_FINAL_QUAD_INSIDE_EDGE_TESSFACTOR;
case 1: return DXIL_PROG_SEM_FINAL_TRI_INSIDE_EDGE_TESSFACTOR;
default:
UNREACHABLE("Invalid row count for inner tess factor");
}
default:
return DXIL_PROG_SEM_UNDEFINED;
}
}
static
uint32_t
copy_semantic_name_to_string(struct _mesa_string_buffer *string_out, const char *name)
{
/* copy the semantic name */
uint32_t retval = string_out->length;
size_t name_len = strlen(name) + 1;
_mesa_string_buffer_append_len(string_out, name, name_len);
return retval;
}
static
uint32_t
append_semantic_index_to_table(struct dxil_psv_sem_index_table *table, uint32_t index,
uint32_t num_rows)
{
for (unsigned i = 0; i < table->size; ++i) {
unsigned j = 0;
for (; j < num_rows && i + j < table->size; ++j)
if (table->data[i + j] != index + j)
break;
if (j == num_rows)
return i;
else if (j > 0)
i += j - 1;
}
uint32_t retval = table->size;
assert(table->size + num_rows <= ARRAY_SIZE(table->data));
for (unsigned i = 0; i < num_rows; ++i)
table->data[table->size++] = index + i;
return retval;
}
static const struct dxil_mdnode *
fill_SV_param_nodes(struct dxil_module *mod, unsigned record_id,
const struct dxil_signature_record *rec,
const struct dxil_psv_signature_element *psv,
bool is_input) {
const struct dxil_mdnode *SV_params_nodes[11];
/* For this to always work we should use vectorize_io, but for FS out and VS in
* this is not implemented globally */
const struct dxil_mdnode *flattened_semantics[256];
for (unsigned i = 0; i < rec->num_elements; ++i)
flattened_semantics[i] = dxil_get_metadata_int32(mod, rec->elements[i].semantic_index);
SV_params_nodes[0] = dxil_get_metadata_int32(mod, (int)record_id); // Unique element ID
SV_params_nodes[1] = dxil_get_metadata_string(mod, rec->name); // Element name
SV_params_nodes[2] = dxil_get_metadata_int8(mod, rec->sig_comp_type); // Element type
SV_params_nodes[3] = dxil_get_metadata_int8(mod, (int8_t)psv->semantic_kind); // Effective system value
SV_params_nodes[4] = dxil_get_metadata_node(mod, flattened_semantics,
rec->num_elements); // Semantic index vector
SV_params_nodes[5] = dxil_get_metadata_int8(mod, psv->interpolation_mode); // Interpolation mode
SV_params_nodes[6] = dxil_get_metadata_int32(mod, psv->rows); // Number of rows
SV_params_nodes[7] = dxil_get_metadata_int8(mod, psv->cols_and_start & 0xf); // Number of columns
SV_params_nodes[8] = dxil_get_metadata_int32(mod, rec->elements[0].reg); // Element packing start row
SV_params_nodes[9] = dxil_get_metadata_int8(mod, (psv->cols_and_start >> 4) & 0x3); // Element packing start column
const struct dxil_mdnode *SV_metadata[6];
unsigned num_metadata_nodes = 0;
if (rec->elements[0].stream != 0) {
SV_metadata[num_metadata_nodes++] = dxil_get_metadata_int32(mod, DXIL_SIGNATURE_ELEMENT_OUTPUT_STREAM);
SV_metadata[num_metadata_nodes++] = dxil_get_metadata_int32(mod, rec->elements[0].stream);
}
uint8_t usage_mask = rec->elements[0].always_reads_mask;
if (!is_input)
usage_mask = 0xf & ~rec->elements[0].never_writes_mask;
if (usage_mask && mod->minor_validator >= 5) {
usage_mask >>= (psv->cols_and_start >> 4) & 0x3;
SV_metadata[num_metadata_nodes++] = dxil_get_metadata_int32(mod, DXIL_SIGNATURE_ELEMENT_USAGE_COMPONENT_MASK);
SV_metadata[num_metadata_nodes++] = dxil_get_metadata_int8(mod, usage_mask);
}
uint8_t dynamic_index_mask = psv->dynamic_mask_and_stream & 0xf;
if (dynamic_index_mask) {
SV_metadata[num_metadata_nodes++] = dxil_get_metadata_int32(mod, DXIL_SIGNATURE_ELEMENT_DYNAMIC_INDEX_COMPONENT_MASK);
SV_metadata[num_metadata_nodes++] = dxil_get_metadata_int8(mod, dynamic_index_mask);
}
SV_params_nodes[10] = num_metadata_nodes ? dxil_get_metadata_node(mod, SV_metadata, num_metadata_nodes) : NULL;
return dxil_get_metadata_node(mod, SV_params_nodes, ARRAY_SIZE(SV_params_nodes));
}
static void
fill_signature_element(struct dxil_signature_element *elm,
struct semantic_info *semantic,
unsigned row)
{
memset(elm, 0, sizeof(struct dxil_signature_element));
elm->stream = semantic->stream;
// elm->semantic_name_offset = 0; // Offset needs to be filled out when writing
elm->semantic_index = semantic->index + row;
elm->system_value = (uint32_t) prog_semantic_from_kind(semantic->kind, semantic->rows, row);
elm->comp_type = (uint32_t) semantic->comp_type;
elm->reg = semantic->start_row + row;
assert(semantic->cols + semantic->start_col <= 4);
elm->mask = (uint8_t) (((1 << semantic->cols) - 1) << semantic->start_col);
elm->min_precision = DXIL_MIN_PREC_DEFAULT;
}
static bool
fill_psv_signature_element(struct dxil_psv_signature_element *psv_elm,
struct semantic_info *semantic, struct dxil_module *mod)
{
memset(psv_elm, 0, sizeof(struct dxil_psv_signature_element));
psv_elm->rows = semantic->rows;
if (semantic->start_row >= 0) {
assert(semantic->start_row < 256);
psv_elm->start_row = semantic->start_row;
psv_elm->cols_and_start = (1u << 6) | (semantic->start_col << 4) | semantic->cols;
} else {
/* The validation expects that the the start row is not egative
* and apparently the extra bit in the cols_and_start indicates that the
* row is meant literally, so don't set it in this case.
* (Source of information: Comparing with the validation structures
* created by dxcompiler)
*/
psv_elm->start_row = 0;
psv_elm->cols_and_start = (semantic->start_col << 4) | semantic->cols;
}
psv_elm->semantic_kind = (uint8_t)semantic->kind;
psv_elm->component_type = semantic->comp_type;
psv_elm->interpolation_mode = semantic->interpolation;
psv_elm->dynamic_mask_and_stream = (semantic->stream) << 4;
if (semantic->kind == DXIL_SEM_ARBITRARY && strlen(semantic->name)) {
psv_elm->semantic_name_offset =
copy_semantic_name_to_string(mod->sem_string_table, semantic->name);
/* TODO: clean up memory */
if (psv_elm->semantic_name_offset == (uint32_t)-1)
return false;
}
psv_elm->semantic_indexes_offset =
append_semantic_index_to_table(&mod->sem_index_table, semantic->index, semantic->rows);
return true;
}
static bool
fill_io_signature(struct dxil_module *mod, int id,
struct semantic_info *semantic,
struct dxil_signature_record *rec,
struct dxil_psv_signature_element *psv_elm)
{
rec->name = ralloc_strdup(mod->ralloc_ctx, semantic->name);
rec->num_elements = semantic->rows;
rec->sig_comp_type = semantic->sig_comp_type;
for (unsigned i = 0; i < semantic->rows; ++i)
fill_signature_element(&rec->elements[i], semantic, i);
return fill_psv_signature_element(psv_elm, semantic, mod);
}
static unsigned
get_input_signature_group(struct dxil_module *mod,
unsigned num_inputs,
nir_shader *s, nir_variable_mode modes,
semantic_info_proc get_semantics, unsigned *row_iter,
unsigned input_clip_size)
{
nir_foreach_variable_with_modes(var, s, modes) {
if (var->data.patch)
continue;
struct semantic_info semantic = {0};
get_semantics(var, &semantic, s->info.stage);
mod->inputs[num_inputs].sysvalue = semantic.sysvalue_name;
nir_variable *base_var = var;
if (var->data.location_frac) {
/* Note: Specifically search for a variable that has space for these additional components */
nir_foreach_variable_with_modes(test_var, s, modes) {
if (var->data.location == test_var->data.location) {
/* Variables should be sorted such that we're only looking for an already-emitted variable */
if (test_var == var)
break;
base_var = test_var;
if (test_var->data.location_frac == 0 &&
glsl_get_component_slots(
nir_is_arrayed_io(test_var, s->info.stage) ?
glsl_get_array_element(test_var->type) : test_var->type) <= var->data.location_frac)
break;
}
}
}
if (base_var != var)
/* Combine fractional vars into any already existing row */
get_additional_semantic_info(s, var, &semantic,
mod->psv_inputs[mod->input_mappings[base_var->data.driver_location]].start_row,
input_clip_size);
else
*row_iter = get_additional_semantic_info(s, var, &semantic, *row_iter, input_clip_size);
mod->input_mappings[var->data.driver_location] = num_inputs;
struct dxil_psv_signature_element *psv_elm = &mod->psv_inputs[num_inputs];
if (!fill_io_signature(mod, num_inputs, &semantic,
&mod->inputs[num_inputs], psv_elm))
return 0;
mod->num_psv_inputs = MAX2(mod->num_psv_inputs,
semantic.start_row + semantic.rows);
++num_inputs;
assert(num_inputs < VARYING_SLOT_MAX * 4);
}
return num_inputs;
}
static void
process_input_signature(struct dxil_module *mod, nir_shader *s, unsigned input_clip_size)
{
if (s->info.stage == MESA_SHADER_KERNEL)
return;
unsigned next_row = 0;
mod->num_sig_inputs = get_input_signature_group(mod, 0,
s, nir_var_shader_in,
s->info.stage == MESA_SHADER_VERTEX ?
get_semantic_vs_in_name : get_semantic_in_name,
&next_row, input_clip_size);
mod->num_sig_inputs = get_input_signature_group(mod, mod->num_sig_inputs,
s, nir_var_system_value,
get_semantic_sv_name,
&next_row, input_clip_size);
}
static const char *out_sysvalue_name(nir_variable *var)
{
switch (var->data.location) {
case VARYING_SLOT_FACE:
return "FACE";
case VARYING_SLOT_POS:
return "POS";
case VARYING_SLOT_CLIP_DIST0:
case VARYING_SLOT_CLIP_DIST1:
return "CLIPDST";
case VARYING_SLOT_PRIMITIVE_ID:
return "PRIMID";
default:
return "NO";
}
}
static void
process_output_signature(struct dxil_module *mod, nir_shader *s)
{
unsigned num_outputs = 0;
unsigned next_row = 0;
nir_foreach_variable_with_modes(var, s, nir_var_shader_out) {
struct semantic_info semantic = {0};
if (var->data.patch)
continue;
if (s->info.stage == MESA_SHADER_FRAGMENT) {
get_semantic_ps_outname(var, &semantic);
mod->outputs[num_outputs].sysvalue = "TARGET";
} else {
const struct glsl_type *type = var->type;
if (nir_is_arrayed_io(var, s->info.stage))
type = glsl_get_array_element(type);
get_semantic_name(var, &semantic, type);
mod->outputs[num_outputs].sysvalue = out_sysvalue_name(var);
}
nir_variable *base_var = var;
if (var->data.location_frac) {
if (s->info.stage == MESA_SHADER_FRAGMENT) {
/* Fragment shader outputs are all either scalars, or must be declared as a single 4-component vector.
* Any attempt to declare partial vectors split across multiple variables is ignored.
*/
continue;
}
base_var = nir_find_variable_with_location(s, nir_var_shader_out, var->data.location);
}
if (base_var != var &&
base_var->data.stream == var->data.stream)
/* Combine fractional vars into any already existing row */
get_additional_semantic_info(s, var, &semantic,
mod->psv_outputs[mod->output_mappings[base_var->data.driver_location]].start_row,
s->info.clip_distance_array_size);
else
next_row = get_additional_semantic_info(s, var, &semantic, next_row, s->info.clip_distance_array_size);
mod->info.has_out_position |= semantic.kind== DXIL_SEM_POSITION;
mod->info.has_out_depth |= semantic.kind == DXIL_SEM_DEPTH;
mod->output_mappings[var->data.driver_location] = num_outputs;
struct dxil_psv_signature_element *psv_elm = &mod->psv_outputs[num_outputs];
if (!fill_io_signature(mod, num_outputs, &semantic,
&mod->outputs[num_outputs], psv_elm))
return;
for (unsigned i = 0; i < mod->outputs[num_outputs].num_elements; ++i) {
struct dxil_signature_element *elm = &mod->outputs[num_outputs].elements[i];
if (mod->minor_validator <= 4)
elm->never_writes_mask = 0xff & ~elm->mask;
else
/* This will be updated by the module processing */
elm->never_writes_mask = 0xf & ~elm->mask;
}
++num_outputs;
mod->num_psv_outputs[semantic.stream] = MAX2(mod->num_psv_outputs[semantic.stream],
semantic.start_row + semantic.rows);
}
mod->num_sig_outputs = num_outputs;
}
static const char *
patch_sysvalue_name(nir_variable *var)
{
switch (var->data.location) {
case VARYING_SLOT_TESS_LEVEL_OUTER:
switch (glsl_get_aoa_size(var->type)) {
case 4:
return "QUADEDGE";
case 3:
return "TRIEDGE";
case 2:
return var->data.location_frac == 0 ?
"LINEDET" : "LINEDEN";
default:
UNREACHABLE("Unexpected outer tess factor array size");
}
break;
case VARYING_SLOT_TESS_LEVEL_INNER:
switch (glsl_get_aoa_size(var->type)) {
case 2:
return "QUADINT";
case 1:
return "TRIINT";
default:
UNREACHABLE("Unexpected inner tess factory array size");
}
break;
default:
return "NO";
}
}
static void
process_patch_const_signature(struct dxil_module *mod, nir_shader *s)
{
if (s->info.stage != MESA_SHADER_TESS_CTRL &&
s->info.stage != MESA_SHADER_TESS_EVAL)
return;
nir_variable_mode mode = s->info.stage == MESA_SHADER_TESS_CTRL ?
nir_var_shader_out : nir_var_shader_in;
unsigned num_consts = 0;
unsigned next_row = 0;
nir_foreach_variable_with_modes(var, s, mode) {
struct semantic_info semantic = {0};
if (!var->data.patch)
continue;
const struct glsl_type *type = var->type;
get_semantic_name(var, &semantic, type);
mod->patch_consts[num_consts].sysvalue = patch_sysvalue_name(var);
nir_variable *base_var = var;
if (var->data.location_frac)
base_var = nir_find_variable_with_location(s, mode, var->data.location);
if (base_var != var)
/* Combine fractional vars into any already existing row */
get_additional_semantic_info(s, var, &semantic,
mod->psv_patch_consts[mod->patch_mappings[base_var->data.driver_location]].start_row,
0);
else
next_row = get_additional_semantic_info(s, var, &semantic, next_row, 0);
mod->patch_mappings[var->data.driver_location] = num_consts;
struct dxil_psv_signature_element *psv_elm = &mod->psv_patch_consts[num_consts];
if (!fill_io_signature(mod, num_consts, &semantic,
&mod->patch_consts[num_consts], psv_elm))
return;
if (mode == nir_var_shader_out) {
for (unsigned i = 0; i < mod->patch_consts[num_consts].num_elements; ++i) {
struct dxil_signature_element *elm = &mod->patch_consts[num_consts].elements[i];
if (mod->minor_validator <= 4)
elm->never_writes_mask = 0xff & ~elm->mask;
else
/* This will be updated by the module processing */
elm->never_writes_mask = 0xf & ~elm->mask;
}
}
++num_consts;
mod->num_psv_patch_consts = MAX2(mod->num_psv_patch_consts,
semantic.start_row + semantic.rows);
}
mod->num_sig_patch_consts = num_consts;
}
static void
prepare_dependency_tables(struct dxil_module *mod, nir_shader *s)
{
bool uses_view_id = BITSET_TEST(s->info.system_values_read, SYSTEM_VALUE_VIEW_INDEX);
uint32_t num_output_streams = s->info.stage == MESA_SHADER_GEOMETRY ? 4 : 1;
uint32_t num_tables = s->info.stage == MESA_SHADER_TESS_CTRL || s->info.stage == MESA_SHADER_TESS_EVAL ? 2 : num_output_streams;
const uint32_t output_vecs_per_dword = 32 /* bits per dword */ / 4 /* components per vec */;
const uint32_t masks_per_input_vec = 4 /* components per vec */;
for (uint32_t i = 0; i < num_output_streams; ++i)
mod->dependency_table_dwords_per_input[i] = DIV_ROUND_UP(mod->num_psv_outputs[i], output_vecs_per_dword);
if (s->info.stage == MESA_SHADER_TESS_CTRL)
mod->dependency_table_dwords_per_input[1] = DIV_ROUND_UP(mod->num_psv_patch_consts, output_vecs_per_dword);
uint32_t view_id_table_sizes[4] = { 0 };
if (uses_view_id) {
for (uint32_t i = 0; i < 4; ++i)
view_id_table_sizes[i] = mod->dependency_table_dwords_per_input[i];
}
for (uint32_t i = 0; i < num_output_streams; ++i)
mod->io_dependency_table_size[i] = mod->dependency_table_dwords_per_input[i] * mod->num_psv_inputs * masks_per_input_vec;
if (s->info.stage == MESA_SHADER_TESS_CTRL)
mod->io_dependency_table_size[1] = mod->dependency_table_dwords_per_input[1] * mod->num_psv_inputs * masks_per_input_vec;
else if (s->info.stage == MESA_SHADER_TESS_EVAL)
mod->io_dependency_table_size[1] = mod->dependency_table_dwords_per_input[0] * mod->num_psv_patch_consts * masks_per_input_vec;
mod->serialized_dependency_table_size = num_tables + 1;
for (uint32_t i = 0; i < num_tables; ++i) {
mod->serialized_dependency_table_size += view_id_table_sizes[i] + mod->io_dependency_table_size[i];
}
uint32_t *table = calloc(mod->serialized_dependency_table_size, sizeof(uint32_t));
mod->serialized_dependency_table = table;
*(table++) = mod->num_psv_inputs * 4;
for (uint32_t i = 0; i < num_output_streams; ++i) {
*(table++) = mod->num_psv_outputs[i] * 4;
mod->viewid_dependency_table[i] = table;
table += view_id_table_sizes[i];
mod->io_dependency_table[i] = table;
table += mod->io_dependency_table_size[i];
}
if (s->info.stage == MESA_SHADER_TESS_CTRL || s->info.stage == MESA_SHADER_TESS_EVAL) {
*(table++) = mod->num_psv_patch_consts * 4;
if (s->info.stage == MESA_SHADER_TESS_CTRL) {
mod->viewid_dependency_table[1] = table;
table += view_id_table_sizes[1];
}
mod->io_dependency_table[1] = table;
table += mod->io_dependency_table_size[1];
}
}
void
preprocess_signatures(struct dxil_module *mod, nir_shader *s, unsigned input_clip_size)
{
/* DXC does the same: Add an empty string before everything else */
mod->sem_string_table = _mesa_string_buffer_create(mod->ralloc_ctx, 1024);
copy_semantic_name_to_string(mod->sem_string_table, "");
process_input_signature(mod, s, input_clip_size);
process_output_signature(mod, s);
process_patch_const_signature(mod, s);
prepare_dependency_tables(mod, s);
}
static const struct dxil_mdnode *
get_signature_metadata(struct dxil_module *mod,
const struct dxil_signature_record *recs,
const struct dxil_psv_signature_element *psvs,
unsigned num_elements,
bool is_input)
{
if (num_elements == 0)
return NULL;
const struct dxil_mdnode *nodes[VARYING_SLOT_MAX * 4];
for (unsigned i = 0; i < num_elements; ++i) {
nodes[i] = fill_SV_param_nodes(mod, i, &recs[i], &psvs[i], is_input);
}
return dxil_get_metadata_node(mod, nodes, num_elements);
}
const struct dxil_mdnode *
get_signatures(struct dxil_module *mod)
{
const struct dxil_mdnode *input_signature = get_signature_metadata(mod, mod->inputs, mod->psv_inputs, mod->num_sig_inputs, true);
const struct dxil_mdnode *output_signature = get_signature_metadata(mod, mod->outputs, mod->psv_outputs, mod->num_sig_outputs, false);
const struct dxil_mdnode *patch_const_signature = get_signature_metadata(mod, mod->patch_consts, mod->psv_patch_consts, mod->num_sig_patch_consts,
mod->shader_kind == DXIL_DOMAIN_SHADER);
const struct dxil_mdnode *SV_nodes[3] = {
input_signature,
output_signature,
patch_const_signature
};
if (output_signature || input_signature || patch_const_signature)
return dxil_get_metadata_node(mod, SV_nodes, ARRAY_SIZE(SV_nodes));
else
return NULL;
}
+169
View File
@@ -0,0 +1,169 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_SIGNATURE_H
#define DXIL_SIGNATURE_H
#include "dxil_enums.h"
#include "nir.h"
#include "util/string_buffer.h"
#ifdef __cplusplus
extern "C" {
#endif
/* struct taken from DXILContainer
* Enums values were replaced by uint32_t since they must occupy 32 bit
*/
struct dxil_signature_element {
uint32_t stream; // Stream index (parameters must appear in non-decreasing stream order)
uint32_t semantic_name_offset; // Offset to char * stream from start of DxilProgramSignature.
uint32_t semantic_index; // Semantic Index
uint32_t system_value; // Semantic type. Similar to DxilSemantic::Kind, but a serialized rather than processing rep.
uint32_t comp_type; // Type of bits.
uint32_t reg; // Register Index (row index)
uint8_t mask; // Mask (column allocation)
union { // Unconditional cases useful for validation of shader linkage.
uint8_t never_writes_mask; // For an output signature, the shader the signature belongs to never
// writes the masked components of the output register.
uint8_t always_reads_mask; // For an input signature, the shader the signature belongs to always
// reads the masked components of the input register.
};
uint16_t pad;
uint32_t min_precision; // Minimum precision of input/output data
};
struct dxil_signature_record {
struct dxil_signature_element elements[32];
unsigned num_elements;
const char *sysvalue;
char *name;
uint8_t sig_comp_type;
};
struct dxil_psv_sem_index_table {
uint32_t data[128];
uint32_t size;
};
struct dxil_psv_signature_element {
uint32_t semantic_name_offset; // Offset into StringTable
uint32_t semantic_indexes_offset; // Offset into PSVSemanticIndexTable, count == Rows
uint8_t rows; // Number of rows this element occupies
uint8_t start_row; // Starting row of packing location if allocated
uint8_t cols_and_start; // 0:4 = Cols, 4:6 = StartCol, 6:7 == Allocated
uint8_t semantic_kind; // PSVSemanticKind
uint8_t component_type; // DxilProgramSigCompType
uint8_t interpolation_mode; // DXIL::InterpolationMode or D3D10_SB_INTERPOLATION_MODE
uint8_t dynamic_mask_and_stream; // 0:4 = DynamicIndexMask, 4:6 = OutputStream (0-3)
uint8_t reserved;
};
struct dxil_psv_runtime_info_0 {
union {
struct {
char output_position_present;
} vs;
struct {
uint32_t input_control_point_count;
uint32_t output_control_point_count;
uint32_t tessellator_domain;
uint32_t tessellator_output_primitive;
} hs;
struct {
uint32_t input_control_point_count;
char output_position_present;
uint32_t tessellator_domain;
} ds;
struct {
uint32_t input_primitive;
uint32_t output_toplology;
uint32_t output_stream_mask;
char output_position_present;
} gs;
struct {
char depth_output;
char sample_frequency;
} ps;
/* Maximum sized defining the union size (MSInfo)*/
struct {
uint32_t dummy1[3];
uint16_t dummy2[2];
} dummy;
};
uint32_t min_expected_wave_lane_count; // minimum lane count required, 0 if unused
uint32_t max_expected_wave_lane_count; // maximum lane count required, 0xffffffff if unused
};
struct dxil_psv_runtime_info_1 {
struct dxil_psv_runtime_info_0 psv0;
uint8_t shader_stage; // PSVShaderKind
uint8_t uses_view_id;
union {
uint16_t max_vertex_count; // MaxVertexCount for GS only (max 1024)
uint8_t sig_patch_const_or_prim_vectors; // Output for HS; Input for DS; Primitive output for MS (overlaps MS1::SigPrimVectors)
// struct { uint8_t dummy[2]; } fill;
};
// PSVSignatureElement counts
uint8_t sig_input_elements;
uint8_t sig_output_elements;
uint8_t sig_patch_const_or_prim_elements;
// Number of packed vectors per signature
uint8_t sig_input_vectors;
uint8_t sig_output_vectors[4];
};
struct dxil_psv_runtime_info_2 {
struct dxil_psv_runtime_info_1 psv1;
uint32_t num_threads_x;
uint32_t num_threads_y;
uint32_t num_threads_z;
};
struct dxil_psv_runtime_info_3 {
struct dxil_psv_runtime_info_2 psv2;
uint32_t entry_function_name;
};
struct dxil_mdnode;
struct dxil_module;
void
preprocess_signatures(struct dxil_module *mod, nir_shader *s, unsigned input_clip_size);
const struct dxil_mdnode *
get_signatures(struct dxil_module *mod);
#ifdef __cplusplus
}
#endif
#endif
+377
View File
@@ -0,0 +1,377 @@
#include "dxil_validator.h"
#include <windows.h>
#include <unknwn.h>
#include "util/ralloc.h"
#include "util/u_debug.h"
#include "util/compiler.h"
#include "dxcapi.h"
#include <wrl/client.h>
using Microsoft::WRL::ComPtr;
struct dxil_validator {
HMODULE dxil_mod;
HMODULE dxcompiler_mod;
IDxcValidator *dxc_validator;
IDxcLibrary *dxc_library;
IDxcCompiler *dxc_compiler;
enum dxil_validator_version version;
};
extern "C" {
extern IMAGE_DOS_HEADER __ImageBase;
}
static HMODULE
load_dxil_mod()
{
/* First, try to load DXIL.dll from the default search-path */
#if defined(_GAMING_XBOX_SCARLETT)
HMODULE mod = LoadLibraryA("dxcompiler_xs.dll");
#elif defined (_GAMING_XBOX)
HMODULE mod = LoadLibraryA("dxcompiler_x.dll");
#else
HMODULE mod = LoadLibraryA("DXIL.dll");
#endif
if (mod)
return mod;
/* If that fails, try to load it next to the current module, so we can
* ship DXIL.dll next to the GLon12 DLL.
*/
char self_path[MAX_PATH];
uint32_t path_size = GetModuleFileNameA((HINSTANCE)&__ImageBase,
self_path, sizeof(self_path));
if (!path_size || path_size == sizeof(self_path)) {
debug_printf("DXIL: Unable to get path to self");
return NULL;
}
auto last_slash = strrchr(self_path, '\\');
if (!last_slash) {
debug_printf("DXIL: Unable to get path to self");
return NULL;
}
*(last_slash + 1) = '\0';
if (strcat_s(self_path, "DXIL.dll") != 0) {
debug_printf("DXIL: Unable to get path to DXIL.dll next to self");
return NULL;
}
return LoadLibraryA(self_path);
}
static IDxcValidator *
create_dxc_validator(HMODULE dxil_mod)
{
DxcCreateInstanceProc dxil_create_func =
(DxcCreateInstanceProc)GetProcAddress(dxil_mod, "DxcCreateInstance");
if (!dxil_create_func) {
debug_printf("DXIL: Failed to load DxcCreateInstance from DXIL.dll\n");
return NULL;
}
IDxcValidator *dxc_validator;
HRESULT hr = dxil_create_func(CLSID_DxcValidator,
IID_PPV_ARGS(&dxc_validator));
if (FAILED(hr)) {
debug_printf("DXIL: Failed to create validator\n");
return NULL;
}
return dxc_validator;
}
static enum dxil_validator_version
get_validator_version(IDxcValidator *val)
{
ComPtr<IDxcVersionInfo> version_info;
if (FAILED(val->QueryInterface(version_info.ReleaseAndGetAddressOf())))
return NO_DXIL_VALIDATION;
UINT32 major, minor;
if (FAILED(version_info->GetVersion(&major, &minor)))
return NO_DXIL_VALIDATION;
if (major == 1)
return (enum dxil_validator_version)(DXIL_VALIDATOR_1_0 + MIN2(minor, 8));
if (major > 1)
return DXIL_VALIDATOR_1_8;
return NO_DXIL_VALIDATION;
}
#ifndef _GAMING_XBOX
static uint64_t
get_dll_version(HMODULE mod)
{
WCHAR filename[MAX_PATH];
DWORD filename_length = GetModuleFileNameW(mod, filename, ARRAY_SIZE(filename));
if (filename_length == 0 || filename_length == ARRAY_SIZE(filename))
return 0;
DWORD version_handle = 0;
DWORD version_size = GetFileVersionInfoSizeW(filename, &version_handle);
if (version_size == 0)
return 0;
void *version_data = malloc(version_size);
if (!version_data)
return 0;
if (!GetFileVersionInfoW(filename, version_handle, version_size, version_data)) {
free(version_data);
return 0;
}
UINT value_size = 0;
VS_FIXEDFILEINFO *version_info = nullptr;
if (!VerQueryValueW(version_data, L"\\", reinterpret_cast<void **>(&version_info), &value_size) ||
!value_size ||
version_info->dwSignature != VS_FFI_SIGNATURE) {
free(version_data);
return 0;
}
uint64_t ret =
((uint64_t)version_info->dwFileVersionMS << 32ull) |
(uint64_t)version_info->dwFileVersionLS;
free(version_data);
return ret;
}
#endif
static enum dxil_validator_version
get_filtered_validator_version(HMODULE mod, enum dxil_validator_version raw)
{
switch (raw) {
#ifndef _GAMING_XBOX
case DXIL_VALIDATOR_1_6: {
uint64_t dxil_version = get_dll_version(mod);
static constexpr uint64_t known_bad_version =
// 101.5.2005.60
(101ull << 48ull) | (5ull << 32ull) | (2005ull << 16ull) | 60ull;
if (dxil_version == known_bad_version)
return DXIL_VALIDATOR_1_5;
FALLTHROUGH;
}
#endif
default:
return raw;
}
}
struct dxil_validator *
dxil_create_validator(const void *ctx)
{
struct dxil_validator *val = rzalloc(ctx, struct dxil_validator);
if (!val)
return NULL;
/* Load DXIL.dll. This is a hard requirement on Windows, so we error
* out if this fails.
*/
val->dxil_mod = load_dxil_mod();
if (!val->dxil_mod) {
debug_printf("DXIL: Failed to load DXIL.dll\n");
goto fail;
}
/* Create IDxcValidator. This is a hard requirement on Windows, so we
* error out if this fails.
*/
val->dxc_validator = create_dxc_validator(val->dxil_mod);
if (!val->dxc_validator)
goto fail;
val->version = get_filtered_validator_version(
val->dxil_mod,
get_validator_version(val->dxc_validator));
/* Try to load dxcompiler.dll. This is just used for diagnostics, and
* will fail on most end-users install. So we do not error out if this
* fails.
*/
val->dxcompiler_mod = LoadLibraryA("dxcompiler.dll");
if (val->dxcompiler_mod) {
/* If we managed to load dxcompiler.dll, but either don't find
* DxcCreateInstance, or fail to create IDxcLibrary or
* IDxcCompiler, this is a good indication that the user wants
* diagnostics, but something went wrong. Print warnings to help
* figuring out what's wrong, but do not treat it as an error.
*/
DxcCreateInstanceProc compiler_create_func =
(DxcCreateInstanceProc)GetProcAddress(val->dxcompiler_mod,
"DxcCreateInstance");
if (!compiler_create_func) {
debug_printf("DXIL: Failed to load DxcCreateInstance from "
"dxcompiler.dll\n");
} else {
if (FAILED(compiler_create_func(CLSID_DxcLibrary,
IID_PPV_ARGS(&val->dxc_library))))
debug_printf("DXIL: Unable to create IDxcLibrary instance\n");
if (FAILED(compiler_create_func(CLSID_DxcCompiler,
IID_PPV_ARGS(&val->dxc_compiler))))
debug_printf("DXIL: Unable to create IDxcCompiler instance\n");
}
}
return val;
fail:
if (val->dxil_mod)
FreeLibrary(val->dxil_mod);
ralloc_free(val);
return NULL;
}
void
dxil_destroy_validator(struct dxil_validator *val)
{
if (!val)
return;
/* if we have a validator, we have these */
val->dxc_validator->Release();
FreeLibrary(val->dxil_mod);
if (val->dxcompiler_mod) {
if (val->dxc_library)
val->dxc_library->Release();
if (val->dxc_compiler)
val->dxc_compiler->Release();
FreeLibrary(val->dxcompiler_mod);
}
ralloc_free(val);
}
class ShaderBlob : public IDxcBlob {
public:
ShaderBlob(void *data, size_t size) :
m_data(data),
m_size(size)
{
}
LPVOID STDMETHODCALLTYPE
GetBufferPointer(void) override
{
return m_data;
}
SIZE_T STDMETHODCALLTYPE
GetBufferSize() override
{
return m_size;
}
HRESULT STDMETHODCALLTYPE
QueryInterface(REFIID, void **) override
{
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE
AddRef() override
{
return 1;
}
ULONG STDMETHODCALLTYPE
Release() override
{
return 0;
}
void *m_data;
size_t m_size;
};
bool
dxil_validate_module(struct dxil_validator *val, void *data, size_t size, char **error)
{
if (!val)
return false;
ShaderBlob source(data, size);
ComPtr<IDxcOperationResult> result;
val->dxc_validator->Validate(&source, DxcValidatorFlags_InPlaceEdit,
&result);
HRESULT hr;
result->GetStatus(&hr);
if (FAILED(hr) && error) {
/* try to resolve error message */
*error = NULL;
if (!val->dxc_library) {
debug_printf("DXIL: validation failed, but lacking IDxcLibrary"
"from dxcompiler.dll for proper diagnostics.\n");
return false;
}
ComPtr<IDxcBlobEncoding> blob, blob_utf8;
if (FAILED(result->GetErrorBuffer(&blob)))
fprintf(stderr, "DXIL: IDxcOperationResult::GetErrorBuffer() failed\n");
else if (FAILED(val->dxc_library->GetBlobAsUtf8(blob.Get(),
blob_utf8.GetAddressOf())))
fprintf(stderr, "DXIL: IDxcLibrary::GetBlobAsUtf8() failed\n");
else {
char *str = reinterpret_cast<char *>(blob_utf8->GetBufferPointer());
str[blob_utf8->GetBufferSize() - 1] = 0;
*error = ralloc_strdup(val, str);
}
}
return SUCCEEDED(hr);
}
char *
dxil_disasm_module(struct dxil_validator *val, void *data, size_t size)
{
if (!val)
return NULL;
if (!val->dxc_compiler || !val->dxc_library) {
fprintf(stderr, "DXIL: disassembly requires IDxcLibrary and "
"IDxcCompiler from dxcompiler.dll\n");
return NULL;
}
ShaderBlob source(data, size);
ComPtr<IDxcBlobEncoding> blob, blob_utf8;
if (FAILED(val->dxc_compiler->Disassemble(&source, &blob))) {
fprintf(stderr, "DXIL: IDxcCompiler::Disassemble() failed\n");
return NULL;
}
if (FAILED(val->dxc_library->GetBlobAsUtf8(blob.Get(), blob_utf8.GetAddressOf()))) {
fprintf(stderr, "DXIL: IDxcLibrary::GetBlobAsUtf8() failed\n");
return NULL;
}
char *str = reinterpret_cast<char*>(blob_utf8->GetBufferPointer());
str[blob_utf8->GetBufferSize() - 1] = 0;
return ralloc_strdup(val, str);
}
enum dxil_validator_version
dxil_get_validator_version(struct dxil_validator *val)
{
return val ? val->version : NO_DXIL_VALIDATION;
}
+57
View File
@@ -0,0 +1,57 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_VALIDATOR_H
#define DXIL_VALIDATOR_H
#include "dxil_versions.h"
#include <stddef.h>
struct dxil_validator;
#ifdef __cplusplus
extern "C" {
#endif
struct dxil_validator *
dxil_create_validator(const void *ctx);
void
dxil_destroy_validator(struct dxil_validator *val);
bool
dxil_validate_module(struct dxil_validator *val, void *data,
size_t size, char **error);
char *
dxil_disasm_module(struct dxil_validator *val, void *data, size_t size);
enum dxil_validator_version
dxil_get_validator_version(struct dxil_validator *val);
#ifdef __cplusplus
}
#endif
#endif
+60
View File
@@ -0,0 +1,60 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_VERSIONS_H
#define DXIL_VERSIONS_H
#ifdef __cplusplus
extern "C" {
#endif
enum dxil_shader_model {
SHADER_MODEL_6_0 = 0x60000,
SHADER_MODEL_6_1,
SHADER_MODEL_6_2,
SHADER_MODEL_6_3,
SHADER_MODEL_6_4,
SHADER_MODEL_6_5,
SHADER_MODEL_6_6,
SHADER_MODEL_6_7,
SHADER_MODEL_6_8,
};
enum dxil_validator_version {
NO_DXIL_VALIDATION,
DXIL_VALIDATOR_1_0 = 0x10000,
DXIL_VALIDATOR_1_1,
DXIL_VALIDATOR_1_2,
DXIL_VALIDATOR_1_3,
DXIL_VALIDATOR_1_4,
DXIL_VALIDATOR_1_5,
DXIL_VALIDATOR_1_6,
DXIL_VALIDATOR_1_7,
DXIL_VALIDATOR_1_8,
};
#ifdef __cplusplus
}
#endif
#endif
+60
View File
@@ -0,0 +1,60 @@
# Copyright © Microsoft Corporation
# SPDX-License-Identifier: MIT
files_libdxil_compiler = files(
'dxil_buffer.c',
'dxil_container.c',
'dxil_dump.c',
'dxil_enums.c',
'dxil_function.c',
'dxil_module.c',
'dxil_nir.c',
'dxil_nir_lower_int_cubemaps.c',
'dxil_nir_lower_int_samplers.c',
'dxil_nir_lower_vs_vertex_conversion.c',
'dxil_signature.c',
'dxil_nir_tess.c',
'nir_to_dxil.c',
)
if host_machine.system() == 'windows'
files_libdxil_compiler += files('dxil_validator.cpp')
endif
dxil_nir_algebraic_c = custom_target(
'dxil_nir_algebraic.c',
input : 'dxil_nir_algebraic.py',
output : 'dxil_nir_algebraic.c',
command : [
prog_python, '@INPUT@', '-p', dir_compiler_nir,
],
capture : true,
depend_files : nir_algebraic_depends,
)
libdxil_compiler = static_library(
'dxil_compiler',
[files_libdxil_compiler, dxil_nir_algebraic_c, sha1_h],
include_directories : [inc_include, inc_src],
dependencies: [idep_nir_headers, dep_valgrind],
gnu_symbol_visibility : 'hidden',
)
idep_libdxil_compiler = declare_dependency(
link_with : libdxil_compiler,
dependencies : [idep_mesautil, dep_version],
include_directories : include_directories('.')
)
if with_tests
test(
'dxil_buffer',
executable(
'dxil_buffer_test',
files('dxil_buffer_test.c'),
include_directories : [inc_src],
dependencies : [idep_libdxil_compiler]
),
suite: 'd3d12'
)
endif
File diff suppressed because it is too large. Load diff
+116
View File
@@ -0,0 +1,116 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef NIR_TO_DXIL_H
#define NIR_TO_DXIL_H
#include <stdbool.h>
#include "nir.h"
#include "dxil_versions.h"
#ifdef __cplusplus
extern "C" {
#endif
struct blob;
/* Controls how resource decls/accesses are handled. Common to all:
* Images, textures, and samplers map to D3D UAV, SRV, and sampler types
* Shared is lowered to explicit I/O and then to a DXIL-specific intrinsic for 4-byte indices instead of byte addressing
* Input/output are lowered to dedicated intrinsics
*/
enum dxil_environment {
/* In the GL environment:
* Samplers/textures are lowered, vars/intrinsics use binding to refer to them; dynamic array indexing supported with offset srcs
* The lowering done by mesa/st assigns bindings from 0 -> N
* All other resource variables have driver_location set instead, assigned from 0 -> N
* UBOs may or may not have interface variables, and are declared from ubo_binding_offset -> num_ubos
* SSBOs may or may not have interface variables, and are declared from from 0 -> num_ssbos
* Images are *not* lowered, so that dynamic indexing can deterministically get a base binding via the deref chain
* TODO: Maybe support lowering and use nir_intrinsic_range_base to get the base
* No immediate constant buffer, or scratch
*/
DXIL_ENVIRONMENT_GL,
/* In the CL environment:
* Shader kind is always KERNEL
* All resources use binding for identification
* Samplers/textures/images are lowered; dynamic indexing not supported by spec
* UBOs are arrays of uints in the NIR
* SSBOs are implicitly declared via num_kernel_globals
* Variables of shader_temp are used to declare an immediate constant buffer, with load_ptr_dxil intrinsics to access it
* Scratch is supported and lowered to DXIL-specific intrinsics for scalar 32-bit access
*/
DXIL_ENVIRONMENT_CL,
/* In the Vulkan environment:
* All resources use binding / descriptor_set for identification
* Samplers/textures/images support two modes:
* 1. Derefs: deref chains are walked to emit the DXIL handle to the resource; dynamic indexing supported
* 2. Bindless: the resource source is assumed as an index into a descriptor heap
* UBOs/SSBOs are struct variables in the NIR, accessed via vulkan_resource_index/load_vulkan_descriptor; dynamic indexing supported
* If load_vulkan_descriptor gets an index that didn't come from vulkan_resource_index, it is assumed to be an index into a descriptor heap
* Read-only SSBOs, as declared in the SPIR-V, are bound as raw buffer SRVs instead of UAVs, unless they're lowered to bindless
* No immediate constant buffer or scratch
*/
DXIL_ENVIRONMENT_VULKAN,
};
struct nir_to_dxil_options {
bool interpolate_at_vertex;
bool lower_int16;
bool disable_math_refactoring;
bool last_ubo_is_not_arrayed;
bool advanced_texture_ops;
unsigned provoking_vertex;
unsigned num_kernel_globals;
unsigned input_clip_size;
enum dxil_environment environment;
enum dxil_shader_model shader_model_max;
enum dxil_validator_version validator_version_max;
};
typedef void (*dxil_msg_callback)(void *priv, const char *msg);
struct dxil_logger {
void *priv;
dxil_msg_callback log;
};
bool
nir_to_dxil(struct nir_shader *s, const struct nir_to_dxil_options *opts,
const struct dxil_logger *logger, struct blob *blob);
const nir_shader_compiler_options*
dxil_get_base_nir_compiler_options(void);
void
dxil_get_nir_compiler_options(nir_shader_compiler_options *options,
enum dxil_shader_model shader_model_max,
unsigned supported_int_sizes,
unsigned supported_float_sizes);
#ifdef __cplusplus
}
#endif
#endif
+15
View File
@@ -0,0 +1,15 @@
# Copyright © Microsoft Corporation
# SPDX-License-Identifier: MIT
if with_microsoft_clc or with_spirv_to_dxil or with_microsoft_vk or (with_gallium_d3d12 and not get_option('gallium-d3d12-graphics').disabled())
subdir('compiler')
if with_microsoft_clc
subdir('clc')
endif
if with_spirv_to_dxil or with_microsoft_vk
subdir('spirv_to_dxil')
endif
if with_microsoft_vk
subdir('vulkan')
endif
endif
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,90 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_SPIRV_NIR_H
#define DXIL_SPIRV_NIR_H
#include "spirv_to_dxil.h"
#include "nir.h"
const struct spirv_to_nir_options*
dxil_spirv_nir_get_spirv_options(void);
void
dxil_spirv_nir_prep(nir_shader *nir);
/* The pipeline will require runtime data if, and only if, any of the multiple reported
* runtime data required flags is true.
*/
void
dxil_spirv_nir_link(nir_shader *nir, nir_shader *prev_stage_nir,
const struct dxil_spirv_runtime_conf *conf,
struct dxil_spirv_metadata *metadata);
void
dxil_spirv_nir_passes(nir_shader *nir,
const struct dxil_spirv_runtime_conf *conf,
struct dxil_spirv_metadata *metadata);
struct dxil_spirv_binding_remapping {
/* If ~0, don't lower to bindless */
uint32_t descriptor_set;
uint32_t binding;
bool is_sampler;
};
struct dxil_spirv_nir_lower_bindless_options {
uint32_t num_descriptor_sets;
uint32_t dynamic_buffer_binding;
void(*remap_binding)(struct dxil_spirv_binding_remapping *inout, void *context);
void *callback_context;
};
/* Each entry in a bindless descriptor set follows this layout. The first 32 bits are
* either a texture or buffer descriptor index in the descriptor heap. For pure
* sampler types, these bits are unused. The upper 32 bits are either a buffer
* offset, or for samplers (including combined image+sampler), a sampler index. */
struct dxil_spirv_bindless_entry {
union {
uint32_t texture_idx;
uint32_t buffer_idx;
};
union {
uint32_t buffer_offset;
uint32_t sampler_idx;
};
};
bool
dxil_spirv_nir_lower_bindless(nir_shader *nir, struct dxil_spirv_nir_lower_bindless_options *options);
bool
dxil_spirv_nir_lower_buffer_device_address(nir_shader *nir);
bool
dxil_spirv_nir_lower_yz_flip(nir_shader *shader,
const struct dxil_spirv_runtime_conf *rt_conf,
bool *reads_sysval_ubo);
#endif
@@ -0,0 +1,315 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "nir.h"
#include "nir_builder.h"
#include "nir_deref.h"
#include "dxil_spirv_nir.h"
#include "dxil_nir.h"
#include "vulkan/vulkan_core.h"
const uint32_t descriptor_size = sizeof(struct dxil_spirv_bindless_entry);
static void
type_size_align_1(const struct glsl_type *type, unsigned *size, unsigned *align)
{
if (glsl_type_is_array(type))
*size = glsl_get_aoa_size(type);
else
*size = 1;
*align = *size;
}
static nir_def *
load_vulkan_ssbo(nir_builder *b, unsigned buf_idx,
nir_def *offset, unsigned num_comps)
{
nir_def *res_index =
nir_vulkan_resource_index(b, 2, 32,
nir_imm_int(b, 0),
.desc_set = 0,
.binding = buf_idx,
.desc_type = nir_descriptor_type_storage_buffer);
nir_def *descriptor =
nir_load_vulkan_descriptor(b, 2, 32, res_index,
.desc_type = nir_descriptor_type_storage_buffer);
return nir_load_ssbo(b, num_comps, 32,
nir_channel(b, descriptor, 0),
offset,
.align_mul = num_comps * 4,
.align_offset = 0,
.access = ACCESS_NON_WRITEABLE | ACCESS_CAN_REORDER);
}
static nir_def *
lower_deref_to_index(nir_builder *b, nir_deref_instr *deref, bool is_sampler_handle,
struct dxil_spirv_nir_lower_bindless_options *options)
{
nir_variable *var = nir_deref_instr_get_variable(deref);
if (!var)
return NULL;
struct dxil_spirv_binding_remapping remap = {
.descriptor_set = var->data.descriptor_set,
.binding = var->data.binding,
.is_sampler = is_sampler_handle
};
options->remap_binding(&remap, options->callback_context);
if (remap.descriptor_set == ~0)
return NULL;
nir_def *index_in_ubo =
nir_iadd_imm(b,
nir_build_deref_offset(b, deref, type_size_align_1),
remap.binding);
nir_def *offset = nir_imul_imm(b, index_in_ubo, descriptor_size);
if (is_sampler_handle)
offset = nir_iadd_imm(b, offset, 4);
return load_vulkan_ssbo(b,
var->data.descriptor_set,
offset,
1);
}
static bool
lower_vulkan_resource_index(nir_builder *b, nir_intrinsic_instr *intr,
struct dxil_spirv_nir_lower_bindless_options *options)
{
struct dxil_spirv_binding_remapping remap = {
.descriptor_set = nir_intrinsic_desc_set(intr),
.binding = nir_intrinsic_binding(intr)
};
if (remap.descriptor_set >= options->num_descriptor_sets)
return false;
options->remap_binding(&remap, options->callback_context);
b->cursor = nir_before_instr(&intr->instr);
nir_def *index = intr->src[0].ssa;
nir_def *index_in_ubo = nir_iadd_imm(b, index, remap.binding);
nir_def *res_idx =
load_vulkan_ssbo(b, remap.descriptor_set, nir_imul_imm(b, index_in_ubo, descriptor_size), 2);
nir_def_rewrite_uses(&intr->def, res_idx);
return true;
}
static bool
lower_bindless_tex_src(nir_builder *b, nir_tex_instr *tex,
nir_tex_src_type old, nir_tex_src_type new,
bool is_sampler_handle,
struct dxil_spirv_nir_lower_bindless_options *options)
{
int index = nir_tex_instr_src_index(tex, old);
if (index == -1)
return false;
b->cursor = nir_before_instr(&tex->instr);
nir_deref_instr *deref = nir_src_as_deref(tex->src[index].src);
nir_def *handle = lower_deref_to_index(b, deref, is_sampler_handle, options);
if (!handle)
return false;
nir_src_rewrite(&tex->src[index].src, handle);
tex->src[index].src_type = new;
return true;
}
static bool
lower_bindless_tex(nir_builder *b, nir_tex_instr *tex, struct dxil_spirv_nir_lower_bindless_options *options)
{
bool texture = lower_bindless_tex_src(b, tex, nir_tex_src_texture_deref, nir_tex_src_texture_handle, false, options);
bool sampler = lower_bindless_tex_src(b, tex, nir_tex_src_sampler_deref, nir_tex_src_sampler_handle, true, options);
return texture || sampler;
}
static bool
lower_bindless_image_intr(nir_builder *b, nir_intrinsic_instr *intr, struct dxil_spirv_nir_lower_bindless_options *options)
{
b->cursor = nir_before_instr(&intr->instr);
nir_deref_instr *deref = nir_src_as_deref(intr->src[0]);
nir_def *handle = lower_deref_to_index(b, deref, false, options);
if (!handle)
return false;
nir_rewrite_image_intrinsic(intr, handle, nir_image_intrinsic_type_bindless);
return true;
}
static bool
lower_bindless_instr(nir_builder *b, nir_instr *instr, void *data)
{
struct dxil_spirv_nir_lower_bindless_options *options = data;
if (instr->type == nir_instr_type_tex)
return lower_bindless_tex(b, nir_instr_as_tex(instr), options);
if (instr->type != nir_instr_type_intrinsic)
return false;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
switch (intr->intrinsic) {
case nir_intrinsic_image_deref_load:
case nir_intrinsic_image_deref_store:
case nir_intrinsic_image_deref_size:
case nir_intrinsic_image_deref_atomic:
case nir_intrinsic_image_deref_atomic_swap:
return lower_bindless_image_intr(b, intr, options);
case nir_intrinsic_vulkan_resource_index:
return lower_vulkan_resource_index(b, intr, options);
default:
return false;
}
}
static nir_variable *
add_bindless_data_var(nir_shader *nir, unsigned binding)
{
const struct glsl_type *array_type =
glsl_array_type(glsl_uint_type(), 0, sizeof(unsigned));
const struct glsl_struct_field field = {array_type, "arr"};
nir_variable *var = nir_variable_create(
nir, nir_var_mem_ssbo,
glsl_struct_type(&field, 1, "bindless_data", false), "bindless_data");
var->data.binding = binding;
var->data.how_declared = nir_var_hidden;
var->data.read_only = 1;
var->data.access = ACCESS_NON_WRITEABLE;
return var;
}
static bool
can_remove_var(nir_variable *var, void *data)
{
struct dxil_spirv_nir_lower_bindless_options *options = data;
if (var->data.descriptor_set >= options->num_descriptor_sets)
return false;
if (!glsl_type_is_sampler(glsl_without_array(var->type)))
return true;
struct dxil_spirv_binding_remapping remap = {
.descriptor_set = var->data.descriptor_set,
.binding = var->data.binding,
.is_sampler = true,
};
options->remap_binding(&remap, options->callback_context);
if (remap.descriptor_set == ~0)
return false;
return true;
}
bool
dxil_spirv_nir_lower_bindless(nir_shader *nir, struct dxil_spirv_nir_lower_bindless_options *options)
{
/* While we still have derefs for images, use that to propagate type info back to image vars,
* and then forward to the intrinsics that reference them. */
bool ret = dxil_nir_guess_image_formats(nir);
ret |= nir_shader_instructions_pass(nir, lower_bindless_instr,
nir_metadata_control_flow |
nir_metadata_loop_analysis,
options);
ret |= nir_remove_dead_derefs(nir);
unsigned descriptor_sets = 0;
const nir_variable_mode modes = nir_var_mem_ubo | nir_var_mem_ssbo | nir_var_image | nir_var_uniform;
nir_foreach_variable_with_modes(var, nir, modes) {
if (var->data.descriptor_set < options->num_descriptor_sets)
descriptor_sets |= (1 << var->data.descriptor_set);
}
if (options->dynamic_buffer_binding != ~0)
descriptor_sets |= (1 << options->dynamic_buffer_binding);
nir_remove_dead_variables_options dead_var_options = {
.can_remove_var = can_remove_var,
.can_remove_var_data = options
};
ret |= nir_remove_dead_variables(nir, modes, &dead_var_options);
if (!descriptor_sets)
return ret;
while (descriptor_sets) {
int index = u_bit_scan(&descriptor_sets);
add_bindless_data_var(nir, index);
}
return true;
}
/* Given a global deref chain that starts as a pointer value and ends with a load/store/atomic,
* create a new SSBO deref chain. The new chain starts with a load_vulkan_descriptor, then casts
* the resulting vec2 to an SSBO deref. */
static bool
lower_buffer_device_address(nir_builder *b, nir_intrinsic_instr *intr, void *data)
{
switch (intr->intrinsic) {
case nir_intrinsic_load_deref:
case nir_intrinsic_store_deref:
case nir_intrinsic_deref_atomic:
case nir_intrinsic_deref_atomic_swap:
break;
default:
assert(intr->intrinsic != nir_intrinsic_copy_deref);
return false;
}
nir_deref_instr *deref = nir_src_as_deref(intr->src[0]);
if (!nir_deref_mode_is(deref, nir_var_mem_global))
return false;
nir_deref_path path;
nir_deref_path_init(&path, deref, NULL);
nir_deref_instr *old_head = path.path[0];
assert(old_head->deref_type == nir_deref_type_cast &&
old_head->parent.ssa->bit_size == 64 &&
old_head->parent.ssa->num_components == 1);
b->cursor = nir_after_instr(&old_head->instr);
nir_def *pointer = old_head->parent.ssa;
nir_def *offset = nir_unpack_64_2x32_split_x(b, pointer);
nir_def *index = nir_iand_imm(b, nir_unpack_64_2x32_split_y(b, pointer), 0xffffff);
nir_def *descriptor = nir_load_vulkan_descriptor(b, 2, 32, nir_vec2(b, index, offset),
.desc_type = nir_descriptor_type_storage_buffer);
nir_deref_instr *head = nir_build_deref_cast_with_alignment(b, descriptor, nir_var_mem_ssbo, old_head->type,
old_head->cast.ptr_stride,
old_head->cast.align_mul,
old_head->cast.align_offset);
for (int i = 1; path.path[i]; ++i) {
nir_deref_instr *old = path.path[i];
b->cursor = nir_after_instr(&old->instr);
head = nir_build_deref_follower(b, head, old);
}
nir_src_rewrite(&intr->src[0], &head->def);
nir_deref_path_finish(&path);
return true;
}
bool
dxil_spirv_nir_lower_buffer_device_address(nir_shader *nir)
{
return nir_shader_intrinsics_pass(nir, lower_buffer_device_address,
nir_metadata_control_flow |
nir_metadata_loop_analysis,
NULL);
}
+36
View File
@@ -0,0 +1,36 @@
# Copyright © Microsoft Corporation
# SPDX-License-Identifier: MIT
libspirv_to_dxil = both_libraries(
'spirv_to_dxil',
[
files(
'dxil_spirv_nir.c',
'dxil_spirv_nir.h',
'dxil_spirv_nir_lower_bindless.c',
'spirv_to_dxil.c',
'spirv_to_dxil.h',
),
sha1_h,
],
vs_module_defs : 'spirv_to_dxil.def',
dependencies : [idep_nir, idep_vtn, idep_libdxil_compiler],
include_directories : [inc_include, inc_src],
install : true,
)
idep_libspirv_to_dxil = declare_dependency(
link_with : libspirv_to_dxil.get_static_lib(),
include_directories : include_directories('.')
)
spirv_to_dxil = executable(
'spirv2dxil',
files(
'spirv2dxil.c',
),
dependencies : [idep_nir, idep_libdxil_compiler, idep_getopt, idep_libspirv_to_dxil],
include_directories : [inc_include, inc_src],
build_by_default : true,
install : true,
)
+303
View File
@@ -0,0 +1,303 @@
/*
* Copyright © 2015 Intel Corporation
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/*
* A simple executable that opens a SPIR-V shader, converts it to DXIL via
* NIR, and dumps out the result. This should be useful for testing the
* nir_to_dxil code. Based on spirv2nir.c.
*/
#include "nir_to_dxil.h"
#include "dxil_validator.h"
#include "spirv/nir_spirv.h"
#include "spirv_to_dxil.h"
#include "dxil_spirv_nir.h"
#include "util/os_file.h"
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <string.h>
#define WORD_SIZE 4
static mesa_shader_stage
stage_to_enum(char *stage)
{
if (!strcmp(stage, "vertex"))
return MESA_SHADER_VERTEX;
else if (!strcmp(stage, "tess-ctrl"))
return MESA_SHADER_TESS_CTRL;
else if (!strcmp(stage, "tess-eval"))
return MESA_SHADER_TESS_EVAL;
else if (!strcmp(stage, "geometry"))
return MESA_SHADER_GEOMETRY;
else if (!strcmp(stage, "fragment"))
return MESA_SHADER_FRAGMENT;
else if (!strcmp(stage, "compute"))
return MESA_SHADER_COMPUTE;
else
return MESA_SHADER_NONE;
}
static void
log_spirv_to_dxil_error(void *priv, const char *msg)
{
fprintf(stderr, "spirv_to_dxil error: %s", msg);
}
struct shader {
const char *entry_point;
const char *output_file;
nir_shader *nir;
};
bool validate = false, debug = false;
enum dxil_validator_version val_ver = DXIL_VALIDATOR_1_4;
struct nir_shader_compiler_options nir_options;
static bool
compile_shader(const char *filename, mesa_shader_stage shader_stage, struct shader *shader,
struct dxil_spirv_runtime_conf *conf)
{
size_t file_size;
char *file_contents = os_read_file(filename, &file_size);
if (!file_contents) {
fprintf(stderr, "Failed to open %s\n", filename);
return false;
}
if (file_size % WORD_SIZE != 0) {
fprintf(stderr, "%s size == %zu is not a multiple of %d\n", filename,
file_size, WORD_SIZE);
free(file_contents);
return false;
}
size_t word_count = file_size / WORD_SIZE;
const struct spirv_to_nir_options *spirv_opts = dxil_spirv_nir_get_spirv_options();
shader->nir = spirv_to_nir(
(const uint32_t *)file_contents, word_count, NULL,
(mesa_shader_stage)shader_stage, shader->entry_point,
spirv_opts, &nir_options);
free(file_contents);
if (!shader->nir) {
fprintf(stderr, "SPIR-V to NIR failed\n");
return false;
}
nir_validate_shader(shader->nir,
"Validate before feeding NIR to the DXIL compiler");
dxil_spirv_nir_prep(shader->nir);
struct dxil_spirv_metadata metadata = { 0 };
dxil_spirv_nir_passes(shader->nir, conf, &metadata);
if (debug)
nir_print_shader(shader->nir, stderr);
return true;
}
#if DETECT_OS_WINDOWS
static bool
validate_dxil(struct blob *blob)
{
struct dxil_validator *val = dxil_create_validator(NULL);
char *err;
bool res = dxil_validate_module(val, blob->data,
blob->size, &err);
if (!res && err)
fprintf(stderr, "DXIL: %s\n\n", err);
dxil_destroy_validator(val);
return res;
}
#else
static bool
validate_dxil(struct blob *blob)
{
fprintf(stderr, "DXIL validation only available in Windows.\n");
return false;
}
#endif
int
main(int argc, char **argv)
{
glsl_type_singleton_init_or_ref();
int ch;
static struct option long_options[] = {
{"stage", required_argument, 0, 's'},
{"entry", required_argument, 0, 'e'},
{"output", required_argument, 0, 'o'},
{"validate", no_argument, 0, 'v'},
{"debug", no_argument, 0, 'd'},
{"shadermodel", required_argument, 0, 'm'},
{"validatorver", required_argument, 0, 'x'},
{0, 0, 0, 0}};
struct shader shaders[MESA_SHADER_COMPUTE + 1];
memset(shaders, 0, sizeof(shaders));
struct shader cur_shader = {
.entry_point = "main",
.output_file = NULL,
};
mesa_shader_stage shader_stage = MESA_SHADER_FRAGMENT;
struct dxil_spirv_runtime_conf conf;
memset(&conf, 0, sizeof(conf));
conf.runtime_data_cbv.base_shader_register = 0;
conf.runtime_data_cbv.register_space = 31;
conf.push_constant_cbv.base_shader_register = 0;
conf.push_constant_cbv.register_space = 30;
conf.first_vertex_and_base_instance_mode = DXIL_SPIRV_SYSVAL_TYPE_ZERO;
conf.declared_read_only_images_as_srvs = true;
conf.shader_model_max = SHADER_MODEL_6_2;
const unsigned supported_bit_sizes = 16 | 32 | 64;
dxil_get_nir_compiler_options(&nir_options, conf.shader_model_max, supported_bit_sizes, supported_bit_sizes);
// We will manually handle base_vertex when vertex_id and instance_id have
// have been already converted to zero-base.
nir_options.lower_base_vertex = false;
bool any_shaders = false;
while ((ch = getopt_long(argc, argv, "-s:e:o:m:x:vd", long_options, NULL)) !=
-1) {
switch (ch)
{
case 's':
shader_stage = stage_to_enum(optarg);
if (shader_stage == MESA_SHADER_NONE) {
fprintf(stderr, "Unknown stage %s\n", optarg);
return 1;
}
break;
case 'e':
cur_shader.entry_point = optarg;
break;
case 'o':
cur_shader.output_file = optarg;
break;
case 'v':
validate = true;
break;
case 'd':
debug = true;
break;
case 'm':
conf.shader_model_max = SHADER_MODEL_6_0 + atoi(optarg);
conf.first_vertex_and_base_instance_mode = conf.shader_model_max >= SHADER_MODEL_6_8 ?
DXIL_SPIRV_SYSVAL_TYPE_NATIVE : DXIL_SPIRV_SYSVAL_TYPE_ZERO;
break;
case 'x':
val_ver = DXIL_VALIDATOR_1_0 + atoi(optarg);
break;
case 1:
if (!compile_shader(optarg, shader_stage, &cur_shader, &conf))
return 1;
shaders[shader_stage] = cur_shader;
any_shaders = true;
break;
default:
fprintf(stderr, "Unrecognized option.\n");
return 1;
}
}
if (!any_shaders) {
fprintf(stderr, "Specify a shader filename\n");
return 1;
}
for (int32_t cur = MESA_SHADER_FRAGMENT; cur >= MESA_SHADER_VERTEX; --cur) {
if (!shaders[cur].nir)
continue;
for (int32_t prev = cur - 1; prev >= MESA_SHADER_VERTEX; --prev) {
if (!shaders[prev].nir)
continue;
struct dxil_spirv_metadata metadata = { 0 };
dxil_spirv_nir_link(shaders[cur].nir, shaders[prev].nir, &conf, &metadata);
break;
}
}
struct nir_to_dxil_options opts = {
.environment = DXIL_ENVIRONMENT_VULKAN,
.shader_model_max = conf.shader_model_max,
.validator_version_max = val_ver,
};
struct dxil_logger logger_inner = {.priv = NULL,
.log = log_spirv_to_dxil_error};
for (uint32_t i = 0; i <= MESA_SHADER_COMPUTE; ++i) {
if (!shaders[i].nir)
continue;
struct blob dxil_blob;
bool success = nir_to_dxil(shaders[i].nir, &opts, &logger_inner, &dxil_blob);
ralloc_free(shaders[i].nir);
if (!success) {
fprintf(stderr, "Failed to convert to DXIL\n");
if (dxil_blob.allocated)
blob_finish(&dxil_blob);
return false;
}
if (validate && !validate_dxil(&dxil_blob)) {
fprintf(stderr, "Failed to validate DXIL\n");
blob_finish(&dxil_blob);
return 1;
}
if (shaders[i].output_file) {
FILE *file = fopen(shaders[i].output_file, "wb");
if (!file) {
fprintf(stderr, "Failed to open %s, %s\n", shaders[i].output_file,
strerror(errno));
blob_finish(&dxil_blob);
return 1;
}
fwrite(dxil_blob.data, sizeof(char), dxil_blob.size, file);
fclose(file);
blob_finish(&dxil_blob);
}
}
glsl_type_singleton_decref();
return 0;
}
+138
View File
@@ -0,0 +1,138 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_spirv_nir.h"
#include "spirv_to_dxil.h"
#include "dxil_nir.h"
#include "nir_to_dxil.h"
#include "shader_enums.h"
#include "spirv/nir_spirv.h"
#include "util/blob.h"
#include "git_sha1.h"
#include "vulkan/vulkan.h"
static_assert((mesa_shader_stage)DXIL_SPIRV_SHADER_NONE == MESA_SHADER_NONE, "must match");
static_assert((mesa_shader_stage)DXIL_SPIRV_SHADER_VERTEX == MESA_SHADER_VERTEX, "must match");
static_assert((mesa_shader_stage)DXIL_SPIRV_SHADER_TESS_CTRL == MESA_SHADER_TESS_CTRL, "must match");
static_assert((mesa_shader_stage)DXIL_SPIRV_SHADER_TESS_EVAL == MESA_SHADER_TESS_EVAL, "must match");
static_assert((mesa_shader_stage)DXIL_SPIRV_SHADER_GEOMETRY == MESA_SHADER_GEOMETRY, "must match");
static_assert((mesa_shader_stage)DXIL_SPIRV_SHADER_FRAGMENT == MESA_SHADER_FRAGMENT, "must match");
static_assert((mesa_shader_stage)DXIL_SPIRV_SHADER_COMPUTE == MESA_SHADER_COMPUTE, "must match");
static_assert((mesa_shader_stage)DXIL_SPIRV_SHADER_KERNEL == MESA_SHADER_KERNEL, "must match");
bool
spirv_to_dxil(const uint32_t *words, size_t word_count,
struct dxil_spirv_specialization *specializations,
unsigned int num_specializations, dxil_spirv_shader_stage stage,
const char *entry_point_name,
enum dxil_validator_version validator_version_max,
const struct dxil_spirv_debug_options *dgb_opts,
const struct dxil_spirv_runtime_conf *conf,
const struct dxil_spirv_logger *logger,
struct dxil_spirv_object *out_dxil)
{
if (stage == DXIL_SPIRV_SHADER_NONE || stage == DXIL_SPIRV_SHADER_KERNEL)
return false;
glsl_type_singleton_init_or_ref();
struct nir_to_dxil_options opts = {
.environment = DXIL_ENVIRONMENT_VULKAN,
.shader_model_max = conf->shader_model_max,
.validator_version_max = validator_version_max,
};
const struct spirv_to_nir_options *spirv_opts = dxil_spirv_nir_get_spirv_options();
nir_shader_compiler_options nir_options;
const unsigned supported_bit_sizes = 16 | 32 | 64;
dxil_get_nir_compiler_options(&nir_options, conf->shader_model_max, supported_bit_sizes, supported_bit_sizes);
// We will manually handle base_vertex when vertex_id and instance_id have
// have been already converted to zero-base.
nir_options.lower_base_vertex = conf->first_vertex_and_base_instance_mode != DXIL_SPIRV_SYSVAL_TYPE_ZERO;
struct nir_spirv_specialization *spec = NULL;
if (specializations && num_specializations > 0) {
spec = vtn_alloc_specialization(num_specializations);
for (unsigned i = 0; i < num_specializations; i++) {
vtn_add_specialization_entry(spec, i, specializations[i].id,
sizeof(specializations[i].value),
&specializations[i].value, false);
}
}
nir_shader *nir = spirv_to_nir(words, word_count, spec,
(mesa_shader_stage)stage, entry_point_name,
spirv_opts, &nir_options);
vtn_free_specialization(spec);
if (!nir) {
glsl_type_singleton_decref();
return false;
}
nir_validate_shader(nir,
"Validate before feeding NIR to the DXIL compiler");
dxil_spirv_nir_prep(nir);
dxil_spirv_nir_passes(nir, conf, &out_dxil->metadata);
if (dgb_opts->dump_nir)
nir_print_shader(nir, stderr);
struct dxil_logger logger_inner = {.priv = logger->priv,
.log = logger->log};
struct blob dxil_blob;
if (!nir_to_dxil(nir, &opts, &logger_inner, &dxil_blob)) {
if (dxil_blob.allocated)
blob_finish(&dxil_blob);
ralloc_free(nir);
glsl_type_singleton_decref();
return false;
}
ralloc_free(nir);
blob_finish_get_buffer(&dxil_blob, &out_dxil->binary.buffer,
&out_dxil->binary.size);
glsl_type_singleton_decref();
return true;
}
void
spirv_to_dxil_free(struct dxil_spirv_object *dxil)
{
free(dxil->binary.buffer);
}
uint64_t
spirv_to_dxil_get_version()
{
const char sha1[] = MESA_GIT_SHA1;
const char* dash = strchr(sha1, '-');
if (dash) {
return strtoull(dash + 1, NULL, 16);
}
return 0;
}
@@ -0,0 +1,4 @@
EXPORTS
spirv_to_dxil
spirv_to_dxil_free
spirv_to_dxil_get_version
+251
View File
@@ -0,0 +1,251 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef SPIRV_TO_DXIL_H
#define SPIRV_TO_DXIL_H
#include "dxil_versions.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// NB: I've copy and pasted some types into this header so we don't have to
// include other headers. This will surely break if any of these types change.
// Copy of mesa_shader_stage
typedef enum {
DXIL_SPIRV_SHADER_NONE = -1,
DXIL_SPIRV_SHADER_VERTEX = 0,
DXIL_SPIRV_SHADER_TESS_CTRL = 1,
DXIL_SPIRV_SHADER_TESS_EVAL = 2,
DXIL_SPIRV_SHADER_GEOMETRY = 3,
DXIL_SPIRV_SHADER_FRAGMENT = 4,
DXIL_SPIRV_SHADER_COMPUTE = 5,
DXIL_SPIRV_SHADER_KERNEL = 14,
} dxil_spirv_shader_stage;
// Copy of nir_spirv_const_value
typedef union {
bool b;
float f32;
double f64;
int8_t i8;
uint8_t u8;
int16_t i16;
uint16_t u16;
int32_t i32;
uint32_t u32;
int64_t i64;
uint64_t u64;
} dxil_spirv_const_value;
struct dxil_spirv_specialization {
uint32_t id;
dxil_spirv_const_value value;
bool defined_on_module;
};
struct dxil_spirv_metadata {
// Some sysval or other type of data is accessed which needs to be piped
// from the app/API implementation into the shader via a buffer
bool requires_runtime_data;
// Specifically if a vertex shader needs the first-vertex or base-instance
// sysval. These are relevant since these can come from an indirect arg
// buffer, and therefore piping them to the runtime data buffer is extra
// complex.
bool needs_draw_sysvals;
};
struct dxil_spirv_object {
struct dxil_spirv_metadata metadata;
struct {
void *buffer;
size_t size;
} binary;
};
/* This struct describes the layout of data expected in the CB bound to
* runtime_data_cbv during compute shader execution */
struct dxil_spirv_compute_runtime_data {
/* Total number of groups dispatched (i.e. value passed to Dispatch()) */
uint32_t group_count_x;
uint32_t group_count_y;
uint32_t group_count_z;
uint32_t padding0;
/* Base */
uint32_t base_group_x;
uint32_t base_group_y;
uint32_t base_group_z;
};
#define DXIL_SPIRV_Y_FLIP_MASK BITFIELD_MASK(DXIL_SPIRV_MAX_VIEWPORT)
#define DXIL_SPIRV_Z_FLIP_SHIFT DXIL_SPIRV_MAX_VIEWPORT
#define DXIL_SPIRV_Z_FLIP_MASK BITFIELD_RANGE(DXIL_SPIRV_Z_FLIP_SHIFT, DXIL_SPIRV_MAX_VIEWPORT)
/* This struct describes the layout of data expected in the CB bound to
* runtime_data_cbv during vertex stages */
struct dxil_spirv_vertex_runtime_data {
uint32_t first_vertex;
uint32_t base_instance;
bool is_indexed_draw;
// The lower 16bits of this mask encode Y-flips (one bit per viewport)
// The higher 16bits of this maks encode Z-flips (one bit per viewport)
union {
uint32_t yz_flip_mask;
struct {
uint16_t y_flip_mask;
uint16_t z_flip_mask;
};
};
uint32_t draw_id;
float viewport_width;
float viewport_height;
uint32_t view_index;
/* When depth bias is dynamic, the constant value to add to point
* primitives when emulating triangle point fill mode. Slope-scaled
* depth bias is currently unsupported. */
float depth_bias;
};
enum dxil_spirv_yz_flip_mode {
DXIL_SPIRV_YZ_FLIP_NONE = 0,
// Y-flip is unconditional: pos.y = -pos.y
// Z-flip is unconditional: pos.z = -pos.z + 1.0f
DXIL_SPIRV_Y_FLIP_UNCONDITIONAL = 1 << 0,
DXIL_SPIRV_Z_FLIP_UNCONDITIONAL = 1 << 1,
DXIL_SPIRV_YZ_FLIP_UNCONDITIONAL = DXIL_SPIRV_Y_FLIP_UNCONDITIONAL | DXIL_SPIRV_Z_FLIP_UNCONDITIONAL,
// Y-flip/Z-flip info are passed through a sysval
DXIL_SPIRV_Y_FLIP_CONDITIONAL = 1 << 2,
DXIL_SPIRV_Z_FLIP_CONDITIONAL = 1 << 3,
DXIL_SPIRV_YZ_FLIP_CONDITIONAL = DXIL_SPIRV_Y_FLIP_CONDITIONAL | DXIL_SPIRV_Z_FLIP_CONDITIONAL,
};
#define DXIL_SPIRV_MAX_VIEWPORT 16
enum dxil_spirv_sysval_type {
// The sysval can be inlined in the shader as a constant zero
DXIL_SPIRV_SYSVAL_TYPE_ZERO,
// The sysval has a supported DXIL equivalent
DXIL_SPIRV_SYSVAL_TYPE_NATIVE,
// The sysval might be nonzero and has no DXIL equivalent, so it
// will need to be provided by the runtime_data constant buffer
DXIL_SPIRV_SYSVAL_TYPE_RUNTIME_DATA,
};
struct dxil_spirv_runtime_conf {
struct {
uint32_t register_space;
uint32_t base_shader_register;
} runtime_data_cbv;
struct {
uint32_t register_space;
uint32_t base_shader_register;
} push_constant_cbv;
enum dxil_spirv_sysval_type first_vertex_and_base_instance_mode;
enum dxil_spirv_sysval_type workgroup_id_mode;
struct {
// mode != DXIL_SPIRV_YZ_FLIP_NONE only valid on vertex/geometry stages.
enum dxil_spirv_yz_flip_mode mode;
// Y/Z flip masks (one bit per viewport)
uint16_t y_mask;
uint16_t z_mask;
} yz_flip;
// The caller supports read-only images to be turned into SRV accesses,
// which allows us to run the nir_opt_access() pass
bool declared_read_only_images_as_srvs;
// The caller supports read-write images to be turned into SRV accesses,
// if they are found not to be written
bool inferred_read_only_images_as_srvs;
// Force sample rate shading on a fragment shader
bool force_sample_rate_shading;
// View index needs to be lowered to a UBO lookup
bool lower_view_index;
// View index also needs to be forwarded to RT layer output
bool lower_view_index_to_rt_layer;
// Affects which features can be used by the shader
enum dxil_shader_model shader_model_max;
};
struct dxil_spirv_debug_options {
bool dump_nir;
};
typedef void (*dxil_spirv_msg_callback)(void *priv, const char *msg);
struct dxil_spirv_logger {
void *priv;
dxil_spirv_msg_callback log;
};
/**
* Compile a SPIR-V module into DXIL.
* \param words SPIR-V module to compile
* \param word_count number of words in the SPIR-V module
* \param specializations specialization constants to compile with the shader
* \param num_specializations number of specialization constants
* \param stage shader stage
* \param entry_point_name name of shader entrypoint
* \param conf configuration for spriv_to_dxil
* \param out_dxil will contain the DXIL bytes on success (call spirv_to_dxil_free after use)
* \return true if compilation succeeded
*/
bool
spirv_to_dxil(const uint32_t *words, size_t word_count,
struct dxil_spirv_specialization *specializations,
unsigned int num_specializations, dxil_spirv_shader_stage stage,
const char *entry_point_name,
enum dxil_validator_version validator_version_max,
const struct dxil_spirv_debug_options *debug_options,
const struct dxil_spirv_runtime_conf *conf,
const struct dxil_spirv_logger *logger,
struct dxil_spirv_object *out_dxil);
/**
* Free the buffer allocated by spirv_to_dxil.
*/
void
spirv_to_dxil_free(struct dxil_spirv_object *dxil);
uint64_t
spirv_to_dxil_get_version(void);
#ifdef __cplusplus
}
#endif
#endif
+123
View File
@@ -0,0 +1,123 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/* The purpose of this file is to abstract the differences between the Windows
* C ABI for D3D12 and the Linux ABI. Essentially, for class methods that return
* structures, the MSVC C++ ABI specifies that they are always called with the return
* structure allocated by the caller, and passed as a hidden second parameter,
* after "this". But the C compiler doesn't apply that automatically to the C
* equivalent definition of the method, and so that ABI needs to be explicitly
* embedded in the C function signature. For Linux, no such ABI difference between
* C and C++ exists, and so C callers should use the same signature as C++.
*/
#ifndef DZN_ABI_HELPER_H
#define DZN_ABI_HELPER_H
static inline D3D12_HEAP_PROPERTIES
dzn_ID3D12Device4_GetCustomHeapProperties(ID3D12Device4 *dev, UINT node_mask, D3D12_HEAP_TYPE type)
{
D3D12_HEAP_PROPERTIES ret;
#ifdef _WIN32
ID3D12Device4_GetCustomHeapProperties(dev, &ret, node_mask, type);
#else
ret = ID3D12Device4_GetCustomHeapProperties(dev, node_mask, type);
#endif
return ret;
}
static inline D3D12_RESOURCE_ALLOCATION_INFO
dzn_ID3D12Device4_GetResourceAllocationInfo(ID3D12Device4 *dev, UINT visible_mask, UINT num_resource_descs, const D3D12_RESOURCE_DESC *resource_descs)
{
D3D12_RESOURCE_ALLOCATION_INFO ret;
#ifdef _WIN32
ID3D12Device4_GetResourceAllocationInfo(dev, &ret, visible_mask, num_resource_descs, resource_descs);
#else
ret = ID3D12Device4_GetResourceAllocationInfo(dev, visible_mask, num_resource_descs, resource_descs);
#endif
return ret;
}
static inline D3D12_RESOURCE_ALLOCATION_INFO
dzn_ID3D12Device12_GetResourceAllocationInfo3(ID3D12Device12 *dev, UINT visible_mask, UINT num_resource_descs, const D3D12_RESOURCE_DESC1 *resource_descs,
const UINT *num_castable_formats, const DXGI_FORMAT *const *castable_formats,
D3D12_RESOURCE_ALLOCATION_INFO1 *allocation_info1)
{
D3D12_RESOURCE_ALLOCATION_INFO ret;
#ifdef _WIN32
ID3D12Device12_GetResourceAllocationInfo3(dev, &ret, visible_mask, num_resource_descs, resource_descs, num_castable_formats, castable_formats, allocation_info1);
#else
ret = ID3D12Device12_GetResourceAllocationInfo3(dev, visible_mask, num_resource_descs, resource_descs, num_castable_formats, castable_formats, allocation_info1);
#endif
return ret;
}
static inline D3D12_RESOURCE_DESC
dzn_ID3D12Resource_GetDesc(ID3D12Resource *res)
{
D3D12_RESOURCE_DESC ret;
#ifdef _WIN32
ID3D12Resource_GetDesc(res, &ret);
#else
ret = ID3D12Resource_GetDesc(res);
#endif
return ret;
}
static inline D3D12_HEAP_DESC
dzn_ID3D12Heap_GetDesc(ID3D12Heap *heap)
{
D3D12_HEAP_DESC ret;
#ifdef _WIN32
ID3D12Heap_GetDesc(heap, &ret);
#else
ret = ID3D12Heap_GetDesc(heap);
#endif
return ret;
}
static inline D3D12_CPU_DESCRIPTOR_HANDLE
dzn_ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
{
D3D12_CPU_DESCRIPTOR_HANDLE ret;
#ifdef _WIN32
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(heap, &ret);
#else
ret = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(heap);
#endif
return ret;
}
static inline D3D12_GPU_DESCRIPTOR_HANDLE
dzn_ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
{
D3D12_GPU_DESCRIPTOR_HANDLE ret;
#ifdef _WIN32
ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(heap, &ret);
#else
ret = ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(heap);
#endif
return ret;
}
#endif /*DZN_ABI_HELPER_H*/
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+119
View File
@@ -0,0 +1,119 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dzn_physical_device_enum.h"
#include <directx/dxcore.h>
#include <dxguids/dxguids.h>
#include "util/u_dl.h"
#include "util/log.h"
VkResult
dzn_enumerate_physical_devices_dxcore(struct vk_instance *instance)
{
util_dl_library *dxcore = util_dl_open(UTIL_DL_PREFIX "dxcore" UTIL_DL_EXT);
if (!dxcore) {
mesa_loge("Failed to load DXCore\n");
return VK_ERROR_INITIALIZATION_FAILED;
}
using PFNDXCoreCreateAdapterFactory = HRESULT (APIENTRY*)(REFIID, void **);
PFNDXCoreCreateAdapterFactory create_func = (PFNDXCoreCreateAdapterFactory)util_dl_get_proc_address(dxcore, "DXCoreCreateAdapterFactory");
if (!create_func) {
mesa_loge("Failed to load DXCoreCreateAdapterFactory\n");
return VK_ERROR_INITIALIZATION_FAILED;
}
IDXCoreAdapterFactory *factory;
if (FAILED(create_func(IID_PPV_ARGS(&factory)))) {
mesa_loge("Failed to create DXCore adapter factory\n");
return VK_ERROR_INITIALIZATION_FAILED;
}
IDXCoreAdapterList *list;
if (FAILED(factory->CreateAdapterList(1, &DXCORE_ADAPTER_ATTRIBUTE_D3D12_GRAPHICS, IID_PPV_ARGS(&list)))) {
factory->Release();
mesa_loge("Failed to create DXCore adapter list\n");
return VK_ERROR_INITIALIZATION_FAILED;
}
VkResult result = VK_SUCCESS;
uint32_t adapter_count = list->GetAdapterCount();
IDXCoreAdapter *adapter;
for (uint32_t i = 0; i < adapter_count && result == VK_SUCCESS; ++i) {
result = VK_ERROR_INITIALIZATION_FAILED;
if (SUCCEEDED(list->GetAdapter(i, IID_PPV_ARGS(&adapter)))) {
dzn_physical_device_desc desc = { 0 };
DXCoreHardwareID hardware_id;
bool is_hardware;
if (FAILED(adapter->GetProperty(DXCoreAdapterProperty::HardwareID, &hardware_id)) ||
FAILED(adapter->GetProperty(DXCoreAdapterProperty::DedicatedAdapterMemory, &desc.dedicated_video_memory)) ||
FAILED(adapter->GetProperty(DXCoreAdapterProperty::SharedSystemMemory, &desc.shared_system_memory)) ||
FAILED(adapter->GetProperty(DXCoreAdapterProperty::DedicatedSystemMemory, &desc.dedicated_system_memory)) ||
FAILED(adapter->GetProperty(DXCoreAdapterProperty::InstanceLuid, &desc.adapter_luid)) ||
FAILED(adapter->GetProperty(DXCoreAdapterProperty::IsHardware, &is_hardware)) ||
FAILED(adapter->GetProperty(DXCoreAdapterProperty::DriverDescription, sizeof(desc.description), desc.description))) {
mesa_loge("Failed to retrieve DXCore adapter properties\n");
result = VK_ERROR_INITIALIZATION_FAILED;
} else {
desc.vendor_id = hardware_id.vendorID;
desc.device_id = hardware_id.deviceID;
desc.subsys_id = hardware_id.subSysID;
desc.revision = hardware_id.revision;
desc.is_warp = !is_hardware;
result = dzn_instance_add_physical_device(instance, adapter, &desc);
}
adapter->Release();
}
}
list->Release();
factory->Release();
return result;
}
void
dzn_query_memory_info(IUnknown* unk, d3d12_memory_info* output){
IDXCoreAdapter* adapter = NULL;
HRESULT hr = unk->QueryInterface(
__uuidof(IDXCoreAdapter),
reinterpret_cast<void**>(&adapter));
if(SUCCEEDED(hr)){
DXCoreAdapterMemoryBudget local_info, nonlocal_info;
DXCoreAdapterMemoryBudgetNodeSegmentGroup local_node_segment = { 0, DXCoreSegmentGroup::Local };
DXCoreAdapterMemoryBudgetNodeSegmentGroup nonlocal_node_segment = { 0, DXCoreSegmentGroup::NonLocal };
adapter->QueryState(DXCoreAdapterState::AdapterMemoryBudget, &local_node_segment, &local_info);
adapter->QueryState(DXCoreAdapterState::AdapterMemoryBudget, &nonlocal_node_segment, &nonlocal_info);
output->budget_local = local_info.budget;
output->budget_nonlocal = nonlocal_info.budget;
output->budget = local_info.budget + nonlocal_info.budget;
output->usage_local = local_info.currentUsage;
output->usage_nonlocal = nonlocal_info.currentUsage;
output->usage = local_info.currentUsage + nonlocal_info.currentUsage;
return;
}
}
+102
View File
@@ -0,0 +1,102 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#define COBJMACROS
#include "dzn_physical_device_enum.h"
#include "dzn_dxgi.h"
#include "util/log.h"
VkResult
dzn_enumerate_physical_devices_dxgi(struct vk_instance *instance)
{
IDXGIFactory4 *factory = dxgi_get_factory(false);
IDXGIAdapter1 *adapter = NULL;
VkResult result = VK_SUCCESS;
for (UINT i = 0; SUCCEEDED(IDXGIFactory4_EnumAdapters1(factory, i, &adapter)); ++i) {
DXGI_ADAPTER_DESC1 dxgi_desc;
IDXGIAdapter1_GetDesc1(adapter, &dxgi_desc);
struct dzn_physical_device_desc desc = {
.adapter_luid = dxgi_desc.AdapterLuid,
.vendor_id = dxgi_desc.VendorId,
.device_id = dxgi_desc.DeviceId,
.subsys_id = dxgi_desc.SubSysId,
.revision = dxgi_desc.Revision,
.shared_system_memory = dxgi_desc.SharedSystemMemory,
.dedicated_system_memory = dxgi_desc.DedicatedSystemMemory,
.dedicated_video_memory = dxgi_desc.DedicatedVideoMemory,
.is_warp = (dxgi_desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) != 0,
};
WideCharToMultiByte(CP_ACP, 0, dxgi_desc.Description, ARRAYSIZE(dxgi_desc.Description),
desc.description, ARRAYSIZE(desc.description), NULL, NULL);
result =
dzn_instance_add_physical_device(instance, (IUnknown *)adapter, &desc);
IDXGIAdapter1_Release(adapter);
if (result != VK_SUCCESS)
break;
}
IDXGIFactory4_Release(factory);
return result;
}
IDXGIFactory4 *
dxgi_get_factory(bool debug)
{
static const GUID IID_IDXGIFactory4 = {
0x1bc6ea02, 0xef36, 0x464f,
{ 0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a }
};
HMODULE dxgi_mod = LoadLibraryA("DXGI.DLL");
if (!dxgi_mod) {
mesa_loge("failed to load DXGI.DLL\n");
return NULL;
}
typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY2)(UINT flags, REFIID riid, void **ppFactory);
PFN_CREATE_DXGI_FACTORY2 CreateDXGIFactory2;
CreateDXGIFactory2 = (PFN_CREATE_DXGI_FACTORY2)GetProcAddress(dxgi_mod, "CreateDXGIFactory2");
if (!CreateDXGIFactory2) {
mesa_loge("failed to load CreateDXGIFactory2 from DXGI.DLL\n");
return NULL;
}
UINT flags = 0;
if (debug)
flags |= DXGI_CREATE_FACTORY_DEBUG;
IDXGIFactory4 *factory;
HRESULT hr = CreateDXGIFactory2(flags, &IID_IDXGIFactory4, (void **)&factory);
if (FAILED(hr)) {
mesa_loge("CreateDXGIFactory2 failed: %08x\n", (int32_t)hr);
return NULL;
}
return factory;
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DZN_DXGI_H
#define DZN_DXGI_H
#include <dxgi1_4.h>
struct dzn_instance;
IDXGIFactory4 *
dxgi_get_factory(bool debug);
#endif /* DZN_DXGI_H */
File diff suppressed because it is too large. Load diff
+850
View File
@@ -0,0 +1,850 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dzn_private.h"
#include "spirv_to_dxil.h"
#include "nir_to_dxil.h"
#include "dxil_nir.h"
#include "dxil_nir_lower_int_samplers.h"
#include "dxil_validator.h"
static void
dzn_meta_compile_shader(struct dzn_device *device, nir_shader *nir,
D3D12_SHADER_BYTECODE *slot)
{
struct dzn_instance *instance =
container_of(device->vk.physical->instance, struct dzn_instance, vk);
struct dzn_physical_device *pdev =
container_of(device->vk.physical, struct dzn_physical_device, vk);
nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir));
if ((instance->debug_flags & DZN_DEBUG_NIR) &&
(instance->debug_flags & DZN_DEBUG_INTERNAL))
nir_print_shader(nir, stderr);
struct nir_to_dxil_options opts = {
.environment = DXIL_ENVIRONMENT_VULKAN,
.shader_model_max = dzn_get_shader_model(pdev),
#ifdef _WIN32
.validator_version_max = dxil_get_validator_version(instance->dxil_validator),
#endif
};
struct blob dxil_blob;
ASSERTED bool ret = nir_to_dxil(nir, &opts, NULL, &dxil_blob);
assert(ret);
#ifdef _WIN32
char *err = NULL;
bool res = dxil_validate_module(instance->dxil_validator,
dxil_blob.data,
dxil_blob.size, &err);
if ((instance->debug_flags & DZN_DEBUG_DXIL) &&
(instance->debug_flags & DZN_DEBUG_INTERNAL)) {
char *disasm = dxil_disasm_module(instance->dxil_validator,
dxil_blob.data,
dxil_blob.size);
if (disasm) {
fprintf(stderr,
"== BEGIN SHADER ============================================\n"
"%s\n"
"== END SHADER ==============================================\n",
disasm);
ralloc_free(disasm);
}
}
if ((instance->debug_flags & DZN_DEBUG_DXIL) &&
(instance->debug_flags & DZN_DEBUG_INTERNAL) &&
!res && !(instance->debug_flags & DZN_DEBUG_EXPERIMENTAL)) {
fprintf(stderr,
"== VALIDATION ERROR =============================================\n"
"%s\n"
"== END ==========================================================\n",
err ? err : "unknown");
ralloc_free(err);
}
assert(res || (instance->debug_flags & DZN_DEBUG_EXPERIMENTAL));
#endif
void *data;
size_t size;
blob_finish_get_buffer(&dxil_blob, &data, &size);
slot->pShaderBytecode = data;
slot->BytecodeLength = size;
}
#define DZN_META_INDIRECT_DRAW_MAX_PARAM_COUNT 5
static void
dzn_meta_indirect_draw_finish(struct dzn_device *device, struct dzn_indirect_draw_type type)
{
struct dzn_meta_indirect_draw *meta = &device->indirect_draws[type.value];
if (meta->root_sig)
ID3D12RootSignature_Release(meta->root_sig);
if (meta->pipeline_state)
ID3D12PipelineState_Release(meta->pipeline_state);
}
static VkResult
dzn_meta_indirect_draw_init(struct dzn_device *device,
struct dzn_indirect_draw_type type)
{
struct dzn_meta_indirect_draw *meta = &device->indirect_draws[type.value];
struct dzn_instance *instance =
container_of(device->vk.physical->instance, struct dzn_instance, vk);
VkResult ret = VK_SUCCESS;
glsl_type_singleton_init_or_ref();
nir_shader *nir = dzn_nir_indirect_draw_shader(type);
uint32_t shader_params_size =
type.triangle_fan_primitive_restart ?
sizeof(struct dzn_indirect_draw_triangle_fan_prim_restart_rewrite_params) :
type.triangle_fan ?
sizeof(struct dzn_indirect_draw_triangle_fan_rewrite_params) :
sizeof(struct dzn_indirect_draw_rewrite_params);
uint32_t root_param_count = 0;
D3D12_ROOT_PARAMETER1 root_params[DZN_META_INDIRECT_DRAW_MAX_PARAM_COUNT];
root_params[root_param_count++] = (D3D12_ROOT_PARAMETER1) {
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
.Constants = {
.ShaderRegister = 0,
.RegisterSpace = 0,
.Num32BitValues = shader_params_size / 4,
},
.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
};
root_params[root_param_count++] = (D3D12_ROOT_PARAMETER1) {
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV,
.Descriptor = {
.ShaderRegister = 1,
.RegisterSpace = 0,
.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
},
.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
};
root_params[root_param_count++] = (D3D12_ROOT_PARAMETER1) {
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV,
.Descriptor = {
.ShaderRegister = 2,
.RegisterSpace = 0,
.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
},
.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
};
if (type.indirect_count) {
root_params[root_param_count++] = (D3D12_ROOT_PARAMETER1) {
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV,
.Descriptor = {
.ShaderRegister = 3,
.RegisterSpace = 0,
.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
},
.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
};
}
if (type.triangle_fan) {
root_params[root_param_count++] = (D3D12_ROOT_PARAMETER1) {
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV,
.Descriptor = {
.ShaderRegister = 4,
.RegisterSpace = 0,
.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
},
.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
};
}
assert(root_param_count <= ARRAY_SIZE(root_params));
D3D12_VERSIONED_ROOT_SIGNATURE_DESC root_sig_desc = {
.Version = D3D_ROOT_SIGNATURE_VERSION_1_1,
.Desc_1_1 = {
.NumParameters = root_param_count,
.pParameters = root_params,
.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE,
},
};
D3D12_COMPUTE_PIPELINE_STATE_DESC desc = {
.Flags = D3D12_PIPELINE_STATE_FLAG_NONE,
};
meta->root_sig =
dzn_device_create_root_sig(device, &root_sig_desc);
if (!meta->root_sig) {
ret = vk_error(instance, VK_ERROR_INITIALIZATION_FAILED);
goto out;
}
desc.pRootSignature = meta->root_sig;
dzn_meta_compile_shader(device, nir, &desc.CS);
assert(desc.CS.pShaderBytecode);
if (FAILED(ID3D12Device1_CreateComputePipelineState(device->dev, &desc,
&IID_ID3D12PipelineState,
(void **)&meta->pipeline_state)))
ret = vk_error(instance, VK_ERROR_INITIALIZATION_FAILED);
out:
if (ret != VK_SUCCESS)
dzn_meta_indirect_draw_finish(device, type);
free((void *)desc.CS.pShaderBytecode);
ralloc_free(nir);
glsl_type_singleton_decref();
return ret;
}
#define DZN_META_TRIANGLE_FAN_REWRITE_IDX_MAX_PARAM_COUNT 4
static void
dzn_meta_triangle_fan_rewrite_index_finish(struct dzn_device *device,
enum dzn_index_type old_index_type)
{
struct dzn_meta_triangle_fan_rewrite_index *meta =
&device->triangle_fan[old_index_type];
if (meta->root_sig)
ID3D12RootSignature_Release(meta->root_sig);
if (meta->pipeline_state)
ID3D12PipelineState_Release(meta->pipeline_state);
if (meta->cmd_sig)
ID3D12CommandSignature_Release(meta->cmd_sig);
}
static VkResult
dzn_meta_triangle_fan_rewrite_index_init(struct dzn_device *device,
enum dzn_index_type old_index_type)
{
struct dzn_meta_triangle_fan_rewrite_index *meta =
&device->triangle_fan[old_index_type];
struct dzn_instance *instance =
container_of(device->vk.physical->instance, struct dzn_instance, vk);
VkResult ret = VK_SUCCESS;
glsl_type_singleton_init_or_ref();
uint8_t old_index_size = dzn_index_size(old_index_type);
bool prim_restart =
old_index_type == DZN_INDEX_2B_WITH_PRIM_RESTART ||
old_index_type == DZN_INDEX_4B_WITH_PRIM_RESTART;
nir_shader *nir =
prim_restart ?
dzn_nir_triangle_fan_prim_restart_rewrite_index_shader(old_index_size) :
dzn_nir_triangle_fan_rewrite_index_shader(old_index_size);
uint32_t root_param_count = 0;
D3D12_ROOT_PARAMETER1 root_params[DZN_META_TRIANGLE_FAN_REWRITE_IDX_MAX_PARAM_COUNT];
root_params[root_param_count++] = (D3D12_ROOT_PARAMETER1) {
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV,
.Descriptor = {
.ShaderRegister = 1,
.RegisterSpace = 0,
.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
},
.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
};
uint32_t params_size =
prim_restart ?
sizeof(struct dzn_triangle_fan_prim_restart_rewrite_index_params) :
sizeof(struct dzn_triangle_fan_rewrite_index_params);
root_params[root_param_count++] = (D3D12_ROOT_PARAMETER1) {
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
.Constants = {
.ShaderRegister = 0,
.RegisterSpace = 0,
.Num32BitValues = params_size / 4,
},
.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
};
if (old_index_type != DZN_NO_INDEX) {
root_params[root_param_count++] = (D3D12_ROOT_PARAMETER1) {
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV,
.Descriptor = {
.ShaderRegister = 2,
.RegisterSpace = 0,
.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
},
.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
};
}
if (prim_restart) {
root_params[root_param_count++] = (D3D12_ROOT_PARAMETER1) {
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV,
.Descriptor = {
.ShaderRegister = 3,
.RegisterSpace = 0,
.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,
},
.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
};
}
assert(root_param_count <= ARRAY_SIZE(root_params));
D3D12_VERSIONED_ROOT_SIGNATURE_DESC root_sig_desc = {
.Version = D3D_ROOT_SIGNATURE_VERSION_1_1,
.Desc_1_1 = {
.NumParameters = root_param_count,
.pParameters = root_params,
.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE,
},
};
D3D12_COMPUTE_PIPELINE_STATE_DESC desc = {
.Flags = D3D12_PIPELINE_STATE_FLAG_NONE,
};
uint32_t cmd_arg_count = 0;
D3D12_INDIRECT_ARGUMENT_DESC cmd_args[4];
cmd_args[cmd_arg_count++] = (D3D12_INDIRECT_ARGUMENT_DESC) {
.Type = D3D12_INDIRECT_ARGUMENT_TYPE_UNORDERED_ACCESS_VIEW,
.UnorderedAccessView = {
.RootParameterIndex = 0,
},
};
cmd_args[cmd_arg_count++] = (D3D12_INDIRECT_ARGUMENT_DESC) {
.Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT,
.Constant = {
.RootParameterIndex = 1,
.DestOffsetIn32BitValues = 0,
.Num32BitValuesToSet = params_size / 4,
},
};
if (prim_restart) {
cmd_args[cmd_arg_count++] = (D3D12_INDIRECT_ARGUMENT_DESC) {
.Type = D3D12_INDIRECT_ARGUMENT_TYPE_UNORDERED_ACCESS_VIEW,
.UnorderedAccessView = {
.RootParameterIndex = 3,
},
};
}
cmd_args[cmd_arg_count++] = (D3D12_INDIRECT_ARGUMENT_DESC) {
.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH,
};
assert(cmd_arg_count <= ARRAY_SIZE(cmd_args));
uint32_t exec_params_size =
prim_restart ?
sizeof(struct dzn_indirect_triangle_fan_prim_restart_rewrite_index_exec_params) :
sizeof(struct dzn_indirect_triangle_fan_rewrite_index_exec_params);
D3D12_COMMAND_SIGNATURE_DESC cmd_sig_desc = {
.ByteStride = exec_params_size,
.NumArgumentDescs = cmd_arg_count,
.pArgumentDescs = cmd_args,
};
assert((cmd_sig_desc.ByteStride & 7) == 0);
meta->root_sig = dzn_device_create_root_sig(device, &root_sig_desc);
if (!meta->root_sig) {
ret = vk_error(instance, VK_ERROR_INITIALIZATION_FAILED);
goto out;
}
desc.pRootSignature = meta->root_sig;
dzn_meta_compile_shader(device, nir, &desc.CS);
if (FAILED(ID3D12Device1_CreateComputePipelineState(device->dev, &desc,
&IID_ID3D12PipelineState,
(void **)&meta->pipeline_state))) {
ret = vk_error(instance, VK_ERROR_INITIALIZATION_FAILED);
goto out;
}
if (FAILED(ID3D12Device1_CreateCommandSignature(device->dev, &cmd_sig_desc,
meta->root_sig,
&IID_ID3D12CommandSignature,
(void **)&meta->cmd_sig)))
ret = vk_error(instance, VK_ERROR_INITIALIZATION_FAILED);
out:
if (ret != VK_SUCCESS)
dzn_meta_triangle_fan_rewrite_index_finish(device, old_index_type);
free((void *)desc.CS.pShaderBytecode);
ralloc_free(nir);
glsl_type_singleton_decref();
return ret;
}
static const D3D12_SHADER_BYTECODE *
dzn_meta_blits_get_vs(struct dzn_device *device)
{
struct dzn_meta_blits *meta = &device->blits;
mtx_lock(&meta->shaders_lock);
if (meta->vs.pShaderBytecode == NULL) {
nir_shader *nir = dzn_nir_blit_vs();
NIR_PASS(_, nir, nir_lower_system_values);
gl_system_value system_values[] = {
SYSTEM_VALUE_FIRST_VERTEX,
SYSTEM_VALUE_BASE_VERTEX,
};
NIR_PASS(_, nir, dxil_nir_lower_system_values_to_zero, system_values,
ARRAY_SIZE(system_values));
D3D12_SHADER_BYTECODE bc;
dzn_meta_compile_shader(device, nir, &bc);
meta->vs.pShaderBytecode =
vk_alloc(&device->vk.alloc, bc.BytecodeLength, 8,
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
if (meta->vs.pShaderBytecode) {
meta->vs.BytecodeLength = bc.BytecodeLength;
memcpy((void *)meta->vs.pShaderBytecode, bc.pShaderBytecode, bc.BytecodeLength);
}
free((void *)bc.pShaderBytecode);
ralloc_free(nir);
}
mtx_unlock(&meta->shaders_lock);
return &meta->vs;
}
static const D3D12_SHADER_BYTECODE *
dzn_meta_blits_get_fs(struct dzn_device *device,
const struct dzn_nir_blit_info *info)
{
struct dzn_meta_blits *meta = &device->blits;
D3D12_SHADER_BYTECODE *out = NULL;
mtx_lock(&meta->shaders_lock);
STATIC_ASSERT(sizeof(struct dzn_nir_blit_info) == sizeof(uint32_t));
struct hash_entry *he =
_mesa_hash_table_search(meta->fs, (void *)(uintptr_t)info->hash_key);
if (!he) {
nir_shader *nir = dzn_nir_blit_fs(info);
if (info->out_type != GLSL_TYPE_FLOAT) {
dxil_wrap_sampler_state wrap_state = {
.is_int_sampler = 1,
.is_linear_filtering = 0,
.skip_boundary_conditions = 1,
};
dxil_lower_sample_to_txf_for_integer_tex(nir, 1, &wrap_state, NULL, 0);
}
D3D12_SHADER_BYTECODE bc;
dzn_meta_compile_shader(device, nir, &bc);
out = vk_alloc(&device->vk.alloc,
sizeof(D3D12_SHADER_BYTECODE) + bc.BytecodeLength, 8,
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
if (out) {
out->pShaderBytecode = out + 1;
memcpy((void *)out->pShaderBytecode, bc.pShaderBytecode, bc.BytecodeLength);
out->BytecodeLength = bc.BytecodeLength;
_mesa_hash_table_insert(meta->fs, &info->hash_key, out);
}
free((void *)bc.pShaderBytecode);
ralloc_free(nir);
} else {
out = he->data;
}
mtx_unlock(&meta->shaders_lock);
return out;
}
static void
dzn_meta_blit_destroy(struct dzn_device *device, struct dzn_meta_blit *blit)
{
if (!blit)
return;
if (blit->root_sig)
ID3D12RootSignature_Release(blit->root_sig);
if (blit->pipeline_state)
ID3D12PipelineState_Release(blit->pipeline_state);
vk_free(&device->vk.alloc, blit);
}
static struct dzn_meta_blit *
dzn_meta_blit_create(struct dzn_device *device, const struct dzn_meta_blit_key *key)
{
struct dzn_meta_blit *blit =
vk_zalloc(&device->vk.alloc, sizeof(*blit), 8,
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
if (!blit)
return NULL;
D3D12_DESCRIPTOR_RANGE1 ranges[] = {
{
.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
.NumDescriptors = 1,
.BaseShaderRegister = 0,
.RegisterSpace = 0,
.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS,
.OffsetInDescriptorsFromTableStart = 0,
},
};
D3D12_DESCRIPTOR_RANGE1 sampler_ranges[] = {
{
.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
.NumDescriptors = 1,
.BaseShaderRegister = 0,
.RegisterSpace = 0,
.Flags = 0,
.OffsetInDescriptorsFromTableStart = 0,
},
};
D3D12_STATIC_SAMPLER_DESC samplers[] = {
{
.Filter = key->linear_filter ?
D3D12_FILTER_MIN_MAG_MIP_LINEAR :
D3D12_FILTER_MIN_MAG_MIP_POINT,
.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
.MipLODBias = 0,
.MaxAnisotropy = 0,
.MinLOD = 0,
.MaxLOD = D3D12_FLOAT32_MAX,
.ShaderRegister = 0,
.RegisterSpace = 0,
.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL,
},
};
D3D12_ROOT_PARAMETER1 root_params[4] = {
{
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
.DescriptorTable = {
.NumDescriptorRanges = ARRAY_SIZE(ranges),
.pDescriptorRanges = ranges,
},
.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL,
},
{
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
.Constants = {
.ShaderRegister = 0,
.RegisterSpace = 0,
.Num32BitValues = 17,
},
.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX,
},
{
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
.DescriptorTable = {
.NumDescriptorRanges = ARRAY_SIZE(sampler_ranges),
.pDescriptorRanges = sampler_ranges,
},
.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL,
},
{
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
.Constants = {
.ShaderRegister = 0,
.RegisterSpace = 0,
.Num32BitValues = 1,
},
.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL,
},
};
uint32_t num_root_params = 2;
uint32_t samples = key->resolve_mode == dzn_blit_resolve_none ?
key->samples : 1;
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = {
.SampleMask = (1ULL << samples) - 1,
.RasterizerState = {
.FillMode = D3D12_FILL_MODE_SOLID,
.CullMode = D3D12_CULL_MODE_NONE,
.DepthClipEnable = true,
},
.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
.SampleDesc = {
.Count = samples,
.Quality = 0,
},
.Flags = D3D12_PIPELINE_STATE_FLAG_NONE,
};
struct dzn_nir_blit_info blit_fs_info = {
.src_samples = key->samples,
.loc = key->loc,
.out_type = key->out_type,
.sampler_dim = key->sampler_dim,
.src_is_array = key->src_is_array,
.resolve_mode = key->resolve_mode,
.stencil_fallback = key->loc == FRAG_RESULT_STENCIL && key->stencil_bit != 0xf,
.padding = 0,
};
D3D12_VERSIONED_ROOT_SIGNATURE_DESC root_sig_desc = {
.Version = D3D_ROOT_SIGNATURE_VERSION_1_1,
.Desc_1_1 = {
.NumParameters = num_root_params,
.pParameters = root_params,
.NumStaticSamplers = ARRAY_SIZE(samplers),
.pStaticSamplers = samplers,
.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE,
},
};
if (!device->support_static_samplers) {
root_sig_desc.Desc_1_1.NumStaticSamplers = 0;
root_sig_desc.Desc_1_1.NumParameters = 3;
}
/* Don't need fs constants unless we're doing the stencil fallback */
if (blit_fs_info.stencil_fallback) {
if (device->support_static_samplers) {
root_params[2] = root_params[3];
root_sig_desc.Desc_1_1.NumParameters = 3;
} else {
root_sig_desc.Desc_1_1.NumParameters = 4;
}
}
blit->root_sig = dzn_device_create_root_sig(device, &root_sig_desc);
if (!blit->root_sig) {
dzn_meta_blit_destroy(device, blit);
return NULL;
}
desc.pRootSignature = blit->root_sig;
const D3D12_SHADER_BYTECODE *vs, *fs;
vs = dzn_meta_blits_get_vs(device);
if (!vs) {
dzn_meta_blit_destroy(device, blit);
return NULL;
}
desc.VS = *vs;
assert(desc.VS.pShaderBytecode);
fs = dzn_meta_blits_get_fs(device, &blit_fs_info);
if (!fs) {
dzn_meta_blit_destroy(device, blit);
return NULL;
}
desc.PS = *fs;
assert(desc.PS.pShaderBytecode);
assert(key->loc == FRAG_RESULT_DATA0 ||
key->loc == FRAG_RESULT_DEPTH ||
key->loc == FRAG_RESULT_STENCIL);
if (key->loc == FRAG_RESULT_DATA0) {
desc.NumRenderTargets = 1;
desc.RTVFormats[0] = key->out_format;
desc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0xf;
} else {
desc.DSVFormat = key->out_format;
if (key->loc == FRAG_RESULT_DEPTH) {
desc.DepthStencilState.DepthEnable = true;
desc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
} else {
assert(key->loc == FRAG_RESULT_STENCIL);
desc.DepthStencilState.StencilEnable = true;
desc.DepthStencilState.StencilWriteMask = key->stencil_bit == 0xf ? 0xff : (1 << key->stencil_bit);
desc.DepthStencilState.FrontFace.StencilFailOp = D3D12_STENCIL_OP_REPLACE;
desc.DepthStencilState.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_REPLACE;
desc.DepthStencilState.FrontFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
desc.DepthStencilState.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
desc.DepthStencilState.BackFace = desc.DepthStencilState.FrontFace;
}
}
if (FAILED(ID3D12Device1_CreateGraphicsPipelineState(device->dev, &desc,
&IID_ID3D12PipelineState,
(void **)&blit->pipeline_state))) {
dzn_meta_blit_destroy(device, blit);
return NULL;
}
return blit;
}
const struct dzn_meta_blit *
dzn_meta_blits_get_context(struct dzn_device *device,
const struct dzn_meta_blit_key *key)
{
struct dzn_meta_blit *out = NULL;
STATIC_ASSERT(sizeof(*key) == sizeof(uint64_t));
mtx_lock(&device->blits.contexts_lock);
out =
_mesa_hash_table_u64_search(device->blits.contexts, key->u64);
if (!out) {
out = dzn_meta_blit_create(device, key);
if (out)
_mesa_hash_table_u64_insert(device->blits.contexts, key->u64, out);
}
mtx_unlock(&device->blits.contexts_lock);
return out;
}
static void
dzn_meta_blits_finish(struct dzn_device *device)
{
struct dzn_meta_blits *meta = &device->blits;
vk_free(&device->vk.alloc, (void *)meta->vs.pShaderBytecode);
if (meta->fs) {
hash_table_foreach(meta->fs, he)
vk_free(&device->vk.alloc, he->data);
_mesa_hash_table_destroy(meta->fs, NULL);
}
if (meta->contexts) {
hash_table_foreach(&meta->contexts->table, he)
dzn_meta_blit_destroy(device, he->data);
_mesa_hash_table_u64_destroy(meta->contexts);
}
mtx_destroy(&meta->shaders_lock);
mtx_destroy(&meta->contexts_lock);
}
static VkResult
dzn_meta_blits_init(struct dzn_device *device)
{
struct dzn_instance *instance =
container_of(device->vk.physical->instance, struct dzn_instance, vk);
struct dzn_meta_blits *meta = &device->blits;
mtx_init(&meta->shaders_lock, mtx_plain);
mtx_init(&meta->contexts_lock, mtx_plain);
meta->fs = _mesa_hash_table_create_u32_keys(NULL);
if (!meta->fs) {
dzn_meta_blits_finish(device);
return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
}
meta->contexts = _mesa_hash_table_u64_create(NULL);
if (!meta->contexts) {
dzn_meta_blits_finish(device);
return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
}
return VK_SUCCESS;
}
void
dzn_meta_finish(struct dzn_device *device)
{
for (uint32_t i = 0; i < ARRAY_SIZE(device->triangle_fan); i++)
dzn_meta_triangle_fan_rewrite_index_finish(device, i);
for (uint32_t i = 0; i < ARRAY_SIZE(device->indirect_draws); i++)
dzn_meta_indirect_draw_finish(device, (struct dzn_indirect_draw_type) { .value = i });
dzn_meta_blits_finish(device);
}
VkResult
dzn_meta_init(struct dzn_device *device)
{
struct dzn_physical_device *pdev = container_of(device->vk.physical, struct dzn_physical_device, vk);
VkResult result = dzn_meta_blits_init(device);
if (result != VK_SUCCESS)
goto out;
for (uint32_t i = 0; i < ARRAY_SIZE(device->indirect_draws); i++) {
struct dzn_indirect_draw_type type = { .value = i };
if (type.triangle_fan_primitive_restart && !type.triangle_fan)
continue;
if (type.triangle_fan && pdev->options15.TriangleFanSupported)
continue;
if (type.draw_params && pdev->options21.ExtendedCommandInfoSupported)
continue;
if (type.draw_id && pdev->options21.ExecuteIndirectTier >= D3D12_EXECUTE_INDIRECT_TIER_1_1)
continue;
result = dzn_meta_indirect_draw_init(device, type);
if (result != VK_SUCCESS)
goto out;
}
if (!pdev->options15.TriangleFanSupported) {
for (uint32_t i = 0; i < ARRAY_SIZE(device->triangle_fan); i++) {
result = dzn_meta_triangle_fan_rewrite_index_init(device, i);
if (result != VK_SUCCESS)
goto out;
}
}
out:
if (result != VK_SUCCESS) {
dzn_meta_finish(device);
return result;
}
return VK_SUCCESS;
}
+986
View File
@@ -0,0 +1,986 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dzn_nir.h"
#include "spirv_to_dxil.h"
#include "nir_to_dxil.h"
#include "nir_builder.h"
#include "nir_builtin_builder.h"
#include "dxil_nir.h"
#include "vk_nir_convert_ycbcr.h"
static nir_def *
dzn_nir_create_bo_desc(nir_builder *b,
nir_variable_mode mode,
uint32_t desc_set,
uint32_t binding,
const char *name,
unsigned access)
{
struct glsl_struct_field field = {
.type = mode == nir_var_mem_ubo ?
glsl_array_type(glsl_uint_type(), 4096, 4) :
glsl_uint_type(),
.name = "dummy_int",
};
const struct glsl_type *dummy_type =
glsl_struct_type(&field, 1, "dummy_type", false);
nir_variable *var =
nir_variable_create(b->shader, mode, dummy_type, name);
var->data.descriptor_set = desc_set;
var->data.binding = binding;
var->data.access = access;
assert(mode == nir_var_mem_ubo || mode == nir_var_mem_ssbo);
if (mode == nir_var_mem_ubo)
b->shader->info.num_ubos++;
else
b->shader->info.num_ssbos++;
nir_descriptor_type desc_type =
var->data.mode == nir_var_mem_ubo ?
nir_descriptor_type_uniform_buffer :
nir_descriptor_type_storage_buffer;
nir_address_format addr_format = nir_address_format_32bit_index_offset;
nir_def *index =
nir_vulkan_resource_index(b,
nir_address_format_num_components(addr_format),
nir_address_format_bit_size(addr_format),
nir_imm_int(b, 0),
.desc_set = desc_set,
.binding = binding,
.desc_type = desc_type);
nir_def *desc =
nir_load_vulkan_descriptor(b,
nir_address_format_num_components(addr_format),
nir_address_format_bit_size(addr_format),
index,
.desc_type = desc_type);
return nir_channel(b, desc, 0);
}
nir_shader *
dzn_nir_indirect_draw_shader(struct dzn_indirect_draw_type type)
{
nir_builder b =
nir_builder_init_simple_shader(MESA_SHADER_COMPUTE,
dxil_get_base_nir_compiler_options(),
"dzn_meta_indirect_%sdraw%s%s%s()",
type.indexed ? "indexed_" : "",
type.indirect_count ? "_count" : "",
type.triangle_fan ? "_triangle_fan" : "",
type.triangle_fan_primitive_restart ? "_primitive_restart" : "");
nir_def *params_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ubo, 0, 0, "params", 0);
nir_def *draw_buf_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ssbo, 0, 1, "draw_buf", ACCESS_NON_WRITEABLE);
nir_def *exec_buf_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ssbo, 0, 2, "exec_buf", ACCESS_NON_READABLE);
unsigned params_size = 0;
if (type.triangle_fan)
params_size = sizeof(struct dzn_indirect_draw_triangle_fan_rewrite_params);
else
params_size = sizeof(struct dzn_indirect_draw_rewrite_params);
nir_def *params =
nir_load_ubo(&b, params_size / 4, 32,
params_desc, nir_imm_int(&b, 0),
.align_mul = 4, .align_offset = 0, .range_base = 0, .range = ~0);
uint32_t exec_stride_imm = 0;
uint32_t draw_args_offset = 0;
if (type.triangle_fan)
exec_stride_imm += sizeof(D3D12_INDEX_BUFFER_VIEW);
if (type.draw_params)
exec_stride_imm += sizeof(uint32_t) * 2;
if (type.draw_id)
exec_stride_imm += sizeof(uint32_t);
draw_args_offset = exec_stride_imm;
exec_stride_imm += (type.indexed || type.triangle_fan) ?
sizeof(D3D12_DRAW_INDEXED_ARGUMENTS) : sizeof(D3D12_DRAW_ARGUMENTS);
nir_def *draw_stride = nir_channel(&b, params, 0);
nir_def *exec_stride = nir_imm_int(&b, exec_stride_imm);
nir_def *index =
nir_channel(&b, nir_load_global_invocation_id(&b, 32), 0);
if (type.indirect_count) {
nir_def *count_buf_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ssbo, 0, 3, "count_buf", ACCESS_NON_WRITEABLE);
nir_def *draw_count =
nir_load_ssbo(&b, 1, 32, count_buf_desc, nir_imm_int(&b, 0), .align_mul = 4);
nir_push_if(&b, nir_ieq_imm(&b, index, 0));
nir_store_ssbo(&b, draw_count, exec_buf_desc, nir_imm_int(&b, 0),
.write_mask = 0x1, .access = ACCESS_NON_READABLE,
.align_mul = 16);
nir_pop_if(&b, NULL);
nir_push_if(&b, nir_ult(&b, index, draw_count));
}
nir_def *draw_offset = nir_imul(&b, draw_stride, index);
/* The first entry contains the indirect count */
nir_def *exec_offset =
type.indirect_count ?
nir_imul(&b, exec_stride, nir_iadd_imm(&b, index, 1)) :
nir_imul(&b, exec_stride, index);
nir_def *draw_info1 =
nir_load_ssbo(&b, 4, 32, draw_buf_desc, draw_offset, .align_mul = 4);
nir_def *draw_info2 =
type.indexed ?
nir_load_ssbo(&b, 1, 32, draw_buf_desc,
nir_iadd_imm(&b, draw_offset, 16), .align_mul = 4) :
nir_imm_int(&b, 0);
nir_def *first_vertex = nir_channel(&b, draw_info1, type.indexed ? 3 : 2);
nir_def *base_instance =
type.indexed ? draw_info2 : nir_channel(&b, draw_info1, 3);
uint32_t exec_val_idx = 0;
nir_def *exec_vals[8] = { NULL };
if (type.draw_params) {
exec_vals[exec_val_idx++] = first_vertex;
exec_vals[exec_val_idx++] = base_instance;
}
if (type.draw_id)
exec_vals[exec_val_idx++] = index;
if (type.triangle_fan) {
/* Patch {vertex,index}_count and first_index */
nir_def *triangle_count =
nir_usub_sat(&b, nir_channel(&b, draw_info1, 0), nir_imm_int(&b, 2));
exec_vals[exec_val_idx++] = nir_imul_imm(&b, triangle_count, 3);
exec_vals[exec_val_idx++] = nir_channel(&b, draw_info1, 1);
exec_vals[exec_val_idx++] = nir_imm_int(&b, 0);
exec_vals[exec_val_idx++] = first_vertex;
exec_vals[exec_val_idx++] = base_instance;
nir_def *triangle_fan_exec_buf_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ssbo, 0, 4,
"triangle_fan_exec_buf",
ACCESS_NON_READABLE);
nir_def *triangle_fan_index_buf_stride = nir_channel(&b, params, 1);
nir_def *triangle_fan_index_buf_addr_lo =
nir_iadd(&b, nir_channel(&b, params, 2),
nir_imul(&b, triangle_fan_index_buf_stride, index));
nir_def *triangle_fan_exec_vals[9] = { 0 };
uint32_t triangle_fan_exec_param_count = 0;
nir_def *addr_lo_overflow =
nir_ult(&b, triangle_fan_index_buf_addr_lo, nir_channel(&b, params, 2));
nir_def *triangle_fan_index_buf_addr_hi =
nir_iadd(&b, nir_channel(&b, params, 3),
nir_bcsel(&b, addr_lo_overflow, nir_imm_int(&b, 1), nir_imm_int(&b, 0)));
triangle_fan_exec_vals[triangle_fan_exec_param_count++] = triangle_fan_index_buf_addr_lo;
triangle_fan_exec_vals[triangle_fan_exec_param_count++] = triangle_fan_index_buf_addr_hi;
if (type.triangle_fan_primitive_restart) {
triangle_fan_exec_vals[triangle_fan_exec_param_count++] = nir_channel(&b, draw_info1, 2);
triangle_fan_exec_vals[triangle_fan_exec_param_count++] = nir_channel(&b, draw_info1, 0);
uint32_t index_count_offset = draw_args_offset +
offsetof(D3D12_DRAW_INDEXED_ARGUMENTS, IndexCountPerInstance);
nir_def *exec_buf_start =
nir_load_ubo(&b, 2, 32,
params_desc, nir_imm_int(&b, 16),
.align_mul = 4, .align_offset = 0, .range_base = 0, .range = ~0);
nir_def *exec_buf_start_lo =
nir_iadd(&b, nir_imm_int(&b, index_count_offset),
nir_iadd(&b, nir_channel(&b, exec_buf_start, 0),
nir_imul(&b, exec_stride, index)));
addr_lo_overflow = nir_ult(&b, exec_buf_start_lo, nir_channel(&b, exec_buf_start, 0));
nir_def *exec_buf_start_hi =
nir_iadd(&b, nir_channel(&b, exec_buf_start, 0),
nir_bcsel(&b, addr_lo_overflow, nir_imm_int(&b, 1), nir_imm_int(&b, 0)));
triangle_fan_exec_vals[triangle_fan_exec_param_count++] = exec_buf_start_lo;
triangle_fan_exec_vals[triangle_fan_exec_param_count++] = exec_buf_start_hi;
triangle_fan_exec_vals[triangle_fan_exec_param_count++] = nir_imm_int(&b, 1);
} else {
triangle_fan_exec_vals[triangle_fan_exec_param_count++] =
type.indexed ? nir_channel(&b, draw_info1, 2) : nir_imm_int(&b, 0);
triangle_fan_exec_vals[triangle_fan_exec_param_count++] =
triangle_count;
}
triangle_fan_exec_vals[triangle_fan_exec_param_count++] = nir_imm_int(&b, 1);
triangle_fan_exec_vals[triangle_fan_exec_param_count++] = nir_imm_int(&b, 1);
unsigned rewrite_index_exec_params =
type.triangle_fan_primitive_restart ?
sizeof(struct dzn_indirect_triangle_fan_prim_restart_rewrite_index_exec_params) :
sizeof(struct dzn_indirect_triangle_fan_rewrite_index_exec_params);
nir_def *triangle_fan_exec_stride =
nir_imm_int(&b, rewrite_index_exec_params);
nir_def *triangle_fan_exec_offset =
nir_imul(&b, triangle_fan_exec_stride, index);
for (uint32_t i = 0; i < triangle_fan_exec_param_count; i += 4) {
unsigned comps = MIN2(triangle_fan_exec_param_count - i, 4);
uint32_t mask = (1 << comps) - 1;
nir_store_ssbo(&b, nir_vec(&b, &triangle_fan_exec_vals[i], comps),
triangle_fan_exec_buf_desc,
nir_iadd_imm(&b, triangle_fan_exec_offset, i * 4),
.write_mask = mask, .access = ACCESS_NON_READABLE, .align_mul = 4);
}
nir_def *ibview_vals[] = {
triangle_fan_index_buf_addr_lo,
triangle_fan_index_buf_addr_hi,
triangle_fan_index_buf_stride,
nir_imm_int(&b, DXGI_FORMAT_R32_UINT),
};
nir_store_ssbo(&b, nir_vec(&b, ibview_vals, ARRAY_SIZE(ibview_vals)),
exec_buf_desc, exec_offset,
.write_mask = 0xf, .access = ACCESS_NON_READABLE, .align_mul = 16);
exec_offset = nir_iadd_imm(&b, exec_offset, ARRAY_SIZE(ibview_vals) * 4);
} else {
exec_vals[exec_val_idx++] = nir_channel(&b, draw_info1, 0);
exec_vals[exec_val_idx++] = nir_channel(&b, draw_info1, 1);
exec_vals[exec_val_idx++] = nir_channel(&b, draw_info1, 2);
exec_vals[exec_val_idx++] = nir_channel(&b, draw_info1, 3);
if (type.indexed)
exec_vals[exec_val_idx++] = draw_info2;
}
nir_store_ssbo(&b, nir_vec(&b, exec_vals, MIN2(exec_val_idx, 4)),
exec_buf_desc, exec_offset,
.write_mask = ((1 << exec_val_idx) - 1) & 0xf, .access = ACCESS_NON_READABLE, .align_mul = 16);
if (exec_val_idx > 4) {
nir_store_ssbo(&b, nir_vec(&b, &exec_vals[4], exec_val_idx - 4),
exec_buf_desc, nir_iadd_imm(&b, exec_offset, 16),
.write_mask = ((1 << (exec_val_idx - 4)) - 1) & 0xf, .access = ACCESS_NON_READABLE, .align_mul = 16);
}
if (type.indirect_count)
nir_pop_if(&b, NULL);
return b.shader;
}
nir_shader *
dzn_nir_triangle_fan_prim_restart_rewrite_index_shader(uint8_t old_index_size)
{
assert(old_index_size == 2 || old_index_size == 4);
nir_builder b =
nir_builder_init_simple_shader(MESA_SHADER_COMPUTE,
dxil_get_base_nir_compiler_options(),
"dzn_meta_triangle_prim_rewrite_index(old_index_size=%d)",
old_index_size);
nir_def *params_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ubo, 0, 0, "params", 0);
nir_def *new_index_buf_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ssbo, 0, 1,
"new_index_buf", ACCESS_NON_READABLE);
nir_def *old_index_buf_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ssbo, 0, 2,
"old_index_buf", ACCESS_NON_WRITEABLE);
nir_def *new_index_count_ptr_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ssbo, 0, 3,
"new_index_count_ptr", ACCESS_NON_READABLE);
nir_def *params =
nir_load_ubo(&b, sizeof(struct dzn_triangle_fan_prim_restart_rewrite_index_params) / 4, 32,
params_desc, nir_imm_int(&b, 0),
.align_mul = 4, .align_offset = 0, .range_base = 0, .range = ~0);
nir_def *prim_restart_val =
nir_imm_int(&b, old_index_size == 2 ? 0xffff : 0xffffffff);
nir_variable *old_index_ptr_var =
nir_local_variable_create(b.impl, glsl_uint_type(), "old_index_ptr_var");
nir_def *old_index_ptr = nir_channel(&b, params, 0);
nir_store_var(&b, old_index_ptr_var, old_index_ptr, 1);
nir_variable *new_index_ptr_var =
nir_local_variable_create(b.impl, glsl_uint_type(), "new_index_ptr_var");
nir_store_var(&b, new_index_ptr_var, nir_imm_int(&b, 0), 1);
nir_def *old_index_count = nir_channel(&b, params, 1);
nir_variable *index0_var =
nir_local_variable_create(b.impl, glsl_uint_type(), "index0_var");
nir_store_var(&b, index0_var, prim_restart_val, 1);
/*
* Filter out all primitive-restart magic values, and generate a triangle list
* from the triangle fan definition.
*
* Basically:
*
* new_index_ptr = 0;
* index0 = restart_prim_value; // 0xffff or 0xffffffff
* for (old_index_ptr = firstIndex; old_index_ptr < indexCount;) {
* // If we have no starting-point we need at least 3 vertices,
* // otherwise we can do with two. If there's not enough vertices
* // to form a primitive, we just bail out.
* min_indices = index0 == restart_prim_value ? 3 : 2;
* if (old_index_ptr + min_indices > firstIndex + indexCount)
* break;
*
* if (index0 == restart_prim_value) {
* // No starting point, skip all entries until we have a
* // non-primitive-restart value
* index0 = old_index_buf[old_index_ptr++];
* continue;
* }
*
* // If at least one index contains the primitive-restart pattern,
// ignore this triangle, and skip the unused entries
* if (old_index_buf[old_index_ptr + 1] == restart_prim_value) {
* old_index_ptr += 2;
* continue;
* }
* if (old_index_buf[old_index_ptr] == restart_prim_value) {
* old_index_ptr++;
* continue;
* }
*
* // We have a valid primitive, queue it to the new index buffer
* new_index_buf[new_index_ptr++] = old_index_buf[old_index_ptr];
* new_index_buf[new_index_ptr++] = old_index_buf[old_index_ptr + 1];
* new_index_buf[new_index_ptr++] = index0;
* }
*
* expressed in NIR, which admitedly is not super easy to grasp with.
* TODO: Might be a good thing to use use the CL compiler we have and turn
* those shaders into CL kernels.
*/
nir_loop *loop = nir_push_loop(&b);
nir_loop_add_continue_construct(loop);
old_index_ptr = nir_load_var(&b, old_index_ptr_var);
nir_def *index0 = nir_load_var(&b, index0_var);
nir_def *read_index_count =
nir_bcsel(&b, nir_ieq(&b, index0, prim_restart_val),
nir_imm_int(&b, 3), nir_imm_int(&b, 2));
nir_break_if(&b, nir_ult(&b, old_index_count, nir_iadd(&b, old_index_ptr, read_index_count)));
nir_def *old_index_offset =
nir_imul_imm(&b, old_index_ptr, old_index_size);
nir_push_if(&b, nir_ieq(&b, index0, prim_restart_val));
nir_def *index_val =
nir_load_ssbo(&b, 1, 32, old_index_buf_desc,
old_index_size == 2 ? nir_iand_imm(&b, old_index_offset, ~3ULL) : old_index_offset,
.align_mul = 4);
if (old_index_size == 2) {
index_val = nir_bcsel(&b, nir_test_mask(&b, old_index_offset, 0x2),
nir_ushr_imm(&b, index_val, 16),
nir_iand_imm(&b, index_val, 0xffff));
}
nir_store_var(&b, index0_var, index_val, 1);
nir_store_var(&b, old_index_ptr_var, nir_iadd_imm(&b, old_index_ptr, 1), 1);
nir_jump(&b, nir_jump_continue);
nir_pop_if(&b, NULL);
nir_def *index12 =
nir_load_ssbo(&b, 2, 32, old_index_buf_desc,
old_index_size == 2 ? nir_iand_imm(&b, old_index_offset, ~3ULL) : old_index_offset,
.align_mul = 4);
if (old_index_size == 2) {
nir_def *indices[] = {
nir_iand_imm(&b, nir_channel(&b, index12, 0), 0xffff),
nir_ushr_imm(&b, nir_channel(&b, index12, 0), 16),
nir_iand_imm(&b, nir_channel(&b, index12, 1), 0xffff),
};
index12 = nir_bcsel(&b, nir_test_mask(&b, old_index_offset, 0x2),
nir_vec2(&b, indices[1], indices[2]),
nir_vec2(&b, indices[0], indices[1]));
}
nir_push_if(&b, nir_ieq(&b, nir_channel(&b, index12, 1), prim_restart_val));
nir_store_var(&b, old_index_ptr_var, nir_iadd_imm(&b, old_index_ptr, 2), 1);
nir_store_var(&b, index0_var, prim_restart_val, 1);
nir_jump(&b, nir_jump_continue);
nir_push_else(&b, NULL);
nir_store_var(&b, old_index_ptr_var, nir_iadd_imm(&b, old_index_ptr, 1), 1);
nir_push_if(&b, nir_ieq(&b, nir_channel(&b, index12, 0), prim_restart_val));
nir_store_var(&b, index0_var, prim_restart_val, 1);
nir_jump(&b, nir_jump_continue);
nir_push_else(&b, NULL);
nir_def *new_indices =
nir_vec3(&b, nir_channel(&b, index12, 0), nir_channel(&b, index12, 1), index0);
nir_def *new_index_ptr = nir_load_var(&b, new_index_ptr_var);
nir_def *new_index_offset = nir_imul_imm(&b, new_index_ptr, sizeof(uint32_t));
nir_store_ssbo(&b, new_indices, new_index_buf_desc,
new_index_offset,
.write_mask = 7, .access = ACCESS_NON_READABLE, .align_mul = 4);
nir_store_var(&b, new_index_ptr_var, nir_iadd_imm(&b, new_index_ptr, 3), 1);
nir_pop_if(&b, NULL);
nir_pop_if(&b, NULL);
nir_pop_loop(&b, NULL);
nir_store_ssbo(&b, nir_load_var(&b, new_index_ptr_var),
new_index_count_ptr_desc, nir_imm_int(&b, 0),
.write_mask = 1, .access = ACCESS_NON_READABLE, .align_mul = 4);
nir_lower_continue_constructs(b.shader);
return b.shader;
}
nir_shader *
dzn_nir_triangle_fan_rewrite_index_shader(uint8_t old_index_size)
{
assert(old_index_size == 0 || old_index_size == 2 || old_index_size == 4);
nir_builder b =
nir_builder_init_simple_shader(MESA_SHADER_COMPUTE,
dxil_get_base_nir_compiler_options(),
"dzn_meta_triangle_rewrite_index(old_index_size=%d)",
old_index_size);
nir_def *params_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ubo, 0, 0, "params", 0);
nir_def *new_index_buf_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ssbo, 0, 1,
"new_index_buf", ACCESS_NON_READABLE);
nir_def *old_index_buf_desc = NULL;
if (old_index_size > 0) {
old_index_buf_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ssbo, 0, 2,
"old_index_buf", ACCESS_NON_WRITEABLE);
}
nir_def *params =
nir_load_ubo(&b, sizeof(struct dzn_triangle_fan_rewrite_index_params) / 4, 32,
params_desc, nir_imm_int(&b, 0),
.align_mul = 4, .align_offset = 0, .range_base = 0, .range = ~0);
nir_def *triangle = nir_channel(&b, nir_load_global_invocation_id(&b, 32), 0);
nir_def *new_indices;
if (old_index_size > 0) {
nir_def *old_first_index = nir_channel(&b, params, 0);
nir_def *old_index0_offset =
nir_imul_imm(&b, old_first_index, old_index_size);
nir_def *old_index1_offset =
nir_imul_imm(&b, nir_iadd(&b, nir_iadd_imm(&b, triangle, 1), old_first_index),
old_index_size);
nir_def *old_index0 =
nir_load_ssbo(&b, 1, 32, old_index_buf_desc,
old_index_size == 2 ? nir_iand_imm(&b, old_index0_offset, ~3ULL) : old_index0_offset,
.align_mul = 4);
if (old_index_size == 2) {
old_index0 = nir_bcsel(&b, nir_test_mask(&b, old_index0_offset, 0x2),
nir_ushr_imm(&b, old_index0, 16),
nir_iand_imm(&b, old_index0, 0xffff));
}
nir_def *old_index12 =
nir_load_ssbo(&b, 2, 32, old_index_buf_desc,
old_index_size == 2 ? nir_iand_imm(&b, old_index1_offset, ~3ULL) : old_index1_offset,
.align_mul = 4);
if (old_index_size == 2) {
nir_def *indices[] = {
nir_iand_imm(&b, nir_channel(&b, old_index12, 0), 0xffff),
nir_ushr_imm(&b, nir_channel(&b, old_index12, 0), 16),
nir_iand_imm(&b, nir_channel(&b, old_index12, 1), 0xffff),
};
old_index12 = nir_bcsel(&b, nir_test_mask(&b, old_index1_offset, 0x2),
nir_vec2(&b, indices[1], indices[2]),
nir_vec2(&b, indices[0], indices[1]));
}
/* TODO: VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT */
new_indices =
nir_vec3(&b, nir_channel(&b, old_index12, 0),
nir_channel(&b, old_index12, 1), old_index0);
} else {
new_indices =
nir_vec3(&b,
nir_iadd_imm(&b, triangle, 1),
nir_iadd_imm(&b, triangle, 2),
nir_imm_int(&b, 0));
}
nir_def *new_index_offset =
nir_imul_imm(&b, triangle, 4 * 3);
nir_store_ssbo(&b, new_indices, new_index_buf_desc,
new_index_offset,
.write_mask = 7, .access = ACCESS_NON_READABLE, .align_mul = 4);
return b.shader;
}
nir_shader *
dzn_nir_blit_vs(void)
{
nir_builder b =
nir_builder_init_simple_shader(MESA_SHADER_VERTEX,
dxil_get_base_nir_compiler_options(),
"dzn_meta_blit_vs()");
nir_def *params_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ubo, 0, 0, "params", 0);
nir_variable *out_pos =
nir_variable_create(b.shader, nir_var_shader_out, glsl_vec4_type(),
"gl_Position");
out_pos->data.location = VARYING_SLOT_POS;
out_pos->data.driver_location = 0;
nir_variable *out_coords =
nir_variable_create(b.shader, nir_var_shader_out, glsl_vec_type(3),
"coords");
out_coords->data.location = VARYING_SLOT_TEX0;
out_coords->data.driver_location = 1;
nir_def *vertex = nir_load_vertex_id(&b);
nir_def *coords_arr[4] = {
nir_load_ubo(&b, 4, 32, params_desc, nir_imm_int(&b, 0),
.align_mul = 16, .align_offset = 0, .range_base = 0, .range = ~0),
nir_load_ubo(&b, 4, 32, params_desc, nir_imm_int(&b, 16),
.align_mul = 16, .align_offset = 0, .range_base = 0, .range = ~0),
nir_load_ubo(&b, 4, 32, params_desc, nir_imm_int(&b, 32),
.align_mul = 16, .align_offset = 0, .range_base = 0, .range = ~0),
nir_load_ubo(&b, 4, 32, params_desc, nir_imm_int(&b, 48),
.align_mul = 16, .align_offset = 0, .range_base = 0, .range = ~0),
};
nir_def *coords =
nir_bcsel(&b, nir_ieq_imm(&b, vertex, 0), coords_arr[0],
nir_bcsel(&b, nir_ieq_imm(&b, vertex, 1), coords_arr[1],
nir_bcsel(&b, nir_ieq_imm(&b, vertex, 2), coords_arr[2], coords_arr[3])));
nir_def *pos =
nir_vec4(&b, nir_channel(&b, coords, 0), nir_channel(&b, coords, 1),
nir_imm_float(&b, 0.0), nir_imm_float(&b, 1.0));
nir_def *z_coord =
nir_load_ubo(&b, 1, 32, params_desc, nir_imm_int(&b, 4 * 4 * sizeof(float)),
.align_mul = 64, .align_offset = 0, .range_base = 0, .range = ~0);
coords = nir_vec3(&b, nir_channel(&b, coords, 2), nir_channel(&b, coords, 3), z_coord);
nir_store_var(&b, out_pos, pos, 0xf);
nir_store_var(&b, out_coords, coords, 0x7);
return b.shader;
}
nir_shader *
dzn_nir_blit_fs(const struct dzn_nir_blit_info *info)
{
bool ms = info->src_samples > 1;
nir_alu_type nir_out_type =
nir_get_nir_type_for_glsl_base_type(info->out_type);
uint32_t coord_comps =
glsl_get_sampler_dim_coordinate_components(info->sampler_dim) +
info->src_is_array;
nir_builder b =
nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT,
dxil_get_base_nir_compiler_options(),
"dzn_meta_blit_fs()");
const struct glsl_type *tex_type =
glsl_texture_type(info->sampler_dim, info->src_is_array, info->out_type);
nir_variable *tex_var =
nir_variable_create(b.shader, nir_var_uniform, tex_type, "texture");
nir_deref_instr *tex_deref = nir_build_deref_var(&b, tex_var);
nir_variable *pos_var =
nir_variable_create(b.shader, nir_var_shader_in,
glsl_vector_type(GLSL_TYPE_FLOAT, 4),
"gl_FragCoord");
pos_var->data.location = VARYING_SLOT_POS;
pos_var->data.driver_location = 0;
nir_variable *coord_var =
nir_variable_create(b.shader, nir_var_shader_in,
glsl_vector_type(GLSL_TYPE_FLOAT, 3),
"coord");
coord_var->data.location = VARYING_SLOT_TEX0;
coord_var->data.driver_location = 1;
nir_def *coord =
nir_trim_vector(&b, nir_load_var(&b, coord_var), coord_comps);
uint32_t out_comps =
(info->loc == FRAG_RESULT_DEPTH || info->loc == FRAG_RESULT_STENCIL) ? 1 : 4;
nir_variable *out = NULL;
if (!info->stencil_fallback) {
out = nir_variable_create(b.shader, nir_var_shader_out,
glsl_vector_type(info->out_type, out_comps),
"out");
out->data.location = info->loc;
}
nir_def *res = NULL;
if (info->resolve_mode != dzn_blit_resolve_none) {
enum dzn_blit_resolve_mode resolve_mode = info->resolve_mode;
nir_op resolve_op = nir_op_mov;
switch (resolve_mode) {
case dzn_blit_resolve_average:
/* When resolving a float type, we need to calculate the average of all
* samples. For integer resolve, Vulkan says that one sample should be
* chosen without telling which. Let's just pick the first one in that
* case.
*/
if (info->out_type == GLSL_TYPE_FLOAT)
resolve_op = nir_op_fadd;
else
resolve_mode = dzn_blit_resolve_sample_zero;
break;
case dzn_blit_resolve_min:
switch (info->out_type) {
case GLSL_TYPE_FLOAT: resolve_op = nir_op_fmin; break;
case GLSL_TYPE_INT: resolve_op = nir_op_imin; break;
case GLSL_TYPE_UINT: resolve_op = nir_op_umin; break;
}
break;
case dzn_blit_resolve_max:
switch (info->out_type) {
case GLSL_TYPE_FLOAT: resolve_op = nir_op_fmax; break;
case GLSL_TYPE_INT: resolve_op = nir_op_imax; break;
case GLSL_TYPE_UINT: resolve_op = nir_op_umax; break;
}
break;
case dzn_blit_resolve_none:
case dzn_blit_resolve_sample_zero:
break;
}
unsigned nsamples = resolve_mode == dzn_blit_resolve_sample_zero ?
1 : info->src_samples;
for (unsigned s = 0; s < nsamples; s++) {
nir_tex_instr *tex = nir_tex_instr_create(b.shader, 4);
tex->op = nir_texop_txf_ms;
tex->dest_type = nir_out_type;
tex->texture_index = 0;
tex->is_array = info->src_is_array;
tex->sampler_dim = info->sampler_dim;
tex->src[0] = nir_tex_src_for_ssa(nir_tex_src_coord,
nir_f2i32(&b, coord));
tex->coord_components = coord_comps;
tex->src[1] = nir_tex_src_for_ssa(nir_tex_src_ms_index,
nir_imm_int(&b, s));
tex->src[2] = nir_tex_src_for_ssa(nir_tex_src_lod,
nir_imm_int(&b, 0));
tex->src[3] = nir_tex_src_for_ssa(nir_tex_src_texture_deref,
&tex_deref->def);
nir_def_init(&tex->instr, &tex->def, 4, 32);
nir_builder_instr_insert(&b, &tex->instr);
res = res ? nir_build_alu2(&b, resolve_op, res, &tex->def) : &tex->def;
}
if (resolve_mode == dzn_blit_resolve_average)
res = nir_fmul_imm(&b, res, 1.0f / nsamples);
} else {
nir_tex_instr *tex =
nir_tex_instr_create(b.shader, ms ? 4 : 3);
tex->dest_type = nir_out_type;
tex->is_array = info->src_is_array;
tex->sampler_dim = info->sampler_dim;
if (ms) {
tex->op = nir_texop_txf_ms;
tex->src[0] = nir_tex_src_for_ssa(nir_tex_src_coord,
nir_f2i32(&b, coord));
tex->coord_components = coord_comps;
tex->src[1] = nir_tex_src_for_ssa(nir_tex_src_ms_index,
nir_load_sample_id(&b));
tex->src[2] = nir_tex_src_for_ssa(nir_tex_src_lod,
nir_imm_int(&b, 0));
tex->src[3] = nir_tex_src_for_ssa(nir_tex_src_texture_deref,
&tex_deref->def);
} else {
nir_variable *sampler_var =
nir_variable_create(b.shader, nir_var_uniform, glsl_bare_sampler_type(), "sampler");
nir_deref_instr *sampler_deref = nir_build_deref_var(&b, sampler_var);
tex->op = nir_texop_tex;
tex->sampler_index = 0;
tex->src[0] = nir_tex_src_for_ssa(nir_tex_src_coord, coord);
tex->coord_components = coord_comps;
tex->src[1] = nir_tex_src_for_ssa(nir_tex_src_texture_deref,
&tex_deref->def);
tex->src[2] = nir_tex_src_for_ssa(nir_tex_src_sampler_deref,
&sampler_deref->def);
}
nir_def_init(&tex->instr, &tex->def, 4, 32);
nir_builder_instr_insert(&b, &tex->instr);
res = &tex->def;
}
if (info->stencil_fallback) {
nir_def *mask_desc =
dzn_nir_create_bo_desc(&b, nir_var_mem_ubo, 0, 0, "mask", 0);
nir_def *mask = nir_load_ubo(&b, 1, 32, mask_desc, nir_imm_int(&b, 0),
.align_mul = 16, .align_offset = 0, .range_base = 0, .range = ~0);
nir_def *fail = nir_ieq_imm(&b, nir_iand(&b, nir_channel(&b, res, 0), mask), 0);
nir_discard_if(&b, fail);
} else {
nir_store_var(&b, out, nir_trim_vector(&b, res, out_comps), 0xf);
}
return b.shader;
}
static nir_def *
cull_face(nir_builder *b, nir_variable *vertices, bool ccw)
{
nir_def *v0 =
nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 0)));
nir_def *v1 =
nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 1)));
nir_def *v2 =
nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 2)));
nir_def *dir = nir_fdot(b, nir_cross4(b, nir_fsub(b, v1, v0),
nir_fsub(b, v2, v0)),
nir_imm_vec4(b, 0.0, 0.0, -1.0, 0.0));
if (ccw)
return nir_fle_imm(b, dir, 0.0f);
else
return nir_fgt_imm(b, dir, 0.0f);
}
static void
copy_vars(nir_builder *b, nir_deref_instr *dst, nir_deref_instr *src)
{
assert(glsl_get_bare_type(dst->type) == glsl_get_bare_type(src->type));
if (glsl_type_is_struct(dst->type)) {
for (unsigned i = 0; i < glsl_get_length(dst->type); ++i) {
copy_vars(b, nir_build_deref_struct(b, dst, i), nir_build_deref_struct(b, src, i));
}
} else if (glsl_type_is_array_or_matrix(dst->type)) {
copy_vars(b, nir_build_deref_array_wildcard(b, dst), nir_build_deref_array_wildcard(b, src));
} else {
nir_copy_deref(b, dst, src);
}
}
static nir_def *
load_dynamic_depth_bias(nir_builder *b, struct dzn_nir_point_gs_info *info)
{
nir_address_format ubo_format = nir_address_format_32bit_index_offset;
unsigned offset = offsetof(struct dxil_spirv_vertex_runtime_data, depth_bias);
nir_def *index = nir_vulkan_resource_index(
b, nir_address_format_num_components(ubo_format),
nir_address_format_bit_size(ubo_format),
nir_imm_int(b, 0),
.desc_set = info->runtime_data_cbv.register_space,
.binding = info->runtime_data_cbv.base_shader_register,
.desc_type = nir_descriptor_type_uniform_buffer);
nir_def *load_desc = nir_load_vulkan_descriptor(
b, nir_address_format_num_components(ubo_format),
nir_address_format_bit_size(ubo_format),
index, .desc_type = nir_descriptor_type_uniform_buffer);
return nir_load_ubo(
b, 1, 32,
nir_channel(b, load_desc, 0),
nir_imm_int(b, offset),
.align_mul = 256,
.align_offset = offset);
}
nir_shader *
dzn_nir_polygon_point_mode_gs(const nir_shader *previous_shader, struct dzn_nir_point_gs_info *info)
{
nir_builder builder;
nir_builder *b = &builder;
nir_variable *pos_var = NULL;
unsigned num_vars = 0;
nir_variable *in[VARYING_SLOT_MAX];
nir_variable *out[VARYING_SLOT_MAX];
builder = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY,
dxil_get_base_nir_compiler_options(),
"implicit_gs");
nir_shader *nir = b->shader;
nir->info.inputs_read = nir->info.outputs_written = previous_shader->info.outputs_written;
nir->info.outputs_written |= (1ull << VARYING_SLOT_VAR12);
nir->info.gs.input_primitive = MESA_PRIM_TRIANGLES;
nir->info.gs.output_primitive = MESA_PRIM_POINTS;
nir->info.gs.vertices_in = 3;
nir->info.gs.vertices_out = 3;
nir->info.gs.invocations = 1;
nir->info.gs.active_stream_mask = 1;
nir_foreach_shader_out_variable(var, previous_shader) {
char tmp[100];
snprintf(tmp, ARRAY_SIZE(tmp), "in_%d", num_vars);
in[num_vars] = nir_variable_create(nir,
nir_var_shader_in,
glsl_array_type(var->type, 3, 0),
tmp);
in[num_vars]->data = var->data;
in[num_vars]->data.mode = nir_var_shader_in;
if (var->data.location == VARYING_SLOT_POS)
pos_var = in[num_vars];
snprintf(tmp, ARRAY_SIZE(tmp), "out_%d", num_vars);
out[num_vars] = nir_variable_create(nir, nir_var_shader_out, var->type, tmp);
out[num_vars]->data = var->data;
num_vars++;
}
nir_variable *front_facing_var = nir_variable_create(nir,
nir_var_shader_out,
glsl_uint_type(),
"gl_FrontFacing");
front_facing_var->data.location = VARYING_SLOT_VAR12;
front_facing_var->data.driver_location = num_vars;
front_facing_var->data.interpolation = INTERP_MODE_FLAT;
nir_def *depth_bias_scale = NULL;
if (info->depth_bias) {
switch (info->ds_fmt) {
case DXGI_FORMAT_D16_UNORM:
depth_bias_scale = nir_imm_float(b, 1.0f / (1 << 16));
break;
case DXGI_FORMAT_D24_UNORM_S8_UINT:
depth_bias_scale = nir_imm_float(b, 1.0f / (1 << 24));
break;
case DXGI_FORMAT_D32_FLOAT:
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: {
nir_deref_instr *deref_pos = nir_build_deref_var(b, pos_var);
nir_def *max_z = NULL;
for (uint32_t i = 0; i < 3; ++i) {
nir_def *pos = nir_load_deref(b, nir_build_deref_array_imm(b, deref_pos, i));
nir_def *z = nir_iand_imm(b, nir_channel(b, pos, 2), 0x7fffffff);
max_z = i == 0 ? z : nir_imax(b, z, max_z);
}
nir_def *exponent = nir_ishr_imm(b, nir_iand_imm(b, max_z, 0x7f800000), 23);
depth_bias_scale = nir_fexp2(b, nir_i2f32(b, nir_iadd_imm(b, exponent, -23)));
break;
}
default:
depth_bias_scale = nir_imm_float(b, 0.0f);
}
}
/* Temporary variable "loop_index" to loop over input vertices */
nir_function_impl *impl = nir_shader_get_entrypoint(nir);
nir_variable *loop_index_var =
nir_local_variable_create(impl, glsl_uint_type(), "loop_index");
nir_deref_instr *loop_index_deref = nir_build_deref_var(b, loop_index_var);
nir_store_deref(b, loop_index_deref, nir_imm_int(b, 0), 1);
nir_def *cull_pass = nir_imm_true(b);
nir_def *front_facing;
assert(info->cull_mode != VK_CULL_MODE_FRONT_AND_BACK);
if (info->cull_mode == VK_CULL_MODE_FRONT_BIT) {
cull_pass = cull_face(b, pos_var, info->front_ccw);
front_facing = nir_b2i32(b, cull_pass);
} else if (info->cull_mode == VK_CULL_MODE_BACK_BIT) {
cull_pass = cull_face(b, pos_var, !info->front_ccw);
front_facing = nir_inot(b, nir_b2i32(b, cull_pass));
} else
front_facing = nir_i2i32(b, cull_face(b, pos_var, info->front_ccw));
/**
* if (cull_pass) {
* while {
* if (loop_index >= 3)
* break;
*/
nir_if *cull_check = nir_push_if(b, cull_pass);
nir_loop *loop = nir_push_loop(b);
nir_def *loop_index = nir_load_deref(b, loop_index_deref);
nir_def *cmp = nir_ige(b, loop_index,
nir_imm_int(b, 3));
nir_break_if(b, cmp);
/**
* [...] // Copy all variables
* EmitVertex();
*/
for (unsigned i = 0; i < num_vars; ++i) {
nir_def *index = loop_index;
nir_deref_instr *in_value = nir_build_deref_array(b, nir_build_deref_var(b, in[i]), index);
if (in[i] == pos_var && info->depth_bias) {
nir_def *bias_val;
if (info->depth_bias_dynamic) {
bias_val = load_dynamic_depth_bias(b, info);
} else {
assert(info->slope_scaled_depth_bias == 0.0f);
bias_val = nir_imm_float(b, info->constant_depth_bias);
}
bias_val = nir_fmul(b, bias_val, depth_bias_scale);
nir_def *old_val = nir_load_deref(b, in_value);
nir_def *new_val = nir_vector_insert_imm(b, old_val,
nir_fadd(b, nir_channel(b, old_val, 2), bias_val),
2);
nir_store_var(b, out[i], new_val, 0xf);
} else {
copy_vars(b, nir_build_deref_var(b, out[i]), in_value);
}
}
nir_store_var(b, front_facing_var, front_facing, 0x1);
nir_emit_vertex(b, 0);
/**
* loop_index++;
* }
* }
*/
nir_store_deref(b, loop_index_deref, nir_iadd_imm(b, loop_index, 1), 1);
nir_pop_loop(b, loop);
nir_pop_if(b, cull_check);
nir_validate_shader(nir, "in dzn_nir_polygon_point_mode_gs");
NIR_PASS(_, nir, nir_lower_var_copies);
return b->shader;
}
+149
View File
@@ -0,0 +1,149 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DZN_NIR_H
#define DZN_NIR_H
#define D3D12_IGNORE_SDK_LAYERS
#define COBJMACROS
#include <unknwn.h>
#include <directx/d3d12.h>
#include "nir.h"
struct dzn_indirect_draw_rewrite_params {
uint32_t draw_buf_stride;
};
struct dzn_indirect_draw_triangle_fan_rewrite_params {
uint32_t draw_buf_stride;
uint32_t triangle_fan_index_buf_stride;
uint64_t triangle_fan_index_buf_start;
};
struct dzn_indirect_draw_triangle_fan_prim_restart_rewrite_params {
uint32_t draw_buf_stride;
uint32_t triangle_fan_index_buf_stride;
uint64_t triangle_fan_index_buf_start;
uint64_t exec_buf_start;
};
struct dzn_triangle_fan_rewrite_index_params {
uint32_t first_index;
};
struct dzn_triangle_fan_prim_restart_rewrite_index_params {
uint32_t first_index;
uint32_t index_count;
};
struct dzn_indirect_triangle_fan_rewrite_index_exec_params {
uint64_t new_index_buf;
struct dzn_triangle_fan_rewrite_index_params params;
struct {
uint32_t x, y, z;
} group_count;
};
struct dzn_indirect_triangle_fan_prim_restart_rewrite_index_exec_params {
uint64_t new_index_buf;
struct dzn_triangle_fan_prim_restart_rewrite_index_params params;
uint64_t index_count_ptr;
struct {
uint32_t x, y, z;
} group_count;
};
struct dzn_indirect_draw_type {
union {
struct {
uint8_t indexed : 1;
uint8_t indirect_count : 1;
uint8_t draw_params : 1;
uint8_t draw_id : 1;
uint8_t triangle_fan : 1;
uint8_t triangle_fan_primitive_restart : 1;
};
uint8_t value;
};
};
#define DZN_NUM_INDIRECT_DRAW_TYPES (1 << 6)
nir_shader *
dzn_nir_indirect_draw_shader(struct dzn_indirect_draw_type type);
nir_shader *
dzn_nir_triangle_fan_rewrite_index_shader(uint8_t old_index_size);
nir_shader *
dzn_nir_triangle_fan_prim_restart_rewrite_index_shader(uint8_t old_index_size);
enum dzn_blit_resolve_mode {
dzn_blit_resolve_none,
dzn_blit_resolve_average,
dzn_blit_resolve_min,
dzn_blit_resolve_max,
dzn_blit_resolve_sample_zero,
};
struct dzn_nir_blit_info {
union {
struct {
uint32_t src_samples : 6;
uint32_t loc : 4;
uint32_t out_type : 4;
uint32_t sampler_dim : 4;
uint32_t src_is_array : 1;
uint32_t resolve_mode : 3;
uint32_t stencil_fallback : 1;
uint32_t padding : 9;
};
const uint32_t hash_key;
};
};
nir_shader *
dzn_nir_blit_vs(void);
nir_shader *
dzn_nir_blit_fs(const struct dzn_nir_blit_info *info);
struct dzn_nir_point_gs_info {
unsigned cull_mode;
bool front_ccw;
bool depth_bias;
bool depth_bias_dynamic;
DXGI_FORMAT ds_fmt;
/* Constant values */
float constant_depth_bias;
float slope_scaled_depth_bias;
float depth_bias_clamp;
/* Used for loading dynamic values */
struct {
uint32_t register_space;
uint32_t base_shader_register;
} runtime_data_cbv;
};
nir_shader *
dzn_nir_polygon_point_mode_gs(const nir_shader *vs, struct dzn_nir_point_gs_info *info);
#endif
@@ -0,0 +1,79 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DZN_PHYSICAL_DEVICE_ENUM_H
#define DZN_PHYSICAL_DEVICE_ENUM_H
#include <vulkan/vulkan_core.h>
#include <wsl/winadapter.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
struct vk_instance;
struct dzn_physical_device_desc {
uint32_t vendor_id;
uint32_t device_id;
uint32_t subsys_id;
uint32_t revision;
uint64_t shared_system_memory;
uint64_t dedicated_system_memory;
uint64_t dedicated_video_memory;
LUID adapter_luid;
bool is_warp;
char description[128];
};
struct d3d12_memory_info {
uint64_t usage_local;
uint64_t budget_local;
uint64_t usage_nonlocal;
uint64_t budget_nonlocal;
uint64_t usage; // local + nonlocal
uint64_t budget; // local + nonlocal
};
VkResult
dzn_enumerate_physical_devices_dxgi(struct vk_instance *instance);
VkResult
dzn_enumerate_physical_devices_dxcore(struct vk_instance *instance);
void
dzn_query_memory_info(IUnknown* unk, struct d3d12_memory_info* memory_info);
VkResult
dzn_instance_add_physical_device(struct vk_instance *instance,
IUnknown *adapter,
const struct dzn_physical_device_desc *desc);
#ifdef __cplusplus
}
#endif
#endif /* DZN_PHYSICAL_DEVICE_ENUM_H */
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+347
View File
@@ -0,0 +1,347 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dzn_private.h"
#include "dzn_abi_helper.h"
#include "vk_alloc.h"
#include "vk_debug_report.h"
#include "vk_util.h"
#include "util/os_time.h"
static D3D12_QUERY_HEAP_TYPE
dzn_query_pool_get_heap_type(VkQueryType in)
{
switch (in) {
case VK_QUERY_TYPE_OCCLUSION: return D3D12_QUERY_HEAP_TYPE_OCCLUSION;
case VK_QUERY_TYPE_PIPELINE_STATISTICS: return D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS;
case VK_QUERY_TYPE_TIMESTAMP: return D3D12_QUERY_HEAP_TYPE_TIMESTAMP;
default: UNREACHABLE("Unsupported query type");
}
}
D3D12_QUERY_TYPE
dzn_query_pool_get_query_type(const struct dzn_query_pool *qpool,
VkQueryControlFlags flags)
{
switch (qpool->heap_type) {
case D3D12_QUERY_HEAP_TYPE_OCCLUSION:
return flags & VK_QUERY_CONTROL_PRECISE_BIT ?
D3D12_QUERY_TYPE_OCCLUSION : D3D12_QUERY_TYPE_BINARY_OCCLUSION;
case D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS: return D3D12_QUERY_TYPE_PIPELINE_STATISTICS;
case D3D12_QUERY_HEAP_TYPE_TIMESTAMP: return D3D12_QUERY_TYPE_TIMESTAMP;
default: UNREACHABLE("Unsupported query type");
}
}
static void
dzn_query_pool_destroy(struct dzn_query_pool *qpool,
const VkAllocationCallbacks *alloc)
{
if (!qpool)
return;
struct dzn_device *device = container_of(qpool->base.device, struct dzn_device, vk);
if (qpool->collect_map)
ID3D12Resource_Unmap(qpool->collect_buffer, 0, NULL);
if (qpool->collect_buffer)
ID3D12Resource_Release(qpool->collect_buffer);
if (qpool->resolve_buffer)
ID3D12Resource_Release(qpool->resolve_buffer);
if (qpool->heap)
ID3D12QueryHeap_Release(qpool->heap);
for (uint32_t q = 0; q < qpool->query_count; q++) {
if (qpool->queries[q].fence)
ID3D12Fence_Release(qpool->queries[q].fence);
}
mtx_destroy(&qpool->queries_lock);
vk_object_base_finish(&qpool->base);
vk_free2(&device->vk.alloc, alloc, qpool);
}
static VkResult
dzn_query_pool_create(struct dzn_device *device,
const VkQueryPoolCreateInfo *info,
const VkAllocationCallbacks *alloc,
VkQueryPool *out)
{
VK_MULTIALLOC(ma);
VK_MULTIALLOC_DECL(&ma, struct dzn_query_pool, qpool, 1);
VK_MULTIALLOC_DECL(&ma, struct dzn_query, queries, info->queryCount);
if (!vk_multialloc_zalloc2(&ma, &device->vk.alloc, alloc,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT))
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
vk_object_base_init(&device->vk, &qpool->base, VK_OBJECT_TYPE_QUERY_POOL);
mtx_init(&qpool->queries_lock, mtx_plain);
qpool->query_count = info->queryCount;
qpool->queries = queries;
D3D12_QUERY_HEAP_DESC desc = { 0 };
qpool->heap_type = desc.Type = dzn_query_pool_get_heap_type(info->queryType);
desc.Count = info->queryCount;
desc.NodeMask = 0;
HRESULT hres =
ID3D12Device1_CreateQueryHeap(device->dev, &desc,
&IID_ID3D12QueryHeap,
(void **)&qpool->heap);
if (FAILED(hres)) {
dzn_query_pool_destroy(qpool, alloc);
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
}
switch (info->queryType) {
case VK_QUERY_TYPE_OCCLUSION:
case VK_QUERY_TYPE_TIMESTAMP:
qpool->query_size = sizeof(uint64_t);
break;
case VK_QUERY_TYPE_PIPELINE_STATISTICS:
qpool->pipeline_statistics = info->pipelineStatistics;
qpool->query_size = sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS);
break;
default: UNREACHABLE("Unsupported query type");
}
D3D12_HEAP_PROPERTIES hprops =
dzn_ID3D12Device4_GetCustomHeapProperties(device->dev, 0, D3D12_HEAP_TYPE_DEFAULT);
D3D12_RESOURCE_DESC rdesc = {
.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
.Width = info->queryCount * qpool->query_size,
.Height = 1,
.DepthOrArraySize = 1,
.MipLevels = 1,
.Format = DXGI_FORMAT_UNKNOWN,
.SampleDesc = { .Count = 1, .Quality = 0 },
.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
.Flags = D3D12_RESOURCE_FLAG_NONE,
};
hres = ID3D12Device1_CreateCommittedResource(device->dev, &hprops,
D3D12_HEAP_FLAG_NONE,
&rdesc,
D3D12_RESOURCE_STATE_COMMON,
NULL,
&IID_ID3D12Resource,
(void **)&qpool->resolve_buffer);
if (FAILED(hres)) {
dzn_query_pool_destroy(qpool, alloc);
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
}
hprops = dzn_ID3D12Device4_GetCustomHeapProperties(device->dev, 0,
D3D12_HEAP_TYPE_READBACK);
rdesc.Width = info->queryCount * (qpool->query_size + sizeof(uint64_t));
hres = ID3D12Device1_CreateCommittedResource(device->dev, &hprops,
D3D12_HEAP_FLAG_NONE,
&rdesc,
D3D12_RESOURCE_STATE_COMMON,
NULL,
&IID_ID3D12Resource,
(void **)&qpool->collect_buffer);
if (FAILED(hres)) {
dzn_query_pool_destroy(qpool, alloc);
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
}
hres = ID3D12Resource_Map(qpool->collect_buffer, 0, NULL, (void **)&qpool->collect_map);
if (FAILED(hres)) {
dzn_query_pool_destroy(qpool, alloc);
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
}
memset(qpool->collect_map, 0, rdesc.Width);
*out = dzn_query_pool_to_handle(qpool);
return VK_SUCCESS;
}
uint32_t
dzn_query_pool_get_result_offset(const struct dzn_query_pool *qpool, uint32_t query)
{
return query * qpool->query_size;
}
uint32_t
dzn_query_pool_get_result_size(const struct dzn_query_pool *qpool, uint32_t query_count)
{
return query_count * qpool->query_size;
}
uint32_t
dzn_query_pool_get_availability_offset(const struct dzn_query_pool *qpool, uint32_t query)
{
return (qpool->query_count * qpool->query_size) + (sizeof(uint64_t) * query);
}
VKAPI_ATTR VkResult VKAPI_CALL
dzn_CreateQueryPool(VkDevice device,
const VkQueryPoolCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkQueryPool *pQueryPool)
{
return dzn_query_pool_create(dzn_device_from_handle(device),
pCreateInfo, pAllocator, pQueryPool);
}
VKAPI_ATTR void VKAPI_CALL
dzn_DestroyQueryPool(VkDevice device,
VkQueryPool queryPool,
const VkAllocationCallbacks *pAllocator)
{
dzn_query_pool_destroy(dzn_query_pool_from_handle(queryPool), pAllocator);
}
VKAPI_ATTR void VKAPI_CALL
dzn_ResetQueryPool(VkDevice device,
VkQueryPool queryPool,
uint32_t firstQuery,
uint32_t queryCount)
{
VK_FROM_HANDLE(dzn_query_pool, qpool, queryPool);
mtx_lock(&qpool->queries_lock);
for (uint32_t q = 0; q < queryCount; q++) {
struct dzn_query *query = &qpool->queries[firstQuery + q];
query->fence_value = 0;
if (query->fence) {
ID3D12Fence_Release(query->fence);
query->fence = NULL;
}
}
mtx_unlock(&qpool->queries_lock);
memset((uint8_t *)qpool->collect_map + dzn_query_pool_get_result_offset(qpool, firstQuery),
0, queryCount * qpool->query_size);
memset((uint8_t *)qpool->collect_map + dzn_query_pool_get_availability_offset(qpool, firstQuery),
0, queryCount * sizeof(uint64_t));
}
VKAPI_ATTR VkResult VKAPI_CALL
dzn_GetQueryPoolResults(VkDevice device,
VkQueryPool queryPool,
uint32_t firstQuery,
uint32_t queryCount,
size_t dataSize,
void *pData,
VkDeviceSize stride,
VkQueryResultFlags flags)
{
VK_FROM_HANDLE(dzn_query_pool, qpool, queryPool);
uint32_t step = (flags & VK_QUERY_RESULT_64_BIT) ?
sizeof(uint64_t) : sizeof(uint32_t);
VkResult result = VK_SUCCESS;
for (uint32_t q = 0; q < queryCount; q++) {
struct dzn_query *query = &qpool->queries[q + firstQuery];
uint8_t *dst_ptr = (uint8_t *)pData + (stride * q);
uint8_t *src_ptr =
(uint8_t *)qpool->collect_map +
dzn_query_pool_get_result_offset(qpool, firstQuery + q);
uint64_t available = 0;
if (flags & VK_QUERY_RESULT_WAIT_BIT) {
ID3D12Fence *query_fence = NULL;
uint64_t query_fence_val = 0;
while (true) {
mtx_lock(&qpool->queries_lock);
if (query->fence) {
query_fence = query->fence;
ID3D12Fence_AddRef(query_fence);
}
query_fence_val = query->fence_value;
mtx_unlock(&qpool->queries_lock);
if (query_fence)
break;
/* Check again in 10ms.
* FIXME: decrease the polling period if it happens to hurt latency.
*/
os_time_sleep(10 * 1000);
}
ID3D12Fence_SetEventOnCompletion(query_fence, query_fence_val, NULL);
ID3D12Fence_Release(query_fence);
available = UINT64_MAX;
} else {
ID3D12Fence *query_fence = NULL;
mtx_lock(&qpool->queries_lock);
if (query->fence) {
query_fence = query->fence;
ID3D12Fence_AddRef(query_fence);
}
uint64_t query_fence_val = query->fence_value;
mtx_unlock(&qpool->queries_lock);
if (query_fence) {
if (ID3D12Fence_GetCompletedValue(query_fence) >= query_fence_val)
available = UINT64_MAX;
ID3D12Fence_Release(query_fence);
}
}
if (qpool->heap_type != D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS) {
if (available)
memcpy(dst_ptr, src_ptr, step);
else if (flags & VK_QUERY_RESULT_PARTIAL_BIT)
memset(dst_ptr, 0, step);
dst_ptr += step;
} else {
for (uint32_t c = 0; c < sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS) / sizeof(uint64_t); c++) {
if (!(BITFIELD_BIT(c) & qpool->pipeline_statistics))
continue;
if (available)
memcpy(dst_ptr, src_ptr + (c * sizeof(uint64_t)), step);
else if (flags & VK_QUERY_RESULT_PARTIAL_BIT)
memset(dst_ptr, 0, step);
dst_ptr += step;
}
}
if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
memcpy(dst_ptr, &available, step);
if (!available && !(flags & VK_QUERY_RESULT_PARTIAL_BIT))
result = VK_NOT_READY;
}
return result;
}
+336
View File
@@ -0,0 +1,336 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dzn_private.h"
#include "vk_alloc.h"
#include "vk_debug_report.h"
#include "vk_util.h"
#include "util/macros.h"
#include "util/os_time.h"
#ifndef _WIN32
#include <sys/eventfd.h>
#include <libsync.h>
#endif
static VkResult
dzn_sync_init(struct vk_device *device,
struct vk_sync *sync,
uint64_t initial_value)
{
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
D3D12_FENCE_FLAGS flags = (sync->flags & VK_SYNC_IS_SHAREABLE) ?
D3D12_FENCE_FLAG_SHARED : D3D12_FENCE_FLAG_NONE;
if (FAILED(ID3D12Device1_CreateFence(ddev->dev, initial_value,
flags,
&IID_ID3D12Fence,
(void **)&dsync->fence)))
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
return VK_SUCCESS;
}
static void
dzn_sync_finish(struct vk_device *device,
struct vk_sync *sync)
{
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
ID3D12Fence_Release(dsync->fence);
#ifdef _WIN32
if (dsync->export_handle)
CloseHandle(dsync->export_handle);
#endif
}
static VkResult
dzn_sync_signal(struct vk_device *device,
struct vk_sync *sync,
uint64_t value)
{
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
if (!(sync->flags & VK_SYNC_IS_TIMELINE))
value = 1;
if (FAILED(ID3D12Fence_Signal(dsync->fence, value)))
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
return VK_SUCCESS;
}
static VkResult
dzn_sync_get_value(struct vk_device *device,
struct vk_sync *sync,
uint64_t *value)
{
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
*value = ID3D12Fence_GetCompletedValue(dsync->fence);
return VK_SUCCESS;
}
static VkResult
dzn_sync_reset(struct vk_device *device,
struct vk_sync *sync)
{
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
if (FAILED(ID3D12Fence_Signal(dsync->fence, 0)))
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
return VK_SUCCESS;
}
static VkResult
dzn_sync_move(struct vk_device *device,
struct vk_sync *dst,
struct vk_sync *src)
{
struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
struct dzn_sync *ddst = container_of(dst, struct dzn_sync, vk);
struct dzn_sync *dsrc = container_of(src, struct dzn_sync, vk);
ID3D12Fence *new_fence;
if (FAILED(ID3D12Device1_CreateFence(ddev->dev, 0,
D3D12_FENCE_FLAG_NONE,
&IID_ID3D12Fence,
(void **)&new_fence)))
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
ID3D12Fence_Release(ddst->fence);
ddst->fence = dsrc->fence;
dsrc->fence = new_fence;
return VK_SUCCESS;
}
static VkResult
dzn_sync_wait(struct vk_device *device,
uint32_t wait_count,
const struct vk_sync_wait *waits,
enum vk_sync_wait_flags wait_flags,
uint64_t abs_timeout_ns)
{
struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
#ifdef _WIN32
HANDLE event = CreateEventA(NULL, false, false, NULL);
if (event == NULL)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
#else
int event_fd = eventfd(0, EFD_CLOEXEC);
if (event_fd == -1)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
/* The D3D12 event-based APIs in WSL expect an eventfd file descriptor cast to HANDLE */
HANDLE event = (HANDLE)(intptr_t)event_fd;
#endif
STACK_ARRAY(ID3D12Fence *, fences, wait_count);
STACK_ARRAY(uint64_t, values, wait_count);
for (uint32_t i = 0; i < wait_count; i++) {
struct dzn_sync *sync = container_of(waits[i].sync, struct dzn_sync, vk);
fences[i] = sync->fence;
values[i] = (sync->vk.flags & VK_SYNC_IS_TIMELINE) ? waits[i].wait_value : 1;
}
D3D12_MULTIPLE_FENCE_WAIT_FLAGS flags =
(wait_flags & VK_SYNC_WAIT_ANY) ?
D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY :
D3D12_MULTIPLE_FENCE_WAIT_FLAG_ALL;
if (FAILED(ID3D12Device1_SetEventOnMultipleFenceCompletion(ddev->dev,
fences,
values,
wait_count,
flags,
event))) {
STACK_ARRAY_FINISH(fences);
STACK_ARRAY_FINISH(values);
#ifdef _WIN32
CloseHandle(event);
#else
close(event_fd);
#endif
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
}
#ifdef _WIN32
DWORD timeout_ms;
static const DWORD timeout_infinite = INFINITE;
#else
int timeout_ms;
static const int timeout_infinite = -1;
#endif
if (abs_timeout_ns == OS_TIMEOUT_INFINITE) {
timeout_ms = timeout_infinite;
} else {
uint64_t cur_time = os_time_get_nano();
uint64_t rel_timeout_ns =
abs_timeout_ns > cur_time ? abs_timeout_ns - cur_time : 0;
timeout_ms = (rel_timeout_ns / 1000000) + (rel_timeout_ns % 1000000 ? 1 : 0);
}
#ifdef _WIN32
DWORD res =
WaitForSingleObject(event, timeout_ms);
CloseHandle(event);
VkResult ret = VK_SUCCESS;
if (res == WAIT_TIMEOUT)
ret = VK_TIMEOUT;
else if (res != WAIT_OBJECT_0)
ret = vk_error(device, VK_ERROR_UNKNOWN);
#else
VkResult ret = sync_wait(event_fd, timeout_ms) != 0 ? VK_TIMEOUT : VK_SUCCESS;
close(event_fd);
#endif
STACK_ARRAY_FINISH(fences);
STACK_ARRAY_FINISH(values);
return ret;
}
#ifdef _WIN32
static VkResult
dzn_sync_import_win32_handle(struct vk_device *device, struct vk_sync *sync,
HANDLE handle, LPCWSTR name)
{
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
dzn_sync_finish(device, sync);
HANDLE handle_to_close = NULL;
if (name) {
if (FAILED(ID3D12Device_OpenSharedHandleByName(ddev->dev, name, GENERIC_ALL, &handle_to_close)))
return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
handle = handle_to_close;
}
HRESULT hr = ID3D12Device_OpenSharedHandle(ddev->dev, handle, &IID_ID3D12Fence, (void **)&dsync->fence);
if (handle_to_close)
CloseHandle(handle_to_close);
if (FAILED(hr))
return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
return VK_SUCCESS;
}
static VkResult
dzn_sync_export_win32_handle(struct vk_device *device, struct vk_sync *sync, HANDLE *handle)
{
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
if (dsync->export_handle) {
if (!DuplicateHandle(GetCurrentProcess(), dsync->export_handle,
GetCurrentProcess(), handle,
0, false, DUPLICATE_SAME_ACCESS))
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
return VK_SUCCESS;
}
struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
if (FAILED(ID3D12Device_CreateSharedHandle(ddev->dev, (ID3D12DeviceChild *)dsync->fence,
NULL, GENERIC_ALL, NULL, handle)))
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
return VK_SUCCESS;
}
static VkResult
dzn_sync_prep_win32_export(struct vk_device *device, struct vk_sync *sync,
const void *security_attributes, uint32_t access,
const wchar_t *name)
{
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
if (FAILED(ID3D12Device_CreateSharedHandle(ddev->dev, (ID3D12DeviceChild *)dsync->fence,
(const LPSECURITY_ATTRIBUTES)security_attributes,
GENERIC_ALL, name, &dsync->export_handle)))
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
return VK_SUCCESS;
}
#else
static VkResult
dzn_sync_import_opaque_fd(struct vk_device *device, struct vk_sync *sync,
int fd)
{
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
dzn_sync_finish(device, sync);
HANDLE handle = (HANDLE)(intptr_t)fd;
if (FAILED(ID3D12Device_OpenSharedHandle(ddev->dev, handle, &IID_ID3D12Fence, (void **)&dsync->fence)))
return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
return VK_SUCCESS;
}
static VkResult
dzn_sync_export_opaque_fd(struct vk_device *device, struct vk_sync *sync, int *fd)
{
struct dzn_sync *dsync = container_of(sync, struct dzn_sync, vk);
struct dzn_device *ddev = container_of(device, struct dzn_device, vk);
HANDLE handle;
if (FAILED(ID3D12Device_CreateSharedHandle(ddev->dev, (ID3D12DeviceChild *)dsync->fence,
NULL, GENERIC_ALL, NULL, &handle)))
return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
*fd = (int)(intptr_t)handle;
return VK_SUCCESS;
}
#endif
const struct vk_sync_type dzn_sync_type = {
.size = sizeof(struct dzn_sync),
.features = (enum vk_sync_features)
(VK_SYNC_FEATURE_TIMELINE |
VK_SYNC_FEATURE_GPU_WAIT |
VK_SYNC_FEATURE_CPU_WAIT |
VK_SYNC_FEATURE_CPU_SIGNAL |
VK_SYNC_FEATURE_WAIT_ANY |
VK_SYNC_FEATURE_WAIT_BEFORE_SIGNAL),
.init = dzn_sync_init,
.finish = dzn_sync_finish,
.signal = dzn_sync_signal,
.get_value = dzn_sync_get_value,
.reset = dzn_sync_reset,
.move = dzn_sync_move,
.wait_many = dzn_sync_wait,
#ifdef _WIN32
.import_win32_handle = dzn_sync_import_win32_handle,
.export_win32_handle = dzn_sync_export_win32_handle,
.set_win32_export_params = dzn_sync_prep_win32_export,
#else
.import_opaque_fd = dzn_sync_import_opaque_fd,
.export_opaque_fd = dzn_sync_export_opaque_fd,
#endif
};
+407
View File
@@ -0,0 +1,407 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dzn_private.h"
#define D3D12_IGNORE_SDK_LAYERS
#define COBJMACROS
#include <directx/d3d12.h>
#include <vulkan/vulkan.h>
#include "util/format/u_format.h"
#include "util/log.h"
#include <directx/d3d12sdklayers.h>
#include <util/u_dl.h>
static const DXGI_FORMAT formats[PIPE_FORMAT_COUNT] = {
#define MAP_FORMAT_NORM(FMT) \
[PIPE_FORMAT_ ## FMT ## _UNORM] = DXGI_FORMAT_ ## FMT ## _UNORM, \
[PIPE_FORMAT_ ## FMT ## _SNORM] = DXGI_FORMAT_ ## FMT ## _SNORM,
#define MAP_FORMAT_INT(FMT) \
[PIPE_FORMAT_ ## FMT ## _UINT] = DXGI_FORMAT_ ## FMT ## _UINT, \
[PIPE_FORMAT_ ## FMT ## _SINT] = DXGI_FORMAT_ ## FMT ## _SINT,
#define MAP_FORMAT_SRGB(FMT) \
[PIPE_FORMAT_ ## FMT ## _SRGB] = DXGI_FORMAT_ ## FMT ## _UNORM_SRGB,
#define MAP_FORMAT_FLOAT(FMT) \
[PIPE_FORMAT_ ## FMT ## _FLOAT] = DXGI_FORMAT_ ## FMT ## _FLOAT,
#define MAP_EMU_FORMAT_NO_ALPHA(BITS, TYPE) \
[PIPE_FORMAT_L ## BITS ## _ ## TYPE] = DXGI_FORMAT_R ## BITS ## _ ## TYPE, \
[PIPE_FORMAT_I ## BITS ## _ ## TYPE] = DXGI_FORMAT_R ## BITS ## _ ## TYPE, \
[PIPE_FORMAT_L ## BITS ## A ## BITS ## _ ## TYPE] = \
DXGI_FORMAT_R ## BITS ## G ## BITS ## _ ## TYPE,
#define MAP_EMU_FORMAT(BITS, TYPE) \
[PIPE_FORMAT_A ## BITS ## _ ## TYPE] = DXGI_FORMAT_R ## BITS ## _ ## TYPE, \
MAP_EMU_FORMAT_NO_ALPHA(BITS, TYPE)
MAP_FORMAT_NORM(R8)
MAP_FORMAT_INT(R8)
MAP_FORMAT_NORM(R8G8)
MAP_FORMAT_INT(R8G8)
MAP_FORMAT_NORM(R8G8B8A8)
MAP_FORMAT_INT(R8G8B8A8)
MAP_FORMAT_SRGB(R8G8B8A8)
[PIPE_FORMAT_B8G8R8X8_UNORM] = DXGI_FORMAT_B8G8R8X8_UNORM,
[PIPE_FORMAT_B8G8R8A8_UNORM] = DXGI_FORMAT_B8G8R8A8_UNORM,
[PIPE_FORMAT_B4G4R4A4_UNORM] = DXGI_FORMAT_B4G4R4A4_UNORM,
[PIPE_FORMAT_A4R4G4B4_UNORM] = DXGI_FORMAT_A4B4G4R4_UNORM,
[PIPE_FORMAT_A4B4G4R4_UNORM] = DXGI_FORMAT_A4B4G4R4_UNORM,
[PIPE_FORMAT_B5G6R5_UNORM] = DXGI_FORMAT_B5G6R5_UNORM,
[PIPE_FORMAT_B5G5R5A1_UNORM] = DXGI_FORMAT_B5G5R5A1_UNORM,
MAP_FORMAT_SRGB(B8G8R8A8)
MAP_FORMAT_INT(R32)
MAP_FORMAT_FLOAT(R32)
MAP_FORMAT_INT(R32G32)
MAP_FORMAT_FLOAT(R32G32)
MAP_FORMAT_INT(R32G32B32)
MAP_FORMAT_FLOAT(R32G32B32)
MAP_FORMAT_INT(R32G32B32A32)
MAP_FORMAT_FLOAT(R32G32B32A32)
MAP_FORMAT_NORM(R16)
MAP_FORMAT_INT(R16)
MAP_FORMAT_FLOAT(R16)
MAP_FORMAT_NORM(R16G16)
MAP_FORMAT_INT(R16G16)
MAP_FORMAT_FLOAT(R16G16)
MAP_FORMAT_NORM(R16G16B16A16)
MAP_FORMAT_INT(R16G16B16A16)
MAP_FORMAT_FLOAT(R16G16B16A16)
[PIPE_FORMAT_A8_UNORM] = DXGI_FORMAT_A8_UNORM,
MAP_EMU_FORMAT_NO_ALPHA(8, UNORM)
MAP_EMU_FORMAT(8, SNORM)
MAP_EMU_FORMAT(8, SINT)
MAP_EMU_FORMAT(8, UINT)
MAP_EMU_FORMAT(16, UNORM)
MAP_EMU_FORMAT(16, SNORM)
MAP_EMU_FORMAT(16, SINT)
MAP_EMU_FORMAT(16, UINT)
MAP_EMU_FORMAT(16, FLOAT)
MAP_EMU_FORMAT(32, SINT)
MAP_EMU_FORMAT(32, UINT)
MAP_EMU_FORMAT(32, FLOAT)
[PIPE_FORMAT_R9G9B9E5_FLOAT] = DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
[PIPE_FORMAT_R11G11B10_FLOAT] = DXGI_FORMAT_R11G11B10_FLOAT,
[PIPE_FORMAT_R10G10B10A2_UINT] = DXGI_FORMAT_R10G10B10A2_UINT,
[PIPE_FORMAT_R10G10B10A2_UNORM] = DXGI_FORMAT_R10G10B10A2_UNORM,
[PIPE_FORMAT_DXT1_RGB] = DXGI_FORMAT_BC1_UNORM,
[PIPE_FORMAT_DXT1_RGBA] = DXGI_FORMAT_BC1_UNORM,
[PIPE_FORMAT_DXT3_RGBA] = DXGI_FORMAT_BC2_UNORM,
[PIPE_FORMAT_DXT5_RGBA] = DXGI_FORMAT_BC3_UNORM,
[PIPE_FORMAT_DXT1_SRGB] = DXGI_FORMAT_BC1_UNORM_SRGB,
[PIPE_FORMAT_DXT1_SRGBA] = DXGI_FORMAT_BC1_UNORM_SRGB,
[PIPE_FORMAT_DXT3_SRGBA] = DXGI_FORMAT_BC2_UNORM_SRGB,
[PIPE_FORMAT_DXT5_SRGBA] = DXGI_FORMAT_BC3_UNORM_SRGB,
[PIPE_FORMAT_RGTC1_UNORM] = DXGI_FORMAT_BC4_UNORM,
[PIPE_FORMAT_RGTC1_SNORM] = DXGI_FORMAT_BC4_SNORM,
[PIPE_FORMAT_RGTC2_UNORM] = DXGI_FORMAT_BC5_UNORM,
[PIPE_FORMAT_RGTC2_SNORM] = DXGI_FORMAT_BC5_SNORM,
[PIPE_FORMAT_BPTC_RGB_UFLOAT] = DXGI_FORMAT_BC6H_UF16,
[PIPE_FORMAT_BPTC_RGB_FLOAT] = DXGI_FORMAT_BC6H_SF16,
[PIPE_FORMAT_BPTC_RGBA_UNORM] = DXGI_FORMAT_BC7_UNORM,
[PIPE_FORMAT_BPTC_SRGBA] = DXGI_FORMAT_BC7_UNORM_SRGB,
[PIPE_FORMAT_Z32_FLOAT] = DXGI_FORMAT_R32_TYPELESS,
[PIPE_FORMAT_Z16_UNORM] = DXGI_FORMAT_R16_TYPELESS,
[PIPE_FORMAT_Z24X8_UNORM] = DXGI_FORMAT_R24G8_TYPELESS,
[PIPE_FORMAT_X24S8_UINT] = DXGI_FORMAT_R24G8_TYPELESS,
[PIPE_FORMAT_Z24_UNORM_S8_UINT] = DXGI_FORMAT_R24G8_TYPELESS,
[PIPE_FORMAT_Z32_FLOAT_S8X24_UINT] = DXGI_FORMAT_R32G8X24_TYPELESS,
[PIPE_FORMAT_X32_S8X24_UINT] = DXGI_FORMAT_R32G8X24_TYPELESS,
};
DXGI_FORMAT
dzn_pipe_to_dxgi_format(enum pipe_format in)
{
return formats[in];
}
DXGI_FORMAT
dzn_get_typeless_dxgi_format(DXGI_FORMAT in)
{
if (in >= DXGI_FORMAT_R32G32B32A32_TYPELESS && in <= DXGI_FORMAT_R32G32B32A32_SINT)
return DXGI_FORMAT_R32G32B32A32_TYPELESS;
if (in >= DXGI_FORMAT_R32G32B32_TYPELESS && in <= DXGI_FORMAT_R32G32B32_SINT)
return DXGI_FORMAT_R32G32B32_TYPELESS;
if (in >= DXGI_FORMAT_R16G16B16A16_TYPELESS && in <= DXGI_FORMAT_R16G16B16A16_SINT)
return DXGI_FORMAT_R16G16B16A16_TYPELESS;
if (in >= DXGI_FORMAT_R32G32_TYPELESS && in <= DXGI_FORMAT_R32G32_SINT)
return DXGI_FORMAT_R32G32_TYPELESS;
if (in >= DXGI_FORMAT_R32G8X24_TYPELESS && in <= DXGI_FORMAT_X32_TYPELESS_G8X24_UINT)
return DXGI_FORMAT_R32G8X24_TYPELESS;
if (in >= DXGI_FORMAT_R10G10B10A2_TYPELESS && in <= DXGI_FORMAT_R10G10B10A2_UINT)
return DXGI_FORMAT_R10G10B10A2_TYPELESS;
if (in >= DXGI_FORMAT_R8G8B8A8_TYPELESS && in <= DXGI_FORMAT_R8G8B8A8_SINT)
return DXGI_FORMAT_R8G8B8A8_TYPELESS;
if (in >= DXGI_FORMAT_R16G16_TYPELESS && in <= DXGI_FORMAT_R16G16_SINT)
return DXGI_FORMAT_R16G16_TYPELESS;
if (in >= DXGI_FORMAT_R32_TYPELESS && in <= DXGI_FORMAT_R32_SINT)
return DXGI_FORMAT_R32_TYPELESS;
if (in >= DXGI_FORMAT_R24G8_TYPELESS && in <= DXGI_FORMAT_X24_TYPELESS_G8_UINT)
return DXGI_FORMAT_R24G8_TYPELESS;
if (in >= DXGI_FORMAT_R8G8_TYPELESS && in <= DXGI_FORMAT_R8G8_SINT)
return DXGI_FORMAT_R8G8_TYPELESS;
if (in >= DXGI_FORMAT_R16_TYPELESS && in <= DXGI_FORMAT_R16_SINT)
return DXGI_FORMAT_R16_TYPELESS;
if (in >= DXGI_FORMAT_R8_TYPELESS && in <= DXGI_FORMAT_R8_SINT)
return DXGI_FORMAT_R8_TYPELESS;
if (in >= DXGI_FORMAT_BC1_TYPELESS && in <= DXGI_FORMAT_BC1_UNORM_SRGB)
return DXGI_FORMAT_BC1_TYPELESS;
if (in >= DXGI_FORMAT_BC2_TYPELESS && in <= DXGI_FORMAT_BC2_UNORM_SRGB)
return DXGI_FORMAT_BC2_TYPELESS;
if (in >= DXGI_FORMAT_BC3_TYPELESS && in <= DXGI_FORMAT_BC3_UNORM_SRGB)
return DXGI_FORMAT_BC3_TYPELESS;
if (in >= DXGI_FORMAT_BC4_TYPELESS && in <= DXGI_FORMAT_BC4_SNORM)
return DXGI_FORMAT_BC4_TYPELESS;
if (in >= DXGI_FORMAT_BC5_TYPELESS && in <= DXGI_FORMAT_BC5_SNORM)
return DXGI_FORMAT_BC5_TYPELESS;
if (in == DXGI_FORMAT_B8G8R8A8_UNORM ||
(in >= DXGI_FORMAT_B8G8R8A8_TYPELESS && in <= DXGI_FORMAT_B8G8R8A8_UNORM_SRGB))
return DXGI_FORMAT_B8G8R8A8_TYPELESS;
if (in == DXGI_FORMAT_B8G8R8X8_UNORM ||
(in >= DXGI_FORMAT_B8G8R8X8_TYPELESS && in <= DXGI_FORMAT_B8G8R8X8_UNORM_SRGB))
return DXGI_FORMAT_B8G8R8X8_TYPELESS;
if (in >= DXGI_FORMAT_BC6H_TYPELESS && in <= DXGI_FORMAT_BC6H_SF16)
return DXGI_FORMAT_BC6H_TYPELESS;
if (in >= DXGI_FORMAT_BC7_TYPELESS && in <= DXGI_FORMAT_BC7_UNORM_SRGB)
return DXGI_FORMAT_BC7_TYPELESS;
return in;
}
static D3D12_FILTER_TYPE
translate_filter_type(VkFilter type)
{
switch (type) {
case VK_FILTER_NEAREST: return D3D12_FILTER_TYPE_POINT;
case VK_FILTER_LINEAR: return D3D12_FILTER_TYPE_LINEAR;
default:
assert(!"Unsupported filter mode");
return D3D12_FILTER_TYPE_POINT;
}
}
static D3D12_FILTER_TYPE
translate_mip_filter_type(VkSamplerMipmapMode type)
{
switch (type) {
case VK_SAMPLER_MIPMAP_MODE_NEAREST: return D3D12_FILTER_TYPE_POINT;
case VK_SAMPLER_MIPMAP_MODE_LINEAR: return D3D12_FILTER_TYPE_LINEAR;
default:
assert(!"Unsupported filter mode");
return D3D12_FILTER_TYPE_POINT;
}
}
D3D12_FILTER
dzn_translate_sampler_filter(const struct dzn_physical_device *pdev,
const VkSamplerCreateInfo *create_info)
{
D3D12_FILTER_REDUCTION_TYPE reduction = create_info->compareEnable ?
D3D12_FILTER_REDUCTION_TYPE_COMPARISON : D3D12_FILTER_REDUCTION_TYPE_STANDARD;
if (create_info->anisotropyEnable) {
if (create_info->mipmapMode == VK_SAMPLER_MIPMAP_MODE_NEAREST &&
pdev->options19.AnisoFilterWithPointMipSupported)
return D3D12_ENCODE_MIN_MAG_ANISOTROPIC_MIP_POINT_FILTER(reduction);
return D3D12_ENCODE_ANISOTROPIC_FILTER(reduction);
}
return D3D12_ENCODE_BASIC_FILTER(
translate_filter_type(create_info->minFilter),
translate_filter_type(create_info->magFilter),
translate_mip_filter_type(create_info->mipmapMode),
reduction);
}
D3D12_COMPARISON_FUNC
dzn_translate_compare_op(VkCompareOp in)
{
switch (in) {
case VK_COMPARE_OP_NEVER: return D3D12_COMPARISON_FUNC_NEVER;
case VK_COMPARE_OP_LESS: return D3D12_COMPARISON_FUNC_LESS;
case VK_COMPARE_OP_EQUAL: return D3D12_COMPARISON_FUNC_EQUAL;
case VK_COMPARE_OP_LESS_OR_EQUAL: return D3D12_COMPARISON_FUNC_LESS_EQUAL;
case VK_COMPARE_OP_GREATER: return D3D12_COMPARISON_FUNC_GREATER;
case VK_COMPARE_OP_NOT_EQUAL: return D3D12_COMPARISON_FUNC_NOT_EQUAL;
case VK_COMPARE_OP_GREATER_OR_EQUAL: return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
case VK_COMPARE_OP_ALWAYS: return D3D12_COMPARISON_FUNC_ALWAYS;
default: UNREACHABLE("Invalid compare op");
}
}
void
dzn_translate_viewport(D3D12_VIEWPORT *out,
const VkViewport *in)
{
out->TopLeftX = in->x;
out->TopLeftY = in->height < 0 ? in->height + in->y : in->y;
out->Width = in->width;
out->Height = fabs(in->height);
out->MinDepth = MIN2(in->minDepth, in->maxDepth);
out->MaxDepth = MAX2(in->maxDepth, in->minDepth);
}
void
dzn_translate_rect(D3D12_RECT *out,
const VkRect2D *in)
{
out->left = in->offset.x;
out->top = in->offset.y;
out->right = in->offset.x + in->extent.width;
out->bottom = in->offset.y + in->extent.height;
}
static ID3D12Debug *
get_debug_interface(struct util_dl_library *d3d12_mod, ID3D12DeviceFactory *factory)
{
typedef HRESULT(WINAPI *PFN_D3D12_GET_DEBUG_INTERFACE)(REFIID riid, void **ppFactory);
PFN_D3D12_GET_DEBUG_INTERFACE D3D12GetDebugInterface;
ID3D12Debug *debug;
if (factory) {
if (FAILED(ID3D12DeviceFactory_GetConfigurationInterface(factory, &CLSID_D3D12Debug, &IID_ID3D12Debug, (void **)&debug))) {
mesa_loge("Failed to retrieve ID3D12Debug from device factory\n");
return NULL;
}
} else {
D3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)util_dl_get_proc_address(d3d12_mod, "D3D12GetDebugInterface");
if (!D3D12GetDebugInterface) {
mesa_loge("failed to load D3D12GetDebugInterface from D3D12.DLL\n");
return NULL;
}
if (FAILED(D3D12GetDebugInterface(&IID_ID3D12Debug, (void **)&debug))) {
mesa_loge("D3D12GetDebugInterface failed\n");
return NULL;
}
}
return debug;
}
void
d3d12_enable_debug_layer(struct util_dl_library *d3d12_mod, ID3D12DeviceFactory *factory)
{
ID3D12Debug *debug = get_debug_interface(d3d12_mod, factory);
if (debug) {
ID3D12Debug_EnableDebugLayer(debug);
ID3D12Debug_Release(debug);
}
}
void
d3d12_enable_gpu_validation(struct util_dl_library *d3d12_mod, ID3D12DeviceFactory *factory)
{
ID3D12Debug *debug = get_debug_interface(d3d12_mod, factory);
if (debug) {
ID3D12Debug3 *debug3;
if (SUCCEEDED(ID3D12Debug_QueryInterface(debug,
&IID_ID3D12Debug3,
(void **)&debug3))) {
ID3D12Debug3_SetEnableGPUBasedValidation(debug3, true);
ID3D12Debug3_Release(debug3);
}
ID3D12Debug_Release(debug);
}
}
ID3D12Device4 *
d3d12_create_device(struct util_dl_library *d3d12_mod, IUnknown *adapter, ID3D12DeviceFactory *factory, bool experimental_features)
{
#ifdef _WIN32
if (experimental_features)
#endif
{
if (factory) {
if (FAILED(ID3D12DeviceFactory_EnableExperimentalFeatures(factory, 1, &D3D12ExperimentalShaderModels, NULL, NULL))) {
mesa_loge("failed to enable experimental shader models\n");
return NULL;
}
} else {
typedef HRESULT(WINAPI *PFN_D3D12ENABLEEXPERIMENTALFEATURES)(UINT, const IID *, void *, UINT *);
PFN_D3D12ENABLEEXPERIMENTALFEATURES D3D12EnableExperimentalFeatures =
(PFN_D3D12ENABLEEXPERIMENTALFEATURES)util_dl_get_proc_address(d3d12_mod, "D3D12EnableExperimentalFeatures");
if (FAILED(D3D12EnableExperimentalFeatures(1, &D3D12ExperimentalShaderModels, NULL, NULL))) {
mesa_loge("failed to enable experimental shader models\n");
return NULL;
}
}
}
ID3D12Device4 *dev;
if (factory) {
ID3D12DeviceFactory_SetFlags(factory, D3D12_DEVICE_FACTORY_FLAG_ALLOW_RETURNING_EXISTING_DEVICE |
D3D12_DEVICE_FACTORY_FLAG_ALLOW_RETURNING_INCOMPATIBLE_EXISTING_DEVICE);
if (FAILED(ID3D12DeviceFactory_CreateDevice(factory, adapter, D3D_FEATURE_LEVEL_11_0,
&IID_ID3D12Device4,
(void **)&dev))) {
mesa_loge("ID3D12DeviceFactory::CreateDevice failed\n");
return NULL;
}
} else {
typedef HRESULT(WINAPI *PFN_D3D12CREATEDEVICE)(IUnknown *, D3D_FEATURE_LEVEL, REFIID, void **);
PFN_D3D12CREATEDEVICE D3D12CreateDevice;
D3D12CreateDevice = (PFN_D3D12CREATEDEVICE)util_dl_get_proc_address(d3d12_mod, "D3D12CreateDevice");
if (!D3D12CreateDevice) {
mesa_loge("failed to load D3D12CreateDevice from D3D12\n");
return NULL;
}
if (FAILED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0,
&IID_ID3D12Device4,
(void **)&dev))) {
mesa_loge("D3D12CreateDevice failed\n");
return NULL;
}
}
return dev;
}
PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE
d3d12_get_serialize_root_sig(struct util_dl_library *d3d12_mod)
{
return (PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)
util_dl_get_proc_address(d3d12_mod, "D3D12SerializeVersionedRootSignature");
}
+116
View File
@@ -0,0 +1,116 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dzn_private.h"
#include "vk_util.h"
static PFN_vkVoidFunction VKAPI_PTR
dzn_wsi_proc_addr(VkPhysicalDevice physicalDevice, const char *pName)
{
VK_FROM_HANDLE(dzn_physical_device, pdevice, physicalDevice);
return vk_instance_get_proc_addr_unchecked(pdevice->vk.instance, pName);
}
static void *
dzn_wsi_get_d3d12_command_queue(VkDevice dev)
{
VK_FROM_HANDLE(dzn_device, device, dev);
return device->swapchain_queue->cmdqueue;
}
static struct vk_queue *
dzn_wsi_get_blit_queue(VkDevice dev)
{
VK_FROM_HANDLE(dzn_device, device, dev);
return &device->swapchain_queue->vk;
}
static bool
dzn_wsi_needs_blits(VkDevice dev)
{
VK_FROM_HANDLE(dzn_device, device, dev);
return device->need_swapchain_blits;
}
static VkResult
dzn_wsi_create_image_memory(VkDevice dev, void *resource,
const VkAllocationCallbacks *alloc,
VkDeviceMemory *out)
{
VK_FROM_HANDLE(dzn_device, device, dev);
struct dzn_device_memory *mem =
vk_zalloc2(&device->vk.alloc, alloc, sizeof(*mem), 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!mem)
return VK_ERROR_OUT_OF_HOST_MEMORY;
vk_object_base_init(&device->vk, &mem->base, VK_OBJECT_TYPE_DEVICE_MEMORY);
mem->dedicated_res = resource;
ID3D12Resource_AddRef(mem->dedicated_res);
*out = dzn_device_memory_to_handle(mem);
return VK_SUCCESS;
}
void
dzn_wsi_finish(struct dzn_physical_device *physical_device)
{
wsi_device_finish(&physical_device->wsi_device,
&physical_device->vk.instance->alloc);
}
VkResult
dzn_wsi_init(struct dzn_physical_device *physical_device)
{
VkResult result;
#ifdef _WIN32
bool sw = false;
#else
bool sw = true;
#endif
result = wsi_device_init(&physical_device->wsi_device,
dzn_physical_device_to_handle(physical_device),
dzn_wsi_proc_addr,
&physical_device->vk.instance->alloc,
-1, NULL,
&(struct wsi_device_options){.sw_device = sw});
if (result != VK_SUCCESS)
return result;
physical_device->wsi_device.win32.get_d3d12_command_queue =
dzn_wsi_get_d3d12_command_queue;
physical_device->wsi_device.win32.requires_blits = dzn_wsi_needs_blits;
physical_device->wsi_device.get_blit_queue = dzn_wsi_get_blit_queue;
physical_device->wsi_device.win32.create_image_memory =
dzn_wsi_create_image_memory;
physical_device->wsi_device.supports_modifiers = false;
physical_device->vk.wsi_device = &physical_device->wsi_device;
return VK_SUCCESS;
}
+122
View File
@@ -0,0 +1,122 @@
# Copyright © Microsoft Corporation
# SPDX-License-Identifier: MIT
dzn_entrypoints = custom_target(
'dzn_entrypoints',
input : [vk_entrypoints_gen, vk_api_xml],
output : ['dzn_entrypoints.h', 'dzn_entrypoints.c'],
command : [
prog_python, '@INPUT0@', '--xml', '@INPUT1@', '--proto', '--weak',
'--out-h', '@OUTPUT0@', '--out-c', '@OUTPUT1@', '--prefix', 'dzn',
'--beta', with_vulkan_beta.to_string()
],
depend_files : vk_entrypoints_gen_depend_files,
)
libdzn_files = files(
'dzn_cmd_buffer.c',
'dzn_descriptor_set.c',
'dzn_device.c',
'dzn_dxcore.cpp',
'dzn_image.c',
'dzn_meta.c',
'dzn_nir.c',
'dzn_pipeline.c',
'dzn_query.c',
'dzn_sync.c',
'dzn_util.c',
'dzn_wsi.c',
)
dzn_deps = [
idep_libdxil_compiler,
idep_libspirv_to_dxil,
idep_nir,
idep_nir_headers,
idep_vulkan_util,
idep_vulkan_runtime,
idep_vulkan_wsi,
idep_mesautil,
dep_dxheaders,
]
dzn_flags = [ ]
dzn_cpp_flags = [ ]
if with_platform_windows
libdzn_files += files('dzn_dxgi.c')
endif
if cc.get_argument_syntax() != 'msvc'
dzn_flags_to_try = [
'-Werror=unused-variable',
'-Werror=unused-but-set-variable',
'-Werror=unused-value',
'-Werror=format',
'-Werror=switch',
]
dzn_flags += cc.get_supported_arguments(dzn_flags_to_try)
dzn_cpp_flags = cpp.get_supported_arguments(['-Wno-error=unused-value'])
endif
libvulkan_dzn = shared_library(
'vulkan_dzn',
[libdzn_files, dzn_entrypoints, sha1_h],
vs_module_defs : vulkan_api_def,
include_directories : [inc_include, inc_src, inc_util],
dependencies : [dzn_deps, idep_vulkan_wsi, idep_xmlconfig],
c_args : dzn_flags,
cpp_args : dzn_cpp_flags,
gnu_symbol_visibility : 'hidden',
link_args : [ld_args_bsymbolic, ld_args_gc_sections],
name_prefix : host_machine.system() == 'windows' ? '' : [],
install : true,
)
icd_file_name = libname_prefix + 'vulkan_dzn.' + libname_suffix
icd_command = [
prog_python, '@INPUT0@',
'--api-version', '1.1', '--xml', '@INPUT1@',
'--sizeof-pointer', sizeof_pointer,
'--icd-lib-path', vulkan_icd_lib_path,
'--icd-filename', icd_file_name,
'--out', '@OUTPUT@',
]
icd_dev_command = [
prog_python, '@INPUT0@',
'--api-version', '1.1', '--xml', '@INPUT1@',
'--sizeof-pointer', sizeof_pointer,
'--icd-lib-path', meson.current_build_dir(),
'--icd-filename', icd_file_name,
'--out', '@OUTPUT@',
]
if with_platform_windows
icd_command += '--use-backslash'
icd_dev_command += '--use-backslash'
endif
dzn_icd = custom_target(
'dzn_icd',
input : [vk_icd_gen, vk_api_xml],
output : 'dzn_icd.' + vulkan_manifest_suffix,
command : icd_command,
build_by_default : true,
install_dir : with_vulkan_icd_dir,
install_tag : 'runtime',
install : true,
)
_dev_icdname = 'dzn_devenv_icd.@[email protected]'.format(host_machine.cpu())
_dev_icd = custom_target(
'dzn_devenv_icd',
input : [vk_icd_gen, vk_api_xml],
output : _dev_icdname,
command : icd_dev_command,
build_by_default : true,
)
devenv.append('VK_DRIVER_FILES', _dev_icd.full_path())