/* * Copyright (C) 2011-2011 Gregory hainaut * Copyright (C) 2007-2009 Gabest * * This Program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This Program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA. * http://www.gnu.org/copyleft/gpl.html * */ #pragma once #include "GLState.h" #ifdef ENABLE_OGL_DEBUG_MEM_BW extern uint64 g_uniform_upload_byte; #endif class GSUniformBufferOGL { GLuint m_buffer; // data object GLuint m_index; // GLSL slot uint32 m_size; // size of the data uint8* m_cache; // content of the previous upload public: GSUniformBufferOGL(const string& pretty_name, GLuint index, uint32 size) : m_index(index), m_size(size) { glGenBuffers(1, &m_buffer); bind(); glObjectLabel(GL_BUFFER, m_buffer, pretty_name.size(), pretty_name.c_str()); allocate(); attach(); m_cache = (uint8*)_aligned_malloc(m_size, 32); memset(m_cache, 0, m_size); } void bind() { if (GLState::ubo != m_buffer) { GLState::ubo = m_buffer; glBindBuffer(GL_UNIFORM_BUFFER, m_buffer); } } void allocate() { glBufferData(GL_UNIFORM_BUFFER, m_size, NULL, GL_DYNAMIC_DRAW); } void attach() { // From the opengl manpage: // glBindBufferBase also binds buffer to the generic buffer binding point specified by target GLState::ubo = m_buffer; glBindBufferBase(GL_UNIFORM_BUFFER, m_index, m_buffer); } void upload(const void* src) { bind(); // glMapBufferRange allow to set various parameter but the call is // synchronous whereas glBufferSubData could be asynchronous. // TODO: investigate the extension ARB_invalidate_subdata glBufferSubData(GL_UNIFORM_BUFFER, 0, m_size, src); #ifdef ENABLE_OGL_DEBUG_MEM_BW g_uniform_upload_byte += m_size; #endif } void cache_upload(const void* src) { if (memcmp(m_cache, src, m_size) != 0) { memcpy(m_cache, src, m_size); upload(src); } } ~GSUniformBufferOGL() { glDeleteBuffers(1, &m_buffer); _aligned_free(m_cache); } }; #define UBO_BUFFER_SIZE (4*1024*1024) class GSUniformBufferStorageOGL { GLuint m_buffer; // data object GLuint m_index; // GLSL slot uint32 m_size; // size of the data uint8* m_buffer_ptr; uint32 m_offset; public: GSUniformBufferStorageOGL(GLuint index, uint32 size) : m_index(index) , m_size(size), m_offset(0) { glGenBuffers(1, &m_buffer); bind(); allocate(); attach(); } void bind() { if (GLState::ubo != m_buffer) { GLState::ubo = m_buffer; glBindBuffer(GL_UNIFORM_BUFFER, m_buffer); } } void allocate() { const GLbitfield common_flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT /*| GL_MAP_COHERENT_BIT */; const GLbitfield map_flags = common_flags | GL_MAP_FLUSH_EXPLICIT_BIT; const GLbitfield create_flags = common_flags /*| GL_CLIENT_STORAGE_BIT */; GLsizei buffer_size = UBO_BUFFER_SIZE; glBufferStorage(GL_UNIFORM_BUFFER, buffer_size, NULL, create_flags); m_buffer_ptr = (uint8*) glMapBufferRange(GL_UNIFORM_BUFFER, 0, buffer_size, map_flags); ASSERT(m_buffer_ptr); } void attach() { // From the opengl manpage: // glBindBufferBase also binds buffer to the generic buffer binding point specified by target GLState::ubo = m_buffer; //glBindBufferBase(GL_UNIFORM_BUFFER, m_index, m_buffer); glBindBufferRange(GL_UNIFORM_BUFFER, m_index, m_buffer, m_offset, m_size); } void upload(const void* src) { #ifdef ENABLE_OGL_DEBUG_MEM_BW g_uniform_upload_byte += m_size; #endif memcpy(m_buffer_ptr + m_offset, src, m_size); attach(); glFlushMappedBufferRange(GL_UNIFORM_BUFFER, m_offset, m_size); m_offset = (m_offset + m_size + 255u) & ~0xFF; if (m_offset >= UBO_BUFFER_SIZE) m_offset = 0; } ~GSUniformBufferStorageOGL() { bind(); glUnmapBuffer(GL_UNIFORM_BUFFER); glDeleteBuffers(1, &m_buffer); } }; #undef UBO_BUFFER_SIZE