1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_SortingMaterialIdGenerator.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: 22799 $
14 *---------------------------------------------------------------------------*/
15
16 #include "precompiled.h"
17
18 #include <nw/gfx/gfx_SortingMaterialIdGenerator.h>
19 #include <nw/gfx/gfx_Material.h>
20
21 namespace nw
22 {
23 namespace gfx
24 {
25
26 NW_UT_RUNTIME_TYPEINFO_ROOT_DEFINITION(SortingMaterialIdGenerator);
27
28 //----------------------------------------
29 IMaterialIdGenerator*
Create(os::IAllocator * allocator)30 SortingMaterialIdGenerator::Builder::Create(
31 os::IAllocator* allocator
32 )
33 {
34 NW_NULL_ASSERT(allocator);
35
36 void* memory = allocator->Alloc(sizeof(SortingMaterialIdGenerator));
37 NW_NULL_ASSERT(memory);
38
39 MaterialKeyValueArray materials;
40 MaterialKeyValueArray materialsWorkSpace;
41 if (m_Description.isFixedSizeMemory)
42 {
43 materials = MaterialKeyValueArray(m_Description.maxMaterials, allocator);
44 materialsWorkSpace = MaterialKeyValueArray(m_Description.maxMaterials, allocator);
45 }
46 else
47 {
48 materials = MaterialKeyValueArray(allocator);
49 materialsWorkSpace = MaterialKeyValueArray(allocator);
50 }
51
52 SortingMaterialIdGenerator* generator =
53 new(memory) SortingMaterialIdGenerator(
54 allocator,
55 materials,
56 materialsWorkSpace);
57
58 return generator;
59 }
60
61
62 //---------------------------------------------------------------------------
63 //! @brief ソート比較用関数オブジェクトです。
64 //---------------------------------------------------------------------------
65
66 struct MaterialKeyValueCompare
67 : public std::binary_function<internal::MaterialKeyValue, internal::MaterialKeyValue, bool>
68 {
operator ()nw::gfx::MaterialKeyValueCompare69 bool operator() (const internal::MaterialKeyValue& lhs,
70 const internal::MaterialKeyValue& rhs)
71 {
72 return lhs.key < rhs.key;
73 }
74 };
75
76 struct MaterialSubKeyValueCompare
77 : public std::binary_function<internal::MaterialKeyValue, internal::MaterialKeyValue, bool>
78 {
operator ()nw::gfx::MaterialSubKeyValueCompare79 bool operator() (const internal::MaterialKeyValue& lhs,
80 const internal::MaterialKeyValue& rhs)
81 {
82 return lhs.subKey < rhs.subKey;
83 }
84 };
85
86 struct MaterialUniqueIdCompare
87 : public std::unary_function<internal::MaterialKeyValue, bool>
88 {
operator ()nw::gfx::MaterialUniqueIdCompare89 bool operator() (const internal::MaterialKeyValue& keyValue, const u32 uniqueId)
90 {
91 return keyValue.uniqueId < uniqueId;
92 }
93
operator ()nw::gfx::MaterialUniqueIdCompare94 bool operator() (const u32 uniqueId, const internal::MaterialKeyValue& keyValue)
95 {
96 return keyValue.uniqueId > uniqueId;
97 }
98 };
99
100 //----------------------------------------
101 void
Accept(Material * material)102 SortingMaterialIdGenerator::Accept(Material* material)
103 {
104 internal::MaterialKeyValue materialKeyValue;
105 materialKeyValue.key = reinterpret_cast<u32>(material->GetOriginal().ptr());
106 materialKeyValue.material = material;
107
108 bool isPushed = m_Materials.push_back(materialKeyValue);
109 NW_ASSERT(isPushed);
110 }
111
112 //----------------------------------------
113 void
Generate()114 SortingMaterialIdGenerator::Generate()
115 {
116 // ResMaterialData を基にソートします。
117 std::sort( m_Materials.begin(), m_Materials.end(),
118 nw::gfx::MaterialKeyValueCompare() );
119
120 u32 lastPtrKey = 0x0;
121 u32 uniquePtrId = 0;
122 // ResMaterialData が同一のノードを統合しつつ ResBinaryShaderData を基にキーを作成します。
123 MaterialKeyValueArray::iterator materialPtrEnd = m_Materials.end();
124 for (MaterialKeyValueArray::iterator iter = m_Materials.begin();
125 iter != materialPtrEnd;
126 ++iter)
127 {
128 if (lastPtrKey != (*iter).key)
129 {
130 ++uniquePtrId;
131
132 ResMaterial resMaterial = (*iter).material->GetOriginal();
133 NW_ASSERT(resMaterial.IsValid());
134 ResShaderProgramDescription resDescription = (*iter).material->GetDescription();
135 NW_ASSERT(resDescription.IsValid());
136 u32 key = reinterpret_cast<u32>(resDescription.GetOwnerShaderData());
137
138 internal::MaterialKeyValue materialKeyValue;
139 materialKeyValue.uniqueId = uniquePtrId;
140 materialKeyValue.key = key;
141 materialKeyValue.subKey = resMaterial.GetFragmentLightingTableHash();
142 materialKeyValue.material = (*iter).material;
143 m_MaterialsWorkSpace.push_back(materialKeyValue);
144 lastPtrKey = (*iter).key;
145 }
146 (*iter).uniqueId = uniquePtrId;
147 }
148
149 // ResBinaryShaderData を基にソートします。
150 std::sort( m_MaterialsWorkSpace.begin(), m_MaterialsWorkSpace.end(),
151 nw::gfx::MaterialKeyValueCompare() );
152
153 // ResBinaryShaderData が同一であるマテリアル列の内部を ResFragmentLightingTable の Hash 値を基にソートします。
154 u32 sortStartIndex = 0;
155 u32 sortEndIndex = 0;
156 u32 lastShaderKey = 0;
157 u32 endIndex = m_MaterialsWorkSpace.size() - 1;
158 for (int index = 0; index < endIndex + 1; ++index)
159 {
160 if (lastShaderKey != m_MaterialsWorkSpace[index].key ||
161 index == endIndex)
162 {
163 sortEndIndex = index;
164 int diff = (sortEndIndex - sortStartIndex);
165 // 同一キーが3ノード以上連続した場合にソートを行います。
166 if (diff >= 3)
167 {
168 std::sort(m_MaterialsWorkSpace.begin() + sortStartIndex,
169 m_MaterialsWorkSpace.begin() + sortEndIndex,
170 nw::gfx::MaterialSubKeyValueCompare() );
171 }
172 sortStartIndex = index;
173 }
174
175 lastShaderKey = m_MaterialsWorkSpace[index].key;
176 }
177
178 // 統合したノードを展開しながら MaterialId を 1 から順に付けます。
179 u32 materialId = 1;
180 MaterialKeyValueArray::iterator shaderEnd = m_MaterialsWorkSpace.end();
181 for (MaterialKeyValueArray::iterator shaderIter = m_MaterialsWorkSpace.begin();
182 shaderIter != shaderEnd;
183 ++shaderIter)
184 {
185 ::std::pair<MaterialKeyValueArray::iterator, MaterialKeyValueArray::iterator> range =
186 equal_range(m_Materials.begin(), m_Materials.end(), (*shaderIter).uniqueId,
187 MaterialUniqueIdCompare());
188
189 for (MaterialKeyValueArray::iterator ptrIter = range.first;
190 ptrIter != range.second;
191 ++ptrIter)
192 {
193 ResMaterial resMaterial = (*ptrIter).material->GetOriginal();
194 resMaterial.SetMaterialId( materialId );
195 ++materialId;
196 }
197 }
198
199 // 生成後はマテリアルのリストを解放します。
200 m_Materials.clear();
201 m_MaterialsWorkSpace.clear();
202 }
203
204 } // namespace gfx
205 } // namespace nw
206