Skip to content

Commit 459c431

Browse files
committed
Moving some Metal rendering code to CCNoARC.m. Avoiding some more method calls.
1 parent 3e133b9 commit 459c431

File tree

6 files changed

+252
-195
lines changed

6 files changed

+252
-195
lines changed

CCRendererGLSupport.m

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -237,27 +237,3 @@ -(void)bind:(BOOL)bind
237237
}
238238

239239
@end
240-
241-
242-
@interface CCRenderCommandDrawGL : CCRenderCommandDraw @end
243-
@implementation CCRenderCommandDrawGL
244-
245-
static const CCRenderCommandDrawMode GLDrawModes[] = {
246-
GL_TRIANGLES,
247-
GL_LINES,
248-
};
249-
250-
-(void)invokeOnRenderer:(CCRenderer *)renderer
251-
{
252-
CCGL_DEBUG_PUSH_GROUP_MARKER("CCRendererCommandDraw: Invoke");
253-
254-
[renderer bindBuffers:YES];
255-
renderer.renderState = _renderState;
256-
257-
glDrawElements(GLDrawModes[_mode], (GLsizei)_count, GL_UNSIGNED_SHORT, (GLvoid *)(_first*sizeof(GLushort)));
258-
CC_INCREMENT_GL_DRAWS(1);
259-
260-
CCGL_DEBUG_POP_GROUP_MARKER();
261-
}
262-
263-
@end

cocos2d/CCNoARC.m

Lines changed: 224 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
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

cocos2d/CCRenderer.m

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,10 @@ -(instancetype)init
545545

546546
_threadsafe = YES;
547547
_queue = [NSMutableArray array];
548+
549+
#warning TEMP
550+
// Should probably change the init method to pass this in?
551+
_context = [NSClassFromString(@"CCMetalContext") currentContext];
548552
}
549553

550554
return self;
@@ -577,23 +581,9 @@ -(void)setGlobalShaderUniforms:(NSDictionary *)globalShaderUniforms
577581
#define glBindVertexArray glBindVertexArrayOES
578582
#endif
579583

580-
-(void)bindBuffers:(BOOL)bind
581-
{
582-
if(bind != _buffersBound){
583-
[_bufferBindings bind:bind];
584-
_buffersBound = bind;
585-
}
586-
}
587-
588-
-(void)setRenderState:(CCRenderState *)renderState
589-
{
590-
if(renderState != _renderState){
591-
[renderState transitionRenderer:self FromState:_renderState];
592-
_renderState = renderState;
593-
}
594-
}
595-
596584
//Implemented in CCNoARC.m
585+
//-(void)bindBuffers:(BOOL)bind
586+
//-(void)setRenderState:(CCRenderState *)renderState
597587
//-(CCRenderBuffer)enqueueTriangles:(NSUInteger)triangleCount andVertexes:(NSUInteger)vertexCount withState:(CCRenderState *)renderState globalSortOrder:(NSInteger)globalSortOrder;
598588
//-(CCRenderBuffer)enqueueLines:(NSUInteger)lineCount andVertexes:(NSUInteger)vertexCount withState:(CCRenderState *)renderState globalSortOrder:(NSInteger)globalSortOrder;
599589

cocos2d/CCRenderer_private.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,9 @@ extern NSDictionary *CCBLEND_DISABLED_OPTIONS;
6868

6969

7070
@interface CCRenderState(){
71-
@private
71+
@public
7272
CCTexture *_mainTexture;
7373
BOOL _immutable;
74-
75-
@public
7674
CCBlendMode *_blendMode;
7775
CCShader *_shader;
7876
NSDictionary *_shaderUniforms;
@@ -189,6 +187,9 @@ CCGraphicsBufferPushElements(CCGraphicsBuffer *buffer, size_t requestedCount, CC
189187
__unsafe_unretained CCRenderState *_renderState;
190188
__unsafe_unretained CCRenderCommandDraw *_lastDrawCommand;
191189
BOOL _buffersBound;
190+
191+
// Currently used for associating a metal context with a given renderer.
192+
id _context;
192193
}
193194

194195
/// Current global shader uniform values.
@@ -206,14 +207,14 @@ CCGraphicsBufferPushElements(CCGraphicsBuffer *buffer, size_t requestedCount, CC
206207
/// Render any currently queued commands.
207208
-(void)flush;
208209

209-
/// Bind the renderer's VAO if it is not currently bound.
210-
-(void)bindBuffers:(BOOL)bind;
211-
212210
@end
213211

214212

215213
@interface CCRenderer(NoARCPrivate)
216214

217215
-(void)setRenderState:(CCRenderState *)renderState;
218216

217+
/// Bind the renderer's VAO if it is not currently bound.
218+
-(void)bindBuffers:(BOOL)bind;
219+
219220
@end

0 commit comments

Comments
 (0)