Roughly working framebuffer. gsoc2009_ps3
authorMartin Lowinski <martin@goldtopf.org>
Thu, 04 Jun 2009 07:02:15 +0000
branchgsoc2009_ps3
changeset 3142 c146645a770e
parent 3141 3df74541339b
child 3143 8fdabaa064c3
Roughly working framebuffer.
src/video/ps3/SDL_ps3render.c
src/video/ps3/SDL_ps3video.c
src/video/ps3/SDL_ps3video.h
--- a/src/video/ps3/SDL_ps3render.c	Fri May 29 09:50:21 2009 +0000
+++ b/src/video/ps3/SDL_ps3render.c	Thu Jun 04 07:02:15 2009 +0000
@@ -26,6 +26,18 @@
 #include "../SDL_yuv_sw_c.h"
 #include "../SDL_renderer_sw.h"
 
+#include "SDL_ps3video.h"
+#include "spulibs/spu_common.h"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <linux/kd.h>
+#include <linux/fb.h>
+#include <sys/mman.h>
+
+#include <asm/ps3fb.h>
+
 /* Debugging
  * 0: No debug messages
  * 1: Video debug messages
@@ -64,14 +76,20 @@
 static void SDL_PS3_RenderPresent(SDL_Renderer * renderer);
 static void SDL_PS3_DestroyRenderer(SDL_Renderer * renderer);
 
+/* Texture */
+static int PS3_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
+static void PS3_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
+
 
 SDL_RenderDriver SDL_PS3_RenderDriver = {
     SDL_PS3_CreateRenderer,
     {
      "ps3",
-     (/*SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY |*/
-      SDL_RENDERER_PRESENTFLIP2 /*| SDL_RENDERER_PRESENTFLIP3 |
-      SDL_RENDERER_PRESENTDISCARD*/),
+     (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTVSYNC |
+      SDL_RENDERER_PRESENTFLIP2)
+     /* (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY |
+      SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 |
+      SDL_RENDERER_PRESENTDISCARD) */,
      }
 };
 
@@ -79,8 +97,35 @@
 {
     int current_screen;
     SDL_Surface *screens[3];
+    SDL_VideoDisplay *display;
+    uint8_t *center[2];
+
+    /* width of input (bounded by writeable width) */
+    unsigned int bounded_width;
+    /* height of input (bounded by writeable height) */
+    unsigned int bounded_height;
+    /* offset from the left side (used for centering) */
+    unsigned int offset_left;
+    /* offset from the upper side (used for centering) */
+    unsigned int offset_top;
+    /* width of screen which is writeable */
+    unsigned int wr_width;
+    /* width of screen which is writeable */
+    unsigned int wr_height;
+    /* size of a screen line: width * bpp/8 */
+    unsigned int line_length;
+
+    /* Use two buffers in fb? res < 720p */
+    unsigned int double_buffering;
 } SDL_PS3_RenderData;
 
+typedef struct
+{
+    void *pixels;
+    int pitch;
+    int bpp;
+} PS3_TextureData;
+
 SDL_Renderer *
 SDL_PS3_CreateRenderer(SDL_Window * window, Uint32 flags)
 {
@@ -113,6 +158,8 @@
     }
     SDL_zerop(data);
 
+    renderer->CreateTexture = PS3_CreateTexture;
+    renderer->DestroyTexture = PS3_DestroyTexture;
     renderer->RenderPoint = SDL_PS3_RenderPoint;
     renderer->RenderLine = SDL_PS3_RenderLine;
     renderer->RenderFill = SDL_PS3_RenderFill;
@@ -125,12 +172,12 @@
     renderer->driverdata = data;
     Setup_SoftwareRenderer(renderer);
 
+    data->double_buffering = 0;
+
     if (flags & SDL_RENDERER_PRESENTFLIP2) {
         renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2;
         n = 2;
-    } else if (flags & SDL_RENDERER_PRESENTFLIP3) {
-        renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3;
-        n = 3;
+        data->double_buffering = 1;
     } else {
         renderer->info.flags |= SDL_RENDERER_PRESENTCOPY;
         n = 1;
@@ -160,6 +207,42 @@
 }
 
 static int
