1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_ResShader.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: 19452 $
14 *---------------------------------------------------------------------------*/
15
16 #include "../precompiled.h"
17
18 #include <nw/gfx/res/gfx_ResShader.h>
19 #include <nw/gfx/res/gfx_ResGraphicsFile.h>
20 #include <nw/gfx/gfx_ShaderUniforms.h>
21 #include <nw/ut/ut_Foreach.h>
22 #include <nw/ut/ut_MoveArray.h>
23 #include <nw/gfx/gfx_ShaderBinaryInfo.h>
24
25 namespace nw {
26 namespace gfx {
27 namespace res {
28
29 typedef Result (*SetupFunc)(os::IAllocator* allocator, ResShader resShader);
30
31 static Result ResBinaryShader_Setup(os::IAllocator* allocator, ResShader resShader);
32 static Result ResReferenceShader_Setup(os::IAllocator* allocator, ResShader resShader);
33
34 static SetupFunc s_ShaderSetupTable[] =
35 {
36 ResBinaryShader_Setup,
37 ResReferenceShader_Setup
38 };
39
40 //----------------------------------------
41 ResBinaryShader
Dereference()42 ResShader::Dereference()
43 {
44 NW_ASSERT( this->IsValid() );
45
46 switch ( this->ref().typeInfo )
47 {
48 case ResBinaryShader::TYPE_INFO:
49 {
50 return ResStaticCast<ResBinaryShader>(*this);
51 }
52
53 case ResReferenceShader::TYPE_INFO:
54 {
55 ResReferenceShader resRefShader = ResStaticCast<ResReferenceShader>( *this );
56
57 NW_ASSERT( resRefShader.GetTargetShader().IsValid() );
58 return resRefShader.GetTargetShader().Dereference();
59 }
60
61 default:
62 {
63 return ResBinaryShader( NULL );
64 }
65 }
66 }
67
68
69 //----------------------------------------
70 const ResBinaryShader
Dereference() const71 ResShader::Dereference() const
72 {
73 NW_ASSERT( this->IsValid() );
74
75 switch ( this->ref().typeInfo )
76 {
77 case ResBinaryShader::TYPE_INFO:
78 {
79 return ResStaticCast<ResBinaryShader>(*this);
80 }
81
82 case ResReferenceShader::TYPE_INFO:
83 {
84 ResReferenceShader resRefShader = ResDynamicCast<ResReferenceShader>( *this );
85
86 NW_ASSERT( resRefShader.GetTargetShader().IsValid() );
87 return resRefShader.GetTargetShader().Dereference();
88 }
89
90 default:
91 {
92 return ResBinaryShader( NULL );
93 }
94 }
95 }
96
97 //----------------------------------------
98 Result
Setup(os::IAllocator * allocator,ResGraphicsFile graphicsFile)99 ResShader::Setup(os::IAllocator* allocator, ResGraphicsFile graphicsFile)
100 {
101 NW_UNUSED_VARIABLE(graphicsFile);
102
103 NW_ASSERT( internal::ResCheckRevision( *this ) );
104
105 Result result = RESOURCE_RESULT_OK;
106 switch ( this->ref().typeInfo )
107 {
108 case ResBinaryShader::TYPE_INFO:
109 {
110 result |= s_ShaderSetupTable[0]( allocator, *this );
111 }
112 break;
113 case ResReferenceShader::TYPE_INFO:
114 {
115 result |= s_ShaderSetupTable[1]( allocator, *this );
116 }
117 break;
118 default:
119 {
120 }
121 }
122 return result;
123 }
124
125 //----------------------------------------
126 static Result
ResBinaryShader_Setup(os::IAllocator * allocator,ResShader resShader)127 ResBinaryShader_Setup(os::IAllocator* allocator, ResShader resShader)
128 {
129 Result result = RESOURCE_RESULT_OK;
130
131 ResBinaryShader resBinaryShader = ResDynamicCast<ResBinaryShader>(resShader);
132
133 NW_ASSERT(resBinaryShader.GetShaderObjectsCount() != 0);
134
135 u32 shaderObjects = resBinaryShader.GetShaderObjects(0);
136
137 if (shaderObjects != NULL)
138 {
139 return result;
140 }
141
142 for (int i = 0; i < resBinaryShader.GetShaderKindsCount(); i++)
143 {
144 GLuint shader = glCreateShader(resBinaryShader.GetShaderKinds(i));
145 resBinaryShader.SetShaderObjects(i, shader);
146 }
147
148 void* binaryAnalyzerBuffer = CommandCacheManager::Allocate( sizeof(ShaderBinaryInfo) );
149
150 resBinaryShader.ref().m_ShaderBinaryInfo = new(binaryAnalyzerBuffer) ShaderBinaryInfo( resBinaryShader.GetBinaryData() );
151
152 ShaderBinaryInfo* shaderInfo = resBinaryShader.GetShaderBinaryInfo();
153 shaderInfo->AnalyzeBinary();
154
155 // シェーダバイナリの設定コマンドを自前で作成する。
156 internal::CommandCacheBuilder builder;
157 builder.Begin();
158
159 {
160 shaderInfo->BuildCommonCommand();
161 }
162
163 builder.End();
164
165 resBinaryShader.ref().m_CommandCache = builder.AllocAndCopy();
166 resBinaryShader.ref().m_CommandCacheSize = builder.GetSize();
167
168 builder.Rollback();
169
170 #if defined(NW_GFX_PROGRAM_OBJECT_ENABLED)
171 glShaderBinary(
172 resBinaryShader.GetShaderObjectsCount(),
173 reinterpret_cast<GLuint*>(resBinaryShader.GetShaderObjects()),
174 GL_PLATFORM_BINARY_DMP,
175 resBinaryShader.GetBinaryData(),
176 resBinaryShader.GetBinaryDataCount());
177 #endif
178
179 for (int i = 0; i < resBinaryShader.GetDescriptionsCount(); i++)
180 {
181 ResShaderProgramDescription description = resBinaryShader.GetDescriptions(i);
182 GLuint vertexShader = 0;
183 s32 vertexIndex = resBinaryShader.GetDescriptions(i).GetVertexShaderIndex();
184 NW_MINMAXLT_ASSERT(vertexIndex, 0, resBinaryShader.GetShaderObjectsCount());
185 vertexShader = resBinaryShader.GetShaderObjects(vertexIndex);
186
187 GLuint geometryShader = 0;
188 s32 geometryIndex = resBinaryShader.GetDescriptions(i).GetGeometryShaderIndex();
189
190 if (0 <= geometryIndex && geometryIndex < resBinaryShader.GetShaderObjectsCount())
191 {
192 geometryShader = resBinaryShader.GetShaderObjects(geometryIndex);
193 }
194
195 resBinaryShader.GetDescriptions(i).SetVertexShaderObject( vertexShader );
196 resBinaryShader.GetDescriptions(i).SetGeometryShaderObject( geometryShader );
197 resBinaryShader.GetDescriptions(i).Setup(allocator);
198 }
199
200 return result;
201 }
202
203 //----------------------------------------
204 static Result
ResReferenceShader_Setup(os::IAllocator * allocator,ResShader resShader)205 ResReferenceShader_Setup(os::IAllocator* allocator, ResShader resShader)
206 {
207 Result result = RESOURCE_RESULT_OK;
208 ResReferenceShader resRefShader = ResDynamicCast<ResReferenceShader>( resShader );
209
210 NW_ASSERT( resRefShader.IsValid() );
211 NW_ASSERT( resRefShader.GetTargetShader().IsValid() );
212
213 ResBinaryShader binaryShader = ResDynamicCast<ResBinaryShader>(resRefShader.GetTargetShader());
214
215 if (binaryShader.IsValid())
216 {
217 ResBinaryShader_Setup(allocator, binaryShader);
218 }
219 return result;
220 }
221
222 //----------------------------------------
223 void
Cleanup()224 ResShader::Cleanup()
225 {
226 ResBinaryShader resBinaryShader = ResDynamicCast<ResBinaryShader>(*this);
227
228 if (resBinaryShader.IsValid())
229 {
230 if ( resBinaryShader.ref().m_CommandCache != NULL )
231 {
232 CommandCacheManager::Free( resBinaryShader.ref().m_CommandCache );
233 resBinaryShader.ref().m_CommandCache = NULL;
234 resBinaryShader.ref().m_CommandCacheSize = 0;
235 }
236
237 if ( resBinaryShader.ref().m_ShaderBinaryInfo != NULL )
238 {
239 ShaderBinaryInfo* shaderInfo = resBinaryShader.GetShaderBinaryInfo();
240 shaderInfo->~ShaderBinaryInfo();
241 CommandCacheManager::Free( shaderInfo );
242
243 resBinaryShader.ref().m_ShaderBinaryInfo = NULL;
244 }
245
246 ut::SafeCleanupAll(resBinaryShader.GetDescriptions());
247
248 for (int i = 0; i < resBinaryShader.GetShaderObjectsCount(); i++)
249 {
250 u32 shaderObject = resBinaryShader.GetShaderObjects(i);
251 if (shaderObject)
252 {
253 glDeleteShader(shaderObject);
254 resBinaryShader.SetShaderObjects(i, 0);
255 }
256 }
257 }
258 }
259
260 //----------------------------------------
261 Result
Setup(os::IAllocator * allocator)262 ResShaderProgramDescription::Setup(os::IAllocator* allocator)
263 {
264 NW_UNUSED_VARIABLE(allocator);
265 Result result = RESOURCE_RESULT_OK;
266
267 #if defined(NW_GFX_PROGRAM_OBJECT_ENABLED)
268 if (this->GetProgramObject() == NULL)
269 {
270 this->ref().m_ProgramObject = CreateProgramObject();
271
272 ShaderUniformLocation* uniformLocation = ShaderUniformLocation::Create(allocator);
273 uniformLocation->BuildUniformLocations(this->ref().m_ProgramObject);
274 this->SetUniformLocation(uniformLocation);
275 }
276 #endif
277
278 s32 symbolsCount = this->GetSymbolsCount();
279 for (int i = 0; i < symbolsCount; ++i)
280 {
281 ResShaderSymbol resShaderSymbol = this->GetSymbols(i);
282 NW_ASSERT(resShaderSymbol.IsValid());
283
284 // シェーダーシンボルのLocationが-1のときのみロケーション値の取得を行います。
285 if (resShaderSymbol.GetLocation() == -1)
286 {
287 s32 regIndex = this->GetVertexUniformIndex( resShaderSymbol.GetName(), NULL );
288
289 if (regIndex >= 0)
290 {
291 resShaderSymbol.SetGeometryUniform( false );
292 resShaderSymbol.SetLocation(regIndex);
293 }
294 else
295 {
296 regIndex = this->GetGeometryUniformIndex( resShaderSymbol.GetName(), NULL );
297
298 if (regIndex >= 0)
299 {
300 resShaderSymbol.SetGeometryUniform( true );
301 resShaderSymbol.SetLocation(regIndex);
302 }
303 else
304 {
305 resShaderSymbol.SetLocation(-1);
306 result |= RESOURCE_RESULT_IRRELEVANT_LOCATION_SHADER_SYMBOL;
307 }
308 }
309 }
310 }
311
312 if ( ref().m_CommandCache )
313 {
314 return result;
315 }
316
317 // 各シェーダプログラムの設定コマンドを自前で作成する。
318 internal::CommandCacheBuilder builder;
319 builder.Begin();
320
321 {
322 ResBinaryShader ownerShader = ResBinaryShader( this->GetOwnerShaderData() );
323
324 ShaderBinaryInfo* shaderInfo = ownerShader.GetShaderBinaryInfo();
325
326 s32 vertexShaderIndex = this->GetVertexShaderIndex();
327 s32 geometryShaderIndex = this->GetGeometryShaderIndex();
328
329 shaderInfo->BuildShaderProgramCommand( vertexShaderIndex, geometryShaderIndex );
330 }
331
332 builder.End();
333
334 ref().m_CommandCache = builder.AllocAndCopy();
335 ref().m_CommandCacheSize = builder.GetSize();
336
337 builder.Rollback();
338
339 return result;
340 }
341
342 //----------------------------------------
343 void
Cleanup()344 ResShaderProgramDescription::Cleanup()
345 {
346 #if defined(NW_GFX_PROGRAM_OBJECT_ENABLED)
347 if (this->GetUniformLocation())
348 {
349 ShaderUniformLocation* uniformLocation = static_cast<ShaderUniformLocation*>(this->GetUniformLocation());
350 uniformLocation->Destroy();
351 this->SetUniformLocation(NULL);
352 }
353 #endif
354
355 s32 symbolsCount = this->GetSymbolsCount();
356 for (int i = 0; i < symbolsCount; ++i)
357 {
358 ResShaderSymbol resShaderSymbol = this->GetSymbols(i);
359 NW_ASSERT(resShaderSymbol.IsValid());
360
361 resShaderSymbol.SetLocation(-1);
362 resShaderSymbol.SetGeometryUniform(false);
363 }
364
365 #if defined(NW_GFX_PROGRAM_OBJECT_ENABLED)
366 if (this->GetProgramObject())
367 {
368 if (this->GetVertexShaderObject() != 0)
369 {
370 glDetachShader(this->GetProgramObject(), this->GetVertexShaderObject());
371 }
372
373 if (this->GetGeometryShaderObject() != 0)
374 {
375 glDetachShader(this->GetProgramObject(), this->GetGeometryShaderObject());
376 }
377
378 glDetachShader(this->GetProgramObject(), GL_DMP_FRAGMENT_SHADER_DMP);
379
380 glDeleteProgram(this->GetProgramObject());
381 }
382 #endif
383
384 this->ref().m_ProgramObject = 0;
385
386 if ( this->ref().m_CommandCache )
387 {
388 CommandCacheManager::Free( this->ref().m_CommandCache );
389 this->ref().m_CommandCache = NULL;
390 this->ref().m_CommandCacheSize = 0;
391 }
392 }
393
394
395 //----------------------------------------
396 s32
GetVertexUniformIndex(const char * name,ShaderBinaryInfo::SymbolType * pSymbolType) const397 ResShaderProgramDescription::GetVertexUniformIndex(
398 const char* name,
399 ShaderBinaryInfo::SymbolType* pSymbolType
400 ) const
401 {
402 const ShaderBinaryInfo* shaderInfo = this->GetShaderBinaryInfo();
403 NW_NULL_ASSERT( shaderInfo );
404
405 ::std::pair<s32, ShaderBinaryInfo::SymbolType> uniformInfo =
406 shaderInfo->SearchUniformIndex( this->GetVertexShaderIndex(), name );
407
408 if ( pSymbolType )
409 {
410 *pSymbolType = uniformInfo.second;
411 }
412
413 return uniformInfo.first;
414 }
415
416 //----------------------------------------
417 s32
GetGeometryUniformIndex(const char * name,ShaderBinaryInfo::SymbolType * pSymbolType) const418 ResShaderProgramDescription::GetGeometryUniformIndex(
419 const char* name,
420 ShaderBinaryInfo::SymbolType* pSymbolType
421 ) const
422 {
423 const ShaderBinaryInfo* shaderInfo = this->GetShaderBinaryInfo();
424 NW_NULL_ASSERT( shaderInfo );
425
426 ::std::pair<s32, ShaderBinaryInfo::SymbolType> uniformInfo =
427 shaderInfo->SearchUniformIndex( this->GetGeometryShaderIndex(), name );
428
429 if ( pSymbolType )
430 {
431 *pSymbolType = uniformInfo.second;
432 }
433
434 return uniformInfo.first;
435 }
436
437
438 #if defined(NW_GFX_PROGRAM_OBJECT_ENABLED)
439
440 //----------------------------------------
441 GLuint
CreateProgramObject()442 ResShaderProgramDescription::CreateProgramObject()
443 {
444 GLuint programObject = glCreateProgram();
445 NW_ASSERTMSG(0 != programObject, "Can't create program.");
446 AttachProgram(programObject);
447 LinkProgram(programObject);
448
449 return programObject;
450 }
451
452 //----------------------------------------
453 void
AttachProgram(GLuint programObject)454 ResShaderProgramDescription::AttachProgram(GLuint programObject)
455 {
456 NW_ASSERT(this->GetVertexShaderObject() != 0);
457
458 glAttachShader(programObject, this->GetVertexShaderObject());
459
460 if (this->GetGeometryShaderObject() != 0)
461 {
462 glAttachShader(programObject, this->GetGeometryShaderObject());
463 }
464
465 glAttachShader(programObject, GL_DMP_FRAGMENT_SHADER_DMP);
466
467 int index = 0;
468 for (int i = 0; i < this->GetAttributeSymbolsCount(); ++i)
469 {
470 if (const char* symbol = this->GetAttributeSymbols(i))
471 {
472 glBindAttribLocation(programObject, index, symbol);
473 ++index;
474 }
475 }
476 }
477
478 //----------------------------------------
479 void
LinkProgram(GLuint programObject)480 ResShaderProgramDescription::LinkProgram(GLuint programObject)
481 {
482 glLinkProgram(programObject);
483 int linked;
484 glGetProgramiv(programObject, GL_LINK_STATUS, &linked);
485 if (linked == 0)
486 {
487 glDeleteProgram(programObject);
488 NW_FATAL_ERROR("Shader Link Error");
489 }
490
491 glValidateProgram(programObject);
492 }
493
494 #endif
495
496 } /* namespace res */
497 } /* namespace gfx */
498 } /* namespace nw */
499
500