PYMOL-5169: Move VertexBufferGL to generalized VertexBuffer (etc)

This commit is contained in:
Jarrett Johnson
2025-04-03 08:28:26 -04:00
parent 57daee0b7e
commit 6977216eb1
14 changed files with 1071 additions and 728 deletions

51
include/pymol/span.h Normal file
View File

@@ -0,0 +1,51 @@
#pragma once
#include <cstddef>
namespace pymol
{
template <typename T> class span
{
public:
span() = default;
span(T* data, std::size_t size)
: data_(data)
, size_(size)
{
}
template <typename RangeT>
span(RangeT& range)
: data_(range.data())
, size_(range.size())
{
}
T& operator[](std::size_t index) { return data_[index]; }
std::size_t size() const { return size_; }
T* data() { return data_; }
const T* data() const { return data_; }
using value_type = T;
private:
T* data_{};
std::size_t size_{};
};
template <typename RangeT> span(RangeT&) -> span<typename RangeT::value_type>;
template <typename RangeT>
span(const RangeT&) -> span<const typename RangeT::value_type>;
template <typename RangeT> span<const std::byte> as_bytes(RangeT& range)
{
return span<const std::byte>(reinterpret_cast<const std::byte*>(range.data()),
range.size() * sizeof(typename RangeT::value_type));
}
} // namespace pymol

View File

@@ -197,286 +197,6 @@ std::size_t GetSizeOfVertexFormat(VertexFormat format)
}
}
GenericBuffer::GenericBuffer(buffer_layout layout, MemoryProperty memProperty)
: m_memProperty(memProperty)
, m_layout(layout)
{
}
GenericBuffer::~GenericBuffer()
{
for (auto i = 0; i < m_desc.size(); ++i) {
auto& glID = desc_glIDs[i];
if (glID) {
glDeleteBuffers(1, &glID);
}
}
if (m_interleavedID) {
glDeleteBuffers(1, &m_interleavedID);
}
}
bool GenericBuffer::bufferData(BufferDataDesc&& desc)
{
m_desc = std::move(desc);
desc_glIDs = std::vector<GLuint>(m_desc.size());
return evaluate();
}
bool GenericBuffer::bufferData(
BufferDataDesc&& desc, const void* data, size_t len, size_t stride)
{
bool ok = true;
m_desc = std::move(desc);
desc_glIDs = std::vector<GLuint>(m_desc.size());
m_interleaved = true;
m_stride = stride;
ok = genBuffer(m_interleavedID, len, data);
return ok;
}
void GenericBuffer::bufferSubData(size_t offset, size_t size, void* data, size_t index)
{
assert("Invalid Desc index" && index < m_desc.size());
assert("Invalid GLDesc index" && index < desc_glIDs.size());
auto glID = m_interleaved ? m_interleavedID : desc_glIDs[index];
glBindBuffer(bufferType(), glID);
glBufferSubData(bufferType(), offset, size, data);
}
void GenericBuffer::bufferReplaceData(size_t offset, size_t len, const void* data)
{
glBindBuffer(bufferType(), m_interleavedID);
glBufferSubData(bufferType(), offset, len, data);
}
const BufferDataDesc& GenericBuffer::getVertDesc() const
{
return m_desc;
}
bool GenericBuffer::evaluate()
{
if (bufferType() == GL_ELEMENT_ARRAY_BUFFER) {
return seqBufferData();
} else {
switch (m_layout) {
case buffer_layout::SEPARATE:
return sepBufferData();
break;
case buffer_layout::SEQUENTIAL:
return seqBufferData();
break;
case buffer_layout::INTERLEAVED:
return interleaveBufferData();
break;
}
}
return true; // unreacheable/Should be false?
}
bool GenericBuffer::sepBufferData()
{
for (auto i = 0; i < m_desc.size(); ++i) {
// If the specified size is 0 but we have a valid pointer
// then we are going to glVertexAttribXfv X in {1,2,3,4}
const auto& d = m_desc[i];
auto& glID = desc_glIDs[i];
if (d.data_ptr && (m_memProperty == MemoryProperty::DeviceLocal)) {
if (d.data_size) {
if (!genBuffer(glID, d.data_size, d.data_ptr)) {
return false;
}
}
}
}
return true;
}
bool GenericBuffer::seqBufferData() {
// this is only going to use a single opengl vbo
m_interleaved = true;
size_t buffer_size { 0 };
for ( auto & d : m_desc ) {
buffer_size += d.data_size;
}
std::vector<std::uint8_t> buffer_data(buffer_size);
auto data_ptr = buffer_data.data();
size_t offset = 0;
for ( auto & d : m_desc ) {
d.offset = offset;
if (d.data_ptr)
memcpy(data_ptr, d.data_ptr, d.data_size);
else
memset(data_ptr, 0, d.data_size);
data_ptr += d.data_size;
offset += d.data_size;
}
return genBuffer(m_interleavedID, buffer_size, buffer_data.data());
}
bool GenericBuffer::interleaveBufferData()
{
const std::size_t bufferCount = m_desc.size();
std::size_t stride = 0;
std::vector<const uint8_t*> data_table(bufferCount);
std::vector<const uint8_t*> ptr_table(bufferCount);
std::vector<std::size_t> size_table(bufferCount);
std::size_t count =
m_desc[0].data_size / GetSizeOfVertexFormat(m_desc[0].m_format);
// Maybe assert that all pointers in d_desc are valid?
for (size_t i = 0; i < bufferCount; ++i) {
auto& d = m_desc[i];
// offset is the current stride
d.offset = stride;
// These must come after so that offset starts at 0
// Size of 3 normals or whatever the current type is
size_table[i] = GetSizeOfVertexFormat(d.m_format);
// Increase our current estimate of the stride by this amount
stride += size_table[i];
// Does the addition of that previous stride leave us on a word boundry?
int m = stride % 4;
stride = (m ? (stride + (4 - m)) : stride);
// data_table a pointer to the begining of each array
data_table[i] = static_cast<const std::uint8_t*>(d.data_ptr);
// We will move these pointers along by the values in the size table
ptr_table[i] = data_table[i];
}
m_stride = stride;
std::size_t interleavedSize = count * stride;
std::vector<std::uint8_t> interleavedData(interleavedSize);
auto iPtr = interleavedData.data();
while (iPtr != (interleavedData.data() + interleavedSize)) {
for (size_t i = 0; i < bufferCount; ++i) {
if (ptr_table[i]) {
memcpy(iPtr, ptr_table[i], size_table[i]);
ptr_table[i] += size_table[i];
}
iPtr += size_table[i];
}
}
m_interleaved = true;
return genBuffer(m_interleavedID, interleavedSize, interleavedData.data());
}
bool GenericBuffer::genBuffer(GLuint& id, size_t size, const void* ptr)
{
glGenBuffers(1, &id);
if (!CheckGLErrorOK(nullptr, "GenericBuffer::genBuffer failed\n"))
return false;
glBindBuffer(bufferType(), id);
if (!CheckGLErrorOK(nullptr, "GenericBuffer::bindBuffer failed\n"))
return false;
glBufferData(bufferType(), size, ptr, GL_STATIC_DRAW);
if (!CheckGLErrorOK(nullptr, "GenericBuffer::bufferData failed\n"))
return false;
return true;
}
void VertexBufferGL::bind_attrib(GLuint prg, const BufferDesc& d, GLuint glID)
{
GLint loc = glGetAttribLocation(prg, d.attr_name);
auto type_dim = VertexFormatToGLSize(d.m_format);
auto type = VertexFormatToGLType(d.m_format);
auto data_norm = VertexFormatToGLNormalized(d.m_format);
bool masked = false;
for (GLint lid : m_attribmask)
if (lid == loc)
masked = true;
if (loc >= 0)
m_locs.push_back(loc);
if (loc >= 0 && !masked) {
if (!m_interleaved && glID)
glBindBuffer(bufferType(), glID);
glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, type_dim, type, data_norm, m_stride,
reinterpret_cast<const void*>(d.offset));
}
};
VertexBufferGL::VertexBufferGL(buffer_layout layout, MemoryProperty memProperty)
: GenericBuffer(layout, memProperty)
{
}
void VertexBufferGL::bind() const
{
// we shouldn't use this one
if (m_interleaved)
glBindBuffer(bufferType(), m_interleavedID);
}
void VertexBufferGL::bind(GLuint prg, int index)
{
if (index >= 0) {
glBindBuffer(bufferType(), m_interleavedID);
bind_attrib(prg, m_desc[index], desc_glIDs[index]);
} else {
if (m_interleaved && m_interleavedID)
glBindBuffer(bufferType(), m_interleavedID);
for (auto i = 0; i < m_desc.size(); ++i) {
const auto& d = m_desc[i];
auto glID = desc_glIDs[i];
bind_attrib(prg, d, glID);
}
m_attribmask.clear();
}
}
void VertexBufferGL::unbind()
{
for (auto& d : m_locs) {
glDisableVertexAttribArray(d);
}
m_locs.clear();
glBindBuffer(bufferType(), 0);
}
void VertexBufferGL::maskAttributes(std::vector<GLint> attrib_locs)
{
m_attribmask = std::move(attrib_locs);
}
void VertexBufferGL::maskAttribute(GLint attrib_loc)
{
m_attribmask.push_back(attrib_loc);
}
std::uint32_t VertexBufferGL::bufferType() const
{
return GL_ARRAY_BUFFER;
}
void IndexBufferGL::bind() const
{
glBindBuffer(bufferType(), m_interleavedID);
}
void IndexBufferGL::unbind()
{
glBindBuffer(bufferType(), 0);
}
std::uint32_t IndexBufferGL::bufferType() const
{
return GL_ELEMENT_ARRAY_BUFFER;
}
/***********************************************************************
* RENDERBUFFER
***********************************************************************/

View File

