Skip to content

Commit ae37cbc

Browse files
committed
Render textures working for Metal.
1 parent 009abb4 commit ae37cbc

File tree

7 files changed

+161
-109
lines changed

7 files changed

+161
-109
lines changed

CCRendererGLSupport.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ -(void)bind
374374

375375
-(void)syncWithView:(CC_VIEW<CCDirectorView> *)view;
376376
{
377+
#warning TODO this won't work for Mac. Need to expand the view protocol.
377378
CCGLView *glView = (CCGLView *)view;
378379
self.sizeInPixels = CC_SIZE_SCALE(view.bounds.size, view.contentScaleFactor);
379380
self.contentScale = view.contentScaleFactor;

cocos2d/CCEffectNode.m

Lines changed: 72 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -119,37 +119,37 @@ -(void)destroy
119119

120120
-(void)begin
121121
{
122-
CGSize pixelSize = self.texture.contentSizeInPixels;
123-
GLuint fbo = [self fbo];
124-
125-
[_renderer pushGroup];
126-
[_renderer enqueueBlock:^{
127-
glGetFloatv(GL_VIEWPORT, _oldViewport.v);
128-
glViewport(0, 0, pixelSize.width, pixelSize.height );
129-
130-
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_oldFBO);
131-
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
132-
133-
} globalSortOrder:NSIntegerMin debugLabel:@"CCEffectNode: Bind FBO" threadSafe:NO];
122+
// CGSize pixelSize = self.texture.contentSizeInPixels;
123+
// GLuint fbo = [self fbo];
124+
//
125+
// [_renderer pushGroup];
126+
// [_renderer enqueueBlock:^{
127+
// glGetFloatv(GL_VIEWPORT, _oldViewport.v);
128+
// glViewport(0, 0, pixelSize.width, pixelSize.height );
129+
//
130+
// glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_oldFBO);
131+
// glBindFramebuffer(GL_FRAMEBUFFER, fbo);
132+
//
133+
// } globalSortOrder:NSIntegerMin debugLabel:@"CCEffectNode: Bind FBO" threadSafe:NO];
134134
}
135135

136136
-(void)endWithDebugLabel:(NSString *)debugLabel
137137
{
138-
[_renderer enqueueBlock:^{
139-
glBindFramebuffer(GL_FRAMEBUFFER, _oldFBO);
140-
glViewport(_oldViewport.v[0], _oldViewport.v[1], _oldViewport.v[2], _oldViewport.v[3]);
141-
} globalSortOrder:NSIntegerMax debugLabel:@"CCEffectNode: Restore FBO" threadSafe:NO];
142-
143-
[_renderer popGroupWithDebugLabel:debugLabel globalSortOrder:0];
138+
// [_renderer enqueueBlock:^{
139+
// glBindFramebuffer(GL_FRAMEBUFFER, _oldFBO);
140+
// glViewport(_oldViewport.v[0], _oldViewport.v[1], _oldViewport.v[2], _oldViewport.v[3]);
141+
// } globalSortOrder:NSIntegerMax debugLabel:@"CCEffectNode: Restore FBO" threadSafe:NO];
142+
//
143+
// [_renderer popGroupWithDebugLabel:debugLabel globalSortOrder:0];
144144
}
145145

146146
-(void)visit
147147
{
148-
[self configureRender];
149-
NSAssert(_renderer, @"Cannot call [CCNode visit] without a currently bound renderer.");
150-
151-
GLKMatrix4 projection; [_renderer.globalShaderUniforms[CCShaderUniformProjection] getValue:&projection];
152-
[self visit:_renderer parentTransform:&projection];
148+
// [self configureRender];
149+
// NSAssert(_renderer, @"Cannot call [CCNode visit] without a currently bound renderer.");
150+
//
151+
// GLKMatrix4 projection; [_renderer.globalShaderUniforms[CCShaderUniformProjection] getValue:&projection];
152+
// [self visit:_renderer parentTransform:&projection];
153153
}
154154

155155
-(void)visit:(CCRenderer *)renderer parentTransform:(const GLKMatrix4 *)parentTransform
@@ -175,9 +175,9 @@ -(void)visit:(CCRenderer *)renderer parentTransform:(const GLKMatrix4 *)parentTr
175175

