changeset 979:e0c254a9a865

add rest
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Fri, 01 Oct 2010 22:13:11 +0900
parents 11879f9ce791
children 4ce73df9ac61
files old/framebuffer/cp_vt.c old/framebuffer/cp_vt.h old/framebuffer/fb_test-1.c
diffstat 3 files changed, 528 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/old/framebuffer/cp_vt.c	Fri Oct 01 22:13:11 2010 +0900
@@ -0,0 +1,285 @@
+// cp_vt.c 
+//
+// Copyright (c) 2006, Mike Acton <macton@cellperformance.com>
+// 
+// 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.
+
+// NOTES:
+// From http://www.linuxjournal.com/article/2597
+//
+//     "Console ttys are used when the keyboard and monitor are directly connected to the system without running
+//     the X Window System. Since you can have several virtual consoles, the devices are tty0 through tty63. In
+//     theory you can have 64 virtual consoles, but most people use only a few. The device /dev/console is
+//     identical to tty0 and is needed for historical reasons. If your system lets you log in on consoles 1
+//     through 6, then when you run X Windows System, X uses console 7, so you'll need /dev/tty1 through /dev/
+//     tty7 on your system. I recommend having files up through /dev/tty12. For more information on using
+//     virtual consoles, see the article Keyboards, Consoles and VT Cruising by John Fisk in the November 1996
+//     issue of Linux Journal"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/vt.h>
+#include <linux/kd.h>
+#include "cp_vt.h"
+
+
+static inline const char*
+select_error_str( int existing_error, const char* const existing_error_str, int new_error, const char* const new_error_str )
+{
+  // Only report the first error found - any error that follows is probably just a cascading effect.
+  const char* error_str = (char*)( (~(intptr_t)existing_error & (intptr_t)new_error & (intptr_t)new_error_str)
+                                 |  ((intptr_t)existing_error & (intptr_t)existing_error_str) );
+
+  return (error_str);
+}
+
+
+int
+cp_vt_open_graphics(cp_vt* restrict vt)
+{
+  const char*    error_str      = NULL;
+  int            error          = 0;
+
+  // Open the current tty
+ 
+  // From http://tldp.org/HOWTO/Text-Terminal-HOWTO-6.html#ss6.3
+  // (An excellent overview by David S. Lawyer)
+  //
+  //     "In Linux the PC monitor is usually called the console and has several device special files associated
+  //     with it: vc/0 (tty0), vc/1 (tty1), vc/2 (tty2), etc. When you log in you are on vc/1. To go to vc/2
+  //     (on the same screen) press down the 2 keys Alt(left)-F3. For vc/3 use Left Alt-F3, etc. These (vc/1,
+  //     vc/2, vc/3, etc.) are called "virtual terminals". vc/0 (tty0) is just an alias for the current virtual
+  //     terminal and it's where messages from the system are sent. Thus messages from the system will be seen
+  //     on the console (monitor) regardless of which virtual terminal it is displaying."
+
+  const int   cur_tty                = open( "/dev/tty0", O_RDWR );
+  const int   open_cur_tty_error     = (cur_tty >> ((sizeof(int)*8)-1));
+  const char* open_cur_tty_error_str = "Could not open /dev/tty0. Check permissions.";
+  
+  error_str = select_error_str( error, error_str, open_cur_tty_error, open_cur_tty_error_str );
+  error     = error | open_cur_tty_error;
+
+  // From: http://www.linuxjournal.com/article/2783
+  // (A little out of date, but a nice primer.)
+  //
+  //     "VT_GETSTATE returns the state of all VT's in the kernel in the structure:
+  //
+  //         struct vt_stat {
+  //               ushort v_active; 
+  //               ushort v_signal; 
+  //               ushort v_state;
+  //          };
+  //
+  //      v_active        the currently active VT 
+  //      v_state         mask of all the opened VT's
+  //
+  //      v_active holds the number of the active VT (starting from 1), while v_state 
+  //      holds a mask where there is a 1 for each VT that has been opened by some process. 
+  //      Note that VT 0 is always opened in this scenario, since it refers to the current VT.
+  //
+  //      Bugs:
+  //      The v_signal member is unsupported."
+
+  struct vt_stat  vts;
+
+  const int   get_state_error     = ioctl( cur_tty, VT_GETSTATE, &vts );
+  const char* get_state_error_str = "VT_GETSTATE failed on /dev/tty0";
+
+  error_str = select_error_str( error, error_str, get_state_error, get_state_error_str );
+  error     = error | get_state_error;
+
+  vt->prev_tty_ndx = vts.v_active;
+
+  // From: http://opensolaris.org/os/project/vconsole/vt.7i.txt
+  // (Close enough to Linux and a pretty good source of documentation.)
+  //
+  // "VT_OPENQRY
+  //     This call is used to find an available VT.    The argu-
+  //     ment to the    ioctl is a pointer to an integer.  The integer
+  //     will be filled in with the number of the first avail-
+  //     able VT that no other process has open (and    hence, is
+  //     available to be opened).  If there are no available
+  //     VTs, then -1 will be filled in."
+
+  const int   open_query_error     = ioctl( cur_tty, VT_OPENQRY, &vt->tty_ndx);
+  const char* open_query_error_str = "No open ttys available";
+
+  error_str = select_error_str( error, error_str, open_query_error, open_query_error_str );
+  error     = error | open_query_error;
+
+  const int   close_cur_tty_error     = close( cur_tty );
+  const char* close_cur_tty_error_str = "Could not close parent tty";
+
+  error_str = select_error_str( error, error_str, close_cur_tty_error, close_cur_tty_error_str );
+  error     = error | close_cur_tty_error;
+
+  char tty_file_name[11];
+
+  (void)snprintf( tty_file_name, 11, "/dev/tty%d", vt->tty_ndx );
+
+  const int   tty                = open( tty_file_name, O_RDWR );
+  const int   open_tty_error     = (cur_tty >> ((sizeof(int)*8)-1));
+  const char* open_tty_error_str = "Could not open tty";
+
+  error_str = select_error_str( error, error_str, open_tty_error, open_tty_error_str );
+  error     = error | open_tty_error;
+
+  vt->tty = tty;
+
+  // From: http://opensolaris.org/os/project/vconsole/vt.7i.txt
+  // (Close enough to Linux and a pretty good source of documentation.)
+  //
+  // "VT_ACTIVATE
+  //    This call has the effect of making the VT specified in
+  //    the argument the active VT. The VT manager will cause
+  //    a switch to occur in the same manner as if a hotkey had
+  //    initiated the switch.  If the specified VT is not open
+  //    or does not exist the call will fail and errno will be
+  //    set to ENXIO."
+  //
+  // "VT_WAITACTIVE
+  //    If the specified VT is already active, this call
+  //    returns immediately. Otherwise, it will sleep until
+  //    the specified VT becomes active, at which point it will
+  //    return."
+
+
+  const int   activate_tty_error     = ioctl( vt->tty, VT_ACTIVATE, vt->tty_ndx );
+  const char* activate_tty_error_str = "Could not activate tty";
+
+  error_str = select_error_str( error, error_str, activate_tty_error, activate_tty_error_str );
+  error     = error | activate_tty_error;
+
+  const int   waitactive_tty_error     = ioctl( vt->tty, VT_WAITACTIVE, vt->tty_ndx );
+  const char* waitactive_tty_error_str = "Could not switch to tty";
+
+  error_str = select_error_str( error, error_str, waitactive_tty_error, waitactive_tty_error_str );
+  error     = error | waitactive_tty_error;
+
+  // From: http://opensolaris.org/os/project/vconsole/vt.7i.txt
+  // (Close enough to Linux and a pretty good source of documentation.)
+  //
+  //  "KDSETMODE
+  //   This call is used to set the text/graphics mode to the VT.
+  //
+  //      KD_TEXT indicates that console text will be displayed on the screen
+  //      with this VT. Normally KD_TEXT is combined with VT_AUTO mode for
+  //      text console terminals, so that the console text display will
+  //      automatically be saved and restored on the hot key screen switches.
+  //
+  //      KD_GRAPHICS indicates that the user/application, usually Xserver,
+  //      will have direct control of the display for this VT in graphics
+  //      mode. Normally KD_GRAPHICS is combined with VT_PROCESS mode for
+  //      this VT indicating direct control of the display in graphics mode.
+  //      In this mode, all writes to this VT using the write system call are
+  //      ignored, and the user is responsible for saving and restoring the
+  //      display on the hot key screen switches."
+
+  // Save the current VT mode. This is most likely KD_TEXT.
+
+  const int   kdgetmode_error     = ioctl( vt->tty, KDGETMODE, &vt->prev_kdmode );
+  const char* kdgetmode_error_str = "Could not get mode for tty";
+
+  error_str = select_error_str( error, error_str, kdgetmode_error, kdgetmode_error_str );
+  error     = error | kdgetmode_error;
+  
+  // Set VT to GRAPHICS (user draw) mode
+
+  const int   kdsetmode_graphics_error     = ioctl( vt->tty, KDSETMODE, KD_GRAPHICS );
+  const char* kdsetmode_graphics_error_str = "Could not set graphics mode for tty";
+
+  error_str = select_error_str( error, error_str, kdsetmode_graphics_error, kdsetmode_graphics_error_str );
+  error     = error | kdsetmode_graphics_error;
+
+  //
+  // Not bothering with VT_PROCESS, VT_AUTO is fine for our purposes.
+  //
+ 
+  // If vt blanking is active, for example when running this program from a remote terminal, 
+  // setting KD_GRAPHICS will not disable the blanking. Reset to KD_TEXT from KD_GRAPHICS will
+  // force disable blanking. Then return to KD_GRAPHICS for drawing.
+  //
+  // Note: KD_TEXT (default) to KD_TEXT will do nothing, so blanking will not be disable unless
+  // the mode is changing. i.e. the initial set to KD_GRAPHICS above is useful.
+
+  const int   kdsetmode_text_error     = ioctl( vt->tty, KDSETMODE, KD_TEXT );
+  const char* kdsetmode_text_error_str = "Could not set text mode for tty";
+
+  error_str = select_error_str( error, error_str, kdsetmode_text_error, kdsetmode_text_error_str );
+  error     = error | kdsetmode_text_error;
+
+  const int   kdsetmode_graphics_reset_error     = ioctl( vt->tty, KDSETMODE, KD_GRAPHICS );
+  const char* kdsetmode_graphics_reset_error_str = "Could not reset graphics mode for tty";
+
+  error_str = select_error_str( error, error_str, kdsetmode_graphics_reset_error, kdsetmode_graphics_reset_error_str );
+  error     = error | kdsetmode_graphics_reset_error;
+
+  if ( error == -1 )
+  {
+      printf("ERROR: vt_graphics_open: %s\n",error_str);
+      return (-1);
+  }
+
+  return (0);
+}
+
+int
+cp_vt_close(cp_vt* restrict vt)
+{
+  const char*    error_str      = NULL;
+  int            error          = 0;
+
+  // Reset previous mode on tty (likely KD_TEXT)
+
+  const int   kdsetmode_error     = ioctl( vt->tty, KDSETMODE, vt->prev_kdmode );
+  const char* kdsetmode_error_str = "Could not reset previous mode for tty";
+
+  error_str = select_error_str( error, error_str, kdsetmode_error, kdsetmode_error_str );
+  error     = error | kdsetmode_error;
+
+  // Restore previous tty
+
+  const int   activate_tty_error     = ioctl( vt->tty, VT_ACTIVATE, vt->prev_tty_ndx );
+  const char* activate_tty_error_str = "Could not activate previous tty";
+
+  error_str = select_error_str( error, error_str, activate_tty_error, activate_tty_error_str );
+  error     = error | activate_tty_error;
+
+  const int   waitactive_tty_error     = ioctl( vt->tty, VT_WAITACTIVE, vt->prev_tty_ndx );
+  const char* waitactive_tty_error_str = "Could not switch to previous tty";
+
+  error_str = select_error_str( error, error_str, waitactive_tty_error, waitactive_tty_error_str );
+  error     = error | waitactive_tty_error;
+
+  // Close tty
+
+  const int   close_tty_error     = close( vt->tty );
+  const char* close_tty_error_str = "Could not close tty";
+
+  error_str = select_error_str( error, error_str, close_tty_error, close_tty_error_str );
+  error     = error | close_tty_error;
+
+  if ( error == -1 )
+  {
+      printf("ERROR: vt_close: %s\n",error_str);
+      return (-1);
+  }
+
+  return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/old/framebuffer/cp_vt.h	Fri Oct 01 22:13:11 2010 +0900
@@ -0,0 +1,45 @@
+// cp_vt.h 
+//
+// Copyright (c) 2006, Mike Acton <macton@cellperformance.com>
+// 
+// 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.
+
+#ifndef CP_VT_H
+#define CP_VT_H
+
+#if defined(__cplusplus)
+extern "C" 
+{
+#endif
+
+typedef struct cp_vt cp_vt;
+
+struct cp_vt
+{
+    int prev_tty_ndx;
+    int prev_kdmode;
+    int tty;
+    int tty_ndx;
+};
+
+int cp_vt_open_graphics(cp_vt* restrict vt);
+int cp_vt_close(cp_vt* restrict vt);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/old/framebuffer/fb_test-1.c	Fri Oct 01 22:13:11 2010 +0900
@@ -0,0 +1,198 @@
+// fb_test.c 
+// Simple test application. Draw something to the frame buffer. 
+//
+// Copyright (c) 2006, Mike Acton <macton@cellperformance.com>
+// 
+// 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 <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "cp_vt.h"
+#include "cp_fb.h"
+
+void write_hline_gouraud_ABGR8888( int32_t x0, int32_t x1, uint32_t left_rgba, uint32_t right_rgba, void* dest_buffer, uint16_t stride );
+
+int 
+main( void )
+{
+    cp_vt vt;
+    cp_fb fb;
+
+    cp_vt_open_graphics(&vt);
+    cp_fb_open(&fb);
+
+    uint32_t frame_ndx        = 0;
+    float    sprite_t         = 0.0f;
+    float    sprite_prev_t[2] = { 0.0f, 0.0f }; 
+
+    // A little example display.
+ 
+    for (uint32_t y_last = 1; y_last < fb.h; y_last++)
+    {
+        uint32_t* const restrict frame_top = (uint32_t*)fb.draw_addr[ frame_ndx ];
+
+        // Clear the background
+
+        memset( frame_top, 0x00, fb.h * fb.stride * 4 );
+
+        // Draw a rectangle that grows from top to bottom
+
+        for (uint32_t y = 0; y < y_last; y++ )
+        {
+            uint32_t* const restrict next_line = frame_top + ( fb.stride * y );
+
+            write_hline_gouraud_ABGR8888( 0,       64-1,      0x00ff0000, 0x00f0f000, next_line, fb.w );
+            write_hline_gouraud_ABGR8888( 64,      fb.w-64-1, 0x0000ff00, 0x000000ff, next_line, fb.w );
+            write_hline_gouraud_ABGR8888( fb.w-64, fb.w-1,    0x00ff00ff, 0x0000f0f0, next_line, fb.w );
+        }
+
+        // Draw a little sprite on a sine wave. 
+
+        sprite_t                    += 0.08f; // Update position
+        sprite_prev_t [ frame_ndx ]  = sprite_t; 
+
+        {
+            float    sprite_amp    = sinf( sprite_t );
+            uint32_t sprite_left   = (uint32_t)(sprite_t * 0.03f * (float)fb.w);
+            uint32_t sprite_top    = (fb.h>>1) + (uint32_t)(sprite_amp * (float)((fb.h-128)>>1));
+            uint32_t sprite_right  = sprite_left + 64;
+            uint32_t sprite_bottom = sprite_top  + 64;
+            uint32_t sprite_middle = sprite_left + (( sprite_right - sprite_left ) >> 1);
+            uint32_t sprite_cr      = ( (uint32_t)(sprite_amp * 127.0f) + 128 ) & 0x000000ff;
+            uint32_t sprite_cg      = ( (uint32_t)(sprite_amp * 127.0f) + 128 ) & 0x000000ff;
+            uint32_t sprite_cb      = ( (uint32_t)(sprite_amp * 127.0f) + 128 ) & 0x000000ff;
+            uint32_t sprite_crgb    = sprite_cr | ( sprite_cg << 8 ) | ( sprite_cb << 16 );
+
+            for (uint32_t y = sprite_top;y < sprite_bottom;y++)
+            {
+                uint32_t* const restrict next_line = frame_top + ( fb.stride * y );
+
+                write_hline_gouraud_ABGR8888( sprite_left,   sprite_middle-1, 0x007f1e00,  sprite_crgb, next_line, fb.w );
+                write_hline_gouraud_ABGR8888( sprite_middle, sprite_right-1,  sprite_crgb, 0x001e7f00,  next_line, fb.w );
+            }
+
+        }
+
+        // At the vsync, the previous frame is finished sending to the CRT
+        cp_fb_wait_vsync( &fb );
+
+        // Send the frame just drawn to the CRT by the next vblank
+        cp_fb_flip( &fb, frame_ndx );
+
+        frame_ndx  = frame_ndx ^ 0x01;
+    }
+
+    cp_vt_close(&vt);
+    cp_fb_close(&fb);
+
+    return (0);
+}
+
+void 
+write_hline_gouraud_ABGR8888( int32_t x0, int32_t x1, uint32_t left_rgba, uint32_t right_rgba, void* dest_buffer, uint16_t width )
+{
+  uint32_t left_r;
+  uint32_t left_g;
+  uint32_t left_b;
+  uint32_t left_a;
+
+  uint32_t step_r;
+  uint32_t step_g;
+  uint32_t step_b;
+  uint32_t step_a;
+
+  if ( (x1-x0+1) == 0 )
+  {
+    return;
+  }
+
+  /* Setup rgbas */
+  {
+    uint32_t right_r;
+    uint32_t right_g;
+    uint32_t right_b;
+    uint32_t right_a;
+    uint32_t step_scale;
+
+    left_r     = ( ( left_rgba       ) & 0x000000ff );
+    left_g     = ( ( left_rgba >> 8  ) & 0x000000ff );
+    left_b     = ( ( left_rgba >> 16 ) & 0x000000ff );
+    left_a     = ( ( left_rgba >> 24 ) & 0x000000ff );
+
+    right_r    = ( ( right_rgba       ) & 0x000000ff );
+    right_g    = ( ( right_rgba >> 8  ) & 0x000000ff );
+    right_b    = ( ( right_rgba >> 16 ) & 0x000000ff );
+    right_a    = ( ( right_rgba >> 24 ) & 0x000000ff );
+
+    step_scale = (1<<16) / (x1-x0+1);
+    step_r     = ( ( right_r - left_r ) * step_scale );
+    step_g     = ( ( right_g - left_g ) * step_scale );
+    step_b     = ( ( right_b - left_b ) * step_scale );
+    step_a     = ( ( right_a - left_a ) * step_scale );
+
+    left_r   <<= 16;
+    left_g   <<= 16;
+    left_b   <<= 16;
+    left_a   <<= 16;
+
+    left_r    += (1<<16)>>1;
+    left_g    += (1<<16)>>1;
+    left_b    += (1<<16)>>1;
+    left_a    += (1<<16)>>1;
+  }
+
+  /* Write to buffer */
+  {
+    uint32_t* restrict dest_pixel;
+    int32_t            x;
+
+    if ( x0 < 0 )
+    {
+      left_r += step_r * (-x0);
+      left_g += step_g * (-x0);
+      left_b += step_b * (-x0);
+      left_a += step_a * (-x0);
+      x0 = 0;
+    }
+
+    if ( x1 >= (int32_t)width )
+    {
+      x1 = width-1;
+    }
+
+    dest_pixel = (uint32_t*)dest_buffer + x0;
+
+    for (x=x0;x<=x1;x++)
+    {
+      uint32_t rgba;
+
+      rgba  = ( ( left_b >> 16 ) & 0x000000ff );
+      rgba |= ( ( left_g >> 16 ) & 0x000000ff ) << 8;
+      rgba |= ( ( left_r >> 16 ) & 0x000000ff ) << 16;
+      rgba |= ( ( left_a >> 16 ) & 0x000000ff ) << 24;
+
+      *dest_pixel = rgba;
+      dest_pixel++;
+
+      left_r += step_r;
+      left_g += step_g;
+      left_b += step_b;
+      left_a += step_a;
+    }
+  }
+}