16.78MHz -17ページ目

fglrxの非二乗サイズテクスチャの秘密

以前fglrxに非二乗サイズテクスチャを食べさせるとハングするということを書いたが、今日新しい発見があった。ハングしたかのように見えた画面のままひたすら待っていると、1フレーム目が表示された。計ってみたところ二乗サイズのテクスチャを使った場合余裕で60フレームに間に合うシーンの表示におよそ16秒を要することが解かった。
一般的に非二乗サイズのテクスチャを使用するとパフォーマンスが悪くなることが知られているが、これはいくらなんでも悪くなりすぎだ。おそらくハードウェアレベルで非二乗サイズのテクスチャをサポートする術が無く、全てソフトウェアでレンダリングしているのではなかろうか
そう思ったのだが、詳しく調べてみたところテクスチャプロクシで非二乗テクスチャの使用が可能かどうか調べただけで時間がかかっていた。一体16秒間も何をやっているのやら...

ちなみに、かつてと比べてATiのビデオカードのLinux対応事情も随分良くなってきているらしい。今度最新のドライバに入れ替えてみるかな。

続々メモ

課題25
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define BUFSIZE 1000

typedef uint8_t Boolean;

#define TRUE (Boolean)-1
#define FALSE (Boolean)0

typedef struct {
int file_descriptor;
uint32_t current_position;
char buffer[ BUFSIZE ];
} StreamBuffer;

Boolean initReadBuffer( StreamBuffer *_arg_target, const char *_arg_filename ) {
int temp;
if( ( temp = open( _arg_filename, O_RDONLY ) ) == -1 )return FALSE;
else {
_arg_target->file_descriptor = temp;
_arg_target->current_position = BUFSIZE;
return TRUE;
}
}


void initWriteBuffer( StreamBuffer *_arg_target ) {
_arg_target->file_descriptor = 1;
_arg_target->current_position = 0;
_arg_target->buffer[ _arg_target->current_position ] = 0;
}

char readBuffer( StreamBuffer *_arg_target ) {
if( _arg_target->current_position == BUFSIZE ) {
ssize_t read_size;
if( ( read_size = read( _arg_target->file_descriptor, (void *)_arg_target->buffer, BUFSIZE ) ) != BUFSIZE )
_arg_target->buffer[ read_size ] = 0;
_arg_target->current_position = 0;
}
char temp = _arg_target->buffer[ _arg_target->current_position ];
_arg_target->current_position++;
return temp;
}

void writeBuffer( StreamBuffer *_arg_target, char _arg_value ) {
_arg_target->buffer[ _arg_target->current_position ] = _arg_value;
_arg_target->current_position++;
if( _arg_target->current_position == BUFSIZE ) {
write( _arg_target->file_descriptor, (void*)_arg_target->buffer, BUFSIZE );
_arg_target->current_position = 0;
}
_arg_target->buffer[ _arg_target->current_position ] = 0;
}

void finalReadBuffer( StreamBuffer *_arg_target ) {
close( _arg_target->file_descriptor );
_arg_target->file_descriptor = 0;
}

void finalWriteBuffer( const StreamBuffer *const _arg_target ) {
ssize_t buffer_size = 0;
for( buffer_size = 0; _arg_target->buffer[ buffer_size ]; buffer_size++ );
write( _arg_target->file_descriptor, (void*)_arg_target->buffer, buffer_size );
write( _arg_target->file_descriptor, "\n", 1 );
}


typedef struct {
int line;
} LineNumber;

void initLineNumber( LineNumber *_arg_target, StreamBuffer *_arg_buffer ) {
const char first_line[ 10 ] = " 0\t";
const char *iterator;
for( iterator = first_line; iterator != first_line + 10; iterator++ ) {
writeBuffer( _arg_buffer, *iterator );
}

_arg_target->line = 1;
}

