Last active
July 21, 2022 12:37
-
-
Save suzumura-ss/79150309af32bf151435acbdff920cfc to your computer and use it in GitHub Desktop.
Offscreen Metal rendering
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#import <MetalKit/MetalKit.h> | |
typedef struct | |
{ | |
vector_float4 position; | |
vector_float2 texCoord; | |
} VertexData; | |
void Exec() | |
{ | |
// initWithMetalKitView | |
id <MTLDevice> device = MTLCreateSystemDefaultDevice(); | |
dispatch_semaphore_t inFlightSemaphore = dispatch_semaphore_create(0); | |
MTLTextureDescriptor* outputDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Uint | |
width:8 | |
height:8 | |
mipmapped:NO]; | |
outputDesc.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead; | |
id <MTLTexture> texture = [device newTextureWithDescriptor:outputDesc]; | |
{ | |
uint8 pixels[outputDesc.width * outputDesc.height * 4]; | |
memset(pixels, 1, sizeof(pixels)); | |
[texture replaceRegion:MTLRegionMake2D(0, 0, outputDesc.width, outputDesc.height) | |
mipmapLevel:0 | |
withBytes:pixels | |
bytesPerRow:outputDesc.width * 4]; | |
} | |
// loadMetalWithView | |
id <MTLLibrary> defaultLibrary = [device newDefaultLibrary]; | |
MTLRenderPipelineDescriptor* pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; | |
pipelineStateDescriptor.sampleCount = 1; | |
pipelineStateDescriptor.vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"]; | |
pipelineStateDescriptor.fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"];; | |
pipelineStateDescriptor.colorAttachments[0].pixelFormat = outputDesc.pixelFormat; | |
NSError *error = NULL; | |
id <MTLRenderPipelineState> pipelineState = [device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error]; | |
if (!pipelineState || error) | |
{ | |
NSLog(@"Failed to created pipeline state, error %@", error); | |
abort(); | |
} | |
id <MTLCommandQueue> commandQueue = [device newCommandQueue]; | |
// loadAssets | |
VertexData vertexData[3] = { | |
{{-1, -1, 0, 1}, {0, 0}}, | |
{{ 1, -1, 0, 1}, {1, 0}}, | |
{{ 0, 1, 0, 1}, {0, 1}} | |
}; | |
id <MTLBuffer> vertexBuffer = [device newBufferWithBytes:vertexData length:sizeof(vertexData) options:MTLResourceCPUCacheModeDefaultCache]; | |
// drawInMTKView | |
@autoreleasepool { | |
id <MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer]; | |
commandBuffer.label = @"MyCommand"; | |
__block dispatch_semaphore_t block_sema = inFlightSemaphore; | |
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) { | |
dispatch_semaphore_signal(block_sema); | |
}]; | |
MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; | |
renderPassDescriptor.colorAttachments[0].texture = texture; | |
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(1, 2, 3, 4); | |
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; | |
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; | |
id <MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; | |
if (!renderEncoder) | |
{ | |
NSLog(@"No renderEncoder"); | |
abort(); | |
} | |
[renderEncoder pushDebugGroup:@"DrawBox"]; | |
[renderEncoder setRenderPipelineState:pipelineState]; | |
[renderEncoder setVertexBuffer:vertexBuffer offset:0 atIndex:0]; | |
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:sizeof(vertexData) / sizeof(VertexData)]; | |
[renderEncoder popDebugGroup]; | |
[renderEncoder endEncoding]; | |
[commandBuffer commit]; | |
dispatch_semaphore_wait(inFlightSemaphore, DISPATCH_TIME_FOREVER); | |
uint8 pixels[outputDesc.width * outputDesc.height * 4]; | |
memset(pixels, 2, sizeof(pixels)); | |
[texture getBytes:pixels | |
bytesPerRow:sizeof(uint8) * 4 * outputDesc.width | |
fromRegion:MTLRegionMake2D(0, 0, outputDesc.width, outputDesc.height) | |
mipmapLevel:0]; | |
uint8* p = pixels; | |
for (int y = 0; y < outputDesc.height; ++y) | |
{ | |
NSMutableString* s = [NSMutableString string]; | |
for (int x = 0; x < outputDesc.width; ++x) | |
{ | |
[s appendString:@"("]; | |
for (int k = 0; k < 4; ++k) | |
{ | |
[s appendFormat:@" %3d", *(p++)]; | |
} | |
[s appendString:@" )"]; | |
} | |
NSLog(@"%@", s); | |
} | |
} | |
} | |
int main(int argc, const char * argv[]) | |
{ | |
@autoreleasepool { | |
Exec(); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment