1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_FrameBuffer.cpp
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: 13145 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <gles2/gl2.h>
19 #include <nn/gx.h>
20 #include <nn/gx/CTR/gx_MacroReg.h>
21 #include <nw/gfx/gfx_FrameBuffer.h>
22 #include <nw/gfx/gfx_GlImplement.h>
23 
24 namespace nw {
25 namespace gfx {
26 
27 //---------------------------------------------------------------------------
28 //! @brief        FloatColor から RGBA8 へ変換します。
29 //!
30 //! @param[in]    color   FloatColor の値です。
31 //!
32 //! @return       RGBA8 の値です。
33 //---------------------------------------------------------------------------
34 static inline u32
ColorToRGBA8(const ut::FloatColor & color)35 ColorToRGBA8( const ut::FloatColor& color )
36 {
37     // RGBA8 の Picaネイティブフォーマットではエンディアンを反転する必要がある。
38 
39     u8 red = static_cast<u8>( 0.5f + nw::ut::Clamp(color.r, 0.0f, 1.0f) * 255.f );
40     u8 green = static_cast<u8>( 0.5f + nw::ut::Clamp(color.g, 0.0f, 1.0f) * 255.f );
41     u8 blue = static_cast<u8>( 0.5f + nw::ut::Clamp(color.b, 0.0f, 1.0f) * 255.f );
42     u8 alpha = static_cast<u8>( 0.5f + nw::ut::Clamp(color.a, 0.0f, 1.0f) * 255.f );
43 
44     return (alpha) | (blue << 8) | (green << 16) | (red << 24);
45 }
46 
47 
48 //---------------------------------------------------------------------------
49 //! @brief        FloatColor から RGB5A1 へ変換します。
50 //!
51 //! @param[in]    color   FloatColor の値です。
52 //!
53 //! @return       RGB5A1 の値です。
54 //---------------------------------------------------------------------------
55 static inline u16
ColorToRGB5A1(const ut::FloatColor & color)56 ColorToRGB5A1( const ut::FloatColor& color )
57 {
58     u8 red = static_cast<u8>( 0.5f + nw::ut::Clamp(color.r, 0.0f, 1.0f) * 31.f );
59     u8 green = static_cast<u8>( 0.5f + nw::ut::Clamp(color.g, 0.0f, 1.0f) * 31.f );
60     u8 blue = static_cast<u8>( 0.5f + nw::ut::Clamp(color.b, 0.0f, 1.0f) * 31.f );
61     u8 alpha = static_cast<u8>( 0.5f + nw::ut::Clamp(color.a, 0.0f, 1.0f) * 1.f );
62 
63     return static_cast<u16>( (alpha) | (blue << 1) | (green << 6) | (red << 11) );
64 }
65 
66 
67 //---------------------------------------------------------------------------
68 //! @brief        FloatColor から RGB565 へ変換します。
69 //!
70 //! @param[in]    color   FloatColor の値です。
71 //!
72 //! @return       RGB565 の値です。
73 //---------------------------------------------------------------------------
74 static inline u16
ColorToRGB565(const ut::FloatColor & color)75 ColorToRGB565( const ut::FloatColor& color )
76 {
77     u8 red = static_cast<u8>( 0.5f + nw::ut::Clamp(color.r, 0.0f, 1.0f) * 31.f );
78     u8 green = static_cast<u8>( 0.5f + nw::ut::Clamp(color.g, 0.0f, 1.0f) * 63.f );
79     u8 blue = static_cast<u8>( 0.5f + nw::ut::Clamp(color.b, 0.0f, 1.0f) * 31.f );
80 
81     return static_cast<u16>( (blue) | (green << 5) | (red << 11) );
82 }
83 
84 
85 //---------------------------------------------------------------------------
86 //! @brief        FloatColor から RGBA4 へ変換します。
87 //!
88 //! @param[in]    color   FloatColor の値です。
89 //!
90 //! @return       RGBA4 の値です。
91 //---------------------------------------------------------------------------
92 static inline u16
ColorToRGBA4(const ut::FloatColor & color)93 ColorToRGBA4( const ut::FloatColor& color )
94 {
95     u8 red = static_cast<u8>( 0.5f + nw::ut::Clamp(color.r, 0.0f, 1.0f) * 15.f );
96     u8 green = static_cast<u8>( 0.5f + nw::ut::Clamp(color.g, 0.0f, 1.0f) * 15.f );
97     u8 blue = static_cast<u8>( 0.5f + nw::ut::Clamp(color.b, 0.0f, 1.0f) * 15.f );
98     u8 alpha = static_cast<u8>( 0.5f + nw::ut::Clamp(color.a, 0.0f, 1.0f) * 15.f );
99 
100     return static_cast<u16>( (alpha) | (blue << 4) | (green << 8) | (red << 12) );
101 }
102 
103 
104 //---------------------------------------------------------------------------
105 void
SetDescription(const Description & description)106 FrameBufferObject::SetDescription(const Description& description)
107 {
108     m_Description = description;
109 
110     if (description.fboID == 0)
111     {
112         this->SetFboID(description.fboID);
113     }
114     else
115     {
116         m_Description = description;
117     }
118 }
119 
120 //---------------------------------------------------------------------------
121 void
SetFboID(GLuint fboID)122 FrameBufferObject::SetFboID(GLuint fboID)
123 {
124     m_Description.fboID = fboID;
125 
126     if (fboID != 0)
127     {
128         internal::GetFrameBufferState(
129             m_Description.fboID,
130             &m_Description.colorAddress,
131             &m_Description.depthAddress
132         );
133     }
134 }
135 
136 
137 //---------------------------------------------------------------------------
138 void
ActivateBuffer() const139 FrameBufferObject::ActivateBuffer() const
140 {
141     const FrameBufferObject::Description& description = this->GetDescription();
142 
143 #if 0
144     // 後で gl で描画する場合の事を考慮していたが、
145     // gl を使って描画する場合には自前で、glBindFramebuffer も呼んでもらうことにする。
146     if ( description.fboID != 0 )
147     {
148         glBindFramebuffer( GL_FRAMEBUFFER, description.fboID );
149     }
150 #endif
151 
152     {
153         NW_ALIGN_ASSERT( description.depthAddress, 0x8 );
154         NW_ALIGN_ASSERT( description.colorAddress, 0x8 );
155         NW_ALIGN_ASSERT( description.height, 0x8 );
156         NW_ALIGN_ASSERT( description.width, 0x8 );
157         NW_ASSERT( description.height <= 1024 );
158         NW_ASSERT( description.width <= 1024 );
159 
160         u32 depthFormat = 0;
161         u32 colorFormat = 0;
162 
163         switch ( description.depthFormat )
164         {
165         case GL_DEPTH_COMPONENT16:     depthFormat = 0; break;
166         case GL_DEPTH_COMPONENT24_OES: depthFormat = 2; break;
167         case GL_DEPTH24_STENCIL8_EXT:  depthFormat = 3; break;
168         default:
169             // デプスバッファを使用しない場合のみ、ここを通る。
170             NW_ASSERTMSG( description.depthAddress == NULL, "Unknown depth format" );
171         }
172 
173         switch ( description.colorFormat )
174         {
175         case GL_RGBA8_OES: colorFormat = (0 << 16) | 0x2; break;
176         case GL_GAS_DMP:   colorFormat = (0 << 16) | 0x2; break;
177         case GL_RGB5_A1:   colorFormat = (2 << 16); break;
178         case GL_RGB565:    colorFormat = (3 << 16); break;
179         case GL_RGBA4:     colorFormat = (4 << 16); break;
180         default:
181             // カラーバッファを使用しない場合のみ、ここを通る。
182             NW_ASSERTMSG( description.colorAddress == NULL, "Unknown color format" );
183         }
184 
185         if (description.depthAddress == NULL)
186         {
187             u32 COMMAND[] =
188             {
189                 0x1,
190                 internal::MakeCommandHeader( PICA_REG_COLOR_DEPTH_BUFFER_CLEAR1, 1, false, 0xf ),
191                 0x1,
192                 internal::MakeCommandHeader( PICA_REG_COLOR_DEPTH_BUFFER_CLEAR0, 1, false, 0xf ),
193 
194                 colorFormat,
195                 internal::MakeCommandHeader( PICA_REG_RENDER_BUFFER_COLOR_MODE, 1, false, 0xf ),
196 
197                 (description.colorAddress != NULL) ? (nngxGetPhysicalAddr( description.colorAddress ) >> 3) : 0,
198                 internal::MakeCommandHeader( PICA_REG_RENDER_BUFFER_COLOR_ADDR, 1, false, 0xf ),
199 
200                 description.width | ((description.height - 1) << 12) | 0x01000000,
201                 internal::MakeCommandHeader( PICA_REG_RENDER_BUFFER_RESOLUTION0, 1, false, 0xf ),
202 
203                 description.width | ((description.height - 1) << 12) | 0x01000000,
204                 internal::MakeCommandHeader( PICA_REG_RENDER_BUFFER_RESOLUTION1, 1, false, 0xf ),
205 
206                 (description.useBlock32)? 1 : 0,
207                 internal::MakeCommandHeader( PICA_REG_RENDER_BLOCK_FORMAT, 1, false, 0xf ),
208             };
209 
210             internal::NWUseCmdlist<sizeof(COMMAND)>( &COMMAND[0] );
211         }
212         else
213         {
214             u32 COMMAND[] =
215             {
216                 0x1,
217                 internal::MakeCommandHeader( PICA_REG_COLOR_DEPTH_BUFFER_CLEAR1, 1, false, 0xf ),
218                 0x1,
219                 internal::MakeCommandHeader( PICA_REG_COLOR_DEPTH_BUFFER_CLEAR0, 1, false, 0xf ),
220 
221                 (description.depthAddress != NULL) ? (nngxGetPhysicalAddr( description.depthAddress ) >> 3) : 0,
222                 internal::MakeCommandHeader( PICA_REG_RENDER_BUFFER_DEPTH_ADDR, 3, true, 0xf ),
223                 (description.colorAddress != NULL) ? (nngxGetPhysicalAddr( description.colorAddress ) >> 3) : 0,
224                 description.width | ((description.height - 1) << 12) | 0x01000000,
225 
226                 description.width | ((description.height - 1) << 12) | 0x01000000,
227                 internal::MakeCommandHeader( PICA_REG_RENDER_BUFFER_RESOLUTION1, 1, false, 0xf ),
228 
229                 depthFormat,
230                 internal::MakeCommandHeader( PICA_REG_RENDER_BUFFER_DEPTH_MODE, 1, false, 0xf ),
231 
232                 colorFormat,
233                 internal::MakeCommandHeader( PICA_REG_RENDER_BUFFER_COLOR_MODE, 1, false, 0xf ),
234 
235                 (description.useBlock32)? 1 : 0,
236                 internal::MakeCommandHeader( PICA_REG_RENDER_BLOCK_FORMAT, 1, false, 0xf ),
237             };
238 
239             internal::NWUseCmdlist<sizeof(COMMAND)>( &COMMAND[0] );
240         }
241     }
242 }
243 
244 //---------------------------------------------------------------------------
245 void
ClearBuffer(u32 mask,const ut::FloatColor & clearColor,f32 clearDepth,u8 clearStencil) const246 FrameBufferObject::ClearBuffer(
247     u32 mask,
248     const ut::FloatColor& clearColor,
249     f32 clearDepth,
250     u8 clearStencil /* = 0 */
251 ) const
252 {
253     const FrameBufferObject::Description& description = this->GetDescription();
254 
255     u32 colorAddress = 0;
256     u32 depthAddress = 0;
257     u32 colorWidth = 0;
258     u32 depthWidth = 0;
259     u32 clearColorHW = 0;
260     u32 clearDepthHW = 0;
261     u32 colorSize = 0;
262     u32 depthSize = 0;
263 
264     if ( mask & CLEAR_MASK_COLOR )
265     {
266         colorAddress = description.colorAddress;
267 
268         switch ( description.colorFormat )
269         {
270         case GL_RGBA8_OES:
271             {
272                 colorWidth = 32;
273                 clearColorHW = ColorToRGBA8( clearColor );
274             }
275             break;
276         case GL_GAS_DMP:
277             {
278                 colorWidth = 32;
279                 // clearColorHW = clearColor.ToPicaU32();
280                 clearColorHW = ColorToRGBA8( clearColor );
281             }
282             break;
283         case GL_RGB5_A1:
284             {
285                 colorWidth = 16;
286                 clearColorHW = ColorToRGB5A1( clearColor );
287                 clearColorHW = (clearColorHW << 16) | clearColorHW;
288             }
289             break;
290         case GL_RGB565:
291             {
292                 colorWidth = 16;
293                 clearColorHW = ColorToRGB565( clearColor );
294                 clearColorHW = (clearColorHW << 16) | clearColorHW;
295             }
296             break;
297         case GL_RGBA4:
298             {
299                 colorWidth = 16;
300                 clearColorHW = ColorToRGBA4( clearColor );
301                 clearColorHW = (clearColorHW << 16) | clearColorHW;
302             }
303             break;
304         default:
305             NW_FATAL_ERROR("Unknown color format");
306         }
307 
308         colorSize = description.height * description.width * colorWidth / 8;
309     }
310 
311     if (mask & CLEAR_MASK_DEPTH)
312     {
313         depthAddress = description.depthAddress;
314 
315         if ( depthAddress == 0 )
316         {
317             depthWidth = 0;
318             clearDepthHW = 0;
319         }
320         else
321         {
322             switch ( description.depthFormat )
323             {
324             case GL_DEPTH_COMPONENT16:
325                 {
326                     depthWidth = 16;
327                     clearDepthHW = static_cast<u16>( nw::ut::Clamp(clearDepth, 0.0f, 1.0f) * static_cast<f32>(0xFFFF) );
328                     clearDepthHW = (clearDepthHW << 16) | clearDepthHW;
329                 }
330                 break;
331             case GL_DEPTH_COMPONENT24_OES:
332                 {
333                     depthWidth = 24;
334                     clearDepthHW = static_cast<u32>( nw::ut::Clamp(clearDepth, 0.0f, 1.0f) * static_cast<f32>(0xFFFFFF) );
335                 }
336                 break;
337             case GL_DEPTH24_STENCIL8_EXT:
338                 {
339                     depthWidth = 32;
340                     clearDepthHW = static_cast<u32>( nw::ut::Clamp(clearDepth, 0.0f, 1.0f) * static_cast<f32>(0xFFFFFF) );
341                     clearDepthHW |= clearStencil << 24;
342                 }
343                 break;
344             default:
345                 NW_FATAL_ERROR("Unknown depth format");
346             }
347         }
348 
349         depthSize = description.height * description.width * depthWidth / 8;
350     }
351 
352     internal::nwgfxClear( colorAddress, colorSize, clearColorHW, colorWidth,
353                 depthAddress, depthSize, clearDepthHW, depthWidth );
354 }
355 
356 
357 } // namespace gfx
358 } // namespace nw
359