diff options
Diffstat (limited to 'source/blender/gpu/opengl')
-rw-r--r-- | source/blender/gpu/opengl/gl_backend.cc | 107 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_backend.hh | 7 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_batch.cc | 16 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_batch.hh | 5 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_compute.cc | 35 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_compute.hh | 30 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_drawlist.cc | 1 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_immediate.hh | 2 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_index_buffer.cc | 34 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_index_buffer.hh | 7 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_shader.cc | 38 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_shader.hh | 4 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_shader_interface.cc | 45 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_state.hh | 3 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_texture.cc | 6 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_vertex_buffer.cc | 45 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_vertex_buffer.hh | 8 |
17 files changed, 318 insertions, 75 deletions
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index ef7788194a1..d85f9f7684d 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -41,39 +41,42 @@ namespace blender::gpu { void GLBackend::platform_init() { BLI_assert(!GPG.initialized); - GPG.initialized = true; + + const char *vendor = (const char *)glGetString(GL_VENDOR); + const char *renderer = (const char *)glGetString(GL_RENDERER); + const char *version = (const char *)glGetString(GL_VERSION); + eGPUDeviceType device = GPU_DEVICE_ANY; + eGPUOSType os = GPU_OS_ANY; + eGPUDriverType driver = GPU_DRIVER_ANY; + eGPUSupportLevel support_level = GPU_SUPPORT_LEVEL_SUPPORTED; #ifdef _WIN32 - GPG.os = GPU_OS_WIN; + os = GPU_OS_WIN; #elif defined(__APPLE__) - GPG.os = GPU_OS_MAC; + os = GPU_OS_MAC; #else - GPG.os = GPU_OS_UNIX; + os = GPU_OS_UNIX; #endif - const char *vendor = (const char *)glGetString(GL_VENDOR); - const char *renderer = (const char *)glGetString(GL_RENDERER); - const char *version = (const char *)glGetString(GL_VERSION); - if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) { - GPG.device = GPU_DEVICE_ATI; - GPG.driver = GPU_DRIVER_OFFICIAL; + device = GPU_DEVICE_ATI; + driver = GPU_DRIVER_OFFICIAL; } else if (strstr(vendor, "NVIDIA")) { - GPG.device = GPU_DEVICE_NVIDIA; - GPG.driver = GPU_DRIVER_OFFICIAL; + device = GPU_DEVICE_NVIDIA; + driver = GPU_DRIVER_OFFICIAL; } else if (strstr(vendor, "Intel") || /* src/mesa/drivers/dri/intel/intel_context.c */ strstr(renderer, "Mesa DRI Intel") || strstr(renderer, "Mesa DRI Mobile Intel")) { - GPG.device = GPU_DEVICE_INTEL; - GPG.driver = GPU_DRIVER_OFFICIAL; + device = GPU_DEVICE_INTEL; + driver = GPU_DRIVER_OFFICIAL; if (strstr(renderer, "UHD Graphics") || /* Not UHD but affected by the same bugs. */ strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2") || strstr(renderer, "Whiskey Lake")) { - GPG.device |= GPU_DEVICE_INTEL_UHD; + device |= GPU_DEVICE_INTEL_UHD; } } else if ((strstr(renderer, "Mesa DRI R")) || @@ -81,49 +84,47 @@ void GLBackend::platform_init() (strstr(renderer, "AMD") && strstr(vendor, "X.Org")) || (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) || (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) { - GPG.device = GPU_DEVICE_ATI; - GPG.driver = GPU_DRIVER_OPENSOURCE; + device = GPU_DEVICE_ATI; + driver = GPU_DRIVER_OPENSOURCE; } else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) { - GPG.device = GPU_DEVICE_NVIDIA; - GPG.driver = GPU_DRIVER_OPENSOURCE; + device = GPU_DEVICE_NVIDIA; + driver = GPU_DRIVER_OPENSOURCE; } else if (strstr(vendor, "Mesa")) { - GPG.device = GPU_DEVICE_SOFTWARE; - GPG.driver = GPU_DRIVER_SOFTWARE; + device = GPU_DEVICE_SOFTWARE; + driver = GPU_DRIVER_SOFTWARE; } else if (strstr(vendor, "Microsoft")) { - GPG.device = GPU_DEVICE_SOFTWARE; - GPG.driver = GPU_DRIVER_SOFTWARE; + device = GPU_DEVICE_SOFTWARE; + driver = GPU_DRIVER_SOFTWARE; } else if (strstr(vendor, "Apple")) { /* Apple Silicon. */ - GPG.device = GPU_DEVICE_APPLE; - GPG.driver = GPU_DRIVER_OFFICIAL; + device = GPU_DEVICE_APPLE; + driver = GPU_DRIVER_OFFICIAL; } else if (strstr(renderer, "Apple Software Renderer")) { - GPG.device = GPU_DEVICE_SOFTWARE; - GPG.driver = GPU_DRIVER_SOFTWARE; + device = GPU_DEVICE_SOFTWARE; + driver = GPU_DRIVER_SOFTWARE; } else if (strstr(renderer, "llvmpipe") || strstr(renderer, "softpipe")) { - GPG.device = GPU_DEVICE_SOFTWARE; - GPG.driver = GPU_DRIVER_SOFTWARE; + device = GPU_DEVICE_SOFTWARE; + driver = GPU_DRIVER_SOFTWARE; } else { printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n"); printf("Detected OpenGL configuration:\n"); printf("Vendor: %s\n", vendor); printf("Renderer: %s\n", renderer); - GPG.device = GPU_DEVICE_ANY; - GPG.driver = GPU_DRIVER_ANY; } /* Detect support level */ if (!GLEW_VERSION_3_3) { - GPG.support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED; + support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED; } else { - if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) { + if ((device & GPU_DEVICE_INTEL) && (os & GPU_OS_WIN)) { /* Old Intel drivers with known bugs that cause material properties to crash. * Version Build 10.18.14.5067 is the latest available and appears to be working * ok with our workarounds, so excluded from this list. */ @@ -132,19 +133,19 @@ void GLBackend::platform_init() strstr(version, "Build 9.18") || strstr(version, "Build 10.18.10.3") || strstr(version, "Build 10.18.10.4") || strstr(version, "Build 10.18.10.5") || strstr(version, "Build 10.18.14.4")) { - GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED; + support_level = GPU_SUPPORT_LEVEL_LIMITED; } } - if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_ANY)) { + if ((device & GPU_DEVICE_ATI) && (os & GPU_OS_UNIX)) { /* Platform seems to work when SB backend is disabled. This can be done * by adding the environment variable `R600_DEBUG=nosb`. */ if (strstr(renderer, "AMD CEDAR")) { - GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED; + support_level = GPU_SUPPORT_LEVEL_LIMITED; } } } - GPG.create_key(GPG.support_level, vendor, renderer, version); - GPG.create_gpu_name(vendor, renderer, version); + + GPG.init(device, os, driver, support_level, vendor, renderer, version); } void GLBackend::platform_exit() @@ -204,6 +205,11 @@ static bool detect_mip_render_workaround() return enable_workaround; } +static const char *gl_extension_get(int i) +{ + return (char *)glGetStringi(GL_EXTENSIONS, i); +} + static void detect_workarounds() { const char *vendor = (const char *)glGetString(GL_VENDOR); @@ -286,8 +292,9 @@ static void detect_workarounds() strstr(renderer, " RX 480 ") || strstr(renderer, " RX 490 ") || strstr(renderer, " RX 560 ") || strstr(renderer, " RX 560X ") || strstr(renderer, " RX 570 ") || strstr(renderer, " RX 580 ") || - strstr(renderer, " RX 590 ") || strstr(renderer, " RX550/550 ") || - strstr(renderer, " (TM) 520 ") || strstr(renderer, " (TM) 530 ") || + strstr(renderer, " RX 580X ") || strstr(renderer, " RX 590 ") || + strstr(renderer, " RX550/550 ") || strstr(renderer, "(TM) 520 ") || + strstr(renderer, "(TM) 530 ") || strstr(renderer, "(TM) 535 ") || strstr(renderer, " R5 ") || strstr(renderer, " R7 ") || strstr(renderer, " R9 ")) { GCaps.use_hq_normals_workaround = true; } @@ -418,8 +425,28 @@ void GLBackend::capabilities_init() glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &GCaps.max_textures_vert); glGetIntegerv(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &GCaps.max_textures_geom); glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &GCaps.max_textures); + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &GCaps.max_uniforms_vert); + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &GCaps.max_uniforms_frag); + glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &GCaps.max_batch_indices); + glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &GCaps.max_batch_vertices); + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &GCaps.max_vertex_attribs); + glGetIntegerv(GL_MAX_VARYING_FLOATS, &GCaps.max_varying_floats); + + glGetIntegerv(GL_NUM_EXTENSIONS, &GCaps.extensions_len); + GCaps.extension_get = gl_extension_get; + GCaps.mem_stats_support = GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo; GCaps.shader_image_load_store_support = GLEW_ARB_shader_image_load_store; + GCaps.compute_shader_support = GLEW_ARB_compute_shader; + if (GCaps.compute_shader_support) { + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &GCaps.max_work_group_count[0]); + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &GCaps.max_work_group_count[1]); + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &GCaps.max_work_group_count[2]); + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &GCaps.max_work_group_size[0]); + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &GCaps.max_work_group_size[1]); + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &GCaps.max_work_group_size[2]); + } + GCaps.shader_storage_buffer_objects_support = GLEW_ARB_shader_storage_buffer_object; /* GL specific capabilities. */ glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &GLContext::max_texture_3d_size); glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GLContext::max_cubemap_size); diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh index 231e5811b45..e9dcdffced0 100644 --- a/source/blender/gpu/opengl/gl_backend.hh +++ b/source/blender/gpu/opengl/gl_backend.hh @@ -28,6 +28,7 @@ #include "BLI_vector.hh" #include "gl_batch.hh" +#include "gl_compute.hh" #include "gl_context.hh" #include "gl_drawlist.hh" #include "gl_framebuffer.hh" @@ -126,6 +127,12 @@ class GLBackend : public GPUBackend { return shared_orphan_list_; }; + void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) override + { + GLContext::get()->state_manager_active_get()->apply_state(); + GLCompute::dispatch(groups_x_len, groups_y_len, groups_z_len); + } + private: static void platform_init(void); static void platform_exit(void); diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc index 321d9552828..fc1d1006d0d 100644 --- a/source/blender/gpu/opengl/gl_batch.cc +++ b/source/blender/gpu/opengl/gl_batch.cc @@ -44,7 +44,7 @@ using namespace blender::gpu; /* -------------------------------------------------------------------- */ -/** \name Vao cache +/** \name VAO Cache * * Each #GLBatch has a small cache of VAO objects that are used to avoid VAO reconfiguration. * TODO(fclem): Could be revisited to avoid so much cross references. @@ -279,20 +279,6 @@ GLuint GLVaoCache::vao_get(GPUBatch *batch) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Creation & Deletion - * \{ */ - -GLBatch::GLBatch() -{ -} - -GLBatch::~GLBatch() -{ -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Drawing * \{ */ diff --git a/source/blender/gpu/opengl/gl_batch.hh b/source/blender/gpu/opengl/gl_batch.hh index 218b9ffe4b7..704b6471dd5 100644 --- a/source/blender/gpu/opengl/gl_batch.hh +++ b/source/blender/gpu/opengl/gl_batch.hh @@ -43,7 +43,7 @@ class GLShaderInterface; #define GPU_VAO_STATIC_LEN 3 -/* Vao management: remembers all geometry state (vertex attribute bindings & element buffer) +/* VAO management: remembers all geometry state (vertex attribute 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. */ class GLVaoCache { @@ -96,9 +96,6 @@ class GLBatch : public Batch { GLVaoCache vao_cache_; public: - GLBatch(); - ~GLBatch(); - void draw(int v_first, int v_count, int i_first, int i_count) override; void bind(int i_first); diff --git a/source/blender/gpu/opengl/gl_compute.cc b/source/blender/gpu/opengl/gl_compute.cc new file mode 100644 index 00000000000..fa8317dde4a --- /dev/null +++ b/source/blender/gpu/opengl/gl_compute.cc @@ -0,0 +1,35 @@ +/* + * 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. + */ + +/** \file + * \ingroup gpu + */ + +#include "gl_compute.hh" + +#include "gl_debug.hh" + +#include "glew-mx.h" + +namespace blender::gpu { + +void GLCompute::dispatch(int group_x_len, int group_y_len, int group_z_len) +{ + glDispatchCompute(group_x_len, group_y_len, group_z_len); + debug::check_gl_error("Dispatch Compute"); +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_compute.hh b/source/blender/gpu/opengl/gl_compute.hh new file mode 100644 index 00000000000..2fd918ddd10 --- /dev/null +++ b/source/blender/gpu/opengl/gl_compute.hh @@ -0,0 +1,30 @@ +/* + * 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. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +namespace blender::gpu { + +class GLCompute { + public: + static void dispatch(int group_x_len, int group_y_len, int group_z_len); +}; + +} // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc index d3401036154..50ab5574cd2 100644 --- a/source/blender/gpu/opengl/gl_drawlist.cc +++ b/source/blender/gpu/opengl/gl_drawlist.cc @@ -68,6 +68,7 @@ GLDrawList::GLDrawList(int length) batch_ = nullptr; buffer_id_ = 0; command_len_ = 0; + base_index_ = 0; command_offset_ = 0; data_size_ = 0; data_ = nullptr; diff --git a/source/blender/gpu/opengl/gl_immediate.hh b/source/blender/gpu/opengl/gl_immediate.hh index d0bf0fcdf1f..b42f439f9ec 100644 --- a/source/blender/gpu/opengl/gl_immediate.hh +++ b/source/blender/gpu/opengl/gl_immediate.hh @@ -38,7 +38,7 @@ namespace blender::gpu { class GLImmediate : public Immediate { private: - /* Use two buffers for strict and unstrict vertex count to + /* Use two buffers for strict and non-strict vertex count to * avoid some huge driver slowdown (see T70922). * Use accessor functions to get / modify. */ struct { diff --git a/source/blender/gpu/opengl/gl_index_buffer.cc b/source/blender/gpu/opengl/gl_index_buffer.cc index e2c18c5d0b9..e305f765ad9 100644 --- a/source/blender/gpu/opengl/gl_index_buffer.cc +++ b/source/blender/gpu/opengl/gl_index_buffer.cc @@ -40,17 +40,14 @@ void GLIndexBuf::bind() return; } - if (ibo_id_ == 0) { + const bool allocate_on_device = ibo_id_ == 0; + if (allocate_on_device) { glGenBuffers(1, &ibo_id_); - - if (data_ == nullptr) { - debug::raise_gl_error("Trying to use Index Buffer but the buffer contains no data"); - } } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id_); - if (data_ != nullptr) { + if (data_ != nullptr || allocate_on_device) { size_t size = this->size_get(); /* Sends data to GPU. */ glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data_, GL_STATIC_DRAW); @@ -59,4 +56,29 @@ void GLIndexBuf::bind() } } +void GLIndexBuf::bind_as_ssbo(uint binding) +{ + bind(); + BLI_assert(ibo_id_ != 0); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, ibo_id_); +} + +const uint32_t *GLIndexBuf::read() const +{ + BLI_assert(is_active()); + void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY); + uint32_t *result = static_cast<uint32_t *>(data); + return result; +} + +bool GLIndexBuf::is_active() const +{ + if (!ibo_id_) { + return false; + } + int active_ibo_id = 0; + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &active_ibo_id); + return ibo_id_ == active_ibo_id; +} + } // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_index_buffer.hh b/source/blender/gpu/opengl/gl_index_buffer.hh index b84934bb77f..0dbdaa6d398 100644 --- a/source/blender/gpu/opengl/gl_index_buffer.hh +++ b/source/blender/gpu/opengl/gl_index_buffer.hh @@ -34,6 +34,7 @@ namespace blender::gpu { class GLIndexBuf : public IndexBuf { friend class GLBatch; friend class GLDrawList; + friend class GLShader; /* For compute shaders. */ private: GLuint ibo_id_ = 0; @@ -42,6 +43,9 @@ class GLIndexBuf : public IndexBuf { ~GLIndexBuf(); void bind(void); + void bind_as_ssbo(uint binding) override; + + const uint32_t *read() const override; void *offset_ptr(uint additional_vertex_offset) const { @@ -57,6 +61,9 @@ class GLIndexBuf : public IndexBuf { return (index_type_ == GPU_INDEX_U16) ? 0xFFFFu : 0xFFFFFFFFu; } + private: + bool is_active() const; + MEM_CXX_CLASS_ALLOC_FUNCS("GLIndexBuf") }; diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index dd08a67517e..e77347d99eb 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -26,6 +26,7 @@ #include "BLI_string.h" #include "BLI_vector.hh" +#include "GPU_capabilities.h" #include "GPU_platform.h" #include "gl_backend.hh" @@ -63,6 +64,7 @@ GLShader::~GLShader() glDeleteShader(vert_shader_); glDeleteShader(geom_shader_); glDeleteShader(frag_shader_); + glDeleteShader(compute_shader_); glDeleteProgram(shader_program_); } @@ -72,7 +74,7 @@ GLShader::~GLShader() /** \name Shader stage creation * \{ */ -char *GLShader::glsl_patch_get() +static char *glsl_patch_default_get() { /** Used for shader patching. Init once. */ static char patch[512] = "\0"; @@ -111,6 +113,30 @@ char *GLShader::glsl_patch_get() return patch; } +static char *glsl_patch_compute_get() +{ + /** Used for shader patching. Init once. */ + static char patch[512] = "\0"; + if (patch[0] != '\0') { + return patch; + } + + size_t slen = 0; + /* Version need to go first. */ + STR_CONCAT(patch, slen, "#version 430\n"); + STR_CONCAT(patch, slen, "#extension GL_ARB_compute_shader :enable\n"); + BLI_assert(slen < sizeof(patch)); + return patch; +} + +char *GLShader::glsl_patch_get(GLenum gl_stage) +{ + if (gl_stage == GL_COMPUTE_SHADER) { + return glsl_patch_compute_get(); + } + return glsl_patch_default_get(); +} + /* Create, compile and attach the shader stage to the shader program. */ GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources) { @@ -121,7 +147,7 @@ GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *> } /* Patch the shader code using the first source slot. */ - sources[0] = glsl_patch_get(); + sources[0] = glsl_patch_get(gl_stage); glShaderSource(shader, sources.size(), sources.data(), nullptr); glCompileShader(shader); @@ -142,6 +168,9 @@ GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *> case GL_FRAGMENT_SHADER: this->print_log(sources, log, "FragShader", !status); break; + case GL_COMPUTE_SHADER: + this->print_log(sources, log, "ComputeShader", !status); + break; } } } @@ -172,6 +201,11 @@ void GLShader::fragment_shader_from_glsl(MutableSpan<const char *> sources) frag_shader_ = this->create_shader_stage(GL_FRAGMENT_SHADER, sources); } +void GLShader::compute_shader_from_glsl(MutableSpan<const char *> sources) +{ + compute_shader_ = this->create_shader_stage(GL_COMPUTE_SHADER, sources); +} + bool GLShader::finalize() { if (compilation_failed_) { diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh index 152eb2f068a..48aaaf2283d 100644 --- a/source/blender/gpu/opengl/gl_shader.hh +++ b/source/blender/gpu/opengl/gl_shader.hh @@ -43,6 +43,7 @@ class GLShader : public Shader { GLuint vert_shader_ = 0; GLuint geom_shader_ = 0; GLuint frag_shader_ = 0; + GLuint compute_shader_ = 0; /** True if any shader failed to compile. */ bool compilation_failed_ = false; @@ -56,6 +57,7 @@ class GLShader : public Shader { void vertex_shader_from_glsl(MutableSpan<const char *> sources) override; void geometry_shader_from_glsl(MutableSpan<const char *> sources) override; void fragment_shader_from_glsl(MutableSpan<const char *> sources) override; + void compute_shader_from_glsl(MutableSpan<const char *> sources) override; bool finalize(void) override; void transform_feedback_names_set(Span<const char *> name_list, @@ -75,7 +77,7 @@ class GLShader : public Shader { int program_handle_get(void) const override; private: - char *glsl_patch_get(void); + char *glsl_patch_get(GLenum gl_stage); GLuint create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources); diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc index 5870c645bf4..9cf072b2e8a 100644 --- a/source/blender/gpu/opengl/gl_shader_interface.cc +++ b/source/blender/gpu/opengl/gl_shader_interface.cc @@ -29,6 +29,8 @@ #include "gl_shader_interface.hh" +#include "GPU_capabilities.h" + namespace blender::gpu { /* -------------------------------------------------------------------- */ @@ -125,6 +127,18 @@ static inline int image_binding(int32_t program, return -1; } } + +static inline int ssbo_binding(int32_t program, uint32_t ssbo_index) +{ + GLint binding = -1; + GLenum property = GL_BUFFER_BINDING; + GLint values_written = 0; + glGetProgramResourceiv( + program, GL_SHADER_STORAGE_BLOCK, ssbo_index, 1, &property, 1, &values_written, &binding); + + return binding; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -149,6 +163,13 @@ GLShaderInterface::GLShaderInterface(GLuint program) glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniform_len); uniform_len = active_uniform_len; + GLint max_ssbo_name_len = 0, ssbo_len = 0; + if (GPU_shader_storage_buffer_objects_support()) { + glGetProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &ssbo_len); + glGetProgramInterfaceiv( + program, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &max_ssbo_name_len); + } + BLI_assert(ubo_len <= 16 && "enabled_ubo_mask_ is uint16_t"); /* Work around driver bug with Intel HD 4600 on Windows 7/8, where @@ -162,6 +183,9 @@ GLShaderInterface::GLShaderInterface(GLuint program) if (uniform_len > 0 && max_uniform_name_len == 0) { max_uniform_name_len = 256; } + if (ssbo_len > 0 && max_ssbo_name_len == 0) { + max_ssbo_name_len = 256; + } /* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before * allocating the uniform array. */ @@ -186,11 +210,12 @@ GLShaderInterface::GLShaderInterface(GLuint program) } MEM_freeN(ubo_uni_ids); - int input_tot_len = attr_len + ubo_len + uniform_len; + int input_tot_len = attr_len + ubo_len + uniform_len + ssbo_len; inputs_ = (ShaderInput *)MEM_callocN(sizeof(ShaderInput) * input_tot_len, __func__); const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len + - uniform_len * max_uniform_name_len; + uniform_len * max_uniform_name_len + + ssbo_len * max_ssbo_name_len; name_buffer_ = (char *)MEM_mallocN(name_buffer_len, "name_buffer"); uint32_t name_buffer_offset = 0; @@ -257,6 +282,22 @@ GLShaderInterface::GLShaderInterface(GLuint program) } } + /* SSBOs */ + for (int i = 0; i < ssbo_len; i++) { + char *name = name_buffer_ + name_buffer_offset; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; + GLsizei name_len = 0; + glGetProgramResourceName( + program, GL_SHADER_STORAGE_BLOCK, i, remaining_buffer, &name_len, name); + + const GLint binding = ssbo_binding(program, i); + + ShaderInput *input = &inputs_[attr_len_ + ubo_len_ + uniform_len_ + ssbo_len_++]; + input->binding = input->location = binding; + + name_buffer_offset += this->set_input_name(input, name, name_len); + } + /* Builtin Uniforms */ for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) { GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int); diff --git a/source/blender/gpu/opengl/gl_state.hh b/source/blender/gpu/opengl/gl_state.hh index 651c3c22afa..3b4b40b1d10 100644 --- a/source/blender/gpu/opengl/gl_state.hh +++ b/source/blender/gpu/opengl/gl_state.hh @@ -121,6 +121,9 @@ static inline GLbitfield to_gl(eGPUBarrier barrier_bits) if (barrier_bits & GPU_BARRIER_TEXTURE_FETCH) { barrier |= GL_TEXTURE_FETCH_BARRIER_BIT; } + if (barrier_bits & GPU_BARRIER_SHADER_STORAGE) { + barrier |= GL_SHADER_STORAGE_BARRIER_BIT; + } return barrier; } diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc index 51cfcd20a6c..e2478a9976c 100644 --- a/source/blender/gpu/opengl/gl_texture.cc +++ b/source/blender/gpu/opengl/gl_texture.cc @@ -290,7 +290,9 @@ void GLTexture::update_sub( } } -/** This will create the mipmap images and populate them with filtered data from base level. +/** + * This will create the mipmap images and populate them with filtered data from base level. + * * WARNING: Depth textures are not populated but they have their mips correctly defined. * WARNING: This resets the mipmap range. */ @@ -366,7 +368,7 @@ void GLTexture::copy_to(Texture *dst_) void *GLTexture::read(int mip, eGPUDataFormat type) { BLI_assert(!(format_flag_ & GPU_FORMAT_COMPRESSED)); - BLI_assert(mip <= mipmaps_); + BLI_assert(mip <= mipmaps_ || mip == 0); BLI_assert(validate_data_format(format_, type)); /* NOTE: mip_size_get() won't override any dimension that is equal to 0. */ diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.cc b/source/blender/gpu/opengl/gl_vertex_buffer.cc index a56d5269fde..ce16a491528 100644 --- a/source/blender/gpu/opengl/gl_vertex_buffer.cc +++ b/source/blender/gpu/opengl/gl_vertex_buffer.cc @@ -29,6 +29,10 @@ namespace blender::gpu { void GLVertBuf::acquire_data() { + if (usage_ == GPU_USAGE_DEVICE_ONLY) { + return; + } + /* Discard previous data if any. */ MEM_SAFE_FREE(data); data = (uchar *)MEM_mallocN(sizeof(uchar) * this->size_alloc_get(), __func__); @@ -36,6 +40,10 @@ void GLVertBuf::acquire_data() void GLVertBuf::resize_data() { + if (usage_ == GPU_USAGE_DEVICE_ONLY) { + return; + } + data = (uchar *)MEM_reallocN(data, sizeof(uchar) * this->size_alloc_get()); } @@ -94,8 +102,10 @@ void GLVertBuf::bind() vbo_size_ = this->size_used_get(); /* Orphan the vbo to avoid sync then upload data. */ glBufferData(GL_ARRAY_BUFFER, vbo_size_, nullptr, to_gl(usage_)); - glBufferSubData(GL_ARRAY_BUFFER, 0, vbo_size_, data); - + /* Do not transfer data from host to device when buffer is device only. */ + if (usage_ != GPU_USAGE_DEVICE_ONLY) { + glBufferSubData(GL_ARRAY_BUFFER, 0, vbo_size_, data); + } memory_usage += vbo_size_; if (usage_ == GPU_USAGE_STATIC) { @@ -106,6 +116,37 @@ void GLVertBuf::bind() } } +void GLVertBuf::bind_as_ssbo(uint binding) +{ + bind(); + BLI_assert(vbo_id_ != 0); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, vbo_id_); +} + +const void *GLVertBuf::read() const +{ + BLI_assert(is_active()); + void *result = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); + return result; +} + +void *GLVertBuf::unmap(const void *mapped_data) const +{ + void *result = MEM_mallocN(vbo_size_, __func__); + memcpy(result, mapped_data, vbo_size_); + return result; +} + +bool GLVertBuf::is_active() const +{ + if (!vbo_id_) { + return false; + } + int active_vbo_id = 0; + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &active_vbo_id); + return vbo_id_ == active_vbo_id; +} + void GLVertBuf::update_sub(uint start, uint len, void *data) { glBufferSubData(GL_ARRAY_BUFFER, start, len, data); diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.hh b/source/blender/gpu/opengl/gl_vertex_buffer.hh index e2bf6cd00e8..6c38a2225b3 100644 --- a/source/blender/gpu/opengl/gl_vertex_buffer.hh +++ b/source/blender/gpu/opengl/gl_vertex_buffer.hh @@ -47,12 +47,19 @@ class GLVertBuf : public VertBuf { void update_sub(uint start, uint len, void *data) override; + const void *read() const override; + void *unmap(const void *mapped_data) const override; + protected: void acquire_data(void) override; void resize_data(void) override; void release_data(void) override; void upload_data(void) override; void duplicate_data(VertBuf *dst) override; + void bind_as_ssbo(uint binding) override; + + private: + bool is_active() const; MEM_CXX_CLASS_ALLOC_FUNCS("GLVertBuf"); }; @@ -65,6 +72,7 @@ static inline GLenum to_gl(GPUUsageType type) case GPU_USAGE_DYNAMIC: return GL_DYNAMIC_DRAW; case GPU_USAGE_STATIC: + case GPU_USAGE_DEVICE_ONLY: return GL_STATIC_DRAW; default: BLI_assert(0); |