Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/r300/r300_vs_draw.c
4570 views
1
/**************************************************************************
2
*
3
* Copyright 2009 Marek Olšák <[email protected]>
4
*
5
* Permission is hereby granted, free of charge, to any person obtaining a
6
* copy of this software and associated documentation files (the
7
* "Software"), to deal in the Software without restriction, including
8
* without limitation the rights to use, copy, modify, merge, publish,
9
* distribute, sub license, and/or sell copies of the Software, and to
10
* permit persons to whom the Software is furnished to do so, subject to
11
* the following conditions:
12
*
13
* The above copyright notice and this permission notice (including the
14
* next paragraph) shall be included in all copies or substantial portions
15
* of the Software.
16
*
17
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
*
25
**************************************************************************/
26
27
/* This file contains the vertex shader tranformations for SW TCL needed
28
* to overcome the limitations of the r300 rasterizer.
29
*
30
* Transformations:
31
* 1) If the secondary color output is present, the primary color must be
32
* present too.
33
* 2) If any back-face color output is present, there must be all 4 color
34
* outputs and missing ones must be inserted.
35
* 3) Insert a trailing texcoord output containing a copy of POS, for WPOS.
36
*
37
* I know this code is cumbersome, but I don't know of any nicer way
38
* of transforming TGSI shaders. ~ M.
39
*/
40
41
#include "r300_vs.h"
42
43
#include <stdio.h>
44
45
#include "tgsi/tgsi_transform.h"
46
#include "tgsi/tgsi_dump.h"
47
48
#include "draw/draw_context.h"
49
50
struct vs_transform_context {
51
struct tgsi_transform_context base;
52
53
boolean color_used[2];
54
boolean bcolor_used[2];
55
56
/* Index of the pos output, typically 0. */
57
unsigned pos_output;
58
/* Index of the pos temp where all writes of pos are redirected to. */
59
unsigned pos_temp;
60
/* The index of the last generic output, after which we insert a new
61
* output for WPOS. */
62
int last_generic;
63
64
unsigned num_outputs;
65
/* Used to shift output decl. indices when inserting new ones. */
66
unsigned decl_shift;
67
/* Used to remap writes to output decls if their indices changed. */
68
unsigned out_remap[32];
69
70
/* First instruction processed? */
71
boolean first_instruction;
72
/* End instruction processed? */
73
boolean end_instruction;
74
75
boolean temp_used[1024];
76
};
77
78
static void emit_temp(struct tgsi_transform_context *ctx, unsigned reg)
79
{
80
struct tgsi_full_declaration decl;
81
82
decl = tgsi_default_full_declaration();
83
decl.Declaration.File = TGSI_FILE_TEMPORARY;
84
decl.Range.First = decl.Range.Last = reg;
85
ctx->emit_declaration(ctx, &decl);
86
}
87
88
static void emit_output(struct tgsi_transform_context *ctx,
89
unsigned name, unsigned index, unsigned interp,
90
unsigned reg)
91
{
92
struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
93
struct tgsi_full_declaration decl;
94
95
decl = tgsi_default_full_declaration();
96
decl.Declaration.File = TGSI_FILE_OUTPUT;
97
decl.Declaration.Interpolate = 1;
98
decl.Declaration.Semantic = TRUE;
99
decl.Semantic.Name = name;
100
decl.Semantic.Index = index;
101
decl.Range.First = decl.Range.Last = reg;
102
decl.Interp.Interpolate = interp;
103
ctx->emit_declaration(ctx, &decl);
104
++vsctx->num_outputs;
105
}
106
107
static void insert_output_before(struct tgsi_transform_context *ctx,
108
struct tgsi_full_declaration *before,
109
unsigned name, unsigned index, unsigned interp)
110
{
111
struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
112
unsigned i;
113
114
/* Make a place for the new output. */
115
for (i = before->Range.First; i < ARRAY_SIZE(vsctx->out_remap); i++) {
116
++vsctx->out_remap[i];
117
}
118
119
/* Insert the new output. */
120
emit_output(ctx, name, index, interp,
121
before->Range.First + vsctx->decl_shift);
122
123
++vsctx->decl_shift;
124
}
125
126
static void insert_output_after(struct tgsi_transform_context *ctx,
127
struct tgsi_full_declaration *after,
128
unsigned name, unsigned index, unsigned interp)
129
{
130
struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
131
unsigned i;
132
133
/* Make a place for the new output. */
134
for (i = after->Range.First+1; i < ARRAY_SIZE(vsctx->out_remap); i++) {
135
++vsctx->out_remap[i];
136
}
137
138
/* Insert the new output. */
139
emit_output(ctx, name, index, interp,
140
after->Range.First + 1);
141
142
++vsctx->decl_shift;
143
}
144
145
static void transform_decl(struct tgsi_transform_context *ctx,
146
struct tgsi_full_declaration *decl)
147
{
148
struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
149
unsigned i;
150
151
if (decl->Declaration.File == TGSI_FILE_OUTPUT) {
152
switch (decl->Semantic.Name) {
153
case TGSI_SEMANTIC_POSITION:
154
vsctx->pos_output = decl->Range.First;
155
break;
156
157
case TGSI_SEMANTIC_COLOR:
158
assert(decl->Semantic.Index < 2);
159
160
/* We must rasterize the first color if the second one is
161
* used, otherwise the rasterizer doesn't do the color
162
* selection correctly. Declare it, but don't write to it. */
163
if (decl->Semantic.Index == 1 && !vsctx->color_used[0]) {
164
insert_output_before(ctx, decl, TGSI_SEMANTIC_COLOR, 0,
165
TGSI_INTERPOLATE_LINEAR);
166
vsctx->color_used[0] = TRUE;
167
}
168
break;
169
170
case TGSI_SEMANTIC_BCOLOR:
171
assert(decl->Semantic.Index < 2);
172
173
/* We must rasterize all 4 colors if back-face colors are
174
* used, otherwise the rasterizer doesn't do the color
175
* selection correctly. Declare it, but don't write to it. */
176
if (!vsctx->color_used[0]) {
177
insert_output_before(ctx, decl, TGSI_SEMANTIC_COLOR, 0,
178
TGSI_INTERPOLATE_LINEAR);
179
vsctx->color_used[0] = TRUE;
180
}
181
if (!vsctx->color_used[1]) {
182
insert_output_before(ctx, decl, TGSI_SEMANTIC_COLOR, 1,
183
TGSI_INTERPOLATE_LINEAR);
184
vsctx->color_used[1] = TRUE;
185
}
186
if (decl->Semantic.Index == 1 && !vsctx->bcolor_used[0]) {
187
insert_output_before(ctx, decl, TGSI_SEMANTIC_BCOLOR, 0,
188
TGSI_INTERPOLATE_LINEAR);
189
vsctx->bcolor_used[0] = TRUE;
190
}
191
break;
192
193
case TGSI_SEMANTIC_GENERIC:
194
vsctx->last_generic = MAX2(vsctx->last_generic, decl->Semantic.Index);
195
break;
196
}
197
198
/* Since we're inserting new outputs in between, the following outputs
199
* should be moved to the right so that they don't overlap with
200
* the newly added ones. */
201
decl->Range.First += vsctx->decl_shift;
202
decl->Range.Last += vsctx->decl_shift;
203
204
++vsctx->num_outputs;
205
} else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {
206
for (i = decl->Range.First; i <= decl->Range.Last; i++) {
207
vsctx->temp_used[i] = TRUE;
208
}
209
}
210
211
ctx->emit_declaration(ctx, decl);
212
213
/* Insert BCOLOR1 if needed. */
214
if (decl->Declaration.File == TGSI_FILE_OUTPUT &&
215
decl->Semantic.Name == TGSI_SEMANTIC_BCOLOR &&
216
!vsctx->bcolor_used[1]) {
217
insert_output_after(ctx, decl, TGSI_SEMANTIC_BCOLOR, 1,
218
TGSI_INTERPOLATE_LINEAR);
219
}
220
}
221
222
static void transform_inst(struct tgsi_transform_context *ctx,
223
struct tgsi_full_instruction *inst)
224
{
225
struct vs_transform_context *vsctx = (struct vs_transform_context *) ctx;
226
struct tgsi_full_instruction new_inst;
227
unsigned i;
228
229
if (!vsctx->first_instruction) {
230
vsctx->first_instruction = TRUE;
231
232
/* Insert the generic output for WPOS. */
233
emit_output(ctx, TGSI_SEMANTIC_GENERIC, vsctx->last_generic + 1,
234
TGSI_INTERPOLATE_PERSPECTIVE, vsctx->num_outputs);
235
236
/* Find a free temp for POSITION. */
237
for (i = 0; i < ARRAY_SIZE(vsctx->temp_used); i++) {
238
if (!vsctx->temp_used[i]) {
239
emit_temp(ctx, i);
240
vsctx->pos_temp = i;
241
break;
242
}
243
}
244
}
245
246
if (inst->Instruction.Opcode == TGSI_OPCODE_END) {
247
/* MOV OUT[pos_output], TEMP[pos_temp]; */
248
new_inst = tgsi_default_full_instruction();
249
new_inst.Instruction.Opcode = TGSI_OPCODE_MOV;
250
new_inst.Instruction.NumDstRegs = 1;
251
new_inst.Dst[0].Register.File = TGSI_FILE_OUTPUT;
252
new_inst.Dst[0].Register.Index = vsctx->pos_output;
253
new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW;
254
new_inst.Instruction.NumSrcRegs = 1;
255
new_inst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
256
new_inst.Src[0].Register.Index = vsctx->pos_temp;
257
ctx->emit_instruction(ctx, &new_inst);
258
259
/* MOV OUT[n-1], TEMP[pos_temp]; */
260
new_inst = tgsi_default_full_instruction();
261
new_inst.Instruction.Opcode = TGSI_OPCODE_MOV;
262
new_inst.Instruction.NumDstRegs = 1;
263
new_inst.Dst[0].Register.File = TGSI_FILE_OUTPUT;
264
new_inst.Dst[0].Register.Index = vsctx->num_outputs - 1;
265
new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW;
266
new_inst.Instruction.NumSrcRegs = 1;
267
new_inst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
268
new_inst.Src[0].Register.Index = vsctx->pos_temp;
269
ctx->emit_instruction(ctx, &new_inst);
270
271
vsctx->end_instruction = TRUE;
272
} else {
273
/* Not an END instruction. */
274
/* Fix writes to outputs. */
275
for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
276
struct tgsi_full_dst_register *dst = &inst->Dst[i];
277
if (dst->Register.File == TGSI_FILE_OUTPUT) {
278
if (dst->Register.Index == vsctx->pos_output) {
279
/* Replace writes to OUT[pos_output] with TEMP[pos_temp]. */
280
dst->Register.File = TGSI_FILE_TEMPORARY;
281
dst->Register.Index = vsctx->pos_temp;
282
} else {
283
/* Not a position, good...
284
* Since we were changing the indices of output decls,
285
* we must redirect writes into them too. */
286
dst->Register.Index = vsctx->out_remap[dst->Register.Index];
287
}
288
}
289
}
290
291
/* Inserting 2 instructions before the END opcode moves all following
292
* labels by 2. Subroutines are always after the END opcode so
293
* they're always moved. */
294
if (inst->Instruction.Opcode == TGSI_OPCODE_CAL) {
295
inst->Label.Label += 2;
296
}
297
/* The labels of the following opcodes are moved only after
298
* the END opcode. */
299
if (vsctx->end_instruction &&
300
(inst->Instruction.Opcode == TGSI_OPCODE_IF ||
301
inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
302
inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP ||
303
inst->Instruction.Opcode == TGSI_OPCODE_ENDLOOP)) {
304
inst->Label.Label += 2;
305
}
306
}
307
308
ctx->emit_instruction(ctx, inst);
309
}
310
311
void r300_draw_init_vertex_shader(struct r300_context *r300,
312
struct r300_vertex_shader *vs)
313
{
314
struct draw_context *draw = r300->draw;
315
struct pipe_shader_state new_vs;
316
struct tgsi_shader_info info;
317
struct vs_transform_context transform;
318
const uint newLen = tgsi_num_tokens(vs->state.tokens) + 100 /* XXX */;
319
unsigned i;
320
321
tgsi_scan_shader(vs->state.tokens, &info);
322
323
new_vs.tokens = tgsi_alloc_tokens(newLen);
324
if (new_vs.tokens == NULL)
325
return;
326
327
memset(&transform, 0, sizeof(transform));
328
for (i = 0; i < ARRAY_SIZE(transform.out_remap); i++) {
329
transform.out_remap[i] = i;
330
}
331
transform.last_generic = -1;
332
transform.base.transform_instruction = transform_inst;
333
transform.base.transform_declaration = transform_decl;
334
335
for (i = 0; i < info.num_outputs; i++) {
336
unsigned index = info.output_semantic_index[i];
337
338
switch (info.output_semantic_name[i]) {
339
case TGSI_SEMANTIC_COLOR:
340
assert(index < 2);
341
transform.color_used[index] = TRUE;
342
break;
343
344
case TGSI_SEMANTIC_BCOLOR:
345
assert(index < 2);
346
transform.bcolor_used[index] = TRUE;
347
break;
348
}
349
}
350
351
tgsi_transform_shader(vs->state.tokens,
352
(struct tgsi_token*)new_vs.tokens,
353
newLen, &transform.base);
354
355
#if 0
356
printf("----------------------------------------------\norig shader:\n");
357
tgsi_dump(vs->state.tokens, 0);
358
printf("----------------------------------------------\nnew shader:\n");
359
tgsi_dump(new_vs.tokens, 0);
360
printf("----------------------------------------------\n");
361
#endif
362
363
/* Free old tokens. */
364
FREE((void*)vs->state.tokens);
365
366
vs->draw_vs = draw_create_vertex_shader(draw, &new_vs);
367
368
/* Instead of duplicating and freeing the tokens, copy the pointer directly. */
369
vs->state.tokens = new_vs.tokens;
370
371
/* Init the VS output table for the rasterizer. */
372
r300_init_vs_outputs(r300, vs);
373
374
/* Make the last generic be WPOS. */
375
vs->outputs.wpos = vs->outputs.generic[transform.last_generic + 1];
376
vs->outputs.generic[transform.last_generic + 1] = ATTR_UNUSED;
377
}
378
379