void writeLineNumber( LineNumber *_arg_target, StreamBuffer *_arg_buffer ) {
char temp[ 10 ];
char *iterator;
memset( (void*)temp + 1, ' ', 8 * sizeof( char ) );
temp[ 0 ] = '\n';
temp[ 9 ] = '\t';
int line = _arg_target->line;
for( iterator = temp + 8; iterator != temp && line; iterator-- ) {
*iterator = '0' + line % 10;
line /= 10;
}
for( iterator = temp; iterator != temp + 10; iterator++ ) {
writeBuffer( _arg_buffer, *iterator );
}

_arg_target->line++;
}

void finalLineNumber( LineNumber *_arg_target ) {
}

int main( int argc, char *argv[] ) {
if( argc <= 1 )exit( EXIT_FAILURE );

StreamBuffer read_buffer;
if( !initReadBuffer( &read_buffer, argv[ 1 ] ) )exit( EXIT_FAILURE );

StreamBuffer write_buffer;
initWriteBuffer( &write_buffer );

LineNumber line_number;
initLineNumber( &line_number, &write_buffer );

char temp;
while( 1 ) {
switch( temp = readBuffer( &read_buffer ) ) {
case '\n':
writeLineNumber( &line_number, &write_buffer );
break;
case 0:
goto FINISH;
default:
writeBuffer( &write_buffer, temp );
break;
}
}
FINISH:
finalWriteBuffer( &write_buffer );
finalReadBuffer( &read_buffer );
finalLineNumber( &line_number );
exit( EXIT_SUCCESS );
}

