mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-12-06 07:12:14 +01:00
200 lines
4.6 KiB
C++
200 lines
4.6 KiB
C++
#include "stdafx.h"
|
|
#include "buffer_object.h"
|
|
|
|
namespace gl
|
|
{
|
|
void buffer::allocate(GLsizeiptr size, const void* data_, memory_type type, GLenum usage)
|
|
{
|
|
if (const auto& caps = get_driver_caps();
|
|
m_target != target::userptr && caps.ARB_buffer_storage_supported)
|
|
{
|
|
GLenum flags = 0;
|
|
if (type == memory_type::host_visible)
|
|
{
|
|
switch (usage)
|
|
{
|
|
case GL_STREAM_DRAW:
|
|
case GL_STATIC_DRAW:
|
|
case GL_DYNAMIC_DRAW:
|
|
flags |= GL_MAP_WRITE_BIT;
|
|
break;
|
|
case GL_STREAM_READ:
|
|
case GL_STATIC_READ:
|
|
case GL_DYNAMIC_READ:
|
|
flags |= GL_MAP_READ_BIT;
|
|
break;
|
|
default:
|
|
fmt::throw_exception("Unsupported buffer usage 0x%x", usage);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Local memory hints
|
|
if (usage == GL_DYNAMIC_COPY)
|
|
{
|
|
flags |= GL_DYNAMIC_STORAGE_BIT;
|
|
}
|
|
}
|
|
|
|
if ((flags & GL_MAP_READ_BIT) && !caps.vendor_AMD)
|
|
{
|
|
// This flag stops NVIDIA from allocating read-only memory in VRAM.
|
|
// NOTE: On AMD, allocating client-side memory via CLIENT_STORAGE_BIT or
|
|
// making use of GL_AMD_pinned_memory brings everything down to a crawl.
|
|
// Afaict there is no reason for this; disabling pixel pack/unpack operations does not alleviate the problem.
|
|
// The driver seems to eventually figure out the optimal storage location by itself.
|
|
flags |= GL_CLIENT_STORAGE_BIT;
|
|
}
|
|
|
|
DSA_CALL2(NamedBufferStorage, m_id, size, data_, flags);
|
|
m_size = size;
|
|
}
|
|
else
|
|
{
|
|
data(size, data_, usage);
|
|
}
|
|
|
|
m_memory_type = type;
|
|
}
|
|
|
|
buffer::~buffer()
|
|
{
|
|
if (created())
|
|
remove();
|
|
}
|
|
|
|
void buffer::recreate()
|
|
{
|
|
if (created())
|
|
{
|
|
remove();
|
|
}
|
|
|
|
create();
|
|
}
|
|
|
|
void buffer::recreate(GLsizeiptr size, const void* data)
|
|
{
|
|
if (created())
|
|
{
|
|
remove();
|
|
}
|
|
|
|
create(size, data);
|
|
}
|
|
|
|
void buffer::create()
|
|
{
|
|
glGenBuffers(1, &m_id);
|
|
save_binding_state save(current_target(), *this);
|
|
}
|
|
|
|
void buffer::create(GLsizeiptr size, const void* data_, memory_type type, GLenum usage)
|
|
{
|
|
create();
|
|
allocate(size, data_, type, usage);
|
|
}
|
|
|
|
void buffer::create(target target_, GLsizeiptr size, const void* data_, memory_type type, GLenum usage)
|
|
{
|
|
m_target = target_;
|
|
|
|
create();
|
|
allocate(size, data_, type, usage);
|
|
}
|
|
|
|
void buffer::remove()
|
|
{
|
|
if (m_id != GL_NONE)
|
|
{
|
|
glDeleteBuffers(1, &m_id);
|
|
m_id = GL_NONE;
|
|
m_size = 0;
|
|
}
|
|
}
|
|
|
|
void buffer::data(GLsizeiptr size, const void* data_, GLenum usage)
|
|
{
|
|
ensure(m_memory_type != memory_type::local);
|
|
|
|
DSA_CALL2(NamedBufferData, m_id, size, data_, usage);
|
|
m_size = size;
|
|
}
|
|
|
|
void buffer::sub_data(GLsizeiptr offset, GLsizeiptr length, GLvoid* data)
|
|
{
|
|
ensure(m_memory_type == memory_type::local);
|
|
DSA_CALL2(NamedBufferSubData, m_id, offset, length, data);
|
|
}
|
|
|
|
GLubyte* buffer::map(GLsizeiptr offset, GLsizeiptr length, access access_)
|
|
{
|
|
ensure(m_memory_type == memory_type::host_visible);
|
|
|
|
GLenum access_bits = static_cast<GLenum>(access_);
|
|
if (access_bits == GL_MAP_WRITE_BIT) access_bits |= GL_MAP_UNSYNCHRONIZED_BIT;
|
|
|
|
auto raw_data = DSA_CALL2_RET(MapNamedBufferRange, id(), offset, length, access_bits);
|
|
return reinterpret_cast<GLubyte*>(raw_data);
|
|
}
|
|
|
|
void buffer::unmap()
|
|
{
|
|
ensure(m_memory_type == memory_type::host_visible);
|
|
DSA_CALL2(UnmapNamedBuffer, id());
|
|
}
|
|
|
|
void buffer::bind_range(u32 index, u32 offset, u32 size) const
|
|
{
|
|
m_bound_range = { offset, size };
|
|
glBindBufferRange(static_cast<GLenum>(current_target()), index, id(), offset, size);
|
|
}
|
|
|
|
void buffer::bind_range(target target_, u32 index, u32 offset, u32 size) const
|
|
{
|
|
m_bound_range = { offset, size };
|
|
glBindBufferRange(static_cast<GLenum>(target_), index, id(), offset, size);
|
|
}
|
|
|
|
void buffer::copy_to(buffer* other, u64 src_offset, u64 dst_offset, u64 size)
|
|
{
|
|
if (get_driver_caps().ARB_dsa_supported)
|
|
{
|
|
glCopyNamedBufferSubData(this->id(), other->id(), src_offset, dst_offset, size);
|
|
}
|
|
else
|
|
{
|
|
glNamedCopyBufferSubDataEXT(this->id(), other->id(), src_offset, dst_offset, size);
|
|
}
|
|
}
|
|
|
|
// Buffer view
|
|
void buffer_view::update(buffer* _buffer, u32 offset, u32 range, GLenum format)
|
|
{
|
|
ensure(_buffer->size() >= (offset + range));
|
|
m_buffer = _buffer;
|
|
m_offset = offset;
|
|
m_range = range;
|
|
m_format = format;
|
|
}
|
|
|
|
bool buffer_view::in_range(u32 address, u32 size, u32& new_offset) const
|
|
{
|
|
if (address < m_offset)
|
|
return false;
|
|
|
|
const u32 _offset = address - m_offset;
|
|
if (m_range < _offset)
|
|
return false;
|
|
|
|
const auto remaining = m_range - _offset;
|
|
if (size <= remaining)
|
|
{
|
|
new_offset = _offset;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|