diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2020-09-08 00:52:55 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2020-09-08 01:02:04 +0300 |
commit | 5c2ac8520e070db2085b7d95d9d232b567edb247 (patch) | |
tree | c91d89789e0e390937c84807dd73cf1637cada70 /source/blender | |
parent | d4fd363d05943eaf021ef3bff8756cdf96241c0e (diff) |
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.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/gpu/CMakeLists.txt | 6 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_backend.hh | 2 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_query.cc | 28 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_query.hh | 59 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_select_private.h | 8 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_select_sample_query.cc (renamed from source/blender/gpu/intern/gpu_select_sample_query.c) | 85 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_backend.hh | 6 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_context.hh | 16 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_query.cc | 78 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_query.hh | 69 |
10 files changed, 294 insertions, 63 deletions
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<uint32_t> 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.cc index 45d52b22664..1b54cbff5dd 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.c +++ b/source/blender/gpu/intern/gpu_select_sample_query.cc @@ -27,7 +27,6 @@ #include <stdlib.h> #include "GPU_framebuffer.h" -#include "GPU_glew.h" #include "GPU_select.h" #include "GPU_state.h" @@ -35,24 +34,25 @@ #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" -/* Ad hoc number of queries to allocate to skip doing many glGenQueries */ -#define ALLOC_QUERIES 200 +using namespace blender; +using namespace blender::gpu; -typedef struct GPUQueryState { +typedef struct GPUSelectQueryState { /* 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; + /* GPU queries abstraction. Contains an array of queries. */ + QueryPool *queries; + /* Array holding the id corresponding id to each query. */ + Vector<uint> *ids; /* cache on initialization */ uint (*buffer)[4]; /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/ @@ -67,29 +67,23 @@ typedef struct GPUQueryState { int scissor[4]; eGPUWriteMask write_mask; eGPUDepthTest depth_test; -} GPUQueryState; +} GPUSelectQueryState; -static GPUQueryState g_query_state = {0}; +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.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.ids = new Vector<uint>(); + 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(); @@ -133,21 +127,11 @@ void gpu_select_query_begin( 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]); + g_query_state.queries->end_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.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) { @@ -158,39 +142,33 @@ bool gpu_select_query_load_id(uint 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); + g_query_state.queries->end_query(); } - 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) { + Span<uint> ids = *g_query_state.ids; + Vector<uint32_t> 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] = g_query_state.id[i]; - + g_query_state.buffer[hits][3] = ids[i]; hits++; } else { @@ -202,7 +180,7 @@ uint gpu_select_query_end(void) 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]) { + if (g_query_state.buffer[j][3] == ids[i]) { g_query_state.buffer[j][1] = 0; g_query_state.buffer[j][2] = 0; } @@ -212,9 +190,8 @@ uint gpu_select_query_end(void) } } - glDeleteQueries(g_query_state.num_of_queries, g_query_state.queries); - MEM_freeN(g_query_state.queries); - MEM_freeN(g_query_state.id); + 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); 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<GLuint> &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<GLuint> &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<uint32_t> 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<GLuint> 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<uint32_t> 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 |