176176
-(void)configureRender
177177
{
178-
// bind renderer
179-
_renderer = [CCRenderer currentRenderer];
180-
178+
// // bind renderer
179+
// _renderer = [CCRenderer currentRenderer];
180+
//
181181
// if(_renderer == nil)
182182
// {
183183
// _renderer = [[CCRenderer alloc] init];
@@ -203,53 +203,53 @@ -(void)configureRender
203203

204204
-(void)draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform
205205
{
206-
[self configureRender];
207-
208-
NSAssert(_renderer == renderer, @"CCEffectNode error!");
209-
210-
// Render children of this effect node into an FBO for use by the
211-
// remainder of the effects.
212-
[self begin];
213-
214-
[_renderer enqueueClear:self.clearFlags color:_clearColor depth:self.clearDepth stencil:self.clearStencil globalSortOrder:NSIntegerMin];
215-
216-
//! make sure all children are drawn
217-
[self sortAllChildren];
218-
219-
for(CCNode *child in _children){
220-
if( child != _sprite) [child visit:renderer parentTransform:&_projection];
221-
}
222-
[self endWithDebugLabel:@"CCEffectNode: Pre-render pass"];
223-
224-
// Done pre-render
225-
226-
if (_effect)
227-
{
228-
_effectRenderer.contentSize = self.contentSizeInPoints;
229-
if ([_effect prepareForRendering] == CCEffectPrepareSuccess)
230-
{
231-
// Preparing an effect for rendering can modify its uniforms
232-
// dictionary which means we need to reinitialize our copy of the
233-
// uniforms.
234-
[self updateShaderUniformsFromEffect];
235-
}
236-
[_effectRenderer drawSprite:_sprite withEffect:_effect uniforms:_shaderUniforms renderer:_renderer transform:transform];
237-
}
238-
else
239-
{
240-
_sprite.anchorPoint = ccp(0.0f, 0.0f);
241-
_sprite.position = ccp(0.0f, 0.0f);
242-
[_sprite visit:_renderer parentTransform:transform];
243-
}
244-
245-
// if(_privateRenderer == NO)
246-
// ;
247-
// #warning FIXME
248-
//// _renderer.globalShaderUniforms = _oldGlobalUniforms;
206+
// [self configureRender];
207+
//
208+
// NSAssert(_renderer == renderer, @"CCEffectNode error!");
209+
//
210+
// // Render children of this effect node into an FBO for use by the
211+
// // remainder of the effects.
212+
// [self begin];
213+
//
214+
// [_renderer enqueueClear:self.clearFlags color:_clearColor depth:self.clearDepth stencil:self.clearStencil globalSortOrder:NSIntegerMin];
215+
//
216+
// //! make sure all children are drawn
217+
// [self sortAllChildren];
218+
//
219+
// for(CCNode *child in _children){
220+
// if( child != _sprite) [child visit:renderer parentTransform:&_projection];
221+
// }
222+
// [self endWithDebugLabel:@"CCEffectNode: Pre-render pass"];
223+
//
224+
// // Done pre-render
225+
//
226+
// if (_effect)
227+
// {
228+
// _effectRenderer.contentSize = self.contentSizeInPoints;
229+
// if ([_effect prepareForRendering] == CCEffectPrepareSuccess)
230+
// {
231+
// // Preparing an effect for rendering can modify its uniforms
232+
// // dictionary which means we need to reinitialize our copy of the
233+
// // uniforms.
234+
// [self updateShaderUniformsFromEffect];
235+
// }
236+
// [_effectRenderer drawSprite:_sprite withEffect:_effect uniforms:_shaderUniforms renderer:_renderer transform:transform];
237+
// }
249238
// else
250-
// [CCRenderer bindRenderer:nil];
251-
252-
_renderer = nil;
239+
// {
240+
// _sprite.anchorPoint = ccp(0.0f, 0.0f);
241+
// _sprite.position = ccp(0.0f, 0.0f);
242+
// [_sprite visit:_renderer parentTransform:transform];
243+
// }
244+
//
245+
//// if(_privateRenderer == NO)
246+
//// ;
247+
//// #warning FIXME
248+
////// _renderer.globalShaderUniforms = _oldGlobalUniforms;
249+
//// else
250+
//// [CCRenderer bindRenderer:nil];
251+
//
252+
// _renderer = nil;
253253
}
254254

255255
- (void)updateShaderUniformsFromEffect

cocos2d/CCRenderTexture.m

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ -(id)initWithWidth:(int)width height:(int)height pixelFormat:(CCTexturePixelForm
127127
_pixelFormat = format;
128128
_depthStencilFormat = depthStencilFormat;
129129

130-
// Flip the projection matrix on the y-axis since Cocos2D uses upside down textures.
131130
_projection = GLKMatrix4MakeOrtho(0.0f, width, 0.0f, height, -1024.0f, 1024.0f);
132131

133132
CCRenderTextureSprite *rtSprite = [CCRenderTextureSprite spriteWithTexture:[CCTexture none]];
@@ -230,8 +229,17 @@ -(CCRenderer *)begin
230229
texture = self.texture;
231230
}
232231

232+
GLKMatrix4 projection = _projection;
233+
234+
#if __CC_METAL_SUPPORTED_AND_ENABLED
235+
if([CCConfiguration sharedConfiguration].graphicsAPI == CCGraphicsAPIMetal){
236+
// Metal texture coordinates are inverted compared to GL.
237+
projection = GLKMatrix4Multiply(GLKMatrix4MakeScale(1.0, -1.0, 1.0), projection);
238+
}
239+
#endif
240+
233241
CCRenderer *renderer = [[CCDirector sharedDirector] rendererFromPool];
234-
[renderer prepareWithProjection:&_projection framebuffer:_framebuffer];
242+
[renderer prepareWithProjection:&projection framebuffer:_framebuffer];
235243

236244
_previousRenderer = [CCRenderer currentRenderer];
237245
[CCRenderer bindRenderer:renderer];

cocos2d/Platforms/iOS/CCMetalSupport.m

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@
2626
#import "CCMetalSupport_Private.h"
2727
#if __CC_METAL_SUPPORTED_AND_ENABLED
2828

29+
#import "CCMetalView.h"
2930
#import "CCTexture_Private.h"
3031
#import "CCShader_Private.h"
3132

32-
@implementation CCMetalContext
33+
@implementation CCMetalContext {
34+
id<MTLTexture> _destinationTexture;
35+
}
3336

3437
-(instancetype)init
3538
{
@@ -60,35 +63,37 @@ +(void)setCurrentContext:(CCMetalContext *)context
6063
}
6164
}
6265

