Skip to main content
added 3 characters in body
Source Link
Chris Gnam
  • 620
  • 6
  • 18

So I've got a rendering engine where in certain applications, it makes sense to use a vertex buffer, while in other applications it makes sense to use a triangle buffer. I'll briefly explain the difference so it is clear:

  • Vertex Buffer: This approach means that triangles are stored using 2 arrays. A vertex buffer and an index buffer. The vertex buffer contains all of the unique vertex information, while the index buffer contains all of the face definitions as indices of the vertex buffer. So for example, to obtain the 2nd vertex in a triangle with index idx you would call: vertex_buffer[index_buffer[3*idx+1]] (assuming both vertex_buffer and index_buffer are just 1d arrays).

  • Triangle Buffer: This approach means that each triangle is represented by a struct containing all of its necessary data. So to access the first element of the 2nd vertex in a triangle with index idx you would call: triangle_buffer[idx].vertex1[0].

The benefit of the triangle buffer approach is that it requires fewer reads from memory for each individual triangle at the expense of potentially duplicating data (as is the case if you have a continuous geometry and so triangles share vertices). The benefit of the vertex buffer approach is that it does not duplicate any memory at the expense of needing more reads from memory to get both the index and subsequent vertex. For a continuous geometry processed coherently though, this is less of an issue as previously loaded triangle vertices will still be in cache.

There are times when it makes more sense to use one of these approaches over the other, and I'd like that to be configurable at compile time. My first gut thought on how to do that would be to create a wrapper function for the this process of fetching triangle data, and inlining that where needed. So the function(s) might look like this:

