/** Create vertex element states, which define a layout for fetching * vertices for rendering. */ static void * etna_vertex_elements_state_create(struct pipe_context *pctx, unsigned num_elements, const struct pipe_vertex_element *elements) { struct etna_context *ctx = etna_context(pctx); struct compiled_vertex_elements_state *cs = CALLOC_STRUCT(compiled_vertex_elements_state); if (!cs) return NULL; if (num_elements > ctx->specs.vertex_max_elements) { BUG("number of elements (%u) exceeds chip maximum (%u)", num_elements, ctx->specs.vertex_max_elements); return NULL; } /* XXX could minimize number of consecutive stretches here by sorting, and * permuting the inputs in shader or does Mesa do this already? */ /* Check that vertex element binding is compatible with hardware; thus * elements[idx].vertex_buffer_index are < stream_count. If not, the binding * uses more streams than is supported, and u_vbuf should have done some * reorganization for compatibility. */ /* TODO: does mesa this for us? */ bool incompatible = false; for (unsigned idx = 0; idx < num_elements; ++idx) { if (elements[idx].vertex_buffer_index >= ctx->specs.stream_count || elements[idx].instance_divisor > 0) incompatible = true; } cs->num_elements = num_elements; if (incompatible || num_elements == 0) { DBG("Error: zero vertex elements, or more vertex buffers used than supported"); FREE(cs); return NULL; } unsigned start_offset = 0; /* start of current consecutive stretch */ bool nonconsecutive = true; /* previous value of nonconsecutive */ for (unsigned idx = 0; idx < num_elements; ++idx) { unsigned element_size = util_format_get_blocksize(elements[idx].src_format); unsigned end_offset = elements[idx].src_offset + element_size; uint32_t format_type, normalize; if (nonconsecutive) start_offset = elements[idx].src_offset; /* maximum vertex size is 256 bytes */ assert(element_size != 0 && end_offset <= 256); /* check whether next element is consecutive to this one */ nonconsecutive = (idx == (num_elements - 1)) || elements[idx + 1].vertex_buffer_index != elements[idx].vertex_buffer_index || end_offset != elements[idx + 1].src_offset; format_type = translate_vertex_format_type(elements[idx].src_format); normalize = translate_vertex_format_normalize(elements[idx].src_format); assert(format_type != ETNA_NO_MATCH); assert(normalize != ETNA_NO_MATCH); if (ctx->specs.halti < 5) { cs->FE_VERTEX_ELEMENT_CONFIG[idx] = COND(nonconsecutive, VIVS_FE_VERTEX_ELEMENT_CONFIG_NONCONSECUTIVE) | format_type | VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM(util_format_get_nr_components(elements[idx].src_format)) | normalize | VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN(ENDIAN_MODE_NO_SWAP) | VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM(elements[idx].vertex_buffer_index) | VIVS_FE_VERTEX_ELEMENT_CONFIG_START(elements[idx].src_offset) | VIVS_FE_VERTEX_ELEMENT_CONFIG_END(end_offset - start_offset); } else { /* HALTI5 spread vertex attrib config over two registers */ cs->NFE_GENERIC_ATTRIB_CONFIG0[idx] = format_type | VIVS_NFE_GENERIC_ATTRIB_CONFIG0_NUM(util_format_get_nr_components(elements[idx].src_format)) | normalize | VIVS_NFE_GENERIC_ATTRIB_CONFIG0_ENDIAN(ENDIAN_MODE_NO_SWAP) | VIVS_NFE_GENERIC_ATTRIB_CONFIG0_STREAM(elements[idx].vertex_buffer_index) | VIVS_NFE_GENERIC_ATTRIB_CONFIG0_START(elements[idx].src_offset); cs->NFE_GENERIC_ATTRIB_CONFIG1[idx] = COND(nonconsecutive, VIVS_NFE_GENERIC_ATTRIB_CONFIG1_NONCONSECUTIVE) | VIVS_NFE_GENERIC_ATTRIB_CONFIG1_END(end_offset - start_offset); } cs->NFE_GENERIC_ATTRIB_SCALE[idx] = 0x3f800000; /* 1 for integer, 1.0 for float */ } return cs; }
int main(int argc, char **argv) { int rv; int width = 256; int height = 256; int padded_width = etna_align_up(width, 64); int padded_height = etna_align_up(height, 64); printf("padded_width %i padded_height %i\n", padded_width, padded_height); struct viv_conn *conn = 0; rv = viv_open(VIV_HW_3D, &conn); if(rv!=0) { fprintf(stderr, "Error opening device\n"); exit(1); } printf("Succesfully opened device\n"); struct etna_vidmem *rt = 0; /* main render target */ struct etna_vidmem *rt_ts = 0; /* tile status for main render target */ struct etna_vidmem *z = 0; /* depth for main render target */ struct etna_vidmem *z_ts = 0; /* depth ts for main render target */ struct etna_vidmem *vtx = 0; /* vertex buffer */ struct etna_vidmem *aux_rt = 0; /* auxilary render target */ struct etna_vidmem *aux_rt_ts = 0; /* tile status for auxilary render target */ struct etna_vidmem *bmp = 0; /* bitmap */ size_t rt_size = padded_width * padded_height * 4; size_t rt_ts_size = etna_align_up((padded_width * padded_height * 4)/0x100, 0x100); size_t z_size = padded_width * padded_height * 2; size_t z_ts_size = etna_align_up((padded_width * padded_height * 2)/0x100, 0x100); size_t bmp_size = width * height * 4; if(etna_vidmem_alloc_linear(conn, &rt, rt_size, VIV_SURF_RENDER_TARGET, VIV_POOL_DEFAULT, true)!=ETNA_OK || etna_vidmem_alloc_linear(conn, &rt_ts, rt_ts_size, VIV_SURF_TILE_STATUS, VIV_POOL_DEFAULT, true)!=ETNA_OK || etna_vidmem_alloc_linear(conn, &z, z_size, VIV_SURF_DEPTH, VIV_POOL_DEFAULT, true)!=ETNA_OK || etna_vidmem_alloc_linear(conn, &z_ts, z_ts_size, VIV_SURF_TILE_STATUS, VIV_POOL_DEFAULT, true)!=ETNA_OK || etna_vidmem_alloc_linear(conn, &vtx, VERTEX_BUFFER_SIZE, VIV_SURF_VERTEX, VIV_POOL_DEFAULT, true)!=ETNA_OK || etna_vidmem_alloc_linear(conn, &aux_rt, 0x4000, VIV_SURF_RENDER_TARGET, VIV_POOL_SYSTEM, true)!=ETNA_OK || etna_vidmem_alloc_linear(conn, &aux_rt_ts, 0x100, VIV_SURF_TILE_STATUS, VIV_POOL_DEFAULT, true)!=ETNA_OK || etna_vidmem_alloc_linear(conn, &bmp, bmp_size, VIV_SURF_BITMAP, VIV_POOL_DEFAULT, true)!=ETNA_OK ) { fprintf(stderr, "Error allocating video memory\n"); exit(1); } /* Phew, now we got all the memory we need. * Write interleaved attribute vertex stream. * Unlike the GL example we only do this once, not every time glDrawArrays is called, the same would be accomplished * from GL by using a vertex buffer object. */ for(int vert=0; vert<NUM_VERTICES; ++vert) { int dest_idx = vert * (3 + 2); for(int comp=0; comp<3; ++comp) ((float*)vtx->logical)[dest_idx+comp+0] = vVertices[vert*3 + comp]; /* 0 */ for(int comp=0; comp<2; ++comp) ((float*)vtx->logical)[dest_idx+comp+3] = vTexCoords[vert*2 + comp]; /* 1 */ } struct etna_ctx *ctx = 0; if(etna_create(conn, &ctx) != ETNA_OK) { printf("Unable to create context\n"); exit(1); } /* Now load the shader itself */ uint32_t vs[] = { 0x02001001, 0x2a800800, 0x00000000, 0x003fc008, 0x02001003, 0x2a800800, 0x00000040, 0x00000002, }; uint32_t vs_size = sizeof(vs); uint32_t *ps; uint32_t ps_size; if(argc < 2) { perror("provide shader on command line"); exit(1); } int fd = open(argv[1], O_RDONLY); if(fd == -1) { perror("opening shader"); exit(1); } ps_size = lseek(fd, 0, SEEK_END); ps = malloc(ps_size); lseek(fd, 0, SEEK_SET); if(ps_size == 0 || ps_size>8192 || read(fd, ps, ps_size) != ps_size) { perror("empty or unreadable shader"); exit(1); } close(fd); /* XXX how important is the ordering? I suppose we could group states (except the flushes, kickers, semaphores etc) * and simply submit them at once. Especially for consecutive states and masked stated this could be a big win * in DMA command buffer size. */ /* Build first command buffer */ etna_set_state(ctx, VIVS_GL_VERTEX_ELEMENT_CONFIG, 0x1); etna_set_state(ctx, VIVS_RA_CONTROL, 0x1); etna_set_state(ctx, VIVS_PA_W_CLIP_LIMIT, 0x34000001); etna_set_state(ctx, VIVS_PA_SYSTEM_MODE, 0x11); etna_set_state(ctx, VIVS_PA_CONFIG, ETNA_MASKED_BIT(VIVS_PA_CONFIG_UNK22, 0)); etna_set_state(ctx, VIVS_SE_CONFIG, 0x0); etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR); /* Set up pixel engine */ etna_set_state(ctx, VIVS_PE_COLOR_FORMAT, ETNA_MASKED_BIT(VIVS_PE_COLOR_FORMAT_OVERWRITE, 0)); etna_set_state(ctx, VIVS_PE_ALPHA_CONFIG, ETNA_MASKED_BIT(VIVS_PE_ALPHA_CONFIG_BLEND_ENABLE_COLOR, 0) & ETNA_MASKED_BIT(VIVS_PE_ALPHA_CONFIG_BLEND_SEPARATE_ALPHA, 0) & ETNA_MASKED(VIVS_PE_ALPHA_CONFIG_SRC_FUNC_COLOR, BLEND_FUNC_ONE) & ETNA_MASKED(VIVS_PE_ALPHA_CONFIG_SRC_FUNC_ALPHA, BLEND_FUNC_ONE) & ETNA_MASKED(VIVS_PE_ALPHA_CONFIG_DST_FUNC_COLOR, BLEND_FUNC_ZERO) & ETNA_MASKED(VIVS_PE_ALPHA_CONFIG_DST_FUNC_ALPHA, BLEND_FUNC_ZERO) & ETNA_MASKED(VIVS_PE_ALPHA_CONFIG_EQ_COLOR, BLEND_EQ_ADD) & ETNA_MASKED(VIVS_PE_ALPHA_CONFIG_EQ_ALPHA, BLEND_EQ_ADD)); etna_set_state(ctx, VIVS_PE_ALPHA_BLEND_COLOR, VIVS_PE_ALPHA_BLEND_COLOR_B(0) | VIVS_PE_ALPHA_BLEND_COLOR_G(0) | VIVS_PE_ALPHA_BLEND_COLOR_R(0) | VIVS_PE_ALPHA_BLEND_COLOR_A(0)); etna_set_state(ctx, VIVS_PE_ALPHA_OP, ETNA_MASKED_BIT(VIVS_PE_ALPHA_OP_ALPHA_TEST, 0)); etna_set_state(ctx, VIVS_PA_CONFIG, ETNA_MASKED_INL(VIVS_PA_CONFIG_CULL_FACE_MODE, OFF)); etna_set_state(ctx, VIVS_PE_DEPTH_CONFIG, ETNA_MASKED_BIT(VIVS_PE_DEPTH_CONFIG_WRITE_ENABLE, 0)); etna_set_state(ctx, VIVS_PE_STENCIL_CONFIG, ETNA_MASKED(VIVS_PE_STENCIL_CONFIG_REF_FRONT, 0) & ETNA_MASKED(VIVS_PE_STENCIL_CONFIG_MASK_FRONT, 0xff) & ETNA_MASKED(VIVS_PE_STENCIL_CONFIG_WRITE_MASK, 0xff)); etna_set_state(ctx, VIVS_PE_STENCIL_OP, ETNA_MASKED(VIVS_PE_STENCIL_OP_FUNC_FRONT, COMPARE_FUNC_ALWAYS) & ETNA_MASKED(VIVS_PE_STENCIL_OP_FUNC_BACK, COMPARE_FUNC_ALWAYS) & ETNA_MASKED(VIVS_PE_STENCIL_OP_FAIL_FRONT, STENCIL_OP_KEEP) & ETNA_MASKED(VIVS_PE_STENCIL_OP_FAIL_BACK, STENCIL_OP_KEEP) & ETNA_MASKED(VIVS_PE_STENCIL_OP_DEPTH_FAIL_FRONT, STENCIL_OP_KEEP) & ETNA_MASKED(VIVS_PE_STENCIL_OP_DEPTH_FAIL_BACK, STENCIL_OP_KEEP) & ETNA_MASKED(VIVS_PE_STENCIL_OP_PASS_FRONT, STENCIL_OP_KEEP) & ETNA_MASKED(VIVS_PE_STENCIL_OP_PASS_BACK, STENCIL_OP_KEEP)); etna_set_state(ctx, VIVS_PE_DEPTH_CONFIG, ETNA_MASKED_BIT(VIVS_PE_DEPTH_CONFIG_EARLY_Z, 0)); etna_set_state(ctx, VIVS_PE_COLOR_FORMAT, ETNA_MASKED(VIVS_PE_COLOR_FORMAT_COMPONENTS, 0xf)); etna_set_state(ctx, VIVS_SE_DEPTH_SCALE, 0x0); etna_set_state(ctx, VIVS_SE_DEPTH_BIAS, 0x0); etna_set_state(ctx, VIVS_PA_CONFIG, ETNA_MASKED_INL(VIVS_PA_CONFIG_FILL_MODE, SOLID)); etna_set_state(ctx, VIVS_PA_CONFIG, ETNA_MASKED_INL(VIVS_PA_CONFIG_SHADE_MODEL, SMOOTH)); /* Set up render target */ etna_set_state(ctx, VIVS_PE_COLOR_FORMAT, ETNA_MASKED(VIVS_PE_COLOR_FORMAT_FORMAT, RS_FORMAT_A8R8G8B8) & ETNA_MASKED_BIT(VIVS_PE_COLOR_FORMAT_SUPER_TILED, 1)); for(int frame=0; frame<1; ++frame) { printf("*** FRAME %i ****\n", frame); etna_set_state(ctx, VIVS_PE_COLOR_ADDR, rt->address); /* ADDR_A */ etna_set_state(ctx, VIVS_PE_COLOR_STRIDE, padded_width * 4); etna_set_state(ctx, VIVS_GL_MULTI_SAMPLE_CONFIG, ETNA_MASKED_INL(VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES, NONE) & ETNA_MASKED(VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES, 0xf) & ETNA_MASKED(VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12, 0x0) & ETNA_MASKED(VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16, 0x0) ); etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR); etna_set_state(ctx, VIVS_PE_COLOR_FORMAT, ETNA_MASKED_BIT(VIVS_PE_COLOR_FORMAT_OVERWRITE, 1)); etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR); etna_set_state(ctx, VIVS_TS_COLOR_CLEAR_VALUE, 0); etna_set_state(ctx, VIVS_TS_COLOR_STATUS_BASE, rt_ts->address); /* ADDR_B */ etna_set_state(ctx, VIVS_TS_COLOR_SURFACE_BASE, rt->address); /* ADDR_A */ etna_set_state(ctx, VIVS_TS_MEM_CONFIG, VIVS_TS_MEM_CONFIG_COLOR_FAST_CLEAR); /* ADDR_A */ etna_set_state(ctx, VIVS_PE_DEPTH_CONFIG, ETNA_MASKED_INL(VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT, D16) & ETNA_MASKED_BIT(VIVS_PE_DEPTH_CONFIG_SUPER_TILED, 1) ); etna_set_state(ctx, VIVS_PE_DEPTH_ADDR, z->address); /* ADDR_C */ etna_set_state(ctx, VIVS_PE_DEPTH_STRIDE, padded_width * 2); etna_set_state(ctx, VIVS_PE_STENCIL_CONFIG, ETNA_MASKED_INL(VIVS_PE_STENCIL_CONFIG_MODE, DISABLED)); etna_set_state(ctx, VIVS_PE_HDEPTH_CONTROL, VIVS_PE_HDEPTH_CONTROL_FORMAT_DISABLED); etna_set_state_f32(ctx, VIVS_PE_DEPTH_NORMALIZE, 65535.0); etna_set_state(ctx, VIVS_PE_DEPTH_CONFIG, ETNA_MASKED_BIT(VIVS_PE_DEPTH_CONFIG_EARLY_Z, 0)); etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_DEPTH); etna_set_state(ctx, VIVS_TS_DEPTH_CLEAR_VALUE, 0xffffffff); etna_set_state(ctx, VIVS_TS_DEPTH_STATUS_BASE, z_ts->address); /* ADDR_D */ etna_set_state(ctx, VIVS_TS_DEPTH_SURFACE_BASE, z->address); /* ADDR_C */ etna_set_state(ctx, VIVS_TS_MEM_CONFIG, VIVS_TS_MEM_CONFIG_DEPTH_FAST_CLEAR | VIVS_TS_MEM_CONFIG_COLOR_FAST_CLEAR | VIVS_TS_MEM_CONFIG_DEPTH_16BPP | VIVS_TS_MEM_CONFIG_DEPTH_COMPRESSION); etna_set_state(ctx, VIVS_PE_DEPTH_CONFIG, ETNA_MASKED_BIT(VIVS_PE_DEPTH_CONFIG_EARLY_Z, 1)); /* flip-flopping once again */ /* Warm up RS on aux render target */ etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH); etna_warm_up_rs(ctx, aux_rt->address, aux_rt_ts->address); /* Phew, now that's one hell of a setup; the serious rendering starts now */ etna_set_state(ctx, VIVS_TS_COLOR_STATUS_BASE, rt_ts->address); /* ADDR_B */ etna_set_state(ctx, VIVS_TS_COLOR_SURFACE_BASE, rt->address); /* ADDR_A */ /* ... or so we thought */ etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH); etna_warm_up_rs(ctx, aux_rt->address, aux_rt_ts->address); /* maybe now? */ etna_set_state(ctx, VIVS_TS_COLOR_STATUS_BASE, rt_ts->address); /* ADDR_B */ etna_set_state(ctx, VIVS_TS_COLOR_SURFACE_BASE, rt->address); /* ADDR_A */ etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH); /* nope, not really... */ etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH); etna_warm_up_rs(ctx, aux_rt->address, aux_rt_ts->address); etna_set_state(ctx, VIVS_TS_COLOR_STATUS_BASE, rt_ts->address); /* ADDR_B */ etna_set_state(ctx, VIVS_TS_COLOR_SURFACE_BASE, rt->address); /* ADDR_A */ etna_stall(ctx, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_PE); /* Set up the resolve to clear tile status for main render target * What the blob does is regard the TS as an image of width N, height 4, with 4 bytes per pixel * Looks like the height always stays the same. I don't think it matters as long as the entire memory are is covered. * XXX need to clear the depth ts too. * */ etna_set_state(ctx, VIVS_RS_CONFIG, VIVS_RS_CONFIG_SOURCE_FORMAT(RS_FORMAT_A8R8G8B8) | VIVS_RS_CONFIG_DEST_FORMAT(RS_FORMAT_A8R8G8B8) ); etna_set_state_multi(ctx, VIVS_RS_DITHER(0), 2, (uint32_t[]){0xffffffff, 0xffffffff}); etna_set_state(ctx, VIVS_RS_DEST_ADDR, rt_ts->address); /* ADDR_B */ etna_set_state(ctx, VIVS_RS_DEST_STRIDE, 0x100); /* 0x100 iso 0x40! seems it uses a width of 256 if width divisible by 256, XXX need to figure out these rules */ etna_set_state(ctx, VIVS_RS_WINDOW_SIZE, VIVS_RS_WINDOW_SIZE_HEIGHT(rt_ts_size/0x100) | VIVS_RS_WINDOW_SIZE_WIDTH(64)); etna_set_state(ctx, VIVS_RS_FILL_VALUE(0), 0x55555555); etna_set_state(ctx, VIVS_RS_CLEAR_CONTROL, VIVS_RS_CLEAR_CONTROL_MODE_ENABLED1 | VIVS_RS_CLEAR_CONTROL_BITS(0xffff)); etna_set_state(ctx, VIVS_RS_EXTRA_CONFIG, 0); /* no AA, no endian switch */ etna_set_state(ctx, VIVS_RS_KICKER, 0xbeebbeeb); etna_set_state(ctx, VIVS_TS_COLOR_CLEAR_VALUE, 0xff7f7f7f); etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR); etna_set_state(ctx, VIVS_TS_COLOR_CLEAR_VALUE, 0xff7f7f7f); etna_set_state(ctx, VIVS_TS_COLOR_STATUS_BASE, rt_ts->address); /* ADDR_B */ etna_set_state(ctx, VIVS_TS_COLOR_SURFACE_BASE, rt->address); /* ADDR_A */ etna_set_state(ctx, VIVS_TS_MEM_CONFIG, VIVS_TS_MEM_CONFIG_DEPTH_FAST_CLEAR | VIVS_TS_MEM_CONFIG_COLOR_FAST_CLEAR | VIVS_TS_MEM_CONFIG_DEPTH_16BPP | VIVS_TS_MEM_CONFIG_DEPTH_COMPRESSION); //etna_set_state(ctx, VIVS_PA_CONFIG, ETNA_MASKED_INL(VIVS_PA_CONFIG_CULL_FACE_MODE, CCW)); etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH); etna_set_state(ctx, VIVS_PE_DEPTH_CONFIG, ETNA_MASKED_BIT(VIVS_PE_DEPTH_CONFIG_WRITE_ENABLE, 0)); etna_set_state(ctx, VIVS_PE_DEPTH_CONFIG, ETNA_MASKED_INL(VIVS_PE_DEPTH_CONFIG_DEPTH_MODE, NONE)); etna_set_state(ctx, VIVS_PE_DEPTH_CONFIG, ETNA_MASKED_BIT(VIVS_PE_DEPTH_CONFIG_WRITE_ENABLE, 0)); etna_set_state(ctx, VIVS_PE_DEPTH_CONFIG, ETNA_MASKED(VIVS_PE_DEPTH_CONFIG_DEPTH_FUNC, COMPARE_FUNC_ALWAYS)); etna_set_state(ctx, VIVS_PE_DEPTH_CONFIG, ETNA_MASKED_INL(VIVS_PE_DEPTH_CONFIG_DEPTH_MODE, Z)); etna_set_state_f32(ctx, VIVS_PE_DEPTH_NEAR, 0.0); etna_set_state_f32(ctx, VIVS_PE_DEPTH_FAR, 1.0); etna_set_state_f32(ctx, VIVS_PE_DEPTH_NORMALIZE, 65535.0); /* set up primitive assembly */ etna_set_state_f32(ctx, VIVS_PA_VIEWPORT_OFFSET_Z, 0.0); etna_set_state_f32(ctx, VIVS_PA_VIEWPORT_SCALE_Z, 1.0); etna_set_state(ctx, VIVS_PE_DEPTH_CONFIG, ETNA_MASKED_BIT(VIVS_PE_DEPTH_CONFIG_ONLY_DEPTH, 0)); etna_set_state_fixp(ctx, VIVS_PA_VIEWPORT_OFFSET_X, width << 15); etna_set_state_fixp(ctx, VIVS_PA_VIEWPORT_OFFSET_Y, height << 15); etna_set_state_fixp(ctx, VIVS_PA_VIEWPORT_SCALE_X, width << 15); etna_set_state_fixp(ctx, VIVS_PA_VIEWPORT_SCALE_Y, height << 15); etna_set_state_fixp(ctx, VIVS_SE_SCISSOR_LEFT, 0); etna_set_state_fixp(ctx, VIVS_SE_SCISSOR_TOP, 0); etna_set_state_fixp(ctx, VIVS_SE_SCISSOR_RIGHT, (width << 16) | 5); etna_set_state_fixp(ctx, VIVS_SE_SCISSOR_BOTTOM, (height << 16) | 5); /* shader setup */ etna_set_state(ctx, VIVS_VS_END_PC, vs_size/16); etna_set_state_multi(ctx, VIVS_VS_INPUT_COUNT, 3, (uint32_t[]){ /* VIVS_VS_INPUT_COUNT */ (1<<8) | 2, /* VIVS_VS_TEMP_REGISTER_CONTROL */ VIVS_VS_TEMP_REGISTER_CONTROL_NUM_TEMPS(2), /* VIVS_VS_OUTPUT(0) */ 0x100}); etna_set_state(ctx, VIVS_VS_START_PC, 0x0); etna_set_state_f32(ctx, VIVS_VS_UNIFORMS(0), 0.5); /* u0.x */ etna_set_state_multi(ctx, VIVS_VS_INST_MEM(0), vs_size/4, vs); etna_set_state(ctx, VIVS_RA_CONTROL, 0x3); /* huh, this is 1 for the cubes */ etna_set_state_multi(ctx, VIVS_PS_END_PC, 2, (uint32_t[]){ /* VIVS_PS_END_PC */ ps_size/16, /* VIVS_PS_OUTPUT_REG */ 0x1}); etna_set_state(ctx, VIVS_PS_START_PC, 0x0); etna_set_state(ctx, VIVS_PA_SHADER_ATTRIBUTES(0), 0x200); etna_set_state(ctx, VIVS_GL_VARYING_NUM_COMPONENTS, /* one varying, with two components */ VIVS_GL_VARYING_NUM_COMPONENTS_VAR0(2) ); etna_set_state_multi(ctx, VIVS_GL_VARYING_COMPONENT_USE(0), 2, (uint32_t[]){ /* one varying, with four components */ VIVS_GL_VARYING_COMPONENT_USE_COMP0(VARYING_COMPONENT_USE_USED) | VIVS_GL_VARYING_COMPONENT_USE_COMP1(VARYING_COMPONENT_USE_USED) | VIVS_GL_VARYING_COMPONENT_USE_COMP2(VARYING_COMPONENT_USE_UNUSED) | VIVS_GL_VARYING_COMPONENT_USE_COMP3(VARYING_COMPONENT_USE_UNUSED) , 0 }); etna_set_state_f32(ctx, VIVS_PS_UNIFORMS(0), 0.0); /* u0.x */ etna_set_state_f32(ctx, VIVS_PS_UNIFORMS(1), 1.0); /* u0.y */ etna_set_state_f32(ctx, VIVS_PS_UNIFORMS(2), 0.5); /* u0.z */ etna_set_state_f32(ctx, VIVS_PS_UNIFORMS(3), 2.0); /* u0.w */ etna_set_state_f32(ctx, VIVS_PS_UNIFORMS(4), 1/256.0); /* u1.x */ etna_set_state_f32(ctx, VIVS_PS_UNIFORMS(5), 16.0); /* u1.y */ etna_set_state_f32(ctx, VIVS_PS_UNIFORMS(6), 10.0); /* u1.z */ etna_set_state_f32(ctx, VIVS_PS_UNIFORMS(8), frame); /* u2.x */ etna_set_state_multi(ctx, VIVS_PS_INST_MEM(0), ps_size/4, ps); etna_set_state(ctx, VIVS_PS_INPUT_COUNT, (31<<8)|2); etna_set_state(ctx, VIVS_PS_TEMP_REGISTER_CONTROL, VIVS_PS_TEMP_REGISTER_CONTROL_NUM_TEMPS(4)); etna_set_state(ctx, VIVS_PS_CONTROL, VIVS_PS_CONTROL_UNK1 ); etna_set_state(ctx, VIVS_PA_ATTRIBUTE_ELEMENT_COUNT, 0x100); etna_set_state(ctx, VIVS_GL_VARYING_TOTAL_COMPONENTS, /* one varying, with two components, must be changed together with GL_VARYING_NUM_COMPONENTS */ VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM(2) ); etna_set_state(ctx, VIVS_VS_LOAD_BALANCING, 0xf3f0582); etna_set_state(ctx, VIVS_VS_OUTPUT_COUNT, 2); etna_set_state(ctx, VIVS_PA_CONFIG, ETNA_MASKED_BIT(VIVS_PA_CONFIG_POINT_SIZE_ENABLE, 0)); etna_set_state(ctx, VIVS_FE_VERTEX_STREAM_BASE_ADDR, vtx->address); /* ADDR_E */ etna_set_state(ctx, VIVS_FE_VERTEX_STREAM_CONTROL, VIVS_FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE(0x14)); etna_set_state(ctx, VIVS_FE_VERTEX_ELEMENT_CONFIG(0), VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FLOAT | VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN(ENDIAN_MODE_NO_SWAP) | VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM(0) | VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM(3) | VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF | VIVS_FE_VERTEX_ELEMENT_CONFIG_START(0x0) | VIVS_FE_VERTEX_ELEMENT_CONFIG_END(0xc)); etna_set_state(ctx, VIVS_FE_VERTEX_ELEMENT_CONFIG(1), VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FLOAT | VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN(ENDIAN_MODE_NO_SWAP) | VIVS_FE_VERTEX_ELEMENT_CONFIG_NONCONSECUTIVE | VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM(0) | VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM(2) | VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF | VIVS_FE_VERTEX_ELEMENT_CONFIG_START(0xc) | VIVS_FE_VERTEX_ELEMENT_CONFIG_END(0x14)); etna_set_state(ctx, VIVS_VS_INPUT(0), 0x00100); /* 0x20000 in etna_cube */ etna_set_state(ctx, VIVS_PA_CONFIG, ETNA_MASKED_BIT(VIVS_PA_CONFIG_POINT_SPRITE_ENABLE, 0)); etna_draw_primitives(ctx, PRIMITIVE_TYPE_TRIANGLE_STRIP, 0, 2); etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH); /* Submit first command buffer */ etna_flush(ctx); etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH); etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH); etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH); etna_set_state(ctx, VIVS_RS_CONFIG, VIVS_RS_CONFIG_SOURCE_FORMAT(RS_FORMAT_A8R8G8B8) | VIVS_RS_CONFIG_SOURCE_TILED | VIVS_RS_CONFIG_DEST_FORMAT(RS_FORMAT_A8R8G8B8) | VIVS_RS_CONFIG_DEST_TILED); etna_set_state(ctx, VIVS_RS_SOURCE_STRIDE, (padded_width * 4 * 4) | VIVS_RS_SOURCE_STRIDE_TILING); etna_set_state(ctx, VIVS_RS_DEST_STRIDE, (padded_width * 4 * 4) | VIVS_RS_DEST_STRIDE_TILING); etna_set_state(ctx, VIVS_RS_DITHER(0), 0xffffffff); etna_set_state(ctx, VIVS_RS_DITHER(1), 0xffffffff); etna_set_state(ctx, VIVS_RS_CLEAR_CONTROL, VIVS_RS_CLEAR_CONTROL_MODE_DISABLED); etna_set_state(ctx, VIVS_RS_EXTRA_CONFIG, 0); /* no AA, no endian switch */ etna_set_state(ctx, VIVS_RS_SOURCE_ADDR, rt->address); /* ADDR_A */ etna_set_state(ctx, VIVS_RS_DEST_ADDR, rt->address); /* ADDR_A */ etna_set_state(ctx, VIVS_RS_WINDOW_SIZE, VIVS_RS_WINDOW_SIZE_HEIGHT(padded_height) | VIVS_RS_WINDOW_SIZE_WIDTH(padded_width)); etna_set_state(ctx, VIVS_RS_KICKER, 0xbeebbeeb); /* Submit second command buffer */ etna_flush(ctx); etna_warm_up_rs(ctx, aux_rt->address, aux_rt_ts->address); etna_set_state(ctx, VIVS_TS_COLOR_STATUS_BASE, rt_ts->address); /* ADDR_B */ etna_set_state(ctx, VIVS_TS_COLOR_SURFACE_BASE, rt->address); /* ADDR_A */ etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR); etna_set_state(ctx, VIVS_TS_MEM_CONFIG, VIVS_TS_MEM_CONFIG_DEPTH_FAST_CLEAR | VIVS_TS_MEM_CONFIG_DEPTH_16BPP | VIVS_TS_MEM_CONFIG_DEPTH_COMPRESSION); etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR); etna_set_state(ctx, VIVS_PE_COLOR_FORMAT, ETNA_MASKED_BIT(VIVS_PE_COLOR_FORMAT_OVERWRITE, 0)); /* Submit third command buffer, wait for pixel engine to finish */ etna_finish(ctx); etna_set_state(ctx, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH); etna_set_state(ctx, VIVS_RS_CONFIG, VIVS_RS_CONFIG_SOURCE_FORMAT(RS_FORMAT_A8R8G8B8) | VIVS_RS_CONFIG_SOURCE_TILED | VIVS_RS_CONFIG_DEST_FORMAT(RS_FORMAT_A8R8G8B8) /*| VIVS_RS_CONFIG_SWAP_RB*/); etna_set_state(ctx, VIVS_RS_SOURCE_STRIDE, (padded_width * 4 * 4) | VIVS_RS_SOURCE_STRIDE_TILING); etna_set_state(ctx, VIVS_RS_DEST_STRIDE, width * 4); etna_set_state(ctx, VIVS_RS_DITHER(0), 0xffffffff); etna_set_state(ctx, VIVS_RS_DITHER(1), 0xffffffff); etna_set_state(ctx, VIVS_RS_CLEAR_CONTROL, VIVS_RS_CLEAR_CONTROL_MODE_DISABLED); etna_set_state(ctx, VIVS_RS_EXTRA_CONFIG, 0); /* no AA, no endian switch */ etna_set_state(ctx, VIVS_RS_SOURCE_ADDR, rt->address); /* ADDR_A */ etna_set_state(ctx, VIVS_RS_DEST_ADDR, bmp->address); /* ADDR_J */ etna_set_state(ctx, VIVS_RS_WINDOW_SIZE, VIVS_RS_WINDOW_SIZE_HEIGHT(height) | VIVS_RS_WINDOW_SIZE_WIDTH(width)); etna_set_state(ctx, VIVS_RS_KICKER, 0xbeebbeeb); etna_finish(ctx); } if(argc>2) { printf("Dumping image to %s\n", argv[2]); bmp_dump32(bmp->logical, width, height, true, argv[2]); } /* Unlock video memory */ if(etna_vidmem_unlock(conn, bmp) != 0) { fprintf(stderr, "Cannot unlock vidmem\n"); exit(1); } etna_free(ctx); viv_close(conn); return 0; }