1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_GraphicsDevice.h
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc.  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   $Revision: 23207 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NW_GFX_GRAPHICSDEVICE_H_
17 #define NW_GFX_GRAPHICSDEVICE_H_
18 
19 #include <GLES2/gl2.h>
20 #include <GLES2/gl2ext.h>
21 
22 #include <nw/types.h>
23 #include <nw/ut/ut_Color.h>
24 #include <nw/ut/ut_Rect.h>
25 #include <nw/gfx/gfx_Viewport.h>
26 
27 // このマクロを定義するとマテリアルの個々の要素の設定に関するプロファイルを行います。
28 // #define NW_MATERIAL_PROFILE
29 
30 namespace nw
31 {
32 namespace os
33 {
34 class IAllocator;
35 }
36 
37 namespace gfx
38 {
39 
40 //---------------------------------------------------------------------------
41 //! @brief        描画内容を GPU に設定するクラスです。
42 //---------------------------------------------------------------------------
43 class GraphicsDevice
44 {
45 public:
46     //----------------------------------------
47     //! @name ラスタライゼーション関連
48     //@{
49 
50     //---------------------------------------------------------------------------
51     //! @brief        ポリゴンオフセットが有効化どうかのフラグを設定します。
52     //!
53     //! @param[in]    enabled ポリゴンオフセットのが有効化どうかのフラグです。
54     //---------------------------------------------------------------------------
SetPolygonOffsetEnabled(bool enabled)55     static NW_INLINE void SetPolygonOffsetEnabled(bool enabled)
56     {
57         s_PolygonOffsetEnabled = enabled;
58     }
59 
60     //---------------------------------------------------------------------------
61     //! @brief        ポリゴンオフセットのユニット要素を設定します。
62     //!
63     //! @param[in]    polygonOffsetUnit ポリゴンオフセットのユニット要素です。
64     //---------------------------------------------------------------------------
SetPolygonOffsetUnit(f32 polygonOffsetUnit)65     static NW_INLINE void SetPolygonOffsetUnit(f32 polygonOffsetUnit)
66     {
67         s_PolygonOffsetUnit = polygonOffsetUnit;
68     }
69 
70     //---------------------------------------------------------------------------
71     //! @brief        ポリゴンオフセットのコマンドを発行します。
72     //---------------------------------------------------------------------------
73     static NW_INLINE void ActivatePolygonOffset();
74 
75     //@}
76 
77     //----------------------------------------
78     //! @name フレームバッファ関連
79     //@{
80     //@}
81 
82     //----------------------------------------
83     //! @name ブレンダ関連
84     //@{
85 
86     //! @brief ブレンド計算を有効または無効にします。
87     //!
88     //! @param[in]  enabled  ブレンド計算の有効フラグです。
89     //!
90     static NW_INLINE void SetBlendEnabled(bool enabled);
91 
92     //@}
93 
94     //----------------------------------------
95     //! @name フラグメントオペレーション関連
96     //@{
97 
98     //! @brief フラグメントオペレーションモードを設定します。
SetFragmentOperationMode(const ResFragmentOperation::FragmentOperationMode mode)99     static NW_INLINE void SetFragmentOperationMode(const ResFragmentOperation::FragmentOperationMode mode)
100     {
101         if (s_FragOperationMode != mode)
102         {
103             s_FragOperationMode = mode;
104             s_IsFrameBufferUpdated = true;
105         }
106     }
107 
108     //! @brief フラグメントオペレーションモードを設定します。
ActivateFragmentOperationMode(ResFragmentOperation::FragmentOperationMode mode)109     static NW_INLINE void ActivateFragmentOperationMode(ResFragmentOperation::FragmentOperationMode mode)
110     {
111         s_FragOperationMode = mode;
112 
113         enum
114         {
115             REG_FRAGMENT_OPERATION = 0x100
116         };
117 
118         const u32 HEADER   = internal::MakeCommandHeader(REG_FRAGMENT_OPERATION, 1, false, 0x1);
119 
120         const u32 COMMAND[] =
121         {
122             mode,
123             HEADER
124         };
125 
126         s_IsFrameBufferUpdated = true;
127         ActivateFrameBuffer();
128     }
129 
130     //! @brief 深度バッファリングを有効または無効にします。
131     //!
132     //! @param[in]  enabled  深度バッファリングの有効フラグです。
133     //!
134     static NW_INLINE void SetDepthTestEnabled(bool enabled);
135 
136     //! @brief ステンシルテストを有効または無効にします。
137     //!
138     //! @param[in]  enabled  ステンシルテストの有効フラグです。
139     //!
140     static NW_INLINE void SetStencilTestEnabled(bool enabled);
141 
142 
143     //! @brief 深度範囲を設定します。
SetDepthRange(f32 near,f32 far)144     static void SetDepthRange(f32 near, f32 far)
145     {
146         s_DepthRangeNear = nw::ut::Clamp(near, 0.0f, 1.0f);
147         s_DepthRangeFar  = nw::ut::Clamp(far, 0.0f, 1.0f);
148         s_DepthRange24   = ut::Float24::Float32ToBits24(s_DepthRangeNear - s_DepthRangeFar);
149     }
150 
151     //! @brief   WScaleの設定をおこないます。
152     //!
153     //! @param[in]    wscale  wscaleの値です。
SetWScale(f32 wscale)154     static void SetWScale(f32 wscale)
155     {
156         if (wscale == 0.0f)
157         {
158             s_WScale24 = 0;
159         }
160         else
161         {
162             s_WScale24 = ut::Float24::Float32ToBits24(-wscale);
163         }
164     }
165 
166     //! @brief        深度フォーマットを設定します。
167     //!
168     //! @details      ここで設定された値はポリゴンオフセットの設定に使用されます。
169     //!               深度フォーマット設定が実際に設定されるわけではありません。
170     //!
171     //! @param[in]    format  深度フォーマットです。
SetDepthFormat(u32 format)172     static void SetDepthFormat(u32 format)
173     {
174         s_DepthFormat = format;
175     }
176 
177     //@}
178 
179     //----------------------------------------
180     //! @name マスク関連
181     //@{
182 
183     //! @brief カラーマスクを設定します。
184     //!
185     //! @param[in] red 赤色のマスクの有効フラグです。
186     //! @param[in] green 緑色のマスクの有効フラグです。
187     //! @param[in] blue 青色のマスクの有効フラグです。
188     //! @param[in] alpha アルファチャンネルのマスクの有効フラグです。
189     //!
190     static NW_INLINE void SetColorMask(bool red, bool green, bool blue, bool alpha);
191 
192     //! @brief 深度マスクを設定します。
193     //!
194     //! @param[in] enabled マスクの有効フラグです。
195     //!
196     static NW_INLINE void SetDepthMaskEnabled(bool enabled);
197 
198     //! @brief ステンシルマスクを設定します。
199     //!
200     //! @param[in] mask マスクの有効フラグです。
201     //!
202     static NW_INLINE void SetStencilMask(u8 mask);
203 
204     //! フレームバッファを有効にするコマンドを発行します。
205     static NW_INLINE void  ActivateFrameBuffer();
206 
207     //! マスクを有効にするコマンドを発行します。
208     static NW_INLINE void ActivateMask();
209 
210     //@}
211 
212     //----------------------------------------
213     //! @name 参照テーブル関連
214     //@{
215 
216     // TODO: Shadow と Gas には未対応ですので、グラフィックスランタイムで実装を行うときに対応します。
217     //! @brief LookupTable を設定するターゲットの定義です。
218     enum LutTarget
219     {
220         LUT_TARGET_D0, //!< D0の参照テーブルを表します。
221         LUT_TARGET_D1, //!< D1の参照テーブルを表します。
222         LUT_TARGET_SP, //!< SPの参照テーブルを表します。
223         LUT_TARGET_FR, //!< FRの参照テーブルを表します。
224         LUT_TARGET_RB, //!< RBの参照テーブルを表します。
225         LUT_TARGET_RG, //!< RGの参照テーブルを表します。
226         LUT_TARGET_RR, //!< RRの参照テーブルを表します。
227         LUT_TARGET_SP0, //!< 0番目の角度減衰テーブルを表します。
228         LUT_TARGET_SP1, //!< 1番目の角度減衰テーブルを表します。
229         LUT_TARGET_SP2, //!< 2番目の角度減衰テーブルを表します。
230         LUT_TARGET_SP3, //!< 3番目の角度減衰テーブルを表します。
231         LUT_TARGET_SP4, //!< 4番目の角度減衰テーブルを表します。
232         LUT_TARGET_SP5, //!< 5番目の角度減衰テーブルを表します。
233         LUT_TARGET_SP6, //!< 6番目の角度減衰テーブルを表します。
234         LUT_TARGET_SP7, //!< 7番目の角度減衰テーブルを表します。
235         LUT_TARGET_DA0, //!< 0番目の距離減衰テーブルを表します。
236         LUT_TARGET_DA1, //!< 1番目の距離減衰テーブルを表します。
237         LUT_TARGET_DA2, //!< 2番目の距離減衰テーブルを表します。
238         LUT_TARGET_DA3, //!< 3番目の距離減衰テーブルを表します。
239         LUT_TARGET_DA4, //!< 4番目の距離減衰テーブルを表します。
240         LUT_TARGET_DA5, //!< 5番目の距離減衰テーブルを表します。
241         LUT_TARGET_DA6, //!< 6番目の距離減衰テーブルを表します。
242         LUT_TARGET_DA7, //!< 7番目の距離減衰テーブルを表します。
243         LUT_TARGET_FOG, //!< FOGの参照テーブルを表します。
244         LUT_TARGET_COUNT //!< 定義数を表します。
245     };
246 
247     //--------------------------------------------------------------------------
248     //! @brief        LUTの入力が絶対値かどうかを指定します。
249     //!
250     //! @param[in]    target  LUTのターゲットを指定します。
251     //! @param[in]    isAbs   LUTの入力が絶対値かどうかを指定します。
252     //---------------------------------------------------------------------------
SetLutIsAbs(LutTarget target,bool isAbs)253     static void SetLutIsAbs(LutTarget target, bool isAbs)
254     {
255         NW_ASSERT(target < LUT_TARGET_COUNT);
256 
257         if (LUT_TARGET_SP0 <= target && target <= LUT_TARGET_SP7)
258         {
259             target = LUT_TARGET_SP;
260         }
261 
262         if (isAbs)
263         {
264             s_LutIsAbs &= ~(0x1 << (1 + 4 * target));
265         }
266         else
267         {
268             s_LutIsAbs |= 0x1 << (1 + 4 * target) ;
269         }
270     }
271 
272     //--------------------------------------------------------------------------
273     //! @brief        LUTの入力値を指定します。
274     //!
275     //! @param[in]    target  LUTのターゲットを指定します。
276     //! @param[in]    input   LUTの入力値を指定します。
277     //---------------------------------------------------------------------------
SetLutInput(LutTarget target,ResLightingLookupTable::Input input)278     static void SetLutInput( LutTarget target, ResLightingLookupTable::Input input )
279     {
280         NW_ASSERT(target  < LUT_TARGET_COUNT);
281         NW_ASSERT(input < ResLightingLookupTable::INPUT_NUM);
282 
283         if (LUT_TARGET_SP0 <= target && target <= LUT_TARGET_SP7)
284         {
285             target = LUT_TARGET_SP;
286         }
287 
288         s_LutInput &= ~(0x7 << (4 * target));
289         s_LutInput |= input << (4 * target);
290     }
291 
292     //--------------------------------------------------------------------------
293     //! @brief        LUTのスケール値を指定します。
294     //!
295     //! @param[in]    target  LUTのターゲットを指定します。
296     //! @param[in]    scale   LUTのスケール値を指定します。
297     //---------------------------------------------------------------------------
SetLutScale(LutTarget target,ResLightingLookupTable::Scale scale)298     static void SetLutScale( LutTarget target, ResLightingLookupTable::Scale scale )
299     {
300         NW_ASSERT(target < LUT_TARGET_COUNT);
301         NW_ASSERT(scale <= ResLightingLookupTable::SCALE_MAX);
302 
303         if (LUT_TARGET_SP0 <= target && target <= LUT_TARGET_SP7)
304         {
305             target = LUT_TARGET_SP;
306         }
307 
308         s_LutScale &= ~(0x7 << (4 * target));
309         s_LutScale |= scale << (4 * target);
310     }
311 
312     //--------------------------------------------------------------------------
313     //! @brief        LUTのパラメータをコマンド出力します。
314     //---------------------------------------------------------------------------
ActivateLutParameters()315     static void ActivateLutParameters()
316     {
317         enum { REG_LUT_ABS = 0x1d0 };
318 
319         const u32 HEADER = internal::MakeCommandHeader( REG_LUT_ABS, 3, true, 0xf );
320 
321         const u32 COMMAND[] =
322         {
323             s_LutIsAbs,
324             HEADER,
325             s_LutInput,
326             s_LutScale
327         };
328 
329         internal::NWUseCmdlist<sizeof(COMMAND)>( &COMMAND[0] );
330     }
331 
332     //--------------------------------------------------------------------------
333     //! @brief        LUTのパラメータの状態をリセットします。
334     //---------------------------------------------------------------------------
ResetLutParameters()335     static void ResetLutParameters()
336     {
337         s_LutIsAbs = 0;
338         s_LutInput = 0;
339         s_LutScale = 0;
340     }
341 
342     //---------------------------------------------------------------------------
343     //! @brief        参照テーブルを参照テーブルキャッシュに設定します。
344     //!
345     //! @param[in]    lookupTable 設定する参照テーブルです。
346     //! @param[in]    target 設定するターゲットです。
347     //---------------------------------------------------------------------------
348     static void ActivateLookupTable(ResImageLookupTable lookupTable, LutTarget target);
349 
350     //---------------------------------------------------------------------------
351     //! @brief        参照テーブルキャッシュに設定された参照テーブルを削除します。
352     //!
353     //! @param[in]    lookupTable 削除する参照テーブルです。
354     //---------------------------------------------------------------------------
355     static void InvalidateLookupTable(ResImageLookupTable lookupTable);
356 
357     //---------------------------------------------------------------------------
358     //! @brief        全ての参照テーブルを無効化します。
359     //---------------------------------------------------------------------------
360     static void InvalidateAllLookupTables();
361 
362     //@}
363 
364 
365     //----------------------------------------
366     //! @name ライト関連
367     //@{
368 
369     //--------------------------------------------------------------------------
370     //! @brief        ライトのイネーブルフラグをリセットします。
371     //---------------------------------------------------------------------------
ResetFragmentLightEnabled()372     static void ResetFragmentLightEnabled()
373     {
374         s_LightPositionW = 0x0;
375         s_LightShadowed = 0xFF;
376         s_LightSpotEnabled = 0xFF;
377         s_LightDistanceAttnEnabled = 0xFF;
378     }
379 
380     //--------------------------------------------------------------------------
381     //! @brief        ポジションWの値を取得します。
382     //!
383     //! @param[in]    index     ライトのインデックスです。
384     //--------------------------------------------------------------------------
GetFragmentLightPositionW(int index)385     static NW_INLINE bool GetFragmentLightPositionW(int index)
386     {
387         return ((s_LightPositionW >> index) & 0x1);
388     }
389 
390     //--------------------------------------------------------------------------
391     //! @brief        ポジションWの値を設定します。
392     //!
393     //! @param[in]    index     ライトのインデックスです。
394     //! @param[in]    isWZero   W成分が0かどうかを表します。
395     //--------------------------------------------------------------------------
SetFragmentLightPositionW(int index,bool isWZero)396     static NW_INLINE void SetFragmentLightPositionW(int index, bool isWZero)
397     {
398         // 1: isWZero, 0: !isWZero
399         if (isWZero)
400         {
401             s_LightPositionW |= (0x1 << index);
402         }
403         else
404         {
405             s_LightPositionW &= ~(0x1 << index);
406         }
407     }
408 
409     //--------------------------------------------------------------------------
410     //! @brief        シャドウ減衰を有効にします。
411     //!
412     //! @param[in]    index     ライトのインデックスです。
413     //! @param[in]    shadowed  シャドウ減衰のイネーブルフラグです。
414     //--------------------------------------------------------------------------
SetFragmentLightShadowed(int index,bool shadowed)415     static void SetFragmentLightShadowed(int index, bool shadowed)
416     {
417         // 0: GL_TRUE, 1: GL_FALSE
418         if (shadowed)
419         {
420             s_LightShadowed &= ~(0x1 << index);
421         }
422         else
423         {
424             s_LightShadowed |= 0x1 << index;
425         }
426     }
427 
428     //--------------------------------------------------------------------------
429     //! @brief        スポットライトの有効設定をおこないます。
430     //!
431     //! @param[in]    index   ライトのインデックスです。
432     //! @param[in]    enabled 距離減衰のイネーブルフラグです。
433     //--------------------------------------------------------------------------
SetFragmentLightSpotEnabled(int index,bool enabled)434     static void SetFragmentLightSpotEnabled(int index, bool enabled)
435     {
436         // 0: GL_TRUE, 1: GL_FALSE
437         if (enabled)
438         {
439             s_LightSpotEnabled &= ~(0x1 << index);
440         }
441         else
442         {
443             s_LightSpotEnabled |= 0x1 << index;
444         }
445     }
446 
447     //--------------------------------------------------------------------------
448     //! @brief        距離減衰の有効設定をおこないます。
449     //!
450     //! @param[in]    index     ライトのインデックスです。
451     //! @param[in]    enabled   距離減衰のイネーブルフラグです。
452     //--------------------------------------------------------------------------
SetFragmentLightDistanceAttnEnabled(int index,bool enabled)453     static void SetFragmentLightDistanceAttnEnabled(int index, bool enabled)
454     {
455         // 0: GL_TRUE, 1: GL_FALSE
456         if (enabled)
457         {
458             s_LightDistanceAttnEnabled &= ~(0x1 << index);
459         }
460         else
461         {
462             s_LightDistanceAttnEnabled |= 0x1 << index;
463         }
464     }
465 
466     //--------------------------------------------------------------------------
467     //! @brief        距離減衰テーブルを設定します。
468     //!
469     //! @param[in]    index       ライトのインデックスです。
470     //! @param[in]    lookupTable 距離減衰のLUTを指定します。
471     //--------------------------------------------------------------------------
ActivateFragmentLightDistanceAttnTable(int index,const ResImageLookupTable lookupTable)472     static NW_INLINE void ActivateFragmentLightDistanceAttnTable(int index, const ResImageLookupTable lookupTable)
473     {
474         GraphicsDevice::LutTarget tableTarget = static_cast<GraphicsDevice::LutTarget>(GraphicsDevice::LUT_TARGET_DA0 + index);
475 
476         GraphicsDevice::ActivateLookupTable(lookupTable, tableTarget);
477     }
478 
479     //--------------------------------------------------------------------------
480     //! @brief        スポットテーブルを設定します。
481     //!
482     //! @param[in]    index       ライトのインデックスです。
483     //! @param[in]    lookupTable スポットライトのLUTを指定します。
484     //--------------------------------------------------------------------------
ActivateFragmentLightSpotTable(int index,const ResImageLookupTable lookupTable)485     static NW_INLINE void ActivateFragmentLightSpotTable(int index, const ResImageLookupTable lookupTable)
486     {
487         GraphicsDevice::LutTarget tableTarget = static_cast<GraphicsDevice::LutTarget>(GraphicsDevice::LUT_TARGET_SP0 + index);
488 
489         GraphicsDevice::ActivateLookupTable(lookupTable, tableTarget);
490     }
491 
492     //--------------------------------------------------------------------------
493     //! @brief        距離減衰のスケールとバイアスのコマンドを発行します。
494     //!
495     //! @param[in]    index      ライトインデックスです。
496     //! @param[in]    scalef20   距離減衰のスケール値です。
497     //! @param[in]    biasf20    距離減衰のバイアス値です。
498     //---------------------------------------------------------------------------
ActivateFragmentLightDistanceAttnScaleBias(int index,u32 scalef20,u32 biasf20)499     static void ActivateFragmentLightDistanceAttnScaleBias(int index, u32 scalef20, u32 biasf20)
500     {
501         enum
502         {
503             REG_DISTANCE_ATTN_BIAS  = 0x14a,
504             REG_DISTANCE_ATTN_SCALE = 0x14b
505         };
506 
507         const u32 HEADER = internal::MakeCommandHeader(REG_DISTANCE_ATTN_BIAS, 2, true, 0x7);
508 
509         u32 COMMAND[] =
510         {
511             biasf20,
512             HEADER + 0x10 * index,
513             scalef20,
514             0
515         };
516 
517         internal::NWUseCmdlist<sizeof(COMMAND)>( &COMMAND[0] );
518     }
519 
520     //--------------------------------------------------------------------------
521     //! @brief        フラグメントライト用のコマンドを発行します。
522     //!
523     //! @param[in]    index   設定するライトのインデックスです。
524     //! @param[in]    pos     ライトのポジションです。
525     //---------------------------------------------------------------------------
526     static NW_INLINE void
ActivateFragmentLightPosition(s32 index,const math::VEC4 & pos)527     ActivateFragmentLightPosition(s32 index, const math::VEC4& pos)
528     {
529         enum
530         {
531             REG_FRAGMENT_LIGHT_POS_BASE = 0x144
532         };
533 
534         const u32 POS_HEADER   = internal::MakeCommandHeader(REG_FRAGMENT_LIGHT_POS_BASE, 2, true, 0xF);
535 
536         u32 LIGHT_COMMAND[4] =
537         {
538             ut::Float16(pos.y).GetFloat16Value() << 16 | ut::Float16(pos.x).GetFloat16Value(), // pos_y << 16 | pos_x
539             POS_HEADER + 0x10 * index,
540             ut::Float16(pos.z).GetFloat16Value(), // pos_z
541             0
542         };
543 
544         internal::NWUseCmdlist<sizeof(LIGHT_COMMAND)>( &LIGHT_COMMAND[0] );
545     }
546 
547     //--------------------------------------------------------------------------
548     //! @brief        フラグメントライトの位置情報を発行します。
549     //!
550     //! @param[in]    index   ライトのインデックスです。
551     //! @param[in]    pos     ライトの位置です。
552     //! @param[in]    spotDir ライトのスポット方向です。
553     //---------------------------------------------------------------------------
554     static NW_INLINE void
ActivateFragmentLightPosition(s32 index,const math::VEC4 & pos,const math::VEC3 & spotDir)555     ActivateFragmentLightPosition(s32 index, const math::VEC4& pos, const math::VEC3& spotDir)
556     {
557         enum
558         {
559             REG_FRAGMENT_LIGHT_POS_BASE = 0x144
560         };
561 
562         const u32 POS_HEADER   = internal::MakeCommandHeader(REG_FRAGMENT_LIGHT_POS_BASE, 4, true, 0xF);
563 
564         u32 LIGHT_COMMAND[6] =
565         {
566             ut::Float16(pos.y).GetFloat16Value() << 16 | ut::Float16(pos.x).GetFloat16Value(), // pos_y << 16 | pos_x
567             POS_HEADER + 0x10 * index,
568             ut::Float16(pos.z).GetFloat16Value(), // pos_z
569             ut::Fixed13(-spotDir.y).GetFixed13Value() << 16 | ut::Fixed13(-spotDir.x).GetFixed13Value(), // dir_y << 16 | dir_x
570             ut::Fixed13(-spotDir.z).GetFixed13Value(), // dir_z
571             0
572         };
573 
574         internal::NWUseCmdlist<sizeof(LIGHT_COMMAND)>( &LIGHT_COMMAND[0] );
575     }
576 
577     //--------------------------------------------------------------------------
578     //! @brief        フラグメントライトの有効設定のコマンドを発行します。
579     //---------------------------------------------------------------------------
ActivateFragmentLightEnabled()580     static void ActivateFragmentLightEnabled()
581     {
582         enum { REG_FRAGMENT_LIGHT_KIND = 0x1c4 };
583 
584         // 0x1c4 の [22:16] はFR,D0,D1,ReflのlutEnableフラグなので、BEを外しておく。
585         const u32 HEADER = internal::MakeCommandHeader(REG_FRAGMENT_LIGHT_KIND, 1, false, 0xb);
586 
587         const u32 COMMAND[] =
588         {
589             s_LightShadowed | (s_LightSpotEnabled << 8) | (s_LightDistanceAttnEnabled << 24),
590             HEADER
591         };
592 
593         internal::NWUseCmdlist<sizeof(COMMAND)>(&COMMAND[0]);
594     }
595 
596     //@}
597 
598 
599     //--------------------------------------------------------------------------
600     //! @brief レンダリングターゲットサーフェスのウィンドウのサイズを設定します。
601     //!
602     //! @param[in]    viewport      設定するビューポートです。
603     //--------------------------------------------------------------------------
ActivateViewport(const Viewport & viewport)604     static void ActivateViewport(const Viewport& viewport)
605     {
606         s_Viewport = viewport;
607 
608         enum
609         {
610             REG_VIEWPORT_WIDTH_HALF    = 0x41,
611             REG_VIEWPORT_WIDTH_HALF_S  = 0x42,
612             REG_VIEWPORT_HEIGHT_HALF   = 0x43,
613             REG_VIEWPORT_HEIGHT_HALF_S = 0x44,
614             REG_VIEWPORT_XY            = 0x68
615         };
616 
617         u16 x16 = static_cast<u16>(s_Viewport.GetBound().GetX());
618         u16 y16 = static_cast<u16>(s_Viewport.GetBound().GetY());
619 
620         const u32 HEADER_VIEWPORT_WIDTH_HALF = nw::gfx::internal::MakeCommandHeader( REG_VIEWPORT_WIDTH_HALF, 4, true, 0xF );
621         const u32 HEADER_VIEWPORT_XY         = nw::gfx::internal::MakeCommandHeader( REG_VIEWPORT_XY, 1, false, 0xF );
622 
623         u32 VIEWPORT_COMMAND[] =
624         {
625             nw::ut::Float24::Float32ToBits24( s_Viewport.GetBound().GetWidth() / 2.f ),
626             HEADER_VIEWPORT_WIDTH_HALF,
627             (ut::Float31::Float32ToBits31( 2.f / s_Viewport.GetBound().GetWidth() ) << 1),
628             nw::ut::Float24::Float32ToBits24( s_Viewport.GetBound().GetHeight()/2.f ),
629             (ut::Float31::Float32ToBits31( 2.f / s_Viewport.GetBound().GetHeight() ) << 1),
630             0,
631             (x16 | (y16 << 16)),
632             HEADER_VIEWPORT_XY
633         };
634 
635         nw::gfx::internal::NWUseCmdlist<sizeof(VIEWPORT_COMMAND)>( &VIEWPORT_COMMAND[0] );
636     }
637 
638     //--------------------------------------------------------------------------
639     //! @brief        レンダリングバッファサイズを指定します。
640     //!
641     //! @param[in]    width  レンダリングバッファの幅サイズです。
642     //! @param[in]    height レンダリングバッファの縦サイズです。
643     //--------------------------------------------------------------------------
SetRenderBufferSize(s32 width,s32 height)644     static void SetRenderBufferSize(s32 width, s32 height)
645     {
646         s_RenderBufferWidth = width;
647         s_RenderBufferHeight = height;
648     }
649 
650     //--------------------------------------------------------------------------
651     //! @brief シザリングの矩形情報を発行します。
652     //!
653     //! @param[in]    enabled  シザリングが有効化どうかのフラグです。
654     //! @param[in]    scissor  設定するシザリング矩形です。
655     //--------------------------------------------------------------------------
ActivateScissor(bool enabled,const ut::Rect & scissor)656     static void ActivateScissor(bool enabled, const ut::Rect& scissor)
657     {
658         enum
659         {
660             REG_SCISSOR_ENABLE = 0x65,
661             REG_SCISSOR_XY     = 0x66,
662             REG_SCISSOR_WH     = 0x67,
663 
664             REG_SCISSOR_DISABLED = 0,
665             REG_SCISSOR_ENABLED = 3
666         };
667 
668         NW_MINMAX_ASSERT(scissor.GetX(), 0, static_cast<s32>(s_RenderBufferWidth));
669         NW_MINMAX_ASSERT(scissor.GetY(), 0, static_cast<s32>(s_RenderBufferHeight));
670         NW_MINMAX_ASSERT(scissor.GetX() + scissor.GetWidth(), 0, static_cast<s32>(s_RenderBufferWidth));
671         NW_MINMAX_ASSERT(scissor.GetY() + scissor.GetHeight(), 0, static_cast<s32>(s_RenderBufferHeight));
672 
673         s_Scissor = scissor;
674         s_ScissorEnabled = enabled;
675 
676         u16 x16 = static_cast<u16>(s_Scissor.GetX());
677         u16 w16 = static_cast<u16>(s_Scissor.GetWidth());
678         u16 y16 = static_cast<u16>(s_Scissor.GetY());
679         u16 h16 = static_cast<u16>(s_Scissor.GetHeight());
680 
681         const u32 HEADER_SCISSOR = nw::gfx::internal::MakeCommandHeader( REG_SCISSOR_ENABLE, 3, true, 0xF );
682 
683         u32 SCISSOR_COMMAND[] =
684         {
685             s_ScissorEnabled ? REG_SCISSOR_ENABLED : REG_SCISSOR_DISABLED,
686             HEADER_SCISSOR,
687             s_ScissorEnabled ? (x16 | (y16 << 16)) : 0,
688             s_ScissorEnabled ? ((x16 + w16 - 1) | ((y16 + h16 - 1) << 16)) : ((s_RenderBufferWidth - 1) | ((s_RenderBufferHeight - 1) << 16)),
689         };
690 
691         nw::gfx::internal::NWUseCmdlist<sizeof(SCISSOR_COMMAND)>( &SCISSOR_COMMAND[0] );
692     }
693 
694 
695     //---------------------------------------------------------------------------
696     //! @brief        GraphicsDevice の状態を表示します。
697     //---------------------------------------------------------------------------
698     static void Report();
699 
700 private:
701     //--------------------------------------------------------------------------
702     //! @brief        LUT 転送の準備コマンドを送信します。
703     //!
704     //! @param[in]    target    LUTのタイプです。
705     //---------------------------------------------------------------------------
706     static NW_INLINE void ActivateLutLoadSetting(LutTarget target);
707 
708     //! @brief フレームバッファコマンドを更新します。
709     static NW_INLINE void UpdateFrameBufferCommand();
710 
711     static ResFragmentOperation::FragmentOperationMode   s_FragOperationMode;
712     static bool  s_IsFrameBufferUpdated;
713     static bool  s_BlendEnabled;
714     static bool  s_DepthTestEnabled;
715     static bool  s_StencilTestEnabled;
716     static bool  s_DepthMask;
717     static bool  s_ScissorEnabled;
718     static u8    s_StencilMask;
719 
720     static u32   s_ColorMask;
721 
722     static Viewport  s_Viewport;
723     static ut::Rect  s_Scissor;
724 
725     static u32   s_RenderBufferWidth;
726     static u32   s_RenderBufferHeight;
727 
728     enum
729     {
730         COLOR_READ_MASK_INDEX = 4,
731         COLOR_WRITE_MASK_INDEX = 6,
732         DEPTH_READ_MASK_INDEX = 7,
733         DEPTH_WRITE_MASK_INDEX = 8
734     };
735 
736     static u32   s_FrameBufferCommand[10];
737 
738     static u32   s_LutIsAbs;
739     static u32   s_LutInput;
740     static u32   s_LutScale;
741 
742     static u32   s_DepthFormat;
743     static u32   s_WScale24;
744     static f32   s_DepthRangeNear;
745     static f32   s_DepthRangeFar;
746     static u32   s_DepthRange24;
747     static bool  s_PolygonOffsetEnabled;
748     static f32   s_PolygonOffsetUnit;
749 
750     static u32   s_LightPositionW;
751     static u32   s_LightShadowed;
752     static u32   s_LightSpotEnabled;
753     static u32   s_LightDistanceAttnEnabled;
754 
755     static ResImageLookupTable m_LutTargets[LUT_TARGET_COUNT];
756 };
757 
758 
759 //----------------------------------------
760 NW_INLINE void
SetBlendEnabled(bool enabled)761 GraphicsDevice::SetBlendEnabled(bool enabled)
762 {
763     s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_BlendEnabled != enabled);
764     s_BlendEnabled = enabled;
765 }
766 
767 //----------------------------------------
768 NW_INLINE void
SetStencilTestEnabled(bool enabled)769 GraphicsDevice::SetStencilTestEnabled(bool enabled)
770 {
771     s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_StencilTestEnabled != enabled);
772     s_StencilTestEnabled = enabled;
773 }
774 
775 //----------------------------------------
776 NW_INLINE void
SetDepthTestEnabled(bool enabled)777 GraphicsDevice::SetDepthTestEnabled(bool enabled)
778 {
779     s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_DepthTestEnabled != enabled);
780     s_DepthTestEnabled = enabled;
781 }
782 
783 
784 //----------------------------------------
785 NW_INLINE void
ActivateMask()786 GraphicsDevice::ActivateMask()
787 {
788     enum RegColorMask
789     {
790         REG_COLOR_MASK_ADDR    = 0x107,
791         REG_COLOR_MASK_SHIFT   = 8,
792         REG_DEPTH_MASK_SHIFT   = 12,
793         REG_STENCIL_MASK_ADDR  = 0x105,
794         REG_STENCIL_MASK_SHIFT = 8
795     };
796 
797     const u32 COLOR_MASK_HEADER =
798         internal::MakeCommandHeader(REG_COLOR_MASK_ADDR, 1, false, 0x2);
799 
800     const u32 STENCIL_MASK_HEADER =
801         internal::MakeCommandHeader(REG_STENCIL_MASK_ADDR, 1, false, 0x2);
802 
803     const u32 COMMAND[] =
804     {
805         s_ColorMask << REG_COLOR_MASK_SHIFT | s_DepthMask << REG_DEPTH_MASK_SHIFT,
806         COLOR_MASK_HEADER,
807         s_StencilMask << REG_STENCIL_MASK_SHIFT,
808         STENCIL_MASK_HEADER
809     };
810 
811     internal::NWUseCmdlist<sizeof(COMMAND)>(&COMMAND[0]);
812 }
813 
814 //----------------------------------------
815 NW_INLINE void
ActivateFrameBuffer()816 GraphicsDevice::ActivateFrameBuffer()
817 {
818     if (s_IsFrameBufferUpdated)
819     {
820         s_IsFrameBufferUpdated = false;
821 
822         UpdateFrameBufferCommand();
823     }
824 
825     internal::NWUseCmdlist(&s_FrameBufferCommand[0], sizeof(s_FrameBufferCommand));
826 }
827 
828 //----------------------------------------
829 void NW_INLINE
UpdateFrameBufferCommand()830 GraphicsDevice::UpdateFrameBufferCommand()
831 {
832     enum
833     {
834         COLOR_MASK_ALL        = 0xF,
835         COLOR_ACCESS_ENABLE   = 0xF,
836         DEPTH_ACCESS_ENABLE   = 0x2,
837         STENCIL_ACCESS_ENABLE = 0x1
838     };
839 
840     s_FrameBufferCommand[COLOR_READ_MASK_INDEX] = 0;
841     s_FrameBufferCommand[COLOR_WRITE_MASK_INDEX] = 0;
842 
843     // カラーバッファのリードとライト設定
844     if (s_FragOperationMode != ResFragmentOperation::FRAGMENT_OPERATION_MODE_GL)
845     {
846         s_FrameBufferCommand[COLOR_READ_MASK_INDEX]  = COLOR_ACCESS_ENABLE;
847         s_FrameBufferCommand[COLOR_WRITE_MASK_INDEX] = COLOR_ACCESS_ENABLE;
848     }
849     else if (s_ColorMask)
850     {
851         if (s_BlendEnabled || (s_ColorMask != COLOR_MASK_ALL))
852         {
853             s_FrameBufferCommand[COLOR_READ_MASK_INDEX] = COLOR_ACCESS_ENABLE;
854         }
855 
856         s_FrameBufferCommand[COLOR_WRITE_MASK_INDEX] = COLOR_ACCESS_ENABLE;
857     }
858 
859     s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] = 0;
860     s_FrameBufferCommand[DEPTH_WRITE_MASK_INDEX] = 0;
861     if (s_FragOperationMode == ResFragmentOperation::FRAGMENT_OPERATION_MODE_GAS)
862     {
863         s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] = DEPTH_ACCESS_ENABLE | STENCIL_ACCESS_ENABLE;
864     }
865     else if (s_FragOperationMode == ResFragmentOperation::FRAGMENT_OPERATION_MODE_GL)
866     {
867         // デプスバッファのリードとライト設定
868         if (s_DepthTestEnabled)
869         {
870             if (s_DepthMask)
871             {
872                 s_FrameBufferCommand[DEPTH_READ_MASK_INDEX]  = DEPTH_ACCESS_ENABLE;
873                 s_FrameBufferCommand[DEPTH_WRITE_MASK_INDEX] = DEPTH_ACCESS_ENABLE;
874             }
875             else if (s_ColorMask)
876             {
877                 s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] = DEPTH_ACCESS_ENABLE;
878             }
879         }
880 
881         // ステンシルバッファのリードとライト設定
882         if (s_StencilTestEnabled)
883         {
884             if (s_StencilMask)
885             {
886                 s_FrameBufferCommand[DEPTH_READ_MASK_INDEX]  |= STENCIL_ACCESS_ENABLE;
887                 s_FrameBufferCommand[DEPTH_WRITE_MASK_INDEX] |= STENCIL_ACCESS_ENABLE;
888             }
889             else if (s_ColorMask)
890             {
891                 s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] |= STENCIL_ACCESS_ENABLE;
892             }
893         }
894     }
895 }
896 
897 //----------------------------------------
898 NW_INLINE void
ActivateLutLoadSetting(LutTarget target)899 GraphicsDevice::ActivateLutLoadSetting(LutTarget target)
900 {
901     enum { REG_PICA_LIGHTING_LUT_SETTING = 0x1C5, REG_PICA_FOG_LUT_SETTING = 0x0e6 };
902 
903     const u32 LIGHTING_HEADER = internal::MakeCommandHeader(REG_PICA_LIGHTING_LUT_SETTING, 1, false, 0xF);
904     const u32 FOG_HEADER = internal::MakeCommandHeader(REG_PICA_FOG_LUT_SETTING, 1, false, 0xF);
905 
906 
907     if (target == LUT_TARGET_FOG)
908     {
909         u32 LUT_COMMAND[2] =
910         {
911             0,
912             FOG_HEADER
913         };
914 
915         internal::NWUseCmdlist<sizeof(LUT_COMMAND)>( &LUT_COMMAND[0] );
916         return;
917     }
918 
919     int targetReg = 0;
920     // スポットと距離減衰はtarget+1のレジスタに設定する。
921     if (target < LUT_TARGET_SP0)
922     {
923         targetReg = static_cast<int>(target);
924     }
925     else
926     {
927         targetReg = static_cast<int>(target) + 1;
928     }
929 
930     u32 LUT_COMMAND[2] =
931     {
932         targetReg << 8,
933         LIGHTING_HEADER
934     };
935 
936     internal::NWUseCmdlist<sizeof(LUT_COMMAND)>( &LUT_COMMAND[0] );
937 }
938 
939 //----------------------------------------
940 NW_INLINE void
ActivatePolygonOffset()941 GraphicsDevice::ActivatePolygonOffset()
942 {
943     // PolygonOffset の設定
944     enum
945     {
946         REG_POLYGON_OFFSET = 0x4d,
947         REG_WSCALE_ENABLE  = 0x6d
948     };
949 
950     const u32 OFFSET_HEADER = internal::MakeCommandHeader(REG_POLYGON_OFFSET, 2, true, 0x7);
951     const u32 WSCALE_HEADER = internal::MakeCommandHeader(REG_WSCALE_ENABLE, 1, false, 0x1);
952 
953     static u32 COMMAND[] =
954     {
955         0,
956         WSCALE_HEADER,
957         0,
958         OFFSET_HEADER,
959         0,
960         0
961     };
962 
963     f32 zBias;
964     f32 offset;
965 
966     if (s_WScale24 == 0)
967     {
968         COMMAND[0] = 1;
969         COMMAND[2] = s_DepthRange24;
970 
971         zBias = s_DepthRangeNear;
972         offset = (s_DepthRangeNear - s_DepthRangeFar) * s_PolygonOffsetUnit;
973     }
974     else
975     {
976         COMMAND[0] = 0;
977         COMMAND[2] = s_WScale24;
978 
979         zBias = 0.0f;
980         offset =  -s_PolygonOffsetUnit;
981     }
982 
983     // DMP のドキュメントでは wScale が有効な際には PolygonOffset が効かない仕様になっていますが、
984     // W-Buffering 時にも PolygonOffset の需要がある為、Z-Buffering と同様に設定します。
985     if (s_PolygonOffsetEnabled)
986     {
987         if (s_DepthFormat == RENDER_DEPTH_FORMAT_16)
988         {
989             zBias -= offset / 65535.0f;
990         }
991         else
992         {
993             // 24bit 浮動小数(仮数16bit)の精度限界により、誤差で消えてしまう為
994             // 精度が問題にならないような定数値を掛けておく必要があります。
995             // 0.5f 付近の深度を基準として 128.0f を掛けておく事にします。
996 
997             zBias -= offset * 128.0f / 16777215.0f;
998         }
999     }
1000 
1001     COMMAND[4] = ut::Float24::Float32ToBits24(zBias);
1002 
1003     internal::NWUseCmdlist<sizeof(COMMAND)>( &COMMAND[0] );
1004 }
1005 
1006 //----------------------------------------
1007 NW_INLINE void
SetColorMask(bool red,bool green,bool blue,bool alpha)1008 GraphicsDevice::SetColorMask(bool red, bool green, bool blue, bool alpha)
1009 {
1010     u32 colorMask = u32(red) |
1011                  (u32(green) << 1) |
1012                  (u32(blue)  << 2) |
1013                  (u32(alpha) << 3);
1014 
1015     s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_ColorMask != colorMask);
1016     s_ColorMask = colorMask;
1017 }
1018 
1019 //----------------------------------------
1020 NW_INLINE void
SetDepthMaskEnabled(bool enabled)1021 GraphicsDevice::SetDepthMaskEnabled(bool enabled)
1022 {
1023     s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_DepthMask != enabled);
1024     s_DepthMask = enabled;
1025 }
1026 
1027 //----------------------------------------
1028 NW_INLINE void
SetStencilMask(u8 mask)1029 GraphicsDevice::SetStencilMask(u8 mask)
1030 {
1031     s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_StencilMask != mask);
1032     s_StencilMask = mask;
1033 }
1034 
1035 } // namespace gfx
1036 } // namespace nw
1037 
1038 #endif // NW_GFX_GRAPHICSDEVICE_H_
1039