rpcs3/rpcs3/Emu/RSX/GL/glutils/buffer_object.h
2022-06-03 11:54:09 +03:00

142 lines
4 KiB
C++

#pragma once
#include "common.h"
namespace gl
{
class buffer
{
public:
enum class target
{
pixel_pack = GL_PIXEL_PACK_BUFFER,
pixel_unpack = GL_PIXEL_UNPACK_BUFFER,
array = GL_ARRAY_BUFFER,
element_array = GL_ELEMENT_ARRAY_BUFFER,
uniform = GL_UNIFORM_BUFFER,
texture = GL_TEXTURE_BUFFER,
ssbo = GL_SHADER_STORAGE_BUFFER
};
enum class access
{
read = GL_MAP_READ_BIT,
write = GL_MAP_WRITE_BIT,
read_write = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT
};
enum class memory_type
{
undefined = 0,
local = 1,
host_visible = 2
};
class save_binding_state
{
GLint m_last_binding;
GLenum m_target;
public:
save_binding_state(target target_, const buffer& new_state) : save_binding_state(target_)
{
new_state.bind(target_);
}
save_binding_state(target target_)
{
GLenum pname{};
switch (target_)
{
case target::pixel_pack: pname = GL_PIXEL_PACK_BUFFER_BINDING; break;
case target::pixel_unpack: pname = GL_PIXEL_UNPACK_BUFFER_BINDING; break;
case target::array: pname = GL_ARRAY_BUFFER_BINDING; break;
case target::element_array: pname = GL_ELEMENT_ARRAY_BUFFER_BINDING; break;
case target::uniform: pname = GL_UNIFORM_BUFFER_BINDING; break;
case target::texture: pname = GL_TEXTURE_BUFFER_BINDING; break;
case target::ssbo: pname = GL_SHADER_STORAGE_BUFFER_BINDING; break;
default: fmt::throw_exception("Invalid binding state target (0x%x)", static_cast<int>(target_));
}
glGetIntegerv(pname, &m_last_binding);
m_target = static_cast<GLenum>(target_);
}
~save_binding_state()
{
glBindBuffer(m_target, m_last_binding);
}
};
protected:
GLuint m_id = GL_NONE;
GLsizeiptr m_size = 0;
target m_target = target::array;
memory_type m_memory_type = memory_type::undefined;
void allocate(GLsizeiptr size, const void* data_, memory_type type, GLenum usage);
public:
buffer() = default;
buffer(const buffer&) = delete;
~buffer();
void recreate();
void recreate(GLsizeiptr size, const void* data = nullptr);
void create();
void create(GLsizeiptr size, const void* data_ = nullptr, memory_type type = memory_type::local, GLenum usage = GL_STREAM_DRAW);
void create(target target_, GLsizeiptr size, const void* data_ = nullptr, memory_type type = memory_type::local, GLenum usage = GL_STREAM_DRAW);
void remove();
void bind(target target_) const { glBindBuffer(static_cast<GLenum>(target_), m_id); }
void bind() const { bind(current_target()); }
void data(GLsizeiptr size, const void* data_ = nullptr, GLenum usage = GL_STREAM_DRAW);
void sub_data(GLsizeiptr offset, GLsizeiptr length, GLvoid* data);
GLubyte* map(GLsizeiptr offset, GLsizeiptr length, access access_);
void unmap();
void bind_range(u32 index, u32 offset, u32 size) const;
void bind_range(target target_, u32 index, u32 offset, u32 size) const;
void copy_to(buffer* other, u64 src_offset, u64 dst_offset, u64 size);
target current_target() const { return m_target; }
GLsizeiptr size() const { return m_size; }
uint id() const { return m_id; }
void set_id(uint id) { m_id = id; }
bool created() const { return m_id != GL_NONE; }
explicit operator bool() const { return created(); }
};
class buffer_view
{
buffer* m_buffer = nullptr;
u32 m_offset = 0;
u32 m_range = 0;
GLenum m_format = GL_R8UI;
public:
buffer_view(buffer* _buffer, u32 offset, u32 range, GLenum format = GL_R8UI)
: m_buffer(_buffer), m_offset(offset), m_range(range), m_format(format)
{}
buffer_view() = default;
void update(buffer* _buffer, u32 offset, u32 range, GLenum format = GL_R8UI);
u32 offset() const { return m_offset; }
u32 range() const { return m_range; }
u32 format() const { return m_format; }
buffer* value() const { return m_buffer; }
bool in_range(u32 address, u32 size, u32& new_offset) const;
};
}