1- #import " CCTexture .h"
1+ #import " CCTexture_Private .h"
22#import " CCNode_Private.h"
33#import " CCSprite_Private.h"
44#import " CCRenderer_Private.h"
55#import " CCShader_Private.h"
66
7+ #if __CC_METAL_SUPPORTED_AND_ENABLED
8+ #import " CCMetalSupport_Private.h"
9+ #endif
10+
711
812@implementation CCNode (NoARC)
913
@@ -166,20 +170,44 @@ -(CCRenderBuffer)enqueueLines:(NSUInteger)lineCount andVertexes:(NSUInteger)vert
166170 return (CCRenderBuffer){vertexes, elements, firstVertex};
167171}
168172
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+
169196@end
170197
171198@interface CCRenderStateGL : CCRenderState @end
172199@implementation CCRenderStateGL
173200
174- -(void )transitionRenderer : (CCRenderer *)renderer FromState : (CCRenderState *)previous
201+ static void
202+ CCRenderStateGLTransition (CCRenderStateGL *self, CCRenderer *renderer, CCRenderStateGL *previous)
175203{
176204 CCGL_DEBUG_PUSH_GROUP_MARKER (" CCRenderStateGL: Transition" );
177205
178206 // Set the blending state.
179- if (previous == nil || _blendMode != previous->_blendMode ){
207+ if (previous == nil || self-> _blendMode != previous->_blendMode ){
180208 CCGL_DEBUG_INSERT_EVENT_MARKER (" Blending mode" );
181209
182- NSDictionary *blendOptions = _blendMode->_options ;
210+ NSDictionary *blendOptions = self-> _blendMode ->_options ;
183211 if (blendOptions == CCBLEND_DISABLED_OPTIONS){
184212 glDisable (GL_BLEND);
185213 } else {
@@ -200,26 +228,213 @@ -(void)transitionRenderer:(CCRenderer *)renderer FromState:(CCRenderState *)prev
200228 }
201229
202230 // Bind the shader.
203- if (previous == nil || _shader != previous->_shader ){
231+ if (previous == nil || self-> _shader != previous->_shader ){
204232 CCGL_DEBUG_INSERT_EVENT_MARKER (" Shader" );
205233
206- glUseProgram (_shader->_program );
234+ glUseProgram (self-> _shader ->_program );
207235 }
208236
209237 // Set the shader's uniform state.
210- if (previous == nil || _shaderUniforms != previous->_shaderUniforms ){
238+ if (previous == nil || self-> _shaderUniforms != previous->_shaderUniforms ){
211239 CCGL_DEBUG_INSERT_EVENT_MARKER (" Uniforms" );
212240
213241 NSDictionary *globalShaderUniforms = renderer->_globalShaderUniforms ;
214- NSDictionary *setters = _shader->_uniformSetters ;
242+ NSDictionary *setters = self-> _shader ->_uniformSetters ;
215243 for (NSString *uniformName in setters){
216244 CCUniformSetter setter = setters[uniformName];
217- setter (renderer, _shaderUniforms, globalShaderUniforms);
245+ setter (renderer, self-> _shaderUniforms , globalShaderUniforms);
218246 }
219247 }
220248
221249 CCGL_DEBUG_POP_GROUP_MARKER ();
222250 CC_CHECK_GL_ERROR_DEBUG ();
223251}
224252
253+ -(void )transitionRenderer : (CCRenderer *)renderer FromState : (CCRenderStateGL *)previous
254+ {
255+ CCRenderStateGLTransition (self, renderer, previous);
256+ }
257+
225258@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