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: 27679 $
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         enum
607         {
608             REG_VIEWPORT_WIDTH_HALF    = 0x41,
609             REG_VIEWPORT_WIDTH_HALF_S  = 0x42,
610             REG_VIEWPORT_HEIGHT_HALF   = 0x43,
611             REG_VIEWPORT_HEIGHT_HALF_S = 0x44,
612             REG_VIEWPORT_XY            = 0x68
613         };
614 
615         u16 x16 = static_cast<u16>(viewport.GetBound().GetX());
616         u16 y16 = static_cast<u16>(viewport.GetBound().GetY());
617 
618         const u32 HEADER_VIEWPORT_WIDTH_HALF = nw::gfx::internal::MakeCommandHeader( REG_VIEWPORT_WIDTH_HALF, 4, true, 0xF );
619         const u32 HEADER_VIEWPORT_XY         = nw::gfx::internal::MakeCommandHeader( REG_VIEWPORT_XY, 1, false, 0xF );
620 
621         u32 VIEWPORT_COMMAND[] =
622         {
623             nw::ut::Float24::Float32ToBits24( viewport.GetBound().GetWidth() / 2.f ),
624             HEADER_VIEWPORT_WIDTH_HALF,
625             (ut::Float31::Float32ToBits31( 2.f / viewport.GetBound().GetWidth() ) << 1),
626             nw::ut::Float24::Float32ToBits24( viewport.GetBound().GetHeight()/2.f ),
627             (ut::Float31::Float32ToBits31( 2.f / viewport.GetBound().GetHeight() ) << 1),
628             0,
629             (x16 | (y16 << 16)),
630             HEADER_VIEWPORT_XY
631         };
632 
633         nw::gfx::internal::NWUseCmdlist<sizeof(VIEWPORT_COMMAND)>( &VIEWPORT_COMMAND[0] );
634     }
635 
636     //--------------------------------------------------------------------------
637     //! @brief        レンダリングバッファサイズを指定します。
638     //!
639     //! @param[in]    width  レンダリングバッファの幅サイズです。
640     //! @param[in]    height レンダリングバッファの縦サイズです。
641     //--------------------------------------------------------------------------
SetRenderBufferSize(s32 width,s32 height)642     static void SetRenderBufferSize(s32 width, s32 height)
643     {
644         s_RenderBufferWidth = width;
645         s_RenderBufferHeight = height;
646     }
647 
648     //--------------------------------------------------------------------------
649     //! @brief シザリングの矩形情報を発行します。
650     //!
651     //! @param[in]    enabled  シザリングが有効化どうかのフラグです。
652     //! @param[in]    scissor  設定するシザリング矩形です。
653     //--------------------------------------------------------------------------
ActivateScissor(bool enabled,const ut::Rect & scissor)654     static void ActivateScissor(bool enabled, const ut::Rect& scissor)
655     {
656         enum
657         {
658             REG_SCISSOR_ENABLE = 0x65,
659             REG_SCISSOR_XY     = 0x66,
660             REG_SCISSOR_WH     = 0x67,
661 
662             REG_SCISSOR_DISABLED = 0,
663             REG_SCISSOR_ENABLED = 3
664         };
665 
666         NW_MINMAX_ASSERT(scissor.GetX(), 0, static_cast<s32>(s_RenderBufferWidth));
667         NW_MINMAX_ASSERT(scissor.GetY(), 0, static_cast<s32>(s_RenderBufferHeight));
668         NW_MINMAX_ASSERT(scissor.GetX() + scissor.GetWidth(), 0, static_cast<s32>(s_RenderBufferWidth));
669         NW_MINMAX_ASSERT(scissor.GetY() + scissor.GetHeight(), 0, static_cast<s32>(s_RenderBufferHeight));
670 
671         u16 x16 = static_cast<u16>(scissor.GetX());
672         u16 w16 = static_cast<u16>(scissor.GetWidth());
673         u16 y16 = static_cast<u16>(scissor.GetY());
674         u16 h16 = static_cast<u16>(scissor.GetHeight());
675 
676         const u32 HEADER_SCISSOR = nw::gfx::internal::MakeCommandHeader( REG_SCISSOR_ENABLE, 3, true, 0xF );
677 
678         u32 SCISSOR_COMMAND[] =
679         {
680             enabled ? REG_SCISSOR_ENABLED : REG_SCISSOR_DISABLED,
681             HEADER_SCISSOR,
682             enabled ? (x16 | (y16 << 16)) : 0,
683             enabled ? ((x16 + w16 - 1) | ((y16 + h16 - 1) << 16)) : ((s_RenderBufferWidth - 1) | ((s_RenderBufferHeight - 1) << 16)),
684         };
685 
686         nw::gfx::internal::NWUseCmdlist<sizeof(SCISSOR_COMMAND)>( &SCISSOR_COMMAND[0] );
687     }
688 
689 
690     //---------------------------------------------------------------------------
691     //! @brief        GraphicsDevice の状態を表示します。
692     //---------------------------------------------------------------------------
693     static void Report();
694 
695 private:
696     //--------------------------------------------------------------------------
697     //! @brief        LUT 転送の準備コマンドを送信します。
698     //!
699     //! @param[in]    target    LUTのタイプです。
700     //---------------------------------------------------------------------------
701     static NW_INLINE void ActivateLutLoadSetting(LutTarget target);
702 
703     //! @brief フレームバッファコマンドを更新します。
704     static NW_INLINE void UpdateFrameBufferCommand();
705 
706     static ResFragmentOperation::FragmentOperationMode   s_FragOperationMode;
707     static bool  s_IsFrameBufferUpdated;
708     static bool  s_BlendEnabled;
709     static bool  s_DepthTestEnabled;
710     static bool  s_StencilTestEnabled;
711     static bool  s_DepthMask;
712     static bool  s_PolygonOffsetEnabled;
713     static u8    s_StencilMask;
714 
715     static u32   s_ColorMask;
716 
717     static u32   s_RenderBufferWidth;
718     static u32   s_RenderBufferHeight;
719 
720     enum
721     {
722         COLOR_READ_MASK_INDEX = 4,
723         COLOR_WRITE_MASK_INDEX = 6,
724         DEPTH_READ_MASK_INDEX = 7,
725         DEPTH_WRITE_MASK_INDEX = 8,
726         FRAME_BUFFER_COMMAND_COUNT = 10
727     };
728 
729     static u32   s_FrameBufferCommand[FRAME_BUFFER_COMMAND_COUNT];
730 
731     static u32   s_LutIsAbs;
732     static u32   s_LutInput;
733     static u32   s_LutScale;
734 
735     static u32   s_DepthFormat;
736     static u32   s_WScale24;
737     static f32   s_DepthRangeNear;
738     static f32   s_DepthRangeFar;
739     static u32   s_DepthRange24;
740     static f32   s_PolygonOffsetUnit;
741 
742     static u32   s_LightPositionW;
743     static u32   s_LightShadowed;
744     static u32   s_LightSpotEnabled;
745     static u32   s_LightDistanceAttnEnabled;
746 
747     static ResImageLookupTable m_LutTargets[LUT_TARGET_COUNT];
748 };
749 
750 
751 //----------------------------------------
752 NW_INLINE void
SetBlendEnabled(bool enabled)753 GraphicsDevice::SetBlendEnabled(bool enabled)
754 {
755     s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_BlendEnabled != enabled);
756     s_BlendEnabled = enabled;
757 }
758 
759 //----------------------------------------
760 NW_INLINE void
SetStencilTestEnabled(bool enabled)761 GraphicsDevice::SetStencilTestEnabled(bool enabled)
762 {
763     s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_StencilTestEnabled != enabled);
764     s_StencilTestEnabled = enabled;
765 }
766 
767 //----------------------------------------
768 NW_INLINE void
SetDepthTestEnabled(bool enabled)769 GraphicsDevice::SetDepthTestEnabled(bool enabled)
770 {
771     s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_DepthTestEnabled != enabled);
772     s_DepthTestEnabled = enabled;
773 }
774 
775 
776 //----------------------------------------
777 NW_INLINE void
ActivateMask()778 GraphicsDevice::ActivateMask()
779 {
780     enum RegColorMask
781     {
782         REG_COLOR_MASK_ADDR    = 0x107,
783         REG_COLOR_MASK_SHIFT   = 8,
784         REG_DEPTH_MASK_SHIFT   = 12,
785         REG_STENCIL_MASK_ADDR  = 0x105,
786         REG_STENCIL_MASK_SHIFT = 8
787     };
788 
789     const u32 COLOR_MASK_HEADER =
790         internal::MakeCommandHeader(REG_COLOR_MASK_ADDR, 1, false, 0x2);
791 
792     const u32 STENCIL_MASK_HEADER =
793         internal::MakeCommandHeader(REG_STENCIL_MASK_ADDR, 1, false, 0x2);
794 
795     const u32 COMMAND[] =
796     {
797         s_ColorMask << REG_COLOR_MASK_SHIFT | s_DepthMask << REG_DEPTH_MASK_SHIFT,
798         COLOR_MASK_HEADER,
799         s_StencilMask << REG_STENCIL_MASK_SHIFT,
800         STENCIL_MASK_HEADER
801     };
802 
803     internal::NWUseCmdlist<sizeof(COMMAND)>(&COMMAND[0]);
804 }
805 
806 //----------------------------------------
807 NW_INLINE void
ActivateFrameBuffer()808 GraphicsDevice::ActivateFrameBuffer()
809 {
810     if (s_IsFrameBufferUpdated)
811     {
812         s_IsFrameBufferUpdated = false;
813 
814         UpdateFrameBufferCommand();
815     }
816 
817     internal::NWUseCmdlist(&s_FrameBufferCommand[0], sizeof(s_FrameBufferCommand));
818 }
819 
820 //----------------------------------------
821 void NW_INLINE
UpdateFrameBufferCommand()822 GraphicsDevice::UpdateFrameBufferCommand()
823 {
824     enum
825     {
826         COLOR_MASK_ALL        = 0xF,
827         COLOR_ACCESS_ENABLE   = 0xF,
828         DEPTH_ACCESS_ENABLE   = 0x2,
829         STENCIL_ACCESS_ENABLE = 0x1
830     };
831 
832     s_FrameBufferCommand[COLOR_READ_MASK_INDEX] = 0;
833     s_FrameBufferCommand[COLOR_WRITE_MASK_INDEX] = 0;
834 
835     // カラーバッファのリードとライト設定
836     if (s_FragOperationMode != ResFragmentOperation::FRAGMENT_OPERATION_MODE_GL)
837     {
838         s_FrameBufferCommand[COLOR_READ_MASK_INDEX]  = COLOR_ACCESS_ENABLE;
839         s_FrameBufferCommand[COLOR_WRITE_MASK_INDEX] = COLOR_ACCESS_ENABLE;
840     }
841     else if (s_ColorMask)
842     {
843         if (s_BlendEnabled || (s_ColorMask != COLOR_MASK_ALL))
844         {
845             s_FrameBufferCommand[COLOR_READ_MASK_INDEX] = COLOR_ACCESS_ENABLE;
846         }
847 
848         s_FrameBufferCommand[COLOR_WRITE_MASK_INDEX] = COLOR_ACCESS_ENABLE;
849     }
850 
851     s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] = 0;
852     s_FrameBufferCommand[DEPTH_WRITE_MASK_INDEX] = 0;
853     if (s_FragOperationMode == ResFragmentOperation::FRAGMENT_OPERATION_MODE_GAS)
854     {
855         s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] = DEPTH_ACCESS_ENABLE | STENCIL_ACCESS_ENABLE;
856     }
857     else if (s_FragOperationMode == ResFragmentOperation::FRAGMENT_OPERATION_MODE_GL)
858     {
859         // デプスバッファのリードとライト設定
860         if (s_DepthTestEnabled)
861         {
862             if (s_DepthMask)
863             {
864                 s_FrameBufferCommand[DEPTH_READ_MASK_INDEX]  = DEPTH_ACCESS_ENABLE;
865                 s_FrameBufferCommand[DEPTH_WRITE_MASK_INDEX] = DEPTH_ACCESS_ENABLE;
866             }
867             else if (s_ColorMask)
868             {
869                 s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] = DEPTH_ACCESS_ENABLE;
870             }
871         }
872 
873         // ステンシルバッファのリードとライト設定
874         if (s_StencilTestEnabled)
875         {
876             if (s_StencilMask)
877             {
878                 s_FrameBufferCommand[DEPTH_READ_MASK_INDEX]  |= STENCIL_ACCESS_ENABLE;
879                 s_FrameBufferCommand[DEPTH_WRITE_MASK_INDEX] |= STENCIL_ACCESS_ENABLE;
880             }
881             else if (s_ColorMask)
882             {
883                 s_FrameBufferCommand[DEPTH_READ_MASK_INDEX] |= STENCIL_ACCESS_ENABLE;
884             }
885         }
886     }
887 }
888 
889 //----------------------------------------
890 NW_INLINE void
ActivateLutLoadSetting(LutTarget target)891 GraphicsDevice::ActivateLutLoadSetting(LutTarget target)
892 {
893     enum { REG_PICA_LIGHTING_LUT_SETTING = 0x1C5, REG_PICA_FOG_LUT_SETTING = 0x0e6 };
894 
895     const u32 LIGHTING_HEADER = internal::MakeCommandHeader(REG_PICA_LIGHTING_LUT_SETTING, 1, false, 0xF);
896     const u32 FOG_HEADER = internal::MakeCommandHeader(REG_PICA_FOG_LUT_SETTING, 1, false, 0xF);
897 
898 
899     if (target == LUT_TARGET_FOG)
900     {
901         u32 LUT_COMMAND[2] =
902         {
903             0,
904             FOG_HEADER
905         };
906 
907         internal::NWUseCmdlist<sizeof(LUT_COMMAND)>( &LUT_COMMAND[0] );
908         return;
909     }
910 
911     int targetReg = 0;
912     // スポットと距離減衰はtarget+1のレジスタに設定する。
913     if (target < LUT_TARGET_SP0)
914     {
915         targetReg = static_cast<int>(target);
916     }
917     else
918     {
919         targetReg = static_cast<int>(target) + 1;
920     }
921 
922     u32 LUT_COMMAND[2] =
923     {
924         targetReg << 8,
925         LIGHTING_HEADER
926     };
927 
928     internal::NWUseCmdlist<sizeof(LUT_COMMAND)>( &LUT_COMMAND[0] );
929 }
930 
931 //----------------------------------------
932 NW_INLINE void
ActivatePolygonOffset()933 GraphicsDevice::ActivatePolygonOffset()
934 {
935     // PolygonOffset の設定
936     enum
937     {
938         REG_POLYGON_OFFSET = 0x4d,
939         REG_WSCALE_ENABLE  = 0x6d
940     };
941 
942     const u32 OFFSET_HEADER = internal::MakeCommandHeader(REG_POLYGON_OFFSET, 2, true, 0x7);
943     const u32 WSCALE_HEADER = internal::MakeCommandHeader(REG_WSCALE_ENABLE, 1, false, 0x1);
944 
945     static u32 COMMAND[] =
946     {
947         0,
948         WSCALE_HEADER,
949         0,
950         OFFSET_HEADER,
951         0,
952         0
953     };
954 
955     f32 zBias;
956     f32 offset;
957 
958     if (s_WScale24 == 0)
959     {
960         COMMAND[0] = 1;
961         COMMAND[2] = s_DepthRange24;
962 
963         zBias = s_DepthRangeNear;
964         offset = (s_DepthRangeNear - s_DepthRangeFar) * s_PolygonOffsetUnit;
965     }
966     else
967     {
968         COMMAND[0] = 0;
969         COMMAND[2] = s_WScale24;
970 
971         zBias = 0.0f;
972         offset =  -s_PolygonOffsetUnit;
973     }
974 
975     // DMP のドキュメントでは wScale が有効な際には PolygonOffset が効かない仕様になっていますが、
976     // W-Buffering 時にも PolygonOffset の需要がある為、Z-Buffering と同様に設定します。
977     if (s_PolygonOffsetEnabled)
978     {
979         if (s_DepthFormat == RENDER_DEPTH_FORMAT_16)
980         {
981             zBias -= offset / 65535.0f;
982         }
983         else
984         {
985             // 24bit 浮動小数(仮数16bit)の精度限界により、誤差で消えてしまう為
986             // 精度が問題にならないような定数値を掛けておく必要があります。
987             // 0.5f 付近の深度を基準として 128.0f を掛けておく事にします。
988 
989             zBias -= offset * 128.0f / 16777215.0f;
990         }
991     }
992 
993     COMMAND[4] = ut::Float24::Float32ToBits24(zBias);
994 
995     internal::NWUseCmdlist<sizeof(COMMAND)>( &COMMAND[0] );
996 }
997 
998 //----------------------------------------
999 NW_INLINE void
SetColorMask(bool red,bool green,bool blue,bool alpha)1000 GraphicsDevice::SetColorMask(bool red, bool green, bool blue, bool alpha)
1001 {
1002     u32 colorMask = u32(red) |
1003                  (u32(green) << 1) |
1004                  (u32(blue)  << 2) |
1005                  (u32(alpha) << 3);
1006 
1007     s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_ColorMask != colorMask);
1008     s_ColorMask = colorMask;
1009 }
1010 
1011 //----------------------------------------
1012 NW_INLINE void
SetDepthMaskEnabled(bool enabled)1013 GraphicsDevice::SetDepthMaskEnabled(bool enabled)
1014 {
1015     s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_DepthMask != enabled);
1016     s_DepthMask = enabled;
1017 }
1018 
1019 //----------------------------------------
1020 NW_INLINE void
SetStencilMask(u8 mask)1021 GraphicsDevice::SetStencilMask(u8 mask)
1022 {
1023     s_IsFrameBufferUpdated = s_IsFrameBufferUpdated || (s_StencilMask != mask);
1024     s_StencilMask = mask;
1025 }
1026 
1027 } // namespace gfx
1028 } // namespace nw
1029 
1030 #endif // NW_GFX_GRAPHICSDEVICE_H_
1031