¿Cuál es un buen enfoque para manejar uniformes en OpenGL moderno?

8

Estoy creando un renderizador usando OpenGL moderno (3.1 y superior) y ahora estoy tratando de crear una forma eficiente pero flexible de manejar uniformes. He estado leyendo sobre objetos de almacenamiento intermedio uniformes y sobre el enfoque 'común' para usarlos (este último desafortunadamente no me dio tantos resultados como esperaba).

Para reducir las llamadas a la API OpenGL y almacenar datos en la memoria contigua, estoy considerando crear múltiples memorias intermedias grandes para cada estructura de datos que se deben cargar en la GPU. Cada búfer tiene un tamaño máximo de 16kb (por lo que entiendo, se garantiza que esta cantidad estará disponible para un UBO). Cuando un objeto quiere poder cargar uniformes en la GPU, obtiene el primer búfer del tipo a cargar que aún no está lleno y obtiene el siguiente índice disponible en ese búfer. Cuando se dibuja el objeto, se une al UBO (si aún no está vinculado) y carga el índice del elemento del UBO.

Esto resulta en algo como esto:

layout(std140) uniform ModelData { 
    mat4 model_matrix[kNumInstancesPerModelUbo]; 
}
uniform int u_ModelDataIndex;

layout(std140) uniform SkeletonData { 
    mat4 bone_transforms[kNumInstancesPerSkeletonUbo][kMaxBones]; 
}
uniform int u_SkeletonDataIndex;

Sin embargo, también estoy considerando lo siguiente:

layout(std140) uniform MeshData {
    mat4 model_matrix[kNumInstancesPerMeshUbo];
    mat4 bone_transforms[kNumInstancesPerMeshUbo][kMaxBones];
}
uniform int u_MeshDataIndex;

De alguna manera, esto se siente mucho más limpio, ya que se necesita un solo índice para acceder a todos los datos relacionados con la malla que se cargará. Por otro lado, esto podría salirse de control (tamaño de búfer mayor de 16 kb, maneja datos irrelevantes (por ejemplo, una malla sin esqueleto) o incluso problemas de sincronización, ya que no tiene acceso para decir los huesos mientras carga las matrices del modelo) y tampoco estoy seguro de cómo esto afectaría el diseño de la memoria en la GPU.

Francamente, parece que estoy atrapado aquí y no puedo encontrar un buen ejemplo concreto de cómo manejaría UBO de manera rápida y flexible.

¿Tiene algún consejo o recurso para mí que pueda ayudarme aquí?

PhilipMR
fuente

Respuestas:

2

Subasignar desde un búfer más grande es absolutamente el camino a seguir, con advertencias. Vengo más del lado de DirectX / Vulkan, pero esto debería aplicarse igualmente a OpenGL (simplemente no tendré llamadas directas a la API aquí en esta respuesta). Las cosas a considerar son las siguientes:

  • ¿Necesita indexar en el búfer más grande o está de acuerdo con vincular el recurso al desplazamiento cada vez?
  • ¿Se ha ocupado de alguna / todas las restricciones de alineación para sus uniformes que están empaquetadas (la alineación de 256 bytes es común)?

Las API de gráficos más recientes tienen un "desplazamiento dinámico" que puede especificar con el comando de dibujo, que es una forma bastante rápida de acceder indirectamente a una subregión de un búfer. Sin embargo, suponiendo que tenga datos de almacenamiento intermedio triple que sean mutables, debe haber poca o ninguna contención en el controlador para vincular los datos (solo algunos gastos generales fijos).

En resumen, sí, asignar regiones más grandes de memoria / memorias intermedias y subarrendar esas regiones se considera la mejor práctica. Esto se aplica incluso a objetos con diferentes sombreadores (si su asignador puede manejarlo).

jeremyong
fuente
0

Incluya una fase de evaluación comparativa de ambas soluciones en su aplicación y luego seleccione la solución ganadora en tiempo de ejecución. Esto es simple, portátil y a prueba de futuro. Quiero decir, tienes prueba para esto, ¿verdad? ;-)

Sé que esta es una respuesta bastante genérica a la "mejor práctica" para un alto rendimiento, pero si lo piensa, hay miles de posibles configuraciones de destino y muchos proveedores a considerar. Si necesita ese pequeño extra, vaya a pagar a su proveedor por un controlador optimizado para su aplicación.

Andreas
fuente