3 * Copyright (c) 2018 Collabora LTD
5 * Author: Gert Wollny <gert.wollny@collabora.com>
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * on the rights to use, copy, modify, merge, publish, distribute, sub
11 * license, and/or sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include "pipe/p_defines.h"
29 #include "tgsi/tgsi_from_mesa.h"
30 #include "sfn_shader_vertex.h"
31 #include "sfn_instruction_lds.h"
38 using std::priority_queue
;
40 VertexShaderFromNir::VertexShaderFromNir(r600_pipe_shader
*sh
,
41 r600_pipe_shader_selector
& sel
,
42 const r600_shader_key
& key
,
43 struct r600_shader
* gs_shader
,
44 enum chip_class chip_class
):
45 VertexStage(PIPE_SHADER_VERTEX
, sel
, sh
->shader
,
46 sh
->scratch_space_needed
, chip_class
),
48 m_last_param_export(nullptr),
49 m_last_pos_export(nullptr),
51 m_enabled_stream_buffers_mask(0),
56 // reg 0 is used in the fetch shader
57 increment_reserved_registers();
59 sh_info().atomic_base
= key
.vs
.first_atomic_counter
;
60 sh_info().vs_as_gs_a
= m_key
.vs
.as_gs_a
;
63 sh
->shader
.vs_as_es
= true;
64 m_export_processor
.reset(new VertexStageExportForGS(*this, gs_shader
));
65 } else if (key
.vs
.as_ls
) {
66 sh
->shader
.vs_as_ls
= true;
67 sfn_log
<< SfnLog::trans
<< "Start VS for GS\n";
68 m_export_processor
.reset(new VertexStageExportForES(*this));
70 m_export_processor
.reset(new VertexStageExportForFS(*this, &sel
.so
, sh
, key
));
74 bool VertexShaderFromNir::do_process_inputs(nir_variable
*input
)
78 if (input
->data
.location
< VERT_ATTRIB_MAX
) {
79 increment_reserved_registers();
82 fprintf(stderr
, "r600-NIR-VS: Unimplemented process_inputs for %d\n", input
->data
.location
);
86 bool VertexShaderFromNir::allocate_reserved_registers()
88 /* Since the vertex ID is nearly always used, we add it here as an input so
89 * that the registers used for vertex attributes don't get clobbered by the
90 * register merge step */
91 auto R0x
= new GPRValue(0,0);
93 m_vertex_id
.reset(R0x
);
94 inject_register(0, 0, m_vertex_id
, false);
96 if (m_key
.vs
.as_gs_a
|| m_sv_values
.test(es_primitive_id
)) {
97 auto R0z
= new GPRValue(0,2);
99 m_primitive_id
.reset(R0z
);
100 inject_register(0, 2, m_primitive_id
, false);
103 if (m_sv_values
.test(es_instanceid
)) {
104 auto R0w
= new GPRValue(0,3);
106 m_instance_id
.reset(R0w
);
107 inject_register(0, 3, m_instance_id
, false);
111 if (m_sv_values
.test(es_rel_patch_id
)) {
112 auto R0y
= new GPRValue(0,1);
114 m_rel_vertex_id
.reset(R0y
);
115 inject_register(0, 1, m_rel_vertex_id
, false);
121 void VertexShaderFromNir::emit_shader_start()
123 m_export_processor
->setup_paramn_map();
126 bool VertexShaderFromNir::scan_sysvalue_access(nir_instr
*instr
)
128 switch (instr
->type
) {
129 case nir_instr_type_intrinsic
: {
130 nir_intrinsic_instr
*ii
= nir_instr_as_intrinsic(instr
);
131 switch (ii
->intrinsic
) {
132 case nir_intrinsic_load_vertex_id
:
133 m_sv_values
.set(es_vertexid
);
135 case nir_intrinsic_load_instance_id
:
136 m_sv_values
.set(es_instanceid
);
138 case nir_intrinsic_load_tcs_rel_patch_id_r600
:
139 m_sv_values
.set(es_rel_patch_id
);
151 bool VertexShaderFromNir::emit_intrinsic_instruction_override(nir_intrinsic_instr
* instr
)
153 switch (instr
->intrinsic
) {
154 case nir_intrinsic_load_vertex_id
:
155 return load_preloaded_value(instr
->dest
, 0, m_vertex_id
);
156 case nir_intrinsic_load_tcs_rel_patch_id_r600
:
157 return load_preloaded_value(instr
->dest
, 0, m_rel_vertex_id
);
158 case nir_intrinsic_load_instance_id
:
159 return load_preloaded_value(instr
->dest
, 0, m_instance_id
);
160 case nir_intrinsic_store_local_shared_r600
:
161 return emit_store_local_shared(instr
);
167 bool VertexShaderFromNir::emit_store_local_shared(nir_intrinsic_instr
* instr
)
169 unsigned write_mask
= nir_intrinsic_write_mask(instr
);
171 auto address
= from_nir(instr
->src
[1], 0);
172 int swizzle_base
= (write_mask
& 0x3) ? 0 : 2;
173 write_mask
|= write_mask
>> 2;
175 auto value
= from_nir(instr
->src
[0], swizzle_base
);
176 if (!(write_mask
& 2)) {
177 emit_instruction(new LDSWriteInstruction(address
, 1, value
));
179 auto value1
= from_nir(instr
->src
[0], swizzle_base
+ 1);
180 emit_instruction(new LDSWriteInstruction(address
, 1, value
, value1
));
186 bool VertexShaderFromNir::do_process_outputs(nir_variable
*output
)
188 return m_export_processor
->do_process_outputs(output
);
191 bool VertexShaderFromNir::do_emit_load_deref(const nir_variable
*in_var
, nir_intrinsic_instr
* instr
)
193 if (in_var
->data
.location
< VERT_ATTRIB_MAX
) {
194 for (int i
= 0; i
< instr
->num_components
; ++i
) {
195 auto s
= new GPRValue(in_var
->data
.driver_location
+ 1, i
);
197 auto src
= PValue(s
);
198 inject_register(in_var
->data
.driver_location
+ 1, i
, src
, false);
201 set_input(in_var
->data
.driver_location
, src
);
203 load_preloaded_value(instr
->dest
, i
, src
, i
== instr
->num_components
- 1);
207 fprintf(stderr
, "r600-NIR: Unimplemented load_deref for %d\n", in_var
->data
.location
);
211 void VertexShaderFromNir::do_finalize()
213 m_export_processor
->finalize_exports();
216 bool VertexShaderFromNir::do_emit_store_deref(const nir_variable
*out_var
, nir_intrinsic_instr
* instr
)
218 return m_export_processor
->store_deref(out_var
, instr
);