From 5c2ac8520e070db2085b7d95d9d232b567edb247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 7 Sep 2020 23:52:55 +0200 Subject: GPUQuery: GL Backend isolation This is part of the Vulkan task T68990. This introduce a new GLQueryPool for managing queries in an implementation agnostic manner. This modify the GPU selection query to use this new object. This also make use of blender::Vector for better code quality. No real functionnal change. --- source/blender/gpu/CMakeLists.txt | 6 +- source/blender/gpu/intern/gpu_backend.hh | 2 + source/blender/gpu/intern/gpu_query.cc | 28 +++ source/blender/gpu/intern/gpu_query.hh | 59 ++++++ source/blender/gpu/intern/gpu_select_private.h | 8 + .../blender/gpu/intern/gpu_select_sample_query.c | 224 --------------------- .../blender/gpu/intern/gpu_select_sample_query.cc | 201 ++++++++++++++++++ source/blender/gpu/opengl/gl_backend.hh | 6 + source/blender/gpu/opengl/gl_context.hh | 16 +- source/blender/gpu/opengl/gl_query.cc | 78 +++++++ source/blender/gpu/opengl/gl_query.hh | 69 +++++++ 11 files changed, 464 insertions(+), 233 deletions(-) create mode 100644 source/blender/gpu/intern/gpu_query.cc create mode 100644 source/blender/gpu/intern/gpu_query.hh delete mode 100644 source/blender/gpu/intern/gpu_select_sample_query.c create mode 100644 source/blender/gpu/intern/gpu_select_sample_query.cc create mode 100644 source/blender/gpu/opengl/gl_query.cc create mode 100644 source/blender/gpu/opengl/gl_query.hh (limited to 'source/blender') diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 6fdd510ad28..0a372125391 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -74,9 +74,10 @@ set(SRC intern/gpu_matrix.cc intern/gpu_node_graph.c intern/gpu_platform.cc + intern/gpu_query.cc intern/gpu_select.c intern/gpu_select_pick.c - intern/gpu_select_sample_query.c + intern/gpu_select_sample_query.cc intern/gpu_shader.cc intern/gpu_shader_builtin.c intern/gpu_shader_interface.cc @@ -95,6 +96,7 @@ set(SRC opengl/gl_framebuffer.cc opengl/gl_immediate.cc opengl/gl_index_buffer.cc + opengl/gl_query.cc opengl/gl_shader.cc opengl/gl_shader_interface.cc opengl/gl_state.cc @@ -146,6 +148,7 @@ set(SRC intern/gpu_node_graph.h intern/gpu_private.h intern/gpu_platform_private.hh + intern/gpu_query.hh intern/gpu_select_private.h intern/gpu_shader_private.hh intern/gpu_shader_interface.hh @@ -164,6 +167,7 @@ set(SRC opengl/gl_immediate.hh opengl/gl_index_buffer.hh opengl/gl_primitive.hh + opengl/gl_query.hh opengl/gl_shader.hh opengl/gl_shader_interface.hh opengl/gl_state.hh diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh index d074350e8d0..1a6a6668b42 100644 --- a/source/blender/gpu/intern/gpu_backend.hh +++ b/source/blender/gpu/intern/gpu_backend.hh @@ -34,6 +34,7 @@ class Batch; class DrawList; class FrameBuffer; class IndexBuf; +class QueryPool; class Shader; class Texture; class UniformBuf; @@ -53,6 +54,7 @@ class GPUBackend { virtual DrawList *drawlist_alloc(int list_length) = 0; virtual FrameBuffer *framebuffer_alloc(const char *name) = 0; virtual IndexBuf *indexbuf_alloc(void) = 0; + virtual QueryPool *querypool_alloc(void) = 0; virtual Shader *shader_alloc(const char *name) = 0; virtual Texture *texture_alloc(const char *name) = 0; virtual UniformBuf *uniformbuf_alloc(int size, const char *name) = 0; diff --git a/source/blender/gpu/intern/gpu_query.cc b/source/blender/gpu/intern/gpu_query.cc new file mode 100644 index 00000000000..ad9b6d21420 --- /dev/null +++ b/source/blender/gpu/intern/gpu_query.cc @@ -0,0 +1,28 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#include "gpu_query.hh" + +using namespace blender::gpu; + +/* TODO(fclem) Make the associated C-API to use inside DRW profiler. */ diff --git a/source/blender/gpu/intern/gpu_query.hh b/source/blender/gpu/intern/gpu_query.hh new file mode 100644 index 00000000000..5e3159a94f7 --- /dev/null +++ b/source/blender/gpu/intern/gpu_query.hh @@ -0,0 +1,59 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "BLI_span.hh" + +namespace blender::gpu { + +typedef enum GPUQueryType { + GPU_QUERY_OCCLUSION = 0, +} GPUQueryType; + +class QueryPool { + public: + virtual ~QueryPool(){}; + + /** + * Will start and end the query at this index inside the pool. The pool will resize + * automatically but does not support sparse allocation. So prefer using consecutive indices. + */ + virtual void init(GPUQueryType type) = 0; + + /** + * Will start and end the query at this index inside the pool. + * The pool will resize automatically. + */ + virtual void begin_query(void) = 0; + virtual void end_query(void) = 0; + + /** + * Must be fed with a buffer large enough to contain all the queries issued. + * IMPORTANT: Result for each query can be either binary or represent the number of samples + * drawn. + */ + virtual void get_occlusion_result(MutableSpan r_values) = 0; +}; + +} // namespace blender::gpu \ No newline at end of file diff --git a/source/blender/gpu/intern/gpu_select_private.h b/source/blender/gpu/intern/gpu_select_private.h index e364b78bff2..f9a1aea8338 100644 --- a/source/blender/gpu/intern/gpu_select_private.h +++ b/source/blender/gpu/intern/gpu_select_private.h @@ -25,6 +25,10 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + /* gpu_select_pick */ void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, char mode); bool gpu_select_pick_load_id(uint id, bool end); @@ -42,3 +46,7 @@ bool gpu_select_query_load_id(uint id); uint gpu_select_query_end(void); #define SELECT_ID_NONE ((uint)0xffffffff) + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c deleted file mode 100644 index 45d52b22664..00000000000 --- a/source/blender/gpu/intern/gpu_select_sample_query.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * 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) 2014 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup gpu - * - * Interface for accessing gpu-related methods for selection. The semantics will be - * similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility. - */ - -#include - -#include "GPU_framebuffer.h" -#include "GPU_glew.h" -#include "GPU_select.h" -#include "GPU_state.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_rect.h" - -#include "BLI_utildefines.h" - -#include "gpu_select_private.h" - -/* Ad hoc number of queries to allocate to skip doing many glGenQueries */ -#define ALLOC_QUERIES 200 - -typedef struct GPUQueryState { - /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */ - bool query_issued; - /* array holding the OpenGL query identifiers */ - uint *queries; - /* array holding the id corresponding to each query */ - uint *id; - /* number of queries in *queries and *id */ - uint num_of_queries; - /* index to the next query to start */ - uint active_query; - /* cache on initialization */ - uint (*buffer)[4]; - /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/ - uint bufsize; - /* mode of operation */ - char mode; - uint index; - int oldhits; - - /* Previous state to restore after drawing. */ - int viewport[4]; - int scissor[4]; - eGPUWriteMask write_mask; - eGPUDepthTest depth_test; -} GPUQueryState; - -static GPUQueryState g_query_state = {0}; - -void gpu_select_query_begin( - uint (*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits) -{ - g_query_state.query_issued = false; - g_query_state.active_query = 0; - g_query_state.num_of_queries = 0; - g_query_state.bufsize = bufsize; - g_query_state.buffer = buffer; - g_query_state.mode = mode; - g_query_state.index = 0; - g_query_state.oldhits = oldhits; - - g_query_state.num_of_queries = ALLOC_QUERIES; - - g_query_state.queries = MEM_mallocN( - g_query_state.num_of_queries * sizeof(*g_query_state.queries), "gpu selection queries"); - g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id), - "gpu selection ids"); - glGenQueries(g_query_state.num_of_queries, g_query_state.queries); - - g_query_state.write_mask = GPU_write_mask_get(); - g_query_state.depth_test = GPU_depth_test_get(); - GPU_scissor_get(g_query_state.scissor); - GPU_viewport_size_get_i(g_query_state.viewport); - - /* Write to color buffer. Seems to fix issues with selecting alpha blended geom (see T7997). */ - GPU_color_mask(true, true, true, true); - - /* In order to save some fill rate we minimize the viewport using rect. - * We need to get the region of the viewport so that our geometry doesn't - * get rejected before the depth test. Should probably cull rect against - * the viewport but this is a rare case I think */ - - int viewport[4] = { - UNPACK2(g_query_state.viewport), BLI_rcti_size_x(input), BLI_rcti_size_y(input)}; - - GPU_viewport(UNPACK4(viewport)); - GPU_scissor(UNPACK4(viewport)); - GPU_scissor_test(false); - - /* occlusion queries operates on fragments that pass tests and since we are interested on all - * objects in the view frustum independently of their order, we need to disable the depth test */ - if (mode == GPU_SELECT_ALL) { - /* glQueries on Windows+Intel drivers only works with depth testing turned on. - * See T62947 for details */ - GPU_depth_test(GPU_DEPTH_ALWAYS); - GPU_depth_mask(true); - } - else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) { - GPU_depth_test(GPU_DEPTH_LESS_EQUAL); - GPU_depth_mask(true); - GPU_clear_depth(1.0f); - } - else if (mode == GPU_SELECT_NEAREST_SECOND_PASS) { - GPU_depth_test(GPU_DEPTH_EQUAL); - GPU_depth_mask(false); - } -} - -bool gpu_select_query_load_id(uint id) -{ - if (g_query_state.query_issued) { - glEndQuery(GL_SAMPLES_PASSED); - } - /* if required, allocate extra queries */ - if (g_query_state.active_query == g_query_state.num_of_queries) { - g_query_state.num_of_queries += ALLOC_QUERIES; - g_query_state.queries = MEM_reallocN( - g_query_state.queries, g_query_state.num_of_queries * sizeof(*g_query_state.queries)); - g_query_state.id = MEM_reallocN(g_query_state.id, - g_query_state.num_of_queries * sizeof(*g_query_state.id)); - glGenQueries(ALLOC_QUERIES, &g_query_state.queries[g_query_state.active_query]); - } - - glBeginQuery(GL_SAMPLES_PASSED, g_query_state.queries[g_query_state.active_query]); - g_query_state.id[g_query_state.active_query] = id; - g_query_state.active_query++; - g_query_state.query_issued = true; - - if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS) { - /* Second pass should never run if first pass fails, can read past 'bufsize' in this case. */ - BLI_assert(g_query_state.oldhits != -1); - if (g_query_state.index < g_query_state.oldhits) { - if (g_query_state.buffer[g_query_state.index][3] == id) { - g_query_state.index++; - return true; - } - - return false; - } - } - - return true; -} - -uint gpu_select_query_end(void) -{ - int i; - - uint hits = 0; - const uint maxhits = g_query_state.bufsize; - - if (g_query_state.query_issued) { - glEndQuery(GL_SAMPLES_PASSED); - } - - for (i = 0; i < g_query_state.active_query; i++) { - uint result = 0; - /* We are not using GL_QUERY_RESULT_AVAILABLE and sleep to wait for results, - * because it causes lagging on Windows/NVIDIA, see T61474. */ - glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT, &result); - if (result > 0) { - if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) { - - if (hits < maxhits) { - g_query_state.buffer[hits][0] = 1; - g_query_state.buffer[hits][1] = 0xFFFF; - g_query_state.buffer[hits][2] = 0xFFFF; - g_query_state.buffer[hits][3] = g_query_state.id[i]; - - hits++; - } - else { - hits = -1; - break; - } - } - else { - int j; - /* search in buffer and make selected object first */ - for (j = 0; j < g_query_state.oldhits; j++) { - if (g_query_state.buffer[j][3] == g_query_state.id[i]) { - g_query_state.buffer[j][1] = 0; - g_query_state.buffer[j][2] = 0; - } - } - break; - } - } - } - - glDeleteQueries(g_query_state.num_of_queries, g_query_state.queries); - MEM_freeN(g_query_state.queries); - MEM_freeN(g_query_state.id); - - GPU_write_mask(g_query_state.write_mask); - GPU_depth_test(g_query_state.depth_test); - GPU_viewport(UNPACK4(g_query_state.viewport)); - - return hits; -} diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc new file mode 100644 index 00000000000..1b54cbff5dd --- /dev/null +++ b/source/blender/gpu/intern/gpu_select_sample_query.cc @@ -0,0 +1,201 @@ +/* + * 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) 2014 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Interface for accessing gpu-related methods for selection. The semantics will be + * similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility. + */ + +#include + +#include "GPU_framebuffer.h" +#include "GPU_select.h" +#include "GPU_state.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_rect.h" + +#include "BLI_bitmap.h" +#include "BLI_utildefines.h" +#include "BLI_vector.hh" + +#include "gpu_backend.hh" +#include "gpu_query.hh" + +#include "gpu_select_private.h" + +using namespace blender; +using namespace blender::gpu; + +typedef struct GPUSelectQueryState { + /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */ + bool query_issued; + /* GPU queries abstraction. Contains an array of queries. */ + QueryPool *queries; + /* Array holding the id corresponding id to each query. */ + Vector *ids; + /* cache on initialization */ + uint (*buffer)[4]; + /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/ + uint bufsize; + /* mode of operation */ + char mode; + uint index; + int oldhits; + + /* Previous state to restore after drawing. */ + int viewport[4]; + int scissor[4]; + eGPUWriteMask write_mask; + eGPUDepthTest depth_test; +} GPUSelectQueryState; + +static GPUSelectQueryState g_query_state = {0}; + +void gpu_select_query_begin( + uint (*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits) +{ + g_query_state.query_issued = false; + g_query_state.bufsize = bufsize; + g_query_state.buffer = buffer; + g_query_state.mode = mode; + g_query_state.index = 0; + g_query_state.oldhits = oldhits; + + g_query_state.ids = new Vector(); + g_query_state.queries = GPUBackend::get()->querypool_alloc(); + g_query_state.queries->init(GPU_QUERY_OCCLUSION); + + g_query_state.write_mask = GPU_write_mask_get(); + g_query_state.depth_test = GPU_depth_test_get(); + GPU_scissor_get(g_query_state.scissor); + GPU_viewport_size_get_i(g_query_state.viewport); + + /* Write to color buffer. Seems to fix issues with selecting alpha blended geom (see T7997). */ + GPU_color_mask(true, true, true, true); + + /* In order to save some fill rate we minimize the viewport using rect. + * We need to get the region of the viewport so that our geometry doesn't + * get rejected before the depth test. Should probably cull rect against + * the viewport but this is a rare case I think */ + + int viewport[4] = { + UNPACK2(g_query_state.viewport), BLI_rcti_size_x(input), BLI_rcti_size_y(input)}; + + GPU_viewport(UNPACK4(viewport)); + GPU_scissor(UNPACK4(viewport)); + GPU_scissor_test(false); + + /* occlusion queries operates on fragments that pass tests and since we are interested on all + * objects in the view frustum independently of their order, we need to disable the depth test */ + if (mode == GPU_SELECT_ALL) { + /* glQueries on Windows+Intel drivers only works with depth testing turned on. + * See T62947 for details */ + GPU_depth_test(GPU_DEPTH_ALWAYS); + GPU_depth_mask(true); + } + else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) { + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); + GPU_depth_mask(true); + GPU_clear_depth(1.0f); + } + else if (mode == GPU_SELECT_NEAREST_SECOND_PASS) { + GPU_depth_test(GPU_DEPTH_EQUAL); + GPU_depth_mask(false); + } +} + +bool gpu_select_query_load_id(uint id) +{ + if (g_query_state.query_issued) { + g_query_state.queries->end_query(); + } + + g_query_state.queries->begin_query(); + g_query_state.ids->append(id); + g_query_state.query_issued = true; + + if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS) { + /* Second pass should never run if first pass fails, can read past 'bufsize' in this case. */ + BLI_assert(g_query_state.oldhits != -1); + if (g_query_state.index < g_query_state.oldhits) { + if (g_query_state.buffer[g_query_state.index][3] == id) { + g_query_state.index++; + return true; + } + return false; + } + } + return true; +} + +uint gpu_select_query_end(void) +{ + uint hits = 0; + const uint maxhits = g_query_state.bufsize; + + if (g_query_state.query_issued) { + g_query_state.queries->end_query(); + } + + Span ids = *g_query_state.ids; + Vector result(ids.size()); + g_query_state.queries->get_occlusion_result(result); + + for (int i = 0; i < result.size(); i++) { + if (result[i] != 0) { + if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) { + if (hits < maxhits) { + g_query_state.buffer[hits][0] = 1; + g_query_state.buffer[hits][1] = 0xFFFF; + g_query_state.buffer[hits][2] = 0xFFFF; + g_query_state.buffer[hits][3] = ids[i]; + hits++; + } + else { + hits = -1; + break; + } + } + else { + int j; + /* search in buffer and make selected object first */ + for (j = 0; j < g_query_state.oldhits; j++) { + if (g_query_state.buffer[j][3] == ids[i]) { + g_query_state.buffer[j][1] = 0; + g_query_state.buffer[j][2] = 0; + } + } + break; + } + } + } + + delete g_query_state.queries; + delete g_query_state.ids; + + GPU_write_mask(g_query_state.write_mask); + GPU_depth_test(g_query_state.depth_test); + GPU_viewport(UNPACK4(g_query_state.viewport)); + + return hits; +} diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh index 0c759d2cd62..94ac1692108 100644 --- a/source/blender/gpu/opengl/gl_backend.hh +++ b/source/blender/gpu/opengl/gl_backend.hh @@ -32,6 +32,7 @@ #include "gl_drawlist.hh" #include "gl_framebuffer.hh" #include "gl_index_buffer.hh" +#include "gl_query.hh" #include "gl_shader.hh" #include "gl_texture.hh" #include "gl_uniform_buffer.hh" @@ -95,6 +96,11 @@ class GLBackend : public GPUBackend { return new GLIndexBuf(); }; + QueryPool *querypool_alloc(void) override + { + return new GLQueryPool(); + }; + Shader *shader_alloc(const char *name) override { return new GLShader(name); diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh index f05029c7075..8bce0d2e345 100644 --- a/source/blender/gpu/opengl/gl_context.hh +++ b/source/blender/gpu/opengl/gl_context.hh @@ -68,13 +68,13 @@ class GLContext : public GPUContext { static bool unused_fb_slot_workaround; static float derivative_signs[2]; + /** VBO for missing vertex attrib binding. Avoid undefined behavior on some implementation. */ + GLuint default_attr_vbo_; + /** Used for debugging purpose. Bitflags of all bound slots. */ uint16_t bound_ubo_slots; - /* TODO(fclem) these needs to become private. */ - public: - /** VBO for missing vertex attrib binding. Avoid undefined behavior on some implementation. */ - GLuint default_attr_vbo_; + private: /** * GPUBatch & GPUFramebuffer have references to the context they are from, in the case the * context is destroyed, we need to remove any reference to it. @@ -112,12 +112,12 @@ class GLContext : public GPUContext { static void buf_free(GLuint buf_id); static void tex_free(GLuint tex_id); - /* TODO(fclem) these needs to become private. */ - public: - static void orphans_add(Vector &orphan_list, std::mutex &list_mutex, GLuint id); - void orphans_clear(void); void vao_cache_register(GLVaoCache *cache); void vao_cache_unregister(GLVaoCache *cache); + + private: + static void orphans_add(Vector &orphan_list, std::mutex &list_mutex, GLuint id); + void orphans_clear(void); }; } // namespace gpu diff --git a/source/blender/gpu/opengl/gl_query.cc b/source/blender/gpu/opengl/gl_query.cc new file mode 100644 index 00000000000..6da5cacfcb2 --- /dev/null +++ b/source/blender/gpu/opengl/gl_query.cc @@ -0,0 +1,78 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#include "gl_query.hh" + +namespace blender::gpu { + +#define QUERY_CHUNCK_LEN 256 + +GLQueryPool::~GLQueryPool() +{ + glDeleteQueries(query_ids_.size(), query_ids_.data()); +} + +void GLQueryPool::init(GPUQueryType type) +{ + BLI_assert(initialized_ == false); + initialized_ = true; + type_ = type; + gl_type_ = to_gl(type); + query_issued_ = 0; +} + +#if 0 /* TODO to avoid realloc of permanent query pool. */ +void GLQueryPool::reset(GPUQueryType type) +{ + initialized_ = false; +} +#endif + +void GLQueryPool::begin_query(void) +{ + /* TODO add assert about expected usage. */ + while (query_issued_ >= query_ids_.size()) { + int64_t prev_size = query_ids_.size(); + query_ids_.resize(prev_size + QUERY_CHUNCK_LEN); + glGenQueries(QUERY_CHUNCK_LEN, &query_ids_[prev_size]); + } + glBeginQuery(gl_type_, query_ids_[query_issued_++]); +} + +void GLQueryPool::end_query(void) +{ + /* TODO add assert about expected usage. */ + glEndQuery(gl_type_); +} + +void GLQueryPool::get_occlusion_result(MutableSpan r_values) +{ + BLI_assert(r_values.size() == query_issued_); + + for (int i = 0; i < query_issued_; i++) { + /* Note: This is a sync point. */ + glGetQueryObjectuiv(query_ids_[i], GL_QUERY_RESULT, &r_values[i]); + } +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_query.hh b/source/blender/gpu/opengl/gl_query.hh new file mode 100644 index 00000000000..fc54c0ee1dd --- /dev/null +++ b/source/blender/gpu/opengl/gl_query.hh @@ -0,0 +1,69 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "BLI_vector.hh" + +#include "gpu_query.hh" + +#include "glew-mx.h" + +namespace blender::gpu { + +class GLQueryPool : public QueryPool { + private: + /** Contains queries object handles. */ + Vector query_ids_; + /** Type of this query pool. */ + GPUQueryType type_; + /** Associated GL type. */ + GLenum gl_type_; + /** Number of queries that have been issued since last initialization. + * Should be equal to query_ids_.size(). */ + uint32_t query_issued_; + /** Can only be initialized once. */ + bool initialized_ = false; + + public: + ~GLQueryPool(); + + void init(GPUQueryType type) override; + + void begin_query(void) override; + void end_query(void) override; + + void get_occlusion_result(MutableSpan r_values) override; +}; + +static inline GLenum to_gl(GPUQueryType type) +{ + if (type == GPU_QUERY_OCCLUSION) { + /* TODO(fclem) try with GL_ANY_SAMPLES_PASSED​. */ + return GL_SAMPLES_PASSED; + } + BLI_assert(0); + return GL_SAMPLES_PASSED; +} + +} // namespace blender::gpu \ No newline at end of file -- cgit v1.2.3