mirror of
https://github.com/elwrcl/intel-hard-graphics.git
synced 2026-10-31 19:08:03 +03:00
init
This commit is contained in:
12511 files changed
+6156641
No files matched your search
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
};
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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, ¶ms);
|
||||
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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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,
|
||||
)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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())
|
||||
Reference in new issue
Block a user