+PS3_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) {
+    deprintf(1, "PS3_CreateTexture()\n");
+    PS3_TextureData *data;
+    data = (PS3_TextureData *) SDL_calloc(1, sizeof(*data));
+    if (!data) {
+        SDL_OutOfMemory();
+        return -1;
+    }
+
+    data->pitch = (texture->w * SDL_BYTESPERPIXEL(texture->format));
+
+    data->pixels = NULL;
+    data->pixels = (void *)memalign(16, texture->h * data->pitch);
+    if (!data->pixels) {
+        PS3_DestroyTexture(renderer, texture);
+        SDL_OutOfMemory();
+        return -1;
+    }
+
+    texture->driverdata = data;
+    return 0;
+}
+
+static void
+PS3_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+    PS3_TextureData *data = (PS3_TextureData *) texture->driverdata;
+
+    if (!data) {
+        return;
+    }
+
+    free(data->pixels);
+}
+
+static int
 SDL_PS3_RenderPoint(SDL_Renderer * renderer, int x, int y)
 {
     SDL_PS3_RenderData *data =
@@ -238,8 +321,11 @@
         (SDL_PS3_RenderData *) renderer->driverdata;
     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
+    PS3_TextureData *txdata = (PS3_TextureData *) texture->driverdata;
+    SDL_VideoData *devdata = display->device->driverdata;
 
     if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
+        deprintf(1, "SDL_ISPIXELFORMAT_FOURCC = true\n");
         SDL_Surface *target = data->screens[data->current_screen];
         void *pixels =
             (Uint8 *) target->pixels + dstrect->y * target->pitch +
@@ -249,11 +335,61 @@
                                    dstrect->w, dstrect->h, pixels,
                                    target->pitch);
     } else {
+        deprintf(1, "SDL_ISPIXELFORMAT_FOURCC = false\n");
         SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
         SDL_Surface *target = data->screens[data->current_screen];
         SDL_Rect real_srcrect = *srcrect;
         SDL_Rect real_dstrect = *dstrect;
 
+        /* For testing */
+        int width = 1280;
+        int height = 720;
+        void *pixels = (void *)memalign(16, height * data->screens[0]->pitch);
+        SDL_memset(pixels, 0x42, height * data->screens[0]->pitch);
+
+        /* Get screeninfo */
+        struct fb_fix_screeninfo fb_finfo;
+        if (ioctl(devdata->fbdev, FBIOGET_FSCREENINFO, &fb_finfo)) {
+            SDL_SetError("[PS3] Can't get fixed screeninfo");
+            return -1;
+        }
+        struct fb_var_screeninfo fb_vinfo;
+        if (ioctl(devdata->fbdev, FBIOGET_VSCREENINFO, &fb_vinfo)) {
+            SDL_SetError("[PS3] Can't get VSCREENINFO");
+            return -1;
+        }
+        /* 16 and 15 bpp is reported as 16 bpp */
+        txdata->bpp = fb_vinfo.bits_per_pixel;
+        if (txdata->bpp == 16)
+            txdata->bpp = fb_vinfo.red.length + fb_vinfo.green.length + fb_vinfo.blue.length;
+
+        /* Adjust centering */
+        data->bounded_width = width < fb_vinfo.xres ? width : fb_vinfo.xres;
+        data->bounded_height = height < fb_vinfo.yres ? height : fb_vinfo.yres;
+        data->offset_left = (fb_vinfo.xres - data->bounded_width) >> 1;
+        data->offset_top = (fb_vinfo.yres - data->bounded_height) >> 1;
+        data->center[0] = devdata->frame_buffer + data->offset_left * txdata->bpp/8 +
+                    data->offset_top * fb_finfo.line_length;
+        data->center[1] = data->center[0] + fb_vinfo.yres * fb_finfo.line_length;
+
+        /* Set SPU parms for copying the surface to framebuffer */
+        devdata->fb_parms->data = (unsigned char *)pixels;
+        devdata->fb_parms->center = data->center[data->current_screen];
+        devdata->fb_parms->out_line_stride = fb_finfo.line_length;
+        devdata->fb_parms->in_line_stride = surface->w * txdata->bpp / 8;
+        devdata->fb_parms->bounded_input_height = data->bounded_height;
+        devdata->fb_parms->bounded_input_width = data->bounded_width;
+        devdata->fb_parms->fb_pixel_size = txdata->bpp / 8;
+
+        deprintf(3, "[PS3->SPU] fb_thread_data->argp = 0x%x\n", devdata->fb_thread_data->argp);
+        
+        /* Copying.. */
+        SPE_SendMsg(devdata->fb_thread_data, SPU_START);
+        SPE_SendMsg(devdata->fb_thread_data, (unsigned int)devdata->fb_thread_data->argp);
+        
+        SPE_WaitForMsg(devdata->fb_thread_data, SPU_FIN);
+        free(pixels);
+
         return SDL_LowerBlit(surface, &real_srcrect, target, &real_dstrect);
     }
 }
@@ -265,6 +401,9 @@
     static int frame_number;
     SDL_PS3_RenderData *data =
         (SDL_PS3_RenderData *) renderer->driverdata;
+    SDL_Window *window = SDL_GetWindowFromID(renderer->window);
+    SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
+    SDL_VideoData *devdata = display->device->driverdata;
 
     /* Send the data to the display */
     if (SDL_getenv("SDL_VIDEO_PS3_SAVE_FRAMES")) {
@@ -274,25 +413,21 @@
         SDL_SaveBMP(data->screens[data->current_screen], file);
     }
 
