#include "util/u_surface.h"
#include "util/u_blitter.h"
#include "v3d_context.h"
+#include "v3d_tiling.h"
#if 0
static struct pipe_surface *
-vc5_get_blit_surface(struct pipe_context *pctx,
+v3d_get_blit_surface(struct pipe_context *pctx,
struct pipe_resource *prsc, unsigned level)
{
struct pipe_surface tmpl;
}
static bool
-vc5_tile_blit(struct pipe_context *pctx, const struct pipe_blit_info *info)
+v3d_tile_blit(struct pipe_context *pctx, const struct pipe_blit_info *info)
{
- struct vc5_context *vc5 = vc5_context(pctx);
+ struct v3d_context *v3d = v3d_context(pctx);
bool msaa = (info->src.resource->nr_samples > 1 ||
info->dst.resource->nr_samples > 1);
int tile_width = msaa ? 32 : 64;
* determine the stride (which could be fixed by explicitly supplying
* it in the ABI).
*/
- struct vc5_resource *rsc = vc5_resource(info->src.resource);
+ struct v3d_resource *rsc = v3d_resource(info->src.resource);
uint32_t stride;
}
struct pipe_surface *dst_surf =
- vc5_get_blit_surface(pctx, info->dst.resource, info->dst.level);
+ v3d_get_blit_surface(pctx, info->dst.resource, info->dst.level);
struct pipe_surface *src_surf =
- vc5_get_blit_surface(pctx, info->src.resource, info->src.level);
+ v3d_get_blit_surface(pctx, info->src.resource, info->src.level);
- vc5_flush_jobs_reading_resource(vc5, info->src.resource);
+ v3d_flush_jobs_reading_resource(v3d, info->src.resource);
- struct vc5_job *job = vc5_get_job(vc5, dst_surf, NULL);
+ struct v3d_job *job = v3d_get_job(v3d, dst_surf, NULL);
pipe_surface_reference(&job->color_read, src_surf);
/* If we're resolving from MSAA to single sample, we still need to run
job->needs_flush = true;
job->resolve |= PIPE_CLEAR_COLOR;
- vc5_job_submit(vc5, job);
+ v3d_job_submit(v3d, job);
pipe_surface_reference(&dst_surf, NULL);
pipe_surface_reference(&src_surf, NULL);
#endif
void
-vc5_blitter_save(struct vc5_context *vc5)
+v3d_blitter_save(struct v3d_context *v3d)
{
- util_blitter_save_fragment_constant_buffer_slot(vc5->blitter,
- vc5->constbuf[PIPE_SHADER_FRAGMENT].cb);
- util_blitter_save_vertex_buffer_slot(vc5->blitter, vc5->vertexbuf.vb);
- util_blitter_save_vertex_elements(vc5->blitter, vc5->vtx);
- util_blitter_save_vertex_shader(vc5->blitter, vc5->prog.bind_vs);
- util_blitter_save_so_targets(vc5->blitter, vc5->streamout.num_targets,
- vc5->streamout.targets);
- util_blitter_save_rasterizer(vc5->blitter, vc5->rasterizer);
- util_blitter_save_viewport(vc5->blitter, &vc5->viewport);
- util_blitter_save_scissor(vc5->blitter, &vc5->scissor);
- util_blitter_save_fragment_shader(vc5->blitter, vc5->prog.bind_fs);
- util_blitter_save_blend(vc5->blitter, vc5->blend);
- util_blitter_save_depth_stencil_alpha(vc5->blitter, vc5->zsa);
- util_blitter_save_stencil_ref(vc5->blitter, &vc5->stencil_ref);
- util_blitter_save_sample_mask(vc5->blitter, vc5->sample_mask);
- util_blitter_save_framebuffer(vc5->blitter, &vc5->framebuffer);
- util_blitter_save_fragment_sampler_states(vc5->blitter,
- vc5->fragtex.num_samplers,
- (void **)vc5->fragtex.samplers);
- util_blitter_save_fragment_sampler_views(vc5->blitter,
- vc5->fragtex.num_textures, vc5->fragtex.textures);
- util_blitter_save_so_targets(vc5->blitter, vc5->streamout.num_targets,
- vc5->streamout.targets);
+ util_blitter_save_fragment_constant_buffer_slot(v3d->blitter,
+ v3d->constbuf[PIPE_SHADER_FRAGMENT].cb);
+ util_blitter_save_vertex_buffer_slot(v3d->blitter, v3d->vertexbuf.vb);
+ util_blitter_save_vertex_elements(v3d->blitter, v3d->vtx);
+ util_blitter_save_vertex_shader(v3d->blitter, v3d->prog.bind_vs);
+ util_blitter_save_so_targets(v3d->blitter, v3d->streamout.num_targets,
+ v3d->streamout.targets);
+ util_blitter_save_rasterizer(v3d->blitter, v3d->rasterizer);
+ util_blitter_save_viewport(v3d->blitter, &v3d->viewport);
+ util_blitter_save_scissor(v3d->blitter, &v3d->scissor);
+ util_blitter_save_fragment_shader(v3d->blitter, v3d->prog.bind_fs);
+ util_blitter_save_blend(v3d->blitter, v3d->blend);
+ util_blitter_save_depth_stencil_alpha(v3d->blitter, v3d->zsa);
+ util_blitter_save_stencil_ref(v3d->blitter, &v3d->stencil_ref);
+ util_blitter_save_sample_mask(v3d->blitter, v3d->sample_mask);
+ util_blitter_save_framebuffer(v3d->blitter, &v3d->framebuffer);
+ util_blitter_save_fragment_sampler_states(v3d->blitter,
+ v3d->tex[PIPE_SHADER_FRAGMENT].num_samplers,
+ (void **)v3d->tex[PIPE_SHADER_FRAGMENT].samplers);
+ util_blitter_save_fragment_sampler_views(v3d->blitter,
+ v3d->tex[PIPE_SHADER_FRAGMENT].num_textures,
+ v3d->tex[PIPE_SHADER_FRAGMENT].textures);
+ util_blitter_save_so_targets(v3d->blitter, v3d->streamout.num_targets,
+ v3d->streamout.targets);
}
static bool
-vc5_render_blit(struct pipe_context *ctx, struct pipe_blit_info *info)
+v3d_render_blit(struct pipe_context *ctx, struct pipe_blit_info *info)
{
- struct vc5_context *vc5 = vc5_context(ctx);
+ struct v3d_context *v3d = v3d_context(ctx);
+ struct v3d_resource *src = v3d_resource(info->src.resource);
+ struct pipe_resource *tiled = NULL;
+
+ if (!src->tiled) {
+ struct pipe_box box = {
+ .x = 0,
+ .y = 0,
+ .width = u_minify(info->src.resource->width0,
+ info->src.level),
+ .height = u_minify(info->src.resource->height0,
+ info->src.level),
+ .depth = 1,
+ };
+ struct pipe_resource tmpl = {
+ .target = info->src.resource->target,
+ .format = info->src.resource->format,
+ .width0 = box.width,
+ .height0 = box.height,
+ .depth0 = 1,
+ .array_size = 1,
+ };
+ tiled = ctx->screen->resource_create(ctx->screen, &tmpl);
+ if (!tiled) {
+ fprintf(stderr, "Failed to create tiled blit temp\n");
+ return false;
+ }
+ ctx->resource_copy_region(ctx,
+ tiled, 0,
+ 0, 0, 0,
+ info->src.resource, info->src.level,
+ &box);
+ info->src.level = 0;
+ info->src.resource = tiled;
+ }
- if (!util_blitter_is_blit_supported(vc5->blitter, info)) {
+ if (!util_blitter_is_blit_supported(v3d->blitter, info)) {
fprintf(stderr, "blit unsupported %s -> %s\n",
util_format_short_name(info->src.resource->format),
util_format_short_name(info->dst.resource->format));
return false;
}
- vc5_blitter_save(vc5);
- util_blitter_blit(vc5->blitter, info);
+ v3d_blitter_save(v3d);
+ util_blitter_blit(v3d->blitter, info);
+
+ pipe_resource_reference(&tiled, NULL);
return true;
}
* or R8 texture.
*/
static void
-vc5_stencil_blit(struct pipe_context *ctx, const struct pipe_blit_info *info)
+v3d_stencil_blit(struct pipe_context *ctx, const struct pipe_blit_info *info)
{
- struct vc5_context *vc5 = vc5_context(ctx);
- struct vc5_resource *src = vc5_resource(info->src.resource);
- struct vc5_resource *dst = vc5_resource(info->dst.resource);
+ struct v3d_context *v3d = v3d_context(ctx);
+ struct v3d_resource *src = v3d_resource(info->src.resource);
+ struct v3d_resource *dst = v3d_resource(info->dst.resource);
enum pipe_format src_format, dst_format;
if (src->separate_stencil) {
struct pipe_sampler_view *src_view =
ctx->create_sampler_view(ctx, &src->base, &src_tmpl);
- vc5_blitter_save(vc5);
- util_blitter_blit_generic(vc5->blitter, dst_surf, &info->dst.box,
+ v3d_blitter_save(v3d);
+ util_blitter_blit_generic(v3d->blitter, dst_surf, &info->dst.box,
src_view, &info->src.box,
src->base.width0, src->base.height0,
PIPE_MASK_R,
pipe_sampler_view_reference(&src_view, NULL);
}
+/* Disable level 0 write, just write following mipmaps */
+#define V3D_TFU_IOA_DIMTW (1 << 0)
+#define V3D_TFU_IOA_FORMAT_SHIFT 3
+#define V3D_TFU_IOA_FORMAT_LINEARTILE 3
+#define V3D_TFU_IOA_FORMAT_UBLINEAR_1_COLUMN 4
+#define V3D_TFU_IOA_FORMAT_UBLINEAR_2_COLUMN 5
+#define V3D_TFU_IOA_FORMAT_UIF_NO_XOR 6
+#define V3D_TFU_IOA_FORMAT_UIF_XOR 7
+
+#define V3D_TFU_ICFG_NUMMM_SHIFT 5
+#define V3D_TFU_ICFG_TTYPE_SHIFT 9
+
+#define V3D_TFU_ICFG_OPAD_SHIFT 22
+
+#define V3D_TFU_ICFG_FORMAT_SHIFT 18
+#define V3D_TFU_ICFG_FORMAT_RASTER 0
+#define V3D_TFU_ICFG_FORMAT_SAND_128 1
+#define V3D_TFU_ICFG_FORMAT_SAND_256 2
+#define V3D_TFU_ICFG_FORMAT_LINEARTILE 11
+#define V3D_TFU_ICFG_FORMAT_UBLINEAR_1_COLUMN 12
+#define V3D_TFU_ICFG_FORMAT_UBLINEAR_2_COLUMN 13
+#define V3D_TFU_ICFG_FORMAT_UIF_NO_XOR 14
+#define V3D_TFU_ICFG_FORMAT_UIF_XOR 15
+
+static bool
+v3d_tfu(struct pipe_context *pctx,
+ struct pipe_resource *pdst,
+ struct pipe_resource *psrc,
+ unsigned int src_level,
+ unsigned int base_level,
+ unsigned int last_level,
+ unsigned int src_layer,
+ unsigned int dst_layer)
+{
+ struct v3d_context *v3d = v3d_context(pctx);
+ struct v3d_screen *screen = v3d->screen;
+ struct v3d_resource *src = v3d_resource(psrc);
+ struct v3d_resource *dst = v3d_resource(pdst);
+ struct v3d_resource_slice *src_base_slice = &src->slices[src_level];
+ struct v3d_resource_slice *dst_base_slice = &dst->slices[base_level];
+ int msaa_scale = pdst->nr_samples > 1 ? 2 : 1;
+ int width = u_minify(pdst->width0, base_level) * msaa_scale;
+ int height = u_minify(pdst->height0, base_level) * msaa_scale;
+
+ if (psrc->format != pdst->format)
+ return false;
+ if (psrc->nr_samples != pdst->nr_samples)
+ return false;
+
+ uint32_t tex_format = v3d_get_tex_format(&screen->devinfo,
+ pdst->format);
+
+ if (!v3d_tfu_supports_tex_format(&screen->devinfo, tex_format))
+ return false;
+
+ if (pdst->target != PIPE_TEXTURE_2D || psrc->target != PIPE_TEXTURE_2D)
+ return false;
+
+ /* Can't write to raster. */
+ if (dst_base_slice->tiling == VC5_TILING_RASTER)
+ return false;
+
+ v3d_flush_jobs_writing_resource(v3d, psrc);
+ v3d_flush_jobs_reading_resource(v3d, pdst);
+
+ struct drm_v3d_submit_tfu tfu = {
+ .ios = (height << 16) | width,
+ .bo_handles = {
+ dst->bo->handle,
+ src != dst ? src->bo->handle : 0
+ },
+ .in_sync = v3d->out_sync,
+ .out_sync = v3d->out_sync,
+ };
+ uint32_t src_offset = (src->bo->offset +
+ v3d_layer_offset(psrc, src_level, src_layer));
+ tfu.iia |= src_offset;
+ if (src_base_slice->tiling == VC5_TILING_RASTER) {
+ tfu.icfg |= (V3D_TFU_ICFG_FORMAT_RASTER <<
+ V3D_TFU_ICFG_FORMAT_SHIFT);
+ } else {
+ tfu.icfg |= ((V3D_TFU_ICFG_FORMAT_LINEARTILE +
+ (src_base_slice->tiling - VC5_TILING_LINEARTILE)) <<
+ V3D_TFU_ICFG_FORMAT_SHIFT);
+ }
+
+ uint32_t dst_offset = (dst->bo->offset +
+ v3d_layer_offset(pdst, src_level, dst_layer));
+ tfu.ioa |= dst_offset;
+ if (last_level != base_level)
+ tfu.ioa |= V3D_TFU_IOA_DIMTW;
+ tfu.ioa |= ((V3D_TFU_IOA_FORMAT_LINEARTILE +
+ (dst_base_slice->tiling - VC5_TILING_LINEARTILE)) <<
+ V3D_TFU_IOA_FORMAT_SHIFT);
+
+ tfu.icfg |= tex_format << V3D_TFU_ICFG_TTYPE_SHIFT;
+ tfu.icfg |= (last_level - base_level) << V3D_TFU_ICFG_NUMMM_SHIFT;
+
+ switch (src_base_slice->tiling) {
+ case VC5_TILING_UIF_NO_XOR:
+ case VC5_TILING_UIF_XOR:
+ tfu.iis |= (src_base_slice->padded_height /
+ (2 * v3d_utile_height(src->cpp)));
+ break;
+ case VC5_TILING_RASTER:
+ tfu.iis |= src_base_slice->stride / src->cpp;
+ break;
+ case VC5_TILING_LINEARTILE:
+ case VC5_TILING_UBLINEAR_1_COLUMN:
+ case VC5_TILING_UBLINEAR_2_COLUMN:
+ break;
+ }
+
+ /* If we're writing level 0 (!IOA_DIMTW), then we need to supply the
+ * OPAD field for the destination (how many extra UIF blocks beyond
+ * those necessary to cover the height). When filling mipmaps, the
+ * miplevel 1+ tiling state is inferred.
+ */
+ if (dst_base_slice->tiling == VC5_TILING_UIF_NO_XOR ||
+ dst_base_slice->tiling == VC5_TILING_UIF_XOR) {
+ int uif_block_h = 2 * v3d_utile_height(dst->cpp);
+ int implicit_padded_height = align(height, uif_block_h);
+
+ tfu.icfg |= (((dst_base_slice->padded_height -
+ implicit_padded_height) / uif_block_h) <<
+ V3D_TFU_ICFG_OPAD_SHIFT);
+ }
+
+ int ret = v3d_ioctl(screen->fd, DRM_IOCTL_V3D_SUBMIT_TFU, &tfu);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to submit TFU job: %d\n", ret);
+ return false;
+ }
+
+ dst->writes++;
+
+ return true;
+}
+
+boolean
+v3d_generate_mipmap(struct pipe_context *pctx,
+ struct pipe_resource *prsc,
+ enum pipe_format format,
+ unsigned int base_level,
+ unsigned int last_level,
+ unsigned int first_layer,
+ unsigned int last_layer)
+{
+ if (format != prsc->format)
+ return false;
+
+ /* We could maybe support looping over layers for array textures, but
+ * we definitely don't support 3D.
+ */
+ if (first_layer != last_layer)
+ return false;
+
+ return v3d_tfu(pctx,
+ prsc, prsc,
+ base_level,
+ base_level, last_level,
+ first_layer, first_layer);
+}
+
+static bool
+v3d_tfu_blit(struct pipe_context *pctx, const struct pipe_blit_info *info)
+{
+ int dst_width = u_minify(info->dst.resource->width0, info->dst.level);
+ int dst_height = u_minify(info->dst.resource->height0, info->dst.level);
+
+ if ((info->mask & PIPE_MASK_RGBA) == 0)
+ return false;
+
+ if (info->scissor_enable ||
+ info->dst.box.x != 0 ||
+ info->dst.box.y != 0 ||
+ info->dst.box.width != dst_width ||
+ info->dst.box.height != dst_height ||
+ info->src.box.x != 0 ||
+ info->src.box.y != 0 ||
+ info->src.box.width != info->dst.box.width ||
+ info->src.box.height != info->dst.box.height) {
+ return false;
+ }
+
+ if (info->dst.format != info->src.format)
+ return false;
+
+ return v3d_tfu(pctx, info->dst.resource, info->src.resource,
+ info->src.level,
+ info->dst.level, info->dst.level,
+ info->src.box.z, info->dst.box.z);
+}
+
/* Optimal hardware path for blitting pixels.
* Scaling, format conversion, up- and downsampling (resolve) are allowed.
*/
void
-vc5_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
+v3d_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
{
+ struct v3d_context *v3d = v3d_context(pctx);
struct pipe_blit_info info = *blit_info;
if (info.mask & PIPE_MASK_S) {
- vc5_stencil_blit(pctx, blit_info);
+ v3d_stencil_blit(pctx, blit_info);
info.mask &= ~PIPE_MASK_S;
}
-#if 0
- if (vc5_tile_blit(pctx, blit_info))
- return;
-#endif
+ if (v3d_tfu_blit(pctx, blit_info))
+ info.mask &= ~PIPE_MASK_RGBA;
+
+ if (info.mask)
+ v3d_render_blit(pctx, &info);
- vc5_render_blit(pctx, &info);
+ /* Flush our blit jobs immediately. They're unlikely to get reused by
+ * normal drawing or other blits, and without flushing we can easily
+ * run into unexpected OOMs when blits are used for a large series of
+ * texture uploads before using the textures.
+ */
+ v3d_flush_jobs_writing_resource(v3d, info.dst.resource);
}