Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/auxiliary/indices/u_primconvert.c
4565 views
1
/*
2
* Copyright (C) 2013 Rob Clark <[email protected]>
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
10
*
11
* The above copyright notice and this permission notice (including the next
12
* paragraph) shall be included in all copies or substantial portions of the
13
* Software.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
* SOFTWARE.
22
*
23
* Authors:
24
* Rob Clark <[email protected]>
25
*/
26
27
/**
28
* This module converts provides a more convenient front-end to u_indices,
29
* etc, utils to convert primitive types supported not supported by the
30
* hardware. It handles binding new index buffer state, and restoring
31
* previous state after. To use, put something like this at the front of
32
* drivers pipe->draw_vbo():
33
*
34
* // emulate unsupported primitives:
35
* if (info->mode needs emulating) {
36
* util_primconvert_save_rasterizer_state(ctx->primconvert, ctx->rasterizer);
37
* util_primconvert_draw_vbo(ctx->primconvert, info);
38
* return;
39
* }
40
*
41
*/
42
43
#include "pipe/p_state.h"
44
#include "util/u_draw.h"
45
#include "util/u_inlines.h"
46
#include "util/u_memory.h"
47
#include "util/u_prim.h"
48
#include "util/u_prim_restart.h"
49
#include "util/u_upload_mgr.h"
50
51
#include "indices/u_indices.h"
52
#include "indices/u_primconvert.h"
53
54
struct primconvert_context
55
{
56
struct pipe_context *pipe;
57
struct primconvert_config cfg;
58
unsigned api_pv;
59
};
60
61
62
struct primconvert_context *
63
util_primconvert_create_config(struct pipe_context *pipe,
64
struct primconvert_config *cfg)
65
{
66
struct primconvert_context *pc = CALLOC_STRUCT(primconvert_context);
67
if (!pc)
68
return NULL;
69
pc->pipe = pipe;
70
pc->cfg = *cfg;
71
return pc;
72
}
73
74
struct primconvert_context *
75
util_primconvert_create(struct pipe_context *pipe, uint32_t primtypes_mask)
76
{
77
struct primconvert_config cfg = { .primtypes_mask = primtypes_mask, .restart_primtypes_mask = primtypes_mask };
78
return util_primconvert_create_config(pipe, &cfg);
79
}
80
81
void
82
util_primconvert_destroy(struct primconvert_context *pc)
83
{
84
FREE(pc);
85
}
86
87
void
88
util_primconvert_save_rasterizer_state(struct primconvert_context *pc,
89
const struct pipe_rasterizer_state
90
*rast)
91
{
92
util_primconvert_save_flatshade_first(pc, rast->flatshade_first);
93
}
94
95
void
96
util_primconvert_save_flatshade_first(struct primconvert_context *pc, bool flatshade_first)
97
{
98
/* if we actually translated the provoking vertex for the buffer,
99
* we would actually need to save/restore rasterizer state. As
100
* it is, we just need to make note of the pv.
101
*/
102
pc->api_pv = flatshade_first ? PV_FIRST : PV_LAST;
103
}
104
105
void
106
util_primconvert_draw_vbo(struct primconvert_context *pc,
107
const struct pipe_draw_info *info,
108
unsigned drawid_offset,
109
const struct pipe_draw_indirect_info *indirect,
110
const struct pipe_draw_start_count_bias *draws,
111
unsigned num_draws)
112
{
113
struct pipe_draw_info new_info;
114
struct pipe_draw_start_count_bias new_draw;
115
struct pipe_draw_start_count_bias *direct_draws = NULL;
116
unsigned num_direct_draws = 0;
117
struct pipe_transfer *src_transfer = NULL;
118
u_translate_func trans_func, direct_draw_func;
119
u_generate_func gen_func;
120
const void *src = NULL;
121
void *dst;
122
unsigned ib_offset;
123
unsigned total_index_count = draws->count;
124
void *rewrite_buffer = NULL;
125
126
if (indirect && indirect->buffer) {
127
/* this is stupid, but we're already doing a readback,
128
* so this thing may as well get the rest of the job done
129
*/
130
unsigned draw_count = 0;
131
struct u_indirect_params *new_draws = util_draw_indirect_read(pc->pipe, info, indirect, &draw_count);
132
if (!new_draws)
133
return;
134
135
for (unsigned i = 0; i < draw_count; i++)
136
util_primconvert_draw_vbo(pc, &new_draws[i].info, drawid_offset + i, NULL, &new_draws[i].draw, 1);
137
free(new_draws);
138
return;
139
}
140
141
if (num_draws > 1) {
142
unsigned drawid = drawid_offset;
143
for (unsigned i = 0; i < num_draws; i++) {
144
if (draws[i].count && info->instance_count)
145
util_primconvert_draw_vbo(pc, info, drawid, NULL, &draws[i], 1);
146
if (info->increment_draw_id)
147
drawid++;
148
}
149
return;
150
}
151
152
const struct pipe_draw_start_count_bias *draw = &draws[0];
153
154
/* Filter out degenerate primitives, u_upload_alloc() will assert
155
* on size==0 so just bail:
156
*/
157
if (!info->primitive_restart &&
158
!u_trim_pipe_prim(info->mode, (unsigned*)&draw->count))
159
return;
160
161
util_draw_init_info(&new_info);
162
new_info.index_bounds_valid = info->index_bounds_valid;
163
new_info.min_index = info->min_index;
164
new_info.max_index = info->max_index;
165
new_info.start_instance = info->start_instance;
166
new_info.instance_count = info->instance_count;
167
new_info.primitive_restart = info->primitive_restart;
168
new_info.restart_index = info->restart_index;
169
if (info->index_size) {
170
enum pipe_prim_type mode = new_info.mode = u_index_prim_type_convert(pc->cfg.primtypes_mask, info->mode, true);
171
unsigned index_size = info->index_size;
172
new_info.index_size = u_index_size_convert(info->index_size);
173
174
src = info->has_user_indices ? info->index.user : NULL;
175
if (!src) {
176
src = pipe_buffer_map(pc->pipe, info->index.resource,
177
PIPE_MAP_READ, &src_transfer);
178
}
179
src = (const uint8_t *)src;
180
181
/* if the resulting primitive type is not supported by the driver for primitive restart,
182
* the draw needs to be rewritten to not use primitive restart
183
*/
184
if (info->primitive_restart &&
185
!(pc->cfg.restart_primtypes_mask & BITFIELD_BIT(mode))) {
186
/* step 1: rewrite draw to not use primitive primitive restart;
187
* this pre-filters degenerate primitives
188
*/
189
direct_draws = util_prim_restart_convert_to_direct(src, info, draw, &num_direct_draws,
190
&new_info.min_index, &new_info.max_index, &total_index_count);
191
new_info.primitive_restart = false;
192
/* step 2: get a translator function which does nothing but handle any index size conversions
193
* which may or may not occur (8bit -> 16bit)
194
*/
195
u_index_translator(0xffff,
196
info->mode, index_size, total_index_count,
197
pc->api_pv, pc->api_pv,
198
PR_DISABLE,
199
&mode, &index_size, &new_draw.count,
200
&direct_draw_func);
201
/* this should always be a direct translation */
202
assert(new_draw.count == total_index_count);
203
/* step 3: allocate a temp buffer for an intermediate rewrite step */
204
rewrite_buffer = malloc(index_size * total_index_count);
205
if (!rewrite_buffer) {
206
if (src_transfer)
207
pipe_buffer_unmap(pc->pipe, src_transfer);
208
return;
209
}
210
}
211
/* (step 4: get the actual primitive conversion translator function) */
212
u_index_translator(pc->cfg.primtypes_mask,
213
info->mode, index_size, total_index_count,
214
pc->api_pv, pc->api_pv,
215
new_info.primitive_restart ? PR_ENABLE : PR_DISABLE,
216
&mode, &index_size, &new_draw.count,
217
&trans_func);
218
assert(new_info.mode == mode);
219
assert(new_info.index_size == index_size);
220
}
221
else {
222
enum pipe_prim_type mode = 0;
223
unsigned index_size;
224
225
u_index_generator(pc->cfg.primtypes_mask,
226
info->mode, draw->start, draw->count,
227
pc->api_pv, pc->api_pv,
228
&mode, &index_size, &new_draw.count,
229
&gen_func);
230
new_info.mode = mode;
231
new_info.index_size = index_size;
232
}
233
234
/* (step 5: allocate gpu memory sized for the FINAL index count) */
235
u_upload_alloc(pc->pipe->stream_uploader, 0, new_info.index_size * new_draw.count, 4,
236
&ib_offset, &new_info.index.resource, &dst);
237
new_draw.start = ib_offset / new_info.index_size;
238
new_draw.index_bias = info->index_size ? draw->index_bias : 0;
239
240
if (info->index_size) {
241
if (num_direct_draws) {
242
uint8_t *ptr = rewrite_buffer;
243
uint8_t *dst_ptr = dst;
244
/* step 6: if rewriting a prim-restart draw to direct draws,
245
* loop over all the direct draws in order to rewrite them into a single index buffer
246
* and draw in order to match the original call
247
*/
248
for (unsigned i = 0; i < num_direct_draws; i++) {
249
/* step 6a: get the index count for this draw, once converted */
250
unsigned tmp_count = u_index_count_converted_indices(pc->cfg.primtypes_mask, true, info->mode, direct_draws[i].count);
251
/* step 6b: handle index size conversion using the temp buffer; no change in index count
252
* TODO: this step can be optimized out if the index size is known to not change
253
*/
254
direct_draw_func(src, direct_draws[i].start, direct_draws[i].count, direct_draws[i].count, info->restart_index, ptr);
255
/* step 6c: handle the primitive type conversion rewriting to the converted index count */
256
trans_func(ptr, 0, direct_draws[i].count, tmp_count, info->restart_index, dst_ptr);
257
/* step 6d: increment the temp buffer and mapped final index buffer pointers */
258
ptr += new_info.index_size * direct_draws[i].count;
259
dst_ptr += new_info.index_size * tmp_count;
260
}
261
/* step 7: set the final index count, which is the converted total index count from the original draw rewrite */
262
new_draw.count = u_index_count_converted_indices(pc->cfg.primtypes_mask, true, info->mode, total_index_count);
263
} else
264
trans_func(src, draw->start, draw->count, new_draw.count, info->restart_index, dst);
265
266
if (pc->cfg.fixed_prim_restart && new_info.primitive_restart) {
267
new_info.restart_index = (1ull << (new_info.index_size * 8)) - 1;
268
if (info->restart_index != new_info.restart_index)
269
util_translate_prim_restart_data(new_info.index_size, dst, dst,
270
new_draw.count,
271
info->restart_index);
272
}
273
}
274
else {
275
gen_func(draw->start, new_draw.count, dst);
276
}
277
278
if (src_transfer)
279
pipe_buffer_unmap(pc->pipe, src_transfer);
280
281
u_upload_unmap(pc->pipe->stream_uploader);
282
283
/* to the translated draw: */
284
pc->pipe->draw_vbo(pc->pipe, &new_info, drawid_offset, NULL, &new_draw, 1);
285
free(direct_draws);
286
free(rewrite_buffer);
287
288
pipe_resource_reference(&new_info.index.resource, NULL);
289
}
290
291