我开始玩Metal(目前我的应用程序正在使用OpenGL)。我试图在一个渲染过程中检查如何使用多个管道状态(多个金属函数)进行渲染。问题是始终只绘制最后一个MTLRenderCommandEncoder。以下是我的代码:
@property (nonatomic, strong) UIView* metalView;
@property (nonatomic, strong) id <MTLDevice> mtlDevice;
@property (nonatomic, strong) id <MTLCommandQueue> mtlCommandQueue;
@property (nonatomic, strong) MTLRenderPassDescriptor *mtlRenderPassDescriptor;
@property (nonatomic, strong) CAMetalLayer *metalLayer;
@property (nonatomic, strong) id <CAMetalDrawable> frameDrawable;
@property (nonatomic, strong) CADisplayLink *displayLink;
@property (nonatomic, strong) MTLRenderPipelineDescriptor *renderPipelineDescriptor;
@property (nonatomic, strong) MTLRenderPipelineDescriptor *renderPipelineDescriptorb;
@property (nonatomic, strong) id <MTLRenderPipelineState> renderPipelineState;
@property (nonatomic, strong) id <MTLRenderPipelineState> renderPipelineStateb;
@property (nonatomic, strong) id <MTLBuffer> object;
@property (nonatomic, strong) id <MTLBuffer> objectb;
@end
@implementation MetalGPUAdapter
- (void)setupGraphics
{
self.mtlDevice = MTLCreateSystemDefaultDevice();
self.mtlCommandQueue = [self.mtlDevice newCommandQueue];
self.metalLayer = [CAMetalLayer layer];
[self.metalLayer setDevice:self.mtlDevice];
[self.metalLayer setPixelFormat:MTLPixelFormatBGRA8Unorm];
self.metalLayer.framebufferOnly = YES;
[self.metalLayer setFrame:self.gpuViewController.view.layer.frame];
self.metalView = [[UIView alloc] initWithFrame:self.gpuViewController.view.frame];
[self.gpuViewController.view addSubview:self.metalView];
[self.gpuViewController.view sendSubviewToBack:self.metalView];
[self.metalView.layer addSublayer:self.metalLayer];
[self.metalView setOpaque:YES];
[self.metalView setBackgroundColor:nil];
[self.metalView setContentScaleFactor:[UIScreen mainScreen].scale];
// Create a reusable pipeline
self.renderPipelineDescriptor = [MTLRenderPipelineDescriptor new];
self.renderPipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
self.renderPipelineDescriptorb = [MTLRenderPipelineDescriptor new];
self.renderPipelineDescriptorb.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
id <MTLLibrary> lib = [self.mtlDevice newDefaultLibrary];
self.renderPipelineDescriptor.vertexFunction = [lib newFunctionWithName:@"VertexColor"];
self.renderPipelineDescriptor.fragmentFunction = [lib newFunctionWithName:@"FragmentColor"];
self.renderPipelineState = [self.mtlDevice newRenderPipelineStateWithDescriptor:self.renderPipelineDescriptor error: nil];
self.renderPipelineDescriptorb.vertexFunction = [lib newFunctionWithName:@"VertexColorb"];
self.renderPipelineDescriptorb.fragmentFunction = [lib newFunctionWithName:@"FragmentColorb"];
self.renderPipelineStateb = [self.mtlDevice newRenderPipelineStateWithDescriptor:self.renderPipelineDescriptorb error: nil];
Triangle triangle[3] = { { -1.0f, -1.0f }, { 1.0f, -1.0f }, { 0.0f, 0.0f } };
Triangle square[4] = { { -1.0f, 0.0f }, { -1.0f, 1.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }};
self.object = [self.mtlDevice newBufferWithBytes:&triangle length:sizeof(Triangle[3]) options:MTLResourceOptionCPUCacheModeDefault];
self.objectb = [self.mtlDevice newBufferWithBytes:&square length:sizeof(Triangle[4]) options:MTLResourceOptionCPUCacheModeDefault];
self.displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector(renderScene)];
[self.displayLink addToRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode];
}
- (void)renderScene
{
id <MTLCommandBuffer>mtlCommandBuffer = [self.mtlCommandQueue commandBuffer];
while (!self.frameDrawable){
self.frameDrawable = [self.metalLayer nextDrawable];
}
if (!self.mtlRenderPassDescriptor)
self.mtlRenderPassDescriptor = [MTLRenderPassDescriptor new];
self.mtlRenderPassDescriptor.colorAttachments[0].texture = self.frameDrawable.texture;
self.mtlRenderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
self.mtlRenderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.75, 0.5, 1.0, 1.0);
self.mtlRenderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
id <MTLRenderCommandEncoder> renderCommand = [mtlCommandBuffer renderCommandEncoderWithDescriptor: self.mtlRenderPassDescriptor];
[renderCommand setRenderPipelineState:self.renderPipelineStateb];
[renderCommand setVertexBuffer:self.object offset:0 atIndex:0];
[renderCommand drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
[renderCommand endEncoding];
id <MTLRenderCommandEncoder> renderCommandb = [mtlCommandBuffer renderCommandEncoderWithDescriptor: self.mtlRenderPassDescriptor];
[renderCommandb setRenderPipelineState:self.renderPipelineStateb];
[renderCommandb setVertexBuffer:self.objectb offset:0 atIndex:0];
[renderCommandb drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
[renderCommandb endEncoding];
[mtlCommandBuffer presentDrawable: self.frameDrawable];
[mtlCommandBuffer commit];
self.mtlRenderPassDescriptor = nil;
self.frameDrawable = nil;
}
我的着色器:
#include <metal_stdlib>
using namespace metal;
typedef struct {
float2 position;
} Triangle;
typedef struct {
float4 position [[position]];
} TriangleOutput;
vertex TriangleOutput VertexColor(const device Triangle *Vertices [[buffer(0)]], const uint index [[vertex_id]])
{
TriangleOutput out;
out.position = float4(Vertices[index].position, 0.0, 1.0);
return out;
}
vertex TriangleOutput VertexColorb(const device Triangle *Vertices [[buffer(0)]], const uint index [[vertex_id]])
{
TriangleOutput out;
out.position = float4(Vertices[index].position, 0.0, 1.0);
return out;
}
fragment half4 FragmentColor(void)
{
return half4(1.0, 0.0, 0.0, 1.0);
}
fragment half4 FragmentColorb(void)
{
return half4(1.0, 0.0, 1.0, 1.0);
}
答案 0 :(得分:2)
您正在尝试将多个渲染过程编码为单个命令缓冲区(一个编码器=一次传递)。这是有效的,但您需要注意您的加载和存储操作才能使其正常工作。由于渲染过程描述符配置为在两次传递之前清除,因此帧缓冲附件基本上在第二次传递之前被擦除。相反,您应该在开始第二次传递之前在传递描述符上设置Load
加载操作。