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