-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Conversation
This could also include a refactor that uses structs as the members of the buffers instead of writing explicit accessors (using With |
@jfirebaugh, thanks for your PR! By analyzing this pull request, we identified @mikemorris, @ansis and @springmeyer to be potential reviewers. |
f65f62e
to
ee3dd65
Compare
CircleVertexBuffer vertexBuffer_; | ||
TriangleElementsBuffer elementsBuffer_; | ||
std::vector<CircleVertex> vertexes; | ||
std::vector<gl::Triangle<uint16_t>> indexes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kkaefer Should we hard-code uint16_t
as the index type? So a declaration like this would be:
std::vector<gl::Triangle> indexes;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OpenGL only supports 16bit unsigned indices anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this is an OpenGL ES limitation and I was looking at generic OpenGL documentation for glDrawElements
. OpenGL ES also supports uint8_t
indexes, but I don't think we'll ever use those. So I'll deparameterize this.
db104b0
to
a327bf5
Compare
namespace gl { | ||
|
||
struct ElementOffset { | ||
std::size_t value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
size_t
is 8 bytes on 64-bit platforms, can we use uint32_t
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? If you want to match GLsizei
, it should be int32_t
, or actually uint16_t
because this must be a non-negative value.
|
||
template <class Primitive> | ||
class IndexBuffer { | ||
public: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we static_assert
that Primitive
is one of Line
and Triangle
?
template <class Vertex> | ||
class VertexBuffer { | ||
public: | ||
static constexpr std::size_t vertexSize = sizeof(Vertex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we use using vertexSize = std::integral_constant<std::size_t, sizeof(Vertex)>;
to avoid static data members that need initialization?
static_cast<uint16_t>(triangleIndex + 2)}); | ||
buffer.triangles.push_back({static_cast<uint16_t>(triangleIndex + 1), | ||
static_cast<uint16_t>(triangleIndex + 2), | ||
static_cast<uint16_t>(triangleIndex + 3)}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why push_back
and not emplace_back
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emplace_back
doesn't work with aggregate initialization. I'll add constructors to Line
and Triangle
so we can use it.
|
||
struct TextBuffer { | ||
TextVertexBuffer vertices; | ||
TriangleElementsBuffer triangles; | ||
std::vector<TextureRectVertex> vertexes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why switch from vertices
/indices
to vertexes
/indexes
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For indexes
I actually meant to use lines
or triangles
depending on the primitive. I'll switch back to vertices
.
void CircleVertex::bind(const int8_t* offset) { | ||
static_assert(sizeof(CircleVertex) == 4, "expected CircleVertex size"); | ||
|
||
MBGL_BIND_VERTEX_ATTRIBUTE(CircleVertex, a_pos, offset); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an incorrect place for using a_pos
; those names/attributes are shader-specific and not Vertex type specific.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Vertex attribute binding involves some shader-specific things and some vertex-specific things:
- Shader-specific: attribute name, index, and GLSL type.
- Vertex-specific: member name, offset, and C++ type.
I'd like to come up with a design where:
- A given C++ vertex type can be used with multiple shaders.
- A shader requires one particular vertex type, enforced at compile time.
- Attribute indexes are defined per-
Shader
-subclass, rather than inShader
, as they are now. Not all shaders have all attributes. - Debug builds verify that the GLSL and native types are consistent, using
glGetActiveAttrib
to introspect the GLSL type. (We should do this for uniforms as well.) - I'm open to a design that doesn't enforce that the GLSL attribute name matches the C++ member name, but it also doesn't seem bad to do so. Why would we need them to differ?
I think the starting point here is to introduce a counterpart to uniform.{hpp,cpp}
for attributes and add members to each Shader
subclass -- e.g.:
AttributeVector<int16_t, 2> a_pos = { "a_pos", *this };
Then see where that leads the binding code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sketched here but currently stuck on a tricky problem with type erasing pointer-to-members.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still have the issue of Vertex types having to have the same names as the shaders. In our code, we (almost?) always do it like that, but there's no reason why we need to do it like that. I.e. VertexType::a_pos
could be bound to Shader::a_pos
, but we could also name the position in the VertexType
something else.
|
||
// This has to be a macro because it uses the offsetof macro, which is the only legal way to get a member offset. | ||
#define MBGL_BIND_VERTEX_ATTRIBUTE(VertexType, member, offset) \ | ||
::mbgl::gl::bindVertexAttribute(Shader::member, &VertexType::member, offset, offsetof(VertexType, member)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be using std::is_standard_layout
to ensure that we can safely use offsetof
. We should also assert that all values we get from offsetof
are multiples of 4.
It also assumes that the shader and the vertex type have identically named member names. I feel a little bit uneasy about that, but can't quite put my finger on it.
} {} | ||
|
||
int16_t a_pos[2]; | ||
int16_t a_texture_pos[2]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make all of these members const
?
class RasterShader : public Shader { | ||
public: | ||
RasterShader(gl::Context&, Defines defines = None); | ||
|
||
void bind(int8_t* offset) final; | ||
void bind(const gl::VertexBuffer<RasterVertex>&, | ||
const int8_t* offset); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we rename offset
to something like begin
to avoid confusion of the offset within a buffer with the offset of an attribute within a vertex?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My plan here is to replace both parameters with const gl::VertexBufferSlice<RasterVertex>&
, but I'd like to put that off until a followup PR.
18ddf48
to
95bbe9e
Compare
@kkaefer Re-review? |
Template on shader types, rather than count. This allows the compiler to enforce using the correct VAO for the shader and PaintMode. This fixes OverdrawMode with circle layers. While here, avoid using unique_ptrs for groups. Instead, ensure ElementGroup is movable.
3390bba
to
39c4cb0
Compare
static_assert(std::is_standard_layout<V>::value, "vertex type must use standard layout"); | ||
static_assert(memberOffset % 4 == 0, "vertex attribute must be optimally aligned"); | ||
static_assert(1 <= N && N <= 4, "count must be 1, 2, 3, or 4"); | ||
static_assert(sizeof(V) <= std::numeric_limits<GLsizei>::max(), "vertex type is too big"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol
|
||
ElementGroup(uint32_t vertex_length_ = 0, uint32_t elements_length_ = 0) | ||
: vertex_length(vertex_length_) | ||
, elements_length(elements_length_) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our current formatting guide does not have leading commas in initializer lists. We should either change this formatting or the formatting guidelines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was fixed in a followup commit.
modified(std::move(modified_)), | ||
expires(std::move(expires_)), | ||
debugMode(debugMode_) { | ||
std::vector<PlainVertex> buildTextVertexes(const OverscaledTileID& id, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are still a few instances of vertexes
in the code.
void CircleVertex::bind(const int8_t* offset) { | ||
static_assert(sizeof(CircleVertex) == 4, "expected CircleVertex size"); | ||
|
||
MBGL_BIND_VERTEX_ATTRIBUTE(CircleVertex, a_pos, offset); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still have the issue of Vertex types having to have the same names as the shaders. In our code, we (almost?) always do it like that, but there's no reason why we need to do it like that. I.e. VertexType::a_pos
could be bound to Shader::a_pos
, but we could also name the position in the VertexType
something else.
As part of the general OpenGL code refactor effort, we should redesign how we handle buffers. The main design goal is to split the current responsibilities of the current
Buffer
class template.std::vector<Vertex>
(orstd::array<Vertex, N>
for fixed-sized arrays).Vertex
is a stand in for any user-defined, plain-old-struct type with appropriate data members for the vertex attributes.Secondary design goals:
Buffer
is templated onGLenum target
, but we want to removeGLenum
from the public interface.)API sketch: