Idris2+WebGL, 파트 #16: 프로그램 다시 바인딩

3797 단어 idriswebglfunctional
이제 9부 이후로 피하고 있던 문제를 해결할 시간입니다. 컴파일러는 특정 명령이 올바른지 여부를 결정하기 위해 바인딩된 프로그램을 어느 정도 알아야 합니다. 이는 전통적으로 수행하기 어려운 상태를 정적으로 추적해야 한다는 의미이기 때문에 좋지 않습니다. 하지만 먼저 한 발 뒤로 물러나자.

내 초기 아이디어는 실존 유형을 사용하여 프로그램과 균일한 위치를 함께 묶는 것이었습니다. 나는 이것이 나쁜 생각이었다는 것을 이제 깨달았다. 빠른 요약.

주어진 (단순화된) 유형:

export
data Program : ProgramID -> Type where
  ...

export
data UniformLocation : ProgramID -> Type where
  ...

Program pidUniformLocation pid 에서 작동하도록 함수를 정의할 수 있으며 pid 값이 동일해야 합니다. 이것으로 우리가 할 수 있는 트릭이 있습니다:

someFunction : forall a . (forall pid . Program pid -> UniformLocation pid -> a) -> a

forall pid 가 첫 번째 인수의 일부이기 때문에 someFunction 에 대한 첫 번째 인수는 pid 의 모든 값을 처리할 수 있는 함수여야 합니다. 그 때문에 pid 에 대해서는 자신이 존재한다는 것 외에는 아무것도 알 수 없으며 ProgramUniformLocation 도 마찬가지입니다. 이런 식으로 특정 변수를 해당 유형으로 묶는 것이 가능합니다.

문제는 이것이 올바른 제한이 아니라는 것입니다.

예를 들어 전화를 걸 때 unifom2fv , 규칙은 바인딩된 프로그램에서 전달된 위치가 2요소 부동 소수점 배열에 대한 것이어야 한다는 것입니다. 다른 프로그램에 대해 동일한 균일한 위치를 갖는 것은 완벽합니다. 개별 유니폼에는 어리석은 것처럼 보이지만 WebGL2는 성능 향상을 위해 프로그램 간에 공유할 수 있는 유니폼 블록을 도입했습니다.

팬텀 ID로 프로그램을 입력하는 것보다 속성과 유니폼으로 입력해야 합니다. 그들이 우리의 기대와 일치하는 한, 우리가 균일한 위치를 얻었던 모든 것이 괜찮습니다.

따라서 프로그램 유형 서명은 다음과 같아야 합니다.

public export
Attribute = (String, Int32, GLEnum) --name, size, type

public export
Uniform = (String, Int32, GLEnum) -- same

export
data Program : List Attribute -> List Uniform -> Type where
  ...


실제 코드는 예를 들어 올바른GLEnum 값만 사용할 수 있도록 하기 위해 조금 더 복잡하지만 이것이 핵심입니다.


이것은 여전히 ​​어떤 프로그램이 사용 중인지 추적하는 문제를 남깁니다. 이에 대한 좋은 해결책이 없습니다.

예를 들어 전화를 걸 때 uniform2fv , 우리는 전달된 변수의 위치와 유형을 알고 있지만 프로그램은 알지 못합니다(컴파일 시간이 아님). 이는 전달된 데이터를 프로그램의 입력과 비교할 수 없으며 런타임 유형 불일치가 가능하다는 것을 의미합니다. OpenGL4 allows for binding uniforms to specific programs , 사용된 프로그램을 추적할 필요가 없습니다. 불행히도 WebGL2에는 이러한 멋진 새 기능이 없습니다. 나는 그들을 에뮬레이트 할 수 있지만 추가하기가 싫은 오버 헤드입니다.

그래서 우리는 인덱싱된 상태 모나드, hoare 모나드 및 선형 값 전달로 돌아갑니다.

프로그램을 사용하는 함수를 고려하십시오.

useProgram : MonadState WebGL2.WebGLRenderingContext m =>
  (1 _ : WebGLProgram attributes uniforms) ->
  m (WebGLProgram attributes uniforms)


순진한 접근 방식은 프로그램에 팬텀 유형을 추가하여 바인딩되었는지 표시하는 것입니다.

useProgram : MonadState WebGL2.WebGLRenderingContext m =>
  (1 _ : WebGLProgram  attributes uniforms NotInUse) ->
  m (WebGLProgram  attributes uniforms InUse)


(유형 정의를 변경할 필요가 없는 종속 유형으로 더 멋진 것을 할 수 있지만 여기서는 특별히 관련이 없습니다.)

이렇게 하면 지워진 암시적 인수로 멋진 작업을 수행할 수 있습니다.

uniform1fv : MonadState WebGL2.WebGLRenderingContext m =>
  WebGLUniformLocation uniformType ->
  {auto 0 prf : WebGLProgram attributes uniforms InUse} ->
  Float32Array ->
  m ()

WebGLProgram (by InUse )로 표시된 useProgam가 현재 컨텍스트에 존재하는지 확인합니다.

문제는 useProgram 를 두 번 호출하여 InUse 인 2개의 프로그램을 얻을 수 있다는 것입니다.

그래서 어떤 식으로든 useProgram 호출될 때 어떤 형태의 프로그램 상태를 "소비"해야 합니다.

더 나쁜 것은 사용자가 존재하지 않는 입력에 바인딩하는 것을 막으려는 것이 아닙니다. 실제로는 괜찮고 디버깅할 때도 유용하며 무시할 수 있습니다. 문제는 사용된 바인딩 값이 아닙니다. 따라서 우리는 또한 바인딩된 입력을 추적해야 합니다.

그 때문에 나는 현재 어떤 형태의 인덱싱된 모나드가 불가피하다고 생각하는 경향이 있습니다. 나는 그것이 최종 사용자를 위해 좀 더 복잡하게 만들기 때문에 그것에 대해별로 행복하지 않습니다. 인덱싱된 모나드는 결국 그렇게 일반적이지 않습니다.

좋은 웹페이지 즐겨찾기