/*---------------------------------------------------------------------------* Project: NintendoWare File: font_RectDrawer.cpp Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. The content herein is highly confidential and should be handled accordingly. $Revision: 31311 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include #if defined(NW_PLATFORM_CTR) #include #include #endif #include #include #define NW_FONT_ADD_COMMANDS( pStrBuf, command, size ) \ NW_ASSERT((pStrBuf)->commandBufferSize + (size) / sizeof(u32) <= (pStrBuf)->commandBufferCapacity); \ std::memcpy(&(pStrBuf)->commandBuffer[(pStrBuf)->commandBufferSize], command, size ); \ (pStrBuf)->commandBufferSize += (size) / sizeof(u32) #define NW_FONT_ADD_SINGLE_COMMAND( pStrBuf, header, data ) \ NW_ASSERT((pStrBuf)->commandBufferSize + 2 <= (pStrBuf)->commandBufferCapacity); \ (pStrBuf)->commandBuffer[(pStrBuf)->commandBufferSize + 0] = (data); \ (pStrBuf)->commandBuffer[(pStrBuf)->commandBufferSize + 1] = (header); \ (pStrBuf)->commandBufferSize += 2 // 描画APIの指定 // 0x253 [0:0] #define NW_FONT_CMD_SET_DRAW_FUNC( func ) \ PICA_CMD_DATA_DRAW_MODE1( func, 0 /* mode */ ), \ PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DRAW_MODE1, 0x1 ) // 描画モード // 0x253 [8:8] #define NW_FONT_CMD_SET_DRAW_MODE1( mode ) \ PICA_CMD_DATA_DRAW_MODE1( 0 /* func */, mode ), \ PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DRAW_MODE1, 0x2 ) // ロードアレイNの要素 8-11、バイト数、要素数 #define NW_FONT_CMD_DATA_LOAD_ARRAY_ELEMENT8( elm8, elm9, elm10, elm11, bytes, num ) \ ((elm8) & 0x0F) << 0 | ((elm9) & 0x0F) << 4 \ | ((elm10) & 0x0F) << 8 | ((elm11) & 0x0F) << 12 \ | ((bytes) & 0xFF) << 16 | ((num) & 0x0F) << 28 // ロードアレイNのアドレスオフセット、要素、バイト数、要素数 #define NW_FONT_CMD_SET_LOAD_ARRAY( offset, elm0, elm1, elm2, elm3, elm4, elm5, elm6, \ elm7, elm8, elm9, elm10, elm11, bytes, num ) \ (offset) & 0x0FFFFFFF, /* アドレスオフセット */ \ PICA_CMD_DATA_LOAD_ARRAY0_ELEMENT( elm0, elm1, elm2, elm3, elm4, elm5, elm6, elm7 ), \ NW_FONT_CMD_DATA_LOAD_ARRAY_ELEMENT8( elm8, elm9, elm10, elm11, bytes, num ) #define NW_FONT_CMD_SET_LOAD_ARRAY_ZERO() \ NW_FONT_CMD_SET_LOAD_ARRAY( \ 0, /* offset */ \ PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, \ PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, \ PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, \ PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, \ 0, /* bytes */ \ 0) /* num */ #define NW_FONT_CMD_SET_TEXTURE_LOD_DISABLE( addr ) \ PICA_CMD_DATA_TEXTURE_LOD_LEVEL( 0 /* lodBias */, 0 /* maxLodLevel */, 0 /* minLodLevel */ ), \ PICA_CMD_HEADER_SINGLE( addr ) // 頂点インデックスの内部状態のクリア #define NW_FONT_CMD_SET_VERTEX_INDEX_CLEAR() \ /* 0x25f */ \ PICA_CMD_DATA_START_DRAW_FUNC1( true ), \ PICA_CMD_HEADER_SINGLE( PICA_REG_START_DRAW_FUNC1 ) #if defined(NW_PLATFORM_CTR) extern unsigned* __cb_current_command_buffer; #endif namespace nw { namespace font { namespace { #if defined(NW_PLATFORM_CTR) const u8 MATRIX_UNIFORM_NUM = 3; // 行列が使用するユニフォームの数 const u8 COLOR_USE_COUNT = 4; // 文字の色1つ当たりで使用するユニフォームの数 // コンバイナに設定するデータ数 const int TEX_ENV_DATA_NUM = PICA_REG_TEX_ENV0_SCALE - PICA_REG_TEX_ENV0 + 1; // コンバイナに設定するコマンドサイズ(u32単位) const int TEX_ENV_COMMAND_SIZE = math::RoundUp(1 + TEX_ENV_DATA_NUM, 2); const int TEX_ENV_OPERAND_OFFS = PICA_REG_TEX_ENV0_OPERAND - PICA_REG_TEX_ENV0; const int TEX_ENV_COLOR_POS = 1 + ( PICA_REG_TEX_ENV0_COLOR - PICA_REG_TEX_ENV0 ); const u32 TEX_FUNC_DATA = PICA_CMD_DATA_TEXTURE_FUNC( PICA_DATA_TEXTURE0_SAMPLER_TYPE_TEXTURE_2D /* texture0SamplerType */, 0 /* texture1SamplerType */, 0 /* texture2SamplerType */, 0 /* texture3Texcoord */, 0 /* texture3SamplerType */, 0 /* texture2Texcoord */, 1 /* clearTextureCache */); const u32 TEX_ENV_SRC3 = PICA_CMD_DATA_TEX_ENV_SRC( PICA_DATA_TEX_ENV_SRC_RGBA_TEXTURE0, PICA_DATA_TEX_ENV_SRC_RGBA_CONSTANT, PICA_DATA_TEX_ENV_SRC_RGBA_CONSTANT, PICA_DATA_TEX_ENV_SRC_RGBA_TEXTURE0, PICA_DATA_TEX_ENV_SRC_RGBA_CONSTANT, PICA_DATA_TEX_ENV_SRC_RGBA_CONSTANT ); const u32 TEX_ENV_SRC4 = PICA_CMD_DATA_TEX_ENV_SRC( PICA_DATA_TEX_ENV_SRC_RGBA_TEXTURE0, PICA_DATA_TEX_ENV_SRC_RGBA_CONSTANT, PICA_DATA_TEX_ENV_SRC_RGBA_PREVIOUS, PICA_DATA_TEX_ENV_SRC_RGBA_TEXTURE0, PICA_DATA_TEX_ENV_SRC_RGBA_CONSTANT, PICA_DATA_TEX_ENV_SRC_RGBA_PREVIOUS ); const u32 TEX_ENV_OPERAND3 = PICA_CMD_DATA_TEX_ENV_OPERAND( PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_ALPHA_SRC_ALPHA, PICA_DATA_OPE_ALPHA_SRC_ALPHA, PICA_DATA_OPE_ALPHA_SRC_ALPHA ); const u32 TEX_ENV_OPERAND4 = PICA_CMD_DATA_TEX_ENV_OPERAND( PICA_DATA_OPE_RGB_ONE_MINUS_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_ALPHA_ONE_MINUS_SRC_ALPHA,PICA_DATA_OPE_ALPHA_SRC_ALPHA, PICA_DATA_OPE_ALPHA_SRC_ALPHA ); const u32 TEX_ENV_OPERAND3_ALPHA = PICA_CMD_DATA_TEX_ENV_OPERAND( PICA_DATA_OPE_RGB_ONE_MINUS_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_ALPHA_SRC_ALPHA, PICA_DATA_OPE_ALPHA_SRC_ALPHA, PICA_DATA_OPE_ALPHA_SRC_ALPHA ); const u32 TEX_ENV_OPERAND4_ALPHA = PICA_CMD_DATA_TEX_ENV_OPERAND( PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_ALPHA_ONE_MINUS_SRC_ALPHA,PICA_DATA_OPE_ALPHA_SRC_ALPHA, PICA_DATA_OPE_ALPHA_SRC_ALPHA ); const u32 TEX_ENV_COMBINE_MODULATE = PICA_CMD_DATA_TEX_ENV_COMBINE( PICA_DATA_TEX_ENV_COMBINE_MODULATE, PICA_DATA_TEX_ENV_COMBINE_MODULATE ); const u32 TEX_ENV_COMBINE_MULT_ADD = PICA_CMD_DATA_TEX_ENV_COMBINE( PICA_DATA_TEX_ENV_COMBINE_MULT_ADD_DMP, PICA_DATA_TEX_ENV_COMBINE_MULT_ADD_DMP ); const u32 TEX_ENV_CONST_COLOR_WHITE = 0xffffffff; const u32 TEX_ENV_CONST_COLOR_BLACK = 0x00000000; const u32 TEX_ENV_SCALE_1 = PICA_CMD_DATA_TEX_ENV_SCALE( PICA_DATA_TEX_ENV_SCALE_1, PICA_DATA_TEX_ENV_SCALE_1 ); // バーストアクセス時の最大サイズ const u32 BURST_MAX = 0x80; const u32 DRAW_MODE0_DEFAULT = 0; // glDrawElementsで、かつmodeがGL_TRIANGLESの場合、1に設定し、 // それ以外の場合では0に設定 #if defined(NW_FONT_RECTDRAWER_USE_DRAW_ARRAYS) const u32 DRAW_MODE2_DEFAULT = 0; const u32 DRAW_FUNC_DEFAULT = 0; #else const u32 DRAW_MODE0_ELEMENT = 1; const u32 DRAW_MODE2_ELEMENT = PICA_DATA_DRAW_TRIANGLES; #endif struct ShaderBinaryFileHeader { u8 signature[4]; u32 exeCount; u32 exeOffsetTop; }; struct ShaderPackageHeader { u8 signature[4]; u8 version[2]; u16 reserved0; u32 instOffset; // プログラムコード情報オフセット u32 instCount; // プログラムコードデータ数 (*4でバイト数) u32 swizzleOffset; u32 swizzleCount; u32 lineOffset; u32 lineCount; u32 stringOffset; u32 stringSize; }; struct SwizzleInfo { u32 value; u16 usedInfo; u16 reserve; }; // 実行イメージ情報ヘッダー struct ExeImageHeader { u8 signature[4]; u8 version[2]; u8 shaderType; u8 mergeOutputMapsDebug; u32 mainAddr; u32 endAddr; u16 inputMask; u16 outputMask; u8 geometryDataMode; u8 startIndex; u8 subdPatchSize; u8 constVertexNumber; u32 setupOffset; u32 setupCount; u32 labelOffset; u32 labelCount; u32 outmapOffset; u32 outmapCount; u32 bsymOffset; u32 bsymCount; u32 stringOffset; u32 stringSize; }; struct SetupInfo { u16 type; u16 index; u32 value[4]; }; struct OutmapInfo { u16 type; u16 index; u16 mask; u16 reserve; }; enum { SHADEROUTMAPTYPE_POSITION, SHADEROUTMAPTYPE_QUATERNION, SHADEROUTMAPTYPE_COLOR, SHADEROUTMAPTYPE_TEXCOORD0, SHADEROUTMAPTYPE_TEXCOORD0W, SHADEROUTMAPTYPE_TEXCOORD1, SHADEROUTMAPTYPE_TEXCOORD2, SHADEROUTMAPTYPE_VIEW, SHADEROUTMAPTYPE_MAX }; // 0x080 ~ 0x0bf の設定前に一度必要なダミーコマンド。 const u32 TextureDummyCommands[] = { 0, PICA_CMD_HEADER_BURST_BE(PICA_REG_TEXTURE_FUNC, 3, 0x0), 0, 0, }; const u32 TextInitCommands[] = { // 頂点シェーダーへ、テクスチャ座標の数の設定 // 0x2b1 PICA_CMD_DATA_VS_INT( 0x01, 0, 0 ), PICA_CMD_HEADER_SINGLE( PICA_REG_VS_INT0 ), // カラー・デプスバッファのクリア (0x100 ~ 0x130 の設定前に一度必要) // 0x111 PICA_CMD_DATA_COLOR_DEPTH_BUFFER_CLEAR(true), PICA_CMD_HEADER_SINGLE(PICA_REG_COLOR_DEPTH_BUFFER_CLEAR1), // デフォルトのブレンド設定(論理演算を無効) // 0x100, 0x101 NW_FONT_COMMAND_SET_BLEND_DEFAULT, // アルファテストを無効 // 0x104 PICA_CMD_DATA_FRAGOP_ALPHA_TEST_DISABLE(), PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_ALPHA_TEST ), // 最終段のテクスチャコンバイナの設定 PICA_CMD_DATA_TEX_ENV_SRC( PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR, PICA_DATA_TEX_ENV_SRC_RGBA_PREVIOUS, PICA_DATA_TEX_ENV_SRC_RGBA_PREVIOUS, PICA_DATA_TEX_ENV_SRC_RGBA_PRIMARY_COLOR, PICA_DATA_TEX_ENV_SRC_RGBA_PREVIOUS, PICA_DATA_TEX_ENV_SRC_RGBA_PREVIOUS ), PICA_CMD_HEADER_BURSTSEQ( PICA_REG_TEX_ENV5, TEX_ENV_DATA_NUM ), PICA_CMD_DATA_TEX_ENV_OPERAND( PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_RGB_SRC_COLOR, PICA_DATA_OPE_ALPHA_SRC_ALPHA, PICA_DATA_OPE_ALPHA_SRC_ALPHA, PICA_DATA_OPE_ALPHA_SRC_ALPHA ), TEX_ENV_COMBINE_MODULATE, TEX_ENV_CONST_COLOR_BLACK, TEX_ENV_SCALE_1, // シェーダーの出力設定 // テクスチャ座標0のみ出力 // 0x06f PICA_CMD_DATA_VS_GS_OUT_ATTR_CLK( false, // posZ false, // col true, // tex0 false, // tex1 false, // tex2 false, // tex0_w false), // view_quart PICA_CMD_HEADER_SINGLE_BE( PICA_REG_VS_OUT_ATTR_CLK, 0x2 ), // 0x080 ~ 0x0bf の設定前に一度必要なダミーコマンド。 // 0x080 0, PICA_CMD_HEADER_BURST_BE(PICA_REG_TEXTURE_FUNC, 3, 0x0), 0, 0, // テクスチャユニットの設定 // サンプラータイプ、座標選択 // 0x080 TEX_FUNC_DATA, PICA_CMD_HEADER_SINGLE_BE( PICA_REG_TEXTURE_FUNC, 0xB ), }; const u32 TexEnvOperand34Commands[] = { // 1段目のオペランド TEX_ENV_OPERAND3, PICA_CMD_HEADER_SINGLE( PICA_REG_TEX_ENV3 + TEX_ENV_OPERAND_OFFS ), // 2段目のオペランド TEX_ENV_OPERAND4, PICA_CMD_HEADER_SINGLE( PICA_REG_TEX_ENV4 + TEX_ENV_OPERAND_OFFS ), }; const u32 TexEnvOperand34AlphaCommands[] = { // 1段目のオペランド TEX_ENV_OPERAND3_ALPHA, PICA_CMD_HEADER_SINGLE( PICA_REG_TEX_ENV3 + TEX_ENV_OPERAND_OFFS ), // 2段目のオペランド TEX_ENV_OPERAND4_ALPHA, PICA_CMD_HEADER_SINGLE( PICA_REG_TEX_ENV4 + TEX_ENV_OPERAND_OFFS ), }; const u32 TexEnv34Commands[] = { TEX_ENV_SRC3, PICA_CMD_HEADER_BURSTSEQ( PICA_REG_TEX_ENV3, TEX_ENV_DATA_NUM ), TEX_ENV_OPERAND3, TEX_ENV_COMBINE_MODULATE, TEX_ENV_CONST_COLOR_WHITE, TEX_ENV_SCALE_1, TEX_ENV_SRC4, PICA_CMD_HEADER_BURSTSEQ( PICA_REG_TEX_ENV4, TEX_ENV_DATA_NUM ), TEX_ENV_OPERAND4, TEX_ENV_COMBINE_MULT_ADD, TEX_ENV_CONST_COLOR_BLACK, TEX_ENV_SCALE_1, }; const u32 TexEnv34AlphaCommands[] = { TEX_ENV_SRC3, PICA_CMD_HEADER_BURSTSEQ( PICA_REG_TEX_ENV3, TEX_ENV_DATA_NUM ), TEX_ENV_OPERAND3_ALPHA, TEX_ENV_COMBINE_MODULATE, TEX_ENV_CONST_COLOR_WHITE, TEX_ENV_SCALE_1, TEX_ENV_SRC4, PICA_CMD_HEADER_BURSTSEQ( PICA_REG_TEX_ENV4, TEX_ENV_DATA_NUM ), TEX_ENV_OPERAND4_ALPHA, TEX_ENV_COMBINE_MULT_ADD, TEX_ENV_CONST_COLOR_BLACK, TEX_ENV_SCALE_1, }; const u32 s_DrawInitCommands[] = { // 0x111, 0x110 PICA_CMD_SET_COLOR_DEPTH_BUFFER_CLEAR( 1 /* data1 */, 1 /* data2 */ ), // 初期化時に呼ばれる DisableTextures() で発行されるので // ここでは 0x080 x 3 のダミーコマンドは必要ない。 // ... // デフォルトのブレンド設定 // 0x100, 0x101 NW_FONT_COMMAND_SET_BLEND_DEFAULT, // アルファテスト無効化 // 0x104 PICA_CMD_DATA_FRAGOP_ALPHA_TEST_DISABLE(), PICA_CMD_HEADER_SINGLE( PICA_REG_FRAGOP_ALPHA_TEST ), // フォグの無効化 // 0x0e0 [2:0] [3:3] [16:16] [25:24] PICA_CMD_DATA_GAS_FOG_MODE( PICA_DATA_FOG_FALSE, 0 /* dmp_Gas.shadingDensitySrc */, 0 /* dmp_Fog.zFlip */ ), PICA_CMD_HEADER_SINGLE_BE( PICA_REG_GAS_FOG_MODE, 0xd ), // フラグメントライティングの無効化 // 0x08f, 0x1c6 PICA_CMD_SET_FRAG_LIGHT_ENABLE( false ), // Color Buffer Read // 0x112 0x0000000f, PICA_CMD_HEADER_SINGLE( PICA_REG_COLOR_BUFFER_READ ), // テクスチャ LOD 無効化 // 0x084 NW_FONT_CMD_SET_TEXTURE_LOD_DISABLE( PICA_REG_TEXTURE0_LOD ), // 0x094 NW_FONT_CMD_SET_TEXTURE_LOD_DISABLE( PICA_REG_TEXTURE1_LOD ), // 0x09c NW_FONT_CMD_SET_TEXTURE_LOD_DISABLE( PICA_REG_TEXTURE2_LOD ), // シャドウテクスチャ無効化 // 0x08b PICA_CMD_DATA_TEXTURE_SHADOW( false, /* perspectiveShadow */ 0, /* shadowZBias */ 0), /* shadowZScale */ PICA_CMD_HEADER_SINGLE( PICA_REG_TEXTURE0_SHADOW ), #if defined(NW_FONT_RECTDRAWER_USE_DRAW_ARRAYS) // glDrawArrays 用の設定 // 描画モード等に関して、念のためにデフォルトにしておく。 // 頂点開始オフセット(glDrawArraysの場合引数firstの値) // 0x22a PICA_CMD_DATA_DRAW_VERTEX_OFFSET(0), PICA_CMD_HEADER_SINGLE( PICA_REG_DRAW_VERTEX_OFFSET ), // 描画モード // 0x229 [8:8] PICA_CMD_SET_DRAW_MODE0( DRAW_MODE0_DEFAULT ), // 描画APIの指定、描画モード // 0x253 [0:0],[8:8] PICA_CMD_SET_DRAW_MODE1( DRAW_FUNC_DEFAULT, DRAW_MODE0_DEFAULT ), // 描画モード // 0x25e [9:8] PICA_CMD_SET_DRAW_MODE2( DRAW_MODE2_DEFAULT ), // 頂点インデックスの内部状態のクリア // glDrawArrays の GL_TRIANGLES モード時で頂点が3の倍数のときは // 最初の1回だけ呼び出す。 // 0x25f NW_FONT_CMD_SET_VERTEX_INDEX_CLEAR(), #else // glDrawElements GL_TRIANGLES 用の設定 // 描画モード // 0x229 [8:8] PICA_CMD_SET_DRAW_MODE0( DRAW_MODE0_ELEMENT ), // 描画APIの指定、描画モード // 0x253 [0:0],[8:8] PICA_CMD_SET_DRAW_MODE1( DRAW_FUNC_DEFAULT, DRAW_MODE0_ELEMENT ), // 描画モード // 0x25e [9:8] PICA_CMD_SET_DRAW_MODE2( DRAW_MODE2_ELEMENT ), #endif }; const u32 s_DrawFinalizeCommands[] = { // 0x232-0x235 固定頂点属性値 PICA_CMD_SET_VS_FIXED_ATTR( 0x0, /* order */ 0x3f000000, /* c0 */ 0x00000000, /* c1 */ 0x00000000), /* c2 */ #if ! defined(NW_FONT_RECTDRAWER_USE_DRAW_ARRAYS) // 描画モード等に関して、デフォルトに戻しておく。 // 描画モード // 0x229 [8:8] PICA_CMD_SET_DRAW_MODE0( DRAW_MODE0_DEFAULT ), // 描画モード // 0x253 [8:8] NW_FONT_CMD_SET_DRAW_MODE1( DRAW_MODE0_DEFAULT ), // 描画モード // 0x25e [9:8] PICA_CMD_SET_DRAW_MODE2( DRAW_MODE2_DEFAULT ), #endif // 0x111, 0x110 PICA_CMD_SET_COLOR_DEPTH_BUFFER_CLEAR( 1 /* data1 */, 1 /* data2 */ ), }; const u32 DrawCommands[] = { #if !defined(NW_FONT_RECTDRAWER_USE_DRAW_ARRAYS) // 頂点インデックスの内部状態のクリア // glDrawElements の GL_TRIANGLES モード時は必要 // 0x25f NW_FONT_CMD_SET_VERTEX_INDEX_CLEAR(), #endif #if defined(NW_FONT_RECTDRAWER_USE_DRAW_ARRAYS) // 0x253 NW_FONT_CMD_SET_DRAW_FUNC( 1 /* func */ ), PICA_CMD_SET_START_DRAW_ARRAY( 0x00000001 /* start */ ), // 0x253 NW_FONT_CMD_SET_DRAW_FUNC( 0 /* func */ ), #else PICA_CMD_SET_START_DRAW_ELEMENT( 0x00000001 /* start */ ), #endif }; const u32 DRAWBEGIN_STATICCOMMAND_BYTES = 656 + sizeof(s_DrawInitCommands) #if !defined(NW_FONT_RECTDRAWER_USE_DRAW_ARRAYS) + sizeof(u32) * 2 * 1 #endif ; const u32 DRAWEND_STATICCOMMAND_BYTES = 176 + sizeof(s_DrawFinalizeCommands); #endif u32 GetColorU32Raw(ut::Color8 color) { return *reinterpret_cast(&color); } void NormalizeF32Colors( math::VEC4* __restrict dst, const ut::Color8* __restrict src ) { register const f32 d = 1.f / 255.f; register f32 colors[4]; for (int i = 0; i < internal::TEXTCOLOR_MAX; ++i) { colors[0] = src[i].r * d; colors[1] = src[i].g * d; colors[2] = src[i].b * d; colors[3] = src[i].a * d; dst[i].x = colors[0]; dst[i].y = colors[1]; dst[i].z = colors[2]; dst[i].w = colors[3]; } } void SetVertexColor( math::VEC4* __restrict dst, const ut::Color8* __restrict src, int mode ) { math::VEC4 wkCols[internal::TEXTCOLOR_MAX]; NormalizeF32Colors(wkCols, src); dst[VERTEX_LT] = wkCols[internal::TEXTCOLOR_START]; dst[VERTEX_RT] = wkCols[ mode != CharWriter::GRADMODE_H ? internal::TEXTCOLOR_START: internal::TEXTCOLOR_END]; dst[VERTEX_LB] = wkCols[ mode != CharWriter::GRADMODE_V ? internal::TEXTCOLOR_START: internal::TEXTCOLOR_END]; dst[VERTEX_RB] = wkCols[ mode == CharWriter::GRADMODE_NONE ? internal::TEXTCOLOR_START: internal::TEXTCOLOR_END]; } inline bool IsDrawChar( const u8* drawFlags, int index ) { return 0 != ut::internal::ReadBits(drawFlags[index / 8], 1, index % 8); } inline void SetDrawChar( u8* drawFlags, int index ) { drawFlags[index / 8] = ut::internal::WriteBits(drawFlags[index / 8], 1, 1, index % 8); } #if defined(NW_PLATFORM_CTR) const ShaderBinaryFileHeader& GetShaderBinaryFileHeader(const void* shaderBinary) { return *static_cast(shaderBinary); } void EnsureShaderBinaryFileHeader(const void* shaderBinary) { const ShaderBinaryFileHeader& header = *static_cast(shaderBinary); NN_ASSERT( header.signature[0] == 'D' && header.signature[1] == 'V' && header.signature[2] == 'L' && header.signature[3] == 'B' ); } const ShaderPackageHeader& GetShaderPackageHeader(const void* shaderBinary) { const ShaderBinaryFileHeader& fileHead = GetShaderBinaryFileHeader(shaderBinary); return *static_cast( ut::AddOffsetToPtr( shaderBinary, sizeof(fileHead) + (fileHead.exeCount - 1) * sizeof(u32) ) ); } void EnsureShaderPackageHeader(const ShaderPackageHeader& header) { (void)header; NN_ASSERT( header.signature[0] == 'D' && header.signature[1] == 'V' && header.signature[2] == 'L' && header.signature[3] == 'P' ); } const ExeImageHeader* GetExeImageHeader(const void* shaderBinary) { const ShaderBinaryFileHeader& fileHead = GetShaderBinaryFileHeader(shaderBinary); return static_cast( ut::AddOffsetToPtr( shaderBinary, fileHead.exeOffsetTop ) ); } void EnsureExeImageHeader(const ExeImageHeader& header) { (void)header; NN_ASSERT( header.signature[0] == 'D' && header.signature[1] == 'V' && header.signature[2] == 'L' && header.signature[3] == 'E' ); } u32 CalcInstCommandCount(u32 count) { u32 size = (count / BURST_MAX) * math::RoundUp(2 + 1 + BURST_MAX, 2); if (0 != count % BURST_MAX) { size += math::RoundUp(2 + 1 + (count % BURST_MAX), 2); } return size; } u32 CalcDrawBeginCommandBytes(const ShaderPackageHeader& header) { const u32 instBytes = sizeof(u32) * ( CalcInstCommandCount(header.instCount) + CalcInstCommandCount(header.swizzleCount) ); // NN_LOG("inst swizzle bytes %d\n", instBytes); return DRAWBEGIN_STATICCOMMAND_BYTES + instBytes; } // 頂点属性配列のコマンドを追加 void AddVertexAttributeArrayCommand( ut::internal::CmdCache& cmdCache, u32 vboBaseAddr, uptr phyArrayBuffer, u32 vtxAttrNum ) { const u32 fixedVtxAttrMask = 0; const u32 loadAryBytes = 16; // ロードアレイの1頂点辺りのバイト数 const u32 loadAryElementNum = 1; const u32 command200[] = { // 0x200 ベースアドレス PICA_CMD_DATA_VERTEX_ATTR_ARRAYS_BASE_ADDR( vboBaseAddr ), PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VTX_ATTR_ARRAYS_BASE_ADDR, (0x202 - 0x200 + 1) + (0x205 - 0x203 + 1) * 12 ), // 0x201 内部頂点属性0-7の型 PICA_CMD_DATA_VERTEX_ATTR_ARRAYS( PICA_DATA_SIZE_4_FLOAT, PICA_DATA_SIZE_1_BYTE, PICA_DATA_SIZE_1_BYTE, PICA_DATA_SIZE_1_BYTE, PICA_DATA_SIZE_1_BYTE, PICA_DATA_SIZE_1_BYTE, PICA_DATA_SIZE_1_BYTE, PICA_DATA_SIZE_1_BYTE), // 0x202 内部頂点属性8-11の型、固定頂点属性マスク、頂点属性数 PICA_DATA_SIZE_1_BYTE << 0 | PICA_DATA_SIZE_1_BYTE << 4 | PICA_DATA_SIZE_1_BYTE << 8 | PICA_DATA_SIZE_1_BYTE << 12 | fixedVtxAttrMask << 16 | (vtxAttrNum - 1) << 28, // 0x203-0x205 ロードアレイ0アドレスオフセット、1-12の要素、バイト数、要素数 NW_FONT_CMD_SET_LOAD_ARRAY( phyArrayBuffer - vboBaseAddr, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, PICA_DATA_VERTEX_0_ATTR, loadAryBytes, loadAryElementNum), }; cmdCache.Add(command200, sizeof(command200)); static const u32 command206[] = { // 0x206-0x226 ロードアレイ1-11 NW_FONT_CMD_SET_LOAD_ARRAY_ZERO(), // ロードアレイ1 NW_FONT_CMD_SET_LOAD_ARRAY_ZERO(), // ロードアレイ2 NW_FONT_CMD_SET_LOAD_ARRAY_ZERO(), // ロードアレイ3 NW_FONT_CMD_SET_LOAD_ARRAY_ZERO(), // ロードアレイ4 NW_FONT_CMD_SET_LOAD_ARRAY_ZERO(), // ロードアレイ5 NW_FONT_CMD_SET_LOAD_ARRAY_ZERO(), // ロードアレイ6 NW_FONT_CMD_SET_LOAD_ARRAY_ZERO(), // ロードアレイ7 NW_FONT_CMD_SET_LOAD_ARRAY_ZERO(), // ロードアレイ8 NW_FONT_CMD_SET_LOAD_ARRAY_ZERO(), // ロードアレイ9 NW_FONT_CMD_SET_LOAD_ARRAY_ZERO(), // ロードアレイ10 NW_FONT_CMD_SET_LOAD_ARRAY_ZERO(), // ロードアレイ11 // 0x2bb 頂点属性の入力レジスタマップ設定レジスタ 1-8 PICA_CMD_DATA_VS_ATTR_IN_REG_MAP0( 0, 0, 0, 0, 0, 0, 0, 0 ), PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP0 ), // 0x2bc 頂点属性の入力レジスタマップ設定レジスタ 9-12 PICA_CMD_DATA_VS_ATTR_IN_REG_MAP1( 0, 0, 0, 0 ), PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_IN_REG_MAP1 ), }; cmdCache.Add(command206, sizeof(command206)); } #endif // #if defined(NW_PLATFORM_CTR) } // namespace bool RectDrawer::s_StaticInitialized = false; RectDrawer::VertexBuffer RectDrawer::s_VertexBuffer; void* RectDrawer::GetVertexBufferData() { if (! s_StaticInitialized) { InitializeStatic(); s_StaticInitialized = true; } return &s_VertexBuffer; } u32 RectDrawer::GetCommandBufferSize( const void* shaderBinary, u32 /* size */ ) { #if defined(NW_PLATFORM_CTR) const ShaderPackageHeader& header = GetShaderPackageHeader(shaderBinary); return CalcDrawBeginCommandBytes(header) + DRAWEND_STATICCOMMAND_BYTES; #else NN_ASSERT(false); return 0; #endif } u32 RectDrawer::GetVertexBufferCommandBufferSize( const void* shaderBinary, u32 size ) { return GetVertexBufferSize() + GetCommandBufferSize(shaderBinary, size); } RectDrawer::RectDrawer() : m_UniformAddrIndex(0), m_UniformMtxIndex(0), m_UniformDataIndex(0), m_UniformTextColorIndex(0), m_UniformAddr(reinterpret_cast(&m_UniformAddrBuffer[3])), m_UniformMtx(reinterpret_cast(&m_UniformMtxBuffer[3])), m_UniformData(reinterpret_cast(&m_UniformDataBuffer[3])), m_UniformTextColor(reinterpret_cast(&m_UniformTextColorBuffer[3])), m_CommandBuffer(NULL), m_VertexBufferArray(NULL), #if defined(NW_FONT_RECTDRAWER_USE_DRAW_ARRAYS) m_VertexBufferBaseAddr(0), #endif m_IsColorDirty(false) { } RectDrawer::~RectDrawer() { this->Finalize(); } void RectDrawer::Initialize( void* vtxBufCmdBuf, const void* shaderBinary, u32 size ) { const u32 cmdBufSize = GetCommandBufferSize(shaderBinary, size); void *const vertexBuffer = ut::AddOffsetToPtr(vtxBufCmdBuf, cmdBufSize); InitializeCMD(vertexBuffer, vtxBufCmdBuf, shaderBinary, size, true); } void RectDrawer::Initialize( void* vertexBuffer, void* commandBuffer, const void* shaderBinary, u32 size ) { InitializeCMD(vertexBuffer, commandBuffer, shaderBinary, size, false); } void RectDrawer::Finalize() { m_CommandBuffer = NULL; m_VertexBufferArray = NULL; } void RectDrawer::DrawBegin(u32 flag) { NN_ASSERT( m_UniformAddrIndex == 0 && m_UniformDataIndex == 0 && m_UniformMtxIndex == 0 && m_UniformTextColorIndex == 0 ); if (0 == (flag & DONT_USE_SETUP_COMMAND)) { UseBeginCommand(); } } void RectDrawer::DrawEnd(u32 flag) { if (0 == (flag & DONT_USE_SETUP_COMMAND)) { UseEndCommand(); } } void RectDrawer::SetProjectionMtx(const nn::math::MTX44& mtx) { #if defined(NW_PLATFORM_CTR) nn::math::MTX44 *const pDst = reinterpret_cast(&m_UniformProjBuffer[3]); nn::math::MTX44Copy(pDst, &mtx); const u32 size = SetUniformCommand(m_UniformProjBuffer, UNIFORM_PROJ_NUM + 1); NW_FONT_RECTDRAWER_ADD_COMMAND(m_UniformProjBuffer, size); #else NN_ASSERT(false); #endif } void RectDrawer::SetViewMtxForText(const nn::math::MTX34& mtx) { #if defined(NW_PLATFORM_CTR) nn::math::MTX34 *const pDst = reinterpret_cast(&m_UniformMtxBuffer[3]); nn::math::MTX34Copy(pDst, &mtx); m_UniformMtxIndex = sizeof(mtx) / sizeof(nn::math::VEC4); const u32 size = SetUniformCommand(m_UniformMtxBuffer, m_UniformMtxIndex); NW_FONT_RECTDRAWER_ADD_COMMAND(m_UniformMtxBuffer, size); m_UniformMtxIndex = 0; #else NN_ASSERT(false); #endif } void RectDrawer::UseBeginCommand() { DisableTextures(); m_CmdCacheDrawBegin.Use(); } void RectDrawer::UseEndCommand() { m_CmdCacheDrawEnd.Use(); } void RectDrawer::DisableTextures() { #if defined(NW_PLATFORM_CTR) // 0x06f NW_FONT_RECTDRAWER_ADD_SINGLE_COMMAND( PICA_CMD_HEADER_SINGLE_BE( PICA_REG_VS_OUT_ATTR_CLK, 0x2 ), 0 ); NW_FONT_RECTDRAWER_ADD_COMMAND(TextureDummyCommands, sizeof(TextureDummyCommands)); // 0x080 // サンプラータイプ、座標選択 NW_FONT_RECTDRAWER_ADD_SINGLE_COMMAND( PICA_CMD_HEADER_SINGLE_BE( PICA_REG_TEXTURE_FUNC, 0xB ), PICA_CMD_DATA_TEXTURE_FUNC( PICA_DATA_TEXTURE0_SAMPLER_TYPE_TEXTURE_FALSE /* texture0SamplerType */, 0 /* texture1SamplerType */, 0 /* texture2SamplerType */, 0 /* texture3Texcoord */, 0 /* texture3SamplerType */, 0 /* texture2Texcoord */, 0 /* clearTextureCache */)); #else NN_ASSERT(false); #endif } void RectDrawer::AddUniformMtx() { #if defined(NW_PLATFORM_CTR) const u32 size = SetUniformCommand(m_UniformMtxBuffer, m_UniformMtxIndex); NW_FONT_RECTDRAWER_ADD_COMMAND(m_UniformMtxBuffer, size); #else NN_ASSERT(false); #endif m_UniformMtxIndex = 0; } void RectDrawer::SetParallax( f32 parallax, f32 dLevel, f32 addDist ) { #if defined(NW_PLATFORM_CTR) nn::math::VEC4 *const pParallaxData = reinterpret_cast(&m_UniformProjBuffer[3 + 4 * 4]); pParallaxData->Set(parallax, dLevel, addDist, 0.0f); #else NN_ASSERT(false); #endif } void RectDrawer::InitializeStatic() { static const int vtx[DRAW_VTX_NUM] = { VERTEX_RT, VERTEX_LT, VERTEX_RB, VERTEX_RB, VERTEX_LT, VERTEX_LB, }; #if defined(NW_PLATFORM_CTR) #if defined(NW_FONT_RECTDRAWER_USE_DRAW_ARRAYS) for (int addr = 0; addr < UNIFORM_ADDR_NUM; ++addr) { for (int vi = 0; vi < DRAW_VTX_NUM; ++vi) { s_VertexBuffer.position[addr][vi][0] = addr; s_VertexBuffer.position[addr][vi][1] = vtx[vi]; s_VertexBuffer.position[addr][vi][2] = vtx[vi] % 2 ? 1.f : 0.f; // 右左 s_VertexBuffer.position[addr][vi][3] = vtx[vi] / 2 ? -1.f : 0.f; // 下上 } } #else for (int addr = 0; addr < UNIFORM_ADDR_NUM; ++addr) { for (int vi = 0; vi < DRAW_VTX_NUM; ++vi) { s_VertexBuffer.indexes[addr][vi] = addr * VERTEX_MAX + vtx[vi]; } } for (int addr = 0; addr < UNIFORM_ADDR_NUM; ++addr) { for (int vi = 0; vi < VERTEX_MAX; ++vi) { s_VertexBuffer.position[addr][vi][0] = addr; s_VertexBuffer.position[addr][vi][1] = vi; s_VertexBuffer.position[addr][vi][2] = vi % 2 ? 1.f : 0.f; // 右左 s_VertexBuffer.position[addr][vi][3] = vi / 2 ? -1.f : 0.f; // 下上 } } #endif #else NN_ASSERT(false); #endif } void RectDrawer::InitializeCMD( void* vertexBuffer, void* commandBuffer, const void* shaderBinary, u32 /* size */, bool initVertexBuffer ) { NN_NULL_ASSERT(vertexBuffer); #if defined(NW_PLATFORM_CTR) EnsureShaderBinaryFileHeader(shaderBinary); const ShaderBinaryFileHeader& fileHead = GetShaderBinaryFileHeader(shaderBinary); NN_ASSERT(fileHead.exeCount == 1); // 実行イメージが1つのときのみ対応 const ShaderPackageHeader& pkgHead = GetShaderPackageHeader(shaderBinary); EnsureShaderPackageHeader(pkgHead); const ExeImageHeader& exeHead = GetExeImageHeader(shaderBinary)[0]; EnsureExeImageHeader(exeHead); NN_ASSERT(exeHead.shaderType == 0); // 頂点シェーダのみ対応 m_VertexBufferArray = vertexBuffer; if (initVertexBuffer) { std::memcpy(vertexBuffer, GetVertexBufferData(), GetVertexBufferSize()); nngxUpdateBuffer(vertexBuffer, GetVertexBufferSize()); } m_CommandBuffer = commandBuffer; const u32 DrawBeginCommandBytes = CalcDrawBeginCommandBytes(pkgHead); m_CmdCacheDrawBegin.Init(m_CommandBuffer, DrawBeginCommandBytes); m_CmdCacheDrawEnd.Init( ut::AddOffsetToPtr(m_CommandBuffer, DrawBeginCommandBytes), DRAWEND_STATICCOMMAND_BYTES); const u32 vtxAttrNum = 1; // 頂点属性数 // ジオメトリシェーダを使用するかどうか const bool useGeometryShader = false; // 予約ジオメトリシェーダのサブディビジョンを使用するかどうか const bool useGeometryShaderSubdivision = false; // DrawBegin() のコマンドキャッシュ生成 { static const u32 commands[] = { PICA_CMD_SET_DRAW_MODE0_DUMMY_BEGIN(), // 0x229 [1:0] ジオメトリシェーダを使用しない PICA_CMD_DATA_DRAW_MODE0( useGeometryShader, 0 /* drawMode */, false), /* useGeometryShaderSubdivision */ PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DRAW_MODE0, 0x1 ), // 0x200 PICA_CMD_SET_DRAW_MODE0_DUMMY_END(), // 0x244 [0:0] 共用プロセッサへのコピー PICA_CMD_SET_VS_COM_MODE( useGeometryShader ), }; m_CmdCacheDrawBegin.Add(commands, sizeof(commands)); } { // 頂点シェーダプログラムコード const u32* progCodes = static_cast(ut::AddOffsetToPtr(&pkgHead, pkgHead.instOffset)); for (u32 totalCnt = 0; totalCnt < pkgHead.instCount; ) { const u32 writeCnt = math::Min(BURST_MAX, pkgHead.instCount - totalCnt); const u32 commands[] = { // 0x2cb プログラムコードのロードアドレス PICA_CMD_DATA_VS_PROG_ADDR( totalCnt ), PICA_CMD_HEADER_SINGLE( PICA_REG_VS_PROG_ADDR ), // 0x2cc プログラムコードのデータ progCodes[totalCnt + 0], PICA_CMD_HEADER_BURST( PICA_REG_VS_PROG_DATA0, writeCnt ), }; m_CmdCacheDrawBegin.Add(commands, sizeof(commands)); m_CmdCacheDrawBegin.Add(&progCodes[totalCnt + 1], sizeof(u32) * (writeCnt - 1)); m_CmdCacheDrawBegin.RoundUp(8); totalCnt += writeCnt; } { static const u32 commands[] = { // 0x2bf プログラム更新完了の通知 PICA_CMD_DATA_VS_PROG_END( 1 ), PICA_CMD_HEADER_SINGLE( PICA_REG_VS_PROG_RENEWAL_END ), }; m_CmdCacheDrawBegin.Add(commands, sizeof(commands)); } } { // 頂点シェーダSwizzleパターン const SwizzleInfo *const swDatas = static_cast(ut::AddOffsetToPtr(&pkgHead, pkgHead.swizzleOffset)); for (u32 totalCnt = 0; totalCnt < pkgHead.swizzleCount; ) { const u32 writeCnt = math::Min(BURST_MAX, pkgHead.swizzleCount - totalCnt); const u32 commands[] = { // 0x2d5 Swizzleパターンのロードアドレス PICA_CMD_DATA_VS_PROG_SWIZZLE_ADDR( totalCnt ), PICA_CMD_HEADER_SINGLE( PICA_REG_VS_PROG_SWIZZLE_ADDR ), // 0x2d6 Swizzleパターンデータ swDatas[totalCnt + 0].value, PICA_CMD_HEADER_BURST( PICA_REG_VS_PROG_SWIZZLE_DATA0, writeCnt ), }; m_CmdCacheDrawBegin.Add(commands, sizeof(commands)); for (int i = 1; i < writeCnt; ++i) { m_CmdCacheDrawBegin.Add(&swDatas[totalCnt + i].value, sizeof(u32)); } m_CmdCacheDrawBegin.RoundUp(8); totalCnt += writeCnt; } } { // 浮動小数点定数レジスタ const SetupInfo* setupInfos = static_cast( ut::AddOffsetToPtr( &exeHead, exeHead.setupOffset ) ); for (int i = 0; i < exeHead.setupCount; ++i) { const SetupInfo& setupInfo = setupInfos[i]; // 浮動小数点の場合のみ実装 NN_ASSERT(setupInfo.type == 2); const int dataNum = 3; // 24bit * 4成分 const int writeCount = 1 + dataNum; // 書き込み数(アドレスとデータ分) const u32 commands[] = { // 0x2c0 PICA_CMD_DATA_VS_FLOAT_ADDR( PICA_DATA_VS_F24, setupInfo.index ), PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VS_FLOAT_ADDR, writeCount ), setupInfo.value[3] << 8 | ((setupInfo.value[2] >> 16) & 0x0000FF), setupInfo.value[2] << 16 | ((setupInfo.value[1] >> 8) & 0x00FFFF), setupInfo.value[1] << 24 | ((setupInfo.value[0] >> 0) & 0xFFFFFF), 0, // アライメント調整 }; m_CmdCacheDrawBegin.Add(commands, sizeof(commands)); } } const uptr phyArrayBuffer = nngxGetPhysicalAddr(reinterpret_cast(m_VertexBufferArray)); // 頂点配列のベースアドレス // 全ての頂点アレイとインデックスアレイのアドレスよりも小さい16バイトアラインの値を設定します。 const u32 vboBaseAddr = math::RoundDown(phyArrayBuffer, 16); AddVertexAttributeArrayCommand(m_CmdCacheDrawBegin, vboBaseAddr, phyArrayBuffer, vtxAttrNum); { const u32 commands[] = { // 0x229 [31:31] PICA_CMD_DATA_DRAW_MODE0( false, /* useGeometryShader */ 0, /* drawMode */ useGeometryShaderSubdivision), PICA_CMD_HEADER_SINGLE_BE( PICA_REG_DRAW_MODE0, 0x8 ), // 0x2b9 頂点シェーダに入力する頂点属性数 PICA_CMD_DATA_VS_ATTR_NUM0( vtxAttrNum ), PICA_CMD_HEADER_SINGLE_BE( PICA_REG_VS_ATTR_NUM0, 0xb ), // 0x2ba 頂点シェーダ開始アドレス PICA_CMD_DATA_VS_START_ADDR( exeHead.mainAddr ), PICA_CMD_HEADER_SINGLE( PICA_REG_VS_START_ADDR ), }; m_CmdCacheDrawBegin.Add(commands, sizeof(commands)); } { const u32 OutRegNum = 7; const int CompNum = 4; static const u8 outAttrs[SHADEROUTMAPTYPE_MAX] = { PICA_DATA_VS_OUT_ATTR_X, PICA_DATA_VS_OUT_ATTR_QUART_X, PICA_DATA_VS_OUT_ATTR_R, PICA_DATA_VS_OUT_ATTR_TEX0_U, PICA_DATA_VS_OUT_ATTR_TEX0_W, PICA_DATA_VS_OUT_ATTR_TEX1_U, PICA_DATA_VS_OUT_ATTR_TEX2_U, PICA_DATA_VS_OUT_ATTR_VIEW_X }; u8 outmaps[OutRegNum][CompNum]; bool useRegs[OutRegNum]; u8 useOutRegTypes[SHADEROUTMAPTYPE_MAX]; for (u32 i = 0; i < SHADEROUTMAPTYPE_MAX; ++i) { useOutRegTypes[i] = 0; } for (u32 j = 0; j < OutRegNum; ++j) { useRegs[j] = false; for (int i = 0; i < CompNum; ++i) { outmaps[j][i] = PICA_DATA_VS_OUT_ATTR_INVALID; } } const OutmapInfo *const outmapInfos = static_cast( ut::AddOffsetToPtr( &exeHead, exeHead.outmapOffset ) ); for (int j = 0; j < math::Min(exeHead.outmapCount, OutRegNum); ++j) { if (outmapInfos[j].type == 9) // generic { continue; } useRegs[outmapInfos[j].index] = true; u8* outmap = outmaps[outmapInfos[j].index]; useOutRegTypes[outmapInfos[j].type] = static_cast(outmapInfos[j].mask); u8 ci = outAttrs[outmapInfos[j].type]; for (int i = 0; i < CompNum; ++i) { if (0 != (outmapInfos[j].mask & (1 << i))) { outmap[i] = ci; ++ci; } } } int outRegUseNum = 0; for (int j = 0; j < OutRegNum; ++j) { if (useRegs[j]) { ++outRegUseNum; } } { const u32 commands[] = { // 0x2bd 頂点シェーダ出力レジスタのマスク PICA_CMD_DATA_VS_OUT_MASK( exeHead.outputMask ), PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_REG_MASK ), // 0x251 頂点シェーダ出力レジスタ使用数 outRegUseNum - 1, PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_REG_NUM2 ), // 0x252 ジオメトリシェーダのモード PICA_CMD_DATA_GS_MISC_REG0( PICA_DATA_GS_OTHER_MODE ), PICA_CMD_HEADER_SINGLE( PICA_REG_GS_MISC_REG0 ), // 0x242 頂点シェーダに入力する頂点属性数 PICA_CMD_DATA_VS_ATTR_NUM1( vtxAttrNum ), PICA_CMD_HEADER_SINGLE( PICA_REG_VS_ATTR_NUM1 ), // 0x24a, 0x25e[3:0], 0x04f 頂点シェーダ出力レジスタ使用数 outRegUseNum - 1, PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_REG_NUM1 ), PICA_CMD_DATA_VS_GS_OUT_REG_NUM3( outRegUseNum, 0 /* mode */ ), PICA_CMD_HEADER_SINGLE_BE( PICA_REG_VS_OUT_REG_NUM3, 0x1 ), outRegUseNum, PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_REG_NUM0 ), }; m_CmdCacheDrawBegin.Add(commands, sizeof(commands)); } // 0x050-0x056 頂点シェーダ出力属性 { const u32 commands[] = { *reinterpret_cast(outmaps[0]), PICA_CMD_HEADER_BURSTSEQ( PICA_REG_VS_OUT_ATTR0, OutRegNum ), }; m_CmdCacheDrawBegin.Add(commands, sizeof(commands)); m_CmdCacheDrawBegin.Add(reinterpret_cast(outmaps[1]), sizeof(u32) * (OutRegNum - 1)); } { bool usePosZ = false; { int outCompNum = 0; for (int i = 0; i < 4; ++i) { if (useOutRegTypes[SHADEROUTMAPTYPE_POSITION] & (1 << i)) { ++outCompNum; } } usePosZ = outCompNum >= 3; } const bool useViewQuaternion = 0 != useOutRegTypes[SHADEROUTMAPTYPE_VIEW] || 0 != useOutRegTypes[SHADEROUTMAPTYPE_QUATERNION]; const u32 outAttrClk = PICA_CMD_DATA_VS_GS_OUT_ATTR_CLK( usePosZ, /* posZ */ 0 != useOutRegTypes[SHADEROUTMAPTYPE_COLOR], /* col */ 0 != useOutRegTypes[SHADEROUTMAPTYPE_TEXCOORD0], /* tex0 */ 0 != useOutRegTypes[SHADEROUTMAPTYPE_TEXCOORD1], /* tex1 */ 0 != useOutRegTypes[SHADEROUTMAPTYPE_TEXCOORD2], /* tex2 */ 0 != useOutRegTypes[SHADEROUTMAPTYPE_TEXCOORD0W], /* tex0_w */ useViewQuaternion); /* view_quart*/ const u32 TexEnableBits = PICA_CMD_DATA_VS_GS_OUT_ATTR_CLK( false, /* posZ */ false, /* col */ true, /* tex0 */ true, /* tex1 */ true, /* tex2 */ true, /* tex0_w */ false); /* view_quart*/ const bool useTexCoords = 0 != (outAttrClk & TexEnableBits); const u32 outAttrMode = useTexCoords ? 1 : 0; const u32 commands[] = { // 0x064 頂点シェーダからテクスチャ座標が出力される場合1 PICA_CMD_DATA_VS_GS_OUT_ATTR_MODE( outAttrMode ), PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_ATTR_MODE ), // 0x06f 頂点シェーダからの出力属性のクロック制御 outAttrClk, PICA_CMD_HEADER_SINGLE( PICA_REG_VS_OUT_ATTR_CLK ), }; m_CmdCacheDrawBegin.Add(commands, sizeof(commands)); } } m_CmdCacheDrawBegin.Add(s_DrawInitCommands, sizeof(s_DrawInitCommands)); #if defined(NW_FONT_RECTDRAWER_USE_DRAW_ARRAYS) m_VertexBufferBaseAddr = vboBaseAddr; #else { void *const eleArrayBuf = ut::AddOffsetToPtr(m_VertexBufferArray, sizeof(s_VertexBuffer.position)); const uptr phyEleArrayBuf = nngxGetPhysicalAddr(reinterpret_cast(eleArrayBuf)); const u32 indexOffset = phyEleArrayBuf - vboBaseAddr; const u32 commands[] = { // 0x227 PICA_CMD_DATA_INDEX_ARRAY_ADDR_OFFSET( indexOffset, 1), /* type */ PICA_CMD_HEADER_SINGLE( PICA_REG_INDEX_ARRAY_ADDR_OFFSET ), }; m_CmdCacheDrawBegin.Add(commands, sizeof(commands) ); } #endif // m_CmdCacheDrawBegin.Dump(); // DrawEnd() のコマンドキャッシュ生成 AddVertexAttributeArrayCommand(m_CmdCacheDrawEnd, vboBaseAddr, phyArrayBuffer, vtxAttrNum); m_CmdCacheDrawEnd.Add(s_DrawFinalizeCommands, sizeof(s_DrawFinalizeCommands)); // m_CmdCacheDrawEnd.Dump(); { // Uniform コマンドの初期化 // プロジェクション行列用コマンドの初期化 InitUniformBuffer(m_UniformProjBuffer, UNIFORM_PROJ_START); // 視差情報用コマンドの初期化 SetParallax(0.0f, 0.0f, 0.0f); // アドレスを詰めていくバッファの初期化 InitUniformBuffer(m_UniformAddrBuffer, UNIFORM_ADDR_START); // 行列、頂点カラー詰めていくバッファの初期化 InitUniformBuffer(m_UniformMtxBuffer, UNIFORM_MTX_START); // テクスチャ座標、を矩形情報を詰めていくバッファの初期化 InitUniformBuffer(m_UniformDataBuffer, UNIFORM_DATA_START); } #else NN_ASSERT(false); #endif } void RectDrawer::InitUniformBuffer( u32* __restrict buf, u32 addr ) { #if defined(NW_PLATFORM_CTR) const u32 data = PICA_CMD_DATA_VS_FLOAT_ADDR( PICA_DATA_VS_F32, addr ); // 0x2c0 buf[0] = data; buf[1] = PICA_CMD_HEADER_SINGLE( PICA_REG_VS_FLOAT_ADDR ); #endif } void RectDrawer::BuildTextCommand(CharWriter* pCharWriter) { #if defined(NW_PLATFORM_CTR) NN_ASSERT( m_UniformAddrIndex == 0 && m_UniformDataIndex == 0 && m_UniformMtxIndex == 0 && m_UniformTextColorIndex == 0 ); DispStringBuffer* __restrict pStringBuffer = pCharWriter->GetDispStringBuffer(); pStringBuffer->commandBufferSize = 0; pStringBuffer->textColorCommandOffset = 0; pStringBuffer->generatedCommand = true; // コマンドを生成済みにします。 const u16 charCount = math::Min(pStringBuffer->charCount, pStringBuffer->GetDrawCharCount()); // 描画する文字数が0のときは抜けます。 if (charCount == 0) { return; } m_UniformAddress.addrMtx = 0; m_IsColorDirty = false; // テキストカラーを詰めていくバッファの初期化 InitUniformBuffer(m_UniformTextColorBuffer, UNIFORM_TEXTCOLOR_START); NW_FONT_ADD_COMMANDS(pStringBuffer, TextInitCommands, sizeof(TextInitCommands)); // 頂点カラーの設定 ut::Color8 vtxColors[internal::TEXTCOLOR_MAX] = { pCharWriter->GetGradationStartColor(), pCharWriter->GetGradationEndColor(), }; AddTextColor( &m_UniformTextColor[m_UniformTextColorIndex], vtxColors, pCharWriter->GetGradationMode()); // 描画したかどうかをあらわすフラグ u8 *const drawFlags = pStringBuffer->drawFlags; for (int i = math::RoundUp(charCount, 8) / 8; i > 0; --i) { drawFlags[i - 1] = 0; /* * std::memset(drawFlags, 0, charCount); * よりも、ループの方が速かった */ } u32 addr = 0; u32 size = 0; u32 format = 0xFFFFFFFF; u32 texFilter = 0xFFFFFFFF; u32 startCharIndex = 0; internal::CharAttribute* __restrict charAttrs = pStringBuffer->GetCharAttrs(); for (u32 drawCharCount = 0; drawCharCount < charCount; ) { u32 i = startCharIndex; for ( ; IsDrawChar(drawFlags, i); ++i) { ; } startCharIndex = i + 1; // 次の探索開始位置 u32 cmdTexAddr = charAttrs[i].pTexObj->GetImage(); if (addr != cmdTexAddr) { addr = cmdTexAddr; // テクスチャを切り替えるので、バッファを書き出す if (drawCharCount > 0 && m_UniformAddrIndex > 0) { UniformAndDrawText(pStringBuffer); } if (format != charAttrs[i].pTexObj->GetFormat()) { const u32 newFormat = charAttrs[i].pTexObj->GetFormat(); const bool isNewAlpha = newFormat == FONT_SHEET_FORMAT_A4 || newFormat == FONT_SHEET_FORMAT_A8; const u32* commands = NULL; u32 commandSize = 0; if (format == 0xFFFFFFFF) // 最初のとき { // テクスチャコンバイナ3、4段の設定を全て積む // // 下記の設定のカラーの値は発行直前(UseCommandBuffer())に // 上書きされるので、コマンドリスト上の位置が変化しない // ように注意すること。 // if (isNewAlpha) { commands = TexEnv34AlphaCommands; commandSize = sizeof(TexEnv34AlphaCommands); } else { commands = TexEnv34Commands; commandSize = sizeof(TexEnv34Commands); } NW_FONT_ADD_COMMANDS(pStringBuffer, commands, commandSize); } else { // テクスチャコンバイナの変更分だけを積む const bool isCrntAlpha = format == FONT_SHEET_FORMAT_A4 || format == FONT_SHEET_FORMAT_A8; if (isCrntAlpha != isNewAlpha) { if (isNewAlpha) { commands = TexEnvOperand34AlphaCommands; commandSize = sizeof(TexEnvOperand34AlphaCommands); } else { commands = TexEnvOperand34Commands; commandSize = sizeof(TexEnvOperand34Commands); } NW_FONT_ADD_COMMANDS(pStringBuffer, commands, commandSize); } NW_FONT_ADD_COMMANDS(pStringBuffer, TextureDummyCommands, sizeof(TextureDummyCommands)); } format = newFormat; // 0x08e NW_FONT_ADD_SINGLE_COMMAND( pStringBuffer, PICA_CMD_HEADER_SINGLE(PICA_REG_TEXTURE0_FORMAT), format); } else { NW_FONT_ADD_COMMANDS(pStringBuffer, TextureDummyCommands, sizeof(TextureDummyCommands)); } // テクスチャキャッシュのクリア // 0x080 NW_FONT_ADD_SINGLE_COMMAND( pStringBuffer, PICA_CMD_HEADER_SINGLE_BE(PICA_REG_TEXTURE_FUNC, 0x4), TEX_FUNC_DATA); // テクスチャアドレス // 0x085 NW_FONT_ADD_SINGLE_COMMAND( pStringBuffer, PICA_CMD_HEADER_SINGLE(PICA_REG_TEXTURE0_ADDR1), addr); // テクスチャサイズ if (size != charAttrs[i].pTexObj->GetSize().size) { size = charAttrs[i].pTexObj->GetSize().size; // 0x082 NW_FONT_ADD_SINGLE_COMMAND( pStringBuffer, PICA_CMD_HEADER_SINGLE(PICA_REG_TEXTURE0_SIZE), size); } const u32 crntTexFilter = charAttrs[i].pTexObj->GetWrapFilter(); if (texFilter != crntTexFilter) { texFilter = crntTexFilter; // 0x083 NW_FONT_ADD_SINGLE_COMMAND( pStringBuffer, PICA_CMD_HEADER_SINGLE(PICA_REG_TEXTURE0_WRAP_FILTER), texFilter); } } for ( ; i < charCount; ++i) { if (IsDrawChar(drawFlags, i) || addr != charAttrs[i].pTexObj->GetImage()) { continue; } const internal::CharAttribute& charAttr= pStringBuffer->GetCharAttrs()[i]; if ( vtxColors[internal::TEXTCOLOR_START] != charAttr.color[internal::TEXTCOLOR_START] || vtxColors[internal::TEXTCOLOR_END ] != charAttr.color[internal::TEXTCOLOR_END ] ) { // 頂点カラーの設定 vtxColors[internal::TEXTCOLOR_START] = charAttr.color[internal::TEXTCOLOR_START]; vtxColors[internal::TEXTCOLOR_END ] = charAttr.color[internal::TEXTCOLOR_END ]; AddTextColor( &m_UniformTextColor[m_UniformTextColorIndex], vtxColors, pCharWriter->GetGradationMode()); } { // テクスチャ座標の設定 m_UniformAddress.addrTexCoord = m_UniformDataIndex; math::VEC4* __restrict pTexCoord = &m_UniformData[m_UniformDataIndex]; *pTexCoord = charAttr.tex; ++m_UniformDataIndex; } { // 矩形の設定 m_UniformAddress.addrSizeAndVtx = m_UniformDataIndex; math::VEC4* __restrict pQuadInfo = &m_UniformData[m_UniformDataIndex]; *pQuadInfo = charAttr.pos; ++m_UniformDataIndex; } SetDrawChar(drawFlags, i); ++drawCharCount; m_UniformAddr[m_UniformAddrIndex] = m_UniformAddress; ++m_UniformAddrIndex; #ifdef NW_FONT_RECTDRAWER_USE_DRAW_BUFFER if ( m_UniformAddrIndex + 1 > UNIFORM_ADDR_NUM || m_UniformDataIndex + 1 + 1 > UNIFORM_DATA_NUM || m_UniformTextColorIndex + COLOR_USE_COUNT > UNIFORM_TEXTCOLOR_NUM ) { UniformAndDrawText(pStringBuffer); } #else UniformAndDrawText(pStringBuffer); #endif } } if (m_UniformAddrIndex > 0) { UniformAndDrawText(pStringBuffer); } m_UniformTextColorIndex = 0; #else NN_ASSERT(false); #endif } void RectDrawer::UniformAndDrawText(DispStringBuffer* pStringBuffer) { #if defined(NW_PLATFORM_CTR) NN_ASSERT(m_UniformAddrIndex > 0); const int vtxNum = DRAW_VTX_NUM * m_UniformAddrIndex; // 描画頂点数 // uUniformAddr へのUniform { u32 size = SetUniformCommand(m_UniformAddrBuffer, m_UniformAddrIndex); NW_FONT_ADD_COMMANDS(pStringBuffer, m_UniformAddrBuffer, size); m_UniformAddrIndex = 0; } if (m_IsColorDirty) { // uUniformMtx への頂点カラーのUniform // テキストカラーのコマンド位置を保存 if (pStringBuffer->textColorCommandOffset == 0) { pStringBuffer->textColorCommandOffset = pStringBuffer->commandBufferSize; } u32 size = SetUniformCommand(m_UniformTextColorBuffer, m_UniformTextColorIndex); NW_FONT_ADD_COMMANDS(pStringBuffer, m_UniformTextColorBuffer, size); const u8 lastColorIdx = m_UniformTextColorIndex - VERTEX_MAX; if (lastColorIdx > 0) { // 色が2つ以上のときは、最後の色を先頭に持ってくる。 for (int i = 0; i < VERTEX_MAX; ++i) { m_UniformTextColor[i] = m_UniformTextColor[lastColorIdx + i]; } m_IsColorDirty = true; } else { // 色が1つだったときは、そのまま。ただし、ヘッダと入れ替えた値を戻しておく。 m_UniformTextColorBuffer[3] = m_UniformTextColorBuffer[2]; m_IsColorDirty = false; } m_UniformAddress.addrColor = MATRIX_UNIFORM_NUM; m_UniformTextColorIndex = VERTEX_MAX; } if (m_UniformDataIndex > 0) { // uUniformData へのUniform u32 size = SetUniformCommand(m_UniformDataBuffer, m_UniformDataIndex); NW_FONT_ADD_COMMANDS(pStringBuffer, m_UniformDataBuffer, size); m_UniformDataIndex = 0; } // コマンドリストに描画コマンドを積む #if defined(NW_FONT_RECTDRAWER_USE_DRAW_ARRAYS) const u32 addrOffset = GetVertexIndexAddressOffset(vtxNum); #else const u32 addrOffset = 0; // dummy #endif u32* cmdPtr = &pStringBuffer->commandBuffer[pStringBuffer->commandBufferSize]; internal::SetVertexNumCmd(&cmdPtr, addrOffset, vtxNum); pStringBuffer->commandBufferSize = cmdPtr - &pStringBuffer->commandBuffer[0]; NW_FONT_ADD_COMMANDS( pStringBuffer, GetDrawCommands(), GetDrawCommandSize() ); #else NN_ASSERT(false); #endif } #if defined(NW_FONT_RECTDRAWER_USE_DRAW_ARRAYS) u32 RectDrawer::GetVertexIndexAddressOffset(u32 vtxNum) const { return (((vtxNum > 0x10 ? (vtxNum - 0x10) * 2: 0) + m_VertexBufferBaseAddr) & 0xFFF) >= 0xFE0 ? 0x20: 0; } #endif const u32* RectDrawer::GetDrawCommands() const { #if defined(NW_PLATFORM_CTR) return DrawCommands; #else return NULL; #endif } u32 RectDrawer::GetDrawCommandSize() const { #if defined(NW_PLATFORM_CTR) return sizeof(DrawCommands); #else return 0; #endif } void RectDrawer::AddTextColor( math::VEC4* __restrict dst, const ut::Color8* __restrict src, int mode ) { #if defined(NW_PLATFORM_CTR) SetVertexColor(dst, src, mode); m_UniformAddress.addrColor = static_cast(MATRIX_UNIFORM_NUM + m_UniformTextColorIndex); m_UniformTextColorIndex += COLOR_USE_COUNT; m_IsColorDirty = true; #else NN_ASSERT(false); #endif } // ---- 以下、 RectDrawer クラス以外のコード ---- u32 DispStringBuffer::CalcCommandBufferCapacity(u32 charNum) { #if defined(NW_PLATFORM_CTR) NN_ASSERT(sizeof(TexEnv34Commands) == sizeof(TexEnv34AlphaCommands)); NN_ASSERT(sizeof(TexEnvOperand34Commands) == sizeof(TexEnvOperand34AlphaCommands)); const int UniformComponents = 4; // ユニフォームの成分の個数(xyzw) const int SingleCommand = 2; // シングルコマンド // Uniform転送用コマンドのヘッダ分 const int UniformHeader = math::RoundUp(SingleCommand + 1, 2); return sizeof(TextInitCommands) / sizeof(u32) // ブレンド・コンバイナ・シェーダー設定 + UniformComponents * COLOR_USE_COUNT // 初期文字色 + sizeof(TexEnv34Commands) / sizeof(u32) // コンバイナ設定 + charNum * ( sizeof(TexEnvOperand34Commands) / sizeof(u32) // コンバイナの変更分 + sizeof(TextureDummyCommands) / sizeof(u32) // 0x080ダミーコマンド + SingleCommand * 5 // テクスチャ用シングルコマンド4つ // (アドレス、サイズ、フォーマット、フィルタ、キャッシュクリア) + UniformHeader + UniformComponents * 1 // アドレス + UniformHeader + UniformComponents * COLOR_USE_COUNT // 文字色 + UniformHeader + UniformComponents * (1 + 1) // テクスチャ座標と矩形情報 #if defined(NW_FONT_RECTDRAWER_USE_DRAW_ARRAYS) + SingleCommand * 1 // 頂点インデックスオフセット #endif + SingleCommand * 1 // 頂点数 + sizeof(DrawCommands) / sizeof(u32) // 描画コマンド ) ; #else return 0; #endif } void CharWriter::UseCommandBuffer() { #if defined(NW_PLATFORM_CTR) NN_NULL_ASSERT(m_pDispStringBuffer); NN_NULL_ASSERT(m_pDispStringBuffer->commandBuffer); NN_ASSERT(m_pDispStringBuffer->IsGeneratedCommand()); if (m_pDispStringBuffer->IsCommandEmpty()) { return; } // 頂点カラーの設定 { NN_ASSERT(m_pDispStringBuffer->textColorCommandOffset != 0); u32 *const cmdBuf = &m_pDispStringBuffer->commandBuffer[m_pDispStringBuffer->textColorCommandOffset]; const u32 header = cmdBuf[3]; math::VEC4 *const dstCol = reinterpret_cast(&cmdBuf[3]); SetVertexColor(dstCol, m_TextColors, GetGradationMode()); cmdBuf[2] = cmdBuf[3]; cmdBuf[3] = header; } // 白黒補間カラーの設定 { const u32 alpha = m_Alpha; ut::Color8 white = m_ColorMapping.max; ut::Color8 black = m_ColorMapping.min; white.a = static_cast(white.a * alpha / 255); black.a = static_cast(black.a * alpha / 255); u32 *const cmdBuf = &m_pDispStringBuffer->commandBuffer[(sizeof(TextInitCommands) / sizeof(u32))]; cmdBuf[0 + TEX_ENV_COLOR_POS] = GetColorU32Raw(white); cmdBuf[TEX_ENV_COMMAND_SIZE + TEX_ENV_COLOR_POS] = GetColorU32Raw(black); } NW_FONT_RECTDRAWER_ADD_COMMAND( m_pDispStringBuffer->commandBuffer, m_pDispStringBuffer->commandBufferSize * sizeof(u32)); #else NN_ASSERT(false); #endif } } // namespace font } // namespace nw