/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_ShaderBinaryInfo.h Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. 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. $Revision: 28011 $ *---------------------------------------------------------------------------*/ #ifndef NW_GFX_SHADERBINARYINFO_H_ #define NW_GFX_SHADERBINARYINFO_H_ #include #include #include #include #include // シェーダバイナリの解析等のシェーダ用のドライバ層です。 namespace nw { namespace gfx { //--------------------------------------------------------------------------- //! @brief シェーダバイナリを解析し、コマンドの生成等の処理をおこなうクラスです。 //--------------------------------------------------------------------------- class ShaderBinaryInfo { private: class SafeBuffer; public: // シンボルの型 enum SymbolType { SYMBOL_TYPE_INVALID, //!< 不正な型。 SYMBOL_TYPE_INPUT, //!< 頂点属性。(v0 ... v15) SYMBOL_TYPE_FLOAT, //!< 浮動小数定数レジスタ。 (c0 ... c95) SYMBOL_TYPE_INT, //!< 整数定数レジスタ。(i0 ... i3) SYMBOL_TYPE_BOOL //!< ブール定数レジスタ。(b0 ... b15) }; //--------------------------------------------------------------------------- //! @brief コンストラクタです。 //! //! @param[in] shaderBinary シェーダバイナリへのポインタです。 //--------------------------------------------------------------------------- ShaderBinaryInfo( const void* shaderBinary ) : m_pShaderBinary( reinterpret_cast(shaderBinary) ), m_ExeImageCount( 0 ), m_pInstruction( NULL ), m_InstructionCount( 0 ), m_SwizzleCount( 0 ), m_GeometryShaderCount( 0 ) { for (int i = 0; i < EXE_IMAGE_MAX; ++i) { m_ExeImageInfo[ i ] = NULL; } // デバッグビルド以外では、m_Swizzle のクリア処理は行なわない。 #if defined(NW_DEBUG) for (int i = 0; i < SWIZZLE_PATTERN_MAX; ++i) { m_Swizzle[ i ] = 0; } #endif } //--------------------------------------------------------------------------- //! @brief シェーダバイナリ転送用コマンドのサイズを取得します。 //! //! @return シェーダバイナリ転送用に必要なコマンドサイズです。 //--------------------------------------------------------------------------- s32 GetCommonCommandSize() const; //--------------------------------------------------------------------------- //! @brief 指定したバッファにシェーダバイナリ転送用のコマンドを作成します。 //! //! @param[out] bufferAddress コマンドを生成するバッファのアドレスです。 //! @param[in] bufferSize バッファの最大サイズです。 //! //! @return 出力したコマンドサイズです。 //--------------------------------------------------------------------------- s32 BuildCommonCommand( u32* bufferAddress, u32 bufferSize ) const; //--------------------------------------------------------------------------- //! @brief カレントのコマンドバッファにシェーダバイナリ転送用のコマンドを //! 作成します。 //! //! @return 出力したコマンドサイズです。 //--------------------------------------------------------------------------- s32 BuildCommonCommand() const { u32* currentBuffer = static_cast( internal::NWGetCurrentCmdBuffer() ); u32* cmdBufferEnd = static_cast( internal::NWGetCmdBufferEnd() ); u32 bufferSize = ut::GetOffsetFromPtr( currentBuffer, cmdBufferEnd ); s32 result = this->BuildCommonCommand( currentBuffer, bufferSize ); if ( result > 0 ) { internal::NWForwardCurrentCmdBuffer( result ); } return result; } //--------------------------------------------------------------------------- //! @brief シェーダプログラム設定用コマンドのサイズを取得します。 //! //! @param[in] vertexIndex 頂点シェーダのインデックスを指定します。 //! @param[in] geometryIndex ジオメトリシェーダのインデックスを指定します。 //! //! @return シェーダプログラム設定用に必要なコマンドサイズです。 //--------------------------------------------------------------------------- s32 GetShaderProgramCommandSize( s32 vertexIndex, s32 geometryIndex ) const; //--------------------------------------------------------------------------- //! @brief シェーダプログラム設定用のコマンドを作成します。 //! //! @param[in] vertexIndex 頂点シェーダのインデックスを指定します。 //! @param[in] geometryIndex ジオメトリシェーダのインデックスを指定します。 //! @param[out] bufferAddress コマンドを生成するバッファのアドレスです。 //! @param[in] bufferSize バッファの最大サイズです。 //! //! @return 出力したコマンドサイズです。 //--------------------------------------------------------------------------- s32 BuildShaderProgramCommand( s32 vertexIndex, s32 geometryIndex, u32* bufferAddress, u32 bufferSize ) const; //--------------------------------------------------------------------------- //! @brief 指定したバッファにシェーダプログラム設定用のコマンドを作成します。 //! //! @param[in] vertexIndex 頂点シェーダのインデックスです。 //! @param[in] geometryIndex ジオメトリシェーダのインデックスです。 //! //! @return 出力したコマンドサイズです。 //--------------------------------------------------------------------------- s32 BuildShaderProgramCommand( s32 vertexIndex, s32 geometryIndex ) const { u32* currentBuffer = static_cast( internal::NWGetCurrentCmdBuffer() ); u32* cmdBufferEnd = static_cast( internal::NWGetCmdBufferEnd() ); u32 bufferSize = ut::GetOffsetFromPtr( currentBuffer, cmdBufferEnd ); s32 result = this->BuildShaderProgramCommand( vertexIndex, geometryIndex, currentBuffer, bufferSize ); if ( result > 0 ) { internal::NWForwardCurrentCmdBuffer( result ); } return result; } //--------------------------------------------------------------------------- //! @name シェーダプログラムの情報へのアクセサ //@{ //--------------------------------------------------------------------------- //! @brief ジオメトリシェーダかどうかを取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! //! @return 指定したシェーダがジオメトリシェーダであれば true を返します。 //--------------------------------------------------------------------------- bool IsGeometryShader(s32 shaderIndex) const { const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex); return exeInfo->isGeometryShader ? true : false; } //--------------------------------------------------------------------------- //! @brief 頂点ユニフォームインデックスを取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! @param[in] name 頂点ユニフォームの名前です。 //! //! @return 対応する頂点インデックスと型情報の組み合わせを取得します。 //--------------------------------------------------------------------------- // NOTE: コンパイラの不具合で、pair が正しく返せない場合があるので、noinline にしておく。 __declspec(noinline) ::std::pair SearchUniformIndex(s32 shaderIndex, const char* name) const { enum { BEGIN_INPUT = 0, BEGIN_FLOAT = 16, BEGIN_INT = 112, BEGIN_BOOL = 120, END_SYMBOL = 136 }; // 出力属性情報 struct BindSymbolInfo { u32 nameIndex; u32 regIndex; }; const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex); const BindSymbolInfo* bindSymbolInfoTable = static_cast( ut::AddOffsetToPtr(exeInfo, exeInfo->bindSymbolOffset) ); const char* stringTable = static_cast( ut::AddOffsetToPtr(exeInfo, exeInfo->stringOffset) ); SymbolType symbolType = SYMBOL_TYPE_INVALID; s32 symbolIndex = -1; u32 nameLen = std::strlen( name ); for (int i = 0; i < static_cast(exeInfo->bindSymbolCount); ++i) { const BindSymbolInfo& info = bindSymbolInfoTable[ i ]; const char* symbolName = &stringTable[ info.nameIndex ]; if ( std::strncmp( name, symbolName, nameLen ) != 0 ) { continue; } if ( symbolName[ nameLen ] != '\0' && symbolName[ nameLen ] != '.' ) { continue; } symbolIndex = static_cast( info.regIndex & 0x0000ffff ); if ( END_SYMBOL <= symbolIndex ) { symbolIndex = -1; } else if (BEGIN_BOOL <= symbolIndex ) { symbolType = SYMBOL_TYPE_BOOL; symbolIndex = symbolIndex - BEGIN_BOOL; } else if (BEGIN_INT <= symbolIndex ) { symbolType = SYMBOL_TYPE_INT; symbolIndex = symbolIndex - BEGIN_INT; } else if (BEGIN_FLOAT <= symbolIndex ) { symbolType = SYMBOL_TYPE_FLOAT; symbolIndex = symbolIndex - BEGIN_FLOAT; } else { symbolType = SYMBOL_TYPE_INPUT; symbolIndex = symbolIndex; } break; } return std::make_pair(symbolIndex, symbolType); } //--------------------------------------------------------------------------- //! @brief 頂点ユニフォームインデックスを取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! @param[in] symbolType レジスタの種類です。 //! @param[in] index レジスタのインデックスです。 //! //! @return 対応する頂点インデックスとジオメトリシェーダフラグの組み合わせを取得します。 //--------------------------------------------------------------------------- const char* SearchUniformIndex(s32 shaderIndex, SymbolType symbolType, s32 index) const { enum { BEGIN_INPUT = 0, BEGIN_FLOAT = 16, BEGIN_INT = 112, BEGIN_BOOL = 120, END_SYMBOL = 136 }; // 出力属性情報 struct BindSymbolInfo { u32 nameIndex; u32 regIndex; }; const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex); const BindSymbolInfo* bindSymbolInfoTable = static_cast( ut::AddOffsetToPtr( exeInfo, exeInfo->bindSymbolOffset ) ); const char* stringTable = static_cast( ut::AddOffsetToPtr( exeInfo, exeInfo->stringOffset ) ); s32 targetIndex = 0; switch ( symbolType ) { case SYMBOL_TYPE_INPUT: { targetIndex = BEGIN_INPUT + index; } break; case SYMBOL_TYPE_FLOAT: { targetIndex = BEGIN_FLOAT + index; } break; case SYMBOL_TYPE_INT : { targetIndex = BEGIN_INT + index; } break; case SYMBOL_TYPE_BOOL : { targetIndex = BEGIN_BOOL + index; } break; default: NW_FATAL_ERROR("Unknown symbolType"); } for (int i = 0; i < static_cast(exeInfo->bindSymbolCount); ++i) { const BindSymbolInfo& info = bindSymbolInfoTable[ i ]; s32 symbolIndex = static_cast( info.regIndex & 0x0000ffff ); if (symbolIndex == targetIndex) { return &stringTable[ info.nameIndex ]; } } return NULL; } //--------------------------------------------------------------------------- //! @brief トータルのシンボル数を取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! @param[in] symbolType レジスタの種類です。 //! //! @return 入力タイプ //--------------------------------------------------------------------------- int SearchBinadSymbolCount(s32 shaderIndex, SymbolType symbolType) const { enum { BEGIN_INPUT = 0, END_INPUT = 15, BEGIN_FLOAT = 16, END_FLOAT = 111, BEGIN_INT = 112, END_INT = 119, BEGIN_BOOL = 120, END_BOOL = 135, END_SYMBOL = 136 }; // 出力属性情報 struct BindSymbolInfo { u32 nameIndex; u32 regIndex; }; const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex); const BindSymbolInfo* bindSymbolInfoTable = static_cast( ut::AddOffsetToPtr( exeInfo, exeInfo->bindSymbolOffset ) ); s32 count = 0; for (int i = 0; i < static_cast(exeInfo->bindSymbolCount); ++i) { const BindSymbolInfo& info = bindSymbolInfoTable[ i ]; s32 symbolIndex = static_cast( info.regIndex & 0x0000ffff ); switch ( symbolType ) { case SYMBOL_TYPE_INPUT: if (BEGIN_INPUT <= symbolIndex && symbolIndex <= END_INPUT) { ++count; } break; case SYMBOL_TYPE_FLOAT: if (BEGIN_FLOAT <= symbolIndex && symbolIndex <= END_FLOAT) { ++count; } break; case SYMBOL_TYPE_INT: if (BEGIN_INT <= symbolIndex && symbolIndex <= END_INT) { ++count; } break; case SYMBOL_TYPE_BOOL: if (BEGIN_BOOL <= symbolIndex && symbolIndex <= END_BOOL) { ++count; } break; default: NW_FATAL_ERROR("Unknown symbolType"); } } return count; } //--------------------------------------------------------------------------- //! @brief 頂点 bool レジスタの定数値を取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! //! @return 対応するシェーダプログラムの定数 bool 値を取得します。 //--------------------------------------------------------------------------- u32 GetBoolConstant(s32 shaderIndex) const { enum { TYPE_BOOL = 0, TYPE_INT = 1, TYPE_FLOAT = 2 }; const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex); // 定数レジスタ情報 struct SetupInfo { u16 type; u16 index; u32 value[4]; }; const SetupInfo* setupInfoTable = static_cast( ut::AddOffsetToPtr( exeInfo, exeInfo->setupOffset) ); u32 boolMap = 0; for ( int i = 0; i < static_cast(exeInfo->setupCount); ++i ) { const SetupInfo& info = setupInfoTable[ i ]; const u32* value = info.value; if (info.type == TYPE_BOOL) { boolMap |= (value[ 0 ] & 0x1) << info.index; } } return boolMap; } //--------------------------------------------------------------------------- //! @brief シェーダのアトリビュート数を取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! //! @return 対応するシェーダプログラムのアトリビュート数を取得します。 //--------------------------------------------------------------------------- u32 GetInputRegisterNum(s32 shaderIndex) const { enum { MAX_INPUT = 16 }; // ジオメトリシェーダは 16まで。 const ExeImageInfo* exeInfo = this->GetShaderProgramInfo( shaderIndex ); u32 mask = exeInfo->inputMask; s32 count = 0; for (int i = 0; i < 16; ++i) { if (mask & (1 << i)) { ++count; } } return count; } //--------------------------------------------------------------------------- //! @brief シェーダの出力数を取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! //! @return 対応するシェーダプログラムの入力数を取得します。 //--------------------------------------------------------------------------- u32 GetOutputRegisterNum(s32 shaderIndex) const { const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex); u32 mask = exeInfo->outputMask; s32 count = 0; for (int i = 0; i < 16; ++i) { if (mask & (1 << i)) { ++count; } } return count; } //--------------------------------------------------------------------------- //! @brief 頂点シェーダの出力レジスタ数を取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! @param[in] pNum 出力レジスタ数を取得する為のポインタです。 //! @param[in] pMask 出力レジスタマスクを取得する為のポインタです。 //--------------------------------------------------------------------------- void GetOutputRegisterNum(s32 shaderIndex, u32* pNum, u32* pMask) const { const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex); u32 mask = exeInfo->outputMask; s32 count = 0; for (int i = 0; i < 16; ++i) { if (mask & (1 << i)) { ++count; } } if (pNum) { *pNum = u32(count); } if (pMask) { *pMask = u32(mask); } } //--------------------------------------------------------------------------- //! @brief シェーダの出力レジスタ数を取得します。 //! //! @param[in] vertexIndex 頂点シェーダーのインデックスです。 //! @param[in] geometryIndex ジオメトリシェーダーのインデックスです。 //! @param[in] pNum 出力レジスタ数を取得する為のポインタです。 //! @param[in] pMask 出力レジスタマスクを取得する為のポインタです。 //--------------------------------------------------------------------------- void GetShaderOutputRegisterNum(s32 vertexIndex, s32 geometryIndex, u32* pNum, u32* pMask) const { const ExeImageInfo* exeInfo = NULL; if (geometryIndex >= 0) { exeInfo= this->GetShaderProgramInfo(geometryIndex); } else { exeInfo = this->GetShaderProgramInfo(vertexIndex); } NW_NULL_ASSERT( exeInfo ); u32 mask = exeInfo->outputMask; s32 count = 0; for (int i = 0; i < 16; ++i) { if (mask & (1 << i)) { ++count; } } if (pNum) { *pNum = u32(count); } if (pMask) { *pMask = u32(mask); } } //--------------------------------------------------------------------------- //! @brief シェーダの出力レジスタフォーマットを取得します。 //! //! @param[in] vertexIndex 頂点シェーダーのインデックスです。 //! @param[in] geometryIndex ジオメトリシェーダーのインデックスです。 //! @param[in] pOutputFormat シェーダの出力レジスタマップを取得する為の //! サイズ7の配列へのポインタです。 //--------------------------------------------------------------------------- void GetShaderOutputRegisterMap(s32 vertexIndex, s32 geometryIndex, u32 pOutputFormat[7]) const { // とりあえず tugal から移植しました。要確認。 enum { OUT_ATTR_INDEX_MAX = 7, OUT_ATTR_DIMENTION_MAX = 4, VS_OUT_ATTR_INDEX_MAX = 16 }; u32 outNum = 0; u32 useTex = 0; u32 clock = 0; u32 outMask = 0; NW_UNUSED_VARIABLE( useTex ); // 出力属性情報 struct OutmapInfo { u16 type; u16 index; u16 mask; u16 reserve; }; enum { OUTPUT_REG_NUM = 7 }; const ExeImageInfo* exeInfo = NULL; if (geometryIndex >= 0) { exeInfo = this->GetShaderProgramInfo(geometryIndex); } else { exeInfo = this->GetShaderProgramInfo(vertexIndex); } NW_NULL_ASSERT( exeInfo ); const OutmapInfo* outmapInfoTable = static_cast( ut::AddOffsetToPtr( exeInfo, exeInfo->outmapOffset ) ); if ( pOutputFormat ) { for ( int outputIndex = 0; outputIndex < OUTPUT_REG_NUM; ++outputIndex ) { pOutputFormat[ outputIndex ] = 0x1f1f1f1f; for ( int i = 0; i < static_cast(exeInfo->outmapCount); ++i ) { u32 c = 0; const OutmapInfo& outmapInfo = outmapInfoTable[ i ]; for ( int j = 0; outmapInfo.index == outputIndex && j < OUT_ATTR_DIMENTION_MAX; ++j ) { if ( ( outmapInfo.mask & ( 1 << j ) ) == 0 ) { continue; } int value = 0x1f; switch ( outmapInfo.type ) { case 0 : { value = 0x00 + c++; if (c == 2) { clock |= 1 << 0; } } break; // position case 1 : { value = 0x04 + c++; clock |= 1 << 24; } break; // quaternion case 2 : { value = 0x08 + c++; clock |= 1 << 1; } break; // color case 3 : { if (c < 2) { value = 0x0c + c++; } useTex = 1; clock |= 1 << 8; } break; // texcoord0 case 4 : { value = 0x10; useTex = 1; clock |= 3 << 16; } break; // texcoord0w case 5 : { if (c < 2) { value = 0x0e + c++; } useTex = 1; clock |= 1 << 9; } break; // texcoord1 case 6 : { if (c < 2) { value = 0x16 + c++; } useTex = 1; clock |= 1 << 10; } break; // texcoord2 case 8 : { if (c < 3) { value = 0x12 + c++; } clock |= 1 << 24; } break; // view } pOutputFormat[ outputIndex ] = pOutputFormat[ outputIndex ] & ~( 0xff << ( j * 8 ) ) | value << ( j * 8 ); } } if (pOutputFormat[ outputIndex ] != 0x1f1f1f1f) { outMask |= ( 1 << outputIndex ); ++outNum; } } } } //--------------------------------------------------------------------------- //! @brief 頂点シェーダの開始アドレスを取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! //! @return 頂点シェーダの開始アドレスです。 //--------------------------------------------------------------------------- u32 GetEntryAddress(s32 shaderIndex) const { const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex); return exeInfo->mainAddress; } //--------------------------------------------------------------------------- //! @brief ジオメトリシェーダのデータモードを取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! //! @return ジオメトリシェーダのデータモードです。 //--------------------------------------------------------------------------- u32 GetGeometryDataMode(s32 shaderIndex) const { NW_ASSERT( this->IsGeometryShader( shaderIndex ) ); const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex); return exeInfo->gsDataMode; } //--------------------------------------------------------------------------- //! @brief ジオメトリシェーダの gs_main_vertex_num の値 を取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! //! @return ジオメトリシェーダの gs_main_vertex_num の値です。 //--------------------------------------------------------------------------- u32 GetGeometryMainVertexNum(s32 shaderIndex) const { NW_ASSERT( this->IsGeometryShader( shaderIndex ) ); const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex); return exeInfo->gsPatchSize; } //--------------------------------------------------------------------------- //! @brief ジオメトリシェーダの gs_patch_size の値を取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! //! @return ジオメトリシェーダのスタートインデックスです。 //--------------------------------------------------------------------------- u32 GetGeometryPatchSize(s32 shaderIndex) const { NW_ASSERT( this->IsGeometryShader( shaderIndex ) ); const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex); return exeInfo->gsVertexNum; } //--------------------------------------------------------------------------- //! @brief ジオメトリシェーダのスタートインデックスを取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! //! @return ジオメトリシェーダのスタートインデックスです。 //--------------------------------------------------------------------------- u32 GetGeometryStartIndex(s32 shaderIndex) const { NW_ASSERT( this->IsGeometryShader( shaderIndex ) ); const ExeImageInfo* exeInfo = this->GetShaderProgramInfo(shaderIndex); return exeInfo->gsVertexStartIndex; } //@} //--------------------------------------------------------------------------- //! @brief シェーダバイナリの解析をおこないます。 //--------------------------------------------------------------------------- void AnalyzeBinary(); private: enum { EXE_IMAGE_MAX = 32, SWIZZLE_PATTERN_MAX = 128, DUMMY_DATA_NUM_251 = 10, DUMMY_DATA_NUM_200 = 30, PADDING_DATA = 0xead0fead }; // シェーダバイナリの実行イメージ情報のヘッダ構造体です。 struct ExeImageInfo { u32 signature; u16 version; u8 isGeometryShader; u8 outputMaps; u32 mainAddress; u32 endAddress; u16 inputMask; u16 outputMask; u8 gsDataMode; u8 gsVertexStartIndex; u8 gsPatchSize; u8 gsVertexNum; u32 setupOffset; u32 setupCount; u32 labelOffset; u32 labelCount; u32 outmapOffset; u32 outmapCount; u32 bindSymbolOffset; u32 bindSymbolCount; u32 stringOffset; u32 stringCount; }; const u32* m_pShaderBinary; u32 m_ExeImageCount; const ExeImageInfo* m_ExeImageInfo[ EXE_IMAGE_MAX ]; const u32* m_pInstruction; u32 m_InstructionCount; u32 m_Swizzle[ SWIZZLE_PATTERN_MAX ]; u32 m_SwizzleCount; s32 m_GeometryShaderCount; //--------------------------------------------------------------------------- //! @brief シェーダプログラムの情報を取得します。 //! //! @param[in] shaderIndex シェーダインデックスです。 //! //! @return シェーダプログラム情報を格納した生の構造体を返します。 //--------------------------------------------------------------------------- const ExeImageInfo* GetShaderProgramInfo( s32 shaderIndex ) const { NW_ASSERT( 0 <= shaderIndex && shaderIndex < static_cast(m_ExeImageCount) ); return m_ExeImageInfo[ shaderIndex ]; } //--------------------------------------------------------------------------- //! @brief シェーダバイナリ中に含んでいる、シェーダの数を取得します。 //! 頂点シェーダ、ジオメトリシェーダを含めた数を返します。 //! リンクした main 関数の数と等しくなります。 //! //! @return 頂点シェーダとジオメトリシェーダを合わせた数です。 //--------------------------------------------------------------------------- s32 GetShaderCount() const { return m_ExeImageCount; } //--------------------------------------------------------------------------- //! @brief シェーダバイナリ中に含んでいる、ジオメトリシェーダーの数を取得します。 //! 0 であれば、このシェーダバイナリでは必ず頂点シェーダのみという事になります。 //! //! @return ジオメトリシェーダの数です。 //--------------------------------------------------------------------------- s32 GetGeometryShaderCount() const { return m_GeometryShaderCount; } // プログラムロードのコマンド生成 void BuildProgramCommand( SafeBuffer& buffer ) const; // Swizzle パターンロードのコマンド生成 void BuildSwizzleCommand( SafeBuffer& buffer ) const; // ジオメトリシェーダー使用設定コマンドを生成 void BuildPrepareCommand( SafeBuffer& buffer ) const; // 定数レジスタのコマンド生成 void BuildConstRegCommand( SafeBuffer& buffer, s32 shaderIndex ) const; // シェーダー出力属性のコマンド生成 void BuildOutAttrCommand( SafeBuffer& buffer, s32 vertexIndex, s32 geometryIndex ) const; // プログラムロードのコマンドサイズを取得 s32 GetProgramCommandSize() const; // Swizzle パターンロードのコマンドサイズを取得 s32 GetSwizzleCommandSize() const; // ジオメトリシェーダー使用設定コマンドサイズを取得 s32 GetPrepareCommandSize() const; // 定数レジスタのコマンドサイズを取得 s32 GetConstRegCommandSize( s32 shaderIndex ) const; // シェーダー出力属性のコマンドサイズを取得 s32 GetOutAttrCommandSize( s32 vertexIndex, s32 geometryIndex ) const; // データ転送コマンドのサイズを取得 s32 GetLoadCommandSize( u32 count ) const; //--------------------------------------------------------------------------- //! @brief ポートレジスタに対して大量のデータを書き込みます。 //! 128バイト以上のデータも指定可能です。 //! //! @param[out] buffer コマンド書き込み先のバッファです。 //! @param[in] regAddr 書き込み先レジスタです。 //! @param[in] src 書き込み元データです。 //! @param[in] count データ数です。(32bit で 1) //--------------------------------------------------------------------------- void PutLoadCommand( SafeBuffer& buffer, u32 regAddr, const u32* src, u32 count ) const; // 頂点シェーダから、共用シェーダのミラーモードを有効にします。 void PutEnableMirroringShaderSetting( SafeBuffer& buffer, bool enableMirroring ) const; //--------------------------------------------------------------------------- //! @brief バッファに対して安全に書き込みをおこなうためのクラスです。 //--------------------------------------------------------------------------- class SafeBuffer { public: typedef SafeBuffer Self; //--------------------------------------------------------------------------- //! @brief コンストラクタです。 //! //! @param[out] start バッファの先頭アドレスです。 //! @param[in] size バッファサイズです。 //--------------------------------------------------------------------------- SafeBuffer(u32* start, s32 size) : m_StartAddress( start ), m_CurrentAddress( start ), m_EndAddress( static_cast( ut::AddOffsetToPtr(start, size) ) ), m_IsFinished( false ) {} const u32* StartAddress() const { return m_StartAddress; } const u32* EndAddress() const { return m_EndAddress; } const u32* CurrentAddress() const { return m_EndAddress; } s32 BufferSize() const { return ut::GetOffsetFromPtr(m_StartAddress, m_EndAddress); } s32 UsedSize() const { return ut::GetOffsetFromPtr(m_StartAddress, m_CurrentAddress); } bool IsFinished() const { return m_IsFinished; } operator const u32*() const { return m_CurrentAddress; } Self& operator++() { return this->MoveAddress(sizeof(u32)); } Self operator++(int) { Self tmp = *this; (void)this->MoveAddress(sizeof(u32)); return tmp; } Self& operator+=(s32 count) { return this->MoveAddress(count * sizeof(u32)); } //--------------------------------------------------------------------------- //! @brief 指定したサイズのデータが書き込めるかどうかの確認をおこないます。 //! 残りサイズが足りない場合には、終了処理をおこない、IsFinished() が //! true を返すようになります。 //! //! @param[in] size 書き込みデータサイズです。 //! //! @return 残り容量に問題がなければ true, 容量が足りなければ false を返します。 //--------------------------------------------------------------------------- bool VerifyWriteSize(int size) { if (ut::AddOffsetToPtr(m_CurrentAddress, size) <= m_EndAddress) { return true; } else { m_IsFinished = true; return false; } } //--------------------------------------------------------------------------- //! @brief データの書き込みを行ないます。 //! 空き容量が足りない場合には中途半端なデータの書き込みは行なわず //! 負のエラーコードを返して終了します。 //! 容量の問題で書き込みに失敗すると、それ以降 IsFinished() が true を //! 返すようになります。 //! //! @param[in] src 書き込み元のデータです。 //! @param[in] size 書き込みデータサイズです。 //! //! @return 書き込みをおこなったデータサイズを返します。 //! 書き込みに失敗した場合には負のエラーコードを返します。 //--------------------------------------------------------------------------- s32 Write(const u32* src, s32 size) { if (size <= 0) { return -1; } if (!this->VerifyWriteSize(size)) { return -1; } nw::os::MemCpy(m_CurrentAddress, src, size); this->MoveAddress(size); return size; } s32 Write(u32 src) { if (!this->VerifyWriteSize(sizeof(u32))) { return -1; } *m_CurrentAddress = src; ++m_CurrentAddress; return sizeof(u32); } private: u32* m_StartAddress; u32* m_CurrentAddress; u32* m_EndAddress; bool m_IsFinished; Self& MoveAddress(s32 size) { m_CurrentAddress = static_cast( ut::AddOffsetToPtr(m_CurrentAddress, size) ); NW_ASSERT(m_CurrentAddress <= m_EndAddress); return *this; } }; }; } // namespace gfx } // namespace nw #endif // NW_GFX_SHADERBINARYINFO_H_