# HG changeset patch # User Shinji KONO # Date 1285938791 -32400 # Node ID e0c254a9a8652e7381fe1e0ef44d05a529fcea8b # Parent 11879f9ce791e1baf5a34bfd04fe6860be434dbd add rest diff -r 11879f9ce791 -r e0c254a9a865 old/framebuffer/cp_vt.c --- /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 +// +// 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 +#include +#include +#include +#include +#include +#include +#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); +} diff -r 11879f9ce791 -r e0c254a9a865 old/framebuffer/cp_vt.h --- /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 +// +// 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 diff -r 11879f9ce791 -r e0c254a9a865 old/framebuffer/fb_test-1.c --- /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 +// +// 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 +#include +#include +#include +#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; + } + } +}