@@ -201,7 +201,7 @@ @implementation CCShader {
201
201
202
202
// MARK: GL Uniform Setters:
203
203
204
- static CCGLUniformSetter
204
+ static CCUniformSetter
205
205
GLUniformSetFloat (NSString *name, GLint location)
206
206
{
207
207
return ^(CCRenderer *renderer, NSDictionary *shaderUniforms, NSDictionary *globalShaderUniforms){
@@ -212,7 +212,7 @@ @implementation CCShader {
212
212
};
213
213
}
214
214
215
- static CCGLUniformSetter
215
+ static CCUniformSetter
216
216
GLUniformSetVec2 (NSString *name, GLint location)
217
217
{
218
218
NSString *textureName = nil ;
@@ -255,7 +255,7 @@ @implementation CCShader {
255
255
};
256
256
}
257
257
258
- static CCGLUniformSetter
258
+ static CCUniformSetter
259
259
GLUniformSetVec3 (NSString *name, GLint location)
260
260
{
261
261
return ^(CCRenderer *renderer, NSDictionary *shaderUniforms, NSDictionary *globalShaderUniforms){
@@ -268,7 +268,7 @@ @implementation CCShader {
268
268
};
269
269
}
270
270
271
- static CCGLUniformSetter
271
+ static CCUniformSetter
272
272
GLUniformSetVec4 (NSString *name, GLint location)
273
273
{
274
274
return ^(CCRenderer *renderer, NSDictionary *shaderUniforms, NSDictionary *globalShaderUniforms){
@@ -288,7 +288,7 @@ @implementation CCShader {
288
288
};
289
289
}
290
290
291
- static CCGLUniformSetter
291
+ static CCUniformSetter
292
292
GLUniformSetMat4 (NSString *name, GLint location)
293
293
{
294
294
return ^(CCRenderer *renderer, NSDictionary *shaderUniforms, NSDictionary *globalShaderUniforms){
@@ -370,14 +370,149 @@ -(instancetype)initWithGLProgram:(GLuint)program uniformSetters:(NSDictionary *)
370
370
}
371
371
372
372
#if __CC_METAL_SUPPORTED_AND_ENABLED
373
+
374
+ static CCUniformSetter
375
+ MetalUniformSetBuffer (NSString *name, MTLArgument *vertexArg, MTLArgument *fragmentArg)
376
+ {
377
+ NSUInteger vertexIndex = vertexArg.index ;
378
+ NSUInteger fragmentIndex = fragmentArg.index ;
379
+ size_t bytes = vertexArg.bufferDataSize ;
380
+
381
+ CCMetalContext *context = [CCMetalContext currentContext ];
382
+
383
+ // Handle cc_VertexAttributes specially.
384
+ if ([name isEqualToString: @" cc_VertexAttributes" ]){
385
+ NSCAssert (vertexArg && !fragmentArg, @" cc_VertexAttributes should only be used by vertex functions." );
386
+ NSCAssert (bytes == sizeof (CCVertex), @"cc_VertexAttributes data size is not sizeof(CCVertex).");
387
+
388
+ return ^(CCRenderer *renderer, NSDictionary *shaderUniforms, NSDictionary *globalShaderUniforms){
389
+ CCGraphicsBufferMetal *vertexBuffer = (CCGraphicsBufferMetal *)renderer->_buffers ->_vertexBuffer ;
390
+ id <MTLBuffer > metalBuffer = vertexBuffer->_buffer ;
391
+
392
+ [context->_currentRenderCommandEncoder setVertexBuffer: metalBuffer offset: 0 atIndex: vertexIndex];
393
+ };
394
+ } else {
395
+ // If both args are active, they must match.
396
+ NSCAssert (!vertexArg || !fragmentArg || bytes == fragmentArg.bufferDataSize, @" Vertex and fragment argument type don't match for '%@ '." , vertexArg.name);
397
+
398
+ return ^(CCRenderer *renderer, NSDictionary *shaderUniforms, NSDictionary *globalShaderUniforms){
399
+ CCGraphicsBufferMetal *uniformBuffer = (CCGraphicsBufferMetal *)renderer->_buffers ->_uniformBuffer ;
400
+ id <MTLBuffer > metalBuffer = uniformBuffer->_buffer ;
401
+
402
+ NSNumber *globalOffset = renderer->_globalShaderUniformBufferOffsets [name];
403
+ NSUInteger offset = globalOffset.unsignedIntegerValue ;
404
+
405
+ if (!globalOffset){
406
+ void *buff = CCGraphicsBufferPushElements (uniformBuffer, bytes);
407
+ [shaderUniforms[name] getValue: buff];
408
+
409
+ offset = buff - uniformBuffer->_ptr ;
410
+ }
411
+
412
+ id <MTLRenderCommandEncoder > renderEncoder = context->_currentRenderCommandEncoder ;
413
+ if (vertexArg) [renderEncoder setVertexBuffer: metalBuffer offset: offset atIndex: vertexIndex];
414
+ if (fragmentArg) [renderEncoder setFragmentBuffer: metalBuffer offset: offset atIndex: fragmentIndex];
415
+ };
416
+ }
417
+ }
418
+
419
+ static CCUniformSetter
420
+ MetalUniformSetSampler (NSString *name, MTLArgument *vertexArg, MTLArgument *fragmentArg)
421
+ {
422
+ NSUInteger vertexIndex = vertexArg.index ;
423
+ NSUInteger fragmentIndex = fragmentArg.index ;
424
+
425
+ // For now, samplers and textures are locked together like in GL.
426
+ NSString *textureName = [name substringToIndex: name.length - @" Sampler" .length];
427
+
428
+ CCMetalContext *context = [CCMetalContext currentContext ];
429
+
430
+ return ^(CCRenderer *renderer, NSDictionary *shaderUniforms, NSDictionary *globalShaderUniforms){
431
+ CCTexture *texture = shaderUniforms[name] ?: globalShaderUniforms[name] ?: [CCTexture none ];
432
+ NSCAssert ([texture isKindOfClass: [CCTexture class ]], @" Shader uniform '%@ ' value must be a CCTexture object." , name);
433
+
434
+ id <MTLSamplerState > sampler = texture.metalSampler ;
435
+
436
+ id <MTLRenderCommandEncoder > renderEncoder = context->_currentRenderCommandEncoder ;
437
+ if (vertexArg) [renderEncoder setVertexSamplerState: sampler atIndex: vertexIndex];
438
+ if (fragmentArg) [renderEncoder setFragmentSamplerState: sampler atIndex: fragmentIndex];
439
+ };
440
+ }
441
+
442
+ static CCUniformSetter
443
+ MetalUniformSetTexture (NSString *name, MTLArgument *vertexArg, MTLArgument *fragmentArg)
444
+ {
445
+ NSUInteger vertexIndex = vertexArg.index ;
446
+ NSUInteger fragmentIndex = fragmentArg.index ;
447
+
448
+ CCMetalContext *context = [CCMetalContext currentContext ];
449
+
450
+ return ^(CCRenderer *renderer, NSDictionary *shaderUniforms, NSDictionary *globalShaderUniforms){
451
+ CCTexture *texture = shaderUniforms[name] ?: globalShaderUniforms[name] ?: [CCTexture none ];
452
+ NSCAssert ([texture isKindOfClass: [CCTexture class ]], @" Shader uniform '%@ ' value must be a CCTexture object." , name);
453
+
454
+ id <MTLTexture > metalTexture = texture.metalTexture ;
455
+
456
+ id <MTLRenderCommandEncoder > renderEncoder = context->_currentRenderCommandEncoder ;
457
+ if (vertexArg) [renderEncoder setVertexTexture: metalTexture atIndex: vertexIndex];
458
+ if (fragmentArg) [renderEncoder setFragmentTexture: metalTexture atIndex: fragmentIndex];
459
+ };
460
+ }
461
+
462
+ static NSDictionary *
463
+ MetalUniformSettersForFunctions (id <MTLFunction > vertexFunction, id <MTLFunction > fragmentFunction)
464
+ {
465
+ // Get the shader reflection information by making a dummy render pipeline state.
466
+ MTLRenderPipelineDescriptor *descriptor = [MTLRenderPipelineDescriptor new ];
467
+ descriptor.vertexFunction = vertexFunction;
468
+ descriptor.fragmentFunction = fragmentFunction;
469
+
470
+ NSError *error = nil ;
471
+ MTLRenderPipelineReflection *reflection = nil ;
472
+ [[CCMetalContext currentContext ].device newRenderPipelineStateWithDescriptor: descriptor options: MTLPipelineOptionArgumentInfo reflection: &reflection error: &error];
473
+
474
+ NSCAssert (!error, @" Error getting Metal shader arguments." );
475
+
476
+ // Collect all of the arguments.
477
+ NSMutableDictionary *vertexArgs = [NSMutableDictionary dictionary ];
478
+ for (MTLArgument *arg in reflection.vertexArguments ){ if (arg.active ){ vertexArgs[arg.name] = arg; }}
479
+
480
+ NSMutableDictionary *fragmentArgs = [NSMutableDictionary dictionary ];
481
+ for (MTLArgument *arg in reflection.fragmentArguments ){ if (arg.active ){ fragmentArgs[arg.name] = arg; }}
482
+
483
+ NSSet *argSet = [[NSSet setWithArray: vertexArgs.allKeys] setByAddingObjectsFromArray: fragmentArgs.allKeys];
484
+
485
+ // Make uniform setters.
486
+ NSMutableDictionary *uniformSetters = [NSMutableDictionary dictionary ];
487
+
488
+ for (NSString *name in argSet){
489
+ MTLArgument *vertexArg = vertexArgs[name];
490
+ MTLArgument *fragmentArg = fragmentArgs[name];
491
+
492
+ // If neither argument is active. Skip.
493
+ if (!vertexArg.active && !fragmentArg.active ) continue ;
494
+
495
+ MTLArgumentType type = (vertexArg ? vertexArg.type : fragmentArg.type );
496
+ NSCAssert (!vertexArg || !fragmentArg || type == fragmentArg.type, @" Vertex and fragment argument type don't match for '%@ '." , name);
497
+
498
+ switch (type){
499
+ case MTLArgumentTypeBuffer : uniformSetters[name] = MetalUniformSetBuffer (name, vertexArg, fragmentArg); break ;
500
+ case MTLArgumentTypeSampler : uniformSetters[name] = MetalUniformSetSampler (name, vertexArg, fragmentArg); break ;
501
+ case MTLArgumentTypeTexture : uniformSetters[name] = MetalUniformSetTexture (name, vertexArg, fragmentArg); break ;
502
+ case MTLArgumentTypeThreadgroupMemory : NSCAssert(NO , @" Compute memory not supported. (yet?)" ); break ;
503
+ }
504
+ }
505
+
506
+ return uniformSetters;
507
+ }
508
+
373
509
-(instancetype )initWithMetalVertexFunction : (id <MTLFunction >)vertexFunction fragmentFunction : (id <MTLFunction >)fragmentFunction
374
510
{
375
511
if ((self = [super init ])){
376
512
_vertexFunction = vertexFunction;
377
513
_fragmentFunction = fragmentFunction;
378
514
379
- #warning TODO setup _uniformSetters
380
- // _uniformSetters = uniformSetters;
515
+ _uniformSetters = MetalUniformSettersForFunctions (vertexFunction, fragmentFunction);
381
516
}
382
517
383
518
return self;
@@ -458,6 +593,8 @@ +(void)initialize
458
593
#if __CC_METAL_SUPPORTED_AND_ENABLED
459
594
if ([CCConfiguration sharedConfiguration ].graphicsAPI == CCGraphicsAPIMetal){
460
595
id <MTLLibrary > library = [CCMetalContext currentContext ].library ;
596
+ NSAssert (library, @" Metal shader library not found." );
597
+
461
598
id <MTLFunction > vertex = [library newFunctionWithName: @" CCVertexFunctionDefault" ];
462
599
463
600
CC_SHADER_POS_COLOR = [[self alloc ] initWithMetalVertexFunction: vertex fragmentFunction: [library newFunctionWithName: @" CCFragmentFunctionDefaultColor" ]];
0 commit comments