Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/crocus/crocus_blit.c
4570 views
1
/*
2
* Copyright © 2017 Intel Corporation
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 shall be included
12
* in all copies or substantial portions of the Software.
13
*
14
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20
* DEALINGS IN THE SOFTWARE.
21
*/
22
23
#include <stdio.h>
24
#include "pipe/p_defines.h"
25
#include "pipe/p_state.h"
26
#include "pipe/p_context.h"
27
#include "pipe/p_screen.h"
28
#include "util/format/u_format.h"
29
#include "util/u_inlines.h"
30
#include "util/u_surface.h"
31
#include "util/ralloc.h"
32
#include "intel/blorp/blorp.h"
33
#include "crocus_context.h"
34
#include "crocus_resource.h"
35
#include "crocus_screen.h"
36
37
void crocus_blitter_begin(struct crocus_context *ice, enum crocus_blitter_op op, bool render_cond)
38
{
39
util_blitter_save_vertex_shader(ice->blitter, ice->shaders.uncompiled[MESA_SHADER_VERTEX]);
40
util_blitter_save_tessctrl_shader(ice->blitter, ice->shaders.uncompiled[MESA_SHADER_TESS_CTRL]);
41
util_blitter_save_tesseval_shader(ice->blitter, ice->shaders.uncompiled[MESA_SHADER_TESS_EVAL]);
42
util_blitter_save_geometry_shader(ice->blitter, ice->shaders.uncompiled[MESA_SHADER_GEOMETRY]);
43
util_blitter_save_so_targets(ice->blitter, ice->state.so_targets,
44
(struct pipe_stream_output_target**)ice->state.so_target);
45
util_blitter_save_vertex_buffer_slot(ice->blitter, ice->state.vertex_buffers);
46
util_blitter_save_vertex_elements(ice->blitter, (void *)ice->state.cso_vertex_elements);
47
if (op & CROCUS_SAVE_FRAGMENT_STATE) {
48
util_blitter_save_blend(ice->blitter, ice->state.cso_blend);
49
util_blitter_save_depth_stencil_alpha(ice->blitter, ice->state.cso_zsa);
50
util_blitter_save_stencil_ref(ice->blitter, &ice->state.stencil_ref);
51
util_blitter_save_fragment_shader(ice->blitter, ice->shaders.uncompiled[MESA_SHADER_FRAGMENT]);
52
util_blitter_save_sample_mask(ice->blitter, ice->state.sample_mask);
53
util_blitter_save_rasterizer(ice->blitter, ice->state.cso_rast);
54
util_blitter_save_scissor(ice->blitter, &ice->state.scissors[0]);
55
util_blitter_save_viewport(ice->blitter, &ice->state.viewports[0]);
56
util_blitter_save_fragment_constant_buffer_slot(ice->blitter, &ice->state.shaders[MESA_SHADER_FRAGMENT].constbufs[0]);
57
}
58
59
if (!render_cond)
60
util_blitter_save_render_condition(ice->blitter,
61
(struct pipe_query *)ice->condition.query,
62
ice->condition.condition,
63
ice->condition.mode);
64
65
// util_blitter_save_scissor(ice->blitter, &ice->scissors[0]);
66
if (op & CROCUS_SAVE_FRAMEBUFFER)
67
util_blitter_save_framebuffer(ice->blitter, &ice->state.framebuffer);
68
69
if (op & CROCUS_SAVE_TEXTURES) {
70
util_blitter_save_fragment_sampler_states(ice->blitter, 1, (void **)ice->state.shaders[MESA_SHADER_FRAGMENT].samplers);
71
util_blitter_save_fragment_sampler_views(ice->blitter, 1, (struct pipe_sampler_view **)ice->state.shaders[MESA_SHADER_FRAGMENT].textures);
72
}
73
}
74
75
/**
76
* Helper function for handling mirror image blits.
77
*
78
* If coord0 > coord1, swap them and return "true" (mirrored).
79
*/
80
static bool
81
apply_mirror(float *coord0, float *coord1)
82
{
83
if (*coord0 > *coord1) {
84
float tmp = *coord0;
85
*coord0 = *coord1;
86
*coord1 = tmp;
87
return true;
88
}
89
return false;
90
}
91
92
/**
93
* Compute the number of pixels to clip for each side of a rect
94
*
95
* \param x0 The rect's left coordinate
96
* \param y0 The rect's bottom coordinate
97
* \param x1 The rect's right coordinate
98
* \param y1 The rect's top coordinate
99
* \param min_x The clipping region's left coordinate
100
* \param min_y The clipping region's bottom coordinate
101
* \param max_x The clipping region's right coordinate
102
* \param max_y The clipping region's top coordinate
103
* \param clipped_x0 The number of pixels to clip from the left side
104
* \param clipped_y0 The number of pixels to clip from the bottom side
105
* \param clipped_x1 The number of pixels to clip from the right side
106
* \param clipped_y1 The number of pixels to clip from the top side
107
*
108
* \return false if we clip everything away, true otherwise
109
*/
110
static inline bool
111
compute_pixels_clipped(float x0, float y0, float x1, float y1,
112
float min_x, float min_y, float max_x, float max_y,
113
float *clipped_x0, float *clipped_y0,
114
float *clipped_x1, float *clipped_y1)
115
{
116
/* If we are going to clip everything away, stop. */
117
if (!(min_x <= max_x &&
118
min_y <= max_y &&
119
x0 <= max_x &&
120
y0 <= max_y &&
121
min_x <= x1 &&
122
min_y <= y1 &&
123
x0 <= x1 &&
124
y0 <= y1)) {
125
return false;
126
}
127
128
if (x0 < min_x)
129
*clipped_x0 = min_x - x0;
130
else
131
*clipped_x0 = 0;
132
if (max_x < x1)
133
*clipped_x1 = x1 - max_x;
134
else
135
*clipped_x1 = 0;
136
137
if (y0 < min_y)
138
*clipped_y0 = min_y - y0;
139
else
140
*clipped_y0 = 0;
141
if (max_y < y1)
142
*clipped_y1 = y1 - max_y;
143
else
144
*clipped_y1 = 0;
145
146
return true;
147
}
148
149
/**
150
* Clips a coordinate (left, right, top or bottom) for the src or dst rect
151
* (whichever requires the largest clip) and adjusts the coordinate
152
* for the other rect accordingly.
153
*
154
* \param mirror true if mirroring is required
155
* \param src the source rect coordinate (for example src_x0)
156
* \param dst0 the dst rect coordinate (for example dst_x0)
157
* \param dst1 the opposite dst rect coordinate (for example dst_x1)
158
* \param clipped_dst0 number of pixels to clip from the dst coordinate
159
* \param clipped_dst1 number of pixels to clip from the opposite dst coordinate
160
* \param scale the src vs dst scale involved for that coordinate
161
* \param is_left_or_bottom true if we are clipping the left or bottom sides
162
* of the rect.
163
*/
164
static void
165
clip_coordinates(bool mirror,
166
float *src, float *dst0, float *dst1,
167
float clipped_dst0,
168
float clipped_dst1,
169
float scale,
170
bool is_left_or_bottom)
171
{
172
/* When clipping we need to add or subtract pixels from the original
173
* coordinates depending on whether we are acting on the left/bottom
174
* or right/top sides of the rect respectively. We assume we have to
175
* add them in the code below, and multiply by -1 when we should
176
* subtract.
177
*/
178
int mult = is_left_or_bottom ? 1 : -1;
179
180
if (!mirror) {
181
*dst0 += clipped_dst0 * mult;
182
*src += clipped_dst0 * scale * mult;
183
} else {
184
*dst1 -= clipped_dst1 * mult;
185
*src += clipped_dst1 * scale * mult;
186
}
187
}
188
189
/**
190
* Apply a scissor rectangle to blit coordinates.
191
*
192
* Returns true if the blit was entirely scissored away.
193
*/
194
static bool
195
apply_blit_scissor(const struct pipe_scissor_state *scissor,
196
float *src_x0, float *src_y0,
197
float *src_x1, float *src_y1,
198
float *dst_x0, float *dst_y0,
199
float *dst_x1, float *dst_y1,
200
bool mirror_x, bool mirror_y)
201
{
202
float clip_dst_x0, clip_dst_x1, clip_dst_y0, clip_dst_y1;
203
204
/* Compute number of pixels to scissor away. */
205
if (!compute_pixels_clipped(*dst_x0, *dst_y0, *dst_x1, *dst_y1,
206
scissor->minx, scissor->miny,
207
scissor->maxx, scissor->maxy,
208
&clip_dst_x0, &clip_dst_y0,
209
&clip_dst_x1, &clip_dst_y1))
210
return true;
211
212
// XXX: comments assume source clipping, which we don't do
213
214
/* When clipping any of the two rects we need to adjust the coordinates
215
* in the other rect considering the scaling factor involved. To obtain
216
* the best precision we want to make sure that we only clip once per
217
* side to avoid accumulating errors due to the scaling adjustment.
218
*
219
* For example, if src_x0 and dst_x0 need both to be clipped we want to
220
* avoid the situation where we clip src_x0 first, then adjust dst_x0
221
* accordingly but then we realize that the resulting dst_x0 still needs
222
* to be clipped, so we clip dst_x0 and adjust src_x0 again. Because we are
223
* applying scaling factors to adjust the coordinates in each clipping
224
* pass we lose some precision and that can affect the results of the
225
* blorp blit operation slightly. What we want to do here is detect the
226
* rect that we should clip first for each side so that when we adjust
227
* the other rect we ensure the resulting coordinate does not need to be
228
* clipped again.
229
*
230
* The code below implements this by comparing the number of pixels that
231
* we need to clip for each side of both rects considering the scales
232
* involved. For example, clip_src_x0 represents the number of pixels
233
* to be clipped for the src rect's left side, so if clip_src_x0 = 5,
234
* clip_dst_x0 = 4 and scale_x = 2 it means that we are clipping more
235
* from the dst rect so we should clip dst_x0 only and adjust src_x0.
236
* This is because clipping 4 pixels in the dst is equivalent to
237
* clipping 4 * 2 = 8 > 5 in the src.
238
*/
239
240
if (*src_x0 == *src_x1 || *src_y0 == *src_y1
241
|| *dst_x0 == *dst_x1 || *dst_y0 == *dst_y1)
242
return true;
243
244
float scale_x = (float) (*src_x1 - *src_x0) / (*dst_x1 - *dst_x0);
245
float scale_y = (float) (*src_y1 - *src_y0) / (*dst_y1 - *dst_y0);
246
247
/* Clip left side */
248
clip_coordinates(mirror_x, src_x0, dst_x0, dst_x1,
249
clip_dst_x0, clip_dst_x1, scale_x, true);
250
251
/* Clip right side */
252
clip_coordinates(mirror_x, src_x1, dst_x1, dst_x0,
253
clip_dst_x1, clip_dst_x0, scale_x, false);
254
255
/* Clip bottom side */
256
clip_coordinates(mirror_y, src_y0, dst_y0, dst_y1,
257
clip_dst_y0, clip_dst_y1, scale_y, true);
258
259
/* Clip top side */
260
clip_coordinates(mirror_y, src_y1, dst_y1, dst_y0,
261
clip_dst_y1, clip_dst_y0, scale_y, false);
262
263
/* Check for invalid bounds
264
* Can't blit for 0-dimensions
265
*/
266
return *src_x0 == *src_x1 || *src_y0 == *src_y1
267
|| *dst_x0 == *dst_x1 || *dst_y0 == *dst_y1;
268
}
269
270
void
271
crocus_blorp_surf_for_resource(struct crocus_vtable *vtbl,
272
struct isl_device *isl_dev,
273
struct blorp_surf *surf,
274
struct pipe_resource *p_res,
275
enum isl_aux_usage aux_usage,
276
unsigned level,
277
bool is_render_target)
278
{
279
struct crocus_resource *res = (void *) p_res;
280
281
assert(!crocus_resource_unfinished_aux_import(res));
282
283
if (isl_aux_usage_has_hiz(aux_usage) &&
284
!crocus_resource_level_has_hiz(res, level))
285
aux_usage = ISL_AUX_USAGE_NONE;
286
287
*surf = (struct blorp_surf) {
288
.surf = &res->surf,
289
.addr = (struct blorp_address) {
290
.buffer = res->bo,
291
.offset = res->offset,
292
.reloc_flags = is_render_target ? EXEC_OBJECT_WRITE : 0,
293
.mocs = crocus_mocs(res->bo, isl_dev),
294
},
295
.aux_usage = aux_usage,
296
};
297
298
if (aux_usage != ISL_AUX_USAGE_NONE) {
299
surf->aux_surf = &res->aux.surf;
300
surf->aux_addr = (struct blorp_address) {
301
.buffer = res->aux.bo,
302
.offset = res->aux.offset,
303
.reloc_flags = is_render_target ? EXEC_OBJECT_WRITE : 0,
304
.mocs = crocus_mocs(res->bo, isl_dev),
305
};
306
surf->clear_color =
307
crocus_resource_get_clear_color(res);
308
}
309
}
310
311
static void
312
tex_cache_flush_hack(struct crocus_batch *batch,
313
enum isl_format view_format,
314
enum isl_format surf_format)
315
{
316
/* The WaSamplerCacheFlushBetweenRedescribedSurfaceReads workaround says:
317
*
318
* "Currently Sampler assumes that a surface would not have two
319
* different format associate with it. It will not properly cache
320
* the different views in the MT cache, causing a data corruption."
321
*
322
* We may need to handle this for texture views in general someday, but
323
* for now we handle it here, as it hurts copies and blits particularly
324
* badly because they ofter reinterpret formats.
325
*
326
* If the BO hasn't been referenced yet this batch, we assume that the
327
* texture cache doesn't contain any relevant data nor need flushing.
328
*
329
* Icelake (Gen11+) claims to fix this issue, but seems to still have
330
* issues with ASTC formats.
331
*/
332
bool need_flush = view_format != surf_format;
333
if (!need_flush)
334
return;
335
336
const char *reason =
337
"workaround: WaSamplerCacheFlushBetweenRedescribedSurfaceReads";
338
339
crocus_emit_pipe_control_flush(batch, reason, PIPE_CONTROL_CS_STALL);
340
crocus_emit_pipe_control_flush(batch, reason,
341
PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE);
342
}
343
344
static struct crocus_resource *
345
crocus_resource_for_aspect(const struct intel_device_info *devinfo,
346
struct pipe_resource *p_res, unsigned pipe_mask)
347
{
348
if (pipe_mask == PIPE_MASK_S) {
349
struct crocus_resource *junk, *s_res;
350
crocus_get_depth_stencil_resources(devinfo, p_res, &junk, &s_res);
351
return s_res;
352
} else {
353
return (struct crocus_resource *)p_res;
354
}
355
}
356
357
static enum pipe_format
358
pipe_format_for_aspect(enum pipe_format format, unsigned pipe_mask)
359
{
360
if (pipe_mask == PIPE_MASK_S) {
361
return util_format_stencil_only(format);
362
} else if (pipe_mask == PIPE_MASK_Z) {
363
return util_format_get_depth_only(format);
364
} else {
365
return format;
366
}
367
}
368
369
static void
370
crocus_u_blitter(struct crocus_context *ice,
371
const struct pipe_blit_info *info)
372
{
373
struct pipe_blit_info dinfo = *info;
374
if (!util_format_has_alpha(dinfo.dst.resource->format))
375
dinfo.mask &= ~PIPE_MASK_A;
376
crocus_blitter_begin(ice, CROCUS_SAVE_FRAMEBUFFER | CROCUS_SAVE_TEXTURES | CROCUS_SAVE_FRAGMENT_STATE, info->render_condition_enable);
377
util_blitter_blit(ice->blitter, &dinfo);
378
}
379
380
/**
381
* The pipe->blit() driver hook.
382
*
383
* This performs a blit between two surfaces, which copies data but may
384
* also perform format conversion, scaling, flipping, and so on.
385
*/
386
static void
387
crocus_blit(struct pipe_context *ctx, const struct pipe_blit_info *info)
388
{
389
struct crocus_context *ice = (void *) ctx;
390
struct crocus_screen *screen = (struct crocus_screen *)ctx->screen;
391
const struct intel_device_info *devinfo = &screen->devinfo;
392
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
393
enum blorp_batch_flags blorp_flags = 0;
394
395
/* We don't support color masking. */
396
assert((info->mask & PIPE_MASK_RGBA) == PIPE_MASK_RGBA ||
397
(info->mask & PIPE_MASK_RGBA) == 0);
398
399
if (info->render_condition_enable)
400
if (!crocus_check_conditional_render(ice))
401
return;
402
403
if (devinfo->ver <= 5) {
404
if (!screen->vtbl.blit_blt(batch, info)) {
405
406
if (!util_format_is_depth_or_stencil(info->src.resource->format) &&
407
info->dst.resource->target != PIPE_TEXTURE_3D)
408
goto use_blorp;
409
410
if (!util_blitter_is_blit_supported(ice->blitter, info)) {
411
if (util_format_is_depth_or_stencil(info->src.resource->format)) {
412
413
struct pipe_blit_info depth_blit = *info;
414
depth_blit.mask = PIPE_MASK_Z;
415
crocus_blitter_begin(ice, CROCUS_SAVE_FRAMEBUFFER | CROCUS_SAVE_TEXTURES | CROCUS_SAVE_FRAGMENT_STATE, info->render_condition_enable);
416
util_blitter_blit(ice->blitter, &depth_blit);
417
418
struct pipe_surface *dst_view, dst_templ;
419
util_blitter_default_dst_texture(&dst_templ, info->dst.resource, info->dst.level, info->dst.box.z);
420
dst_view = ctx->create_surface(ctx, info->dst.resource, &dst_templ);
421
422
crocus_blitter_begin(ice, CROCUS_SAVE_FRAMEBUFFER | CROCUS_SAVE_TEXTURES | CROCUS_SAVE_FRAGMENT_STATE, info->render_condition_enable);
423
424
util_blitter_clear_depth_stencil(ice->blitter, dst_view, PIPE_CLEAR_STENCIL,
425
0, 0, info->dst.box.x, info->dst.box.y,
426
info->dst.box.width, info->dst.box.height);
427
crocus_blitter_begin(ice, CROCUS_SAVE_FRAMEBUFFER | CROCUS_SAVE_TEXTURES | CROCUS_SAVE_FRAGMENT_STATE, info->render_condition_enable);
428
util_blitter_stencil_fallback(ice->blitter,
429
info->dst.resource,
430
info->dst.level,
431
&info->dst.box,
432
info->src.resource,
433
info->src.level,
434
&info->src.box, NULL);
435
436
}
437
return;
438
}
439
440
crocus_u_blitter(ice, info);
441
}
442
return;
443
}
444
445
if (devinfo->ver == 6) {
446
if (info->src.resource->target == PIPE_TEXTURE_3D &&
447
info->dst.resource->target == PIPE_TEXTURE_3D) {
448
crocus_u_blitter(ice, info);
449
return;
450
}
451
}
452
453
use_blorp:
454
if (info->render_condition_enable) {
455
if (ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT)
456
blorp_flags |= BLORP_BATCH_PREDICATE_ENABLE;
457
}
458
459
float src_x0 = info->src.box.x;
460
float src_x1 = info->src.box.x + info->src.box.width;
461
float src_y0 = info->src.box.y;
462
float src_y1 = info->src.box.y + info->src.box.height;
463
float dst_x0 = info->dst.box.x;
464
float dst_x1 = info->dst.box.x + info->dst.box.width;
465
float dst_y0 = info->dst.box.y;
466
float dst_y1 = info->dst.box.y + info->dst.box.height;
467
bool mirror_x = apply_mirror(&src_x0, &src_x1);
468
bool mirror_y = apply_mirror(&src_y0, &src_y1);
469
enum blorp_filter filter;
470
471
if (info->scissor_enable) {
472
bool noop = apply_blit_scissor(&info->scissor,
473
&src_x0, &src_y0, &src_x1, &src_y1,
474
&dst_x0, &dst_y0, &dst_x1, &dst_y1,
475
mirror_x, mirror_y);
476
if (noop)
477
return;
478
}
479
480
if (abs(info->dst.box.width) == abs(info->src.box.width) &&
481
abs(info->dst.box.height) == abs(info->src.box.height)) {
482
if (info->src.resource->nr_samples > 1 &&
483
info->dst.resource->nr_samples <= 1) {
484
/* The OpenGL ES 3.2 specification, section 16.2.1, says:
485
*
486
* "If the read framebuffer is multisampled (its effective
487
* value of SAMPLE_BUFFERS is one) and the draw framebuffer
488
* is not (its value of SAMPLE_BUFFERS is zero), the samples
489
* corresponding to each pixel location in the source are
490
* converted to a single sample before being written to the
491
* destination. The filter parameter is ignored. If the
492
* source formats are integer types or stencil values, a
493
* single sample’s value is selected for each pixel. If the
494
* source formats are floating-point or normalized types,
495
* the sample values for each pixel are resolved in an
496
* implementation-dependent manner. If the source formats
497
* are depth values, sample values are resolved in an
498
* implementation-dependent manner where the result will be
499
* between the minimum and maximum depth values in the pixel."
500
*
501
* When selecting a single sample, we always choose sample 0.
502
*/
503
if (util_format_is_depth_or_stencil(info->src.format) ||
504
util_format_is_pure_integer(info->src.format)) {
505
filter = BLORP_FILTER_SAMPLE_0;
506
} else {
507
filter = BLORP_FILTER_AVERAGE;
508
}
509
} else {
510
/* The OpenGL 4.6 specification, section 18.3.1, says:
511
*
512
* "If the source and destination dimensions are identical,
513
* no filtering is applied."
514
*
515
* Using BLORP_FILTER_NONE will also handle the upsample case by
516
* replicating the one value in the source to all values in the
517
* destination.
518
*/
519
filter = BLORP_FILTER_NONE;
520
}
521
} else if (info->filter == PIPE_TEX_FILTER_LINEAR) {
522
filter = BLORP_FILTER_BILINEAR;
523
} else {
524
filter = BLORP_FILTER_NEAREST;
525
}
526
527
struct blorp_batch blorp_batch;
528
blorp_batch_init(&ice->blorp, &blorp_batch, batch, blorp_flags);
529
530
float src_z_step = (float)info->src.box.depth / (float)info->dst.box.depth;
531
532
/* There is no interpolation to the pixel center during rendering, so
533
* add the 0.5 offset ourselves here.
534
*/
535
float depth_center_offset = 0;
536
if (info->src.resource->target == PIPE_TEXTURE_3D)
537
depth_center_offset = 0.5 / info->dst.box.depth * info->src.box.depth;
538
539
/* Perform a blit for each aspect requested by the caller. PIPE_MASK_R is
540
* used to represent the color aspect. */
541
unsigned aspect_mask = info->mask & (PIPE_MASK_R | PIPE_MASK_ZS);
542
while (aspect_mask) {
543
unsigned aspect = 1 << u_bit_scan(&aspect_mask);
544
545
struct crocus_resource *src_res =
546
crocus_resource_for_aspect(devinfo, info->src.resource, aspect);
547
struct crocus_resource *dst_res =
548
crocus_resource_for_aspect(devinfo, info->dst.resource, aspect);
549
550
enum pipe_format src_pfmt =
551
pipe_format_for_aspect(info->src.format, aspect);
552
enum pipe_format dst_pfmt =
553
pipe_format_for_aspect(info->dst.format, aspect);
554
555
if (crocus_resource_unfinished_aux_import(src_res))
556
crocus_resource_finish_aux_import(ctx->screen, src_res);
557
if (crocus_resource_unfinished_aux_import(dst_res))
558
crocus_resource_finish_aux_import(ctx->screen, dst_res);
559
560
struct crocus_format_info src_fmt =
561
crocus_format_for_usage(devinfo, src_pfmt, ISL_SURF_USAGE_TEXTURE_BIT);
562
enum isl_aux_usage src_aux_usage =
563
crocus_resource_texture_aux_usage(src_res);
564
565
crocus_resource_prepare_texture(ice, src_res, src_fmt.fmt,
566
info->src.level, 1, info->src.box.z,
567
info->src.box.depth);
568
// crocus_emit_buffer_barrier_for(batch, src_res->bo,
569
// CROCUS_DOMAIN_OTHER_READ);
570
571
bool dst_aux_disable = false;
572
/* on SNB blorp will use render target instead of depth
573
* so disable HiZ.
574
*/
575
if (devinfo->ver <= 6 && util_format_is_depth_or_stencil(dst_pfmt))
576
dst_aux_disable = true;
577
struct crocus_format_info dst_fmt =
578
crocus_format_for_usage(devinfo, dst_pfmt,
579
ISL_SURF_USAGE_RENDER_TARGET_BIT);
580
enum isl_aux_usage dst_aux_usage =
581
crocus_resource_render_aux_usage(ice, dst_res, info->dst.level,
582
dst_fmt.fmt, dst_aux_disable);
583
584
struct blorp_surf src_surf, dst_surf;
585
crocus_blorp_surf_for_resource(&screen->vtbl, &screen->isl_dev, &src_surf,
586
&src_res->base.b, src_aux_usage,
587
info->src.level, false);
588
crocus_blorp_surf_for_resource(&screen->vtbl, &screen->isl_dev, &dst_surf,
589
&dst_res->base.b, dst_aux_usage,
590
info->dst.level, true);
591
592
crocus_resource_prepare_render(ice, dst_res, info->dst.level,
593
info->dst.box.z, info->dst.box.depth,
594
dst_aux_usage);
595
// crocus_emit_buffer_barrier_for(batch, dst_res->bo,
596
// CROCUS_DOMAIN_RENDER_WRITE);
597
598
if (crocus_batch_references(batch, src_res->bo))
599
tex_cache_flush_hack(batch, src_fmt.fmt, src_res->surf.format);
600
601
if (dst_res->base.b.target == PIPE_BUFFER) {
602
util_range_add(&dst_res->base.b, &dst_res->valid_buffer_range,
603
dst_x0, dst_x1);
604
}
605
606
struct isl_swizzle src_swiz = pipe_to_isl_swizzles(src_fmt.swizzles);
607
struct isl_swizzle dst_swiz = pipe_to_isl_swizzles(dst_fmt.swizzles);
608
609
for (int slice = 0; slice < info->dst.box.depth; slice++) {
610
unsigned dst_z = info->dst.box.z + slice;
611
float src_z = info->src.box.z + slice * src_z_step +
612
depth_center_offset;
613
614
crocus_batch_maybe_flush(batch, 1500);
615
616
blorp_blit(&blorp_batch,
617
&src_surf, info->src.level, src_z,
618
src_fmt.fmt, src_swiz,
619
&dst_surf, info->dst.level, dst_z,
620
dst_fmt.fmt, dst_swiz,
621
src_x0, src_y0, src_x1, src_y1,
622
dst_x0, dst_y0, dst_x1, dst_y1,
623
filter, mirror_x, mirror_y);
624
625
}
626
627
tex_cache_flush_hack(batch, src_fmt.fmt, src_res->surf.format);
628
629
crocus_resource_finish_render(ice, dst_res, info->dst.level,
630
info->dst.box.z, info->dst.box.depth,
631
dst_aux_usage);
632
}
633
634
blorp_batch_finish(&blorp_batch);
635
636
crocus_flush_and_dirty_for_history(ice, batch, (struct crocus_resource *)
637
info->dst.resource,
638
PIPE_CONTROL_RENDER_TARGET_FLUSH,
639
"cache history: post-blit");
640
}
641
642
static void
643
get_copy_region_aux_settings(struct crocus_resource *res,
644
enum isl_aux_usage *out_aux_usage,
645
bool is_render_target)
646
{
647
switch (res->aux.usage) {
648
case ISL_AUX_USAGE_MCS:
649
/* A stencil resolve operation must be performed prior to doing resource
650
* copies or used by CPU.
651
* (see HSD 1209978162)
652
*/
653
if (is_render_target && isl_surf_usage_is_stencil(res->surf.usage)) {
654
*out_aux_usage = ISL_AUX_USAGE_NONE;
655
} else {
656
*out_aux_usage = res->aux.usage;
657
}
658
break;
659
default:
660
*out_aux_usage = ISL_AUX_USAGE_NONE;
661
break;
662
}
663
}
664
665
/**
666
* Perform a GPU-based raw memory copy between compatible view classes.
667
*
668
* Does not perform any flushing - the new data may still be left in the
669
* render cache, and old data may remain in other caches.
670
*
671
* Wraps blorp_copy() and blorp_buffer_copy().
672
*/
673
void
674
crocus_copy_region(struct blorp_context *blorp,
675
struct crocus_batch *batch,
676
struct pipe_resource *dst,
677
unsigned dst_level,
678
unsigned dstx, unsigned dsty, unsigned dstz,
679
struct pipe_resource *src,
680
unsigned src_level,
681
const struct pipe_box *src_box)
682
{
683
struct blorp_batch blorp_batch;
684
struct crocus_context *ice = blorp->driver_ctx;
685
struct crocus_screen *screen = (void *) ice->ctx.screen;
686
const struct intel_device_info *devinfo = &screen->devinfo;
687
struct crocus_resource *src_res = (void *) src;
688
struct crocus_resource *dst_res = (void *) dst;
689
690
if (devinfo->ver <= 5) {
691
if (screen->vtbl.copy_region_blt(batch, dst_res,
692
dst_level, dstx, dsty, dstz,
693
src_res, src_level, src_box))
694
return;
695
}
696
enum isl_aux_usage src_aux_usage, dst_aux_usage;
697
get_copy_region_aux_settings(src_res, &src_aux_usage,
698
false);
699
get_copy_region_aux_settings(dst_res, &dst_aux_usage,
700
true);
701
702
if (crocus_batch_references(batch, src_res->bo))
703
tex_cache_flush_hack(batch, ISL_FORMAT_UNSUPPORTED, src_res->surf.format);
704
705
if (dst->target == PIPE_BUFFER)
706
util_range_add(&dst_res->base.b, &dst_res->valid_buffer_range, dstx, dstx + src_box->width);
707
708
if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
709
struct blorp_address src_addr = {
710
.buffer = crocus_resource_bo(src), .offset = src_box->x,
711
};
712
struct blorp_address dst_addr = {
713
.buffer = crocus_resource_bo(dst), .offset = dstx,
714
.reloc_flags = EXEC_OBJECT_WRITE,
715
};
716
717
crocus_batch_maybe_flush(batch, 1500);
718
719
blorp_batch_init(&ice->blorp, &blorp_batch, batch, 0);
720
blorp_buffer_copy(&blorp_batch, src_addr, dst_addr, src_box->width);
721
blorp_batch_finish(&blorp_batch);
722
} else {
723
// XXX: what about one surface being a buffer and not the other?
724
725
struct blorp_surf src_surf, dst_surf;
726
crocus_blorp_surf_for_resource(&screen->vtbl, &screen->isl_dev, &src_surf,
727
src, src_aux_usage, src_level, false);
728
crocus_blorp_surf_for_resource(&screen->vtbl, &screen->isl_dev, &dst_surf,
729
dst, dst_aux_usage, dst_level, true);
730
731
crocus_resource_prepare_access(ice, src_res, src_level, 1,
732
src_box->z, src_box->depth,
733
src_aux_usage, false);
734
crocus_resource_prepare_access(ice, dst_res, dst_level, 1,
735
dstz, src_box->depth,
736
dst_aux_usage, false);
737
738
blorp_batch_init(&ice->blorp, &blorp_batch, batch, 0);
739
740
for (int slice = 0; slice < src_box->depth; slice++) {
741
crocus_batch_maybe_flush(batch, 1500);
742
743
blorp_copy(&blorp_batch, &src_surf, src_level, src_box->z + slice,
744
&dst_surf, dst_level, dstz + slice,
745
src_box->x, src_box->y, dstx, dsty,
746
src_box->width, src_box->height);
747
}
748
blorp_batch_finish(&blorp_batch);
749
750
crocus_resource_finish_write(ice, dst_res, dst_level, dstz,
751
src_box->depth, dst_aux_usage);
752
}
753
754
tex_cache_flush_hack(batch, ISL_FORMAT_UNSUPPORTED, src_res->surf.format);
755
}
756
757
static struct crocus_batch *
758
get_preferred_batch(struct crocus_context *ice, struct crocus_bo *bo)
759
{
760
/* If the compute batch is already using this buffer, we'd prefer to
761
* continue queueing in the compute batch.
762
*/
763
if (crocus_batch_references(&ice->batches[CROCUS_BATCH_COMPUTE], bo))
764
return &ice->batches[CROCUS_BATCH_COMPUTE];
765
766
/* Otherwise default to the render batch. */
767
return &ice->batches[CROCUS_BATCH_RENDER];
768
}
769
770
771
/**
772
* The pipe->resource_copy_region() driver hook.
773
*
774
* This implements ARB_copy_image semantics - a raw memory copy between
775
* compatible view classes.
776
*/
777
static void
778
crocus_resource_copy_region(struct pipe_context *ctx,
779
struct pipe_resource *p_dst,
780
unsigned dst_level,
781
unsigned dstx, unsigned dsty, unsigned dstz,
782
struct pipe_resource *p_src,
783
unsigned src_level,
784
const struct pipe_box *src_box)
785
{
786
struct crocus_context *ice = (void *) ctx;
787
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
788
struct crocus_screen *screen = (struct crocus_screen *)ctx->screen;
789
const struct intel_device_info *devinfo = &screen->devinfo;
790
struct crocus_resource *src = (void *) p_src;
791
struct crocus_resource *dst = (void *) p_dst;
792
793
if (crocus_resource_unfinished_aux_import(src))
794
crocus_resource_finish_aux_import(ctx->screen, src);
795
if (crocus_resource_unfinished_aux_import(dst))
796
crocus_resource_finish_aux_import(ctx->screen, dst);
797
798
/* Use MI_COPY_MEM_MEM for tiny (<= 16 byte, % 4) buffer copies. */
799
if (p_src->target == PIPE_BUFFER && p_dst->target == PIPE_BUFFER &&
800
(src_box->width % 4 == 0) && src_box->width <= 16 &&
801
screen->vtbl.copy_mem_mem) {
802
struct crocus_bo *dst_bo = crocus_resource_bo(p_dst);
803
batch = get_preferred_batch(ice, dst_bo);
804
crocus_batch_maybe_flush(batch, 24 + 5 * (src_box->width / 4));
805
crocus_emit_pipe_control_flush(batch,
806
"stall for MI_COPY_MEM_MEM copy_region",
807
PIPE_CONTROL_CS_STALL);
808
screen->vtbl.copy_mem_mem(batch, dst_bo, dstx, crocus_resource_bo(p_src),
809
src_box->x, src_box->width);
810
return;
811
}
812
813
if (devinfo->ver < 6 && util_format_is_depth_or_stencil(p_dst->format)) {
814
util_resource_copy_region(ctx, p_dst, dst_level, dstx, dsty, dstz,
815
p_src, src_level, src_box);
816
return;
817
}
818
crocus_copy_region(&ice->blorp, batch, p_dst, dst_level, dstx, dsty, dstz,
819
p_src, src_level, src_box);
820
821
if (util_format_is_depth_and_stencil(p_dst->format) &&
822
util_format_has_stencil(util_format_description(p_src->format)) &&
823
devinfo->ver >= 6) {
824
struct crocus_resource *junk, *s_src_res, *s_dst_res;
825
crocus_get_depth_stencil_resources(devinfo, p_src, &junk, &s_src_res);
826
crocus_get_depth_stencil_resources(devinfo, p_dst, &junk, &s_dst_res);
827
828
crocus_copy_region(&ice->blorp, batch, &s_dst_res->base.b, dst_level, dstx,
829
dsty, dstz, &s_src_res->base.b, src_level, src_box);
830
}
831
832
crocus_flush_and_dirty_for_history(ice, batch, dst,
833
PIPE_CONTROL_RENDER_TARGET_FLUSH,
834
"cache history: post copy_region");
835
}
836
837
void
838
crocus_init_blit_functions(struct pipe_context *ctx)
839
{
840
ctx->blit = crocus_blit;
841
ctx->resource_copy_region = crocus_resource_copy_region;
842
}
843
844