목차

  • [[#6.6 상수 버퍼|6.6 상수 버퍼]]
    • [[#6.6 상수 버퍼#6.6.4 상수 버퍼 서술자|6.6.4 상수 버퍼 서술자]]
    • [[#6.6 상수 버퍼#6.6.5 루트 서명과 서술자 테이블|6.6.5 루트 서명과 서술자 테이블]]
  • [[#6.7 셰이더의 컴파일|6.7 셰이더의 컴파일]]
    • [[#6.7 셰이더의 컴파일#6.7.1 오프라인 컴파일|6.7.1 오프라인 컴파일]]
  • [[#6.8 래스터화기 상태|6.8 래스터화기 상태]]
  • [[#6.9 파이프라인 상태 객체|6.9 파이프라인 상태 객체]]
  • [[#번외|번외]]
    • [[#번외#✅ 구성만 가능한 고정 기능(Fixed-function) 단계들(shader가 아닌 단계들)|✅ 구성만 가능한 고정 기능(Fixed-function) 단계들(shader가 아닌 단계들)]]

6.6 상수 버퍼

  • 상수 버퍼(contant buffer) : 셰이더 프로그램에서 참조하는 자료를 담는 GPU 자원(ID3DResource)의 예

    • 변하지 않는 작은 데이터를 저장하는 용도로 사용

    • HLSL에서의 상수 버퍼는 cbuffer 타입 <- "ShaderModel 4.0"; "5.1 이상에서는 ConstantBuffer<{type}>을 선호"

      • 최대 4096개의 벡터 보유가능 ( 최대 4개의 32비트 값 포함)

        • 256개의 float4x4 -> 64 KB
      • 파이프라인 단계당 최대 14개의 상수 버퍼 바인딩 가능(2개의 추가 슬롯은 내부용으로 예약되어 있음) { b0 ~ b13 }

          cbuffer cbPerObject : register(b0) <- b0 상수 버퍼 사용
          { ... }
    • CPU가 프레임당 한 번 갱신하는 것이 일반적 (업로드 힙 사용)

      • GPU가 빠르게 참조
      • CPU-GPU 동기화를 피하기 위해서 , 상수 버퍼에도 더블, 트리플 버퍼링 사용
      • 정적 데이터 사용 시에는 디폴트 힙 사용
    • 최소 하드웨어 할당 크기(256 Byte)의 배수여야 함

      • GPU는 256바이트 단위로 상수버퍼 로딩

      • 효율적인 캐시/버스 활용을 위해

      • HLSL에서 사용자의 정의 Byte가 256일 필요x (내부적으로 256 byte 배수로 처리)

        • Dx(c++)에서는 지정해야 함;
          (256 Byte 단위로 읽기 때문에 패딩을 맞춰주어야 하기 때문)

          cbuffer PerFrame : register(b0)
          {
            float4x4 view;          // 64 bytes
            float4x4 projection;    // 64 bytes
            float time;             // 4 bytes
            float3 padding;         // 12 bytes (패딩 맞춤)
          }
          // 총 크기 = 64 + 64 + 4 + 12 = 144 bytes → 내부적으로는 256 bytes로 할당됨
  • Dx 상수버퍼 생성 예제

      struct ObjectConstants
      {
          DirectX::XMFLOAT4X4 WorldViewProj = MathHelper::Identity4x4();
      };
    
      UINT mElementByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
    
      // 업로드 힙에 상수 버퍼 생성
      ComPtr<ID3D12Resource> mUploadCBuffer;
      device->CreateCommitedResource(
          &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
          D3D12_HEAP_FLAG_NONE,
          &CD3DX12_RESOURCE_DESC::Buffer(mElementByteSize * NumElements),
          D3D12_RESOURCE_STATE_GENERIC_READ,
          nullptr,
          IID_PPV_ARGS(&mUploadCBuffer));
    
      // CBV(상수 버퍼 뷰) 생성
      D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc;
      cbvDesc.BufferLocation = mUploadCBuffer->GetGPUVirtualAddress();
      cbvDesc.SizeInBytes = mElementByteSize;
    
      device->CreateConstantBufferView(&cbvDesc, cbvHeap->GetCPUDescriptorHandleForHeapStart());
    
      // CBV 루트 시그니처에 바인딩
      commandList->SetGraphicsRootDescriptorTable(0, cbvHeap->GetGPUDescriptorHandleForHeapStart());
    
      // 상수 버퍼 갱신
      ObjectConstants* mMappedData = nullptr;
      // (대응 부분자원 색인, 메모리 범위 서술(nullptr 전체대응). 대응된 자료 가리키는 포인터)
      mUploadCBuffer->Map(0, nullptr, reinterpret_cast<void**>(&mMappedData));
      // 쓰기만 할거기에 메모리 범위를 나타내는 CD3DX12_RANGE readRange(0, 0);가 범위
      // 그래서 nullptr을 쓸 수 있다 
    
      ObjectConstants objConstants;
      DirectX::XMMATRIX world = DirectX::XMMatrixIdentity();
      DirectX::XMMATRIX view = ...;   // 뷰 행렬
      DirectX::XMMATRIX proj = ...;   // 프로젝션 행렬
      DirectX::XMMATRIX wvp = world * view * proj;
    
      XMStoreFloat4x4(&objConstants.WorldViewProj, XMMatrixTranspose(wvp)); // HLSL과 행 우선/열 우선 일치
    
      // 프레임마다 갱신 시
      mMappedData[i] = objContants;
    
      // 리소스 해제는 선택 사항 : dx에서 알아서 해제해줌, 그래도 디버깅 및 예외 발생을 대비해 하는것이 좋음 (! 지속적으로 사용되는 리소스는 해제x )
      // 업로드 힙 더이상 사용안하면 리소스 해제
      if (mUploadBuffer != nullptr)
          mUploadBuffer->Unmap(0, nullptr);
    
      mMappedData = nullptr;

    -> d3dUtil::CalcConstantBufferByteSize() : 256 byte 배수 단위 버퍼 크기로 계산 반환
    -> 상수 버퍼에서 해당 물체를 위한 상수들이 있는 부분 영역을 서술하는 상수 버퍼 뷰를 파이프라인에 묶음

  • 256 Byte배수 단위 변환 구현

      #include <iostream>
      using namespace std;
    
      constexpr size_t ALIGNMENT = 256;
    
      size_t CeilAlign(size_t size) {
          return (size + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1);
      }
    
      int main() {
          size_t size1 = 180; // 예제: 180바이트 데이터
          size_t size2 = 300; // 예제: 300바이트 데이터
    
          // 256
          cout << "Ceil Align  (180): " << CeilAlign(size1) << endl;
    
          // 512
          cout << "Ceil Align  (300): " << CeilAlign(size2) << endl;
    
          return 0;
      }

6.6.4 상수 버퍼 서술자

  • D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV 형식의 서술자 힙에 담김
D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc;
cbvHeapDesc.NumDescriptors = 1;
cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
cbvHeapDesc.NodeMask = 0;

ComPtr<ID3D12DescriptorHeap> mCbvHeap = nullptr;
md3dDevice->CreateDescriptorHeap(&cbvHeapDesc, IID_PPV_ARGS(&mCbvHeap);
-> 셰이더 프로그램에서 서술자에게 접근할 것임을 뜻하는 flag 지정

6.6.5 루트 서명과 서술자 테이블

  • 루트 서명(root signature) : 그리기 호출 전에 응용 프로그램이 필수로 바인딩 해야하는 자원 및 그 자원들에 대한 셰이더 입력 레지스터들에 어떻게 대응되는지를 정의

    • 반드시, 그리기 호출에 쓰이는 셰이더들과 호환되어야 함
    • 루트 서명 유효성은 파이프라인 상태 객체를 생성할 떄 검증
    • 정의를 할 뿐, 바인딩 하지는 않음
  • 대표 인터페이스 : ID3D12RootSignature

    • 주어진 그리기 호출에서 셰이더들이 기대하는 자원들을 서술하는 루트 매개변수들의 배열로 정의
    • 루트 매개변수 : 하나의 루트 상수 or 루트 서술자 or 서술자 테이블 일 수 있음
  • 루트 서명 생성 예시

      CD3DX12_ROOT_PARAMETER slotRootParameter[1];
    
      // CVB 하나를 담는 서술자 테이블 생성
      CD3DX12_DESCRIPTOR_RANGE cbvTable;
      cbvTable.Init(
          D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
          1, // 테이블의 서술자 개수
          0 // 이루트 매개변수에 묶일 셰이더 인수들의 기준 레지스터 번호
      );
    
      slotRootParameter[0].InitAsDescriptorTable(
          1, // range 개수
          &cbvTable // 구간들의 배열을 가리키는 포인터
      );
    
      // 루트 서명은 루트 매개변수들의 배열
      CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(1, slotRootParameter, 0, nullptr,
          D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
    
      // 상수 버퍼 하나로 구성된 서술자 구간을 가리키는
      // 슬롯 하나로 이루어진 루트 서명 생성
      ComPtr<ID3DBlob> serializedRootSig = nullptr;
      ComPtr<ID3DBlob> errorBlob = nullptr;
      HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc,
          D3D_ROOT_SIGANTURE_VERSION_1,
          serializedRootSig->GetAddressOf(),
          errorBlob.GetAddressOf());
    
      ThrowIfFailed(md3dDevice->CreateRootSignature(
          0,
          serializedRootSig->GetBufferPointer(),
          serializedRootSig->GetBufferSize(),
          IID_PPV_ARGS(&mRootSignature)));
  • 자원 바인딩 : ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable을 호출해서 서술자 테이블을 파이프라인에 묶음

      void ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable(
          UINT RootParameterIndex,
          D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor);
    • RootParameterIndex : 설정하고자 하는 루트 서명의 색인
    • BaseDescriptor : 설정하고자 하는 서술자 테이블으 첫 서술자에 해당하는 서술자의 핸들
  • 루트 서명과 CBV 힙을 명력 목록에 설정하고, 파이프라인에 묶을 자원들을 지정하는 서술자 테이블 생성

     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
     ID3D12DescriptorHeap* descriptorHeaps[] = {mCbvHeap.Get()};
     mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
    
     // 이번 그리기 호출에서 사용할 CBV의 오프셋
     CD3DX12_GPU_DESCRIPTOR_HANDLE cbv(mCbvHeap->GetGPUDescriptorHandleForHeapStart());
     cbv.Offset(cbvIndex, mCbvSrvUavDescritoprSize);
    
     mCommandList->SetGraphicsRootDescriptorTable(0, cbv);
  • 성능을 위해서는 루트 서명을 최대한 작게 만들고, 렌더링 과정에서 루트 서명 변경 최소화

  • 응용 프로그램이 묶은 루트 서명의 구성물이 그리기/분배(dispatch) 호출들 사이에서 변할 때마다, D3D12 드라이버가 해당 내용물에 자동으로 버전 번호 부여.

    • 각각의 그리기/분배 호출은 고유한 루트 서명 상태들의 집합을 받게 됨
  • 루트 서명 변경시, 기존의 모든 바인딩이 삭제됨

6.7 셰이더의 컴파일

  • D3DCompileFromFile

      HRESULT D3DCompileFromFile (
          LPCWSTR pFileName,
          const D3D_SHADER_MACRO *pDefines,
          ID3DInclude *pInclude,
          LPCSTR pEntrypoint,
          LPCSTR pTarget,
          UINT Flags1,
          UINT Flags2,
          ID3DBlob **ppCode,
          ID3DBlob **ppErrorMsgs);
    • pFileName : 컴파일할 HLSL 소스 코드를 담은 .hlsl 파일 이름
    • pEntrypoint : 파일 내부에 여러개의 셰이더 있을 시, 진입점 명시
    • pTarget : 셰이더 프로그램의 종류와 대상 버전을 나타내는 문자열 (vs, hs, ds, ...)
    • Flags1 : 셰이더 코드의 세부적인 컴파일 방식 제어 플래그
      • D3DCOMPILE_DEBUG : 셰이더를 디버그 모드에서 컴파일
      • D3DCOMPILE_SKIP_OPTIMIZATION : 최적화 생략 (디버깅에 용이)
    • Flags2 : 효과(effect)의 컴파일 관한 고급옵션
    • ppCode : 컴파일된 셰이더 목적 바이트코드를 담은 II3DBlob 구조체의 포인터를 매개변수를 통해 돌려줌
    • ppErrorMsgs : 컴파일 오류 발생한 경우, 오류 메시지 문자열을 담은 ID3DBlob 구조체의 포인터를 이 매개변수를 통해 돌려줌
  • ID3DBlob 을 이용한 디버깅

    • LPVOID GetBufferPointer : 버퍼를 가리키는 void* 포인터를 돌려줌. (실제 사용하려면 적절한 형식으로 캐스팅)

    • SIZE_T GetBufferSize : 버퍼의 크기(바이트 개수)를 반환

    • 사용 예시

        UINT compileFlags = 0;
        #if defined(DEBUG) || defined(_DEBUF)
            compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
        #endif
      
        HRESULT hr = S_OK;
        ComPtr<ID3DBlob> byteCode = nullptr;
        ComPtr<ID3DBlob> errors;
        hr = D3DCompileFromFile(filename.c_str(), defines,
            D3D_COMPILE_STANDARD_FILE_INCLUDE,
            entrypoint.c_str(), target.c_str(), compileFlags, 0, &byteCode, &errors);
      
        // 오류 메시지 디버그 창에 출력
        if (errors != nullptr)
            OutputDebugStringA((char*)errors->GetBufferPointer()));
      
        ThrowIfFailed(hr);
      
        return byteCode;
    • 셰이더의 컴파일은 파이프라인에 바인딩 되는 것을 의미하지 않는다

    • VS에서는 hlsl 확장자 파일이 HLSL컴파일러 타입 빌드로 되어있는데, 이를 빌드하지 않음으로 설정한다; (D3D에서 별도 컴파일 API 사용 or fxc.exe 도구로 사전 컴파일 선호)

6.7.1 오프라인 컴파일

  • 오프라인 컴파일 하는 이유

    • 복잡한 셰이더는 컴파일 시간이 오래 걸림; 오프라인 컴파일 시, 게임의 적재(loading)시간이 빨라짐
    • 셰이더 컴파일 오류들은 실행 시점이 아니라 빌드 과정에서 일찍 점검하는 것이 편함
    • Windows8 스토어 앱은 반드시 오프라인 컴파일 사용
  • 컴파일된 셰이더를 담는 파일의 확자자로는 .cso(compiled shader object)를 사용하는 것이 관례

  • 셰이더 오프라인 컴파일할 떄에는 DirectX에 포함된 FXC 도구 사용 (CL 도구)

    • 디버그 모드 컴파일
      • fxc "color.hlsl" /Od /Zi /T vs_5_0 /E "VS" /Fo "color_vs.cso" /Fc "color_vs.asm"
    • 명령줄 옵션
      • /Od : 최적화 비활성화
      • /Zi : 디버그 정보 활성화
      • /T <문자열> : 셰이더의 종류와 대상 버전
      • /E <문자열> : 셰이더 진입점
      • /Fo <문자열> : 컴파일된 셰이더 바이트코드 목적 파일(object file)
      • /Fc <문자열> : 어셈블리 코드 목록 출력 (디버깅, 명령 개수 점검, 생성된 코드 종류 확인 등에 유용)
  • 컴파일된 셰이더 파일 사용 예시

      bool LoadShader(const std::string& path, ComPtr<ID3DBlob>& outBlob)
      {
          std::ifstream file(path, std::ios::binary | std::ios::ate);
          if (!file) return false;
    
          std::streamsize size = file.tellg();
          if (size <= 0) return false;
          file.seekg(0, std::ios::beg);
    
          if (FAILED(D3DCreateBlob(size, &outBlob))) return false;
          if (!file.read((char*)outBlob->GetBufferPointer(), size)) return false;
    
          return true;
      }

6.8 래스터화기 상태

  • 렌더링 파이프라인 단계 중 구성(설정)만 가능한 단계

  • 래스터화기 상태(resterizer state) 를 통해서 구성

  • 대표 구조체 : D3D12_RASTERIZER_DESC 구조체

      typedef struct D3D12_RASTERIZER_DESC {
          D3D12_FILL_MODE FillMode; // 기본값 : D3D12_FILL_SOLID
          D3D12_CULL_MODE CullMode; // 기본값 : D3D12_CULL_BACK
          BOOL FrontCounterClockwise; // 기본값 : false
          INT DepthBias; // 기본값 : 0
          FLOAT DepthBiasClamp; // 기본값 : 0.0f
          FLOAT SlopeScaledDepthBias; // 기본값 : 0.0f
          BOOL DepthClipEnable; // 기본값 : true
          BOOL ScissorEnable; // 기본값 : false
          BOOL MultisampleEnable; // 기본값 : false
          BOOL AntialiasedLineEnable; // 기본값 : false
          UINT ForcedSampleCount; // 기본값 : 0
      }
    • FillMode : 와이어프레임 렌더링을 위해서는 D3D12_FILL_WIREFRAME 을, 면의 속을 채운 (solid) 렌더링을 위해서는 D3D12_FILL_SOLID 지정
    • CullMode : 선별을 끄려면 D3D12_CULL_NONE, 후면 삼각형들을 선별하려면 D3D12_CULL_BACK, 전면 선별은 D3D12_CULL_FRONT
    • FrontCounterClockwise : 정점들이 시계방향(카메라 기준)으로 감긴 삼각형을 전면 삼각형으로 취급하려면 true, 반시계방향(카메라 기준)으로 감긴 삼각형을 후면 삼각형으로 취급하려면 false
    • ScissorEnable : 가위 판정 활성화는 true

6.9 파이프라인 상태 객체

  • 파이프라인 상태 객체(pipeline state object, PSO) :

    • 렌더링 파이프라인의 상태를 제어하는 집합체
    • 그래픽스 파이프라인의 다양한 상태(예: 셰이더, 블렌드 상태, 래스터라이저 상태, 깊이 스텐실 상태 등)를 하나의 객체로 묶음
    • PSO는 생성 후 변경할 수 없는 불변 객체;
      따라서 렌더링 중에 빠르게 상태를 전환할 수 있음
    • 기존 D11에서 개별로 관리하던 파이프라인 상태를 D12에서 PSO로 통합관리
    • PSO는 검증과 생성에 많은 시간이 걸릴 수 있으므로 초기화 시점에서 생성
    • 다른 PSO로 교체할 떄를 대비해, 미리 PSO를 만들어 두고 사용
  • 대표 구조체 : ID3D12PipelineState

      typedef struct D3D12_GRAPHICS_PIPELINE_STATE_DESC
      {
          ID3D12RootSignature* pRootSignature;
          D3D12_SHADER_BYTECODE VS;
          D3D12_SHADER_BYTECODE PS;
          D3D12_SHADER_BYTECODE DS;
          D3D12_SHADER_BYTECODE HS;
          D3D12_SHADER_BYTECODE GS;
          D3D12_STREAM_OUTPUT_DESC StreamOutput;
          D3D12_BLEND_DESC BlendState;
          UINT SampleMask;
          D3D12_RASTERIZER_DESC RasterizerState;
          D3D12_DEPTH_STENCIL_DESC DepthStencilState;
          D3D12_INPUT_LAYOUT_DESC InputLayout;
          D3D12_PRIMITIVE_TOPOLOGY_TYPE
              PrimitiveTopologyType;
          UINT NumRenderTargets;
          DXGI_FORMAT RTVFormats[8];
          DXGI_FORMAT DSVFormat;
          DXGI_SAMPLE_DESC SampleDesc;
      } D3D12_GRAPHICS_PIPELINE_STATE_DESC;
    • pRootSignature :
      PSO(Pipeline State Object)와 함꼐 묶을 루트 서명을 가리키는 포인터, 
      루트 서명은 반드시 PSO로 묶는 셰이더들과 호환되어야 함
    • D3D12_SHADER_BYTE_CODE : 셰이더 컴파일 바이트 코드; (VS, PS, DS, HS, GS)
        typedef struct D3D12_SHADER_BYTE_CODE {
            const BYTE *pShaderBytecode;
            SIZE_T BytecodeLength;
        } D3D12_SHADER_BYTECODE;
    • StreamOutput :
      • 출력 정의, 주로 데이터 캡처 or 변환 작업에 사용
    • State & Layout :
      • 각각의 상태 정의
    • SampleMask :
      • 다중표본화 샘플 개수(최대 32개까지 가능);
      • SampleDesc의 Count보다 큰 비트는 무시됨
      • 기본 값 0xffffffff(모든 표본 활성)
    • NumRenderTargets :
      • 동시에 사용할 렌더 대상 개수
    • RTVFormats :
      • 렌더 타겟 포맷
      • PSO와 함께 사용할 렌더 타겟의 설정들과 부합해야 함
    • DSVFormats :
      • 깊이 스텐실 버퍼 포맷
      • PSO와 함께 사용할 깊이 스텐실 버퍼의 설정들과 부합해야 함
    • SampleDesc :
      • 멀티 샘플링 샘플 개수 및 품질 수준 서술
      • PSO와 함꼐 사용할 렌더 타겟의 설정들과 부합해야 함
  • 생성 예제

          D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc;
          ZeroMemory(&psoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
          psoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
          psoDesc.pRootSignature = mRootSignature.Get();
          psoDesc.VS = 
          { 
              reinterpret_cast<BYTE*>(mvsByteCode->GetBufferPointer()), 
              mvsByteCode->GetBufferSize() 
          };
          psoDesc.PS = 
          { 
              reinterpret_cast<BYTE*>(mpsByteCode->GetBufferPointer()), 
              mpsByteCode->GetBufferSize() 
          };
          psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
          psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
          psoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
          psoDesc.SampleMask = UINT_MAX;
          psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
          psoDesc.NumRenderTargets = 1;
          psoDesc.RTVFormats[0] = mBackBufferFormat;
          psoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
          psoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
          psoDesc.DSVFormat = mDepthStencilFormat;
          ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&mPSO)));
  • PSO 교체

    • 성능을 위해 상태 변경을 최소화
    • 같은 PSO 사용 가능 물체는 함께 그리기
  • PSO 교체 예제

      // Reset을 호출해서 초기 PSO 지정
      mCommandList->Reset(mDirectCmdListAlloc.Get(), mPSO1.Get());
      /* PSO1 물체 */
    
      // PSO 변경
      mCommandList->SetPipelineState(mPSO2.Get());

번외

✅ 구성만 가능한 고정 기능(Fixed-function) 단계들(shader가 아닌 단계들)

단계 구성만 가능? 설명
Input Assembler (IA) ✅ 예 정점 버퍼, 인덱스 버퍼, Input Layout 등 구성
Rasterizer Stage ✅ 예 뷰포트, 스카이솟, 카울링, 와이어프레임 설정 등
Output Merger (OM) ✅ 예 렌더 타겟, 깊이-스텐실 버퍼 설정, 블렌딩 옵션 등
Stream Output (SO) ✅ 예 정점 쉐이더 결과를 GPU 메모리로 출력할 수 있도록 설정만 함
Multisample Stage (MSAA) ✅ 예 샘플링 품질 및 해상도 등 구성만 가능

상수 버퍼의 업로드 힙, 디폴트 힙 사용 비교

힙 타입 CPU 접근 가능 여부 GPU 성능 사용 예시
업로드 힙 (D3D12_HEAP_TYPE_UPLOAD) ✅ 가능 🚀 중간 프레임마다 갱신되는 상수 버퍼 (예: 카메라 변환 행렬, 조명 데이터)
디폴트 힙 (D3D12_HEAP_TYPE_DEFAULT) ❌ 불가능 ⚡ 빠름 변경되지 않는 정적 데이터 (예: 모델 정점 데이터, 고정된 조명 설정)

+ Recent posts

let textNodes = document.querySelectorAll("div.tt_article_useless_p_margin.contents_style > *:not(figure):not(pre)"); textNodes.forEach(function(a) { a.innerHTML = a.innerHTML.replace(/`(.*?)`/g, '$1'); });