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