1
- #import " CCTexture .h"
1
+ #import " CCTexture_Private .h"
2
2
#import " CCNode_Private.h"
3
3
#import " CCSprite_Private.h"
4
4
#import " CCRenderer_Private.h"
5
5
#import " CCShader_Private.h"
6
6
7
+ #if __CC_METAL_SUPPORTED_AND_ENABLED
8
+ #import " CCMetalSupport_Private.h"
9
+ #endif
10
+
7
11
8
12
@implementation CCNode (NoARC)
9
13
@@ -166,20 +170,44 @@ -(CCRenderBuffer)enqueueLines:(NSUInteger)lineCount andVertexes:(NSUInteger)vert
166
170
return (CCRenderBuffer){vertexes, elements, firstVertex};
167
171
}
168
172
173
+ static inline void
174
+ CCRendererBindBuffers (CCRenderer *self, BOOL bind)
175
+ {
176
+ if (bind != self->_buffersBound ){
177
+ [self ->_bufferBindings bind: bind];
178
+ self->_buffersBound = bind;
179
+ }
180
+ }
181
+
182
+ -(void )bindBuffers : (BOOL )bind
183
+ {
184
+ CCRendererBindBuffers (self, bind);
185
+ }
186
+
187
+
188
+ -(void )setRenderState : (CCRenderState *)renderState
189
+ {
190
+ if (renderState != _renderState){
191
+ [renderState transitionRenderer: self FromState: _renderState];
192
+ _renderState = renderState;
193
+ }
194
+ }
195
+
169
196
@end
170
197
171
198
@interface CCRenderStateGL : CCRenderState @end
172
199
@implementation CCRenderStateGL
173
200
174
- -(void )transitionRenderer : (CCRenderer *)renderer FromState : (CCRenderState *)previous
201
+ static void
202
+ CCRenderStateGLTransition (CCRenderStateGL *self, CCRenderer *renderer, CCRenderStateGL *previous)
175
203
{
176
204
CCGL_DEBUG_PUSH_GROUP_MARKER (" CCRenderStateGL: Transition" );
177
205
178
206
// Set the blending state.
179
- if (previous == nil || _blendMode != previous->_blendMode ){
207
+ if (previous == nil || self-> _blendMode != previous->_blendMode ){
180
208
CCGL_DEBUG_INSERT_EVENT_MARKER (" Blending mode" );
181
209
182
- NSDictionary *blendOptions = _blendMode->_options ;
210
+ NSDictionary *blendOptions = self-> _blendMode ->_options ;
183
211
if (blendOptions == CCBLEND_DISABLED_OPTIONS){
184
212
glDisable (GL_BLEND);
185
213
} else {
@@ -200,26 +228,213 @@ -(void)transitionRenderer:(CCRenderer *)renderer FromState:(CCRenderState *)prev
200
228
}
201
229
202
230
// Bind the shader.
203
- if (previous == nil || _shader != previous->_shader ){
231
+ if (previous == nil || self-> _shader != previous->_shader ){
204
232
CCGL_DEBUG_INSERT_EVENT_MARKER (" Shader" );
205
233
206
- glUseProgram (_shader->_program );
234
+ glUseProgram (self-> _shader ->_program );
207
235
}
208
236
209
237
// Set the shader's uniform state.
210
- if (previous == nil || _shaderUniforms != previous->_shaderUniforms ){
238
+ if (previous == nil || self-> _shaderUniforms != previous->_shaderUniforms ){
211
239
CCGL_DEBUG_INSERT_EVENT_MARKER (" Uniforms" );
212
240
213
241
NSDictionary *globalShaderUniforms = renderer->_globalShaderUniforms ;
214
- NSDictionary *setters = _shader->_uniformSetters ;
242
+ NSDictionary *setters = self-> _shader ->_uniformSetters ;
215
243
for (NSString *uniformName in setters){
216
244
CCUniformSetter setter = setters[uniformName];
217
- setter (renderer, _shaderUniforms, globalShaderUniforms);
245
+ setter (renderer, self-> _shaderUniforms , globalShaderUniforms);
218
246
}
219
247
}
220
248
221
249
CCGL_DEBUG_POP_GROUP_MARKER ();
222
250
CC_CHECK_GL_ERROR_DEBUG ();
223
251
}
224
252
253
+ -(void )transitionRenderer : (CCRenderer *)renderer FromState : (CCRenderStateGL *)previous
254
+ {
255
+ CCRenderStateGLTransition (self, renderer, previous);
256
+ }
257
+
225
258
@end
259
+
260
+ @interface CCRenderCommandDrawGL : CCRenderCommandDraw @end
261
+ @implementation CCRenderCommandDrawGL
262
+
263
+ static const CCRenderCommandDrawMode GLDrawModes[] = {
264
+ GL_TRIANGLES,
265
+ GL_LINES,
266
+ };
267
+
268
+ -(void )invokeOnRenderer : (CCRenderer *)renderer
269
+ {
270
+ CCGL_DEBUG_PUSH_GROUP_MARKER (" CCRendererCommandDraw: Invoke" );
271
+
272
+ CCRendererBindBuffers (renderer, YES );
273
+ CCRenderStateGLTransition ((CCRenderStateGL *)_renderState, renderer, (CCRenderStateGL *)renderer->_renderState );
274
+ renderer->_renderState = _renderState;
275
+
276
+ glDrawElements (GLDrawModes[_mode], (GLsizei)_count, GL_UNSIGNED_SHORT, (GLvoid *)(_first*sizeof (GLushort)));
277
+ CC_INCREMENT_GL_DRAWS (1 );
278
+
279
+ CCGL_DEBUG_POP_GROUP_MARKER ();
280
+ }
281
+
282
+ @end
283
+
284
+
285
+ #if __CC_METAL_SUPPORTED_AND_ENABLED
286
+
287
+ // This is effectively hardcoded to 10 by Apple's docs and there is no API to query capabilities...
288
+ // Seems like an oversight, but whatever.
289
+ #define CCMTL_MAX_TEXTURES 10
290
+
291
+
292
+ @interface CCRenderStateMetal : CCRenderState @end
293
+ @implementation CCRenderStateMetal {
294
+ id <MTLRenderPipelineState > _renderPipelineState;
295
+
296
+ NSRange _textureRange;
297
+ id <MTLSamplerState > _samplers[CCMTL_MAX_TEXTURES];
298
+ id <MTLTexture > _textures[CCMTL_MAX_TEXTURES];
299
+
300
+ @public
301
+ BOOL _uniformsPrepared;
302
+ }
303
+
304
+ // Using GL enums for CCBlendMode types should never have happened. Oops.
305
+ static NSUInteger
306
+ GLBLEND_TO_METAL (NSNumber *glenum)
307
+ {
308
+ switch (glenum.unsignedIntValue ){
309
+ case GL_ZERO: return MTLBlendFactorZero ;
310
+ case GL_ONE: return MTLBlendFactorOne ;
311
+ case GL_SRC_COLOR: return MTLBlendFactorSourceColor ;
312
+ case GL_ONE_MINUS_SRC_COLOR: return MTLBlendFactorOneMinusSourceColor ;
313
+ case GL_SRC_ALPHA: return MTLBlendFactorSourceAlpha ;
314
+ case GL_ONE_MINUS_SRC_ALPHA: return MTLBlendFactorOneMinusSourceAlpha ;
315
+ case GL_DST_COLOR: return MTLBlendFactorDestinationColor ;
316
+ case GL_ONE_MINUS_DST_COLOR: return MTLBlendFactorOneMinusDestinationColor ;
317
+ case GL_DST_ALPHA: return MTLBlendFactorDestinationAlpha ;
318
+ case GL_ONE_MINUS_DST_ALPHA: return MTLBlendFactorOneMinusDestinationAlpha ;
319
+ case GL_FUNC_ADD: return MTLBlendOperationAdd ;
320
+ case GL_FUNC_SUBTRACT: return MTLBlendOperationSubtract ;
321
+ case GL_FUNC_REVERSE_SUBTRACT: return MTLBlendOperationReverseSubtract ;
322
+ case GL_MIN_EXT: return MTLBlendOperationMin ;
323
+ case GL_MAX_EXT: return MTLBlendOperationMax ;
324
+ default :
325
+ NSCAssert (NO , @" Bad enumeration detected in a CCBlendMode. 0x%X " , glenum.unsignedIntValue);
326
+ return 0 ;
327
+ }
328
+ }
329
+
330
+ static void
331
+ CCRenderStateMetalPrepare (CCRenderStateMetal *self)
332
+ {
333
+ if (self->_renderPipelineState == nil ){
334
+ #warning Should get this from the renderer somehow.
335
+ CCMetalContext *context = [CCMetalContext currentContext ];
336
+
337
+ MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc ] init ];
338
+ pipelineStateDescriptor.sampleCount = 1 ;
339
+
340
+ id <MTLLibrary > library = context.library ;
341
+ #warning TEMP Hard coded shaders.
342
+ pipelineStateDescriptor.vertexFunction = [library newFunctionWithName: @" CCVertexFunctionDefault" ];
343
+ if (self->_shader == [CCShader positionColorShader ]){
344
+ pipelineStateDescriptor.fragmentFunction = [library newFunctionWithName: @" CCFragmentFunctionDefaultColor" ];
345
+ } else if (self->_shader == [CCShader positionTextureColorShader ]){
346
+ pipelineStateDescriptor.fragmentFunction = [library newFunctionWithName: @" CCFragmentFunctionDefaultTextureColor" ];
347
+ } else if (self->_shader == [CCShader positionTextureA8ColorShader ]){
348
+ pipelineStateDescriptor.fragmentFunction = [library newFunctionWithName: @" CCFragmentFunctionDefaultTextureA8Color" ];
349
+ } else {
350
+ pipelineStateDescriptor.fragmentFunction = [library newFunctionWithName: @" TempUnsupported" ];
351
+ }
352
+
353
+ NSDictionary *blendOptions = self->_blendMode .options ;
354
+ MTLRenderPipelineColorAttachmentDescriptor *colorDescriptor = [MTLRenderPipelineColorAttachmentDescriptor new ];
355
+ colorDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm ;
356
+ colorDescriptor.blendingEnabled = (blendOptions != CCBLEND_DISABLED_OPTIONS);
357
+ colorDescriptor.sourceRGBBlendFactor = GLBLEND_TO_METAL (blendOptions[CCBlendFuncSrcColor]);
358
+ colorDescriptor.sourceAlphaBlendFactor = GLBLEND_TO_METAL (blendOptions[CCBlendFuncSrcAlpha]);
359
+ colorDescriptor.destinationRGBBlendFactor = GLBLEND_TO_METAL (blendOptions[CCBlendFuncDstColor]);
360
+ colorDescriptor.destinationAlphaBlendFactor = GLBLEND_TO_METAL (blendOptions[CCBlendFuncDstAlpha]);
361
+ colorDescriptor.rgbBlendOperation = GLBLEND_TO_METAL (blendOptions[CCBlendEquationColor]);
362
+ colorDescriptor.alphaBlendOperation = GLBLEND_TO_METAL (blendOptions[CCBlendEquationAlpha]);
363
+ pipelineStateDescriptor.colorAttachments [0 ] = colorDescriptor;
364
+
365
+ self->_renderPipelineState = [[context.device newRenderPipelineStateWithDescriptor: pipelineStateDescriptor error: nil ] retain ];
366
+ }
367
+
368
+ if (!self->_uniformsPrepared ){
369
+ CCTexture *mainTexture = self->_shaderUniforms [CCShaderUniformMainTexture];
370
+
371
+ self->_textureRange = NSMakeRange (0 , 1 );
372
+ self->_samplers [0 ] = mainTexture.metalSampler ;
373
+ self->_textures [0 ] = mainTexture.metalTexture ;
374
+
375
+ self->_uniformsPrepared = YES ;
376
+ }
377
+ }
378
+
379
+ static void
380
+ CCRenderStateMetalTransition (CCRenderStateMetal *self, CCRenderer *renderer, CCRenderStateMetal *previous)
381
+ {
382
+ CCMetalContext *context = renderer->_context ;
383
+ id <MTLRenderCommandEncoder > renderEncoder = context->_currentRenderCommandEncoder ;
384
+ [renderEncoder setRenderPipelineState: self ->_renderPipelineState];
385
+
386
+ NSRange range = self->_textureRange ;
387
+ [renderEncoder setFragmentSamplerStates: self ->_samplers withRange: range];
388
+ [renderEncoder setFragmentTextures: self ->_textures withRange: range];
389
+ }
390
+
391
+ -(void )transitionRenderer : (CCRenderer *)renderer FromState : (CCRenderState *)previous
392
+ {
393
+ CCRenderStateMetalTransition ((CCRenderStateMetal *)self, renderer, (CCRenderStateMetal *)previous);
394
+ }
395
+
396
+ @end
397
+
398
+ @implementation CCRenderCommandDrawMetal
399
+
400
+ static const MTLPrimitiveType MetalDrawModes[] = {
401
+ MTLPrimitiveTypeTriangle ,
402
+ MTLPrimitiveTypeLine ,
403
+ };
404
+
405
+ -(instancetype )initWithMode : (CCRenderCommandDrawMode)mode renderState : (CCRenderState *)renderState first : (NSUInteger )first count : (size_t )count globalSortOrder : (NSInteger )globalSortOrder
406
+ {
407
+ if ((self = [super initWithMode: mode renderState: renderState first: first count: count globalSortOrder: globalSortOrder])){
408
+ CCRenderStateMetalPrepare ((CCRenderStateMetal *)renderState);
409
+ }
410
+
411
+ return self;
412
+ }
413
+
414
+ -(void )invokeOnRenderer : (CCRenderer *)renderer
415
+ {
416
+ CCMetalContext *context = renderer->_context ;
417
+ id <MTLRenderCommandEncoder > renderEncoder = context->_currentRenderCommandEncoder ;
418
+ id <MTLBuffer > indexBuffer = ((CCGraphicsBufferMetal *)renderer->_elementBuffer )->_buffer ;
419
+
420
+ CCMTL_DEBUG_PUSH_GROUP_MARKER (renderEncoder, @" CCRendererCommandDraw: Invoke" );
421
+ CCRendererBindBuffers (renderer, YES );
422
+ CCRenderStateMetalTransition ((CCRenderStateMetal *)_renderState, renderer, (CCRenderStateMetal *)renderer->_renderState );
423
+ renderer->_renderState = _renderState;
424
+
425
+ [renderEncoder drawIndexedPrimitives: MetalDrawModes[_mode] indexCount: _count indexType: MTLIndexTypeUInt16 indexBuffer: indexBuffer indexBufferOffset: 2 *_first];
426
+ CCMTL_DEBUG_POP_GROUP_MARKER (renderEncoder);
427
+
428
+ if (!_renderState->_immutable ){
429
+ // This is sort of a weird place to put this, but couldn't find somewhere better.
430
+ // Mutable render states need to have their uniforms redone at least once per frame.
431
+ // Putting it here ensures that it's been after all render commands for the frame have prepared it.
432
+ ((CCRenderStateMetal *)_renderState)->_uniformsPrepared = NO ;
433
+ }
434
+
435
+ CC_INCREMENT_GL_DRAWS (1 );
436
+ }
437
+
438
+ @end
439
+
440
+ #endif
0 commit comments