@@ -1,59 +1,15 @@
#pragma once
// -----------------------------------------------------------------------------
#include "GPUEnums.h"
#include "GPUVertexDesc.h"
#include "Vector.h"
#include <vector>
#include <tuple>
#include <map>
#include <array>
#include <type_traits>
#include <cstdlib>
#include <string.h>
#include <glm/vec2.hpp>
enum class VertexFormat {
// 8 bit
Byte,
Byte2,
Byte3,
Byte4,
ByteNorm,
Byte2Norm,
Byte3Norm,
Byte4Norm,
UByte,
UByte2,
UByte3,
UByte4,
UByteNorm,
UByte2Norm,
UByte3Norm,
UByte4Norm,
//Single Precision
Float,
Float2,
Float3,
Float4,
// 32 bit
Int,
Int2,
Int3,
Int4,
UInt,
UInt2,
UInt3,
UInt4,
};
enum class VertexFormatBaseType { Byte, UByte, Float, Int, UInt };
/**
* @param format Vertex format
* @return The base type of the vertex format
*/
VertexFormatBaseType GetVertexFormatBaseType(VertexFormat format);
/**
* @param format Vertex format
* @return The GL type of the vertex format
@@ -66,50 +22,12 @@ GLenum VertexFormatToGLType(VertexFormat format);
*/
GLint VertexFormatToGLSize(VertexFormat format);
/**
* @param format Vertex format
* @return Whether the vertex format is a normalized type
*/
bool VertexFormatIsNormalized(VertexFormat format);
/**
* @param format Vertex format
* @return Whether the vertex format is a normalized type as a GLboolean
*/
GLboolean VertexFormatToGLNormalized(VertexFormat format);
/**
* @param format Vertex format
* @return The size of the vertex format in bytes
*/
std::size_t GetSizeOfVertexFormat(VertexFormat format);
// -----------------------------------------------------------------------------
// DESCRIPTORS
// -----------------------------------------------------------------------------
// Describes a single array held in the vbo
struct BufferDesc {
BufferDesc(const char* _attr_name, VertexFormat _format,
std::size_t _data_size = 0, const void* _data_ptr = nullptr,
std::uint32_t offset = 0)
: attr_name(_attr_name)
, m_format(_format)
, data_size(_data_size)
, data_ptr(_data_ptr)
, offset(offset)
{
}
const char* attr_name{nullptr};
VertexFormat m_format{VertexFormat::Float};
std::size_t data_size{};
const void* data_ptr{nullptr};
std::uint32_t offset{};
};
using BufferDataDesc = std::vector< BufferDesc >;
/* different types of AttribOp */
enum attrib_op_type {
NO_COPY = 0,
@@ -244,186 +162,6 @@ private:
size_t _hashid { 0 };
};
enum class buffer_layout {
SEPARATE, // multiple vbos
SEQUENTIAL, // single vbo
INTERLEAVED // single vbo
};
enum class MemoryProperty {
DeviceLocal,
HostVisible,
};
// -----------------------------------------------------------------------------
/* Vertexbuffer rules:
* -----------------------------------------------------------------------------
* - If the buffer data is interleaved then buffer sub data functionality cannot
* be used.
* - The same order of buffer data must be maintained when uploading and binding
*
*-----------------------------------------------------------------------
* USAGE_PATTERN:
* SEPARATE:
* vbo1 [ data1 ]
* vbo2 [ data2 ]
* ...
* vboN [ dataN ]
* SEQUENTIAL:
* vbo [ data1 | data2 | ... | dataN ]
* INTERLEAVED:
* vbo [ data1[0], data2[0], ..., dataN[0] | ... | data1[M], data2[M], ..., dataN[M] ]
*/
class GenericBuffer : public GPUBuffer
{
friend class CShaderMgr;
public:
GenericBuffer(buffer_layout layout = buffer_layout::SEPARATE,
MemoryProperty properties = MemoryProperty::DeviceLocal);
GenericBuffer(const GenericBuffer&) = delete;
GenericBuffer& operator=(const GenericBuffer&) = delete;
GenericBuffer(GenericBuffer&&) = delete;
GenericBuffer& operator=(GenericBuffer&&) = delete;
~GenericBuffer();
/**
* Conditionally generates a GPU buffer for the given data descriptor
* @param desc The buffer data descriptor
* @return Whether the buffer data was successfully buffered
* @note The supplied data ptr in the struct can
* be zero, in which case if the default usage is STATIC_DRAW then no
* opengl buffer will be generated for that, else it is assumed that the
* data will be supplied at a later point because it's dynamic draw.
*/
bool bufferData(BufferDataDesc&& desc);
/**
* Generates a GPU buffer for the given data descriptor
* @param desc The buffer data descriptor
* @param data The data to buffer
* @param len The length of the data
* @param stride The stride of the data
* @note assumes the data is interleaved
*/
bool bufferData(
BufferDataDesc&& desc, const void* data, size_t len, size_t stride);
// -----------------------------------------------------------------------------
/**
* Updates (a portion of) the buffer data
* @param offset The offset to start updating the buffer data
* @param size The size of the data to update
* @param data The data to update
* @param index The index of the buffer data to update
* @note This function assumes that the data layout hasn't changed
*/
void bufferSubData(size_t offset, size_t size, void* data, size_t index = 0);
/**
* Replaces the whole interleaved buffer data
* @param data The data to replace the buffer data with
* @param len The length of the data
* @param data The data to replace the buffer data with
* @note This function assumes that the data layout hasn't changed
*/
void bufferReplaceData(size_t offset, size_t len, const void* data);
const BufferDataDesc& getVertDesc() const;
protected:
/**
* Generates GPU buffer(s) for the given data descriptor
* @return Whether the buffer data was successfully buffered
*/
bool evaluate();
// USAGE PATTERNS
/**
* Generates a separate buffer for each data descriptor
* @return Whether the buffer data was successfully buffered
*/
bool sepBufferData();
/**
* Generates a single sequential buffer for all data descriptors
* @return Whether the buffer data was successfully buffered
*/
bool seqBufferData();
/**
* Generates a single interleaved buffer for all data descriptors
* @return Whether the buffer data was successfully buffered
*/
bool interleaveBufferData();
/**
* Generates an OpenGL buffer with given size and data
* @param id The OpenGL buffer ID
* @param size The size of the buffer
* @param ptr The data to buffer
* @return Whether the buffer was successfully generated
*/
bool genBuffer(GLuint& id, size_t size, const void* ptr);
/**
* @return OpenGL buffer type
*/
virtual GLenum bufferType() const = 0;
protected:
bool m_status{false};
bool m_interleaved{false};
GLuint m_interleavedID{0};
MemoryProperty m_memProperty{MemoryProperty::DeviceLocal};
const buffer_layout m_layout{ buffer_layout::SEPARATE };
size_t m_stride{0};
BufferDataDesc m_desc;
std::vector<GLuint> desc_glIDs; // m_desc's gl buffer IDs
};
/**
* Vertex buffer specialization
*/
class VertexBufferGL : public GenericBuffer {
void bind_attrib(GLuint prg, const BufferDesc& d, GLuint glID);
public:
VertexBufferGL(buffer_layout layout = buffer_layout::SEPARATE,
MemoryProperty property = MemoryProperty::DeviceLocal);
void bind() const override;
void bind(GLuint prg, int index = -1);
void unbind();
void maskAttributes(std::vector<GLint> attrib_locs);
void maskAttribute(GLint attrib_loc);
GLenum bufferType() const override;
private:
// m_locs is only for interleaved data
std::vector<GLint> m_locs;
std::vector<GLint> m_attribmask;
};
/**
* Index buffer specialization
*/
class IndexBufferGL : public GenericBuffer {
public:
using GenericBuffer::GenericBuffer;
void bind() const override;
void unbind();
GLenum bufferType() const override;
};
// Forward Decls
class FramebufferGL;
class RenderbufferGL;

View File

