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