/* * 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 buffer; // data object GLuint index; // GLSL slot uint32 size; // size of the data public: GSUniformBufferOGL(GLuint index, uint32 size) : index(index) , size(size) { glGenBuffers(1, &buffer); bind(); allocate(); attach(); } void bind() { if (GLState::ubo != buffer) { GLState::ubo = buffer; glBindBuffer(GL_UNIFORM_BUFFER, buffer); } } void allocate() { glBufferData(GL_UNIFORM_BUFFER, 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 = buffer; glBindBufferBase(GL_UNIFORM_BUFFER, index, 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, size, src); #ifdef ENABLE_OGL_DEBUG_MEM_BW g_uniform_upload_byte += size; #endif } ~GSUniformBufferOGL() { glDeleteBuffers(1, &buffer); } }; #define UBO_BUFFER_SIZE (4*1024*1024) class GSUniformBufferStorageOGL { GLuint buffer; // data object GLuint index; // GLSL slot uint32 size; // size of the data uint8* m_buffer_ptr; uint32 m_offset; public: GSUniformBufferStorageOGL(GLuint index, uint32 size) : index(index) , size(size), m_offset(0) { glGenBuffers(1, &buffer); bind(); allocate(); attach(); } void bind() { if (GLState::ubo != buffer) { GLState::ubo = buffer; glBindBuffer(GL_UNIFORM_BUFFER, 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 = buffer; //glBindBufferBase(GL_UNIFORM_BUFFER, index, buffer); glBindBufferRange(GL_UNIFORM_BUFFER, index, buffer, m_offset, size); } void upload(const void* src) { #ifdef ENABLE_OGL_DEBUG_MEM_BW g_uniform_upload_byte += size; #endif memcpy(m_buffer_ptr + m_offset, src, size); attach(); glFlushMappedBufferRange(GL_UNIFORM_BUFFER, m_offset, size); m_offset = (m_offset + size + 255u) & ~0xFF; if (m_offset >= UBO_BUFFER_SIZE) m_offset = 0; } ~GSUniformBufferStorageOGL() { bind(); glUnmapBuffer(GL_UNIFORM_BUFFER); glDeleteBuffers(1, &buffer); } }; #undef UBO_BUFFER_SIZE