스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
Mac에 게임 가져오기, 3부: Metal로 렌더링하기
3부로 구성된 ‘Mac에 게임 가져오기' 마지막 세션에서는 렌더링 코드에서 Metal을 지원하는 방법을 알아봅니다. Game Porting Toolkit으로 기존의 Windows 바이너리를 실행하고 HLSL 셰이더를 Metal로 가져왔다면, 최신 게임에서 요구되는 고성능 기능 구현을 최적화할 방법을 살펴볼 차례입니다. GPU 리소스 바인딩과 리소스 상주, 그리고 동기화를 관리하는 방법을 소개해 드립니다. 그 밖에 GPU 커맨드 전송을 최적화하는 방법과 MetalFX 업스케일링을 통해 선명한 화면을 렌더링하는 방법 등을 살펴보세요. 이번 세션을 최대한 활용하려면 WWDC23의 'Mac에 게임 가져오기 1부: 게임 플랜 만들기'와 'Mac에 게임 가져오기 2부: 셰이더 컴파일하기'를 먼저 시청해 주시기 바랍니다.
챕터
- 0:00 - Intro
- 1:58 - Manage GPU resources
- 9:08 - Optimize rendering commands
- 18:00 - Handle indirect rendering
- 22:41 - Upscale with MetalFX
- 25:31 - Wrap-Up
리소스
- Applying temporal antialiasing and upscaling using MetalFX
- Metal
- MetalFX
- Modern Rendering with Metal
관련 비디오
WWDC23
Tech Talks
WWDC22
WWDC21
WWDC20
-
다운로드Array
-
-
3:55 - Encode the texture tables.
// Encode the texture tables outside of the rendering loop. id<MTLBuffer> textureTable = [device newBufferWithLength:sizeof(MTLResourceID) * texturesCount options:MTLResourceStorageModeShared]; MTLResourceID* textureTableCPUPtr = (MTLResourceID*)textureTable.contents; for (uint32_t i = 0; i < texturesCount; ++i) { // create the textures. id<MTLTexture> texture = [device newTextureWithDescriptor:textureDesc[i]]; // encode texture in argument buffer textureTableCPUPtr[i] = texture.gpuResourceID; }
-
4:33 - Encode the sampler tables.
// Encode the sampler tables outside of the rendering loop. id<MTLBuffer> samplerTable = [device newBufferWithLength:sizeof(MTLResourceID) * samplersCount options:MTLResourceStorageModeShared]; MTLResourceID* samplerTableCPUPtr = (MTLResourceID*)samplerTable.contents; for (uint32_t i = 0; i < samplersCount; ++i) { // create sampler descriptor MTLSamplerDescriptor* desc = [MTLSamplerDescriptor new]; desc.supportArgumentBuffers = YES; . . . // create a sampler id<MTLSamplerState> sampler = [device newSamplerStateWithDescriptor:desc]; // encode the sampler in argument buffer samplerTableCPUPtr[i] = sampler.gpuResourceID; }
-
5:05 - Encode the top level argument buffer.
// Encode the top level argument buffer. struct TopLevelAB { MTLResourceID* textureTable; float* myBuffer; uint32_t myConstant; MTLResourceID* samplerTable; }; id<MTLBuffer> topAB = [device newBufferWithLength:sizeof(TopLevelAB) options:MTLResourceStorageModeShared]; TopLevelAB* topABCPUPtr = (TopLevelAB*)topAB.contents; topABCPUPtr->textureTable = (MTLResourceID*)textureTable.gpuAddress; topABCPUPtr->myBuffer = (float*)myBuffer.gpuAddress; topABCPUPtr->myConstant = 128; topABCPUPtr->samplerTable = (MTLResourceID*)samplerTable.gpuAddress;
-
6:49 - Allocate the read-only resources.
// Allocate the read-only resources from a heap. MTLHeapDescriptor* heapDesc = [MTLHeapDescriptor new]; heapDesc.size = requiredSize; heapDesc.type = MTLHeapTypeAutomatic; id<MTLHeap> heap = [device newHeapWithDescriptor:heapDesc]; // Allocate the textures and the buffers from the heap. id<MTLTexture> texture = [heap newTextureWithDescriptor:desc]; id<MTLBuffer> buffer = [heap newBufferWithLength:length options:options]; . . . // Make the heap resident once for each encoder that uses it. [encoder useHeap:heap];
-
7:34 - Allocate the writable resources.
// Allocate the writable resources individually. id<MTLTexture> textureRW = [device newTextureWithDescriptor:desc]; id<MTLBuffer> bufferRW = [device newBufferWithLength:length options:options]; // Mark these resources resident when they're needed in the current encoder. // Specify the resource usage in the encoder using MTLResourceUsage. [encoder useResource:textureRW usage:MTLResourceUsageWrite stages:stage]; [encoder useResource:bufferRW usage:MTLResourceUsageRead stages:stage];
-
19:31 - Encode the execute indirect
// Encode the execute indirect command as a series of indirect draw calls. for (uint32_t i = 0; i < maxDrawCount; ++i) { // Encode the current indirect draw call. [renderEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexType:MTLIndexTypeUInt16 indexBuffer:indexBuffer indexBufferOffset:indexBufferOffset indirectBuffer:drawArgumentsBuffer indirectBufferOffset:drawArgumentsBufferOffset]; // Advance the draw arguments buffer offset to the next indirect arguments. drawArgumentsBufferOffset += sizeof(MTLDrawIndexedPrimitivesIndirectArguments); }
-
21:48 - Translate the indirect draw arguments to ICB.
// Kernel written in Metal Shading Language to translate the indirect draw arguments to an ICB. kernel void translateToICB(device const Command* indirectCommands [[ buffer(0) ]], device const ICBContainerAB* icb [[ buffer(1) ]], . . .) { . . . device const Command* indirectCommand = &indirectCommands[commandIndex]; device const MTLDrawIndexedPrimitivesIndirectArguments* args = &command->mdiBuffer[mdiIndex]; render_command drawCall(icb->buffer, indirectCommand->mdiCmdStart + mdiIndex); if(args->indexCount > 0 && args->instanceCount > 0) { encodeCommand(indirectCommand, args, drawCall); } else { cmd.reset(); } } // Encode a render command on the GPU. void encodeCommand(device const Command* indirectCommand, device const MTLDrawIndexedPrimitivesIndirectArguments* args, thread render_command& drawCall) { drawCall.set_render_pipeline_state(indirectCommand->pso); for(ushort i = 0; i < indirectCommand->vertexBuffersCount; ++i) { drawCall.set_vertex_buffer(indirectCommand->vertexBuffer[i].buffer, indirectCommand->vertexBuffer[i].slot); } for(ushort i = 0; i < indirectCommand->fragmentBuffersCount; ++i) { drawCall.set_fragment_buffer(indirectCommand->fragmentBuffer[i].buffer, indirectCommand->fragmentBuffer[i].slot); } drawCall.draw_indexed_primitives(primitive_type::triangle, args->indexCount, indirectCommand->indexBuffer + args->indexStart, args->instanceCount, args->baseVertex, args->baseInstance); }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.