/*---------------------------------------------------------------------------* Project: Horizon File: gr_RenderState.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: 38755 $ *---------------------------------------------------------------------------*/ #include namespace nn { namespace gr { namespace CTR { bit32* RenderState::Culling::MakeCommand( bit32* command, bool isUpdateFBAccess ) const { bit32 culling = 0; if ( isEnable ) { if ( ( frontFace == FRONT_FACE_CW && cullFace == CULL_FACE_FRONT ) || ( frontFace == FRONT_FACE_CCW && cullFace == CULL_FACE_BACK ) ) { culling = 2; } else { culling = 1; } } // 0x040 *command++ = culling; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_CULL_FACE ); return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command; } //------------------------------------------------------------------------------ bit32* RenderState::Culling::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache ) { // 0x040 *command++ = 0x0; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_CULL_FACE, 0x1 ); if ( isClearFrameBufferCache ) { command = FBAccess::MakeClearCacheCommand( command ); } return command; } //------------------------------------------------------------------------------ bit32* RenderState::Blend::MakeCommand( bit32* command, bool isUpdateFBAccess ) const { if ( isEnable ) { // 0x100 *command++ = PICA_CMD_DATA_COLOR_OPERATION( PICA_DATA_FRAGOP_MODE_DMP, PICA_DATA_ENABLE_BLEND ); *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_COLOR_OPERATION, 0x3 ); // 0x101 *command++ = PICA_CMD_DATA_BLEND_FUNC_SEPARATE( eqRgb, eqAlpha, srcRgb, dstRgb, srcAlpha, dstAlpha ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_BLEND_FUNC ); // 0x102 *command++ = PICA_CMD_DATA_LOGIC_OP( PICA_DATA_LOGIC_NOOP ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_LOGIC_OP ); // 0x103 *command++ = colorR | colorG << 8 | colorB << 16 | colorA << 24; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_BLEND_COLOR ); } else { command = Blend::MakeDisableCommand( command, false ); } return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command; } //------------------------------------------------------------------------------ bit32* RenderState::Blend::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache ) { // 0x100 *command++ = PICA_CMD_DATA_COLOR_OPERATION( PICA_DATA_FRAGOP_MODE_DMP, PICA_DATA_ENABLE_BLEND ); *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_COLOR_OPERATION, 0x3 ); // 0x101 *command++ = PICA_CMD_DATA_BLEND_FUNC( PICA_DATA_BLEND_EQUATION_ADD, PICA_DATA_BLEND_FUNC_ONE, PICA_DATA_BLEND_FUNC_ZERO ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_BLEND_FUNC ); if ( isClearFrameBufferCache ) { command = FBAccess::MakeClearCacheCommand( command ); } return command; } //------------------------------------------------------------------------------ bit32* RenderState::LogicOp::MakeCommand( bit32* command, bool isUpdateFBAccess ) const { if ( isEnable ) { // 0x100 *command++ = PICA_CMD_DATA_COLOR_OPERATION( PICA_DATA_FRAGOP_MODE_DMP, PICA_DATA_ENABLE_COLOR_LOGIC_OP ); *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_COLOR_OPERATION, 0x3 ); // 0x101 *command++ = PICA_CMD_DATA_LOGIC_OP_ENABLE(); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_BLEND_FUNC ); // 0x102 *command++ = PICA_CMD_DATA_LOGIC_OP( opCode ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_LOGIC_OP ); } return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command; } //------------------------------------------------------------------------------ bit32* RenderState::ShadowMap::MakeCommand( bit32* command, bool isUpdateFBAccess, bool isAddDummyCommand ) const { if ( isEnable ) { // 0x100 *command++ = PICA_CMD_DATA_COLOR_OPERATION( PICA_DATA_FRAGOP_MODE_SHADOW_DMP, PICA_DATA_ENABLE_BLEND ); *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_COLOR_OPERATION, 0x1 ); // 0x8b command = MakeTextureCommand( command, isAddDummyCommand ); // 0x130 command = MakeAttenuationCommand( command ); } return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command; } //------------------------------------------------------------------------------ bit32* RenderState::ShadowMap::MakeTextureCommand( bit32* command, bool isAddDummyCommand ) const { // Send a dummy command to 0x080 three times if ( isAddDummyCommand ) { *command++ = 0x0; *command++ = PICA_CMD_HEADER_BURST_BE( PICA_REG_TEXTURE_FUNC, 0x3, 0x0 ); *command++ = 0x0; *command++ = 0x0; } // Clear the lowest 1 bit and use the upper 23 bits of the 24 bits u32 zBiasFix24 = Float32ToUnsignedFix24( zBias ); bit32 clearMask = 0x00fffffe; zBiasFix24 &= clearMask; // The zScale value is invalid and kept just for compatibility. // (Assigned to 0 here.) u8 zScale8 = 0; // 0x8b *command++ = PICA_CMD_DATA_TEXTURE_SHADOW( isPerspective, // f32 -> 24bit unsigned, fixed point upper 23 bits zBiasFix24, // zScale value is invalid zScale8 ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_TEXTURE0_SHADOW ); return command; } //------------------------------------------------------------------------------ bit32* RenderState::ShadowMap::MakeAttenuationCommand( bit32* command ) const { // 0x130 *command++ = ( Float32ToFloat16( - penumbraScale ) ) << 16 | Float32ToFloat16( penumbraScale + penumbraBias ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_SHADOW ); return command; } //------------------------------------------------------------------------------ bit32* RenderState::AlphaTest::MakeCommand( bit32* command, bool isUpdateFBAccess ) const { // 0x104 *command++ = PICA_CMD_DATA_FRAGOP_ALPHA_TEST( isEnable, func, refValue ); *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_FRAGOP_ALPHA_TEST, 0x3 ); return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command; } //------------------------------------------------------------------------------ bit32* RenderState::AlphaTest::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache ) { // 0x104 *command++ = 0x0; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_FRAGOP_ALPHA_TEST, 0x1 ); if ( isClearFrameBufferCache ) { command = FBAccess::MakeClearCacheCommand( command ); } return command; } //------------------------------------------------------------------------------ bit32* RenderState::StencilTest::MakeCommand( bit32* command, bool isUpdateFBAccess ) const { // 0x105 *command++ = PICA_CMD_DATA_STENCIL_TEST( isEnable, func, maskOp, ref, mask ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_STENCIL_TEST ); // 0x106 *command++ = PICA_CMD_DATA_STENCIL_OP( opFail, opZFail, opZPass ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_STENCIL_OP ); return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command; } //------------------------------------------------------------------------------ bit32* RenderState::StencilTest::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache ) { // 0x105 *command++ = 0x0; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_STENCIL_TEST, 0x1 ); if ( isClearFrameBufferCache ) { command = FBAccess::MakeClearCacheCommand( command ); } return command; } //------------------------------------------------------------------------------ bit32* RenderState::DepthTest::MakeCommand( bit32* command, bool isUpdateFBAccess ) const { // [ 0:7 ] and [12:12] in 0x107 are depth test settings, and [8:11] is the color mask settings. *command++ = PICA_CMD_DATA_DEPTH_COLOR_MASK( isEnable, func, m_RenderState.colorMask & COLOR_MASK_R, m_RenderState.colorMask & COLOR_MASK_G, m_RenderState.colorMask & COLOR_MASK_B, m_RenderState.colorMask & COLOR_MASK_A, isEnableWrite ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_DEPTH_COLOR_MASK ); return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command; } //------------------------------------------------------------------------------ bit32* RenderState::DepthTest::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache ) { const bool isEnableDepth = false; const PicaDataDepthTest depthFunc = PICA_DATA_DEPTH_TEST_LESS; const bool colorMaskRed = true; const bool colorMaskGreen = true; const bool colorMaskBlue = true; const bool colorMaskAlpha = true; const bool isEnableDepthWrite = false; // [ 0:7 ] and [12:12] in 0x107 are depth test settings, and [8:11] is the color mask settings. *command++ = PICA_CMD_DATA_DEPTH_COLOR_MASK( isEnableDepth, depthFunc, colorMaskRed, colorMaskGreen, colorMaskBlue, colorMaskAlpha, isEnableDepthWrite ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_DEPTH_COLOR_MASK ); if ( isClearFrameBufferCache ) { command = FBAccess::MakeClearCacheCommand( command ); } return command; } //------------------------------------------------------------------------------ bit32* RenderState::WBuffer::MakeCommand( bit32* command, bool isUpdateFBAccess ) const { // When the w buffer is disabled if ( wScale == 0.0f ) { // 0x6d *command++ = 1; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_WSCALE ); // 0x04d *command++ = Float32ToFloat24( depthRangeNear - depthRangeFar ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_WSCALE_DATA1 ); // 0x04e // Set the polygon offset f32 zNear = isEnablePolygonOffset ? depthRangeNear - (depthRangeNear - depthRangeFar) * polygonOffsetUnit / f32( (1 << depthRangeBit) - 1) : depthRangeNear; *command++ = Float32ToFloat24( zNear ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_WSCALE_DATA2 ); } // When the w buffer is enabled else { // 0x6d *command++ = 0; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_WSCALE ); // 0x04d *command++ = Float32ToFloat24( - wScale ); *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_WSCALE_DATA1 ); // 0x04e *command++ = isEnablePolygonOffset ? ( ( depthRangeBit == 24 ) ? // To avoid loss of data due to the precision of the 24-bit float type, multiply by 128.0f using a value near 0.5f as the baseline depth value. // ( polygonOffsetUnit * 128.0f / f32( (1 << depthRangeBit) - 1 ) ) : ( polygonOffsetUnit / f32( (1 << depthRangeBit) - 1 ) ) ) : 0.0f; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_WSCALE_DATA2 ); } return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command; } //------------------------------------------------------------------------------ bit32* RenderState::FBAccess::MakeCommand( bit32* command, bool isClearFrameBufferCache ) const { if ( isClearFrameBufferCache ) { // 0x111 *command++ = 0x1; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_COLOR_DEPTH_BUFFER_CLEAR1 ); // 0x110 *command++ = 0x1; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_COLOR_DEPTH_BUFFER_CLEAR0 ); } if ( m_RenderState.shadowMap.isEnable ) { // 0x112 Enable color buffer READ *command++ = 0xf; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_COLOR_BUFFER_READ, 0x1 ); // 0x113 Enable color buffer WRITE *command++ = 0xf; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_COLOR_BUFFER_WRITE, 0x1 ); // 0x114 Enable depth/stencil buffer READ *command++ = 0x0; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DEPTH_STENCIL_BUFFER_READ, 0x1 ); // 0x115 Enable depth/stencil buffer WRITE *command++ = 0x0; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DEPTH_STENCIL_BUFFER_WRITE, 0x1 ); } else { // 0x112 *command++ = ( (m_RenderState.colorMask && m_RenderState.colorMask != 0xf) || (m_RenderState.colorMask && m_RenderState.blend.isEnable ) || (m_RenderState.colorMask && m_RenderState.logicOp.isEnable ) ) ? 0xf : 0; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_COLOR_BUFFER_READ, 0x1 ); // 0x113 *command++ = m_RenderState.colorMask ? 0xf : 0; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_COLOR_BUFFER_WRITE, 0x1 ); bit32 depth_stencil_read = 0; bit32 depth_stencil_write = 0; if ( m_RenderState.depthTest.isEnable ) { if ( m_RenderState.depthTest.isEnableWrite ) { depth_stencil_read |= 2; depth_stencil_write |= 2; } else if ( m_RenderState.colorMask ) { depth_stencil_read |= 2; } } if ( m_RenderState.stencilTest.isEnable ) { if ( m_RenderState.stencilTest.maskOp != 0 ) { depth_stencil_read |= 1; depth_stencil_write |= 1; } else if ( m_RenderState.colorMask ) { depth_stencil_read |= 1; } } // 0x114 *command++ = depth_stencil_read; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DEPTH_STENCIL_BUFFER_READ, 0x1 ); // 0x115 *command++ = depth_stencil_write; *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DEPTH_STENCIL_BUFFER_WRITE, 0x1 ); } return command; } //------------------------------------------------------------------------------ bit32* RenderState::FBAccess::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache ) { if ( isClearFrameBufferCache ) { command = MakeClearCacheCommand( command ); } // 0x112 : Color read *command++ = 0xf; *command++ = PICA_CMD_HEADER_BURSTSEQ_BE( PICA_REG_COLOR_BUFFER_READ, 0x4, 0x1 ); // 0x113 : Color write *command++ = 0xf; // 0x114 : Depth/Stencil read *command++ = 0x0; // 0x115 : Depth/Stencil write *command++ = 0x0; // Padding *command++ = 0x0; return command; } //------------------------------------------------------------------------------ bit32* RenderState::FBAccess::MakeClearCacheCommand( bit32* command ) { // 0x111 *command++ = 0x1; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_COLOR_DEPTH_BUFFER_CLEAR1 ); // 0x110 *command++ = 0x1; *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_COLOR_DEPTH_BUFFER_CLEAR0 ); return command; } //------------------------------------------------------------------------------ bit32* RenderState::RenderState::MakeCommand( bit32* buffer, bool isClearFrameBufferCache ) const { bit32* command = buffer; command = cullingTest.MakeCommand( command, false ); command = blend.MakeCommand( command, false ); command = logicOp.MakeCommand( command, false ); command = shadowMap.MakeCommand( command, false ); command = alphaTest.MakeCommand( command, false ); command = stencilTest.MakeCommand( command, false ); command = depthTest.MakeCommand( command, false ); command = wBuffer.MakeCommand( command, false ); command = fbAccess.MakeCommand( command, isClearFrameBufferCache ); return command; } //------------------------------------------------------------------------------ RenderState::Culling::Culling( const RenderState& renderState_ ) : isEnable( true ), frontFace( FRONT_FACE_CCW ), cullFace( CULL_FACE_BACK ), m_RenderState( renderState_ ) { } //------------------------------------------------------------------------------ RenderState::Blend::Blend( const RenderState& renderState_ ) : isEnable( false ), eqRgb ( PICA_DATA_BLEND_EQUATION_ADD ), eqAlpha ( PICA_DATA_BLEND_EQUATION_ADD ), srcRgb ( PICA_DATA_BLEND_FUNC_SRC_ALPHA ), srcAlpha( PICA_DATA_BLEND_FUNC_SRC_ALPHA ), dstRgb ( PICA_DATA_BLEND_FUNC_ONE_MINUS_SRC_ALPHA ), dstAlpha( PICA_DATA_BLEND_FUNC_ONE_MINUS_SRC_ALPHA ), colorR( 0xff ), colorG( 0xff ), colorB( 0xff ), colorA( 0xff ), m_RenderState( renderState_ ) { } //------------------------------------------------------------------------------ RenderState::LogicOp::LogicOp( const RenderState& renderState_ ) : isEnable( false ), opCode( PICA_DATA_LOGIC_NOOP ), m_RenderState( renderState_ ) { } //------------------------------------------------------------------------------ RenderState::ShadowMap::ShadowMap( const RenderState& renderState_ ) : isEnable( false ), isPerspective( true ), zBias( 0.0f ), zScale( 1.0f ), penumbraScale( 0.0f ), penumbraBias( 1.0f ), m_RenderState( renderState_ ) { } //------------------------------------------------------------------------------ RenderState::AlphaTest::AlphaTest( const RenderState& renderState_ ) : isEnable( false ), refValue( 0 ), func ( PICA_DATA_ALPHA_TEST_NEVER ), m_RenderState( renderState_ ) { } //------------------------------------------------------------------------------ RenderState::StencilTest::StencilTest( const RenderState& renderState_ ) : isEnable ( false ), maskOp ( 0xff ), func ( PICA_DATA_STENCIL_TEST_ALWAYS ), ref ( 0 ), mask ( 0xff ), opFail ( PICA_DATA_STENCIL_OP_KEEP ), opZFail ( PICA_DATA_STENCIL_OP_KEEP ), opZPass ( PICA_DATA_STENCIL_OP_KEEP ), m_RenderState( renderState_ ) { } //------------------------------------------------------------------------------ RenderState::DepthTest::DepthTest( const RenderState& renderState_ ) : isEnable( true ), isEnableWrite( true ), func( PICA_DATA_DEPTH_TEST_LESS ), m_RenderState( renderState_ ) { } //------------------------------------------------------------------------------ RenderState::WBuffer::WBuffer( const RenderState& renderState_ ) : wScale( 0.f ), isEnablePolygonOffset( false ), polygonOffsetUnit ( 0.f ), depthRangeNear ( 0.0f ), depthRangeFar ( 1.0f ), depthRangeBit ( 24 ), m_RenderState ( renderState_ ) { } //------------------------------------------------------------------------------ RenderState::FBAccess::FBAccess( const RenderState& renderState_ ) : m_RenderState( renderState_ ) { } //------------------------------------------------------------------------------ RenderState::RenderState() : blend ( *this ), logicOp ( *this ), shadowMap ( *this ), alphaTest ( *this ), stencilTest ( *this ), colorMask ( COLOR_MASK_RGBA ), depthTest ( *this ), cullingTest ( *this ), wBuffer ( *this ), fbAccess ( *this ) { } //------------------------------------------------------------------------------ bit32* RenderState::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache ) { command = Culling::MakeDisableCommand( command, false ); command = Blend::MakeDisableCommand( command, false ); command = AlphaTest::MakeDisableCommand( command, false ); command = StencilTest::MakeDisableCommand( command, false ); command = DepthTest::MakeDisableCommand( command, false ); command = FBAccess::MakeDisableCommand( command, isClearFrameBufferCache ); return command; } } // namespace CTR } // namespace gr } // namespace nn