diff options
Diffstat (limited to 'source/blender/gpu/intern')
27 files changed, 712 insertions, 839 deletions
diff --git a/source/blender/gpu/intern/gpu_attr_binding.cc b/source/blender/gpu/intern/gpu_attr_binding.cc index 6cb60884620..2a48107e190 100644 --- a/source/blender/gpu/intern/gpu_attr_binding.cc +++ b/source/blender/gpu/intern/gpu_attr_binding.cc @@ -61,9 +61,7 @@ static void write_attr_location(GPUAttrBinding *binding, uint a_idx, uint locati binding->enabled_bits |= 1 << a_idx; } -void get_attr_locations(const GPUVertFormat *format, - GPUAttrBinding *binding, - const GPUShaderInterface *shaderface) +void get_attr_locations(const GPUVertFormat *format, GPUAttrBinding *binding, GPUShader *shader) { AttrBinding_clear(binding); @@ -71,13 +69,12 @@ void get_attr_locations(const GPUVertFormat *format, const GPUVertAttr *a = &format->attrs[a_idx]; for (uint n_idx = 0; n_idx < a->name_len; n_idx++) { const char *name = GPU_vertformat_attr_name_get(format, a, n_idx); - const GPUShaderInput *input = GPU_shaderinterface_attr(shaderface, name); -#if TRUST_NO_ONE - assert(input != NULL); + int loc = GPU_shader_get_attribute(shader, name); /* TODO: make this a recoverable runtime error? * indicates mismatch between vertex format and program. */ -#endif - write_attr_location(binding, a_idx, input->location); + BLI_assert(loc != -1); + + write_attr_location(binding, a_idx, loc); } } } diff --git a/source/blender/gpu/intern/gpu_attr_binding_private.h b/source/blender/gpu/intern/gpu_attr_binding_private.h index 4d359343c38..cd67a51a822 100644 --- a/source/blender/gpu/intern/gpu_attr_binding_private.h +++ b/source/blender/gpu/intern/gpu_attr_binding_private.h @@ -25,8 +25,8 @@ #pragma once -#include "GPU_shader_interface.h" #include "GPU_vertex_format.h" +#include "gpu_shader_interface.hh" #ifdef __cplusplus extern "C" { @@ -35,9 +35,7 @@ extern "C" { /* TODO(fclem) remove, use shaderface directly. */ void AttrBinding_clear(GPUAttrBinding *binding); -void get_attr_locations(const GPUVertFormat *format, - GPUAttrBinding *binding, - const GPUShaderInterface *shaderface); +void get_attr_locations(const GPUVertFormat *format, GPUAttrBinding *binding, GPUShader *shader); uint read_attr_location(const GPUAttrBinding *binding, uint a_idx); #ifdef __cplusplus diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh index 6ab0e32a754..f63f3cead2b 100644 --- a/source/blender/gpu/intern/gpu_backend.hh +++ b/source/blender/gpu/intern/gpu_backend.hh @@ -25,14 +25,16 @@ #pragma once -#include "gpu_batch_private.hh" -#include "gpu_context_private.hh" -#include "gpu_drawlist_private.hh" -#include "gpu_shader_private.hh" +struct GPUContext; namespace blender { namespace gpu { +class Batch; +class DrawList; +class Shader; +class UniformBuf; + class GPUBackend { public: virtual ~GPUBackend(){}; @@ -46,6 +48,7 @@ class GPUBackend { // virtual FrameBuffer *framebuffer_alloc(void) = 0; virtual Shader *shader_alloc(const char *name) = 0; // virtual Texture *texture_alloc(void) = 0; + virtual UniformBuf *uniformbuf_alloc(int size, const char *name) = 0; }; } // namespace gpu diff --git a/source/blender/gpu/intern/gpu_batch_private.hh b/source/blender/gpu/intern/gpu_batch_private.hh index 3a8044efc1d..c0444647fe1 100644 --- a/source/blender/gpu/intern/gpu_batch_private.hh +++ b/source/blender/gpu/intern/gpu_batch_private.hh @@ -28,11 +28,14 @@ #include "GPU_batch.h" #include "GPU_context.h" -#include "GPU_shader_interface.h" namespace blender { namespace gpu { +/** + * Base class which is then specialized for each implementation (GL, VK, ...). + * NOTE: Extends GPUBatch as we still needs to expose some of the internals to the outside C code. + **/ class Batch : public GPUBatch { public: Batch(){}; diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index b051d4fe59a..1629584e841 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -43,7 +43,7 @@ #include "GPU_extensions.h" #include "GPU_material.h" #include "GPU_shader.h" -#include "GPU_uniformbuffer.h" +#include "GPU_uniform_buffer.h" #include "GPU_vertex_format.h" #include "BLI_sys_types.h" /* for intptr_t support */ diff --git a/source/blender/gpu/intern/gpu_context_private.hh b/source/blender/gpu/intern/gpu_context_private.hh index b774d6b0995..e8c9c976e9a 100644 --- a/source/blender/gpu/intern/gpu_context_private.hh +++ b/source/blender/gpu/intern/gpu_context_private.hh @@ -29,6 +29,7 @@ #include "GPU_context.h" +#include "gpu_shader_private.hh" #include "gpu_state_private.hh" #include <mutex> @@ -43,7 +44,7 @@ struct GPUMatrixState; struct GPUContext { public: /** State managment */ - GPUShader *shader = NULL; + blender::gpu::Shader *shader = NULL; GPUFrameBuffer *current_fbo = NULL; GPUMatrixState *matrix_state = NULL; blender::gpu::GPUStateManager *state_manager = NULL; diff --git a/source/blender/gpu/intern/gpu_drawlist_private.hh b/source/blender/gpu/intern/gpu_drawlist_private.hh index 04cc18a5ffd..ddb09fb0c89 100644 --- a/source/blender/gpu/intern/gpu_drawlist_private.hh +++ b/source/blender/gpu/intern/gpu_drawlist_private.hh @@ -28,6 +28,10 @@ namespace blender { namespace gpu { +/** + * Implementation of Multi Draw Indirect. + * Base class which is then specialized for each implementation (GL, VK, ...). + **/ class DrawList { public: virtual ~DrawList(){}; diff --git a/source/blender/gpu/intern/gpu_extensions.cc b/source/blender/gpu/intern/gpu_extensions.cc index 8074e4b64f0..1d607d79b01 100644 --- a/source/blender/gpu/intern/gpu_extensions.cc +++ b/source/blender/gpu/intern/gpu_extensions.cc @@ -71,12 +71,10 @@ static struct GPUGlobal { GLint maxubosize; GLint maxubobinds; int samples_color_texture_max; - float line_width_range[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers * calculate dfdy in shader differently when drawing to an off-screen buffer. First * number is factor on screen and second is off-screen */ float dfdyfactors[2]; - float max_anisotropy; /* Some Intel drivers have limited support for `GLEW_ARB_base_instance` so in * these cases it is best to indicate that it is not supported. See T67951 */ bool glew_arb_base_instance_is_supported; @@ -164,11 +162,6 @@ int GPU_max_textures_vert(void) return GG.maxtexturesvert; } -float GPU_max_texture_anisotropy(void) -{ - return GG.max_anisotropy; -} - int GPU_max_color_texture_samples(void) { return GG.samples_color_texture_max; @@ -189,11 +182,6 @@ int GPU_max_ubo_size(void) return GG.maxubosize; } -float GPU_max_line_width(void) -{ - return GG.line_width_range[1]; -} - void GPU_get_dfdy_factors(float fac[2]) { copy_v2_v2(fac, GG.dfdyfactors); @@ -264,18 +252,9 @@ void gpu_extensions_init(void) glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &GG.maxtexlayers); glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GG.maxcubemapsize); - if (GLEW_EXT_texture_filter_anisotropic) { - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &GG.max_anisotropy); - } - else { - GG.max_anisotropy = 1.0f; - } - glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &GG.maxubobinds); glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GG.maxubosize); - glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, GG.line_width_range); - glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &GG.samples_color_texture_max); const char *vendor = (const char *)glGetString(GL_VENDOR); diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc index da8ab80b347..88013640bfc 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.cc +++ b/source/blender/gpu/intern/gpu_framebuffer.cc @@ -622,23 +622,37 @@ void GPU_framebuffer_clear(GPUFrameBuffer *fb, { CHECK_FRAMEBUFFER_IS_BOUND(fb); - GPU_context_active_get()->state_manager->apply_state(); + /* Save and restore the state. */ + eGPUWriteMask write_mask = GPU_write_mask_get(); + uint stencil_mask = GPU_stencil_mask_get(); + eGPUStencilTest stencil_test = GPU_stencil_test_get(); if (buffers & GPU_COLOR_BIT) { - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + GPU_color_mask(true, true, true, true); glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]); } if (buffers & GPU_DEPTH_BIT) { - glDepthMask(GL_TRUE); + GPU_depth_mask(true); glClearDepth(clear_depth); } if (buffers & GPU_STENCIL_BIT) { - glStencilMask(0xFF); + GPU_stencil_write_mask_set(0xFFu); + GPU_stencil_test(GPU_STENCIL_ALWAYS); glClearStencil(clear_stencil); } + GPU_context_active_get()->state_manager->apply_state(); + GLbitfield mask = convert_buffer_bits_to_gl(buffers); glClear(mask); + + if (buffers & (GPU_COLOR_BIT | GPU_DEPTH_BIT)) { + GPU_write_mask(write_mask); + } + if (buffers & GPU_STENCIL_BIT) { + GPU_stencil_write_mask_set(stencil_mask); + GPU_stencil_test(stencil_test); + } } /* Clear all textures bound to this framebuffer with a different color. */ @@ -1103,18 +1117,22 @@ void GPU_offscreen_viewport_data_get(GPUOffScreen *ofs, void GPU_clear_color(float red, float green, float blue, float alpha) { + BLI_assert((GPU_write_mask_get() & GPU_WRITE_COLOR) != 0); + + GPU_context_active_get()->state_manager->apply_state(); + glClearColor(red, green, blue, alpha); + glClear(GL_COLOR_BUFFER_BIT); } void GPU_clear_depth(float depth) { - glClearDepth(depth); -} + BLI_assert((GPU_write_mask_get() & GPU_WRITE_DEPTH) != 0); -void GPU_clear(eGPUFrameBufferBits flags) -{ GPU_context_active_get()->state_manager->apply_state(); - glClear(convert_buffer_bits_to_gl(flags)); + + glClearDepth(depth); + glClear(GL_DEPTH_BUFFER_BIT); } void GPU_frontbuffer_read_pixels( diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc index dd05689d69a..431dbe848f7 100644 --- a/source/blender/gpu/intern/gpu_immediate.cc +++ b/source/blender/gpu/intern/gpu_immediate.cc @@ -73,7 +73,6 @@ typedef struct { GLuint vao_id; GPUShader *bound_program; - const GPUShaderInterface *shader_interface; GPUAttrBinding attr_binding; uint16_t prev_enabled_attr_bits; /* <-- only affects this VAO, so we're ok */ } Immediate; @@ -148,14 +147,13 @@ void immBindShader(GPUShader *shader) BLI_assert(imm.bound_program == NULL); imm.bound_program = shader; - imm.shader_interface = shader->interface; if (!imm.vertex_format.packed) { VertexFormat_pack(&imm.vertex_format); } GPU_shader_bind(shader); - get_attr_locations(&imm.vertex_format, &imm.attr_binding, imm.shader_interface); + get_attr_locations(&imm.vertex_format, &imm.attr_binding, shader); GPU_matrix_bind(shader); GPU_shader_set_srgb_uniform(shader); } @@ -749,123 +747,77 @@ void immVertex2iv(uint attr_id, const int data[2]) /* --- generic uniform functions --- */ -#if 0 -# if TRUST_NO_ONE -# define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); \ - assert(uniform); -# else -# define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_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 GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); \ - if (uniform == NULL) \ - return; -#endif - void immUniform1f(const char *name, float x) { - GET_UNIFORM - glUniform1f(uniform->location, x); + GPU_shader_uniform_1f(imm.bound_program, name, x); } void immUniform2f(const char *name, float x, float y) { - GET_UNIFORM - glUniform2f(uniform->location, x, y); + GPU_shader_uniform_2f(imm.bound_program, name, x, y); } void immUniform2fv(const char *name, const float data[2]) { - GET_UNIFORM - glUniform2fv(uniform->location, 1, data); + GPU_shader_uniform_2fv(imm.bound_program, name, data); } void immUniform3f(const char *name, float x, float y, float z) { - GET_UNIFORM - glUniform3f(uniform->location, x, y, z); + GPU_shader_uniform_3f(imm.bound_program, name, 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 - -/* Note array index is not supported for name (i.e: "array[0]"). */ -void immUniformArray3fv(const char *name, const float *data, int count) -{ - GET_UNIFORM - glUniform3fv(uniform->location, count, data); + GPU_shader_uniform_3fv(imm.bound_program, name, data); } void immUniform4f(const char *name, float x, float y, float z, float w) { - GET_UNIFORM - glUniform4f(uniform->location, x, y, z, w); + GPU_shader_uniform_4f(imm.bound_program, name, x, y, z, w); } void immUniform4fv(const char *name, const float data[4]) { - GET_UNIFORM - glUniform4fv(uniform->location, 1, data); + GPU_shader_uniform_4fv(imm.bound_program, name, data); } /* Note array index is not supported for name (i.e: "array[0]"). */ void immUniformArray4fv(const char *name, const float *data, int count) { - GET_UNIFORM - glUniform4fv(uniform->location, count, data); + GPU_shader_uniform_4fv_array(imm.bound_program, name, count, (float(*)[4])data); } void immUniformMatrix4fv(const char *name, const float data[4][4]) { - GET_UNIFORM - glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (float *)data); + GPU_shader_uniform_mat4(imm.bound_program, name, 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); + GPU_shader_uniform_1i(imm.bound_program, name, x); } void immBindTexture(const char *name, GPUTexture *tex) { - GET_UNIFORM - GPU_texture_bind(tex, uniform->binding); + int binding = GPU_shader_get_texture_binding(imm.bound_program, name); + GPU_texture_bind(tex, binding); } void immBindTextureSampler(const char *name, GPUTexture *tex, eGPUSamplerState state) { - GET_UNIFORM - GPU_texture_bind_ex(tex, state, uniform->binding, true); + int binding = GPU_shader_get_texture_binding(imm.bound_program, name); + GPU_texture_bind_ex(tex, state, binding, true); } /* --- convenience functions for setting "uniform vec4 color" --- */ void immUniformColor4f(float r, float g, float b, float a) { - int32_t uniform_loc = GPU_shaderinterface_uniform_builtin(imm.shader_interface, - GPU_UNIFORM_COLOR); + int32_t uniform_loc = GPU_shader_get_builtin_uniform(imm.bound_program, GPU_UNIFORM_COLOR); BLI_assert(uniform_loc != -1); - glUniform4f(uniform_loc, r, g, b, a); + float data[4] = {r, g, b, a}; + GPU_shader_uniform_vector(imm.bound_program, uniform_loc, 4, 1, data); } void immUniformColor4fv(const float rgba[4]) diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 8df1f94238a..1016e766140 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -47,7 +47,7 @@ #include "GPU_material.h" #include "GPU_shader.h" #include "GPU_texture.h" -#include "GPU_uniformbuffer.h" +#include "GPU_uniform_buffer.h" #include "DRW_engine.h" @@ -88,11 +88,11 @@ struct GPUMaterial { eGPUMatFlag flag; /* Used by 2.8 pipeline */ - GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */ + GPUUniformBuf *ubo; /* UBOs for shader uniforms. */ /* Eevee SSS */ - GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */ - GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */ + GPUUniformBuf *sss_profile; /* UBO containing SSS profile. */ + GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */ float sss_enabled; float sss_radii[3]; int sss_samples; @@ -174,13 +174,13 @@ static void gpu_material_free_single(GPUMaterial *material) GPU_pass_release(material->pass); } if (material->ubo != NULL) { - GPU_uniformbuffer_free(material->ubo); + GPU_uniformbuf_free(material->ubo); } if (material->sss_tex_profile != NULL) { GPU_texture_free(material->sss_tex_profile); } if (material->sss_profile != NULL) { - GPU_uniformbuffer_free(material->sss_profile); + GPU_uniformbuf_free(material->sss_profile); } if (material->coba_tex != NULL) { GPU_texture_free(material->coba_tex); @@ -220,7 +220,7 @@ Material *GPU_material_get_material(GPUMaterial *material) return material->ma; } -GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material) +GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material) { return material->ubo; } @@ -232,7 +232,12 @@ GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material) */ void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs) { - material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL); +#ifndef NDEBUG + const char *name = material->name; +#else + const char *name = "Material"; +#endif + material->ubo = GPU_uniformbuf_create_from_list(inputs, name); } /* Eevee Subsurface scattering. */ @@ -507,13 +512,13 @@ void GPU_material_sss_profile_create(GPUMaterial *material, /* Update / Create UBO */ if (material->sss_profile == NULL) { - material->sss_profile = GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL); + material->sss_profile = GPU_uniformbuf_create(sizeof(GPUSssKernelData)); } } -struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, - int sample_len, - GPUTexture **tex_profile) +struct GPUUniformBuf *GPU_material_sss_profile_get(GPUMaterial *material, + int sample_len, + GPUTexture **tex_profile) { if (!material->sss_enabled) { return NULL; @@ -530,7 +535,7 @@ struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, compute_sss_kernel(&kd, material->sss_radii, sample_len, material->sss_falloff, sharpness); /* Update / Create UBO */ - GPU_uniformbuffer_update(material->sss_profile, &kd); + GPU_uniformbuf_update(material->sss_profile, &kd); /* Update / Create Tex */ float *translucence_profile; @@ -555,9 +560,9 @@ struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, return material->sss_profile; } -struct GPUUniformBuffer *GPU_material_create_sss_profile_ubo(void) +struct GPUUniformBuf *GPU_material_create_sss_profile_ubo(void) { - return GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL); + return GPU_uniformbuf_create(sizeof(GPUSssKernelData)); } #undef SSS_EXPONENT @@ -735,7 +740,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, gpu_node_graph_free(&mat->graph); } - /* Only free after GPU_pass_shader_get where GPUUniformBuffer + /* Only free after GPU_pass_shader_get where GPUUniformBuf * read data from the local tree. */ ntreeFreeLocalTree(localtree); MEM_freeN(localtree); diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc index 951652b9393..cdb6d303588 100644 --- a/source/blender/gpu/intern/gpu_matrix.cc +++ b/source/blender/gpu/intern/gpu_matrix.cc @@ -21,8 +21,6 @@ * \ingroup gpu */ -#include "GPU_shader_interface.h" - #include "gpu_context_private.hh" #include "gpu_matrix_private.h" @@ -649,14 +647,13 @@ void GPU_matrix_bind(GPUShader *shader) * call this before a draw call if desired matrices are dirty * call glUseProgram before this, as glUniform expects program to be bound */ - const GPUShaderInterface *shaderface = shader->interface; - int32_t MV = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW); - int32_t P = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION); - int32_t MVP = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MVP); - - int32_t N = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_NORMAL); - int32_t MV_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW_INV); - int32_t P_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION_INV); + int32_t MV = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW); + int32_t P = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_PROJECTION); + int32_t MVP = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP); + + int32_t N = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL); + int32_t MV_inv = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV); + int32_t P_inv = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_PROJECTION_INV); if (MV != -1) { GPU_shader_uniform_vector(shader, MV, 16, 1, (const float *)GPU_matrix_model_view_get(NULL)); diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index 81cf2d69f4d..1b8a5e20240 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -592,10 +592,10 @@ bool GPU_stack_link(GPUMaterial *material, return true; } -GPUNodeLink *GPU_uniformbuffer_link_out(GPUMaterial *mat, - bNode *node, - GPUNodeStack *stack, - const int index) +GPUNodeLink *GPU_uniformbuf_link_out(GPUMaterial *mat, + bNode *node, + GPUNodeStack *stack, + const int index) { return gpu_uniformbuffer_link(mat, node, stack, index, SOCK_OUT); } diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c index 29e2615345c..c3ccb68a998 100644 --- a/source/blender/gpu/intern/gpu_select_pick.c +++ b/source/blender/gpu/intern/gpu_select_pick.c @@ -27,6 +27,7 @@ #include <stdlib.h> #include <string.h> +#include "GPU_framebuffer.h" #include "GPU_glew.h" #include "GPU_immediate.h" #include "GPU_select.h" @@ -287,7 +288,7 @@ typedef struct GPUPickState { int viewport[4]; int scissor[4]; eGPUWriteMask write_mask; - bool depth_test; + eGPUDepthTest depth_test; } GPUPickState; static GPUPickState g_pick_state = {0}; @@ -311,18 +312,17 @@ void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, c /* Restrict OpenGL operations for when we don't have cache */ if (ps->is_cached == false) { ps->write_mask = GPU_write_mask_get(); - ps->depth_test = GPU_depth_test_enabled(); + ps->depth_test = GPU_depth_test_get(); GPU_scissor_get(ps->scissor); /* disable writing to the framebuffer */ GPU_color_mask(false, false, false, false); - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); + GPU_depth_mask(true); /* Always use #GL_LEQUAL even though GPU_SELECT_PICK_ALL always clears the buffer. This is * because individual objects themselves might have sections that overlap and we need these * to have the correct distance information. */ - glDepthFunc(GL_LEQUAL); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); float viewport[4]; GPU_viewport_size_get_f(viewport); @@ -339,7 +339,7 @@ void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, c /* It's possible we don't want to clear depth buffer, * so existing elements are masked by current z-buffer. */ - glClear(GL_DEPTH_BUFFER_BIT); + GPU_clear_depth(1.0f); /* scratch buffer (read new values here) */ ps->gl.rect_depth_test = depth_buf_malloc(rect_len); @@ -518,8 +518,13 @@ bool gpu_select_pick_load_id(uint id, bool end) SWAP(DepthBufCache *, ps->gl.rect_depth, ps->gl.rect_depth_test); if (g_pick_state.mode == GPU_SELECT_PICK_ALL) { + /* (fclem) This is to be on the safe side. I don't know if this is required. */ + bool prev_depth_mask = GPU_depth_mask_get(); /* we want new depths every time */ - glClear(GL_DEPTH_BUFFER_BIT); + GPU_depth_mask(true); + GPU_clear_depth(1.0f); + + GPU_depth_mask(prev_depth_mask); } } } diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c index 62414febb44..45d52b22664 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.c +++ b/source/blender/gpu/intern/gpu_select_sample_query.c @@ -26,6 +26,7 @@ #include <stdlib.h> +#include "GPU_framebuffer.h" #include "GPU_glew.h" #include "GPU_select.h" #include "GPU_state.h" @@ -65,7 +66,7 @@ typedef struct GPUQueryState { int viewport[4]; int scissor[4]; eGPUWriteMask write_mask; - bool depth_test; + eGPUDepthTest depth_test; } GPUQueryState; static GPUQueryState g_query_state = {0}; @@ -91,41 +92,41 @@ void gpu_select_query_begin( 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_enabled(); + 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); - /* disable writing to the framebuffer */ - GPU_color_mask(false, false, false, false); + /* 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 */ - GPU_viewport_size_get_i(g_query_state.viewport); - GPU_viewport(g_query_state.viewport[0], - g_query_state.viewport[1], - BLI_rcti_size_x(input), - BLI_rcti_size_y(input)); + + 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 */ - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glDepthMask(GL_TRUE); + GPU_depth_test(GPU_DEPTH_ALWAYS); + GPU_depth_mask(true); } else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) { - glClear(GL_DEPTH_BUFFER_BIT); - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); - glDepthFunc(GL_LEQUAL); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); + GPU_depth_mask(true); + GPU_clear_depth(1.0f); } else if (mode == GPU_SELECT_NEAREST_SECOND_PASS) { - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - glDepthFunc(GL_EQUAL); + GPU_depth_test(GPU_DEPTH_EQUAL); + GPU_depth_mask(false); } } diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index 536396ad3c6..b1772bed6e8 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -41,7 +41,7 @@ #include "GPU_platform.h" #include "GPU_shader.h" #include "GPU_texture.h" -#include "GPU_uniformbuffer.h" +#include "GPU_uniform_buffer.h" #include "gpu_backend.hh" #include "gpu_context_private.hh" @@ -52,6 +52,11 @@ extern "C" char datatoc_gpu_shader_colorspace_lib_glsl[]; using namespace blender; using namespace blender::gpu; +/** Opaque type hidding blender::gpu::Shader */ +struct GPUShader { + char _pad[1]; +}; + /* -------------------------------------------------------------------- */ /** \name Debug functions * \{ */ @@ -196,9 +201,7 @@ Shader::Shader(const char *sh_name) Shader::~Shader() { - if (this->interface) { - GPU_shaderinterface_discard(this->interface); - } + delete interface; } static void standard_defines(Vector<const char *> &sources) @@ -304,12 +307,12 @@ GPUShader *GPU_shader_create_ex(const char *vertcode, return NULL; }; - return static_cast<GPUShader *>(shader); + return reinterpret_cast<GPUShader *>(shader); } void GPU_shader_free(GPUShader *shader) { - delete static_cast<Shader *>(shader); + delete reinterpret_cast<Shader *>(shader); } /** \} */ @@ -345,7 +348,7 @@ GPUShader *GPU_shader_create_from_python(const char *vertcode, } GPUShader *sh = GPU_shader_create_ex( - vertcode, fragcode, geomcode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, NULL); + vertcode, fragcode, geomcode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, "pyGPUShader"); MEM_SAFE_FREE(libcodecat); return sh; @@ -431,19 +434,19 @@ struct GPUShader *GPU_shader_create_from_arrays_impl( void GPU_shader_bind(GPUShader *gpu_shader) { - Shader *shader = static_cast<Shader *>(gpu_shader); + Shader *shader = reinterpret_cast<Shader *>(gpu_shader); GPUContext *ctx = GPU_context_active_get(); if (ctx->shader != shader) { ctx->shader = shader; shader->bind(); - GPU_matrix_bind(shader); - GPU_shader_set_srgb_uniform(shader); + GPU_matrix_bind(gpu_shader); + GPU_shader_set_srgb_uniform(gpu_shader); } if (GPU_matrix_dirty_get()) { - GPU_matrix_bind(shader); + GPU_matrix_bind(gpu_shader); } } @@ -452,7 +455,7 @@ void GPU_shader_unbind(void) #ifndef NDEBUG GPUContext *ctx = GPU_context_active_get(); if (ctx->shader) { - static_cast<Shader *>(ctx->shader)->unbind(); + reinterpret_cast<Shader *>(ctx->shader)->unbind(); } ctx->shader = NULL; #endif @@ -468,12 +471,12 @@ void GPU_shader_unbind(void) bool GPU_shader_transform_feedback_enable(GPUShader *shader, GPUVertBuf *vertbuf) { - return static_cast<Shader *>(shader)->transform_feedback_enable(vertbuf); + return reinterpret_cast<Shader *>(shader)->transform_feedback_enable(vertbuf); } void GPU_shader_transform_feedback_disable(GPUShader *shader) { - static_cast<Shader *>(shader)->transform_feedback_disable(); + reinterpret_cast<Shader *>(shader)->transform_feedback_disable(); } /** \} */ @@ -484,43 +487,49 @@ void GPU_shader_transform_feedback_disable(GPUShader *shader) int GPU_shader_get_uniform(GPUShader *shader, const char *name) { - const GPUShaderInput *uniform = GPU_shaderinterface_uniform(shader->interface, name); + ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface; + const ShaderInput *uniform = interface->uniform_get(name); return uniform ? uniform->location : -1; } int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin) { - return GPU_shaderinterface_uniform_builtin(shader->interface, - static_cast<GPUUniformBuiltin>(builtin)); + ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface; + return interface->uniform_builtin((GPUUniformBuiltin)builtin); } int GPU_shader_get_builtin_block(GPUShader *shader, int builtin) { - return GPU_shaderinterface_block_builtin(shader->interface, - static_cast<GPUUniformBlockBuiltin>(builtin)); + ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface; + return interface->ubo_builtin((GPUUniformBlockBuiltin)builtin); } +/* DEPRECATED. */ int GPU_shader_get_uniform_block(GPUShader *shader, const char *name) { - const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name); + ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface; + const ShaderInput *ubo = interface->ubo_get(name); return ubo ? ubo->location : -1; } int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name) { - const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name); + ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface; + const ShaderInput *ubo = interface->ubo_get(name); return ubo ? ubo->binding : -1; } int GPU_shader_get_texture_binding(GPUShader *shader, const char *name) { - const GPUShaderInput *tex = GPU_shaderinterface_uniform(shader->interface, name); + ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface; + const ShaderInput *tex = interface->uniform_get(name); return tex ? tex->binding : -1; } int GPU_shader_get_attribute(GPUShader *shader, const char *name) { - const GPUShaderInput *attr = GPU_shaderinterface_attr(shader->interface, name); + ShaderInterface *interface = reinterpret_cast<Shader *>(shader)->interface; + const ShaderInput *attr = interface->attr_get(name); return attr ? attr->location : -1; } @@ -546,13 +555,13 @@ int GPU_shader_get_program(GPUShader *UNUSED(shader)) void GPU_shader_uniform_vector( GPUShader *shader, int loc, int len, int arraysize, const float *value) { - static_cast<Shader *>(shader)->uniform_float(loc, len, arraysize, value); + reinterpret_cast<Shader *>(shader)->uniform_float(loc, len, arraysize, value); } void GPU_shader_uniform_vector_int( GPUShader *shader, int loc, int len, int arraysize, const int *value) { - static_cast<Shader *>(shader)->uniform_int(loc, len, arraysize, value); + reinterpret_cast<Shader *>(shader)->uniform_int(loc, len, arraysize, value); } void GPU_shader_uniform_int(GPUShader *shader, int location, int value) @@ -565,14 +574,10 @@ void GPU_shader_uniform_float(GPUShader *shader, int location, float value) GPU_shader_uniform_vector(shader, location, 1, 1, &value); } -#define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform(sh->interface, name); \ - BLI_assert(uniform); - void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value) { - GET_UNIFORM - GPU_shader_uniform_int(sh, uniform->location, value); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_int(sh, loc, value); } void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value) @@ -600,44 +605,44 @@ void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, fl void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float x) { - GET_UNIFORM - GPU_shader_uniform_float(sh, uniform->location, x); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_float(sh, loc, x); } void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2]) { - GET_UNIFORM - GPU_shader_uniform_vector(sh, uniform->location, 2, 1, data); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector(sh, loc, 2, 1, data); } void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3]) { - GET_UNIFORM - GPU_shader_uniform_vector(sh, uniform->location, 3, 1, data); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector(sh, loc, 3, 1, data); } void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4]) { - GET_UNIFORM - GPU_shader_uniform_vector(sh, uniform->location, 4, 1, data); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector(sh, loc, 4, 1, data); } void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4]) { - GET_UNIFORM - GPU_shader_uniform_vector(sh, uniform->location, 16, 1, (const float *)data); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector(sh, loc, 16, 1, (const float *)data); } void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]) { - GET_UNIFORM - GPU_shader_uniform_vector(sh, uniform->location, 2, len, (const float *)val); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector(sh, loc, 2, len, (const float *)val); } void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4]) { - GET_UNIFORM - GPU_shader_uniform_vector(sh, uniform->location, 4, len, (const float *)val); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector(sh, loc, 4, len, (const float *)val); } /** \} */ @@ -657,7 +662,7 @@ static int g_shader_builtin_srgb_transform = 0; void GPU_shader_set_srgb_uniform(GPUShader *shader) { - int32_t loc = GPU_shaderinterface_uniform_builtin(shader->interface, GPU_UNIFORM_SRGB_TRANSFORM); + int32_t loc = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_SRGB_TRANSFORM); if (loc != -1) { GPU_shader_uniform_vector_int(shader, loc, 1, 1, &g_shader_builtin_srgb_transform); } diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c index da5bcaeca17..ed95a236da5 100644 --- a/source/blender/gpu/intern/gpu_shader_builtin.c +++ b/source/blender/gpu/intern/gpu_shader_builtin.c @@ -40,7 +40,7 @@ #include "GPU_platform.h" #include "GPU_shader.h" #include "GPU_texture.h" -#include "GPU_uniformbuffer.h" +#include "GPU_uniform_buffer.h" /* Adjust these constants as needed. */ #define MAX_DEFINE_LENGTH 256 diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc index ef90dde1877..dc59dca9f78 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.cc +++ b/source/blender/gpu/intern/gpu_shader_interface.cc @@ -23,161 +23,41 @@ * GPU shader interface (C --> GLSL) */ -#include "BKE_global.h" - -#include "BLI_bitmap.h" -#include "BLI_math_base.h" - #include "MEM_guardedalloc.h" -#include "GPU_shader_interface.h" - -#include "gpu_batch_private.hh" -#include "gpu_context_private.hh" - -#include "gl_batch.hh" - -#include <stddef.h> -#include <stdlib.h> -#include <string.h> - -#define DEBUG_SHADER_INTERFACE 0 - -#if DEBUG_SHADER_INTERFACE -# include <stdio.h> -#endif - -using namespace blender::gpu; - -static const char *BuiltinUniform_name(GPUUniformBuiltin u) -{ - switch (u) { - case GPU_UNIFORM_MODEL: - return "ModelMatrix"; - case GPU_UNIFORM_VIEW: - return "ViewMatrix"; - case GPU_UNIFORM_MODELVIEW: - return "ModelViewMatrix"; - case GPU_UNIFORM_PROJECTION: - return "ProjectionMatrix"; - case GPU_UNIFORM_VIEWPROJECTION: - return "ViewProjectionMatrix"; - case GPU_UNIFORM_MVP: - return "ModelViewProjectionMatrix"; - - case GPU_UNIFORM_MODEL_INV: - return "ModelMatrixInverse"; - case GPU_UNIFORM_VIEW_INV: - return "ViewMatrixInverse"; - case GPU_UNIFORM_MODELVIEW_INV: - return "ModelViewMatrixInverse"; - case GPU_UNIFORM_PROJECTION_INV: - return "ProjectionMatrixInverse"; - case GPU_UNIFORM_VIEWPROJECTION_INV: - return "ViewProjectionMatrixInverse"; - - case GPU_UNIFORM_NORMAL: - return "NormalMatrix"; - case GPU_UNIFORM_ORCO: - return "OrcoTexCoFactors"; - case GPU_UNIFORM_CLIPPLANES: - return "WorldClipPlanes"; - - case GPU_UNIFORM_COLOR: - return "color"; - case GPU_UNIFORM_BASE_INSTANCE: - return "baseInstance"; - case GPU_UNIFORM_RESOURCE_CHUNK: - return "resourceChunk"; - case GPU_UNIFORM_RESOURCE_ID: - return "resourceId"; - case GPU_UNIFORM_SRGB_TRANSFORM: - return "srgbTarget"; +#include "BLI_span.hh" +#include "BLI_vector.hh" - default: - return NULL; - } -} +#include "gpu_shader_interface.hh" -static const char *BuiltinUniformBlock_name(GPUUniformBlockBuiltin u) -{ - switch (u) { - case GPU_UNIFORM_BLOCK_VIEW: - return "viewBlock"; - case GPU_UNIFORM_BLOCK_MODEL: - return "modelBlock"; - case GPU_UNIFORM_BLOCK_INFO: - return "infoBlock"; - default: - return NULL; - } -} +namespace blender::gpu { -GPU_INLINE bool match(const char *a, const char *b) +ShaderInterface::ShaderInterface(void) { - return STREQ(a, b); + /* TODO(fclem) add unique ID for debugging. */ } -GPU_INLINE uint hash_string(const char *str) +ShaderInterface::~ShaderInterface(void) { - uint i = 0, c; - while ((c = *str++)) { - i = i * 37 + c; - } - return i; + /* Free memory used by name_buffer. */ + MEM_freeN(name_buffer_); + MEM_freeN(inputs_); } -GPU_INLINE uint32_t set_input_name(GPUShaderInterface *shaderface, - GPUShaderInput *input, - char *name, - uint32_t name_len) +static void sort_input_list(MutableSpan<ShaderInput> dst) { - /* remove "[0]" from array name */ - if (name[name_len - 1] == ']') { - name[name_len - 3] = '\0'; - name_len -= 3; + if (dst.size() == 0) { + return; } - input->name_offset = (uint32_t)(name - shaderface->name_buffer); - input->name_hash = hash_string(name); - return name_len + 1; /* include NULL terminator */ -} - -GPU_INLINE const GPUShaderInput *input_lookup(const GPUShaderInterface *shaderface, - const GPUShaderInput *const inputs, - const uint inputs_len, - const char *name) -{ - const uint name_hash = hash_string(name); - /* Simple linear search for now. */ - for (int i = inputs_len - 1; i >= 0; i--) { - if (inputs[i].name_hash == name_hash) { - if ((i > 0) && UNLIKELY(inputs[i - 1].name_hash == name_hash)) { - /* Hash colision resolve. */ - for (; i >= 0 && inputs[i].name_hash == name_hash; i--) { - if (match(name, shaderface->name_buffer + inputs[i].name_offset)) { - return inputs + i; /* not found */ - } - } - return NULL; /* not found */ - } - - /* This is a bit dangerous since we could have a hash collision. - * where the asked uniform that does not exist has the same hash - * as a real uniform. */ - BLI_assert(match(name, shaderface->name_buffer + inputs[i].name_offset)); - return inputs + i; - } - } - return NULL; /* not found */ -} + Vector<ShaderInput> inputs_vec = Vector<ShaderInput>(dst.size()); + MutableSpan<ShaderInput> src = inputs_vec.as_mutable_span(); + src.copy_from(dst); -/* Note that this modify the src array. */ -GPU_INLINE void sort_input_list(GPUShaderInput *dst, GPUShaderInput *src, const uint input_len) -{ - for (uint i = 0; i < input_len; i++) { - GPUShaderInput *input_src = &src[0]; - for (uint j = 1; j < input_len; j++) { + /* Simple sorting by going through the array and selecting the biggest element each time. */ + for (uint i = 0; i < dst.size(); i++) { + ShaderInput *input_src = &src[0]; + for (uint j = 1; j < src.size(); j++) { if (src[j].name_hash > input_src->name_hash) { input_src = &src[j]; } @@ -187,360 +67,60 @@ GPU_INLINE void sort_input_list(GPUShaderInput *dst, GPUShaderInput *src, const } } -static int block_binding(int32_t program, uint32_t block_index) +/* Sorts all inputs inside their respective array. + * This is to allow fast hash collision detection. + * See ShaderInterface::input_lookup for more details. */ +void ShaderInterface::sort_inputs(void) { - /* For now just assign a consecutive index. In the future, we should set it in - * the shader using layout(binding = i) and query its value. */ - glUniformBlockBinding(program, block_index, block_index); - return block_index; + sort_input_list(MutableSpan<ShaderInput>(inputs_, attr_len_)); + sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_, ubo_len_)); + sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_)); } -static int sampler_binding(int32_t program, - uint32_t uniform_index, - int32_t uniform_location, - int *sampler_len) +void ShaderInterface::debug_print(void) { - /* Identify sampler uniforms and asign sampler units to them. */ - GLint type; - glGetActiveUniformsiv(program, 1, &uniform_index, GL_UNIFORM_TYPE, &type); - - switch (type) { - case GL_SAMPLER_1D: - case GL_SAMPLER_2D: - case GL_SAMPLER_3D: - case GL_SAMPLER_CUBE: - case GL_SAMPLER_CUBE_MAP_ARRAY_ARB: /* OpenGL 4.0 */ - case GL_SAMPLER_1D_SHADOW: - case GL_SAMPLER_2D_SHADOW: - case GL_SAMPLER_1D_ARRAY: - case GL_SAMPLER_2D_ARRAY: - case GL_SAMPLER_1D_ARRAY_SHADOW: - case GL_SAMPLER_2D_ARRAY_SHADOW: - case GL_SAMPLER_2D_MULTISAMPLE: - case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_SAMPLER_CUBE_SHADOW: - case GL_SAMPLER_BUFFER: - case GL_INT_SAMPLER_1D: - case GL_INT_SAMPLER_2D: - case GL_INT_SAMPLER_3D: - case GL_INT_SAMPLER_CUBE: - case GL_INT_SAMPLER_1D_ARRAY: - case GL_INT_SAMPLER_2D_ARRAY: - case GL_INT_SAMPLER_2D_MULTISAMPLE: - case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_INT_SAMPLER_BUFFER: - case GL_UNSIGNED_INT_SAMPLER_1D: - case GL_UNSIGNED_INT_SAMPLER_2D: - case GL_UNSIGNED_INT_SAMPLER_3D: - case GL_UNSIGNED_INT_SAMPLER_CUBE: - case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_BUFFER: { - /* For now just assign a consecutive index. In the future, we should set it in - * the shader using layout(binding = i) and query its value. */ - int binding = *sampler_len; - glUniform1i(uniform_location, binding); - (*sampler_len)++; - return binding; - } - default: - return -1; - } -} + Span<ShaderInput> attrs = Span<ShaderInput>(inputs_, attr_len_); + Span<ShaderInput> ubos = Span<ShaderInput>(inputs_ + attr_len_, ubo_len_); + Span<ShaderInput> uniforms = Span<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_); + char *name_buf = name_buffer_; + const char format[] = " | %.8x : %4d : %s\n"; -GPUShaderInterface *GPU_shaderinterface_create(int32_t program) -{ -#ifndef NDEBUG - GLint curr_program; - glGetIntegerv(GL_CURRENT_PROGRAM, &curr_program); - BLI_assert(curr_program == program); -#endif - - GLint max_attr_name_len = 0, attr_len = 0; - glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attr_name_len); - glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attr_len); - - GLint max_ubo_name_len = 0, ubo_len = 0; - glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len); - glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len); - - GLint max_uniform_name_len = 0, active_uniform_len = 0, uniform_len = 0; - glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len); - glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniform_len); - uniform_len = active_uniform_len; - - /* Work around driver bug with Intel HD 4600 on Windows 7/8, where - * GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH does not work. */ - if (attr_len > 0 && max_attr_name_len == 0) { - max_attr_name_len = 256; - } - if (ubo_len > 0 && max_ubo_name_len == 0) { - max_ubo_name_len = 256; + printf(" \033[1mGPUShaderInterface : \033[0m\n"); + if (attrs.size() > 0) { + printf("\n Attributes :\n"); } - if (uniform_len > 0 && max_uniform_name_len == 0) { - max_uniform_name_len = 256; + for (const ShaderInput &attr : attrs) { + printf(format, attr.name_hash, attr.location, name_buf + attr.name_offset); } - /* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before - * allocating the uniform array. */ - GLint max_ubo_uni_len = 0; - for (int i = 0; i < ubo_len; i++) { - GLint ubo_uni_len; - glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len); - max_ubo_uni_len = max_ii(max_ubo_uni_len, ubo_uni_len); - uniform_len -= ubo_uni_len; + if (uniforms.size() > 0) { + printf("\n Uniforms :\n"); } - /* Bit set to true if uniform comes from a uniform block. */ - BLI_bitmap *uniforms_from_blocks = BLI_BITMAP_NEW(active_uniform_len, __func__); - /* Set uniforms from block for exclusion. */ - GLint *ubo_uni_ids = (GLint *)MEM_mallocN(sizeof(GLint) * max_ubo_uni_len, __func__); - for (int i = 0; i < ubo_len; i++) { - GLint ubo_uni_len; - glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len); - glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, ubo_uni_ids); - for (int u = 0; u < ubo_uni_len; u++) { - BLI_BITMAP_ENABLE(uniforms_from_blocks, ubo_uni_ids[u]); + for (const ShaderInput &uni : uniforms) { + /* Bypass samplers. */ + if (uni.binding == -1) { + printf(format, uni.name_hash, uni.location, name_buf + uni.name_offset); } } - MEM_freeN(ubo_uni_ids); - uint32_t name_buffer_offset = 0; - const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len + - uniform_len * max_uniform_name_len; - - int input_tot_len = attr_len + ubo_len + uniform_len; - size_t interface_size = sizeof(GPUShaderInterface) + sizeof(GPUShaderInput) * input_tot_len; - - GPUShaderInterface *shaderface = (GPUShaderInterface *)MEM_callocN(interface_size, - "GPUShaderInterface"); - shaderface->attribute_len = attr_len; - shaderface->ubo_len = ubo_len; - shaderface->uniform_len = uniform_len; - shaderface->name_buffer = (char *)MEM_mallocN(name_buffer_len, "name_buffer"); - GPUShaderInput *inputs = shaderface->inputs; - - /* Temp buffer. */ - int input_tmp_len = max_iii(attr_len, ubo_len, uniform_len); - GPUShaderInput *inputs_tmp = (GPUShaderInput *)MEM_mallocN( - sizeof(GPUShaderInput) * input_tmp_len, "name_buffer"); - - /* Attributes */ - shaderface->enabled_attr_mask = 0; - for (int i = 0, idx = 0; i < attr_len; i++) { - char *name = shaderface->name_buffer + name_buffer_offset; - GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; - GLsizei name_len = 0; - GLenum type; - GLint size; - - glGetActiveAttrib(program, i, remaining_buffer, &name_len, &size, &type, name); - GLint location = glGetAttribLocation(program, name); - /* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */ - if (location == -1) { - shaderface->attribute_len--; - continue; - } - - GPUShaderInput *input = &inputs_tmp[idx++]; - input->location = input->binding = location; - - name_buffer_offset += set_input_name(shaderface, input, name, name_len); - shaderface->enabled_attr_mask |= (1 << input->location); + if (ubos.size() > 0) { + printf("\n Uniform Buffer Objects :\n"); } - sort_input_list(inputs, inputs_tmp, shaderface->attribute_len); - inputs += shaderface->attribute_len; - - /* Uniform Blocks */ - for (int i = 0, idx = 0; i < ubo_len; i++) { - char *name = shaderface->name_buffer + name_buffer_offset; - GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; - GLsizei name_len = 0; - - glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name); - - GPUShaderInput *input = &inputs_tmp[idx++]; - input->binding = input->location = block_binding(program, i); - - name_buffer_offset += set_input_name(shaderface, input, name, name_len); - shaderface->enabled_ubo_mask |= (1 << input->binding); + for (const ShaderInput &ubo : ubos) { + printf(format, ubo.name_hash, ubo.binding, name_buf + ubo.name_offset); } - sort_input_list(inputs, inputs_tmp, shaderface->ubo_len); - inputs += shaderface->ubo_len; - /* Uniforms */ - for (int i = 0, idx = 0, sampler = 0; i < active_uniform_len; i++) { - if (BLI_BITMAP_TEST(uniforms_from_blocks, i)) { - continue; - } - char *name = shaderface->name_buffer + name_buffer_offset; - GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; - GLsizei name_len = 0; - - glGetActiveUniformName(program, i, remaining_buffer, &name_len, name); - - GPUShaderInput *input = &inputs_tmp[idx++]; - input->location = glGetUniformLocation(program, name); - input->binding = sampler_binding(program, i, input->location, &sampler); - - name_buffer_offset += set_input_name(shaderface, input, name, name_len); - shaderface->enabled_tex_mask |= (input->binding != -1) ? (1lu << input->binding) : 0lu; - } - sort_input_list(inputs, inputs_tmp, shaderface->uniform_len); - - /* Builtin Uniforms */ - for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) { - GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int); - shaderface->builtins[u] = glGetUniformLocation(program, BuiltinUniform_name(u)); - } - - /* Builtin Uniforms Blocks */ - for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) { - GPUUniformBlockBuiltin u = static_cast<GPUUniformBlockBuiltin>(u_int); - const GPUShaderInput *block = GPU_shaderinterface_ubo(shaderface, BuiltinUniformBlock_name(u)); - shaderface->builtin_blocks[u] = (block != NULL) ? block->binding : -1; - } - - /* Batches ref buffer */ - shaderface->batches_len = GPU_SHADERINTERFACE_REF_ALLOC_COUNT; - shaderface->batches = (void **)MEM_callocN(shaderface->batches_len * sizeof(GPUBatch *), - "GPUShaderInterface batches"); - - MEM_freeN(uniforms_from_blocks); - MEM_freeN(inputs_tmp); - - /* Resize name buffer to save some memory. */ - if (name_buffer_offset < name_buffer_len) { - shaderface->name_buffer = (char *)MEM_reallocN(shaderface->name_buffer, name_buffer_offset); - } - -#if DEBUG_SHADER_INTERFACE - char *name_buf = shaderface->name_buffer; - printf("--- GPUShaderInterface %p, program %d ---\n", shaderface, program); - if (shaderface->attribute_len > 0) { - printf("Attributes {\n"); - for (int i = 0; i < shaderface->attribute_len; i++) { - GPUShaderInput *input = shaderface->inputs + i; - printf("\t(location = %d) %s;\n", input->location, name_buf + input->name_offset); - } - printf("};\n"); - } - if (shaderface->ubo_len > 0) { - printf("Uniform Buffer Objects {\n"); - for (int i = 0; i < shaderface->ubo_len; i++) { - GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + i; - printf("\t(binding = %d) %s;\n", input->binding, name_buf + input->name_offset); - } - printf("};\n"); + if (enabled_tex_mask_ > 0) { + printf("\n Samplers :\n"); } - if (shaderface->enabled_tex_mask > 0) { - printf("Samplers {\n"); - for (int i = 0; i < shaderface->uniform_len; i++) { - GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + - shaderface->ubo_len + i; - if (input->binding != -1) { - printf("\t(location = %d, binding = %d) %s;\n", - input->location, - input->binding, - name_buf + input->name_offset); - } - } - printf("};\n"); - } - if (shaderface->uniform_len > 0) { - printf("Uniforms {\n"); - for (int i = 0; i < shaderface->uniform_len; i++) { - GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + - shaderface->ubo_len + i; - if (input->binding == -1) { - printf("\t(location = %d) %s;\n", input->location, name_buf + input->name_offset); - } + for (const ShaderInput &samp : uniforms) { + /* Bypass uniforms. */ + if (samp.binding != -1) { + printf(format, samp.name_hash, samp.binding, name_buf + samp.name_offset); } - printf("};\n"); } - printf("--- GPUShaderInterface end ---\n\n"); -#endif - return shaderface; -} - -void GPU_shaderinterface_discard(GPUShaderInterface *shaderface) -{ - /* Free memory used by name_buffer. */ - MEM_freeN(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) { - /* XXX GL specific. to be removed during refactor. */ - reinterpret_cast<GLVaoCache *>(shaderface->batches[i])->remove(shaderface); - } - } - MEM_freeN(shaderface->batches); - /* Free memory used by shader interface by its self. */ - MEM_freeN(shaderface); + printf("\n"); } -const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderface, - const char *name) -{ - uint ofs = 0; - return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->attribute_len, name); -} - -const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *shaderface, - const char *name) -{ - uint ofs = shaderface->attribute_len; - return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->ubo_len, name); -} - -const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *shaderface, - const char *name) -{ - uint ofs = shaderface->attribute_len + shaderface->ubo_len; - return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->uniform_len, name); -} - -int32_t GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface, - GPUUniformBuiltin builtin) -{ - BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORMS); - return shaderface->builtins[builtin]; -} - -int32_t GPU_shaderinterface_block_builtin(const GPUShaderInterface *shaderface, - GPUUniformBlockBuiltin builtin) -{ - BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORM_BLOCKS); - return shaderface->builtin_blocks[builtin]; -} - -void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, void *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 += GPU_SHADERINTERFACE_REF_ALLOC_COUNT; - shaderface->batches = (void **)MEM_recallocN(shaderface->batches, - sizeof(void *) * shaderface->batches_len); - } - /** XXX todo cleanup. */ - shaderface->batches[i] = reinterpret_cast<void *>(batch); -} - -void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *shaderface, void *batch) -{ - for (int i = 0; i < shaderface->batches_len; i++) { - if (shaderface->batches[i] == batch) { - shaderface->batches[i] = NULL; - break; /* cannot have duplicates */ - } - } -} +} // namespace blender::gpu diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh new file mode 100644 index 00000000000..6e1cb342c68 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_interface.hh @@ -0,0 +1,229 @@ +/* + * 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. + */ + +/** \file + * \ingroup gpu + * + * GPU shader interface (C --> GLSL) + * + * Structure detailing needed vertex inputs and resources for a specific shader. + * A shader interface can be shared between two similar shaders. + */ + +#pragma once + +#include <cstring> /* required for STREQ later on. */ + +#include "BLI_hash.h" +#include "BLI_utildefines.h" + +#include "GPU_shader.h" + +namespace blender::gpu { + +typedef struct ShaderInput { + uint32_t name_offset; + uint32_t name_hash; + int32_t location; + /** Defined at interface creation or in shader. Only for Samplers, UBOs and Vertex Attribs. */ + int32_t binding; +} ShaderInput; + +/** + * Implementation of Shader interface. + * Base class which is then specialized for each implementation (GL, VK, ...). + **/ +class ShaderInterface { + /* TODO(fclem) should be protected. */ + public: + /** Flat array. In this order: Attributes, Ubos, Uniforms. */ + ShaderInput *inputs_ = NULL; + /** Buffer containing all inputs names separated by '\0'. */ + char *name_buffer_ = NULL; + /** Input counts inside input array. */ + uint attr_len_ = 0; + uint ubo_len_ = 0; + uint uniform_len_ = 0; + /** Enabled bindpoints that needs to be fed with data. */ + uint16_t enabled_attr_mask_ = 0; + uint16_t enabled_ubo_mask_ = 0; + uint64_t enabled_tex_mask_ = 0; + /** Location of builtin uniforms. Fast access, no lookup needed. */ + int32_t builtins_[GPU_NUM_UNIFORMS]; + int32_t builtin_blocks_[GPU_NUM_UNIFORM_BLOCKS]; + + public: + ShaderInterface(); + virtual ~ShaderInterface(); + + void debug_print(void); + + inline const ShaderInput *attr_get(const char *name) const + { + return input_lookup(inputs_, attr_len_, name); + } + + inline const ShaderInput *ubo_get(const char *name) const + { + return input_lookup(inputs_ + attr_len_, ubo_len_, name); + } + + inline const ShaderInput *uniform_get(const char *name) const + { + return input_lookup(inputs_ + attr_len_ + ubo_len_, uniform_len_, name); + } + + /* Returns uniform location. */ + inline int32_t uniform_builtin(const GPUUniformBuiltin builtin) const + { + BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORMS); + return builtins_[builtin]; + } + + /* Returns binding position. */ + inline int32_t ubo_builtin(const GPUUniformBlockBuiltin builtin) const + { + BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORM_BLOCKS); + return builtin_blocks_[builtin]; + } + + protected: + static inline const char *builtin_uniform_name(GPUUniformBuiltin u); + static inline const char *builtin_uniform_block_name(GPUUniformBlockBuiltin u); + + inline uint32_t set_input_name(ShaderInput *input, char *name, uint32_t name_len) const; + + /* Finalize interface construction by sorting the ShaderInputs for faster lookups. */ + void sort_inputs(void); + + private: + inline const ShaderInput *input_lookup(const ShaderInput *const inputs, + const uint inputs_len, + const char *name) const; +}; + +inline const char *ShaderInterface::builtin_uniform_name(GPUUniformBuiltin u) +{ + switch (u) { + case GPU_UNIFORM_MODEL: + return "ModelMatrix"; + case GPU_UNIFORM_VIEW: + return "ViewMatrix"; + case GPU_UNIFORM_MODELVIEW: + return "ModelViewMatrix"; + case GPU_UNIFORM_PROJECTION: + return "ProjectionMatrix"; + case GPU_UNIFORM_VIEWPROJECTION: + return "ViewProjectionMatrix"; + case GPU_UNIFORM_MVP: + return "ModelViewProjectionMatrix"; + + case GPU_UNIFORM_MODEL_INV: + return "ModelMatrixInverse"; + case GPU_UNIFORM_VIEW_INV: + return "ViewMatrixInverse"; + case GPU_UNIFORM_MODELVIEW_INV: + return "ModelViewMatrixInverse"; + case GPU_UNIFORM_PROJECTION_INV: + return "ProjectionMatrixInverse"; + case GPU_UNIFORM_VIEWPROJECTION_INV: + return "ViewProjectionMatrixInverse"; + + case GPU_UNIFORM_NORMAL: + return "NormalMatrix"; + case GPU_UNIFORM_ORCO: + return "OrcoTexCoFactors"; + case GPU_UNIFORM_CLIPPLANES: + return "WorldClipPlanes"; + + case GPU_UNIFORM_COLOR: + return "color"; + case GPU_UNIFORM_BASE_INSTANCE: + return "baseInstance"; + case GPU_UNIFORM_RESOURCE_CHUNK: + return "resourceChunk"; + case GPU_UNIFORM_RESOURCE_ID: + return "resourceId"; + case GPU_UNIFORM_SRGB_TRANSFORM: + return "srgbTarget"; + + default: + return NULL; + } +} + +inline const char *ShaderInterface::builtin_uniform_block_name(GPUUniformBlockBuiltin u) +{ + switch (u) { + case GPU_UNIFORM_BLOCK_VIEW: + return "viewBlock"; + case GPU_UNIFORM_BLOCK_MODEL: + return "modelBlock"; + case GPU_UNIFORM_BLOCK_INFO: + return "infoBlock"; + default: + return NULL; + } +} + +/* Returns string length including '\0' terminator. */ +inline uint32_t ShaderInterface::set_input_name(ShaderInput *input, + char *name, + uint32_t name_len) const +{ + /* remove "[0]" from array name */ + if (name[name_len - 1] == ']') { + name[name_len - 3] = '\0'; + name_len -= 3; + } + + input->name_offset = (uint32_t)(name - name_buffer_); + input->name_hash = BLI_hash_string(name); + return name_len + 1; /* include NULL terminator */ +} + +inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const inputs, + const uint inputs_len, + const char *name) const +{ + const uint name_hash = BLI_hash_string(name); + /* Simple linear search for now. */ + for (int i = inputs_len - 1; i >= 0; i--) { + if (inputs[i].name_hash == name_hash) { + if ((i > 0) && UNLIKELY(inputs[i - 1].name_hash == name_hash)) { + /* Hash colision resolve. */ + for (; i >= 0 && inputs[i].name_hash == name_hash; i--) { + if (STREQ(name, name_buffer_ + inputs[i].name_offset)) { + return inputs + i; /* not found */ + } + } + return NULL; /* not found */ + } + + /* This is a bit dangerous since we could have a hash collision. + * where the asked uniform that does not exist has the same hash + * as a real uniform. */ + BLI_assert(STREQ(name, name_buffer_ + inputs[i].name_offset)); + return inputs + i; + } + } + return NULL; /* not found */ +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/intern/gpu_shader_private.hh b/source/blender/gpu/intern/gpu_shader_private.hh index 1f667fb4cf9..d56a7b2500b 100644 --- a/source/blender/gpu/intern/gpu_shader_private.hh +++ b/source/blender/gpu/intern/gpu_shader_private.hh @@ -23,13 +23,25 @@ #include "BLI_span.hh" #include "GPU_shader.h" -#include "GPU_shader_interface.h" #include "GPU_vertex_buffer.h" +#include "gpu_shader_interface.hh" namespace blender { namespace gpu { -class Shader : public GPUShader { +/** + * Implementation of shader compilation and uniforms handling. + * Base class which is then specialized for each implementation (GL, VK, ...). + **/ +class Shader { + public: + /** Uniform & attribute locations for shader. */ + ShaderInterface *interface = nullptr; + + protected: + /** For debugging purpose. */ + char name[64]; + public: Shader(const char *name); virtual ~Shader(); diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc index f02ec9c5cd4..fcbaa500e2d 100644 --- a/source/blender/gpu/intern/gpu_state.cc +++ b/source/blender/gpu/intern/gpu_state.cc @@ -44,7 +44,7 @@ using namespace blender::gpu; do { \ GPUStateManager *stack = GPU_context_active_get()->state_manager; \ auto &state_object = stack->_prefix##state; \ - state_object._state = _value; \ + state_object._state = (_value); \ } while (0) #define SET_IMMUTABLE_STATE(_state, _value) SET_STATE(, _state, _value) @@ -74,10 +74,14 @@ void GPU_provoking_vertex(eGPUProvokingVertex vert) SET_IMMUTABLE_STATE(provoking_vert, vert); } -/* TODO explicit depth test. */ -void GPU_depth_test(bool enable) +void GPU_depth_test(eGPUDepthTest test) { - SET_IMMUTABLE_STATE(depth_test, (enable) ? GPU_DEPTH_LESS_EQUAL : GPU_DEPTH_NONE); + SET_IMMUTABLE_STATE(depth_test, test); +} + +void GPU_stencil_test(eGPUStencilTest test) +{ + SET_IMMUTABLE_STATE(stencil_test, test); } void GPU_line_smooth(bool enable) @@ -104,11 +108,11 @@ void GPU_color_mask(bool r, bool g, bool b, bool a) { GPUStateManager *stack = GPU_context_active_get()->state_manager; auto &state = stack->state; - eGPUWriteMask write_mask = state.write_mask; - SET_FLAG_FROM_TEST(write_mask, r, GPU_WRITE_RED); - SET_FLAG_FROM_TEST(write_mask, g, GPU_WRITE_GREEN); - SET_FLAG_FROM_TEST(write_mask, b, GPU_WRITE_BLUE); - SET_FLAG_FROM_TEST(write_mask, a, GPU_WRITE_ALPHA); + uint32_t write_mask = state.write_mask; + SET_FLAG_FROM_TEST(write_mask, r, (uint32_t)GPU_WRITE_RED); + SET_FLAG_FROM_TEST(write_mask, g, (uint32_t)GPU_WRITE_GREEN); + SET_FLAG_FROM_TEST(write_mask, b, (uint32_t)GPU_WRITE_BLUE); + SET_FLAG_FROM_TEST(write_mask, a, (uint32_t)GPU_WRITE_ALPHA); state.write_mask = write_mask; } @@ -116,8 +120,8 @@ void GPU_depth_mask(bool depth) { GPUStateManager *stack = GPU_context_active_get()->state_manager; auto &state = stack->state; - eGPUWriteMask write_mask = state.write_mask; - SET_FLAG_FROM_TEST(write_mask, depth, GPU_WRITE_DEPTH); + uint32_t write_mask = state.write_mask; + SET_FLAG_FROM_TEST(write_mask, depth, (uint32_t)GPU_WRITE_DEPTH); state.write_mask = write_mask; } @@ -141,13 +145,13 @@ void GPU_state_set(eGPUWriteMask write_mask, { GPUStateManager *stack = GPU_context_active_get()->state_manager; auto &state = stack->state; - state.write_mask = write_mask; - state.blend = blend; - state.culling_test = culling_test; - state.depth_test = depth_test; - state.stencil_test = stencil_test; - state.stencil_op = stencil_op; - state.provoking_vert = provoking_vert; + state.write_mask = (uint32_t)write_mask; + state.blend = (uint32_t)blend; + state.culling_test = (uint32_t)culling_test; + state.depth_test = (uint32_t)depth_test; + state.stencil_test = (uint32_t)stencil_test; + state.stencil_op = (uint32_t)stencil_op; + state.provoking_vert = (uint32_t)provoking_vert; } /** \} */ @@ -197,7 +201,8 @@ void GPU_scissor(int x, int y, int width, int height) { GPUStateManager *stack = GPU_context_active_get()->state_manager; auto &state = stack->mutable_state; - int scissor_rect[4] = {x, y, width, height}; + bool enabled = state.scissor_rect[2] > 0; + int scissor_rect[4] = {x, y, enabled ? width : -width, height}; copy_v4_v4_int(state.scissor_rect, scissor_rect); } @@ -213,10 +218,12 @@ void GPU_stencil_reference_set(uint reference) { SET_MUTABLE_STATE(stencil_reference, (uint8_t)reference); } + void GPU_stencil_write_mask_set(uint write_mask) { SET_MUTABLE_STATE(stencil_write_mask, (uint8_t)write_mask); } + void GPU_stencil_compare_mask_set(uint compare_mask) { SET_MUTABLE_STATE(stencil_compare_mask, (uint8_t)compare_mask); @@ -231,19 +238,31 @@ void GPU_stencil_compare_mask_set(uint compare_mask) eGPUBlend GPU_blend_get() { GPUState &state = GPU_context_active_get()->state_manager->state; - return state.blend; + return (eGPUBlend)state.blend; } eGPUWriteMask GPU_write_mask_get() { GPUState &state = GPU_context_active_get()->state_manager->state; - return state.write_mask; + return (eGPUWriteMask)state.write_mask; +} + +uint GPU_stencil_mask_get() +{ + GPUStateMutable &state = GPU_context_active_get()->state_manager->mutable_state; + return state.stencil_write_mask; +} + +eGPUDepthTest GPU_depth_test_get() +{ + GPUState &state = GPU_context_active_get()->state_manager->state; + return (eGPUDepthTest)state.depth_test; } -bool GPU_depth_test_enabled() +eGPUStencilTest GPU_stencil_test_get() { GPUState &state = GPU_context_active_get()->state_manager->state; - return state.depth_test != GPU_DEPTH_NONE; + return (eGPUStencilTest)state.stencil_test; } void GPU_scissor_get(int coords[4]) diff --git a/source/blender/gpu/intern/gpu_state_private.hh b/source/blender/gpu/intern/gpu_state_private.hh index 1ba79c7c048..a1bfefbaff5 100644 --- a/source/blender/gpu/intern/gpu_state_private.hh +++ b/source/blender/gpu/intern/gpu_state_private.hh @@ -35,13 +35,20 @@ namespace gpu { * Try to keep small to reduce validation time. */ union GPUState { struct { - eGPUWriteMask write_mask : 13; - eGPUBlend blend : 4; - eGPUFaceCullTest culling_test : 2; - eGPUDepthTest depth_test : 3; - eGPUStencilTest stencil_test : 3; - eGPUStencilOp stencil_op : 3; - eGPUProvokingVertex provoking_vert : 1; + /** eGPUWriteMask */ + uint32_t write_mask : 13; + /** eGPUBlend */ + uint32_t blend : 4; + /** eGPUFaceCullTest */ + uint32_t culling_test : 2; + /** eGPUDepthTest */ + uint32_t depth_test : 3; + /** eGPUStencilTest */ + uint32_t stencil_test : 3; + /** eGPUStencilOp */ + uint32_t stencil_op : 3; + /** eGPUProvokingVertex */ + uint32_t provoking_vert : 1; /** Enable bits. */ uint32_t logic_op_xor : 1; uint32_t invert_facing : 1; @@ -144,6 +151,10 @@ inline GPUStateMutable operator~(const GPUStateMutable &a) return r; } +/** + * State manager keeping track of the draw state and applying it before drawing. + * Base class which is then specialized for each implementation (GL, VK, ...). + **/ class GPUStateManager { public: GPUState state; diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc index 91990dac83f..e70eeece104 100644 --- a/source/blender/gpu/intern/gpu_texture.cc +++ b/source/blender/gpu/intern/gpu_texture.cc @@ -1158,9 +1158,9 @@ static GLenum convert_target_to_gl(int dimension, bool is_array) { switch (dimension) { case 1: - return is_array ? GL_TEXTURE_1D : GL_TEXTURE_1D_ARRAY; + return is_array ? GL_TEXTURE_1D_ARRAY : GL_TEXTURE_1D; case 2: - return is_array ? GL_TEXTURE_2D : GL_TEXTURE_2D_ARRAY; + return is_array ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; case 3: return GL_TEXTURE_3D; default: @@ -2179,6 +2179,11 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size) void GPU_samplers_init(void) { + float max_anisotropy = 1.0f; + if (GLEW_EXT_texture_filter_anisotropic) { + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy); + } + glGenSamplers(GPU_SAMPLER_MAX, GG.samplers); for (int i = 0; i < GPU_SAMPLER_MAX; i++) { eGPUSamplerState state = static_cast<eGPUSamplerState>(i); @@ -2193,7 +2198,7 @@ void GPU_samplers_init(void) GLenum compare_mode = (state & GPU_SAMPLER_COMPARE) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE; /* TODO(fclem) Anisotropic level should be a render engine parameter. */ float aniso_filter = ((state & GPU_SAMPLER_MIPMAP) && (state & GPU_SAMPLER_ANISO)) ? - U.anisotropic_filter : + max_ff(max_anisotropy, U.anisotropic_filter) : 1.0f; glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_S, wrap_s); diff --git a/source/blender/gpu/intern/gpu_uniformbuffer.cc b/source/blender/gpu/intern/gpu_uniform_buffer.cc index e203ffd848f..94aa6bd76ab 100644 --- a/source/blender/gpu/intern/gpu_uniformbuffer.cc +++ b/source/blender/gpu/intern/gpu_uniform_buffer.cc @@ -13,7 +13,7 @@ * 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) 2005 Blender Foundation. + * The Original Code is Copyright (C) 2020 Blender Foundation. * All rights reserved. */ @@ -27,58 +27,46 @@ #include "BLI_blenlib.h" #include "BLI_math_base.h" -#include "gpu_context_private.hh" +#include "gpu_backend.hh" #include "gpu_node_graph.h" -#include "GPU_extensions.h" -#include "GPU_glew.h" #include "GPU_material.h" -#include "GPU_uniformbuffer.h" - -typedef struct GPUUniformBuffer { - /** Data size in bytes. */ - int size; - /** GL handle for UBO. */ - GLuint bindcode; - /** Current binding point. */ - int bindpoint; - /** Continuous memory block to copy to GPU. Is own by the GPUUniformBuffer. */ - void *data; -} GPUUniformBuffer; - -GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256]) + +#include "GPU_extensions.h" + +#include "GPU_uniform_buffer.h" +#include "gpu_uniform_buffer_private.hh" + +/* -------------------------------------------------------------------- */ +/** \name Creation & Deletion + * \{ */ + +namespace blender::gpu { + +UniformBuf::UniformBuf(size_t size, const char *name) { /* Make sure that UBO is padded to size of vec4 */ BLI_assert((size % 16) == 0); + BLI_assert(size <= GPU_max_ubo_size()); - if (size > GPU_max_ubo_size()) { - if (err_out) { - BLI_strncpy(err_out, "GPUUniformBuffer: UBO too big", 256); - } - return NULL; - } - - GPUUniformBuffer *ubo = (GPUUniformBuffer *)MEM_mallocN(sizeof(GPUUniformBuffer), __func__); - ubo->size = size; - ubo->data = NULL; - ubo->bindcode = 0; - ubo->bindpoint = -1; - - /* Direct init. */ - if (data != NULL) { - GPU_uniformbuffer_update(ubo, data); - } + size_in_bytes_ = size; - return ubo; + BLI_strncpy(name_, name, sizeof(name_)); } -void GPU_uniformbuffer_free(GPUUniformBuffer *ubo) +UniformBuf::~UniformBuf() { - MEM_SAFE_FREE(ubo->data); - GPU_buf_free(ubo->bindcode); - MEM_freeN(ubo); + MEM_SAFE_FREE(data_); } +} // namespace blender::gpu + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Uniform buffer from GPUInput list + * \{ */ + /** * We need to pad some data types (vec3) on the C side * To match the GPU expected memory block alignment. @@ -111,10 +99,10 @@ static int inputs_cmp(const void *a, const void *b) * Make sure we respect the expected alignment of UBOs. * mat4, vec4, pad vec3 as vec4, then vec2, then floats. */ -static void gpu_uniformbuffer_inputs_sort(ListBase *inputs) +static void buffer_from_list_inputs_sort(ListBase *inputs) { -/* Only support up to this type, if you want to extend it, make sure the - * padding logic is correct for the new types. */ +/* Only support up to this type, if you want to extend it, make sure static void + * inputs_sobuffer_size_compute *inputs) padding logic is correct for the new types. */ #define MAX_UBO_GPU_TYPE GPU_MAT4 /* Order them as mat4, vec4, vec3, vec2, float. */ @@ -173,23 +161,9 @@ static void gpu_uniformbuffer_inputs_sort(ListBase *inputs) #undef MAX_UBO_GPU_TYPE } -/** - * Create dynamic UBO from parameters - * Return NULL if failed to create or if \param inputs: is empty. - * - * \param inputs: ListBase of #BLI_genericNodeN(#GPUInput). - */ -GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_out[256]) +static inline size_t buffer_size_from_list(ListBase *inputs) { - /* There is no point on creating an UBO if there is no arguments. */ - if (BLI_listbase_is_empty(inputs)) { - return NULL; - } - /* Make sure we comply to the ubo alignment requirements. */ - gpu_uniformbuffer_inputs_sort(inputs); - size_t buffer_size = 0; - LISTBASE_FOREACH (LinkData *, link, inputs) { const eGPUType gputype = get_padded_gpu_type(link); buffer_size += gputype * sizeof(float); @@ -197,8 +171,12 @@ GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_ou /* Round up to size of vec4. (Opengl Requirement) */ size_t alignment = sizeof(float[4]); buffer_size = divide_ceil_u(buffer_size, alignment) * alignment; - void *data = MEM_mallocN(buffer_size, __func__); + return buffer_size; +} + +static inline void buffer_fill_from_list(void *data, ListBase *inputs) +{ /* Now that we know the total ubo size we can start populating it. */ float *offset = (float *)data; LISTBASE_FOREACH (LinkData *, link, inputs) { @@ -206,71 +184,73 @@ GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_ou memcpy(offset, input->vec, input->type * sizeof(float)); offset += get_padded_gpu_type(link); } - - /* Pass data as NULL for late init. */ - GPUUniformBuffer *ubo = GPU_uniformbuffer_create(buffer_size, NULL, err_out); - /* Data will be update just before binding. */ - ubo->data = data; - return ubo; } -static void gpu_uniformbuffer_init(GPUUniformBuffer *ubo) -{ - BLI_assert(ubo->bindcode == 0); - ubo->bindcode = GPU_buf_alloc(); +/** \} */ - if (ubo->bindcode == 0) { - fprintf(stderr, "GPUUniformBuffer: UBO create failed"); - BLI_assert(0); - return; - } +/* -------------------------------------------------------------------- */ +/** \name C-API + * \{ */ - glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode); - glBufferData(GL_UNIFORM_BUFFER, ubo->size, NULL, GL_DYNAMIC_DRAW); -} +using namespace blender::gpu; -void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data) +GPUUniformBuf *GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name) { - if (ubo->bindcode == 0) { - gpu_uniformbuffer_init(ubo); + UniformBuf *ubo = GPUBackend::get()->uniformbuf_alloc(size, name); + /* Direct init. */ + if (data != NULL) { + ubo->update(data); } - - glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode); - glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo->size, data); - glBindBuffer(GL_UNIFORM_BUFFER, 0); + return reinterpret_cast<GPUUniformBuf *>(ubo); } -void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number) +/** + * Create UBO from inputs list. + * Return NULL if failed to create or if \param inputs: is empty. + * + * \param inputs: ListBase of #BLI_genericNodeN(#GPUInput). + */ +GPUUniformBuf *GPU_uniformbuf_create_from_list(ListBase *inputs, const char *name) { - if (number >= GPU_max_ubo_binds()) { - fprintf(stderr, "Not enough UBO slots.\n"); - return; + /* There is no point on creating an UBO if there is no arguments. */ + if (BLI_listbase_is_empty(inputs)) { + return NULL; } - if (ubo->bindcode == 0) { - gpu_uniformbuffer_init(ubo); - } + buffer_from_list_inputs_sort(inputs); + size_t buffer_size = buffer_size_from_list(inputs); + void *data = MEM_mallocN(buffer_size, __func__); + buffer_fill_from_list(data, inputs); - if (ubo->data != NULL) { - GPU_uniformbuffer_update(ubo, ubo->data); - MEM_SAFE_FREE(ubo->data); - } + UniformBuf *ubo = GPUBackend::get()->uniformbuf_alloc(buffer_size, name); + /* Defer data upload. */ + ubo->attach_data(data); + return reinterpret_cast<GPUUniformBuf *>(ubo); +} - glBindBufferBase(GL_UNIFORM_BUFFER, number, ubo->bindcode); - ubo->bindpoint = number; +void GPU_uniformbuf_free(GPUUniformBuf *ubo) +{ + delete reinterpret_cast<UniformBuf *>(ubo); } -void GPU_uniformbuffer_unbind(GPUUniformBuffer *ubo) +void GPU_uniformbuf_update(GPUUniformBuf *ubo, const void *data) { -#ifndef NDEBUG - glBindBufferBase(GL_UNIFORM_BUFFER, ubo->bindpoint, 0); -#endif - ubo->bindpoint = 0; + reinterpret_cast<UniformBuf *>(ubo)->update(data); } -void GPU_uniformbuffer_unbind_all(void) +void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot) { - for (int i = 0; i < GPU_max_ubo_binds(); i++) { - glBindBufferBase(GL_UNIFORM_BUFFER, i, 0); - } + reinterpret_cast<UniformBuf *>(ubo)->bind(slot); } + +void GPU_uniformbuf_unbind(GPUUniformBuf *ubo) +{ + reinterpret_cast<UniformBuf *>(ubo)->unbind(); +} + +void GPU_uniformbuf_unbind_all(void) +{ + /* FIXME */ +} + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh new file mode 100644 index 00000000000..288cbae526e --- /dev/null +++ b/source/blender/gpu/intern/gpu_uniform_buffer_private.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. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "BLI_sys_types.h" + +namespace blender { +namespace gpu { + +#ifdef DEBUG +# define DEBUG_NAME_LEN 8 +#else +# define DEBUG_NAME_LEN 64 +#endif + +/** + * Implementation of Uniform Buffers. + * Base class which is then specialized for each implementation (GL, VK, ...). + **/ +class UniformBuf { + protected: + /** Data size in bytes. */ + size_t size_in_bytes_; + /** Continuous memory block to copy to GPU. This data is owned by the UniformBuf. */ + void *data_ = NULL; + /** Debugging name */ + char name_[DEBUG_NAME_LEN]; + + public: + UniformBuf(size_t size, const char *name); + virtual ~UniformBuf(); + + virtual void update(const void *data) = 0; + virtual void bind(int slot) = 0; + virtual void unbind(void) = 0; + + /** Used to defer data upload at drawing time. + * This is useful if the thread has no context bound. + * This transfers ownership to this UniformBuf. */ + void attach_data(void *data) + { + data_ = data; + } +}; + +#undef DEBUG_NAME_LEN + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc index 2b16f4482b4..ed317b3a0df 100644 --- a/source/blender/gpu/intern/gpu_vertex_format.cc +++ b/source/blender/gpu/intern/gpu_vertex_format.cc @@ -407,6 +407,6 @@ void VertexFormat_pack(GPUVertFormat *format) void GPU_vertformat_from_shader(GPUVertFormat *format, const struct GPUShader *gpushader) { - const Shader *shader = static_cast<const Shader *>(gpushader); + const Shader *shader = reinterpret_cast<const Shader *>(gpushader); shader->vertformat_from_shader(format); } diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index ba938349761..fd1265dc2a6 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -41,7 +41,7 @@ #include "GPU_immediate.h" #include "GPU_matrix.h" #include "GPU_texture.h" -#include "GPU_uniformbuffer.h" +#include "GPU_uniform_buffer.h" #include "GPU_viewport.h" #include "DRW_engine.h" @@ -1020,8 +1020,8 @@ void GPU_viewport_free(GPUViewport *viewport) } for (int i = 0; i < viewport->vmempool.ubo_len; i++) { - GPU_uniformbuffer_free(viewport->vmempool.matrices_ubo[i]); - GPU_uniformbuffer_free(viewport->vmempool.obinfos_ubo[i]); + GPU_uniformbuf_free(viewport->vmempool.matrices_ubo[i]); + GPU_uniformbuf_free(viewport->vmempool.obinfos_ubo[i]); } MEM_SAFE_FREE(viewport->vmempool.matrices_ubo); MEM_SAFE_FREE(viewport->vmempool.obinfos_ubo); |