63-
-(void)setDestinationTexture:(id<MTLTexture>)destinationTexture
66+
-(void)endRenderPass
6467
{
65-
if(_destinationTexture != destinationTexture){
66-
MTLRenderPassColorAttachmentDescriptor *colorAttachment = [MTLRenderPassColorAttachmentDescriptor new];
67-
colorAttachment.texture = destinationTexture;
68-
colorAttachment.loadAction = MTLLoadActionClear;
69-
colorAttachment.clearColor = MTLClearColorMake(0, 0, 0, 0);
70-
colorAttachment.storeAction = MTLStoreActionStore;
71-
72-
MTLRenderPassDescriptor *renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
73-
renderPassDescriptor.colorAttachments[0] = colorAttachment;
74-
75-
_currentRenderCommandEncoder = [self.currentCommandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
76-
_destinationTexture = destinationTexture;
77-
}
68+
[_currentRenderCommandEncoder endEncoding];
69+
_currentRenderCommandEncoder = nil;
7870
}
7971

80-
-(void)prepareCommandBuffer
72+
-(void)beginRenderPass:(id<MTLTexture>)destinationTexture;
8173
{
82-
_currentCommandBuffer = [_commandQueue commandBuffer];
83-
_currentCommandBuffer.label = @"Main Cocos2D Command Buffer";
74+
// End the previous render pass.
75+
[self endRenderPass];
76+
77+
MTLRenderPassColorAttachmentDescriptor *colorAttachment = [MTLRenderPassColorAttachmentDescriptor new];
78+
colorAttachment.texture = destinationTexture;
79+
colorAttachment.loadAction = MTLLoadActionClear;
80+
colorAttachment.clearColor = MTLClearColorMake(0, 0, 0, 0);
81+
colorAttachment.storeAction = MTLStoreActionStore;
82+
83+
MTLRenderPassDescriptor *renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
84+
renderPassDescriptor.colorAttachments[0] = colorAttachment;
85+
86+
_currentRenderCommandEncoder = [_currentCommandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
87+
_destinationTexture = destinationTexture;
8488
}
8589

86-
-(void)commitCurrentCommandBuffer
90+
-(void)flushCommandBuffer
8791
{
88-
[_currentRenderCommandEncoder endEncoding];
89-
92+
[self endRenderPass];
9093
[_currentCommandBuffer commit];
91-
_currentCommandBuffer = nil;
94+
95+
_currentCommandBuffer = [_commandQueue commandBuffer];
96+
_currentCommandBuffer.label = @"Main Cocos2D Command Buffer";
9297
}
9398

9499
@end
@@ -156,4 +161,34 @@ -(instancetype)init
156161

157162
@end
158163

164+
165+
@implementation CCFrameBufferObjectMetal
166+
167+
-(instancetype)initWithTexture:(CCTexture *)texture depthStencilFormat:(GLuint)depthStencilFormat
168+
{
169+
if((self = [super initWithTexture:texture depthStencilFormat:depthStencilFormat])){
170+
self.sizeInPixels = texture.contentSizeInPixels;
171+
self.contentScale = texture.contentScale;
172+
_frameBufferTexture = texture.metalTexture;
173+
}
174+
175+
return self;
176+
}
177+
178+
-(void)bind
179+
{
180+
[[CCMetalContext currentContext] beginRenderPass:_frameBufferTexture];
181+
}
182+
183+
-(void)syncWithView:(CC_VIEW<CCDirectorView> *)view;
184+
{
185+
CCMetalView *metalView = (CCMetalView *)view;
186+
self.sizeInPixels = CC_SIZE_SCALE(view.bounds.size, view.contentScaleFactor);
187+
self.contentScale = view.contentScaleFactor;
188+
189+
_frameBufferTexture = metalView.destinationTexture;
190+
}
191+
192+
@end
193+
159194
#endif

cocos2d/Platforms/iOS/CCMetalSupport_Private.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,14 @@
6666
@property(nonatomic, readonly) id<MTLCommandQueue> commandQueue;
6767
@property(nonatomic, readonly) id<MTLCommandBuffer> currentCommandBuffer;
6868

69-
@property(nonatomic, strong) id<MTLTexture> destinationTexture;
7069
@property(nonatomic, readonly) id<MTLRenderCommandEncoder> currentRenderCommandEncoder;
7170

7271
+(instancetype)currentContext;
7372
+(void)setCurrentContext:(CCMetalContext *)context;
7473

75-
-(void)prepareCommandBuffer;
76-
-(void)commitCurrentCommandBuffer;
74+
-(void)beginRenderPass:(id<MTLTexture>)destinationTexture;
75+
76+
-(void)flushCommandBuffer;
7777

7878
@end
7979

@@ -98,4 +98,10 @@
9898
@end
9999

100100

101+
@interface CCFrameBufferObjectMetal : CCFrameBufferObject
102+
103+
@property(nonatomic, strong) id<MTLTexture> frameBufferTexture;
104+
105+
@end
106+
101107
#endif

cocos2d/Platforms/iOS/CCMetalView.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
@interface CCMetalView : UIView<CCDirectorView>
1111

12+
@property(nonatomic, readonly, strong) id<MTLTexture> destinationTexture;
13+
1214
/** returns surface size in pixels */
1315
@property(nonatomic,readonly) CGSize surfaceSize;
1416

cocos2d/Platforms/iOS/CCMetalView.m

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,14 +141,6 @@ -(void)beginFrame
141141
_layerSizeDidUpdate = NO;
142142
}
143143

144-
[_context prepareCommandBuffer];
145-
146-
// Prevent the block from retaining self via the ivar.
147-
dispatch_semaphore_t sema = _queuedFramesSemaphore;
148-
[_context.currentCommandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer){
149-
dispatch_semaphore_signal(sema);
150-
}];
151-
152144
// id<CAMetalDrawable> drawable = nil;
153145
// while(drawable == nil){
154146
// drawable = [self.metalLayer nextDrawable];
@@ -160,12 +152,20 @@ -(void)beginFrame
160152
[_context.currentCommandBuffer presentDrawable:drawable];
161153

162154
_currentDrawable = drawable;
163-
_context.destinationTexture = drawable.texture;
155+
_destinationTexture = drawable.texture;
164156
}
165157

166158
- (void)presentFrame
167159
{
168-
[_context commitCurrentCommandBuffer];
160+
// Prevent the block from retaining self via the ivar.
161+
dispatch_semaphore_t sema = _queuedFramesSemaphore;
162+
[_context.currentCommandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer){
163+
dispatch_semaphore_signal(sema);
164+
}];
165+
166+
[_context flushCommandBuffer];
167+
168+
[_currentDrawable present];
169169
_currentDrawable = nil;
170170
}
171171

0 commit comments

Comments
 (0)