| /* |
| * Copyright 2008 Sony Corporation of America |
| * |
| * |
| * 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, sublicense, 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 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 NONINFRINGEMENT. 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. |
| */ |
| |
| #include <stdlib.h> |
| #include <termios.h> |
| #include <sys/time.h> |
| #include <libspe2.h> |
| #include <mars/task.h> |
| #include "mpu_mandelbrot.h" |
| #include "mpu_grayscale.h" |
| #include "host_vfb.h" |
| |
| #define INFO \ |
| "\ |
| MARS Task Mandelbrot Sample \n\ |
| ------------------------ \n\ |
| This program is an example of a mandelbrot explorer. \n\ |
| For the purposes of this sample, rendering to the frame buffer \n\ |
| is disabled. \n\ |
| \n\ |
| The sample creates %d task instances for the mandelbrot \n\ |
| calculation and %d task instances for the grayscale conversion \n\ |
| of each frame and a total of %d frames. \n\ |
| \n\ |
| Please wait... \n\ |
| \n", NUM_TASKS, NUM_TASKS, NUM_FRAMES |
| |
| #define USE_MARS 1 |
| #define USE_INPUT 0 |
| #define USE_VFB 0 |
| |
| #define NUM_TASKS 128 |
| #define NUM_FRAMES 1000 |
| #define NUM_ITERATIONS 1000 |
| |
| #define TEXTURE_WIDTH 640 |
| #define TEXTURE_HEIGHT 480 |
| #define TEXTURE_SIZE TEXTURE_WIDTH * TEXTURE_HEIGHT * VFB_BPP |
| |
| #define ZOOM_INIT 2.0 |
| #define ZOOM_FACTOR 0.99 |
| |
| #if USE_INPUT |
| #define CENTER_X 0 |
| #define CENTER_Y 0 |
| #else |
| #define CENTER_X -1.2 |
| #define CENTER_Y -0.155 |
| #endif |
| |
| #define TIMER_START(timer)\ |
| {\ |
| struct timeval tv;\ |
| gettimeofday(&tv, NULL);\ |
| timer = tv.tv_sec * 1000000 + tv.tv_usec;\ |
| } |
| |
| #define TIMER_STOP(timer)\ |
| {\ |
| struct timeval tv;\ |
| gettimeofday(&tv, NULL);\ |
| timer = tv.tv_sec * 1000000 + tv.tv_usec - timer;\ |
| } |
| |
| static vfb_t vfb; |
| static struct termios ios, saved_ios; |
| static unsigned char mandelbrot_buffer[TEXTURE_SIZE] __attribute__((aligned(128))); |
| static unsigned char grayscale_buffer[TEXTURE_SIZE] __attribute__((aligned(128))); |
| static float center_x = CENTER_X; |
| static float center_y = CENTER_Y; |
| static float zoom = ZOOM_INIT; |
| |
| #if USE_MARS |
| extern struct spe_program_handle mpu_mandelbrot_prog; |
| extern struct spe_program_handle mpu_grayscale_prog; |
| |
| static struct mars_context *mars_ctx; |
| static struct mars_task_args task_args; |
| |
| static struct mars_task_id mandelbrot_task_id[NUM_TASKS]; |
| static struct mandelbrot_params mandelbrot_params[NUM_TASKS]; |
| |
| static struct mars_task_id grayscale_task_id[NUM_TASKS]; |
| static struct grayscale_params grayscale_params[NUM_TASKS]; |
| #endif |
| |
| static inline unsigned int color_lookup(unsigned int n, unsigned int max) |
| { |
| return (n == max) ? 0 : (n << 10) + n * 10; |
| } |
| |
| static inline unsigned int get_pixel_color(float x0, float y0, |
| unsigned int max_iterations) |
| { |
| float x = x0; |
| float y = y0; |
| unsigned int iteration; |
| |
| for (iteration = 0; iteration < max_iterations; iteration++) { |
| float xtemp, ytemp; |
| float x2 = x * x; |
| float y2 = y * y; |
| |
| if (x2 + y2 >= 4) |
| break; |
| |
| xtemp = x2 - y2 + x0; |
| ytemp = 2 * x * y + y0; |
| |
| x = xtemp; |
| y = ytemp; |
| } |
| |
| return color_lookup(iteration, max_iterations); |
| } |
| |
| static inline void process_mandelbrot(void) |
| { |
| unsigned int *buffer = (unsigned int *)mandelbrot_buffer; |
| unsigned int buffer_w = TEXTURE_WIDTH; |
| unsigned int buffer_h = TEXTURE_HEIGHT; |
| unsigned int max_iterations = NUM_ITERATIONS; |
| |
| float xmin = center_x - zoom; |
| float xmax = center_x + zoom; |
| float ymin = center_y - zoom; |
| float ymax = center_y + zoom; |
| |
| #if USE_MARS |
| int ret; |
| unsigned int i; |
| unsigned int lines_per_task = buffer_h / NUM_TASKS; |
| |
| for (i = 0; i < NUM_TASKS; i++) { |
| mandelbrot_params[i].buffer_ea = (uint64_t)(uintptr_t) |
| (buffer + buffer_w * lines_per_task * i); |
| mandelbrot_params[i].buffer_w = buffer_w; |
| mandelbrot_params[i].buffer_h = buffer_h; |
| mandelbrot_params[i].line_index = lines_per_task * i; |
| mandelbrot_params[i].line_count = lines_per_task; |
| mandelbrot_params[i].max_iterations = max_iterations; |
| mandelbrot_params[i].xmin = xmin; |
| mandelbrot_params[i].xmax = xmax; |
| mandelbrot_params[i].ymin = ymin; |
| mandelbrot_params[i].ymax = ymax; |
| |
| task_args.type.u64[0] = mars_ptr_to_ea(&mandelbrot_params[i]); |
| ret = mars_task_schedule(&mandelbrot_task_id[i], &task_args, 0); |
| if (ret) { |
| printf("MARS task schedule failed! (%d)\n", ret); |
| exit(1); |
| } |
| } |
| |
| for (i = 0; i < NUM_TASKS; i++) { |
| ret = mars_task_wait(&mandelbrot_task_id[i], NULL); |
| if (ret) { |
| printf("MARS task wait failed! (%d)\n", ret); |
| exit(1); |
| } |
| } |
| #else |
| unsigned int i, j; |
| float dx = (xmax - xmin) / buffer_w; |
| float dy = (ymax - ymin) / buffer_h; |
| float y = ymin; |
| |
| for (i = 0; i < buffer_h; i++) { |
| float x = xmin; |
| |
| for (j = 0; j < buffer_w; j++) { |
| *buffer = get_pixel_color(x, y, max_iterations); |
| buffer++; |
| |
| x += dx; |
| } |
| |
| y += dy; |
| } |
| #endif |
| } |
| |
| static inline void process_grayscale() |
| { |
| unsigned char *src = mandelbrot_buffer; |
| unsigned char *dst = grayscale_buffer; |
| |
| #if USE_MARS |
| int ret; |
| unsigned int buffer_w = TEXTURE_WIDTH; |
| unsigned int buffer_h = TEXTURE_HEIGHT; |
| unsigned int lines_per_task = buffer_h / NUM_TASKS; |
| unsigned int i; |
| |
| for (i = 0; i < NUM_TASKS; i++) { |
| grayscale_params[i].src_buffer_ea = (uint64_t)(uintptr_t) |
| (src + buffer_w * lines_per_task * i * sizeof(unsigned int)); |
| grayscale_params[i].dst_buffer_ea = (uint64_t)(uintptr_t) |
| (dst + buffer_w * lines_per_task * i * sizeof(unsigned int)); |
| grayscale_params[i].buffer_w = buffer_w; |
| grayscale_params[i].buffer_h = buffer_h; |
| grayscale_params[i].line_index = lines_per_task * i; |
| grayscale_params[i].line_count = lines_per_task; |
| |
| task_args.type.u64[0] = mars_ptr_to_ea(&grayscale_params[i]); |
| ret = mars_task_schedule(&grayscale_task_id[i], &task_args, 0); |
| if (ret) { |
| printf("MARS task schedule failed! (%d)\n", ret); |
| exit(1); |
| } |
| } |
| |
| for (i = 0; i < NUM_TASKS; i++) { |
| ret = mars_task_wait(&grayscale_task_id[i], NULL); |
| if (ret) { |
| printf("MARS task wait failed! (%d)\n", ret); |
| exit(1); |
| } |
| } |
| #else |
| static float rconst = 0.29891f; |
| static float gconst = 0.58661f; |
| static float bconst = 0.11448f; |
| float r, g, b, y; |
| int i; |
| |
| for (i = 0; i < TEXTURE_WIDTH * TEXTURE_HEIGHT; i++) { |
| r = (float)src[i * 4 + 1]; |
| g = (float)src[i * 4 + 2]; |
| b = (float)src[i * 4 + 3]; |
| |
| y = r * rconst + g * gconst + b * bconst; |
| y = y < 0xff ? y : 0xff; |
| |
| dst[i * 4 + 1] = dst[i * 4 + 2] = dst[i * 4 + 3] = (unsigned char)y; |
| } |
| #endif |
| } |
| |
| static inline void process_vfb_pass(int frame, unsigned int x, unsigned int y, |
| unsigned char *texture_buffer) |
| { |
| unsigned int vfb_size = vfb.xres * vfb.yres * VFB_BPP; |
| unsigned char *vfb_buffer = vfb.addr + vfb_size * frame; |
| |
| unsigned int *vfb_ptr = |
| (unsigned int *)vfb_buffer + y * vfb.xres + x; |
| unsigned int *tex_ptr = |
| (unsigned int *)texture_buffer; |
| |
| unsigned int i; |
| |
| for (i = 0; i < TEXTURE_HEIGHT; i++) { |
| memcpy(vfb_ptr, tex_ptr, TEXTURE_WIDTH * sizeof(unsigned int)); |
| vfb_ptr += vfb.xres; |
| tex_ptr += TEXTURE_WIDTH; |
| } |
| } |
| |
| static inline void process_vfb(int frame) |
| { |
| unsigned int x; |
| unsigned int y; |
| |
| /* pass 1 */ |
| x = (vfb.xres - TEXTURE_WIDTH) / 2 - 340; |
| y = (vfb.yres - TEXTURE_HEIGHT) / 2 - 210; |
| process_vfb_pass(frame, x, y, mandelbrot_buffer); |
| |
| /* pass 2 */ |
| x = (vfb.xres - TEXTURE_WIDTH) / 2 + 340; |
| y = (vfb.yres - TEXTURE_HEIGHT) / 2 - 210; |
| process_vfb_pass(frame, x, y, grayscale_buffer); |
| |
| /* pass 3 */ |
| x = (vfb.xres - TEXTURE_WIDTH) / 2 - 340; |
| y = (vfb.yres - TEXTURE_HEIGHT) / 2 + 210; |
| process_vfb_pass(frame, x, y, grayscale_buffer); |
| |
| /* pass 4 */ |
| x = (vfb.xres - TEXTURE_WIDTH) / 2 + 340; |
| y = (vfb.yres - TEXTURE_HEIGHT) / 2 + 210; |
| process_vfb_pass(frame, x, y, mandelbrot_buffer); |
| |
| vfb_flip(&vfb, frame % 2); |
| } |
| |
| static inline void input_init() |
| { |
| tcgetattr(0, &saved_ios); |
| ios = saved_ios; |
| ios.c_lflag &= ~ISIG; /* don't enable signals */ |
| ios.c_lflag &= ~ICANON;/* don't do canonical input */ |
| ios.c_lflag &= ~ECHO; /* don't echo */ |
| ios.c_iflag &= ~INLCR; /* don't convert nl to cr */ |
| ios.c_iflag &= ~IGNCR; /* don't ignore cr */ |
| ios.c_iflag &= ~ICRNL; /* don't convert cr to nl */ |
| ios.c_iflag &= ~IUCLC; /* don't map upper to lower */ |
| ios.c_iflag &= ~IXON; /* don't enable ^S/^Q on output */ |
| ios.c_iflag &= ~IXOFF; /* don't enable ^S/^Q on input */ |
| ios.c_oflag &= ~OPOST; /* don't enable output processing */ |
| ios.c_cc[VMIN] = 0; |
| ios.c_cc[VTIME] = 1; |
| tcsetattr(0, TCSANOW, &ios); |
| } |
| |
| static inline void input_exit() |
| { |
| tcsetattr(0, TCSANOW, &saved_ios); |
| } |
| |
| static inline int process_input() |
| { |
| int input_ready; |
| unsigned char input; |
| |
| do { |
| struct timeval tv; |
| fd_set read_fd; |
| |
| FD_ZERO(&read_fd); |
| FD_SET(0, &read_fd); |
| |
| tv.tv_sec = 0; |
| tv.tv_usec = 0; |
| |
| select(1, &read_fd, NULL, NULL, &tv); |
| |
| input_ready = FD_ISSET(0, &read_fd) ? 1 : 0; |
| } while (!input_ready); |
| |
| read(0, &input, 1); |
| |
| switch (input) { |
| case 'w': |
| center_y -= 0.01f * zoom; |
| break; |
| case 's': |
| center_y += 0.01f * zoom; |
| break; |
| case 'a': |
| center_x -= 0.01f * zoom; |
| break; |
| case 'd': |
| center_x += 0.01f * zoom; |
| break; |
| case 'z': |
| zoom *= 0.99f; |
| break; |
| case 'x': |
| zoom *= 1.01f; |
| break; |
| case 'q': |
| return 0; |
| default: |
| break; |
| } |
| |
| return 1; |
| } |
| |
| int main(void) |
| { |
| int ret; |
| unsigned int i, frame = 0; |
| |
| printf(INFO); |
| |
| #if USE_MARS |
| ret = mars_context_create(&mars_ctx, 0, 0); |
| if (ret) { |
| printf("MARS context create failed! (%d)\n", ret); |
| return 1; |
| } |
| |
| for (i = 0; i < NUM_TASKS; i++) { |
| ret = mars_task_create(mars_ctx, &mandelbrot_task_id[i], |
| "mandelbrot", mpu_mandelbrot_prog.elf_image, 0); |
| if (ret) { |
| printf("MARS task create failed! (%d)\n", ret); |
| return 1; |
| } |
| } |
| |
| for (i = 0; i < NUM_TASKS; i++) { |
| ret = mars_task_create(mars_ctx, &grayscale_task_id[i], |
| "grayscale", mpu_grayscale_prog.elf_image, 0); |
| if (ret) { |
| printf("MARS task create failed! (%d)\n", ret); |
| return 1; |
| } |
| } |
| #endif |
| |
| #if USE_VFB |
| vfb_open(&vfb); |
| vfb_clear(&vfb); |
| #endif |
| |
| #if USE_INPUT |
| input_init(); |
| |
| do { |
| process_mandelbrot(); |
| process_grayscale(); |
| #if USE_VFB |
| process_vfb(0); |
| //process_vfb(frame % 2); |
| #endif |
| frame++; |
| |
| } while (process_input()); |
| |
| input_exit(); |
| #else |
| unsigned long long timer; |
| TIMER_START(timer); |
| |
| for (frame = 0; frame < NUM_FRAMES; frame++) { |
| zoom *= ZOOM_FACTOR; |
| process_mandelbrot(); |
| process_grayscale(); |
| #if USE_VFB |
| process_vfb(0); |
| //process_vfb(frame % 2); |
| #endif |
| }; |
| |
| TIMER_STOP(timer); |
| printf("%f sec\n", (float)timer * 1.0e-6); |
| #endif |
| |
| #if USE_VFB |
| vfb_clear(&vfb); |
| vfb_close(&vfb); |
| #endif |
| |
| #if USE_MARS |
| for (i = 0; i < NUM_TASKS; i++) { |
| ret = mars_task_destroy(&mandelbrot_task_id[i]); |
| if (ret) { |
| printf("MARS task destroy failed! (%d)\n", ret); |
| return 1; |
| } |
| } |
| |
| for (i = 0; i < NUM_TASKS; i++) { |
| ret = mars_task_destroy(&grayscale_task_id[i]); |
| if (ret) { |
| printf("MARS task create failed! (%d)\n", ret); |
| return 1; |
| } |
| } |
| |
| ret = mars_context_destroy(mars_ctx); |
| if (ret) { |
| printf("MARS context destroy failed! (%d)\n", ret); |
| return 1; |
| } |
| #endif |
| |
| return 0; |
| } |