diff options
author | Julian Eisel <eiseljulian@gmail.com> | 2017-04-04 22:39:57 +0300 |
---|---|---|
committer | Julian Eisel <eiseljulian@gmail.com> | 2017-04-04 22:39:57 +0300 |
commit | 7576ad3d043ac5d15e0c5a68e65339904441b5e7 (patch) | |
tree | bb990cce1eec04d45ab57e8a42af2669f9d7522f /source/blender/draw/intern/draw_manager.c | |
parent | 10b24eabbab0193f6944cdf3bec7b386c75d5445 (diff) | |
parent | db0f67f46454fd0bfeb886d3e61227b65fbc6ac1 (diff) |
Merge branch 'blender2.8' into transform-manipulatorstransform-manipulators
Conflicts:
intern/gawain/gawain/immediate.h
intern/gawain/src/immediate.c
source/blender/editors/physics/physics_ops.c
source/blender/editors/screen/glutil.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_ops.c
source/blender/editors/transform/transform_manipulator.c
Diffstat (limited to 'source/blender/draw/intern/draw_manager.c')
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 1121 |
1 files changed, 853 insertions, 268 deletions
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 970bd2f6dee..d2d98f15fa9 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -19,12 +19,13 @@ * */ -/** \file blender/draw/draw_manager.c +/** \file blender/draw/intern/draw_manager.c * \ingroup draw */ #include <stdio.h> +#include "BLI_dynstr.h" #include "BLI_listbase.h" #include "BLI_rect.h" #include "BLI_string.h" @@ -34,35 +35,43 @@ #include "BKE_global.h" #include "BLT_translation.h" +#include "BLF_api.h" #include "DRW_engine.h" #include "DRW_render.h" #include "DNA_view3d_types.h" +#include "DNA_screen_types.h" + +#include "ED_space_api.h" +#include "ED_screen.h" -#include "GPU_basic_shader.h" #include "GPU_batch.h" #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_framebuffer.h" -#include "GPU_immediate.h" -#include "GPU_matrix.h" #include "GPU_shader.h" #include "GPU_texture.h" #include "GPU_uniformbuffer.h" #include "GPU_viewport.h" +#include "GPU_matrix.h" + +#include "PIL_time.h" #include "RE_engine.h" #include "UI_resources.h" +#include "draw_mode_engines.h" #include "clay.h" +#include "eevee.h" #define MAX_ATTRIB_NAME 32 +#define MAX_PASS_NAME 32 extern char datatoc_gpu_shader_2D_vert_glsl[]; extern char datatoc_gpu_shader_3D_vert_glsl[]; -extern char datatoc_gpu_shader_basic_vert_glsl[]; +extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; /* Structures */ typedef enum { @@ -81,7 +90,7 @@ typedef enum { DRW_ATTRIB_FLOAT, } DRWAttribType; -typedef struct DRWUniform { +struct DRWUniform { struct DRWUniform *next, *prev; DRWUniformType type; int location; @@ -89,7 +98,7 @@ typedef struct DRWUniform { int arraysize; int bindloc; const void *value; -} DRWUniform; +}; typedef struct DRWAttrib { struct DRWAttrib *next, *prev; @@ -108,11 +117,14 @@ struct DRWInterface { int attribs_size[16]; int attribs_loc[16]; /* matrices locations */ + int model; int modelview; int projection; + int view; int modelviewprojection; int viewprojection; int normal; + int worldnormal; int eye; /* Dynamic batch */ GLuint instance_vbo; @@ -123,7 +135,13 @@ struct DRWInterface { struct DRWPass { ListBase shgroups; /* DRWShadingGroup */ DRWState state; - float state_param; /* Line / Point width */ + char name[MAX_PASS_NAME]; + /* use two query to not stall the cpu waiting for queries to complete */ + unsigned int timer_queries[2]; + /* alternate between front and back query */ + unsigned int front_idx; + unsigned int back_idx; + bool wasdrawn; /* if it was drawn during this frame */ }; typedef struct DRWCall { @@ -143,7 +161,7 @@ struct DRWShadingGroup { struct GPUShader *shader; /* Shader to bind */ struct DRWInterface *interface; /* Uniforms pointers */ ListBase calls; /* DRWCall or DRWDynamicCall depending of type*/ - int state; /* State changes for this batch only */ + DRWState state; /* State changes for this batch only */ int type; Batch *instance_geom; /* Geometry to instance */ @@ -158,22 +176,33 @@ enum { DRW_SHG_INSTANCE, }; +/* only 16 bits long */ +enum { + STENCIL_SELECT = (1 << 0), + STENCIL_ACTIVE = (1 << 1), +}; + /* Render State */ -static struct DRWGlobalState{ +static struct DRWGlobalState { + /* Rendering state */ GPUShader *shader; - struct GPUFrameBuffer *default_framebuffer; - FramebufferList *current_fbl; - TextureList *current_txl; - PassList *current_psl; ListBase bound_texs; int tex_bind_id; + + /* Per viewport */ + GPUViewport *viewport; + struct GPUFrameBuffer *default_framebuffer; float size[2]; float screenvecs[2][3]; float pixsize; - /* Current rendering context set by DRW_viewport_init */ + + /* Current rendering context */ const struct bContext *context; + ListBase enabled_engines; /* RenderEngineType */ } DST = {NULL}; +ListBase DRW_engines = {NULL, NULL}; + /* ***************************************** TEXTURES ******************************************/ static void drw_texture_get_format(DRWTextureFormat format, GPUTextureFormat *data_type, int *channels) { @@ -183,13 +212,13 @@ static void drw_texture_get_format(DRWTextureFormat format, GPUTextureFormat *da case DRW_TEX_RG_16: *data_type = GPU_RG16F; break; case DRW_TEX_RG_32: *data_type = GPU_RG32F; break; case DRW_TEX_R_8: *data_type = GPU_R8; break; + case DRW_TEX_R_16: *data_type = GPU_R16F; break; #if 0 case DRW_TEX_RGBA_32: *data_type = GPU_RGBA32F; break; case DRW_TEX_RGB_8: *data_type = GPU_RGB8; break; case DRW_TEX_RGB_16: *data_type = GPU_RGB16F; break; case DRW_TEX_RGB_32: *data_type = GPU_RGB32F; break; case DRW_TEX_RG_8: *data_type = GPU_RG8; break; - case DRW_TEX_R_16: *data_type = GPU_R16F; break; case DRW_TEX_R_32: *data_type = GPU_R32F; break; #endif case DRW_TEX_DEPTH_16: *data_type = GPU_DEPTH_COMPONENT16; break; @@ -299,6 +328,44 @@ GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *fra return GPU_shader_create(vert, frag, geom, NULL, defines, 0, 0, 0); } +GPUShader *DRW_shader_create_with_lib(const char *vert, const char *geom, const char *frag, const char *lib, const char *defines) +{ + GPUShader *sh; + char *vert_with_lib = NULL; + char *frag_with_lib = NULL; + char *geom_with_lib = NULL; + + DynStr *ds_vert = BLI_dynstr_new(); + BLI_dynstr_append(ds_vert, lib); + BLI_dynstr_append(ds_vert, vert); + vert_with_lib = BLI_dynstr_get_cstring(ds_vert); + BLI_dynstr_free(ds_vert); + + DynStr *ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, lib); + BLI_dynstr_append(ds_frag, frag); + frag_with_lib = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + if (geom) { + DynStr *ds_geom = BLI_dynstr_new(); + BLI_dynstr_append(ds_geom, lib); + BLI_dynstr_append(ds_geom, geom); + geom_with_lib = BLI_dynstr_get_cstring(ds_geom); + BLI_dynstr_free(ds_geom); + } + + sh = GPU_shader_create(vert_with_lib, frag_with_lib, geom_with_lib, NULL, defines, 0, 0, 0); + + MEM_freeN(vert_with_lib); + MEM_freeN(frag_with_lib); + if (geom) { + MEM_freeN(geom_with_lib); + } + + return sh; +} + GPUShader *DRW_shader_create_2D(const char *frag, const char *defines) { return GPU_shader_create(datatoc_gpu_shader_2D_vert_glsl, frag, NULL, NULL, defines, 0, 0, 0); @@ -309,6 +376,11 @@ GPUShader *DRW_shader_create_3D(const char *frag, const char *defines) return GPU_shader_create(datatoc_gpu_shader_3D_vert_glsl, frag, NULL, NULL, defines, 0, 0, 0); } +GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines) +{ + return GPU_shader_create(datatoc_gpu_shader_fullscreen_vert_glsl, frag, NULL, NULL, defines, 0, 0, 0); +} + GPUShader *DRW_shader_create_3D_depth_only(void) { return GPU_shader_get_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY); @@ -325,11 +397,14 @@ static DRWInterface *DRW_interface_create(GPUShader *shader) { DRWInterface *interface = MEM_mallocN(sizeof(DRWInterface), "DRWInterface"); + interface->model = GPU_shader_get_uniform(shader, "ModelMatrix"); interface->modelview = GPU_shader_get_uniform(shader, "ModelViewMatrix"); interface->projection = GPU_shader_get_uniform(shader, "ProjectionMatrix"); + interface->view = GPU_shader_get_uniform(shader, "ViewMatrix"); interface->viewprojection = GPU_shader_get_uniform(shader, "ViewProjectionMatrix"); interface->modelviewprojection = GPU_shader_get_uniform(shader, "ModelViewProjectionMatrix"); interface->normal = GPU_shader_get_uniform(shader, "NormalMatrix"); + interface->worldnormal = GPU_shader_get_uniform(shader, "WorldNormalMatrix"); interface->eye = GPU_shader_get_uniform(shader, "eye"); interface->instance_count = 0; interface->attribs_count = 0; @@ -457,7 +532,11 @@ void DRW_shgroup_free(struct DRWShadingGroup *shgroup) BLI_freelistN(&shgroup->calls); BLI_freelistN(&shgroup->interface->uniforms); BLI_freelistN(&shgroup->interface->attribs); - /* TODO free instance vbo */ + + if (shgroup->interface->instance_vbo) { + glDeleteBuffers(1, &shgroup->interface->instance_vbo); + } + MEM_freeN(shgroup->interface); if (shgroup->batch_geom) { @@ -467,14 +546,14 @@ void DRW_shgroup_free(struct DRWShadingGroup *shgroup) void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Batch *geom, float (*obmat)[4]) { - if (geom) { - DRWCall *call = MEM_callocN(sizeof(DRWCall), "DRWCall"); + BLI_assert(geom != NULL); - call->obmat = obmat; - call->geometry = geom; + DRWCall *call = MEM_callocN(sizeof(DRWCall), "DRWCall"); - BLI_addtail(&shgroup->calls, call); - } + call->obmat = obmat; + call->geometry = geom; + + BLI_addtail(&shgroup->calls, call); } void DRW_shgroup_dynamic_call_add(DRWShadingGroup *shgroup, ...) @@ -519,10 +598,9 @@ void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 0, loc); } -void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, const int value, int loc) +void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex, int loc) { - /* we abuse the lenght attrib to store the buffer index */ - DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, NULL, value, 0, loc); + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, tex, 0, 0, loc); } void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize) @@ -672,9 +750,12 @@ static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup) { -#ifdef WITH_VIEWPORT_CACHE_TEST - if (shgroup->interface->instance_vbo || shgroup->batch_geom) return; -#endif + if ((shgroup->interface->instance_vbo || shgroup->batch_geom) && + (G.debug_value == 667)) + { + return; + } + if (shgroup->type == DRW_SHG_INSTANCE) { shgroup_dynamic_instance(shgroup); } @@ -689,6 +770,7 @@ DRWPass *DRW_pass_create(const char *name, DRWState state) { DRWPass *pass = MEM_callocN(sizeof(DRWPass), name); pass->state = state; + BLI_strncpy(pass->name, name, MAX_PASS_NAME); BLI_listbase_clear(&pass->shgroups); @@ -700,87 +782,136 @@ void DRW_pass_free(DRWPass *pass) for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { DRW_shgroup_free(shgroup); } + + glDeleteQueries(2, pass->timer_queries); BLI_freelistN(&pass->shgroups); } /* ****************************************** DRAW ******************************************/ -void DRW_draw_background(void) +#ifdef WITH_CLAY_ENGINE +static void set_state(DRWState flag, const bool reset) { - /* Just to make sure */ - glDepthMask(GL_TRUE); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { - /* Gradient background Color */ - gpuMatrixBegin3D(); /* TODO: finish 2D API */ - - glClear(GL_DEPTH_BUFFER_BIT); - - VertexFormat *format = immVertexFormat(); - unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); - unsigned color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); - unsigned char col_hi[3], col_lo[3]; + /* TODO Keep track of the state and only revert what is needed */ - immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + if (reset) { + /* Depth Write */ + if (flag & DRW_STATE_WRITE_DEPTH) + glDepthMask(GL_TRUE); + else + glDepthMask(GL_FALSE); + + /* Color Write */ + if (flag & DRW_STATE_WRITE_COLOR) + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + else + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + /* Backface Culling */ + if (flag & DRW_STATE_CULL_BACK || + flag & DRW_STATE_CULL_FRONT) + { + glEnable(GL_CULL_FACE); - UI_GetThemeColor3ubv(TH_LOW_GRAD, col_lo); - UI_GetThemeColor3ubv(TH_HIGH_GRAD, col_hi); + if (flag & DRW_STATE_CULL_BACK) + glCullFace(GL_BACK); + else if (flag & DRW_STATE_CULL_FRONT) + glCullFace(GL_FRONT); + } + else { + glDisable(GL_CULL_FACE); + } - immBegin(GL_QUADS, 4); - immAttrib3ubv(color, col_lo); - immVertex2f(pos, -1.0f, -1.0f); - immVertex2f(pos, 1.0f, -1.0f); + /* Depht Test */ + if (flag & (DRW_STATE_DEPTH_LESS | DRW_STATE_DEPTH_EQUAL | DRW_STATE_DEPTH_GREATER)) + { + glEnable(GL_DEPTH_TEST); + + if (flag & DRW_STATE_DEPTH_LESS) + glDepthFunc(GL_LEQUAL); + else if (flag & DRW_STATE_DEPTH_EQUAL) + glDepthFunc(GL_EQUAL); + else if (flag & DRW_STATE_DEPTH_GREATER) + glDepthFunc(GL_GREATER); + } + else { + glDisable(GL_DEPTH_TEST); + } + } - immAttrib3ubv(color, col_hi); - immVertex2f(pos, 1.0f, 1.0f); - immVertex2f(pos, -1.0f, 1.0f); - immEnd(); + /* Wire Width */ + if (flag & DRW_STATE_WIRE) { + glLineWidth(1.0f); + } + else if (flag & DRW_STATE_WIRE_LARGE) { + glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); + } - immUnbindProgram(); + /* Points Size */ + if (flag & DRW_STATE_POINT) { + GPU_enable_program_point_size(); + glPointSize(5.0f); + } + else if (reset) { + GPU_disable_program_point_size(); + } - gpuMatrixEnd(); + /* Blending (all buffer) */ + if (flag & DRW_STATE_BLEND) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } - else { - /* Solid background Color */ - UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + else if (reset) { + glDisable(GL_BLEND); } -} -#ifdef WITH_CLAY_ENGINE -/* Only alter the state (does not reset it like set_state() ) */ -static void shgroup_set_state(DRWShadingGroup *shgroup) -{ - if (shgroup->state) { - /* Blend */ - if (shgroup->state & DRW_STATE_BLEND) { - glEnable(GL_BLEND); - } - /* Wire width */ - if (shgroup->state & DRW_STATE_WIRE) { - glLineWidth(1.0f); - } - else if (shgroup->state & DRW_STATE_WIRE_LARGE) { - glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); - } + /* Line Stipple */ + if (flag & DRW_STATE_STIPPLE_2) { + setlinestyle(2); + } + else if (flag & DRW_STATE_STIPPLE_3) { + setlinestyle(3); + } + else if (flag & DRW_STATE_STIPPLE_4) { + setlinestyle(4); + } + else if (reset) { + setlinestyle(0); + } - /* Line Stipple */ - if (shgroup->state & DRW_STATE_STIPPLE_2) { - setlinestyle(2); + /* Stencil */ + if (flag & (DRW_STATE_WRITE_STENCIL_SELECT | DRW_STATE_WRITE_STENCIL_ACTIVE | + DRW_STATE_TEST_STENCIL_SELECT | DRW_STATE_TEST_STENCIL_ACTIVE)) + { + glEnable(GL_STENCIL_TEST); + + /* Stencil Write */ + if (flag & DRW_STATE_WRITE_STENCIL_SELECT) { + glStencilMask(STENCIL_SELECT); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 0xFF, STENCIL_SELECT); } - else if (shgroup->state & DRW_STATE_STIPPLE_3) { - setlinestyle(3); + else if (flag & DRW_STATE_WRITE_STENCIL_ACTIVE) { + glStencilMask(STENCIL_ACTIVE); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 0xFF, STENCIL_ACTIVE); } - else if (shgroup->state & DRW_STATE_STIPPLE_4) { - setlinestyle(4); + /* Stencil Test */ + else if (flag & DRW_STATE_TEST_STENCIL_SELECT) { + glStencilMask(0x00); /* disable write */ + glStencilFunc(GL_NOTEQUAL, 0xFF, STENCIL_SELECT); } - - if (shgroup->state & DRW_STATE_POINT) { - GPU_enable_program_point_size(); - glPointSize(5.0f); + else if (flag & DRW_STATE_TEST_STENCIL_ACTIVE) { + glStencilMask(0x00); /* disable write */ + glStencilFunc(GL_NOTEQUAL, 0xFF, STENCIL_ACTIVE); } } + else if (reset) { + /* disable write & test */ + glStencilMask(0x00); + glStencilFunc(GL_ALWAYS, 1, 0xFF); + glDisable(GL_STENCIL_TEST); + } } typedef struct DRWBoundTexture { @@ -792,13 +923,14 @@ static void draw_geometry(DRWShadingGroup *shgroup, Batch *geom, const float (*o { RegionView3D *rv3d = CTX_wm_region_view3d(DST.context); DRWInterface *interface = shgroup->interface; - - float mvp[4][4], mv[4][4], n[3][3]; + + float mvp[4][4], mv[4][4], n[3][3], wn[3][3]; float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */ bool do_mvp = (interface->modelviewprojection != -1); bool do_mv = (interface->modelview != -1); bool do_n = (interface->normal != -1); + bool do_wn = (interface->worldnormal != -1); bool do_eye = (interface->eye != -1); if (do_mvp) { @@ -812,6 +944,11 @@ static void draw_geometry(DRWShadingGroup *shgroup, Batch *geom, const float (*o invert_m3(n); transpose_m3(n); } + if (do_wn) { + copy_m3_m4(wn, obmat); + invert_m3(wn); + transpose_m3(wn); + } if (do_eye) { /* Used by orthographic wires */ float tmp[3][3]; @@ -822,6 +959,9 @@ static void draw_geometry(DRWShadingGroup *shgroup, Batch *geom, const float (*o /* Should be really simple */ /* step 1 : bind object dependent matrices */ + if (interface->model != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->model, 16, 1, (float *)obmat); + } if (interface->modelviewprojection != -1) { GPU_shader_uniform_vector(shgroup->shader, interface->modelviewprojection, 16, 1, (float *)mvp); } @@ -831,12 +971,18 @@ static void draw_geometry(DRWShadingGroup *shgroup, Batch *geom, const float (*o if (interface->projection != -1) { GPU_shader_uniform_vector(shgroup->shader, interface->projection, 16, 1, (float *)rv3d->winmat); } + if (interface->view != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->view, 16, 1, (float *)rv3d->viewmat); + } if (interface->modelview != -1) { GPU_shader_uniform_vector(shgroup->shader, interface->modelview, 16, 1, (float *)mv); } if (interface->normal != -1) { GPU_shader_uniform_vector(shgroup->shader, interface->normal, 9, 1, (float *)n); } + if (interface->worldnormal != -1) { + GPU_shader_uniform_vector(shgroup->shader, interface->worldnormal, 9, 1, (float *)wn); + } if (interface->eye != -1) { GPU_shader_uniform_vector(shgroup->shader, interface->eye, 3, 1, (float *)eye); } @@ -858,6 +1004,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup) BLI_assert(shgroup->interface); DRWInterface *interface = shgroup->interface; + GPUTexture *tex; if (DST.shader != shgroup->shader) { if (DST.shader) GPU_shader_unbind(); @@ -869,7 +1016,9 @@ static void draw_shgroup(DRWShadingGroup *shgroup) shgroup_dynamic_batch_from_calls(shgroup); } - shgroup_set_state(shgroup); + if (shgroup->state != 0) { + set_state(shgroup->state, false); + } /* Binding Uniform */ /* Don't check anything, Interface should already contain the least uniform as possible */ @@ -887,25 +1036,26 @@ static void draw_shgroup(DRWShadingGroup *shgroup) GPU_shader_uniform_vector(shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)uni->value); break; case DRW_UNIFORM_TEXTURE: - GPU_texture_bind((GPUTexture *)uni->value, uni->bindloc); + tex = (GPUTexture *)uni->value; + GPU_texture_bind(tex, uni->bindloc); bound_tex = MEM_callocN(sizeof(DRWBoundTexture), "DRWBoundTexture"); - bound_tex->tex = (GPUTexture *)uni->value; + bound_tex->tex = tex; BLI_addtail(&DST.bound_texs, bound_tex); - GPU_shader_uniform_texture(shgroup->shader, uni->location, (GPUTexture *)uni->value); + GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); break; case DRW_UNIFORM_BUFFER: - /* restore index from lenght we abused */ - GPU_texture_bind(DST.current_txl->textures[uni->length], uni->bindloc); - GPU_texture_compare_mode(DST.current_txl->textures[uni->length], false); - GPU_texture_filter_mode(DST.current_txl->textures[uni->length], false); - + tex = *((GPUTexture **)uni->value); + GPU_texture_bind(tex, uni->bindloc); + GPU_texture_compare_mode(tex, false); + GPU_texture_filter_mode(tex, false); + bound_tex = MEM_callocN(sizeof(DRWBoundTexture), "DRWBoundTexture"); - bound_tex->tex = DST.current_txl->textures[uni->length]; + bound_tex->tex = tex; BLI_addtail(&DST.bound_texs, bound_tex); - GPU_shader_uniform_texture(shgroup->shader, uni->location, DST.current_txl->textures[uni->length]); + GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); break; case DRW_UNIFORM_BLOCK: GPU_uniformbuffer_bind((GPUUniformBuffer *)uni->value, uni->bindloc); @@ -937,100 +1087,37 @@ static void draw_shgroup(DRWShadingGroup *shgroup) } } -static void set_state(short flag) +void DRW_draw_pass(DRWPass *pass) { - /* TODO Keep track of the state and only revert what is needed */ - - /* Depth Write */ - if (flag & DRW_STATE_WRITE_DEPTH) - glDepthMask(GL_TRUE); - else - glDepthMask(GL_FALSE); - - /* Color Write */ - if (flag & DRW_STATE_WRITE_COLOR) - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - else - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - - /* Backface Culling */ - if (flag & DRW_STATE_CULL_BACK || - flag & DRW_STATE_CULL_FRONT) { - - glEnable(GL_CULL_FACE); - - if (flag & DRW_STATE_CULL_BACK) - glCullFace(GL_BACK); - else if (flag & DRW_STATE_CULL_FRONT) - glCullFace(GL_FRONT); - } - else { - glDisable(GL_CULL_FACE); - } - - /* Depht Test */ - if (flag & DRW_STATE_DEPTH_LESS || - flag & DRW_STATE_DEPTH_EQUAL) { + /* Start fresh */ + DST.shader = NULL; + DST.tex_bind_id = 0; - glEnable(GL_DEPTH_TEST); + set_state(pass->state, true); + BLI_listbase_clear(&DST.bound_texs); - if (flag & DRW_STATE_DEPTH_LESS) - glDepthFunc(GL_LEQUAL); - else if (flag & DRW_STATE_DEPTH_EQUAL) - glDepthFunc(GL_EQUAL); - } - else { - glDisable(GL_DEPTH_TEST); - } + pass->wasdrawn = true; - /* Wire Width */ - if (flag & DRW_STATE_WIRE) { - glLineWidth(1.0f); - } - else if (flag & DRW_STATE_WIRE_LARGE) { - glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); - } - - /* Points Size */ - if (flag & DRW_STATE_POINT) { - GPU_enable_program_point_size(); - glPointSize(5.0f); - } - else { - GPU_disable_program_point_size(); - } + /* Init Timer queries */ + if (pass->timer_queries[0] == 0) { + pass->front_idx = 0; + pass->back_idx = 1; - /* Blending (all buffer) */ - if (flag & DRW_STATE_BLEND) { - glEnable(GL_BLEND); - } - else { - glDisable(GL_BLEND); - } + glGenQueries(2, pass->timer_queries); - /* Line Stipple */ - if (flag & DRW_STATE_STIPPLE_2) { - setlinestyle(2); - } - else if (flag & DRW_STATE_STIPPLE_3) { - setlinestyle(3); - } - else if (flag & DRW_STATE_STIPPLE_4) { - setlinestyle(4); + /* dummy query, avoid gl error */ + glBeginQuery(GL_TIME_ELAPSED, pass->timer_queries[pass->front_idx]); + glEndQuery(GL_TIME_ELAPSED); } else { - setlinestyle(0); + /* swap indices */ + unsigned int tmp = pass->back_idx; + pass->back_idx = pass->front_idx; + pass->front_idx = tmp; } -} - -void DRW_draw_pass(DRWPass *pass) -{ - /* Start fresh */ - DST.shader = NULL; - DST.tex_bind_id = 0; - set_state(pass->state); - BLI_listbase_clear(&DST.bound_texs); + /* issue query for the next frame */ + glBeginQuery(GL_TIME_ELAPSED, pass->timer_queries[pass->back_idx]); for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { draw_shgroup(shgroup); @@ -1047,6 +1134,30 @@ void DRW_draw_pass(DRWPass *pass) GPU_shader_unbind(); DST.shader = NULL; } + + glEndQuery(GL_TIME_ELAPSED); +} + +void DRW_draw_callbacks_pre_scene(void) +{ + struct ARegion *ar = CTX_wm_region(DST.context); + RegionView3D *rv3d = CTX_wm_region_view3d(DST.context); + + gpuLoadProjectionMatrix3D(rv3d->winmat); + gpuLoadMatrix3D(rv3d->viewmat); + + ED_region_draw_cb_draw(DST.context, ar, REGION_DRAW_PRE_VIEW); +} + +void DRW_draw_callbacks_post_scene(void) +{ + struct ARegion *ar = CTX_wm_region(DST.context); + RegionView3D *rv3d = CTX_wm_region_view3d(DST.context); + + gpuLoadProjectionMatrix3D(rv3d->winmat); + gpuLoadMatrix3D(rv3d->viewmat); + + ED_region_draw_cb_draw(DST.context, ar, REGION_DRAW_POST_VIEW); } /* Reset state to not interfer with other UI drawcall */ @@ -1056,102 +1167,81 @@ void DRW_state_reset(void) state |= DRW_STATE_WRITE_DEPTH; state |= DRW_STATE_WRITE_COLOR; state |= DRW_STATE_DEPTH_LESS; - set_state(state); + set_state(state, true); } -#endif -/* ****************************************** Settings ******************************************/ -void *DRW_material_settings_get(Material *ma, const char *engine_name) -{ - MaterialEngineSettings *ms = NULL; - - ms = BLI_findstring(&ma->engines_settings, engine_name, offsetof(MaterialEngineSettings, name)); - -#ifdef WITH_CLAY_ENGINE - /* If the settings does not exists yet, create it */ - if (ms == NULL) { - ms = MEM_callocN(sizeof(RenderEngineSettings), "RenderEngineSettings"); - BLI_strncpy(ms->name, engine_name, 32); - - /* TODO make render_settings_create a polymorphic function */ - if (STREQ(engine_name, RE_engine_id_BLENDER_CLAY)) { - ms->data = CLAY_material_settings_create(); - } - else { - /* No engine matched */ - BLI_assert(false); - } - - BLI_addtail(&ma->engines_settings, ms); - } #else - return NULL; +void DRW_draw_pass(DRWPass *UNUSED(pass)) +{ +} + #endif - return ms->data; -} +/* ****************************************** Settings ******************************************/ -/* If scene is NULL, use context scene */ -void *DRW_render_settings_get(Scene *scene, const char *engine_name) +bool DRW_is_object_renderable(Object *ob) { - RenderEngineSettings *rs = NULL; + Scene *scene = CTX_data_scene(DST.context); + Object *obedit = scene->obedit; - if (scene == NULL) - scene = CTX_data_scene(DST.context); + if (ob->type == OB_MESH) { + if (ob == obedit) { + IDProperty *props = BKE_object_collection_engine_get(ob, COLLECTION_MODE_EDIT, ""); + bool do_occlude_wire = BKE_collection_engine_property_value_get_bool(props, "show_occlude_wire"); - rs = BLI_findstring(&scene->engines_settings, engine_name, offsetof(RenderEngineSettings, name)); + if (do_occlude_wire) + return false; + } + } -#ifdef WITH_CLAY_ENGINE - /* If the settings does not exists yet, create it */ - if (rs == NULL) { - rs = MEM_callocN(sizeof(RenderEngineSettings), "RenderEngineSettings"); + return true; +} - BLI_strncpy(rs->name, engine_name, 32); +/* ****************************************** Framebuffers ******************************************/ - /* TODO make render_settings_create a polymorphic function */ - if (STREQ(engine_name, RE_engine_id_BLENDER_CLAY)) { - rs->data = CLAY_render_settings_create(); - } - else { - /* No engine matched */ +static GPUTextureFormat convert_tex_format(int fbo_format, int *channels) +{ + switch (fbo_format) { + case DRW_BUF_RGBA_8: *channels = 4; return GPU_RGBA8; + case DRW_BUF_RGBA_16: *channels = 4; return GPU_RGBA16F; + case DRW_BUF_DEPTH_24: *channels = 1; return GPU_DEPTH_COMPONENT24; + default: BLI_assert(false); - } - - BLI_addtail(&scene->engines_settings, rs); + *channels = 4; return GPU_RGBA8; } -#else - return NULL; -#endif - - return rs->data; } -/* ****************************************** Framebuffers ******************************************/ + void DRW_framebuffer_init(struct GPUFrameBuffer **fb, int width, int height, DRWFboTexture textures[MAX_FBO_TEX], int texnbr) { + BLI_assert(texnbr <= MAX_FBO_TEX); + if (!*fb) { int color_attachment = -1; *fb = GPU_framebuffer_create(); - for (int i = 0; i < texnbr; ++i) - { + for (int i = 0; i < texnbr; ++i) { DRWFboTexture fbotex = textures[i]; - + if (!*fbotex.tex) { + int channels; + GPUTextureFormat gpu_format = convert_tex_format(fbotex.format, &channels); + /* TODO refine to opengl formats */ if (fbotex.format == DRW_BUF_DEPTH_16 || - fbotex.format == DRW_BUF_DEPTH_24) { + fbotex.format == DRW_BUF_DEPTH_24) + { *fbotex.tex = GPU_texture_create_depth(width, height, NULL); GPU_texture_compare_mode(*fbotex.tex, false); GPU_texture_filter_mode(*fbotex.tex, false); } else { - *fbotex.tex = GPU_texture_create_2D(width, height, NULL, NULL); + *fbotex.tex = GPU_texture_create_2D_custom(width, height, channels, gpu_format, NULL, NULL); ++color_attachment; } } - + GPU_framebuffer_texture_attach(*fb, *fbotex.tex, color_attachment); } @@ -1168,6 +1258,24 @@ void DRW_framebuffer_bind(struct GPUFrameBuffer *fb) GPU_framebuffer_bind(fb); } +void DRW_framebuffer_clear(bool color, bool depth, bool stencil, float clear_col[4], float clear_depth) +{ + if (color) { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]); + } + if (depth) { + glDepthMask(GL_TRUE); + glClearDepth(clear_depth); + } + if (stencil) { + glStencilMask(0xFF); + } + glClear(((color) ? GL_COLOR_BUFFER_BIT : 0) | + ((depth) ? GL_DEPTH_BUFFER_BIT : 0) | + ((stencil) ? GL_STENCIL_BUFFER_BIT : 0)); +} + void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, GPUTexture *tex, int slot) { GPU_framebuffer_texture_attach(fb, tex, slot); @@ -1178,7 +1286,21 @@ void DRW_framebuffer_texture_detach(GPUTexture *tex) GPU_framebuffer_texture_detach(tex); } +void DRW_framebuffer_blit(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer *fb_write, bool depth) +{ + GPU_framebuffer_blit(fb_read, 0, fb_write, 0, depth); +} + /* ****************************************** Viewport ******************************************/ +static void *DRW_viewport_engine_data_get(void *engine_type) +{ + void *data = GPU_viewport_engine_data_get(DST.viewport, engine_type); + + if (data == NULL) { + data = GPU_viewport_engine_data_create(DST.viewport, engine_type); + } + return data; +} float *DRW_viewport_size_get(void) { @@ -1195,25 +1317,23 @@ float *DRW_viewport_pixelsize_get(void) return &DST.pixsize; } -void DRW_viewport_init(const bContext *C, void **buffers, void **textures, void **passes, void **storage) +/* It also stores viewport variable to an immutable place: DST + * This is because a cache uniform only store reference + * to its value. And we don't want to invalidate the cache + * if this value change per viewport */ +static void DRW_viewport_var_init(const bContext *C) { RegionView3D *rv3d = CTX_wm_region_view3d(C); - GPUViewport *viewport = rv3d->viewport; - - GPU_viewport_get_engine_data(viewport, buffers, textures, passes, storage); /* Refresh DST.size */ - DefaultTextureList *txl = (DefaultTextureList *)*textures; - DST.size[0] = (float)GPU_texture_width(txl->color); - DST.size[1] = (float)GPU_texture_height(txl->color); + int size[2]; + GPU_viewport_size_get(DST.viewport, size); + DST.size[0] = size[0]; + DST.size[1] = size[1]; - DefaultFramebufferList *fbl = (DefaultFramebufferList *)*buffers; + DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get(DST.viewport); DST.default_framebuffer = fbl->default_fb; - DST.current_txl = (TextureList *)*textures; - DST.current_fbl = (FramebufferList *)*buffers; - DST.current_psl = (PassList *)*passes; - /* Refresh DST.screenvecs */ copy_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]); copy_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]); @@ -1233,8 +1353,10 @@ void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type) if (type == DRW_MAT_PERS) copy_m4_m4(mat, rv3d->persmat); - else if (type == DRW_MAT_WIEW) + else if (type == DRW_MAT_VIEW) copy_m4_m4(mat, rv3d->viewmat); + else if (type == DRW_MAT_VIEWINV) + copy_m4_m4(mat, rv3d->viewinv); else if (type == DRW_MAT_WIN) copy_m4_m4(mat, rv3d->winmat); } @@ -1245,28 +1367,491 @@ bool DRW_viewport_is_persp_get(void) return rv3d->is_persp; } -bool DRW_viewport_cache_is_dirty(void) +DefaultFramebufferList *DRW_viewport_framebuffer_list_get(void) +{ + return GPU_viewport_framebuffer_list_get(DST.viewport); +} + +DefaultTextureList *DRW_viewport_texture_list_get(void) +{ + return GPU_viewport_texture_list_get(DST.viewport); +} + +/* **************************************** OBJECTS *************************************** */ + +typedef struct ObjectEngineData { + struct ObjectEngineData *next, *prev; + DrawEngineType *engine_type; + void *storage; +} ObjectEngineData; + +void **DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type) +{ + ObjectEngineData *oed; + + for (oed = ob->drawdata.first; oed; oed = oed->next) { + if (oed->engine_type == engine_type) { + return &oed->storage; + } + } + + oed = MEM_callocN(sizeof(ObjectEngineData), "ObjectEngineData"); + oed->engine_type = engine_type; + BLI_addtail(&ob->drawdata, oed); + + return &oed->storage; +} + +void DRW_object_engine_data_free(Object *ob) +{ + for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) { + if (oed->storage) { + MEM_freeN(oed->storage); + } + } + + BLI_freelistN(&ob->drawdata); +} + +/* **************************************** RENDERING ************************************** */ + +#define TIMER_FALLOFF 0.1f + +static void DRW_engines_init(void) +{ + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + DrawEngineType *engine = link->data; + ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + double stime = PIL_check_seconds_timer(); + + if (engine->engine_init) { + engine->engine_init(data); + } + + double ftime = (PIL_check_seconds_timer() - stime) * 1e3; + data->init_time = data->init_time * (1.0f - TIMER_FALLOFF) + ftime * TIMER_FALLOFF; /* exp average */ + } +} + +static void DRW_engines_cache_init(void) +{ + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + DrawEngineType *engine = link->data; + ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + double stime = PIL_check_seconds_timer(); + data->cache_time = 0.0; + + if (engine->cache_init) { + engine->cache_init(data); + } + + data->cache_time += (PIL_check_seconds_timer() - stime) * 1e3; + } +} + +static void DRW_engines_cache_populate(Object *ob) +{ + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + DrawEngineType *engine = link->data; + ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + double stime = PIL_check_seconds_timer(); + + if (engine->cache_populate) { + engine->cache_populate(data, ob); + } + + data->cache_time += (PIL_check_seconds_timer() - stime) * 1e3; + } +} + +static void DRW_engines_cache_finish(void) +{ + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + DrawEngineType *engine = link->data; + ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + double stime = PIL_check_seconds_timer(); + + if (engine->cache_finish) { + engine->cache_finish(data); + } + + data->cache_time += (PIL_check_seconds_timer() - stime) * 1e3; + } +} + +static void DRW_engines_draw_background(void) +{ + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + DrawEngineType *engine = link->data; + ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + double stime = PIL_check_seconds_timer(); + + if (engine->draw_background) { + engine->draw_background(data); + return; + } + + double ftime = (PIL_check_seconds_timer() - stime) * 1e3; + data->background_time = data->background_time * (1.0f - TIMER_FALLOFF) + ftime * TIMER_FALLOFF; /* exp average */ + } + + /* No draw_background found, doing default background */ + DRW_draw_background(); +} + +static void DRW_engines_draw_scene(void) +{ + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + DrawEngineType *engine = link->data; + ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + double stime = PIL_check_seconds_timer(); + + if (engine->draw_scene) { + engine->draw_scene(data); + } + + double ftime = (PIL_check_seconds_timer() - stime) * 1e3; + data->render_time = data->render_time * (1.0f - TIMER_FALLOFF) + ftime * TIMER_FALLOFF; /* exp average */ + } +} + +static void use_drw_engine(DrawEngineType *engine) +{ + LinkData *ld = MEM_callocN(sizeof(LinkData), "enabled engine link data"); + ld->data = engine; + BLI_addtail(&DST.enabled_engines, ld); +} + +/* TODO revisit this when proper layering is implemented */ +/* Gather all draw engines needed and store them in DST.enabled_engines + * That also define the rendering order of engines */ +static void DRW_engines_enable(const bContext *C) +{ + /* TODO layers */ + Scene *scene = CTX_data_scene(C); + RenderEngineType *type = RE_engines_find(scene->r.engine); + use_drw_engine(type->draw_engine); + + /* TODO Refine the folowing logic based on objects states + * not on global state. + * Order is important */ + use_drw_engine(&draw_engine_object_type); + + switch (CTX_data_mode_enum(C)) { + case CTX_MODE_EDIT_MESH: + use_drw_engine(&draw_engine_edit_mesh_type); + break; + case CTX_MODE_EDIT_CURVE: + use_drw_engine(&draw_engine_edit_curve_type); + break; + case CTX_MODE_EDIT_SURFACE: + use_drw_engine(&draw_engine_edit_surface_type); + break; + case CTX_MODE_EDIT_TEXT: + use_drw_engine(&draw_engine_edit_text_type); + break; + case CTX_MODE_EDIT_ARMATURE: + use_drw_engine(&draw_engine_edit_armature_type); + break; + case CTX_MODE_EDIT_METABALL: + use_drw_engine(&draw_engine_edit_metaball_type); + break; + case CTX_MODE_EDIT_LATTICE: + use_drw_engine(&draw_engine_edit_lattice_type); + break; + case CTX_MODE_POSE: + use_drw_engine(&draw_engine_pose_type); + break; + case CTX_MODE_SCULPT: + use_drw_engine(&draw_engine_sculpt_type); + break; + case CTX_MODE_PAINT_WEIGHT: + use_drw_engine(&draw_engine_paint_weight_type); + break; + case CTX_MODE_PAINT_VERTEX: + use_drw_engine(&draw_engine_paint_vertex_type); + break; + case CTX_MODE_PAINT_TEXTURE: + use_drw_engine(&draw_engine_paint_texture_type); + break; + case CTX_MODE_PARTICLE: + use_drw_engine(&draw_engine_particle_type); + break; + case CTX_MODE_OBJECT: + break; + } +} + +static void DRW_engines_disable(void) +{ + BLI_freelistN(&DST.enabled_engines); +} + +static unsigned int DRW_engines_get_hash(void) +{ + unsigned int hash = 0; + /* The cache depends on enabled engines */ + /* FIXME : if collision occurs ... segfault */ + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + DrawEngineType *engine = link->data; + hash += BLI_ghashutil_strhash_p(engine->idname); + } + + return hash; +} + +static void draw_stat(rcti *rect, int u, int v, const char *txt, const int size) +{ + BLF_draw_default_ascii(rect->xmin + (1 + u * 5) * U.widget_unit, + rect->ymax - (3 + v++) * U.widget_unit, 0.0f, + txt, size); +} + +/* CPU stats */ +static void DRW_debug_cpu_stats(void) +{ + int u, v; + double cache_tot_time = 0.0, init_tot_time = 0.0, background_tot_time = 0.0, render_tot_time = 0.0, tot_time = 0.0; + /* local coordinate visible rect inside region, to accomodate overlapping ui */ + rcti rect; + struct ARegion *ar = CTX_wm_region(DST.context); + ED_region_visible_rect(ar, &rect); + + UI_FontThemeColor(BLF_default(), TH_TEXT_HI); + + /* row by row */ + v = 0; u = 0; + /* Label row */ + char col_label[32]; + sprintf(col_label, "Engine"); + draw_stat(&rect, u++, v, col_label, sizeof(col_label)); + sprintf(col_label, "Cache"); + draw_stat(&rect, u++, v, col_label, sizeof(col_label)); + sprintf(col_label, "Init"); + draw_stat(&rect, u++, v, col_label, sizeof(col_label)); + sprintf(col_label, "Background"); + draw_stat(&rect, u++, v, col_label, sizeof(col_label)); + sprintf(col_label, "Render"); + draw_stat(&rect, u++, v, col_label, sizeof(col_label)); + sprintf(col_label, "Total (w/o cache)"); + draw_stat(&rect, u++, v, col_label, sizeof(col_label)); + v++; + + /* Engines rows */ + char time_to_txt[16]; + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + u = 0; + DrawEngineType *engine = link->data; + ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + + draw_stat(&rect, u++, v, engine->idname, sizeof(engine->idname)); + + cache_tot_time += data->cache_time; + sprintf(time_to_txt, "%.2fms", data->cache_time); + draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); + + init_tot_time += data->init_time; + sprintf(time_to_txt, "%.2fms", data->init_time); + draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); + + background_tot_time += data->background_time; + sprintf(time_to_txt, "%.2fms", data->background_time); + draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); + + render_tot_time += data->render_time; + sprintf(time_to_txt, "%.2fms", data->render_time); + draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); + + tot_time += data->init_time + data->background_time + data->render_time; + sprintf(time_to_txt, "%.2fms", data->init_time + data->background_time + data->render_time); + draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); + v++; + } + + /* Totals row */ + u = 0; + sprintf(col_label, "Sub Total"); + draw_stat(&rect, u++, v, col_label, sizeof(col_label)); + sprintf(time_to_txt, "%.2fms", cache_tot_time); + draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); + sprintf(time_to_txt, "%.2fms", init_tot_time); + draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); + sprintf(time_to_txt, "%.2fms", background_tot_time); + draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); + sprintf(time_to_txt, "%.2fms", render_tot_time); + draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); + sprintf(time_to_txt, "%.2fms", tot_time); + draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); +} + +/* Display GPU time for each passes */ +static void DRW_debug_gpu_stats(void) +{ + /* local coordinate visible rect inside region, to accomodate overlapping ui */ + rcti rect; + struct ARegion *ar = CTX_wm_region(DST.context); + ED_region_visible_rect(ar, &rect); + + UI_FontThemeColor(BLF_default(), TH_TEXT_HI); + + char time_to_txt[16]; + char pass_name[MAX_PASS_NAME + 8]; + int v = BLI_listbase_count(&DST.enabled_engines) + 3; + GLuint64 tot_time = 0; + + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + GLuint64 engine_time = 0; + DrawEngineType *engine = link->data; + ViewportEngineData *data = DRW_viewport_engine_data_get(engine); + int vsta = v; + + draw_stat(&rect, 0, v, engine->idname, sizeof(engine->idname)); + v++; + + for (int i = 0; i < MAX_PASSES; ++i) { + DRWPass *pass = data->psl->passes[i]; + if (pass != NULL) { + GLuint64 time; + glGetQueryObjectui64v(pass->timer_queries[pass->front_idx], GL_QUERY_RESULT, &time); + tot_time += time; + engine_time += time; + + sprintf(pass_name, " |--> %s", pass->name); + draw_stat(&rect, 0, v, pass_name, sizeof(pass_name)); + + if (pass->wasdrawn) + sprintf(time_to_txt, "%.2fms", time / 1000000.0); + else + sprintf(time_to_txt, "Not drawn"); + draw_stat(&rect, 2, v++, time_to_txt, sizeof(time_to_txt)); + + pass->wasdrawn = false; + } + } + /* engine total time */ + sprintf(time_to_txt, "%.2fms", engine_time / 1000000.0); + draw_stat(&rect, 2, vsta, time_to_txt, sizeof(time_to_txt)); + v++; + } + + sprintf(pass_name, "Total GPU time %.2fms (%.1f fps)", tot_time / 1000000.0, 1000000000.0 / tot_time); + draw_stat(&rect, 0, v, pass_name, sizeof(pass_name)); +} + +/* Everything starts here. + * This function takes care of calling all cache and rendering functions + * for each relevant engine / mode engine. */ +void DRW_draw_view(const bContext *C) +{ + bool cache_is_dirty; + RegionView3D *rv3d = CTX_wm_region_view3d(C); + View3D *v3d = CTX_wm_view3d(C); + DST.viewport = rv3d->viewport; + v3d->zbuf = true; + + /* Get list of enabled engines */ + DRW_engines_enable(C); + + /* Setup viewport */ + cache_is_dirty = GPU_viewport_cache_validate(DST.viewport, DRW_engines_get_hash()); + DRW_viewport_var_init(C); + + /* Update ubos */ + DRW_globals_update(); + + /* Init engines */ + DRW_engines_init(); + + /* TODO : tag to refresh by the deps graph */ + /* ideally only refresh when objects are added/removed */ + /* or render properties / materials change */ + if (cache_is_dirty) { + SceneLayer *sl = CTX_data_scene_layer(C); + + DRW_engines_cache_init(); + DEG_OBJECT_ITER(sl, ob); + { + DRW_engines_cache_populate(ob); + } + DEG_OBJECT_ITER_END + DRW_engines_cache_finish(); + } + + /* Start Drawing */ + DRW_engines_draw_background(); + + DRW_draw_callbacks_pre_scene(); + // DRW_draw_grid(); + DRW_engines_draw_scene(); + DRW_draw_callbacks_post_scene(); + + DRW_draw_region_info(); + + if (G.debug_value > 20) { + DRW_debug_cpu_stats(); + DRW_debug_gpu_stats(); + } + + DRW_state_reset(); + DRW_engines_disable(); +} + +/* ****************************************** OTHER ***************************************** */ + +const bContext *DRW_get_context(void) { - /* TODO Use a dirty flag */ - return (DST.current_psl->passes[0] == NULL); + return DST.context; } -/* ****************************************** INIT ******************************************/ +/* ****************************************** INIT ***************************************** */ + +void DRW_engine_register(DrawEngineType *draw_engine_type) +{ + BLI_addtail(&DRW_engines, draw_engine_type); +} -void DRW_engines_init(void) +void DRW_engines_register(void) { #ifdef WITH_CLAY_ENGINE RE_engines_register(NULL, &viewport_clay_type); + RE_engines_register(NULL, &viewport_eevee_type); + + DRW_engine_register(&draw_engine_object_type); + DRW_engine_register(&draw_engine_edit_armature_type); + DRW_engine_register(&draw_engine_edit_curve_type); + DRW_engine_register(&draw_engine_edit_lattice_type); + DRW_engine_register(&draw_engine_edit_mesh_type); + DRW_engine_register(&draw_engine_edit_metaball_type); + DRW_engine_register(&draw_engine_edit_surface_type); + DRW_engine_register(&draw_engine_edit_text_type); + DRW_engine_register(&draw_engine_paint_texture_type); + DRW_engine_register(&draw_engine_paint_vertex_type); + DRW_engine_register(&draw_engine_paint_weight_type); + DRW_engine_register(&draw_engine_particle_type); + DRW_engine_register(&draw_engine_pose_type); + DRW_engine_register(&draw_engine_sculpt_type); #endif } +extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */ void DRW_engines_free(void) { #ifdef WITH_CLAY_ENGINE - clay_engine_free(); - DRW_shape_cache_free(); + DrawEngineType *next; + for (DrawEngineType *type = DRW_engines.first; type; type = next) { + next = type->next; + BLI_remlink(&R_engines, type); + + if (type->engine_free) { + type->engine_free(); + } + } + + if (globals_ubo) + GPU_uniformbuffer_free(globals_ubo); + BLI_remlink(&R_engines, &viewport_clay_type); #endif -}
\ No newline at end of file +} |