static void llvm_emit_prologue(struct lp_build_tgsi_context * bld_base) { struct radeon_llvm_context * ctx = radeon_llvm_context(bld_base); struct lp_build_context * base = &bld_base->base; unsigned i; /* Reserve special input registers */ for (i = 0; i < ctx->reserved_reg_count; i++) { unsigned chan; for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { LLVMValueRef reg; LLVMValueRef reg_index = lp_build_const_int32( base->gallivm, radeon_llvm_reg_index_soa(i, chan)); reg = lp_build_intrinsic_unary(base->gallivm->builder, "llvm.AMDGPU.reserve.reg", base->elem_type, reg_index); lp_build_intrinsic_unary(base->gallivm->builder, "llvm.AMDGPU.export.reg", LLVMVoidTypeInContext(base->gallivm->context), reg); } } }
static void llvm_load_input( struct radeon_llvm_context * ctx, unsigned input_index, const struct tgsi_full_declaration *decl) { const struct r600_shader_io * input = &ctx->r600_inputs[input_index]; unsigned chan; #if HAVE_LLVM < 0x0304 unsigned interp = 0; int ij_index; #endif int two_side = (ctx->two_side && input->name == TGSI_SEMANTIC_COLOR); LLVMValueRef v; #if HAVE_LLVM >= 0x0304 boolean require_interp_intrinsic = ctx->chip_class >= EVERGREEN && ctx->type == TGSI_PROCESSOR_FRAGMENT; #endif #if HAVE_LLVM >= 0x0304 if (require_interp_intrinsic && input->spi_sid) { v = llvm_load_input_vector(ctx, input->lds_pos, input->ij_index, (input->interpolate > 0)); } else v = LLVMGetParam(ctx->main_fn, input->gpr); if (two_side) { struct r600_shader_io * back_input = &ctx->r600_inputs[input->back_color_input]; LLVMValueRef v2; LLVMValueRef face = LLVMGetParam(ctx->main_fn, ctx->face_gpr); face = LLVMBuildExtractElement(ctx->gallivm.builder, face, lp_build_const_int32(&(ctx->gallivm), 0), ""); if (require_interp_intrinsic && back_input->spi_sid) v2 = llvm_load_input_vector(ctx, back_input->lds_pos, back_input->ij_index, (back_input->interpolate > 0)); else v2 = LLVMGetParam(ctx->main_fn, back_input->gpr); v = llvm_face_select_helper(ctx, face, v, v2); } for (chan = 0; chan < 4; chan++) { unsigned soa_index = radeon_llvm_reg_index_soa(input_index, chan); ctx->inputs[soa_index] = LLVMBuildExtractElement(ctx->gallivm.builder, v, lp_build_const_int32(&(ctx->gallivm), chan), ""); if (input->name == TGSI_SEMANTIC_POSITION && ctx->type == TGSI_PROCESSOR_FRAGMENT && chan == 3) { /* RCP for fragcoord.w */ ctx->inputs[soa_index] = LLVMBuildFDiv(ctx->gallivm.builder, lp_build_const_float(&(ctx->gallivm), 1.0f), ctx->inputs[soa_index], ""); } } #else if (ctx->chip_class >= EVERGREEN && ctx->type == TGSI_PROCESSOR_FRAGMENT && input->spi_sid) { interp = 1; ij_index = (input->interpolate > 0) ? input->ij_index : -1; } for (chan = 0; chan < 4; chan++) { unsigned soa_index = radeon_llvm_reg_index_soa(input_index, chan); int loc; if (interp) { loc = 4 * input->lds_pos + chan; } else { if (input->name == TGSI_SEMANTIC_FACE) loc = 4 * ctx->face_gpr; else loc = 4 * input->gpr + chan; } v = llvm_load_input_helper(ctx, loc, interp, ij_index); if (two_side) { struct r600_shader_io * back_input = &ctx->r600_inputs[input->back_color_input]; int back_loc = interp ? back_input->lds_pos : back_input->gpr; LLVMValueRef v2; back_loc = 4 * back_loc + chan; v2 = llvm_load_input_helper(ctx, back_loc, interp, ij_index); v = llvm_face_select_helper(ctx, 4 * ctx->face_gpr, v, v2); } else if (input->name == TGSI_SEMANTIC_POSITION && ctx->type == TGSI_PROCESSOR_FRAGMENT && chan == 3) { /* RCP for fragcoord.w */ v = LLVMBuildFDiv(ctx->gallivm.builder, lp_build_const_float(&(ctx->gallivm), 1.0f), v, ""); } ctx->inputs[soa_index] = v; } #endif }
static void declare_input_fs( struct si_shader_context * si_shader_ctx, unsigned input_index, const struct tgsi_full_declaration *decl) { struct si_shader *shader = &si_shader_ctx->shader->shader; struct lp_build_context * base = &si_shader_ctx->radeon_bld.soa.bld_base.base; struct gallivm_state * gallivm = base->gallivm; LLVMTypeRef input_type = LLVMFloatTypeInContext(gallivm->context); LLVMValueRef main_fn = si_shader_ctx->radeon_bld.main_fn; LLVMValueRef interp_param; const char * intr_name; /* This value is: * [15:0] NewPrimMask (Bit mask for each quad. It is set it the * quad begins a new primitive. Bit 0 always needs * to be unset) * [32:16] ParamOffset * */ LLVMValueRef params = LLVMGetParam(si_shader_ctx->radeon_bld.main_fn, SI_PARAM_PRIM_MASK); LLVMValueRef attr_number; unsigned chan; if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION) { for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { unsigned soa_index = radeon_llvm_reg_index_soa(input_index, chan); si_shader_ctx->radeon_bld.inputs[soa_index] = LLVMGetParam(main_fn, SI_PARAM_POS_X_FLOAT + chan); if (chan == 3) /* RCP for fragcoord.w */ si_shader_ctx->radeon_bld.inputs[soa_index] = LLVMBuildFDiv(gallivm->builder, lp_build_const_float(gallivm, 1.0f), si_shader_ctx->radeon_bld.inputs[soa_index], ""); } return; } if (decl->Semantic.Name == TGSI_SEMANTIC_FACE) { LLVMValueRef face, is_face_positive; face = LLVMGetParam(main_fn, SI_PARAM_FRONT_FACE); is_face_positive = LLVMBuildFCmp(gallivm->builder, LLVMRealUGT, face, lp_build_const_float(gallivm, 0.0f), ""); si_shader_ctx->radeon_bld.inputs[radeon_llvm_reg_index_soa(input_index, 0)] = LLVMBuildSelect(gallivm->builder, is_face_positive, lp_build_const_float(gallivm, 1.0f), lp_build_const_float(gallivm, 0.0f), ""); si_shader_ctx->radeon_bld.inputs[radeon_llvm_reg_index_soa(input_index, 1)] = si_shader_ctx->radeon_bld.inputs[radeon_llvm_reg_index_soa(input_index, 2)] = lp_build_const_float(gallivm, 0.0f); si_shader_ctx->radeon_bld.inputs[radeon_llvm_reg_index_soa(input_index, 3)] = lp_build_const_float(gallivm, 1.0f); return; } shader->input[input_index].param_offset = shader->ninterp++; attr_number = lp_build_const_int32(gallivm, shader->input[input_index].param_offset); /* XXX: Handle all possible interpolation modes */ switch (decl->Interp.Interpolate) { case TGSI_INTERPOLATE_COLOR: if (si_shader_ctx->shader->key.ps.flatshade) { interp_param = 0; } else { if (decl->Interp.Centroid) interp_param = LLVMGetParam(main_fn, SI_PARAM_PERSP_CENTROID); else interp_param = LLVMGetParam(main_fn, SI_PARAM_PERSP_CENTER); } break; case TGSI_INTERPOLATE_CONSTANT: interp_param = 0; break; case TGSI_INTERPOLATE_LINEAR: if (decl->Interp.Centroid) interp_param = LLVMGetParam(main_fn, SI_PARAM_LINEAR_CENTROID); else interp_param = LLVMGetParam(main_fn, SI_PARAM_LINEAR_CENTER); break; case TGSI_INTERPOLATE_PERSPECTIVE: if (decl->Interp.Centroid) interp_param = LLVMGetParam(main_fn, SI_PARAM_PERSP_CENTROID); else interp_param = LLVMGetParam(main_fn, SI_PARAM_PERSP_CENTER); break; default: fprintf(stderr, "Warning: Unhandled interpolation mode.\n"); return; } intr_name = interp_param ? "llvm.SI.fs.interp" : "llvm.SI.fs.constant"; /* XXX: Could there be more than TGSI_NUM_CHANNELS (4) ? */ if (decl->Semantic.Name == TGSI_SEMANTIC_COLOR && si_shader_ctx->shader->key.ps.color_two_side) { LLVMValueRef args[4]; LLVMValueRef face, is_face_positive; LLVMValueRef back_attr_number = lp_build_const_int32(gallivm, shader->input[input_index].param_offset + 1); face = LLVMGetParam(main_fn, SI_PARAM_FRONT_FACE); is_face_positive = LLVMBuildFCmp(gallivm->builder, LLVMRealUGT, face, lp_build_const_float(gallivm, 0.0f), ""); args[2] = params; args[3] = interp_param; for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { LLVMValueRef llvm_chan = lp_build_const_int32(gallivm, chan); unsigned soa_index = radeon_llvm_reg_index_soa(input_index, chan); LLVMValueRef front, back; args[0] = llvm_chan; args[1] = attr_number; front = build_intrinsic(base->gallivm->builder, intr_name, input_type, args, args[3] ? 4 : 3, LLVMReadNoneAttribute | LLVMNoUnwindAttribute); args[1] = back_attr_number; back = build_intrinsic(base->gallivm->builder, intr_name, input_type, args, args[3] ? 4 : 3, LLVMReadNoneAttribute | LLVMNoUnwindAttribute); si_shader_ctx->radeon_bld.inputs[soa_index] = LLVMBuildSelect(gallivm->builder, is_face_positive, front, back, ""); } shader->ninterp++; } else { for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { LLVMValueRef args[4]; LLVMValueRef llvm_chan = lp_build_const_int32(gallivm, chan); unsigned soa_index = radeon_llvm_reg_index_soa(input_index, chan); args[0] = llvm_chan; args[1] = attr_number; args[2] = params; args[3] = interp_param; si_shader_ctx->radeon_bld.inputs[soa_index] = build_intrinsic(base->gallivm->builder, intr_name, input_type, args, args[3] ? 4 : 3, LLVMReadNoneAttribute | LLVMNoUnwindAttribute); } } }
static void llvm_emit_epilogue(struct lp_build_tgsi_context * bld_base) { struct radeon_llvm_context * ctx = radeon_llvm_context(bld_base); struct lp_build_context * base = &bld_base->base; unsigned i; unsigned color_count = 0; boolean has_color = false; /* Add the necessary export instructions */ for (i = 0; i < ctx->output_reg_count; i++) { unsigned chan; for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { LLVMValueRef output; unsigned adjusted_reg_idx = i + ctx->reserved_reg_count; output = LLVMBuildLoad(base->gallivm->builder, ctx->soa.outputs[i][chan], ""); if (ctx->type == TGSI_PROCESSOR_VERTEX) { LLVMValueRef reg_index = lp_build_const_int32( base->gallivm, radeon_llvm_reg_index_soa(adjusted_reg_idx, chan)); lp_build_intrinsic_binary( base->gallivm->builder, "llvm.AMDGPU.store.output", LLVMVoidTypeInContext(base->gallivm->context), output, reg_index); } else if (ctx->type == TGSI_PROCESSOR_FRAGMENT) { switch (ctx->r600_outputs[i].name) { case TGSI_SEMANTIC_COLOR: has_color = true; if ( color_count/4 < ctx->color_buffer_count) { if (ctx->fs_color_all) { for (unsigned j = 0; j < ctx->color_buffer_count; j++) { LLVMValueRef reg_index = lp_build_const_int32( base->gallivm, (j * 4) + chan); lp_build_intrinsic_binary( base->gallivm->builder, "llvm.R600.store.pixel.color", LLVMVoidTypeInContext(base->gallivm->context), output, reg_index); } } else { LLVMValueRef reg_index = lp_build_const_int32( base->gallivm, (color_count++/4) * 4 + chan); lp_build_intrinsic_binary( base->gallivm->builder, "llvm.R600.store.pixel.color", LLVMVoidTypeInContext(base->gallivm->context), output, reg_index); } } break; case TGSI_SEMANTIC_POSITION: if (chan != 2) continue; lp_build_intrinsic_unary( base->gallivm->builder, "llvm.R600.store.pixel.depth", LLVMVoidTypeInContext(base->gallivm->context), output); break; case TGSI_SEMANTIC_STENCIL: if (chan != 1) continue; lp_build_intrinsic_unary( base->gallivm->builder, "llvm.R600.store.pixel.stencil", LLVMVoidTypeInContext(base->gallivm->context), output); break; } } } } if (!has_color && ctx->type == TGSI_PROCESSOR_FRAGMENT) lp_build_intrinsic(base->gallivm->builder, "llvm.R600.store.pixel.dummy", LLVMVoidTypeInContext(base->gallivm->context), 0, 0); }
static void llvm_load_input( struct radeon_llvm_context * ctx, unsigned input_index, const struct tgsi_full_declaration *decl) { unsigned chan; const char *intrinsics = "llvm.R600.load.input"; unsigned offset = 4 * ctx->reserved_reg_count; if (ctx->type == TGSI_PROCESSOR_FRAGMENT && ctx->chip_class >= EVERGREEN) { switch (decl->Interp.Interpolate) { case TGSI_INTERPOLATE_COLOR: case TGSI_INTERPOLATE_PERSPECTIVE: offset = 0; intrinsics = "llvm.R600.load.input.perspective"; break; case TGSI_INTERPOLATE_LINEAR: offset = 0; intrinsics = "llvm.R600.load.input.linear"; break; case TGSI_INTERPOLATE_CONSTANT: offset = 0; intrinsics = "llvm.R600.load.input.constant"; break; default: assert(0 && "Unknow Interpolate mode"); } } for (chan = 0; chan < 4; chan++) { unsigned soa_index = radeon_llvm_reg_index_soa(input_index, chan); switch (decl->Semantic.Name) { case TGSI_SEMANTIC_FACE: ctx->inputs[soa_index] = llvm_load_input_helper(ctx, "llvm.R600.load.input", 4 * ctx->face_input); break; case TGSI_SEMANTIC_POSITION: if (ctx->type != TGSI_PROCESSOR_FRAGMENT || chan != 3) { ctx->inputs[soa_index] = llvm_load_input_helper(ctx, "llvm.R600.load.input", soa_index + (ctx->reserved_reg_count * 4)); } else { LLVMValueRef w_coord = llvm_load_input_helper(ctx, "llvm.R600.load.input", soa_index + (ctx->reserved_reg_count * 4)); ctx->inputs[soa_index] = LLVMBuildFDiv(ctx->gallivm.builder, lp_build_const_float(&(ctx->gallivm), 1.0f), w_coord, ""); } break; case TGSI_SEMANTIC_COLOR: if (ctx->two_side) { unsigned front_location, back_location; unsigned back_reg = ctx->r600_inputs[input_index] .potential_back_facing_reg; if (ctx->chip_class >= EVERGREEN) { front_location = 4 * ctx->r600_inputs[input_index].lds_pos + chan; back_location = 4 * ctx->r600_inputs[back_reg].lds_pos + chan; } else { front_location = soa_index + 4 * ctx->reserved_reg_count; back_location = radeon_llvm_reg_index_soa( ctx->r600_inputs[back_reg].gpr, chan); } ctx->inputs[soa_index] = llvm_face_select_helper(ctx, intrinsics, 4 * ctx->face_input, front_location, back_location); break; } default: { unsigned location; if (ctx->chip_class >= EVERGREEN) { location = 4 * ctx->r600_inputs[input_index].lds_pos + chan; } else { location = soa_index + 4 * ctx->reserved_reg_count; } /* The * 4 is assuming that we are in soa mode. */ ctx->inputs[soa_index] = llvm_load_input_helper(ctx, intrinsics, location); break; } } } }