blob: 9cfca321a37dc5a65b42fe5dab1783013d6529d4 [file] [log] [blame]
/*
* 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;
}