35
35
#import " CCConfiguration.h"
36
36
#import " CCMetalSupport_Private.h"
37
37
38
+ // Vertex shader that performs the modelview-projection multiplication on the GPU.
39
+ // Faster for draw nodes that draw many vertexes, but can't be batched.
40
+ static NSString *CCDrawNodeHWTransformVertexShaderSource =
41
+ @" uniform highp mat4 u_MVP;\n "
42
+ @" void main(){\n "
43
+ @" gl_Position = u_MVP*cc_Position;\n "
44
+ @" cc_FragColor = clamp(cc_Color, 0.0, 1.0);\n "
45
+ @" cc_FragTexCoord1 = cc_TexCoord1;\n "
46
+ @" }\n " ;
47
+
38
48
#ifdef ANDROID // Many Android devices do NOT support GL_OES_standard_derivatives correctly
39
- static NSString *CCDrawNodeShaderSource =
49
+ static NSString *CCDrawNodeFragmentShaderSource =
40
50
@" void main(){\n "
41
51
@" gl_FragColor = cc_FragColor*step(0.0, 1.0 - length(cc_FragTexCoord1));\n "
42
52
@" }\n " ;
43
53
#else
44
- static NSString *CCDrawNodeShaderSource =
54
+ static NSString *CCDrawNodeFragmentShaderSource =
45
55
@" #ifdef GL_ES\n "
46
56
@" #extension GL_OES_standard_derivatives : enable\n "
47
57
@" #endif\n "
@@ -55,31 +65,35 @@ @implementation CCDrawNode {
55
65
GLsizei _vertexCount, _vertexCapacity;
56
66
CCVertex *_vertexes;
57
67
58
- GLsizei _elementCount, _elementCapacity;
59
- GLushort *_elements;
68
+ GLsizei _indexCount, _indexCapacity;
69
+ GLushort *_indexes;
70
+
71
+ BOOL _useBatchMode;
60
72
}
61
73
62
- + (CCShader *)fragmentShader
74
+ CCShader *CCDRAWNODE_HWTRANSFORM_SHADER = nil ;
75
+ CCShader *CCDRAWNODE_BATCH_SHADER = nil ;
76
+
77
+ +(void )initialize
63
78
{
64
- static CCShader *shader = nil ;
65
- static dispatch_once_t once = 0L ;
66
- dispatch_once (&once, ^{
67
79
#if __CC_METAL_SUPPORTED_AND_ENABLED
68
- if ([CCConfiguration sharedConfiguration ].graphicsAPI == CCGraphicsAPIMetal){
69
- id <MTLLibrary > library = [CCMetalContext currentContext ].library ;
70
- NSAssert (library, @" Metal shader library not found." );
71
-
72
- id <MTLFunction > vertexFunc = [library newFunctionWithName: @" CCVertexFunctionDefault" ];
73
-
74
- shader = [[CCShader alloc ] initWithMetalVertexFunction: vertexFunc fragmentFunction: [library newFunctionWithName: @" CCFragmentFunctionDefaultDrawNode" ]];
75
- shader .debugName = @" CCFragmentFunctionDefaultDrawNode" ;
76
- } else
80
+ if ([CCConfiguration sharedConfiguration ].graphicsAPI == CCGraphicsAPIMetal){
81
+ id <MTLLibrary > library = [CCMetalContext currentContext ].library ;
82
+ NSAssert (library, @" Metal shader library not found." );
83
+
84
+ id <MTLFunction > vertexFunc = [library newFunctionWithName: @" CCVertexFunctionDefault" ];
85
+
86
+ CCDRAWNODE_BATCH_SHADER = [[CCShader alloc ] initWithMetalVertexFunction: vertexFunc fragmentFunction: [library newFunctionWithName: @" CCFragmentFunctionDefaultDrawNode" ]];
87
+ CCDRAWNODE_BATCH_SHADER .debugName = @" CCFragmentFunctionDefaultDrawNode" ;
88
+ } else
77
89
#endif
78
- {
79
- shader = [[CCShader alloc ] initWithFragmentShaderSource: CCDrawNodeShaderSource];
80
- }
81
- });
82
- return shader;
90
+ {
91
+ CCDRAWNODE_HWTRANSFORM_SHADER = [[CCShader alloc ] initWithVertexShaderSource: CCDrawNodeHWTransformVertexShaderSource fragmentShaderSource: CCDrawNodeFragmentShaderSource];
92
+ CCDRAWNODE_HWTRANSFORM_SHADER.debugName = @" CCDRAWNODE_HWTRANSFORM_SHADER" ;
93
+
94
+ CCDRAWNODE_BATCH_SHADER = [[CCShader alloc ] initWithFragmentShaderSource: CCDrawNodeFragmentShaderSource];
95
+ CCDRAWNODE_BATCH_SHADER.debugName = @" CCDRAWNODE_BATCH_SHADER" ;
96
+ }
83
97
}
84
98
85
99
#pragma mark memory
@@ -88,44 +102,47 @@ -(CCRenderBuffer)bufferVertexes:(GLsizei)vertexCount andTriangleCount:(GLsizei)t
88
102
{
89
103
GLsizei requiredVertexes = _vertexCount + vertexCount;
90
104
if (requiredVertexes > _vertexCapacity){
91
- // Double the size of the buffer until it fits.
92
- while (requiredVertexes >= _vertexCapacity) _vertexCapacity *= 2 ;
93
-
105
+ _vertexCapacity = requiredVertexes*1.5 ;
94
106
_vertexes = realloc (_vertexes, _vertexCapacity*sizeof (*_vertexes));
95
107
}
96
108
97
- GLsizei elementCount = 3 *triangleCount;
98
- GLsizei requiredElements = _elementCount + elementCount;
99
- if (requiredElements > _elementCapacity){
100
- // Double the size of the buffer until it fits.
101
- while (requiredElements >= _elementCapacity) _elementCapacity *= 2 ;
102
-
103
- _elements = realloc (_elements, _elementCapacity*sizeof (*_elements));
109
+ GLsizei indexCount = 3 *triangleCount;
110
+ GLsizei requiredIndexes = _indexCount + indexCount;
111
+ if (requiredIndexes > _indexCapacity){
112
+ _indexCapacity = requiredIndexes*1.5 ;
113
+ _indexes = realloc (_indexes, _indexCapacity*sizeof (*_indexes));
104
114
}
105
115
106
116
CCRenderBuffer buffer = {
107
117
_vertexes + _vertexCount,
108
- _elements + _elementCount ,
118
+ _indexes + _indexCount ,
109
119
_vertexCount
110
120
};
111
121
112
122
_vertexCount += vertexCount;
113
- _elementCount += elementCount ;
123
+ _indexCount += indexCount ;
114
124
115
125
return buffer;
116
126
}
117
127
118
128
-(id )init
119
129
{
120
130
if ((self = [super init ])){
121
- self.blendMode = [CCBlendMode premultipliedAlphaMode ];
122
- self.shader = [CCDrawNode fragmentShader ];
131
+ _blendMode = [CCBlendMode premultipliedAlphaMode ];
132
+
133
+ if (CCDRAWNODE_HWTRANSFORM_SHADER){
134
+ _shader = CCDRAWNODE_HWTRANSFORM_SHADER;
135
+ } else {
136
+ // HWTransform shader not currently supported for Metal rendering.
137
+ _shader = CCDRAWNODE_BATCH_SHADER;
138
+ _useBatchMode = YES ;
139
+ }
123
140
124
141
_vertexCapacity = 128 ;
125
142
_vertexes = calloc (_vertexCapacity, sizeof (*_vertexes));
126
143
127
- _elementCapacity = 128 ;
128
- _elements = calloc (_elementCapacity , sizeof (*_elements ));
144
+ _indexCapacity = 128 ;
145
+ _indexes = calloc (_indexCapacity , sizeof (*_indexes ));
129
146
}
130
147
131
148
return self;
@@ -134,25 +151,61 @@ -(id)init
134
151
-(void )dealloc
135
152
{
136
153
free (_vertexes); _vertexes = NULL ;
137
- free (_elements ); _elements = NULL ;
154
+ free (_indexes ); _indexes = NULL ;
138
155
}
139
156
140
157
#pragma mark Rendering
141
158
159
+ -(void )enableBatchMode
160
+ {
161
+ _useBatchMode = YES ;
162
+
163
+ if (_shader == CCDRAWNODE_HWTRANSFORM_SHADER){
164
+ _shader = CCDRAWNODE_BATCH_SHADER;
165
+ }
166
+
167
+ // Reset the render state.
168
+ _renderState = nil ;
169
+ }
170
+
171
+ // Force batch mode on if the user changes the blendmode or shader.
172
+ -(void )setBlendMode : (CCBlendMode *)blendMode
173
+ {
174
+ [super setBlendMode: blendMode];
175
+ [self enableBatchMode ];
176
+ }
177
+
178
+ -(void )setShader : (CCShader *)shader
179
+ {
180
+ [super setShader: shader];
181
+ [self enableBatchMode ];
182
+ }
183
+
142
184
-(void )draw : (CCRenderer *)renderer transform : (const GLKMatrix4 *)transform
143
185
{
144
- if (_elementCount == 0 ) return ;
145
-
146
- CCRenderBuffer buffer = [renderer enqueueTriangles: _elementCount/3 andVertexes: _vertexCount withState: self .renderState globalSortOrder: 0 ];
186
+ if (_indexCount == 0 ) return ;
187
+
188
+ // If batch mode is disabled (default), update the MVP matrix in the uniforms.
189
+ if (!_useBatchMode){
190
+ self.shaderUniforms [@" u_MVP" ] = [NSValue valueWithGLKMatrix4: *transform];
191
+ }
192
+
193
+ CCRenderBuffer buffer = [renderer enqueueTriangles: _indexCount/3 andVertexes: _vertexCount withState: self .renderState globalSortOrder: 0 ];
147
194
148
- // TODO Maybe it would be even better to skip the CPU transform and use a uniform matrix?
149
- for (int i=0 ; i<_vertexCount; i++){
150
- CCRenderBufferSetVertex (buffer, i, CCVertexApplyTransform (_vertexes[i], transform));
151
- }
195
+ if (_useBatchMode){
196
+ // Transform the vertexes on the CPU.
197
+ for (int i=0 ; i<_vertexCount; i++){
198
+ CCRenderBufferSetVertex (buffer, i, CCVertexApplyTransform (_vertexes[i], transform));
199
+ }
200
+ } else {
201
+ // memcpy() the buffer and let the GPU handle the transform.
202
+ memcpy (buffer.vertexes , _vertexes, _vertexCount*sizeof (*_vertexes));
203
+ }
152
204
153
- for (int i=0 ; i<_elementCount; i++){
154
- buffer.elements [i] = _elements[i] + buffer.startIndex ;
155
- }
205
+ // Offset the indices.
206
+ for (int i=0 ; i<_indexCount; i++){
207
+ buffer.elements [i] = _indexes[i] + buffer.startIndex ;
208
+ }
156
209
}
157
210
158
211
#pragma mark Immediate Mode
@@ -290,7 +343,7 @@ -(void)drawPolyWithVerts:(const CGPoint *)_verts count:(NSUInteger)count fillCol
290
343
-(void )clear
291
344
{
292
345
_vertexCount = 0 ;
293
- _elementCount = 0 ;
346
+ _indexCount = 0 ;
294
347
}
295
348
296
349
@end
0 commit comments