mirror of
https://github.com/schrodinger/pymol-open-source.git
synced 2026-06-03 19:54:24 +08:00
PYMOL-5169: Move VertexBufferGL to generalized VertexBuffer (etc)
This commit is contained in:
51
include/pymol/span.h
Normal file
51
include/pymol/span.h
Normal 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
|
||||
@@ -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
|
||||
***********************************************************************/
|
||||
|
||||
@@ -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;
|
||||
|
||||
415
layer1/CGO.cpp
415
layer1/CGO.cpp
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
30
layer1/CGO.h
30
layer1/CGO.h
@@ -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);
|
||||
|
||||
|
||||
@@ -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
25
layerGraphics/GPUEnums.h
Normal 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
|
||||
};
|
||||
61
layerGraphics/GPUVertexDesc.h
Normal file
61
layerGraphics/GPUVertexDesc.h
Normal 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;
|
||||
13
layerGraphics/IndexBuffer.h
Normal file
13
layerGraphics/IndexBuffer.h
Normal 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;
|
||||
};
|
||||
36
layerGraphics/VertexBuffer.h
Normal file
36
layerGraphics/VertexBuffer.h
Normal 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;
|
||||
};
|
||||
66
layerGraphics/VertexFormat.h
Normal file
66
layerGraphics/VertexFormat.h
Normal 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);
|
||||
323
layerGraphics/gl/GLVertexBuffer.cpp
Normal file
323
layerGraphics/gl/GLVertexBuffer.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
221
layerGraphics/gl/GLVertexBuffer.h
Normal file
221
layerGraphics/gl/GLVertexBuffer.h
Normal 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{};
|
||||
};
|
||||
Reference in New Issue
Block a user