1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     gr_RenderState.cpp
4 
5   Copyright (C)2010 Nintendo Co., Ltd.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Rev: 33699 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/gr/CTR/gr_RenderState.h>
17 
18 namespace nn
19 {
20     namespace gr
21     {
22         namespace CTR
23         {
24 
MakeCommand(bit32 * command,bool isUpdateFBAccess) const25             bit32* RenderState::Culling::MakeCommand( bit32* command, bool isUpdateFBAccess ) const
26             {
27                 bit32 culling = 0;
28 
29                 if ( isEnable )
30                 {
31                     if ( ( frontFace == FRONT_FACE_CW  && cullFace == CULL_FACE_FRONT ) ||
32                          ( frontFace == FRONT_FACE_CCW && cullFace == CULL_FACE_BACK ) )
33                     {
34                         culling = 2;
35                     }
36                     else
37                     {
38                         culling = 1;
39                     }
40                 }
41 
42                 // 0x040
43                 *command++ = culling;
44                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_CULL_FACE );
45 
46                 return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command;
47             }
48 
49             //------------------------------------------------------------------------------
50 
MakeDisableCommand(bit32 * command,bool isClearFrameBufferCache)51             bit32* RenderState::Culling::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache )
52             {
53                 // 0x040
54                 *command++ = 0x0;
55                 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_CULL_FACE, 0x1 );
56 
57                 if ( isClearFrameBufferCache )
58                 {
59                     command = FBAccess::MakeClearCacheCommand( command );
60                 }
61 
62                 return command;
63             }
64 
65             //------------------------------------------------------------------------------
66 
MakeCommand(bit32 * command,bool isUpdateFBAccess) const67             bit32* RenderState::Blend::MakeCommand( bit32* command, bool isUpdateFBAccess ) const
68             {
69                 if ( isEnable )
70                 {
71                     // 0x100
72                     *command++ = PICA_CMD_DATA_COLOR_OPERATION( PICA_DATA_FRAGOP_MODE_DMP, PICA_DATA_ENABLE_BLEND );
73                     *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_COLOR_OPERATION, 0x3 );
74 
75                     // 0x101
76                     *command++ = PICA_CMD_DATA_BLEND_FUNC_SEPARATE( eqRgb, eqAlpha, srcRgb, dstRgb, srcAlpha, dstAlpha );
77                     *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_BLEND_FUNC );
78 
79                     // 0x102
80                     *command++ = PICA_CMD_DATA_LOGIC_OP( PICA_DATA_LOGIC_NOOP );
81                     *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_LOGIC_OP );
82 
83                     // 0x103
84                     *command++ = colorR | colorG << 8 | colorB << 16 | colorA << 24;
85                     *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_BLEND_COLOR );
86                 }
87                 else
88                 {
89                     command = Blend::MakeDisableCommand( command, false );
90                 }
91 
92                 return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command;
93             }
94 
95             //------------------------------------------------------------------------------
96 
MakeDisableCommand(bit32 * command,bool isClearFrameBufferCache)97             bit32* RenderState::Blend::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache )
98             {
99                 // 0x100
100                 *command++ = PICA_CMD_DATA_COLOR_OPERATION( PICA_DATA_FRAGOP_MODE_DMP, PICA_DATA_ENABLE_BLEND );
101                 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_COLOR_OPERATION, 0x3 );
102 
103                 // 0x101
104                 *command++ = PICA_CMD_DATA_BLEND_FUNC( PICA_DATA_BLEND_EQUATION_ADD, PICA_DATA_BLEND_FUNC_ONE, PICA_DATA_BLEND_FUNC_ZERO );
105                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_BLEND_FUNC );
106 
107                 if ( isClearFrameBufferCache )
108                 {
109                     command = FBAccess::MakeClearCacheCommand( command );
110                 }
111 
112                 return command;
113             }
114 
115             //------------------------------------------------------------------------------
116 
MakeCommand(bit32 * command,bool isUpdateFBAccess) const117             bit32* RenderState::LogicOp::MakeCommand( bit32* command, bool isUpdateFBAccess ) const
118             {
119                 if ( isEnable )
120                 {
121                     // 0x100
122                     *command++ = PICA_CMD_DATA_COLOR_OPERATION( PICA_DATA_FRAGOP_MODE_DMP, PICA_DATA_ENABLE_COLOR_LOGIC_OP );
123                     *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_COLOR_OPERATION, 0x3 );
124 
125                     // 0x101
126                     *command++ = PICA_CMD_DATA_LOGIC_OP_ENABLE();
127                     *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_BLEND_FUNC );
128 
129                     // 0x102
130                     *command++ = PICA_CMD_DATA_LOGIC_OP( opCode );
131                     *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_LOGIC_OP );
132                 }
133 
134                 return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command;
135             }
136 
137             //------------------------------------------------------------------------------
138 
MakeCommand(bit32 * command,bool isUpdateFBAccess) const139             bit32* RenderState::AlphaTest::MakeCommand( bit32* command, bool isUpdateFBAccess ) const
140             {
141                 // 0x104
142                 *command++ = PICA_CMD_DATA_FRAGOP_ALPHA_TEST( isEnable, func, refValue );
143                 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_FRAGOP_ALPHA_TEST, 0x3 );
144 
145                 return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command;
146             }
147 
148             //------------------------------------------------------------------------------
149 
MakeDisableCommand(bit32 * command,bool isClearFrameBufferCache)150             bit32* RenderState::AlphaTest::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache )
151             {
152                 // 0x104
153                 *command++ = 0x0;
154                 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_FRAGOP_ALPHA_TEST, 0x1 );
155 
156                 if ( isClearFrameBufferCache )
157                 {
158                     command = FBAccess::MakeClearCacheCommand( command );
159                 }
160 
161                 return command;
162             }
163 
164             //------------------------------------------------------------------------------
165 
MakeCommand(bit32 * command,bool isUpdateFBAccess) const166             bit32* RenderState::StencilTest::MakeCommand( bit32* command, bool isUpdateFBAccess ) const
167             {
168                 // 0x105
169                 *command++ = PICA_CMD_DATA_STENCIL_TEST( isEnable, func, maskOp, ref, mask );
170                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_STENCIL_TEST );
171 
172                 // 0x106
173                 *command++ = PICA_CMD_DATA_STENCIL_OP( opFail, opZFail, opZPass );
174                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_STENCIL_OP );
175 
176                 return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command;
177             }
178 
179             //------------------------------------------------------------------------------
180 
MakeDisableCommand(bit32 * command,bool isClearFrameBufferCache)181             bit32* RenderState::StencilTest::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache )
182             {
183                 // 0x105
184                 *command++ = 0x0;
185                 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_STENCIL_TEST, 0x1 );
186 
187                 if ( isClearFrameBufferCache )
188                 {
189                     command = FBAccess::MakeClearCacheCommand( command );
190                 }
191 
192                 return command;
193             }
194 
195             //------------------------------------------------------------------------------
196 
MakeCommand(bit32 * command,bool isUpdateFBAccess) const197             bit32* RenderState::DepthTest::MakeCommand( bit32* command, bool isUpdateFBAccess ) const
198             {
199                 // 0x107の[ 0:7 ]と[12:12]がデプステストの設定で、[8:11]がカラーマスクの設定です。
200                 *command++ = PICA_CMD_DATA_DEPTH_COLOR_MASK( isEnable,
201                                                              func,
202                                                              m_RenderState.colorMask & COLOR_MASK_R,
203                                                              m_RenderState.colorMask & COLOR_MASK_G,
204                                                              m_RenderState.colorMask & COLOR_MASK_B,
205                                                              m_RenderState.colorMask & COLOR_MASK_A,
206                                                              isEnableWrite );
207                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_DEPTH_COLOR_MASK );
208 
209                 return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command;
210             }
211 
212             //------------------------------------------------------------------------------
213 
MakeDisableCommand(bit32 * command,bool isClearFrameBufferCache)214             bit32* RenderState::DepthTest::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache )
215             {
216                 const bool isEnableDepth          = false;
217                 const PicaDataDepthTest depthFunc = PICA_DATA_DEPTH_TEST_LESS;
218                 const bool colorMaskRed           = true;
219                 const bool colorMaskGreen         = true;
220                 const bool colorMaskBlue          = true;
221                 const bool colorMaskAlpha         = true;
222                 const bool isEnableDepthWrite     = false;
223 
224                 // 0x107の[ 0:7 ]と[12:12]がデプステストの設定で、[8:11]がカラーマスクの設定です。
225                 *command++ = PICA_CMD_DATA_DEPTH_COLOR_MASK( isEnableDepth,
226                                                              depthFunc,
227                                                              colorMaskRed,
228                                                              colorMaskGreen,
229                                                              colorMaskBlue,
230                                                              colorMaskAlpha,
231                                                              isEnableDepthWrite );
232                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_DEPTH_COLOR_MASK );
233 
234                 if ( isClearFrameBufferCache )
235                 {
236                     command = FBAccess::MakeClearCacheCommand( command );
237                 }
238 
239                 return command;
240             }
241 
242             //------------------------------------------------------------------------------
243 
MakeCommand(bit32 * command,bool isUpdateFBAccess) const244             bit32* RenderState::WBuffer::MakeCommand( bit32* command, bool isUpdateFBAccess ) const
245             {
246                 // w バッファが無効のとき
247                 if ( wScale == 0.f )
248                 {
249                     // 0x6d
250                     *command++ = 1;
251                     *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_WSCALE );
252 
253                     // 0x04d
254                     *command++ = Float32ToFloat24( depthRangeNear - depthRangeFar );
255                     *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_WSCALE_DATA1 );
256 
257                     // 0x04e
258                     // ポリゴンオフセットを設定する
259                     f32 zNear = isEnablePolygonOffset ?
260                         depthRangeNear - (depthRangeNear - depthRangeFar) * polygonOffsetUnit / f32( (1 << depthRangeBit) - 1) :
261                         depthRangeNear;
262                     *command++ = Float32ToFloat24( zNear );
263                     *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_WSCALE_DATA2 );
264                 }
265                 // w バッファが有効のとき
266                 else
267                 {
268                     // 0x6d
269                     *command++ = 0;
270                     *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_WSCALE );
271 
272                     // 0x04d
273                     *command++ = Float32ToFloat24( - wScale );
274                     *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_WSCALE_DATA1 );
275 
276                     // 0x04e
277                     *command++ = isEnablePolygonOffset ?
278                         ( ( depthRangeBit == 24 ) ?
279                           // 24 bit float の精度限界により誤差で消えてしまうのを避けるため、
280                           // 0.5f 付近の深度値を基準として、128.0f をかけておきます。
281                           ( polygonOffsetUnit * 128.0f / f32( (1 << depthRangeBit) - 1 ) ) :
282                           ( polygonOffsetUnit / f32( (1 << depthRangeBit) - 1 ) ) )
283                         : 0.0f;
284                     *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_WSCALE_DATA2 );
285                 }
286 
287                 return isUpdateFBAccess ? m_RenderState.fbAccess.MakeCommand( command ) : command;
288             }
289 
290             //------------------------------------------------------------------------------
291 
MakeCommand(bit32 * command,bool isClearFrameBufferCache) const292             bit32* RenderState::FBAccess::MakeCommand( bit32* command, bool isClearFrameBufferCache ) const
293             {
294                 if ( isClearFrameBufferCache )
295                 {
296                     // 0x111
297                     *command++ = 0x1;
298                     *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_COLOR_DEPTH_BUFFER_CLEAR1 );
299 
300                     // 0x110
301                     *command++ = 0x1;
302                     *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_COLOR_DEPTH_BUFFER_CLEAR0 );
303                 }
304 
305                 // 0x112
306                 *command++ = ( (m_RenderState.colorMask && m_RenderState.colorMask != 0xf)  ||
307                                (m_RenderState.colorMask && m_RenderState.blend.isEnable ) ||
308                                (m_RenderState.colorMask && m_RenderState.logicOp.isEnable ) ) ? 0xf : 0;
309                 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_COLOR_BUFFER_READ, 0x1 );
310 
311                 // 0x113
312                 *command++ = m_RenderState.colorMask ? 0xf : 0;
313                 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_COLOR_BUFFER_WRITE, 0x1 );
314 
315                 bit32 depth_stencil_read = 0;
316                 bit32 depth_stencil_write = 0;
317 
318                 if ( m_RenderState.depthTest.isEnable )
319                 {
320                     if ( m_RenderState.depthTest.isEnableWrite )   { depth_stencil_read  |= 2;  depth_stencil_write |= 2;  }
321                     else if ( m_RenderState.colorMask )            { depth_stencil_read  |= 2; }
322                 }
323 
324                 if ( m_RenderState.stencilTest.isEnable )
325                 {
326                     if (  m_RenderState.stencilTest.maskOp != 0 ) { depth_stencil_read  |= 1;  depth_stencil_write |= 1;  }
327                     else if ( m_RenderState.colorMask )   { depth_stencil_read  |= 1; }
328                 }
329 
330                 // 0x114
331                 *command++ = depth_stencil_read;
332                 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DEPTH_STENCIL_BUFFER_READ,  0x1 );
333 
334                 // 0x115
335                 *command++ = depth_stencil_write;
336                 *command++ = PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DEPTH_STENCIL_BUFFER_WRITE, 0x1 );
337 
338                 return command;
339             }
340 
341             //------------------------------------------------------------------------------
342 
MakeDisableCommand(bit32 * command,bool isClearFrameBufferCache)343             bit32* RenderState::FBAccess::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache )
344             {
345                 if ( isClearFrameBufferCache )
346                 {
347                     command = MakeClearCacheCommand( command );
348                 }
349 
350                 // 0x112 : Color read
351                 *command++ = 0xf;
352                 *command++ = PICA_CMD_HEADER_BURSTSEQ_BE( PICA_REG_COLOR_BUFFER_READ, 0x4, 0x1 );
353 
354                 // 0x113 : Color write
355                 *command++ = 0xf;
356                 // 0x114 : Depth/Stencil read
357                 *command++ = 0x0;
358 
359                 // 0x115 : Depth/Stencil write
360                 *command++ = 0x0;
361                 // padding
362                 *command++ = 0x0;
363 
364                 return command;
365             }
366 
367             //------------------------------------------------------------------------------
368 
MakeClearCacheCommand(bit32 * command)369             bit32* RenderState::FBAccess::MakeClearCacheCommand( bit32* command )
370             {
371                 // 0x111
372                 *command++ = 0x1;
373                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_COLOR_DEPTH_BUFFER_CLEAR1 );
374 
375                 // 0x110
376                 *command++ = 0x1;
377                 *command++ = PICA_CMD_HEADER_SINGLE( PICA_REG_COLOR_DEPTH_BUFFER_CLEAR0 );
378 
379                 return command;
380             }
381 
382             //------------------------------------------------------------------------------
383 
MakeCommand(bit32 * buffer,bool isClearFrameBufferCache) const384             bit32* RenderState::RenderState::MakeCommand( bit32* buffer, bool isClearFrameBufferCache ) const
385             {
386                 bit32* command = buffer;
387 
388                 command = cullingTest.MakeCommand( command, false );
389                 command = blend.MakeCommand( command, false );
390                 command = logicOp.MakeCommand( command, false );
391                 command = alphaTest.MakeCommand( command, false );
392                 command = stencilTest.MakeCommand( command, false );
393                 command = depthTest.MakeCommand( command, false );
394                 command = wBuffer.MakeCommand( command, false );
395                 command = fbAccess.MakeCommand( command, isClearFrameBufferCache );
396 
397                 return command;
398             }
399 
400             //------------------------------------------------------------------------------
401 
Culling(const RenderState & renderState_)402             RenderState::Culling::Culling( const RenderState& renderState_ )
403                 : isEnable( true ),
404                   frontFace( FRONT_FACE_CCW ),
405                   cullFace(  CULL_FACE_BACK ),
406                   m_RenderState( renderState_ )
407             {
408             }
409 
410             //------------------------------------------------------------------------------
411 
Blend(const RenderState & renderState_)412             RenderState::Blend::Blend( const RenderState& renderState_ )
413                 : isEnable( false ),
414                   eqRgb   ( PICA_DATA_BLEND_EQUATION_ADD ),
415                   eqAlpha ( PICA_DATA_BLEND_EQUATION_ADD ),
416                   srcRgb  ( PICA_DATA_BLEND_FUNC_SRC_ALPHA ),
417                   srcAlpha( PICA_DATA_BLEND_FUNC_SRC_ALPHA ),
418                   dstRgb  ( PICA_DATA_BLEND_FUNC_ONE_MINUS_SRC_ALPHA ),
419                   dstAlpha( PICA_DATA_BLEND_FUNC_ONE_MINUS_SRC_ALPHA ),
420                   colorR( 0xff),
421                   colorG( 0xff),
422                   colorB( 0xff),
423                   colorA( 0xff),
424                   m_RenderState( renderState_ )
425             {
426             }
427 
428             //------------------------------------------------------------------------------
429 
LogicOp(const RenderState & renderState_)430             RenderState::LogicOp::LogicOp( const RenderState& renderState_ )
431                 : isEnable( false ),
432                   opCode( PICA_DATA_LOGIC_NOOP ),
433                   m_RenderState( renderState_ )
434             {
435             }
436 
437             //------------------------------------------------------------------------------
438 
AlphaTest(const RenderState & renderState_)439             RenderState::AlphaTest::AlphaTest( const RenderState& renderState_ )
440                 : isEnable( false ),
441                   refValue( 0 ),
442                   func ( PICA_DATA_ALPHA_TEST_NEVER ),
443                   m_RenderState( renderState_ )
444             {
445             }
446 
447             //------------------------------------------------------------------------------
448 
StencilTest(const RenderState & renderState_)449             RenderState::StencilTest::StencilTest( const RenderState& renderState_ )
450                 : isEnable     ( false ),
451                   maskOp       ( 0 ),
452                   func         ( PICA_DATA_STENCIL_TEST_ALWAYS ),
453                   ref          ( 0 ),
454                   mask         ( 0xff ),
455                   opFail       ( PICA_DATA_STENCIL_OP_KEEP ),
456                   opZFail      ( PICA_DATA_STENCIL_OP_KEEP ),
457                   opZPass      ( PICA_DATA_STENCIL_OP_KEEP ),
458                   m_RenderState  ( renderState_ )
459             {
460             }
461 
462             //------------------------------------------------------------------------------
463 
DepthTest(const RenderState & renderState_)464             RenderState::DepthTest::DepthTest( const RenderState& renderState_ )
465                 : isEnable( true ),
466                   isEnableWrite( true ),
467                   func( PICA_DATA_DEPTH_TEST_LESS ),
468                   m_RenderState( renderState_ )
469             {
470             }
471 
472             //------------------------------------------------------------------------------
473 
WBuffer(const RenderState & renderState_)474             RenderState::WBuffer::WBuffer( const RenderState& renderState_ )
475                 : wScale( 0.f ),
476                   isEnablePolygonOffset( false ),
477                   polygonOffsetUnit    ( 0.f ),
478                   depthRangeNear       ( 0.0f ),
479                   depthRangeFar        ( 1.0f ),
480                   depthRangeBit        ( 24 ),
481                   m_RenderState        ( renderState_ )
482             {
483             }
484 
485 
486             //------------------------------------------------------------------------------
487 
FBAccess(const RenderState & renderState_)488             RenderState::FBAccess::FBAccess( const RenderState& renderState_ )
489                 : m_RenderState( renderState_ )
490             {
491             }
492 
493             //------------------------------------------------------------------------------
494 
RenderState()495             RenderState::RenderState() :
496                   blend       ( *this ),
497                   logicOp     ( *this ),
498                   alphaTest   ( *this ),
499                   stencilTest ( *this ),
500                   colorMask   ( COLOR_MASK_RGBA ),
501                   depthTest   ( *this ),
502                   cullingTest ( *this ),
503                   wBuffer     ( *this ),
504                   fbAccess    ( *this )
505             {
506             }
507 
508             //------------------------------------------------------------------------------
509 
MakeDisableCommand(bit32 * command,bool isClearFrameBufferCache)510             bit32* RenderState::MakeDisableCommand( bit32* command, bool isClearFrameBufferCache )
511             {
512                 command = Culling::MakeDisableCommand( command, false );
513                 command = Blend::MakeDisableCommand( command, false );
514                 command = AlphaTest::MakeDisableCommand( command, false );
515                 command = StencilTest::MakeDisableCommand( command, false );
516                 command = DepthTest::MakeDisableCommand( command, false );
517                 command = FBAccess::MakeDisableCommand( command, isClearFrameBufferCache );
518 
519                 return command;
520             }
521 
522         } // namespace CTR
523     } // namespace gr
524 } // namespace nn
525