Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/v3d/v3d_context.c
4570 views
1
/*
2
* Copyright © 2014-2017 Broadcom
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
20
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
* IN THE SOFTWARE.
22
*/
23
24
#include <xf86drm.h>
25
#include <err.h>
26
27
#include "pipe/p_defines.h"
28
#include "util/hash_table.h"
29
#include "util/ralloc.h"
30
#include "util/u_inlines.h"
31
#include "util/u_memory.h"
32
#include "util/u_blitter.h"
33
#include "util/u_upload_mgr.h"
34
#include "util/u_prim.h"
35
#include "indices/u_primconvert.h"
36
#include "pipe/p_screen.h"
37
38
#include "v3d_screen.h"
39
#include "v3d_context.h"
40
#include "v3d_resource.h"
41
#include "broadcom/compiler/v3d_compiler.h"
42
43
void
44
v3d_flush(struct pipe_context *pctx)
45
{
46
struct v3d_context *v3d = v3d_context(pctx);
47
48
hash_table_foreach(v3d->jobs, entry) {
49
struct v3d_job *job = entry->data;
50
v3d_job_submit(v3d, job);
51
}
52
}
53
54
static void
55
v3d_pipe_flush(struct pipe_context *pctx, struct pipe_fence_handle **fence,
56
unsigned flags)
57
{
58
struct v3d_context *v3d = v3d_context(pctx);
59
60
v3d_flush(pctx);
61
62
if (fence) {
63
struct pipe_screen *screen = pctx->screen;
64
struct v3d_fence *f = v3d_fence_create(v3d);
65
screen->fence_reference(screen, fence, NULL);
66
*fence = (struct pipe_fence_handle *)f;
67
}
68
}
69
70
static void
71
v3d_memory_barrier(struct pipe_context *pctx, unsigned int flags)
72
{
73
struct v3d_context *v3d = v3d_context(pctx);
74
75
/* We only need to flush for SSBOs and images, because for everything
76
* else we flush the job automatically when we needed.
77
*/
78
const unsigned int flush_flags = PIPE_BARRIER_SHADER_BUFFER |
79
PIPE_BARRIER_IMAGE;
80
81
if (!(flags & flush_flags))
82
return;
83
84
/* We only need to flush jobs writing to SSBOs/images. */
85
perf_debug("Flushing all jobs for glMemoryBarrier(), could do better");
86
v3d_flush(pctx);
87
}
88
89
static void
90
v3d_set_debug_callback(struct pipe_context *pctx,
91
const struct pipe_debug_callback *cb)
92
{
93
struct v3d_context *v3d = v3d_context(pctx);
94
95
if (cb)
96
v3d->debug = *cb;
97
else
98
memset(&v3d->debug, 0, sizeof(v3d->debug));
99
}
100
101
static void
102
v3d_invalidate_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
103
{
104
struct v3d_context *v3d = v3d_context(pctx);
105
struct v3d_resource *rsc = v3d_resource(prsc);
106
107
rsc->initialized_buffers = 0;
108
109
struct hash_entry *entry = _mesa_hash_table_search(v3d->write_jobs,
110
prsc);
111
if (!entry)
112
return;
113
114
struct v3d_job *job = entry->data;
115
if (job->key.zsbuf && job->key.zsbuf->texture == prsc)
116
job->store &= ~(PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL);
117
}
118
119
/**
120
* Flushes the current job to get up-to-date primitive counts written to the
121
* primitive counts BO, then accumulates the transform feedback primitive count
122
* in the context and the corresponding vertex counts in the bound stream
123
* output targets.
124
*/
125
void
126
v3d_update_primitive_counters(struct v3d_context *v3d)
127
{
128
struct v3d_job *job = v3d_get_job_for_fbo(v3d);
129
if (job->draw_calls_queued == 0)
130
return;
131
132
/* In order to get up-to-date primitive counts we need to submit
133
* the job for execution so we get the counts written to memory.
134
* Notice that this will require a sync wait for the buffer write.
135
*/
136
uint32_t prims_before = v3d->tf_prims_generated;
137
v3d_job_submit(v3d, job);
138
uint32_t prims_after = v3d->tf_prims_generated;
139
if (prims_before == prims_after)
140
return;
141
142
enum pipe_prim_type prim_type = u_base_prim_type(v3d->prim_mode);
143
uint32_t num_verts = u_vertices_for_prims(prim_type,
144
prims_after - prims_before);
145
for (int i = 0; i < v3d->streamout.num_targets; i++) {
146
struct v3d_stream_output_target *so =
147
v3d_stream_output_target(v3d->streamout.targets[i]);
148
so->recorded_vertex_count += num_verts;
149
}
150
}
151
152
bool
153
v3d_line_smoothing_enabled(struct v3d_context *v3d)
154
{
155
if (!v3d->rasterizer->base.line_smooth)
156
return false;
157
158
/* According to the OpenGL docs, line smoothing shouldn’t be applied
159
* when multisampling
160
*/
161
if (v3d->job->msaa || v3d->rasterizer->base.multisample)
162
return false;
163
164
if (v3d->framebuffer.nr_cbufs <= 0)
165
return false;
166
167
struct pipe_surface *cbuf = v3d->framebuffer.cbufs[0];
168
if (!cbuf)
169
return false;
170
171
/* Modifying the alpha for pure integer formats probably
172
* doesn’t make sense because we don’t know how the application
173
* uses the alpha value.
174
*/
175
if (util_format_is_pure_integer(cbuf->format))
176
return false;
177
178
return true;
179
}
180
181
float
182
v3d_get_real_line_width(struct v3d_context *v3d)
183
{
184
float width = v3d->rasterizer->base.line_width;
185
186
if (v3d_line_smoothing_enabled(v3d)) {
187
/* If line smoothing is enabled then we want to add some extra
188
* pixels to the width in order to have some semi-transparent
189
* edges.
190
*/
191
width = floorf(M_SQRT2 * width) + 3;
192
}
193
194
return width;
195
}
196
197
void
198
v3d_flag_dirty_sampler_state(struct v3d_context *v3d,
199
enum pipe_shader_type shader)
200
{
201
switch (shader) {
202
case PIPE_SHADER_VERTEX:
203
v3d->dirty |= V3D_DIRTY_VERTTEX;
204
break;
205
case PIPE_SHADER_GEOMETRY:
206
v3d->dirty |= V3D_DIRTY_GEOMTEX;
207
break;
208
case PIPE_SHADER_FRAGMENT:
209
v3d->dirty |= V3D_DIRTY_FRAGTEX;
210
break;
211
case PIPE_SHADER_COMPUTE:
212
v3d->dirty |= V3D_DIRTY_COMPTEX;
213
break;
214
default:
215
unreachable("Unsupported shader stage");
216
}
217
}
218
219
void
220
v3d_create_texture_shader_state_bo(struct v3d_context *v3d,
221
struct v3d_sampler_view *so)
222
{
223
if (v3d->screen->devinfo.ver >= 41)
224
v3d41_create_texture_shader_state_bo(v3d, so);
225
else
226
v3d33_create_texture_shader_state_bo(v3d, so);
227
}
228
229
void
230
v3d_get_tile_buffer_size(bool is_msaa,
231
uint32_t nr_cbufs,
232
struct pipe_surface **cbufs,
233
struct pipe_surface *bbuf,
234
uint32_t *tile_width,
235
uint32_t *tile_height,
236
uint32_t *max_bpp)
237
{
238
static const uint8_t tile_sizes[] = {
239
64, 64,
240
64, 32,
241
32, 32,
242
32, 16,
243
16, 16,
244
};
245
int tile_size_index = 0;
246
if (is_msaa)
247
tile_size_index += 2;
248
249
if (cbufs[3] || cbufs[2])
250
tile_size_index += 2;
251
else if (cbufs[1])
252
tile_size_index++;
253
254
*max_bpp = 0;
255
for (int i = 0; i < nr_cbufs; i++) {
256
if (cbufs[i]) {
257
struct v3d_surface *surf = v3d_surface(cbufs[i]);
258
*max_bpp = MAX2(*max_bpp, surf->internal_bpp);
259
}
260
}
261
262
if (bbuf) {
263
struct v3d_surface *bsurf = v3d_surface(bbuf);
264
assert(bbuf->texture->nr_samples <= 1 || is_msaa);
265
*max_bpp = MAX2(*max_bpp, bsurf->internal_bpp);
266
}
267
268
tile_size_index += *max_bpp;
269
270
assert(tile_size_index < ARRAY_SIZE(tile_sizes));
271
*tile_width = tile_sizes[tile_size_index * 2 + 0];
272
*tile_height = tile_sizes[tile_size_index * 2 + 1];
273
}
274
275
static void
276
v3d_context_destroy(struct pipe_context *pctx)
277
{
278
struct v3d_context *v3d = v3d_context(pctx);
279
280
v3d_flush(pctx);
281
282
if (v3d->blitter)
283
util_blitter_destroy(v3d->blitter);
284
285
if (v3d->primconvert)
286
util_primconvert_destroy(v3d->primconvert);
287
288
if (v3d->uploader)
289
u_upload_destroy(v3d->uploader);
290
if (v3d->state_uploader)
291
u_upload_destroy(v3d->state_uploader);
292
293
if (v3d->prim_counts)
294
pipe_resource_reference(&v3d->prim_counts, NULL);
295
296
slab_destroy_child(&v3d->transfer_pool);
297
298
pipe_surface_reference(&v3d->framebuffer.cbufs[0], NULL);
299
pipe_surface_reference(&v3d->framebuffer.zsbuf, NULL);
300
301
if (v3d->sand8_blit_vs)
302
pctx->delete_vs_state(pctx, v3d->sand8_blit_vs);
303
if (v3d->sand8_blit_fs_luma)
304
pctx->delete_fs_state(pctx, v3d->sand8_blit_fs_luma);
305
if (v3d->sand8_blit_fs_chroma)
306
pctx->delete_fs_state(pctx, v3d->sand8_blit_fs_chroma);
307
308
v3d_program_fini(pctx);
309
310
ralloc_free(v3d);
311
}
312
313
static void
314
v3d_get_sample_position(struct pipe_context *pctx,
315
unsigned sample_count, unsigned sample_index,
316
float *xy)
317
{
318
struct v3d_context *v3d = v3d_context(pctx);
319
320
if (sample_count <= 1) {
321
xy[0] = 0.5;
322
xy[1] = 0.5;
323
} else {
324
static const int xoffsets_v33[] = { 1, -3, 3, -1 };
325
static const int xoffsets_v42[] = { -1, 3, -3, 1 };
326
const int *xoffsets = (v3d->screen->devinfo.ver >= 42 ?
327
xoffsets_v42 : xoffsets_v33);
328
329
xy[0] = 0.5 + xoffsets[sample_index] * .125;
330
xy[1] = .125 + sample_index * .25;
331
}
332
}
333
334
struct pipe_context *
335
v3d_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
336
{
337
struct v3d_screen *screen = v3d_screen(pscreen);
338
struct v3d_context *v3d;
339
340
/* Prevent dumping of the shaders built during context setup. */
341
uint32_t saved_shaderdb_flag = V3D_DEBUG & V3D_DEBUG_SHADERDB;
342
V3D_DEBUG &= ~V3D_DEBUG_SHADERDB;
343
344
v3d = rzalloc(NULL, struct v3d_context);
345
if (!v3d)
346
return NULL;
347
struct pipe_context *pctx = &v3d->base;
348
349
v3d->screen = screen;
350
351
int ret = drmSyncobjCreate(screen->fd, DRM_SYNCOBJ_CREATE_SIGNALED,
352
&v3d->out_sync);
353
if (ret) {
354
ralloc_free(v3d);
355
return NULL;
356
}
357
358
pctx->screen = pscreen;
359
pctx->priv = priv;
360
pctx->destroy = v3d_context_destroy;
361
pctx->flush = v3d_pipe_flush;
362
pctx->memory_barrier = v3d_memory_barrier;
363
pctx->set_debug_callback = v3d_set_debug_callback;
364
pctx->invalidate_resource = v3d_invalidate_resource;
365
pctx->get_sample_position = v3d_get_sample_position;
366
367
if (screen->devinfo.ver >= 41) {
368
v3d41_draw_init(pctx);
369
v3d41_state_init(pctx);
370
} else {
371
v3d33_draw_init(pctx);
372
v3d33_state_init(pctx);
373
}
374
v3d_program_init(pctx);
375
v3d_query_init(pctx);
376
v3d_resource_context_init(pctx);
377
378
v3d_job_init(v3d);
379
380
v3d->fd = screen->fd;
381
382
slab_create_child(&v3d->transfer_pool, &screen->transfer_pool);
383
384
v3d->uploader = u_upload_create_default(&v3d->base);
385
v3d->base.stream_uploader = v3d->uploader;
386
v3d->base.const_uploader = v3d->uploader;
387
v3d->state_uploader = u_upload_create(&v3d->base,
388
4096,
389
PIPE_BIND_CONSTANT_BUFFER,
390
PIPE_USAGE_STREAM, 0);
391
392
v3d->blitter = util_blitter_create(pctx);
393
if (!v3d->blitter)
394
goto fail;
395
v3d->blitter->use_index_buffer = true;
396
397
v3d->primconvert = util_primconvert_create(pctx,
398
(1 << PIPE_PRIM_QUADS) - 1);
399
if (!v3d->primconvert)
400
goto fail;
401
402
V3D_DEBUG |= saved_shaderdb_flag;
403
404
v3d->sample_mask = (1 << V3D_MAX_SAMPLES) - 1;
405
v3d->active_queries = true;
406
407
return &v3d->base;
408
409
fail:
410
pctx->destroy(pctx);
411
return NULL;
412
}
413
414