blob: 269309f261a496d72b0548652a036ec808d4a6ee [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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <sys/stat.h>
#include <libspe2.h>
#include <mars/task.h>
#define INFO \
"\
MARS Task Grayscale Sample \n\
-------------------------- \n\
This program does grayscale image conversion of an input \n\
file ('%s') and outputs the resulting grayscale image to \n\
an output file ('%s'). \n\
\n\
The sample creates a single task instance of the main task 1 \n\
program that also creates %d task instances of the sub task 2 \n\
program that handles the actual processing of the grayscale \n\
conversion. The main task feeds data into a MARS task queue \n\
from which each sub task instance processes a portion of the \n\
input image data. Each sub task instance sets a unique bit in \n\
a MARS task event flag when processing is complete. When all \n\
tasks have completed processing and the main task receives the \n\
event signaling completion, the main task completes execution. \n\
\n", IN_FILENAME, OUT_FILENAME, NUM_TASKS
#define IN_FILENAME "in.ppm"
#define OUT_FILENAME "out.ppm"
#define PPM_MAGIC "P6"
#define NUM_TASKS 4
#define QUEUE_DEPTH 4
typedef struct _image_t {
int width;
int height;
unsigned char *src;
unsigned char *dst;
} image_t;
typedef struct {
uint64_t ea_task_id;
uint64_t ea_event;
uint64_t ea_queue;
uint64_t ea_src;
uint64_t ea_dst;
uint32_t num;
uint32_t pad;
} grayscale_params_t;
typedef struct {
uint64_t ea_event;
uint64_t ea_src;
uint64_t ea_dst;
uint32_t num;
uint32_t id;
} grayscale_queue_elem_t;
extern struct spe_program_handle mpu_task1_prog;
extern struct spe_program_handle mpu_task2_prog;
static struct mars_context *mars_ctx;
static struct mars_task_id task1_id;
static struct mars_task_id task2_id[NUM_TASKS] __attribute__((aligned(16)));
static struct mars_task_args task_args;
static uint64_t ea_event;
static uint64_t ea_queue;
static grayscale_params_t grayscale_params __attribute__((aligned(16)));
/* create MARS execution environment for rgb2y processing */
void rgb2y(unsigned char *src, unsigned char *dst, int num)
{
int ret, i;
ret = mars_context_create(&mars_ctx, 0, 0);
if (ret) {
printf("MARS context create failed! (%d)\n", ret);
exit(1);
}
ret = mars_task_event_flag_create(mars_ctx, &ea_event,
MARS_TASK_EVENT_FLAG_MPU_TO_MPU,
MARS_TASK_EVENT_FLAG_CLEAR_AUTO);
if (ret) {
printf("MARS task event flag create failed! (%d)\n", ret);
exit(1);
}
ret = mars_task_queue_create(mars_ctx, &ea_queue,
sizeof(grayscale_queue_elem_t),
QUEUE_DEPTH,
MARS_TASK_QUEUE_MPU_TO_MPU);
if (ret) {
printf("MARS task queue create failed! (%d)\n", ret);
exit(1);
}
ret = mars_task_create(mars_ctx, &task1_id, "Grayscale Main Task",
mpu_task1_prog.elf_image, MARS_TASK_CONTEXT_SAVE_SIZE_MAX);
if (ret) {
printf("MARS task 1 create failed! (%d)\n", ret);
exit(1);
}
for (i = 0; i < NUM_TASKS; i++) {
ret = mars_task_create(mars_ctx, &task2_id[i],
"Grayscale Sub Task", mpu_task2_prog.elf_image,
MARS_TASK_CONTEXT_SAVE_SIZE_MAX);
if (ret) {
printf("MARS task 2 create failed! (%d)\n", ret);
exit(1);
}
}
grayscale_params.ea_task_id = mars_ptr_to_ea(&task2_id);
grayscale_params.ea_event = ea_event;
grayscale_params.ea_queue = ea_queue;
grayscale_params.ea_src = mars_ptr_to_ea(src);
grayscale_params.ea_dst = mars_ptr_to_ea(dst);
grayscale_params.num = num;
task_args.type.u64[0] = mars_ptr_to_ea(&grayscale_params);
ret = mars_task_schedule(&task1_id, &task_args, 0);
if (ret) {
printf("MARS task 1 schedule failed! (%d)\n", ret);
exit(1);
}
ret = mars_task_wait(&task1_id, NULL);
if (ret) {
printf("MARS task 1 wait failed! (%d)\n", ret);
exit(1);
}
ret = mars_task_destroy(&task1_id);
if (ret) {
printf("MARS task 1 destroy failed! (%d)\n", ret);
exit(1);
}
for (i = 0; i < NUM_TASKS; i++) {
ret = mars_task_destroy(&task2_id[i]);
if (ret) {
printf("MARS task 2 destroy failed! (%d)\n", ret);
exit(1);
}
}
ret = mars_task_event_flag_destroy(ea_event);
if (ret) {
printf("MARS task event flag destroy failed! (%d)\n", ret);
exit(1);
}
ret = mars_task_queue_destroy(ea_queue);
if (ret) {
printf("MARS task queue destroy failed! (%d)\n", ret);
exit(1);
}
ret = mars_context_destroy(mars_ctx);
if (ret) {
printf("MARS context destroy failed! (%d)\n", ret);
exit(1);
}
}
/* read ppm data from input file */
void read_ppm(image_t *img, char *fname)
{
char *token, *pc, *buf, *del = " \t\n";
int i, w, h, luma, pixs, filesize;
struct stat st;
unsigned char *dot;
FILE *fp;
/* read raw data */
stat(fname, &st);
filesize = (int) st.st_size;
buf = (char *) malloc(filesize * sizeof(char));
if ((fp = fopen(fname, "r")) == NULL) {
fprintf(stderr, "error: failed to open file %s\n", fname);
exit(1);
}
fseek(fp, 0, SEEK_SET);
fread(buf, filesize * sizeof(char), 1, fp);
fclose(fp);
/* validate file format */
token = (char *) (unsigned long) strtok(buf, del);
if (strncmp(token, PPM_MAGIC, 2) != 0) {
fprintf(stderr, "error: invalid file format\n");
exit(1);
}
/* skip comments */
token = (char *) (unsigned long) strtok(NULL, del);
if (token[0] == '#') {
token = (char *) (unsigned long) strtok(NULL, "\n");
token = (char *) (unsigned long) strtok(NULL, del);
}
/* read picture size (and luma) */
w = strtoul(token, &pc, 10);
token = (char *) (unsigned long) strtok(NULL, del);
h = strtoul(token, &pc, 10);
token = (char *) (unsigned long) strtok(NULL, del);
luma = strtoul(token, &pc, 10);
img->width = w;
img->height = h;
/* allocate an aligned memory */
pixs = w * h;
img->src = (unsigned char *)memalign(16, pixs*4);
img->dst = (unsigned char *)memalign(16, pixs*4);
/* read rgb data with 'r,g,b,0' formatted */
dot = img->src;
pc++;
for (i = 0; i < pixs*4; i++) {
if (i % 4 == 3) {
*dot++ = 0;
} else {
*dot++ = *pc++;
}
}
return;
}
/* write ppm data to output file */
void write_ppm(image_t *img, char *fname)
{
int i;
int w = img->width;
int h = img->height;
unsigned char *dot = img->dst;
FILE *fp;
if ((fp = fopen(fname, "wb+")) == NULL) {
fprintf(stderr, "failed to open file %s\n", fname);
exit(1);
}
fprintf(fp, "%s\n", PPM_MAGIC);
fprintf(fp, "%d %d\n", w, h);
fprintf(fp, "255\n");
for (i = 0; i < (w * h * 4); i++) {
if (i % 4 == 3) {
dot++;
} else {
putc((int) *dot++, fp);
}
}
fclose(fp);
return;
}
void delete_image(image_t *img)
{
free(img->src);
free(img->dst);
return;
}
int main(int argc, char **argv)
{
image_t image;
printf(INFO);
read_ppm(&image, IN_FILENAME);
rgb2y(image.src, image.dst, image.width * image.height);
write_ppm(&image, OUT_FILENAME);
delete_image(&image);
return 0;
}