Skip to content

Commit 74b8dff

Browse files
committed
Hasty (but working) implementation of Metal textures.
1 parent 405a734 commit 74b8dff

File tree

5 files changed

+97
-35
lines changed

5 files changed

+97
-35
lines changed

cocos2d/CCLabelTTF.m

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#import "CCConfiguration.h"
3838
#import "CCNode_Private.h"
3939
#import "CCDirector.h"
40+
#import "CCTexture_Private.h"
4041
#import <Foundation/Foundation.h>
4142

4243
#if __CC_PLATFORM_IOS
@@ -54,15 +55,6 @@
5455
static __strong NSMutableDictionary* ccLabelTTF_registeredFonts;
5556

5657

57-
@implementation CCTexture (CCLabelTTF)
58-
59-
- (void) setPremultipliedAlpha:(BOOL)flag
60-
{
61-
_premultipliedAlpha = flag;
62-
}
63-
64-
@end
65-
6658
#pragma mark CCLabelTTF
6759

6860

cocos2d/CCTexture.h

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -118,24 +118,7 @@ typedef NS_ENUM(NSUInteger, CCTexturePixelFormat) {
118118
* - i.e. "contentSize" != (pixelsWide, pixelsHigh) and (maxS, maxT) != (1.0, 1.0).
119119
* Be aware that the content of the generated textures will be upside-down!
120120
*/
121-
@interface CCTexture : NSObject {
122-
GLuint _name;
123-
CGSize _sizeInPixels;
124-
CGFloat _contentScale;
125-
NSUInteger _width,
126-
_height;
127-
CCTexturePixelFormat _format;
128-
GLfloat _maxS,
129-
_maxT;
130-
BOOL _premultipliedAlpha;
131-
BOOL _hasMipmaps;
132-
133-
BOOL _antialiased;
134-
135-
// Needed for drawAtRect, drawInPoint.
136-
CCShader *_shaderProgram;
137-
}
138-
121+
@interface CCTexture : NSObject
139122

140123
/// -----------------------------------------------------------------------
141124
/// @name Initializing a CCTexture Object

cocos2d/CCTexture.m

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
8888
#import "CCTextureCache.h"
8989
#import "CCSpriteFrame.h"
9090

91+
#if __CC_METAL_SUPPORTED_AND_ENABLED
92+
#import "CCMetalSupport_Private.h"
93+
#endif
94+
9195

9296
//CLASS IMPLEMENTATIONS:
9397

@@ -113,7 +117,7 @@ -(BOOL)isKindOfClass:(Class)aClass {return [_target isKindOfClass:aClass];}
113117

114118
// Make concrete implementations for CCTexture methods commonly called at runtime.
115119
-(GLuint)name {return [(CCTexture *)_target name];}
116-
-(CGFloat)contentScale {return [_target contentScale];}
120+
-(CGFloat)contentScale {return [(CCTexture *)_target contentScale];}
117121
-(CGSize)contentSize {return [_target contentSize];}
118122
-(NSUInteger)pixelWidth {return [_target pixelWidth];}
119123
-(NSUInteger)pixelHeight {return [_target pixelHeight];}
@@ -122,7 +126,7 @@ -(CCSpriteFrame *)createSpriteFrame {return [_target createSpriteFrame];}
122126

123127
// Make concrete implementations for CCSpriteFrame methods commonly called at runtime.
124128
-(CGRect)rect {return [_target rect];}
125-
-(CGPoint)offset {return [_target offset];}
129+
-(CGPoint)offset {return [(CCSpriteFrame *)_target offset];}
126130
-(BOOL)rotated {return [_target rotated];}
127131
-(CGSize)originalSize {return [_target originalSize];}
128132
-(CCTexture *)texture {return [_target texture];}
@@ -152,7 +156,18 @@ - (void)dealloc
152156

153157
@implementation CCTexture
154158
{
155-
CCProxy __weak *_proxy;
159+
GLuint _name;
160+
CGSize _sizeInPixels;
161+
CGFloat _contentScale;
162+
NSUInteger _width, _height;
163+
CCTexturePixelFormat _format;
164+
GLfloat _maxS, _maxT;
165+
BOOL _premultipliedAlpha;
166+
BOOL _hasMipmaps;
167+
168+
BOOL _antialiased;
169+
170+
CCProxy __weak *_proxy;
156171
}
157172

158173
@synthesize contentSizeInPixels = _sizeInPixels, pixelFormat = _format, pixelWidth = _width, pixelHeight = _height, name = _name, maxS = _maxS, maxT = _maxT;
@@ -187,6 +202,42 @@ - (id) initWithData:(const void*)data pixelFormat:(CCTexturePixelFormat)pixelFor
187202
{
188203
if((self = [super init])) {
189204
CCRenderDispatch(NO, ^{
205+
#if __CC_METAL_SUPPORTED_AND_ENABLED
206+
if([CCConfiguration sharedConfiguration].graphicsAPI == CCGraphicsAPIMetal){
207+
id<MTLDevice> device = [CCMetalContext currentContext].device;
208+
209+
MTLSamplerDescriptor *samplerDesc = [MTLSamplerDescriptor new];
210+
samplerDesc.minFilter = MTLSamplerMinMagFilterLinear;
211+
samplerDesc.magFilter = MTLSamplerMinMagFilterLinear;
212+
samplerDesc.mipFilter = MTLSamplerMipFilterNotMipmapped;
213+
samplerDesc.sAddressMode = MTLSamplerAddressModeClampToEdge;
214+
samplerDesc.tAddressMode = MTLSamplerAddressModeClampToEdge;
215+
216+
_metalSampler = [device newSamplerStateWithDescriptor:samplerDesc];
217+
218+
static const MTLPixelFormat metalFormats[] = {
219+
MTLPixelFormatRGBA8Unorm,
220+
MTLPixelFormatInvalid, //CCTexturePixelFormat_RGB888,
221+
MTLPixelFormatInvalid, //CCTexturePixelFormat_RGB565,
222+
MTLPixelFormatA8Unorm, //CCTexturePixelFormat_A8,
223+
MTLPixelFormatRG8Unorm, //CCTexturePixelFormat_I8,
224+
MTLPixelFormatInvalid, //CCTexturePixelFormat_AI88,
225+
MTLPixelFormatABGR4Unorm, //CCTexturePixelFormat_RGBA4444,
226+
MTLPixelFormatInvalid, //CCTexturePixelFormat_RGB5A1,
227+
MTLPixelFormatPVRTC_RGBA_4BPP, //CCTexturePixelFormat_PVRTC4,
228+
MTLPixelFormatPVRTC_RGBA_2BPP, //CCTexturePixelFormat_PVRTC2,
229+
};
230+
MTLPixelFormat metalFormat = metalFormats[pixelFormat];
231+
NSAssert(metalFormat != MTLPixelFormatInvalid, @"This texture format is not supported by Apple's Metal API.");
232+
233+
MTLTextureDescriptor *textureDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:metalFormat width:width height:height mipmapped:NO];
234+
_metalTexture = [device newTextureWithDescriptor:textureDesc];
235+
236+
NSUInteger bytesPerRow = width*[CCTexture bitsPerPixelForFormat:pixelFormat]/8;
237+
[_metalTexture replaceRegion:MTLRegionMake2D(0, 0, width, height) mipmapLevel:0 withBytes:data bytesPerRow:bytesPerRow];
238+
} else
239+
#endif
240+
{
190241
CCGL_DEBUG_PUSH_GROUP_MARKER("CCTexture: Init");
191242

192243
// XXX: 32 bits or POT textures uses UNPACK of 4 (is this correct ??? )
@@ -233,6 +284,7 @@ - (id) initWithData:(const void*)data pixelFormat:(CCTexturePixelFormat)pixelFor
233284
}
234285

235286
CCGL_DEBUG_POP_GROUP_MARKER();
287+
}
236288
});
237289

238290
_sizeInPixels = sizeInPixels;
@@ -296,7 +348,7 @@ - (void*) keepData:(void*)data length:(NSUInteger)length
296348
- (void) dealloc
297349
{
298350
CCLOGINFO(@"cocos2d: deallocing %@", self);
299-
351+
300352
GLuint name = _name;
301353
if(name){
302354
CCRenderDispatch(YES, ^{
@@ -618,6 +670,8 @@ +(void) PVRImagesHavePremultipliedAlpha:(BOOL)haveAlphaPremultiplied
618670
#pragma mark -
619671
#pragma mark CCTexture2D - GLFilter
620672

673+
#warning Not implemented for Metal.
674+
621675
//
622676
// Use to apply MIN/MAG filter
623677
//

cocos2d/CCTexture_Private.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525

2626
#import "CCTexture.h"
2727

28+
#if __CC_METAL_SUPPORTED_AND_ENABLED
29+
#import <Metal/Metal.h>
30+
#endif
31+
32+
2833
// -------------------------------------------------------------
2934

3035
// Proxy object returned in place of a CCTexture or CCSpriteFrame by the texture cache.
@@ -47,11 +52,18 @@
4752
/* texture name */
4853
@property(nonatomic,readonly) GLuint name;
4954

55+
#if __CC_METAL_SUPPORTED_AND_ENABLED
56+
@property(nonatomic,readonly) id<MTLTexture> metalTexture;
57+
@property(nonatomic,readonly) id<MTLSamplerState> metalSampler;
58+
#endif
59+
5060
/* texture max S */
5161
@property(nonatomic,readwrite) GLfloat maxS;
5262
/* texture max T */
5363
@property(nonatomic,readwrite) GLfloat maxT;
5464

65+
@property(nonatomic,readwrite) BOOL premultipliedAlpha;
66+
5567
// Check if the texture's weakly retained proxy still exists.
5668
@property(atomic, readonly) BOOL hasProxy;
5769

cocos2d/Platforms/iOS/CCMetalSupport.m

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@
2424
*/
2525

2626
#import "CCMetalSupport_Private.h"
27-
2827
#if __CC_METAL_SUPPORTED_AND_ENABLED
2928

29+
#import "CCTexture_Private.h"
30+
3031
@implementation CCMetalContext
3132

3233
-(instancetype)init
@@ -44,6 +45,9 @@ -(instancetype)init
4445

4546
NSString *CURRENT_CONTEXT_KEY = @"CURRENT_CONTEXT_KEY";
4647

48+
#warning TODO
49+
// This uses a pretty measurable piece of CPU time.
50+
// Access through the CCRenderer when possible somehow?
4751
static inline CCMetalContext *
4852
CCMetalContextCurrent(void)
4953
{
@@ -164,9 +168,19 @@ -(void)bind:(BOOL)bind
164168
@end
165169

166170

171+
// This is effectively hardcoded to 10 by Apple's docs and there is no API to query capabilities...
172+
// Seems like an oversight, but whatever.
173+
#define CCMTL_MAX_TEXTURES 10
174+
175+
167176
@interface CCRenderStateMetal : CCRenderState @end
168177
@implementation CCRenderStateMetal {
169178
id<MTLRenderPipelineState> _renderPipelineState;
179+
180+
NSRange _textureRange;
181+
// TODO should be unretained once the sampler issue is fixed.
182+
id<MTLSamplerState> _samplers[CCMTL_MAX_TEXTURES];
183+
__unsafe_unretained id<MTLTexture> _textures[CCMTL_MAX_TEXTURES];
170184
}
171185

172186
// Using GL enums for CCBlendMode types should never have happened. Oops.
@@ -206,7 +220,7 @@ -(void)prepare
206220
id<MTLLibrary> library = context.library;
207221
#warning TEMP Hard coded shaders.
208222
pipelineStateDescriptor.vertexFunction = [library newFunctionWithName:@"CCVertexFunctionDefault"];
209-
pipelineStateDescriptor.fragmentFunction = [library newFunctionWithName:@"CCFragmentFunctionDefaultColor"];
223+
pipelineStateDescriptor.fragmentFunction = [library newFunctionWithName:@"CCFragmentFunctionDefaultTextureColor"];
210224

211225
NSDictionary *blendOptions = _blendMode.options;
212226
MTLRenderPipelineColorAttachmentDescriptor *colorDescriptor = [MTLRenderPipelineColorAttachmentDescriptor new];
@@ -221,13 +235,20 @@ -(void)prepare
221235
pipelineStateDescriptor.colorAttachments[0] = colorDescriptor;
222236

223237
_renderPipelineState = [context.device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:nil];
238+
239+
CCTexture *texture = _shaderUniforms[CCShaderUniformMainTexture] ?: [CCTexture none];
240+
_textureRange = NSMakeRange(0, 1);
241+
_samplers[0] = texture.metalSampler ?: [context.device newSamplerStateWithDescriptor:[MTLSamplerDescriptor new]];
242+
_textures[0] = texture.metalTexture;
224243
}
225244
}
226245

227246
-(void)transitionRenderer:(CCRenderer *)renderer FromState:(CCRenderState *)previous
228247
{
229-
// TODO Get the context more efficiently through the renderer perhaps?
230-
[CCMetalContextCurrent().currentRenderCommandEncoder setRenderPipelineState:_renderPipelineState];
248+
id<MTLRenderCommandEncoder> renderEncoder = CCMetalContextCurrent().currentRenderCommandEncoder;
249+
[renderEncoder setRenderPipelineState:_renderPipelineState];
250+
[renderEncoder setFragmentSamplerStates:_samplers withRange:_textureRange];
251+
[renderEncoder setFragmentTextures:_textures withRange:_textureRange];
231252
}
232253

233254
@end

0 commit comments

Comments
 (0)