@@ -47,6 +47,7 @@ Z* -------------------------------------------------------------------
#include "VFont.h"
#include "Vector.h"
#include "GraphicsUtil.h"
#include "GLVertexBuffer.h"
#include "pymol/algorithm.h"
@@ -2229,6 +2230,69 @@ static NormalColorFormatSize GetNormalColorFormatSize(PyMOLGlobals* G)
return fmt;
}
// TODO: The following functions are temporary until OpenGL is a backend
/**
* @brief Create a vertex buffer
* @param layout Vertex buffer layout
* @param memProperty Usage property for Vertex buffer
* @return Reference to created Vertex Buffer (no mem allocated)
*/
static VertexBuffer& CreateVertexBuffer(PyMOLGlobals* G,
VertexBufferLayout layout = VertexBufferLayout::Separate,
MemoryUsageProperty memProperty = MemoryUsageProperty::GpuOnly)
{
return *G->ShaderMgr->newGPUBuffer<VertexBufferGL>(layout, memProperty);
}
/**
* @brief Allocates GPU memory for vertex buffer and sets data
* @param dataDesc Buffer data description
* @param dataOverride Optional data override
*/
static void SetVertexBufferData(PyMOLGlobals* G, VertexBuffer& vertexBuffer,
BufferDataDesc&& dataDesc, pymol::span<const std::byte> dataOverride = {})
{
auto* vbo = static_cast<VertexBufferGL*>(&vertexBuffer);
vbo->bufferData(std::move(dataDesc));
}
/**
* @brief Allocates GPU memory for vertex buffer and sets data
* @param vertexBuffer Vertex buffer
* @param dataDesc Buffer data description
* @param bufferSize Size of the buffer
* @param dataOverride Optional data override
*/
static void SetVertexBufferDataSized(PyMOLGlobals* G,
VertexBuffer& vertexBuffer, BufferDataDesc&& dataDesc,
std::size_t bufferSize, std::byte* dataOverride = nullptr)
{
auto* vbo = static_cast<VertexBufferGL*>(&vertexBuffer);
vbo->bufferData(std::move(dataDesc), dataOverride, bufferSize);
}
/**
* @brief Create an index buffer
* @return Reference to created Index Buffer (no mem allocated)
*/
static IndexBuffer& CreateIndexBuffer(PyMOLGlobals* G)
{
return *G->ShaderMgr->newGPUBuffer<IndexBufferGL>();
}
/**
* @brief Allocates GPU memory for index buffer and sets data
* @param indexBuffer Index buffer
* @param data Index data
*/
static void SetIndexBufferData(PyMOLGlobals* G, IndexBuffer& indexBuffer,
pymol::span<const std::uint32_t> data)
{
auto* ibo = static_cast<IndexBufferGL*>(&indexBuffer);
ibo->copyFrom(data);
}
static int OptimizePointsToVBO(const CGO* I, CGO* cgo,
int num_total_vertices_points, float* min, float* max,
short* has_draw_buffer, bool addshaders)
@@ -2368,26 +2432,26 @@ static int OptimizePointsToVBO(const CGO* I, CGO* cgo,
short arrays = CGO_VERTEX_ARRAY | CGO_PICK_COLOR_ARRAY;
auto fmt = GetNormalColorFormatSize(I->G);
auto* vbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>();
auto& vbo = CreateVertexBuffer(I->G);
BufferDataDesc bufData = {{"a_Vertex", VertexFormat::Float3,
sizeof(float) * num_total_vertices_points * 3, vertexVals}};
BufferDataDesc bufData{{{"a_Vertex", VertexFormat::Float3,
sizeof(float) * num_total_vertices_points * 3, vertexVals}}};
if (has_normals) {
bufData.push_back({"a_Normal", fmt.normalFormat,
bufData.descs.push_back({"a_Normal", fmt.normalFormat,
num_total_vertices_points * fmt.normalSize, normalVals});
}
if (has_colors) {
bufData.push_back({"a_Color", fmt.colorFormat,
bufData.descs.push_back({"a_Color", fmt.colorFormat,
num_total_vertices_points * fmt.colorSize, colorVals});
}
ok = vbo->bufferData(std::move(bufData));
SetVertexBufferData(I->G, vbo, std::move(bufData));
if (ok && has_colors) {
arrays |= CGO_COLOR_ARRAY;
}
size_t vboid = vbo->get_hash_id();
auto vboid = vbo.get_hash_id();
if (ok) {
float* newPickColorVals;
@@ -2915,34 +2979,36 @@ static bool OptimizeVertsToVBONotIndexed(const CGO* I, CGO* cgo,
if (ok) {
auto fmt = GetNormalColorFormatSize(G);
auto* vbo =
G->ShaderMgr->newGPUBuffer<VertexBufferGL>(buffer_layout::SEQUENTIAL);
BufferDataDesc bufData = {{"a_Vertex", VertexFormat::Float3,
sizeof(float) * count.num_total_indexes * 3, vertexVals}};
auto& vbo = CreateVertexBuffer(
G, VertexBufferLayout::Sequential);
BufferDataDesc bufData{{{"a_Vertex", VertexFormat::Float3,
sizeof(float) * count.num_total_indexes * 3, vertexVals}}};
if (has_normals) {
bufData.push_back({"a_Normal", fmt.normalFormat,
bufData.descs.push_back({"a_Normal", fmt.normalFormat,
count.num_total_indexes * fmt.normalSize, normalVals});
}
if (has_colors) {
bufData.push_back({"a_Color", fmt.colorFormat,
bufData.descs.push_back({"a_Color", fmt.colorFormat,
count.num_total_indexes * fmt.colorSize, colorVals});
}
if (has_accessibility) {
bufData.push_back({"a_Accessibility", VertexFormat::Float,
bufData.descs.push_back({"a_Accessibility", VertexFormat::Float,
sizeof(float) * count.num_total_indexes, accessibilityVals});
}
ok = vbo->bufferData(std::move(bufData));
SetVertexBufferData(I->G, vbo, std::move(bufData));
size_t vboid = vbo->get_hash_id();
auto vboid = vbo.get_hash_id();
// picking VBO: generate a buffer twice the size needed, for each picking
// pass
auto* pickvbo = G->ShaderMgr->newGPUBuffer<VertexBufferGL>(
buffer_layout::SEQUENTIAL, MemoryProperty::HostVisible);
ok = pickvbo->bufferData({BufferDesc{"a_Color", VertexFormat::UByte4Norm,
sizeof(float) * count.num_total_indexes},
auto& pickvbo = CreateVertexBuffer(
G, VertexBufferLayout::Sequential, MemoryUsageProperty::CpuToGpu);
BufferDataDesc pickDataDesc{{//
BufferDesc{"a_Color", VertexFormat::UByte4Norm,
sizeof(float) * count.num_total_indexes}});
size_t pickvboid = pickvbo->get_hash_id();
sizeof(float) * count.num_total_indexes},
BufferDesc{"a_Color", VertexFormat::UByte4Norm,
sizeof(float) * count.num_total_indexes}}};
SetVertexBufferData(G, pickvbo, std::move(pickDataDesc));
auto pickvboid = pickvbo.get_hash_id();
if (ok) {
float* newPickColorVals;
@@ -3179,31 +3245,32 @@ static bool OptimizeLinesToVBONotIndexed(const CGO* I, CGO* cgo,
}
auto fmt = GetNormalColorFormatSize(G);
auto* vbo =
G->ShaderMgr->newGPUBuffer<VertexBufferGL>(buffer_layout::SEQUENTIAL);
BufferDataDesc bufData = {{"a_Vertex", VertexFormat::Float3,
sizeof(float) * count.num_total_indexes_lines * 3, vertexVals}};
auto& vbo = CreateVertexBuffer(G, VertexBufferLayout::Sequential);
BufferDataDesc bufData{{{"a_Vertex", VertexFormat::Float3,
sizeof(float) * count.num_total_indexes_lines * 3, vertexVals}}};
if (has_normals) {
bufData.push_back({"a_Normal", fmt.normalFormat,
bufData.descs.push_back({"a_Normal", fmt.normalFormat,
count.num_total_indexes_lines * fmt.normalSize, normalVals});
}
if (has_color) {
bufData.push_back({"a_Color", fmt.colorFormat,
bufData.descs.push_back({"a_Color", fmt.colorFormat,
count.num_total_indexes_lines * fmt.colorSize, colorVals});
}
ok = vbo->bufferData(std::move(bufData));
size_t vboid = vbo->get_hash_id();
SetVertexBufferData(I->G, vbo, std::move(bufData));
auto vboid = vbo.get_hash_id();
// picking VBO: generate a buffer twice the size needed, for each picking
// pass
auto* pickvbo = G->ShaderMgr->newGPUBuffer<VertexBufferGL>(
buffer_layout::SEQUENTIAL, MemoryProperty::HostVisible);
ok &= pickvbo->bufferData({BufferDesc("a_Color", VertexFormat::UByte4Norm,
sizeof(float) * count.num_total_indexes_lines),
auto& pickvbo = CreateVertexBuffer(
G, VertexBufferLayout::Sequential, MemoryUsageProperty::CpuToGpu);
BufferDataDesc pickDataDesc{{//
BufferDesc("a_Color", VertexFormat::UByte4Norm,
sizeof(float) * count.num_total_indexes_lines)});
size_t pickvboid = pickvbo->get_hash_id();
sizeof(float) * count.num_total_indexes_lines),
BufferDesc("a_Color", VertexFormat::UByte4Norm,
sizeof(float) * count.num_total_indexes_lines)}};
SetVertexBufferData(G, pickvbo, std::move(pickDataDesc));
auto pickvboid = pickvbo.get_hash_id();
if (ok) {
float* newPickColorVals;
@@ -3573,32 +3640,33 @@ static bool OptimizeVertsToVBOIndexed(const CGO* I, CGO* cgo,
if (ok) {
auto fmt = GetNormalColorFormatSize(I->G);
auto* vbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>();
ok &= vbo->bufferData(
{BufferDesc{"a_Vertex", VertexFormat::Float3,
sizeof(float) * count.num_total_vertices * 3, vertexVals},
BufferDesc{"a_Normal", fmt.normalFormat,
count.num_total_vertices * fmt.normalSize, normalVals},
BufferDesc{"a_Color", fmt.colorFormat,
count.num_total_vertices * fmt.colorSize, colorVals},
BufferDesc{"a_Accessibility", VertexFormat::Float,
sizeof(float) * count.num_total_vertices, accessibilityVals}});
auto& vbo = CreateVertexBuffer(I->G);
BufferDataDesc dataDesc{{//
BufferDesc{"a_Vertex", VertexFormat::Float3,
sizeof(float) * count.num_total_vertices * 3, vertexVals},
BufferDesc{"a_Normal", fmt.normalFormat,
count.num_total_vertices * fmt.normalSize, normalVals},
BufferDesc{"a_Color", fmt.colorFormat,
count.num_total_vertices * fmt.colorSize, colorVals},
BufferDesc{"a_Accessibility", VertexFormat::Float,
sizeof(float) * count.num_total_vertices, accessibilityVals}}};
SetVertexBufferData(I->G, vbo, std::move(dataDesc));
auto* ibo = I->G->ShaderMgr->newGPUBuffer<IndexBufferGL>();
ok &= ibo->bufferData({BufferDesc{nullptr, VertexFormat::UInt,
sizeof(VertexIndex_t) * count.num_total_indexes, vertexIndices.data()}});
auto& ibo = CreateIndexBuffer(I->G);
SetIndexBufferData(I->G, ibo, vertexIndices);
size_t vboid = vbo->get_hash_id();
size_t iboid = ibo->get_hash_id();
auto vboid = vbo.get_hash_id();
auto iboid = ibo.get_hash_id();
auto* pickvbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>(
buffer_layout::SEQUENTIAL, MemoryProperty::HostVisible);
ok &= pickvbo->bufferData({BufferDesc{"a_Color", VertexFormat::UByte4Norm,
sizeof(float) * count.num_total_indexes},
auto& pickvbo = CreateVertexBuffer(
I->G, VertexBufferLayout::Sequential, MemoryUsageProperty::CpuToGpu);
BufferDataDesc pickDataDesc{{//
BufferDesc{"a_Color", VertexFormat::UByte4Norm,
sizeof(float) * count.num_total_indexes}});
size_t pickvboid = pickvbo->get_hash_id();
sizeof(float) * count.num_total_indexes},
BufferDesc{"a_Color", VertexFormat::UByte4Norm,
sizeof(float) * count.num_total_indexes}}};
SetVertexBufferData(I->G, pickvbo, std::move(pickDataDesc));
auto pickvboid = pickvbo.get_hash_id();
if (ok) {
float* newPickColorVals;
@@ -3859,31 +3927,32 @@ static bool OptimizeLinesToVBOIndexed(const CGO* I, CGO* cgo,
if (ok) {
auto fmt = GetNormalColorFormatSize(I->G);
auto* vbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>();
ok &= vbo->bufferData({
auto& vbo = CreateVertexBuffer(I->G);
BufferDataDesc dataDesc{{//
BufferDesc{"a_Vertex", VertexFormat::Float3,
sizeof(float) * count.num_total_vertices_lines * 3, vertexVals},
BufferDesc{"a_Normal", fmt.normalFormat,
count.num_total_vertices_lines * fmt.normalSize, normalVals},
BufferDesc{"a_Color", fmt.colorFormat,
count.num_total_vertices_lines * fmt.colorSize, colorVals},
});
}};
SetVertexBufferData(I->G, vbo, std::move(dataDesc));
auto* ibo = I->G->ShaderMgr->newGPUBuffer<IndexBufferGL>();
ok &= ibo->bufferData({BufferDesc(nullptr, VertexFormat::UInt,
sizeof(VertexIndex_t) * count.num_total_indexes_lines,
vertexIndexes.data())});
auto& ibo = CreateIndexBuffer(I->G);
SetIndexBufferData(I->G, ibo, vertexIndexes);
size_t vboid = vbo->get_hash_id();
size_t iboid = ibo->get_hash_id();
auto vboid = vbo.get_hash_id();
auto iboid = ibo.get_hash_id();
auto* pickvbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>(
buffer_layout::SEQUENTIAL, MemoryProperty::HostVisible);
ok &= pickvbo->bufferData({BufferDesc("a_Color", VertexFormat::UByte4Norm,
sizeof(float) * count.num_total_indexes),
auto& pickvbo = CreateVertexBuffer(
I->G, VertexBufferLayout::Sequential, MemoryUsageProperty::CpuToGpu);
BufferDataDesc pickDataDesc{{//
BufferDesc("a_Color", VertexFormat::UByte4Norm,
sizeof(float) * count.num_total_indexes)});
size_t pickvboid = pickvbo->get_hash_id();
sizeof(float) * count.num_total_indexes),
BufferDesc("a_Color", VertexFormat::UByte4Norm,
sizeof(float) * count.num_total_indexes)}};
SetVertexBufferData(I->G, pickvbo, std::move(pickDataDesc));
auto pickvboid = pickvbo.get_hash_id();
if (ok) {
if (addshaders) {
@@ -4204,7 +4273,7 @@ static OptimizeSphereData GetOptimizeSphereData(
* @pre cgo must not be nullptr
*/
static bool PopulateGLBufferOptimizedSphereData(const CGO* I, CGO* cgo,
static bool PopulateBufferOptimizedSphereData(const CGO* I, CGO* cgo,
bool addshaders, int num_total_spheres,
const OptimizeSphereData& sphereData)
{
@@ -4220,8 +4289,8 @@ static bool PopulateGLBufferOptimizedSphereData(const CGO* I, CGO* cgo,
radiusptr = sphereData.rightUpFlagsUB.data();
}
auto* vbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>();
ok &= vbo->bufferData({
auto& vbo = CreateVertexBuffer(I->G);
BufferDataDesc vertDescs{{//
BufferDesc("a_vertex_radius", VertexFormat::Float4,
sizeof(float) * sphereData.total_vert * 4, sphereData.vert.data()),
BufferDesc("a_Color", VertexFormat::UByte4Norm,
@@ -4229,16 +4298,20 @@ static bool PopulateGLBufferOptimizedSphereData(const CGO* I, CGO* cgo,
BufferDesc("a_rightUpFlags", rtp,
rsz * sphereData.total_vert * VALUES_PER_IMPOSTER_SPACE_COORD,
radiusptr),
});
size_t vboid = vbo->get_hash_id();
}};
SetVertexBufferData(I->G, vbo, std::move(vertDescs));
auto vboid = vbo.get_hash_id();
auto* pickvbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>(
buffer_layout::SEQUENTIAL, MemoryProperty::HostVisible);
ok &= pickvbo->bufferData({BufferDesc("a_Color", VertexFormat::UByte4Norm, 0),
BufferDesc("a_Color", VertexFormat::UByte4Norm,
sizeof(float) * sphereData.total_vert)},
0, sizeof(float) * sphereData.total_vert * 2, 0);
size_t pickvboid = pickvbo->get_hash_id();
auto& pickvbo = CreateVertexBuffer(
I->G, VertexBufferLayout::Sequential, MemoryUsageProperty::CpuToGpu);
BufferDataDesc pickDataDesc{{//
BufferDesc("a_Color", VertexFormat::UByte4Norm, 0),
BufferDesc("a_Color", VertexFormat::UByte4Norm,
sizeof(float) * sphereData.total_vert)}};
auto size = sizeof(float) * sphereData.total_vert * 2;
SetVertexBufferDataSized(I->G, pickvbo, std::move(pickDataDesc), size);
auto pickvboid = pickvbo.get_hash_id();
cgo->has_draw_buffers = true;
cgo->has_draw_sphere_buffers = true;
@@ -4295,7 +4368,7 @@ CGO* CGOOptimizeSpheresToVBONonIndexed(
GetOptimizeSphereData(I, cgo, num_total_spheres, leftOverCGO);
if (ok && sphereData.total_spheres > 0) {
ok = PopulateGLBufferOptimizedSphereData(
ok = PopulateBufferOptimizedSphereData(
I, cgo, addshaders, num_total_spheres, sphereData);
}
@@ -4324,7 +4397,7 @@ CGO* CGOOptimizeBezier(const CGO* I)
{
auto cgo = std::make_unique<CGO>(I->G);
int num_splines = CGOCountNumberOfOperationsOfType(I, CGO_BEZIER);
auto vbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>();
auto& vbo = CreateVertexBuffer(I->G);
std::vector<float> vertData;
vertData.reserve(num_splines * CGO_BEZIER_SZ);
for (auto it = I->begin(); !it.is_stop(); ++it) {
@@ -4341,11 +4414,12 @@ CGO* CGOOptimizeBezier(const CGO* I)
std::size_t numDimensions = 3;
std::size_t numVerts = 4;
vbo->bufferData({
BufferDataDesc dataDesc{{
BufferDesc("position", VertexFormat::Float3,
sizeof(float) * numVerts * numDimensions, vertData.data()),
});
size_t vboid = vbo->get_hash_id();
}};
SetVertexBufferData(I->G, vbo, std::move(dataDesc));
auto vboid = vbo.get_hash_id();
CGOEnable(cgo.get(), GL_BEZIER_SHADER);
cgo->add<cgo::draw::bezier_buffers>(vboid);
@@ -4904,16 +4978,16 @@ CGO* CGOOptimizeTextures(const CGO* I, int est)
ok &= !I->G->Interrupt;
}
if (ok) {
auto* vbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>(
buffer_layout::SEQUENTIAL);
ok &= vbo->bufferData(
{BufferDesc("attr_worldpos", VertexFormat::Float3,
sizeof(float) * num_total_textures * 18, worldPos.data()),
BufferDesc("attr_screenoffset", VertexFormat::Float3,
sizeof(float) * num_total_textures * 18, screenValues.data()),
BufferDesc("attr_texcoords", VertexFormat::Float3,
sizeof(float) * num_total_textures * 18, textExtents.data())});
size_t vboid = vbo->get_hash_id();
auto& vbo = CreateVertexBuffer(I->G, VertexBufferLayout::Sequential);
BufferDataDesc dataDesc{{
BufferDesc("attr_worldpos", VertexFormat::Float3,
sizeof(float) * num_total_textures * 18, worldPos.data()),
BufferDesc("attr_screenoffset", VertexFormat::Float3,
sizeof(float) * num_total_textures * 18, screenValues.data()),
BufferDesc("attr_texcoords", VertexFormat::Float3,
sizeof(float) * num_total_textures * 18, textExtents.data())}};
SetVertexBufferData(I->G, vbo, std::move(dataDesc));
auto vboid = vbo.get_hash_id();
if (ok) {
float* pickArray =
@@ -5030,7 +5104,7 @@ CGO* CGOConvertToLabelShader(const CGO* I, CGO* addTo)
AttribDataDesc pickDesc = {
{"attr_pickcolor", VertexFormat::UByte4Norm, pickOp}};
return CGOConvertToShader(
I, attrDesc, pickDesc, GL_TRIANGLES, buffer_layout::INTERLEAVED, true);
I, attrDesc, pickDesc, GL_TRIANGLES, VertexBufferLayout::Interleaved, true);
}
CGO* CGOOptimizeLabels(const CGO* I, int est, bool addshaders)
@@ -5141,31 +5215,33 @@ CGO* CGOOptimizeLabels(const CGO* I, int est, bool addshaders)
}
if (ok) {
// Static Vertex Data
auto* vbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>(
buffer_layout::SEQUENTIAL);
ok &=
vbo->bufferData({BufferDesc("attr_worldpos", VertexFormat::Float3,
sizeof(float) * num_total_labels * 18, worldPos.data()),
BufferDesc("attr_targetpos", VertexFormat::Float3,
sizeof(float) * num_total_labels * 18, targetPos),
BufferDesc("attr_screenoffset", VertexFormat::Float3,
sizeof(float) * num_total_labels * 18, screenValues),
BufferDesc("attr_texcoords", VertexFormat::Float2,
sizeof(float) * num_total_labels * 12, textExtents),
BufferDesc("attr_screenworldoffset", VertexFormat::Float3,
sizeof(float) * num_total_labels * 18, screenWorldValues),
BufferDesc("attr_relative_mode", VertexFormat::Float,
sizeof(float) * num_total_labels * 6, relativeMode)});
size_t vboid = vbo->get_hash_id();
auto& vbo = CreateVertexBuffer(I->G, VertexBufferLayout::Sequential);
BufferDataDesc dataDesc{{
BufferDesc("attr_worldpos", VertexFormat::Float3,
sizeof(float) * num_total_labels * 18, worldPos.data()),
BufferDesc("attr_targetpos", VertexFormat::Float3,
sizeof(float) * num_total_labels * 18, targetPos),
BufferDesc("attr_screenoffset", VertexFormat::Float3,
sizeof(float) * num_total_labels * 18, screenValues),
BufferDesc("attr_texcoords", VertexFormat::Float2,
sizeof(float) * num_total_labels * 12, textExtents),
BufferDesc("attr_screenworldoffset", VertexFormat::Float3,
sizeof(float) * num_total_labels * 18, screenWorldValues),
BufferDesc("attr_relative_mode", VertexFormat::Float,
sizeof(float) * num_total_labels * 6, relativeMode)}};
SetVertexBufferData(I->G, vbo, std::move(dataDesc));
auto vboid = vbo.get_hash_id();
auto* pickvbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>(
buffer_layout::SEQUENTIAL, MemoryProperty::HostVisible);
ok &= pickvbo->bufferData(
{BufferDesc("attr_pickcolor", VertexFormat::UByteNorm, 0),
BufferDesc("attr_pickcolor", VertexFormat::UByteNorm,
sizeof(float) * num_total_labels * 6)},
0, sizeof(float) * num_total_labels * 12, 0);
size_t pickvboid = pickvbo->get_hash_id();
auto& pickvbo = CreateVertexBuffer(
I->G, VertexBufferLayout::Sequential, MemoryUsageProperty::CpuToGpu);
BufferDataDesc pickDataDesc{{
BufferDesc("attr_pickcolor", VertexFormat::UByteNorm, 0),
BufferDesc("attr_pickcolor", VertexFormat::UByteNorm,
sizeof(float) * num_total_labels * 6)}};
std::size_t bufferSize = sizeof(float) * num_total_labels * 12;
SetVertexBufferDataSized(
I->G, pickvbo, std::move(pickDataDesc), bufferSize);
auto pickvboid = pickvbo.get_hash_id();
auto freebuffers = [vboid, pickvboid, I]() {
I->G->ShaderMgr->freeGPUBuffer(vboid);
@@ -5312,9 +5388,10 @@ CGO* CGOOptimizeConnectors(const CGO* I, int est)
}
if (ok) {
const size_t quant = factor * num_total_connectors;
auto* vbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>();
ok = vbo->bufferData({BufferDesc("a_target_pt3d", VertexFormat::Float3,
sizeof(float) * 3 * quant, targetPt3d.data()),
auto& vbo = CreateVertexBuffer(I->G);
BufferDataDesc bufferDataDesc{{//
BufferDesc("a_target_pt3d", VertexFormat::Float3,
sizeof(float) * 3 * quant, targetPt3d.data()),
BufferDesc("a_center_pt3d", VertexFormat::Float3,
sizeof(float) * 3 * quant, labelCenterPt3d),
BufferDesc("a_indentFactor", VertexFormat::Float2,
@@ -5336,8 +5413,9 @@ CGO* CGOOptimizeConnectors(const CGO* I, int est)
BufferDesc("a_con_width", VertexFormat::Float, sizeof(float) * quant,
connectorWidth),
BufferDesc("a_isCenterPt", VertexFormat::UByte,
sizeof(std::uint8_t) * quant, isCenterPt)});
size_t vboid = vbo->get_hash_id();
sizeof(std::uint8_t) * quant, isCenterPt)}};
SetVertexBufferData(I->G, vbo, std::move(bufferDataDesc));
auto vboid = vbo.get_hash_id();
if (ok) {
cgo->add<cgo::draw::connectors>(num_total_connectors, vboid);
if (ok)
@@ -7500,15 +7578,16 @@ CGO* CGOOptimizeScreenTexturesAndPolygons(CGO* I, int est)
G, I, vertexVals, texcoordVals, colorVals, colorValsUC);
RETURN_VAL_IF_FAIL(ok && !G->Interrupt, nullptr);
if (ok) {
auto* vbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>();
ok = vbo->bufferData(
{BufferDesc("attr_screenoffset", VertexFormat::Float3,
sizeof(float) * num_total_indices * 3, vertexVals),
BufferDesc("attr_texcoords", VertexFormat::Float2,
sizeof(float) * num_total_indices * 2, texcoordVals),
BufferDesc("attr_backgroundcolor", VertexFormat::UByte4Norm,
sizeof(std::uint8_t) * num_total_indices * 4, colorValsUC)});
size_t vboid = vbo->get_hash_id();
auto& vbo = CreateVertexBuffer(I->G);
BufferDataDesc dataDesc{{
BufferDesc("attr_screenoffset", VertexFormat::Float3,
sizeof(float) * num_total_indices * 3, vertexVals),
BufferDesc("attr_texcoords", VertexFormat::Float2,
sizeof(float) * num_total_indices * 2, texcoordVals),
BufferDesc("attr_backgroundcolor", VertexFormat::UByte4Norm,
sizeof(std::uint8_t) * num_total_indices * 4, colorValsUC)}};
SetVertexBufferData(I->G, vbo, std::move(dataDesc));
auto vboid = vbo.get_hash_id();
if (ok) {
CGOEnable(cgo, GL_SCREEN_SHADER);
cgo->add<cgo::draw::screen_textures>(num_total_indices, vboid);
@@ -8971,13 +9050,13 @@ static void PopulateOpsIntoStructuresForConversion(
*
*/
CGO* CGOConvertToShader(const CGO* I, AttribDataDesc& attrData,
AttribDataDesc& pickData, int mode, const buffer_layout layout,
AttribDataDesc& pickData, int mode, const VertexBufferLayout layout,
bool check_attr_for_data, int* idx_array, int nvertsperfrag,
int nfragspergroup)
{
CGO* cgo;
int ok = true;
bool isInterleaved = (layout == buffer_layout::INTERLEAVED);
bool isInterleaved = (layout == VertexBufferLayout::Interleaved);
bool has_picking = true;
std::map<std::string, AttribDesc*> attrToDesc;
@@ -9057,11 +9136,11 @@ CGO* CGOConvertToShader(const CGO* I, AttribDataDesc& attrData,
// - pickvbo is interleaved so that for multiple channels, pick data for each
// vertex
// is contiguous
auto* vbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>(layout);
VertexBufferGL* pickvbo = nullptr;
auto& vbo = CreateVertexBuffer(I->G, layout);
VertexBuffer* pickvbo = nullptr;
if (pickDataSize) {
pickvbo = I->G->ShaderMgr->newGPUBuffer<VertexBufferGL>(
buffer_layout::SEQUENTIAL, MemoryProperty::HostVisible);
pickvbo = &CreateVertexBuffer(I->G, VertexBufferLayout::Sequential,
MemoryUsageProperty::CpuToGpu);
pickvbohash = pickvbo->get_hash_id();
}
@@ -9089,7 +9168,7 @@ CGO* CGOConvertToShader(const CGO* I, AttribDataDesc& attrData,
for (auto& pickDesc : pickData) {
cgo->add<cgo::draw::mask_attribute_if_picking>(
I->G->ShaderMgr->GetAttributeUID(pickDesc.attr_name),
vbo->get_hash_id());
vbo.get_hash_id());
if (has_picking) {
cgo->add<cgo::draw::bind_vbo_for_picking>(pickvbohash, pl++, npickattr);
} else {
@@ -9115,15 +9194,14 @@ CGO* CGOConvertToShader(const CGO* I, AttribDataDesc& attrData,
}
vpl += nvertsperindivfrag;
}
auto* ibo = I->G->ShaderMgr->newGPUBuffer<IndexBufferGL>();
ok &= ibo->bufferData({BufferDesc(nullptr, VertexFormat::UInt,
sizeof(VertexIndex_t) * num_total_indexes, vertexIndices.data())});
iboid = ibo->get_hash_id();
auto& ibo = CreateIndexBuffer(I->G);
SetIndexBufferData(I->G, ibo, vertexIndices);
iboid = ibo.get_hash_id();
}
// pick_data is interleaved if more than one attribute
float* pick_data = cgo->add<cgo::draw::custom>(mode, ntotalverts,
vbo->get_hash_id(), pickvbohash, vertsperpickinfo, pickDataSize, iboid,
vbo.get_hash_id(), pickvbohash, vertsperpickinfo, pickDataSize, iboid,
num_total_indexes);
std::vector<unsigned char> allData(ntotalverts * vertexDataSize);
std::vector<void*> dataPtrs;
@@ -9332,19 +9410,19 @@ CGO* CGOConvertToShader(const CGO* I, AttribDataDesc& attrData,
for (int i = 0; i < npickcolattr; i++) {
for (auto& pickDesc : pickData) {
auto pickSize = GetSizeOfVertexFormat(pickDesc.m_format);
pickBufferData.push_back(BufferDesc(
pickBufferData.descs.push_back(BufferDesc(
pickDesc.attr_name, pickDesc.m_format, pickSize * nvert));
}
}
pickvbo->bufferData(std::move(pickBufferData));
SetVertexBufferData(I->G, *pickvbo, std::move(pickBufferData));
}
/* Generate VBO Buffers with all pick attributes based on the VertexBuffer
* type SEPARATE/SEQUENTIAL/INTERLEAVED*/
BufferDataDesc bufferData;
switch (layout) {
case buffer_layout::SEPARATE:
case buffer_layout::SEQUENTIAL: {
case VertexBufferLayout::Separate:
case VertexBufferLayout::Sequential: {
auto attrDataIt = attrData.begin();
auto dataPtrIt = dataPtrs.begin();
auto attrSizeIt = attrSizes.begin();
@@ -9354,24 +9432,25 @@ CGO* CGOConvertToShader(const CGO* I, AttribDataDesc& attrData,
auto attrDesc = &(*attrDataIt);
auto dataPtr = *dataPtrIt;
auto attrSize = *attrSizeIt;
bufferData.push_back(BufferDesc(
bufferData.descs.push_back(BufferDesc(
attrDesc->attr_name, attrDesc->m_format, nvert * attrSize, dataPtr));
}
vbo->bufferData(std::move(bufferData));
SetVertexBufferData(I->G, vbo, std::move(bufferData));
break;
} break;
case buffer_layout::INTERLEAVED: {
case VertexBufferLayout::Interleaved: {
auto attrDataIt = attrData.begin();
auto attrOffsetIt = attrOffset.begin();
for (; attrDataIt != attrData.end() && attrOffsetIt != attrOffset.end();
++attrDataIt, ++attrOffsetIt) {
auto attrDesc = &(*attrDataIt);
auto offset = *attrOffsetIt;
bufferData.push_back(BufferDesc{attrDesc->attr_name, attrDesc->m_format,
bufferData.descs.push_back(BufferDesc{attrDesc->attr_name, attrDesc->m_format,
0, nullptr, (std::uint32_t) offset});
}
vbo->bufferData(std::move(bufferData), allData.data(),
(size_t) (nvert * vertexDataSize), (size_t) vertexDataSize);
bufferData.stride = static_cast<std::size_t>(vertexDataSize);
SetVertexBufferDataSized(I->G, vbo, std::move(bufferData),
nvert * vertexDataSize, reinterpret_cast<std::byte*>(allData.data()));
break;
}
}
@@ -9523,7 +9602,7 @@ CGO* CGOConvertToTrilinesShader(const CGO* I, CGO* addTo, bool add_color)
}
return CGOConvertToShader(
I, attrDesc, pickDesc, GL_TRIANGLES, buffer_layout::INTERLEAVED);
I, attrDesc, pickDesc, GL_TRIANGLES, VertexBufferLayout::Interleaved);
}
CGO* CGOConvertToLinesShader(const CGO* I, CGO* addTo, bool add_color)
@@ -9579,7 +9658,7 @@ CGO* CGOConvertToLinesShader(const CGO* I, CGO* addTo, bool add_color)
}
return CGOConvertToShader(
I, attrDesc, pickDesc, GL_LINES, buffer_layout::INTERLEAVED);
I, attrDesc, pickDesc, GL_LINES, VertexBufferLayout::Interleaved);
}
CGO* CGOConvertLinesToCylinderShader(const CGO* I, CGO* addTo, bool add_color)
@@ -9664,7 +9743,7 @@ CGO* CGOConvertLinesToCylinderShader(const CGO* I, CGO* addTo, bool add_color)
{"a_Color", VertexFormat::UByte4Norm, extraPickColorOps},
{"a_Color2", VertexFormat::UByte4Norm, extraPickColor2Ops}};
return CGOConvertToShader(I, attrDesc, pickDesc, GL_TRIANGLES,
buffer_layout::INTERLEAVED, true, box_indices_ptr, 36);
VertexBufferLayout::Interleaved, true, box_indices_ptr, 36);
}
struct CrossSizeData {
@@ -9748,7 +9827,7 @@ CGO* CGOConvertCrossesToCylinderShader(
{"a_Color", VertexFormat::UByte4Norm, extraPickColorOps},
{"a_Color2", VertexFormat::UByte4Norm, extraPickColor2Ops}};
return CGOConvertToShader(I, attrDesc, pickDesc, GL_TRIANGLES,
buffer_layout::INTERLEAVED, true, box_indices_ptr, 36, 3);
VertexBufferLayout::Interleaved, true, box_indices_ptr, 36, 3);
}
struct CrossSizeDataLines {
@@ -9814,7 +9893,7 @@ CGO* CGOConvertCrossesToLinesShader(
}
#endif
return CGOConvertToShader(
I, attrDesc, pickDesc, GL_LINES, buffer_layout::INTERLEAVED);
I, attrDesc, pickDesc, GL_LINES, VertexBufferLayout::Interleaved);
}
static void CrossVertexConversionTrilines(
@@ -9872,7 +9951,7 @@ CGO* CGOConvertCrossesToTrilinesShader(
G->ShaderMgr->GetAttributeUID("a_interpolate"), 0.f);
return CGOConvertToShader(
I, attrDesc, pickDesc, GL_TRIANGLES, buffer_layout::INTERLEAVED);
I, attrDesc, pickDesc, GL_TRIANGLES, VertexBufferLayout::Interleaved);
}
cgo::draw::shadercylinder2ndcolor::shadercylinder2ndcolor(CGO* I,
@@ -10041,7 +10120,7 @@ CGO* CGOConvertShaderCylindersToCylinderShader(const CGO* I, CGO* addTo)
{"a_Color", VertexFormat::UByte4Norm, extraPickColorOps},
{"a_Color2", VertexFormat::UByte4Norm, extraPickColor2Ops}};
return CGOConvertToShader(I, attrDesc, pickDesc, GL_TRIANGLES,
buffer_layout::INTERLEAVED, true, box_indices_ptr, 36);
VertexBufferLayout::Interleaved, true, box_indices_ptr, 36);
}
/**

View File

@@ -17,22 +17,26 @@ Z* -------------------------------------------------------------------
#ifndef _H_CGO
#define _H_CGO
#include"Base.h"
#include"Ray.h"
#include"Setting.h"
#include"os_gl_cgo.h"
#include"Rep.h"
#include"MemoryDebug.h"
#include <vector>
#include <unordered_map>
#include <typeinfo>
#include <type_traits>
#include <memory>
#include "Base.h"
#include "GPUEnums.h"
#include "GenericBuffer.h"
#include <set>
#include "MemoryDebug.h"
#include "Ray.h"
#include "Rep.h"
#include "Setting.h"
#include "os_gl_cgo.h"
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <cstdint>
#include <map>
#include <memory>
#include <set>
#include <type_traits>
#include <typeinfo>
#include <unordered_map>
#include <vector>
/* Compiled Graphics Library for simple graphics objects
in floating point three-space, with the goal of achieving
@@ -1185,7 +1189,7 @@ CGO *CGOConvertSpheresToPoints(const CGO *I);
CGO* CGOConvertToShader(const CGO* I, AttribDataDesc& attrData,
AttribDataDesc& pickData, int mode,
const buffer_layout layout = buffer_layout::INTERLEAVED,
const VertexBufferLayout layout = VertexBufferLayout::Interleaved,
bool check_attr_for_data = true, int* idx_array = nullptr,
int nindicesperfrag = 0, int nfragspergroup = 1);

View File

@@ -5,6 +5,7 @@
#include "CGORenderer.h"
#include "CoordSet.h"
#include "Feedback.h"
#include "GLVertexBuffer.h"
#include "GraphicsUtil.h"
#include "Scene.h"
#include "SceneDef.h"
@@ -472,7 +473,7 @@ static void CGOReorderIndicesWithTransparentInfo(PyMOLGlobals* G, int nindices,
vertexIndices[pl++] = vertexIndicesOriginal[idx + 1];
vertexIndices[pl++] = vertexIndicesOriginal[idx + 2];
}
ibo->bufferSubData(0, sizeof(VertexIndex_t) * nindices, vertexIndices);
ibo->copyFrom(pymol::span{vertexIndices, static_cast<std::size_t>(nindices)});
}
static void CGO_gl_draw_buffers_indexed(CCGORenderer* I, CGO_op_data pc)
@@ -2108,8 +2109,11 @@ void CGORenderGLPicking(CGO* I, RenderInfo* info, PickContext* context,
// reload entire vbo
auto* vbo =
I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(pickvbo);
vbo->bufferReplaceData(destOffset,
sizeof(float) * nverts * bufsizemult, pickColorDestUC);
auto pickPtrBytes =
reinterpret_cast<const std::byte*>(pickColorDestUC);
auto dataSpan =
pymol::span{pickPtrBytes, sizeof(float) * nverts * bufsizemult};
vbo->bufferReplaceData(destOffset, dataSpan);
(*pickcolors_are_set_ptr) = true;
}

25
layerGraphics/GPUEnums.h Normal file
View File

@@ -0,0 +1,25 @@
#pragma once
enum class MemoryUsageProperty {
GpuOnly, ///< Keep in GPU Memory
CpuToGpu, ///< Usual Memcpy from CPU to GPU
GpuToCpu, ///< Readback from GPU to CPU
};
enum class VertexBufferLayout {
Separate, // multiple vbos
Sequential, // single vbo
Interleaved // single vbo
};
enum class GPUPrimitiveTopology
{
Triangles,
TriangleStrip,
TriangleFan,
Lines,
LinesStrip,
LineLoop,
Points,
Quads // depreated
};

View File

@@ -0,0 +1,61 @@
#pragma once
#include "GPUEnums.h"
#include "VertexFormat.h"
#include <cstddef>
#include <optional>
// #include <span>
#include "pymol/span.h"
#include <string_view>
#include <variant>
#include <vector>
// -----------------------------------------------------------------------------
// DESCRIPTORS
// -----------------------------------------------------------------------------
// Describes a single array held in the vbo
struct BufferDesc {
BufferDesc(std::string_view _attr_name, VertexFormat _format,
std::size_t _data_size = 0, const void* _data_ptr = nullptr,
std::uint32_t offset = 0)
: attr_name(_attr_name)
, m_format(_format)
, data_size(_data_size)
, data_ptr(_data_ptr)
, offset(offset)
{
}
std::string_view attr_name;
VertexFormat m_format{VertexFormat::Float};
std::size_t data_size{};
const void* data_ptr{nullptr};
std::uint32_t offset{};
};
/**
* @brief Describes the vertex buffer data
*/
struct BufferDataDesc {
/**
* @brief Default constructor
*/
BufferDataDesc() = default;
/**
* @brief Constructor
* @param _descs The buffer descriptors
*/
BufferDataDesc(std::vector<BufferDesc> _descs)
: descs(std::move(_descs))
{
}
std::vector<BufferDesc> descs;
GPUPrimitiveTopology topology{GPUPrimitiveTopology::Triangles};
std::optional<std::size_t> stride;
};
using VertexBufferDataDesc = BufferDataDesc;
using VertexBufferDesc = BufferDesc;

View File

@@ -0,0 +1,13 @@
#pragma once
#include "GenericBuffer.h"
#include <cstdint>
class IndexBuffer : public GPUBuffer
{
public:
[[nodiscard]] virtual std::uint64_t getBufferID() const = 0;
virtual void copyFrom(pymol::span<const std::uint32_t> data) = 0;
};

View File

@@ -0,0 +1,36 @@
#pragma once
#include <cstddef>
// #include <span>
#include "pymol/span.h"
#include <vector>
#include "GenericBuffer.h"
struct BufferAndOffsets {
std::size_t bufferIdx{};
std::size_t offset{};
};
class VertexBuffer : public GPUBuffer
{
public:
/**
* @return Underlying buffers Image IDs
*/
virtual std::vector<std::uint64_t> getBufferIDs() const = 0;
/**
* @return Underlying buffers and offsets
*/
virtual std::vector<BufferAndOffsets> getBufferOffsets() const = 0;
/**
* @brief Copies data from external source to this buffer
* @param bufferAndOffets Buffer index and offset
* @param data The data to copy to the buffer
*/
virtual void copyFrom(const BufferAndOffsets& bufferAndOffsets,
pymol::span<const std::byte> data) = 0;
};

View File

@@ -0,0 +1,66 @@
#pragma once
#include <cstddef>
enum class VertexFormat {
// 8 bit
Byte,
Byte2,
Byte3,
Byte4,
ByteNorm,
Byte2Norm,
Byte3Norm,
Byte4Norm,
UByte,
UByte2,
UByte3,
UByte4,
UByteNorm,
UByte2Norm,
UByte3Norm,
UByte4Norm,
// Single Precision
Float,
Float2,
Float3,
Float4,
// Double Precision
Float64,
Float64_2,
Float64_3,
Float64_4,
// 32 bit
Int,
Int2,
Int3,
Int4,
UInt,
UInt2,
UInt3,
UInt4,
};
enum class VertexFormatBaseType { Byte, UByte, Float, Int, UInt };
/**
* @param format Vertex format
* @return The base type of the vertex format
*/
VertexFormatBaseType GetVertexFormatBaseType(VertexFormat format);
/**
* @param format Vertex format
* @return Whether the vertex format is a normalized type
*/
bool VertexFormatIsNormalized(VertexFormat format);
/**
* @param format Vertex format
* @return The size of the vertex format in bytes
*/
std::size_t GetSizeOfVertexFormat(VertexFormat format);

View File

@@ -0,0 +1,323 @@
#include "GLVertexBuffer.h"
#include "GraphicsUtil.h"
#include "pymol/algorithm.h"
static bool GLGenBuffer(GLuint& id, GLuint bufferType, pymol::span<const std::byte> data)
{
glGenBuffers(1, &id);
if (!CheckGLErrorOK(nullptr, "GenericBuffer::genBuffer failed\n"))
return false;
glBindBuffer(bufferType, id);
if (!CheckGLErrorOK(nullptr, "GenericBuffer::bindBuffer failed\n"))
return false;
glBufferData(bufferType, data.size(), data.data(), GL_STATIC_DRAW);
return CheckGLErrorOK(nullptr, "GenericBuffer::bufferData failed\n");
}
/**
* @brief Converts raw data (void*) to a byte span
* @param data The data
* @param size The size of the data in bytes
* @return The byte span
*/
static pymol::span<const std::byte> RawDataToByteSpan(
const void* data, std::size_t size)
{
return {static_cast<const std::byte*>(data), size};
}
std::vector<std::uint64_t> VertexBufferGL::getBufferIDs() const
{
std::vector<std::uint64_t> bufferIDs;
for (const auto& glID : desc_glIDs) {
bufferIDs.push_back(glID);
}
return bufferIDs;
}
std::vector<BufferAndOffsets> VertexBufferGL::getBufferOffsets() const
{
std::vector<BufferAndOffsets> bufferOffsets;
return bufferOffsets;
}
void VertexBufferGL::copyFrom(
const BufferAndOffsets& bufferAndOffsets, pymol::span<const std::byte> data)
{
}
void VertexBufferGL::bufferReplaceData(std::size_t offset, pymol::span<const std::byte> data)
{
glBindBuffer(bufferType(), m_interleavedID);
glBufferSubData(bufferType(), offset, data.size(), data.data());
}
void VertexBufferGL::bind_attrib(GLuint prg, const BufferDesc& d, GLuint glID)
{
GLint loc = glGetAttribLocation(prg, d.attr_name.data());
auto type_dim = VertexFormatToGLSize(d.m_format);
auto type = VertexFormatToGLType(d.m_format);
auto data_norm = VertexFormatToGLNormalized(d.m_format);
bool masked = false;
for (GLint lid : m_attribmask)
if (lid == loc)
masked = true;
if (loc >= 0)
m_locs.push_back(loc);
if (loc >= 0 && !masked) {
if (!isInterleaved() && glID)
glBindBuffer(bufferType(), glID);
glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, type_dim, type, data_norm, m_stride,
reinterpret_cast<const void*>(d.offset));
}
};
VertexBufferGL::VertexBufferGL(
VertexBufferLayout layout, MemoryUsageProperty memProperty)
: m_layout{layout}
, m_memProperty{memProperty}
{
}
void VertexBufferGL::bind() const
{
// we shouldn't use this one
if (isInterleaved())
glBindBuffer(bufferType(), m_interleavedID);
}
void VertexBufferGL::bind(GLuint prg, int index)
{
auto& descs = m_desc.descs;
if (index >= 0) {
glBindBuffer(bufferType(), m_interleavedID);
bind_attrib(prg, descs[index], desc_glIDs[index]);
} else {
if (isInterleaved() && m_interleavedID)
glBindBuffer(bufferType(), m_interleavedID);
for (auto i = 0; i < descs.size(); ++i) {
const auto& d = descs[i];
auto glID = desc_glIDs[i];
bind_attrib(prg, d, glID);
}
m_attribmask.clear();
}
}
void VertexBufferGL::unbind()
{
for (auto& d : m_locs) {
glDisableVertexAttribArray(d);
}
m_locs.clear();
glBindBuffer(bufferType(), 0);
}
bool VertexBufferGL::isInterleaved() const noexcept
{
return m_layout == VertexBufferLayout::Interleaved;
}
void VertexBufferGL::maskAttributes(std::vector<GLint> attrib_locs)
{
m_attribmask = std::move(attrib_locs);
}
void VertexBufferGL::maskAttribute(GLint attrib_loc)
{
m_attribmask.push_back(attrib_loc);
}
std::uint32_t VertexBufferGL::bufferType() const
{
return GL_ARRAY_BUFFER;
}
bool VertexBufferGL::sepBufferData()
{
auto& descs = m_desc.descs;
for (auto i = 0; i < descs.size(); ++i) {
// If the specified size is 0 but we have a valid pointer
// then we are going to glVertexAttribXfv X in {1,2,3,4}
const auto& d = descs[i];
auto& glID = desc_glIDs[i];
if (d.data_ptr && (m_memProperty == MemoryUsageProperty::GpuOnly)) {
if (d.data_size) {
auto data = RawDataToByteSpan(d.data_ptr, d.data_size);
if (!GLGenBuffer(glID, bufferType(), data)) {
return false;
}
}
}
}
return true;
}
bool VertexBufferGL::seqBufferData() {
// this is only going to use a single opengl vbo
m_layout = VertexBufferLayout::Interleaved;
auto& descs = m_desc.descs;
size_t buffer_size { 0 };
for ( auto & d : descs ) {
buffer_size += d.data_size;
}
std::vector<std::byte> buffer_data(buffer_size);
auto data_ptr = buffer_data.data();
size_t offset = 0;
for ( auto & d : descs ) {
d.offset = offset;
if (d.data_ptr)
memcpy(data_ptr, d.data_ptr, d.data_size);
else
memset(data_ptr, 0, d.data_size);
data_ptr += d.data_size;
offset += d.data_size;
}
return GLGenBuffer(m_interleavedID, bufferType(), pymol::span{buffer_data});
}
bool VertexBufferGL::interleaveBufferData()
{
auto& descs = m_desc.descs;
const std::size_t bufferCount = descs.size();
std::size_t stride = 0;
std::vector<const uint8_t*> data_table(bufferCount);
std::vector<const uint8_t*> ptr_table(bufferCount);
std::vector<std::size_t> size_table(bufferCount);
std::size_t count =
descs[0].data_size / GetSizeOfVertexFormat(descs[0].m_format);
// Maybe assert that all pointers in d_desc are valid?
for (size_t i = 0; i < bufferCount; ++i) {
auto& d = descs[i];
// offset is the current stride
d.offset = stride;
// These must come after so that offset starts at 0
// Size of 3 normals or whatever the current type is
size_table[i] = GetSizeOfVertexFormat(d.m_format);
// Increase our current estimate of the stride by this amount
stride += size_table[i];
// Does the addition of that previous stride leave us on a word boundry?
int m = stride % 4;
stride = (m ? (stride + (4 - m)) : stride);
// data_table a pointer to the begining of each array
data_table[i] = static_cast<const std::uint8_t*>(d.data_ptr);
// We will move these pointers along by the values in the size table
ptr_table[i] = data_table[i];
}
m_stride = stride;
std::size_t interleavedSize = count * stride;
std::vector<std::byte> interleavedData(interleavedSize);
auto iPtr = interleavedData.data();
while (iPtr != (interleavedData.data() + interleavedSize)) {
for (size_t i = 0; i < bufferCount; ++i) {
if (ptr_table[i]) {
memcpy(iPtr, ptr_table[i], size_table[i]);
ptr_table[i] += size_table[i];
}
iPtr += size_table[i];
}
}
m_layout = VertexBufferLayout::Interleaved;
return GLGenBuffer(m_interleavedID, bufferType(), pymol::span{interleavedData});
}
bool VertexBufferGL::evaluate()
{
switch (m_layout) {
case VertexBufferLayout::Separate:
return sepBufferData();
break;
case VertexBufferLayout::Sequential:
return seqBufferData();
break;
case VertexBufferLayout::Interleaved:
return interleaveBufferData();
default:
assert("Invalid VertexBufferLayout" && false);
break;
}
return false;
}
bool VertexBufferGL::bufferData(BufferDataDesc&& desc)
{
m_desc = std::move(desc);
desc_glIDs = std::vector<GLuint>(m_desc.descs.size());
return evaluate();
}
bool VertexBufferGL::bufferData(
BufferDataDesc&& desc, const void* data, size_t len)
{
m_desc = std::move(desc);
desc_glIDs = std::vector<GLuint>(m_desc.descs.size());
m_layout = VertexBufferLayout::Interleaved;
m_stride = desc.stride.value_or(0);
auto span = RawDataToByteSpan(data, len);
return GLGenBuffer(m_interleavedID, bufferType(), span);
}
void VertexBufferGL::bufferSubData(size_t offset, size_t size, void* data, size_t index)
{
assert("Invalid Desc index" && index < m_desc.size());
assert("Invalid GLDesc index" && index < desc_glIDs.size());
auto glID = isInterleaved() ? m_interleavedID : desc_glIDs[index];
glBindBuffer(bufferType(), glID);
glBufferSubData(bufferType(), offset, size, data);
}
std::uint64_t IndexBufferGL::getBufferID() const
{
return static_cast<std::uint64_t>(m_bufferID);
}
void IndexBufferGL::bind() const
{
glBindBuffer(bufferType(), m_bufferID);
}
void IndexBufferGL::unbind()
{
glBindBuffer(bufferType(), 0);
}
std::uint32_t IndexBufferGL::bufferType() const
{
return GL_ELEMENT_ARRAY_BUFFER;
}
void IndexBufferGL::bufferSubData(
std::size_t offset, pymol::span<const std::byte> data)
{
glBindBuffer(bufferType(), m_bufferID);
glBufferSubData(bufferType(), offset, data.size(), data.data());
}
void IndexBufferGL::copyFrom(pymol::span<const std::uint32_t> data)
{
auto bytesSpan = pymol::as_bytes(data);
if (!m_bufferID) {
GLGenBuffer(m_bufferID, bufferType(), bytesSpan);
} else {
bufferSubData(0, bytesSpan);
}
}

View File

@@ -0,0 +1,221 @@
#pragma once
#include "GPUEnums.h"
#include "IndexBuffer.h"
#include "VertexBuffer.h"
// #include <span>
#include "pymol/span.h"
#include <vector>
// -----------------------------------------------------------------------------
/* Vertexbuffer rules:
* -----------------------------------------------------------------------------
* - If the buffer data is interleaved then buffer sub data functionality cannot
* be used.
* - The same order of buffer data must be maintained when uploading and binding
*
*-----------------------------------------------------------------------
* USAGE_PATTERN:
* SEPARATE:
* vbo1 [ data1 ]
* vbo2 [ data2 ]
* ...
* vboN [ dataN ]
* SEQUENTIAL:
* vbo [ data1 | data2 | ... | dataN ]
* INTERLEAVED:
* vbo [ data1[0], data2[0], ..., dataN[0] | ... | data1[M], data2[M], ..., dataN[M] ]
*/
class VertexBufferGL : public VertexBuffer
{
public:
/**
* @brief Constructs a Vertex Buffer
* @param layout The vertex buffer layout
* @param memProperty The memory usage property
*/
VertexBufferGL(VertexBufferLayout layout = VertexBufferLayout::Separate,
MemoryUsageProperty property = MemoryUsageProperty::GpuOnly);
/**
* @brief Binds this Vertex Buffer
*/
void bind() const override;
/**
* @brief Binds a specific buffer in the Vertex Buffer
*/
void bind(GLuint prg, int index = -1);
/**
* @brief Unbinds this Vertex Buffer
*/
void unbind();
/**
* @brief Masks the attributes to be used in the shader
* @param attrib_locs The attribute locations
*/
void maskAttributes(std::vector<GLint> attrib_locs);
/**
* @brief Masks a specific attribute to be used in the shader
* @param attrib_loc The attribute location
*/
void maskAttribute(GLint attrib_loc);
/**
* @return Underlying buffers Image IDs
*/
std::vector<std::uint64_t> getBufferIDs() const override;
/**
* @return Underlying buffers and offsets
*/
std::vector<BufferAndOffsets> getBufferOffsets() const override;
/**
* @brief Copies data from external source to this buffer
* @param bufferAndOffets Buffer index and offset
* @param data The data to copy to the buffer
*/
void copyFrom(const BufferAndOffsets& bufferAndOffsets,
pymol::span<const std::byte> data) override;
/**
* Conditionally generates a GPU buffer for the given data descriptor
* @param desc The buffer data descriptor
* @return Whether the buffer data was successfully buffered
* @note The supplied data ptr in the struct can
* be zero, in which case if the default usage is STATIC_DRAW then no
* opengl buffer will be generated for that, else it is assumed that the
* data will be supplied at a later point because it's dynamic draw.
*/
bool bufferData(BufferDataDesc&& desc);
/**
* Generates a GPU buffer for the given data descriptor
* @param desc The buffer data descriptor
* @param data The data to buffer
* @param len The length of the data
* @note assumes the data is interleaved
*/
bool bufferData(
BufferDataDesc&& desc, const void* data, size_t len);
// -----------------------------------------------------------------------------
/**
* Updates (a portion of) the buffer data
* @param offset The offset to start updating the buffer data
* @param size The size of the data to update
* @param data The data to update
* @param index The index of the buffer data to update
* @note This function assumes that the data layout hasn't changed
*/
void bufferSubData(size_t offset, size_t size, void* data, size_t index = 0);
/**
* Replaces the whole interleaved buffer data
* @param data The data to replace the buffer data with
* @param len The length of the data
* @param data The data to replace the buffer data with
* @note This function assumes that the data layout hasn't changed
*/
void bufferReplaceData(std::size_t offset, pymol::span<const std::byte> data);
private:
/**
* @return Vertex buffer type (GL_ARRAY_BUFFER)
*/
GLenum bufferType() const;
/**
* @brief Binds an attribute to the shader program
* @param prg The shader program
* @param d The buffer descriptor
* @param glID The OpenGL buffer ID
*/
void bind_attrib(GLuint prg, const BufferDesc& d, GLuint glID);
/**
* @return true if the data is interleaved
*/
bool isInterleaved() const noexcept;
/**
* Generates a separate buffer for each data descriptor
* @return Whether the buffer data was successfully buffered
*/
bool sepBufferData();
/**
* Generates a single sequential buffer for all data descriptors
* @return Whether the buffer data was successfully buffered
*/
bool seqBufferData();
/**
* Generates a single interleaved buffer for all data descriptors
* @return Whether the buffer data was successfully buffered
*/
bool interleaveBufferData();
/**
* Generates GPU buffer(s) for the given data descriptor
* @return Whether the buffer data was successfully buffered
*/
bool evaluate();
bool m_status{false};
GLuint m_interleavedID{};
MemoryUsageProperty m_memProperty{MemoryUsageProperty::GpuOnly};
VertexBufferLayout m_layout{ VertexBufferLayout::Separate };
std::size_t m_stride{};
BufferDataDesc m_desc;
std::vector<GLuint> desc_glIDs; // m_desc's gl buffer IDs
// m_locs is only for interleaved data
std::vector<GLint> m_locs;
std::vector<GLint> m_attribmask;
};
/**
* Index buffer specialization
*/
class IndexBufferGL : public IndexBuffer
{
public:
/**
* @brief Binds this Index Buffer
*/
void bind() const override;
/**
* @brief Unbinds this Index Buffer
*/
void unbind();
/**
* @return Index buffer type (GL_ELEMENT_ARRAY_BUFFER)
*/
GLenum bufferType() const;
/**
* @brief Copies index data from external source to this buffer
*/
void copyFrom(pymol::span<const std::uint32_t> data);
/**
* @return The OpenGL buffer ID
*/
std::uint64_t getBufferID() const override;
private:
void bufferSubData(std::size_t offset, pymol::span<const std::byte> data);
GLuint m_bufferID{};
};

View File

@@ -548,6 +548,8 @@ pymol_src_dirs = [
"layer3",
"layer4",
"layer5",
"layerGraphics",
"layerGraphics/gl",
generated_dir,
]