2015-05-24 04:55:12 +00:00
|
|
|
// Copyright 2008 Dolphin Emulator Project
|
2015-05-17 23:08:10 +00:00
|
|
|
// Licensed under GPLv2+
|
2013-04-18 03:29:41 +00:00
|
|
|
// Refer to the license.txt file included.
|
2009-04-03 14:35:49 +00:00
|
|
|
|
2017-02-01 15:56:13 +00:00
|
|
|
#include "VideoBackends/OGL/VertexManager.h"
|
|
|
|
|
2008-12-08 05:25:12 +00:00
|
|
|
#include <fstream>
|
2015-12-21 15:15:17 +00:00
|
|
|
#include <memory>
|
2014-06-03 05:08:54 +00:00
|
|
|
#include <string>
|
2008-12-08 05:25:12 +00:00
|
|
|
#include <vector>
|
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
#include "Common/Align.h"
|
2016-01-02 20:01:12 +00:00
|
|
|
#include "Common/CommonTypes.h"
|
|
|
|
#include "Common/GL/GLExtensions/GLExtensions.h"
|
2014-02-17 10:18:15 +00:00
|
|
|
|
2018-11-27 07:16:53 +00:00
|
|
|
#include "VideoBackends/OGL/OGLPipeline.h"
|
2014-02-17 10:18:15 +00:00
|
|
|
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
|
|
|
#include "VideoBackends/OGL/Render.h"
|
|
|
|
#include "VideoBackends/OGL/StreamBuffer.h"
|
|
|
|
|
|
|
|
#include "VideoCommon/IndexGenerator.h"
|
|
|
|
#include "VideoCommon/Statistics.h"
|
2014-07-25 23:10:44 +00:00
|
|
|
#include "VideoCommon/VertexLoaderManager.h"
|
2014-02-17 10:18:15 +00:00
|
|
|
#include "VideoCommon/VideoConfig.h"
|
2010-08-04 21:02:32 +00:00
|
|
|
|
2010-10-03 00:41:06 +00:00
|
|
|
namespace OGL
|
2008-12-08 05:25:12 +00:00
|
|
|
{
|
2019-02-15 01:59:50 +00:00
|
|
|
static void CheckBufferBinding()
|
2010-09-28 02:15:02 +00:00
|
|
|
{
|
2019-02-15 01:59:50 +00:00
|
|
|
// The index buffer is part of the VAO state, therefore we need to bind it first.
|
|
|
|
if (!ProgramShaderCache::IsValidVertexFormatBound())
|
|
|
|
{
|
|
|
|
ProgramShaderCache::BindVertexFormat(
|
|
|
|
static_cast<GLVertexFormat*>(VertexLoaderManager::GetCurrentVertexFormat()));
|
|
|
|
}
|
2012-10-26 14:34:02 +00:00
|
|
|
}
|
2013-01-07 19:47:34 +00:00
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
VertexManager::VertexManager() = default;
|
|
|
|
|
2012-10-26 14:34:02 +00:00
|
|
|
VertexManager::~VertexManager()
|
|
|
|
{
|
2019-02-15 01:59:50 +00:00
|
|
|
if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
|
|
|
|
{
|
|
|
|
glDeleteTextures(static_cast<GLsizei>(m_texel_buffer_views.size()),
|
|
|
|
m_texel_buffer_views.data());
|
|
|
|
}
|
2008-12-08 05:25:12 +00:00
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
// VAO must be found when destroying the index buffer.
|
|
|
|
CheckBufferBinding();
|
|
|
|
m_texel_buffer.reset();
|
|
|
|
m_index_buffer.reset();
|
|
|
|
m_vertex_buffer.reset();
|
2012-10-20 13:22:15 +00:00
|
|
|
}
|
2013-02-22 09:25:38 +00:00
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
bool VertexManager::Initialize()
|
2012-10-20 13:22:15 +00:00
|
|
|
{
|
2019-02-15 01:59:50 +00:00
|
|
|
if (!VertexManagerBase::Initialize())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
m_vertex_buffer = StreamBuffer::Create(GL_ARRAY_BUFFER, VERTEX_STREAM_BUFFER_SIZE);
|
|
|
|
m_index_buffer = StreamBuffer::Create(GL_ELEMENT_ARRAY_BUFFER, INDEX_STREAM_BUFFER_SIZE);
|
|
|
|
|
|
|
|
if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
|
|
|
|
{
|
|
|
|
// The minimum MAX_TEXTURE_BUFFER_SIZE that the spec mandates is 65KB, we are asking for a 1MB
|
|
|
|
// buffer here. This buffer is also used as storage for undecoded textures when compute shader
|
|
|
|
// texture decoding is enabled, in which case the requested size is 32MB.
|
|
|
|
GLint max_buffer_size;
|
|
|
|
glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &max_buffer_size);
|
|
|
|
m_texel_buffer = StreamBuffer::Create(
|
|
|
|
GL_TEXTURE_BUFFER, std::min(max_buffer_size, static_cast<GLint>(TEXEL_STREAM_BUFFER_SIZE)));
|
|
|
|
|
|
|
|
// Allocate texture views backed by buffer.
|
|
|
|
static constexpr std::array<std::pair<TexelBufferFormat, GLenum>, NUM_TEXEL_BUFFER_FORMATS>
|
|
|
|
format_mapping = {{
|
|
|
|
{TEXEL_BUFFER_FORMAT_R8_UINT, GL_R8UI},
|
|
|
|
{TEXEL_BUFFER_FORMAT_R16_UINT, GL_R16UI},
|
2019-02-28 10:35:17 +00:00
|
|
|
{TEXEL_BUFFER_FORMAT_RGBA8_UINT, GL_RGBA8UI},
|
2019-02-15 01:59:50 +00:00
|
|
|
{TEXEL_BUFFER_FORMAT_R32G32_UINT, GL_RG32UI},
|
|
|
|
}};
|
|
|
|
glGenTextures(static_cast<GLsizei>(m_texel_buffer_views.size()), m_texel_buffer_views.data());
|
|
|
|
glActiveTexture(GL_MUTABLE_TEXTURE_INDEX);
|
|
|
|
for (const auto& it : format_mapping)
|
|
|
|
{
|
|
|
|
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[it.first]);
|
|
|
|
glTexBuffer(GL_TEXTURE_BUFFER, it.second, m_texel_buffer->GetGLBufferId());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2012-10-20 13:22:15 +00:00
|
|
|
}
|
|
|
|
|
2018-11-27 07:16:53 +00:00
|
|
|
void VertexManager::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size)
|
2017-09-08 09:42:56 +00:00
|
|
|
{
|
2019-02-15 01:59:50 +00:00
|
|
|
InvalidateConstants();
|
2018-11-27 07:16:53 +00:00
|
|
|
ProgramShaderCache::UploadConstants(uniforms, uniforms_size);
|
2017-09-08 09:42:56 +00:00
|
|
|
}
|
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
|
|
|
|
u32* out_offset)
|
2017-09-02 22:05:49 +00:00
|
|
|
{
|
2019-02-15 01:59:50 +00:00
|
|
|
if (data_size > m_texel_buffer->GetSize())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const u32 elem_size = GetTexelBufferElementSize(format);
|
|
|
|
const auto dst = m_texel_buffer->Map(data_size, elem_size);
|
|
|
|
std::memcpy(dst.first, data, data_size);
|
2019-07-11 03:34:50 +00:00
|
|
|
ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, data_size);
|
2019-02-15 01:59:50 +00:00
|
|
|
*out_offset = dst.second / elem_size;
|
|
|
|
m_texel_buffer->Unmap(data_size);
|
|
|
|
|
|
|
|
// Bind the correct view to the texel buffer slot.
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]);
|
|
|
|
Renderer::GetInstance()->InvalidateTextureBinding(0);
|
|
|
|
return true;
|
2017-09-02 22:05:49 +00:00
|
|
|
}
|
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
|
|
|
|
u32* out_offset, const void* palette_data, u32 palette_size,
|
|
|
|
TexelBufferFormat palette_format, u32* out_palette_offset)
|
2017-09-02 22:05:49 +00:00
|
|
|
{
|
2019-02-15 01:59:50 +00:00
|
|
|
const u32 elem_size = GetTexelBufferElementSize(format);
|
|
|
|
const u32 palette_elem_size = GetTexelBufferElementSize(palette_format);
|
|
|
|
const u32 reserve_size = data_size + palette_size + palette_elem_size;
|
|
|
|
if (reserve_size > m_texel_buffer->GetSize())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const auto dst = m_texel_buffer->Map(reserve_size, elem_size);
|
|
|
|
const u32 palette_byte_offset = Common::AlignUp(data_size, palette_elem_size);
|
|
|
|
std::memcpy(dst.first, data, data_size);
|
|
|
|
std::memcpy(dst.first + palette_byte_offset, palette_data, palette_size);
|
2019-07-11 03:34:50 +00:00
|
|
|
ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, palette_byte_offset + palette_size);
|
2019-02-15 01:59:50 +00:00
|
|
|
*out_offset = dst.second / elem_size;
|
|
|
|
*out_palette_offset = (dst.second + palette_byte_offset) / palette_elem_size;
|
|
|
|
m_texel_buffer->Unmap(palette_byte_offset + palette_size);
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]);
|
|
|
|
Renderer::GetInstance()->InvalidateTextureBinding(0);
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
|
|
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(palette_format)]);
|
|
|
|
Renderer::GetInstance()->InvalidateTextureBinding(1);
|
|
|
|
|
|
|
|
return true;
|
2017-09-02 22:05:49 +00:00
|
|
|
}
|
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
GLuint VertexManager::GetVertexBufferHandle() const
|
2010-06-16 10:12:57 +00:00
|
|
|
{
|
2019-02-15 01:59:50 +00:00
|
|
|
return m_vertex_buffer->m_buffer;
|
2012-10-26 14:34:02 +00:00
|
|
|
}
|
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
GLuint VertexManager::GetIndexBufferHandle() const
|
2014-01-23 12:41:53 +00:00
|
|
|
{
|
2019-02-15 01:59:50 +00:00
|
|
|
return m_index_buffer->m_buffer;
|
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
void VertexManager::ResetBuffer(u32 vertex_stride)
|
|
|
|
{
|
|
|
|
CheckBufferBinding();
|
2018-01-20 14:59:10 +00:00
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
auto buffer = m_vertex_buffer->Map(MAXVBUFFERSIZE, vertex_stride);
|
|
|
|
m_cur_buffer_pointer = m_base_buffer_pointer = buffer.first;
|
|
|
|
m_end_buffer_pointer = buffer.first + MAXVBUFFERSIZE;
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
buffer = m_index_buffer->Map(MAXIBUFFERSIZE * sizeof(u16));
|
|
|
|
IndexGenerator::Start((u16*)buffer.first);
|
2014-01-23 12:41:53 +00:00
|
|
|
}
|
|
|
|
|
2018-11-27 07:16:53 +00:00
|
|
|
void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices,
|
|
|
|
u32* out_base_vertex, u32* out_base_index)
|
2012-10-27 02:18:09 +00:00
|
|
|
{
|
2018-11-27 07:16:53 +00:00
|
|
|
u32 vertex_data_size = num_vertices * vertex_stride;
|
|
|
|
u32 index_data_size = num_indices * sizeof(u16);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2018-11-27 07:16:53 +00:00
|
|
|
*out_base_vertex = vertex_stride > 0 ? (m_vertex_buffer->GetCurrentOffset() / vertex_stride) : 0;
|
|
|
|
*out_base_index = m_index_buffer->GetCurrentOffset() / sizeof(u16);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2018-11-27 07:16:53 +00:00
|
|
|
CheckBufferBinding();
|
|
|
|
m_vertex_buffer->Unmap(vertex_data_size);
|
|
|
|
m_index_buffer->Unmap(index_data_size);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2019-07-11 03:34:50 +00:00
|
|
|
ADDSTAT(g_stats.this_frame.bytes_vertex_streamed, vertex_data_size);
|
|
|
|
ADDSTAT(g_stats.this_frame.bytes_index_streamed, index_data_size);
|
2008-12-08 05:25:12 +00:00
|
|
|
}
|
|
|
|
|
2019-02-15 01:59:50 +00:00
|
|
|
void VertexManager::UploadUniforms()
|
2008-12-08 05:25:12 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
ProgramShaderCache::UploadConstants();
|
2018-11-27 07:16:53 +00:00
|
|
|
}
|
|
|
|
} // namespace OGL
|