template <typename Scalar> inline Vertex<Scalar> get_triangle_vertex0(size_t triangle_idx) { #if defined(TRIANGLE_BUFFER) return triangle_buffer[idx].vertex0 #else return vertex_buffer[index_buffer[3*idx+1]] #endif } template <typename Scalar> inline Vertex<Scalar> get_triangle_vertex1(size_t triangle_idx) { #if defined(TRIANGLE_BUFFER) return triangle_buffer[idx].vertex1 #else return vertex_buffer[index_buffer[3*idx+1] + 1] #endif } 

NOTE: For this is just rough pseudo code just meant to outline the rough concept of my initial plan, which is to wrap each of the indexing methods in an inlined function so that at compile time you can decide between each method.

Is this the correct way of handling this sort of thing? Is there a performance penalty for this? Or is there a more sensible way to achieve the same result?

The only alternative I can think of is to go through and manually put the preprocessor directives everywhere I need to access triangle data. Which is why I thought an inline function like this might help consolidate that and keep things clean.

So I've got a rendering engine where in certain applications, it makes sense to use a vertex buffer, while in other applications it makes sense to use a triangle buffer. I'll briefly explain the difference so it is clear:

  • Vertex Buffer: This approach means that triangles are stored using 2 arrays. A vertex buffer and an index buffer. The vertex buffer contains all of the unique vertex information, while the index buffer contains all of the face definitions as indices of the vertex buffer. So for example, to obtain the 2nd vertex in a triangle with index idx you would call: vertex_buffer[index_buffer[3*idx+1]] (assuming both vertex_buffer and index_buffer are just 1d arrays).

  • Triangle Buffer: This approach means that each triangle is represented by a struct containing all of its necessary data. So to access the first element of the 2nd vertex in a triangle with index idx you would call: triangle_buffer[idx].vertex1[0].

The benefit of the triangle buffer approach is that it requires fewer reads from memory for each individual triangle at the expense of potentially duplicating data (as is the case if you have a continuous geometry and so triangles share vertices). The benefit of the vertex buffer approach is that it does not duplicate any memory at the expense of needing more reads from memory to get both the index and subsequent vertex. For a continuous geometry processed coherently though, this is less of an issue as previously loaded triangle vertices will still be in cache.

There are times when it makes more sense to use one of these approaches over the other, and I'd like that to be configurable at compile time. My first gut thought on how to do that would be to create a wrapper function for the this process of fetching triangle data, and inlining that where needed. So the function might look like this:

template <typename Scalar> inline Vertex<Scalar> get_triangle_vertex0(size_t triangle_idx) { #if defined(TRIANGLE_BUFFER) return triangle_buffer[idx].vertex0 #else return vertex_buffer[index_buffer[3*idx+1]] #endif } template <typename Scalar> inline Vertex<Scalar> get_triangle_vertex1(size_t triangle_idx) { #if defined(TRIANGLE_BUFFER) return triangle_buffer[idx].vertex1 #else return vertex_buffer[index_buffer[3*idx+1] + 1] #endif } 

NOTE: For this is just rough pseudo code just meant to outline the rough concept of my initial plan, which is to wrap each of the indexing methods in an inlined function so that at compile time you can decide between each method.

Is this the correct way of handling this sort of thing? Is there a performance penalty for this? Or is there a more sensible way to achieve the same result?

The only alternative I can think of is to go through and manually put the preprocessor directives everywhere I need to access triangle data. Which is why I thought an inline function like this might help consolidate that and keep things clean.

So I've got a rendering engine where in certain applications, it makes sense to use a vertex buffer, while in other applications it makes sense to use a triangle buffer. I'll briefly explain the difference so it is clear:

  • Vertex Buffer: This approach means that triangles are stored using 2 arrays. A vertex buffer and an index buffer. The vertex buffer contains all of the unique vertex information, while the index buffer contains all of the face definitions as indices of the vertex buffer. So for example, to obtain the 2nd vertex in a triangle with index idx you would call: vertex_buffer[index_buffer[3*idx+1]] (assuming both vertex_buffer and index_buffer are just 1d arrays).

  • Triangle Buffer: This approach means that each triangle is represented by a struct containing all of its necessary data. So to access the first element of the 2nd vertex in a triangle with index idx you would call: triangle_buffer[idx].vertex1[0].

The benefit of the triangle buffer approach is that it requires fewer reads from memory for each individual triangle at the expense of potentially duplicating data (as is the case if you have a continuous geometry and so triangles share vertices). The benefit of the vertex buffer approach is that it does not duplicate any memory at the expense of needing more reads from memory to get both the index and subsequent vertex. For a continuous geometry processed coherently though, this is less of an issue as previously loaded triangle vertices will still be in cache.

There are times when it makes more sense to use one of these approaches over the other, and I'd like that to be configurable at compile time. My first gut thought on how to do that would be to create a wrapper function for the this process of fetching triangle data, and inlining that where needed. So the function(s) might look like this:

template <typename Scalar> inline Vertex<Scalar> get_triangle_vertex0(size_t triangle_idx) { #if defined(TRIANGLE_BUFFER) return triangle_buffer[idx].vertex0 #else return vertex_buffer[index_buffer[3*idx+1]] #endif } template <typename Scalar> inline Vertex<Scalar> get_triangle_vertex1(size_t triangle_idx) { #if defined(TRIANGLE_BUFFER) return triangle_buffer[idx].vertex1 #else return vertex_buffer[index_buffer[3*idx+1] + 1] #endif } 

NOTE: For this is just rough pseudo code just meant to outline the rough concept of my initial plan, which is to wrap each of the indexing methods in an inlined function so that at compile time you can decide between each method.

Is this the correct way of handling this sort of thing? Is there a performance penalty for this? Or is there a more sensible way to achieve the same result?

The only alternative I can think of is to go through and manually put the preprocessor directives everywhere I need to access triangle data. Which is why I thought an inline function like this might help consolidate that and keep things clean.

added 247 characters in body
Source Link
Chris Gnam
  • 620
  • 6
  • 18

So I've got a rendering engine where in certain applications, it makes sense to use a vertex buffer, while in other applications it makes sense to use a triangle buffer. I'll briefly explain the difference so it is clear:

  • Vertex Buffer: This approach means that triangles are stored using 2 arrays. A vertex buffer and an index buffer. The vertex buffer contains all of the unique vertex information, while the index buffer contains all of the face definitions as indices inof the vertex buffer. So for example, to obtain the first element of the 2nd vertex in a triangle with index idx you would call: vertex_buffer[index_buffer[3*idx+1]] (assuming both vertex_buffer and index_buffer are just 1d arrays).

  • Triangle Buffer: This approach means that each triangle is represented by a struct containing all of its necessary data. So to access the first element of the 2nd vertex in a triangle with index idx you would call: triangle_buffer[idx].vertex1[0].

The benefit of the triangle buffer approach is that it requires fewer reads from memory for each individual triangle at the expense of potentially duplicating data (as is the case if you have a continuous geometry and so triangles share vertices). The benefit of the vertex buffer approach is that it does not duplicate any memory at the expense of needing more reads from memory to get both the index and subsequent vertex. For a continuous geometry processed coherently though, this is less of an issue as previously loaded triangle vertices will still be in cache.

There are times when it makes more sense to use one of these approaches over the other, and I'd like that to be configurable at compile time. My first gut thought on how to do that would be to create a wrapper function for the this process of fetching triangle data, and inlining that where needed. So the function might look like this:

<templatetemplate typename<typename Scalar> inline ScalarVertex<Scalar> get_triangle_vertexget_triangle_vertex0(size_t triangle_idx) { #if defined(TRIANGLE_BUFFER) return vertex_buffer[index_buffer[3*idx+1]]triangle_buffer[idx].vertex0 #else return vertex_buffer[index_buffer[3*idx+1]] #endif } template <typename Scalar> inline Vertex<Scalar> get_triangle_vertex1(size_t triangle_idx) { #if defined(TRIANGLE_BUFFER) return triangle_buffer[idx].vertex1 #else return vertex_buffer[index_buffer[3*idx+1] + 1] #endif } 

NOTE: For this is just rough pseudo code just meant to outline the rough concept of my initial plan, which is to wrap each of the indexing methods in an inlined function so that at compile time you can decide between each method.

Is this the correct way of handling this sort of thing? Is there a performance penalty for this? Or is there a more sensible way to achieve the same result?

The only alternative I can think of is to go through and manually put the preprocessor directives everywhere I need to access triangle data. Which is why I thought an inline function like this might help consolidate that and keep things clean.

So I've got a rendering engine where in certain applications, it makes sense to use a vertex buffer, while in other applications it makes sense to use a triangle buffer. I'll briefly explain the difference so it is clear:

  • Vertex Buffer: This approach means that triangles are stored using 2 arrays. A vertex buffer and an index buffer. The vertex buffer contains all of the unique vertex information, while the index buffer contains all of the face definitions as indices in the vertex buffer. So for example, to obtain the first element of the 2nd vertex in a triangle with index idx you would call: vertex_buffer[index_buffer[3*idx+1]] (assuming both vertex_buffer and index_buffer are just 1d arrays).

  • Triangle Buffer: This approach means that each triangle is represented by a struct containing all of its necessary data. So to access the first element of the 2nd vertex in a triangle with index idx you would call: triangle_buffer[idx].vertex1[0].

The benefit of the triangle buffer approach is that it requires fewer reads from memory for each individual triangle at the expense of potentially duplicating data (as is the case if you have a continuous geometry and so triangles share vertices). The benefit of the vertex buffer approach is that it does not duplicate any memory at the expense of needing more reads from memory to get both the index and subsequent vertex. For a continuous geometry processed coherently though, this is less of an issue as previously loaded triangle vertices will still be in cache.

There are times when it makes more sense to use one of these approaches over the other, and I'd like that to be configurable at compile time. My first gut thought on how to do that would be to create a wrapper function for the this process of fetching triangle data, and inlining that where needed. So the function might look like this:

<template typename Scalar> inline Scalar get_triangle_vertex(size_t triangle_idx) { #if defined(TRIANGLE_BUFFER) return vertex_buffer[index_buffer[3*idx+1]] #else return triangle_buffer[idx].vertex1 #endif } 

NOTE: For this is just rough pseudo code just meant to outline the rough concept of my initial plan, which is to wrap each of the indexing methods in an inlined function so that at compile time you can decide between each method.

Is this the correct way of handling this sort of thing? Is there a performance penalty for this? Or is there a more sensible way to achieve the same result?

The only alternative I can think of is to go through and manually put the preprocessor directives everywhere I need to access triangle data. Which is why I thought an inline function like this might help consolidate that and keep things clean.

So I've got a rendering engine where in certain applications, it makes sense to use a vertex buffer, while in other applications it makes sense to use a triangle buffer. I'll briefly explain the difference so it is clear:

  • Vertex Buffer: This approach means that triangles are stored using 2 arrays. A vertex buffer and an index buffer. The vertex buffer contains all of the unique vertex information, while the index buffer contains all of the face definitions as indices of the vertex buffer. So for example, to obtain the 2nd vertex in a triangle with index idx you would call: vertex_buffer[index_buffer[3*idx+1]] (assuming both vertex_buffer and index_buffer are just 1d arrays).

  • Triangle Buffer: This approach means that each triangle is represented by a struct containing all of its necessary data. So to access the first element of the 2nd vertex in a triangle with index idx you would call: triangle_buffer[idx].vertex1[0].

The benefit of the triangle buffer approach is that it requires fewer reads from memory for each individual triangle at the expense of potentially duplicating data (as is the case if you have a continuous geometry and so triangles share vertices). The benefit of the vertex buffer approach is that it does not duplicate any memory at the expense of needing more reads from memory to get both the index and subsequent vertex. For a continuous geometry processed coherently though, this is less of an issue as previously loaded triangle vertices will still be in cache.

There are times when it makes more sense to use one of these approaches over the other, and I'd like that to be configurable at compile time. My first gut thought on how to do that would be to create a wrapper function for the this process of fetching triangle data, and inlining that where needed. So the function might look like this:

template <typename Scalar> inline Vertex<Scalar> get_triangle_vertex0(size_t triangle_idx) { #if defined(TRIANGLE_BUFFER) return triangle_buffer[idx].vertex0 #else return vertex_buffer[index_buffer[3*idx+1]] #endif } template <typename Scalar> inline Vertex<Scalar> get_triangle_vertex1(size_t triangle_idx) { #if defined(TRIANGLE_BUFFER) return triangle_buffer[idx].vertex1 #else return vertex_buffer[index_buffer[3*idx+1] + 1] #endif } 

NOTE: For this is just rough pseudo code just meant to outline the rough concept of my initial plan, which is to wrap each of the indexing methods in an inlined function so that at compile time you can decide between each method.

Is this the correct way of handling this sort of thing? Is there a performance penalty for this? Or is there a more sensible way to achieve the same result?

The only alternative I can think of is to go through and manually put the preprocessor directives everywhere I need to access triangle data. Which is why I thought an inline function like this might help consolidate that and keep things clean.

Source Link
Chris Gnam
  • 620
  • 6
  • 18

Is using an inline function a correct way of handling needing to access the same data from different structures given compile settings?

So I've got a rendering engine where in certain applications, it makes sense to use a vertex buffer, while in other applications it makes sense to use a triangle buffer. I'll briefly explain the difference so it is clear:

  • Vertex Buffer: This approach means that triangles are stored using 2 arrays. A vertex buffer and an index buffer. The vertex buffer contains all of the unique vertex information, while the index buffer contains all of the face definitions as indices in the vertex buffer. So for example, to obtain the first element of the 2nd vertex in a triangle with index idx you would call: vertex_buffer[index_buffer[3*idx+1]] (assuming both vertex_buffer and index_buffer are just 1d arrays).

  • Triangle Buffer: This approach means that each triangle is represented by a struct containing all of its necessary data. So to access the first element of the 2nd vertex in a triangle with index idx you would call: triangle_buffer[idx].vertex1[0].

The benefit of the triangle buffer approach is that it requires fewer reads from memory for each individual triangle at the expense of potentially duplicating data (as is the case if you have a continuous geometry and so triangles share vertices). The benefit of the vertex buffer approach is that it does not duplicate any memory at the expense of needing more reads from memory to get both the index and subsequent vertex. For a continuous geometry processed coherently though, this is less of an issue as previously loaded triangle vertices will still be in cache.

There are times when it makes more sense to use one of these approaches over the other, and I'd like that to be configurable at compile time. My first gut thought on how to do that would be to create a wrapper function for the this process of fetching triangle data, and inlining that where needed. So the function might look like this:

<template typename Scalar> inline Scalar get_triangle_vertex(size_t triangle_idx) { #if defined(TRIANGLE_BUFFER) return vertex_buffer[index_buffer[3*idx+1]] #else return triangle_buffer[idx].vertex1 #endif } 

NOTE: For this is just rough pseudo code just meant to outline the rough concept of my initial plan, which is to wrap each of the indexing methods in an inlined function so that at compile time you can decide between each method.

Is this the correct way of handling this sort of thing? Is there a performance penalty for this? Or is there a more sensible way to achieve the same result?

The only alternative I can think of is to go through and manually put the preprocessor directives everywhere I need to access triangle data. Which is why I thought an inline function like this might help consolidate that and keep things clean.