/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_ActivateCommand.cpp 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: 28084 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include #include #include namespace nw { namespace gfx { nw::os::IAllocator* CommandCacheManager::s_Allocator = NULL; namespace internal { namespace { // 全ロードアレイをクリアし、固定頂点属性を設定する。 const u32 CLEAR_VERTEX_COMMAND[] = { // 固定頂点属性の設定 0xBFFF0000, internal::MakeCommandHeader(0x202, 1, false, 0xF), // ロードアレイの無効化 0, internal::MakeCommandHeader(0x205 , 1, false, 0xF), 0, internal::MakeCommandHeader(0x205 + 3 , 1, false, 0xF), 0, internal::MakeCommandHeader(0x205 + 3 * 2, 1, false, 0xF), 0, internal::MakeCommandHeader(0x205 + 3 * 3, 1, false, 0xF), 0, internal::MakeCommandHeader(0x205 + 3 * 4, 1, false, 0xF), 0, internal::MakeCommandHeader(0x205 + 3 * 5, 1, false, 0xF), 0, internal::MakeCommandHeader(0x205 + 3 * 6, 1, false, 0xF), 0, internal::MakeCommandHeader(0x205 + 3 * 7, 1, false, 0xF), 0, internal::MakeCommandHeader(0x205 + 3 * 8, 1, false, 0xF), 0, internal::MakeCommandHeader(0x205 + 3 * 9, 1, false, 0xF), 0, internal::MakeCommandHeader(0x205 + 3 * 10, 1, false, 0xF), 0, internal::MakeCommandHeader(0x205 + 3 * 11, 1, false, 0xF), 1, internal::MakeCommandHeader(0x232, 4, true, 0xF), 0, 0, 0, 0, 2, internal::MakeCommandHeader(0x232, 4, true, 0xF), 0, 0, 0, 0, 3, internal::MakeCommandHeader(0x232, 4, true, 0xF), 0, 0, 0, 0, 4, internal::MakeCommandHeader(0x232, 4, true, 0xF), 0, 0, 0, 0, 5, internal::MakeCommandHeader(0x232, 4, true, 0xF), 0, 0, 0, 0, 6, internal::MakeCommandHeader(0x232, 4, true, 0xF), 0, 0, 0, 0, 7, internal::MakeCommandHeader(0x232, 4, true, 0xF), 0, 0, 0, 0, 8, internal::MakeCommandHeader(0x232, 4, true, 0xF), 0, 0, 0, 0, 9, internal::MakeCommandHeader(0x232, 4, true, 0xF), 0, 0, 0, 0, 10, internal::MakeCommandHeader(0x232, 4, true, 0xF), 0, 0, 0, 0, 11, internal::MakeCommandHeader(0x232, 4, true, 0xF), 0, 0, 0, 0 }; //--------------------------------------------------------------------------- //! @brief SetupActivateVertexAttributeCommand_ で生成されるコマンドサイズを計算します。 //! //! @param[in] shape 頂点設定コマンドを設定するシェイプです。 //! @param[in] shaderProgramDesc 対応するシェーダプログラムです。 //! //! @return コマンドのサイズです。 //--------------------------------------------------------------------------- template s32 CalcSetupActivateVertexAttributeCommandSize_( TShape shape, ResShaderProgramDescription shaderProgramDesc ) { s32 commandSize = 12; s32 vtxAttrNum = shape.GetVertexAttributesCount(); // 頂点ストリームを番号の若い順に設定 for ( s32 i = 0; i < vtxAttrNum; ++ i ) { ResVertexAttribute attribute = shape.GetVertexAttributes( i ); if ( attribute.GetFlags() & ResVertexAttributeData::FLAG_VERTEX_PARAM ) { commandSize += 6; } else { commandSize += 4; } } if (shaderProgramDesc.GetGeometryShaderIndex() >= 0) { commandSize += 4; } return sizeof(u32) * commandSize; } //--------------------------------------------------------------------------- template s32 CalcSetupDeactivateVertexAttributeCommandSize_( TShape shape, ResShaderProgramDescription shaderProgramDesc ) { NW_UNUSED_VARIABLE( shaderProgramDesc ); int inputIndex = 0; // 内部頂点属性番号 s32 vtxAttrNum = shape.GetVertexAttributesCount(); s32 commandIndex = 0; // 頂点ストリームを番号の若い順に設定 for ( s32 i = 0; i < vtxAttrNum; ++ i ) { ResVertexAttribute attribute = shape.GetVertexAttributes( i ); // 固定頂点属性は無視する。 if ( attribute.GetFlags() & ResVertexAttributeData::FLAG_VERTEX_PARAM ) { ++inputIndex; continue; } if (attribute.GetFlags() & ResVertexAttributeData::FLAG_INTERLEAVE) { ResInterleavedVertexStream interleave = ResStaticCast(attribute); s32 streamCount = interleave.GetVertexStreamsCount(); inputIndex += streamCount; } else { ++inputIndex; } commandIndex += 2; } commandIndex += 6; // (0,0,0,0) の固定属性を設定 for ( int i = 1; i < inputIndex; ++i ) { commandIndex += 6; } return sizeof(u32) * commandIndex; } //--------------------------------------------------------------------------- //! @brief 頂点属性の Usage から頂点属性のインデックスに変換します。 //! //! @param[in] shaderProgramDesc シェーダプログラム情報です。 //! @param[in] usage 頂点の種別情報です。 //! //! @return 頂点属性のインデックスを返します。 //--------------------------------------------------------------------------- NW_INLINE s32 GetAttributeIndexFromUsage(ResShaderProgramDescription shaderProgramDesc, s32 usage) { return shaderProgramDesc.GetAttributeIndices(usage); } } // namespace //--------------------------------------------------------------------------- void ClearVertexAttribute() { NWUseCmdlist( CLEAR_VERTEX_COMMAND, sizeof(CLEAR_VERTEX_COMMAND) ); } //--------------------------------------------------------------------------- template static s32 SetupActivateVertexAttributeCommand_( CommandBufferInfo& bufferInfo, TShape shape, ResShaderProgramDescription shaderProgramDesc ) { enum { MAX_ATTRIBUTES_NUM = 12, REG_VTX_SHADER_ATTR_NUM = 0x2b9, // [3:0] 頂点属性数 - 1 REG_VTX_SHADER_ATTR_NUM_2 = 0x242, // [3:0] 頂点族整数 - 1 REG_VTX_MAP_0 = 0x2bb, // [31:0] 入力レジスタのインデックス REG_VTX_MAP_1 = 0x2bc, // [15:0] 入力レジスタのインデックス REG_VTX_STREAM_BASE = 0x200, // [28:1] 頂点アレイのベースアドレス REG_VTX_ARRAY_OFFSET = 0x203, // [27:0] ロードアレイ0のアドレスオフセット REG_VTX_PARAM_INDEX = 0x232, // [3:0] 頂点シェーダの入力番号指定 REG_GEOM_MAP_0 = 0x28b, // [31:0] 入力レジスタのインデックス REG_GEOM_MAP_1 = 0x28c // [15:0] 入力レジスタのインデックス }; const ShaderBinaryInfo* shaderInfo = shaderProgramDesc.GetShaderBinaryInfo(); NW_NULL_ASSERT( shaderInfo ); u32 shaderVtxAttrNum = shaderInfo->GetInputRegisterNum( shaderProgramDesc.GetVertexShaderIndex() ); // VRAM, FCRAM のメモリマップの中からアドレスの一番小さいものをベースに設定 u32 baseAddr = nngxGetPhysicalAddr(nn::gx::GetVramStartAddr(nn::gx::MEM_VRAMA)); shape.ref().m_BaseAddress = baseAddr; s32 vtxAttrNum = shape.GetVertexAttributesCount(); s32 inputRegNum = shaderVtxAttrNum; u32* command = reinterpret_cast( bufferInfo.GetCurrentAddress() ); // シェーダの入力レジスタ数を設定。 command[0] = (inputRegNum - 1) | 0xa0000000; command[1] = internal::MakeCommandHeader(REG_VTX_SHADER_ATTR_NUM, 1, false, 0xb); command[2] = (inputRegNum - 1); command[3] = internal::MakeCommandHeader(REG_VTX_SHADER_ATTR_NUM_2, 1, false, 0x1); command[4] = 0; command[5] = internal::MakeCommandHeader(REG_VTX_MAP_0, 2, true, 0xF); command[6] = 0; command[7] = 0; command[8] = baseAddr >> 3; command[9] = internal::MakeCommandHeader(REG_VTX_STREAM_BASE, 3, true, 0xF); command[10] = 0; command[11] = static_cast(inputRegNum - 1) << 28; u32* inputMapTable = &command[4]; // 0x2bb u32* inputFormat = &command[10]; // 0x201 u32* vertexParamMask = &command[11]; // 0x202 int inputIndex = 0; // 内部頂点属性番号 int arrayIndex = 0; // ロードアレイ番号 u32 commandIndex = 12; u32 usedFlag = 0; // 0x2bb, 0x2bc に頂点ストリームを前から順に詰めて設定する。 // その後に、固定頂点属性を設定する。未使用の項目は Deactivate 用のコマンドであらかじめクリアされている前提とする。 // 頂点ストリームを番号の若い順に設定 for ( s32 i = 0; i < vtxAttrNum; ++ i ) { ResVertexAttribute attribute = shape.GetVertexAttributes( i ); if ( attribute.GetFlags() & ResVertexAttributeData::FLAG_VERTEX_PARAM ) { // 固定頂点属性は無視する。 continue; } if (attribute.GetFlags() & ResVertexAttributeData::FLAG_INTERLEAVE) // インターリーブフォーマットの場合。 { ResInterleavedVertexStream interleave = ResStaticCast(attribute); // ロードアレイの設定。 // インターリブ形式なので 1 本のロードアレイに複数の要素が入ります。 u32 bufferAddr = nngxGetPhysicalAddr( interleave.GetImageAddress() ); s32 streamCount = interleave.GetVertexStreamsCount(); command[commandIndex ] = bufferAddr - baseAddr; command[commandIndex + 1] = internal::MakeCommandHeader(REG_VTX_ARRAY_OFFSET + 3 * arrayIndex, 3, true, 0xF); command[commandIndex + 2] = 0; command[commandIndex + 3] = (interleave.GetStride() << 16) | (streamCount << 28); u32* arraySetting = &command[commandIndex + 2]; commandIndex += 4; for ( s32 streamIdx = 0; streamIdx < streamCount; ++streamIdx ) { ResVertexStream stream = interleave.GetVertexStreams( streamIdx ); s32 usage = stream.GetUsage(); s32 usageIndex = GetAttributeIndexFromUsage( shaderProgramDesc, usage ); NW_ASSERT(0 <= usageIndex && usageIndex < MAX_ATTRIBUTES_NUM); inputMapTable[ (inputIndex / 8) * 2 ] |= (usageIndex & 0xf) << (4 * (inputIndex % 8)); // (inputIndex >= 8) ? 2 : 0 のアドレスに書き込む。 usedFlag |= 0x1 << usageIndex; u32 format = stream.GetFormatType(); u32 dimension = stream.GetDimension(); inputFormat[ inputIndex / 8 ] |= CommandCacheHelper::GetVertexFormat(dimension, format) << ((inputIndex % 8) * 4); if (streamIdx < 8) { arraySetting[0] |= inputIndex << (streamIdx * 4); } else { arraySetting[1] |= inputIndex << ((streamIdx - 8) * 4); } ++inputIndex; } } else // 非インターリーブフォーマットの場合。 { s32 usage = attribute.GetUsage(); s32 usageIndex = GetAttributeIndexFromUsage( shaderProgramDesc, usage ); NW_ASSERT(0 <= usageIndex && usageIndex < MAX_ATTRIBUTES_NUM); inputMapTable[ (inputIndex / 8) * 2 ] |= (usageIndex & 0xF) << (4 * (inputIndex % 8)); usedFlag |= 0x1 << usageIndex; ResVertexStream stream = ResStaticCast(attribute); u32 format = stream.GetFormatType(); u32 dimension = stream.GetDimension(); inputFormat[ inputIndex / 8 ] |= CommandCacheHelper::GetVertexFormat(dimension, format) << ((inputIndex % 8) * 4); // ロードアレイの設定 u32 bufferAddr = nngxGetPhysicalAddr( stream.GetImageAddress() ); // このクラスでは interleave 形式には対応しないので、(0番目の要素 == 内部頂点属性 index 番目) command[commandIndex] = bufferAddr - baseAddr; command[commandIndex + 1] = internal::MakeCommandHeader(REG_VTX_ARRAY_OFFSET + 3 * arrayIndex, 3, true, 0xF); command[commandIndex + 2] = inputIndex; command[commandIndex + 3] = (CommandCacheHelper::GetVertexSize(dimension, format) << 16) + (1 << 28); ++inputIndex; commandIndex += 4; } ++arrayIndex; } const u32 HEADER_VTX_PARAM_INDEX = internal::MakeCommandHeader(REG_VTX_PARAM_INDEX, 4, true, 0xF); // 頂点ストリームの後に頂点パラメータを設定。 for ( s32 i = 0; i < vtxAttrNum; ++ i ) { ResVertexAttribute attribute = shape.GetVertexAttributes( i ); if ( attribute.GetFlags() & ResVertexAttributeData::FLAG_VERTEX_PARAM ) { ResVertexParamAttribute param = ResStaticCast(attribute); s32 usage = param.GetUsage(); s32 usageIndex = GetAttributeIndexFromUsage( shaderProgramDesc, usage ); NW_ASSERT(0 <= usageIndex && usageIndex < 12); inputMapTable[ (inputIndex / 8) * 2 ] |= (usageIndex & 0xF) << (4 * (inputIndex % 8)); usedFlag |= 0x1 << usageIndex; // 頂点パラメータの場合の処理 u32 data[4] = { 0, 0, 0, 0 }; int count = param.GetAttributeCount(); f32* fdata = param.GetAttribute(); for (int j = 0; j < count; ++j) { data[j] = ut::Float24::Float32ToBits24( fdata[j] ); } command[commandIndex] = inputIndex; command[commandIndex + 1] = HEADER_VTX_PARAM_INDEX; command[commandIndex + 2] = (data[3] << 8) | (data[2] >> 16); command[commandIndex + 3] = (data[2] << 16) | (data[1] >> 8); command[commandIndex + 4] = (data[1] << 24) | (data[0]); command[commandIndex + 5] = 0; vertexParamMask[0] |= 1 << (16 + inputIndex); ++inputIndex; commandIndex += 6; } } // 残りの部分には元々固定頂点属性が設定されているのでフラグだけ立てておく。 while ( inputIndex < shaderVtxAttrNum ) { s32 usage = shaderVtxAttrNum - 1; s32 usageIndex = GetAttributeIndexFromUsage( shaderProgramDesc, usage ); while (usedFlag & (0x1 << usageIndex)) { --usageIndex; } inputMapTable[ (inputIndex / 8) * 2 ] |= (usageIndex & 0xF) << (4 * (inputIndex % 8)); usedFlag |= 0x1 << usageIndex; #if 0 // 不具合発生時の確認用コード // 残りの部分には (0,0,0,1) の固定属性を設定 command[commandIndex] = inputIndex; command[commandIndex + 1] = HEADER_VTX_PARAM_INDEX; command[commandIndex + 2] = (ut::Float24::Float32ToBits24( 1.0f ) << 8); command[commandIndex + 3] = 0; command[commandIndex + 4] = 0; command[commandIndex + 5] = 0; commandIndex += 6; #endif vertexParamMask[0] |= 1 << (16 + inputIndex); ++inputIndex; } const u32 HEADER_GEOM_MAP_0 = internal::MakeCommandHeader(REG_GEOM_MAP_0, 1, false, 0xF); const u32 HEADER_GEOM_MAP_1 = internal::MakeCommandHeader(REG_GEOM_MAP_1, 1, false, 0xF); if (shaderProgramDesc.GetGeometryShaderIndex() >= 0) { // TODO: ジオメトリシェーダの入力マップは、ひとまず 0x76543210, 0xfedcba98 に固定 command[commandIndex + 0] = 0x76543210; command[commandIndex + 1] = HEADER_GEOM_MAP_0; command[commandIndex + 2] = 0xfedcba98; command[commandIndex + 3] = HEADER_GEOM_MAP_1; commandIndex += 4; } NW_ENSURE_AND_ASSERT( bufferInfo.ForwardCommand( commandIndex * sizeof(u32) ) ); return static_cast(commandIndex * sizeof(u32)); } //--------------------------------------------------------------------------- template static s32 SetupDeactivateVertexAttributeCommand_( CommandBufferInfo& bufferInfo, TShape shape, ResShaderProgramDescription shaderProgramDesc ) { NW_UNUSED_VARIABLE(shaderProgramDesc); // NOTE: // ・使用したロードアレイの要素数を 0 にリセットする。 // ・使用した頂点の設定を固定頂点属性 (0,0,0,0) にクリアする。 enum { REG_VTX_ARRAY_VTXMASK = 0x202, REG_VTX_ARRAY_OFFSET = 0x203, // [27:0] ロードアレイ0のアドレスオフセット REG_VTX_PARAM_INDEX = 0x232, // [3:0] 頂点シェーダの入力番号指定。 REG_VTX_MAP_0 = 0x2bb, // [31:0] 入力レジスタのインデックス REG_VTX_MAP_1 = 0x2bc // [15:0] 入力レジスタのインデックス }; s32 vtxAttrNum = shape.GetVertexAttributesCount(); u32* command = reinterpret_cast(bufferInfo.GetCurrentAddress()); int inputIndex = 0; // 内部頂点属性番号 int arrayIndex = 0; // ロードアレイ番号 u32 commandIndex = 0; // 頂点ストリームを番号の若い順に設定 for ( s32 i = 0; i < vtxAttrNum; ++ i ) { ResVertexAttribute attribute = shape.GetVertexAttributes( i ); // 固定頂点属性は後の処理で無効化する。 if ( attribute.GetFlags() & ResVertexAttributeData::FLAG_VERTEX_PARAM ) { ++inputIndex; continue; } if (attribute.GetFlags() & ResVertexAttributeData::FLAG_INTERLEAVE) { ResInterleavedVertexStream interleave = ResStaticCast(attribute); // ロードアレイの無効化 command[commandIndex ] = 0; command[commandIndex + 1] = internal::MakeCommandHeader(REG_VTX_ARRAY_OFFSET + 2 + 3 * arrayIndex, 1, false, 0xF); commandIndex += 2; s32 streamCount = interleave.GetVertexStreamsCount(); inputIndex += streamCount; } else { // ロードアレイの無効化 command[commandIndex ] = 0; command[commandIndex + 1] = internal::MakeCommandHeader(REG_VTX_ARRAY_OFFSET + 2 + 3 * arrayIndex, 1, false, 0xF); commandIndex += 2; ++inputIndex; } ++arrayIndex; } // 入力レジスタマップを初期化 // HACK: ここで設定していなくても正しく表示されるかもしれません。 { const u32 INPUT_MAP0 = 0x76543210; const u32 INPUT_MAP1 = 0x0000ba98; command[commandIndex++] = INPUT_MAP0; command[commandIndex++] = internal::MakeCommandHeader(REG_VTX_MAP_0, 2, true, 0xF); command[commandIndex++] = INPUT_MAP1; command[commandIndex++] = 0; } command[commandIndex++] = (static_cast(inputIndex - 1) << 28) | (((0x1 << inputIndex) - 2) << 16); command[commandIndex++] = internal::MakeCommandHeader(REG_VTX_ARRAY_VTXMASK, 1, false, 0xF); const u32 HEADER_VTX_PARAM_INDEX = internal::MakeCommandHeader(REG_VTX_PARAM_INDEX, 4, true, 0xF); // (0,0,0,0) の固定属性を設定 for ( int i = 1; i < inputIndex; ++i ) { command[commandIndex] = i; command[commandIndex + 1] = HEADER_VTX_PARAM_INDEX; command[commandIndex + 2] = 0; command[commandIndex + 3] = 0; command[commandIndex + 4] = 0; command[commandIndex + 5] = 0; commandIndex += 6; } NW_ENSURE_AND_ASSERT( bufferInfo.ForwardCommand( commandIndex * sizeof(u32) ) ); return static_cast( commandIndex * sizeof(u32) ); } //-------------------------------------------------------------------------- s32 SetupVertexAttributeCommand( CommandBufferInfo& bufferInfo, ResSeparateDataShape shape, ResShaderProgramDescription shaderProgramDesc ) { return SetupActivateVertexAttributeCommand_( bufferInfo, shape, shaderProgramDesc ); } //-------------------------------------------------------------------------- s32 SetupVertexAttributeCommand( CommandBufferInfo& bufferInfo, ResParticleShape shape, ResShaderProgramDescription shaderProgramDesc ) { return SetupActivateVertexAttributeCommand_( bufferInfo, shape, shaderProgramDesc ); } //-------------------------------------------------------------------------- s32 SetupDeactivateVertexAttributeCommand( CommandBufferInfo& bufferInfo, ResSeparateDataShape shape, ResShaderProgramDescription shaderProgramDesc ) { return SetupDeactivateVertexAttributeCommand_( bufferInfo, shape, shaderProgramDesc ); } //-------------------------------------------------------------------------- s32 SetupDeactivateVertexAttributeCommand( CommandBufferInfo& bufferInfo, ResParticleShape shape, ResShaderProgramDescription shaderProgramDesc ) { return SetupDeactivateVertexAttributeCommand_( bufferInfo, shape, shaderProgramDesc ); } //-------------------------------------------------------------------------- s32 CalcSetupActivateVertexAttributeCommandSize( ResSeparateDataShape shape, ResShaderProgramDescription shaderProgramDesc ) { return CalcSetupActivateVertexAttributeCommandSize_( shape, shaderProgramDesc ); } //-------------------------------------------------------------------------- s32 CalcSetupActivateVertexAttributeCommandSize_( ResParticleShape shape, ResShaderProgramDescription shaderProgramDesc ) { return CalcSetupActivateVertexAttributeCommandSize_( shape, shaderProgramDesc ); } //-------------------------------------------------------------------------- s32 CalcSetupDeactivateVertexAttributeCommandSize( ResSeparateDataShape shape, ResShaderProgramDescription shaderProgramDesc ) { return CalcSetupDeactivateVertexAttributeCommandSize_( shape, shaderProgramDesc ); } //-------------------------------------------------------------------------- s32 CalcSetupDeactivateVertexAttributeCommandSize_( ResParticleShape shape, ResShaderProgramDescription shaderProgramDesc ) { return CalcSetupDeactivateVertexAttributeCommandSize_( shape, shaderProgramDesc ); } //-------------------------------------------------------------------------- s32 SetupShaderProgramMode(bool useGeometry) { // 初回時と 頂点シェーダとジオメトリシェーダの切り替え時のみ、 // 0x229[1:0]のコマンドとダミーコマンドを積む。 // ジオメトリシェーダのON/OFF切り替え。 // ジオメトリシェーダを使用しない場合には、0x244を0にすることで、 // 以後、0x2b0-0x2df の設定が 0x280-0x2af にミラーコピーされる。 static u32 USE_GEOMETRY_COMMAND[] = { 0x00000000, 0x00900251, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x01d00200, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0, 0x00010229, // index : 44, 45 0x00000000, 0x01d00200, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }; const u32 IDX_REG_229 = 44; if ( useGeometry ) { USE_GEOMETRY_COMMAND[ IDX_REG_229 ] = 0x00000002; } else { USE_GEOMETRY_COMMAND[ IDX_REG_229 ] = 0x0; } NWUseCmdlist( &USE_GEOMETRY_COMMAND[0] ); return sizeof(USE_GEOMETRY_COMMAND); } //--------------------------------------------------------------------------- //! @brief GL のモードを取得します。 //! //! @param[in] mode 描画モードです。 //! @param[in] isGeometryShaderEnabled ジオメトリシェーダーが有効かどうかを指定します。 //! //! @return GL のモードです。 //--------------------------------------------------------------------------- static NW_INLINE GLuint ToPrimitiveModeGL(u8 mode, bool isGeometryShaderEnabled) { static const GLuint PRIM_MODE_TABLE[] = { GL_TRIANGLES, // Triangles GL_TRIANGLE_STRIP, // TriangleStrip GL_TRIANGLE_FAN // TriangleFan }; NW_ASSERT( mode < (sizeof(PRIM_MODE_TABLE) / sizeof(GLuint)) ); GLuint glMode = PRIM_MODE_TABLE[ mode ]; if (isGeometryShaderEnabled) { glMode = GL_GEOMETRY_PRIMITIVE_DMP; } return glMode; } //-------------------------------------------------------------------------- s32 CalcSetupDrawIndexStreamCommand(ResIndexStream indexStream) { NW_UNUSED_VARIABLE( indexStream ); return 28 * sizeof(u32); } //-------------------------------------------------------------------------- // NOTE: コマンドのサイズが変わる場合は、必ず CalcSetupDrawIndexStreamCommand も合わせて修正する。 s32 SetupDrawIndexStreamCommand( CommandBufferInfo& bufferInfo, ResIndexStream indexStream, bool hasGeometryShader ) { enum { REG_INDEX_STREAM_OFFSET = 0x227, REG_INDEX_STREAM_COUNT = 0x228, REG_ELEMENTS_MODE = 0x229, // [23:16]にはバイトイネーブルでアクセスしてはいけない。 REG_ELEMENTS_MODE_2 = 0x253, // [31:16]にはバイトイネーブルでアクセスしてはいけない。 REG_ELEMENTS_MODE_3 = 0x25e, // [23:16]にはバイトイネーブルでアクセスしてはいけない。 REG_TRIANGLE_INDEX_RESET = 0x25f, REG_DRAW_READY = 0x245, REG_DRAW_KICK = 0x22f, REG_VERTEX_CACHE_CLEAR = 0x231, REG_COLOR_DEPTH_CACHE_CLEAR = 0x110, REG_COLOR_DEPTH_CACHE_FLUSH = 0x111 }; GLuint mode = ToPrimitiveModeGL( indexStream.GetPrimitiveMode(), hasGeometryShader); const size_t commandCount = 28; u32* command = reinterpret_cast( bufferInfo.GetCurrentAddress() ); u32 baseAddr = nngxGetPhysicalAddr(nn::gx::GetVramStartAddr(nn::gx::MEM_VRAMA)); u32 bufferAddr = nngxGetPhysicalAddr( indexStream.GetImageAddress() ); NW_ASSERT((bufferAddr - baseAddr) < 0x10000000); const u32 HEADER_INDEX_STREAM_OFFSET = internal::MakeCommandHeader(REG_INDEX_STREAM_OFFSET, 1, false, 0xF); const u32 HEADER_INDEX_STREAM_COUNT = internal::MakeCommandHeader(REG_INDEX_STREAM_COUNT, 1, false, 0xF); command[0] = (bufferAddr - baseAddr); command[1] = HEADER_INDEX_STREAM_OFFSET; command[2] = indexStream.GetStreamCount(); command[3] = HEADER_INDEX_STREAM_COUNT; // CTR では GL_UNSIGNED_INT は未対応です。 if (indexStream.GetFormatType() == GL_UNSIGNED_SHORT) { command[0] |= 0x80000000; command[2] /= 2; } const u32 HEADER_ELEMENTS_MODE = internal::MakeCommandHeader(REG_ELEMENTS_MODE, 1, false, 0x2); const u32 HEADER_ELEMENTS_MODE_2 = internal::MakeCommandHeader(REG_ELEMENTS_MODE_2, 1, false, 0x2); if (mode == GL_TRIANGLES) { command[4] = 1 << 8; command[5] = HEADER_ELEMENTS_MODE; command[6] = 1 << 8; command[7] = HEADER_ELEMENTS_MODE_2; } else { command[4] = 0; command[5] = HEADER_ELEMENTS_MODE; command[6] = 0; command[7] = HEADER_ELEMENTS_MODE_2; } switch (mode) { case GL_TRIANGLES: command[8] = 3 << 8; break; case GL_TRIANGLE_STRIP: command[8] = 1 << 8; break; case GL_TRIANGLE_FAN: command[8] = 2 << 8; break; case GL_GEOMETRY_PRIMITIVE_DMP: command[8] = 3 << 8; break; } u32 commandIndex = 9; command[commandIndex++] = internal::MakeCommandHeader(REG_ELEMENTS_MODE_3, 1, false, 0x2); command[commandIndex++] = 1; command[commandIndex++] = internal::MakeCommandHeader(REG_TRIANGLE_INDEX_RESET, 1, false, 0xF); command[commandIndex++] = 0; command[commandIndex++] = internal::MakeCommandHeader(REG_DRAW_READY, 1, false, 0xF); command[commandIndex++] = 1; command[commandIndex++] = internal::MakeCommandHeader(REG_DRAW_KICK, 1, false, 0xF); command[commandIndex++] = 1; command[commandIndex++] = internal::MakeCommandHeader(REG_DRAW_READY, 1, false, 0xF); command[commandIndex++] = 1; command[commandIndex++] = internal::MakeCommandHeader(REG_VERTEX_CACHE_CLEAR, 1, false, 0xF); command[commandIndex++] = 0; command[commandIndex++] = internal::MakeCommandHeader(REG_ELEMENTS_MODE_3, 1, false, 0x8); command[commandIndex++] = 0; command[commandIndex++] = internal::MakeCommandHeader(REG_ELEMENTS_MODE_3, 1, false, 0x8); command[commandIndex++] = 1; command[commandIndex++] = internal::MakeCommandHeader(REG_COLOR_DEPTH_CACHE_FLUSH, 1, false, 0xF); command[commandIndex++] = 1; command[commandIndex++] = internal::MakeCommandHeader(REG_COLOR_DEPTH_CACHE_CLEAR, 1, false, 0xF); NW_ENSURE_AND_ASSERT( bufferInfo.ForwardCommand(commandIndex * sizeof(u32)) ); return commandIndex * sizeof(u32); } } // namespace internal } // namespace gfx } // namespace nw