Index: libvo/spe/vo_fbdevps3_yuv2rgb.c =================================================================== --- libvo/spe/vo_fbdevps3_yuv2rgb.c (revision 0) +++ libvo/spe/vo_fbdevps3_yuv2rgb.c (revision 0) @@ -0,0 +1,354 @@ +/* + * YUV 2 RGB converter + * Copyright (c) 2007 Rasmus Rohde + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This progam is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include + +#include "yuv_datastructs.h" + +int main(unsigned long long spe_id, unsigned long long program_data_ea, + unsigned long long env) { + img_args pd __attribute__((aligned(16))); + unsigned long long Yin; + unsigned long long Uin; + unsigned long long Vin; + unsigned long long Output; + + vector unsigned char *YtempA1, *YtempB1, *YtempA2, *YtempB2; + vector unsigned char *UtempA, *UtempB; + vector unsigned char *VtempA, *VtempB; + vector unsigned char *OutA1, *OutA2, *OutB1, *OutB2; + + int i, x, y; + int width, height, widthdiv16; + + int mbox_val; + int tag_id_input_yA = 1; + int tag_id_input_yB = 2; + int tag_id_input_uvA = 4; + int tag_id_input_uvB = 8; + int tag_id_output = 16; + + //Initiate copy + mfc_get(&pd, program_data_ea, sizeof(pd), tag_id_input_yA, 0, 0); + //Wait for completion + mfc_write_tag_mask(1< + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This progam is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __YUV_DATASTRUCTS_H +#define __YUV_DATASTRUCTS_H + +typedef struct { + int width; + int height; + unsigned long long Ystart[2]; + unsigned long long Ustart[2]; + unsigned long long Vstart[2]; + unsigned long long Output[2]; +} __attribute__((aligned(16))) img_args; + +#endif + Index: libvo/spe/vo_fbdevps3_scaler.c =================================================================== --- libvo/spe/vo_fbdevps3_scaler.c (revision 0) +++ libvo/spe/vo_fbdevps3_scaler.c (revision 0) @@ -0,0 +1,372 @@ +/* + * RGB bilinear scaler + * Copyright (c) 2007 Rasmus Rohde + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This progam is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include + +typedef struct { + unsigned long long in[2]; + unsigned long long out[2]; + + unsigned int in_width; // Must be a multiple of 4 + float scale; + unsigned int out_height; + unsigned int out_width_total; // Must be a multiple of 4 + unsigned int out_width_overscan; // Must be a multiple of 4 +} __attribute__((aligned(16))) spe_data; + +static inline void pixels_to_svector(vector unsigned char *pixels, + vector unsigned short *dst); + +/* + Bilinear scaler. Input must be 24-bit RGB where unsigned char in[0] = 0, + in[1] = red, in[2] = green, in[3] = blue. + + Output will be in the same format. + + To quit the SPE thread write a number <= 0 in its mailbox. + To scale to out[0] from in[0] write 1 in its mailbox and write 2 + to use out[1] from in[1] + + A zero will be written to the interrupt mailbox when a new frame is ready + to be received. + + Compile with -funroll-loops -O4 for best performance. + */ +int main(unsigned long long spe_id, unsigned long long program_data_ea, + unsigned long long env) { + vector unsigned char *temp_output_vec; + vector unsigned short *in_line_temp; + vector unsigned short *hscaled_line; + vector unsigned char *in_line_dma_buf; + vector unsigned short *hfilter, *hfilterPos; + unsigned short *vfilter, *vfilterPos; + + spe_data pd __attribute__((aligned(16))); + + unsigned int yc __attribute__((aligned(16))); + unsigned int xc __attribute__((aligned(16))); + unsigned int out_height __attribute__((aligned(16))); + unsigned int out_width_total __attribute__((aligned(16))); + unsigned int out_width __attribute__((aligned(16))); + float scale __attribute__((aligned(16))); + + unsigned int width8x __attribute__((aligned(16))); + + vector unsigned char extract_pix = {0x80, 0x80, 0x80, 0x80, 0x80, 5, + 0x80, 21, 0x80, 9, 0x80, 25, 0x80, + 13, 0x80, 29}; + + int tag_id_input = 1; + int tag_id_output = 2; + + //Initiate copy + mfc_get(&pd, program_data_ea, sizeof(pd), tag_id_input, 0, 0); + //Wait for completion + mfc_write_tag_mask(1<= 65536) + w = 65535; + tempPos[yc] = ipos; + temp[yc*2] = 65536-w; + temp[yc*2+1] = w; + } + hfilterPos[xc/8] = *(vector unsigned short *)tempPos; + hfilter[xc/4] = *(vector unsigned short *)temp; + hfilter[xc/4+1] = *(vector unsigned short *)&temp[8]; + } + + for(yc=0; yc= 65536) + w = 65535; + + vfilterPos[yc] = ipos; + vfilter[yc*2] = 65536-w; + vfilter[yc*2+1] = w; + } + + do { + int pixel_y, dma_data_ready; + int line_in_use_dma_buf = 0; + int hscaled_line_in_use = 0; + vector unsigned short *next_hscaled_line = hscaled_line; + vector unsigned char *next_in_line_dma_buf = in_line_dma_buf; + int last_transferred_line; + int last_converted_line; + int mbox_val; + unsigned long long in __attribute__((aligned(16))); + unsigned long long out __attribute__((aligned(16))); + unsigned long long in_temp; + vector unsigned short *hline1 = hscaled_line; + vector unsigned short *hline2 = hscaled_line+out_width/2; + + // Wait for completion from possible previous transfer + mfc_write_tag_mask(1<= last_converted_line) { + int i; + // Ok - we need to do some work since we are + // missing the next lines. + // First make sure the dma transfer is done + if(dma_data_ready) { + mfc_write_tag_mask(1<= last_transferred_line && + yc+2 < out_height) { + // Start transfer of the next 2 lines + mfc_get(in_line_dma_buf, in_temp, width8x, + tag_id_input, 0, 0); + in_temp += width8x; + + if(pixel_y > last_transferred_line) { + // Make absolutely sure we get 2 + // conversions next time + last_converted_line = pixel_y - 1; + } + + last_transferred_line += 2; + dma_data_ready = 1; + } + + vector unsigned short w1 = spu_splats(vfilter[yc*2]); + vector unsigned short w2 = spu_splats(vfilter[yc*2+1]); + + for(xc=0; xc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This progam is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include + + +#include "video_out.h" +#include "video_out_internal.h" +#include "mp_msg.h" + +#include "spe/yuv_datastructs.h" + +// ugly yet simple workaround +#ifndef _PS3FB_H_ +#define _PS3FB_H_ + +/* ioctl */ +#define PS3FB_IOCTL_SETMODE _IOW('r', 1, int) /* set video mode */ +#define PS3FB_IOCTL_GETMODE _IOR('r', 2, int) /* get video mode */ +#define PS3FB_IOCTL_SCREENINFO _IOR('r', 3, int) /* get screen info */ +#define PS3FB_IOCTL_ON _IO('r', 4) /* use IOCTL_FSEL */ +#define PS3FB_IOCTL_OFF _IO('r', 5) /* return to normal-flip */ +#define PS3FB_IOCTL_FSEL _IOW('r', 6, int) /* blit and flip request */ + +#ifndef FBIO_WAITFORVSYNC +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, uint32_t) /* wait for vsync */ +#endif + +struct ps3fb_ioctl_res { + uint32_t xres; /* frame buffer x_size */ + uint32_t yres; /* frame buffer y_size */ + uint32_t xoff; /* margine x */ + uint32_t yoff; /* margine y */ + uint32_t num_frames; /* num of frame buffers */ +}; + +#endif /* _PS3FB_H_ */ + +static vo_info_t info = { + "Framebuffer Device", + "fbdevps3", + "Rasmus Rohde ", + "" +}; + +LIBVO_EXTERN(fbdevps3) + +extern spe_program_handle_t vo_fbdevps3_scaler; +extern spe_program_handle_t vo_fbdevps3_yuv2rgb; + +static const char *spe_yuv2rgb_filename = "vo_fbdevps3_yuv2rgb"; +static const char *spe_scaler_filename = "vo_fbdevps3_scaler"; +static const char *fb_dev_name = "/dev/fb0"; +static int fb_dev_fd; +struct ps3fb_ioctl_res res; +static struct fb_var_screeninfo fb_vinfo; +static struct fb_fix_screeninfo fb_finfo; +static int fb_tty_fd; + +static int fb_line_len; +static size_t fb_size; +static void *frame_buffer; +static void *center; + +static int fb_pixel_size; +static int in_width; +static int in_height; +static uint32_t img_format; + +static unsigned int fb_page; + +/* Here comes data for the SPU yuv2rgb */ +static int init_spu_yuv2rgb(int w, int h); +static spe_context_ptr_t spe_context_yuv2rgb; +static spe_event_handler_ptr_t spe_event_yuv2rgb; +static img_args *pd_yuv2rgb; +static int yuv_thread_running; + + +/* Here comes data for the SPU scaler and blitter */ +static int init_spu_scaler(int orig_w, int w, int h); +static spe_context_ptr_t spe_context_scaler; +static spe_event_handler_ptr_t spe_event_scaler; +static int spe_init_done_scaler; +static int spe_init_done_yuv2rgb; +static int scaler_thread_running; + +typedef struct { + unsigned long long in[2]; + unsigned long long out[2]; + + unsigned int in_width; // Must be a multiple of 4 + float scale; + unsigned int out_height; + unsigned int out_width_total; // Must be a multiple of 4 + unsigned int out_width_overscan; // Must be a multiple of 4 +} __attribute__((aligned(16))) spe_data_scaler; + +static spe_data_scaler *pd_scaler; +static uint8_t *temp_input; +static uint8_t *temp_input_yuv; + +static int preinit(const char *vo_subdevice) +{ + if ((fb_dev_fd = open(fb_dev_name, O_RDWR)) == -1) { + mp_msg(MSGT_VO, MSGL_ERR, "Can't open %s: %s\n", + fb_dev_name, strerror(errno)); + goto err_out; + } + if (ioctl(fb_dev_fd, FBIOGET_VSCREENINFO, &fb_vinfo)) { + mp_msg(MSGT_VO, MSGL_ERR, "Can't get VSCREENINFO: %s\n", + strerror(errno)); + goto err_out_fd; + } + + if ((fb_tty_fd = open("/dev/tty", O_RDWR)) < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "notice: Can't open /dev/tty: %s\n", + strerror(errno)); + } + + fb_pixel_size = fb_vinfo.bits_per_pixel / 8; + fb_page = 0; + + return 0; + +err_out_fd: + close(fb_dev_fd); +err_out: + return -1; +} + +static void uninit(void) +{ + if(spe_init_done_scaler) { + int mbox_data = -1; + int retries = 3; + struct spe_event_unit event; + + // Stop the SPU + spe_in_mbox_write(spe_context_scaler, &mbox_data, 1, + SPE_MBOX_ANY_NONBLOCKING); + + while(retries) { + if(spe_event_wait(spe_event_scaler, &event, 1, -1) <= 0 + || !(event.events & SPE_EVENT_OUT_INTR_MBOX)) { + retries--; + } else { + break; + } + } + + spe_init_done_scaler = 0; + } + + if(spe_init_done_yuv2rgb) { + int mbox_data = 0; + int retries = 3; + struct spe_event_unit event; + + // Stop the SPU + spe_in_mbox_write(spe_context_yuv2rgb, &mbox_data, 1, + SPE_MBOX_ANY_NONBLOCKING); + + while(retries) { + if(spe_event_wait(spe_event_yuv2rgb, &event, 1, -1) <= 0 + || !(event.events & SPE_EVENT_OUT_INTR_MBOX)) { + retries--; + } else { + break; + } + } + + spe_init_done_yuv2rgb = 0; + } + + if (fb_tty_fd >= 0) { + if (ioctl(fb_tty_fd, KDSETMODE, KD_TEXT) < 0) + mp_msg(MSGT_VO, MSGL_WARN, "Can't restore text mode" + ": %s\n", strerror(errno)); + } + + ioctl(fb_dev_fd, PS3FB_IOCTL_OFF, 0); + + close(fb_tty_fd); + close(fb_dev_fd); + if(frame_buffer) munmap(frame_buffer, fb_size); + frame_buffer = NULL; + + if(temp_input) { + free(temp_input); + temp_input = NULL; + } + + if(temp_input_yuv) { + free(temp_input_yuv); + temp_input_yuv = NULL; + } + + if(pd_scaler) { + free(pd_scaler); + pd_scaler = NULL; + } + + if(pd_yuv2rgb) { + free(pd_yuv2rgb); + pd_yuv2rgb = NULL; + } +} + +static int config(uint32_t width, uint32_t height, uint32_t d_width, + uint32_t d_height, uint32_t flags, char *title, + uint32_t format) +{ + int size_temp_input; + + if (fb_tty_fd >= 0 && ioctl(fb_tty_fd, KDSETMODE, KD_GRAPHICS) < 0) { + mp_msg(MSGT_VO, MSGL_V, "Can't set graphics mode: %s\n", + strerror(errno)); + close(fb_tty_fd); + fb_tty_fd = -1; + } else { + mp_msg(MSGT_VO, MSGL_V, "Unable to open tty, which means I " + "cannot disable the blinking cursor\n"); + } + + if (ioctl(fb_dev_fd, FBIOGET_FSCREENINFO, &fb_finfo)) { + mp_msg(MSGT_VO, MSGL_ERR, "Can't get FSCREENINFO: %s\n", + strerror(errno)); + return 1; + } + + if (ioctl(fb_dev_fd, PS3FB_IOCTL_SCREENINFO, &res) < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "Can't get PS3FB_IOCTL_SCREENINFO" + ": %s\n", strerror(errno)); + return 1; + } + + + fb_line_len = fb_finfo.line_length; + fb_size = fb_finfo.smem_len; + + frame_buffer = (uint8_t *) mmap(0, fb_size, PROT_READ | PROT_WRITE, + MAP_SHARED, fb_dev_fd, 0); + if (frame_buffer == (uint8_t *) -1) { + mp_msg(MSGT_VO, MSGL_ERR, "Can't mmap %s: %s\n", + fb_dev_name, strerror(errno)); + return 1; + } + + memset(frame_buffer, 0, fb_size); + + ioctl(fb_dev_fd, PS3FB_IOCTL_ON, 0); + + in_width = width; + in_height = height; + + width = ((width+15) & (~0xf)); + + posix_memalign(&temp_input_yuv, 128, width*height*2+width*height); + + size_temp_input = width*height*fb_pixel_size*2; + posix_memalign(&temp_input, 128, size_temp_input); + memset(temp_input, 0, size_temp_input); + + if(init_spu_scaler(in_width, width, height) < 0) { + return 1; + } + + if(init_spu_yuv2rgb(width, height) < 0) { + return 1; + } + + center = temp_input + + ( in_width / 2 ) * fb_pixel_size + + ( in_height / 2 ) * fb_line_len; + + img_format = format; + + return 0; +} + +struct spe_thread_data { + void *context; + void *pd; + char *name; + unsigned long size; +}; + +static void *spe_thread(void *data) +{ + struct spe_thread_data *spe_data = (struct spe_thread_data *)data; + unsigned int runflags = 0; + unsigned int entry = SPE_DEFAULT_ENTRY; + + int status = spe_context_run(spe_data->context, &entry, runflags, + spe_data->pd, (void *)spe_data->size, + NULL); + + free(data); + if(status < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "OUCH - could not run SPE thread " + "%s\n", spe_data->name); + return 0; + } + + return 0; +} + +static void wait_yuv2rgb_conversion(void) +{ + if(yuv_thread_running > 0) { + int retries = 3, mbox_data; + + while(retries) { + struct spe_event_unit event; + if(spe_event_wait(spe_event_yuv2rgb, &event, 1, -1) <= 0 + || !(event.events & SPE_EVENT_OUT_INTR_MBOX)) { + retries--; + } else { + break; + } + } + if(retries == 0) { + mp_msg(MSGT_VO, MSGL_WARN, "Failed to receive yuv2rgb " + "result from SPE\n"); + } + + spe_out_intr_mbox_read(spe_context_yuv2rgb, &mbox_data, 1, + SPE_MBOX_ANY_NONBLOCKING); + yuv_thread_running--; + + if(yuv_thread_running > 0) { + mp_msg(MSGT_VO, MSGL_WARN, "yuv_thread_running was not" + " 0 as expected but %d\n", yuv_thread_running); + } + } +} + +static void wait_scaler(void) +{ + if(scaler_thread_running > 0) { + int retries = 3, mbox_data; + + while(retries) { + struct spe_event_unit event; + if(spe_event_wait(spe_event_scaler, &event, 1, -1) <= 0 + || !(event.events & SPE_EVENT_OUT_INTR_MBOX)) { + retries--; + } else { + break; + } + } + if(retries == 0) { + mp_msg(MSGT_VO, MSGL_WARN, "Failed to receive scaling" + " result from SPE\n"); + } + + spe_out_intr_mbox_read(spe_context_scaler, &mbox_data, 1, + SPE_MBOX_ANY_NONBLOCKING); + + scaler_thread_running--; + + if(scaler_thread_running > 0) { + mp_msg(MSGT_VO, MSGL_WARN, "scaler_thread_running was" + " not 0 as expected but %d\n", + scaler_thread_running); + } + } +} + +static int init_spu_yuv2rgb(int width, int height) +{ + int retries = 3, mbox_data; + struct spe_event_unit event; + unsigned int createflags = SPE_EVENTS_ENABLE; + spe_program_handle_t *software_yuv2rgb_spe2; + int status, thread_id; + pthread_t pts; + struct spe_thread_data *thread_data; + unsigned char use_external_code = 0; + + // Fill in the struct + posix_memalign(&pd_yuv2rgb, 128,sizeof(*pd_yuv2rgb)); + + pd_yuv2rgb->width=width; + pd_yuv2rgb->height=height; + pd_yuv2rgb->Output[0]=(unsigned long long)temp_input; + pd_yuv2rgb->Output[1]=(unsigned long long)temp_input+width*height*4; + pd_yuv2rgb->Ystart[0] = (unsigned long long)temp_input_yuv; + pd_yuv2rgb->Ustart[0] = (unsigned long long)temp_input_yuv+width*height; + pd_yuv2rgb->Vstart[0] = (unsigned long long)temp_input_yuv + +width*height+width*height/4; + pd_yuv2rgb->Ystart[1] = pd_yuv2rgb->Ystart[0] + +width*height+width*height/2; + pd_yuv2rgb->Ustart[1] = pd_yuv2rgb->Ustart[0] + +width*height+width*height/2; + pd_yuv2rgb->Vstart[1] = pd_yuv2rgb->Vstart[0] + +width*height+width*height/2; + + // Start the SPE + spe_context_yuv2rgb = spe_context_create(createflags, NULL); + + if(!spe_context_yuv2rgb) { + mp_msg(MSGT_VO, MSGL_ERR, "OUCH - could not spawn SPE" + " thread %d\n", errno); + return -1; + } + + // Try and see if we can find an external + software_yuv2rgb_spe2 = spe_image_open(spe_yuv2rgb_filename); + + if(software_yuv2rgb_spe2) { + status = spe_program_load(spe_context_yuv2rgb, + software_yuv2rgb_spe2); + if(status >= 0) { + mp_msg(MSGT_VO, MSGL_INFO, "Using external" + " %s\n", spe_yuv2rgb_filename); + use_external_code = 1; + } + spe_image_close(software_yuv2rgb_spe2); + } + + if(!use_external_code) { + spe_program_load(spe_context_yuv2rgb, &vo_fbdevps3_yuv2rgb); + } + + thread_data = (struct spe_thread_data *)malloc(sizeof(*thread_data)); + thread_data->context = spe_context_yuv2rgb; + thread_data->pd = pd_yuv2rgb; + thread_data->name = "yuv2rgb"; + thread_data->size = sizeof(*pd_yuv2rgb); + + memset(frame_buffer, 0, fb_vinfo.xres*fb_vinfo.yres*4*2); + + spe_event_yuv2rgb = spe_event_handler_create(); + event.spe = spe_context_yuv2rgb; + event.events = SPE_EVENT_OUT_INTR_MBOX | SPE_EVENT_SPE_STOPPED; + status = spe_event_handler_register(spe_event_yuv2rgb, &event); + if(status < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "OUCH - failed to register" + " event handler %d\n", errno); + return -1; + } + + thread_id = pthread_create(&pts, 0, &spe_thread, thread_data); + pthread_detach(pts); + + yuv_thread_running = 1; + wait_yuv2rgb_conversion(); + + spe_init_done_yuv2rgb = 1; + + return 0; +} + +static int init_spu_scaler(int orig_w, int w, int h) +{ + int retries = 3; + int mbox_data = 0; + struct spe_event_unit event; + unsigned int createflags = SPE_EVENTS_ENABLE; + spe_program_handle_t *software_scale_spe2; + int status, thread_id; + pthread_t pts; + struct spe_thread_data *thread_data; + unsigned char use_external_code = 0; + + posix_memalign(&pd_scaler, 16, sizeof(spe_data_scaler)); + + pd_scaler->in[0] = (unsigned long long)temp_input; + pd_scaler->in[1] = (unsigned long long)(temp_input+w*h*4); + pd_scaler->in_width = w; + pd_scaler->scale = orig_w / (float)(fb_vinfo.xres); + pd_scaler->out_height = (int)(h / pd_scaler->scale); + + pd_scaler->out[0] = (unsigned long long)frame_buffer; + pd_scaler->out_width_total = fb_line_len / fb_pixel_size; + + if(pd_scaler->out_height > fb_vinfo.yres) { + int w_diff; + // We cannot scale to full-screen + pd_scaler->out_height = fb_vinfo.yres; + pd_scaler->scale = h / (float)(fb_vinfo.yres); + pd_scaler->out_width_overscan = pd_scaler->out_width_total + -(int)(orig_w / pd_scaler->scale); + // Make sure we align on an 8 byte boundary + pd_scaler->out_width_overscan = (pd_scaler-> + out_width_overscan+3) & (~7); + w_diff = pd_scaler->out_width_overscan + -(res.xres - fb_vinfo.xres); + if(w_diff > 16) + pd_scaler->out[0] += ((w_diff - 16 + 1) & (~0x3)) + *fb_pixel_size / 2; + } else { + pd_scaler->out_width_overscan = fb_line_len / fb_pixel_size + -fb_vinfo.xres; + } + + if(pd_scaler->out_height < (fb_vinfo.yres)) { + // yres + 8 centers on my tv - may be incorrect for other tvs + pd_scaler->out[0] += fb_line_len* + (((fb_vinfo.yres + 8 - pd_scaler->out_height)/2)&(~3)); + } + + pd_scaler->out[1] = pd_scaler->out[0] + res.xres + * res.yres * fb_pixel_size; + + // Start the SPE + spe_context_scaler = spe_context_create(createflags, NULL); + + if(!spe_context_scaler) { + mp_msg(MSGT_VO, MSGL_ERR, "OUCH - could not spawn SPE" + " thread %d\n", errno); + return -1; + } + + // Try and see if we can find an external + software_scale_spe2 = spe_image_open(spe_scaler_filename); + + if(software_scale_spe2) { + status = spe_program_load(spe_context_scaler, + software_scale_spe2); + if(status >= 0) { + mp_msg(MSGT_VO, MSGL_INFO, "Using external %s\n", + spe_scaler_filename); + use_external_code = 1; + } + + spe_image_close(software_scale_spe2); + } + + if(!use_external_code) { + spe_program_load(spe_context_scaler, &vo_fbdevps3_scaler); + } + + thread_data = (struct spe_thread_data *)malloc(sizeof(*thread_data)); + thread_data->context = spe_context_scaler; + thread_data->pd = pd_scaler; + thread_data->name = "scaler"; + thread_data->size = sizeof(*pd_scaler); + + memset(frame_buffer, 0, fb_vinfo.xres*fb_vinfo.yres*4*2); + + spe_event_scaler = spe_event_handler_create(); + event.spe = spe_context_scaler; + event.events = SPE_EVENT_OUT_INTR_MBOX | SPE_EVENT_SPE_STOPPED; + status = spe_event_handler_register(spe_event_scaler, &event); + if(status < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "OUCH - failed to register event" + " handler %d\n", errno); + return -1; + } + + thread_id = pthread_create(&pts, 0, &spe_thread, thread_data); + pthread_detach(pts); + + scaler_thread_running = 1; + wait_scaler(); + + spe_init_done_scaler = 1; + + return 0; +} + +static void flip_page(void) +{ + unsigned int wait_vsync = 0; + + ioctl(fb_dev_fd, FBIO_WAITFORVSYNC, &wait_vsync); + ioctl(fb_dev_fd, PS3FB_IOCTL_FSEL, &fb_page); +} + +static int draw_slice(uint8_t *src[], int stride[], int w, int h, int x, + int y) +{ + if ((img_format & IMGFMT_BGR_MASK) == IMGFMT_BGR) { + unsigned int mbox_data; + + wait_scaler(); + + fb_page ^= 1; + memcpy((void *)pd_scaler->in[fb_page], src[0], + w*h*fb_pixel_size); + + // Start the SPE + mbox_data = 1 + fb_page; + spe_in_mbox_write(spe_context_scaler, &mbox_data, 1, + SPE_MBOX_ANY_NONBLOCKING); + scaler_thread_running++; + } else { + memcpy((void *)pd_yuv2rgb->Ystart[fb_page^1]+stride[0]*y, + src[0], stride[0]*h); + memcpy((void *)pd_yuv2rgb->Ustart[fb_page^1]+stride[1]*y/2, + src[1], stride[1]*h/2); + memcpy((void *)pd_yuv2rgb->Vstart[fb_page^1]+stride[2]*y/2, + src[2], stride[2]*h/2); + } +} + +static void check_events(void) +{ +} + +static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, + unsigned char *srca, int stride) +{ + unsigned char *dst; + + dst = center + fb_line_len * y0 + fb_pixel_size * x0; + + vo_draw_alpha_rgb24(w, h, src, srca, stride, dst, fb_line_len); +} + +static void draw_osd(void) +{ + vo_draw_text(in_width, in_height, draw_alpha); +} + +static uint32_t get_image(mp_image_t *mpi) +{ + if (mpi->flags & MP_IMGFLAG_READABLE) return VO_FALSE; + if (mpi->type == MP_IMGTYPE_IP || mpi->type == MP_IMGTYPE_IPB) + return VO_FALSE; // we can not provide readable buffers + + if (!IMGFMT_IS_BGR(mpi->imgfmt) || + ((mpi->type != MP_IMGTYPE_STATIC) && (mpi->type != MP_IMGTYPE_TEMP)) + || (mpi->flags & MP_IMGFLAG_PLANAR) + || (mpi->flags & MP_IMGFLAG_YUV) + || (mpi->width != in_width) + || (mpi->height != in_height) + ) + return(VO_FALSE); + + mpi->planes[0] = center; + mpi->stride[0] = fb_line_len; + mpi->flags |= MP_IMGFLAG_DIRECT; + return(VO_TRUE); +} + +static int draw_frame(uint8_t *src[]) +{ + return 1; +} + +static int query_format(uint32_t format) +{ + if ((format & IMGFMT_BGR_MASK) == IMGFMT_BGR) { + int bpp = format & 0xff; + + if (bpp == 32) + return VFCAP_ACCEPT_STRIDE | VFCAP_CSP_SUPPORTED + | VFCAP_CSP_SUPPORTED_BY_HW; + } else if(format == IMGFMT_YV12 || + format == IMGFMT_I420 || + format == IMGFMT_IYUV) { + return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW + | VFCAP_ACCEPT_STRIDE; + } + + return 0; +} + +int draw_image(mp_image_t *img) +{ + int mbox_data; + + if (img->flags & MP_IMGFLAG_DRAW_CALLBACK) { + wait_yuv2rgb_conversion(); + wait_scaler(); + + mbox_data = 1 + fb_page; + spe_in_mbox_write(spe_context_scaler, &mbox_data, 1, + SPE_MBOX_ANY_NONBLOCKING); + scaler_thread_running++; + + fb_page ^= 1; + + mbox_data = fb_page; + spe_in_mbox_write(spe_context_yuv2rgb, &mbox_data, 1, + SPE_MBOX_ANY_NONBLOCKING); + + yuv_thread_running++; + return VO_TRUE; + } + + return VO_ERROR; +} + +static int control(uint32_t request, void *data, ...) +{ + switch (request) { + case VOCTRL_GET_IMAGE: + return get_image(data); + case VOCTRL_DRAW_IMAGE: + return draw_image((mp_image_t *)data); + case VOCTRL_QUERY_FORMAT: + return query_format(*((uint32_t*)data)); + } + return VO_NOTIMPL; +} Index: configure =================================================================== --- configure (revision 23402) +++ configure (working copy) @@ -296,6 +296,8 @@ --disable-libpostproc_so disable shared libpostproc [autodetect] --disable-libavcodec_mpegaudio_hp disable high precision audio decoding in libavcodec [enabled] + --disable-libspe2 disable libspe2 [autodetect] + --disable-spu disable building spu specific code [autodetect] --disable-tremor-internal disable internal Tremor [enabled] --enable-tremor-low enable lower accuracy internal Tremor [disabled] --enable-tremor-external enable external Tremor [autodetect] @@ -651,6 +653,8 @@ _stream_cache=yes _def_stream_cache="#define USE_STREAM_CACHE 1" _need_shmem=yes +_libspe2=auto +_spu=auto for ac_option do case "$ac_option" in --help|-help|-h) @@ -1002,6 +1006,10 @@ --disable-libpostproc_so) _libpostproc_so=no ;; --enable-libavcodec_mpegaudio_hp) _libavcodec_mpegaudio_hp=yes ;; --disable-libavcodec_mpegaudio_hp) _libavcodec_mpegaudio_hp=no ;; + --enable-libspe2) _libspe2=yes ;; + --disable-libspe2) _libspe2=no ;; + --enable-spu) _spu=yes ;; + --disable-spu) _spu=no ;; --enable-lirc) _lirc=yes ;; --disable-lirc) _lirc=no ;; @@ -1960,7 +1968,7 @@ iproc='ppc' proc='' _march='' - _mcpu='' + _mcpu='-mcpu=cell' _optimizing='' _altivec=no @@ -5548,7 +5556,57 @@ fi echores "$_zlib" +echocheck "libspe2" +if test "$_libspe2" = auto ; then +cat > $TMPC << EOF +#include +int main(void) { spe_program_handle_t *p=spe_image_open("t"); return 0; } +EOF + _libspe2=no + if $_pkg_config --exists libspe2 ; then + _inc_libspe2=`$_pkg_config --cflags libspe2` + _ld_tmp=`$_pkg_config --libs libspe2` + cc_check $_inc_libspe2 $_ld_tmp && _ld_extra="$_ld_extra $_ld_tmp" \ + && _libspe2=yes + fi +fi +if test "$_libspe2" = yes ; then + _def_libspe2='#define HAVE_LIBSPE2 1' +else + _def_libspe2='#undef HAVE_LIBSPE2' +fi +echores "$_libspe2" +echocheck "spu support" +if test "$_spu" = auto ; then +cat > $TMPC << EOF +int main(unsigned long long spe_id, unsigned long long program_data_ea, unsigned +long long env) { asm("ceqi \$2, \$1, 0"); return 0; } +EOF + _spu=no + _spucc_found=no + _realcc=$_cc + for _spucc in spu-gcc spu-elf-gcc ; do + rm -f "$TMPO" + echo "$_spucc $TMPC -o $TMPO" >> "$TMPLOG" + $_spucc $TMPC -o $TMPO >> "$TMPLOG" 2>&1 && _spucc_found=yes + test "$_spucc_found" = yes && break + done + if test "$_spucc_found" = yes ; then + for _embedspu in ppu-embedspu embedspu ; do + $_embedspu test "$TMPO" "$TMPC" >> "$TMPLOG" 2>&1 && _spu=yes + test "$_spu" = yes && break + done + fi +fi + +if test "$_spu" = yes ; then + _def_spu='#define HAVE_SPU 1' +else + _def_spu='#undef HAVE_SPU' +fi +echores "$_spu" + echocheck "RTC" if test "$_rtc" = auto ; then cat > $TMPC << EOF @@ -7610,6 +7668,10 @@ CONFIG_XVID=$_lavc_xvid CONFIG_X264=$_lavc_x264 CONFIG_ZLIB=$_zlib +CONFIG_LIBSPE2=$_libspe2 +CONFIG_SPU=$_spu +SPUCC=$_spucc +EMBEDSPU=$_embedspu CONFIG_GPL=yes CONFIG_ENCODERS=$_mencoder CONFIG_MUXERS=$_mencoder @@ -7878,6 +7940,18 @@ #define CONFIG_ZLIB 1 #endif +/* Define this if you have libspe2 */ +$_def_libspe2 +#ifdef HAVE_LIBSPE2 +#define CONFIG_LIBSPE2 1 +#endif + +/* Define this if you have spu support */ +$_def_spu +#ifdef HAVE_SPU +#define CONFIG_SPU 1 +#endif + /* Define this if you have shm support */ $_def_shm