-    /* Update the flipping chain, if any */
-    if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
-        data->current_screen = (data->current_screen + 1) % 2;
-    } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
-        data->current_screen = (data->current_screen + 1) % 3;
+    /* Wait for vsync */
+    if (renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) {
+        unsigned long crt = 0;
+        deprintf(1, "[PS3] Wait for vsync\n");
+        ioctl(devdata->fbdev, FBIO_WAITFORVSYNC, &crt);
     }
 
-    /* How to access the framebuffer from here? 
-    unsigned long crt = 0;
-    unsigned int s_center_index = 0;
-    unsigned int * s_center[2];
-    s_center[0] = frame_buffer;
-    // Wait for vsync
-    deprintf(1, "[PS3] Wait for vsync\n");
-    ioctl(fbdev, FBIO_WAITFORVSYNC, &crt);
-    // Page flip
-    deprintf(1, "[PS3] Page flip to buffer #%u 0x%x\n", s_center_index, s_center[s_center_index]);
-    ioctl(fbdev, PS3FB_IOCTL_FSEL, (unsigned long)&s_center_index);
-    */
+    /* Page flip */
+    deprintf(1, "[PS3] Page flip to buffer #%u 0x%x\n", data->current_screen, data->center[data->current_screen]);
+    ioctl(devdata->fbdev, PS3FB_IOCTL_FSEL, (unsigned long)&data->current_screen);
+
+    /* Update the flipping chain, if any */
+    if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2 && data->double_buffering) {
+        data->current_screen = (data->current_screen + 1) % 2;
+    }
 }
 
 static void
--- a/src/video/ps3/SDL_ps3video.c	Fri May 29 09:50:21 2009 +0000
+++ b/src/video/ps3/SDL_ps3video.c	Thu Jun 04 07:02:15 2009 +0000
@@ -57,8 +57,8 @@
 int SPE_Stop(_THIS, spu_data_t * spe_data);
 int SPE_Boot(_THIS, spu_data_t * spe_data);
 int SPE_Shutdown(_THIS, spu_data_t * spe_data);
-int SPE_SendMsg(_THIS, spu_data_t * spe_data, unsigned int msg);
-int SPE_WaitForMsg(_THIS, spu_data_t * spe_data, unsigned int msg);
+int SPE_SendMsg(spu_data_t * spe_data, unsigned int msg);
+int SPE_WaitForMsg(spu_data_t * spe_data, unsigned int msg);
 void SPE_RunContext(void *thread_argp);
 
 /* Stores the SPE executable name of fb_writer_spu */
@@ -262,7 +262,7 @@
   }
 
   if (spe_data->keepalive)
-    SPE_WaitForMsg(_this, spe_data, SPU_READY);
+    SPE_WaitForMsg(spe_data, SPU_READY);
 }
 
 
@@ -311,7 +311,7 @@
 int SPE_Shutdown(_THIS, spu_data_t * spe_data)
 {
   if (spe_data->keepalive && spe_data->booted) {
-    SPE_SendMsg(_this, spe_data, SPU_EXIT);
+    SPE_SendMsg(spe_data, SPU_EXIT);
     SPE_Stop(_this, spe_data);
   }
 
@@ -327,7 +327,7 @@
 }
 
 /* Send message to the SPE via mailboxe */
-int SPE_SendMsg(_THIS, spu_data_t * spe_data, unsigned int msg)
+int SPE_SendMsg(spu_data_t * spe_data, unsigned int msg)
 {
   deprintf(2, "[PS3->SPU] Sending message %u to %s\n", msg, spe_data->program_name);
   /* Send one message, block until message was sent */
@@ -345,7 +345,7 @@
 
 
 /* Read 1 message from SPE, block until at least 1 message was received */
-int SPE_WaitForMsg(_THIS, spu_data_t * spe_data, unsigned int msg)
+int SPE_WaitForMsg(spu_data_t * spe_data, unsigned int msg)
 {
   deprintf(2, "[PS3->SPU] Waiting for message from %s\n", spe_data->program_name);
   unsigned int out_messages[1];
--- a/src/video/ps3/SDL_ps3video.h	Fri May 29 09:50:21 2009 +0000
+++ b/src/video/ps3/SDL_ps3video.h	Thu Jun 04 07:02:15 2009 +0000
@@ -56,8 +56,8 @@
 /* SPU thread data */
 typedef struct spu_data {
     spe_context_ptr_t ctx;
+    spe_program_handle_t program;
     pthread_t thread;
-    spe_program_handle_t program;
     char * program_name;
     unsigned int booted;
     unsigned int keepalive;