Skip to content

Commit 8d6af69

Browse files
committed
Fix some issues with setting metal shader state. More shader API for metal.
1 parent 2449289 commit 8d6af69

File tree

6 files changed

+152
-23
lines changed

6 files changed

+152
-23
lines changed

cocos2d-tests-ios.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
D28A2E1F1954F7E900ADC03D /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D28A2E1E1954F7E900ADC03D /* OpenGLES.framework */; };
7272
D2B4894C1917EE6700C3443A /* CCEffectsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D2B4894B1917EE6700C3443A /* CCEffectsTest.m */; };
7373
D2D59897198747DE00BDAF25 /* Music in Resources */ = {isa = PBXBuildFile; fileRef = D2D59896198747DE00BDAF25 /* Music */; };
74+
D3269DE819CC985900406282 /* TestShaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = D3269DE719CC985900406282 /* TestShaders.metal */; };
75+
D3269DEA19CCC11800406282 /* CCRendererSharedTypes.h in Resources */ = {isa = PBXBuildFile; fileRef = D3269DE919CCC11800406282 /* CCRendererSharedTypes.h */; };
7476
D32FDE8619B645CA0078CC16 /* CCTextureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D32FDE8519B645CA0078CC16 /* CCTextureTests.m */; };
7577
D3395F1A187F83E600F22C74 /* CCMemoryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D3395F19187F83E600F22C74 /* CCMemoryTests.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
7678
D340E10E185660BE006E605C /* CCPhysicsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D340E10C185660BE006E605C /* CCPhysicsTest.m */; };
@@ -274,6 +276,8 @@
274276
D2D0E6951950B16300E9103F /* libGLESv3.so */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libGLESv3.so; path = "../../../Library/Application Support/Developer/Shared/Xcode/Platforms/Android.platform/Developer/SDKs/ApportableSDK1.0.sdk/usr/lib/armeabi/libGLESv3.so"; sourceTree = "<group>"; };
275277
D2D0E6991950B16800E9103F /* libEGL.so */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libEGL.so; path = "../../../Library/Application Support/Developer/Shared/Xcode/Platforms/Android.platform/Developer/SDKs/ApportableSDK1.0.sdk/usr/lib/armeabi/libEGL.so"; sourceTree = "<group>"; };
276278
D2D59896198747DE00BDAF25 /* Music */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Music; path = Resources/Music; sourceTree = SOURCE_ROOT; };
279+
D3269DE719CC985900406282 /* TestShaders.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; name = TestShaders.metal; path = "cocos2d-ui-tests/tests/TestShaders.metal"; sourceTree = SOURCE_ROOT; };
280+
D3269DE919CCC11800406282 /* CCRendererSharedTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CCRendererSharedTypes.h; path = cocos2d/CCRendererSharedTypes.h; sourceTree = "<group>"; };
277281
D32FDE8519B645CA0078CC16 /* CCTextureTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCTextureTests.m; sourceTree = "<group>"; };
278282
D3395F19187F83E600F22C74 /* CCMemoryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCMemoryTests.m; sourceTree = "<group>"; };
279283
D340E10C185660BE006E605C /* CCPhysicsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CCPhysicsTest.m; path = "cocos2d-ui-tests/tests/CCPhysicsTest.m"; sourceTree = SOURCE_ROOT; };
@@ -520,6 +524,7 @@
520524
D3B2A7E4187DD60B00406C5A /* CCBMFontTest.m */,
521525
A6167B92189A7D4D0044D391 /* VertexZTest.m */,
522526
A664A4EE18A3D9B8006184B8 /* PositioningTest.m */,
527+
D3269DE719CC985900406282 /* TestShaders.metal */,
523528
);
524529
name = Tests;
525530
path = "cocos2d-ui-tests/tests";
@@ -528,6 +533,7 @@
528533
B7E2603F17E7D278007067F0 = {
529534
isa = PBXGroup;
530535
children = (
536+
D3269DE919CCC11800406282 /* CCRendererSharedTypes.h */,
531537
755569ED1856361100ED1B0F /* UnitTests */,
532538
B7E2605F17E7D278007067F0 /* cocos2d-tests-ios */,
533539
B7E2604A17E7D278007067F0 /* Frameworks */,
@@ -838,6 +844,7 @@
838844
isa = PBXResourcesBuildPhase;
839845
buildActionMask = 2147483647;
840846
files = (
847+
D3269DEA19CCC11800406282 /* CCRendererSharedTypes.h in Resources */,
841848
D4AFE91B1977100000261299 /* bitmapFontTest.fnt in Resources */,
842849
D4AFE9231977100000261299 /* bitmapFontTest5.png in Resources */,
843850
758A6C6C1843E5CB00D1A8D2 /* TileMaps in Resources */,
@@ -940,6 +947,7 @@
940947
isa = PBXSourcesBuildPhase;
941948
buildActionMask = 2147483647;
942949
files = (
950+
D3269DE819CC985900406282 /* TestShaders.metal in Sources */,
943951
B71B087C17EA5B490082EBC0 /* TestBase.m in Sources */,
944952
D3870C6018B440150033D885 /* SpritePerformanceTest.m in Sources */,
945953
B71B088217EA5B6A0082EBC0 /* CCScrollViewTest.m in Sources */,

cocos2d-ui-tests/tests/CCRendererTest.m

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ -(id)init
135135
// [self.contentNode addChild:sprite];
136136
//}
137137

138+
#if !__CC_METAL_SUPPORTED_AND_ENABLED
138139
-(void)setupClippingNodeTest
139140
{
140141
self.subTitle = @"ClippingNode test.";
@@ -202,6 +203,7 @@ -(void)setupInfiniteWindowTest
202203
[timer repeatOnceWithInterval:0.125];
203204
} delay:0.0];
204205
}
206+
#endif
205207

206208
-(CCSprite *)simpleShaderTestHelper
207209
{
@@ -218,13 +220,31 @@ -(void)setupSimpleShaderTest
218220

219221
// Normally you'd load shaders from a file using the [CCShader shaderNamed:] method to use the shader cache.
220222
// Embedding shaders in the source code is handy when they are short though.
221-
CCShader *shader = [[CCShader alloc] initWithFragmentShaderSource:CC_GLSL(
222-
uniform lowp mat4 u_ColorMatrix;
223-
224-
void main(void){
225-
gl_FragColor = u_ColorMatrix*texture2D(cc_MainTexture, cc_FragTexCoord1);
226-
}
227-
)];
223+
CCShader *shader = nil;
224+
225+
#if __CC_METAL_SUPPORTED_AND_ENABLED
226+
if([CCConfiguration sharedConfiguration].graphicsAPI == CCGraphicsAPIMetal){
227+
shader = [[CCShader alloc] initWithFragmentShaderSource:CC_METAL(
228+
fragment half4 ShaderMain(
229+
const CCFragData in [[stage_in]],
230+
const device float4x4 *u_ColorMatrix [[buffer(0)]],
231+
texture2d<float> cc_MainTexture [[texture(0)]],
232+
sampler cc_MainTextureSampler [[sampler(0)]]
233+
){
234+
return half4((*u_ColorMatrix)*cc_MainTexture.sample(cc_MainTextureSampler, in.texCoord1));
235+
}
236+
)];
237+
} else
238+
#endif
239+
{
240+
shader = [[CCShader alloc] initWithFragmentShaderSource:CC_GLSL(
241+
uniform lowp mat4 u_ColorMatrix;
242+
243+
void main(void){
244+
gl_FragColor = u_ColorMatrix*texture2D(cc_MainTexture, cc_FragTexCoord1);
245+
}
246+
)];
247+
}
228248

229249
CCSprite *sprite1 = [self simpleShaderTestHelper];
230250
sprite1.position = ccp(0.3, 0.4);
@@ -248,6 +268,8 @@ void main(void){
248268
label2.position = ccp(0.7, 0.3);
249269
[self.contentNode addChild:label2];
250270

271+
[CCDirector sharedDirector].globalShaderUniforms[@"u_ColorMatrix"] = [NSValue valueWithGLKMatrix4:GLKMatrix4Identity];
272+
251273
[self scheduleBlock:^(CCTimer *timer) {
252274
// Set up a global uniform matrix to rotate colors counter-clockwise.
253275
GLKMatrix4 colorMatrix1 = GLKMatrix4MakeRotation(2.0f*timer.invokeTime, 1.0f, 1.0f, 1.0f);

cocos2d/CCNoARC.m

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ @implementation CCRenderStateMetal {
320320
CCRenderStateMetalPrepare(CCRenderStateMetal *self)
321321
{
322322
if(self->_renderPipelineState == nil){
323-
#warning Should get this from the renderer somehow.
323+
// TODO Should get this from the renderer somehow?
324324
CCMetalContext *context = [CCMetalContext currentContext];
325325

326326
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
@@ -341,7 +341,11 @@ @implementation CCRenderStateMetal {
341341
colorDescriptor.alphaBlendOperation = GLBLEND_TO_METAL(blendOptions[CCBlendEquationAlpha]);
342342
pipelineStateDescriptor.colorAttachments[0] = colorDescriptor;
343343

344-
self->_renderPipelineState = [[context.device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:nil] retain];
344+
NSError *err = nil;
345+
self->_renderPipelineState = [[context.device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&err] retain];
346+
347+
if(err) CCLOG(@"Error creating metal render pipeline state. %@", err);
348+
NSCAssert(self->_renderPipelineState, @"Could not create render pipeline state.");
345349
}
346350
}
347351

@@ -381,7 +385,8 @@ @implementation CCRenderCommandDrawMetal
381385
-(instancetype)initWithMode:(CCRenderCommandDrawMode)mode renderState:(CCRenderState *)renderState first:(NSUInteger)first count:(size_t)count globalSortOrder:(NSInteger)globalSortOrder
382386
{
383387
if((self = [super initWithMode:mode renderState:renderState first:first count:count globalSortOrder:globalSortOrder])){
384-
CCRenderStateMetalPrepare((CCRenderStateMetal *)renderState);
388+
// The renderer may have copied the render state, use the ivar.
389+
CCRenderStateMetalPrepare((CCRenderStateMetal *)_renderState);
385390
}
386391

387392
return self;

cocos2d/CCShader.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,15 @@
3232
#import "ccMacros.h"
3333
#import "Platforms/CCGL.h"
3434

35-
/// Macro to embed GLSL source
35+
#if __CC_METAL_SUPPORTED_AND_ENABLED
36+
#import <Metal/Metal.h>
37+
38+
/// Macro to embed Metal shading language source.
39+
#define CC_METAL(x) @#x
40+
#endif
41+
42+
43+
/// Macro to embed GLSL source.
3644
#define CC_GLSL(x) @#x
3745

3846

@@ -68,6 +76,10 @@ extern const NSString *CCShaderUniformAlphaTestValue;
6876
-(instancetype)initWithVertexShaderSource:(NSString *)vertexSource fragmentShaderSource:(NSString *)fragmentSource;
6977
-(instancetype)initWithFragmentShaderSource:(NSString *)source;
7078

79+
#if __CC_METAL_SUPPORTED_AND_ENABLED
80+
-(instancetype)initWithMetalVertexFunction:(id<MTLFunction>)vertexFunction fragmentFunction:(id<MTLFunction>)fragmentFunction;
81+
#endif
82+
7183
+(instancetype)positionColorShader;
7284
+(instancetype)positionTextureColorShader;
7385
+(instancetype)positionTextureColorAlphaTestShader;

cocos2d/CCShader.m

Lines changed: 93 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,9 @@ -(instancetype)initWithGLProgram:(GLuint)program uniformSetters:(NSDictionary *)
376376
{
377377
NSUInteger vertexIndex = vertexArg.index;
378378
NSUInteger fragmentIndex = fragmentArg.index;
379-
size_t bytes = vertexArg.bufferDataSize;
379+
380+
// vertexArg may be nil.
381+
size_t bytes = (vertexArg.bufferDataSize ?: fragmentArg.bufferDataSize);
380382

381383
CCMetalContext *context = [CCMetalContext currentContext];
382384

@@ -393,20 +395,27 @@ -(instancetype)initWithGLProgram:(GLuint)program uniformSetters:(NSDictionary *)
393395
};
394396
} else {
395397
// 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);
398+
NSCAssert(!vertexArg || !fragmentArg || vertexArg.bufferDataSize == fragmentArg.bufferDataSize, @"Vertex and fragment argument type don't match for '%@'.", vertexArg.name);
397399

398400
return ^(CCRenderer *renderer, NSDictionary *shaderUniforms, NSDictionary *globalShaderUniforms){
399401
CCGraphicsBufferMetal *uniformBuffer = (CCGraphicsBufferMetal *)renderer->_buffers->_uniformBuffer;
400402
id<MTLBuffer> metalBuffer = uniformBuffer->_buffer;
401403

402-
NSNumber *globalOffset = renderer->_globalShaderUniformBufferOffsets[name];
403-
NSUInteger offset = globalOffset.unsignedIntegerValue;
404+
NSUInteger offset = 0;
404405

405-
if(!globalOffset){
406+
NSValue *value = shaderUniforms[name];
407+
if(value){
408+
// Try finding a per-node value first and append it to the uniform buffer.
406409
void *buff = CCGraphicsBufferPushElements(uniformBuffer, bytes);
407-
[shaderUniforms[name] getValue:buff];
410+
[value getValue:buff];
408411

409412
offset = buff - uniformBuffer->_ptr;
413+
} else {
414+
// Look for a global offset instead.
415+
NSNumber *globalOffset = renderer->_globalShaderUniformBufferOffsets[name];
416+
NSCAssert(globalOffset, @"Shader value named '%@' not found.", name);
417+
418+
offset = globalOffset.unsignedIntegerValue;
410419
}
411420

412421
id<MTLRenderCommandEncoder> renderEncoder = context->_currentRenderCommandEncoder;
@@ -509,6 +518,8 @@ -(instancetype)initWithGLProgram:(GLuint)program uniformSetters:(NSDictionary *)
509518
-(instancetype)initWithMetalVertexFunction:(id<MTLFunction>)vertexFunction fragmentFunction:(id<MTLFunction>)fragmentFunction
510519
{
511520
if((self = [super init])){
521+
NSAssert(vertexFunction && fragmentFunction, @"Must create have both a vertex and fragment function to make a CCShader.");
522+
512523
_vertexFunction = vertexFunction;
513524
_fragmentFunction = fragmentFunction;
514525

@@ -517,13 +528,73 @@ -(instancetype)initWithMetalVertexFunction:(id<MTLFunction>)vertexFunction fragm
517528

518529
return self;
519530
}
520-
#endif
521531

522-
-(instancetype)initWithVertexShaderSource:(NSString *)vertexSource fragmentShaderSource:(NSString *)fragmentSource
532+
-(instancetype)initWithMetalVertexShaderSource:(NSString *)vertexSource fragmentShaderSource:(NSString *)fragmentSource
523533
{
524-
#warning TODO
525-
if([CCConfiguration sharedConfiguration].graphicsAPI == CCGraphicsAPIMetal) return self;
534+
CCMetalContext *context = [CCMetalContext currentContext];
535+
NSString *header = CC_METAL(
536+
using namespace metal;
537+
538+
typedef struct CCVertex {
539+
float4 position;
540+
float2 texCoord1;
541+
float2 texCoord2;
542+
float4 color;
543+
} CCVertex;
544+
545+
typedef struct CCFragData {
546+
float4 position [[position]];
547+
float2 texCoord1;
548+
float2 texCoord2;
549+
half4 color;
550+
} CCFragData;
551+
552+
typedef struct CCGlobalUniforms {
553+
float4x4 projection;
554+
float4x4 projectionInv;
555+
float2 viewSize;
556+
float2 viewSizeInPixels;
557+
float4 time;
558+
float4 sinTime;
559+
float4 cosTime;
560+
float4 random01;
561+
} CCGlobalUniforms;
562+
563+
);
564+
565+
id<MTLFunction> vertexFunction = nil;
566+
if(vertexSource == CCDefaultVShader){
567+
// Use the default vertex shader.
568+
vertexFunction = [context.library newFunctionWithName:@"CCVertexFunctionDefault"];
569+
} else {
570+
// Append on the standard header since JIT compiled shaders can't use #import
571+
vertexSource = [header stringByAppendingString:vertexSource];
572+
573+
// Compile the vertex shader.
574+
NSError *verr = nil;
575+
id<MTLLibrary> vlib = [context.device newLibraryWithSource:vertexSource options:nil error:&verr];
576+
if(verr) CCLOG(@"Error compiling metal vertex shader: %@", verr);
577+
578+
vertexFunction = [vlib newFunctionWithName:@"ShaderMain"];
579+
}
580+
581+
// Append on the standard header since JIT compiled shaders can't use #import
582+
fragmentSource = [header stringByAppendingString:fragmentSource];
526583

584+
// compile the fragment shader.
585+
NSError *ferr = nil;
586+
id<MTLLibrary> flib = [context.device newLibraryWithSource:fragmentSource options:nil error:&ferr];
587+
if(ferr) CCLOG(@"Error compiling metal fragment shader: %@", ferr);
588+
589+
id<MTLFunction> fragmentFunction = [flib newFunctionWithName:@"ShaderMain"];
590+
591+
// Done!
592+
return [self initWithMetalVertexFunction:vertexFunction fragmentFunction:fragmentFunction];
593+
}
594+
#endif
595+
596+
-(instancetype)initWithGLVertexShaderSource:(NSString *)vertexSource fragmentShaderSource:(NSString *)fragmentSource
597+
{
527598
__block typeof(self) blockself = self;
528599

529600
CCRenderDispatch(NO, ^{
@@ -555,6 +626,18 @@ -(instancetype)initWithVertexShaderSource:(NSString *)vertexSource fragmentShade
555626
return blockself;
556627
}
557628

629+
-(instancetype)initWithVertexShaderSource:(NSString *)vertexSource fragmentShaderSource:(NSString *)fragmentSource
630+
{
631+
#if __CC_METAL_SUPPORTED_AND_ENABLED
632+
if([CCConfiguration sharedConfiguration].graphicsAPI == CCGraphicsAPIMetal){
633+
return [self initWithMetalVertexShaderSource:vertexSource fragmentShaderSource:fragmentSource];
634+
}
635+
#endif
636+
{
637+
return [self initWithGLVertexShaderSource:vertexSource fragmentShaderSource:fragmentSource];
638+
}
639+
}
640+
558641
-(instancetype)initWithFragmentShaderSource:(NSString *)source
559642
{
560643
return [self initWithVertexShaderSource:CCDefaultVShader fragmentShaderSource:source];

cocos2d/Platforms/iOS/CCShaders.metal

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ CCFragmentFunctionDefaultTextureA8Color(
7373

7474
fragment half4
7575
CCFragmentFunctionUnsupported(
76-
const CCFragData in [[stage_in]],
77-
texture2d<half> cc_MainTexture [[texture(0)]]
76+
const CCFragData in [[stage_in]]
7877
){
7978
return half4(1, 0, 1, 1);
8079
}

0 commit comments

Comments
 (0)