blob: 17a463b8c714dc9bac0387c2653c45e0fba26044 [file] [log] [blame]
#define _POSIX_C_SOURCE 200112L
#define _XOPEN_SOURCE 500
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "write_bmp.h"
#include "memutil.h"
#include "etnaviv_blt.h"
#include "drm_setup.h"
#include "cmdstream.h"
#include "etna_fb.h"
#include "etna_util.h"
#include "color.h"
#include "hw/common_3d.xml.h"
#include "hw/state.xml.h"
#include "hw/state_3d.xml.h"
#include "hw/state_blt.xml.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#define WIDTH 1920
#define HEIGHT 1080
struct test_info {
struct etna_bo *bo_color;
struct etna_bo *bo_color_ts;
struct etna_reloc ADDR_RENDER_TARGET_A;
struct etna_reloc ADDR_TILE_STATUS_B; /* Color TS */
struct etna_reloc ADDR_USER_A; /* Bitmap out */
struct fb_info *fb;
uint32_t ts_clear_value[2];
};
void init_reloc(struct etna_reloc *reloc, struct etna_bo *bo, uint32_t offset, uint32_t flags)
{
reloc->bo = bo;
reloc->offset = offset;
reloc->flags = flags;
}
struct test_info *test_init(struct etna_device *conn)
{
struct test_info *info = CALLOC_STRUCT(test_info);
/* Allocate bos */
info->bo_color = etna_bo_new(conn, 0x7f8000, DRM_ETNA_GEM_TYPE_RT);
assert(info->bo_color);
info->bo_color_ts = etna_bo_new(conn, 0x3fc0, DRM_ETNA_GEM_TYPE_TS);
assert(info->bo_color_ts);
/* Initialize relocs */
init_reloc(&info->ADDR_RENDER_TARGET_A, info->bo_color, 0x0, ETNA_RELOC_READ|ETNA_RELOC_WRITE);
init_reloc(&info->ADDR_TILE_STATUS_B, info->bo_color_ts, 0x0, ETNA_RELOC_READ|ETNA_RELOC_WRITE);
int rv = fb_open(conn, 0, &info->fb);
assert(rv == 0);
/* HD or bust... */
assert(info->fb->width == WIDTH && info->fb->height == HEIGHT && info->fb->rs_format==RS_FORMAT_A8R8G8B8);
fb_set_buffer(info->fb, 0);
info->ADDR_USER_A = info->fb->buffer[0];
return info;
}
void test_free(struct etna_device *conn, struct test_info *info)
{
etna_bo_del(info->bo_color);
etna_bo_del(info->bo_color_ts);
free(info);
}
/* Copy frame from render target to framebuffer */
void gen_cmdbuf_2(struct etna_cmd_stream *stream, struct test_info *info)
{
etna_cmd_stream_reserve(stream, 64*2); /* Make sure BLT op doesn't get broken up */
etna_set_state(stream, VIVS_GL_FLUSH_CACHE, 0x00000c23);
etna_set_state(stream, VIVS_TS_FLUSH_CACHE, 0x00000001);
etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000001);
etna_set_state(stream, VIVS_BLT_CONFIG, 0x00000000);
etna_set_state(stream, VIVS_BLT_SRC_STRIDE, 0x60c01e00);
etna_set_state(stream, VIVS_BLT_SRC_CONFIG, 0x0023c833);
etna_set_state(stream, VIVS_BLT_SWIZZLE, 0x00688688);
etna_set_state(stream, VIVS_BLT_UNK140A0, 0x00040004);
etna_set_state(stream, VIVS_BLT_UNK1409C, 0x00400040);
etna_set_state_reloc(stream, VIVS_BLT_SRC_TS, &info->ADDR_TILE_STATUS_B);
etna_set_state(stream, VIVS_BLT_SRC_TS_CLEAR_VALUE0, info->ts_clear_value[0]);
etna_set_state_reloc(stream, VIVS_BLT_SRC_ADDR, &info->ADDR_RENDER_TARGET_A);
etna_set_state(stream, VIVS_BLT_DEST_STRIDE, 0x00c01e00);
etna_set_state(stream, VIVS_BLT_DEST_CONFIG, 0x0041c800);
etna_set_state_reloc(stream, VIVS_BLT_DEST_ADDR, &info->ADDR_USER_A);
etna_set_state(stream, VIVS_BLT_SRC_POS, 0x00000000);
etna_set_state(stream, VIVS_BLT_DEST_POS, 0x00000000);
etna_set_state(stream, VIVS_BLT_IMAGE_SIZE, 0x04380780);
etna_set_state(stream, VIVS_BLT_UNK14058, 0xffffffff);
etna_set_state(stream, VIVS_BLT_UNK1405C, 0xffffffff);
etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003);
etna_set_state(stream, VIVS_BLT_COMMAND, VIVS_BLT_COMMAND_COMMAND_COPY_IMAGE);
etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003);
etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000000);
/* Make FE wait for BLT (to be able to sync frame swap) */
etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000001);
etna_set_state(stream, VIVS_GL_SEMAPHORE_TOKEN, 0x00001001);
etna_cmd_stream_reserve(stream, 2);
etna_cmd_stream_emit(stream, 0x48000000); /* command STALL (9) OP=STALL */
etna_cmd_stream_emit(stream, 0x00001001); /* command TOKEN FROM=FE,TO=BLT,UNK28=0x0 */
etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000000);
etna_set_state(stream, VIVS_GL_FLUSH_CACHE, 0x00000c23);
}
#define NUM_BOGEYS 40
struct bogey {
int iw;
int ih;
float posx;
float posy;
int iposx;
int iposy;
float dx;
float dy;
float color_phase;
float size_phase;
float intensity;
uint32_t color;
};
int main(int argc, char **argv)
{
struct drm_test_info *info;
uint64_t val;
if ((info = drm_test_setup(argc, argv)) == NULL) {
return 1;
}
if (etna_gpu_get_param(info->gpu, ETNA_GPU_MODEL, &val)) {
fprintf(stderr, "Could not get GPU model\n");
goto error;
}
if (val != 0x7000) {
fprintf(stderr, "This only runs on GC7000\n");
goto error;
}
struct test_info *tinfo = test_init(info->dev);
assert(tinfo);
int frame = 0;
struct bogey bogeys[NUM_BOGEYS];
float phase = 0.0f;
struct timespec tprev;
uint32_t background = 0xff000000;
clock_gettime(CLOCK_MONOTONIC, &tprev);
for (unsigned i=0; i<NUM_BOGEYS; ++i) {
struct bogey *b = &bogeys[i];
memset(b, 0, sizeof(struct bogey));
b->posx = random() % WIDTH;
b->posy = random() % HEIGHT;
b->dx = 100.0f + i*10.0f;
b->dy = 100.0f + i*10.0f;
b->color_phase = i * 0.005f;
b->size_phase = i * 0.31f;
b->intensity = ((float)i / (NUM_BOGEYS - 1) * 0.5f) + 0.5f;
}
while (true) {
struct timespec tcur;
clock_gettime(CLOCK_MONOTONIC, &tcur);
float dt = (float)(tcur.tv_sec - tprev.tv_sec) + (float)(tcur.tv_nsec - tprev.tv_nsec)*1e-9f;
/* Update physics */
phase += dt;
for (unsigned i=0; i<NUM_BOGEYS; ++i) {
struct bogey *b = &bogeys[i];
b->iw = (int)((sinf(phase * 0.50f + b->size_phase) + 1.0f)*200.0f) + 1;
b->ih = (int)((cosf(phase * 0.95f + b->size_phase) + 1.0f)*200.0f) + 1;
b->posx += b->dx * dt;
b->posy += b->dy * dt;
b->iw = etna_smax(b->iw, 1);
b->ih = etna_smax(b->ih, 1);
b->iposx = (int)b->posx;
b->iposy = (int)b->posy;
if (b->iposx < 0) {
b->iposx = 0;
b->dx = fabsf(b->dx);
}
if (b->iposy < 0) {
b->iposy = 0;
b->dy = fabs(b->dy);
}
if (b->iposx + b->iw > WIDTH) {
b->iposx = WIDTH - b->iw;
b->dx = -fabsf(b->dx);
}
if (b->iposy + b->ih > HEIGHT) {
b->iposy = HEIGHT - b->ih;
b->dy = -fabsf(b->dy);
}
b->color = hsv_argb(
fmod(phase * 0.03f + b->color_phase, 1.0f),
0.5f + fabsf(sinf(phase * 2.0f + b->color_phase * 10.0f)) * 0.5f,
b->intensity,
1.0f);
}
tinfo->ts_clear_value[0] = background;
tinfo->ts_clear_value[1] = background;
/* Clear framebuffer */
struct blt_clear_op clr = {};
clr.dest.addr = tinfo->ADDR_RENDER_TARGET_A;
clr.dest.ts_addr = tinfo->ADDR_TILE_STATUS_B;
clr.dest.bpp = 4;
clr.dest.stride = 0x1e00;
clr.dest.compressed = 1;
clr.dest.compress_fmt = 3;
clr.dest.tiling = ETNA_LAYOUT_SUPER_TILED;
clr.dest.use_ts = 1;
clr.dest.ts_clear_value[0] = tinfo->ts_clear_value[0];
clr.dest.ts_clear_value[1] = tinfo->ts_clear_value[1];
clr.dest.cache_mode = TS_CACHE_MODE_256;
clr.clear_value[0] = background;
clr.clear_value[1] = background;
clr.clear_bits[0] = 0xffffffff;
clr.clear_bits[1] = 0xffffffff;
clr.rect_x = 0;
clr.rect_y = 0;
clr.rect_w = WIDTH;
clr.rect_h = HEIGHT;
emit_blt_clearimage(info->stream, &clr);
/* Draw bouncing squares */
for (unsigned i=0; i<NUM_BOGEYS; ++i) {
struct blt_clear_op clr = {};
struct bogey *b = &bogeys[i];
clr.dest.addr = tinfo->ADDR_RENDER_TARGET_A;
clr.dest.ts_addr = tinfo->ADDR_TILE_STATUS_B;
clr.dest.bpp = 4;
clr.dest.stride = 0x1e00;
clr.dest.compressed = 1;
clr.dest.compress_fmt = 3;
clr.dest.tiling = ETNA_LAYOUT_SUPER_TILED;
clr.dest.use_ts = 1;
clr.dest.ts_clear_value[0] = tinfo->ts_clear_value[0];
clr.dest.ts_clear_value[1] = tinfo->ts_clear_value[1];
clr.dest.cache_mode = TS_CACHE_MODE_256;
clr.clear_value[0] = clr.clear_value[1] = b->color;
clr.clear_bits[0] = 0xffffffff; clr.clear_bits[1] = 0xffffffff;
clr.rect_x = b->iposx;
clr.rect_y = b->iposy;
clr.rect_w = b->iw;
clr.rect_h = b->ih;
assert(clr.rect_x < WIDTH);
assert(clr.rect_y < HEIGHT);
assert(clr.rect_w > 0);
assert(clr.rect_h > 0);
assert((clr.rect_x + clr.rect_w) <= WIDTH);
assert((clr.rect_y + clr.rect_h) <= HEIGHT);
emit_blt_clearimage(info->stream, &clr);
}
/* Copy framebuffer to screen */
gen_cmdbuf_2(info->stream, tinfo);
etna_cmd_stream_flush(info->stream);
frame += 1;
tprev = tcur;
if ((frame % 1024)==0) {
printf("FPS %.1f. %.1f ms per frame\n", frame / phase, phase / frame*1000.0f);
}
}
test_free(info->dev, tinfo);
drm_test_teardown(info);
return 0;
error:
drm_test_teardown(info);
return 1;
}