1 #import "MTLPipelineStatesStorage.h"
   2 #import "Trace.h"
   3 
   4 #include "GraphicsPrimitiveMgr.h"
   5 #import "common.h"
   6 
   7 @implementation MTLPipelineStatesStorage
   8 
   9 @synthesize device;
  10 @synthesize library;
  11 @synthesize shaders;
  12 @synthesize states;
  13 @synthesize templateRenderPipelineDesc;
  14 @synthesize templateTexturePipelineDesc;
  15 
  16 - (id) initWithDevice:(id<MTLDevice>)dev shaderLibPath:(NSString *)shadersLib {
  17     self = [super init];
  18     if (self == nil) return self;
  19 
  20     self.device = dev;
  21 
  22     NSError *error = nil;
  23     self.library = [dev newLibraryWithFile:shadersLib error:&error];
  24     if (!self.library) {
  25         NSLog(@"Failed to load library. error %@", error);
  26         exit(0);
  27     }
  28     self.shaders = [NSMutableDictionary dictionaryWithCapacity:10];
  29     self.states = [NSMutableDictionary dictionaryWithCapacity:10];
  30 
  31     { // init template descriptors
  32         MTLVertexDescriptor *vertDesc = [[MTLVertexDescriptor new] autorelease];
  33         vertDesc.attributes[VertexAttributePosition].format = MTLVertexFormatFloat3;
  34         vertDesc.attributes[VertexAttributePosition].offset = 0;
  35         vertDesc.attributes[VertexAttributePosition].bufferIndex = MeshVertexBuffer;
  36         vertDesc.layouts[MeshVertexBuffer].stride = sizeof(struct Vertex);
  37         vertDesc.layouts[MeshVertexBuffer].stepRate = 1;
  38         vertDesc.layouts[MeshVertexBuffer].stepFunction = MTLVertexStepFunctionPerVertex;
  39 
  40         self.templateRenderPipelineDesc = [[MTLRenderPipelineDescriptor new] autorelease];
  41         self.templateRenderPipelineDesc.sampleCount = 1;
  42         self.templateRenderPipelineDesc.vertexDescriptor = vertDesc;
  43         self.templateRenderPipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
  44         self.templateRenderPipelineDesc.label = @"template_render";
  45 
  46         self.templateTexturePipelineDesc = [[self.templateRenderPipelineDesc copy] autorelease];
  47         self.templateTexturePipelineDesc.vertexDescriptor.attributes[VertexAttributeTexPos].format = MTLVertexFormatFloat2;
  48         self.templateTexturePipelineDesc.vertexDescriptor.attributes[VertexAttributeTexPos].offset = 3*sizeof(float);
  49         self.templateTexturePipelineDesc.vertexDescriptor.attributes[VertexAttributeTexPos].bufferIndex = MeshVertexBuffer;
  50         self.templateTexturePipelineDesc.vertexDescriptor.layouts[MeshVertexBuffer].stride = sizeof(struct TxtVertex);
  51         self.templateTexturePipelineDesc.vertexDescriptor.layouts[MeshVertexBuffer].stepRate = 1;
  52         self.templateTexturePipelineDesc.vertexDescriptor.layouts[MeshVertexBuffer].stepFunction = MTLVertexStepFunctionPerVertex;
  53         self.templateTexturePipelineDesc.label = @"template_texture";
  54     }
  55 
  56     { // pre-create main states
  57         [self getRenderPipelineState:YES];
  58         [self getRenderPipelineState:NO];
  59         [self getTexturePipelineState:NO compositeRule:RULE_Src];
  60         [self getTexturePipelineState:NO compositeRule:RULE_SrcOver];
  61     }
  62 
  63     return self;
  64 }
  65 
  66 - (id<MTLRenderPipelineState>) getRenderPipelineState:(bool)isGradient {
  67     NSString * uid = [NSString stringWithFormat:@"render_grad[%d]", isGradient];
  68 
  69     id<MTLRenderPipelineState> result = [self.states valueForKey:uid];
  70     if (result == nil) {
  71         id<MTLFunction> vertexShader   = isGradient ? [self getShader:@"vert_grad"] : [self getShader:@"vert_col"];
  72         id<MTLFunction> fragmentShader = isGradient ? [self getShader:@"frag_grad"] : [self getShader:@"frag_col"];
  73         MTLRenderPipelineDescriptor *pipelineDesc = [[self.templateRenderPipelineDesc copy] autorelease];
  74         pipelineDesc.vertexFunction = vertexShader;
  75         pipelineDesc.fragmentFunction = fragmentShader;
  76         pipelineDesc.label = uid;
  77 
  78         NSError *error = nil;
  79         result = [self.device newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
  80         if (result == nil) {
  81             NSLog(@"Failed to create render pipeline state '%@', error %@", uid, error);
  82             exit(0);
  83         }
  84 
  85         [self.states setValue:result forKey:uid];
  86     }
  87 
  88     return result;
  89 };
  90 
  91 - (id<MTLRenderPipelineState>) getTexturePipelineState:(bool)isSourcePremultiplied compositeRule:(int)compositeRule {
  92     NSString * uid = [NSString stringWithFormat:@"texture_compositeRule[%d]", compositeRule];
  93 
  94     id<MTLRenderPipelineState> result = [self.states valueForKey:uid];
  95     if (result == nil) {
  96         id<MTLFunction> vertexShader   = [self getShader:@"vert_txt"];
  97         id<MTLFunction> fragmentShader = [self getShader:@"frag_txt"];
  98         MTLRenderPipelineDescriptor *pipelineDesc = [[self.templateTexturePipelineDesc copy] autorelease];
  99         pipelineDesc.vertexFunction = vertexShader;
 100         pipelineDesc.fragmentFunction = fragmentShader;
 101 
 102         if (compositeRule != RULE_Src) {
 103             pipelineDesc.colorAttachments[0].blendingEnabled = YES;
 104 
 105             if (!isSourcePremultiplied)
 106                 pipelineDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
 107 
 108             //RGB = Source.rgb * SBF + Dest.rgb * DBF
 109             //A = Source.a * SBF + Dest.a * DBF
 110             //
 111             //default SRC:
 112             //DBF=0
 113             //SBF=1
 114             if (compositeRule == RULE_SrcOver) {
 115                 // SRC_OVER (Porter-Duff Source Over Destination rule):
 116                 // Ar = As + Ad*(1-As)
 117                 // Cr = Cs + Cd*(1-As)
 118                 pipelineDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
 119                 pipelineDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
 120             } else {
 121                 J2dTrace1(J2D_TRACE_ERROR, "Unimplemented composite rule %d (will be used Src)", compositeRule);
 122                 pipelineDesc.colorAttachments[0].blendingEnabled = NO;
 123             }
 124         }
 125 
 126         NSError *error = nil;
 127         result = [self.device newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
 128         if (result == nil) {
 129             NSLog(@"Failed to create texture pipeline state '%@', error %@", uid, error);
 130             exit(0);
 131         }
 132 
 133         [self.states setValue:result forKey:uid];
 134     }
 135 
 136     return result;
 137 }
 138 
 139 - (id<MTLFunction>) getShader:(NSString *)name {
 140     id<MTLFunction> result = [self.shaders valueForKey:name];
 141     if (result == nil) {
 142         result = [[self.library newFunctionWithName:name] autorelease];
 143         [self.shaders setValue:result forKey:name];
 144     }
 145     return result;
 146 }
 147 @end