From 9006de318ebfb086b45fbce3a8eaabe33faa9ec7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 9 Mar 2015 13:16:05 +1000 Subject: [PATCH] tests: more inline transfer tests This adds code to the encoder that needs to be backported to the mesa virgl driver to support inline writes for non-buffer objects. --- tests/test_virgl_transfer.c | 88 ++++++++++++++++++++++++++++++------- tests/testvirgl_encode.c | 88 +++++++++++++++++++++++++++++-------- 2 files changed, 142 insertions(+), 34 deletions(-) diff --git a/tests/test_virgl_transfer.c b/tests/test_virgl_transfer.c index 57a991d..53108e0 100644 --- a/tests/test_virgl_transfer.c +++ b/tests/test_virgl_transfer.c @@ -374,9 +374,12 @@ END_TEST /* for each texture type construct a valid and invalid transfer, invalid using a box outside the bounds of the transfer */ +#define LARGE_FLAG_WIDTH (1 << 0) +#define LARGE_FLAG_HEIGHT (1 << 1) +#define LARGE_FLAG_DEPTH (1 << 2) void get_resource_args(enum pipe_texture_target target, bool invalid, struct virgl_renderer_resource_create_args *args, - struct pipe_box *box, int nsamples, bool large) + struct pipe_box *box, int nsamples, int large_flags) { memset(args, 0, sizeof(*args)); memset(box, 0, sizeof(*box)); @@ -393,7 +396,7 @@ void get_resource_args(enum pipe_texture_target target, bool invalid, args->nr_samples = nsamples; args->flags = 0; - if (large && target == PIPE_BUFFER) + if (large_flags & LARGE_FLAG_WIDTH) args->width = 65536*2; else args->width = 50; @@ -423,7 +426,10 @@ void get_resource_args(enum pipe_texture_target target, bool invalid, case PIPE_TEXTURE_1D_ARRAY: break; default: - args->height = 50; + if (large_flags & LARGE_FLAG_HEIGHT) + args->height = 64000; + else + args->height = 50; break; } @@ -442,6 +448,11 @@ void get_resource_args(enum pipe_texture_target target, bool invalid, } } +static unsigned get_box_size(struct pipe_box *box, int elsize) +{ + return elsize * box->width * box->height * box->depth; +} + static void virgl_test_transfer_res(enum pipe_texture_target target, bool write, bool invalid) { @@ -451,12 +462,14 @@ static void virgl_test_transfer_res(enum pipe_texture_target target, struct iovec iovs[1]; int niovs = 1; int ret; + int size; - data = calloc(1, 65536); - iovs[0].iov_base = data; - iovs[0].iov_len = 65536; + get_resource_args(target, invalid, &res, &box, 1, 0); - get_resource_args(target, invalid, &res, &box, 1, false); + size = get_box_size(&box, target == PIPE_BUFFER ? 1 : 4); + data = calloc(1, size); + iovs[0].iov_base = data; + iovs[0].iov_len = size; ret = virgl_renderer_resource_create(&res, NULL, 0); ck_assert_int_eq(ret, 0); @@ -501,7 +514,7 @@ START_TEST(virgl_test_transfer_res_write_invalid) END_TEST static void virgl_test_transfer_inline(enum pipe_texture_target target, - bool invalid) + bool invalid, int large_flags) { struct virgl_renderer_resource_create_args args; struct pipe_box box; @@ -509,12 +522,15 @@ static void virgl_test_transfer_inline(enum pipe_texture_target target, struct virgl_resource res; int ret; int elsize = target == 0 ? 1 : 4; - void *data = calloc(1, 65536); + void *data; + unsigned size; ret = testvirgl_init_ctx_cmdbuf(&ctx); ck_assert_int_eq(ret, 0); - get_resource_args(target, invalid, &args, &box, 1, false); + get_resource_args(target, invalid, &args, &box, 1, large_flags); + size = get_box_size(&box, elsize); + data = calloc(1, size); ret = virgl_renderer_resource_create(&args, NULL, 0); ck_assert_int_eq(ret, 0); @@ -535,13 +551,54 @@ static void virgl_test_transfer_inline(enum pipe_texture_target target, START_TEST(virgl_test_transfer_inline_valid) { - virgl_test_transfer_inline(_i, false); + virgl_test_transfer_inline(_i, false, 0); } END_TEST START_TEST(virgl_test_transfer_inline_invalid) { - virgl_test_transfer_inline(_i, true); + virgl_test_transfer_inline(_i, true, 0); +} +END_TEST + +START_TEST(virgl_test_transfer_inline_valid_large) +{ + virgl_test_transfer_inline(_i, false, LARGE_FLAG_WIDTH); +} +END_TEST + +/* transfer writes have to fit in cmd stream, make sure we split them */ +START_TEST(virgl_test_transfer_inline_large_buffer) +{ + struct virgl_renderer_resource_create_args args; + struct pipe_box box; + struct virgl_context ctx; + struct virgl_resource res; + int ret; + int elsize = 1; + void *data = calloc(1, 65536*3); + + ret = testvirgl_init_ctx_cmdbuf(&ctx); + ck_assert_int_eq(ret, 0); + + get_resource_args(PIPE_BUFFER, false, &args, &box, 1, LARGE_FLAG_WIDTH); + + ret = virgl_renderer_resource_create(&args, NULL, 0); + ck_assert_int_eq(ret, 0); + + res.handle = args.handle; + res.base.target = args.target; + res.base.format = args.format; + + virgl_renderer_ctx_attach_resource(ctx.ctx_id, res.handle); + + virgl_encoder_inline_write(&ctx, &res, 0, 0, (struct pipe_box *)&box, data, box.width * elsize, 0); + ret = virgl_renderer_submit_cmd(ctx.cbuf->buf, ctx.ctx_id, ctx.cbuf->cdw); + ck_assert_int_eq(ret, 0); + virgl_renderer_ctx_detach_resource(ctx.ctx_id, res.handle); + virgl_renderer_resource_unref(res.handle); + testvirgl_fini_ctx_cmdbuf(&ctx); + free(data); } END_TEST @@ -578,9 +635,10 @@ Suite *virgl_init_suite(void) suite_add_tcase(s, tc_core); tc_core = tcase_create("transfer_inline_write"); - /* only support on buffer for now */ - tcase_add_loop_test(tc_core, virgl_test_transfer_inline_valid, 0, PIPE_BUFFER + 1);//PIPE_MAX_TEXTURE_TYPES); - tcase_add_loop_test(tc_core, virgl_test_transfer_inline_invalid, 0, PIPE_BUFFER + 1);//PIPE_MAX_TEXTURE_TYPES); + tcase_add_loop_test(tc_core, virgl_test_transfer_inline_valid, 0, PIPE_MAX_TEXTURE_TYPES); + tcase_add_loop_test(tc_core, virgl_test_transfer_inline_invalid, 0, PIPE_MAX_TEXTURE_TYPES); + tcase_add_loop_test(tc_core, virgl_test_transfer_inline_valid_large, 0, PIPE_MAX_TEXTURE_TYPES); + suite_add_tcase(s, tc_core); return s; diff --git a/tests/testvirgl_encode.c b/tests/testvirgl_encode.c index 898aaf9..8829977 100644 --- a/tests/testvirgl_encode.c +++ b/tests/testvirgl_encode.c @@ -4,6 +4,7 @@ #include "util/u_memory.h" #include "util/u_math.h" +#include "util/u_format.h" #include "pipe/p_state.h" #include "testvirgl_encode.h" #include "virgl_protocol.h" @@ -405,6 +406,18 @@ static void virgl_encoder_iw_emit_header_1d(struct virgl_context *ctx, virgl_encoder_write_dword(ctx->cbuf, box->depth); } +static void virgl_encoder_inline_send_box(struct virgl_context *ctx, + struct virgl_resource *res, + unsigned level, unsigned usage, + const struct pipe_box *box, + const void *data, unsigned stride, + unsigned layer_stride, int length) +{ + virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_RESOURCE_INLINE_WRITE, 0, ((length + 3) / 4) + 11)); + virgl_encoder_iw_emit_header_1d(ctx, res, level, usage, box, stride, layer_stride); + virgl_encoder_write_block(ctx->cbuf, data, length); +} + int virgl_encoder_inline_write(struct virgl_context *ctx, struct virgl_resource *res, unsigned level, unsigned usage, @@ -412,34 +425,71 @@ int virgl_encoder_inline_write(struct virgl_context *ctx, const void *data, unsigned stride, unsigned layer_stride) { - uint32_t size = (stride ? stride : box->width) * box->height; uint32_t length, thispass, left_bytes; struct pipe_box mybox = *box; + unsigned elsize, size; + unsigned layer_size; + unsigned stride_internal = stride; + unsigned layer_stride_internal = layer_stride; + unsigned layer, row; + elsize = util_format_get_blocksize(res->base.format); + + /* total size of data to transfer */ + if (!stride) + stride_internal = box->width * elsize; + layer_size = box->height * stride_internal; + if (layer_stride && layer_stride < layer_size) + return -1; + if (!layer_stride) + layer_stride_internal = layer_size; + size = layer_stride_internal * box->depth; length = 11 + (size + 3) / 4; - if ((ctx->cbuf->cdw + length + 1) > VIRGL_MAX_CMDBUF_DWORDS) { - if (box->height > 1 || box->depth > 1) { - debug_printf("inline transfer failed due to multi dimensions and too large\n"); - assert(0); - } + + /* can we send it all in one cmdbuf? */ + if (length < VIRGL_MAX_CMDBUF_DWORDS) { + /* is there space in this cmdbuf? if not flush and use another one */ + if ((ctx->cbuf->cdw + length + 1) > VIRGL_MAX_CMDBUF_DWORDS) { + ctx->flush(ctx); + } + /* send it all in one go. */ + virgl_encoder_inline_send_box(ctx, res, level, usage, &mybox, data, stride, layer_stride, size); + return 0; } - left_bytes = size; - while (left_bytes) { - if (ctx->cbuf->cdw + 12 > VIRGL_MAX_CMDBUF_DWORDS) - ctx->flush(ctx); + /* break things down into chunks we can send */ + /* send layers in separate chunks */ + for (layer = 0; layer < box->depth; layer++) { + const void *layer_data = data; + mybox.z = layer; + mybox.depth = 1; - thispass = (VIRGL_MAX_CMDBUF_DWORDS - ctx->cbuf->cdw - 12) * 4; + /* send one line in separate chunks */ + for (row = 0; row < box->height; row++) { + const void *row_data = layer_data; + mybox.y = row; + mybox.height = 1; + mybox.x = 0; - length = MIN2(thispass, left_bytes); + left_bytes = box->width * elsize; + while (left_bytes) { + if (ctx->cbuf->cdw + 12 > VIRGL_MAX_CMDBUF_DWORDS) + ctx->flush(ctx); - mybox.width = length; - virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_RESOURCE_INLINE_WRITE, 0, ((length + 3) / 4) + 11)); - virgl_encoder_iw_emit_header_1d(ctx, res, level, usage, &mybox, stride, layer_stride); - virgl_encoder_write_block(ctx->cbuf, data, length); - left_bytes -= length; - mybox.x += length; - data += length; + thispass = (VIRGL_MAX_CMDBUF_DWORDS - ctx->cbuf->cdw - 12) * 4; + + length = MIN2(thispass, left_bytes); + + mybox.width = length / elsize; + + virgl_encoder_inline_send_box(ctx, res, level, usage, &mybox, row_data, stride, layer_stride, length); + left_bytes -= length; + mybox.x += length / elsize; + row_data += length; + } + layer_data += stride_internal; + } + data += layer_stride_internal; } return 0; }