/*---------------------------------------------------------------------------* Project: Horizon File: gr_Shader.cpp Copyright (C)2010 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 26006 $ *---------------------------------------------------------------------------*/ #include namespace nn { namespace gr { namespace CTR { void Shader::SetupBinary( const void* shader_binary, const int vtx_shader_index, const int geo_shader_index ) { const u32* binary = reinterpret_cast< const u32* >( shader_binary ); NN_GR_ASSERT( binary != NULL ); NN_GR_ASSERT( *binary == 0x424C5644 ); // DVLB ++binary; NN_GR_ASSERT( *binary < EXE_IMAGE_MAX ); m_ExeImageInfoNum = *binary; ++binary; m_VtxShaderIndex = vtx_shader_index; m_GeoShaderIndex = geo_shader_index; m_VtxShaderBoolMapUniform = 0; m_GeoShaderBoolMapUniform = 0; for ( int i = 0; i < m_ExeImageInfoNum; ++i ) { m_ExeImageInfo[ i ] = reinterpret_cast< const ExeImageInfo* >( (u8*)shader_binary + *binary ); NN_GR_ASSERT( m_ExeImageInfo[ i ]->signature == 0x454c5644 ); // DVLP ++binary; } const u32* package_info = binary; NN_GR_ASSERT( *binary == 0x504C5644 ); // DVLP ++binary; ++binary; m_Instruction = reinterpret_cast< const u32* >( (u8*)package_info + *binary ); ++binary; m_InstructionCount = *binary; ++binary; const u32* swizzle = reinterpret_cast< const u32* >( (u8*)package_info + *binary ); ++binary; m_SwizzleCount = *binary; NN_GR_ASSERT( m_SwizzleCount < SWIZZLE_PATTERN_MAX ); ++binary; for ( int i = 0; i < m_SwizzleCount; i++ ) { m_Swizzle[ i ] = swizzle[ i * 2 ] ; } m_DrawMode = PICA_DATA_DRAW_TRIANGLES; // 範囲テスト NN_GR_ASSERT( 0 <= m_VtxShaderIndex && m_VtxShaderIndex < m_ExeImageInfoNum ); // バイナリとの整合性のテスト NN_GR_ASSERT( !m_ExeImageInfo[ m_VtxShaderIndex ]->isGeoShader ); if ( IsEnableGeoShader() ) { // 範囲テスト NN_GR_ASSERT( m_GeoShaderIndex < GetShaderNum() ); // バイナリとの整合性のテスト NN_GR_ASSERT( m_ExeImageInfo[ m_GeoShaderIndex ]->isGeoShader ); // 定数レジスタのコマンド生成 m_CmdCacheGeoConstNum = MakeConstRgCommand_( m_CmdCacheGeoConst, true ) - m_CmdCacheGeoConst; NN_GR_ASSERT( m_CmdCacheGeoConstNum <= CONST_REG_COMMAND_MAX ); } // 定数レジスタのコマンド生成 m_CmdCacheVtxConstNum = MakeConstRgCommand_( m_CmdCacheVtxConst, false ) - m_CmdCacheVtxConst; NN_GR_ASSERT( m_CmdCacheVtxConstNum <= CONST_REG_COMMAND_MAX ); // 出力属性のコマンド生成 m_CmdCacheOutAttrNum = MakeOutAttrCommand_( m_CmdCacheOutAttr ) - m_CmdCacheOutAttr; NN_GR_ASSERT( m_CmdCacheOutAttrNum <= OUT_ATTR_COMMAND_MAX ); } //------------------------------------------------------------------------ u32* Shader::MakeFullCommand( u32* command ) const { { // ジオメトリシェーダー使用設定コマンドなどの生成 command = MakePrepareCommand( command ); } if ( IsEnableGeoShader() ) { // ジオメトリシェーダー command = MakeGeoProgramCommand( command ); command = MakeGeoSwizzleCommand( command ); command = MakeGeoConstRgCommand( command ); command = MakeGeoBoolMapCommand( command ); } { // 頂点シェーダー command = MakeVtxProgramCommand( command ); command = MakeVtxSwizzleCommand( command ); command = MakeVtxConstRgCommand( command ); command = MakeVtxBoolMapCommand( command ); } { // 出力属性(outmap)関連 command = MakeOutAttrCommand( command ); } return command; } //------------------------------------------------------------------------ u32* Shader::MakePrepareCommand( u32* command ) const { { // 0x253 [8:9]への設定 if ( IsEnableGeoShader() ) { *command++ = PICA_DATA_DRAW_GEOMETRY_PRIMITIVE << 8; } else { *command++ = m_DrawMode << 8; } *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_VS_OUT_REG_NUM3, 2 ); } { // 0x251へのダミーコマンド command = MakeDummyCommand_( command, PICA_REG_VS_OUT_REG_NUM2, DUMMY_DATA_NUM_251 ); } { // 0x200へのダミーコマンド command = MakeDummyCommand_( command, PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, DUMMY_DATA_NUM_200 ); } { // ジオメトリシェーダーの有効、無効を設定 *command++ = IsEnableGeoShader() ? 2 : 0; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DRAW_MODE0, 1 ); } { // 0x200へのダミーコマンド command = MakeDummyCommand_( command, PICA_REG_VERTEX_ATTR_ARRAYS_BASE_ADDR, DUMMY_DATA_NUM_200 ); } { // ジオメトリシェーダーの設定を頂点シェーダーと共有するかどうか *command++ = IsEnableGeoShader() ? 1 : 0; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_VS_COM_MODE, 1 ); } return command; } //------------------------------------------------------------------------ u32* Shader::MakeVtxProgramCommand( u32* command ) const { int shader_index = GetVtxShaderIndex(); u32 reg_addr = PICA_REG_VS_PROG_ADDR; // 0x2cb u32 reg_load = PICA_REG_VS_PROG_DATA0; // 0x2cc u32 reg_end = PICA_REG_VS_PROG_UPDATE_END; // 0x2bf { // プログラムコードのロードアドレスを設定 *command++ = 0; *command++ = PICA_CMD_HEADER_SINGLE( reg_addr ); } { // プログラムコードのロード NN_GR_ASSERT( 0 <= shader_index && shader_index < m_ExeImageInfoNum ); const ExeImageInfo* exe_info = m_ExeImageInfo[ shader_index ]; NN_UNUSED_VAR( exe_info ); u32 instructionCount = m_InstructionCount; if ( instructionCount > 512 ) { instructionCount = 512; } command = MakeLoadCommand_( command, reg_load, m_Instruction, m_InstructionCount < 512 ? m_InstructionCount : 512 ); } { // プログラム更新の完了通知 *command++ = 1; *command++ = PICA_CMD_HEADER_SINGLE( reg_end ); } return command; } //------------------------------------------------------------------------ u32* Shader::MakeGeoProgramCommand( u32* command ) const { int shader_index = GetGeoShaderIndex(); u32 reg_addr = PICA_REG_GS_PROG_ADDR; // 0x29b u32 reg_load = PICA_REG_GS_PROG_DATA0; // 0x29c u32 reg_end = PICA_REG_GS_PROG_UPDATE_END; // 0x28f { // プログラムコードのロードアドレスを設定 *command++ = 0; *command++ = PICA_CMD_HEADER_SINGLE( reg_addr ); } { // プログラムコードのロード NN_GR_ASSERT( 0 <= shader_index && shader_index < m_ExeImageInfoNum ); const ExeImageInfo* exe_info = m_ExeImageInfo[ shader_index ]; NN_UNUSED_VAR( exe_info ); command = MakeLoadCommand_( command, reg_load, m_Instruction, m_InstructionCount ); } { // プログラム更新の完了通知 *command++ = 1; *command++ = PICA_CMD_HEADER_SINGLE( reg_end ); } return command; } //------------------------------------------------------------------------ u32* Shader::MakeConstRgCommand_( u32* command, const bool is_geometry_shader ) { int shader_index = GetVtxShaderIndex(); u32 reg_float = PICA_REG_VS_FLOAT_ADDR; // 0x2c0 u32 reg_integer = PICA_REG_VS_INT0; // 0x2b1 u32* boolMap = &m_VtxShaderBoolMapUniform; if ( is_geometry_shader ) { shader_index = GetGeoShaderIndex(); reg_float = PICA_REG_GS_FLOAT_ADDR; // 0x290 reg_integer = PICA_REG_GS_INT0; // 0x281 boolMap = &m_GeoShaderBoolMapUniform; } // プログラム情報 NN_GR_ASSERT( 0 <= shader_index && shader_index < m_ExeImageInfoNum ); const ExeImageInfo* exe_info = m_ExeImageInfo[ shader_index ]; // 定数レジスタ情報 struct SetupInfo { u16 type; u16 index; u32 value[4]; }; const SetupInfo* setupInfo = reinterpret_cast< const SetupInfo* >( reinterpret_cast< const u8* >( exe_info ) + exe_info->setupOffset ); // 定数レジスタのコマンド生成 for ( int i = 0; i < exe_info->setupCount; ++i ) { const SetupInfo& info = setupInfo[ i ]; const u32* value = info.value; switch ( info.type ) { case 0 : // bool register setup *boolMap |= ( info.value[ 0 ] << info.index ) & ( 1 << info.index ); break; case 1 : // integer register setup *command++ = value[ 0 ] | value[ 1 ] << 8 | value[ 2 ] << 16 | value[ 3 ] << 24; *command++ = PICA_CMD_HEADER_SINGLE( reg_integer + info.index ); break; case 2 : // float register setup *command++ = info.index; *command++ = PICA_CMD_HEADER_BURSTSEQ( reg_float, 4 ); *command++ = ( value[ 3 ] << 8 & 0xffffff00 ) | ( value[ 2 ] >> 16 & 0x000000ff ); *command++ = ( value[ 2 ] << 16 & 0xffff0000 ) | ( value[ 1 ] >> 8 & 0x0000ffff ); *command++ = ( value[ 1 ] << 24 & 0xff000000 ) | ( value[ 0 ] >> 0 & 0x00ffffff ); *command++ = PADDING_DATA; // padding break; } } return command; } //------------------------------------------------------------------------ u32* Shader::MakeOutAttrCommand_( u32* command ) { // 出力属性の設定 // ジオメトリシェーダーが有効な場合、 // 出力属性は、ジオメトリシェーダーについて設定をおこなう const int shader_index = IsEnableGeoShader() ? GetGeoShaderIndex() : GetVtxShaderIndex(); NN_GR_ASSERT( 0 <= shader_index && shader_index < m_ExeImageInfoNum ); enum { OUT_ATTR_INDEX_MAX = 7, OUT_ATTR_DIMENTION_MAX = 4, OUT_ATTR_BUFFER_MAX = 16 * 4, VS_OUT_ATTR_INDEX_MAX = 16 }; // 出力属性情報 struct OutmapInfo { u16 type; u16 index; u16 mask; u16 reserve; }; u32 outNum = 0; u32 useTex = 0; u32 clock = 0; u32 outMask = 0; u32 attr[ OUT_ATTR_INDEX_MAX ]; { // 出力属性の設定をもとめる // プログラム情報 const ExeImageInfo* exe_info = m_ExeImageInfo[ shader_index ]; // 実際の出力属性情報. OutmapInfo outmap_buffer[ OUT_ATTR_BUFFER_MAX ]; s32 outMapBufferCount = 0; // マージ. if ( IsEnableGeoShader() && exe_info->outputMaps ) { u32 gs_copy_mask = 0; u32 vs_copy_mask = 0; // GS出力属性情報 const OutmapInfo* outmapInfo = reinterpret_cast< const OutmapInfo* >( reinterpret_cast< const u8* >( exe_info ) + exe_info->outMapOffset ); // VSプログラム情報 int vtx_shader_index = GetVtxShaderIndex(); NN_GR_ASSERT( 0 <= vtx_shader_index && vtx_shader_index < m_ExeImageInfoNum ); const ExeImageInfo* vtx_exe_info = m_ExeImageInfo[ vtx_shader_index ]; // VS出力属性情報 const OutmapInfo* vtxOutmapInfo = reinterpret_cast< const OutmapInfo* >( reinterpret_cast< const u8* >( vtx_exe_info ) + vtx_exe_info->outMapOffset ); // 最初にVSとGS両方で指定されているものを設定. NN_GR_ASSERT( outMapBufferCount < OUT_ATTR_BUFFER_MAX ); for( int g = 0; g < exe_info->outMapCount; ++g ) { for( int v = 0; v < vtx_exe_info->outMapCount; ++v ) { if ( outmapInfo[ g ].type == vtxOutmapInfo[ v ].type ) { NN_GR_ASSERT( outMapBufferCount < OUT_ATTR_INDEX_MAX ); outmap_buffer[ outMapBufferCount ].type = outmapInfo[ g ].type; outmap_buffer[ outMapBufferCount ].index = outMapBufferCount; outmap_buffer[ outMapBufferCount ].mask = outmapInfo[ g ].mask; gs_copy_mask |= 1 << g; vs_copy_mask |= 1 << v; ++outMapBufferCount; } } } // 次にGSのみで定義されているものを設定. for( int g = 0; g < exe_info->outMapCount; ++g ) { if ( !( gs_copy_mask & ( 1 << g ) ) && ( outmapInfo[ g ].type >= 0 && outmapInfo[ g ].type < 9 && outmapInfo[ g ].type != 7 ) ) { NN_GR_ASSERT( outMapBufferCount < OUT_ATTR_BUFFER_MAX ); outmap_buffer[ outMapBufferCount ].type = outmapInfo[ g ].type; outmap_buffer[ outMapBufferCount ].index = outMapBufferCount; outmap_buffer[ outMapBufferCount ].mask = outmapInfo[ g ].mask; ++outMapBufferCount; } } // 最後ににVSのみで定義されているものを設定. for( int v = 0; v < vtx_exe_info->outMapCount; ++v ) { if ( !( vs_copy_mask & ( 1 << v ) ) && ( vtxOutmapInfo[ v ].type >= 0 && vtxOutmapInfo[ v ].type < 9 && vtxOutmapInfo[ v ].type != 7 ) ) { NN_GR_ASSERT( outMapBufferCount < OUT_ATTR_BUFFER_MAX ); outmap_buffer[ outMapBufferCount ].type = vtxOutmapInfo[ v ].type; outmap_buffer[ outMapBufferCount ].index = outMapBufferCount; outmap_buffer[ outMapBufferCount ].mask = vtxOutmapInfo[ v ].mask; ++outMapBufferCount; } } } else { // 出力属性情報 const OutmapInfo* outmapInfo = reinterpret_cast< const OutmapInfo* >( reinterpret_cast< const u8* >( exe_info ) + exe_info->outMapOffset ); // マージしない場合はコピー. for( int i = 0; i < exe_info->outMapCount; ++i ) { outmap_buffer[ i ] = outmapInfo[ i ]; } outMapBufferCount = exe_info->outMapCount; } for ( int index = 0; index < OUT_ATTR_INDEX_MAX; ++index ) { attr[ index ] = 0x1f1f1f1f; for ( int i = 0; i ( reinterpret_cast< const u8* >( exe_info ) + exe_info->outMapOffset ); for ( int index = 0; index < VS_OUT_ATTR_INDEX_MAX; ++index ) { vtxAttr[ index ] = 0x1f1f1f1f; for ( int i = 0; i < exe_info->outMapCount; ++i ) { u32 c = 0; for ( int j = 0; outmapInfo[ i ].index == index && j < OUT_ATTR_DIMENTION_MAX; ++j ) { if ( ( outmapInfo[ i ].mask & ( 1 << j ) ) == 0 ) continue; int value = 0x1f; switch ( outmapInfo[ i ].type ) { case 0 : value = 0x00 + c++; break; // position case 1 : value = 0x04 + c++; break; // quaternion case 2 : value = 0x08 + c++; break; // color case 3 : if (c < 2) value = 0x0c + c++; break; // texcoord0 case 4 : value = 0x10; break; // texcoord0w case 5 : if (c < 2) value = 0x0e + c++; break; // texcoord1 case 6 : if (c < 2) value = 0x16 + c++; break; // texcoord2 case 8 : if (c < 3) value = 0x12 + c++; break; // view case 9 : value = 0xff; } vtxAttr[ index ] = vtxAttr[ index ] & ~( 0xff << ( j * 8 ) ) | value << ( j * 8 ); } } if ( vtxAttr[ index ] != 0x1f1f1f1f ) { vtxOutMask |= ( 1 << index ); ++vtxOutNum; } } u32 gsDataMode = m_ExeImageInfo[ m_GeoShaderIndex ]->gsDataMode; // GL_GEOMETRY_PRIMITIVE_DMP *command++ = 0x00000000; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DRAW_MODE0, 0xa ); // 0x229 // GL_GEOMETRY_PRIMITIVE_DMP *command++ = 0x00000000; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DRAW_MODE1, 0x3 ); // 0x253 // 頂点シェーダーの出力数 *command++ = 0x08000000 | (gsDataMode == 0 ? 0x0000 : 0x0100) | vtxOutNum - 1; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_GS_ATTR_NUM, 0xb ); // 0x289 // ジオメトリシェーダーのmainラベルのアドレス *command++ = 0x7fff0000 | m_ExeImageInfo[ m_GeoShaderIndex ]->mainAddress; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_START_ADDR ); // 0x28a // 頂点シェーダーの出力mask *command++ = outMask; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_OUT_REG_MASK ); // 0x28d // 頂点シェーダーのmainラベルのアドレス *command++ = 0x7fff0000 | m_ExeImageInfo[ m_VtxShaderIndex ]->mainAddress; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_START_ADDR ); // 0x2ba // 頂点シェーダーの出力レジスタマスク *command++ = vtxOutMask; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_REG_MASK ); // 0x2bd // 頂点シェーダーの出力数 *command++ = vtxOutNum - 1; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_REG_NUM2 ); // 0x251 // 頂点シェーダーの出力とジオメトリシェーダーの入力は一致させているのが前提 *command++ = 0x76543210; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_ATTR_IN_REG_MAP0 ); // 0x28b *command++ = 0xfedcba98; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_ATTR_IN_REG_MAP1 ); // 0x28c if ( gsDataMode == 2 ) { gsDataMode |= 0x01 << 24; gsDataMode |= ( m_ExeImageInfo[ m_GeoShaderIndex ]->gsVertexStartIndex ) << 16; gsDataMode |= ( vtxOutNum - 1 ) << 12; gsDataMode |= ( m_ExeImageInfo[ m_GeoShaderIndex ]->gsVertexNum - 1 ) << 8; } *command++ = gsDataMode; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_MISC_REG0 ); // 0x252 *command++ = vtxOutNum - 1; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_REG_NUM1 ); // 0x24a } else { *command++ = 0x00000100; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DRAW_MODE0, 0xa ); // 0x229 *command++ = 0x00000100; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DRAW_MODE1, 0x3 ); // 0x253 // 頂点シェーダーのmainラベルのアドレス *command++ = 0x7fff0000 | m_ExeImageInfo[ m_VtxShaderIndex ]->mainAddress; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_START_ADDR ); // 0x2ba // 頂点シェーダーの出力レジスタマスク *command++ = outMask; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_REG_MASK ); // 0x2bd *command++ = outNum - 1; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_REG_NUM2 ); // 0x251 *command++ = 0; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_GS_MISC_REG0 ); // 0x252 *command++ = outNum - 1; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_REG_NUM1 ); // 0x24a } { *command++ = outNum - 1; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_VS_OUT_REG_NUM3, 1 ); // 0x25e *command++ = outNum; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_REG_NUM0 ); // 0x04f // 出力属性のコマンド outNum = 0; for ( int index = 0; index < OUT_ATTR_INDEX_MAX; ++index ) { if ( attr[ index ] != 0x1f1f1f1f ) { *command++ = attr[ index ]; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_ATTR0 + outNum ); ++outNum; } } for ( int index = outNum; index < OUT_ATTR_INDEX_MAX; ++index ) { *command++ = attr[ index ]; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_ATTR0 + index ); } } // テクスチャ座標を使うかどうかを設定 *command++ = useTex; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_ATTR_MODE ); // 0x064 // 出力属性のクロック制御を設定 *command++ = clock; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_ATTR_CLK ); // 0x06f if ( IsEnableGeoShader() ) { *command++ = 0; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_VS_OUT_REG_NUM3, 8 ); // 0x25e } return command; } //------------------------------------------------------------------------ u32* Shader::MakeLoadCommand_( u32* command, const u32 load_reg, const u32* src_buffer_ptr, const u32 src_data_num ) const { enum { WRITE_MAX = 128 }; u32 rest = src_data_num; while ( true ) { if ( rest <= WRITE_MAX ) { *command++ = *src_buffer_ptr++; *command++ = PICA_CMD_HEADER_BURST( load_reg, rest ); std::memcpy( command, src_buffer_ptr, ( rest - 1 ) * sizeof( u32 ) ); command += rest - 1; if ( ( rest & 1 ) == 0 ) *command++ = PADDING_DATA; // padding break; } else { *command++ = *src_buffer_ptr++; *command++ = PICA_CMD_HEADER_BURST( load_reg, WRITE_MAX ); std::memcpy( command, src_buffer_ptr, ( WRITE_MAX - 1 ) * sizeof( u32 ) ); command += WRITE_MAX - 1; src_buffer_ptr += WRITE_MAX - 1; rest -= WRITE_MAX; if ( ( WRITE_MAX & 1 ) == 0 ) *command++ = PADDING_DATA; // padding } } return command; } //------------------------------------------------------------------------ u32* Shader::MakeDummyCommand_( u32* command, const u32 load_reg, const u32 dataNum ) const { *command++ = 0; *command++ = PICA_CMD_HEADER_BURST_BE( load_reg, dataNum, 0 ); for ( int i = 0; i < dataNum - ( dataNum & 1 ); ++i) { *command++ = PADDING_DATA; } return command; } //------------------------------------------------------------------------ bool Shader::SearchBindSymbol( BindSymbol* symbol, const char* name ) const { const int shader_index = symbol->shaderType == BindSymbol::SHADER_TYPE_GEOMETRY ? GetGeoShaderIndex() : GetVtxShaderIndex(); NN_GR_ASSERT( 0 <= shader_index && shader_index < m_ExeImageInfoNum ); // プログラム情報 const ExeImageInfo* exe_info = m_ExeImageInfo[ shader_index ]; // シンボル情報 struct BindSymbolInfo { u32 nameIndex; u32 regIndex; }; const BindSymbolInfo* bind_symbol_info = reinterpret_cast< const BindSymbolInfo* >( reinterpret_cast< const u8* >( exe_info ) + exe_info->bindSymbolOffset ); // 文字列情報 const char* string = reinterpret_cast< const char* >( reinterpret_cast< const u8* >( exe_info ) + exe_info->stringOffset ); // 検索 u32 namelen = std::strlen( name ); for ( int i = 0; i < exe_info->bindSymbolCount; ++i ) { const BindSymbolInfo& info = bind_symbol_info[ i ]; if ( std::strncmp( name, &string[ info.nameIndex ], namelen ) != 0 ) continue; if ( string[ info.nameIndex + namelen ] != '\0' && string[ info.nameIndex + namelen ] != '.' ) continue; symbol->name = &string[ info.nameIndex ]; symbol->start = (info.regIndex & 0x0000ffff); symbol->end = (info.regIndex & 0xffff0000) >> 16; if ( 136 <= symbol->start ) { return false; } else if ( 120 <= symbol->start ) { symbol->start -= 120; symbol->end -= 120; return symbol->symbolType == BindSymbol::SYMBOL_TYPE_BOOL; } else if ( 112 <= symbol->start ) { symbol->start -= 112; symbol->end -= 112; return symbol->symbolType == BindSymbol::SYMBOL_TYPE_INTEGER; } else if ( 16 <= symbol->start ) { symbol->start -= 16; symbol->end -= 16; return symbol->symbolType == BindSymbol::SYMBOL_TYPE_FLOAT; } else { return symbol->symbolType == BindSymbol::SYMBOL_TYPE_INPUT; } } return false; } //------------------------------------------------------------------------ u32 Shader::SearchBindSymbolNum( const BindSymbol::ShaderType shader_type, const BindSymbol::SymbolType symbol_type ) const { const int shader_index = ( shader_type == BindSymbol::SHADER_TYPE_GEOMETRY ) ? GetGeoShaderIndex() : GetVtxShaderIndex(); NN_GR_ASSERT( 0 <= shader_index && shader_index < m_ExeImageInfoNum ); // プログラム情報 const ExeImageInfo* exe_info = m_ExeImageInfo[ shader_index ]; // 出力属性情報 struct BindSymbolInfo { u32 nameIndex; u32 regIndex; }; const BindSymbolInfo* bind_symbol_info = reinterpret_cast< const BindSymbolInfo* >( reinterpret_cast< const u8* >( exe_info ) + exe_info->bindSymbolOffset ); int num = 0; // 検索 for ( int i = 0; i < exe_info->bindSymbolCount; ++i ) { int regStart = bind_symbol_info[ i ].regIndex & 0x0000ffff; if ( 120 <= regStart && regStart < 136 && symbol_type == BindSymbol::SYMBOL_TYPE_BOOL ) ++num; else if ( 112 <= regStart && regStart < 115 && symbol_type == BindSymbol::SYMBOL_TYPE_INTEGER ) ++num; else if ( 16 <= regStart && regStart < 111 && symbol_type == BindSymbol::SYMBOL_TYPE_FLOAT ) ++num; else if ( regStart < 15 && symbol_type == BindSymbol::SYMBOL_TYPE_INPUT ) ++num; } return num; } //------------------------------------------------------------------------ bool Shader::SearchBindSymbol( BindSymbol* symbol, const u8 symbol_index ) const { const BindSymbol::SymbolType type = symbol->symbolType; const int shader_index = type == ( BindSymbol::SHADER_TYPE_GEOMETRY ) ? GetGeoShaderIndex() : GetVtxShaderIndex(); NN_GR_ASSERT( 0 <= shader_index && shader_index < m_ExeImageInfoNum ); // プログラム情報 const ExeImageInfo* exe_info = m_ExeImageInfo[ shader_index ]; // シンボル情報 struct BindSymbolInfo { u32 nameIndex; u32 regIndex; }; const BindSymbolInfo* bind_symbol_info = reinterpret_cast< const BindSymbolInfo* >( reinterpret_cast< const u8* >( exe_info ) + exe_info->bindSymbolOffset ); // 文字列情報 const char* string = reinterpret_cast< const char* >( reinterpret_cast< const u8* >( exe_info ) + exe_info->stringOffset ); int index = -1; // 検索 for ( int i = 0; i < exe_info->bindSymbolCount; ++i ) { int regStart = bind_symbol_info[ i ].regIndex & 0x0000ffff; if ( 120 <= regStart && regStart < 136 && type == BindSymbol::SYMBOL_TYPE_BOOL ) ++index; else if ( 112 <= regStart && regStart < 115 && type == BindSymbol::SYMBOL_TYPE_INTEGER ) ++index; else if ( 16 <= regStart && regStart < 111 && type == BindSymbol::SYMBOL_TYPE_FLOAT ) ++index; else if ( regStart < 15 && type == BindSymbol::SYMBOL_TYPE_INPUT ) ++index; if ( index == symbol_index ) { const BindSymbolInfo& info = bind_symbol_info[ i ]; symbol->name = &string[ info.nameIndex ]; symbol->start = (info.regIndex & 0x0000ffff); symbol->end = (info.regIndex & 0xffff0000) >> 16; if ( 120 <= symbol->start ) { symbol->start -= 120; symbol->end -= 120; } else if ( 112 <= symbol->start ) { symbol->start -= 112; symbol->end -= 112; } else if ( 16 <= symbol->start ) { symbol->start -= 16; symbol->end -= 16; } return true; } } return false; } } //namespace CTR } //namespace gr } //namespace nn