/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_GraphicsDevice.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: 27679 $ *---------------------------------------------------------------------------*/ #ifndef NW_GFX_GRAPHICSDEVICE_H_ #define NW_GFX_GRAPHICSDEVICE_H_ #include #include #include #include #include #include // このマクロを定義するとマテリアルの個々の要素の設定に関するプロファイルを行います。 // #define NW_MATERIAL_PROFILE namespace nw { namespace os { class IAllocator; } namespace gfx { //--------------------------------------------------------------------------- //! @brief 描画内容を GPU に設定するクラスです。 //--------------------------------------------------------------------------- class GraphicsDevice { public: //---------------------------------------- //! @name ラスタライゼーション関連 //@{ //--------------------------------------------------------------------------- //! @brief ポリゴンオフセットが有効化どうかのフラグを設定します。 //! //! @param[in] enabled ポリゴンオフセットのが有効化どうかのフラグです。 //--------------------------------------------------------------------------- static NW_INLINE void SetPolygonOffsetEnabled(bool enabled) { s_PolygonOffsetEnabled = enabled; } //--------------------------------------------------------------------------- //! @brief ポリゴンオフセットのユニット要素を設定します。 //! //! @param[in] polygonOffsetUnit ポリゴンオフセットのユニット要素です。 //--------------------------------------------------------------------------- static NW_INLINE void SetPolygonOffsetUnit(f32 polygonOffsetUnit) { s_PolygonOffsetUnit = polygonOffsetUnit; } //--------------------------------------------------------------------------- //! @brief ポリゴンオフセットのコマンドを発行します。 //--------------------------------------------------------------------------- static NW_INLINE void ActivatePolygonOffset(); //@} //---------------------------------------- //! @name フレームバッファ関連 //@{ //@} //---------------------------------------- //! @name ブレンダ関連 //@{ //! @brief ブレンド計算を有効または無効にします。 //! //! @param[in] enabled ブレンド計算の有効フラグです。 //! static NW_INLINE void SetBlendEnabled(bool enabled); //@} //---------------------------------------- //! @name フラグメントオペレーション関連 //@{ //! @brief フラグメントオペレーションモードを設定します。 static NW_INLINE void SetFragmentOperationMode(const ResFragmentOperation::FragmentOperationMode mode) { if (s_FragOperationMode != mode) { s_FragOperationMode = mode; s_IsFrameBufferUpdated = true; } } //! @brief フラグメントオペレーションモードを設定します。 static NW_INLINE void ActivateFragmentOperationMode(ResFragmentOperation::FragmentOperationMode mode) { s_FragOperationMode = mode; enum { REG_FRAGMENT_OPERATION = 0x100 }; const u32 HEADER = internal::MakeCommandHeader(REG_FRAGMENT_OPERATION, 1, false, 0x1); const u32 COMMAND[] = { mode, HEADER }; s_IsFrameBufferUpdated = true; ActivateFrameBuffer(); } //! @brief 深度バッファリングを有効または無効にします。 //! //! @param[in] enabled 深度バッファリングの有効フラグです。 //! static NW_INLINE void SetDepthTestEnabled(bool enabled); //! @brief ステンシルテストを有効または無効にします。 //! //! @param[in] enabled ステンシルテストの有効フラグです。 //! static NW_INLINE void SetStencilTestEnabled(bool enabled); //! @brief 深度範囲を設定します。 static void SetDepthRange(f32 near, f32 far) { s_DepthRangeNear = nw::ut::Clamp(near, 0.0f, 1.0f); s_DepthRangeFar = nw::ut::Clamp(far, 0.0f, 1.0f); s_DepthRange24 = ut::Float24::Float32ToBits24(s_DepthRangeNear - s_DepthRangeFar); } //! @brief WScaleの設定をおこないます。 //! //! @param[in] wscale wscaleの値です。 static void SetWScale(f32 wscale) { if (wscale == 0.0f) { s_WScale24 = 0; } else { s_WScale24 = ut::Float24::Float32ToBits24(-wscale); } } //! @brief 深度フォーマットを設定します。 //! //! @details ここで設定された値はポリゴンオフセットの設定に使用されます。 //! 深度フォーマット設定が実際に設定されるわけではありません。 //! //! @param[in] format 深度フォーマットです。 static void SetDepthFormat(u32 format) { s_DepthFormat = format; } //@} //---------------------------------------- //! @name マスク関連 //@{ //! @brief カラーマスクを設定します。 //! //! @param[in] red 赤色のマスクの有効フラグです。 //! @param[in] green 緑色のマスクの有効フラグです。 //! @param[in] blue 青色のマスクの有効フラグです。 //! @param[in] alpha アルファチャンネルのマスクの有効フラグです。 //! static NW_INLINE void SetColorMask(bool red, bool green, bool blue, bool alpha); //! @brief 深度マスクを設定します。 //! //! @param[in] enabled マスクの有効フラグです。 //! static NW_INLINE void SetDepthMaskEnabled(bool enabled); //! @brief ステンシルマスクを設定します。 //! //! @param[in] mask マスクの有効フラグです。 //! static NW_INLINE void SetStencilMask(u8 mask); //! フレームバッファを有効にするコマンドを発行します。 static NW_INLINE void ActivateFrameBuffer(); //! マスクを有効にするコマンドを発行します。 static NW_INLINE void ActivateMask(); //@} //---------------------------------------- //! @name 参照テーブル関連 //@{ // TODO: Shadow と Gas には未対応ですので、グラフィックスランタイムで実装を行うときに対応します。 //! @brief LookupTable を設定するターゲットの定義です。 enum LutTarget { LUT_TARGET_D0, //!< D0の参照テーブルを表します。 LUT_TARGET_D1, //!< D1の参照テーブルを表します。 LUT_TARGET_SP, //!< SPの参照テーブルを表します。 LUT_TARGET_FR, //!< FRの参照テーブルを表します。 LUT_TARGET_RB, //!< RBの参照テーブルを表します。 LUT_TARGET_RG, //!< RGの参照テーブルを表します。 LUT_TARGET_RR, //!< RRの参照テーブルを表します。 LUT_TARGET_SP0, //!< 0番目の角度減衰テーブルを表します。 LUT_TARGET_SP1, //!< 1番目の角度減衰テーブルを表します。 LUT_TARGET_SP2, //!< 2番目の角度減衰テーブルを表します。 LUT_TARGET_SP3, //!< 3番目の角度減衰テーブルを表します。 LUT_TARGET_SP4, //!< 4番目の角度減衰テーブルを表します。 LUT_TARGET_SP5, //!< 5番目の角度減衰テーブルを表します。 LUT_TARGET_SP6, //!< 6番目の角度減衰テーブルを表します。 LUT_TARGET_SP7, //!< 7番目の角度減衰テーブルを表します。 LUT_TARGET_DA0, //!< 0番目の距離減衰テーブルを表します。 LUT_TARGET_DA1, //!< 1番目の距離減衰テーブルを表します。 LUT_TARGET_DA2, //!< 2番目の距離減衰テーブルを表します。 LUT_TARGET_DA3, //!< 3番目の距離減衰テーブルを表します。 LUT_TARGET_DA4, //!< 4番目の距離減衰テーブルを表します。 LUT_TARGET_DA5, //!< 5番目の距離減衰テーブルを表します。 LUT_TARGET_DA6, //!< 6番目の距離減衰テーブルを表します。 LUT_TARGET_DA7, //!< 7番目の距離減衰テーブルを表します。 LUT_TARGET_FOG, //!< FOGの参照テーブルを表します。 LUT_TARGET_COUNT //!< 定義数を表します。 }; //-------------------------------------------------------------------------- //! @brief LUTの入力が絶対値かどうかを指定します。 //! //! @param[in] target LUTのターゲットを指定します。 //! @param[in] isAbs LUTの入力が絶対値かどうかを指定します。 //--------------------------------------------------------------------------- static void SetLutIsAbs(LutTarget target, bool isAbs) { NW_ASSERT(target < LUT_TARGET_COUNT); if (LUT_TARGET_SP0 <= target && target <= LUT_TARGET_SP7) { target = LUT_TARGET_SP; } if (isAbs) { s_LutIsAbs &= ~(0x1 << (1 + 4 * target)); } else { s_LutIsAbs |= 0x1 << (1 + 4 * target) ; } } //-------------------------------------------------------------------------- //! @brief LUTの入力値を指定します。 //! //! @param[in] target LUTのターゲットを指定します。 //! @param[in] input LUTの入力値を指定します。 //--------------------------------------------------------------------------- static void SetLutInput( LutTarget target, ResLightingLookupTable::Input input ) { NW_ASSERT(target < LUT_TARGET_COUNT); NW_ASSERT(input < ResLightingLookupTable::INPUT_NUM); if (LUT_TARGET_SP0 <= target && target <= LUT_TARGET_SP7) { target = LUT_TARGET_SP; } s_LutInput &= ~(0x7 << (4 * target)); s_LutInput |= input << (4 * target); } //-------------------------------------------------------------------------- //! @brief LUTのスケール値を指定します。 //! //! @param[in] target LUTのターゲットを指定します。 //! @param[in] scale LUTのスケール値を指定します。 //--------------------------------------------------------------------------- static void SetLutScale( LutTarget target, ResLightingLookupTable::Scale scale ) { NW_ASSERT(target < LUT_TARGET_COUNT); NW_ASSERT(scale <= ResLightingLookupTable::SCALE_MAX); if (LUT_TARGET_SP0 <= target && target <= LUT_TARGET_SP7) { target = LUT_TARGET_SP; } s_LutScale &= ~(0x7 << (4 * target)); s_LutScale |= scale << (4 * target); } //-------------------------------------------------------------------------- //! @brief LUTのパラメータをコマンド出力します。 //--------------------------------------------------------------------------- static void ActivateLutParameters() { enum { REG_LUT_ABS = 0x1d0 }; const u32 HEADER = internal::MakeCommandHeader( REG_LUT_ABS, 3, true, 0xf ); const u32 COMMAND[] = { s_LutIsAbs, HEADER, s_LutInput, s_LutScale }; internal::NWUseCmdlist( &COMMAND[0] ); } //-------------------------------------------------------------------------- //! @brief LUTのパラメータの状態をリセットします。 //--------------------------------------------------------------------------- static void ResetLutParameters() { s_LutIsAbs = 0; s_LutInput = 0; s_LutScale = 0; } //--------------------------------------------------------------------------- //! @brief 参照テーブルを参照テーブルキャッシュに設定します。 //! //! @param[in] lookupTable 設定する参照テーブルです。 //! @param[in] target 設定するターゲットです。 //--------------------------------------------------------------------------- static void ActivateLookupTable(ResImageLookupTable lookupTable, LutTarget target); //--------------------------------------------------------------------------- //! @brief 参照テーブルキャッシュに設定された参照テーブルを削除します。 //! //! @param[in] lookupTable 削除する参照テーブルです。 //--------------------------------------------------------------------------- static void InvalidateLookupTable(ResImageLookupTable lookupTable); //--------------------------------------------------------------------------- //! @brief 全ての参照テーブルを無効化します。 //--------------------------------------------------------------------------- static void InvalidateAllLookupTables(); //@} //---------------------------------------- //! @name ライト関連 //@{ //-------------------------------------------------------------------------- //! @brief ライトのイネーブルフラグをリセットします。 //--------------------------------------------------------------------------- static void ResetFragmentLightEnabled() { s_LightPositionW = 0x0; s_LightShadowed = 0xFF; s_LightSpotEnabled = 0xFF; s_LightDistanceAttnEnabled = 0xFF; } //-------------------------------------------------------------------------- //! @brief ポジションWの値を取得します。 //! //! @param[in] index ライトのインデックスです。 //-------------------------------------------------------------------------- static NW_INLINE bool GetFragmentLightPositionW(int index) { return ((s_LightPositionW >> index) & 0x1); } //-------------------------------------------------------------------------- //! @brief ポジションWの値を設定します。 //! //! @param[in] index ライトのインデックスです。 //! @param[in] isWZero W成分が0かどうかを表します。 //-------------------------------------------------------------------------- static NW_INLINE void SetFragmentLightPositionW(int index, bool isWZero) { // 1: isWZero, 0: !isWZero if (isWZero) { s_LightPositionW |= (0x1 << index); } else { s_LightPositionW &= ~(0x1 << index); } } //-------------------------------------------------------------------------- //! @brief シャドウ減衰を有効にします。 //! //! @param[in] index ライトのインデックスです。 //! @param[in] shadowed シャドウ減衰のイネーブルフラグです。 //-------------------------------------------------------------------------- static void SetFragmentLightShadowed(int index, bool shadowed) { // 0: GL_TRUE, 1: GL_FALSE if (shadowed) { s_LightShadowed &= ~(0x1 << index); } else { s_LightShadowed |= 0x1 << index; } } //-------------------------------------------------------------------------- //! @brief スポットライトの有効設定をおこないます。 //! //! @param[in] index ライトのインデックスです。 //! @param[in] enabled 距離減衰のイネーブルフラグです。 //-------------------------------------------------------------------------- static void SetFragmentLightSpotEnabled(int index, bool enabled) { // 0: GL_TRUE, 1: GL_FALSE if (enabled) { s_LightSpotEnabled &= ~(0x1 << index); } else { s_LightSpotEnabled |= 0x1 << index; } } //-------------------------------------------------------------------------- //! @brief 距離減衰の有効設定をおこないます。 //! //! @param[in] index ライトのインデックスです。 //! @param[in] enabled 距離減衰のイネーブルフラグです。 //-------------------------------------------------------------------------- static void SetFragmentLightDistanceAttnEnabled(int index, bool enabled) { // 0: GL_TRUE, 1: GL_FALSE if (enabled) { s_LightDistanceAttnEnabled &= ~(0x1 << index); } else { s_LightDistanceAttnEnabled |= 0x1 << index; } } //-------------------------------------------------------------------------- //! @brief 距離減衰テーブルを設定します。 //! //! @param[in] index ライトのインデックスです。 //! @param[in] lookupTable 距離減衰のLUTを指定します。 //-------------------------------------------------------------------------- static NW_INLINE void ActivateFragmentLightDistanceAttnTable(int index, const ResImageLookupTable lookupTable) { GraphicsDevice::LutTarget tableTarget = static_cast(GraphicsDevice::LUT_TARGET_DA0 + index); GraphicsDevice::ActivateLookupTable(lookupTable, tableTarget); } //-------------------------------------------------------------------------- //! @brief スポットテーブルを設定します。 //! //! @param[in] index ライトのインデックスです。 //! @param[in] lookupTable スポットライトのLUTを指定します。 //-------------------------------------------------------------------------- static NW_INLINE void ActivateFragmentLightSpotTable(int index, const ResImageLookupTable lookupTable) { GraphicsDevice::LutTarget tableTarget = static_cast(GraphicsDevice::LUT_TARGET_SP0 + index); GraphicsDevice::ActivateLookupTable(lookupTable, tableTarget); } //-------------------------------------------------------------------------- //! @brief 距離減衰のスケールとバイアスのコマンドを発行します。 //! //! @param[in] index ライトインデックスです。 //! @param[in] scalef20 距離減衰のスケール値です。 //! @param[in] biasf20 距離減衰のバイアス値です。 //--------------------------------------------------------------------------- static void ActivateFragmentLightDistanceAttnScaleBias(int index, u32 scalef20, u32 biasf20) { enum { REG_DISTANCE_ATTN_BIAS = 0x14a, REG_DISTANCE_ATTN_SCALE = 0x14b }; const u32 HEADER = internal::MakeCommandHeader(REG_DISTANCE_ATTN_BIAS, 2, true, 0x7); u32 COMMAND[] = { biasf20, HEADER + 0x10 * index, scalef20, 0 }; internal::NWUseCmdlist( &COMMAND[0] ); } //-------------------------------------------------------------------------- //! @brief フラグメントライト用のコマンドを発行します。 //! //! @param[in] index 設定するライトのインデックスです。 //! @param[in] pos ライトのポジションです。 //--------------------------------------------------------------------------- static NW_INLINE void ActivateFragmentLightPosition(s32 index, const math::VEC4& pos) { enum { REG_FRAGMENT_LIGHT_POS_BASE = 0x144 }; const u32 POS_HEADER = internal::MakeCommandHeader(REG_FRAGMENT_LIGHT_POS_BASE, 2, true, 0xF); u32 LIGHT_COMMAND[4] = { ut::Float16(pos.y).GetFloat16Value() << 16 | ut::Float16(pos.x).GetFloat16Value(), // pos_y << 16 | pos_x POS_HEADER + 0x10 * index, ut::Float16(pos.z).GetFloat16Value(), // pos_z 0 }; internal::NWUseCmdlist( &LIGHT_COMMAND[0] ); } //-------------------------------------------------------------------------- //! @brief フラグメントライトの位置情報を発行します。 //! //! @param[in] index ライトのインデックスです。 //! @param[in] pos ライトの位置です。 //! @param[in] spotDir ライトのスポット方向です。 //--------------------------------------------------------------------------- static NW_INLINE void ActivateFragmentLightPosition(s32 index, const math::VEC4& pos, const math::VEC3& spotDir) { enum { REG_FRAGMENT_LIGHT_POS_BASE = 0x144 }; const u32 POS_HEADER = internal::MakeCommandHeader(REG_FRAGMENT_LIGHT_POS_BASE, 4, true, 0xF); u32 LIGHT_COMMAND[6] = { ut::Float16(pos.y).GetFloat16Value() << 16 | ut::Float16(pos.x).GetFloat16Value(), // pos_y << 16 | pos_x POS_HEADER + 0x10 * index, ut::Float16(pos.z).GetFloat16Value(), // pos_z ut::Fixed13(-spotDir.y).GetFixed13Value() << 16 | ut::Fixed13(-spotDir.x).GetFixed13Value(), // dir_y << 16 | dir_x ut::Fixed13(-spotDir.z).GetFixed13Value(), // dir_z 0 }; internal::NWUseCmdlist( &LIGHT_COMMAND[0] ); } //-------------------------------------------------------------------------- //! @brief フラグメントライトの有効設定のコマンドを発行します。 //--------------------------------------------------------------------------- static void ActivateFragmentLightEnabled() { enum { REG_FRAGMENT_LIGHT_KIND = 0x1c4 }; // 0x1c4 の [22:16] はFR,D0,D1,ReflのlutEnableフラグなので、BEを外しておく。 const u32 HEADER = internal::MakeCommandHeader(REG_FRAGMENT_LIGHT_KIND, 1, false, 0xb); const u32 COMMAND[] = { s_LightShadowed | (s_LightSpotEnabled << 8) | (s_LightDistanceAttnEnabled << 24), HEADER }; internal::NWUseCmdlist(&COMMAND[0]); } //@} //-------------------------------------------------------------------------- //! @brief レンダリングターゲットサーフェスのウィンドウのサイズを設定します。 //! //! @param[in] viewport 設定するビューポートです。 //-------------------------------------------------------------------------- static void ActivateViewport(const Viewport& viewport) { enum { REG_VIEWPORT_WIDTH_HALF = 0x41, REG_VIEWPORT_WIDTH_HALF_S = 0x42, REG_VIEWPORT_HEIGHT_HALF = 0x43, REG_VIEWPORT_HEIGHT_HALF_S = 0x44, REG_VIEWPORT_XY = 0x68 }; u16 x16 = static_cast(viewport.GetBound().GetX()); u16 y16 = static_cast(viewport.GetBound().GetY()); const u32 HEADER_VIEWPORT_WIDTH_HALF = nw::gfx::internal::MakeCommandHeader( REG_VIEWPORT_WIDTH_HALF, 4, true, 0xF ); const u32 HEADER_VIEWPORT_XY = nw::gfx::internal::MakeCommandHeader( REG_VIEWPORT_XY, 1, false, 0xF ); u32 VIEWPORT_COMMAND[] = { nw::ut::Float24::Float32ToBits24( viewport.GetBound().GetWidth() / 2.f ), HEADER_VIEWPORT_WIDTH_HALF, (ut::Float31::Float32ToBits31( 2.f / viewport.GetBound().GetWidth() ) << 1), nw::ut::Float24::Float32ToBits24( viewport.GetBound().GetHeight()/2.f ), (ut::Float31::Float32ToBits31( 2.f / viewport.GetBound().GetHeight() ) << 1), 0, (x16 | (y16 << 16)), HEADER_VIEWPORT_XY }; nw::gfx::internal::NWUseCmdlist( &VIEWPORT_COMMAND[0] ); } //-------------------------------------------------------------------------- //! @brief レンダリングバッファサイズを指定します。 //! //! @param[in] width レンダリングバッファの幅サイズです。 //! @param[in] height レンダリングバッファの縦サイズです。 //-------------------------------------------------------------------------- static void SetRenderBufferSize(s32 width, s32 height) { s_RenderBufferWidth = width; s_RenderBufferHeight = height; } //-------------------------------------------------------------------------- //! @brief シザリングの矩形情報を発行します。 //! //! @param[in] enabled シザリングが有効化どうかのフラグです。 //! @param[in] scissor 設定するシザリング矩形です。 //-------------------------------------------------------------------------- static void ActivateScissor(bool enabled, const ut::Rect& scissor) { enum { REG_SCISSOR_ENABLE = 0x65, REG_SCISSOR_XY = 0x66, REG_SCISSOR_WH = 0x67, REG_SCISSOR_DISABLED = 0, REG_SCISSOR_ENABLED = 3 }; NW_MINMAX_ASSERT(scissor.GetX(), 0, static_cast(s_RenderBufferWidth)); NW_MINMAX_ASSERT(scissor.GetY(), 0, static_cast(s_RenderBufferHeight)); NW_MINMAX_ASSERT(scissor.GetX() + scissor.GetWidth(), 0, static_cast(s_RenderBufferWidth)); NW_MINMAX_ASSERT(scissor.GetY() + scissor.GetHeight(), 0, static_cast(s_RenderBufferHeight)); u16 x16 = static_cast(scissor.GetX()); u16 w16 = static_cast(scissor.GetWidth()); u16 y16 = static_cast(scissor.GetY()); u16 h16 = static_cast(scissor.GetHeight()); const u32 HEADER_SCISSOR = nw::gfx::internal::MakeCommandHeader( REG_SCISSOR_ENABLE, 3, true, 0xF ); u32 SCISSOR_COMMAND[] = { enabled ? REG_SCISSOR_ENABLED : REG_SCISSOR_DISABLED, HEADER_SCISSOR, enabled ? (x16 | (y16 << 16)) : 0, enabled ? ((x16 + w16 - 1) | ((y16 + h16 - 1) << 16)) : ((s_RenderBufferWidth - 1) | ((s_RenderBufferHeight - 1) << 16)), }; nw::gfx::internal::NWUseCmdlist( &SCISSOR_COMMAND[0] ); } //--------------------------------------------------------------------------- //! @brief GraphicsDevice の状態を表示します。 //--------------------------------------------------------------------------- static void Report(); private: //-------------------------------------------------------------------------- //! @brief LUT 転送の準備コマンドを送信します。 //! //! @param[in] target LUTのタイプです。 //--------------------------------------------------------------------------- static NW_INLINE void ActivateLutLoadSetting(LutTarget target); //! @brief フレームバッファコマンドを更新します。 static NW_INLINE void UpdateFrameBufferCommand(); static ResFragmentOperation::FragmentOperationMode s_FragOperationMode; static bool s_IsFrameBufferUpdated; static bool s_BlendEnabled; static bool s_DepthTestEnabled; static bool s_StencilTestEnabled; static bool s_DepthMask; static bool s_PolygonOffsetEnabled; static u8 s_StencilMask; static u32 s_ColorMask; static u32 s_RenderBufferWidth; static u32 s_RenderBufferHeight; enum { COLOR_READ_MASK_INDEX = 4, COLOR_WRITE_MASK_INDEX = 6, DEPTH_READ_MASK_INDEX = 7, DEPTH_WRITE_MASK_INDEX = 8, FRAME_BUFFER_COMMAND_COUNT = 10 }; static u32 s_FrameBufferCommand[FRAME_BUFFER_COMMAND_COUNT]; static u32 s_LutIsAbs; static u32 s_LutInput; static u32 s_LutScale; static u32 s_DepthFormat; static u32 s_WScale24; static f32 s_DepthRangeNear; static f32 s_DepthRangeFar; static u32 s_DepthRange24; static f32 s_PolygonOffsetUnit; static u32 s_LightPositionW; static u32 s_LightShadowed; static u32 s_LightSpotEnabled; static u32 s_LightDistanceAttnEnabled; static ResImageLookupTable m_LutTargets[LUT_TARGET_COUNT]; }; //---------------------------------------- NW_INLINE void GraphicsDevice::SetBlendEnabled(bool enabled) { s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_BlendEnabled != enabled); s_BlendEnabled = enabled; } //---------------------------------------- NW_INLINE void GraphicsDevice::SetStencilTestEnabled(bool enabled) { s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_StencilTestEnabled != enabled); s_StencilTestEnabled = enabled; } //---------------------------------------- NW_INLINE void GraphicsDevice::SetDepthTestEnabled(bool enabled) { s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_DepthTestEnabled != enabled); s_DepthTestEnabled = enabled; } //---------------------------------------- NW_INLINE void GraphicsDevice::ActivateMask() { enum RegColorMask { REG_COLOR_MASK_ADDR = 0x107, REG_COLOR_MASK_SHIFT = 8, REG_DEPTH_MASK_SHIFT = 12, REG_STENCIL_MASK_ADDR = 0x105, REG_STENCIL_MASK_SHIFT = 8 }; const u32 COLOR_MASK_HEADER = internal::MakeCommandHeader(REG_COLOR_MASK_ADDR, 1, false, 0x2); const u32 STENCIL_MASK_HEADER = internal::MakeCommandHeader(REG_STENCIL_MASK_ADDR, 1, false, 0x2); const u32 COMMAND[] = { s_ColorMask << REG_COLOR_MASK_SHIFT | s_DepthMask << REG_DEPTH_MASK_SHIFT, COLOR_MASK_HEADER, s_StencilMask << REG_STENCIL_MASK_SHIFT, STENCIL_MASK_HEADER }; internal::NWUseCmdlist(&COMMAND[0]); } //---------------------------------------- NW_INLINE void GraphicsDevice::ActivateFrameBuffer() { if (s_IsFrameBufferUpdated) { s_IsFrameBufferUpdated = false; UpdateFrameBufferCommand(); } internal::NWUseCmdlist(&s_FrameBufferCommand[0], sizeof(s_FrameBufferCommand)); } //---------------------------------------- void NW_INLINE GraphicsDevice::UpdateFrameBufferCommand() { enum { COLOR_MASK_ALL = 0xF, COLOR_ACCESS_ENABLE = 0xF, DEPTH_ACCESS_ENABLE = 0x2, STENCIL_ACCESS_ENABLE = 0x1 }; s_FrameBufferCommand[COLOR_READ_MASK_INDEX] = 0; s_FrameBufferCommand[COLOR_WRITE_MASK_INDEX] = 0; // カラーバッファのリードとライト設定 if (s_FragOperationMode != ResFragmentOperation::FRAGMENT_OPERATION_MODE_GL) { s_FrameBufferCommand[COLOR_READ_MASK_INDEX] = COLOR_ACCESS_ENABLE; s_FrameBufferCommand[COLOR_WRITE_MASK_INDEX] = COLOR_ACCESS_ENABLE; } else if (s_ColorMask) { if (s_BlendEnabled || (s_ColorMask != COLOR_MASK_ALL)) { s_FrameBufferCommand[COLOR_READ_MASK_INDEX] = COLOR_ACCESS_ENABLE; } s_FrameBufferCommand[COLOR_WRITE_MASK_INDEX] = COLOR_ACCESS_ENABLE; } s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] = 0; s_FrameBufferCommand[DEPTH_WRITE_MASK_INDEX] = 0; if (s_FragOperationMode == ResFragmentOperation::FRAGMENT_OPERATION_MODE_GAS) { s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] = DEPTH_ACCESS_ENABLE | STENCIL_ACCESS_ENABLE; } else if (s_FragOperationMode == ResFragmentOperation::FRAGMENT_OPERATION_MODE_GL) { // デプスバッファのリードとライト設定 if (s_DepthTestEnabled) { if (s_DepthMask) { s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] = DEPTH_ACCESS_ENABLE; s_FrameBufferCommand[DEPTH_WRITE_MASK_INDEX] = DEPTH_ACCESS_ENABLE; } else if (s_ColorMask) { s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] = DEPTH_ACCESS_ENABLE; } } // ステンシルバッファのリードとライト設定 if (s_StencilTestEnabled) { if (s_StencilMask) { s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] |= STENCIL_ACCESS_ENABLE; s_FrameBufferCommand[DEPTH_WRITE_MASK_INDEX] |= STENCIL_ACCESS_ENABLE; } else if (s_ColorMask) { s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] |= STENCIL_ACCESS_ENABLE; } } } } //---------------------------------------- NW_INLINE void GraphicsDevice::ActivateLutLoadSetting(LutTarget target) { enum { REG_PICA_LIGHTING_LUT_SETTING = 0x1C5, REG_PICA_FOG_LUT_SETTING = 0x0e6 }; const u32 LIGHTING_HEADER = internal::MakeCommandHeader(REG_PICA_LIGHTING_LUT_SETTING, 1, false, 0xF); const u32 FOG_HEADER = internal::MakeCommandHeader(REG_PICA_FOG_LUT_SETTING, 1, false, 0xF); if (target == LUT_TARGET_FOG) { u32 LUT_COMMAND[2] = { 0, FOG_HEADER }; internal::NWUseCmdlist( &LUT_COMMAND[0] ); return; } int targetReg = 0; // スポットと距離減衰はtarget+1のレジスタに設定する。 if (target < LUT_TARGET_SP0) { targetReg = static_cast(target); } else { targetReg = static_cast(target) + 1; } u32 LUT_COMMAND[2] = { targetReg << 8, LIGHTING_HEADER }; internal::NWUseCmdlist( &LUT_COMMAND[0] ); } //---------------------------------------- NW_INLINE void GraphicsDevice::ActivatePolygonOffset() { // PolygonOffset の設定 enum { REG_POLYGON_OFFSET = 0x4d, REG_WSCALE_ENABLE = 0x6d }; const u32 OFFSET_HEADER = internal::MakeCommandHeader(REG_POLYGON_OFFSET, 2, true, 0x7); const u32 WSCALE_HEADER = internal::MakeCommandHeader(REG_WSCALE_ENABLE, 1, false, 0x1); static u32 COMMAND[] = { 0, WSCALE_HEADER, 0, OFFSET_HEADER, 0, 0 }; f32 zBias; f32 offset; if (s_WScale24 == 0) { COMMAND[0] = 1; COMMAND[2] = s_DepthRange24; zBias = s_DepthRangeNear; offset = (s_DepthRangeNear - s_DepthRangeFar) * s_PolygonOffsetUnit; } else { COMMAND[0] = 0; COMMAND[2] = s_WScale24; zBias = 0.0f; offset = -s_PolygonOffsetUnit; } // DMP のドキュメントでは wScale が有効な際には PolygonOffset が効かない仕様になっていますが、 // W-Buffering 時にも PolygonOffset の需要がある為、Z-Buffering と同様に設定します。 if (s_PolygonOffsetEnabled) { if (s_DepthFormat == RENDER_DEPTH_FORMAT_16) { zBias -= offset / 65535.0f; } else { // 24bit 浮動小数(仮数16bit)の精度限界により、誤差で消えてしまう為 // 精度が問題にならないような定数値を掛けておく必要があります。 // 0.5f 付近の深度を基準として 128.0f を掛けておく事にします。 zBias -= offset * 128.0f / 16777215.0f; } } COMMAND[4] = ut::Float24::Float32ToBits24(zBias); internal::NWUseCmdlist( &COMMAND[0] ); } //---------------------------------------- NW_INLINE void GraphicsDevice::SetColorMask(bool red, bool green, bool blue, bool alpha) { u32 colorMask = u32(red) | (u32(green) << 1) | (u32(blue) << 2) | (u32(alpha) << 3); s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_ColorMask != colorMask); s_ColorMask = colorMask; } //---------------------------------------- NW_INLINE void GraphicsDevice::SetDepthMaskEnabled(bool enabled) { s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_DepthMask != enabled); s_DepthMask = enabled; } //---------------------------------------- NW_INLINE void GraphicsDevice::SetStencilMask(u8 mask) { s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_StencilMask != mask); s_StencilMask = mask; } } // namespace gfx } // namespace nw #endif // NW_GFX_GRAPHICSDEVICE_H_