From 247ad2034de2c33a6d9cb7d3b6f1ef7ffa5b859d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 17 Jul 2018 21:11:23 +0200 Subject: GWN: Port to GPU module: Move files to GPU This does not include all the struct and type renaming. Only files were renamed. gwn_batch.c/h was fusioned with GPU_batch.c/h gwn_immediate.c/h was fusioned with GPU_immediate.c/h gwn_imm_util.c/h was fusioned with GPU_immediate_util.c/h --- intern/CMakeLists.txt | 1 - intern/gawain/CMakeLists.txt | 50 -- intern/gawain/gawain/gwn_attr_binding.h | 42 - intern/gawain/gawain/gwn_attr_binding_private.h | 43 - intern/gawain/gawain/gwn_batch.h | 193 ----- intern/gawain/gawain/gwn_batch_private.h | 54 -- intern/gawain/gawain/gwn_buffer_id.h | 53 -- intern/gawain/gawain/gwn_common.h | 61 -- intern/gawain/gawain/gwn_context.h | 55 -- intern/gawain/gawain/gwn_element.h | 102 --- intern/gawain/gawain/gwn_imm_util.h | 46 -- intern/gawain/gawain/gwn_immediate.h | 132 ---- intern/gawain/gawain/gwn_primitive.h | 65 -- intern/gawain/gawain/gwn_primitive_private.h | 37 - intern/gawain/gawain/gwn_shader_interface.h | 104 --- intern/gawain/gawain/gwn_vertex_array_id.h | 55 -- intern/gawain/gawain/gwn_vertex_buffer.h | 144 ---- intern/gawain/gawain/gwn_vertex_format.h | 101 --- intern/gawain/gawain/gwn_vertex_format_private.h | 39 - intern/gawain/src/gwn_attr_binding.c | 85 -- intern/gawain/src/gwn_batch.c | 645 --------------- intern/gawain/src/gwn_buffer_id.cpp | 89 --- intern/gawain/src/gwn_element.c | 307 -------- intern/gawain/src/gwn_imm_util.c | 100 --- intern/gawain/src/gwn_immediate.c | 863 --------------------- intern/gawain/src/gwn_primitive.c | 84 -- intern/gawain/src/gwn_shader_interface.c | 361 --------- intern/gawain/src/gwn_vertex_array_id.cpp | 196 ----- intern/gawain/src/gwn_vertex_buffer.c | 268 ------- intern/gawain/src/gwn_vertex_format.c | 310 -------- intern/opencolorio/CMakeLists.txt | 2 +- intern/opencolorio/ocio_impl_glsl.cc | 2 +- .../blender/blenfont/intern/blf_internal_types.h | 2 +- .../blender/draw/engines/eevee/eevee_lightcache.c | 2 +- source/blender/draw/intern/draw_manager.c | 2 +- source/blender/draw/intern/draw_manager.h | 1 + source/blender/gpu/CMakeLists.txt | 22 +- source/blender/gpu/GPU_attr_binding.h | 42 + source/blender/gpu/GPU_batch.h | 182 ++++- source/blender/gpu/GPU_buffer_id.h | 53 ++ source/blender/gpu/GPU_common.h | 61 ++ source/blender/gpu/GPU_context.h | 55 ++ source/blender/gpu/GPU_element.h | 102 +++ source/blender/gpu/GPU_immediate.h | 112 ++- source/blender/gpu/GPU_immediate_util.h | 9 + source/blender/gpu/GPU_primitive.h | 65 ++ source/blender/gpu/GPU_shader_interface.h | 104 +++ source/blender/gpu/GPU_vertex_array_id.h | 55 ++ source/blender/gpu/GPU_vertex_buffer.h | 144 ++++ source/blender/gpu/GPU_vertex_format.h | 101 +++ source/blender/gpu/intern/gpu_attr_binding.c | 85 ++ .../blender/gpu/intern/gpu_attr_binding_private.h | 43 + source/blender/gpu/intern/gpu_batch.c | 637 ++++++++++++++- source/blender/gpu/intern/gpu_batch_private.h | 53 ++ source/blender/gpu/intern/gpu_buffer_id.cpp | 90 +++ source/blender/gpu/intern/gpu_element.c | 308 ++++++++ source/blender/gpu/intern/gpu_immediate.c | 849 +++++++++++++++++++- source/blender/gpu/intern/gpu_immediate_util.c | 70 +- source/blender/gpu/intern/gpu_matrix.c | 2 +- source/blender/gpu/intern/gpu_primitive.c | 84 ++ source/blender/gpu/intern/gpu_primitive_private.h | 37 + source/blender/gpu/intern/gpu_shader_interface.c | 361 +++++++++ source/blender/gpu/intern/gpu_shader_private.h | 2 +- source/blender/gpu/intern/gpu_vertex_array_id.cpp | 196 +++++ source/blender/gpu/intern/gpu_vertex_buffer.c | 268 +++++++ source/blender/gpu/intern/gpu_vertex_format.c | 310 ++++++++ .../blender/gpu/intern/gpu_vertex_format_private.h | 39 + source/blender/python/gawain/gwn_py_api.c | 4 +- source/blender/python/gawain/gwn_py_types.c | 4 +- source/blender/render/CMakeLists.txt | 1 + source/blender/render/intern/source/pipeline.c | 2 +- source/blender/windowmanager/intern/wm_playanim.c | 2 +- source/blender/windowmanager/intern/wm_window.c | 3 +- 73 files changed, 4501 insertions(+), 4752 deletions(-) delete mode 100644 intern/gawain/CMakeLists.txt delete mode 100644 intern/gawain/gawain/gwn_attr_binding.h delete mode 100644 intern/gawain/gawain/gwn_attr_binding_private.h delete mode 100644 intern/gawain/gawain/gwn_batch.h delete mode 100644 intern/gawain/gawain/gwn_batch_private.h delete mode 100644 intern/gawain/gawain/gwn_buffer_id.h delete mode 100644 intern/gawain/gawain/gwn_common.h delete mode 100644 intern/gawain/gawain/gwn_context.h delete mode 100644 intern/gawain/gawain/gwn_element.h delete mode 100644 intern/gawain/gawain/gwn_imm_util.h delete mode 100644 intern/gawain/gawain/gwn_immediate.h delete mode 100644 intern/gawain/gawain/gwn_primitive.h delete mode 100644 intern/gawain/gawain/gwn_primitive_private.h delete mode 100644 intern/gawain/gawain/gwn_shader_interface.h delete mode 100644 intern/gawain/gawain/gwn_vertex_array_id.h delete mode 100644 intern/gawain/gawain/gwn_vertex_buffer.h delete mode 100644 intern/gawain/gawain/gwn_vertex_format.h delete mode 100644 intern/gawain/gawain/gwn_vertex_format_private.h delete mode 100644 intern/gawain/src/gwn_attr_binding.c delete mode 100644 intern/gawain/src/gwn_batch.c delete mode 100644 intern/gawain/src/gwn_buffer_id.cpp delete mode 100644 intern/gawain/src/gwn_element.c delete mode 100644 intern/gawain/src/gwn_imm_util.c delete mode 100644 intern/gawain/src/gwn_immediate.c delete mode 100644 intern/gawain/src/gwn_primitive.c delete mode 100644 intern/gawain/src/gwn_shader_interface.c delete mode 100644 intern/gawain/src/gwn_vertex_array_id.cpp delete mode 100644 intern/gawain/src/gwn_vertex_buffer.c delete mode 100644 intern/gawain/src/gwn_vertex_format.c create mode 100644 source/blender/gpu/GPU_attr_binding.h create mode 100644 source/blender/gpu/GPU_buffer_id.h create mode 100644 source/blender/gpu/GPU_common.h create mode 100644 source/blender/gpu/GPU_context.h create mode 100644 source/blender/gpu/GPU_element.h create mode 100644 source/blender/gpu/GPU_primitive.h create mode 100644 source/blender/gpu/GPU_shader_interface.h create mode 100644 source/blender/gpu/GPU_vertex_array_id.h create mode 100644 source/blender/gpu/GPU_vertex_buffer.h create mode 100644 source/blender/gpu/GPU_vertex_format.h create mode 100644 source/blender/gpu/intern/gpu_attr_binding.c create mode 100644 source/blender/gpu/intern/gpu_attr_binding_private.h create mode 100644 source/blender/gpu/intern/gpu_batch_private.h create mode 100644 source/blender/gpu/intern/gpu_buffer_id.cpp create mode 100644 source/blender/gpu/intern/gpu_element.c create mode 100644 source/blender/gpu/intern/gpu_primitive.c create mode 100644 source/blender/gpu/intern/gpu_primitive_private.h create mode 100644 source/blender/gpu/intern/gpu_shader_interface.c create mode 100644 source/blender/gpu/intern/gpu_vertex_array_id.cpp create mode 100644 source/blender/gpu/intern/gpu_vertex_buffer.c create mode 100644 source/blender/gpu/intern/gpu_vertex_format.c create mode 100644 source/blender/gpu/intern/gpu_vertex_format_private.h diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt index 1a050892836..1459100d415 100644 --- a/intern/CMakeLists.txt +++ b/intern/CMakeLists.txt @@ -34,7 +34,6 @@ add_subdirectory(opencolorio) add_subdirectory(mikktspace) add_subdirectory(glew-mx) add_subdirectory(eigen) -add_subdirectory(gawain) if(WITH_AUDASPACE) add_subdirectory(audaspace) diff --git a/intern/gawain/CMakeLists.txt b/intern/gawain/CMakeLists.txt deleted file mode 100644 index 7ebd3ee7622..00000000000 --- a/intern/gawain/CMakeLists.txt +++ /dev/null @@ -1,50 +0,0 @@ -# WITH_OPENGL limits the visibility of the opengl headers to just gawain and bg_gpu, -# to more easily highlight codepadths in other libraries that need to be refactored, -# bf_intern_gawain is allowed to have opengl regardless of this option. - -if(NOT WITH_OPENGL) - add_definitions(-DWITH_OPENGL) -endif() - -set(INC - gawain -) - -set(INC_SYS - ${GLEW_INCLUDE_PATH} -) - -set(SRC - src/gwn_attr_binding.c - src/gwn_batch.c - src/gwn_element.c - src/gwn_buffer_id.cpp - src/gwn_immediate.c - src/gwn_imm_util.c - src/gwn_primitive.c - src/gwn_shader_interface.c - src/gwn_vertex_array_id.cpp - src/gwn_vertex_buffer.c - src/gwn_vertex_format.c - - gawain/gwn_attr_binding.h - gawain/gwn_attr_binding_private.h - gawain/gwn_batch.h - gawain/gwn_batch_private.h - gawain/gwn_buffer_id.h - gawain/gwn_common.h - gawain/gwn_element.h - gawain/gwn_imm_util.h - gawain/gwn_immediate.h - gawain/gwn_primitive.h - gawain/gwn_primitive_private.h - gawain/gwn_shader_interface.h - gawain/gwn_vertex_array_id.h - gawain/gwn_vertex_buffer.h - gawain/gwn_vertex_format.h - gawain/gwn_vertex_format_private.h -) - -add_definitions(${GL_DEFINITIONS}) - -blender_add_lib(bf_intern_gawain "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/gawain/gawain/gwn_attr_binding.h b/intern/gawain/gawain/gwn_attr_binding.h deleted file mode 100644 index 8030e86ea92..00000000000 --- a/intern/gawain/gawain/gwn_attr_binding.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_attr_binding.h - * \ingroup gpu - * - * Gawain vertex attribute binding - */ - -#ifndef __GWN_ATTR_BINDING_H__ -#define __GWN_ATTR_BINDING_H__ - -#include "gwn_common.h" - -typedef struct Gwn_AttrBinding { - uint64_t loc_bits; /* store 4 bits for each of the 16 attribs */ - uint16_t enabled_bits; /* 1 bit for each attrib */ -} Gwn_AttrBinding; - -#endif /* __GWN_ATTR_BINDING_H__ */ diff --git a/intern/gawain/gawain/gwn_attr_binding_private.h b/intern/gawain/gawain/gwn_attr_binding_private.h deleted file mode 100644 index cead1896ec7..00000000000 --- a/intern/gawain/gawain/gwn_attr_binding_private.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_attr_binding_private.h - * \ingroup gpu - * - * Gawain vertex attribute binding - */ - -#ifndef __GWN_ATTR_BINDING_PRIVATE_H__ -#define __GWN_ATTR_BINDING_PRIVATE_H__ - -#include "gwn_vertex_format.h" -#include "gwn_shader_interface.h" - -void AttribBinding_clear(Gwn_AttrBinding*); - -void get_attrib_locations(const Gwn_VertFormat*, Gwn_AttrBinding*, const Gwn_ShaderInterface*); -unsigned read_attrib_location(const Gwn_AttrBinding*, unsigned a_idx); - -#endif /* __GWN_ATTR_BINDING_PRIVATE_H__ */ diff --git a/intern/gawain/gawain/gwn_batch.h b/intern/gawain/gawain/gwn_batch.h deleted file mode 100644 index a7a54502cc0..00000000000 --- a/intern/gawain/gawain/gwn_batch.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_batch.h - * \ingroup gpu - * - * Gawain geometry batch - * Contains VAOs + VBOs + Shader representing a drawable entity. - */ - -#ifndef __GWN_BATCH_H__ -#define __GWN_BATCH_H__ - -#include "gwn_vertex_buffer.h" -#include "gwn_element.h" -#include "gwn_shader_interface.h" - -typedef enum { - GWN_BATCH_READY_TO_FORMAT, - GWN_BATCH_READY_TO_BUILD, - GWN_BATCH_BUILDING, - GWN_BATCH_READY_TO_DRAW -} Gwn_BatchPhase; - -#define GWN_BATCH_VBO_MAX_LEN 3 -#define GWN_BATCH_VAO_STATIC_LEN 3 -#define GWN_BATCH_VAO_DYN_ALLOC_COUNT 16 - -typedef struct Gwn_Batch { - /* geometry */ - Gwn_VertBuf* verts[GWN_BATCH_VBO_MAX_LEN]; /* verts[0] is required, others can be NULL */ - Gwn_VertBuf* inst; /* instance attribs */ - Gwn_IndexBuf* elem; /* NULL if element list not needed */ - uint32_t gl_prim_type; - - /* cached values (avoid dereferencing later) */ - uint32_t vao_id; - uint32_t program; - const struct Gwn_ShaderInterface* interface; - - /* book-keeping */ - uint owns_flag; - struct Gwn_Context *context; /* used to free all vaos. this implies all vaos were created under the same context. */ - Gwn_BatchPhase phase; - bool program_in_use; - - /* Vao management: remembers all geometry state (vertex attrib bindings & element buffer) - * for each shader interface. Start with a static number of vaos and fallback to dynamic count - * if necessary. Once a batch goes dynamic it does not go back. */ - bool is_dynamic_vao_count; - union { - /* Static handle count */ - struct { - const struct Gwn_ShaderInterface* interfaces[GWN_BATCH_VAO_STATIC_LEN]; - uint32_t vao_ids[GWN_BATCH_VAO_STATIC_LEN]; - } static_vaos; - /* Dynamic handle count */ - struct { - uint count; - const struct Gwn_ShaderInterface** interfaces; - uint32_t* vao_ids; - } dynamic_vaos; - }; - - /* XXX This is the only solution if we want to have some data structure using - * batches as key to identify nodes. We must destroy these nodes with this callback. */ - void (*free_callback)(struct Gwn_Batch*, void*); - void* callback_data; -} Gwn_Batch; - -enum { - GWN_BATCH_OWNS_VBO = (1 << 0), - /* each vbo index gets bit-shifted */ - GWN_BATCH_OWNS_INSTANCES = (1 << 30), - GWN_BATCH_OWNS_INDEX = (1 << 31), -}; - -Gwn_Batch* GWN_batch_create_ex(Gwn_PrimType, Gwn_VertBuf*, Gwn_IndexBuf*, uint owns_flag); -void GWN_batch_init_ex(Gwn_Batch*, Gwn_PrimType, Gwn_VertBuf*, Gwn_IndexBuf*, uint owns_flag); -Gwn_Batch* GWN_batch_duplicate(Gwn_Batch* batch_src); - -#define GWN_batch_create(prim, verts, elem) \ - GWN_batch_create_ex(prim, verts, elem, 0) -#define GWN_batch_init(batch, prim, verts, elem) \ - GWN_batch_init_ex(batch, prim, verts, elem, 0) - -void GWN_batch_discard(Gwn_Batch*); /* verts & elem are not discarded */ - -void GWN_batch_callback_free_set(Gwn_Batch*, void (*callback)(Gwn_Batch*, void*), void*); - -void GWN_batch_instbuf_set(Gwn_Batch*, Gwn_VertBuf*, bool own_vbo); /* Instancing */ - -int GWN_batch_vertbuf_add_ex(Gwn_Batch*, Gwn_VertBuf*, bool own_vbo); - -#define GWN_batch_vertbuf_add(batch, verts) \ - GWN_batch_vertbuf_add_ex(batch, verts, false) - -void GWN_batch_program_set_no_use(Gwn_Batch*, uint32_t program, const Gwn_ShaderInterface*); -void GWN_batch_program_set(Gwn_Batch*, uint32_t program, const Gwn_ShaderInterface*); -/* Entire batch draws with one shader program, but can be redrawn later with another program. */ -/* Vertex shader's inputs must be compatible with the batch's vertex format. */ - -void GWN_batch_program_use_begin(Gwn_Batch*); /* call before Batch_Uniform (temp hack?) */ -void GWN_batch_program_use_end(Gwn_Batch*); - -void GWN_batch_uniform_1ui(Gwn_Batch*, const char* name, int value); -void GWN_batch_uniform_1i(Gwn_Batch*, const char* name, int value); -void GWN_batch_uniform_1b(Gwn_Batch*, const char* name, bool value); -void GWN_batch_uniform_1f(Gwn_Batch*, const char* name, float value); -void GWN_batch_uniform_2f(Gwn_Batch*, const char* name, float x, float y); -void GWN_batch_uniform_3f(Gwn_Batch*, const char* name, float x, float y, float z); -void GWN_batch_uniform_4f(Gwn_Batch*, const char* name, float x, float y, float z, float w); -void GWN_batch_uniform_2fv(Gwn_Batch*, const char* name, const float data[2]); -void GWN_batch_uniform_3fv(Gwn_Batch*, const char* name, const float data[3]); -void GWN_batch_uniform_4fv(Gwn_Batch*, const char* name, const float data[4]); -void GWN_batch_uniform_2fv_array(Gwn_Batch*, const char* name, int len, const float *data); -void GWN_batch_uniform_4fv_array(Gwn_Batch*, const char* name, int len, const float *data); -void GWN_batch_uniform_mat4(Gwn_Batch*, const char* name, const float data[4][4]); - -void GWN_batch_draw(Gwn_Batch*); - -/* This does not bind/unbind shader and does not call GPU_matrix_bind() */ -void GWN_batch_draw_range_ex(Gwn_Batch*, int v_first, int v_count, bool force_instance); - -/* Does not even need batch */ -void GWN_draw_primitive(Gwn_PrimType, int v_count); - -#if 0 /* future plans */ - -/* Can multiple batches share a Gwn_VertBuf? Use ref count? */ - - -/* We often need a batch with its own data, to be created and discarded together. */ -/* WithOwn variants reduce number of system allocations. */ - -typedef struct BatchWithOwnVertexBuffer { - Gwn_Batch batch; - Gwn_VertBuf verts; /* link batch.verts to this */ -} BatchWithOwnVertexBuffer; - -typedef struct BatchWithOwnElementList { - Gwn_Batch batch; - Gwn_IndexBuf elem; /* link batch.elem to this */ -} BatchWithOwnElementList; - -typedef struct BatchWithOwnVertexBufferAndElementList { - Gwn_Batch batch; - Gwn_IndexBuf elem; /* link batch.elem to this */ - Gwn_VertBuf verts; /* link batch.verts to this */ -} BatchWithOwnVertexBufferAndElementList; - -Gwn_Batch* create_BatchWithOwnVertexBuffer(Gwn_PrimType, Gwn_VertFormat*, uint v_len, Gwn_IndexBuf*); -Gwn_Batch* create_BatchWithOwnElementList(Gwn_PrimType, Gwn_VertBuf*, uint prim_len); -Gwn_Batch* create_BatchWithOwnVertexBufferAndElementList(Gwn_PrimType, Gwn_VertFormat*, uint v_len, uint prim_len); -/* verts: shared, own */ -/* elem: none, shared, own */ -Gwn_Batch* create_BatchInGeneral(Gwn_PrimType, VertexBufferStuff, ElementListStuff); - -#endif /* future plans */ - - -/* Macros */ - -#define GWN_BATCH_DISCARD_SAFE(batch) do { \ - if (batch != NULL) { \ - GWN_batch_discard(batch); \ - batch = NULL; \ - } \ -} while (0) - -#endif /* __GWN_BATCH_H__ */ diff --git a/intern/gawain/gawain/gwn_batch_private.h b/intern/gawain/gawain/gwn_batch_private.h deleted file mode 100644 index e7d42ff0249..00000000000 --- a/intern/gawain/gawain/gwn_batch_private.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_batch_private.h - * \ingroup gpu - * - * Gawain geometry batch - * Contains VAOs + VBOs + Shader representing a drawable entity. - */ - -#ifndef __GWN_BATCH_PRIVATE_H__ -#define __GWN_BATCH_PRIVATE_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "gwn_batch.h" -#include "gwn_context.h" -#include "gwn_shader_interface.h" - -void gwn_batch_remove_interface_ref(Gwn_Batch*, const Gwn_ShaderInterface*); -void gwn_batch_vao_cache_clear(Gwn_Batch*); - -void gwn_context_add_batch(Gwn_Context*, Gwn_Batch*); -void gwn_context_remove_batch(Gwn_Context*, Gwn_Batch*); - -#ifdef __cplusplus -} -#endif - -#endif /* __GWN_BATCH_PRIVATE_H__ */ diff --git a/intern/gawain/gawain/gwn_buffer_id.h b/intern/gawain/gawain/gwn_buffer_id.h deleted file mode 100644 index 0c2537a5d5a..00000000000 --- a/intern/gawain/gawain/gwn_buffer_id.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_buffer_id.h - * \ingroup gpu - * - * Gawain buffer IDs - */ - -#ifndef __GWN_BUFFER_ID_H__ -#define __GWN_BUFFER_ID_H__ - -/* Manage GL buffer IDs in a thread-safe way - * Use these instead of glGenBuffers & its friends - * - alloc must be called from main thread - * - free can be called from any thread */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "gwn_common.h" - -GLuint GWN_buf_id_alloc(void); -void GWN_buf_id_free(GLuint buffer_id); - -#ifdef __cplusplus -} -#endif - -#endif /* __GWN_BUFFER_ID_H__ */ diff --git a/intern/gawain/gawain/gwn_common.h b/intern/gawain/gawain/gwn_common.h deleted file mode 100644 index 2587e8670a9..00000000000 --- a/intern/gawain/gawain/gwn_common.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_common.h - * \ingroup gpu - */ - -#ifndef __GWN_COMMON_H__ -#define __GWN_COMMON_H__ - -#define PROGRAM_NO_OPTI 0 - -#if defined(NDEBUG) - #define TRUST_NO_ONE 0 -#else - /* strict error checking, enabled for debug builds during early development */ - #define TRUST_NO_ONE 1 -#endif - -#if defined(WITH_OPENGL) - #include -#endif - -#include -#include -#include - -#if TRUST_NO_ONE - #include -#endif - -/* GWN_INLINE */ -#if defined(_MSC_VER) -# define GWN_INLINE static __forceinline -#else -# define GWN_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__)) -#endif - -#endif /* __GWN_COMMON_H__ */ diff --git a/intern/gawain/gawain/gwn_context.h b/intern/gawain/gawain/gwn_context.h deleted file mode 100644 index 7784fc30562..00000000000 --- a/intern/gawain/gawain/gwn_context.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_context.h - * \ingroup gpu - * - * This interface allow Gawain to manage VAOs for mutiple context and threads. - */ - -#ifndef __GWN_CONTEXT_H__ -#define __GWN_CONTEXT_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "gwn_common.h" -#include "gwn_batch.h" -#include "gwn_shader_interface.h" - -typedef struct Gwn_Context Gwn_Context; - -Gwn_Context* GWN_context_create(void); -void GWN_context_discard(Gwn_Context*); - -void GWN_context_active_set(Gwn_Context*); -Gwn_Context* GWN_context_active_get(void); - -#ifdef __cplusplus -} -#endif - -#endif /* __GWN_CONTEXT_H__ */ diff --git a/intern/gawain/gawain/gwn_element.h b/intern/gawain/gawain/gwn_element.h deleted file mode 100644 index 2d5b6bb692b..00000000000 --- a/intern/gawain/gawain/gwn_element.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_element.h - * \ingroup gpu - * - * Gawain element list (AKA index buffer) - */ - -#ifndef __GWN_ELEMENT_H__ -#define __GWN_ELEMENT_H__ - -#include "gwn_primitive.h" - -#define GWN_TRACK_INDEX_RANGE 1 - -#define GWN_PRIM_RESTART 0xFFFFFFFF - -typedef enum { - GWN_INDEX_U8, /* GL has this, Vulkan does not */ - GWN_INDEX_U16, - GWN_INDEX_U32 -} Gwn_IndexBufType; - -typedef struct Gwn_IndexBuf { - uint index_len; -#if GWN_TRACK_INDEX_RANGE - Gwn_IndexBufType index_type; - uint32_t gl_index_type; - uint min_index; - uint max_index; - uint base_index; -#endif - uint32_t vbo_id; /* 0 indicates not yet sent to VRAM */ - bool use_prim_restart; -} Gwn_IndexBuf; - -void GWN_indexbuf_use(Gwn_IndexBuf*); -uint GWN_indexbuf_size_get(const Gwn_IndexBuf*); - -typedef struct Gwn_IndexBufBuilder { - uint max_allowed_index; - uint max_index_len; - uint index_len; - Gwn_PrimType prim_type; - uint* data; - bool use_prim_restart; -} Gwn_IndexBufBuilder; - - -/* supports all primitive types. */ -void GWN_indexbuf_init_ex(Gwn_IndexBufBuilder*, Gwn_PrimType, uint index_len, uint vertex_len, bool use_prim_restart); - -/* supports only GWN_PRIM_POINTS, GWN_PRIM_LINES and GWN_PRIM_TRIS. */ -void GWN_indexbuf_init(Gwn_IndexBufBuilder*, Gwn_PrimType, uint prim_len, uint vertex_len); - -void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder*, uint v); -void GWN_indexbuf_add_primitive_restart(Gwn_IndexBufBuilder*); - -void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder*, uint v); -void GWN_indexbuf_add_line_verts(Gwn_IndexBufBuilder*, uint v1, uint v2); -void GWN_indexbuf_add_tri_verts(Gwn_IndexBufBuilder*, uint v1, uint v2, uint v3); -void GWN_indexbuf_add_line_adj_verts(Gwn_IndexBufBuilder*, uint v1, uint v2, uint v3, uint v4); - -Gwn_IndexBuf* GWN_indexbuf_build(Gwn_IndexBufBuilder*); -void GWN_indexbuf_build_in_place(Gwn_IndexBufBuilder*, Gwn_IndexBuf*); - -void GWN_indexbuf_discard(Gwn_IndexBuf*); - - -/* Macros */ - -#define GWN_INDEXBUF_DISCARD_SAFE(elem) do { \ - if (elem != NULL) { \ - GWN_indexbuf_discard(elem); \ - elem = NULL; \ - } \ -} while (0) - -#endif /* __GWN_ELEMENT_H__ */ diff --git a/intern/gawain/gawain/gwn_imm_util.h b/intern/gawain/gawain/gwn_imm_util.h deleted file mode 100644 index e512d071dca..00000000000 --- a/intern/gawain/gawain/gwn_imm_util.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_imm_util.h - * \ingroup gpu - * - * Gawain element list (AKA index buffer) - */ - -#ifndef __GWN_IMM_UTIL_H__ -#define __GWN_IMM_UTIL_H__ - -#include - -/* Draw 2D rectangles (replaces glRect functions) */ -/* caller is reponsible for vertex format & shader */ -void immRectf(uint pos, float x1, float y1, float x2, float y2); -void immRecti(uint pos, int x1, int y1, int x2, int y2); - -/* Same as immRectf/immRecti but does not call immBegin/immEnd. To use with GWN_PRIM_TRIS. */ -void immRectf_fast_with_color(uint pos, uint col, float x1, float y1, float x2, float y2, const float color[4]); -void immRecti_fast_with_color(uint pos, uint col, int x1, int y1, int x2, int y2, const float color[4]); - -#endif /* __GWN_IMM_UTIL_H__ */ diff --git a/intern/gawain/gawain/gwn_immediate.h b/intern/gawain/gawain/gwn_immediate.h deleted file mode 100644 index 8231942d735..00000000000 --- a/intern/gawain/gawain/gwn_immediate.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_immediate.h - * \ingroup gpu - * - * Gawain immediate mode work-alike - */ - -#ifndef __GWN_IMMEDIATE_H__ -#define __GWN_IMMEDIATE_H__ - -#include "gwn_vertex_format.h" -#include "gwn_primitive.h" -#include "gwn_shader_interface.h" -#include "gwn_batch.h" - -Gwn_VertFormat* immVertexFormat(void); /* returns a cleared vertex format, ready for add_attrib. */ - -void immBindProgram(uint32_t program, const Gwn_ShaderInterface*); /* every immBegin must have a program bound first. */ -void immUnbindProgram(void); /* call after your last immEnd, or before binding another program. */ - -void immBegin(Gwn_PrimType, uint vertex_len); /* must supply exactly vertex_len vertices. */ -void immBeginAtMost(Gwn_PrimType, uint max_vertex_len); /* can supply fewer vertices. */ -void immEnd(void); /* finishes and draws. */ - -/* ImmBegin a batch, then use standard immFunctions as usual. */ -/* ImmEnd will finalize the batch instead of drawing. */ -/* Then you can draw it as many times as you like! Partially replaces the need for display lists. */ -Gwn_Batch* immBeginBatch(Gwn_PrimType, uint vertex_len); -Gwn_Batch* immBeginBatchAtMost(Gwn_PrimType, uint vertex_len); - -/* Provide attribute values that can change per vertex. */ -/* First vertex after immBegin must have all its attributes specified. */ -/* Skipped attributes will continue using the previous value for that attrib_id. */ -void immAttrib1f(uint attrib_id, float x); -void immAttrib2f(uint attrib_id, float x, float y); -void immAttrib3f(uint attrib_id, float x, float y, float z); -void immAttrib4f(uint attrib_id, float x, float y, float z, float w); - -void immAttrib2i(uint attrib_id, int x, int y); - -void immAttrib1u(uint attrib_id, uint x); - -void immAttrib2s(uint attrib_id, short x, short y); - -void immAttrib2fv(uint attrib_id, const float data[2]); -void immAttrib3fv(uint attrib_id, const float data[3]); -void immAttrib4fv(uint attrib_id, const float data[4]); - -void immAttrib3ub(uint attrib_id, unsigned char r, unsigned char g, unsigned char b); -void immAttrib4ub(uint attrib_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a); - -void immAttrib3ubv(uint attrib_id, const unsigned char data[4]); -void immAttrib4ubv(uint attrib_id, const unsigned char data[4]); - -/* Explicitly skip an attribute. */ -/* This advanced option kills automatic value copying for this attrib_id. */ -void immSkipAttrib(uint attrib_id); - -/* Provide one last attribute value & end the current vertex. */ -/* This is most often used for 2D or 3D position (similar to glVertex). */ -void immVertex2f(uint attrib_id, float x, float y); -void immVertex3f(uint attrib_id, float x, float y, float z); -void immVertex4f(uint attrib_id, float x, float y, float z, float w); - -void immVertex2i(uint attrib_id, int x, int y); - -void immVertex2s(uint attrib_id, short x, short y); - -void immVertex2fv(uint attrib_id, const float data[2]); -void immVertex3fv(uint attrib_id, const float data[3]); - -void immVertex2iv(uint attrib_id, const int data[2]); - -/* Provide uniform values that don't change for the entire draw call. */ -void immUniform1i(const char* name, int x); -void immUniform4iv(const char* name, const int data[4]); -void immUniform1f(const char* name, float x); -void immUniform2f(const char* name, float x, float y); -void immUniform2fv(const char* name, const float data[2]); -void immUniform3f(const char* name, float x, float y, float z); -void immUniform3fv(const char* name, const float data[3]); -void immUniformArray3fv(const char* name, const float *data, int count); -void immUniform4f(const char* name, float x, float y, float z, float w); -void immUniform4fv(const char* name, const float data[4]); -void immUniformArray4fv(const char* bare_name, const float *data, int count); -void immUniformMatrix4fv(const char* name, const float data[4][4]); - -/* Convenience functions for setting "uniform vec4 color". */ -/* The rgb functions have implicit alpha = 1.0. */ -void immUniformColor4f(float r, float g, float b, float a); -void immUniformColor4fv(const float rgba[4]); -void immUniformColor3f(float r, float g, float b); -void immUniformColor3fv(const float rgb[3]); -void immUniformColor3fvAlpha(const float rgb[3], float a); - -void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b); -void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); -void immUniformColor3ubv(const unsigned char rgb[3]); -void immUniformColor3ubvAlpha(const unsigned char rgb[3], unsigned char a); -void immUniformColor4ubv(const unsigned char rgba[4]); - -/* These are called by the system -- not part of drawing API. */ -void immInit(void); -void immActivate(void); -void immDeactivate(void); -void immDestroy(void); - -#endif /* __GWN_IMMEDIATE_H__ */ diff --git a/intern/gawain/gawain/gwn_primitive.h b/intern/gawain/gawain/gwn_primitive.h deleted file mode 100644 index 346f77441d3..00000000000 --- a/intern/gawain/gawain/gwn_primitive.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_primitive.h - * \ingroup gpu - * - * Gawain geometric primitives - */ - -#ifndef __GWN_PRIMITIVE_H__ -#define __GWN_PRIMITIVE_H__ - -#include "gwn_common.h" - -typedef enum { - GWN_PRIM_POINTS, - GWN_PRIM_LINES, - GWN_PRIM_TRIS, - GWN_PRIM_LINE_STRIP, - GWN_PRIM_LINE_LOOP, /* GL has this, Vulkan does not */ - GWN_PRIM_TRI_STRIP, - GWN_PRIM_TRI_FAN, - - GWN_PRIM_LINES_ADJ, - GWN_PRIM_TRIS_ADJ, - GWN_PRIM_LINE_STRIP_ADJ, - - GWN_PRIM_NONE -} Gwn_PrimType; - -/* what types of primitives does each shader expect? */ -typedef enum { - GWN_PRIM_CLASS_NONE = 0, - GWN_PRIM_CLASS_POINT = (1 << 0), - GWN_PRIM_CLASS_LINE = (1 << 1), - GWN_PRIM_CLASS_SURFACE = (1 << 2), - GWN_PRIM_CLASS_ANY = GWN_PRIM_CLASS_POINT | GWN_PRIM_CLASS_LINE | GWN_PRIM_CLASS_SURFACE -} Gwn_PrimClass; - -Gwn_PrimClass GWN_primtype_class(Gwn_PrimType); -bool GWN_primtype_belongs_to_class(Gwn_PrimType, Gwn_PrimClass); - -#endif /* __GWN_PRIMITIVE_H__ */ diff --git a/intern/gawain/gawain/gwn_primitive_private.h b/intern/gawain/gawain/gwn_primitive_private.h deleted file mode 100644 index 6d3f1e20da7..00000000000 --- a/intern/gawain/gawain/gwn_primitive_private.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_primitive_private.h - * \ingroup gpu - * - * Gawain geometric primitives - */ - -#ifndef __GWN_PRIMITIVE_PRIVATE_H__ -#define __GWN_PRIMITIVE_PRIVATE_H__ - -GLenum convert_prim_type_to_gl(Gwn_PrimType); - -#endif /* __GWN_PRIMITIVE_PRIVATE_H__ */ diff --git a/intern/gawain/gawain/gwn_shader_interface.h b/intern/gawain/gawain/gwn_shader_interface.h deleted file mode 100644 index 4b20719b329..00000000000 --- a/intern/gawain/gawain/gwn_shader_interface.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_shader_interface.h - * \ingroup gpu - * - * Gawain shader interface (C --> GLSL) - */ - -#ifndef __GWN_SHADER_INTERFACE_H__ -#define __GWN_SHADER_INTERFACE_H__ - -#include "gwn_common.h" - -typedef enum { - GWN_UNIFORM_NONE = 0, /* uninitialized/unknown */ - - GWN_UNIFORM_MODEL, /* mat4 ModelMatrix */ - GWN_UNIFORM_VIEW, /* mat4 ViewMatrix */ - GWN_UNIFORM_MODELVIEW, /* mat4 ModelViewMatrix */ - GWN_UNIFORM_PROJECTION, /* mat4 ProjectionMatrix */ - GWN_UNIFORM_VIEWPROJECTION, /* mat4 ViewProjectionMatrix */ - GWN_UNIFORM_MVP, /* mat4 ModelViewProjectionMatrix */ - - GWN_UNIFORM_MODEL_INV, /* mat4 ModelMatrixInverse */ - GWN_UNIFORM_VIEW_INV, /* mat4 ViewMatrixInverse */ - GWN_UNIFORM_MODELVIEW_INV, /* mat4 ModelViewMatrixInverse */ - GWN_UNIFORM_PROJECTION_INV, /* mat4 ProjectionMatrixInverse */ - GWN_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */ - - GWN_UNIFORM_NORMAL, /* mat3 NormalMatrix */ - GWN_UNIFORM_WORLDNORMAL, /* mat3 WorldNormalMatrix */ - GWN_UNIFORM_CAMERATEXCO, /* vec4 CameraTexCoFactors */ - GWN_UNIFORM_ORCO, /* vec3 OrcoTexCoFactors[] */ - - GWN_UNIFORM_COLOR, /* vec4 color */ - GWN_UNIFORM_EYE, /* vec3 eye */ - GWN_UNIFORM_CALLID, /* int callId */ - - GWN_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */ - - GWN_NUM_UNIFORMS, /* Special value, denotes number of builtin uniforms. */ -} Gwn_UniformBuiltin; - -typedef struct Gwn_ShaderInput { - struct Gwn_ShaderInput* next; - uint32_t name_offset; - uint name_hash; - Gwn_UniformBuiltin builtin_type; /* only for uniform inputs */ - uint32_t gl_type; /* only for attrib inputs */ - int32_t size; /* only for attrib inputs */ - int32_t location; -} Gwn_ShaderInput; - -#define GWN_NUM_SHADERINTERFACE_BUCKETS 257 -#define GWN_SHADERINTERFACE_REF_ALLOC_COUNT 16 - -typedef struct Gwn_ShaderInterface { - int32_t program; - uint32_t name_buffer_offset; - Gwn_ShaderInput* attrib_buckets[GWN_NUM_SHADERINTERFACE_BUCKETS]; - Gwn_ShaderInput* uniform_buckets[GWN_NUM_SHADERINTERFACE_BUCKETS]; - Gwn_ShaderInput* ubo_buckets[GWN_NUM_SHADERINTERFACE_BUCKETS]; - Gwn_ShaderInput* builtin_uniforms[GWN_NUM_UNIFORMS]; - char* name_buffer; - struct Gwn_Batch** batches; /* references to batches using this interface */ - uint batches_len; -} Gwn_ShaderInterface; - -Gwn_ShaderInterface* GWN_shaderinterface_create(int32_t program_id); -void GWN_shaderinterface_discard(Gwn_ShaderInterface*); - -const Gwn_ShaderInput* GWN_shaderinterface_uniform(const Gwn_ShaderInterface*, const char* name); -const Gwn_ShaderInput* GWN_shaderinterface_uniform_builtin(const Gwn_ShaderInterface*, Gwn_UniformBuiltin); -const Gwn_ShaderInput* GWN_shaderinterface_ubo(const Gwn_ShaderInterface*, const char* name); -const Gwn_ShaderInput* GWN_shaderinterface_attr(const Gwn_ShaderInterface*, const char* name); - -/* keep track of batches using this interface */ -void GWN_shaderinterface_add_batch_ref(Gwn_ShaderInterface*, struct Gwn_Batch*); -void GWN_shaderinterface_remove_batch_ref(Gwn_ShaderInterface*, struct Gwn_Batch*); - -#endif /* __GWN_SHADER_INTERFACE_H__ */ diff --git a/intern/gawain/gawain/gwn_vertex_array_id.h b/intern/gawain/gawain/gwn_vertex_array_id.h deleted file mode 100644 index 6ba26612b4e..00000000000 --- a/intern/gawain/gawain/gwn_vertex_array_id.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_vertex_array_id.h - * \ingroup gpu - * - * Manage GL vertex array IDs in a thread-safe way - * Use these instead of glGenBuffers & its friends - * - alloc must be called from a thread that is bound - * to the context that will be used for drawing with - * this vao. - * - free can be called from any thread - */ - -#ifndef __GWN_VERTEX_ARRAY_ID_H__ -#define __GWN_VERTEX_ARRAY_ID_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "gwn_common.h" -#include "gwn_context.h" - -GLuint GWN_vao_default(void); -GLuint GWN_vao_alloc(void); -void GWN_vao_free(GLuint vao_id, Gwn_Context*); - -#ifdef __cplusplus -} -#endif - -#endif /* __GWN_VERTEX_ARRAY_ID_H__ */ diff --git a/intern/gawain/gawain/gwn_vertex_buffer.h b/intern/gawain/gawain/gwn_vertex_buffer.h deleted file mode 100644 index 84ea12f86d1..00000000000 --- a/intern/gawain/gawain/gwn_vertex_buffer.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_vertex_buffer.h - * \ingroup gpu - * - * Gawain vertex buffer - */ - -#ifndef __GWN_VERTEX_BUFFER_H__ -#define __GWN_VERTEX_BUFFER_H__ - -#include "gwn_vertex_format.h" - -#define VRAM_USAGE 1 -/* How to create a Gwn_VertBuf: */ -/* 1) verts = GWN_vertbuf_create() or GWN_vertbuf_init(verts) */ -/* 2) GWN_vertformat_attr_add(verts->format, ...) */ -/* 3) GWN_vertbuf_data_alloc(verts, vertex_len) <-- finalizes/packs vertex format */ -/* 4) GWN_vertbuf_attr_fill(verts, pos, application_pos_buffer) */ - -/* Is Gwn_VertBuf always used as part of a Gwn_Batch? */ - -typedef enum { - /* can be extended to support more types */ - GWN_USAGE_STREAM, - GWN_USAGE_STATIC, /* do not keep data in memory */ - GWN_USAGE_DYNAMIC -} Gwn_UsageType; - -typedef struct Gwn_VertBuf { - Gwn_VertFormat format; - uint vertex_len; /* number of verts we want to draw */ - uint vertex_alloc; /* number of verts data */ - bool dirty; - unsigned char* data; /* NULL indicates data in VRAM (unmapped) */ - uint32_t vbo_id; /* 0 indicates not yet allocated */ - Gwn_UsageType usage; /* usage hint for GL optimisation */ -} Gwn_VertBuf; - -Gwn_VertBuf* GWN_vertbuf_create(Gwn_UsageType); -Gwn_VertBuf* GWN_vertbuf_create_with_format_ex(const Gwn_VertFormat*, Gwn_UsageType); - -#define GWN_vertbuf_create_with_format(format) \ - GWN_vertbuf_create_with_format_ex(format, GWN_USAGE_STATIC) - -void GWN_vertbuf_discard(Gwn_VertBuf*); - -void GWN_vertbuf_init(Gwn_VertBuf*, Gwn_UsageType); -void GWN_vertbuf_init_with_format_ex(Gwn_VertBuf*, const Gwn_VertFormat*, Gwn_UsageType); - -#define GWN_vertbuf_init_with_format(verts, format) \ - GWN_vertbuf_init_with_format_ex(verts, format, GWN_USAGE_STATIC) - -uint GWN_vertbuf_size_get(const Gwn_VertBuf*); -void GWN_vertbuf_data_alloc(Gwn_VertBuf*, uint v_len); -void GWN_vertbuf_data_resize(Gwn_VertBuf*, uint v_len); -void GWN_vertbuf_vertex_count_set(Gwn_VertBuf*, uint v_len); - -/* The most important set_attrib variant is the untyped one. Get it right first. */ -/* It takes a void* so the app developer is responsible for matching their app data types */ -/* to the vertex attribute's type and component count. They're in control of both, so this */ -/* should not be a problem. */ - -void GWN_vertbuf_attr_set(Gwn_VertBuf*, uint a_idx, uint v_idx, const void* data); -void GWN_vertbuf_attr_fill(Gwn_VertBuf*, uint a_idx, const void* data); /* tightly packed, non interleaved input data */ -void GWN_vertbuf_attr_fill_stride(Gwn_VertBuf*, uint a_idx, uint stride, const void* data); - -/* For low level access only */ -typedef struct Gwn_VertBufRaw { - uint size; - uint stride; - unsigned char* data; - unsigned char* data_init; -#if TRUST_NO_ONE - /* Only for overflow check */ - unsigned char* _data_end; -#endif -} Gwn_VertBufRaw; - -GWN_INLINE void *GWN_vertbuf_raw_step(Gwn_VertBufRaw *a) -{ - unsigned char* data = a->data; - a->data += a->stride; -#if TRUST_NO_ONE - assert(data < a->_data_end); -#endif - return (void *)data; -} - -GWN_INLINE uint GWN_vertbuf_raw_used(Gwn_VertBufRaw *a) -{ - return ((a->data - a->data_init) / a->stride); -} - -void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf*, uint a_idx, Gwn_VertBufRaw *access); - -/* TODO: decide whether to keep the functions below */ -/* doesn't immediate mode satisfy these needs? */ - -/* void setAttrib1f(uint a_idx, uint v_idx, float x); */ -/* void setAttrib2f(uint a_idx, unsigned v_idx, float x, float y); */ -/* void setAttrib3f(unsigned a_idx, unsigned v_idx, float x, float y, float z); */ -/* void setAttrib4f(unsigned a_idx, unsigned v_idx, float x, float y, float z, float w); */ - -/* void setAttrib3ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b); */ -/* void setAttrib4ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b, unsigned char a); */ - -void GWN_vertbuf_use(Gwn_VertBuf*); - -/* Metrics */ -uint GWN_vertbuf_get_memory_usage(void); - -/* Macros */ -#define GWN_VERTBUF_DISCARD_SAFE(verts) do { \ - if (verts != NULL) { \ - GWN_vertbuf_discard(verts); \ - verts = NULL; \ - } \ -} while (0) - -#endif /* __GWN_VERTEX_BUFFER_H__ */ diff --git a/intern/gawain/gawain/gwn_vertex_format.h b/intern/gawain/gawain/gwn_vertex_format.h deleted file mode 100644 index 1197a8ef842..00000000000 --- a/intern/gawain/gawain/gwn_vertex_format.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_vertex_format.h - * \ingroup gpu - * - * Gawain vertex format - */ - -#ifndef __GWN_VERTEX_FORMAT_H__ -#define __GWN_VERTEX_FORMAT_H__ - -#include "gwn_common.h" - -#define GWN_VERT_ATTR_MAX_LEN 16 -#define GWN_VERT_ATTR_MAX_NAMES 3 -#define GWN_VERT_ATTR_NAME_AVERAGE_LEN 11 -#define GWN_VERT_ATTR_NAMES_BUF_LEN ((GWN_VERT_ATTR_NAME_AVERAGE_LEN + 1) * GWN_VERT_ATTR_MAX_LEN) - -typedef enum { - GWN_COMP_I8, - GWN_COMP_U8, - GWN_COMP_I16, - GWN_COMP_U16, - GWN_COMP_I32, - GWN_COMP_U32, - - GWN_COMP_F32, - - GWN_COMP_I10 -} Gwn_VertCompType; - -typedef enum { - GWN_FETCH_FLOAT, - GWN_FETCH_INT, - GWN_FETCH_INT_TO_FLOAT_UNIT, /* 127 (ubyte) -> 0.5 (and so on for other int types) */ - GWN_FETCH_INT_TO_FLOAT /* 127 (any int type) -> 127.0 */ -} Gwn_VertFetchMode; - -typedef struct Gwn_VertAttr { - Gwn_VertFetchMode fetch_mode; - Gwn_VertCompType comp_type; - uint gl_comp_type; - uint comp_len; /* 1 to 4 or 8 or 12 or 16 */ - uint sz; /* size in bytes, 1 to 64 */ - uint offset; /* from beginning of vertex, in bytes */ - uint name_len; /* up to GWN_VERT_ATTR_MAX_NAMES */ - const char* name[GWN_VERT_ATTR_MAX_NAMES]; -} Gwn_VertAttr; - -typedef struct Gwn_VertFormat { - uint attr_len; /* 0 to 16 (GWN_VERT_ATTR_MAX_LEN) */ - uint name_len; /* total count of active vertex attrib */ - uint stride; /* stride in bytes, 1 to 256 */ - uint name_offset; - bool packed; - char names[GWN_VERT_ATTR_NAMES_BUF_LEN]; - Gwn_VertAttr attribs[GWN_VERT_ATTR_MAX_LEN]; /* TODO: variable-size attribs array */ -} Gwn_VertFormat; - -void GWN_vertformat_clear(Gwn_VertFormat*); -void GWN_vertformat_copy(Gwn_VertFormat* dest, const Gwn_VertFormat* src); - -uint GWN_vertformat_attr_add(Gwn_VertFormat*, const char* name, Gwn_VertCompType, uint comp_len, Gwn_VertFetchMode); -void GWN_vertformat_alias_add(Gwn_VertFormat*, const char* alias); - -/* format conversion */ - -typedef struct Gwn_PackedNormal { - int x : 10; - int y : 10; - int z : 10; - int w : 2; /* 0 by default, can manually set to { -2, -1, 0, 1 } */ -} Gwn_PackedNormal; - -Gwn_PackedNormal GWN_normal_convert_i10_v3(const float data[3]); -Gwn_PackedNormal GWN_normal_convert_i10_s3(const short data[3]); - -#endif /* __GWN_VERTEX_FORMAT_H__ */ diff --git a/intern/gawain/gawain/gwn_vertex_format_private.h b/intern/gawain/gawain/gwn_vertex_format_private.h deleted file mode 100644 index 3cae9969fd8..00000000000 --- a/intern/gawain/gawain/gwn_vertex_format_private.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_vertex_format_private.h - * \ingroup gpu - * - * Gawain vertex format - */ - -#ifndef __GWN_VERTEX_FORMAT_PRIVATE_H__ -#define __GWN_VERTEX_FORMAT_PRIVATE_H__ - -void VertexFormat_pack(Gwn_VertFormat*); -uint padding(uint offset, uint alignment); -uint vertex_buffer_size(const Gwn_VertFormat*, uint vertex_len); - -#endif /* __GWN_VERTEX_FORMAT_PRIVATE_H__ */ diff --git a/intern/gawain/src/gwn_attr_binding.c b/intern/gawain/src/gwn_attr_binding.c deleted file mode 100644 index 727aceb0140..00000000000 --- a/intern/gawain/src/gwn_attr_binding.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/intern/gwn_attr_binding.c - * \ingroup gpu - * - * Gawain vertex attribute binding - */ - -#include "gwn_attr_binding.h" -#include "gwn_attr_binding_private.h" -#include -#include - -#if GWN_VERT_ATTR_MAX_LEN != 16 - #error "attrib binding code assumes GWN_VERT_ATTR_MAX_LEN = 16" -#endif - -void AttribBinding_clear(Gwn_AttrBinding* binding) -{ - binding->loc_bits = 0; - binding->enabled_bits = 0; -} - -uint read_attrib_location(const Gwn_AttrBinding* binding, uint a_idx) -{ -#if TRUST_NO_ONE - assert(a_idx < GWN_VERT_ATTR_MAX_LEN); - assert(binding->enabled_bits & (1 << a_idx)); -#endif - return (binding->loc_bits >> (4 * a_idx)) & 0xF; -} - -static void write_attrib_location(Gwn_AttrBinding* binding, uint a_idx, uint location) -{ -#if TRUST_NO_ONE - assert(a_idx < GWN_VERT_ATTR_MAX_LEN); - assert(location < GWN_VERT_ATTR_MAX_LEN); -#endif - const uint shift = 4 * a_idx; - const uint64_t mask = ((uint64_t)0xF) << shift; - /* overwrite this attrib's previous location */ - binding->loc_bits = (binding->loc_bits & ~mask) | (location << shift); - /* mark this attrib as enabled */ - binding->enabled_bits |= 1 << a_idx; -} - -void get_attrib_locations(const Gwn_VertFormat* format, Gwn_AttrBinding* binding, const Gwn_ShaderInterface* shaderface) -{ - AttribBinding_clear(binding); - - for (uint a_idx = 0; a_idx < format->attr_len; ++a_idx) { - const Gwn_VertAttr* a = format->attribs + a_idx; - for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) { - const Gwn_ShaderInput* input = GWN_shaderinterface_attr(shaderface, a->name[n_idx]); -#if TRUST_NO_ONE - assert(input != NULL); - /* TODO: make this a recoverable runtime error? indicates mismatch between vertex format and program */ -#endif - write_attrib_location(binding, a_idx, input->location); - } - } -} diff --git a/intern/gawain/src/gwn_batch.c b/intern/gawain/src/gwn_batch.c deleted file mode 100644 index 5daf0e87aec..00000000000 --- a/intern/gawain/src/gwn_batch.c +++ /dev/null @@ -1,645 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/intern/gwn_batch.c - * \ingroup gpu - * - * Gawain geometry batch - * Contains VAOs + VBOs + Shader representing a drawable entity. - */ - -#include "gwn_batch.h" -#include "gwn_batch_private.h" -#include "gwn_buffer_id.h" -#include "gwn_vertex_array_id.h" -#include "gwn_primitive_private.h" -#include -#include - -/* necessary functions from matrix API */ -extern void GPU_matrix_bind(const Gwn_ShaderInterface* shaderface); - -static void batch_update_program_bindings(Gwn_Batch* batch, uint v_first); - -void gwn_batch_vao_cache_clear(Gwn_Batch* batch) -{ - if (batch->context == NULL) { - return; - } - if (batch->is_dynamic_vao_count) { - for (int i = 0; i < batch->dynamic_vaos.count; ++i) { - if (batch->dynamic_vaos.vao_ids[i]) { - GWN_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context); - } - if (batch->dynamic_vaos.interfaces[i]) { - GWN_shaderinterface_remove_batch_ref((Gwn_ShaderInterface *)batch->dynamic_vaos.interfaces[i], batch); - } - } - free(batch->dynamic_vaos.interfaces); - free(batch->dynamic_vaos.vao_ids); - } - else { - for (int i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i) { - if (batch->static_vaos.vao_ids[i]) { - GWN_vao_free(batch->static_vaos.vao_ids[i], batch->context); - } - if (batch->static_vaos.interfaces[i]) { - GWN_shaderinterface_remove_batch_ref((Gwn_ShaderInterface *)batch->static_vaos.interfaces[i], batch); - } - } - } - batch->is_dynamic_vao_count = false; - for (int i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i) { - batch->static_vaos.vao_ids[i] = 0; - batch->static_vaos.interfaces[i] = NULL; - } - gwn_context_remove_batch(batch->context, batch); - batch->context = NULL; -} - -Gwn_Batch* GWN_batch_create_ex( - Gwn_PrimType prim_type, Gwn_VertBuf* verts, Gwn_IndexBuf* elem, - uint owns_flag) -{ - Gwn_Batch* batch = calloc(1, sizeof(Gwn_Batch)); - GWN_batch_init_ex(batch, prim_type, verts, elem, owns_flag); - return batch; -} - -void GWN_batch_init_ex( - Gwn_Batch* batch, Gwn_PrimType prim_type, Gwn_VertBuf* verts, Gwn_IndexBuf* elem, - uint owns_flag) -{ -#if TRUST_NO_ONE - assert(verts != NULL); -#endif - - batch->verts[0] = verts; - for (int v = 1; v < GWN_BATCH_VBO_MAX_LEN; ++v) { - batch->verts[v] = NULL; - } - batch->inst = NULL; - batch->elem = elem; - batch->gl_prim_type = convert_prim_type_to_gl(prim_type); - batch->phase = GWN_BATCH_READY_TO_DRAW; - batch->is_dynamic_vao_count = false; - batch->owns_flag = owns_flag; - batch->free_callback = NULL; -} - -/* This will share the VBOs with the new batch. */ -Gwn_Batch* GWN_batch_duplicate(Gwn_Batch* batch_src) -{ - Gwn_Batch* batch = GWN_batch_create_ex(GWN_PRIM_POINTS, batch_src->verts[0], batch_src->elem, 0); - - batch->gl_prim_type = batch_src->gl_prim_type; - for (int v = 1; v < GWN_BATCH_VBO_MAX_LEN; ++v) { - batch->verts[v] = batch_src->verts[v]; - } - return batch; -} - -void GWN_batch_discard(Gwn_Batch* batch) -{ - if (batch->owns_flag & GWN_BATCH_OWNS_INDEX) { - GWN_indexbuf_discard(batch->elem); - } - if (batch->owns_flag & GWN_BATCH_OWNS_INSTANCES) { - GWN_vertbuf_discard(batch->inst); - } - if ((batch->owns_flag & ~GWN_BATCH_OWNS_INDEX) != 0) { - for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v) { - if (batch->verts[v] == NULL) { - break; - } - if (batch->owns_flag & (1 << v)) { - GWN_vertbuf_discard(batch->verts[v]); - } - } - } - gwn_batch_vao_cache_clear(batch); - - if (batch->free_callback) { - batch->free_callback(batch, batch->callback_data); - } - free(batch); -} - -void GWN_batch_callback_free_set(Gwn_Batch* batch, void (*callback)(Gwn_Batch*, void*), void* user_data) -{ - batch->free_callback = callback; - batch->callback_data = user_data; -} - -void GWN_batch_instbuf_set(Gwn_Batch* batch, Gwn_VertBuf* inst, bool own_vbo) -{ -#if TRUST_NO_ONE - assert(inst != NULL); -#endif - /* redo the bindings */ - gwn_batch_vao_cache_clear(batch); - - if (batch->inst != NULL && (batch->owns_flag & GWN_BATCH_OWNS_INSTANCES)) { - GWN_vertbuf_discard(batch->inst); - } - batch->inst = inst; - - if (own_vbo) { - batch->owns_flag |= GWN_BATCH_OWNS_INSTANCES; - } - else { - batch->owns_flag &= ~GWN_BATCH_OWNS_INSTANCES; - } -} - -/* Returns the index of verts in the batch. */ -int GWN_batch_vertbuf_add_ex( - Gwn_Batch* batch, Gwn_VertBuf* verts, - bool own_vbo) -{ - /* redo the bindings */ - gwn_batch_vao_cache_clear(batch); - - for (uint v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v) { - if (batch->verts[v] == NULL) { -#if TRUST_NO_ONE - /* for now all VertexBuffers must have same vertex_len */ - assert(verts->vertex_len == batch->verts[0]->vertex_len); -#endif - batch->verts[v] = verts; - /* TODO: mark dirty so we can keep attrib bindings up-to-date */ - if (own_vbo) - batch->owns_flag |= (1 << v); - return v; - } - } - - /* we only make it this far if there is no room for another Gwn_VertBuf */ -#if TRUST_NO_ONE - assert(false); -#endif - return -1; -} - -static GLuint batch_vao_get(Gwn_Batch *batch) -{ - /* Search through cache */ - if (batch->is_dynamic_vao_count) { - for (int i = 0; i < batch->dynamic_vaos.count; ++i) - if (batch->dynamic_vaos.interfaces[i] == batch->interface) - return batch->dynamic_vaos.vao_ids[i]; - } - else { - for (int i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i) - if (batch->static_vaos.interfaces[i] == batch->interface) - return batch->static_vaos.vao_ids[i]; - } - - /* Set context of this batch. - * It will be bound to it until gwn_batch_vao_cache_clear is called. - * Until then it can only be drawn with this context. */ - if (batch->context == NULL) { - batch->context = GWN_context_active_get(); - gwn_context_add_batch(batch->context, batch); - } -#if TRUST_NO_ONE - else { - /* Make sure you are not trying to draw this batch in another context. */ - assert(batch->context == GWN_context_active_get()); - } -#endif - - /* Cache miss, time to add a new entry! */ - GLuint new_vao = 0; - if (!batch->is_dynamic_vao_count) { - int i; /* find first unused slot */ - for (i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i) - if (batch->static_vaos.vao_ids[i] == 0) - break; - - if (i < GWN_BATCH_VAO_STATIC_LEN) { - batch->static_vaos.interfaces[i] = batch->interface; - batch->static_vaos.vao_ids[i] = new_vao = GWN_vao_alloc(); - } - else { - /* Not enough place switch to dynamic. */ - batch->is_dynamic_vao_count = true; - /* Erase previous entries, they will be added back if drawn again. */ - for (int j = 0; j < GWN_BATCH_VAO_STATIC_LEN; ++j) { - GWN_shaderinterface_remove_batch_ref((Gwn_ShaderInterface*)batch->static_vaos.interfaces[j], batch); - GWN_vao_free(batch->static_vaos.vao_ids[j], batch->context); - } - /* Init dynamic arrays and let the branch below set the values. */ - batch->dynamic_vaos.count = GWN_BATCH_VAO_DYN_ALLOC_COUNT; - batch->dynamic_vaos.interfaces = calloc(batch->dynamic_vaos.count, sizeof(Gwn_ShaderInterface*)); - batch->dynamic_vaos.vao_ids = calloc(batch->dynamic_vaos.count, sizeof(GLuint)); - } - } - - if (batch->is_dynamic_vao_count) { - int i; /* find first unused slot */ - for (i = 0; i < batch->dynamic_vaos.count; ++i) - if (batch->dynamic_vaos.vao_ids[i] == 0) - break; - - if (i == batch->dynamic_vaos.count) { - /* Not enough place, realloc the array. */ - i = batch->dynamic_vaos.count; - batch->dynamic_vaos.count += GWN_BATCH_VAO_DYN_ALLOC_COUNT; - batch->dynamic_vaos.interfaces = realloc(batch->dynamic_vaos.interfaces, sizeof(Gwn_ShaderInterface*) * batch->dynamic_vaos.count); - batch->dynamic_vaos.vao_ids = realloc(batch->dynamic_vaos.vao_ids, sizeof(GLuint) * batch->dynamic_vaos.count); - memset(batch->dynamic_vaos.interfaces + i, 0, sizeof(Gwn_ShaderInterface*) * GWN_BATCH_VAO_DYN_ALLOC_COUNT); - memset(batch->dynamic_vaos.vao_ids + i, 0, sizeof(GLuint) * GWN_BATCH_VAO_DYN_ALLOC_COUNT); - } - batch->dynamic_vaos.interfaces[i] = batch->interface; - batch->dynamic_vaos.vao_ids[i] = new_vao = GWN_vao_alloc(); - } - - GWN_shaderinterface_add_batch_ref((Gwn_ShaderInterface*)batch->interface, batch); - -#if TRUST_NO_ONE - assert(new_vao != 0); -#endif - - /* We just got a fresh VAO we need to initialize it. */ - glBindVertexArray(new_vao); - batch_update_program_bindings(batch, 0); - glBindVertexArray(0); - - return new_vao; -} - -void GWN_batch_program_set_no_use(Gwn_Batch* batch, uint32_t program, const Gwn_ShaderInterface* shaderface) -{ -#if TRUST_NO_ONE - assert(glIsProgram(shaderface->program)); - assert(batch->program_in_use == 0); -#endif - batch->interface = shaderface; - batch->program = program; - batch->vao_id = batch_vao_get(batch); -} - -void GWN_batch_program_set(Gwn_Batch* batch, uint32_t program, const Gwn_ShaderInterface* shaderface) -{ - GWN_batch_program_set_no_use(batch, program, shaderface); - GWN_batch_program_use_begin(batch); /* hack! to make Batch_Uniform* simpler */ -} - -void gwn_batch_remove_interface_ref(Gwn_Batch* batch, const Gwn_ShaderInterface* interface) -{ - if (batch->is_dynamic_vao_count) { - for (int i = 0; i < batch->dynamic_vaos.count; ++i) { - if (batch->dynamic_vaos.interfaces[i] == interface) { - GWN_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context); - batch->dynamic_vaos.vao_ids[i] = 0; - batch->dynamic_vaos.interfaces[i] = NULL; - break; /* cannot have duplicates */ - } - } - } - else { - int i; - for (i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i) { - if (batch->static_vaos.interfaces[i] == interface) { - GWN_vao_free(batch->static_vaos.vao_ids[i], batch->context); - batch->static_vaos.vao_ids[i] = 0; - batch->static_vaos.interfaces[i] = NULL; - break; /* cannot have duplicates */ - } - } - } -} - -static void create_bindings( - Gwn_VertBuf* verts, const Gwn_ShaderInterface* interface, - uint v_first, const bool use_instancing) -{ - const Gwn_VertFormat* format = &verts->format; - - const uint attr_len = format->attr_len; - const uint stride = format->stride; - - GWN_vertbuf_use(verts); - - for (uint a_idx = 0; a_idx < attr_len; ++a_idx) { - const Gwn_VertAttr* a = format->attribs + a_idx; - const GLvoid* pointer = (const GLubyte*)0 + a->offset + v_first * stride; - - for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) { - const Gwn_ShaderInput* input = GWN_shaderinterface_attr(interface, a->name[n_idx]); - - if (input == NULL) continue; - - if (a->comp_len == 16 || a->comp_len == 12 || a->comp_len == 8) { -#if TRUST_NO_ONE - assert(a->fetch_mode == GWN_FETCH_FLOAT); - assert(a->gl_comp_type == GL_FLOAT); -#endif - for (int i = 0; i < a->comp_len / 4; ++i) { - glEnableVertexAttribArray(input->location + i); - glVertexAttribDivisor(input->location + i, (use_instancing) ? 1 : 0); - glVertexAttribPointer(input->location + i, 4, a->gl_comp_type, GL_FALSE, stride, - (const GLubyte*)pointer + i * 16); - } - } - else - { - glEnableVertexAttribArray(input->location); - glVertexAttribDivisor(input->location, (use_instancing) ? 1 : 0); - - switch (a->fetch_mode) { - case GWN_FETCH_FLOAT: - case GWN_FETCH_INT_TO_FLOAT: - glVertexAttribPointer(input->location, a->comp_len, a->gl_comp_type, GL_FALSE, stride, pointer); - break; - case GWN_FETCH_INT_TO_FLOAT_UNIT: - glVertexAttribPointer(input->location, a->comp_len, a->gl_comp_type, GL_TRUE, stride, pointer); - break; - case GWN_FETCH_INT: - glVertexAttribIPointer(input->location, a->comp_len, a->gl_comp_type, stride, pointer); - break; - } - } - } - } -} - -static void batch_update_program_bindings(Gwn_Batch* batch, uint v_first) -{ - for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN && batch->verts[v] != NULL; ++v) { - create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false); - } - if (batch->inst) { - create_bindings(batch->inst, batch->interface, v_first, true); - } - if (batch->elem) { - GWN_indexbuf_use(batch->elem); - } -} - -void GWN_batch_program_use_begin(Gwn_Batch* batch) -{ - /* NOTE: use_program & done_using_program are fragile, depend on staying in sync with - * the GL context's active program. use_program doesn't mark other programs as "not used". */ - /* TODO: make not fragile (somehow) */ - - if (!batch->program_in_use) { - glUseProgram(batch->program); - batch->program_in_use = true; - } -} - -void GWN_batch_program_use_end(Gwn_Batch* batch) -{ - if (batch->program_in_use) { -#if PROGRAM_NO_OPTI - glUseProgram(0); -#endif - batch->program_in_use = false; - } -} - -#if TRUST_NO_ONE - #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(batch->interface, name); assert(uniform); -#else - #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(batch->interface, name); -#endif - -void GWN_batch_uniform_1ui(Gwn_Batch* batch, const char* name, int value) -{ - GET_UNIFORM - glUniform1ui(uniform->location, value); -} - -void GWN_batch_uniform_1i(Gwn_Batch* batch, const char* name, int value) -{ - GET_UNIFORM - glUniform1i(uniform->location, value); -} - -void GWN_batch_uniform_1b(Gwn_Batch* batch, const char* name, bool value) -{ - GET_UNIFORM - glUniform1i(uniform->location, value ? GL_TRUE : GL_FALSE); -} - -void GWN_batch_uniform_2f(Gwn_Batch* batch, const char* name, float x, float y) -{ - GET_UNIFORM - glUniform2f(uniform->location, x, y); -} - -void GWN_batch_uniform_3f(Gwn_Batch* batch, const char* name, float x, float y, float z) -{ - GET_UNIFORM - glUniform3f(uniform->location, x, y, z); -} - -void GWN_batch_uniform_4f(Gwn_Batch* batch, const char* name, float x, float y, float z, float w) -{ - GET_UNIFORM - glUniform4f(uniform->location, x, y, z, w); -} - -void GWN_batch_uniform_1f(Gwn_Batch* batch, const char* name, float x) -{ - GET_UNIFORM - glUniform1f(uniform->location, x); -} - -void GWN_batch_uniform_2fv(Gwn_Batch* batch, const char* name, const float data[2]) -{ - GET_UNIFORM - glUniform2fv(uniform->location, 1, data); -} - -void GWN_batch_uniform_3fv(Gwn_Batch* batch, const char* name, const float data[3]) -{ - GET_UNIFORM - glUniform3fv(uniform->location, 1, data); -} - -void GWN_batch_uniform_4fv(Gwn_Batch* batch, const char* name, const float data[4]) -{ - GET_UNIFORM - glUniform4fv(uniform->location, 1, data); -} - -void GWN_batch_uniform_2fv_array(Gwn_Batch* batch, const char* name, const int len, const float *data) -{ - GET_UNIFORM - glUniform2fv(uniform->location, len, data); -} - -void GWN_batch_uniform_4fv_array(Gwn_Batch* batch, const char* name, const int len, const float *data) -{ - GET_UNIFORM - glUniform4fv(uniform->location, len, data); -} - -void GWN_batch_uniform_mat4(Gwn_Batch* batch, const char* name, const float data[4][4]) -{ - GET_UNIFORM - glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (const float *)data); -} - -static void primitive_restart_enable(const Gwn_IndexBuf *el) -{ - // TODO(fclem) Replace by GL_PRIMITIVE_RESTART_FIXED_INDEX when we have ogl 4.3 - glEnable(GL_PRIMITIVE_RESTART); - GLuint restart_index = (GLuint)0xFFFFFFFF; - -#if GWN_TRACK_INDEX_RANGE - if (el->index_type == GWN_INDEX_U8) - restart_index = (GLuint)0xFF; - else if (el->index_type == GWN_INDEX_U16) - restart_index = (GLuint)0xFFFF; -#endif - - glPrimitiveRestartIndex(restart_index); -} - -static void primitive_restart_disable(void) -{ - glDisable(GL_PRIMITIVE_RESTART); -} - -void GWN_batch_draw(Gwn_Batch* batch) -{ -#if TRUST_NO_ONE - assert(batch->phase == GWN_BATCH_READY_TO_DRAW); - assert(batch->verts[0]->vbo_id != 0); -#endif - GWN_batch_program_use_begin(batch); - GPU_matrix_bind(batch->interface); // external call. - - GWN_batch_draw_range_ex(batch, 0, 0, false); - - GWN_batch_program_use_end(batch); -} - -void GWN_batch_draw_range_ex(Gwn_Batch* batch, int v_first, int v_count, bool force_instance) -{ -#if TRUST_NO_ONE - assert(!(force_instance && (batch->inst == NULL)) || v_count > 0); // we cannot infer length if force_instance -#endif - const bool do_instance = (force_instance || batch->inst); - - // If using offset drawing, use the default VAO and redo bindings. - if (v_first != 0 && (do_instance || batch->elem)) { - glBindVertexArray(GWN_vao_default()); - batch_update_program_bindings(batch, v_first); - } - else { - glBindVertexArray(batch->vao_id); - } - - if (do_instance) { - /* Infer length if vertex count is not given */ - if (v_count == 0) { - v_count = batch->inst->vertex_len; - } - - if (batch->elem) { - const Gwn_IndexBuf* el = batch->elem; - - if (el->use_prim_restart) { - primitive_restart_enable(el); - } -#if GWN_TRACK_INDEX_RANGE - glDrawElementsInstancedBaseVertex(batch->gl_prim_type, - el->index_len, - el->gl_index_type, - 0, - v_count, - el->base_index); -#else - glDrawElementsInstanced(batch->gl_prim_type, el->index_len, GL_UNSIGNED_INT, 0, v_count); -#endif - if (el->use_prim_restart) { - primitive_restart_disable(); - } - } - else { - glDrawArraysInstanced(batch->gl_prim_type, 0, batch->verts[0]->vertex_len, v_count); - } - } - else { - /* Infer length if vertex count is not given */ - if (v_count == 0) { - v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len; - } - - if (batch->elem) { - const Gwn_IndexBuf* el = batch->elem; - - if (el->use_prim_restart) { - primitive_restart_enable(el); - } - -#if GWN_TRACK_INDEX_RANGE - if (el->base_index) { - glDrawRangeElementsBaseVertex(batch->gl_prim_type, - el->min_index, - el->max_index, - v_count, - el->gl_index_type, - 0, - el->base_index); - } - else { - glDrawRangeElements(batch->gl_prim_type, el->min_index, el->max_index, v_count, el->gl_index_type, 0); - } -#else - glDrawElements(batch->gl_prim_type, v_count, GL_UNSIGNED_INT, 0); -#endif - if (el->use_prim_restart) { - primitive_restart_disable(); - } - } - else { - glDrawArrays(batch->gl_prim_type, v_first, v_count); - } - } - - /* Performance hog if you are drawing with the same vao multiple time. - * Only activate for debugging. */ - // glBindVertexArray(0); -} - -/* just draw some vertices and let shader place them where we want. */ -void GWN_draw_primitive(Gwn_PrimType prim_type, int v_count) - { - /* we cannot draw without vao ... annoying ... */ - glBindVertexArray(GWN_vao_default()); - - GLenum type = convert_prim_type_to_gl(prim_type); - glDrawArrays(type, 0, v_count); - - /* Performance hog if you are drawing with the same vao multiple time. - * Only activate for debugging.*/ - // glBindVertexArray(0); - } diff --git a/intern/gawain/src/gwn_buffer_id.cpp b/intern/gawain/src/gwn_buffer_id.cpp deleted file mode 100644 index 2c267682f65..00000000000 --- a/intern/gawain/src/gwn_buffer_id.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/intern/gwn_buffer_id.cpp - * \ingroup gpu - * - * Gawain buffer IDs - */ - -#include "gwn_buffer_id.h" -#include -#include - -#define ORPHAN_DEBUG 0 - -#if ORPHAN_DEBUG - #include -#endif - -static std::vector orphaned_buffer_ids; - -static std::mutex orphan_mutex; - -extern "C" { -extern int BLI_thread_is_main(void); /* Blender-specific function */ -} - -static bool thread_is_main() -{ - /* "main" here means the GL context's thread */ - return BLI_thread_is_main(); -} - -GLuint GWN_buf_id_alloc() -{ - /* delete orphaned IDs */ - orphan_mutex.lock(); - if (!orphaned_buffer_ids.empty()) { - const auto orphaned_buffer_len = (uint)orphaned_buffer_ids.size(); -#if ORPHAN_DEBUG - printf("deleting %u orphaned VBO%s\n", orphaned_buffer_len, orphaned_buffer_len == 1 ? "" : "s"); -#endif - glDeleteBuffers(orphaned_buffer_len, orphaned_buffer_ids.data()); - orphaned_buffer_ids.clear(); - } - orphan_mutex.unlock(); - - GLuint new_buffer_id = 0; - glGenBuffers(1, &new_buffer_id); - return new_buffer_id; -} - -void GWN_buf_id_free(GLuint buffer_id) -{ - if (thread_is_main()) { - glDeleteBuffers(1, &buffer_id); - } - else { - /* add this ID to the orphaned list */ - orphan_mutex.lock(); -#if ORPHAN_DEBUG - printf("orphaning VBO %u\n", buffer_id); -#endif - orphaned_buffer_ids.emplace_back(buffer_id); - orphan_mutex.unlock(); - } -} diff --git a/intern/gawain/src/gwn_element.c b/intern/gawain/src/gwn_element.c deleted file mode 100644 index a8c99f20860..00000000000 --- a/intern/gawain/src/gwn_element.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/intern/gwn_element.c - * \ingroup gpu - * - * Gawain element list (AKA index buffer) - */ - -#include "gwn_element.h" -#include "gwn_buffer_id.h" -#include - -#define KEEP_SINGLE_COPY 1 - -static GLenum convert_index_type_to_gl(Gwn_IndexBufType type) -{ - static const GLenum table[] = { - [GWN_INDEX_U8] = GL_UNSIGNED_BYTE, /* GL has this, Vulkan does not */ - [GWN_INDEX_U16] = GL_UNSIGNED_SHORT, - [GWN_INDEX_U32] = GL_UNSIGNED_INT - }; - return table[type]; -} - -uint GWN_indexbuf_size_get(const Gwn_IndexBuf* elem) -{ -#if GWN_TRACK_INDEX_RANGE - static const uint table[] = { - [GWN_INDEX_U8] = sizeof(GLubyte), /* GL has this, Vulkan does not */ - [GWN_INDEX_U16] = sizeof(GLushort), - [GWN_INDEX_U32] = sizeof(GLuint) - }; - return elem->index_len * table[elem->index_type]; -#else - return elem->index_len * sizeof(GLuint); -#endif -} - -void GWN_indexbuf_init_ex( - Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, - uint index_len, uint vertex_len, bool use_prim_restart) -{ - builder->use_prim_restart = use_prim_restart; - builder->max_allowed_index = vertex_len - 1; - builder->max_index_len = index_len; - builder->index_len = 0; // start empty - builder->prim_type = prim_type; - builder->data = calloc(builder->max_index_len, sizeof(uint)); -} - -void GWN_indexbuf_init(Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, uint prim_len, uint vertex_len) -{ - uint verts_per_prim = 0; - switch (prim_type) { - case GWN_PRIM_POINTS: - verts_per_prim = 1; - break; - case GWN_PRIM_LINES: - verts_per_prim = 2; - break; - case GWN_PRIM_TRIS: - verts_per_prim = 3; - break; - case GWN_PRIM_LINES_ADJ: - verts_per_prim = 4; - break; - default: -#if TRUST_NO_ONE - assert(false); -#endif - return; - } - - GWN_indexbuf_init_ex(builder, prim_type, prim_len * verts_per_prim, vertex_len, false); -} - -void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder* builder, uint v) -{ -#if TRUST_NO_ONE - assert(builder->data != NULL); - assert(builder->index_len < builder->max_index_len); - assert(v <= builder->max_allowed_index); -#endif - builder->data[builder->index_len++] = v; -} - -void GWN_indexbuf_add_primitive_restart(Gwn_IndexBufBuilder* builder) -{ -#if TRUST_NO_ONE - assert(builder->data != NULL); - assert(builder->index_len < builder->max_index_len); - assert(builder->use_prim_restart); -#endif - builder->data[builder->index_len++] = GWN_PRIM_RESTART; -} - -void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder* builder, uint v) -{ -#if TRUST_NO_ONE - assert(builder->prim_type == GWN_PRIM_POINTS); -#endif - GWN_indexbuf_add_generic_vert(builder, v); -} - -void GWN_indexbuf_add_line_verts(Gwn_IndexBufBuilder* builder, uint v1, uint v2) -{ -#if TRUST_NO_ONE - assert(builder->prim_type == GWN_PRIM_LINES); - assert(v1 != v2); -#endif - GWN_indexbuf_add_generic_vert(builder, v1); - GWN_indexbuf_add_generic_vert(builder, v2); -} - -void GWN_indexbuf_add_tri_verts(Gwn_IndexBufBuilder* builder, uint v1, uint v2, uint v3) -{ -#if TRUST_NO_ONE - assert(builder->prim_type == GWN_PRIM_TRIS); - assert(v1 != v2 && v2 != v3 && v3 != v1); -#endif - GWN_indexbuf_add_generic_vert(builder, v1); - GWN_indexbuf_add_generic_vert(builder, v2); - GWN_indexbuf_add_generic_vert(builder, v3); -} - -void GWN_indexbuf_add_line_adj_verts(Gwn_IndexBufBuilder* builder, uint v1, uint v2, uint v3, uint v4) -{ -#if TRUST_NO_ONE - assert(builder->prim_type == GWN_PRIM_LINES_ADJ); - assert(v2 != v3); /* only the line need diff indices */ -#endif - GWN_indexbuf_add_generic_vert(builder, v1); - GWN_indexbuf_add_generic_vert(builder, v2); - GWN_indexbuf_add_generic_vert(builder, v3); - GWN_indexbuf_add_generic_vert(builder, v4); -} - -#if GWN_TRACK_INDEX_RANGE -/* Everything remains 32 bit while building to keep things simple. - * Find min/max after, then convert to smallest index type possible. */ - -static uint index_range(const uint values[], uint value_len, uint* min_out, uint* max_out) -{ - if (value_len == 0) { - *min_out = 0; - *max_out = 0; - return 0; - } - uint min_value = values[0]; - uint max_value = values[0]; - for (uint i = 1; i < value_len; ++i) { - const uint value = values[i]; - if (value == GWN_PRIM_RESTART) - continue; - else if (value < min_value) - min_value = value; - else if (value > max_value) - max_value = value; - } - *min_out = min_value; - *max_out = max_value; - return max_value - min_value; -} - -static void squeeze_indices_byte(Gwn_IndexBufBuilder *builder, Gwn_IndexBuf* elem) -{ - const uint *values = builder->data; - const uint index_len = elem->index_len; - - /* data will never be *larger* than builder->data... - * converting in place to avoid extra allocation */ - GLubyte *data = (GLubyte *)builder->data; - - if (elem->max_index > 0xFF) { - const uint base = elem->min_index; - elem->base_index = base; - elem->min_index = 0; - elem->max_index -= base; - for (uint i = 0; i < index_len; ++i) { - data[i] = (values[i] == GWN_PRIM_RESTART) ? 0xFF : (GLubyte)(values[i] - base); - } - } - else { - elem->base_index = 0; - for (uint i = 0; i < index_len; ++i) { - data[i] = (GLubyte)(values[i]); - } - } -} - -static void squeeze_indices_short(Gwn_IndexBufBuilder *builder, Gwn_IndexBuf* elem) -{ - const uint *values = builder->data; - const uint index_len = elem->index_len; - - /* data will never be *larger* than builder->data... - * converting in place to avoid extra allocation */ - GLushort *data = (GLushort *)builder->data; - - if (elem->max_index > 0xFFFF) { - const uint base = elem->min_index; - elem->base_index = base; - elem->min_index = 0; - elem->max_index -= base; - for (uint i = 0; i < index_len; ++i) { - data[i] = (values[i] == GWN_PRIM_RESTART) ? 0xFFFF : (GLushort)(values[i] - base); - } - } - else { - elem->base_index = 0; - for (uint i = 0; i < index_len; ++i) { - data[i] = (GLushort)(values[i]); - } - } -} - -#endif /* GWN_TRACK_INDEX_RANGE */ - -Gwn_IndexBuf* GWN_indexbuf_build(Gwn_IndexBufBuilder* builder) -{ - Gwn_IndexBuf* elem = calloc(1, sizeof(Gwn_IndexBuf)); - GWN_indexbuf_build_in_place(builder, elem); - return elem; -} - -void GWN_indexbuf_build_in_place(Gwn_IndexBufBuilder* builder, Gwn_IndexBuf* elem) -{ -#if TRUST_NO_ONE - assert(builder->data != NULL); -#endif - elem->index_len = builder->index_len; - elem->use_prim_restart = builder->use_prim_restart; - -#if GWN_TRACK_INDEX_RANGE - uint range = index_range(builder->data, builder->index_len, &elem->min_index, &elem->max_index); - - /* count the primitive restart index. */ - if (elem->use_prim_restart) { - range += 1; - } - - if (range <= 0xFF) { - elem->index_type = GWN_INDEX_U8; - squeeze_indices_byte(builder, elem); - } - else if (range <= 0xFFFF) { - elem->index_type = GWN_INDEX_U16; - squeeze_indices_short(builder, elem); - } - else { - elem->index_type = GWN_INDEX_U32; - elem->base_index = 0; - } - elem->gl_index_type = convert_index_type_to_gl(elem->index_type); -#endif - - if (elem->vbo_id == 0) { - elem->vbo_id = GWN_buf_id_alloc(); - } - /* send data to GPU */ - /* GL_ELEMENT_ARRAY_BUFFER changes the state of the last VAO bound, - * so we use the GL_ARRAY_BUFFER here to create a buffer without - * interfering in the VAO state. */ - glBindBuffer(GL_ARRAY_BUFFER, elem->vbo_id); - glBufferData(GL_ARRAY_BUFFER, GWN_indexbuf_size_get(elem), builder->data, GL_STATIC_DRAW); - - /* discard builder (one-time use) */ - free(builder->data); - builder->data = NULL; - /* other fields are safe to leave */ -} - -void GWN_indexbuf_use(Gwn_IndexBuf* elem) -{ - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id); -} - -void GWN_indexbuf_discard(Gwn_IndexBuf* elem) -{ - if (elem->vbo_id) { - GWN_buf_id_free(elem->vbo_id); - } - free(elem); -} diff --git a/intern/gawain/src/gwn_imm_util.c b/intern/gawain/src/gwn_imm_util.c deleted file mode 100644 index cdf55c3dfc4..00000000000 --- a/intern/gawain/src/gwn_imm_util.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/intern/gwn_imm_util.c - * \ingroup gpu - * - * Gawain immediate mode drawing utilities - */ - -#include "gwn_imm_util.h" -#include "gwn_immediate.h" -#include - -void immRectf(uint pos, float x1, float y1, float x2, float y2) -{ - immBegin(GWN_PRIM_TRI_FAN, 4); - immVertex2f(pos, x1, y1); - immVertex2f(pos, x2, y1); - immVertex2f(pos, x2, y2); - immVertex2f(pos, x1, y2); - immEnd(); -} - -void immRecti(uint pos, int x1, int y1, int x2, int y2) -{ - immBegin(GWN_PRIM_TRI_FAN, 4); - immVertex2i(pos, x1, y1); - immVertex2i(pos, x2, y1); - immVertex2i(pos, x2, y2); - immVertex2i(pos, x1, y2); - immEnd(); -} - -void immRectf_fast_with_color(uint pos, uint col, float x1, float y1, float x2, float y2, const float color[4]) -{ - immAttrib4fv(col, color); - immVertex2f(pos, x1, y1); - immAttrib4fv(col, color); - immVertex2f(pos, x2, y1); - immAttrib4fv(col, color); - immVertex2f(pos, x2, y2); - - immAttrib4fv(col, color); - immVertex2f(pos, x1, y1); - immAttrib4fv(col, color); - immVertex2f(pos, x2, y2); - immAttrib4fv(col, color); - immVertex2f(pos, x1, y2); -} - -void immRecti_fast_with_color(uint pos, uint col, int x1, int y1, int x2, int y2, const float color[4]) -{ - immAttrib4fv(col, color); - immVertex2i(pos, x1, y1); - immAttrib4fv(col, color); - immVertex2i(pos, x2, y1); - immAttrib4fv(col, color); - immVertex2i(pos, x2, y2); - - immAttrib4fv(col, color); - immVertex2i(pos, x1, y1); - immAttrib4fv(col, color); - immVertex2i(pos, x2, y2); - immAttrib4fv(col, color); - immVertex2i(pos, x1, y2); -} - -#if 0 /* more complete version in case we want that */ -void immRecti_complete(int x1, int y1, int x2, int y2, const float color[4]) -{ - Gwn_VertFormat *format = immVertexFormat(); - uint pos = add_attrib(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor4fv(color); - immRecti(pos, x1, y1, x2, y2); - immUnbindProgram(); -} -#endif diff --git a/intern/gawain/src/gwn_immediate.c b/intern/gawain/src/gwn_immediate.c deleted file mode 100644 index 442aa85ece4..00000000000 --- a/intern/gawain/src/gwn_immediate.c +++ /dev/null @@ -1,863 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/intern/gwn_immediate.c - * \ingroup gpu - * - * Gawain immediate mode work-alike - */ - -#include "gwn_immediate.h" -#include "gwn_buffer_id.h" -#include "gwn_attr_binding.h" -#include "gwn_attr_binding_private.h" -#include "gwn_vertex_format_private.h" -#include "gwn_vertex_array_id.h" -#include "gwn_primitive_private.h" -#include -#include - -/* necessary functions from matrix API */ -extern void GPU_matrix_bind(const Gwn_ShaderInterface*); -extern bool GPU_matrix_dirty_get(void); - -typedef struct { - /* TODO: organize this struct by frequency of change (run-time) */ - - Gwn_Batch* batch; - Gwn_Context* context; - - /* current draw call */ - GLubyte* buffer_data; - uint buffer_offset; - uint buffer_bytes_mapped; - uint vertex_len; - bool strict_vertex_len; - Gwn_PrimType prim_type; - - Gwn_VertFormat vertex_format; - - /* current vertex */ - uint vertex_idx; - GLubyte* vertex_data; - uint16_t unassigned_attrib_bits; /* which attributes of current vertex have not been given values? */ - - GLuint vbo_id; - GLuint vao_id; - - GLuint bound_program; - const Gwn_ShaderInterface* shader_interface; - Gwn_AttrBinding attrib_binding; - uint16_t prev_enabled_attrib_bits; /* <-- only affects this VAO, so we're ok */ -} Immediate; - -/* size of internal buffer -- make this adjustable? */ -#define IMM_BUFFER_SIZE (4 * 1024 * 1024) - -static bool initialized = false; -static Immediate imm; - -void immInit(void) -{ -#if TRUST_NO_ONE - assert(!initialized); -#endif - memset(&imm, 0, sizeof(Immediate)); - - imm.vbo_id = GWN_buf_id_alloc(); - glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id); - glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); - - imm.prim_type = GWN_PRIM_NONE; - imm.strict_vertex_len = true; - - glBindBuffer(GL_ARRAY_BUFFER, 0); - initialized = true; -} - -void immActivate(void) -{ -#if TRUST_NO_ONE - assert(initialized); - assert(imm.prim_type == GWN_PRIM_NONE); /* make sure we're not between a Begin/End pair */ - assert(imm.vao_id == 0); -#endif - imm.vao_id = GWN_vao_alloc(); - imm.context = GWN_context_active_get(); -} - -void immDeactivate(void) -{ -#if TRUST_NO_ONE - assert(initialized); - assert(imm.prim_type == GWN_PRIM_NONE); /* make sure we're not between a Begin/End pair */ - assert(imm.vao_id != 0); -#endif - GWN_vao_free(imm.vao_id, imm.context); - imm.vao_id = 0; - imm.prev_enabled_attrib_bits = 0; -} - -void immDestroy(void) -{ - GWN_buf_id_free(imm.vbo_id); - initialized = false; -} - -Gwn_VertFormat* immVertexFormat(void) -{ - GWN_vertformat_clear(&imm.vertex_format); - return &imm.vertex_format; -} - -void immBindProgram(GLuint program, const Gwn_ShaderInterface* shaderface) -{ -#if TRUST_NO_ONE - assert(imm.bound_program == 0); - assert(glIsProgram(program)); -#endif - - imm.bound_program = program; - imm.shader_interface = shaderface; - - if (!imm.vertex_format.packed) - VertexFormat_pack(&imm.vertex_format); - - glUseProgram(program); - get_attrib_locations(&imm.vertex_format, &imm.attrib_binding, shaderface); - GPU_matrix_bind(shaderface); -} - -void immUnbindProgram(void) -{ -#if TRUST_NO_ONE - assert(imm.bound_program != 0); -#endif -#if PROGRAM_NO_OPTI - glUseProgram(0); -#endif - imm.bound_program = 0; -} - -#if TRUST_NO_ONE -static bool vertex_count_makes_sense_for_primitive(uint vertex_len, Gwn_PrimType prim_type) -{ - /* does vertex_len make sense for this primitive type? */ - if (vertex_len == 0) { - return false; - } - - switch (prim_type) { - case GWN_PRIM_POINTS: - return true; - case GWN_PRIM_LINES: - return vertex_len % 2 == 0; - case GWN_PRIM_LINE_STRIP: - case GWN_PRIM_LINE_LOOP: - return vertex_len >= 2; - case GWN_PRIM_LINE_STRIP_ADJ: - return vertex_len >= 4; - case GWN_PRIM_TRIS: - return vertex_len % 3 == 0; - case GWN_PRIM_TRI_STRIP: - case GWN_PRIM_TRI_FAN: - return vertex_len >= 3; - default: - return false; - } -} -#endif - -void immBegin(Gwn_PrimType prim_type, uint vertex_len) -{ -#if TRUST_NO_ONE - assert(initialized); - assert(imm.prim_type == GWN_PRIM_NONE); /* make sure we haven't already begun */ - assert(vertex_count_makes_sense_for_primitive(vertex_len, prim_type)); -#endif - imm.prim_type = prim_type; - imm.vertex_len = vertex_len; - imm.vertex_idx = 0; - imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; - - /* how many bytes do we need for this draw call? */ - const uint bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_len); - -#if TRUST_NO_ONE - assert(bytes_needed <= IMM_BUFFER_SIZE); -#endif - - glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id); - - /* does the current buffer have enough room? */ - const uint available_bytes = IMM_BUFFER_SIZE - imm.buffer_offset; - /* ensure vertex data is aligned */ - const uint pre_padding = padding(imm.buffer_offset, imm.vertex_format.stride); /* might waste a little space, but it's safe */ - if ((bytes_needed + pre_padding) <= available_bytes) { - imm.buffer_offset += pre_padding; - } - else { - /* orphan this buffer & start with a fresh one */ - /* this method works on all platforms, old & new */ - glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); - - imm.buffer_offset = 0; - } - -/* printf("mapping %u to %u\n", imm.buffer_offset, imm.buffer_offset + bytes_needed - 1); */ - - imm.buffer_data = glMapBufferRange(GL_ARRAY_BUFFER, imm.buffer_offset, bytes_needed, - GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | (imm.strict_vertex_len ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT)); - -#if TRUST_NO_ONE - assert(imm.buffer_data != NULL); -#endif - - imm.buffer_bytes_mapped = bytes_needed; - imm.vertex_data = imm.buffer_data; -} - -void immBeginAtMost(Gwn_PrimType prim_type, uint vertex_len) -{ -#if TRUST_NO_ONE - assert(vertex_len > 0); -#endif - - imm.strict_vertex_len = false; - immBegin(prim_type, vertex_len); -} - - -Gwn_Batch* immBeginBatch(Gwn_PrimType prim_type, uint vertex_len) -{ -#if TRUST_NO_ONE - assert(initialized); - assert(imm.prim_type == GWN_PRIM_NONE); /* make sure we haven't already begun */ - assert(vertex_count_makes_sense_for_primitive(vertex_len, prim_type)); -#endif - imm.prim_type = prim_type; - imm.vertex_len = vertex_len; - imm.vertex_idx = 0; - imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; - - Gwn_VertBuf* verts = GWN_vertbuf_create_with_format(&imm.vertex_format); - GWN_vertbuf_data_alloc(verts, vertex_len); - - imm.buffer_bytes_mapped = GWN_vertbuf_size_get(verts); - imm.vertex_data = verts->data; - - imm.batch = GWN_batch_create_ex(prim_type, verts, NULL, GWN_BATCH_OWNS_VBO); - imm.batch->phase = GWN_BATCH_BUILDING; - - return imm.batch; -} - -Gwn_Batch* immBeginBatchAtMost(Gwn_PrimType prim_type, uint vertex_len) -{ - imm.strict_vertex_len = false; - return immBeginBatch(prim_type, vertex_len); -} - -static void immDrawSetup(void) -{ - /* set up VAO -- can be done during Begin or End really */ - glBindVertexArray(imm.vao_id); - - /* enable/disable vertex attribs as needed */ - if (imm.attrib_binding.enabled_bits != imm.prev_enabled_attrib_bits) { - for (uint loc = 0; loc < GWN_VERT_ATTR_MAX_LEN; ++loc) { - bool is_enabled = imm.attrib_binding.enabled_bits & (1 << loc); - bool was_enabled = imm.prev_enabled_attrib_bits & (1 << loc); - - if (is_enabled && !was_enabled) { - glEnableVertexAttribArray(loc); - } - else if (was_enabled && !is_enabled) { - glDisableVertexAttribArray(loc); - } - } - - imm.prev_enabled_attrib_bits = imm.attrib_binding.enabled_bits; - } - - const uint stride = imm.vertex_format.stride; - - for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) { - const Gwn_VertAttr* a = imm.vertex_format.attribs + a_idx; - - const uint offset = imm.buffer_offset + a->offset; - const GLvoid* pointer = (const GLubyte*)0 + offset; - - const uint loc = read_attrib_location(&imm.attrib_binding, a_idx); - - switch (a->fetch_mode) { - case GWN_FETCH_FLOAT: - case GWN_FETCH_INT_TO_FLOAT: - glVertexAttribPointer(loc, a->comp_len, a->gl_comp_type, GL_FALSE, stride, pointer); - break; - case GWN_FETCH_INT_TO_FLOAT_UNIT: - glVertexAttribPointer(loc, a->comp_len, a->gl_comp_type, GL_TRUE, stride, pointer); - break; - case GWN_FETCH_INT: - glVertexAttribIPointer(loc, a->comp_len, a->gl_comp_type, stride, pointer); - } - } - - if (GPU_matrix_dirty_get()) { - GPU_matrix_bind(imm.shader_interface); - } -} - -void immEnd(void) -{ -#if TRUST_NO_ONE - assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ -#endif - - uint buffer_bytes_used; - if (imm.strict_vertex_len) { -#if TRUST_NO_ONE - assert(imm.vertex_idx == imm.vertex_len); /* with all vertices defined */ -#endif - buffer_bytes_used = imm.buffer_bytes_mapped; - } - else { -#if TRUST_NO_ONE - assert(imm.vertex_idx <= imm.vertex_len); -#endif - if (imm.vertex_idx == imm.vertex_len) { - buffer_bytes_used = imm.buffer_bytes_mapped; - } - else { -#if TRUST_NO_ONE - assert(imm.vertex_idx == 0 || vertex_count_makes_sense_for_primitive(imm.vertex_idx, imm.prim_type)); -#endif - imm.vertex_len = imm.vertex_idx; - buffer_bytes_used = vertex_buffer_size(&imm.vertex_format, imm.vertex_len); - /* unused buffer bytes are available to the next immBegin */ - } - /* tell OpenGL what range was modified so it doesn't copy the whole mapped range */ - glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, buffer_bytes_used); - } - - if (imm.batch) { - if (buffer_bytes_used != imm.buffer_bytes_mapped) { - GWN_vertbuf_data_resize(imm.batch->verts[0], imm.vertex_len); - /* TODO: resize only if vertex count is much smaller */ - } - GWN_batch_program_set(imm.batch, imm.bound_program, imm.shader_interface); - imm.batch->phase = GWN_BATCH_READY_TO_DRAW; - imm.batch = NULL; /* don't free, batch belongs to caller */ - } - else { - glUnmapBuffer(GL_ARRAY_BUFFER); - if (imm.vertex_len > 0) { - immDrawSetup(); - glDrawArrays(convert_prim_type_to_gl(imm.prim_type), 0, imm.vertex_len); - } - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - /* prep for next immBegin */ - imm.buffer_offset += buffer_bytes_used; - } - - /* prep for next immBegin */ - imm.prim_type = GWN_PRIM_NONE; - imm.strict_vertex_len = true; -} - -static void setAttribValueBit(uint attrib_id) -{ - uint16_t mask = 1 << attrib_id; -#if TRUST_NO_ONE - assert(imm.unassigned_attrib_bits & mask); /* not already set */ -#endif - imm.unassigned_attrib_bits &= ~mask; -} - - -/* --- generic attribute functions --- */ - -void immAttrib1f(uint attrib_id, float x) -{ - Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; -#if TRUST_NO_ONE - assert(attrib_id < imm.vertex_format.attr_len); - assert(attrib->comp_type == GWN_COMP_F32); - assert(attrib->comp_len == 1); - assert(imm.vertex_idx < imm.vertex_len); - assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ -#endif - setAttribValueBit(attrib_id); - - float* data = (float*)(imm.vertex_data + attrib->offset); -/* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */ - - data[0] = x; -} - -void immAttrib2f(uint attrib_id, float x, float y) -{ - Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; -#if TRUST_NO_ONE - assert(attrib_id < imm.vertex_format.attr_len); - assert(attrib->comp_type == GWN_COMP_F32); - assert(attrib->comp_len == 2); - assert(imm.vertex_idx < imm.vertex_len); - assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ -#endif - setAttribValueBit(attrib_id); - - float* data = (float*)(imm.vertex_data + attrib->offset); -/* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */ - - data[0] = x; - data[1] = y; -} - -void immAttrib3f(uint attrib_id, float x, float y, float z) -{ - Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; -#if TRUST_NO_ONE - assert(attrib_id < imm.vertex_format.attr_len); - assert(attrib->comp_type == GWN_COMP_F32); - assert(attrib->comp_len == 3); - assert(imm.vertex_idx < imm.vertex_len); - assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ -#endif - setAttribValueBit(attrib_id); - - float* data = (float*)(imm.vertex_data + attrib->offset); -/* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */ - - data[0] = x; - data[1] = y; - data[2] = z; -} - -void immAttrib4f(uint attrib_id, float x, float y, float z, float w) -{ - Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; -#if TRUST_NO_ONE - assert(attrib_id < imm.vertex_format.attr_len); - assert(attrib->comp_type == GWN_COMP_F32); - assert(attrib->comp_len == 4); - assert(imm.vertex_idx < imm.vertex_len); - assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ -#endif - setAttribValueBit(attrib_id); - - float* data = (float*)(imm.vertex_data + attrib->offset); -/* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */ - - data[0] = x; - data[1] = y; - data[2] = z; - data[3] = w; -} - -void immAttrib1u(uint attrib_id, uint x) -{ - Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; -#if TRUST_NO_ONE - assert(attrib_id < imm.vertex_format.attr_len); - assert(attrib->comp_type == GWN_COMP_U32); - assert(attrib->comp_len == 1); - assert(imm.vertex_idx < imm.vertex_len); - assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ -#endif - setAttribValueBit(attrib_id); - - uint* data = (uint*)(imm.vertex_data + attrib->offset); - - data[0] = x; -} - -void immAttrib2i(uint attrib_id, int x, int y) -{ - Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; -#if TRUST_NO_ONE - assert(attrib_id < imm.vertex_format.attr_len); - assert(attrib->comp_type == GWN_COMP_I32); - assert(attrib->comp_len == 2); - assert(imm.vertex_idx < imm.vertex_len); - assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ -#endif - setAttribValueBit(attrib_id); - - int* data = (int*)(imm.vertex_data + attrib->offset); - - data[0] = x; - data[1] = y; -} - -void immAttrib2s(uint attrib_id, short x, short y) -{ - Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; -#if TRUST_NO_ONE - assert(attrib_id < imm.vertex_format.attr_len); - assert(attrib->comp_type == GWN_COMP_I16); - assert(attrib->comp_len == 2); - assert(imm.vertex_idx < imm.vertex_len); - assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ -#endif - setAttribValueBit(attrib_id); - - short* data = (short*)(imm.vertex_data + attrib->offset); - - data[0] = x; - data[1] = y; -} - -void immAttrib2fv(uint attrib_id, const float data[2]) -{ - immAttrib2f(attrib_id, data[0], data[1]); -} - -void immAttrib3fv(uint attrib_id, const float data[3]) -{ - immAttrib3f(attrib_id, data[0], data[1], data[2]); -} - -void immAttrib4fv(uint attrib_id, const float data[4]) -{ - immAttrib4f(attrib_id, data[0], data[1], data[2], data[3]); -} - -void immAttrib3ub(uint attrib_id, unsigned char r, unsigned char g, unsigned char b) -{ - Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; -#if TRUST_NO_ONE - assert(attrib_id < imm.vertex_format.attr_len); - assert(attrib->comp_type == GWN_COMP_U8); - assert(attrib->comp_len == 3); - assert(imm.vertex_idx < imm.vertex_len); - assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ -#endif - setAttribValueBit(attrib_id); - - GLubyte* data = imm.vertex_data + attrib->offset; -/* printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); */ - - data[0] = r; - data[1] = g; - data[2] = b; -} - -void immAttrib4ub(uint attrib_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a) -{ - Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; -#if TRUST_NO_ONE - assert(attrib_id < imm.vertex_format.attr_len); - assert(attrib->comp_type == GWN_COMP_U8); - assert(attrib->comp_len == 4); - assert(imm.vertex_idx < imm.vertex_len); - assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ -#endif - setAttribValueBit(attrib_id); - - GLubyte* data = imm.vertex_data + attrib->offset; -/* printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); */ - - data[0] = r; - data[1] = g; - data[2] = b; - data[3] = a; -} - -void immAttrib3ubv(uint attrib_id, const unsigned char data[3]) -{ - immAttrib3ub(attrib_id, data[0], data[1], data[2]); -} - -void immAttrib4ubv(uint attrib_id, const unsigned char data[4]) -{ - immAttrib4ub(attrib_id, data[0], data[1], data[2], data[3]); -} - -void immSkipAttrib(uint attrib_id) -{ -#if TRUST_NO_ONE - assert(attrib_id < imm.vertex_format.attr_len); - assert(imm.vertex_idx < imm.vertex_len); - assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ -#endif - setAttribValueBit(attrib_id); -} - -static void immEndVertex(void) /* and move on to the next vertex */ -{ -#if TRUST_NO_ONE - assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ - assert(imm.vertex_idx < imm.vertex_len); -#endif - - /* have all attribs been assigned values? - * if not, copy value from previous vertex */ - if (imm.unassigned_attrib_bits) { -#if TRUST_NO_ONE - assert(imm.vertex_idx > 0); /* first vertex must have all attribs specified */ -#endif - for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) { - if ((imm.unassigned_attrib_bits >> a_idx) & 1) { - const Gwn_VertAttr* a = imm.vertex_format.attribs + a_idx; - -/* printf("copying %s from vertex %u to %u\n", a->name, imm.vertex_idx - 1, imm.vertex_idx); */ - - GLubyte* data = imm.vertex_data + a->offset; - memcpy(data, data - imm.vertex_format.stride, a->sz); - /* TODO: consolidate copy of adjacent attributes */ - } - } - } - - imm.vertex_idx++; - imm.vertex_data += imm.vertex_format.stride; - imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; -} - -void immVertex2f(uint attrib_id, float x, float y) -{ - immAttrib2f(attrib_id, x, y); - immEndVertex(); -} - -void immVertex3f(uint attrib_id, float x, float y, float z) -{ - immAttrib3f(attrib_id, x, y, z); - immEndVertex(); -} - -void immVertex4f(uint attrib_id, float x, float y, float z, float w) -{ - immAttrib4f(attrib_id, x, y, z, w); - immEndVertex(); -} - -void immVertex2i(uint attrib_id, int x, int y) -{ - immAttrib2i(attrib_id, x, y); - immEndVertex(); -} - -void immVertex2s(uint attrib_id, short x, short y) -{ - immAttrib2s(attrib_id, x, y); - immEndVertex(); -} - -void immVertex2fv(uint attrib_id, const float data[2]) -{ - immAttrib2f(attrib_id, data[0], data[1]); - immEndVertex(); -} - -void immVertex3fv(uint attrib_id, const float data[3]) -{ - immAttrib3f(attrib_id, data[0], data[1], data[2]); - immEndVertex(); -} - -void immVertex2iv(uint attrib_id, const int data[2]) -{ - immAttrib2i(attrib_id, data[0], data[1]); - immEndVertex(); -} - - -/* --- generic uniform functions --- */ - -#if 0 - #if TRUST_NO_ONE - #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(imm.shader_interface, name); assert(uniform); - #else - #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(imm.shader_interface, name); - #endif -#else - /* NOTE: It is possible to have uniform fully optimized out from the shader. - * In this case we can't assert failure or allow NULL-pointer dereference. - * TODO(sergey): How can we detect existing-but-optimized-out uniform but still - * catch typos in uniform names passed to immUniform*() functions? */ - #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(imm.shader_interface, name); if (uniform == NULL) return; -#endif - -void immUniform1f(const char* name, float x) -{ - GET_UNIFORM - glUniform1f(uniform->location, x); -} - -void immUniform2f(const char* name, float x, float y) -{ - GET_UNIFORM - glUniform2f(uniform->location, x, y); -} - -void immUniform2fv(const char* name, const float data[2]) -{ - GET_UNIFORM - glUniform2fv(uniform->location, 1, data); -} - -void immUniform3f(const char* name, float x, float y, float z) -{ - GET_UNIFORM - glUniform3f(uniform->location, x, y, z); -} - -void immUniform3fv(const char* name, const float data[3]) -{ - GET_UNIFORM - glUniform3fv(uniform->location, 1, data); -} - -/* can increase this limit or move to another file */ -#define MAX_UNIFORM_NAME_LEN 60 - -void immUniformArray3fv(const char* bare_name, const float *data, int count) -{ - /* look up "name[0]" when given "name" */ - const size_t len = strlen(bare_name); -#if TRUST_NO_ONE - assert(len <= MAX_UNIFORM_NAME_LEN); -#endif - char name[MAX_UNIFORM_NAME_LEN]; - strcpy(name, bare_name); - name[len + 0] = '['; - name[len + 1] = '0'; - name[len + 2] = ']'; - name[len + 3] = '\0'; - - GET_UNIFORM - glUniform3fv(uniform->location, count, data); -} - -void immUniform4f(const char* name, float x, float y, float z, float w) -{ - GET_UNIFORM - glUniform4f(uniform->location, x, y, z, w); -} - -void immUniform4fv(const char* name, const float data[4]) -{ - GET_UNIFORM - glUniform4fv(uniform->location, 1, data); -} - -void immUniformArray4fv(const char* bare_name, const float *data, int count) -{ - /* look up "name[0]" when given "name" */ - const size_t len = strlen(bare_name); -#if TRUST_NO_ONE - assert(len <= MAX_UNIFORM_NAME_LEN); -#endif - char name[MAX_UNIFORM_NAME_LEN]; - strcpy(name, bare_name); - name[len + 0] = '['; - name[len + 1] = '0'; - name[len + 2] = ']'; - name[len + 3] = '\0'; - - GET_UNIFORM - glUniform4fv(uniform->location, count, data); -} - -void immUniformMatrix4fv(const char* name, const float data[4][4]) -{ - GET_UNIFORM - glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (float *)data); -} - -void immUniform1i(const char* name, int x) -{ - GET_UNIFORM - glUniform1i(uniform->location, x); -} - -void immUniform4iv(const char* name, const int data[4]) -{ - GET_UNIFORM - glUniform4iv(uniform->location, 1, data); -} - -/* --- convenience functions for setting "uniform vec4 color" --- */ - -void immUniformColor4f(float r, float g, float b, float a) -{ - const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform_builtin(imm.shader_interface, GWN_UNIFORM_COLOR); -#if TRUST_NO_ONE - assert(uniform != NULL); -#endif - glUniform4f(uniform->location, r, g, b, a); -} - -void immUniformColor4fv(const float rgba[4]) -{ - immUniformColor4f(rgba[0], rgba[1], rgba[2], rgba[3]); -} - -void immUniformColor3f(float r, float g, float b) -{ - immUniformColor4f(r, g, b, 1.0f); -} - -void immUniformColor3fv(const float rgb[3]) -{ - immUniformColor4f(rgb[0], rgb[1], rgb[2], 1.0f); -} - -void immUniformColor3fvAlpha(const float rgb[3], float a) -{ - immUniformColor4f(rgb[0], rgb[1], rgb[2], a); -} - -/* TODO: v-- treat as sRGB? --v */ - -void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b) -{ - const float scale = 1.0f / 255.0f; - immUniformColor4f(scale * r, scale * g, scale * b, 1.0f); -} - -void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) -{ - const float scale = 1.0f / 255.0f; - immUniformColor4f(scale * r, scale * g, scale * b, scale * a); -} - -void immUniformColor3ubv(const unsigned char rgb[3]) -{ - immUniformColor3ub(rgb[0], rgb[1], rgb[2]); -} - -void immUniformColor3ubvAlpha(const unsigned char rgb[3], unsigned char alpha) -{ - immUniformColor4ub(rgb[0], rgb[1], rgb[2], alpha); -} - -void immUniformColor4ubv(const unsigned char rgba[4]) -{ - immUniformColor4ub(rgba[0], rgba[1], rgba[2], rgba[3]); -} diff --git a/intern/gawain/src/gwn_primitive.c b/intern/gawain/src/gwn_primitive.c deleted file mode 100644 index bec638a4972..00000000000 --- a/intern/gawain/src/gwn_primitive.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/intern/gwn_primitive.c - * \ingroup gpu - * - * Gawain geometric primitives - */ - -#include "gwn_primitive.h" -#include "gwn_primitive_private.h" - -Gwn_PrimClass GWN_primtype_class(Gwn_PrimType prim_type) -{ - static const Gwn_PrimClass classes[] = { - [GWN_PRIM_POINTS] = GWN_PRIM_CLASS_POINT, - [GWN_PRIM_LINES] = GWN_PRIM_CLASS_LINE, - [GWN_PRIM_LINE_STRIP] = GWN_PRIM_CLASS_LINE, - [GWN_PRIM_LINE_LOOP] = GWN_PRIM_CLASS_LINE, - [GWN_PRIM_TRIS] = GWN_PRIM_CLASS_SURFACE, - [GWN_PRIM_TRI_STRIP] = GWN_PRIM_CLASS_SURFACE, - [GWN_PRIM_TRI_FAN] = GWN_PRIM_CLASS_SURFACE, - - [GWN_PRIM_LINES_ADJ] = GWN_PRIM_CLASS_LINE, - [GWN_PRIM_LINE_STRIP_ADJ] = GWN_PRIM_CLASS_LINE, - [GWN_PRIM_TRIS_ADJ] = GWN_PRIM_CLASS_SURFACE, - - [GWN_PRIM_NONE] = GWN_PRIM_CLASS_NONE - }; - - return classes[prim_type]; -} - -bool GWN_primtype_belongs_to_class(Gwn_PrimType prim_type, Gwn_PrimClass prim_class) -{ - if (prim_class == GWN_PRIM_CLASS_NONE && prim_type == GWN_PRIM_NONE) { - return true; - } - return prim_class & GWN_primtype_class(prim_type); -} - -GLenum convert_prim_type_to_gl(Gwn_PrimType prim_type) -{ -#if TRUST_NO_ONE - assert(prim_type != GWN_PRIM_NONE); -#endif - static const GLenum table[] = { - [GWN_PRIM_POINTS] = GL_POINTS, - [GWN_PRIM_LINES] = GL_LINES, - [GWN_PRIM_LINE_STRIP] = GL_LINE_STRIP, - [GWN_PRIM_LINE_LOOP] = GL_LINE_LOOP, - [GWN_PRIM_TRIS] = GL_TRIANGLES, - [GWN_PRIM_TRI_STRIP] = GL_TRIANGLE_STRIP, - [GWN_PRIM_TRI_FAN] = GL_TRIANGLE_FAN, - - [GWN_PRIM_LINES_ADJ] = GL_LINES_ADJACENCY, - [GWN_PRIM_LINE_STRIP_ADJ] = GL_LINE_STRIP_ADJACENCY, - [GWN_PRIM_TRIS_ADJ] = GL_TRIANGLES_ADJACENCY, - }; - - return table[prim_type]; -} diff --git a/intern/gawain/src/gwn_shader_interface.c b/intern/gawain/src/gwn_shader_interface.c deleted file mode 100644 index 997d5215d5b..00000000000 --- a/intern/gawain/src/gwn_shader_interface.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/intern/gwn_shader_interface.c - * \ingroup gpu - * - * Gawain shader interface (C --> GLSL) - */ - -#include "gwn_batch_private.h" -#include "gwn_shader_interface.h" -#include "gwn_vertex_array_id.h" -#include -#include -#include - -#define DEBUG_SHADER_INTERFACE 0 - -#if DEBUG_SHADER_INTERFACE - #include -#endif - -static const char* BuiltinUniform_name(Gwn_UniformBuiltin u) -{ - static const char* names[] = { - [GWN_UNIFORM_NONE] = NULL, - - [GWN_UNIFORM_MODEL] = "ModelMatrix", - [GWN_UNIFORM_VIEW] = "ViewMatrix", - [GWN_UNIFORM_MODELVIEW] = "ModelViewMatrix", - [GWN_UNIFORM_PROJECTION] = "ProjectionMatrix", - [GWN_UNIFORM_VIEWPROJECTION] = "ViewProjectionMatrix", - [GWN_UNIFORM_MVP] = "ModelViewProjectionMatrix", - - [GWN_UNIFORM_MODEL_INV] = "ModelMatrixInverse", - [GWN_UNIFORM_VIEW_INV] = "ViewMatrixInverse", - [GWN_UNIFORM_MODELVIEW_INV] = "ModelViewMatrixInverse", - [GWN_UNIFORM_PROJECTION_INV] = "ProjectionMatrixInverse", - [GWN_UNIFORM_VIEWPROJECTION_INV] = "ViewProjectionMatrixInverse", - - [GWN_UNIFORM_NORMAL] = "NormalMatrix", - [GWN_UNIFORM_WORLDNORMAL] = "WorldNormalMatrix", - [GWN_UNIFORM_CAMERATEXCO] = "CameraTexCoFactors", - [GWN_UNIFORM_ORCO] = "OrcoTexCoFactors", - - [GWN_UNIFORM_COLOR] = "color", - [GWN_UNIFORM_EYE] = "eye", - [GWN_UNIFORM_CALLID] = "callId", - - [GWN_UNIFORM_CUSTOM] = NULL, - [GWN_NUM_UNIFORMS] = NULL, - }; - - return names[u]; -} - -GWN_INLINE bool match(const char* a, const char* b) -{ - return strcmp(a, b) == 0; -} - -GWN_INLINE uint hash_string(const char *str) -{ - uint i = 0, c; - while ((c = *str++)) { - i = i * 37 + c; - } - return i; -} - -GWN_INLINE void set_input_name(Gwn_ShaderInterface* shaderface, Gwn_ShaderInput* input, - const char* name, uint32_t name_len) -{ - input->name_offset = shaderface->name_buffer_offset; - input->name_hash = hash_string(name); - shaderface->name_buffer_offset += name_len + 1; /* include NULL terminator */ -} - -GWN_INLINE void shader_input_to_bucket(Gwn_ShaderInput* input, - Gwn_ShaderInput* buckets[GWN_NUM_SHADERINTERFACE_BUCKETS]) -{ - const uint bucket_index = input->name_hash % GWN_NUM_SHADERINTERFACE_BUCKETS; - input->next = buckets[bucket_index]; - buckets[bucket_index] = input; -} - -GWN_INLINE const Gwn_ShaderInput* buckets_lookup(Gwn_ShaderInput* const buckets[GWN_NUM_SHADERINTERFACE_BUCKETS], - const char *name_buffer, const char *name) -{ - const uint name_hash = hash_string(name); - const uint bucket_index = name_hash % GWN_NUM_SHADERINTERFACE_BUCKETS; - const Gwn_ShaderInput* input = buckets[bucket_index]; - if (input == NULL) { - /* Requested uniform is not found at all. */ - return NULL; - } - /* Optimization bit: if there is no hash collision detected when constructing shader interface - * it means we can only request the single possible uniform. Surely, it's possible we request - * uniform which causes hash collision, but that will be detected in debug builds. */ - if (input->next == NULL) { - if (name_hash == input->name_hash) { -#if TRUST_NO_ONE - assert(match(name_buffer + input->name_offset, name)); -#endif - return input; - } - return NULL; - } - /* Work through possible collisions. */ - const Gwn_ShaderInput* next = input; - while (next != NULL) { - input = next; - next = input->next; - if (input->name_hash != name_hash) { - continue; - } - if (match(name_buffer + input->name_offset, name)) { - return input; - } - } - return NULL; /* not found */ -} - -GWN_INLINE void buckets_free(Gwn_ShaderInput* buckets[GWN_NUM_SHADERINTERFACE_BUCKETS]) -{ - for (uint bucket_index = 0; bucket_index < GWN_NUM_SHADERINTERFACE_BUCKETS; ++bucket_index) { - Gwn_ShaderInput *input = buckets[bucket_index]; - while (input != NULL) { - Gwn_ShaderInput *input_next = input->next; - free(input); - input = input_next; - } - } -} - -static bool setup_builtin_uniform(Gwn_ShaderInput* input, const char* name) -{ - /* TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types */ - - /* detect built-in uniforms (name must match) */ - for (Gwn_UniformBuiltin u = GWN_UNIFORM_NONE + 1; u < GWN_UNIFORM_CUSTOM; ++u) { - const char* builtin_name = BuiltinUniform_name(u); - if (match(name, builtin_name)) { - input->builtin_type = u; - return true; - } - } - input->builtin_type = GWN_UNIFORM_CUSTOM; - return false; -} - -static const Gwn_ShaderInput* add_uniform(Gwn_ShaderInterface* shaderface, const char* name) -{ - Gwn_ShaderInput* input = malloc(sizeof(Gwn_ShaderInput)); - - input->location = glGetUniformLocation(shaderface->program, name); - - uint name_len = strlen(name); - shaderface->name_buffer = realloc(shaderface->name_buffer, shaderface->name_buffer_offset + name_len + 1); /* include NULL terminator */ - char* name_buffer = shaderface->name_buffer + shaderface->name_buffer_offset; - strcpy(name_buffer, name); - - set_input_name(shaderface, input, name, name_len); - setup_builtin_uniform(input, name); - - shader_input_to_bucket(input, shaderface->uniform_buckets); - if (input->builtin_type != GWN_UNIFORM_NONE && - input->builtin_type != GWN_UNIFORM_CUSTOM) - { - shaderface->builtin_uniforms[input->builtin_type] = input; - } -#if DEBUG_SHADER_INTERFACE - printf("Gwn_ShaderInterface %p, program %d, uniform[] '%s' at location %d\n", shaderface, - shaderface->program, - name, - input->location); -#endif - return input; -} - -Gwn_ShaderInterface* GWN_shaderinterface_create(int32_t program) -{ - Gwn_ShaderInterface* shaderface = calloc(1, sizeof(Gwn_ShaderInterface)); - shaderface->program = program; - -#if DEBUG_SHADER_INTERFACE - printf("%s {\n", __func__); /* enter function */ - printf("Gwn_ShaderInterface %p, program %d\n", shaderface, program); -#endif - - GLint max_attrib_name_len, attr_len; - glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attrib_name_len); - glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attr_len); - - GLint max_ubo_name_len, ubo_len; - glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len); - glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len); - - const uint32_t name_buffer_len = attr_len * max_attrib_name_len + ubo_len * max_ubo_name_len; - shaderface->name_buffer = malloc(name_buffer_len); - - /* Attributes */ - for (uint32_t i = 0; i < attr_len; ++i) { - Gwn_ShaderInput* input = malloc(sizeof(Gwn_ShaderInput)); - GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset; - char* name = shaderface->name_buffer + shaderface->name_buffer_offset; - GLsizei name_len = 0; - - glGetActiveAttrib(program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name); - - /* remove "[0]" from array name */ - if (name[name_len-1] == ']') { - name[name_len-3] = '\0'; - name_len -= 3; - } - - /* TODO: reject DOUBLE gl_types */ - - input->location = glGetAttribLocation(program, name); - - set_input_name(shaderface, input, name, name_len); - - shader_input_to_bucket(input, shaderface->attrib_buckets); - -#if DEBUG_SHADER_INTERFACE - printf("attrib[%u] '%s' at location %d\n", i, name, input->location); -#endif - } - /* Uniform Blocks */ - for (uint32_t i = 0; i < ubo_len; ++i) { - Gwn_ShaderInput* input = malloc(sizeof(Gwn_ShaderInput)); - GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset; - char* name = shaderface->name_buffer + shaderface->name_buffer_offset; - GLsizei name_len = 0; - - glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name); - - input->location = i; - - set_input_name(shaderface, input, name, name_len); - - shader_input_to_bucket(input, shaderface->ubo_buckets); - -#if DEBUG_SHADER_INTERFACE - printf("ubo '%s' at location %d\n", name, input->location); -#endif - } - /* Builtin Uniforms */ - for (Gwn_UniformBuiltin u = GWN_UNIFORM_NONE + 1; u < GWN_UNIFORM_CUSTOM; ++u) { - const char* builtin_name = BuiltinUniform_name(u); - if (glGetUniformLocation(program, builtin_name) != -1) { - add_uniform((Gwn_ShaderInterface*)shaderface, builtin_name); - } - } - /* Batches ref buffer */ - shaderface->batches_len = GWN_SHADERINTERFACE_REF_ALLOC_COUNT; - shaderface->batches = calloc(shaderface->batches_len, sizeof(Gwn_Batch*)); - - return shaderface; -} - -void GWN_shaderinterface_discard(Gwn_ShaderInterface* shaderface) -{ - /* Free memory used by buckets and has entries. */ - buckets_free(shaderface->uniform_buckets); - buckets_free(shaderface->attrib_buckets); - buckets_free(shaderface->ubo_buckets); - /* Free memory used by name_buffer. */ - free(shaderface->name_buffer); - /* Remove this interface from all linked Batches vao cache. */ - for (int i = 0; i < shaderface->batches_len; ++i) { - if (shaderface->batches[i] != NULL) { - gwn_batch_remove_interface_ref(shaderface->batches[i], shaderface); - } - } - free(shaderface->batches); - /* Free memory used by shader interface by its self. */ - free(shaderface); -} - -const Gwn_ShaderInput* GWN_shaderinterface_uniform(const Gwn_ShaderInterface* shaderface, const char* name) -{ - /* TODO: Warn if we find a matching builtin, since these can be looked up much quicker. */ - const Gwn_ShaderInput* input = buckets_lookup(shaderface->uniform_buckets, shaderface->name_buffer, name); - /* If input is not found add it so it's found next time. */ - if (input == NULL) { - input = add_uniform((Gwn_ShaderInterface*)shaderface, name); - } - return (input->location != -1) ? input : NULL; -} - -const Gwn_ShaderInput* GWN_shaderinterface_uniform_builtin( - const Gwn_ShaderInterface* shaderface, Gwn_UniformBuiltin builtin) -{ -#if TRUST_NO_ONE - assert(builtin != GWN_UNIFORM_NONE); - assert(builtin != GWN_UNIFORM_CUSTOM); - assert(builtin != GWN_NUM_UNIFORMS); -#endif - return shaderface->builtin_uniforms[builtin]; -} - -const Gwn_ShaderInput* GWN_shaderinterface_ubo(const Gwn_ShaderInterface* shaderface, const char* name) -{ - return buckets_lookup(shaderface->ubo_buckets, shaderface->name_buffer, name); -} - -const Gwn_ShaderInput* GWN_shaderinterface_attr(const Gwn_ShaderInterface* shaderface, const char* name) -{ - return buckets_lookup(shaderface->attrib_buckets, shaderface->name_buffer, name); -} - -void GWN_shaderinterface_add_batch_ref(Gwn_ShaderInterface* shaderface, Gwn_Batch* batch) -{ - int i; /* find first unused slot */ - for (i = 0; i < shaderface->batches_len; ++i) { - if (shaderface->batches[i] == NULL) { - break; - } - } - if (i == shaderface->batches_len) { - /* Not enough place, realloc the array. */ - i = shaderface->batches_len; - shaderface->batches_len += GWN_SHADERINTERFACE_REF_ALLOC_COUNT; - shaderface->batches = realloc(shaderface->batches, sizeof(Gwn_Batch*) * shaderface->batches_len); - memset(shaderface->batches + i, 0, sizeof(Gwn_Batch*) * GWN_SHADERINTERFACE_REF_ALLOC_COUNT); - } - shaderface->batches[i] = batch; -} - -void GWN_shaderinterface_remove_batch_ref(Gwn_ShaderInterface* shaderface, Gwn_Batch* batch) -{ - for (int i = 0; i < shaderface->batches_len; ++i) { - if (shaderface->batches[i] == batch) { - shaderface->batches[i] = NULL; - break; /* cannot have duplicates */ - } - } -} diff --git a/intern/gawain/src/gwn_vertex_array_id.cpp b/intern/gawain/src/gwn_vertex_array_id.cpp deleted file mode 100644 index 04470bf6844..00000000000 --- a/intern/gawain/src/gwn_vertex_array_id.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation, Clément Foucault - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/gwn_vertex_array_id.cpp - * \ingroup gpu - * - * Manage GL vertex array IDs in a thread-safe way - * Use these instead of glGenBuffers & its friends - * - alloc must be called from a thread that is bound - * to the context that will be used for drawing with - * this vao. - * - free can be called from any thread - */ - -#include "gwn_batch_private.h" -#include "gwn_vertex_array_id.h" -#include "gwn_context.h" -#include -#include -#include -#include -#include - -#if TRUST_NO_ONE -#if 0 -extern "C" { -extern int BLI_thread_is_main(void); /* Blender-specific function */ -} - -static bool thread_is_main() { - /* "main" here means the GL context's thread */ - return BLI_thread_is_main(); -} -#endif -#endif - -struct Gwn_Context { - GLuint default_vao; - std::unordered_set batches; /* Batches that have VAOs from this context */ - std::vector orphaned_vertarray_ids; - std::mutex orphans_mutex; /* todo: try spinlock instead */ -#if TRUST_NO_ONE - pthread_t thread; /* Thread on which this context is active. */ - bool thread_is_used; - - Gwn_Context() { - thread_is_used = false; - } -#endif -}; - -#if defined(_MSC_VER) && (_MSC_VER == 1800) -#define thread_local __declspec(thread) -thread_local Gwn_Context* active_ctx = NULL; -#else -static thread_local Gwn_Context* active_ctx = NULL; -#endif - -static void clear_orphans(Gwn_Context* ctx) -{ - ctx->orphans_mutex.lock(); - if (!ctx->orphaned_vertarray_ids.empty()) { - uint orphan_len = (uint)ctx->orphaned_vertarray_ids.size(); - glDeleteVertexArrays(orphan_len, ctx->orphaned_vertarray_ids.data()); - ctx->orphaned_vertarray_ids.clear(); - } - ctx->orphans_mutex.unlock(); -} - -Gwn_Context* GWN_context_create(void) -{ -#if TRUST_NO_ONE - /* assert(thread_is_main()); */ -#endif - Gwn_Context* ctx = new Gwn_Context; - glGenVertexArrays(1, &ctx->default_vao); - GWN_context_active_set(ctx); - return ctx; -} - -/* to be called after GWN_context_active_set(ctx_to_destroy) */ -void GWN_context_discard(Gwn_Context* ctx) -{ -#if TRUST_NO_ONE - /* Make sure no other thread has locked it. */ - assert(ctx == active_ctx); - assert(pthread_equal(pthread_self(), ctx->thread)); - assert(ctx->orphaned_vertarray_ids.empty()); -#endif - /* delete remaining vaos */ - while (!ctx->batches.empty()) { - /* this removes the array entry */ - gwn_batch_vao_cache_clear(*ctx->batches.begin()); - } - glDeleteVertexArrays(1, &ctx->default_vao); - delete ctx; - active_ctx = NULL; -} - -/* ctx can be NULL */ -void GWN_context_active_set(Gwn_Context* ctx) -{ -#if TRUST_NO_ONE - if (active_ctx) { - active_ctx->thread_is_used = false; - } - /* Make sure no other context is already bound to this thread. */ - if (ctx) { - /* Make sure no other thread has locked it. */ - assert(ctx->thread_is_used == false); - ctx->thread = pthread_self(); - ctx->thread_is_used = true; - } -#endif - if (ctx) { - clear_orphans(ctx); - } - active_ctx = ctx; -} - -Gwn_Context* GWN_context_active_get(void) -{ - return active_ctx; -} - -GLuint GWN_vao_default(void) -{ -#if TRUST_NO_ONE - assert(active_ctx); /* need at least an active context */ - assert(pthread_equal(pthread_self(), active_ctx->thread)); /* context has been activated by another thread! */ -#endif - return active_ctx->default_vao; -} - -GLuint GWN_vao_alloc(void) -{ -#if TRUST_NO_ONE - assert(active_ctx); /* need at least an active context */ - assert(pthread_equal(pthread_self(), active_ctx->thread)); /* context has been activated by another thread! */ -#endif - clear_orphans(active_ctx); - - GLuint new_vao_id = 0; - glGenVertexArrays(1, &new_vao_id); - return new_vao_id; -} - -/* this can be called from multiple thread */ -void GWN_vao_free(GLuint vao_id, Gwn_Context* ctx) -{ -#if TRUST_NO_ONE - assert(ctx); -#endif - if (ctx == active_ctx) { - glDeleteVertexArrays(1, &vao_id); - } - else { - ctx->orphans_mutex.lock(); - ctx->orphaned_vertarray_ids.emplace_back(vao_id); - ctx->orphans_mutex.unlock(); - } -} - -void gwn_context_add_batch(Gwn_Context* ctx, Gwn_Batch* batch) -{ - ctx->batches.emplace(batch); -} - -void gwn_context_remove_batch(Gwn_Context* ctx, Gwn_Batch* batch) -{ - ctx->orphans_mutex.lock(); - ctx->batches.erase(batch); - ctx->orphans_mutex.unlock(); -} diff --git a/intern/gawain/src/gwn_vertex_buffer.c b/intern/gawain/src/gwn_vertex_buffer.c deleted file mode 100644 index c3440b25da2..00000000000 --- a/intern/gawain/src/gwn_vertex_buffer.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation, Clément Foucault - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/intern/gwn_vertex_buffer.c - * \ingroup gpu - * - * Gawain vertex buffer - */ - -#include "gwn_vertex_buffer.h" -#include "gwn_buffer_id.h" -#include "gwn_vertex_format_private.h" -#include -#include - -#define KEEP_SINGLE_COPY 1 - -static uint vbo_memory_usage; - -static GLenum convert_usage_type_to_gl(Gwn_UsageType type) -{ - static const GLenum table[] = { - [GWN_USAGE_STREAM] = GL_STREAM_DRAW, - [GWN_USAGE_STATIC] = GL_STATIC_DRAW, - [GWN_USAGE_DYNAMIC] = GL_DYNAMIC_DRAW - }; - return table[type]; -} - -Gwn_VertBuf* GWN_vertbuf_create(Gwn_UsageType usage) -{ - Gwn_VertBuf* verts = malloc(sizeof(Gwn_VertBuf)); - GWN_vertbuf_init(verts, usage); - return verts; -} - -Gwn_VertBuf* GWN_vertbuf_create_with_format_ex(const Gwn_VertFormat* format, Gwn_UsageType usage) -{ - Gwn_VertBuf* verts = GWN_vertbuf_create(usage); - GWN_vertformat_copy(&verts->format, format); - if (!format->packed) { - VertexFormat_pack(&verts->format); - } - return verts; - - /* this function might seem redundant, but there is potential for memory savings here... */ - /* TODO: implement those memory savings */ -} - -void GWN_vertbuf_init(Gwn_VertBuf* verts, Gwn_UsageType usage) -{ - memset(verts, 0, sizeof(Gwn_VertBuf)); - verts->usage = usage; - verts->dirty = true; -} - -void GWN_vertbuf_init_with_format_ex(Gwn_VertBuf* verts, const Gwn_VertFormat* format, Gwn_UsageType usage) -{ - GWN_vertbuf_init(verts, usage); - GWN_vertformat_copy(&verts->format, format); - if (!format->packed) { - VertexFormat_pack(&verts->format); - } -} - -void GWN_vertbuf_discard(Gwn_VertBuf* verts) -{ - if (verts->vbo_id) { - GWN_buf_id_free(verts->vbo_id); -#if VRAM_USAGE - vbo_memory_usage -= GWN_vertbuf_size_get(verts); -#endif - } - if (verts->data) { - free(verts->data); - } - free(verts); -} - -uint GWN_vertbuf_size_get(const Gwn_VertBuf* verts) -{ - return vertex_buffer_size(&verts->format, verts->vertex_len); -} - -/* create a new allocation, discarding any existing data */ -void GWN_vertbuf_data_alloc(Gwn_VertBuf* verts, uint v_len) -{ - Gwn_VertFormat* format = &verts->format; - if (!format->packed) { - VertexFormat_pack(format); - } -#if TRUST_NO_ONE - /* catch any unnecessary use */ - assert(verts->vertex_alloc != v_len || verts->data == NULL); -#endif - /* only create the buffer the 1st time */ - if (verts->vbo_id == 0) { - verts->vbo_id = GWN_buf_id_alloc(); - } - /* discard previous data if any */ - if (verts->data) { - free(verts->data); - } -#if VRAM_USAGE - uint new_size = vertex_buffer_size(&verts->format, v_len); - vbo_memory_usage += new_size - GWN_vertbuf_size_get(verts); -#endif - verts->dirty = true; - verts->vertex_len = verts->vertex_alloc = v_len; - verts->data = malloc(sizeof(GLubyte) * GWN_vertbuf_size_get(verts)); -} - -/* resize buffer keeping existing data */ -void GWN_vertbuf_data_resize(Gwn_VertBuf* verts, uint v_len) -{ -#if TRUST_NO_ONE - assert(verts->data != NULL); - assert(verts->vertex_alloc != v_len); -#endif - -#if VRAM_USAGE - uint new_size = vertex_buffer_size(&verts->format, v_len); - vbo_memory_usage += new_size - GWN_vertbuf_size_get(verts); -#endif - verts->dirty = true; - verts->vertex_len = verts->vertex_alloc = v_len; - verts->data = realloc(verts->data, sizeof(GLubyte) * GWN_vertbuf_size_get(verts)); -} - -/* Set vertex count but does not change allocation. - * Only this many verts will be uploaded to the GPU and rendered. - * This is usefull for streaming data. */ -void GWN_vertbuf_vertex_count_set(Gwn_VertBuf* verts, uint v_len) -{ -#if TRUST_NO_ONE - assert(verts->data != NULL); /* only for dynamic data */ - assert(v_len <= verts->vertex_alloc); -#endif - -#if VRAM_USAGE - uint new_size = vertex_buffer_size(&verts->format, v_len); - vbo_memory_usage += new_size - GWN_vertbuf_size_get(verts); -#endif - verts->vertex_len = v_len; -} - -void GWN_vertbuf_attr_set(Gwn_VertBuf* verts, uint a_idx, uint v_idx, const void* data) -{ - const Gwn_VertFormat* format = &verts->format; - const Gwn_VertAttr* a = format->attribs + a_idx; - -#if TRUST_NO_ONE - assert(a_idx < format->attr_len); - assert(v_idx < verts->vertex_alloc); - assert(verts->data != NULL); -#endif - verts->dirty = true; - memcpy((GLubyte*)verts->data + a->offset + v_idx * format->stride, data, a->sz); -} - -void GWN_vertbuf_attr_fill(Gwn_VertBuf* verts, uint a_idx, const void* data) -{ - const Gwn_VertFormat* format = &verts->format; - const Gwn_VertAttr* a = format->attribs + a_idx; - -#if TRUST_NO_ONE - assert(a_idx < format->attr_len); -#endif - const uint stride = a->sz; /* tightly packed input data */ - - GWN_vertbuf_attr_fill_stride(verts, a_idx, stride, data); -} - -void GWN_vertbuf_attr_fill_stride(Gwn_VertBuf* verts, uint a_idx, uint stride, const void* data) -{ - const Gwn_VertFormat* format = &verts->format; - const Gwn_VertAttr* a = format->attribs + a_idx; - -#if TRUST_NO_ONE - assert(a_idx < format->attr_len); - assert(verts->data != NULL); -#endif - verts->dirty = true; - const uint vertex_len = verts->vertex_len; - - if (format->attr_len == 1 && stride == format->stride) { - /* we can copy it all at once */ - memcpy(verts->data, data, vertex_len * a->sz); - } - else { - /* we must copy it per vertex */ - for (uint v = 0; v < vertex_len; ++v) { - memcpy((GLubyte*)verts->data + a->offset + v * format->stride, (const GLubyte*)data + v * stride, a->sz); - } - } -} - -void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf* verts, uint a_idx, Gwn_VertBufRaw *access) -{ - const Gwn_VertFormat* format = &verts->format; - const Gwn_VertAttr* a = format->attribs + a_idx; - -#if TRUST_NO_ONE - assert(a_idx < format->attr_len); - assert(verts->data != NULL); -#endif - - verts->dirty = true; - - access->size = a->sz; - access->stride = format->stride; - access->data = (GLubyte*)verts->data + a->offset; - access->data_init = access->data; -#if TRUST_NO_ONE - access->_data_end = access->data_init + (size_t)(verts->vertex_alloc * format->stride); -#endif -} - -static void VertBuffer_upload_data(Gwn_VertBuf* verts) -{ - uint buffer_sz = GWN_vertbuf_size_get(verts); - - /* orphan the vbo to avoid sync */ - glBufferData(GL_ARRAY_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage)); - /* upload data */ - glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_sz, verts->data); - - if (verts->usage == GWN_USAGE_STATIC) { - free(verts->data); - verts->data = NULL; - } - verts->dirty = false; -} - -void GWN_vertbuf_use(Gwn_VertBuf* verts) -{ - glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); - if (verts->dirty) { - VertBuffer_upload_data(verts); - } -} - -uint GWN_vertbuf_get_memory_usage(void) -{ - return vbo_memory_usage; -} diff --git a/intern/gawain/src/gwn_vertex_format.c b/intern/gawain/src/gwn_vertex_format.c deleted file mode 100644 index 41179ae21eb..00000000000 --- a/intern/gawain/src/gwn_vertex_format.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * 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 - * of the License, 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 by Mike Erwin. - * All rights reserved. - * - * Contributor(s): Blender Foundation, Clément Foucault - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/intern/gwn_vertex_format.c - * \ingroup gpu - * - * Gawain vertex format - */ - -#include "gwn_vertex_format.h" -#include "gwn_vertex_format_private.h" -#include -#include - -#define PACK_DEBUG 0 - -#if PACK_DEBUG - #include -#endif - -void GWN_vertformat_clear(Gwn_VertFormat* format) -{ -#if TRUST_NO_ONE - memset(format, 0, sizeof(Gwn_VertFormat)); -#else - format->attr_len = 0; - format->packed = false; - format->name_offset = 0; - format->name_len = 0; - - for (unsigned i = 0; i < GWN_VERT_ATTR_MAX_LEN; i++) { - format->attribs[i].name_len = 0; - } -#endif -} - -void GWN_vertformat_copy(Gwn_VertFormat* dest, const Gwn_VertFormat* src) -{ - /* copy regular struct fields */ - memcpy(dest, src, sizeof(Gwn_VertFormat)); - - for (unsigned i = 0; i < dest->attr_len; i++) { - for (unsigned j = 0; j < dest->attribs[i].name_len; j++) { - dest->attribs[i].name[j] = (char *)dest + (src->attribs[i].name[j] - ((char *)src)); - } - } -} - -static GLenum convert_comp_type_to_gl(Gwn_VertCompType type) -{ - static const GLenum table[] = { - [GWN_COMP_I8] = GL_BYTE, - [GWN_COMP_U8] = GL_UNSIGNED_BYTE, - [GWN_COMP_I16] = GL_SHORT, - [GWN_COMP_U16] = GL_UNSIGNED_SHORT, - [GWN_COMP_I32] = GL_INT, - [GWN_COMP_U32] = GL_UNSIGNED_INT, - - [GWN_COMP_F32] = GL_FLOAT, - - [GWN_COMP_I10] = GL_INT_2_10_10_10_REV - }; - return table[type]; -} - -static unsigned comp_sz(Gwn_VertCompType type) -{ -#if TRUST_NO_ONE - assert(type <= GWN_COMP_F32); /* other types have irregular sizes (not bytes) */ -#endif - const GLubyte sizes[] = {1,1,2,2,4,4,4}; - return sizes[type]; -} - -static unsigned attrib_sz(const Gwn_VertAttr *a) -{ - if (a->comp_type == GWN_COMP_I10) { - return 4; /* always packed as 10_10_10_2 */ - } - return a->comp_len * comp_sz(a->comp_type); -} - -static unsigned attrib_align(const Gwn_VertAttr *a) -{ - if (a->comp_type == GWN_COMP_I10) { - return 4; /* always packed as 10_10_10_2 */ - } - unsigned c = comp_sz(a->comp_type); - if (a->comp_len == 3 && c <= 2) { - return 4 * c; /* AMD HW can't fetch these well, so pad it out (other vendors too?) */ - } - else { - return c; /* most fetches are ok if components are naturally aligned */ - } -} - -unsigned vertex_buffer_size(const Gwn_VertFormat* format, unsigned vertex_len) -{ -#if TRUST_NO_ONE - assert(format->packed && format->stride > 0); -#endif - return format->stride * vertex_len; -} - -static const char* copy_attrib_name(Gwn_VertFormat* format, const char* name) -{ - /* strncpy does 110% of what we need; let's do exactly 100% */ - char* name_copy = format->names + format->name_offset; - unsigned available = GWN_VERT_ATTR_NAMES_BUF_LEN - format->name_offset; - bool terminated = false; - - for (unsigned i = 0; i < available; ++i) { - const char c = name[i]; - name_copy[i] = c; - if (c == '\0') { - terminated = true; - format->name_offset += (i + 1); - break; - } - } -#if TRUST_NO_ONE - assert(terminated); - assert(format->name_offset <= GWN_VERT_ATTR_NAMES_BUF_LEN); -#else - (void)terminated; -#endif - return name_copy; -} - -unsigned GWN_vertformat_attr_add(Gwn_VertFormat* format, const char* name, Gwn_VertCompType comp_type, unsigned comp_len, Gwn_VertFetchMode fetch_mode) -{ -#if TRUST_NO_ONE - assert(format->name_len < GWN_VERT_ATTR_MAX_LEN); /* there's room for more */ - assert(format->attr_len < GWN_VERT_ATTR_MAX_LEN); /* there's room for more */ - assert(!format->packed); /* packed means frozen/locked */ - assert((comp_len >= 1 && comp_len <= 4) || comp_len == 8 || comp_len == 12 || comp_len == 16); - - switch (comp_type) { - case GWN_COMP_F32: - /* float type can only kept as float */ - assert(fetch_mode == GWN_FETCH_FLOAT); - break; - case GWN_COMP_I10: - /* 10_10_10 format intended for normals (xyz) or colors (rgb) - * extra component packed.w can be manually set to { -2, -1, 0, 1 } */ - assert(comp_len == 3 || comp_len == 4); - assert(fetch_mode == GWN_FETCH_INT_TO_FLOAT_UNIT); /* not strictly required, may relax later */ - break; - default: - /* integer types can be kept as int or converted/normalized to float */ - assert(fetch_mode != GWN_FETCH_FLOAT); - /* only support float matrices (see Batch_update_program_bindings) */ - assert(comp_len != 8 && comp_len != 12 && comp_len != 16); - } -#endif - format->name_len++; /* multiname support */ - - const unsigned attrib_id = format->attr_len++; - Gwn_VertAttr* attrib = format->attribs + attrib_id; - - attrib->name[attrib->name_len++] = copy_attrib_name(format, name); - attrib->comp_type = comp_type; - attrib->gl_comp_type = convert_comp_type_to_gl(comp_type); - attrib->comp_len = (comp_type == GWN_COMP_I10) ? 4 : comp_len; /* system needs 10_10_10_2 to be 4 or BGRA */ - attrib->sz = attrib_sz(attrib); - attrib->offset = 0; /* offsets & stride are calculated later (during pack) */ - attrib->fetch_mode = fetch_mode; - - return attrib_id; -} - -void GWN_vertformat_alias_add(Gwn_VertFormat* format, const char* alias) -{ - Gwn_VertAttr* attrib = format->attribs + (format->attr_len - 1); -#if TRUST_NO_ONE - assert(format->name_len < GWN_VERT_ATTR_MAX_LEN); /* there's room for more */ - assert(attrib->name_len < GWN_VERT_ATTR_MAX_NAMES); -#endif - format->name_len++; /* multiname support */ - attrib->name[attrib->name_len++] = copy_attrib_name(format, alias); -} - -unsigned padding(unsigned offset, unsigned alignment) -{ - const unsigned mod = offset % alignment; - return (mod == 0) ? 0 : (alignment - mod); -} - -#if PACK_DEBUG -static void show_pack(unsigned a_idx, unsigned sz, unsigned pad) -{ - const char c = 'A' + a_idx; - for (unsigned i = 0; i < pad; ++i) { - putchar('-'); - } - for (unsigned i = 0; i < sz; ++i) { - putchar(c); - } -} -#endif - -void VertexFormat_pack(Gwn_VertFormat* format) -{ - /* For now, attributes are packed in the order they were added, - * making sure each attrib is naturally aligned (add padding where necessary) - * Later we can implement more efficient packing w/ reordering - * (keep attrib ID order, adjust their offsets to reorder in buffer). */ - - /* TODO: realloc just enough to hold the final combo string. And just enough to - * hold used attribs, not all 16. */ - - Gwn_VertAttr* a0 = format->attribs + 0; - a0->offset = 0; - unsigned offset = a0->sz; - -#if PACK_DEBUG - show_pack(0, a0->sz, 0); -#endif - - for (unsigned a_idx = 1; a_idx < format->attr_len; ++a_idx) { - Gwn_VertAttr* a = format->attribs + a_idx; - unsigned mid_padding = padding(offset, attrib_align(a)); - offset += mid_padding; - a->offset = offset; - offset += a->sz; - -#if PACK_DEBUG - show_pack(a_idx, a->sz, mid_padding); -#endif - } - - unsigned end_padding = padding(offset, attrib_align(a0)); - -#if PACK_DEBUG - show_pack(0, 0, end_padding); - putchar('\n'); -#endif - format->stride = offset + end_padding; - format->packed = true; -} - - -/* OpenGL ES packs in a different order as desktop GL but component conversion is the same. - * Of the code here, only struct Gwn_PackedNormal needs to change. */ - -#define SIGNED_INT_10_MAX 511 -#define SIGNED_INT_10_MIN -512 - -static int clampi(int x, int min_allowed, int max_allowed) -{ -#if TRUST_NO_ONE - assert(min_allowed <= max_allowed); -#endif - if (x < min_allowed) { - return min_allowed; - } - else if (x > max_allowed) { - return max_allowed; - } - else { - return x; - } -} - -static int quantize(float x) -{ - int qx = x * 511.0f; - return clampi(qx, SIGNED_INT_10_MIN, SIGNED_INT_10_MAX); -} - -static int convert_i16(short x) -{ - /* 16-bit signed --> 10-bit signed */ - /* TODO: round? */ - return x >> 6; -} - -Gwn_PackedNormal GWN_normal_convert_i10_v3(const float data[3]) -{ - Gwn_PackedNormal n = { .x = quantize(data[0]), .y = quantize(data[1]), .z = quantize(data[2]) }; - return n; -} - -Gwn_PackedNormal GWN_normal_convert_i10_s3(const short data[3]) -{ - Gwn_PackedNormal n = { .x = convert_i16(data[0]), .y = convert_i16(data[1]), .z = convert_i16(data[2]) }; - return n; -} diff --git a/intern/opencolorio/CMakeLists.txt b/intern/opencolorio/CMakeLists.txt index 2611477252a..10898e4239b 100644 --- a/intern/opencolorio/CMakeLists.txt +++ b/intern/opencolorio/CMakeLists.txt @@ -27,8 +27,8 @@ set(INC . ../glew-mx ../guardedalloc - ../gawain ../../source/blender/blenlib + ../../source/blender/gpu ) set(INC_SYS diff --git a/intern/opencolorio/ocio_impl_glsl.cc b/intern/opencolorio/ocio_impl_glsl.cc index 090422ff795..10acdb9d281 100644 --- a/intern/opencolorio/ocio_impl_glsl.cc +++ b/intern/opencolorio/ocio_impl_glsl.cc @@ -49,7 +49,7 @@ #endif extern "C" { -#include "gawain/gwn_immediate.h" +#include "GPU_immediate.h" } using namespace OCIO_NAMESPACE; diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 999773d0212..03bf7fa67d8 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -31,7 +31,7 @@ #ifndef __BLF_INTERNAL_TYPES_H__ #define __BLF_INTERNAL_TYPES_H__ -#include "../../../intern/gawain/gawain/gwn_vertex_buffer.h" +#include "GPU_vertex_buffer.h" #include "GPU_texture.h" #define BLF_BATCH_DRAW_LEN_MAX 2048 /* in glyph */ diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index bf3ee34a03e..a6d11f1edac 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -45,7 +45,7 @@ #include "eevee_lightcache.h" #include "eevee_private.h" -#include "../../../intern/gawain/gawain/gwn_context.h" +#include "GPU_context.h" #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 58ce9dd5218..4c6f8962d82 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -82,7 +82,7 @@ #include "engines/workbench/workbench_engine.h" #include "engines/external/external_engine.h" -#include "../../../intern/gawain/gawain/gwn_context.h" +#include "GPU_context.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index d25e372c26e..2d44fb5b6d8 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -35,6 +35,7 @@ #include "BLI_threads.h" #include "GPU_batch.h" +#include "GPU_context.h" #include "GPU_framebuffer.h" #include "GPU_shader.h" #include "GPU_uniformbuffer.h" diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 716e00164ce..3d207b85760 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -50,7 +50,6 @@ set(INC ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/smoke/extern - ../../../intern/gawain ) set(INC_SYS @@ -58,14 +57,17 @@ set(INC_SYS ) set(SRC + intern/gpu_attr_binding.c intern/gpu_basic_shader.c intern/gpu_batch.c intern/gpu_batch_presets.c intern/gpu_batch_utils.c + intern/gpu_buffer_id.cpp intern/gpu_buffers.c intern/gpu_codegen.c intern/gpu_debug.c intern/gpu_draw.c + intern/gpu_element.c intern/gpu_extensions.c intern/gpu_framebuffer.c intern/gpu_immediate.c @@ -73,13 +75,18 @@ set(SRC intern/gpu_init_exit.c intern/gpu_material.c intern/gpu_matrix.c + intern/gpu_primitive.c intern/gpu_select.c intern/gpu_select_pick.c intern/gpu_select_sample_query.c intern/gpu_shader.c + intern/gpu_shader_interface.c intern/gpu_state.c intern/gpu_texture.c intern/gpu_uniformbuffer.c + intern/gpu_vertex_array_id.cpp + intern/gpu_vertex_buffer.c + intern/gpu_vertex_format.c intern/gpu_viewport.c shaders/gpu_shader_fx_lib.glsl @@ -103,11 +110,15 @@ set(SRC shaders/gpu_shader_smoke_frag.glsl shaders/gpu_shader_smoke_vert.glsl + GPU_attr_binding.h GPU_basic_shader.h GPU_batch.h + GPU_buffer_id.h GPU_buffers.h + GPU_common.h GPU_debug.h GPU_draw.h + GPU_element.h GPU_extensions.h GPU_framebuffer.h GPU_glew.h @@ -117,17 +128,26 @@ set(SRC GPU_legacy_stubs.h GPU_material.h GPU_matrix.h + GPU_primitive.h GPU_select.h GPU_shader.h + GPU_shader_interface.h GPU_state.h GPU_texture.h GPU_uniformbuffer.h + GPU_vertex_array_id.h + GPU_vertex_buffer.h + GPU_vertex_format.h GPU_viewport.h + intern/gpu_attr_binding_private.h + intern/gpu_batch_private.h intern/gpu_codegen.h + intern/gpu_primitive_private.h intern/gpu_private.h intern/gpu_select_private.h intern/gpu_shader_private.h + intern/gpu_vertex_format_private.h ) data_to_c_simple(shaders/gpu_shader_depth_only_frag.glsl SRC) diff --git a/source/blender/gpu/GPU_attr_binding.h b/source/blender/gpu/GPU_attr_binding.h new file mode 100644 index 00000000000..41050a095cd --- /dev/null +++ b/source/blender/gpu/GPU_attr_binding.h @@ -0,0 +1,42 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_attr_binding.h + * \ingroup gpu + * + * Gawain vertex attribute binding + */ + +#ifndef __GWN_ATTR_BINDING_H__ +#define __GWN_ATTR_BINDING_H__ + +#include "GPU_common.h" + +typedef struct Gwn_AttrBinding { + uint64_t loc_bits; /* store 4 bits for each of the 16 attribs */ + uint16_t enabled_bits; /* 1 bit for each attrib */ +} Gwn_AttrBinding; + +#endif /* __GWN_ATTR_BINDING_H__ */ diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h index f73968eda54..4c98eb8f537 100644 --- a/source/blender/gpu/GPU_batch.h +++ b/source/blender/gpu/GPU_batch.h @@ -15,37 +15,185 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2016 Blender Foundation. + * The Original Code is Copyright (C) 2016 by Mike Erwin. * All rights reserved. * - * - * Contributor(s): Mike Erwin + * Contributor(s): Blender Foundation * * ***** END GPL LICENSE BLOCK ***** */ -/* Batched geometry rendering is powered by the Gawain library. - * This file contains any additions or modifications specific to Blender. +/** \file blender/gpu/gwn_batch.h + * \ingroup gpu + * + * Gawain geometry batch + * Contains VAOs + VBOs + Shader representing a drawable entity. */ -#ifndef __GPU_BATCH_H__ -#define __GPU_BATCH_H__ +#ifndef __GWN_BATCH_H__ +#define __GWN_BATCH_H__ -#include "../../../intern/gawain/gawain/gwn_batch.h" -#include "../../../intern/gawain/gawain/gwn_batch_private.h" +#include "GPU_vertex_buffer.h" +#include "GPU_element.h" +#include "GPU_shader_interface.h" +#include "GPU_shader.h" -// TODO: CMake magic to do this: -// #include "gawain/batch.h" +typedef enum { + GWN_BATCH_READY_TO_FORMAT, + GWN_BATCH_READY_TO_BUILD, + GWN_BATCH_BUILDING, + GWN_BATCH_READY_TO_DRAW +} Gwn_BatchPhase; -#include "BLI_compiler_attrs.h" -#include "BLI_sys_types.h" +#define GWN_BATCH_VBO_MAX_LEN 3 +#define GWN_BATCH_VAO_STATIC_LEN 3 +#define GWN_BATCH_VAO_DYN_ALLOC_COUNT 16 -#include "GPU_shader.h" +typedef struct Gwn_Batch { + /* geometry */ + Gwn_VertBuf* verts[GWN_BATCH_VBO_MAX_LEN]; /* verts[0] is required, others can be NULL */ + Gwn_VertBuf* inst; /* instance attribs */ + Gwn_IndexBuf* elem; /* NULL if element list not needed */ + uint32_t gl_prim_type; + + /* cached values (avoid dereferencing later) */ + uint32_t vao_id; + uint32_t program; + const struct Gwn_ShaderInterface* interface; + + /* book-keeping */ + uint owns_flag; + struct Gwn_Context *context; /* used to free all vaos. this implies all vaos were created under the same context. */ + Gwn_BatchPhase phase; + bool program_in_use; + + /* Vao management: remembers all geometry state (vertex attrib bindings & element buffer) + * for each shader interface. Start with a static number of vaos and fallback to dynamic count + * if necessary. Once a batch goes dynamic it does not go back. */ + bool is_dynamic_vao_count; + union { + /* Static handle count */ + struct { + const struct Gwn_ShaderInterface* interfaces[GWN_BATCH_VAO_STATIC_LEN]; + uint32_t vao_ids[GWN_BATCH_VAO_STATIC_LEN]; + } static_vaos; + /* Dynamic handle count */ + struct { + uint count; + const struct Gwn_ShaderInterface** interfaces; + uint32_t* vao_ids; + } dynamic_vaos; + }; + + /* XXX This is the only solution if we want to have some data structure using + * batches as key to identify nodes. We must destroy these nodes with this callback. */ + void (*free_callback)(struct Gwn_Batch*, void*); + void* callback_data; +} Gwn_Batch; + +enum { + GWN_BATCH_OWNS_VBO = (1 << 0), + /* each vbo index gets bit-shifted */ + GWN_BATCH_OWNS_INSTANCES = (1 << 30), + GWN_BATCH_OWNS_INDEX = (1 << 31), +}; + +Gwn_Batch* GWN_batch_create_ex(Gwn_PrimType, Gwn_VertBuf*, Gwn_IndexBuf*, uint owns_flag); +void GWN_batch_init_ex(Gwn_Batch*, Gwn_PrimType, Gwn_VertBuf*, Gwn_IndexBuf*, uint owns_flag); +Gwn_Batch* GWN_batch_duplicate(Gwn_Batch* batch_src); + +#define GWN_batch_create(prim, verts, elem) \ + GWN_batch_create_ex(prim, verts, elem, 0) +#define GWN_batch_init(batch, prim, verts, elem) \ + GWN_batch_init_ex(batch, prim, verts, elem, 0) + +void GWN_batch_discard(Gwn_Batch*); /* verts & elem are not discarded */ + +void gwn_batch_vao_cache_clear(Gwn_Batch*); + +void GWN_batch_callback_free_set(Gwn_Batch*, void (*callback)(Gwn_Batch*, void*), void*); + +void GWN_batch_instbuf_set(Gwn_Batch*, Gwn_VertBuf*, bool own_vbo); /* Instancing */ + +int GWN_batch_vertbuf_add_ex(Gwn_Batch*, Gwn_VertBuf*, bool own_vbo); + +#define GWN_batch_vertbuf_add(batch, verts) \ + GWN_batch_vertbuf_add_ex(batch, verts, false) -/* gpu_batch.c */ -void GWN_batch_program_set_builtin(Gwn_Batch *batch, GPUBuiltinShader shader_id) ATTR_NONNULL(1); +void GWN_batch_program_set_no_use(Gwn_Batch*, uint32_t program, const Gwn_ShaderInterface*); +void GWN_batch_program_set(Gwn_Batch*, uint32_t program, const Gwn_ShaderInterface*); +void GWN_batch_program_set_builtin(Gwn_Batch *batch, GPUBuiltinShader shader_id); +/* Entire batch draws with one shader program, but can be redrawn later with another program. */ +/* Vertex shader's inputs must be compatible with the batch's vertex format. */ + +void GWN_batch_program_use_begin(Gwn_Batch*); /* call before Batch_Uniform (temp hack?) */ +void GWN_batch_program_use_end(Gwn_Batch*); + +void GWN_batch_uniform_1ui(Gwn_Batch*, const char* name, int value); +void GWN_batch_uniform_1i(Gwn_Batch*, const char* name, int value); +void GWN_batch_uniform_1b(Gwn_Batch*, const char* name, bool value); +void GWN_batch_uniform_1f(Gwn_Batch*, const char* name, float value); +void GWN_batch_uniform_2f(Gwn_Batch*, const char* name, float x, float y); +void GWN_batch_uniform_3f(Gwn_Batch*, const char* name, float x, float y, float z); +void GWN_batch_uniform_4f(Gwn_Batch*, const char* name, float x, float y, float z, float w); +void GWN_batch_uniform_2fv(Gwn_Batch*, const char* name, const float data[2]); +void GWN_batch_uniform_3fv(Gwn_Batch*, const char* name, const float data[3]); +void GWN_batch_uniform_4fv(Gwn_Batch*, const char* name, const float data[4]); +void GWN_batch_uniform_2fv_array(Gwn_Batch*, const char* name, int len, const float *data); +void GWN_batch_uniform_4fv_array(Gwn_Batch*, const char* name, int len, const float *data); +void GWN_batch_uniform_mat4(Gwn_Batch*, const char* name, const float data[4][4]); + +void GWN_batch_draw(Gwn_Batch*); + +/* This does not bind/unbind shader and does not call GPU_matrix_bind() */ +void GWN_batch_draw_range_ex(Gwn_Batch*, int v_first, int v_count, bool force_instance); + +/* Does not even need batch */ +void GWN_draw_primitive(Gwn_PrimType, int v_count); + +#if 0 /* future plans */ + +/* Can multiple batches share a Gwn_VertBuf? Use ref count? */ + + +/* We often need a batch with its own data, to be created and discarded together. */ +/* WithOwn variants reduce number of system allocations. */ + +typedef struct BatchWithOwnVertexBuffer { + Gwn_Batch batch; + Gwn_VertBuf verts; /* link batch.verts to this */ +} BatchWithOwnVertexBuffer; + +typedef struct BatchWithOwnElementList { + Gwn_Batch batch; + Gwn_IndexBuf elem; /* link batch.elem to this */ +} BatchWithOwnElementList; + +typedef struct BatchWithOwnVertexBufferAndElementList { + Gwn_Batch batch; + Gwn_IndexBuf elem; /* link batch.elem to this */ + Gwn_VertBuf verts; /* link batch.verts to this */ +} BatchWithOwnVertexBufferAndElementList; + +Gwn_Batch* create_BatchWithOwnVertexBuffer(Gwn_PrimType, Gwn_VertFormat*, uint v_len, Gwn_IndexBuf*); +Gwn_Batch* create_BatchWithOwnElementList(Gwn_PrimType, Gwn_VertBuf*, uint prim_len); +Gwn_Batch* create_BatchWithOwnVertexBufferAndElementList(Gwn_PrimType, Gwn_VertFormat*, uint v_len, uint prim_len); +/* verts: shared, own */ +/* elem: none, shared, own */ +Gwn_Batch* create_BatchInGeneral(Gwn_PrimType, VertexBufferStuff, ElementListStuff); + +#endif /* future plans */ void gpu_batch_init(void); void gpu_batch_exit(void); -#endif /* __GPU_BATCH_H__ */ +/* Macros */ + +#define GWN_BATCH_DISCARD_SAFE(batch) do { \ + if (batch != NULL) { \ + GWN_batch_discard(batch); \ + batch = NULL; \ + } \ +} while (0) + +#endif /* __GWN_BATCH_H__ */ diff --git a/source/blender/gpu/GPU_buffer_id.h b/source/blender/gpu/GPU_buffer_id.h new file mode 100644 index 00000000000..fd680ff31f5 --- /dev/null +++ b/source/blender/gpu/GPU_buffer_id.h @@ -0,0 +1,53 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_buffer_id.h + * \ingroup gpu + * + * Gawain buffer IDs + */ + +#ifndef __GWN_BUFFER_ID_H__ +#define __GWN_BUFFER_ID_H__ + +/* Manage GL buffer IDs in a thread-safe way + * Use these instead of glGenBuffers & its friends + * - alloc must be called from main thread + * - free can be called from any thread */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "GPU_common.h" + +GLuint GWN_buf_id_alloc(void); +void GWN_buf_id_free(GLuint buffer_id); + +#ifdef __cplusplus +} +#endif + +#endif /* __GWN_BUFFER_ID_H__ */ diff --git a/source/blender/gpu/GPU_common.h b/source/blender/gpu/GPU_common.h new file mode 100644 index 00000000000..2587e8670a9 --- /dev/null +++ b/source/blender/gpu/GPU_common.h @@ -0,0 +1,61 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_common.h + * \ingroup gpu + */ + +#ifndef __GWN_COMMON_H__ +#define __GWN_COMMON_H__ + +#define PROGRAM_NO_OPTI 0 + +#if defined(NDEBUG) + #define TRUST_NO_ONE 0 +#else + /* strict error checking, enabled for debug builds during early development */ + #define TRUST_NO_ONE 1 +#endif + +#if defined(WITH_OPENGL) + #include +#endif + +#include +#include +#include + +#if TRUST_NO_ONE + #include +#endif + +/* GWN_INLINE */ +#if defined(_MSC_VER) +# define GWN_INLINE static __forceinline +#else +# define GWN_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__)) +#endif + +#endif /* __GWN_COMMON_H__ */ diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h new file mode 100644 index 00000000000..0cedc109645 --- /dev/null +++ b/source/blender/gpu/GPU_context.h @@ -0,0 +1,55 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_context.h + * \ingroup gpu + * + * This interface allow Gawain to manage VAOs for mutiple context and threads. + */ + +#ifndef __GWN_CONTEXT_H__ +#define __GWN_CONTEXT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "GPU_common.h" +#include "GPU_batch.h" +#include "GPU_shader_interface.h" + +typedef struct Gwn_Context Gwn_Context; + +Gwn_Context* GWN_context_create(void); +void GWN_context_discard(Gwn_Context*); + +void GWN_context_active_set(Gwn_Context*); +Gwn_Context* GWN_context_active_get(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __GWN_CONTEXT_H__ */ diff --git a/source/blender/gpu/GPU_element.h b/source/blender/gpu/GPU_element.h new file mode 100644 index 00000000000..0c23e90569b --- /dev/null +++ b/source/blender/gpu/GPU_element.h @@ -0,0 +1,102 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_element.h + * \ingroup gpu + * + * Gawain element list (AKA index buffer) + */ + +#ifndef __GWN_ELEMENT_H__ +#define __GWN_ELEMENT_H__ + +#include "GPU_primitive.h" + +#define GWN_TRACK_INDEX_RANGE 1 + +#define GWN_PRIM_RESTART 0xFFFFFFFF + +typedef enum { + GWN_INDEX_U8, /* GL has this, Vulkan does not */ + GWN_INDEX_U16, + GWN_INDEX_U32 +} Gwn_IndexBufType; + +typedef struct Gwn_IndexBuf { + uint index_len; +#if GWN_TRACK_INDEX_RANGE + Gwn_IndexBufType index_type; + uint32_t gl_index_type; + uint min_index; + uint max_index; + uint base_index; +#endif + uint32_t vbo_id; /* 0 indicates not yet sent to VRAM */ + bool use_prim_restart; +} Gwn_IndexBuf; + +void GWN_indexbuf_use(Gwn_IndexBuf*); +uint GWN_indexbuf_size_get(const Gwn_IndexBuf*); + +typedef struct Gwn_IndexBufBuilder { + uint max_allowed_index; + uint max_index_len; + uint index_len; + Gwn_PrimType prim_type; + uint* data; + bool use_prim_restart; +} Gwn_IndexBufBuilder; + + +/* supports all primitive types. */ +void GWN_indexbuf_init_ex(Gwn_IndexBufBuilder*, Gwn_PrimType, uint index_len, uint vertex_len, bool use_prim_restart); + +/* supports only GWN_PRIM_POINTS, GWN_PRIM_LINES and GWN_PRIM_TRIS. */ +void GWN_indexbuf_init(Gwn_IndexBufBuilder*, Gwn_PrimType, uint prim_len, uint vertex_len); + +void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder*, uint v); +void GWN_indexbuf_add_primitive_restart(Gwn_IndexBufBuilder*); + +void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder*, uint v); +void GWN_indexbuf_add_line_verts(Gwn_IndexBufBuilder*, uint v1, uint v2); +void GWN_indexbuf_add_tri_verts(Gwn_IndexBufBuilder*, uint v1, uint v2, uint v3); +void GWN_indexbuf_add_line_adj_verts(Gwn_IndexBufBuilder*, uint v1, uint v2, uint v3, uint v4); + +Gwn_IndexBuf* GWN_indexbuf_build(Gwn_IndexBufBuilder*); +void GWN_indexbuf_build_in_place(Gwn_IndexBufBuilder*, Gwn_IndexBuf*); + +void GWN_indexbuf_discard(Gwn_IndexBuf*); + + +/* Macros */ + +#define GWN_INDEXBUF_DISCARD_SAFE(elem) do { \ + if (elem != NULL) { \ + GWN_indexbuf_discard(elem); \ + elem = NULL; \ + } \ +} while (0) + +#endif /* __GWN_ELEMENT_H__ */ diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h index 2a2692e6baf..c5892886825 100644 --- a/source/blender/gpu/GPU_immediate.h +++ b/source/blender/gpu/GPU_immediate.h @@ -24,29 +24,113 @@ * ***** END GPL LICENSE BLOCK ***** */ -/* Immediate mode rendering is powered by the Gawain library. - * This file contains any additions or modifications specific to Blender. +/** \file blender/gpu/GPU_immediate.h + * \ingroup gpu + * + * Gawain immediate mode work-alike */ #ifndef __GPU_IMMEDIATE_H__ #define __GPU_IMMEDIATE_H__ -#include "../../../intern/gawain/gawain/gwn_immediate.h" -#include "../../../intern/gawain/gawain/gwn_imm_util.h" +#include "GPU_vertex_format.h" +#include "GPU_primitive.h" +#include "GPU_shader_interface.h" +#include "GPU_batch.h" +#include "GPU_immediate_util.h" +#include "GPU_shader.h" -// TODO: CMake magic to do this: -// #include "gawain/gwn_immediate.h" -// #include "gawain/gwn_imm_util.h" +Gwn_VertFormat* immVertexFormat(void); /* returns a cleared vertex format, ready for add_attrib. */ -#include "GPU_shader.h" +void immBindProgram(uint32_t program, const Gwn_ShaderInterface*); /* every immBegin must have a program bound first. */ +void immUnbindProgram(void); /* call after your last immEnd, or before binding another program. */ + +void immBegin(Gwn_PrimType, uint vertex_len); /* must supply exactly vertex_len vertices. */ +void immBeginAtMost(Gwn_PrimType, uint max_vertex_len); /* can supply fewer vertices. */ +void immEnd(void); /* finishes and draws. */ + +/* ImmBegin a batch, then use standard immFunctions as usual. */ +/* ImmEnd will finalize the batch instead of drawing. */ +/* Then you can draw it as many times as you like! Partially replaces the need for display lists. */ +Gwn_Batch* immBeginBatch(Gwn_PrimType, uint vertex_len); +Gwn_Batch* immBeginBatchAtMost(Gwn_PrimType, uint vertex_len); + +/* Provide attribute values that can change per vertex. */ +/* First vertex after immBegin must have all its attributes specified. */ +/* Skipped attributes will continue using the previous value for that attrib_id. */ +void immAttrib1f(uint attrib_id, float x); +void immAttrib2f(uint attrib_id, float x, float y); +void immAttrib3f(uint attrib_id, float x, float y, float z); +void immAttrib4f(uint attrib_id, float x, float y, float z, float w); + +void immAttrib2i(uint attrib_id, int x, int y); + +void immAttrib1u(uint attrib_id, uint x); + +void immAttrib2s(uint attrib_id, short x, short y); + +void immAttrib2fv(uint attrib_id, const float data[2]); +void immAttrib3fv(uint attrib_id, const float data[3]); +void immAttrib4fv(uint attrib_id, const float data[4]); + +void immAttrib3ub(uint attrib_id, unsigned char r, unsigned char g, unsigned char b); +void immAttrib4ub(uint attrib_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +void immAttrib3ubv(uint attrib_id, const unsigned char data[4]); +void immAttrib4ubv(uint attrib_id, const unsigned char data[4]); + +/* Explicitly skip an attribute. */ +/* This advanced option kills automatic value copying for this attrib_id. */ +void immSkipAttrib(uint attrib_id); + +/* Provide one last attribute value & end the current vertex. */ +/* This is most often used for 2D or 3D position (similar to glVertex). */ +void immVertex2f(uint attrib_id, float x, float y); +void immVertex3f(uint attrib_id, float x, float y, float z); +void immVertex4f(uint attrib_id, float x, float y, float z, float w); + +void immVertex2i(uint attrib_id, int x, int y); + +void immVertex2s(uint attrib_id, short x, short y); + +void immVertex2fv(uint attrib_id, const float data[2]); +void immVertex3fv(uint attrib_id, const float data[3]); + +void immVertex2iv(uint attrib_id, const int data[2]); + +/* Provide uniform values that don't change for the entire draw call. */ +void immUniform1i(const char* name, int x); +void immUniform4iv(const char* name, const int data[4]); +void immUniform1f(const char* name, float x); +void immUniform2f(const char* name, float x, float y); +void immUniform2fv(const char* name, const float data[2]); +void immUniform3f(const char* name, float x, float y, float z); +void immUniform3fv(const char* name, const float data[3]); +void immUniformArray3fv(const char* name, const float *data, int count); +void immUniform4f(const char* name, float x, float y, float z, float w); +void immUniform4fv(const char* name, const float data[4]); +void immUniformArray4fv(const char* bare_name, const float *data, int count); +void immUniformMatrix4fv(const char* name, const float data[4][4]); + +/* Convenience functions for setting "uniform vec4 color". */ +/* The rgb functions have implicit alpha = 1.0. */ +void immUniformColor4f(float r, float g, float b, float a); +void immUniformColor4fv(const float rgba[4]); +void immUniformColor3f(float r, float g, float b); +void immUniformColor3fv(const float rgb[3]); +void immUniformColor3fvAlpha(const float rgb[3], float a); + +void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b); +void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); +void immUniformColor3ubv(const unsigned char rgb[3]); +void immUniformColor3ubvAlpha(const unsigned char rgb[3], unsigned char a); +void immUniformColor4ubv(const unsigned char rgba[4]); /* Extend immBindProgram to use Blender’s library of built-in shader programs. * Use immUnbindProgram() when done. */ void immBindBuiltinProgram(GPUBuiltinShader shader_id); -/* - * Extend immUniformColor to take Blender's themes - */ +/* Extend immUniformColor to take Blender's themes */ void immUniformThemeColor(int color_id); void immUniformThemeColor3(int color_id); void immUniformThemeColorShade(int color_id, int offset); @@ -55,4 +139,10 @@ void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int void immUniformThemeColorBlend(int color_id1, int color_id2, float fac); void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset); +/* These are called by the system -- not part of drawing API. */ +void immInit(void); +void immActivate(void); +void immDeactivate(void); +void immDestroy(void); + #endif /* __GPU_IMMEDIATE_H__ */ diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h index c31d477ff5b..0a5c9805509 100644 --- a/source/blender/gpu/GPU_immediate_util.h +++ b/source/blender/gpu/GPU_immediate_util.h @@ -27,6 +27,15 @@ #ifndef __GPU_IMMEDIATE_UTIL_H__ #define __GPU_IMMEDIATE_UTIL_H__ +/* Draw 2D rectangles (replaces glRect functions) */ +/* caller is reponsible for vertex format & shader */ +void immRectf(uint pos, float x1, float y1, float x2, float y2); +void immRecti(uint pos, int x1, int y1, int x2, int y2); + +/* Same as immRectf/immRecti but does not call immBegin/immEnd. To use with GWN_PRIM_TRIS. */ +void immRectf_fast_with_color(uint pos, uint col, float x1, float y1, float x2, float y2, const float color[4]); +void immRecti_fast_with_color(uint pos, uint col, int x1, int y1, int x2, int y2, const float color[4]); + void imm_cpack(uint x); void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments); diff --git a/source/blender/gpu/GPU_primitive.h b/source/blender/gpu/GPU_primitive.h new file mode 100644 index 00000000000..44348b9b593 --- /dev/null +++ b/source/blender/gpu/GPU_primitive.h @@ -0,0 +1,65 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_primitive.h + * \ingroup gpu + * + * Gawain geometric primitives + */ + +#ifndef __GWN_PRIMITIVE_H__ +#define __GWN_PRIMITIVE_H__ + +#include "GPU_common.h" + +typedef enum { + GWN_PRIM_POINTS, + GWN_PRIM_LINES, + GWN_PRIM_TRIS, + GWN_PRIM_LINE_STRIP, + GWN_PRIM_LINE_LOOP, /* GL has this, Vulkan does not */ + GWN_PRIM_TRI_STRIP, + GWN_PRIM_TRI_FAN, + + GWN_PRIM_LINES_ADJ, + GWN_PRIM_TRIS_ADJ, + GWN_PRIM_LINE_STRIP_ADJ, + + GWN_PRIM_NONE +} Gwn_PrimType; + +/* what types of primitives does each shader expect? */ +typedef enum { + GWN_PRIM_CLASS_NONE = 0, + GWN_PRIM_CLASS_POINT = (1 << 0), + GWN_PRIM_CLASS_LINE = (1 << 1), + GWN_PRIM_CLASS_SURFACE = (1 << 2), + GWN_PRIM_CLASS_ANY = GWN_PRIM_CLASS_POINT | GWN_PRIM_CLASS_LINE | GWN_PRIM_CLASS_SURFACE +} Gwn_PrimClass; + +Gwn_PrimClass GWN_primtype_class(Gwn_PrimType); +bool GWN_primtype_belongs_to_class(Gwn_PrimType, Gwn_PrimClass); + +#endif /* __GWN_PRIMITIVE_H__ */ diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h new file mode 100644 index 00000000000..36842e9847a --- /dev/null +++ b/source/blender/gpu/GPU_shader_interface.h @@ -0,0 +1,104 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_shader_interface.h + * \ingroup gpu + * + * Gawain shader interface (C --> GLSL) + */ + +#ifndef __GWN_SHADER_INTERFACE_H__ +#define __GWN_SHADER_INTERFACE_H__ + +#include "GPU_common.h" + +typedef enum { + GWN_UNIFORM_NONE = 0, /* uninitialized/unknown */ + + GWN_UNIFORM_MODEL, /* mat4 ModelMatrix */ + GWN_UNIFORM_VIEW, /* mat4 ViewMatrix */ + GWN_UNIFORM_MODELVIEW, /* mat4 ModelViewMatrix */ + GWN_UNIFORM_PROJECTION, /* mat4 ProjectionMatrix */ + GWN_UNIFORM_VIEWPROJECTION, /* mat4 ViewProjectionMatrix */ + GWN_UNIFORM_MVP, /* mat4 ModelViewProjectionMatrix */ + + GWN_UNIFORM_MODEL_INV, /* mat4 ModelMatrixInverse */ + GWN_UNIFORM_VIEW_INV, /* mat4 ViewMatrixInverse */ + GWN_UNIFORM_MODELVIEW_INV, /* mat4 ModelViewMatrixInverse */ + GWN_UNIFORM_PROJECTION_INV, /* mat4 ProjectionMatrixInverse */ + GWN_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */ + + GWN_UNIFORM_NORMAL, /* mat3 NormalMatrix */ + GWN_UNIFORM_WORLDNORMAL, /* mat3 WorldNormalMatrix */ + GWN_UNIFORM_CAMERATEXCO, /* vec4 CameraTexCoFactors */ + GWN_UNIFORM_ORCO, /* vec3 OrcoTexCoFactors[] */ + + GWN_UNIFORM_COLOR, /* vec4 color */ + GWN_UNIFORM_EYE, /* vec3 eye */ + GWN_UNIFORM_CALLID, /* int callId */ + + GWN_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */ + + GWN_NUM_UNIFORMS, /* Special value, denotes number of builtin uniforms. */ +} Gwn_UniformBuiltin; + +typedef struct Gwn_ShaderInput { + struct Gwn_ShaderInput* next; + uint32_t name_offset; + uint name_hash; + Gwn_UniformBuiltin builtin_type; /* only for uniform inputs */ + uint32_t gl_type; /* only for attrib inputs */ + int32_t size; /* only for attrib inputs */ + int32_t location; +} Gwn_ShaderInput; + +#define GWN_NUM_SHADERINTERFACE_BUCKETS 257 +#define GWN_SHADERINTERFACE_REF_ALLOC_COUNT 16 + +typedef struct Gwn_ShaderInterface { + int32_t program; + uint32_t name_buffer_offset; + Gwn_ShaderInput* attrib_buckets[GWN_NUM_SHADERINTERFACE_BUCKETS]; + Gwn_ShaderInput* uniform_buckets[GWN_NUM_SHADERINTERFACE_BUCKETS]; + Gwn_ShaderInput* ubo_buckets[GWN_NUM_SHADERINTERFACE_BUCKETS]; + Gwn_ShaderInput* builtin_uniforms[GWN_NUM_UNIFORMS]; + char* name_buffer; + struct Gwn_Batch** batches; /* references to batches using this interface */ + uint batches_len; +} Gwn_ShaderInterface; + +Gwn_ShaderInterface* GWN_shaderinterface_create(int32_t program_id); +void GWN_shaderinterface_discard(Gwn_ShaderInterface*); + +const Gwn_ShaderInput* GWN_shaderinterface_uniform(const Gwn_ShaderInterface*, const char* name); +const Gwn_ShaderInput* GWN_shaderinterface_uniform_builtin(const Gwn_ShaderInterface*, Gwn_UniformBuiltin); +const Gwn_ShaderInput* GWN_shaderinterface_ubo(const Gwn_ShaderInterface*, const char* name); +const Gwn_ShaderInput* GWN_shaderinterface_attr(const Gwn_ShaderInterface*, const char* name); + +/* keep track of batches using this interface */ +void GWN_shaderinterface_add_batch_ref(Gwn_ShaderInterface*, struct Gwn_Batch*); +void GWN_shaderinterface_remove_batch_ref(Gwn_ShaderInterface*, struct Gwn_Batch*); + +#endif /* __GWN_SHADER_INTERFACE_H__ */ diff --git a/source/blender/gpu/GPU_vertex_array_id.h b/source/blender/gpu/GPU_vertex_array_id.h new file mode 100644 index 00000000000..925cd74511d --- /dev/null +++ b/source/blender/gpu/GPU_vertex_array_id.h @@ -0,0 +1,55 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_vertex_array_id.h + * \ingroup gpu + * + * Manage GL vertex array IDs in a thread-safe way + * Use these instead of glGenBuffers & its friends + * - alloc must be called from a thread that is bound + * to the context that will be used for drawing with + * this vao. + * - free can be called from any thread + */ + +#ifndef __GWN_VERTEX_ARRAY_ID_H__ +#define __GWN_VERTEX_ARRAY_ID_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "GPU_common.h" +#include "GPU_context.h" + +GLuint GWN_vao_default(void); +GLuint GWN_vao_alloc(void); +void GWN_vao_free(GLuint vao_id, Gwn_Context*); + +#ifdef __cplusplus +} +#endif + +#endif /* __GWN_VERTEX_ARRAY_ID_H__ */ diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h new file mode 100644 index 00000000000..7e4aa24ff2c --- /dev/null +++ b/source/blender/gpu/GPU_vertex_buffer.h @@ -0,0 +1,144 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_vertex_buffer.h + * \ingroup gpu + * + * Gawain vertex buffer + */ + +#ifndef __GWN_VERTEX_BUFFER_H__ +#define __GWN_VERTEX_BUFFER_H__ + +#include "GPU_vertex_format.h" + +#define VRAM_USAGE 1 +/* How to create a Gwn_VertBuf: */ +/* 1) verts = GWN_vertbuf_create() or GWN_vertbuf_init(verts) */ +/* 2) GWN_vertformat_attr_add(verts->format, ...) */ +/* 3) GWN_vertbuf_data_alloc(verts, vertex_len) <-- finalizes/packs vertex format */ +/* 4) GWN_vertbuf_attr_fill(verts, pos, application_pos_buffer) */ + +/* Is Gwn_VertBuf always used as part of a Gwn_Batch? */ + +typedef enum { + /* can be extended to support more types */ + GWN_USAGE_STREAM, + GWN_USAGE_STATIC, /* do not keep data in memory */ + GWN_USAGE_DYNAMIC +} Gwn_UsageType; + +typedef struct Gwn_VertBuf { + Gwn_VertFormat format; + uint vertex_len; /* number of verts we want to draw */ + uint vertex_alloc; /* number of verts data */ + bool dirty; + unsigned char* data; /* NULL indicates data in VRAM (unmapped) */ + uint32_t vbo_id; /* 0 indicates not yet allocated */ + Gwn_UsageType usage; /* usage hint for GL optimisation */ +} Gwn_VertBuf; + +Gwn_VertBuf* GWN_vertbuf_create(Gwn_UsageType); +Gwn_VertBuf* GWN_vertbuf_create_with_format_ex(const Gwn_VertFormat*, Gwn_UsageType); + +#define GWN_vertbuf_create_with_format(format) \ + GWN_vertbuf_create_with_format_ex(format, GWN_USAGE_STATIC) + +void GWN_vertbuf_discard(Gwn_VertBuf*); + +void GWN_vertbuf_init(Gwn_VertBuf*, Gwn_UsageType); +void GWN_vertbuf_init_with_format_ex(Gwn_VertBuf*, const Gwn_VertFormat*, Gwn_UsageType); + +#define GWN_vertbuf_init_with_format(verts, format) \ + GWN_vertbuf_init_with_format_ex(verts, format, GWN_USAGE_STATIC) + +uint GWN_vertbuf_size_get(const Gwn_VertBuf*); +void GWN_vertbuf_data_alloc(Gwn_VertBuf*, uint v_len); +void GWN_vertbuf_data_resize(Gwn_VertBuf*, uint v_len); +void GWN_vertbuf_vertex_count_set(Gwn_VertBuf*, uint v_len); + +/* The most important set_attrib variant is the untyped one. Get it right first. */ +/* It takes a void* so the app developer is responsible for matching their app data types */ +/* to the vertex attribute's type and component count. They're in control of both, so this */ +/* should not be a problem. */ + +void GWN_vertbuf_attr_set(Gwn_VertBuf*, uint a_idx, uint v_idx, const void* data); +void GWN_vertbuf_attr_fill(Gwn_VertBuf*, uint a_idx, const void* data); /* tightly packed, non interleaved input data */ +void GWN_vertbuf_attr_fill_stride(Gwn_VertBuf*, uint a_idx, uint stride, const void* data); + +/* For low level access only */ +typedef struct Gwn_VertBufRaw { + uint size; + uint stride; + unsigned char* data; + unsigned char* data_init; +#if TRUST_NO_ONE + /* Only for overflow check */ + unsigned char* _data_end; +#endif +} Gwn_VertBufRaw; + +GWN_INLINE void *GWN_vertbuf_raw_step(Gwn_VertBufRaw *a) +{ + unsigned char* data = a->data; + a->data += a->stride; +#if TRUST_NO_ONE + assert(data < a->_data_end); +#endif + return (void *)data; +} + +GWN_INLINE uint GWN_vertbuf_raw_used(Gwn_VertBufRaw *a) +{ + return ((a->data - a->data_init) / a->stride); +} + +void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf*, uint a_idx, Gwn_VertBufRaw *access); + +/* TODO: decide whether to keep the functions below */ +/* doesn't immediate mode satisfy these needs? */ + +/* void setAttrib1f(uint a_idx, uint v_idx, float x); */ +/* void setAttrib2f(uint a_idx, unsigned v_idx, float x, float y); */ +/* void setAttrib3f(unsigned a_idx, unsigned v_idx, float x, float y, float z); */ +/* void setAttrib4f(unsigned a_idx, unsigned v_idx, float x, float y, float z, float w); */ + +/* void setAttrib3ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b); */ +/* void setAttrib4ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b, unsigned char a); */ + +void GWN_vertbuf_use(Gwn_VertBuf*); + +/* Metrics */ +uint GWN_vertbuf_get_memory_usage(void); + +/* Macros */ +#define GWN_VERTBUF_DISCARD_SAFE(verts) do { \ + if (verts != NULL) { \ + GWN_vertbuf_discard(verts); \ + verts = NULL; \ + } \ +} while (0) + +#endif /* __GWN_VERTEX_BUFFER_H__ */ diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h new file mode 100644 index 00000000000..91e31b5ece4 --- /dev/null +++ b/source/blender/gpu/GPU_vertex_format.h @@ -0,0 +1,101 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_vertex_format.h + * \ingroup gpu + * + * Gawain vertex format + */ + +#ifndef __GWN_VERTEX_FORMAT_H__ +#define __GWN_VERTEX_FORMAT_H__ + +#include "GPU_common.h" + +#define GWN_VERT_ATTR_MAX_LEN 16 +#define GWN_VERT_ATTR_MAX_NAMES 3 +#define GWN_VERT_ATTR_NAME_AVERAGE_LEN 11 +#define GWN_VERT_ATTR_NAMES_BUF_LEN ((GWN_VERT_ATTR_NAME_AVERAGE_LEN + 1) * GWN_VERT_ATTR_MAX_LEN) + +typedef enum { + GWN_COMP_I8, + GWN_COMP_U8, + GWN_COMP_I16, + GWN_COMP_U16, + GWN_COMP_I32, + GWN_COMP_U32, + + GWN_COMP_F32, + + GWN_COMP_I10 +} Gwn_VertCompType; + +typedef enum { + GWN_FETCH_FLOAT, + GWN_FETCH_INT, + GWN_FETCH_INT_TO_FLOAT_UNIT, /* 127 (ubyte) -> 0.5 (and so on for other int types) */ + GWN_FETCH_INT_TO_FLOAT /* 127 (any int type) -> 127.0 */ +} Gwn_VertFetchMode; + +typedef struct Gwn_VertAttr { + Gwn_VertFetchMode fetch_mode; + Gwn_VertCompType comp_type; + uint gl_comp_type; + uint comp_len; /* 1 to 4 or 8 or 12 or 16 */ + uint sz; /* size in bytes, 1 to 64 */ + uint offset; /* from beginning of vertex, in bytes */ + uint name_len; /* up to GWN_VERT_ATTR_MAX_NAMES */ + const char* name[GWN_VERT_ATTR_MAX_NAMES]; +} Gwn_VertAttr; + +typedef struct Gwn_VertFormat { + uint attr_len; /* 0 to 16 (GWN_VERT_ATTR_MAX_LEN) */ + uint name_len; /* total count of active vertex attrib */ + uint stride; /* stride in bytes, 1 to 256 */ + uint name_offset; + bool packed; + char names[GWN_VERT_ATTR_NAMES_BUF_LEN]; + Gwn_VertAttr attribs[GWN_VERT_ATTR_MAX_LEN]; /* TODO: variable-size attribs array */ +} Gwn_VertFormat; + +void GWN_vertformat_clear(Gwn_VertFormat*); +void GWN_vertformat_copy(Gwn_VertFormat* dest, const Gwn_VertFormat* src); + +uint GWN_vertformat_attr_add(Gwn_VertFormat*, const char* name, Gwn_VertCompType, uint comp_len, Gwn_VertFetchMode); +void GWN_vertformat_alias_add(Gwn_VertFormat*, const char* alias); + +/* format conversion */ + +typedef struct Gwn_PackedNormal { + int x : 10; + int y : 10; + int z : 10; + int w : 2; /* 0 by default, can manually set to { -2, -1, 0, 1 } */ +} Gwn_PackedNormal; + +Gwn_PackedNormal GWN_normal_convert_i10_v3(const float data[3]); +Gwn_PackedNormal GWN_normal_convert_i10_s3(const short data[3]); + +#endif /* __GWN_VERTEX_FORMAT_H__ */ diff --git a/source/blender/gpu/intern/gpu_attr_binding.c b/source/blender/gpu/intern/gpu_attr_binding.c new file mode 100644 index 00000000000..e7eba369335 --- /dev/null +++ b/source/blender/gpu/intern/gpu_attr_binding.c @@ -0,0 +1,85 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gwn_attr_binding.c + * \ingroup gpu + * + * Gawain vertex attribute binding + */ + +#include "GPU_attr_binding.h" +#include "gpu_attr_binding_private.h" +#include +#include + +#if GWN_VERT_ATTR_MAX_LEN != 16 + #error "attrib binding code assumes GWN_VERT_ATTR_MAX_LEN = 16" +#endif + +void AttribBinding_clear(Gwn_AttrBinding* binding) +{ + binding->loc_bits = 0; + binding->enabled_bits = 0; +} + +uint read_attrib_location(const Gwn_AttrBinding* binding, uint a_idx) +{ +#if TRUST_NO_ONE + assert(a_idx < GWN_VERT_ATTR_MAX_LEN); + assert(binding->enabled_bits & (1 << a_idx)); +#endif + return (binding->loc_bits >> (4 * a_idx)) & 0xF; +} + +static void write_attrib_location(Gwn_AttrBinding* binding, uint a_idx, uint location) +{ +#if TRUST_NO_ONE + assert(a_idx < GWN_VERT_ATTR_MAX_LEN); + assert(location < GWN_VERT_ATTR_MAX_LEN); +#endif + const uint shift = 4 * a_idx; + const uint64_t mask = ((uint64_t)0xF) << shift; + /* overwrite this attrib's previous location */ + binding->loc_bits = (binding->loc_bits & ~mask) | (location << shift); + /* mark this attrib as enabled */ + binding->enabled_bits |= 1 << a_idx; +} + +void get_attrib_locations(const Gwn_VertFormat* format, Gwn_AttrBinding* binding, const Gwn_ShaderInterface* shaderface) +{ + AttribBinding_clear(binding); + + for (uint a_idx = 0; a_idx < format->attr_len; ++a_idx) { + const Gwn_VertAttr* a = format->attribs + a_idx; + for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) { + const Gwn_ShaderInput* input = GWN_shaderinterface_attr(shaderface, a->name[n_idx]); +#if TRUST_NO_ONE + assert(input != NULL); + /* TODO: make this a recoverable runtime error? indicates mismatch between vertex format and program */ +#endif + write_attrib_location(binding, a_idx, input->location); + } + } +} diff --git a/source/blender/gpu/intern/gpu_attr_binding_private.h b/source/blender/gpu/intern/gpu_attr_binding_private.h new file mode 100644 index 00000000000..0e0bf89178a --- /dev/null +++ b/source/blender/gpu/intern/gpu_attr_binding_private.h @@ -0,0 +1,43 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_attr_binding_private.h + * \ingroup gpu + * + * Gawain vertex attribute binding + */ + +#ifndef __GWN_ATTR_BINDING_PRIVATE_H__ +#define __GWN_ATTR_BINDING_PRIVATE_H__ + +#include "GPU_vertex_format.h" +#include "GPU_shader_interface.h" + +void AttribBinding_clear(Gwn_AttrBinding*); + +void get_attrib_locations(const Gwn_VertFormat*, Gwn_AttrBinding*, const Gwn_ShaderInterface*); +unsigned read_attrib_location(const Gwn_AttrBinding*, unsigned a_idx); + +#endif /* __GWN_ATTR_BINDING_PRIVATE_H__ */ diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c index 5bfd20e3c8b..90f30930884 100644 --- a/source/blender/gpu/intern/gpu_batch.c +++ b/source/blender/gpu/intern/gpu_batch.c @@ -15,32 +15,639 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2016 Blender Foundation. + * The Original Code is Copyright (C) 2016 by Mike Erwin. * All rights reserved. * - * The Original Code is: all of this file. - * - * Contributor(s): Mike Erwin + * Contributor(s): Blender Foundation * * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/gpu/intern/gpu_batch.c +/** \file blender/gpu/intern/gwn_batch.c * \ingroup gpu + * + * Gawain geometry batch + * Contains VAOs + VBOs + Shader representing a drawable entity. */ -#include "MEM_guardedalloc.h" - -#include "BLI_utildefines.h" -#include "BLI_rect.h" -#include "BLI_math.h" -#include "BLI_polyfill_2d.h" -#include "BLI_sort_utils.h" - -#include "GPU_batch.h" /* own include */ +#include "GPU_batch.h" #include "GPU_batch_presets.h" +#include "GPU_buffer_id.h" +#include "GPU_matrix.h" +#include "GPU_shader.h" +#include "GPU_vertex_array_id.h" + +#include "gpu_batch_private.h" +#include "gpu_primitive_private.h" #include "gpu_shader_private.h" +#include +#include + +static void batch_update_program_bindings(Gwn_Batch* batch, uint v_first); + +void gwn_batch_vao_cache_clear(Gwn_Batch* batch) +{ + if (batch->context == NULL) { + return; + } + if (batch->is_dynamic_vao_count) { + for (int i = 0; i < batch->dynamic_vaos.count; ++i) { + if (batch->dynamic_vaos.vao_ids[i]) { + GWN_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context); + } + if (batch->dynamic_vaos.interfaces[i]) { + GWN_shaderinterface_remove_batch_ref((Gwn_ShaderInterface *)batch->dynamic_vaos.interfaces[i], batch); + } + } + free(batch->dynamic_vaos.interfaces); + free(batch->dynamic_vaos.vao_ids); + } + else { + for (int i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i) { + if (batch->static_vaos.vao_ids[i]) { + GWN_vao_free(batch->static_vaos.vao_ids[i], batch->context); + } + if (batch->static_vaos.interfaces[i]) { + GWN_shaderinterface_remove_batch_ref((Gwn_ShaderInterface *)batch->static_vaos.interfaces[i], batch); + } + } + } + batch->is_dynamic_vao_count = false; + for (int i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i) { + batch->static_vaos.vao_ids[i] = 0; + batch->static_vaos.interfaces[i] = NULL; + } + gwn_context_remove_batch(batch->context, batch); + batch->context = NULL; +} + +Gwn_Batch* GWN_batch_create_ex( + Gwn_PrimType prim_type, Gwn_VertBuf* verts, Gwn_IndexBuf* elem, + uint owns_flag) +{ + Gwn_Batch* batch = calloc(1, sizeof(Gwn_Batch)); + GWN_batch_init_ex(batch, prim_type, verts, elem, owns_flag); + return batch; +} + +void GWN_batch_init_ex( + Gwn_Batch* batch, Gwn_PrimType prim_type, Gwn_VertBuf* verts, Gwn_IndexBuf* elem, + uint owns_flag) +{ +#if TRUST_NO_ONE + assert(verts != NULL); +#endif + + batch->verts[0] = verts; + for (int v = 1; v < GWN_BATCH_VBO_MAX_LEN; ++v) { + batch->verts[v] = NULL; + } + batch->inst = NULL; + batch->elem = elem; + batch->gl_prim_type = convert_prim_type_to_gl(prim_type); + batch->phase = GWN_BATCH_READY_TO_DRAW; + batch->is_dynamic_vao_count = false; + batch->owns_flag = owns_flag; + batch->free_callback = NULL; +} + +/* This will share the VBOs with the new batch. */ +Gwn_Batch* GWN_batch_duplicate(Gwn_Batch* batch_src) +{ + Gwn_Batch* batch = GWN_batch_create_ex(GWN_PRIM_POINTS, batch_src->verts[0], batch_src->elem, 0); + + batch->gl_prim_type = batch_src->gl_prim_type; + for (int v = 1; v < GWN_BATCH_VBO_MAX_LEN; ++v) { + batch->verts[v] = batch_src->verts[v]; + } + return batch; +} + +void GWN_batch_discard(Gwn_Batch* batch) +{ + if (batch->owns_flag & GWN_BATCH_OWNS_INDEX) { + GWN_indexbuf_discard(batch->elem); + } + if (batch->owns_flag & GWN_BATCH_OWNS_INSTANCES) { + GWN_vertbuf_discard(batch->inst); + } + if ((batch->owns_flag & ~GWN_BATCH_OWNS_INDEX) != 0) { + for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v) { + if (batch->verts[v] == NULL) { + break; + } + if (batch->owns_flag & (1 << v)) { + GWN_vertbuf_discard(batch->verts[v]); + } + } + } + gwn_batch_vao_cache_clear(batch); + + if (batch->free_callback) { + batch->free_callback(batch, batch->callback_data); + } + free(batch); +} + +void GWN_batch_callback_free_set(Gwn_Batch* batch, void (*callback)(Gwn_Batch*, void*), void* user_data) +{ + batch->free_callback = callback; + batch->callback_data = user_data; +} + +void GWN_batch_instbuf_set(Gwn_Batch* batch, Gwn_VertBuf* inst, bool own_vbo) +{ +#if TRUST_NO_ONE + assert(inst != NULL); +#endif + /* redo the bindings */ + gwn_batch_vao_cache_clear(batch); + + if (batch->inst != NULL && (batch->owns_flag & GWN_BATCH_OWNS_INSTANCES)) { + GWN_vertbuf_discard(batch->inst); + } + batch->inst = inst; + + if (own_vbo) { + batch->owns_flag |= GWN_BATCH_OWNS_INSTANCES; + } + else { + batch->owns_flag &= ~GWN_BATCH_OWNS_INSTANCES; + } +} + +/* Returns the index of verts in the batch. */ +int GWN_batch_vertbuf_add_ex( + Gwn_Batch* batch, Gwn_VertBuf* verts, + bool own_vbo) +{ + /* redo the bindings */ + gwn_batch_vao_cache_clear(batch); + + for (uint v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v) { + if (batch->verts[v] == NULL) { +#if TRUST_NO_ONE + /* for now all VertexBuffers must have same vertex_len */ + assert(verts->vertex_len == batch->verts[0]->vertex_len); +#endif + batch->verts[v] = verts; + /* TODO: mark dirty so we can keep attrib bindings up-to-date */ + if (own_vbo) + batch->owns_flag |= (1 << v); + return v; + } + } + + /* we only make it this far if there is no room for another Gwn_VertBuf */ +#if TRUST_NO_ONE + assert(false); +#endif + return -1; +} + +static GLuint batch_vao_get(Gwn_Batch *batch) +{ + /* Search through cache */ + if (batch->is_dynamic_vao_count) { + for (int i = 0; i < batch->dynamic_vaos.count; ++i) + if (batch->dynamic_vaos.interfaces[i] == batch->interface) + return batch->dynamic_vaos.vao_ids[i]; + } + else { + for (int i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i) + if (batch->static_vaos.interfaces[i] == batch->interface) + return batch->static_vaos.vao_ids[i]; + } + + /* Set context of this batch. + * It will be bound to it until gwn_batch_vao_cache_clear is called. + * Until then it can only be drawn with this context. */ + if (batch->context == NULL) { + batch->context = GWN_context_active_get(); + gwn_context_add_batch(batch->context, batch); + } +#if TRUST_NO_ONE + else { + /* Make sure you are not trying to draw this batch in another context. */ + assert(batch->context == GWN_context_active_get()); + } +#endif + + /* Cache miss, time to add a new entry! */ + GLuint new_vao = 0; + if (!batch->is_dynamic_vao_count) { + int i; /* find first unused slot */ + for (i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i) + if (batch->static_vaos.vao_ids[i] == 0) + break; + + if (i < GWN_BATCH_VAO_STATIC_LEN) { + batch->static_vaos.interfaces[i] = batch->interface; + batch->static_vaos.vao_ids[i] = new_vao = GWN_vao_alloc(); + } + else { + /* Not enough place switch to dynamic. */ + batch->is_dynamic_vao_count = true; + /* Erase previous entries, they will be added back if drawn again. */ + for (int j = 0; j < GWN_BATCH_VAO_STATIC_LEN; ++j) { + GWN_shaderinterface_remove_batch_ref((Gwn_ShaderInterface*)batch->static_vaos.interfaces[j], batch); + GWN_vao_free(batch->static_vaos.vao_ids[j], batch->context); + } + /* Init dynamic arrays and let the branch below set the values. */ + batch->dynamic_vaos.count = GWN_BATCH_VAO_DYN_ALLOC_COUNT; + batch->dynamic_vaos.interfaces = calloc(batch->dynamic_vaos.count, sizeof(Gwn_ShaderInterface*)); + batch->dynamic_vaos.vao_ids = calloc(batch->dynamic_vaos.count, sizeof(GLuint)); + } + } + + if (batch->is_dynamic_vao_count) { + int i; /* find first unused slot */ + for (i = 0; i < batch->dynamic_vaos.count; ++i) + if (batch->dynamic_vaos.vao_ids[i] == 0) + break; + + if (i == batch->dynamic_vaos.count) { + /* Not enough place, realloc the array. */ + i = batch->dynamic_vaos.count; + batch->dynamic_vaos.count += GWN_BATCH_VAO_DYN_ALLOC_COUNT; + batch->dynamic_vaos.interfaces = realloc(batch->dynamic_vaos.interfaces, sizeof(Gwn_ShaderInterface*) * batch->dynamic_vaos.count); + batch->dynamic_vaos.vao_ids = realloc(batch->dynamic_vaos.vao_ids, sizeof(GLuint) * batch->dynamic_vaos.count); + memset(batch->dynamic_vaos.interfaces + i, 0, sizeof(Gwn_ShaderInterface*) * GWN_BATCH_VAO_DYN_ALLOC_COUNT); + memset(batch->dynamic_vaos.vao_ids + i, 0, sizeof(GLuint) * GWN_BATCH_VAO_DYN_ALLOC_COUNT); + } + batch->dynamic_vaos.interfaces[i] = batch->interface; + batch->dynamic_vaos.vao_ids[i] = new_vao = GWN_vao_alloc(); + } + + GWN_shaderinterface_add_batch_ref((Gwn_ShaderInterface*)batch->interface, batch); + +#if TRUST_NO_ONE + assert(new_vao != 0); +#endif + + /* We just got a fresh VAO we need to initialize it. */ + glBindVertexArray(new_vao); + batch_update_program_bindings(batch, 0); + glBindVertexArray(0); + + return new_vao; +} + +void GWN_batch_program_set_no_use(Gwn_Batch* batch, uint32_t program, const Gwn_ShaderInterface* shaderface) +{ +#if TRUST_NO_ONE + assert(glIsProgram(shaderface->program)); + assert(batch->program_in_use == 0); +#endif + batch->interface = shaderface; + batch->program = program; + batch->vao_id = batch_vao_get(batch); +} + +void GWN_batch_program_set(Gwn_Batch* batch, uint32_t program, const Gwn_ShaderInterface* shaderface) +{ + GWN_batch_program_set_no_use(batch, program, shaderface); + GWN_batch_program_use_begin(batch); /* hack! to make Batch_Uniform* simpler */ +} + +void gwn_batch_remove_interface_ref(Gwn_Batch* batch, const Gwn_ShaderInterface* interface) +{ + if (batch->is_dynamic_vao_count) { + for (int i = 0; i < batch->dynamic_vaos.count; ++i) { + if (batch->dynamic_vaos.interfaces[i] == interface) { + GWN_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context); + batch->dynamic_vaos.vao_ids[i] = 0; + batch->dynamic_vaos.interfaces[i] = NULL; + break; /* cannot have duplicates */ + } + } + } + else { + int i; + for (i = 0; i < GWN_BATCH_VAO_STATIC_LEN; ++i) { + if (batch->static_vaos.interfaces[i] == interface) { + GWN_vao_free(batch->static_vaos.vao_ids[i], batch->context); + batch->static_vaos.vao_ids[i] = 0; + batch->static_vaos.interfaces[i] = NULL; + break; /* cannot have duplicates */ + } + } + } +} + +static void create_bindings( + Gwn_VertBuf* verts, const Gwn_ShaderInterface* interface, + uint v_first, const bool use_instancing) +{ + const Gwn_VertFormat* format = &verts->format; + + const uint attr_len = format->attr_len; + const uint stride = format->stride; + + GWN_vertbuf_use(verts); + + for (uint a_idx = 0; a_idx < attr_len; ++a_idx) { + const Gwn_VertAttr* a = format->attribs + a_idx; + const GLvoid* pointer = (const GLubyte*)0 + a->offset + v_first * stride; + + for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) { + const Gwn_ShaderInput* input = GWN_shaderinterface_attr(interface, a->name[n_idx]); + + if (input == NULL) continue; + + if (a->comp_len == 16 || a->comp_len == 12 || a->comp_len == 8) { +#if TRUST_NO_ONE + assert(a->fetch_mode == GWN_FETCH_FLOAT); + assert(a->gl_comp_type == GL_FLOAT); +#endif + for (int i = 0; i < a->comp_len / 4; ++i) { + glEnableVertexAttribArray(input->location + i); + glVertexAttribDivisor(input->location + i, (use_instancing) ? 1 : 0); + glVertexAttribPointer(input->location + i, 4, a->gl_comp_type, GL_FALSE, stride, + (const GLubyte*)pointer + i * 16); + } + } + else + { + glEnableVertexAttribArray(input->location); + glVertexAttribDivisor(input->location, (use_instancing) ? 1 : 0); + + switch (a->fetch_mode) { + case GWN_FETCH_FLOAT: + case GWN_FETCH_INT_TO_FLOAT: + glVertexAttribPointer(input->location, a->comp_len, a->gl_comp_type, GL_FALSE, stride, pointer); + break; + case GWN_FETCH_INT_TO_FLOAT_UNIT: + glVertexAttribPointer(input->location, a->comp_len, a->gl_comp_type, GL_TRUE, stride, pointer); + break; + case GWN_FETCH_INT: + glVertexAttribIPointer(input->location, a->comp_len, a->gl_comp_type, stride, pointer); + break; + } + } + } + } +} + +static void batch_update_program_bindings(Gwn_Batch* batch, uint v_first) +{ + for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN && batch->verts[v] != NULL; ++v) { + create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false); + } + if (batch->inst) { + create_bindings(batch->inst, batch->interface, v_first, true); + } + if (batch->elem) { + GWN_indexbuf_use(batch->elem); + } +} + +void GWN_batch_program_use_begin(Gwn_Batch* batch) +{ + /* NOTE: use_program & done_using_program are fragile, depend on staying in sync with + * the GL context's active program. use_program doesn't mark other programs as "not used". */ + /* TODO: make not fragile (somehow) */ + + if (!batch->program_in_use) { + glUseProgram(batch->program); + batch->program_in_use = true; + } +} + +void GWN_batch_program_use_end(Gwn_Batch* batch) +{ + if (batch->program_in_use) { +#if PROGRAM_NO_OPTI + glUseProgram(0); +#endif + batch->program_in_use = false; + } +} + +#if TRUST_NO_ONE + #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(batch->interface, name); assert(uniform); +#else + #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(batch->interface, name); +#endif + +void GWN_batch_uniform_1ui(Gwn_Batch* batch, const char* name, int value) +{ + GET_UNIFORM + glUniform1ui(uniform->location, value); +} + +void GWN_batch_uniform_1i(Gwn_Batch* batch, const char* name, int value) +{ + GET_UNIFORM + glUniform1i(uniform->location, value); +} + +void GWN_batch_uniform_1b(Gwn_Batch* batch, const char* name, bool value) +{ + GET_UNIFORM + glUniform1i(uniform->location, value ? GL_TRUE : GL_FALSE); +} + +void GWN_batch_uniform_2f(Gwn_Batch* batch, const char* name, float x, float y) +{ + GET_UNIFORM + glUniform2f(uniform->location, x, y); +} + +void GWN_batch_uniform_3f(Gwn_Batch* batch, const char* name, float x, float y, float z) +{ + GET_UNIFORM + glUniform3f(uniform->location, x, y, z); +} + +void GWN_batch_uniform_4f(Gwn_Batch* batch, const char* name, float x, float y, float z, float w) +{ + GET_UNIFORM + glUniform4f(uniform->location, x, y, z, w); +} + +void GWN_batch_uniform_1f(Gwn_Batch* batch, const char* name, float x) +{ + GET_UNIFORM + glUniform1f(uniform->location, x); +} + +void GWN_batch_uniform_2fv(Gwn_Batch* batch, const char* name, const float data[2]) +{ + GET_UNIFORM + glUniform2fv(uniform->location, 1, data); +} + +void GWN_batch_uniform_3fv(Gwn_Batch* batch, const char* name, const float data[3]) +{ + GET_UNIFORM + glUniform3fv(uniform->location, 1, data); +} + +void GWN_batch_uniform_4fv(Gwn_Batch* batch, const char* name, const float data[4]) +{ + GET_UNIFORM + glUniform4fv(uniform->location, 1, data); +} + +void GWN_batch_uniform_2fv_array(Gwn_Batch* batch, const char* name, const int len, const float *data) +{ + GET_UNIFORM + glUniform2fv(uniform->location, len, data); +} + +void GWN_batch_uniform_4fv_array(Gwn_Batch* batch, const char* name, const int len, const float *data) +{ + GET_UNIFORM + glUniform4fv(uniform->location, len, data); +} + +void GWN_batch_uniform_mat4(Gwn_Batch* batch, const char* name, const float data[4][4]) +{ + GET_UNIFORM + glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (const float *)data); +} + +static void primitive_restart_enable(const Gwn_IndexBuf *el) +{ + // TODO(fclem) Replace by GL_PRIMITIVE_RESTART_FIXED_INDEX when we have ogl 4.3 + glEnable(GL_PRIMITIVE_RESTART); + GLuint restart_index = (GLuint)0xFFFFFFFF; + +#if GWN_TRACK_INDEX_RANGE + if (el->index_type == GWN_INDEX_U8) + restart_index = (GLuint)0xFF; + else if (el->index_type == GWN_INDEX_U16) + restart_index = (GLuint)0xFFFF; +#endif + + glPrimitiveRestartIndex(restart_index); +} + +static void primitive_restart_disable(void) +{ + glDisable(GL_PRIMITIVE_RESTART); +} + +void GWN_batch_draw(Gwn_Batch* batch) +{ +#if TRUST_NO_ONE + assert(batch->phase == GWN_BATCH_READY_TO_DRAW); + assert(batch->verts[0]->vbo_id != 0); +#endif + GWN_batch_program_use_begin(batch); + GPU_matrix_bind(batch->interface); // external call. + + GWN_batch_draw_range_ex(batch, 0, 0, false); + + GWN_batch_program_use_end(batch); +} + +void GWN_batch_draw_range_ex(Gwn_Batch* batch, int v_first, int v_count, bool force_instance) +{ +#if TRUST_NO_ONE + assert(!(force_instance && (batch->inst == NULL)) || v_count > 0); // we cannot infer length if force_instance +#endif + const bool do_instance = (force_instance || batch->inst); + + // If using offset drawing, use the default VAO and redo bindings. + if (v_first != 0 && (do_instance || batch->elem)) { + glBindVertexArray(GWN_vao_default()); + batch_update_program_bindings(batch, v_first); + } + else { + glBindVertexArray(batch->vao_id); + } + + if (do_instance) { + /* Infer length if vertex count is not given */ + if (v_count == 0) { + v_count = batch->inst->vertex_len; + } + + if (batch->elem) { + const Gwn_IndexBuf* el = batch->elem; + + if (el->use_prim_restart) { + primitive_restart_enable(el); + } +#if GWN_TRACK_INDEX_RANGE + glDrawElementsInstancedBaseVertex(batch->gl_prim_type, + el->index_len, + el->gl_index_type, + 0, + v_count, + el->base_index); +#else + glDrawElementsInstanced(batch->gl_prim_type, el->index_len, GL_UNSIGNED_INT, 0, v_count); +#endif + if (el->use_prim_restart) { + primitive_restart_disable(); + } + } + else { + glDrawArraysInstanced(batch->gl_prim_type, 0, batch->verts[0]->vertex_len, v_count); + } + } + else { + /* Infer length if vertex count is not given */ + if (v_count == 0) { + v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len; + } + + if (batch->elem) { + const Gwn_IndexBuf* el = batch->elem; + + if (el->use_prim_restart) { + primitive_restart_enable(el); + } + +#if GWN_TRACK_INDEX_RANGE + if (el->base_index) { + glDrawRangeElementsBaseVertex(batch->gl_prim_type, + el->min_index, + el->max_index, + v_count, + el->gl_index_type, + 0, + el->base_index); + } + else { + glDrawRangeElements(batch->gl_prim_type, el->min_index, el->max_index, v_count, el->gl_index_type, 0); + } +#else + glDrawElements(batch->gl_prim_type, v_count, GL_UNSIGNED_INT, 0); +#endif + if (el->use_prim_restart) { + primitive_restart_disable(); + } + } + else { + glDrawArrays(batch->gl_prim_type, v_first, v_count); + } + } + + /* Performance hog if you are drawing with the same vao multiple time. + * Only activate for debugging. */ + // glBindVertexArray(0); +} + +/* just draw some vertices and let shader place them where we want. */ +void GWN_draw_primitive(Gwn_PrimType prim_type, int v_count) + { + /* we cannot draw without vao ... annoying ... */ + glBindVertexArray(GWN_vao_default()); + + GLenum type = convert_prim_type_to_gl(prim_type); + glDrawArrays(type, 0, v_count); + + /* Performance hog if you are drawing with the same vao multiple time. + * Only activate for debugging.*/ + // glBindVertexArray(0); + } + + /* -------------------------------------------------------------------- */ /** \name Utilities * \{ */ @@ -67,4 +674,4 @@ void gpu_batch_exit(void) gpu_batch_presets_exit(); } -/** \} */ +/** \} */ \ No newline at end of file diff --git a/source/blender/gpu/intern/gpu_batch_private.h b/source/blender/gpu/intern/gpu_batch_private.h new file mode 100644 index 00000000000..1e72bae503f --- /dev/null +++ b/source/blender/gpu/intern/gpu_batch_private.h @@ -0,0 +1,53 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_batch_private.h + * \ingroup gpu + * + * Gawain geometry batch + * Contains VAOs + VBOs + Shader representing a drawable entity. + */ + +#ifndef __GWN_BATCH_PRIVATE_H__ +#define __GWN_BATCH_PRIVATE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "GPU_batch.h" +#include "GPU_context.h" +#include "GPU_shader_interface.h" + +void gwn_batch_remove_interface_ref(Gwn_Batch*, const Gwn_ShaderInterface*); + +void gwn_context_add_batch(Gwn_Context*, Gwn_Batch*); +void gwn_context_remove_batch(Gwn_Context*, Gwn_Batch*); + +#ifdef __cplusplus +} +#endif + +#endif /* __GWN_BATCH_PRIVATE_H__ */ diff --git a/source/blender/gpu/intern/gpu_buffer_id.cpp b/source/blender/gpu/intern/gpu_buffer_id.cpp new file mode 100644 index 00000000000..0c442f687a0 --- /dev/null +++ b/source/blender/gpu/intern/gpu_buffer_id.cpp @@ -0,0 +1,90 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gwn_buffer_id.cpp + * \ingroup gpu + * + * Gawain buffer IDs + */ + +#include "GPU_buffer_id.h" + +#include +#include + +#define ORPHAN_DEBUG 0 + +#if ORPHAN_DEBUG + #include +#endif + +static std::vector orphaned_buffer_ids; + +static std::mutex orphan_mutex; + +extern "C" { +extern int BLI_thread_is_main(void); /* Blender-specific function */ +} + +static bool thread_is_main() +{ + /* "main" here means the GL context's thread */ + return BLI_thread_is_main(); +} + +GLuint GWN_buf_id_alloc() +{ + /* delete orphaned IDs */ + orphan_mutex.lock(); + if (!orphaned_buffer_ids.empty()) { + const auto orphaned_buffer_len = (uint)orphaned_buffer_ids.size(); +#if ORPHAN_DEBUG + printf("deleting %u orphaned VBO%s\n", orphaned_buffer_len, orphaned_buffer_len == 1 ? "" : "s"); +#endif + glDeleteBuffers(orphaned_buffer_len, orphaned_buffer_ids.data()); + orphaned_buffer_ids.clear(); + } + orphan_mutex.unlock(); + + GLuint new_buffer_id = 0; + glGenBuffers(1, &new_buffer_id); + return new_buffer_id; +} + +void GWN_buf_id_free(GLuint buffer_id) +{ + if (thread_is_main()) { + glDeleteBuffers(1, &buffer_id); + } + else { + /* add this ID to the orphaned list */ + orphan_mutex.lock(); +#if ORPHAN_DEBUG + printf("orphaning VBO %u\n", buffer_id); +#endif + orphaned_buffer_ids.emplace_back(buffer_id); + orphan_mutex.unlock(); + } +} diff --git a/source/blender/gpu/intern/gpu_element.c b/source/blender/gpu/intern/gpu_element.c new file mode 100644 index 00000000000..596530a6ff4 --- /dev/null +++ b/source/blender/gpu/intern/gpu_element.c @@ -0,0 +1,308 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gwn_element.c + * \ingroup gpu + * + * Gawain element list (AKA index buffer) + */ + +#include "GPU_element.h" +#include "GPU_buffer_id.h" + +#include + +#define KEEP_SINGLE_COPY 1 + +static GLenum convert_index_type_to_gl(Gwn_IndexBufType type) +{ + static const GLenum table[] = { + [GWN_INDEX_U8] = GL_UNSIGNED_BYTE, /* GL has this, Vulkan does not */ + [GWN_INDEX_U16] = GL_UNSIGNED_SHORT, + [GWN_INDEX_U32] = GL_UNSIGNED_INT + }; + return table[type]; +} + +uint GWN_indexbuf_size_get(const Gwn_IndexBuf* elem) +{ +#if GWN_TRACK_INDEX_RANGE + static const uint table[] = { + [GWN_INDEX_U8] = sizeof(GLubyte), /* GL has this, Vulkan does not */ + [GWN_INDEX_U16] = sizeof(GLushort), + [GWN_INDEX_U32] = sizeof(GLuint) + }; + return elem->index_len * table[elem->index_type]; +#else + return elem->index_len * sizeof(GLuint); +#endif +} + +void GWN_indexbuf_init_ex( + Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, + uint index_len, uint vertex_len, bool use_prim_restart) +{ + builder->use_prim_restart = use_prim_restart; + builder->max_allowed_index = vertex_len - 1; + builder->max_index_len = index_len; + builder->index_len = 0; // start empty + builder->prim_type = prim_type; + builder->data = calloc(builder->max_index_len, sizeof(uint)); +} + +void GWN_indexbuf_init(Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, uint prim_len, uint vertex_len) +{ + uint verts_per_prim = 0; + switch (prim_type) { + case GWN_PRIM_POINTS: + verts_per_prim = 1; + break; + case GWN_PRIM_LINES: + verts_per_prim = 2; + break; + case GWN_PRIM_TRIS: + verts_per_prim = 3; + break; + case GWN_PRIM_LINES_ADJ: + verts_per_prim = 4; + break; + default: +#if TRUST_NO_ONE + assert(false); +#endif + return; + } + + GWN_indexbuf_init_ex(builder, prim_type, prim_len * verts_per_prim, vertex_len, false); +} + +void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder* builder, uint v) +{ +#if TRUST_NO_ONE + assert(builder->data != NULL); + assert(builder->index_len < builder->max_index_len); + assert(v <= builder->max_allowed_index); +#endif + builder->data[builder->index_len++] = v; +} + +void GWN_indexbuf_add_primitive_restart(Gwn_IndexBufBuilder* builder) +{ +#if TRUST_NO_ONE + assert(builder->data != NULL); + assert(builder->index_len < builder->max_index_len); + assert(builder->use_prim_restart); +#endif + builder->data[builder->index_len++] = GWN_PRIM_RESTART; +} + +void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder* builder, uint v) +{ +#if TRUST_NO_ONE + assert(builder->prim_type == GWN_PRIM_POINTS); +#endif + GWN_indexbuf_add_generic_vert(builder, v); +} + +void GWN_indexbuf_add_line_verts(Gwn_IndexBufBuilder* builder, uint v1, uint v2) +{ +#if TRUST_NO_ONE + assert(builder->prim_type == GWN_PRIM_LINES); + assert(v1 != v2); +#endif + GWN_indexbuf_add_generic_vert(builder, v1); + GWN_indexbuf_add_generic_vert(builder, v2); +} + +void GWN_indexbuf_add_tri_verts(Gwn_IndexBufBuilder* builder, uint v1, uint v2, uint v3) +{ +#if TRUST_NO_ONE + assert(builder->prim_type == GWN_PRIM_TRIS); + assert(v1 != v2 && v2 != v3 && v3 != v1); +#endif + GWN_indexbuf_add_generic_vert(builder, v1); + GWN_indexbuf_add_generic_vert(builder, v2); + GWN_indexbuf_add_generic_vert(builder, v3); +} + +void GWN_indexbuf_add_line_adj_verts(Gwn_IndexBufBuilder* builder, uint v1, uint v2, uint v3, uint v4) +{ +#if TRUST_NO_ONE + assert(builder->prim_type == GWN_PRIM_LINES_ADJ); + assert(v2 != v3); /* only the line need diff indices */ +#endif + GWN_indexbuf_add_generic_vert(builder, v1); + GWN_indexbuf_add_generic_vert(builder, v2); + GWN_indexbuf_add_generic_vert(builder, v3); + GWN_indexbuf_add_generic_vert(builder, v4); +} + +#if GWN_TRACK_INDEX_RANGE +/* Everything remains 32 bit while building to keep things simple. + * Find min/max after, then convert to smallest index type possible. */ + +static uint index_range(const uint values[], uint value_len, uint* min_out, uint* max_out) +{ + if (value_len == 0) { + *min_out = 0; + *max_out = 0; + return 0; + } + uint min_value = values[0]; + uint max_value = values[0]; + for (uint i = 1; i < value_len; ++i) { + const uint value = values[i]; + if (value == GWN_PRIM_RESTART) + continue; + else if (value < min_value) + min_value = value; + else if (value > max_value) + max_value = value; + } + *min_out = min_value; + *max_out = max_value; + return max_value - min_value; +} + +static void squeeze_indices_byte(Gwn_IndexBufBuilder *builder, Gwn_IndexBuf* elem) +{ + const uint *values = builder->data; + const uint index_len = elem->index_len; + + /* data will never be *larger* than builder->data... + * converting in place to avoid extra allocation */ + GLubyte *data = (GLubyte *)builder->data; + + if (elem->max_index > 0xFF) { + const uint base = elem->min_index; + elem->base_index = base; + elem->min_index = 0; + elem->max_index -= base; + for (uint i = 0; i < index_len; ++i) { + data[i] = (values[i] == GWN_PRIM_RESTART) ? 0xFF : (GLubyte)(values[i] - base); + } + } + else { + elem->base_index = 0; + for (uint i = 0; i < index_len; ++i) { + data[i] = (GLubyte)(values[i]); + } + } +} + +static void squeeze_indices_short(Gwn_IndexBufBuilder *builder, Gwn_IndexBuf* elem) +{ + const uint *values = builder->data; + const uint index_len = elem->index_len; + + /* data will never be *larger* than builder->data... + * converting in place to avoid extra allocation */ + GLushort *data = (GLushort *)builder->data; + + if (elem->max_index > 0xFFFF) { + const uint base = elem->min_index; + elem->base_index = base; + elem->min_index = 0; + elem->max_index -= base; + for (uint i = 0; i < index_len; ++i) { + data[i] = (values[i] == GWN_PRIM_RESTART) ? 0xFFFF : (GLushort)(values[i] - base); + } + } + else { + elem->base_index = 0; + for (uint i = 0; i < index_len; ++i) { + data[i] = (GLushort)(values[i]); + } + } +} + +#endif /* GWN_TRACK_INDEX_RANGE */ + +Gwn_IndexBuf* GWN_indexbuf_build(Gwn_IndexBufBuilder* builder) +{ + Gwn_IndexBuf* elem = calloc(1, sizeof(Gwn_IndexBuf)); + GWN_indexbuf_build_in_place(builder, elem); + return elem; +} + +void GWN_indexbuf_build_in_place(Gwn_IndexBufBuilder* builder, Gwn_IndexBuf* elem) +{ +#if TRUST_NO_ONE + assert(builder->data != NULL); +#endif + elem->index_len = builder->index_len; + elem->use_prim_restart = builder->use_prim_restart; + +#if GWN_TRACK_INDEX_RANGE + uint range = index_range(builder->data, builder->index_len, &elem->min_index, &elem->max_index); + + /* count the primitive restart index. */ + if (elem->use_prim_restart) { + range += 1; + } + + if (range <= 0xFF) { + elem->index_type = GWN_INDEX_U8; + squeeze_indices_byte(builder, elem); + } + else if (range <= 0xFFFF) { + elem->index_type = GWN_INDEX_U16; + squeeze_indices_short(builder, elem); + } + else { + elem->index_type = GWN_INDEX_U32; + elem->base_index = 0; + } + elem->gl_index_type = convert_index_type_to_gl(elem->index_type); +#endif + + if (elem->vbo_id == 0) { + elem->vbo_id = GWN_buf_id_alloc(); + } + /* send data to GPU */ + /* GL_ELEMENT_ARRAY_BUFFER changes the state of the last VAO bound, + * so we use the GL_ARRAY_BUFFER here to create a buffer without + * interfering in the VAO state. */ + glBindBuffer(GL_ARRAY_BUFFER, elem->vbo_id); + glBufferData(GL_ARRAY_BUFFER, GWN_indexbuf_size_get(elem), builder->data, GL_STATIC_DRAW); + + /* discard builder (one-time use) */ + free(builder->data); + builder->data = NULL; + /* other fields are safe to leave */ +} + +void GWN_indexbuf_use(Gwn_IndexBuf* elem) +{ + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id); +} + +void GWN_indexbuf_discard(Gwn_IndexBuf* elem) +{ + if (elem->vbo_id) { + GWN_buf_id_free(elem->vbo_id); + } + free(elem); +} diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c index 5f22b7f9279..661594faf39 100644 --- a/source/blender/gpu/intern/gpu_immediate.c +++ b/source/blender/gpu/intern/gpu_immediate.c @@ -15,22 +15,145 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2016 Blender Foundation. + * The Original Code is Copyright (C) 2016 by Mike Erwin. * All rights reserved. * - * The Original Code is: all of this file. - * - * Contributor(s): Mike Erwin + * Contributor(s): Blender Foundation * * ***** END GPL LICENSE BLOCK ***** */ -#include "GPU_immediate.h" -#include "GPU_matrix.h" +/** \file blender/gpu/intern/gwn_immediate.c + * \ingroup gpu + * + * Gawain immediate mode work-alike + */ + #include "UI_resources.h" -#include "BLI_utildefines.h" +#include "GPU_attr_binding.h" +#include "GPU_buffer_id.h" +#include "GPU_immediate.h" +#include "GPU_vertex_array_id.h" + +#include "gpu_attr_binding_private.h" +#include "gpu_primitive_private.h" #include "gpu_shader_private.h" +#include "gpu_vertex_format_private.h" + +#include +#include + +/* necessary functions from matrix API */ +extern void GPU_matrix_bind(const Gwn_ShaderInterface*); +extern bool GPU_matrix_dirty_get(void); + +typedef struct { + /* TODO: organize this struct by frequency of change (run-time) */ + + Gwn_Batch* batch; + Gwn_Context* context; + + /* current draw call */ + GLubyte* buffer_data; + uint buffer_offset; + uint buffer_bytes_mapped; + uint vertex_len; + bool strict_vertex_len; + Gwn_PrimType prim_type; + + Gwn_VertFormat vertex_format; + + /* current vertex */ + uint vertex_idx; + GLubyte* vertex_data; + uint16_t unassigned_attrib_bits; /* which attributes of current vertex have not been given values? */ + + GLuint vbo_id; + GLuint vao_id; + + GLuint bound_program; + const Gwn_ShaderInterface* shader_interface; + Gwn_AttrBinding attrib_binding; + uint16_t prev_enabled_attrib_bits; /* <-- only affects this VAO, so we're ok */ +} Immediate; + +/* size of internal buffer -- make this adjustable? */ +#define IMM_BUFFER_SIZE (4 * 1024 * 1024) + +static bool initialized = false; +static Immediate imm; + +void immInit(void) +{ +#if TRUST_NO_ONE + assert(!initialized); +#endif + memset(&imm, 0, sizeof(Immediate)); + + imm.vbo_id = GWN_buf_id_alloc(); + glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id); + glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); + + imm.prim_type = GWN_PRIM_NONE; + imm.strict_vertex_len = true; + + glBindBuffer(GL_ARRAY_BUFFER, 0); + initialized = true; +} + +void immActivate(void) +{ +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == GWN_PRIM_NONE); /* make sure we're not between a Begin/End pair */ + assert(imm.vao_id == 0); +#endif + imm.vao_id = GWN_vao_alloc(); + imm.context = GWN_context_active_get(); +} + +void immDeactivate(void) +{ +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == GWN_PRIM_NONE); /* make sure we're not between a Begin/End pair */ + assert(imm.vao_id != 0); +#endif + GWN_vao_free(imm.vao_id, imm.context); + imm.vao_id = 0; + imm.prev_enabled_attrib_bits = 0; +} + +void immDestroy(void) +{ + GWN_buf_id_free(imm.vbo_id); + initialized = false; +} + +Gwn_VertFormat* immVertexFormat(void) +{ + GWN_vertformat_clear(&imm.vertex_format); + return &imm.vertex_format; +} + +void immBindProgram(GLuint program, const Gwn_ShaderInterface* shaderface) +{ +#if TRUST_NO_ONE + assert(imm.bound_program == 0); + assert(glIsProgram(program)); +#endif + + imm.bound_program = program; + imm.shader_interface = shaderface; + + if (!imm.vertex_format.packed) + VertexFormat_pack(&imm.vertex_format); + + glUseProgram(program); + get_attrib_locations(&imm.vertex_format, &imm.attrib_binding, shaderface); + GPU_matrix_bind(shaderface); +} void immBindBuiltinProgram(GPUBuiltinShader shader_id) { @@ -38,6 +161,718 @@ void immBindBuiltinProgram(GPUBuiltinShader shader_id) immBindProgram(shader->program, shader->interface); } +void immUnbindProgram(void) +{ +#if TRUST_NO_ONE + assert(imm.bound_program != 0); +#endif +#if PROGRAM_NO_OPTI + glUseProgram(0); +#endif + imm.bound_program = 0; +} + +#if TRUST_NO_ONE +static bool vertex_count_makes_sense_for_primitive(uint vertex_len, Gwn_PrimType prim_type) +{ + /* does vertex_len make sense for this primitive type? */ + if (vertex_len == 0) { + return false; + } + + switch (prim_type) { + case GWN_PRIM_POINTS: + return true; + case GWN_PRIM_LINES: + return vertex_len % 2 == 0; + case GWN_PRIM_LINE_STRIP: + case GWN_PRIM_LINE_LOOP: + return vertex_len >= 2; + case GWN_PRIM_LINE_STRIP_ADJ: + return vertex_len >= 4; + case GWN_PRIM_TRIS: + return vertex_len % 3 == 0; + case GWN_PRIM_TRI_STRIP: + case GWN_PRIM_TRI_FAN: + return vertex_len >= 3; + default: + return false; + } +} +#endif + +void immBegin(Gwn_PrimType prim_type, uint vertex_len) +{ +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == GWN_PRIM_NONE); /* make sure we haven't already begun */ + assert(vertex_count_makes_sense_for_primitive(vertex_len, prim_type)); +#endif + imm.prim_type = prim_type; + imm.vertex_len = vertex_len; + imm.vertex_idx = 0; + imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; + + /* how many bytes do we need for this draw call? */ + const uint bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_len); + +#if TRUST_NO_ONE + assert(bytes_needed <= IMM_BUFFER_SIZE); +#endif + + glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id); + + /* does the current buffer have enough room? */ + const uint available_bytes = IMM_BUFFER_SIZE - imm.buffer_offset; + /* ensure vertex data is aligned */ + const uint pre_padding = padding(imm.buffer_offset, imm.vertex_format.stride); /* might waste a little space, but it's safe */ + if ((bytes_needed + pre_padding) <= available_bytes) { + imm.buffer_offset += pre_padding; + } + else { + /* orphan this buffer & start with a fresh one */ + /* this method works on all platforms, old & new */ + glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); + + imm.buffer_offset = 0; + } + +/* printf("mapping %u to %u\n", imm.buffer_offset, imm.buffer_offset + bytes_needed - 1); */ + + imm.buffer_data = glMapBufferRange(GL_ARRAY_BUFFER, imm.buffer_offset, bytes_needed, + GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | (imm.strict_vertex_len ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT)); + +#if TRUST_NO_ONE + assert(imm.buffer_data != NULL); +#endif + + imm.buffer_bytes_mapped = bytes_needed; + imm.vertex_data = imm.buffer_data; +} + +void immBeginAtMost(Gwn_PrimType prim_type, uint vertex_len) +{ +#if TRUST_NO_ONE + assert(vertex_len > 0); +#endif + + imm.strict_vertex_len = false; + immBegin(prim_type, vertex_len); +} + + +Gwn_Batch* immBeginBatch(Gwn_PrimType prim_type, uint vertex_len) +{ +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == GWN_PRIM_NONE); /* make sure we haven't already begun */ + assert(vertex_count_makes_sense_for_primitive(vertex_len, prim_type)); +#endif + imm.prim_type = prim_type; + imm.vertex_len = vertex_len; + imm.vertex_idx = 0; + imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; + + Gwn_VertBuf* verts = GWN_vertbuf_create_with_format(&imm.vertex_format); + GWN_vertbuf_data_alloc(verts, vertex_len); + + imm.buffer_bytes_mapped = GWN_vertbuf_size_get(verts); + imm.vertex_data = verts->data; + + imm.batch = GWN_batch_create_ex(prim_type, verts, NULL, GWN_BATCH_OWNS_VBO); + imm.batch->phase = GWN_BATCH_BUILDING; + + return imm.batch; +} + +Gwn_Batch* immBeginBatchAtMost(Gwn_PrimType prim_type, uint vertex_len) +{ + imm.strict_vertex_len = false; + return immBeginBatch(prim_type, vertex_len); +} + +static void immDrawSetup(void) +{ + /* set up VAO -- can be done during Begin or End really */ + glBindVertexArray(imm.vao_id); + + /* enable/disable vertex attribs as needed */ + if (imm.attrib_binding.enabled_bits != imm.prev_enabled_attrib_bits) { + for (uint loc = 0; loc < GWN_VERT_ATTR_MAX_LEN; ++loc) { + bool is_enabled = imm.attrib_binding.enabled_bits & (1 << loc); + bool was_enabled = imm.prev_enabled_attrib_bits & (1 << loc); + + if (is_enabled && !was_enabled) { + glEnableVertexAttribArray(loc); + } + else if (was_enabled && !is_enabled) { + glDisableVertexAttribArray(loc); + } + } + + imm.prev_enabled_attrib_bits = imm.attrib_binding.enabled_bits; + } + + const uint stride = imm.vertex_format.stride; + + for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) { + const Gwn_VertAttr* a = imm.vertex_format.attribs + a_idx; + + const uint offset = imm.buffer_offset + a->offset; + const GLvoid* pointer = (const GLubyte*)0 + offset; + + const uint loc = read_attrib_location(&imm.attrib_binding, a_idx); + + switch (a->fetch_mode) { + case GWN_FETCH_FLOAT: + case GWN_FETCH_INT_TO_FLOAT: + glVertexAttribPointer(loc, a->comp_len, a->gl_comp_type, GL_FALSE, stride, pointer); + break; + case GWN_FETCH_INT_TO_FLOAT_UNIT: + glVertexAttribPointer(loc, a->comp_len, a->gl_comp_type, GL_TRUE, stride, pointer); + break; + case GWN_FETCH_INT: + glVertexAttribIPointer(loc, a->comp_len, a->gl_comp_type, stride, pointer); + } + } + + if (GPU_matrix_dirty_get()) { + GPU_matrix_bind(imm.shader_interface); + } +} + +void immEnd(void) +{ +#if TRUST_NO_ONE + assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ +#endif + + uint buffer_bytes_used; + if (imm.strict_vertex_len) { +#if TRUST_NO_ONE + assert(imm.vertex_idx == imm.vertex_len); /* with all vertices defined */ +#endif + buffer_bytes_used = imm.buffer_bytes_mapped; + } + else { +#if TRUST_NO_ONE + assert(imm.vertex_idx <= imm.vertex_len); +#endif + if (imm.vertex_idx == imm.vertex_len) { + buffer_bytes_used = imm.buffer_bytes_mapped; + } + else { +#if TRUST_NO_ONE + assert(imm.vertex_idx == 0 || vertex_count_makes_sense_for_primitive(imm.vertex_idx, imm.prim_type)); +#endif + imm.vertex_len = imm.vertex_idx; + buffer_bytes_used = vertex_buffer_size(&imm.vertex_format, imm.vertex_len); + /* unused buffer bytes are available to the next immBegin */ + } + /* tell OpenGL what range was modified so it doesn't copy the whole mapped range */ + glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, buffer_bytes_used); + } + + if (imm.batch) { + if (buffer_bytes_used != imm.buffer_bytes_mapped) { + GWN_vertbuf_data_resize(imm.batch->verts[0], imm.vertex_len); + /* TODO: resize only if vertex count is much smaller */ + } + GWN_batch_program_set(imm.batch, imm.bound_program, imm.shader_interface); + imm.batch->phase = GWN_BATCH_READY_TO_DRAW; + imm.batch = NULL; /* don't free, batch belongs to caller */ + } + else { + glUnmapBuffer(GL_ARRAY_BUFFER); + if (imm.vertex_len > 0) { + immDrawSetup(); + glDrawArrays(convert_prim_type_to_gl(imm.prim_type), 0, imm.vertex_len); + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + /* prep for next immBegin */ + imm.buffer_offset += buffer_bytes_used; + } + + /* prep for next immBegin */ + imm.prim_type = GWN_PRIM_NONE; + imm.strict_vertex_len = true; +} + +static void setAttribValueBit(uint attrib_id) +{ + uint16_t mask = 1 << attrib_id; +#if TRUST_NO_ONE + assert(imm.unassigned_attrib_bits & mask); /* not already set */ +#endif + imm.unassigned_attrib_bits &= ~mask; +} + + +/* --- generic attribute functions --- */ + +void immAttrib1f(uint attrib_id, float x) +{ + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attr_len); + assert(attrib->comp_type == GWN_COMP_F32); + assert(attrib->comp_len == 1); + assert(imm.vertex_idx < imm.vertex_len); + assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ +#endif + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +/* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */ + + data[0] = x; +} + +void immAttrib2f(uint attrib_id, float x, float y) +{ + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attr_len); + assert(attrib->comp_type == GWN_COMP_F32); + assert(attrib->comp_len == 2); + assert(imm.vertex_idx < imm.vertex_len); + assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ +#endif + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +/* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */ + + data[0] = x; + data[1] = y; +} + +void immAttrib3f(uint attrib_id, float x, float y, float z) +{ + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attr_len); + assert(attrib->comp_type == GWN_COMP_F32); + assert(attrib->comp_len == 3); + assert(imm.vertex_idx < imm.vertex_len); + assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ +#endif + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +/* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */ + + data[0] = x; + data[1] = y; + data[2] = z; +} + +void immAttrib4f(uint attrib_id, float x, float y, float z, float w) +{ + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attr_len); + assert(attrib->comp_type == GWN_COMP_F32); + assert(attrib->comp_len == 4); + assert(imm.vertex_idx < imm.vertex_len); + assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ +#endif + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +/* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */ + + data[0] = x; + data[1] = y; + data[2] = z; + data[3] = w; +} + +void immAttrib1u(uint attrib_id, uint x) +{ + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attr_len); + assert(attrib->comp_type == GWN_COMP_U32); + assert(attrib->comp_len == 1); + assert(imm.vertex_idx < imm.vertex_len); + assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ +#endif + setAttribValueBit(attrib_id); + + uint* data = (uint*)(imm.vertex_data + attrib->offset); + + data[0] = x; +} + +void immAttrib2i(uint attrib_id, int x, int y) +{ + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attr_len); + assert(attrib->comp_type == GWN_COMP_I32); + assert(attrib->comp_len == 2); + assert(imm.vertex_idx < imm.vertex_len); + assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ +#endif + setAttribValueBit(attrib_id); + + int* data = (int*)(imm.vertex_data + attrib->offset); + + data[0] = x; + data[1] = y; +} + +void immAttrib2s(uint attrib_id, short x, short y) +{ + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attr_len); + assert(attrib->comp_type == GWN_COMP_I16); + assert(attrib->comp_len == 2); + assert(imm.vertex_idx < imm.vertex_len); + assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ +#endif + setAttribValueBit(attrib_id); + + short* data = (short*)(imm.vertex_data + attrib->offset); + + data[0] = x; + data[1] = y; +} + +void immAttrib2fv(uint attrib_id, const float data[2]) +{ + immAttrib2f(attrib_id, data[0], data[1]); +} + +void immAttrib3fv(uint attrib_id, const float data[3]) +{ + immAttrib3f(attrib_id, data[0], data[1], data[2]); +} + +void immAttrib4fv(uint attrib_id, const float data[4]) +{ + immAttrib4f(attrib_id, data[0], data[1], data[2], data[3]); +} + +void immAttrib3ub(uint attrib_id, unsigned char r, unsigned char g, unsigned char b) +{ + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attr_len); + assert(attrib->comp_type == GWN_COMP_U8); + assert(attrib->comp_len == 3); + assert(imm.vertex_idx < imm.vertex_len); + assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ +#endif + setAttribValueBit(attrib_id); + + GLubyte* data = imm.vertex_data + attrib->offset; +/* printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); */ + + data[0] = r; + data[1] = g; + data[2] = b; +} + +void immAttrib4ub(uint attrib_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attr_len); + assert(attrib->comp_type == GWN_COMP_U8); + assert(attrib->comp_len == 4); + assert(imm.vertex_idx < imm.vertex_len); + assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ +#endif + setAttribValueBit(attrib_id); + + GLubyte* data = imm.vertex_data + attrib->offset; +/* printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); */ + + data[0] = r; + data[1] = g; + data[2] = b; + data[3] = a; +} + +void immAttrib3ubv(uint attrib_id, const unsigned char data[3]) +{ + immAttrib3ub(attrib_id, data[0], data[1], data[2]); +} + +void immAttrib4ubv(uint attrib_id, const unsigned char data[4]) +{ + immAttrib4ub(attrib_id, data[0], data[1], data[2], data[3]); +} + +void immSkipAttrib(uint attrib_id) +{ +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attr_len); + assert(imm.vertex_idx < imm.vertex_len); + assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ +#endif + setAttribValueBit(attrib_id); +} + +static void immEndVertex(void) /* and move on to the next vertex */ +{ +#if TRUST_NO_ONE + assert(imm.prim_type != GWN_PRIM_NONE); /* make sure we're between a Begin/End pair */ + assert(imm.vertex_idx < imm.vertex_len); +#endif + + /* have all attribs been assigned values? + * if not, copy value from previous vertex */ + if (imm.unassigned_attrib_bits) { +#if TRUST_NO_ONE + assert(imm.vertex_idx > 0); /* first vertex must have all attribs specified */ +#endif + for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) { + if ((imm.unassigned_attrib_bits >> a_idx) & 1) { + const Gwn_VertAttr* a = imm.vertex_format.attribs + a_idx; + +/* printf("copying %s from vertex %u to %u\n", a->name, imm.vertex_idx - 1, imm.vertex_idx); */ + + GLubyte* data = imm.vertex_data + a->offset; + memcpy(data, data - imm.vertex_format.stride, a->sz); + /* TODO: consolidate copy of adjacent attributes */ + } + } + } + + imm.vertex_idx++; + imm.vertex_data += imm.vertex_format.stride; + imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; +} + +void immVertex2f(uint attrib_id, float x, float y) +{ + immAttrib2f(attrib_id, x, y); + immEndVertex(); +} + +void immVertex3f(uint attrib_id, float x, float y, float z) +{ + immAttrib3f(attrib_id, x, y, z); + immEndVertex(); +} + +void immVertex4f(uint attrib_id, float x, float y, float z, float w) +{ + immAttrib4f(attrib_id, x, y, z, w); + immEndVertex(); +} + +void immVertex2i(uint attrib_id, int x, int y) +{ + immAttrib2i(attrib_id, x, y); + immEndVertex(); +} + +void immVertex2s(uint attrib_id, short x, short y) +{ + immAttrib2s(attrib_id, x, y); + immEndVertex(); +} + +void immVertex2fv(uint attrib_id, const float data[2]) +{ + immAttrib2f(attrib_id, data[0], data[1]); + immEndVertex(); +} + +void immVertex3fv(uint attrib_id, const float data[3]) +{ + immAttrib3f(attrib_id, data[0], data[1], data[2]); + immEndVertex(); +} + +void immVertex2iv(uint attrib_id, const int data[2]) +{ + immAttrib2i(attrib_id, data[0], data[1]); + immEndVertex(); +} + + +/* --- generic uniform functions --- */ + +#if 0 + #if TRUST_NO_ONE + #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(imm.shader_interface, name); assert(uniform); + #else + #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(imm.shader_interface, name); + #endif +#else + /* NOTE: It is possible to have uniform fully optimized out from the shader. + * In this case we can't assert failure or allow NULL-pointer dereference. + * TODO(sergey): How can we detect existing-but-optimized-out uniform but still + * catch typos in uniform names passed to immUniform*() functions? */ + #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(imm.shader_interface, name); if (uniform == NULL) return; +#endif + +void immUniform1f(const char* name, float x) +{ + GET_UNIFORM + glUniform1f(uniform->location, x); +} + +void immUniform2f(const char* name, float x, float y) +{ + GET_UNIFORM + glUniform2f(uniform->location, x, y); +} + +void immUniform2fv(const char* name, const float data[2]) +{ + GET_UNIFORM + glUniform2fv(uniform->location, 1, data); +} + +void immUniform3f(const char* name, float x, float y, float z) +{ + GET_UNIFORM + glUniform3f(uniform->location, x, y, z); +} + +void immUniform3fv(const char* name, const float data[3]) +{ + GET_UNIFORM + glUniform3fv(uniform->location, 1, data); +} + +/* can increase this limit or move to another file */ +#define MAX_UNIFORM_NAME_LEN 60 + +void immUniformArray3fv(const char* bare_name, const float *data, int count) +{ + /* look up "name[0]" when given "name" */ + const size_t len = strlen(bare_name); +#if TRUST_NO_ONE + assert(len <= MAX_UNIFORM_NAME_LEN); +#endif + char name[MAX_UNIFORM_NAME_LEN]; + strcpy(name, bare_name); + name[len + 0] = '['; + name[len + 1] = '0'; + name[len + 2] = ']'; + name[len + 3] = '\0'; + + GET_UNIFORM + glUniform3fv(uniform->location, count, data); +} + +void immUniform4f(const char* name, float x, float y, float z, float w) +{ + GET_UNIFORM + glUniform4f(uniform->location, x, y, z, w); +} + +void immUniform4fv(const char* name, const float data[4]) +{ + GET_UNIFORM + glUniform4fv(uniform->location, 1, data); +} + +void immUniformArray4fv(const char* bare_name, const float *data, int count) +{ + /* look up "name[0]" when given "name" */ + const size_t len = strlen(bare_name); +#if TRUST_NO_ONE + assert(len <= MAX_UNIFORM_NAME_LEN); +#endif + char name[MAX_UNIFORM_NAME_LEN]; + strcpy(name, bare_name); + name[len + 0] = '['; + name[len + 1] = '0'; + name[len + 2] = ']'; + name[len + 3] = '\0'; + + GET_UNIFORM + glUniform4fv(uniform->location, count, data); +} + +void immUniformMatrix4fv(const char* name, const float data[4][4]) +{ + GET_UNIFORM + glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (float *)data); +} + +void immUniform1i(const char* name, int x) +{ + GET_UNIFORM + glUniform1i(uniform->location, x); +} + +void immUniform4iv(const char* name, const int data[4]) +{ + GET_UNIFORM + glUniform4iv(uniform->location, 1, data); +} + +/* --- convenience functions for setting "uniform vec4 color" --- */ + +void immUniformColor4f(float r, float g, float b, float a) +{ + const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform_builtin(imm.shader_interface, GWN_UNIFORM_COLOR); +#if TRUST_NO_ONE + assert(uniform != NULL); +#endif + glUniform4f(uniform->location, r, g, b, a); +} + +void immUniformColor4fv(const float rgba[4]) +{ + immUniformColor4f(rgba[0], rgba[1], rgba[2], rgba[3]); +} + +void immUniformColor3f(float r, float g, float b) +{ + immUniformColor4f(r, g, b, 1.0f); +} + +void immUniformColor3fv(const float rgb[3]) +{ + immUniformColor4f(rgb[0], rgb[1], rgb[2], 1.0f); +} + +void immUniformColor3fvAlpha(const float rgb[3], float a) +{ + immUniformColor4f(rgb[0], rgb[1], rgb[2], a); +} + +/* TODO: v-- treat as sRGB? --v */ + +void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b) +{ + const float scale = 1.0f / 255.0f; + immUniformColor4f(scale * r, scale * g, scale * b, 1.0f); +} + +void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + const float scale = 1.0f / 255.0f; + immUniformColor4f(scale * r, scale * g, scale * b, scale * a); +} + +void immUniformColor3ubv(const unsigned char rgb[3]) +{ + immUniformColor3ub(rgb[0], rgb[1], rgb[2]); +} + +void immUniformColor3ubvAlpha(const unsigned char rgb[3], unsigned char alpha) +{ + immUniformColor4ub(rgb[0], rgb[1], rgb[2], alpha); +} + +void immUniformColor4ubv(const unsigned char rgba[4]) +{ + immUniformColor4ub(rgba[0], rgba[1], rgba[2], rgba[3]); +} + void immUniformThemeColor(int color_id) { float color[4]; diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c index 30672af9c02..4b2fb1b8e8a 100644 --- a/source/blender/gpu/intern/gpu_immediate_util.c +++ b/source/blender/gpu/intern/gpu_immediate_util.c @@ -18,8 +18,10 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file source/blender/gpu/intern/gpu_immediate_util.c +/** \file blender/gpu/intern/gwn_imm_util.c * \ingroup gpu + * + * Gawain immediate mode drawing utilities */ #include @@ -66,6 +68,72 @@ static const int cube_line_index[12][2] = { {6, 7}, }; +void immRectf(uint pos, float x1, float y1, float x2, float y2) +{ + immBegin(GWN_PRIM_TRI_FAN, 4); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x1, y2); + immEnd(); +} + +void immRecti(uint pos, int x1, int y1, int x2, int y2) +{ + immBegin(GWN_PRIM_TRI_FAN, 4); + immVertex2i(pos, x1, y1); + immVertex2i(pos, x2, y1); + immVertex2i(pos, x2, y2); + immVertex2i(pos, x1, y2); + immEnd(); +} + +void immRectf_fast_with_color(uint pos, uint col, float x1, float y1, float x2, float y2, const float color[4]) +{ + immAttrib4fv(col, color); + immVertex2f(pos, x1, y1); + immAttrib4fv(col, color); + immVertex2f(pos, x2, y1); + immAttrib4fv(col, color); + immVertex2f(pos, x2, y2); + + immAttrib4fv(col, color); + immVertex2f(pos, x1, y1); + immAttrib4fv(col, color); + immVertex2f(pos, x2, y2); + immAttrib4fv(col, color); + immVertex2f(pos, x1, y2); +} + +void immRecti_fast_with_color(uint pos, uint col, int x1, int y1, int x2, int y2, const float color[4]) +{ + immAttrib4fv(col, color); + immVertex2i(pos, x1, y1); + immAttrib4fv(col, color); + immVertex2i(pos, x2, y1); + immAttrib4fv(col, color); + immVertex2i(pos, x2, y2); + + immAttrib4fv(col, color); + immVertex2i(pos, x1, y1); + immAttrib4fv(col, color); + immVertex2i(pos, x2, y2); + immAttrib4fv(col, color); + immVertex2i(pos, x1, y2); +} + +#if 0 /* more complete version in case we want that */ +void immRecti_complete(int x1, int y1, int x2, int y2, const float color[4]) +{ + Gwn_VertFormat *format = immVertexFormat(); + uint pos = add_attrib(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(color); + immRecti(pos, x1, y1, x2, y2); + immUnbindProgram(); +} +#endif + /** * Pack color into 3 bytes * diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c index 2af1375a620..13c6fbea1c6 100644 --- a/source/blender/gpu/intern/gpu_matrix.c +++ b/source/blender/gpu/intern/gpu_matrix.c @@ -29,7 +29,7 @@ * \ingroup gpu */ -#include "../../../intern/gawain/gawain/gwn_shader_interface.h" +#include "GPU_shader_interface.h" #define SUPPRESS_GENERIC_MATRIX_API #define USE_GPU_PY_MATRIX_API /* only so values are declared */ diff --git a/source/blender/gpu/intern/gpu_primitive.c b/source/blender/gpu/intern/gpu_primitive.c new file mode 100644 index 00000000000..0f0c28c05dc --- /dev/null +++ b/source/blender/gpu/intern/gpu_primitive.c @@ -0,0 +1,84 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gwn_primitive.c + * \ingroup gpu + * + * Gawain geometric primitives + */ + +#include "GPU_primitive.h" +#include "gpu_primitive_private.h" + +Gwn_PrimClass GWN_primtype_class(Gwn_PrimType prim_type) +{ + static const Gwn_PrimClass classes[] = { + [GWN_PRIM_POINTS] = GWN_PRIM_CLASS_POINT, + [GWN_PRIM_LINES] = GWN_PRIM_CLASS_LINE, + [GWN_PRIM_LINE_STRIP] = GWN_PRIM_CLASS_LINE, + [GWN_PRIM_LINE_LOOP] = GWN_PRIM_CLASS_LINE, + [GWN_PRIM_TRIS] = GWN_PRIM_CLASS_SURFACE, + [GWN_PRIM_TRI_STRIP] = GWN_PRIM_CLASS_SURFACE, + [GWN_PRIM_TRI_FAN] = GWN_PRIM_CLASS_SURFACE, + + [GWN_PRIM_LINES_ADJ] = GWN_PRIM_CLASS_LINE, + [GWN_PRIM_LINE_STRIP_ADJ] = GWN_PRIM_CLASS_LINE, + [GWN_PRIM_TRIS_ADJ] = GWN_PRIM_CLASS_SURFACE, + + [GWN_PRIM_NONE] = GWN_PRIM_CLASS_NONE + }; + + return classes[prim_type]; +} + +bool GWN_primtype_belongs_to_class(Gwn_PrimType prim_type, Gwn_PrimClass prim_class) +{ + if (prim_class == GWN_PRIM_CLASS_NONE && prim_type == GWN_PRIM_NONE) { + return true; + } + return prim_class & GWN_primtype_class(prim_type); +} + +GLenum convert_prim_type_to_gl(Gwn_PrimType prim_type) +{ +#if TRUST_NO_ONE + assert(prim_type != GWN_PRIM_NONE); +#endif + static const GLenum table[] = { + [GWN_PRIM_POINTS] = GL_POINTS, + [GWN_PRIM_LINES] = GL_LINES, + [GWN_PRIM_LINE_STRIP] = GL_LINE_STRIP, + [GWN_PRIM_LINE_LOOP] = GL_LINE_LOOP, + [GWN_PRIM_TRIS] = GL_TRIANGLES, + [GWN_PRIM_TRI_STRIP] = GL_TRIANGLE_STRIP, + [GWN_PRIM_TRI_FAN] = GL_TRIANGLE_FAN, + + [GWN_PRIM_LINES_ADJ] = GL_LINES_ADJACENCY, + [GWN_PRIM_LINE_STRIP_ADJ] = GL_LINE_STRIP_ADJACENCY, + [GWN_PRIM_TRIS_ADJ] = GL_TRIANGLES_ADJACENCY, + }; + + return table[prim_type]; +} diff --git a/source/blender/gpu/intern/gpu_primitive_private.h b/source/blender/gpu/intern/gpu_primitive_private.h new file mode 100644 index 00000000000..6d3f1e20da7 --- /dev/null +++ b/source/blender/gpu/intern/gpu_primitive_private.h @@ -0,0 +1,37 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_primitive_private.h + * \ingroup gpu + * + * Gawain geometric primitives + */ + +#ifndef __GWN_PRIMITIVE_PRIVATE_H__ +#define __GWN_PRIMITIVE_PRIVATE_H__ + +GLenum convert_prim_type_to_gl(Gwn_PrimType); + +#endif /* __GWN_PRIMITIVE_PRIVATE_H__ */ diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c new file mode 100644 index 00000000000..56b25726a84 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_interface.c @@ -0,0 +1,361 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gwn_shader_interface.c + * \ingroup gpu + * + * Gawain shader interface (C --> GLSL) + */ + +#include "gpu_batch_private.h" +#include "GPU_shader_interface.h" +#include "GPU_vertex_array_id.h" +#include +#include +#include + +#define DEBUG_SHADER_INTERFACE 0 + +#if DEBUG_SHADER_INTERFACE + #include +#endif + +static const char* BuiltinUniform_name(Gwn_UniformBuiltin u) +{ + static const char* names[] = { + [GWN_UNIFORM_NONE] = NULL, + + [GWN_UNIFORM_MODEL] = "ModelMatrix", + [GWN_UNIFORM_VIEW] = "ViewMatrix", + [GWN_UNIFORM_MODELVIEW] = "ModelViewMatrix", + [GWN_UNIFORM_PROJECTION] = "ProjectionMatrix", + [GWN_UNIFORM_VIEWPROJECTION] = "ViewProjectionMatrix", + [GWN_UNIFORM_MVP] = "ModelViewProjectionMatrix", + + [GWN_UNIFORM_MODEL_INV] = "ModelMatrixInverse", + [GWN_UNIFORM_VIEW_INV] = "ViewMatrixInverse", + [GWN_UNIFORM_MODELVIEW_INV] = "ModelViewMatrixInverse", + [GWN_UNIFORM_PROJECTION_INV] = "ProjectionMatrixInverse", + [GWN_UNIFORM_VIEWPROJECTION_INV] = "ViewProjectionMatrixInverse", + + [GWN_UNIFORM_NORMAL] = "NormalMatrix", + [GWN_UNIFORM_WORLDNORMAL] = "WorldNormalMatrix", + [GWN_UNIFORM_CAMERATEXCO] = "CameraTexCoFactors", + [GWN_UNIFORM_ORCO] = "OrcoTexCoFactors", + + [GWN_UNIFORM_COLOR] = "color", + [GWN_UNIFORM_EYE] = "eye", + [GWN_UNIFORM_CALLID] = "callId", + + [GWN_UNIFORM_CUSTOM] = NULL, + [GWN_NUM_UNIFORMS] = NULL, + }; + + return names[u]; +} + +GWN_INLINE bool match(const char* a, const char* b) +{ + return strcmp(a, b) == 0; +} + +GWN_INLINE uint hash_string(const char *str) +{ + uint i = 0, c; + while ((c = *str++)) { + i = i * 37 + c; + } + return i; +} + +GWN_INLINE void set_input_name(Gwn_ShaderInterface* shaderface, Gwn_ShaderInput* input, + const char* name, uint32_t name_len) +{ + input->name_offset = shaderface->name_buffer_offset; + input->name_hash = hash_string(name); + shaderface->name_buffer_offset += name_len + 1; /* include NULL terminator */ +} + +GWN_INLINE void shader_input_to_bucket(Gwn_ShaderInput* input, + Gwn_ShaderInput* buckets[GWN_NUM_SHADERINTERFACE_BUCKETS]) +{ + const uint bucket_index = input->name_hash % GWN_NUM_SHADERINTERFACE_BUCKETS; + input->next = buckets[bucket_index]; + buckets[bucket_index] = input; +} + +GWN_INLINE const Gwn_ShaderInput* buckets_lookup(Gwn_ShaderInput* const buckets[GWN_NUM_SHADERINTERFACE_BUCKETS], + const char *name_buffer, const char *name) +{ + const uint name_hash = hash_string(name); + const uint bucket_index = name_hash % GWN_NUM_SHADERINTERFACE_BUCKETS; + const Gwn_ShaderInput* input = buckets[bucket_index]; + if (input == NULL) { + /* Requested uniform is not found at all. */ + return NULL; + } + /* Optimization bit: if there is no hash collision detected when constructing shader interface + * it means we can only request the single possible uniform. Surely, it's possible we request + * uniform which causes hash collision, but that will be detected in debug builds. */ + if (input->next == NULL) { + if (name_hash == input->name_hash) { +#if TRUST_NO_ONE + assert(match(name_buffer + input->name_offset, name)); +#endif + return input; + } + return NULL; + } + /* Work through possible collisions. */ + const Gwn_ShaderInput* next = input; + while (next != NULL) { + input = next; + next = input->next; + if (input->name_hash != name_hash) { + continue; + } + if (match(name_buffer + input->name_offset, name)) { + return input; + } + } + return NULL; /* not found */ +} + +GWN_INLINE void buckets_free(Gwn_ShaderInput* buckets[GWN_NUM_SHADERINTERFACE_BUCKETS]) +{ + for (uint bucket_index = 0; bucket_index < GWN_NUM_SHADERINTERFACE_BUCKETS; ++bucket_index) { + Gwn_ShaderInput *input = buckets[bucket_index]; + while (input != NULL) { + Gwn_ShaderInput *input_next = input->next; + free(input); + input = input_next; + } + } +} + +static bool setup_builtin_uniform(Gwn_ShaderInput* input, const char* name) +{ + /* TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types */ + + /* detect built-in uniforms (name must match) */ + for (Gwn_UniformBuiltin u = GWN_UNIFORM_NONE + 1; u < GWN_UNIFORM_CUSTOM; ++u) { + const char* builtin_name = BuiltinUniform_name(u); + if (match(name, builtin_name)) { + input->builtin_type = u; + return true; + } + } + input->builtin_type = GWN_UNIFORM_CUSTOM; + return false; +} + +static const Gwn_ShaderInput* add_uniform(Gwn_ShaderInterface* shaderface, const char* name) +{ + Gwn_ShaderInput* input = malloc(sizeof(Gwn_ShaderInput)); + + input->location = glGetUniformLocation(shaderface->program, name); + + uint name_len = strlen(name); + shaderface->name_buffer = realloc(shaderface->name_buffer, shaderface->name_buffer_offset + name_len + 1); /* include NULL terminator */ + char* name_buffer = shaderface->name_buffer + shaderface->name_buffer_offset; + strcpy(name_buffer, name); + + set_input_name(shaderface, input, name, name_len); + setup_builtin_uniform(input, name); + + shader_input_to_bucket(input, shaderface->uniform_buckets); + if (input->builtin_type != GWN_UNIFORM_NONE && + input->builtin_type != GWN_UNIFORM_CUSTOM) + { + shaderface->builtin_uniforms[input->builtin_type] = input; + } +#if DEBUG_SHADER_INTERFACE + printf("Gwn_ShaderInterface %p, program %d, uniform[] '%s' at location %d\n", shaderface, + shaderface->program, + name, + input->location); +#endif + return input; +} + +Gwn_ShaderInterface* GWN_shaderinterface_create(int32_t program) +{ + Gwn_ShaderInterface* shaderface = calloc(1, sizeof(Gwn_ShaderInterface)); + shaderface->program = program; + +#if DEBUG_SHADER_INTERFACE + printf("%s {\n", __func__); /* enter function */ + printf("Gwn_ShaderInterface %p, program %d\n", shaderface, program); +#endif + + GLint max_attrib_name_len, attr_len; + glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attrib_name_len); + glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attr_len); + + GLint max_ubo_name_len, ubo_len; + glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len); + glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len); + + const uint32_t name_buffer_len = attr_len * max_attrib_name_len + ubo_len * max_ubo_name_len; + shaderface->name_buffer = malloc(name_buffer_len); + + /* Attributes */ + for (uint32_t i = 0; i < attr_len; ++i) { + Gwn_ShaderInput* input = malloc(sizeof(Gwn_ShaderInput)); + GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset; + char* name = shaderface->name_buffer + shaderface->name_buffer_offset; + GLsizei name_len = 0; + + glGetActiveAttrib(program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name); + + /* remove "[0]" from array name */ + if (name[name_len-1] == ']') { + name[name_len-3] = '\0'; + name_len -= 3; + } + + /* TODO: reject DOUBLE gl_types */ + + input->location = glGetAttribLocation(program, name); + + set_input_name(shaderface, input, name, name_len); + + shader_input_to_bucket(input, shaderface->attrib_buckets); + +#if DEBUG_SHADER_INTERFACE + printf("attrib[%u] '%s' at location %d\n", i, name, input->location); +#endif + } + /* Uniform Blocks */ + for (uint32_t i = 0; i < ubo_len; ++i) { + Gwn_ShaderInput* input = malloc(sizeof(Gwn_ShaderInput)); + GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset; + char* name = shaderface->name_buffer + shaderface->name_buffer_offset; + GLsizei name_len = 0; + + glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name); + + input->location = i; + + set_input_name(shaderface, input, name, name_len); + + shader_input_to_bucket(input, shaderface->ubo_buckets); + +#if DEBUG_SHADER_INTERFACE + printf("ubo '%s' at location %d\n", name, input->location); +#endif + } + /* Builtin Uniforms */ + for (Gwn_UniformBuiltin u = GWN_UNIFORM_NONE + 1; u < GWN_UNIFORM_CUSTOM; ++u) { + const char* builtin_name = BuiltinUniform_name(u); + if (glGetUniformLocation(program, builtin_name) != -1) { + add_uniform((Gwn_ShaderInterface*)shaderface, builtin_name); + } + } + /* Batches ref buffer */ + shaderface->batches_len = GWN_SHADERINTERFACE_REF_ALLOC_COUNT; + shaderface->batches = calloc(shaderface->batches_len, sizeof(Gwn_Batch*)); + + return shaderface; +} + +void GWN_shaderinterface_discard(Gwn_ShaderInterface* shaderface) +{ + /* Free memory used by buckets and has entries. */ + buckets_free(shaderface->uniform_buckets); + buckets_free(shaderface->attrib_buckets); + buckets_free(shaderface->ubo_buckets); + /* Free memory used by name_buffer. */ + free(shaderface->name_buffer); + /* Remove this interface from all linked Batches vao cache. */ + for (int i = 0; i < shaderface->batches_len; ++i) { + if (shaderface->batches[i] != NULL) { + gwn_batch_remove_interface_ref(shaderface->batches[i], shaderface); + } + } + free(shaderface->batches); + /* Free memory used by shader interface by its self. */ + free(shaderface); +} + +const Gwn_ShaderInput* GWN_shaderinterface_uniform(const Gwn_ShaderInterface* shaderface, const char* name) +{ + /* TODO: Warn if we find a matching builtin, since these can be looked up much quicker. */ + const Gwn_ShaderInput* input = buckets_lookup(shaderface->uniform_buckets, shaderface->name_buffer, name); + /* If input is not found add it so it's found next time. */ + if (input == NULL) { + input = add_uniform((Gwn_ShaderInterface*)shaderface, name); + } + return (input->location != -1) ? input : NULL; +} + +const Gwn_ShaderInput* GWN_shaderinterface_uniform_builtin( + const Gwn_ShaderInterface* shaderface, Gwn_UniformBuiltin builtin) +{ +#if TRUST_NO_ONE + assert(builtin != GWN_UNIFORM_NONE); + assert(builtin != GWN_UNIFORM_CUSTOM); + assert(builtin != GWN_NUM_UNIFORMS); +#endif + return shaderface->builtin_uniforms[builtin]; +} + +const Gwn_ShaderInput* GWN_shaderinterface_ubo(const Gwn_ShaderInterface* shaderface, const char* name) +{ + return buckets_lookup(shaderface->ubo_buckets, shaderface->name_buffer, name); +} + +const Gwn_ShaderInput* GWN_shaderinterface_attr(const Gwn_ShaderInterface* shaderface, const char* name) +{ + return buckets_lookup(shaderface->attrib_buckets, shaderface->name_buffer, name); +} + +void GWN_shaderinterface_add_batch_ref(Gwn_ShaderInterface* shaderface, Gwn_Batch* batch) +{ + int i; /* find first unused slot */ + for (i = 0; i < shaderface->batches_len; ++i) { + if (shaderface->batches[i] == NULL) { + break; + } + } + if (i == shaderface->batches_len) { + /* Not enough place, realloc the array. */ + i = shaderface->batches_len; + shaderface->batches_len += GWN_SHADERINTERFACE_REF_ALLOC_COUNT; + shaderface->batches = realloc(shaderface->batches, sizeof(Gwn_Batch*) * shaderface->batches_len); + memset(shaderface->batches + i, 0, sizeof(Gwn_Batch*) * GWN_SHADERINTERFACE_REF_ALLOC_COUNT); + } + shaderface->batches[i] = batch; +} + +void GWN_shaderinterface_remove_batch_ref(Gwn_ShaderInterface* shaderface, Gwn_Batch* batch) +{ + for (int i = 0; i < shaderface->batches_len; ++i) { + if (shaderface->batches[i] == batch) { + shaderface->batches[i] = NULL; + break; /* cannot have duplicates */ + } + } +} diff --git a/source/blender/gpu/intern/gpu_shader_private.h b/source/blender/gpu/intern/gpu_shader_private.h index de5439c5638..bf54d269fb5 100644 --- a/source/blender/gpu/intern/gpu_shader_private.h +++ b/source/blender/gpu/intern/gpu_shader_private.h @@ -26,7 +26,7 @@ #define __GPU_SHADER_PRIVATE_H__ #include "GPU_glew.h" -#include "gawain/gwn_shader_interface.h" +#include "GPU_shader_interface.h" struct GPUShader { GLuint program; /* handle for full program (links shader stages below) */ diff --git a/source/blender/gpu/intern/gpu_vertex_array_id.cpp b/source/blender/gpu/intern/gpu_vertex_array_id.cpp new file mode 100644 index 00000000000..de5be15ec19 --- /dev/null +++ b/source/blender/gpu/intern/gpu_vertex_array_id.cpp @@ -0,0 +1,196 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation, Clément Foucault + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_vertex_array_id.cpp + * \ingroup gpu + * + * Manage GL vertex array IDs in a thread-safe way + * Use these instead of glGenBuffers & its friends + * - alloc must be called from a thread that is bound + * to the context that will be used for drawing with + * this vao. + * - free can be called from any thread + */ + +#include "gpu_batch_private.h" +#include "GPU_vertex_array_id.h" +#include "GPU_context.h" +#include +#include +#include +#include +#include + +#if TRUST_NO_ONE +#if 0 +extern "C" { +extern int BLI_thread_is_main(void); /* Blender-specific function */ +} + +static bool thread_is_main() { + /* "main" here means the GL context's thread */ + return BLI_thread_is_main(); +} +#endif +#endif + +struct Gwn_Context { + GLuint default_vao; + std::unordered_set batches; /* Batches that have VAOs from this context */ + std::vector orphaned_vertarray_ids; + std::mutex orphans_mutex; /* todo: try spinlock instead */ +#if TRUST_NO_ONE + pthread_t thread; /* Thread on which this context is active. */ + bool thread_is_used; + + Gwn_Context() { + thread_is_used = false; + } +#endif +}; + +#if defined(_MSC_VER) && (_MSC_VER == 1800) +#define thread_local __declspec(thread) +thread_local Gwn_Context* active_ctx = NULL; +#else +static thread_local Gwn_Context* active_ctx = NULL; +#endif + +static void clear_orphans(Gwn_Context* ctx) +{ + ctx->orphans_mutex.lock(); + if (!ctx->orphaned_vertarray_ids.empty()) { + uint orphan_len = (uint)ctx->orphaned_vertarray_ids.size(); + glDeleteVertexArrays(orphan_len, ctx->orphaned_vertarray_ids.data()); + ctx->orphaned_vertarray_ids.clear(); + } + ctx->orphans_mutex.unlock(); +} + +Gwn_Context* GWN_context_create(void) +{ +#if TRUST_NO_ONE + /* assert(thread_is_main()); */ +#endif + Gwn_Context* ctx = new Gwn_Context; + glGenVertexArrays(1, &ctx->default_vao); + GWN_context_active_set(ctx); + return ctx; +} + +/* to be called after GWN_context_active_set(ctx_to_destroy) */ +void GWN_context_discard(Gwn_Context* ctx) +{ +#if TRUST_NO_ONE + /* Make sure no other thread has locked it. */ + assert(ctx == active_ctx); + assert(pthread_equal(pthread_self(), ctx->thread)); + assert(ctx->orphaned_vertarray_ids.empty()); +#endif + /* delete remaining vaos */ + while (!ctx->batches.empty()) { + /* this removes the array entry */ + gwn_batch_vao_cache_clear(*ctx->batches.begin()); + } + glDeleteVertexArrays(1, &ctx->default_vao); + delete ctx; + active_ctx = NULL; +} + +/* ctx can be NULL */ +void GWN_context_active_set(Gwn_Context* ctx) +{ +#if TRUST_NO_ONE + if (active_ctx) { + active_ctx->thread_is_used = false; + } + /* Make sure no other context is already bound to this thread. */ + if (ctx) { + /* Make sure no other thread has locked it. */ + assert(ctx->thread_is_used == false); + ctx->thread = pthread_self(); + ctx->thread_is_used = true; + } +#endif + if (ctx) { + clear_orphans(ctx); + } + active_ctx = ctx; +} + +Gwn_Context* GWN_context_active_get(void) +{ + return active_ctx; +} + +GLuint GWN_vao_default(void) +{ +#if TRUST_NO_ONE + assert(active_ctx); /* need at least an active context */ + assert(pthread_equal(pthread_self(), active_ctx->thread)); /* context has been activated by another thread! */ +#endif + return active_ctx->default_vao; +} + +GLuint GWN_vao_alloc(void) +{ +#if TRUST_NO_ONE + assert(active_ctx); /* need at least an active context */ + assert(pthread_equal(pthread_self(), active_ctx->thread)); /* context has been activated by another thread! */ +#endif + clear_orphans(active_ctx); + + GLuint new_vao_id = 0; + glGenVertexArrays(1, &new_vao_id); + return new_vao_id; +} + +/* this can be called from multiple thread */ +void GWN_vao_free(GLuint vao_id, Gwn_Context* ctx) +{ +#if TRUST_NO_ONE + assert(ctx); +#endif + if (ctx == active_ctx) { + glDeleteVertexArrays(1, &vao_id); + } + else { + ctx->orphans_mutex.lock(); + ctx->orphaned_vertarray_ids.emplace_back(vao_id); + ctx->orphans_mutex.unlock(); + } +} + +void gwn_context_add_batch(Gwn_Context* ctx, Gwn_Batch* batch) +{ + ctx->batches.emplace(batch); +} + +void gwn_context_remove_batch(Gwn_Context* ctx, Gwn_Batch* batch) +{ + ctx->orphans_mutex.lock(); + ctx->batches.erase(batch); + ctx->orphans_mutex.unlock(); +} diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.c b/source/blender/gpu/intern/gpu_vertex_buffer.c new file mode 100644 index 00000000000..32f3d494015 --- /dev/null +++ b/source/blender/gpu/intern/gpu_vertex_buffer.c @@ -0,0 +1,268 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation, Clément Foucault + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gwn_vertex_buffer.c + * \ingroup gpu + * + * Gawain vertex buffer + */ + +#include "GPU_vertex_buffer.h" +#include "GPU_buffer_id.h" +#include "gpu_vertex_format_private.h" +#include +#include + +#define KEEP_SINGLE_COPY 1 + +static uint vbo_memory_usage; + +static GLenum convert_usage_type_to_gl(Gwn_UsageType type) +{ + static const GLenum table[] = { + [GWN_USAGE_STREAM] = GL_STREAM_DRAW, + [GWN_USAGE_STATIC] = GL_STATIC_DRAW, + [GWN_USAGE_DYNAMIC] = GL_DYNAMIC_DRAW + }; + return table[type]; +} + +Gwn_VertBuf* GWN_vertbuf_create(Gwn_UsageType usage) +{ + Gwn_VertBuf* verts = malloc(sizeof(Gwn_VertBuf)); + GWN_vertbuf_init(verts, usage); + return verts; +} + +Gwn_VertBuf* GWN_vertbuf_create_with_format_ex(const Gwn_VertFormat* format, Gwn_UsageType usage) +{ + Gwn_VertBuf* verts = GWN_vertbuf_create(usage); + GWN_vertformat_copy(&verts->format, format); + if (!format->packed) { + VertexFormat_pack(&verts->format); + } + return verts; + + /* this function might seem redundant, but there is potential for memory savings here... */ + /* TODO: implement those memory savings */ +} + +void GWN_vertbuf_init(Gwn_VertBuf* verts, Gwn_UsageType usage) +{ + memset(verts, 0, sizeof(Gwn_VertBuf)); + verts->usage = usage; + verts->dirty = true; +} + +void GWN_vertbuf_init_with_format_ex(Gwn_VertBuf* verts, const Gwn_VertFormat* format, Gwn_UsageType usage) +{ + GWN_vertbuf_init(verts, usage); + GWN_vertformat_copy(&verts->format, format); + if (!format->packed) { + VertexFormat_pack(&verts->format); + } +} + +void GWN_vertbuf_discard(Gwn_VertBuf* verts) +{ + if (verts->vbo_id) { + GWN_buf_id_free(verts->vbo_id); +#if VRAM_USAGE + vbo_memory_usage -= GWN_vertbuf_size_get(verts); +#endif + } + if (verts->data) { + free(verts->data); + } + free(verts); +} + +uint GWN_vertbuf_size_get(const Gwn_VertBuf* verts) +{ + return vertex_buffer_size(&verts->format, verts->vertex_len); +} + +/* create a new allocation, discarding any existing data */ +void GWN_vertbuf_data_alloc(Gwn_VertBuf* verts, uint v_len) +{ + Gwn_VertFormat* format = &verts->format; + if (!format->packed) { + VertexFormat_pack(format); + } +#if TRUST_NO_ONE + /* catch any unnecessary use */ + assert(verts->vertex_alloc != v_len || verts->data == NULL); +#endif + /* only create the buffer the 1st time */ + if (verts->vbo_id == 0) { + verts->vbo_id = GWN_buf_id_alloc(); + } + /* discard previous data if any */ + if (verts->data) { + free(verts->data); + } +#if VRAM_USAGE + uint new_size = vertex_buffer_size(&verts->format, v_len); + vbo_memory_usage += new_size - GWN_vertbuf_size_get(verts); +#endif + verts->dirty = true; + verts->vertex_len = verts->vertex_alloc = v_len; + verts->data = malloc(sizeof(GLubyte) * GWN_vertbuf_size_get(verts)); +} + +/* resize buffer keeping existing data */ +void GWN_vertbuf_data_resize(Gwn_VertBuf* verts, uint v_len) +{ +#if TRUST_NO_ONE + assert(verts->data != NULL); + assert(verts->vertex_alloc != v_len); +#endif + +#if VRAM_USAGE + uint new_size = vertex_buffer_size(&verts->format, v_len); + vbo_memory_usage += new_size - GWN_vertbuf_size_get(verts); +#endif + verts->dirty = true; + verts->vertex_len = verts->vertex_alloc = v_len; + verts->data = realloc(verts->data, sizeof(GLubyte) * GWN_vertbuf_size_get(verts)); +} + +/* Set vertex count but does not change allocation. + * Only this many verts will be uploaded to the GPU and rendered. + * This is usefull for streaming data. */ +void GWN_vertbuf_vertex_count_set(Gwn_VertBuf* verts, uint v_len) +{ +#if TRUST_NO_ONE + assert(verts->data != NULL); /* only for dynamic data */ + assert(v_len <= verts->vertex_alloc); +#endif + +#if VRAM_USAGE + uint new_size = vertex_buffer_size(&verts->format, v_len); + vbo_memory_usage += new_size - GWN_vertbuf_size_get(verts); +#endif + verts->vertex_len = v_len; +} + +void GWN_vertbuf_attr_set(Gwn_VertBuf* verts, uint a_idx, uint v_idx, const void* data) +{ + const Gwn_VertFormat* format = &verts->format; + const Gwn_VertAttr* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attr_len); + assert(v_idx < verts->vertex_alloc); + assert(verts->data != NULL); +#endif + verts->dirty = true; + memcpy((GLubyte*)verts->data + a->offset + v_idx * format->stride, data, a->sz); +} + +void GWN_vertbuf_attr_fill(Gwn_VertBuf* verts, uint a_idx, const void* data) +{ + const Gwn_VertFormat* format = &verts->format; + const Gwn_VertAttr* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attr_len); +#endif + const uint stride = a->sz; /* tightly packed input data */ + + GWN_vertbuf_attr_fill_stride(verts, a_idx, stride, data); +} + +void GWN_vertbuf_attr_fill_stride(Gwn_VertBuf* verts, uint a_idx, uint stride, const void* data) +{ + const Gwn_VertFormat* format = &verts->format; + const Gwn_VertAttr* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attr_len); + assert(verts->data != NULL); +#endif + verts->dirty = true; + const uint vertex_len = verts->vertex_len; + + if (format->attr_len == 1 && stride == format->stride) { + /* we can copy it all at once */ + memcpy(verts->data, data, vertex_len * a->sz); + } + else { + /* we must copy it per vertex */ + for (uint v = 0; v < vertex_len; ++v) { + memcpy((GLubyte*)verts->data + a->offset + v * format->stride, (const GLubyte*)data + v * stride, a->sz); + } + } +} + +void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf* verts, uint a_idx, Gwn_VertBufRaw *access) +{ + const Gwn_VertFormat* format = &verts->format; + const Gwn_VertAttr* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attr_len); + assert(verts->data != NULL); +#endif + + verts->dirty = true; + + access->size = a->sz; + access->stride = format->stride; + access->data = (GLubyte*)verts->data + a->offset; + access->data_init = access->data; +#if TRUST_NO_ONE + access->_data_end = access->data_init + (size_t)(verts->vertex_alloc * format->stride); +#endif +} + +static void VertBuffer_upload_data(Gwn_VertBuf* verts) +{ + uint buffer_sz = GWN_vertbuf_size_get(verts); + + /* orphan the vbo to avoid sync */ + glBufferData(GL_ARRAY_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage)); + /* upload data */ + glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_sz, verts->data); + + if (verts->usage == GWN_USAGE_STATIC) { + free(verts->data); + verts->data = NULL; + } + verts->dirty = false; +} + +void GWN_vertbuf_use(Gwn_VertBuf* verts) +{ + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + if (verts->dirty) { + VertBuffer_upload_data(verts); + } +} + +uint GWN_vertbuf_get_memory_usage(void) +{ + return vbo_memory_usage; +} diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c new file mode 100644 index 00000000000..bd9f9250564 --- /dev/null +++ b/source/blender/gpu/intern/gpu_vertex_format.c @@ -0,0 +1,310 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation, Clément Foucault + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gwn_vertex_format.c + * \ingroup gpu + * + * Gawain vertex format + */ + +#include "GPU_vertex_format.h" +#include "gpu_vertex_format_private.h" +#include +#include + +#define PACK_DEBUG 0 + +#if PACK_DEBUG + #include +#endif + +void GWN_vertformat_clear(Gwn_VertFormat* format) +{ +#if TRUST_NO_ONE + memset(format, 0, sizeof(Gwn_VertFormat)); +#else + format->attr_len = 0; + format->packed = false; + format->name_offset = 0; + format->name_len = 0; + + for (unsigned i = 0; i < GWN_VERT_ATTR_MAX_LEN; i++) { + format->attribs[i].name_len = 0; + } +#endif +} + +void GWN_vertformat_copy(Gwn_VertFormat* dest, const Gwn_VertFormat* src) +{ + /* copy regular struct fields */ + memcpy(dest, src, sizeof(Gwn_VertFormat)); + + for (unsigned i = 0; i < dest->attr_len; i++) { + for (unsigned j = 0; j < dest->attribs[i].name_len; j++) { + dest->attribs[i].name[j] = (char *)dest + (src->attribs[i].name[j] - ((char *)src)); + } + } +} + +static GLenum convert_comp_type_to_gl(Gwn_VertCompType type) +{ + static const GLenum table[] = { + [GWN_COMP_I8] = GL_BYTE, + [GWN_COMP_U8] = GL_UNSIGNED_BYTE, + [GWN_COMP_I16] = GL_SHORT, + [GWN_COMP_U16] = GL_UNSIGNED_SHORT, + [GWN_COMP_I32] = GL_INT, + [GWN_COMP_U32] = GL_UNSIGNED_INT, + + [GWN_COMP_F32] = GL_FLOAT, + + [GWN_COMP_I10] = GL_INT_2_10_10_10_REV + }; + return table[type]; +} + +static unsigned comp_sz(Gwn_VertCompType type) +{ +#if TRUST_NO_ONE + assert(type <= GWN_COMP_F32); /* other types have irregular sizes (not bytes) */ +#endif + const GLubyte sizes[] = {1,1,2,2,4,4,4}; + return sizes[type]; +} + +static unsigned attrib_sz(const Gwn_VertAttr *a) +{ + if (a->comp_type == GWN_COMP_I10) { + return 4; /* always packed as 10_10_10_2 */ + } + return a->comp_len * comp_sz(a->comp_type); +} + +static unsigned attrib_align(const Gwn_VertAttr *a) +{ + if (a->comp_type == GWN_COMP_I10) { + return 4; /* always packed as 10_10_10_2 */ + } + unsigned c = comp_sz(a->comp_type); + if (a->comp_len == 3 && c <= 2) { + return 4 * c; /* AMD HW can't fetch these well, so pad it out (other vendors too?) */ + } + else { + return c; /* most fetches are ok if components are naturally aligned */ + } +} + +unsigned vertex_buffer_size(const Gwn_VertFormat* format, unsigned vertex_len) +{ +#if TRUST_NO_ONE + assert(format->packed && format->stride > 0); +#endif + return format->stride * vertex_len; +} + +static const char* copy_attrib_name(Gwn_VertFormat* format, const char* name) +{ + /* strncpy does 110% of what we need; let's do exactly 100% */ + char* name_copy = format->names + format->name_offset; + unsigned available = GWN_VERT_ATTR_NAMES_BUF_LEN - format->name_offset; + bool terminated = false; + + for (unsigned i = 0; i < available; ++i) { + const char c = name[i]; + name_copy[i] = c; + if (c == '\0') { + terminated = true; + format->name_offset += (i + 1); + break; + } + } +#if TRUST_NO_ONE + assert(terminated); + assert(format->name_offset <= GWN_VERT_ATTR_NAMES_BUF_LEN); +#else + (void)terminated; +#endif + return name_copy; +} + +unsigned GWN_vertformat_attr_add(Gwn_VertFormat* format, const char* name, Gwn_VertCompType comp_type, unsigned comp_len, Gwn_VertFetchMode fetch_mode) +{ +#if TRUST_NO_ONE + assert(format->name_len < GWN_VERT_ATTR_MAX_LEN); /* there's room for more */ + assert(format->attr_len < GWN_VERT_ATTR_MAX_LEN); /* there's room for more */ + assert(!format->packed); /* packed means frozen/locked */ + assert((comp_len >= 1 && comp_len <= 4) || comp_len == 8 || comp_len == 12 || comp_len == 16); + + switch (comp_type) { + case GWN_COMP_F32: + /* float type can only kept as float */ + assert(fetch_mode == GWN_FETCH_FLOAT); + break; + case GWN_COMP_I10: + /* 10_10_10 format intended for normals (xyz) or colors (rgb) + * extra component packed.w can be manually set to { -2, -1, 0, 1 } */ + assert(comp_len == 3 || comp_len == 4); + assert(fetch_mode == GWN_FETCH_INT_TO_FLOAT_UNIT); /* not strictly required, may relax later */ + break; + default: + /* integer types can be kept as int or converted/normalized to float */ + assert(fetch_mode != GWN_FETCH_FLOAT); + /* only support float matrices (see Batch_update_program_bindings) */ + assert(comp_len != 8 && comp_len != 12 && comp_len != 16); + } +#endif + format->name_len++; /* multiname support */ + + const unsigned attrib_id = format->attr_len++; + Gwn_VertAttr* attrib = format->attribs + attrib_id; + + attrib->name[attrib->name_len++] = copy_attrib_name(format, name); + attrib->comp_type = comp_type; + attrib->gl_comp_type = convert_comp_type_to_gl(comp_type); + attrib->comp_len = (comp_type == GWN_COMP_I10) ? 4 : comp_len; /* system needs 10_10_10_2 to be 4 or BGRA */ + attrib->sz = attrib_sz(attrib); + attrib->offset = 0; /* offsets & stride are calculated later (during pack) */ + attrib->fetch_mode = fetch_mode; + + return attrib_id; +} + +void GWN_vertformat_alias_add(Gwn_VertFormat* format, const char* alias) +{ + Gwn_VertAttr* attrib = format->attribs + (format->attr_len - 1); +#if TRUST_NO_ONE + assert(format->name_len < GWN_VERT_ATTR_MAX_LEN); /* there's room for more */ + assert(attrib->name_len < GWN_VERT_ATTR_MAX_NAMES); +#endif + format->name_len++; /* multiname support */ + attrib->name[attrib->name_len++] = copy_attrib_name(format, alias); +} + +unsigned padding(unsigned offset, unsigned alignment) +{ + const unsigned mod = offset % alignment; + return (mod == 0) ? 0 : (alignment - mod); +} + +#if PACK_DEBUG +static void show_pack(unsigned a_idx, unsigned sz, unsigned pad) +{ + const char c = 'A' + a_idx; + for (unsigned i = 0; i < pad; ++i) { + putchar('-'); + } + for (unsigned i = 0; i < sz; ++i) { + putchar(c); + } +} +#endif + +void VertexFormat_pack(Gwn_VertFormat* format) +{ + /* For now, attributes are packed in the order they were added, + * making sure each attrib is naturally aligned (add padding where necessary) + * Later we can implement more efficient packing w/ reordering + * (keep attrib ID order, adjust their offsets to reorder in buffer). */ + + /* TODO: realloc just enough to hold the final combo string. And just enough to + * hold used attribs, not all 16. */ + + Gwn_VertAttr* a0 = format->attribs + 0; + a0->offset = 0; + unsigned offset = a0->sz; + +#if PACK_DEBUG + show_pack(0, a0->sz, 0); +#endif + + for (unsigned a_idx = 1; a_idx < format->attr_len; ++a_idx) { + Gwn_VertAttr* a = format->attribs + a_idx; + unsigned mid_padding = padding(offset, attrib_align(a)); + offset += mid_padding; + a->offset = offset; + offset += a->sz; + +#if PACK_DEBUG + show_pack(a_idx, a->sz, mid_padding); +#endif + } + + unsigned end_padding = padding(offset, attrib_align(a0)); + +#if PACK_DEBUG + show_pack(0, 0, end_padding); + putchar('\n'); +#endif + format->stride = offset + end_padding; + format->packed = true; +} + + +/* OpenGL ES packs in a different order as desktop GL but component conversion is the same. + * Of the code here, only struct Gwn_PackedNormal needs to change. */ + +#define SIGNED_INT_10_MAX 511 +#define SIGNED_INT_10_MIN -512 + +static int clampi(int x, int min_allowed, int max_allowed) +{ +#if TRUST_NO_ONE + assert(min_allowed <= max_allowed); +#endif + if (x < min_allowed) { + return min_allowed; + } + else if (x > max_allowed) { + return max_allowed; + } + else { + return x; + } +} + +static int quantize(float x) +{ + int qx = x * 511.0f; + return clampi(qx, SIGNED_INT_10_MIN, SIGNED_INT_10_MAX); +} + +static int convert_i16(short x) +{ + /* 16-bit signed --> 10-bit signed */ + /* TODO: round? */ + return x >> 6; +} + +Gwn_PackedNormal GWN_normal_convert_i10_v3(const float data[3]) +{ + Gwn_PackedNormal n = { .x = quantize(data[0]), .y = quantize(data[1]), .z = quantize(data[2]) }; + return n; +} + +Gwn_PackedNormal GWN_normal_convert_i10_s3(const short data[3]) +{ + Gwn_PackedNormal n = { .x = convert_i16(data[0]), .y = convert_i16(data[1]), .z = convert_i16(data[2]) }; + return n; +} diff --git a/source/blender/gpu/intern/gpu_vertex_format_private.h b/source/blender/gpu/intern/gpu_vertex_format_private.h new file mode 100644 index 00000000000..3cae9969fd8 --- /dev/null +++ b/source/blender/gpu/intern/gpu_vertex_format_private.h @@ -0,0 +1,39 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 + * of the License, 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/gwn_vertex_format_private.h + * \ingroup gpu + * + * Gawain vertex format + */ + +#ifndef __GWN_VERTEX_FORMAT_PRIVATE_H__ +#define __GWN_VERTEX_FORMAT_PRIVATE_H__ + +void VertexFormat_pack(Gwn_VertFormat*); +uint padding(uint offset, uint alignment); +uint vertex_buffer_size(const Gwn_VertFormat*, uint vertex_len); + +#endif /* __GWN_VERTEX_FORMAT_PRIVATE_H__ */ diff --git a/source/blender/python/gawain/gwn_py_api.c b/source/blender/python/gawain/gwn_py_api.c index d79ef070649..1f7a1297448 100644 --- a/source/blender/python/gawain/gwn_py_api.c +++ b/source/blender/python/gawain/gwn_py_api.c @@ -27,8 +27,8 @@ #include -#include "gawain/gwn_batch.h" -#include "gawain/gwn_vertex_format.h" +#include "GPU_batch.h" +#include "GPU_vertex_format.h" #include "gwn_py_api.h" #include "gwn_py_types.h" diff --git a/source/blender/python/gawain/gwn_py_types.c b/source/blender/python/gawain/gwn_py_types.c index bdf0be9f7e1..04c50ac0784 100644 --- a/source/blender/python/gawain/gwn_py_types.c +++ b/source/blender/python/gawain/gwn_py_types.c @@ -27,8 +27,8 @@ #include -#include "gawain/gwn_batch.h" -#include "gawain/gwn_vertex_format.h" +#include "GPU_batch.h" +#include "GPU_vertex_format.h" #include "BLI_math.h" diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index d3fef51e9e9..8f921d7850a 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -37,6 +37,7 @@ set(INC ../nodes ../physics ../draw + ../gpu ../../../intern/atomic ../../../intern/guardedalloc ../../../intern/mikktspace diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 82595527d30..af8746a4734 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -97,7 +97,7 @@ #include "../../../windowmanager/WM_api.h" /* XXX */ #include "../../../windowmanager/wm_window.h" /* XXX */ -#include "../../../intern/gawain/gawain/gwn_context.h" +#include "GPU_context.h" #ifdef WITH_FREESTYLE # include "FRS_freestyle.h" diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index d1a7f4ffea1..00e7f77569b 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -69,7 +69,7 @@ #include "GPU_matrix.h" #include "GPU_immediate.h" #include "GPU_immediate_util.h" -#include "GPU_batch.h" +#include "GPU_context.h" #include "GPU_init_exit.h" #include "DNA_scene_types.h" diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index f55fc5703f4..669480bf098 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -90,12 +90,11 @@ #include "GPU_immediate.h" #include "GPU_material.h" #include "GPU_texture.h" +#include "GPU_context.h" #include "BLF_api.h" #include "UI_resources.h" -#include "../../../intern/gawain/gawain/gwn_context.h" - /* for assert */ #ifndef NDEBUG # include "BLI_threads.h" -- cgit v1.2.3