Commit 7ddb9b09 authored by Dave Airlie's avatar Dave Airlie Committed by Erik Faye-Lund

zink/spirv: add support for clip/cull distances.

parent fad58570
......@@ -51,12 +51,15 @@ struct ntv_context {
std::map<std::pair<int, int>, SpvId> input_types;
std::map<std::pair<int, int>, SpvId> outputs;
std::map<std::pair<int, int>, SpvId> output_types;
std::map<std::pair<int, int>, bool> output_is_clip_cull;
std::map<std::pair<int, int>, SpvId> so_outputs;
std::vector<SpvId> uniforms;
std::vector<SpvId> samplers;
std::vector<SpvId> sampler_types;
std::vector<SpvId> entry_ifaces;
SpvId clip_output, cull_output;
uint32_t clip_size, cull_size;
SpvId pos_val;
uint32_t max_output_location;
std::map<struct nir_ssa_def *, struct ntv_def> defs;
......@@ -222,7 +225,19 @@ emit_input(struct ntv_context *ctx, struct nir_variable *var)
static void
emit_output(struct ntv_context *ctx, struct nir_variable *var)
{
auto pair = std::make_pair((int)var->data.driver_location, (int)var->data.location_frac);
assert(ctx->outputs.count(pair) == 0);
SpvId vec_type = get_glsl_type(ctx, var->type);
/* handle clip in a separate pass */
if (var->data.location == VARYING_SLOT_CLIP_DIST0 ||
var->data.location == VARYING_SLOT_CLIP_DIST1) {
ctx->outputs[pair] = var->data.location;
ctx->output_is_clip_cull[pair] = true;
ctx->output_types[pair] = vec_type;
return;
}
SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
SpvStorageClassOutput,
vec_type);
......@@ -265,14 +280,55 @@ emit_output(struct ntv_context *ctx, struct nir_variable *var)
spirv_builder_emit_component(&ctx->builder, var_id,
var->data.location_frac);
auto pair = std::make_pair((int)var->data.driver_location, (int)var->data.location_frac);
assert(ctx->outputs.count(pair) == 0);
ctx->outputs[pair] = var_id;
ctx->output_types[pair] = vec_type;
ctx->output_is_clip_cull[pair] = false;
ctx->entry_ifaces.push_back(var_id);
}
static void
emit_clip_vars(struct ntv_context *ctx, struct nir_shader *s)
{
if (s->info.stage == MESA_SHADER_FRAGMENT)
return;
if (!s->info.clip_distance_array_size &&
!s->info.cull_distance_array_size)
return;
SpvId clip_vec_type, cull_vec_type;
SpvId pointer_type, var_id;
SpvId float_type = spirv_builder_type_float(&ctx->builder, 32);
if (s->info.clip_distance_array_size) {
SpvId array_length = spirv_builder_const_uint(&ctx->builder, 32, s->info.clip_distance_array_size);
clip_vec_type = spirv_builder_type_array(&ctx->builder, float_type, array_length);
pointer_type = spirv_builder_type_pointer(&ctx->builder,
SpvStorageClassOutput,
clip_vec_type);
var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
SpvStorageClassOutput);
spirv_builder_emit_name(&ctx->builder, var_id, "gl_ClipDistance");
spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInClipDistance);
ctx->clip_output = var_id;
ctx->clip_size = s->info.clip_distance_array_size;
ctx->entry_ifaces.push_back(var_id);
}
if (s->info.cull_distance_array_size) {
SpvId array_length = spirv_builder_const_uint(&ctx->builder, 32, s->info.cull_distance_array_size);
cull_vec_type = spirv_builder_type_array(&ctx->builder, float_type, array_length);
pointer_type = spirv_builder_type_pointer(&ctx->builder,
SpvStorageClassOutput,
cull_vec_type);
var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
SpvStorageClassOutput);
spirv_builder_emit_name(&ctx->builder, var_id, "gl_CullDistance");
spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInCullDistance);
ctx->cull_output = var_id;
ctx->cull_size = s->info.cull_distance_array_size;
ctx->entry_ifaces.push_back(var_id);
}
}
static SpvId
emit_unop(struct ntv_context *ctx, SpvOp op, SpvId type, SpvId src)
{
......@@ -1251,6 +1307,45 @@ emit_store_output(struct ntv_context *ctx, nir_intrinsic_instr *intr)
SpvId src = get_src(ctx, &intr->src[0]).result;
SpvId spirv_type = ctx->output_types[pair];
SpvId result;
if (ctx->output_is_clip_cull[pair] == true) {
uint32_t offset = 0;
if (ctx->outputs[pair] == VARYING_SLOT_CLIP_DIST1)
offset = 4;
uint32_t this_clips = MIN2(offset + 4, ctx->clip_size);
SpvId utype = get_uvec_type(ctx, 32, 1);
SpvId ftype = spirv_builder_type_float(&ctx->builder, 32);
SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
SpvStorageClassOutput,
ftype);
for (uint32_t i = offset; i < this_clips; i++) {
uint32_t indices[] = { i - offset };
SpvId spv_indices[] = { spirv_builder_const_uint(&ctx->builder, 32, i) };
result = spirv_builder_emit_composite_extract(&ctx->builder, utype,
src, indices, 1);
result = emit_unop(ctx, SpvOpBitcast, ftype, result);
SpvId output = spirv_builder_emit_access_chain(&ctx->builder, pointer_type,
ctx->clip_output, spv_indices, 1);
spirv_builder_emit_store(&ctx->builder, output, result);
}
if (ctx->cull_size == 0)
return;
uint32_t first_cull = MAX2(offset, ctx->clip_size);
uint32_t last_cull = MIN2(offset + 4, ctx->clip_size + ctx->cull_size);
for (uint32_t i = first_cull; i < last_cull; i++) {
uint32_t indices[] = { i - offset };
SpvId spv_indices[] = { spirv_builder_const_uint(&ctx->builder, 32, i - this_clips) };
result = spirv_builder_emit_composite_extract(&ctx->builder, utype,
src, indices, 1);
result = emit_unop(ctx, SpvOpBitcast, ftype, result);
SpvId output = spirv_builder_emit_access_chain(&ctx->builder, pointer_type,
ctx->cull_output, spv_indices, 1);
spirv_builder_emit_store(&ctx->builder, output, result);
}
return;
}
if (base == 0 && ctx->stage == MESA_SHADER_VERTEX) {
/* position output in vertex needs conversion */
ctx->pos_val = src;
......@@ -1680,6 +1775,12 @@ nir_to_spirv(struct nir_shader *s, const struct pipe_stream_output_info *so_info
unreachable("invalid stage");
}
if (s->info.clip_distance_array_size)
spirv_builder_emit_cap(&ctx.builder, SpvCapabilityClipDistance);
if (s->info.cull_distance_array_size)
spirv_builder_emit_cap(&ctx.builder, SpvCapabilityCullDistance);
ctx.stage = s->info.stage;
ctx.GLSL_std_450 = spirv_builder_import(&ctx.builder, "GLSL.std.450");
spirv_builder_emit_source(&ctx.builder, SpvSourceLanguageGLSL, 450);
......@@ -1724,6 +1825,7 @@ nir_to_spirv(struct nir_shader *s, const struct pipe_stream_output_info *so_info
nir_foreach_variable(var, &s->outputs)
emit_output(&ctx, var);
emit_clip_vars(&ctx, s);
if (so_info)
emit_so_info(&ctx, so_info);
nir_foreach_variable(var, &s->uniforms)
......
......@@ -261,10 +261,8 @@ zink_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
case PIPE_CAP_PCI_FUNCTION:
return 0; /* TODO: figure these out */
#if 0 /* TODO: Enable me */
case PIPE_CAP_CULL_DISTANCE:
return screen->feats.shaderCullDistance;
#endif
case PIPE_CAP_VIEWPORT_SUBPIXEL_BITS:
return screen->props.limits.viewportSubPixelBits;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment