View in English

  • 메뉴 열기 메뉴 닫기
  • Apple Developer
검색
검색 닫기
  • Apple Developer
  • 뉴스
  • 둘러보기
  • 디자인
  • 개발
  • 배포
  • 지원
  • 계정
페이지에서만 검색

빠른 링크

5 빠른 링크

비디오

메뉴 열기 메뉴 닫기
  • 컬렉션
  • 주제
  • 전체 비디오
  • 소개

WWDC23 컬렉션으로 돌아가기

스트리밍은 대부분의 브라우저와
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
      • HD 비디오
      • SD 비디오

    관련 비디오

    WWDC23

    • 게임을 Mac으로 가져오기, 1단계: 기본 계획 세우기
    • Mac에 게임 가져오기, 2부: 셰이더 컴파일하기

    Tech Talks

    • iPhone 15 Pro에서 고사양 게임 선보이기

    WWDC22

    • MetalFX Upscaling을 통한 성능 향상

    WWDC21

    • Discover Metal debugging, profiling, and asset creation tools

    WWDC20

    • Bring your Metal app to Apple silicon Macs
    • Gain insights into your Metal app with Xcode 12
    • Harness Apple GPUs with Metal
    • Optimize Metal Performance for Apple silicon Macs
  • 비디오 검색…
    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);
      }

Developer Footer

  • 비디오
  • WWDC23
  • Mac에 게임 가져오기, 3부: Metal로 렌더링하기
  • 메뉴 열기 메뉴 닫기
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    메뉴 열기 메뉴 닫기
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    메뉴 열기 메뉴 닫기
    • 손쉬운 사용
    • 액세서리
    • 앱 확장 프로그램
    • App Store
    • 오디오 및 비디오(영문)
    • 증강 현실
    • 디자인
    • 배포
    • 교육
    • 서체(영문)
    • 게임
    • 건강 및 피트니스
    • 앱 내 구입
    • 현지화
    • 지도 및 위치
    • 머신 러닝
    • 오픈 소스(영문)
    • 보안
    • Safari 및 웹(영문)
    메뉴 열기 메뉴 닫기
    • 문서(영문)
    • 튜토리얼
    • 다운로드(영문)
    • 포럼(영문)
    • 비디오
    메뉴 열기 메뉴 닫기
    • 지원 문서
    • 문의하기
    • 버그 보고
    • 시스템 상태(영문)
    메뉴 열기 메뉴 닫기
    • Apple Developer
    • App Store Connect
    • 인증서, 식별자 및 프로파일(영문)
    • 피드백 지원
    메뉴 열기 메뉴 닫기
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(영문)
    • News Partner Program(영문)
    • Video Partner Program(영문)
    • Security Bounty Program(영문)
    • Security Research Device Program(영문)
    메뉴 열기 메뉴 닫기
    • Apple과의 만남
    • Apple Developer Center
    • App Store 어워드(영문)
    • Apple 디자인 어워드
    • Apple Developer Academy(영문)
    • WWDC
    Apple Developer 앱 받기
    Copyright © 2025 Apple Inc. 모든 권리 보유.
    약관 개인정보 처리방침 계약 및 지침