begin 644 25.c.gz
M'XL("#'&&T<``S(U+F,`M5;;3MM`$'VNOV*@:N(D3INT+[0F2$!!C82H1(IZ
M@<ARG#6LZMB1O:8WY=\[>XO7CB$N;?M`G;F=F3.SL_N4QD&4SPGL9VQ.D^>W
M!]934Q31V8:,QJPJ2VE\4Y;E,453+C,-?V0OV(\ER2K^*,Z87XD:!C&+9(`Y
M"6E,X.CR=#+^<O+DR7`P&%@6CX0:R#&A/8_!49)$Q(_=PN'#Q25:VTK1Z0_7
MFM/#LXFI,L)A-7G`X)<%^`]#0T@CXLU)%J1TR9+4%0H.^NHEH@9YFI*8><LD
MHXPFL50'MWX*LSP,27JE\X:I:ZU@PE+B+XZ$"E-5"2`091?$GTN%73*#KN>G
M-Q[#/X0Y$"1QQB2"5/`$8W]!H".RYCDSLECR3&AH@RU^P0B2)8EM*+DX\-Z[
M>/O^_.PS.G=@-(+^$#HI87D:2Y)X%!)E1!%B9-(_J#"#$!JW8E@E"2T5*=)8
M`?)^<<'*6EF6=9?0N>#E8TH9V4J,JGY+@D.W:E.3VV##2+?R8<^I],7D17?2
M)OW430OM;6FM.5,N`%E&?Q*<00[D\6_)IFSZ6HA)\6_[06H<L`7?W4Y-W8Z!
MW($=(Q&!=P]710)3S6E#ZE>6.D%J<!_3BJU][O6XB9H\.;<K-73?&@V<(W,4
MDCL_RDG=!#8?G").P]0?-3*BM$:CL&T2_K"??W6<1%=P<?M1HQVIJ@VB)-M2
MJRQCR\ZHYE#:1W(;EU.1LLV$]'F5Y>O#*2@*$XQ5E=>39EI-7?-GKR?K^>LF
MFQ#-(^Y>Q[L.#+D'W]\U%RJ_FB*\?_E%>(;_G^>+F;@&U[N^D-J&1>7<U31>
M9JP;7]R0(4TSYG',*Q@.Q$CMRIT%@VNVZY:MNUAEZJM+7K1$"]"O".46XAU3
M#CW$*)2\'>:QTR-C).P4D))H)*XRCR*PN+A*Z^G?$*67K"3'U:(2#PNRR`BS
M]<"(G8R%.M"&M@-[T`4^)PEN(^';D87(J)+Q]G7<+F2OE8P)F1Z)ZIJ78[+9
M!06_5^Z!D+9:4.Y.O[]N0-<(T1ZT,8(`?<8;)@S$SQ<C]7MU#W(-ZO_J.5_R
MI;73H.,"&YTXJ0N?XFN/?Z$J4)=5%[_OKJ;&HX,K87_$CRWY3K'-)Y_&'[S3
MP_'9Y878\FA7&B-QK<_4^U7&V*F^7EN&D0,"$P$X;$,0P9V)4GT&MDP+%<$@
MA1/HQ6J[P,9F:1EZIS;6^F2([7>+J\[F%.F'US?*@MOUPSJ]IW3Q7/JEWDB!
MCX]H?A+>*`%L'N0M>6F_&6)\=<VX@R+H3<(2.!V?CR?OM`EN83^/6`6XEDI'
MUE0/MA+#*F/S8)NW84W*&]=VF:&UR7T\2!-C;":7Q\<GDPG*`7#8?P.%VA-+
$PPX`````
`
end

学祭の収穫

学祭のフリーマーケットで面白いものを見つけた。

初代iMac( ジャンク )

お値段1000円。とりあえず買って帰って電源をいれてみる。

じゃーーーん
起動音がしてもすぐにはりんごマークが表示されず、ぶぉーんと唸りながら少しづつ明るくなるブラウン管ディスプレイに時代を感じる。

が、そこに映ったのはりんごではなかった。ファインダー顔したディレクトリが疑問符を浮かべている。MacOSのインストールされたハードディスクが見付かりません、ということだと思う、たぶん。フリーマーケットの店員さんがハードディスクがおかしいと言っていたので、ハードディスク周りが死んでいるためにOpenFirmwareがMacOSを見つけられないのだろう。

とりあえず分解してみたところIDEケーブルにRev.Aと書かれていた。そうか、こいつは233MHzの最初期のiMacなのか。...と思ったのだがどうもiMac G3 Rev.Aはボンダイカラーしか存在しないらしい。インディゴっぽいガワをかぶってる以上、IDEケーブルだけ後から変更したか、ガワだけ後から変更したか、といったところだろう。昔のMacには詳しくないが、メイン基板のシールドに直接貼り付けられたIOパネルの模様だけボンダイカラーなのが激しく不安だ。あのAppleがそんなちぐはぐデザインをするだろうか、これはインディゴのガワにボンダイを詰めたものではなかろうか。付属してきたマウスがグラファイトカラーだったのが更に謎である。

とりあえずCPUボードをチェックしてみた。ボンダイなら前の持ち主が中身いじってなければ233MHzが載ってるはずだ。

333MHz + 容量不明SO-DIMM(推定128MB)

333MHzということはこいつはもともとインディゴ、かと思ったが明らかに前の持ち主は中身をいじっている。よし、こいつが何者なのかを考えるのは止めよう。とりあえずiMacには違いない

イマドキのMacOSXを入れてもあまり幸せになれそうにない性能なのでLinuxをいれてみようと思うわけだが、経験上圧縮ファイルシステムとバイナリサイズの節約、要らないリソースの削除を徹底すればLinux環境はおよそ600MBあれば満足に使うことが出来る。今回はファイルをキャッシュしておけるメモリに全く余裕が無いのでCDブートは断念するとして、ホームディレクトリの余裕とswapを考慮して2GBのハードディスクを積むのが妥当かと思われる。クロスコンパイルでシステム構築ってのは想像を絶する茨の道なので、スクラッチビルドを時間がかかってもできればセルフコンパイルで行いたい。というわけで暫定的にDebianを入れる容量も考慮して4GBのコンパクトフラッシュを繋ぐことにした。

とりあえず、モノが揃うまでiMacには下を向いたまま絨毯の上に鎮座してもらう

メンバポインタ

C++では &クラス名::メンバ名 と書くとメンバポインタというモノが得られる。
boost::mem_fnやboost::bindなんかでも使われる使われるからこれ自体の知名度は高い思う。問題はこのメンバポインタは何型で受け取ればいいのかである。
メンバポインタは普通のポインタとは全く別物なので、メンバポインタ型なんてものがC++にはちゃんと用意されている。が、その宣言文は関数ポインタ級に変態的である。
メンバの型名 クラス名::*変数名 = 初期値;

こんなかんじ。メンバポインタを使ってメンバにアクセスする場合は通常のアロー演算子等ではなくメンバポインタ演算子( ->*, .* )なるものを使う。
インスタンス.*メンバポインタ

以下サンプルコード
#include <cstdlib>
#include <iostream>

struct Sample {
int num;
int func() {
return num;
}
};

int main() {
Sample hoge;
Sample *hoge_ptr = &hoge;
int Sample::*num_ptr = &Sample::num;
int (Sample::*func_ptr)() = &Sample::func;

hoge.*num_ptr = 3;
std::cout << ( hoge.*func_ptr )() << std::endl;

hoge_ptr->*num_ptr = 5;
std::cout << ( hoge_ptr->*func_ptr )() << std::endl;

exit( EXIT_SUCCESS );
}

サンプルを見れば解かるが、メンバ関数もメンバポインタで扱うことが出来る。これを宣言文や呼び出しを直感的に行えるようにラップしたのがboost::mem_fnかと思われる。

メモ続き

課題23
#include <stdio.h>
#include <stdlib.h>

/*
* element of list
*/
typedef struct Element {
int value;
struct Element *next;
} Element;

/*
* Returns the value of element
* First argument: target element
*/
int getValue( Element *_arg_element ) {
return _arg_element->value;
}

/*
* Returns the next element
* First argument: target element
*/
Element *getNext( Element *_arg_element ) {
return _arg_element->next;
}

/*
* Set the value of element
* First argument: target element
* Second argument: value
*/
void setValue( Element *_arg_element, int _arg_value ) {
_arg_element->value = _arg_value;
}

/*
* Set the next element
* First argument: target element
* Second argument: next element
*/
void setNext( Element *_arg_element, Element *_arg_next ) {
_arg_element->next = _arg_next;
}

/*
* a thing well known as "init"
* First argument: target element
*/
void initElement( Element *_arg_element ) {
setValue( _arg_element, 0 );
setNext( _arg_element, NULL );
}

/*
* Inserts the element to correct position in the list
* First argument: first element of the list
* Second argument: element to insert
*/
void insertElement( Element *_arg_begin, Element *_arg_element ) {
Element *previous;
for( previous = NULL; _arg_begin != NULL; previous = _arg_begin, _arg_begin = getNext( _arg_begin ) ) {
if( getValue( _arg_begin ) > getValue( _arg_element ) ) {
setNext( _arg_element, _arg_begin );
setNext( previous, _arg_element );
return;
}
}
setNext( previous, _arg_element );
}

/*
* Free all elements in the list
* First argument: first element of the list
*/
void freeList( Element *_arg_begin ) {
Element *iterator;
for( iterator = _arg_begin; iterator != NULL; iterator = getNext( iterator ) )
free( iterator );
}

/*
* main function
*/
int main() {
Element *base = malloc( sizeof( Element ) );
initElement( base );

Element *temp;

while( 1 ) {
temp = malloc( sizeof( Element ) );
if( temp == NULL ) {
freeList( base );
printf( "Memory allocation failed.\n" );
exit( EXIT_FAILURE );
}
initElement( temp );
int input;
scanf( "%d", &input );
if( !input )break;
setValue( temp, input );
insertElement( base, temp );
}

Element *iterator;
for( iterator = getNext( base ); iterator != NULL; ) {
printf( "%d\n", getValue( iterator ) );
iterator = getNext( iterator );
}

freeList( base );
exit( EXIT_SUCCESS );
}