diff options
-rw-r--r-- | native/fb/Makefile | 7 | ||||
-rw-r--r-- | native/fb/cube_companion.c | 466 |
2 files changed, 469 insertions, 4 deletions
diff --git a/native/fb/Makefile b/native/fb/Makefile index 1faca47..03f43f8 100644 --- a/native/fb/Makefile +++ b/native/fb/Makefile @@ -7,7 +7,7 @@ CFLAGS += $(COMMON_FLAGS) CXXFLAGS += $(COMMON_FLAGS) LDFLAGS += -lm -TARGETS = mip_cube cubemap_sphere stencil_test alpha_blend +TARGETS = mip_cube cubemap_sphere stencil_test alpha_blend cube_companion COMPANION_OBJS = ../resources/companion_array.o ../resources/companion_mesh.o ../resources/companion_texture.o ETNA_OBJS = ../lib/viv.o ../lib/etna.o ../lib/etna_rs.o ../lib/etna_fb.o ../lib/etna_mem.o ../lib/etna_bswap.o ../lib/etna_tex.o ../lib/etna_pipe.o @@ -27,9 +27,8 @@ mip_cube: mip_cube.o ../lib/write_bmp.o ../lib/esTransform.o ../lib/dds.o $(ETNA cubemap_sphere: cubemap_sphere.o ../lib/write_bmp.o ../lib/esTransform.o ../lib/dds.o ../lib/esShapes.o $(ETNA_OBJS) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) -# XXX port this to etna_pipe -#cube_companion: cube_companion.o ../lib/write_bmp.o ../lib/esTransform.o $(COMPANION_OBJS) $(ETNA_OBJS) -# $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) +cube_companion: cube_companion.o ../lib/write_bmp.o ../lib/esTransform.o $(COMPANION_OBJS) $(ETNA_OBJS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) alpha_blend: alpha_blend.o ../lib/write_bmp.o ../lib/esTransform.o $(ETNA_OBJS) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) diff --git a/native/fb/cube_companion.c b/native/fb/cube_companion.c new file mode 100644 index 0000000..cd4dc17 --- /dev/null +++ b/native/fb/cube_companion.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2012-2013 Etnaviv Project + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* Animated rotating "weighted companion cube", using array or indexed rendering + * Exercised in this demo: + * - Array and indexed rendering of arbitrary mesh + * - Video memory allocation + * - Setting up render state + * - Depth buffer + * - Vertex / fragment shader + * - Texturing + * - Double-buffered rendering to framebuffer + * - Anti-aliasing (MSAA) + * + * Still TODO: + * - Mipmapping (hw generation, if possible) + */ +#define INDEXED + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <stdarg.h> +#include <assert.h> +#include <math.h> + +#include <errno.h> + +#include "etna_pipe.h" + +#include "etna/common.xml.h" +#include "etna/state.xml.h" +#include "etna/state_3d.xml.h" +#include "etna/cmdstream.xml.h" + +#include "write_bmp.h" +#include "viv.h" +#include "etna.h" +#include "etna_state.h" +#include "etna_rs.h" +#include "etna_fb.h" +#include "etna_bswap.h" +#include "etna_tex.h" + +#include "esTransform.h" +#include "dds.h" +#include "companion.h" + +/*********************************************************************/ +#define INDEXED /* Used indexed rendering */ +#define INDEX_BUFFER_SIZE 0x8000 +#define VERTEX_BUFFER_SIZE 0x60000 +uint32_t vs[] = { + 0x01831009, 0x00000000, 0x00000000, 0x203fc048, + 0x02031009, 0x00000000, 0x00000000, 0x203fc058, + 0x07841003, 0x39000800, 0x00000050, 0x00000000, + 0x07841002, 0x39001800, 0x00aa0050, 0x00390048, + 0x07841002, 0x39002800, 0x01540050, 0x00390048, + 0x07841002, 0x39003800, 0x01fe0050, 0x00390048, + 0x03851003, 0x29004800, 0x000000d0, 0x00000000, + 0x03851002, 0x29005800, 0x00aa00d0, 0x00290058, + 0x03811002, 0x29006800, 0x015400d0, 0x00290058, + 0x07851003, 0x39007800, 0x00000050, 0x00000000, + 0x07851002, 0x39008800, 0x00aa0050, 0x00390058, + 0x07851002, 0x39009800, 0x01540050, 0x00390058, + 0x07801002, 0x3900a800, 0x01fe0050, 0x00390058, + 0x0401100c, 0x00000000, 0x00000000, 0x003fc008, + 0x03801002, 0x69000800, 0x01fe00c0, 0x00290038, + 0x03831005, 0x29000800, 0x01480040, 0x00000000, + 0x0383100d, 0x00000000, 0x00000000, 0x00000038, + 0x03801003, 0x29000800, 0x014801c0, 0x00000000, + 0x00801005, 0x29001800, 0x01480040, 0x00000000, + 0x0380108f, 0x3fc06800, 0x00000050, 0x203fc068, + 0x04001009, 0x00000000, 0x00000000, 0x200000b8, + 0x01811009, 0x00000000, 0x00000000, 0x00150028, + 0x02041001, 0x2a804800, 0x00000000, 0x003fc048, + 0x02041003, 0x2a804800, 0x00aa05c0, 0x00000002, +}; +uint32_t ps[] = { /* texture sampling */ + 0x07811003, 0x00000800, 0x01c800d0, 0x00000000, + 0x07821018, 0x15002f20, 0x00000000, 0x00000000, + 0x07811003, 0x39001800, 0x01c80140, 0x00000000, +}; + +const struct etna_shader_program shader = { + .num_inputs = 3, + .inputs = {{.vs_reg=0},{.vs_reg=1},{.vs_reg=2}}, + .num_varyings = 2, + .varyings = { + {.num_components=4, .special=ETNA_VARYING_VSOUT, .pa_attributes=0x200, .vs_reg=0}, /* color */ + {.num_components=2, .special=ETNA_VARYING_VSOUT, .pa_attributes=0x200, .vs_reg=1} /* texcoord */ + }, + .vs_code_size = sizeof(vs)/4, + .vs_code = (uint32_t*)vs, + .vs_pos_out_reg = 4, // t4 out + .vs_load_balancing = 0xf3f0542, /* depends on number of inputs/outputs/varyings? XXX how exactly */ + .vs_num_temps = 6, + .vs_uniforms_size = 12*4, + .vs_uniforms = (uint32_t*)(const float[12*4]){ + [19] = 2.0f, /* u4.w */ + [23] = 20.0f, /* u5.w */ + [27] = 0.0f, /* u6.w */ + [45] = 0.5f, /* u11.y */ + [44] = 1.0f, /* u11.x */ + }, + .ps_code_size = sizeof(ps)/4, + .ps_code = (uint32_t*)ps, + .ps_color_out_reg = 1, // t1 out + .ps_num_temps = 3, + .ps_uniforms_size = 1*4, + .ps_uniforms = (uint32_t*)(const float[1*4]){ + [0] = 1.0f, + }, +}; + +inline void convert_r8g8b8_to_b8g8r8x8(uint32_t *dst, const uint8_t *src, unsigned num_pixels) +{ + for(unsigned idx=0; idx<num_pixels; ++idx) + { + dst[idx] = ((0xFF) << 24) | (src[idx*3+0] << 16) | (src[idx*3+1] << 8) | src[idx*3+2]; + } +} + +int main(int argc, char **argv) +{ + int rv; + int width = 256; + int height = 256; + + fb_info fb; + rv = fb_open(0, &fb); + if(rv!=0) + { + exit(1); + } + width = fb.fb_var.xres; + height = fb.fb_var.yres; + + rv = viv_open(); + if(rv!=0) + { + fprintf(stderr, "Error opening device\n"); + exit(1); + } + printf("Succesfully opened device\n"); + + etna_ctx *ctx = 0; + struct pipe_context *pipe = 0; + etna_bswap_buffers *buffers = 0; + if(etna_create(&ctx) != ETNA_OK || + etna_bswap_create(ctx, &buffers, (etna_set_buffer_cb_t)&fb_set_buffer, (etna_copy_buffer_cb_t)&etna_fb_copy_buffer, &fb) != ETNA_OK || + (pipe = etna_new_pipe_context(ctx)) == NULL) + { + printf("Unable to create etna context\n"); + exit(1); + } + + /* Convert and upload embedded texture */ + struct pipe_resource *tex_resource = etna_pipe_create_2d(pipe, ETNA_IS_TEXTURE, PIPE_FORMAT_B8G8R8X8_UNORM, + COMPANION_TEXTURE_WIDTH, COMPANION_TEXTURE_HEIGHT, 0); + void *temp = malloc(COMPANION_TEXTURE_WIDTH * COMPANION_TEXTURE_HEIGHT * 4); + convert_r8g8b8_to_b8g8r8x8(temp, (const uint8_t*)companion_texture, COMPANION_TEXTURE_WIDTH * COMPANION_TEXTURE_HEIGHT); + etna_pipe_inline_write(pipe, tex_resource, 0, 0, temp, COMPANION_TEXTURE_WIDTH * COMPANION_TEXTURE_HEIGHT * 4); + free(temp); + + /* resources */ + struct pipe_resource *rt_resource = etna_pipe_create_2d(pipe, ETNA_IS_RENDER_TARGET, PIPE_FORMAT_B8G8R8X8_UNORM, width, height, 0); + struct pipe_resource *z_resource = etna_pipe_create_2d(pipe, ETNA_IS_RENDER_TARGET, PIPE_FORMAT_Z16_UNORM, width, height, 0); + + /* bind render target to framebuffer */ + etna_fb_bind_resource(&fb, rt_resource); + + /* geometry */ + struct pipe_resource *vtx_resource = etna_pipe_create_buffer(pipe, ETNA_IS_VERTEX, VERTEX_BUFFER_SIZE); + struct pipe_resource *idx_resource = etna_pipe_create_buffer(pipe, ETNA_IS_INDEX, INDEX_BUFFER_SIZE); + + float *vtx_logical = etna_pipe_get_resource_ptr(pipe, vtx_resource, 0, 0); + assert(vtx_logical); + float *idx_logical = etna_pipe_get_resource_ptr(pipe, idx_resource, 0, 0); + assert(idx_logical); +#ifndef INDEXED + printf("Interleaving vertices...\n"); + float *vertices_array = companion_vertices_array(); + float *texture_coordinates_array = + companion_texture_coordinates_array(); + float *normals_array = companion_normals_array(); + assert(COMPANION_ARRAY_COUNT*(3+3+2)*sizeof(float) < VERTEX_BUFFER_SIZE); + for(int vert=0; vert<COMPANION_ARRAY_COUNT; ++vert) + { + int dest_idx = vert * (3 + 3 + 2); + for(int comp=0; comp<3; ++comp) + ((float*)vtx_logical)[dest_idx+comp+0] = vertices_array[vert*3 + comp]; /* 0 */ + for(int comp=0; comp<3; ++comp) + ((float*)vtx_logical)[dest_idx+comp+3] = normals_array[vert*3 + comp]; /* 1 */ + for(int comp=0; comp<2; ++comp) + ((float*)vtx_logical)[dest_idx+comp+6] = texture_coordinates_array[vert*2 + comp]; /* 2 */ + } +#else + printf("Interleaving vertices and copying index buffer...\n"); + assert(COMPANION_VERTEX_COUNT*(3+3+2)*sizeof(float) < VERTEX_BUFFER_SIZE); + for(int vert=0; vert<COMPANION_VERTEX_COUNT; ++vert) + { + int dest_idx = vert * (3 + 3 + 2); + for(int comp=0; comp<3; ++comp) + ((float*)vtx_logical)[dest_idx+comp+0] = companion_vertices[vert][comp]; /* 0 */ + for(int comp=0; comp<3; ++comp) + ((float*)vtx_logical)[dest_idx+comp+3] = companion_normals[vert][comp]; /* 1 */ + for(int comp=0; comp<2; ++comp) + ((float*)vtx_logical)[dest_idx+comp+6] = companion_texture_coordinates[vert][comp]; /* 2 */ + } + assert(COMPANION_TRIANGLE_COUNT*3*sizeof(unsigned short) < INDEX_BUFFER_SIZE); + memcpy(idx_logical, &companion_triangles[0][0], COMPANION_TRIANGLE_COUNT*3*sizeof(unsigned short)); +#endif + struct pipe_vertex_buffer vertex_buffer_desc = { + .stride = (3 + 3 + 2)*4, + .buffer_offset = 0, + .buffer = vtx_resource, + .user_buffer = 0 + }; + struct pipe_index_buffer index_buffer_desc = { + .index_size = sizeof(unsigned short), + .offset = 0, + .buffer = idx_resource, + .user_buffer = 0 + }; + struct pipe_vertex_element pipe_vertex_elements[] = { + { /* positions */ + .src_offset = 0, + .instance_divisor = 0, + .vertex_buffer_index = 0, + .src_format = PIPE_FORMAT_R32G32B32_FLOAT + }, + { /* normals */ + .src_offset = 0xc, + .instance_divisor = 0, + .vertex_buffer_index = 0, + .src_format = PIPE_FORMAT_R32G32B32_FLOAT + }, + { /* texture coord */ + .src_offset = 0x18, + .instance_divisor = 0, + .vertex_buffer_index = 0, + .src_format = PIPE_FORMAT_R32G32_FLOAT + } + }; + void *vertex_elements = pipe->create_vertex_elements_state(pipe, + sizeof(pipe_vertex_elements)/sizeof(pipe_vertex_elements[0]), pipe_vertex_elements); + + /* compile other gallium3d states */ + void *blend = pipe->create_blend_state(pipe, &(struct pipe_blend_state) { + .rt[0] = { + .blend_enable = 0, + .rgb_func = PIPE_BLEND_ADD, + .rgb_src_factor = PIPE_BLENDFACTOR_ONE, + .rgb_dst_factor = PIPE_BLENDFACTOR_ZERO, + .alpha_func = PIPE_BLEND_ADD, + .alpha_src_factor = PIPE_BLENDFACTOR_ONE, + .alpha_dst_factor = PIPE_BLENDFACTOR_ZERO, + .colormask = 0xf + } + }); + + void *sampler = pipe->create_sampler_state(pipe, &(struct pipe_sampler_state) { + .wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE, + .wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE, + .wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE, + .min_img_filter = PIPE_TEX_FILTER_LINEAR, + .min_mip_filter = PIPE_TEX_MIPFILTER_LINEAR, + .mag_img_filter = PIPE_TEX_FILTER_LINEAR, + .normalized_coords = 1, + .lod_bias = 0.0f, + .min_lod = 0.0f, .max_lod=1000.0f + }); + + void *rasterizer = pipe->create_rasterizer_state(pipe, &(struct pipe_rasterizer_state){ + .flatshade = 0, + .light_twoside = 1, + .clamp_vertex_color = 1, + .clamp_fragment_color = 1, + .front_ccw = 1, + .cull_face = PIPE_FACE_BACK, /**< PIPE_FACE_x */ + .fill_front = PIPE_POLYGON_MODE_FILL, /**< PIPE_POLYGON_MODE_x */ + .fill_back = PIPE_POLYGON_MODE_FILL, /**< PIPE_POLYGON_MODE_x */ + .offset_point = 0, + .offset_line = 0, + .offset_tri = 0, + .scissor = 0, + .poly_smooth = 1, + .poly_stipple_enable = 0, + .point_smooth = 0, + .sprite_coord_mode = 0, /**< PIPE_SPRITE_COORD_ */ + .point_quad_rasterization = 0, /** points rasterized as quads or points */ + .point_size_per_vertex = 0, /**< size computed in vertex shader */ + .multisample = 0, + .line_smooth = 0, + .line_stipple_enable = 0, + .line_last_pixel = 0, + .flatshade_first = 0, + .gl_rasterization_rules = 1, + .rasterizer_discard = 0, + .depth_clip = 0, + .clip_plane_enable = 0, + .line_stipple_factor = 0, + .line_stipple_pattern = 0, + .sprite_coord_enable = 0, + .line_width = 1.0f, + .point_size = 1.0f, + .offset_units = 0.0f, + .offset_scale = 0.0f, + .offset_clamp = 0.0f + }); + + void *dsa = pipe->create_depth_stencil_alpha_state(pipe, &(struct pipe_depth_stencil_alpha_state){ + .depth = { + .enabled = 1, + .writemask = 1, + .func = PIPE_FUNC_LESS /* GL default */ + }, + .stencil[0] = { + .enabled = 0 + }, + .stencil[1] = { + .enabled = 0 + }, + .alpha = { + .enabled = 0 + } + }); + + struct pipe_sampler_view *sampler_view = pipe->create_sampler_view(pipe, tex_resource, &(struct pipe_sampler_view){ + .format = tex_resource->format, + .u.tex.first_level = 0, + .u.tex.last_level = 0, + .swizzle_r = PIPE_SWIZZLE_RED, + .swizzle_g = PIPE_SWIZZLE_GREEN, + .swizzle_b = PIPE_SWIZZLE_BLUE, + .swizzle_a = PIPE_SWIZZLE_ALPHA, + }); + struct pipe_surface *cbuf = pipe->create_surface(pipe, rt_resource, &(struct pipe_surface){ + .texture = rt_resource, + .format = rt_resource->format, + .u.tex.level = 0 + }); + struct pipe_surface *zsbuf = pipe->create_surface(pipe, z_resource, &(struct pipe_surface){ + .texture = z_resource, + .format = z_resource->format, + .u.tex.level = 0 + }); + + /* bind */ + pipe->bind_blend_state(pipe, blend); + pipe->bind_fragment_sampler_states(pipe, 1, &sampler); + pipe->bind_rasterizer_state(pipe, rasterizer); + pipe->bind_depth_stencil_alpha_state(pipe, dsa); + pipe->bind_vertex_elements_state(pipe, vertex_elements); + + pipe->set_blend_color(pipe, &(struct pipe_blend_color){ + .color = {0.0f,0.0f,0.0f,1.0f} + }); + pipe->set_stencil_ref(pipe, &(struct pipe_stencil_ref){ + .ref_value[0] = 0xff, + .ref_value[1] = 0xff + }); + pipe->set_sample_mask(pipe, 0xf); + pipe->set_framebuffer_state(pipe, &(struct pipe_framebuffer_state){ + .width = width, + .height = height, + .nr_cbufs = 1, + .cbufs[0] = cbuf, + .zsbuf = zsbuf + }); + pipe->set_scissor_state(pipe, &(struct pipe_scissor_state){ + .minx = 0, + .miny = 0, + .maxx = 65535, + .maxy = 65535 + }); + pipe->set_viewport_state(pipe, &(struct pipe_viewport_state){ + .scale = {width/2.0f, height/2.0f, 0.5f, 1.0f}, + .translate = {width/2.0f, height/2.0f, 0.5f, 1.0f} + }); + pipe->set_fragment_sampler_views(pipe, 1, &sampler_view); + pipe->set_vertex_buffers(pipe, 0, 1, &vertex_buffer_desc); + pipe->set_index_buffer(pipe, &index_buffer_desc); + + void *shader_state = pipe->create_etna_shader_state(pipe, &shader); + pipe->bind_etna_shader_state(pipe, shader_state); + + for(int frame=0; frame<1000; ++frame) + { + if(frame%50 == 0) + printf("*** FRAME %i ****\n", frame); + /* Compute transform matrices in the same way as cube egl demo */ + ESMatrix modelview, projection, modelviewprojection; + ESMatrix inverse, normal; + esMatrixLoadIdentity(&modelview); + esTranslate(&modelview, 0.0f, 0.0f, -9.0f); + esRotate(&modelview, 45.0f, 1.0f, 0.0f, 0.0f); + esRotate(&modelview, 45.0f, 0.0f, 1.0f, 0.0f); + esRotate(&modelview, frame*0.5f, 0.0f, 0.0f, 1.0f); + esScale(&modelview, 0.475f, 0.475f, 0.475f); + GLfloat aspect = (GLfloat)(height) / (GLfloat)(width); + esMatrixLoadIdentity(&projection); + esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f); + esMatrixLoadIdentity(&modelviewprojection); + esMatrixMultiply(&modelviewprojection, &modelview, &projection); + esMatrixInverse3x3(&inverse, &modelview); + esMatrixTranspose(&normal, &inverse); + + /* Clear render target */ + pipe->clear(pipe, PIPE_CLEAR_COLOR | PIPE_CLEAR_DEPTHSTENCIL, &(const union pipe_color_union) { + .f = {0.2, 0.2, 0.2, 1.0} + }, 1.0, 0xff); + + pipe->set_etna_uniforms(pipe, shader_state, PIPE_SHADER_VERTEX, 0, 16, (uint32_t*)&modelviewprojection.m[0][0]); + pipe->set_etna_uniforms(pipe, shader_state, PIPE_SHADER_VERTEX, 16, 3, (uint32_t*)&normal.m[0][0]); /* u4.xyz */ + pipe->set_etna_uniforms(pipe, shader_state, PIPE_SHADER_VERTEX, 20, 3, (uint32_t*)&normal.m[1][0]); /* u5.xyz */ + pipe->set_etna_uniforms(pipe, shader_state, PIPE_SHADER_VERTEX, 24, 3, (uint32_t*)&normal.m[2][0]); /* u6.xyz */ + pipe->set_etna_uniforms(pipe, shader_state, PIPE_SHADER_VERTEX, 28, 16, (uint32_t*)&modelview.m[0][0]); + + pipe->draw_vbo(pipe, &(struct pipe_draw_info){ +#ifdef INDEXED + .indexed = 1, +#else + .indexed = 0, +#endif + .mode = PIPE_PRIM_TRIANGLES, + .start = 0, + .count = COMPANION_TRIANGLE_COUNT * 3 + }); + + etna_swap_buffers(buffers); + } +#ifdef DUMP + bmp_dump32(fb.logical[1-backbuffer], width, height, false, "/mnt/sdcard/fb.bmp"); + printf("Dump complete\n"); +#endif + etna_bswap_free(buffers); + etna_free(ctx); + viv_close(); + return 0; +} |