diff options
Diffstat (limited to 'source/blender/gpu/intern')
26 files changed, 6788 insertions, 3344 deletions
diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c index 8505bd847a0..620a06ae606 100644 --- a/source/blender/gpu/intern/gpu_basic_shader.c +++ b/source/blender/gpu/intern/gpu_basic_shader.c @@ -140,114 +140,6 @@ const GLubyte stipple_checker_8px[128] = { 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255}; -const GLubyte stipple_interlace_row[128] = { - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}; - -const GLubyte stipple_interlace_row_swap[128] = { - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}; - -const GLubyte stipple_interlace_column[128] = { - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}; - -const GLubyte stipple_interlace_column_swap[128] = { - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}; - -const GLubyte stipple_interlace_checker[128] = { - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa}; - -const GLubyte stipple_interlace_checker_swap[128] = { - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55}; - const GLubyte stipple_hexagon[128] = { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, @@ -267,24 +159,6 @@ const GLubyte stipple_hexagon[128] = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22}; /* ********************************************* */ -/* GLSL State */ - -static bool USE_GLSL = false; - -/** - * \note this isn't part of the basic shader API, - * only set from the command line once on startup. - */ -void GPU_basic_shader_use_glsl_set(bool enabled) -{ - USE_GLSL = enabled; -} - -bool GPU_basic_shader_use_glsl_get(void) -{ - return USE_GLSL; -} - /* Init / exit */ void GPU_basic_shaders_init(void) @@ -316,31 +190,6 @@ static bool solid_compatible_lighting(void) return ((directional & enabled) == enabled); } -#if 0 -static int detect_options() -{ - GLint two_sided; - int options = 0; - - if (glIsEnabled(GL_TEXTURE_2D)) - options |= GPU_SHADER_TEXTURE_2D; - if (glIsEnabled(GL_TEXTURE_RECTANGLE)) - options |= GPU_SHADER_TEXTURE_RECT; - GPU_SHADER_TEXTURE_RECT - if (glIsEnabled(GL_COLOR_MATERIAL)) - options |= GPU_SHADER_USE_COLOR; - - if (glIsEnabled(GL_LIGHTING)) - options |= GPU_SHADER_LIGHTING; - - glGetIntegerv(GL_LIGHT_MODEL_TWO_SIDE, &two_sided); - if (two_sided == GL_TRUE) - options |= GPU_SHADER_TWO_SIDED; - - return options; -} -#endif - static GPUShader *gpu_basic_shader(int options) { /* glsl code */ @@ -388,7 +237,7 @@ static GPUShader *gpu_basic_shader(int options) datatoc_gpu_shader_basic_frag_glsl, geom_glsl, NULL, - defines, 0, 0, 0); + defines); if (shader) { /* set texture map to first texture unit */ @@ -420,102 +269,16 @@ static void gpu_basic_shader_uniform_autoset(GPUShader *shader, int options) void GPU_basic_shader_bind(int options) { - if (USE_GLSL) { - if (options) { - const int bound_options = GPU_MATERIAL_STATE.bound_options; - - /* texture options need to be set for basic shader too */ - if (options & GPU_SHADER_TEXTURE_2D) { - glEnable(GL_TEXTURE_2D); - } - else if (bound_options & GPU_SHADER_TEXTURE_2D) { - glDisable(GL_TEXTURE_2D); - } - - if (options & GPU_SHADER_TEXTURE_RECT) { - glEnable(GL_TEXTURE_RECTANGLE); - } - else if (bound_options & GPU_SHADER_TEXTURE_RECT) { - glDisable(GL_TEXTURE_RECTANGLE); - } - - GPUShader *shader = gpu_basic_shader(options); + if (options) { + GPUShader *shader = gpu_basic_shader(options); - if (shader) { - GPU_shader_bind(shader); - gpu_basic_shader_uniform_autoset(shader, options); - } - } - else { - GPU_shader_unbind(); + if (shader) { + GPU_shader_bind(shader); + gpu_basic_shader_uniform_autoset(shader, options); } } else { - const int bound_options = GPU_MATERIAL_STATE.bound_options; - - if (options & GPU_SHADER_LIGHTING) { - glEnable(GL_LIGHTING); - - if (options & GPU_SHADER_USE_COLOR) - glEnable(GL_COLOR_MATERIAL); - else - glDisable(GL_COLOR_MATERIAL); - - if (options & GPU_SHADER_TWO_SIDED) - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); - else - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); - } - else if (bound_options & GPU_SHADER_LIGHTING) { - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); - } - - if (options & GPU_SHADER_TEXTURE_2D) { - GLint env_mode = (options & (GPU_SHADER_USE_COLOR | GPU_SHADER_LIGHTING)) ? GL_MODULATE : GL_REPLACE; - glEnable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode); - } - else if (bound_options & GPU_SHADER_TEXTURE_2D) { - if ((options & GPU_SHADER_TEXTURE_RECT) == 0) { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } - glDisable(GL_TEXTURE_2D); - } - - if (options & GPU_SHADER_TEXTURE_RECT) { - GLint env_mode = (options & (GPU_SHADER_USE_COLOR | GPU_SHADER_LIGHTING)) ? GL_MODULATE : GL_REPLACE; - glEnable(GL_TEXTURE_RECTANGLE); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode); - } - else if (bound_options & GPU_SHADER_TEXTURE_RECT) { - if ((options & GPU_SHADER_TEXTURE_2D) == 0) { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } - glDisable(GL_TEXTURE_RECTANGLE); - } - - if ((options & GPU_SHADER_LINE) && (options & GPU_SHADER_STIPPLE)) { - glEnable(GL_LINE_STIPPLE); - } - else if ((bound_options & GPU_SHADER_LINE) && (bound_options & GPU_SHADER_STIPPLE)) { - glDisable(GL_LINE_STIPPLE); - } - - if (((options & GPU_SHADER_LINE) == 0) && (options & GPU_SHADER_STIPPLE)) { - glEnable(GL_POLYGON_STIPPLE); - } - else if (((bound_options & GPU_SHADER_LINE) == 0) && (bound_options & GPU_SHADER_STIPPLE)) { - glDisable(GL_POLYGON_STIPPLE); - } - - if (options & GPU_SHADER_FLAT_NORMAL) { - glShadeModel(GL_FLAT); - } - else if (bound_options & GPU_SHADER_FLAT_NORMAL) { - glShadeModel(GL_SMOOTH); - } + GPU_shader_unbind(); } GPU_MATERIAL_STATE.bound_options = options; @@ -544,175 +307,37 @@ void GPU_basic_shader_colors( const float diffuse[3], const float specular[3], int shininess, float alpha) { - float gl_diffuse[4], gl_specular[4]; - - if (diffuse) - copy_v3_v3(gl_diffuse, diffuse); - else - zero_v3(gl_diffuse); - gl_diffuse[3] = alpha; - - if (specular) - copy_v3_v3(gl_specular, specular); - else - zero_v3(gl_specular); - gl_specular[3] = 1.0f; - - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, gl_diffuse); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, gl_specular); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, CLAMPIS(shininess, 1, 128)); + UNUSED_VARS(diffuse, specular, shininess, alpha); + return; } void GPU_basic_shader_light_set(int light_num, GPULightData *light) { - int light_bit = (1 << light_num); - - /* note that light position is affected by the current modelview matrix! */ - - GPU_MATERIAL_STATE.lights_enabled &= ~light_bit; - GPU_MATERIAL_STATE.lights_directional &= ~light_bit; - - if (light) { - float position[4], diffuse[4], specular[4]; - - glEnable(GL_LIGHT0 + light_num); - - /* position */ - if (light->type == GPU_LIGHT_SUN) { - copy_v3_v3(position, light->direction); - position[3] = 0.0f; - } - else { - copy_v3_v3(position, light->position); - position[3] = 1.0f; - } - glLightfv(GL_LIGHT0 + light_num, GL_POSITION, position); - - /* energy */ - copy_v3_v3(diffuse, light->diffuse); - copy_v3_v3(specular, light->specular); - diffuse[3] = 1.0f; - specular[3] = 1.0f; - glLightfv(GL_LIGHT0 + light_num, GL_DIFFUSE, diffuse); - glLightfv(GL_LIGHT0 + light_num, GL_SPECULAR, specular); - - /* attenuation */ - if (light->type == GPU_LIGHT_SUN) { - glLightf(GL_LIGHT0 + light_num, GL_CONSTANT_ATTENUATION, 1.0f); - glLightf(GL_LIGHT0 + light_num, GL_LINEAR_ATTENUATION, 0.0f); - glLightf(GL_LIGHT0 + light_num, GL_QUADRATIC_ATTENUATION, 0.0f); - } - else { - glLightf(GL_LIGHT0 + light_num, GL_CONSTANT_ATTENUATION, light->constant_attenuation); - glLightf(GL_LIGHT0 + light_num, GL_LINEAR_ATTENUATION, light->linear_attenuation); - glLightf(GL_LIGHT0 + light_num, GL_QUADRATIC_ATTENUATION, light->quadratic_attenuation); - } - - /* spot */ - glLightfv(GL_LIGHT0 + light_num, GL_SPOT_DIRECTION, light->direction); - if (light->type == GPU_LIGHT_SPOT) { - glLightf(GL_LIGHT0 + light_num, GL_SPOT_CUTOFF, light->spot_cutoff); - glLightf(GL_LIGHT0 + light_num, GL_SPOT_EXPONENT, light->spot_exponent); - } - else { - glLightf(GL_LIGHT0 + light_num, GL_SPOT_CUTOFF, 180.0f); - glLightf(GL_LIGHT0 + light_num, GL_SPOT_EXPONENT, 0.0f); - } - - GPU_MATERIAL_STATE.lights_enabled |= light_bit; - if (position[3] == 0.0f) - GPU_MATERIAL_STATE.lights_directional |= light_bit; - } - else { - /* TODO(sergey): Needs revisit. */ - if (USE_GLSL || true) { - /* glsl shader needs these zero to skip them */ - const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - - glLightfv(GL_LIGHT0 + light_num, GL_POSITION, zero); - glLightfv(GL_LIGHT0 + light_num, GL_DIFFUSE, zero); - glLightfv(GL_LIGHT0 + light_num, GL_SPECULAR, zero); - } - - glDisable(GL_LIGHT0 + light_num); - } + UNUSED_VARS(light_num, light); + return; } void GPU_basic_shader_light_set_viewer(bool local) { - glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (local) ? GL_TRUE: GL_FALSE); + UNUSED_VARS(local); + return; } void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id) { - if (USE_GLSL) { - glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_id"), stipple_id); - } - else { - switch (stipple_id) { - case GPU_SHADER_STIPPLE_HALFTONE: - glPolygonStipple(stipple_halftone); - return; - case GPU_SHADER_STIPPLE_QUARTTONE: - glPolygonStipple(stipple_quarttone); - return; - case GPU_SHADER_STIPPLE_CHECKER_8PX: - glPolygonStipple(stipple_checker_8px); - return; - case GPU_SHADER_STIPPLE_HEXAGON: - glPolygonStipple(stipple_hexagon); - return; - case GPU_SHADER_STIPPLE_DIAG_STRIPES_SWAP: - glPolygonStipple(stipple_diag_stripes_neg); - return; - case GPU_SHADER_STIPPLE_DIAG_STRIPES: - glPolygonStipple(stipple_diag_stripes_pos); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW: - glPolygonStipple(stipple_interlace_row); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW_SWAP: - glPolygonStipple(stipple_interlace_row_swap); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN: - glPolygonStipple(stipple_interlace_column); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN_SWAP: - glPolygonStipple(stipple_interlace_column_swap); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER: - glPolygonStipple(stipple_interlace_checker); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER_SWAP: - glPolygonStipple(stipple_interlace_checker_swap); - return; - default: - glPolygonStipple(stipple_hexagon); - return; - } - } + glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_id"), stipple_id); } void GPU_basic_shader_line_width(float line_width) { - if (USE_GLSL) { - GPU_MATERIAL_STATE.line_width = line_width; - if (GPU_MATERIAL_STATE.bound_options & GPU_SHADER_LINE) { - glUniform1f(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "line_width"), line_width); - } - } - else { - glLineWidth(line_width); + GPU_MATERIAL_STATE.line_width = line_width; + if (GPU_MATERIAL_STATE.bound_options & GPU_SHADER_LINE) { + glUniform1f(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "line_width"), line_width); } } void GPU_basic_shader_line_stipple(GLint stipple_factor, GLushort stipple_pattern) { - if (USE_GLSL) { - glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_factor"), stipple_factor); - glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_pattern"), stipple_pattern); - } - else { - glLineStipple(stipple_factor, stipple_pattern); - } + glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_factor"), stipple_factor); + glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_pattern"), stipple_pattern); } diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c new file mode 100644 index 00000000000..0400fc1025b --- /dev/null +++ b/source/blender/gpu/intern/gpu_batch.c @@ -0,0 +1,281 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_basic_shader.c + * \ingroup gpu + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_rect.h" +#include "BLI_math.h" +#include "BLI_polyfill2d.h" +#include "BLI_sort_utils.h" + + +#include "GPU_batch.h" /* own include */ +#include "gpu_shader_private.h" + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +void GWN_batch_program_set_builtin(Gwn_Batch *batch, GPUBuiltinShader shader_id) +{ + GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); + GWN_batch_program_set(batch, shader->program, shader->interface); +} + +/** \} */ + + + +/* -------------------------------------------------------------------- */ +/** \name Batch Creation + * \{ */ + +/** + * Creates triangles from a byte-array of polygons. + * + * See 'make_shape_2d_from_blend.py' utility to create data to pass to this function. + * + * \param polys_flat: Pairs of X, Y coordinates (repeating to signify closing the polygon). + * \param polys_flat_len: Length of the array (must be an even number). + * \param rect: Optional region to map the byte 0..255 coords to. When not set use -1..1. + */ +Gwn_Batch *GPU_batch_tris_from_poly_2d_encoded( + const uchar *polys_flat, uint polys_flat_len, const rctf *rect) +{ + const uchar (*polys)[2] = (const void *)polys_flat; + const uint polys_len = polys_flat_len / 2; + BLI_assert(polys_flat_len == polys_len * 2); + + /* Over alloc in both cases */ + float (*verts)[2] = MEM_mallocN(sizeof(*verts) * polys_len, __func__); + float (*verts_step)[2] = verts; + uint (*tris)[3] = MEM_mallocN(sizeof(*tris) * polys_len, __func__); + uint (*tris_step)[3] = tris; + + const float range_uchar[2] = { + (rect ? (rect->xmax - rect->xmin) : 2.0f) / 255.0f, + (rect ? (rect->ymax - rect->ymin) : 2.0f) / 255.0f, + }; + const float min_uchar[2] = { + (rect ? rect->xmin : -1.0f), + (rect ? rect->ymin : -1.0f), + }; + + uint i_poly = 0; + uint i_vert = 0; + while (i_poly != polys_len) { + for (uint j = 0; j < 2; j++) { + verts[i_vert][j] = min_uchar[j] + ((float)polys[i_poly][j] * range_uchar[j]); + } + i_vert++; + i_poly++; + if (polys[i_poly - 1][0] == polys[i_poly][0] && + polys[i_poly - 1][1] == polys[i_poly][1]) + { + const uint verts_step_len = (&verts[i_vert]) - verts_step; + BLI_assert(verts_step_len >= 3); + const uint tris_len = (verts_step_len - 2); + BLI_polyfill_calc(verts_step, verts_step_len, -1, tris_step); + /* offset indices */ + if (verts_step != verts) { + uint *t = tris_step[0]; + const uint offset = (verts_step - verts); + uint tot = tris_len * 3; + while (tot--) { + *t += offset; + t++; + } + BLI_assert(t == tris_step[tris_len]); + } + verts_step += verts_step_len; + tris_step += tris_len; + i_poly++; + /* ignore the duplicate point */ + } + } + + /* We have vertices and tris, make a batch from this. */ + static Gwn_VertFormat format = {0}; + static struct { uint pos; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + + const uint verts_len = (verts_step - verts); + const uint tris_len = (tris_step - tris); + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, verts_len); + + Gwn_VertBufRaw pos_step; + GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); + + for (uint i = 0; i < verts_len; i++) { + copy_v2_v2(GWN_vertbuf_raw_step(&pos_step), verts[i]); + } + + Gwn_IndexBufBuilder elb; + GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tris_len, verts_len); + for (uint i = 0; i < tris_len; i++) { + GWN_indexbuf_add_tri_verts(&elb, UNPACK3(tris[i])); + } + Gwn_IndexBuf *indexbuf = GWN_indexbuf_build(&elb); + + MEM_freeN(tris); + MEM_freeN(verts); + + return GWN_batch_create_ex( + GWN_PRIM_TRIS, vbo, + indexbuf, + GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX); +} + +Gwn_Batch *GPU_batch_wire_from_poly_2d_encoded( + const uchar *polys_flat, uint polys_flat_len, const rctf *rect) +{ + const uchar (*polys)[2] = (const void *)polys_flat; + const uint polys_len = polys_flat_len / 2; + BLI_assert(polys_flat_len == polys_len * 2); + + /* Over alloc */ + /* Lines are pairs of (x, y) byte locations packed into an int32_t. */ + int32_t *lines = MEM_mallocN(sizeof(*lines) * polys_len, __func__); + int32_t *lines_step = lines; + + const float range_uchar[2] = { + (rect ? (rect->xmax - rect->xmin) : 2.0f) / 255.0f, + (rect ? (rect->ymax - rect->ymin) : 2.0f) / 255.0f, + }; + const float min_uchar[2] = { + (rect ? rect->xmin : -1.0f), + (rect ? rect->ymin : -1.0f), + }; + + uint i_poly_prev = 0; + uint i_poly = 0; + while (i_poly != polys_len) { + i_poly++; + if (polys[i_poly - 1][0] == polys[i_poly][0] && + polys[i_poly - 1][1] == polys[i_poly][1]) + { + const uchar (*polys_step)[2] = polys + i_poly_prev; + const uint polys_step_len = i_poly - i_poly_prev; + BLI_assert(polys_step_len >= 2); + for (uint i_prev = polys_step_len - 1, i = 0; i < polys_step_len; i_prev = i++) { + union { + uint8_t as_u8[4]; + uint16_t as_u16[2]; + uint32_t as_u32; + } data; + data.as_u16[0] = *((const uint16_t *)polys_step[i_prev]); + data.as_u16[1] = *((const uint16_t *)polys_step[i]); + if (data.as_u16[0] > data.as_u16[1]) { + SWAP(uint16_t, data.as_u16[0], data.as_u16[1]); + } + *lines_step = data.as_u32; + lines_step++; + } + i_poly++; + i_poly_prev = i_poly; + /* ignore the duplicate point */ + } + } + + uint lines_len = lines_step - lines; + + /* Hide Lines (we could make optional) */ + { + qsort(lines, lines_len, sizeof(int32_t), BLI_sortutil_cmp_int); + lines_step = lines; + + if (lines[0] != lines[1]) { + *lines_step++ = lines[0]; + } + for (uint i_prev = 0, i = 1; i < lines_len; i_prev = i++) { + if (lines[i] != lines[i_prev]) { + *lines_step++ = lines[i]; + } + } + lines_len = lines_step - lines; + } + + /* We have vertices and tris, make a batch from this. */ + static Gwn_VertFormat format = {0}; + static struct { uint pos; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + const uint vbo_len_capacity = lines_len * 2; + GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); + + Gwn_VertBufRaw pos_step; + GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); + + for (uint i = 0; i < lines_len; i++) { + union { + uint8_t as_u8_pair[2][2]; + uint32_t as_u32; + } data; + data.as_u32 = lines[i]; + for (uint k = 0; k < 2; k++) { + float *pos_v2 = GWN_vertbuf_raw_step(&pos_step); + for (uint j = 0; j < 2; j++) { + pos_v2[j] = min_uchar[j] + ((float)data.as_u8_pair[k][j] * range_uchar[j]); + } + } + } + BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step)); + MEM_freeN(lines); + return GWN_batch_create_ex( + GWN_PRIM_LINES, vbo, + NULL, + GWN_BATCH_OWNS_VBO); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Init/Exit + * \{ */ + +void gpu_batch_init(void) +{ + gpu_batch_presets_init(); +} + +void gpu_batch_exit(void) +{ + gpu_batch_presets_exit(); +} + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c new file mode 100644 index 00000000000..9db04832a51 --- /dev/null +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -0,0 +1,200 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_batch_presets.c + * \ingroup gpu + */ + +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "GPU_batch.h" +#include "gpu_shader_private.h" + +/* Struct to store 3D Batches and their format */ +static struct { + struct { + Gwn_Batch *sphere_high; + Gwn_Batch *sphere_med; + Gwn_Batch *sphere_low; + Gwn_Batch *sphere_wire_low; + Gwn_Batch *sphere_wire_med; + } batch; + + Gwn_VertFormat format; + + struct { + uint pos, nor; + } attr_id; +} g_presets_3d = {0}; + +/* We may want 2D presets later. */ + +/* -------------------------------------------------------------------- */ +/** \name 3D Primitives + * \{ */ + +static void batch_sphere_lat_lon_vert( + Gwn_VertBufRaw *pos_step, Gwn_VertBufRaw *nor_step, + float lat, float lon) +{ + float pos[3]; + pos[0] = sinf(lat) * cosf(lon); + pos[1] = cosf(lat); + pos[2] = sinf(lat) * sinf(lon); + copy_v3_v3(GWN_vertbuf_raw_step(pos_step), pos); + copy_v3_v3(GWN_vertbuf_raw_step(nor_step), pos); +} + +/* Replacement for gluSphere */ +static Gwn_Batch *batch_sphere(int lat_res, int lon_res) +{ + const float lon_inc = 2 * M_PI / lon_res; + const float lat_inc = M_PI / lat_res; + float lon, lat; + + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&g_presets_3d.format); + const uint vbo_len = (lat_res - 1) * lon_res * 6; + GWN_vertbuf_data_alloc(vbo, vbo_len); + + Gwn_VertBufRaw pos_step, nor_step; + GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.pos, &pos_step); + GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.nor, &nor_step); + + lon = 0.0f; + for (int i = 0; i < lon_res; i++, lon += lon_inc) { + lat = 0.0f; + for (int j = 0; j < lat_res; j++, lat += lat_inc) { + if (j != lat_res - 1) { /* Pole */ + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon); + } + + if (j != 0) { /* Pole */ + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon + lon_inc); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon); + } + } + } + + BLI_assert(vbo_len == GWN_vertbuf_raw_used(&pos_step)); + BLI_assert(vbo_len == GWN_vertbuf_raw_used(&nor_step)); + + return GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO); +} + +static Gwn_Batch *batch_sphere_wire(int lat_res, int lon_res) +{ + const float lon_inc = 2 * M_PI / lon_res; + const float lat_inc = M_PI / lat_res; + float lon, lat; + + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&g_presets_3d.format); + const uint vbo_len = (lat_res * lon_res * 2) + ((lat_res - 1) * lon_res * 2); + GWN_vertbuf_data_alloc(vbo, vbo_len); + + Gwn_VertBufRaw pos_step, nor_step; + GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.pos, &pos_step); + GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.nor, &nor_step); + + lon = 0.0f; + for (int i = 0; i < lon_res; i++, lon += lon_inc) { + lat = 0.0f; + for (int j = 0; j < lat_res; j++, lat += lat_inc) { + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon); + + if (j != lat_res - 1) { /* Pole */ + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon); + } + } + } + + BLI_assert(vbo_len == GWN_vertbuf_raw_used(&pos_step)); + BLI_assert(vbo_len == GWN_vertbuf_raw_used(&nor_step)); + + return GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); +} + +Gwn_Batch *GPU_batch_preset_sphere(int lod) +{ + BLI_assert(lod >= 0 && lod <= 2); + + if (lod == 0) { + return g_presets_3d.batch.sphere_low; + } + else if (lod == 1) { + return g_presets_3d.batch.sphere_med; + } + else { + return g_presets_3d.batch.sphere_high; + } +} + +Gwn_Batch *GPU_batch_preset_sphere_wire(int lod) +{ + BLI_assert(lod >= 0 && lod <= 1); + + if (lod == 0) { + return g_presets_3d.batch.sphere_wire_low; + } + else { + return g_presets_3d.batch.sphere_wire_med; + } +} + +/** \} */ + + +void gpu_batch_presets_init(void) +{ + if (g_presets_3d.format.attrib_ct == 0) { + Gwn_VertFormat *format = &g_presets_3d.format; + g_presets_3d.attr_id.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + g_presets_3d.attr_id.nor = GWN_vertformat_attr_add(format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + } + + /* Hard coded resolution */ + g_presets_3d.batch.sphere_low = batch_sphere(8, 16); + g_presets_3d.batch.sphere_med = batch_sphere(16, 10); + g_presets_3d.batch.sphere_high = batch_sphere(32, 24); + + g_presets_3d.batch.sphere_wire_low = batch_sphere_wire(6, 8); + g_presets_3d.batch.sphere_wire_med = batch_sphere_wire(8, 16); +} + +void gpu_batch_presets_exit(void) +{ + GWN_batch_discard(g_presets_3d.batch.sphere_low); + GWN_batch_discard(g_presets_3d.batch.sphere_med); + GWN_batch_discard(g_presets_3d.batch.sphere_high); + GWN_batch_discard(g_presets_3d.batch.sphere_wire_low); + GWN_batch_discard(g_presets_3d.batch.sphere_wire_med); +} diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index d6e01b6765a..d0efee79ab0 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -35,8 +35,6 @@ #include <stddef.h> #include <string.h> -#include "GPU_glew.h" - #include "MEM_guardedalloc.h" #include "BLI_bitmap.h" @@ -55,10 +53,14 @@ #include "GPU_buffers.h" #include "GPU_draw.h" -#include "GPU_basic_shader.h" +#include "GPU_immediate.h" +#include "GPU_batch.h" #include "bmesh.h" +/* TODO: gawain support for baseelemarray */ +// #define USE_BASE_ELEM + typedef enum { GPU_BUFFER_VERTEX_STATE = (1 << 0), GPU_BUFFER_NORMAL_STATE = (1 << 1), @@ -106,9 +108,8 @@ static ThreadMutex buffer_mutex = BLI_MUTEX_INITIALIZER; /* multires global buffer, can be used for many grids having the same grid size */ typedef struct GridCommonGPUBuffer { - GPUBuffer *mres_buffer; + Gwn_IndexBuf *mres_buffer; int mres_prev_gridsize; - GLenum mres_prev_index_type; unsigned mres_prev_totquad; } GridCommonGPUBuffer; @@ -943,26 +944,12 @@ void GPU_buffer_draw_elements(GPUBuffer *UNUSED(elements), unsigned int mode, in /* XXX: the rest of the code in this file is used for optimized PBVH * drawing and doesn't interact at all with the buffer code above */ -/* Convenience struct for building the VBO. */ -typedef struct { - float co[3]; - short no[3]; - - /* inserting this to align the 'color' field to a four-byte - * boundary; drastically increases viewport performance on my - * drivers (Gallium/Radeon) --nicholasbishop */ - char pad[2]; - - unsigned char color[3]; -} VertexBufferFormat; - struct GPU_PBVH_Buffers { - /* opengl buffer handles */ - GPUBuffer *vert_buf, *index_buf, *index_buf_fast; - GLenum index_type; + Gwn_IndexBuf *index_buf, *index_buf_fast; + Gwn_VertBuf *vert_buf; - int *baseelemarray; - void **baseindex; + Gwn_Batch *triangles; + Gwn_Batch *triangles_fast; /* mesh pointers in case buffer allocation fails */ const MPoly *mpoly; @@ -999,6 +986,39 @@ struct GPU_PBVH_Buffers { float diffuse_color[4]; }; +typedef struct { + uint pos, nor, col; +} VertexBufferAttrID; + +static void gpu_pbvh_vert_format_init__gwn(Gwn_VertFormat *format, VertexBufferAttrID *vbo_id) +{ + vbo_id->pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + vbo_id->nor = GWN_vertformat_attr_add(format, "nor", GWN_COMP_I16, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); + vbo_id->col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); +} + +static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers) +{ + /* force flushing to the GPU */ + if (buffers->vert_buf->data) { + GWN_vertbuf_use(buffers->vert_buf); + } + + GWN_BATCH_DISCARD_SAFE(buffers->triangles); + buffers->triangles = GWN_batch_create( + GWN_PRIM_TRIS, buffers->vert_buf, + /* can be NULL */ + buffers->index_buf); + + GWN_BATCH_DISCARD_SAFE(buffers->triangles_fast); + if (buffers->index_buf_fast) { + buffers->triangles_fast = GWN_batch_create( + GWN_PRIM_TRIS, buffers->vert_buf, + /* can be NULL */ + buffers->index_buf_fast); + } +} + static float gpu_color_from_mask(float mask) { return 1.0f - mask * 0.75f; @@ -1040,8 +1060,6 @@ void GPU_pbvh_mesh_buffers_update( { const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0; const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; - VertexBufferFormat *vert_data; - int i; buffers->vmask = vmask; buffers->show_diffuse_color = show_diffuse_color; @@ -1067,35 +1085,39 @@ void GPU_pbvh_mesh_buffers_update( rgba_float_to_uchar(diffuse_color_ub, diffuse_color); /* Build VBO */ - if (buffers->vert_buf) - GPU_buffer_free(buffers->vert_buf); - buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totelem); - vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY); + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + + /* match 'VertexBufferFormat' */ + Gwn_VertFormat format = {0}; + VertexBufferAttrID vbo_id; + gpu_pbvh_vert_format_init__gwn(&format, &vbo_id); + + buffers->vert_buf = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(buffers->vert_buf, totelem); - if (vert_data) { + if (buffers->vert_buf->data) { /* Vertex data is shared if smooth-shaded, but separate * copies are made for flat shading because normals * shouldn't be shared. */ if (buffers->smooth) { - for (i = 0; i < totvert; ++i) { + for (uint i = 0; i < totvert; ++i) { const MVert *v = &mvert[vert_indices[i]]; - VertexBufferFormat *out = vert_data + i; - - copy_v3_v3(out->co, v->co); - memcpy(out->no, v->no, sizeof(short) * 3); + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.pos, i, v->co); + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.nor, i, v->no); } - for (i = 0; i < buffers->face_indices_len; i++) { + for (uint i = 0; i < buffers->face_indices_len; i++) { const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; for (uint j = 0; j < 3; j++) { - VertexBufferFormat *out = vert_data + face_vert_indices[i][j]; - + int vidx = face_vert_indices[i][j]; if (vmask && show_mask) { - uint v_index = buffers->mloop[lt->tri[j]].v; - gpu_color_from_mask_copy(vmask[v_index], diffuse_color, out->color); + int v_index = buffers->mloop[lt->tri[j]].v; + uchar color_ub[3]; + gpu_color_from_mask_copy(vmask[v_index], diffuse_color, color_ub); + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vidx, color_ub); } else { - copy_v3_v3_uchar(out->color, diffuse_color_ub); + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vidx, diffuse_color_ub); } } } @@ -1104,8 +1126,9 @@ void GPU_pbvh_mesh_buffers_update( /* calculate normal for each polygon only once */ unsigned int mpoly_prev = UINT_MAX; short no[3]; + int vbo_index = 0; - for (i = 0; i < buffers->face_indices_len; ++i) { + for (uint i = 0; i < buffers->face_indices_len; i++) { const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; const unsigned int vtri[3] = { buffers->mloop[lt->tri[0]].v, @@ -1136,22 +1159,20 @@ void GPU_pbvh_mesh_buffers_update( for (uint j = 0; j < 3; j++) { const MVert *v = &mvert[vtri[j]]; - VertexBufferFormat *out = vert_data; - copy_v3_v3(out->co, v->co); - copy_v3_v3_short(out->no, no); - copy_v3_v3_uchar(out->color, color_ub); + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.pos, vbo_index, v->co); + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.nor, vbo_index, no); + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub); - vert_data++; + vbo_index++; } } } - GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY); + gpu_pbvh_batch_init(buffers); } else { - GPU_buffer_free(buffers->vert_buf); - buffers->vert_buf = NULL; + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); } } @@ -1166,12 +1187,17 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build( const int face_indices_len) { GPU_PBVH_Buffers *buffers; - unsigned short *tri_data; - int i, j, tottri; + int i, tottri; buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); - buffers->index_type = GL_UNSIGNED_SHORT; + + /* smooth or flat for all */ +#if 0 buffers->smooth = mpoly[looptri[face_indices[0]].poly].flag & ME_SMOOTH; +#else + /* for DrawManager we dont support mixed smooth/flat */ + buffers->smooth = (mpoly[0].flag & ME_SMOOTH) != 0; +#endif buffers->show_diffuse_color = false; buffers->show_mask = true; @@ -1200,35 +1226,28 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build( * shading requires separate vertex normals so an index buffer is * can't be used there. */ if (buffers->smooth) { - buffers->index_buf = GPU_buffer_alloc(sizeof(unsigned short) * tottri * 3); - buffers->is_index_buf_global = false; - } - - if (buffers->index_buf) { /* Fill the triangle buffer */ - tri_data = GPU_buffer_lock(buffers->index_buf, GPU_BINDING_INDEX); - if (tri_data) { - for (i = 0; i < face_indices_len; ++i) { - const MLoopTri *lt = &looptri[face_indices[i]]; - - /* Skip hidden faces */ - if (paint_is_face_hidden(lt, mvert, mloop)) - continue; - - for (j = 0; j < 3; ++j) { - *tri_data = face_vert_indices[i][j]; - tri_data++; - } - } - GPU_buffer_unlock(buffers->index_buf, GPU_BINDING_INDEX); + buffers->index_buf = NULL; + Gwn_IndexBufBuilder elb; + GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tottri, INT_MAX); + + for (i = 0; i < face_indices_len; ++i) { + const MLoopTri *lt = &looptri[face_indices[i]]; + + /* Skip hidden faces */ + if (paint_is_face_hidden(lt, mvert, mloop)) + continue; + + GWN_indexbuf_add_tri_verts(&elb, UNPACK3(face_vert_indices[i])); } - else { - if (!buffers->is_index_buf_global) { - GPU_buffer_free(buffers->index_buf); - } - buffers->index_buf = NULL; - buffers->is_index_buf_global = false; + buffers->index_buf = GWN_indexbuf_build(&elb); + } + else { + if (!buffers->is_index_buf_global) { + GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf); } + buffers->index_buf = NULL; + buffers->is_index_buf_global = false; } buffers->tot_tri = tottri; @@ -1251,7 +1270,6 @@ void GPU_pbvh_grid_buffers_update( { const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0; const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; - VertexBufferFormat *vert_data; int i, j, k, x, y; buffers->show_diffuse_color = show_diffuse_color; @@ -1260,12 +1278,13 @@ void GPU_pbvh_grid_buffers_update( buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; /* Build VBO */ - if (buffers->vert_buf) { + if (buffers->index_buf) { const int has_mask = key->has_mask; float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; - if (buffers->use_matcaps) + if (buffers->use_matcaps) { diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0; + } else if (show_diffuse_color) { const DMFlagMat *flags = &grid_flag_mats[grid_indices[0]]; @@ -1274,38 +1293,48 @@ void GPU_pbvh_grid_buffers_update( copy_v4_v4(buffers->diffuse_color, diffuse_color); - vert_data = GPU_buffer_lock_stream(buffers->vert_buf, GPU_BINDING_ARRAY); - if (vert_data) { + Gwn_VertFormat format = {0}; + VertexBufferAttrID vbo_id; + gpu_pbvh_vert_format_init__gwn(&format, &vbo_id); + + /* Build coord/normal VBO */ + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + buffers->vert_buf = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(buffers->vert_buf, totgrid * key->grid_area); + + uint vbo_index_offset = 0; + if (buffers->vert_buf->data) { for (i = 0; i < totgrid; ++i) { - VertexBufferFormat *vd = vert_data; CCGElem *grid = grids[grid_indices[i]]; + int vbo_index = vbo_index_offset; for (y = 0; y < key->grid_size; y++) { for (x = 0; x < key->grid_size; x++) { CCGElem *elem = CCG_grid_elem(key, grid, x, y); - - copy_v3_v3(vd->co, CCG_elem_co(key, elem)); + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.pos, vbo_index, CCG_elem_co(key, elem)); + if (buffers->smooth) { - normal_float_to_short_v3(vd->no, CCG_elem_no(key, elem)); + short no_short[3]; + normal_float_to_short_v3(no_short, CCG_elem_no(key, elem)); + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.nor, vbo_index, no_short); if (has_mask) { + uchar color_ub[3]; if (show_mask) { gpu_color_from_mask_copy(*CCG_elem_mask(key, elem), - diffuse_color, vd->color); + diffuse_color, color_ub); } else { - F3TOCHAR3(diffuse_color, vd->color); + F3TOCHAR3(diffuse_color, color_ub); } + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub); } } - vd++; + vbo_index += 1; } } if (!buffers->smooth) { - /* for flat shading, recalc normals and set the last vertex of - * each triangle in the index buffer to have the flat normal as - * that is what opengl will use */ for (j = 0; j < key->grid_size - 1; j++) { for (k = 0; k < key->grid_size - 1; k++) { CCGElem *elems[4] = { @@ -1322,10 +1351,13 @@ void GPU_pbvh_grid_buffers_update( CCG_elem_co(key, elems[2]), CCG_elem_co(key, elems[3])); - vd = vert_data + (j + 1) * key->grid_size + k; - normal_float_to_short_v3(vd->no, fno); + vbo_index = vbo_index_offset + ((j + 1) * key->grid_size + k); + short no_short[3]; + normal_float_to_short_v3(no_short, fno); + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.nor, vbo_index, no_short); if (has_mask) { + uchar color_ub[3]; if (show_mask) { gpu_color_from_mask_quad_copy(key, elems[0], @@ -1333,24 +1365,24 @@ void GPU_pbvh_grid_buffers_update( elems[2], elems[3], diffuse_color, - vd->color); + color_ub); } else { - F3TOCHAR3(diffuse_color, vd->color); + F3TOCHAR3(diffuse_color, color_ub); } + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub); } } } } - vert_data += key->grid_area; + vbo_index_offset += key->grid_area; } - GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY); + gpu_pbvh_batch_init(buffers); } else { - GPU_buffer_free(buffers->vert_buf); - buffers->vert_buf = NULL; + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); } } @@ -1365,57 +1397,54 @@ void GPU_pbvh_grid_buffers_update( /* Build the element array buffer of grid indices using either * unsigned shorts or unsigned ints. */ -#define FILL_QUAD_BUFFER(type_, tot_quad_, buffer_) \ +#define FILL_QUAD_BUFFER(max_vert_, tot_quad_, buffer_) \ { \ - type_ *tri_data; \ int offset = 0; \ int i, j, k; \ - buffer_ = GPU_buffer_alloc(sizeof(type_) * (tot_quad_) * 6); \ + \ + Gwn_IndexBufBuilder elb; \ + GWN_indexbuf_init( \ + &elb, GWN_PRIM_TRIS, tot_quad_ * 2, max_vert_); \ \ /* Fill the buffer */ \ - tri_data = GPU_buffer_lock(buffer_, GPU_BINDING_INDEX); \ - if (tri_data) { \ - for (i = 0; i < totgrid; ++i) { \ - BLI_bitmap *gh = NULL; \ - if (grid_hidden) \ - gh = grid_hidden[(grid_indices)[i]]; \ + for (i = 0; i < totgrid; ++i) { \ + BLI_bitmap *gh = NULL; \ + if (grid_hidden) \ + gh = grid_hidden[(grid_indices)[i]]; \ \ - for (j = 0; j < gridsize - 1; ++j) { \ - for (k = 0; k < gridsize - 1; ++k) { \ - /* Skip hidden grid face */ \ - if (gh && \ - paint_is_grid_face_hidden(gh, \ - gridsize, k, j)) \ - continue; \ - \ - *(tri_data++) = offset + j * gridsize + k + 1; \ - *(tri_data++) = offset + j * gridsize + k; \ - *(tri_data++) = offset + (j + 1) * gridsize + k; \ - \ - *(tri_data++) = offset + (j + 1) * gridsize + k + 1; \ - *(tri_data++) = offset + j * gridsize + k + 1; \ - *(tri_data++) = offset + (j + 1) * gridsize + k; \ - } \ - } \ - \ - offset += gridsize * gridsize; \ + for (j = 0; j < gridsize - 1; ++j) { \ + for (k = 0; k < gridsize - 1; ++k) { \ + /* Skip hidden grid face */ \ + if (gh && paint_is_grid_face_hidden( \ + gh, gridsize, k, j)) \ + { \ + continue; \ + } \ + GWN_indexbuf_add_generic_vert(&elb, offset + j * gridsize + k + 1); \ + GWN_indexbuf_add_generic_vert(&elb, offset + j * gridsize + k); \ + GWN_indexbuf_add_generic_vert(&elb, offset + (j + 1) * gridsize + k); \ + \ + GWN_indexbuf_add_generic_vert(&elb, offset + (j + 1) * gridsize + k + 1); \ + GWN_indexbuf_add_generic_vert(&elb, offset + j * gridsize + k + 1); \ + GWN_indexbuf_add_generic_vert(&elb, offset + (j + 1) * gridsize + k); \ + } \ } \ - GPU_buffer_unlock(buffer_, GPU_BINDING_INDEX); \ - } \ - else { \ - GPU_buffer_free(buffer_); \ - (buffer_) = NULL; \ + \ + offset += gridsize * gridsize; \ } \ + buffer_ = GWN_indexbuf_build(&elb); \ } (void)0 /* end FILL_QUAD_BUFFER */ -static GPUBuffer *gpu_get_grid_buffer( - int gridsize, GLenum *index_type, unsigned *totquad, GridCommonGPUBuffer **grid_common_gpu_buffer) +static Gwn_IndexBuf *gpu_get_grid_buffer( + int gridsize, unsigned *totquad, GridCommonGPUBuffer **grid_common_gpu_buffer, + /* remove this arg when gawain gets base-vertex support! */ + int totgrid) { /* used in the FILL_QUAD_BUFFER macro */ BLI_bitmap * const *grid_hidden = NULL; const int *grid_indices = NULL; - int totgrid = 1; + // int totgrid = 1; GridCommonGPUBuffer *gridbuff = *grid_common_gpu_buffer; @@ -1423,65 +1452,48 @@ static GPUBuffer *gpu_get_grid_buffer( *grid_common_gpu_buffer = gridbuff = MEM_mallocN(sizeof(GridCommonGPUBuffer), __func__); gridbuff->mres_buffer = NULL; gridbuff->mres_prev_gridsize = -1; - gridbuff->mres_prev_index_type = 0; gridbuff->mres_prev_totquad = 0; } /* VBO is already built */ if (gridbuff->mres_buffer && gridbuff->mres_prev_gridsize == gridsize) { - *index_type = gridbuff->mres_prev_index_type; *totquad = gridbuff->mres_prev_totquad; return gridbuff->mres_buffer; } /* we can't reuse old, delete the existing buffer */ else if (gridbuff->mres_buffer) { - GPU_buffer_free(gridbuff->mres_buffer); + GWN_indexbuf_discard(gridbuff->mres_buffer); + gridbuff->mres_buffer = NULL; } /* Build new VBO */ - *totquad = (gridsize - 1) * (gridsize - 1); + *totquad = (gridsize - 1) * (gridsize - 1) * totgrid; + int max_vert = gridsize * gridsize * totgrid; - if (gridsize * gridsize < USHRT_MAX) { - *index_type = GL_UNSIGNED_SHORT; - FILL_QUAD_BUFFER(unsigned short, *totquad, gridbuff->mres_buffer); - } - else { - *index_type = GL_UNSIGNED_INT; - FILL_QUAD_BUFFER(unsigned int, *totquad, gridbuff->mres_buffer); - } + FILL_QUAD_BUFFER(max_vert, *totquad, gridbuff->mres_buffer); gridbuff->mres_prev_gridsize = gridsize; - gridbuff->mres_prev_index_type = *index_type; gridbuff->mres_prev_totquad = *totquad; return gridbuff->mres_buffer; } -#define FILL_FAST_BUFFER(type_) \ +#define FILL_FAST_BUFFER() \ { \ - type_ *buffer; \ - buffers->index_buf_fast = GPU_buffer_alloc(sizeof(type_) * 6 * totgrid); \ - buffer = GPU_buffer_lock(buffers->index_buf_fast, GPU_BINDING_INDEX); \ - if (buffer) { \ - int i; \ - for (i = 0; i < totgrid; i++) { \ - int currentquad = i * 6; \ - buffer[currentquad] = i * gridsize * gridsize + gridsize - 1; \ - buffer[currentquad + 1] = i * gridsize * gridsize; \ - buffer[currentquad + 2] = (i + 1) * gridsize * gridsize - gridsize; \ - buffer[currentquad + 3] = (i + 1) * gridsize * gridsize - 1; \ - buffer[currentquad + 4] = i * gridsize * gridsize + gridsize - 1; \ - buffer[currentquad + 5] = (i + 1) * gridsize * gridsize - gridsize; \ - } \ - GPU_buffer_unlock(buffers->index_buf_fast, GPU_BINDING_INDEX); \ - } \ - else { \ - GPU_buffer_free(buffers->index_buf_fast); \ - buffers->index_buf_fast = NULL; \ + Gwn_IndexBufBuilder elb; \ + GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, 6 * totgrid, INT_MAX); \ + for (int i = 0; i < totgrid; i++) { \ + GWN_indexbuf_add_generic_vert(&elb, i * gridsize * gridsize + gridsize - 1); \ + GWN_indexbuf_add_generic_vert(&elb, i * gridsize * gridsize); \ + GWN_indexbuf_add_generic_vert(&elb, (i + 1) * gridsize * gridsize - gridsize); \ + GWN_indexbuf_add_generic_vert(&elb, (i + 1) * gridsize * gridsize - 1); \ + GWN_indexbuf_add_generic_vert(&elb, i * gridsize * gridsize + gridsize - 1); \ + GWN_indexbuf_add_generic_vert(&elb, (i + 1) * gridsize * gridsize - gridsize); \ } \ + buffers->index_buf_fast = GWN_indexbuf_build(&elb); \ } (void)0 GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build( - int *grid_indices, int totgrid, BLI_bitmap **grid_hidden, int gridsize, const CCGKey *key, + int *grid_indices, int totgrid, BLI_bitmap **grid_hidden, int gridsize, const CCGKey *UNUSED(key), GridCommonGPUBuffer **grid_common_gpu_buffer) { GPU_PBVH_Buffers *buffers; @@ -1504,39 +1516,26 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build( return buffers; /* create and fill indices of the fast buffer too */ - if (totgrid * gridsize * gridsize < USHRT_MAX) { - FILL_FAST_BUFFER(unsigned short); - } - else { - FILL_FAST_BUFFER(unsigned int); - } + FILL_FAST_BUFFER(); if (totquad == fully_visible_totquad) { buffers->index_buf = gpu_get_grid_buffer( - gridsize, &buffers->index_type, &buffers->tot_quad, grid_common_gpu_buffer); + gridsize, &buffers->tot_quad, grid_common_gpu_buffer, totgrid); buffers->has_hidden = false; buffers->is_index_buf_global = true; } else { + uint max_vert = totgrid * gridsize * gridsize; buffers->tot_quad = totquad; - if (totgrid * gridsize * gridsize < USHRT_MAX) { - buffers->index_type = GL_UNSIGNED_SHORT; - FILL_QUAD_BUFFER(unsigned short, totquad, buffers->index_buf); - } - else { - buffers->index_type = GL_UNSIGNED_INT; - FILL_QUAD_BUFFER(unsigned int, totquad, buffers->index_buf); - } + FILL_QUAD_BUFFER(max_vert, totquad, buffers->index_buf); - buffers->has_hidden = true; + buffers->has_hidden = false; buffers->is_index_buf_global = false; } +#ifdef USE_BASE_ELEM /* Build coord/normal VBO */ - if (buffers->index_buf) - buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totgrid * key->grid_area); - if (GLEW_ARB_draw_elements_base_vertex /* 3.2 */) { int i; buffers->baseelemarray = MEM_mallocN(sizeof(int) * totgrid * 2, "GPU_PBVH_Buffers.baseelemarray"); @@ -1547,6 +1546,7 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build( buffers->baseindex[i] = NULL; } } +#endif return buffers; } @@ -1559,32 +1559,45 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build( * index '*v_index' in the 'vert_data' array and '*v_index' is * incremented. */ -static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, - VertexBufferFormat *vert_data, - int *v_index, - const float fno[3], - const float *fmask, - const int cd_vert_mask_offset, - const float diffuse_color[4], - const bool show_mask) +static void gpu_bmesh_vert_to_buffer_copy__gwn( + BMVert *v, + Gwn_VertBuf *vert_buf, + const VertexBufferAttrID *vbo_id, + int *v_index, + const float fno[3], + const float *fmask, + const int cd_vert_mask_offset, + const float diffuse_color[4], + const bool show_mask) { if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { - VertexBufferFormat *vd = &vert_data[*v_index]; /* Set coord, normal, and mask */ - copy_v3_v3(vd->co, v->co); - normal_float_to_short_v3(vd->no, fno ? fno : v->no); + GWN_vertbuf_attr_set(vert_buf, vbo_id->pos, *v_index, v->co); - float effective_mask; - if (show_mask) { - effective_mask = fmask ? *fmask - : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); - } - else { - effective_mask = 0.0f; + { + short no_short[3]; + normal_float_to_short_v3(no_short, fno ? fno : v->no); + GWN_vertbuf_attr_set(vert_buf, vbo_id->nor, *v_index, no_short); } - gpu_color_from_mask_copy(effective_mask, diffuse_color, vd->color); + { + uchar color_ub[3]; + float effective_mask; + if (show_mask) { + effective_mask = fmask ? *fmask + : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); + } + else { + effective_mask = 0.0f; + } + + gpu_color_from_mask_copy( + effective_mask, + diffuse_color, + color_ub); + GWN_vertbuf_attr_set(vert_buf, vbo_id->col, *v_index, color_ub); + } /* Assign index for use in the triangle index buffer */ /* note: caller must set: bm->elem_index_dirty |= BM_VERT; */ @@ -1643,8 +1656,6 @@ void GPU_pbvh_bmesh_buffers_update( { const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0; const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; - VertexBufferFormat *vert_data; - void *tri_data; int tottri, totvert, maxvert = 0; float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; @@ -1684,13 +1695,17 @@ void GPU_pbvh_bmesh_buffers_update( copy_v4_v4(buffers->diffuse_color, diffuse_color); /* Initialize vertex buffer */ - if (buffers->vert_buf) - GPU_buffer_free(buffers->vert_buf); - buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totvert); + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + /* match 'VertexBufferFormat' */ + Gwn_VertFormat format = {0}; + VertexBufferAttrID vbo_id; + gpu_pbvh_vert_format_init__gwn(&format, &vbo_id); + + buffers->vert_buf = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(buffers->vert_buf, totvert); /* Fill vertex buffer */ - vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY); - if (vert_data) { + if (buffers->vert_buf->data) { int v_index = 0; if (buffers->smooth) { @@ -1701,17 +1716,19 @@ void GPU_pbvh_bmesh_buffers_update( bm->elem_index_dirty |= BM_VERT; GSET_ITER (gs_iter, bm_unique_verts) { - gpu_bmesh_vert_to_buffer_copy(BLI_gsetIterator_getKey(&gs_iter), - vert_data, &v_index, NULL, NULL, - cd_vert_mask_offset, diffuse_color, - show_mask); + gpu_bmesh_vert_to_buffer_copy__gwn( + BLI_gsetIterator_getKey(&gs_iter), + buffers->vert_buf, &vbo_id, &v_index, NULL, NULL, + cd_vert_mask_offset, diffuse_color, + show_mask); } GSET_ITER (gs_iter, bm_other_verts) { - gpu_bmesh_vert_to_buffer_copy(BLI_gsetIterator_getKey(&gs_iter), - vert_data, &v_index, NULL, NULL, - cd_vert_mask_offset, diffuse_color, - show_mask); + gpu_bmesh_vert_to_buffer_copy__gwn( + BLI_gsetIterator_getKey(&gs_iter), + buffers->vert_buf, &vbo_id, &v_index, NULL, NULL, + cd_vert_mask_offset, diffuse_color, + show_mask); } maxvert = v_index; @@ -1741,10 +1758,11 @@ void GPU_pbvh_bmesh_buffers_update( fmask /= 3.0f; for (i = 0; i < 3; i++) { - gpu_bmesh_vert_to_buffer_copy(v[i], vert_data, - &v_index, f->no, &fmask, - cd_vert_mask_offset, diffuse_color, - show_mask); + gpu_bmesh_vert_to_buffer_copy__gwn( + v[i], buffers->vert_buf, &vbo_id, + &v_index, f->no, &fmask, + cd_vert_mask_offset, diffuse_color, + show_mask); } } } @@ -1752,32 +1770,30 @@ void GPU_pbvh_bmesh_buffers_update( buffers->tot_tri = tottri; } - GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY); - /* gpu_bmesh_vert_to_buffer_copy sets dirty index values */ bm->elem_index_dirty |= BM_VERT; } else { + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); /* Memory map failed */ - GPU_buffer_free(buffers->vert_buf); - buffers->vert_buf = NULL; return; } if (buffers->smooth) { - const int use_short = (maxvert < USHRT_MAX); + /* Fill the triangle buffer */ + buffers->index_buf = NULL; + Gwn_IndexBufBuilder elb; + GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tottri, maxvert); /* Initialize triangle index buffer */ - if (buffers->index_buf && !buffers->is_index_buf_global) - GPU_buffer_free(buffers->index_buf); + if (buffers->triangles && !buffers->is_index_buf_global) { + GWN_BATCH_DISCARD_SAFE(buffers->triangles); + } buffers->is_index_buf_global = false; - buffers->index_buf = GPU_buffer_alloc((use_short ? - sizeof(unsigned short) : - sizeof(unsigned int)) * 3 * tottri); /* Fill triangle index buffer */ - tri_data = GPU_buffer_lock(buffers->index_buf, GPU_BINDING_INDEX); - if (tri_data) { + + { GSetIterator gs_iter; GSET_ITER (gs_iter, bm_faces) { @@ -1789,46 +1805,25 @@ void GPU_pbvh_bmesh_buffers_update( l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - BMVert *v = l_iter->v; - if (use_short) { - unsigned short *elem = tri_data; - (*elem) = BM_elem_index_get(v); - elem++; - tri_data = elem; - } - else { - unsigned int *elem = tri_data; - (*elem) = BM_elem_index_get(v); - elem++; - tri_data = elem; - } + GWN_indexbuf_add_generic_vert(&elb, BM_elem_index_get(l_iter->v)); } while ((l_iter = l_iter->next) != l_first); } } - GPU_buffer_unlock(buffers->index_buf, GPU_BINDING_INDEX); - buffers->tot_tri = tottri; - buffers->index_type = (use_short ? - GL_UNSIGNED_SHORT : - GL_UNSIGNED_INT); - } - else { - /* Memory map failed */ - if (!buffers->is_index_buf_global) { - GPU_buffer_free(buffers->index_buf); - } - buffers->index_buf = NULL; - buffers->is_index_buf_global = false; + + buffers->index_buf = GWN_indexbuf_build(&elb); } } else if (buffers->index_buf) { if (!buffers->is_index_buf_global) { - GPU_buffer_free(buffers->index_buf); + GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf); } buffers->index_buf = NULL; buffers->is_index_buf_global = false; } + + gpu_pbvh_batch_init(buffers); } GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading) @@ -1849,145 +1844,42 @@ void GPU_pbvh_buffers_draw( GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, bool wireframe, bool fast) { - bool do_fast = fast && buffers->index_buf_fast; - /* sets material from the first face, to solve properly face would need to - * be sorted in buckets by materials */ - if (setMaterial) { - if (buffers->face_indices_len) { - const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]]; - const MPoly *mp = &buffers->mpoly[lt->poly]; - if (!setMaterial(mp->mat_nr + 1, NULL)) - return; - } - else if (buffers->totgrid) { - const DMFlagMat *f = &buffers->grid_flag_mats[buffers->grid_indices[0]]; - if (!setMaterial(f->mat_nr + 1, NULL)) - return; - } - else { - if (!setMaterial(1, NULL)) - return; - } - } - - if (buffers->vert_buf) { - char *base = NULL; - char *index_base = NULL; - /* weak inspection of bound options, should not be necessary ideally */ - const int bound_options_old = GPU_basic_shader_bound_options(); - int bound_options_new = 0; - glEnableClientState(GL_VERTEX_ARRAY); - if (!wireframe) { - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - bound_options_new |= GPU_SHADER_USE_COLOR; - } - - GPU_buffer_bind(buffers->vert_buf, GPU_BINDING_ARRAY); - - if (do_fast) { - GPU_buffer_bind(buffers->index_buf_fast, GPU_BINDING_INDEX); - } - else if (buffers->index_buf) { - GPU_buffer_bind(buffers->index_buf, GPU_BINDING_INDEX); - } - - if (wireframe) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } - else { - if ((buffers->smooth == false) && (buffers->face_indices_len == 0)) { - bound_options_new |= GPU_SHADER_FLAT_NORMAL; - } - } - - if (bound_options_new & ~bound_options_old) { - GPU_basic_shader_bind(bound_options_old | bound_options_new); - } - - if (buffers->tot_quad) { - const char *offset = base; - const bool drawall = !(buffers->has_hidden || do_fast); - - if (GLEW_ARB_draw_elements_base_vertex && drawall) { - - glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), - offset + offsetof(VertexBufferFormat, co)); - if (!wireframe) { - glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), - offset + offsetof(VertexBufferFormat, no)); - glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), - offset + offsetof(VertexBufferFormat, color)); - } - - glMultiDrawElementsBaseVertex(GL_TRIANGLES, buffers->baseelemarray, buffers->index_type, - (const void * const *)buffers->baseindex, - buffers->totgrid, &buffers->baseelemarray[buffers->totgrid]); - } - else { - int i, last = drawall ? buffers->totgrid : 1; - - /* we could optimize this to one draw call, but it would need more memory */ - for (i = 0; i < last; i++) { - glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), - offset + offsetof(VertexBufferFormat, co)); - if (!wireframe) { - glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), - offset + offsetof(VertexBufferFormat, no)); - glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), - offset + offsetof(VertexBufferFormat, color)); - } + UNUSED_VARS(wireframe, fast, setMaterial); + bool do_fast = fast && buffers->triangles_fast; + Gwn_Batch *triangles = do_fast ? buffers->triangles_fast : buffers->triangles; - if (do_fast) - glDrawElements(GL_TRIANGLES, buffers->totgrid * 6, buffers->index_type, index_base); - else - glDrawElements(GL_TRIANGLES, buffers->tot_quad * 6, buffers->index_type, index_base); + if (triangles) { - offset += buffers->gridkey.grid_area * sizeof(VertexBufferFormat); - } - } - } - else if (buffers->tot_tri) { - int totelem = buffers->tot_tri * 3; - - glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), - (void *)(base + offsetof(VertexBufferFormat, co))); - - if (!wireframe) { - glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), - (void *)(base + offsetof(VertexBufferFormat, no))); - glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), - (void *)(base + offsetof(VertexBufferFormat, color))); - } - - if (buffers->index_buf) - glDrawElements(GL_TRIANGLES, totelem, buffers->index_type, index_base); - else - glDrawArrays(GL_TRIANGLES, 0, totelem); - } + /* Simple Shader: use when drawing without the draw-manager (old 2.7x viewport) */ + if (triangles->interface == NULL) { + GPUBuiltinShader shader_id = + buffers->smooth ? GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR : GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR; + GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); - if (wireframe) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + GWN_batch_program_set( + triangles, + GPU_shader_get_program(shader), GPU_shader_get_interface(shader)); - GPU_buffer_unbind(buffers->vert_buf, GPU_BINDING_ARRAY); - if (buffers->index_buf || do_fast) - GPU_buffer_unbind(do_fast ? buffers->index_buf_fast : buffers->index_buf, GPU_BINDING_INDEX); + static float light[3] = {-0.3f, 0.5f, 1.0f}; + static float alpha = 1.0f; + static float world_light = 1.0f; - glDisableClientState(GL_VERTEX_ARRAY); - if (!wireframe) { - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - } + GPU_shader_uniform_vector(shader, GPU_shader_get_uniform(shader, "light"), 3, 1, light); + GPU_shader_uniform_vector(shader, GPU_shader_get_uniform(shader, "alpha"), 1, 1, &alpha); + GPU_shader_uniform_vector(shader, GPU_shader_get_uniform(shader, "global"), 1, 1, &world_light); - if (bound_options_new & ~bound_options_old) { - GPU_basic_shader_bind(bound_options_old); } + GWN_batch_draw(triangles); } } -bool GPU_pbvh_buffers_diffuse_changed( - GPU_PBVH_Buffers *buffers, GSet *bm_faces, bool show_diffuse_color) +Gwn_Batch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast) +{ + return (fast && buffers->triangles_fast) ? + buffers->triangles_fast : buffers->triangles; +} + +bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, bool show_diffuse_color) { float diffuse_color[4]; bool use_matcaps = GPU_material_use_matcaps_get(); @@ -2038,16 +1930,20 @@ bool GPU_pbvh_buffers_mask_changed(GPU_PBVH_Buffers *buffers, bool show_mask) void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers) { if (buffers) { - if (buffers->vert_buf) - GPU_buffer_free(buffers->vert_buf); - if (buffers->index_buf && !buffers->is_index_buf_global) - GPU_buffer_free(buffers->index_buf); - if (buffers->index_buf_fast) - GPU_buffer_free(buffers->index_buf_fast); + GWN_BATCH_DISCARD_SAFE(buffers->triangles); + GWN_BATCH_DISCARD_SAFE(buffers->triangles_fast); + if (!buffers->is_index_buf_global) { + GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf); + } + GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast); + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + +#ifdef USE_BASE_ELEM if (buffers->baseelemarray) MEM_freeN(buffers->baseelemarray); if (buffers->baseindex) MEM_freeN(buffers->baseindex); +#endif MEM_freeN(buffers); } @@ -2060,7 +1956,7 @@ void GPU_pbvh_multires_buffers_free(GridCommonGPUBuffer **grid_common_gpu_buffer if (gridbuff) { if (gridbuff->mres_buffer) { BLI_mutex_lock(&buffer_mutex); - gpu_buffer_free_intern(gridbuff->mres_buffer); + GWN_INDEXBUF_DISCARD_SAFE(gridbuff->mres_buffer); BLI_mutex_unlock(&buffer_mutex); } MEM_freeN(gridbuff); @@ -2069,59 +1965,57 @@ void GPU_pbvh_multires_buffers_free(GridCommonGPUBuffer **grid_common_gpu_buffer } /* debug function, draws the pbvh BB */ -void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf) +void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf, unsigned int pos) { - const float quads[4][4][3] = { - { - {min[0], min[1], min[2]}, - {max[0], min[1], min[2]}, - {max[0], min[1], max[2]}, - {min[0], min[1], max[2]} - }, + if (leaf) + immUniformColor4f(0.0, 1.0, 0.0, 0.5); + else + immUniformColor4f(1.0, 0.0, 0.0, 0.5); - { - {min[0], min[1], min[2]}, - {min[0], max[1], min[2]}, - {min[0], max[1], max[2]}, - {min[0], min[1], max[2]} - }, + /* TODO(merwin): revisit this after we have mutable VertexBuffers + * could keep a static batch & index buffer, change the VBO contents per draw + */ - { - {max[0], max[1], min[2]}, - {max[0], min[1], min[2]}, - {max[0], min[1], max[2]}, - {max[0], max[1], max[2]} - }, + immBegin(GWN_PRIM_LINES, 24); - { - {max[0], max[1], min[2]}, - {min[0], max[1], min[2]}, - {min[0], max[1], max[2]}, - {max[0], max[1], max[2]} - }, - }; + /* top */ + immVertex3f(pos, min[0], min[1], max[2]); + immVertex3f(pos, min[0], max[1], max[2]); - if (leaf) - glColor4f(0.0, 1.0, 0.0, 0.5); - else - glColor4f(1.0, 0.0, 0.0, 0.5); + immVertex3f(pos, min[0], max[1], max[2]); + immVertex3f(pos, max[0], max[1], max[2]); - glVertexPointer(3, GL_FLOAT, 0, &quads[0][0][0]); - glDrawArrays(GL_QUADS, 0, 16); -} + immVertex3f(pos, max[0], max[1], max[2]); + immVertex3f(pos, max[0], min[1], max[2]); -void GPU_pbvh_BB_draw_init(void) -{ - glPushAttrib(GL_ENABLE_BIT); - glDisable(GL_CULL_FACE); - glEnableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glEnable(GL_BLEND); -} + immVertex3f(pos, max[0], min[1], max[2]); + immVertex3f(pos, min[0], min[1], max[2]); -void GPU_pbvh_BB_draw_end(void) -{ - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glPopAttrib(); + /* bottom */ + immVertex3f(pos, min[0], min[1], min[2]); + immVertex3f(pos, min[0], max[1], min[2]); + + immVertex3f(pos, min[0], max[1], min[2]); + immVertex3f(pos, max[0], max[1], min[2]); + + immVertex3f(pos, max[0], max[1], min[2]); + immVertex3f(pos, max[0], min[1], min[2]); + + immVertex3f(pos, max[0], min[1], min[2]); + immVertex3f(pos, min[0], min[1], min[2]); + + /* sides */ + immVertex3f(pos, min[0], min[1], min[2]); + immVertex3f(pos, min[0], min[1], max[2]); + + immVertex3f(pos, min[0], max[1], min[2]); + immVertex3f(pos, min[0], max[1], max[2]); + + immVertex3f(pos, max[0], max[1], min[2]); + immVertex3f(pos, max[0], max[1], max[2]); + + immVertex3f(pos, max[0], min[1], min[2]); + immVertex3f(pos, max[0], min[1], max[2]); + + immEnd(); } diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index b5512aa108d..9e4daa2a036 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -36,6 +36,7 @@ #include "DNA_customdata_types.h" #include "DNA_image_types.h" #include "DNA_material_types.h" +#include "DNA_node_types.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" @@ -47,6 +48,7 @@ #include "GPU_material.h" #include "GPU_shader.h" #include "GPU_texture.h" +#include "GPU_uniformbuffer.h" #include "BLI_sys_types.h" /* for intptr_t support */ @@ -88,7 +90,7 @@ typedef struct GPUFunction { /* Indices match the GPUType enum */ static const char *GPU_DATATYPE_STR[17] = { "", "float", "vec2", "vec3", "vec4", - NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4", + NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4" }; /* GLSL code parsing for finding function definitions. @@ -172,7 +174,7 @@ static void gpu_parse_functions_string(GHash *hash, char *code) /* test for type */ type = GPU_NONE; - for (i = 1; i <= 16; i++) { + for (i = 1; i < ARRAY_SIZE(GPU_DATATYPE_STR); i++) { if (GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) { type = i; break; @@ -188,6 +190,13 @@ static void gpu_parse_functions_string(GHash *hash, char *code) if (!type && gpu_str_prefix(code, "sampler2D")) { type = GPU_TEX2D; } + if (!type && gpu_str_prefix(code, "sampler3D")) { + type = GPU_TEX3D; + } + + if (!type && gpu_str_prefix(code, "Closure")) { + type = GPU_CLOSURE; + } if (type) { /* add parameter */ @@ -350,6 +359,8 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t BLI_dynstr_appendf(ds, "vec4(%s.r, %s.r, %s.r, %s.g)", name, name, name, name); else if (from == GPU_FLOAT) BLI_dynstr_appendf(ds, "vec4(%s, %s, %s, 1.0)", name, name, name); + else /* can happen with closure */ + BLI_dynstr_append(ds, name); } } @@ -412,6 +423,10 @@ const char *GPU_builtin_name(GPUBuiltin builtin) return "unfparticleangvel"; else if (builtin == GPU_OBJECT_INFO) return "unfobjectinfo"; + else if (builtin == GPU_VOLUME_DENSITY) + return "sampdensity"; + else if (builtin == GPU_VOLUME_FLAME) + return "sampflame"; else return ""; } @@ -500,12 +515,16 @@ static void codegen_set_unique_ids(ListBase *nodes) BLI_ghash_free(definehash, NULL, NULL); } -static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes) +/** + * It will create an UBO for GPUMaterial if there is any GPU_DYNAMIC_UBO. + */ +static int codegen_process_uniforms_functions(GPUMaterial *material, DynStr *ds, ListBase *nodes) { GPUNode *node; GPUInput *input; const char *name; int builtins = 0; + ListBase ubo_inputs = {NULL, NULL}; /* print uniforms */ for (node = nodes->first; node; node = node->next) { @@ -525,7 +544,14 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes) builtins |= input->builtin; name = GPU_builtin_name(input->builtin); - if (gpu_str_prefix(name, "unf")) { + if (gpu_str_prefix(name, "samp")) { + if ((input->builtin == GPU_VOLUME_DENSITY) || + (input->builtin == GPU_VOLUME_FLAME)) + { + BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", name); + } + } + else if (gpu_str_prefix(name, "unf")) { BLI_dynstr_appendf(ds, "uniform %s %s;\n", GPU_DATATYPE_STR[input->type], name); } @@ -536,14 +562,23 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes) } } } + else if (input->source == GPU_SOURCE_STRUCT) { + /* Add other struct here if needed. */ + BLI_dynstr_appendf(ds, "Closure strct%d = CLOSURE_DEFAULT;\n", input->id); + } else if (input->source == GPU_SOURCE_VEC_UNIFORM) { - if (input->dynamicvec) { + if (input->dynamictype == GPU_DYNAMIC_UBO) { + if (!input->link) { + /* We handle the UBOuniforms separately. */ + BLI_addtail(&ubo_inputs, BLI_genericNodeN(input)); + } + } + else if (input->dynamicvec) { /* only create uniforms for dynamic vectors */ BLI_dynstr_appendf(ds, "uniform %s unf%d;\n", GPU_DATATYPE_STR[input->type], input->id); } else { - /* for others use const so the compiler can do folding */ BLI_dynstr_appendf(ds, "const %s cons%d = ", GPU_DATATYPE_STR[input->type], input->id); codegen_print_datatype(ds, input->type, input->vec); @@ -569,6 +604,22 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes) } } + /* Handle the UBO block separately. */ + if ((material != NULL) && !BLI_listbase_is_empty(&ubo_inputs)) { + GPU_material_create_uniform_buffer(material, &ubo_inputs); + + /* Inputs are sorted */ + BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME); + + for (LinkData *link = ubo_inputs.first; link; link = link->next) { + input = link->data; + BLI_dynstr_appendf(ds, "\t%s unf%d;\n", + GPU_DATATYPE_STR[input->type], input->id); + } + BLI_dynstr_append(ds, "};\n"); + BLI_freelistN(&ubo_inputs); + } + BLI_dynstr_append(ds, "\n"); return builtins; @@ -594,8 +645,13 @@ static void codegen_declare_tmps(DynStr *ds, ListBase *nodes) /* declare temporary variables for node output storage */ for (output = node->outputs.first; output; output = output->next) { - BLI_dynstr_appendf(ds, "\t%s tmp%d;\n", - GPU_DATATYPE_STR[output->type], output->id); + if (output->type == GPU_CLOSURE) { + BLI_dynstr_appendf(ds, "\tClosure tmp%d;\n", output->id); + } + else { + BLI_dynstr_appendf(ds, "\t%s tmp%d;\n", + GPU_DATATYPE_STR[output->type], output->id); + } } } @@ -622,11 +678,26 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final "tmp", input->link->output->id); } else if (input->source == GPU_SOURCE_BUILTIN) { - if (input->builtin == GPU_VIEW_NORMAL) + if (input->builtin == GPU_INVERSE_VIEW_MATRIX) + BLI_dynstr_append(ds, "viewinv"); + else if (input->builtin == GPU_VIEW_MATRIX) + BLI_dynstr_append(ds, "viewmat"); + else if (input->builtin == GPU_CAMERA_TEXCO_FACTORS) + BLI_dynstr_append(ds, "camtexfac"); + else if (input->builtin == GPU_OBJECT_MATRIX) + BLI_dynstr_append(ds, "objmat"); + else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX) + BLI_dynstr_append(ds, "objinv"); + else if (input->builtin == GPU_VIEW_POSITION) + BLI_dynstr_append(ds, "viewposition"); + else if (input->builtin == GPU_VIEW_NORMAL) BLI_dynstr_append(ds, "facingnormal"); else BLI_dynstr_append(ds, GPU_builtin_name(input->builtin)); } + else if (input->source == GPU_SOURCE_STRUCT) { + BLI_dynstr_appendf(ds, "strct%d", input->id); + } else if (input->source == GPU_SOURCE_VEC_UNIFORM) { if (input->dynamicvec) BLI_dynstr_appendf(ds, "unf%d", input->id); @@ -655,12 +726,11 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final BLI_dynstr_append(ds, ");\n"); } - BLI_dynstr_append(ds, "\n\tgl_FragColor = "); - codegen_convert_datatype(ds, finaloutput->type, GPU_VEC4, "tmp", finaloutput->id); + BLI_dynstr_appendf(ds, "\n\treturn tmp%d", finaloutput->id); BLI_dynstr_append(ds, ";\n"); } -static char *code_generate_fragment(ListBase *nodes, GPUOutput *output) +static char *code_generate_fragment(GPUMaterial *material, ListBase *nodes, GPUOutput *output, bool use_new_shading) { DynStr *ds = BLI_dynstr_new(); char *code; @@ -677,17 +747,47 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output) #endif codegen_set_unique_ids(nodes); - builtins = codegen_print_uniforms_functions(ds, nodes); + builtins = codegen_process_uniforms_functions(material, ds, nodes); #if 0 if (G.debug & G_DEBUG) BLI_dynstr_appendf(ds, "/* %s */\n", name); #endif - BLI_dynstr_append(ds, "void main()\n{\n"); + BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n"); - if (builtins & GPU_VIEW_NORMAL) - BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? varnormal: -varnormal;\n"); + if (use_new_shading) { + if (builtins & GPU_VIEW_MATRIX) + BLI_dynstr_append(ds, "\tmat4 viewmat = ViewMatrix;\n"); + if (builtins & GPU_CAMERA_TEXCO_FACTORS) + BLI_dynstr_append(ds, "\tvec4 camtexfac = CameraTexCoFactors;\n"); + if (builtins & GPU_OBJECT_MATRIX) + BLI_dynstr_append(ds, "\tmat4 objmat = ModelMatrix;\n"); + if (builtins & GPU_INVERSE_OBJECT_MATRIX) + BLI_dynstr_append(ds, "\tmat4 objinv = ModelMatrixInverse;\n"); + if (builtins & GPU_INVERSE_VIEW_MATRIX) + BLI_dynstr_append(ds, "\tmat4 viewinv = ViewMatrixInverse;\n"); + if (builtins & GPU_VIEW_NORMAL) + BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? viewNormal: -viewNormal;\n"); + if (builtins & GPU_VIEW_POSITION) + BLI_dynstr_append(ds, "\tvec3 viewposition = viewPosition;\n"); + } + else { + if (builtins & GPU_VIEW_MATRIX) + BLI_dynstr_append(ds, "\tmat4 viewmat = unfviewmat;\n"); + if (builtins & GPU_CAMERA_TEXCO_FACTORS) + BLI_dynstr_append(ds, "\tvec4 camtexfac = unfcameratexfactors;\n"); + if (builtins & GPU_OBJECT_MATRIX) + BLI_dynstr_append(ds, "\tmat4 objmat = unfobmat;\n"); + if (builtins & GPU_INVERSE_OBJECT_MATRIX) + BLI_dynstr_append(ds, "\tmat4 objinv = unfinvobmat;\n"); + if (builtins & GPU_INVERSE_VIEW_MATRIX) + BLI_dynstr_append(ds, "\tmat4 viewinv = unfinvviewmat;\n"); + if (builtins & GPU_VIEW_NORMAL) + BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? varnormal: -varnormal;\n"); + if (builtins & GPU_VIEW_POSITION) + BLI_dynstr_append(ds, "\tvec3 viewposition = varposition;\n"); + } /* Calculate tangent space. */ #ifdef WITH_OPENSUBDIV @@ -722,6 +822,17 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output) BLI_dynstr_append(ds, "}\n"); + /* XXX This cannot go into gpu_shader_material.glsl because main() would be parsed and generate error */ + /* Old glsl mode compat. */ + BLI_dynstr_append(ds, "#ifndef NODETREE_EXEC\n"); + BLI_dynstr_append(ds, "out vec4 fragColor;\n"); + BLI_dynstr_append(ds, "void main()\n"); + BLI_dynstr_append(ds, "{\n"); + BLI_dynstr_append(ds, "\tClosure cl = nodetree_exec();\n"); + BLI_dynstr_append(ds, "\tfragColor = vec4(cl.radiance, cl.opacity);\n"); + BLI_dynstr_append(ds, "}\n"); + BLI_dynstr_append(ds, "#endif\n\n"); + /* create shader */ code = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); @@ -733,6 +844,95 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output) return code; } +static const char *attrib_prefix_get(CustomDataType type) +{ + switch (type) { + case CD_ORCO: return "orco"; + case CD_MTFACE: return "u"; + case CD_TANGENT: return "t"; + case CD_MCOL: return "c"; + case CD_AUTO_FROM_NAME: return "a"; + default: BLI_assert(false && "Gwn_VertAttr Prefix type not found : This should not happen!"); return ""; + } +} + +static char *code_generate_vertex_new(ListBase *nodes, const char *vert_code, bool use_geom) +{ + DynStr *ds = BLI_dynstr_new(); + GPUNode *node; + GPUInput *input; + char *code; + + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { + /* XXX FIXME : see notes in mesh_render_data_create() */ + /* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */ + if (input->attribtype == CD_ORCO) { + /* orco is computed from local positions, see bellow */ + BLI_dynstr_appendf(ds, "uniform vec3 OrcoTexCoFactors[2];\n"); + } + else if (input->attribname[0] == '\0') { + BLI_dynstr_appendf(ds, "in %s %s;\n", GPU_DATATYPE_STR[input->type], attrib_prefix_get(input->attribtype)); + BLI_dynstr_appendf(ds, "#define att%d %s\n", input->attribid, attrib_prefix_get(input->attribtype)); + } + else { + unsigned int hash = BLI_ghashutil_strhash_p(input->attribname); + BLI_dynstr_appendf(ds, "in %s %s%u;\n", + GPU_DATATYPE_STR[input->type], attrib_prefix_get(input->attribtype), hash); + BLI_dynstr_appendf(ds, "#define att%d %s%u\n", + input->attribid, attrib_prefix_get(input->attribtype), hash); + } + BLI_dynstr_appendf(ds, "out %s var%d%s;\n", + GPU_DATATYPE_STR[input->type], input->attribid, use_geom ? "g" : ""); + } + } + } + + BLI_dynstr_append(ds, "\n"); + + BLI_dynstr_append(ds, "#define ATTRIB\n"); + BLI_dynstr_append(ds, "uniform mat3 NormalMatrix;\n"); + BLI_dynstr_append(ds, "void pass_attrib(in vec3 position) {\n"); + + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { + if (input->attribtype == CD_TANGENT) { /* silly exception */ + BLI_dynstr_appendf( + ds, "\tvar%d%s.xyz = normalize(NormalMatrix * att%d.xyz);\n", + input->attribid, use_geom ? "g" : "", input->attribid); + BLI_dynstr_appendf( + ds, "\tvar%d%s.w = att%d.w;\n", + input->attribid, use_geom ? "g" : "", input->attribid); + } + else if (input->attribtype == CD_ORCO) { + BLI_dynstr_appendf(ds, "\tvar%d%s = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n", + input->attribid, use_geom ? "g" : ""); + } + else { + BLI_dynstr_appendf(ds, "\tvar%d%s = att%d;\n", + input->attribid, use_geom ? "g" : "", input->attribid); + } + } + } + } + + BLI_dynstr_append(ds, "}\n"); + + BLI_dynstr_append(ds, vert_code); + + code = BLI_dynstr_get_cstring(ds); + + BLI_dynstr_free(ds); + +#if 0 + if (G.debug & G_DEBUG) printf("%s\n", code); +#endif + + return code; +} + static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) { DynStr *ds = BLI_dynstr_new(); @@ -790,7 +990,7 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n"); #endif BLI_dynstr_appendf( - ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n", + ds, "\tvar%d.xyz = normalize(NormalMatrix * att%d.xyz);\n", input->attribid, input->attribid); BLI_dynstr_appendf( ds, "\tvar%d.w = att%d.w;\n", @@ -841,6 +1041,51 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) return code; } +static char *code_generate_geometry_new(ListBase *nodes, const char *geom_code) +{ + DynStr *ds = BLI_dynstr_new(); + GPUNode *node; + GPUInput *input; + char *code; + + /* Create prototype because attributes cannot be declared before layout. */ + BLI_dynstr_appendf(ds, "void pass_attrib(in int vert);\n"); + BLI_dynstr_append(ds, "#define ATTRIB\n"); + + BLI_dynstr_append(ds, geom_code); + + /* Generate varying declarations. */ + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { + BLI_dynstr_appendf(ds, "in %s var%dg[];\n", + GPU_DATATYPE_STR[input->type], + input->attribid); + BLI_dynstr_appendf(ds, "out %s var%d;\n", + GPU_DATATYPE_STR[input->type], + input->attribid); + } + } + } + + /* Generate varying assignments. */ + BLI_dynstr_appendf(ds, "void pass_attrib(in int vert) {\n"); + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { + /* TODO let shader choose what to do depending on what the attrib is. */ + BLI_dynstr_appendf(ds, "\tvar%d = var%dg[vert];\n", input->attribid, input->attribid); + } + } + } + BLI_dynstr_append(ds, "}\n"); + + code = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + return code; +} + static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv) { #ifdef WITH_OPENSUBDIV @@ -928,6 +1173,67 @@ GPUShader *GPU_pass_shader(GPUPass *pass) return pass->shader; } +static void gpu_nodes_extract_dynamic_inputs_new(GPUPass *pass, ListBase *nodes) +{ + GPUShader *shader = pass->shader; + GPUNode *node; + GPUInput *next, *input; + ListBase *inputs = &pass->inputs; + int extract, z; + + memset(inputs, 0, sizeof(*inputs)); + + if (!shader) + return; + + GPU_shader_bind(shader); + + for (node = nodes->first; node; node = node->next) { + z = 0; + for (input = node->inputs.first; input; input = next, z++) { + next = input->next; + + /* attributes don't need to be bound, they already have + * an id that the drawing functions will use */ + if (input->source == GPU_SOURCE_ATTRIB) { + continue; + } + + if (input->source == GPU_SOURCE_BUILTIN || + input->source == GPU_SOURCE_OPENGL_BUILTIN) + { + continue; + } + + if (input->ima || input->tex || input->prv) + BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid); + else + BLI_snprintf(input->shadername, sizeof(input->shadername), "unf%d", input->id); + + /* pass non-dynamic uniforms to opengl */ + extract = 0; + + if (input->ima || input->tex || input->prv) { + if (input->bindtex) + extract = 1; + } + else if (input->dynamicvec) + extract = 1; + + if (extract) + input->shaderloc = GPU_shader_get_uniform(shader, input->shadername); + + /* extract nodes */ + if (extract) { + BLI_remlink(&node->inputs, input); + BLI_addtail(inputs, input); + } + } + } + + GPU_shader_unbind(); +} + static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) { GPUShader *shader = pass->shader; @@ -1135,7 +1441,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType name = outnode->name; input = outnode->inputs.first; - if ((STREQ(name, "set_value") || STREQ(name, "set_rgb")) && + if ((STREQ(name, "set_value") || STREQ(name, "set_rgb") || STREQ(name, "set_rgba")) && (input->type == type)) { input = MEM_dupallocN(outnode->inputs.first); @@ -1194,7 +1500,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType #if 0 input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL); #endif - input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, GPU_HDR_NONE, NULL); + input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, NULL); input->textarget = GL_TEXTURE_2D; MEM_freeN(link->ptr1); @@ -1235,6 +1541,12 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType BLI_strncpy(input->attribname, link->attribname, sizeof(input->attribname)); MEM_freeN(link); } + else if (type == GPU_CLOSURE) { + input->type = type; + input->source = GPU_SOURCE_STRUCT; + + MEM_freeN(link); + } else { /* uniform vector */ input->type = type; @@ -1246,21 +1558,100 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType input->dynamictype = link->dynamictype; input->dynamicdata = link->ptr2; } + MEM_freeN(link); } BLI_addtail(&node->inputs, input); } -static void gpu_node_input_socket(GPUNode *node, GPUNodeStack *sock) + +static const char *gpu_uniform_set_function_from_type(eNodeSocketDatatype type) +{ + switch (type) { + case SOCK_FLOAT: + return "set_value"; + case SOCK_VECTOR: + return "set_rgb"; + case SOCK_RGBA: + return "set_rgba"; + default: + BLI_assert(!"No gpu function for non-supported eNodeSocketDatatype"); + return NULL; + } +} + +/** + * Link stack uniform buffer. + * This is called for the input/output sockets that are note connected. + */ +static GPUNodeLink *gpu_uniformbuffer_link( + GPUMaterial *mat, bNode *node, GPUNodeStack *stack, const int index, const eNodeSocketInOut in_out) { - GPUNodeLink *link; + bNodeSocket *socket; + + /* Some nodes can have been create on the fly and does + * not have an original to point to. (i.e. the bump from + * ntree_shader_relink_displacement). In this case just + * revert to static constant folding. */ + if (node->original == NULL) { + return NULL; + } + + if (in_out == SOCK_IN) { + socket = BLI_findlink(&node->original->inputs, index); + } + else { + socket = BLI_findlink(&node->original->outputs, index); + } + + BLI_assert(socket != NULL); + BLI_assert(socket->in_out == in_out); + + if ((socket->flag & SOCK_HIDE_VALUE) == 0) { + GPUNodeLink *link; + switch (socket->type) { + case SOCK_FLOAT: + { + bNodeSocketValueFloat *socket_data = socket->default_value; + link = GPU_uniform_buffer(&socket_data->value, GPU_FLOAT); + break; + } + case SOCK_VECTOR: + { + bNodeSocketValueRGBA *socket_data = socket->default_value; + link = GPU_uniform_buffer(socket_data->value, GPU_VEC3); + break; + } + case SOCK_RGBA: + { + bNodeSocketValueRGBA *socket_data = socket->default_value; + link = GPU_uniform_buffer(socket_data->value, GPU_VEC4); + break; + } + default: + return NULL; + break; + } + + if (in_out == SOCK_IN) { + GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link); + } + return link; + } + return NULL; +} +static void gpu_node_input_socket(GPUMaterial *material, bNode *bnode, GPUNode *node, GPUNodeStack *sock, const int index) +{ if (sock->link) { gpu_node_input_link(node, sock->link, sock->type); } + else if ((material != NULL) && (gpu_uniformbuffer_link(material, bnode, sock, index, SOCK_IN) != NULL)) { + gpu_node_input_link(node, sock->link, sock->type); + } else { - link = GPU_node_link_create(); + GPUNodeLink *link = GPU_node_link_create(); link->ptr1 = sock->vec; gpu_node_input_link(node, link, sock->type); } @@ -1387,7 +1778,14 @@ GPUNodeLink *GPU_attribute(const CustomDataType type, const char *name) { GPUNodeLink *link = GPU_node_link_create(); - link->attribtype = type; + /* Fall back to the UV layer, which matches old behavior. */ + if (type == CD_AUTO_FROM_NAME && name[0] == '\0') { + link->attribtype = CD_MTFACE; + } + else { + link->attribtype = type; + } + link->attribname = name; return link; @@ -1416,6 +1814,21 @@ GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *d return link; } +/** + * Add uniform to UBO struct of GPUMaterial. + */ +GPUNodeLink *GPU_uniform_buffer(float *num, GPUType gputype) +{ + GPUNodeLink *link = GPU_node_link_create(); + link->ptr1 = num; + link->ptr2 = NULL; + link->dynamic = true; + link->dynamictype = GPU_DYNAMIC_UBO; + link->type = gputype; + + return link; +} + GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data) { GPUNodeLink *link = GPU_node_link_create(); @@ -1526,7 +1939,7 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...) return true; } -bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...) +bool GPU_stack_link(GPUMaterial *material, bNode *bnode, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...) { GPUNode *node; GPUFunction *function; @@ -1546,11 +1959,11 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod if (in) { for (i = 0; in[i].type != GPU_NONE; i++) { - gpu_node_input_socket(node, &in[i]); + gpu_node_input_socket(material, bnode, node, &in[i], i); totin++; } } - + if (out) { for (i = 0; out[i].type != GPU_NONE; i++) { gpu_node_output(node, out[i].type, &out[i].link); @@ -1572,7 +1985,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod if (totin == 0) { link = va_arg(params, GPUNodeLink *); if (link->socket) - gpu_node_input_socket(node, link->socket); + gpu_node_input_socket(NULL, NULL, node, link->socket, -1); else gpu_node_input_link(node, link, function->paramtype[i]); } @@ -1582,8 +1995,8 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod } va_end(params); - gpu_material_add_node(mat, node); - + gpu_material_add_node(material, node); + return true; } @@ -1608,6 +2021,11 @@ int GPU_link_changed(GPUNodeLink *link) return 0; } +GPUNodeLink *GPU_uniformbuffer_link_out(GPUMaterial *mat, bNode *node, GPUNodeStack *stack, const int index) +{ + return gpu_uniformbuffer_link(mat, node, stack, index, SOCK_OUT); +} + /* Pass create/free */ static void gpu_nodes_tag(GPUNodeLink *link) @@ -1647,6 +2065,78 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) } } +GPUPass *GPU_generate_pass_new( + struct GPUMaterial *material, + ListBase *nodes, struct GPUNodeLink *frag_outlink, + GPUVertexAttribs *attribs, + const char *vert_code, const char *geom_code, + const char *frag_lib, const char *defines) +{ + GPUShader *shader; + GPUPass *pass; + char *vertexgen, *fragmentgen, *tmp; + char *vertexcode, *geometrycode, *fragmentcode; + + /* prune unused nodes */ + gpu_nodes_prune(nodes, frag_outlink); + + gpu_nodes_get_vertex_attributes(nodes, attribs); + + /* generate code and compile with opengl */ + fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output, true); + vertexgen = code_generate_vertex_new(nodes, vert_code, (geom_code != NULL)); + + tmp = BLI_strdupcat(frag_lib, glsl_material_library); + fragmentcode = BLI_strdupcat(tmp, fragmentgen); + vertexcode = BLI_strdup(vertexgen); + + if (geom_code) { + geometrycode = code_generate_geometry_new(nodes, geom_code); + } + else { + geometrycode = NULL; + } + + shader = GPU_shader_create(vertexcode, + fragmentcode, + geometrycode, + NULL, + defines); + + MEM_freeN(tmp); + + /* failed? */ + if (!shader) { + if (fragmentcode) + MEM_freeN(fragmentcode); + if (vertexcode) + MEM_freeN(vertexcode); + if (geometrycode) + MEM_freeN(geometrycode); + MEM_freeN(fragmentgen); + MEM_freeN(vertexgen); + gpu_nodes_free(nodes); + return NULL; + } + + /* create pass */ + pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); + pass->shader = shader; + pass->fragmentcode = fragmentcode; + pass->geometrycode = geometrycode; + pass->vertexcode = vertexcode; + pass->libcode = glsl_material_library; + + /* extract dynamic inputs and throw away nodes */ + gpu_nodes_extract_dynamic_inputs_new(pass, nodes); + gpu_nodes_free(nodes); + + MEM_freeN(fragmentgen); + MEM_freeN(vertexgen); + + return pass; +} + GPUPass *GPU_generate_pass( ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttribs *attribs, int *builtins, @@ -1672,7 +2162,7 @@ GPUPass *GPU_generate_pass( gpu_nodes_get_builtin_flag(nodes, builtins); /* generate code and compile with opengl */ - fragmentcode = code_generate_fragment(nodes, outlink->output); + fragmentcode = code_generate_fragment(NULL, nodes, outlink->output, false); vertexcode = code_generate_vertex(nodes, type); geometrycode = code_generate_geometry(nodes, use_opensubdiv); @@ -1688,9 +2178,6 @@ GPUPass *GPU_generate_pass( geometrycode, glsl_material_library, NULL, - 0, - 0, - 0, flags); /* failed? */ @@ -1708,7 +2195,6 @@ GPUPass *GPU_generate_pass( /* create pass */ pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); - pass->output = outlink->output; pass->shader = shader; pass->fragmentcode = fragmentcode; pass->geometrycode = geometrycode; diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index 7af17f9122d..14e07a6e012 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -57,7 +57,8 @@ typedef enum GPUDataSource { GPU_SOURCE_OPENGL_BUILTIN, GPU_SOURCE_TEX_PIXEL, GPU_SOURCE_TEX, - GPU_SOURCE_ATTRIB + GPU_SOURCE_ATTRIB, + GPU_SOURCE_STRUCT } GPUDataSource; typedef enum { @@ -156,10 +157,7 @@ typedef struct GPUInput { } GPUInput; struct GPUPass { - struct GPUPass *next, *prev; - ListBase inputs; - struct GPUOutput *output; struct GPUShader *shader; char *fragmentcode; char *geometrycode; @@ -170,11 +168,18 @@ struct GPUPass { typedef struct GPUPass GPUPass; -GPUPass *GPU_generate_pass(ListBase *nodes, struct GPUNodeLink *outlink, - struct GPUVertexAttribs *attribs, int *builtin, - const GPUMatType type, const char *name, - const bool use_opensubdiv, - const bool use_new_shading); +GPUPass *GPU_generate_pass_new( + struct GPUMaterial *material, + ListBase *nodes, struct GPUNodeLink *frag_outlink, + struct GPUVertexAttribs *attribs, + const char *vert_code, const char *geom_code, + const char *frag_lib, const char *defines); +GPUPass *GPU_generate_pass( + ListBase *nodes, struct GPUNodeLink *outlink, + struct GPUVertexAttribs *attribs, int *builtin, + const GPUMatType type, const char *name, + const bool use_opensubdiv, + const bool use_new_shading); struct GPUShader *GPU_pass_shader(GPUPass *pass); diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c index 2f2a16f9e1d..3de363cc76e 100644 --- a/source/blender/gpu/intern/gpu_compositing.c +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -42,11 +42,13 @@ #include "DNA_gpu_types.h" #include "GPU_compositing.h" +#include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_framebuffer.h" #include "GPU_glew.h" #include "GPU_shader.h" #include "GPU_texture.h" +#include "GPU_batch.h" #include "MEM_guardedalloc.h" @@ -193,7 +195,8 @@ struct GPUFX { /* we have a stencil, restore the previous state */ bool restore_stencil; - unsigned int vbuffer; + Gwn_Batch *quad_batch; + Gwn_Batch *point_batch; }; #if 0 @@ -225,7 +228,13 @@ static GPUTexture * create_concentric_sample_texture(int side) } } - tex = GPU_texture_create_1D_procedural(side * side, texels, NULL); + tex = GPU_texture_create_1D_custom(side * side, 2, GPU_RG16F, (float *)texels, NULL); + + /* Set parameters */ + GPU_texture_bind(tex, 0); + GPU_texture_filter_mode(tex, false); + GPU_texture_unbind(tex); + MEM_freeN(texels); return tex; } @@ -247,7 +256,13 @@ static GPUTexture *create_spiral_sample_texture(int numsaples) texels[i][1] = r * sinf(phi); } - tex = GPU_texture_create_1D_procedural(numsaples, (float *)texels, NULL); + tex = GPU_texture_create_1D_custom(numsaples, 2, GPU_RG16F, (float *)texels, NULL); + + /* Set parameters */ + GPU_texture_bind(tex, 0); + GPU_texture_filter_mode(tex, false); + GPU_texture_unbind(tex); + MEM_freeN(texels); return tex; } @@ -257,12 +272,32 @@ GPUFX *GPU_fx_compositor_create(void) { GPUFX *fx = MEM_callocN(sizeof(GPUFX), "GPUFX compositor"); - glGenBuffers(1, &fx->vbuffer); - glBindBuffer(GL_ARRAY_BUFFER, fx->vbuffer); - glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(float), fullscreencos); - glBufferSubData(GL_ARRAY_BUFFER, 8 * sizeof(float), 8 * sizeof(float), fullscreenuvs); - glBindBuffer(GL_ARRAY_BUFFER, 0); + /* Quad buffer */ + static Gwn_VertFormat format = {0}; + static unsigned int pos, uvs; + if (format.attrib_ct == 0) { + pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + uvs = GWN_vertformat_attr_add(&format, "uvs", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, 4); + for (int i = 0; i < 4; ++i) { + GWN_vertbuf_attr_set(vbo, pos, i, fullscreencos[i]); + GWN_vertbuf_attr_set(vbo, uvs, i, fullscreenuvs[i]); + } + fx->quad_batch = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO); + + /* Point Buffer */ + static Gwn_VertFormat format_point = {0}; + static unsigned int dummy_attrib; + if (format_point.attrib_ct == 0) { + dummy_attrib = GWN_vertformat_attr_add(&format_point, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + float dummy[2] = {0.0f, 0.0f}; + Gwn_VertBuf *vbo_point = GWN_vertbuf_create_with_format(&format_point); + GWN_vertbuf_data_alloc(vbo_point, 1); + GWN_vertbuf_attr_set(vbo_point, dummy_attrib, 0, &dummy); + fx->point_batch = GWN_batch_create_ex(GWN_PRIM_POINTS, vbo_point, NULL, GWN_BATCH_OWNS_VBO); return fx; } @@ -352,12 +387,14 @@ static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo) void GPU_fx_compositor_destroy(GPUFX *fx) { cleanup_fx_gl_data(fx, true); - glDeleteBuffers(1, &fx->vbuffer); + GWN_batch_discard(fx->quad_batch); + GWN_batch_discard(fx->point_batch); MEM_freeN(fx); } static GPUTexture * create_jitter_texture(void) { + GPUTexture *tex; float jitter[64 * 64][2]; int i; @@ -367,7 +404,15 @@ static GPUTexture * create_jitter_texture(void) normalize_v2(jitter[i]); } - return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], true, NULL); + tex = GPU_texture_create_2D_custom(64, 64, 2, GPU_RG16F, &jitter[0][0], NULL); + + /* Set parameters */ + GPU_texture_bind(tex, 0); + GPU_texture_filter_mode(tex, false); + GPU_texture_wrap_mode(tex, true); + GPU_texture_unbind(tex); + + return tex; } @@ -382,9 +427,6 @@ bool GPU_fx_compositor_initialize_passes( fx->effects = 0; - if (!GLEW_EXT_framebuffer_object) - return false; - if (!fx_settings) { cleanup_fx_gl_data(fx, true); return false; @@ -436,7 +478,7 @@ bool GPU_fx_compositor_initialize_passes( if (!fx->color_buffer || !fx->depth_buffer || w != fx->gbuffer_dim[0] || h != fx->gbuffer_dim[1]) { cleanup_fx_gl_data(fx, false); - if (!(fx->color_buffer = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) { + if (!(fx->color_buffer = GPU_texture_create_2D(w, h, NULL, err_out))) { printf(".256%s\n", err_out); cleanup_fx_gl_data(fx, true); return false; @@ -472,8 +514,7 @@ bool GPU_fx_compositor_initialize_passes( /* create textures for dof effect */ if (fx_flag & GPU_FX_FLAG_DOF) { - bool dof_high_quality = (fx_settings->dof->high_quality != 0) && - GPU_geometry_shader_support() && GPU_instanced_drawing_support(); + bool dof_high_quality = (fx_settings->dof->high_quality != 0); /* cleanup buffers if quality setting has changed (no need to keep more buffers around than necessary ) */ if (dof_high_quality != fx->dof_high_quality) @@ -488,38 +529,42 @@ bool GPU_fx_compositor_initialize_passes( { if (!(fx->dof_half_downsampled_near = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } if (!(fx->dof_half_downsampled_far = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } - if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_procedural( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, err_out))) + + if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_custom( + fx->dof_downsampled_w, fx->dof_downsampled_h, 2, GPU_RG16F, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } + GPU_texture_bind(fx->dof_nearfar_coc, 0); + GPU_texture_filter_mode(fx->dof_nearfar_coc, false); + GPU_texture_wrap_mode(fx->dof_nearfar_coc, false); + GPU_texture_unbind(fx->dof_nearfar_coc); - - if (!(fx->dof_near_blur = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out))) + if (!(fx->dof_near_blur = GPU_texture_create_2D_custom( + fx->dof_downsampled_w, fx->dof_downsampled_h, 4, GPU_RGBA16F, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } - if (!(fx->dof_far_blur = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out))) + if (!(fx->dof_far_blur = GPU_texture_create_2D_custom( + fx->dof_downsampled_w, fx->dof_downsampled_h, 4, GPU_RGBA16F, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); @@ -534,21 +579,21 @@ bool GPU_fx_compositor_initialize_passes( if (!fx->dof_near_coc_buffer || !fx->dof_near_coc_blurred_buffer || !fx->dof_near_coc_final_buffer) { if (!(fx->dof_near_coc_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); @@ -567,7 +612,7 @@ bool GPU_fx_compositor_initialize_passes( /* we need to pass data between shader stages, allocate an extra color buffer */ if (num_passes > 1) { if (!fx->color_buffer_sec) { - if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) { + if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, err_out))) { printf(".256%s\n", err_out); cleanup_fx_gl_data(fx, true); return false; @@ -585,11 +630,8 @@ bool GPU_fx_compositor_initialize_passes( /* bind the buffers */ /* first depth buffer, because system assumes read/write buffers */ - if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, err_out)) - printf("%.256s\n", err_out); - - if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, err_out)) - printf("%.256s\n", err_out); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, 0); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, 0); if (!GPU_framebuffer_check_valid(fx->gbuffer, err_out)) printf("%.256s\n", err_out); @@ -600,7 +642,7 @@ bool GPU_fx_compositor_initialize_passes( if (scissor_rect) { int w_sc = BLI_rcti_size_x(scissor_rect) + 1; int h_sc = BLI_rcti_size_y(scissor_rect) + 1; - glPushAttrib(GL_SCISSOR_BIT); + gpuPushAttrib(GPU_SCISSOR_BIT); glEnable(GL_SCISSOR_TEST); glScissor(scissor_rect->xmin - rect->xmin, scissor_rect->ymin - rect->ymin, w_sc, h_sc); @@ -634,7 +676,7 @@ static void gpu_fx_bind_render_target(int *passes_left, GPUFX *fx, struct GPUOff } else { /* bind the ping buffer to the color buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, target, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, target, 0, 0); } } @@ -663,8 +705,7 @@ void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray) GPU_framebuffer_texture_detach(fx->depth_buffer); /* first depth buffer, because system assumes read/write buffers */ - if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, err_out)) - printf("%.256s\n", err_out); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, 0); } @@ -674,39 +715,35 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx) GPU_framebuffer_texture_detach(fx->depth_buffer_xray); /* attach regular framebuffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, 0); /* full screen quad where we will always write to depth buffer */ - glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT); + gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_SCISSOR_BIT); glDepthFunc(GL_ALWAYS); /* disable scissor from sculpt if any */ glDisable(GL_SCISSOR_TEST); /* disable writing to color buffer, it's depth only pass */ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - /* set up quad buffer */ - glBindBuffer(GL_ARRAY_BUFFER, fx->vbuffer); - glVertexPointer(2, GL_FLOAT, 0, NULL); - glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float))); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - depth_resolve_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_RESOLVE, false); if (depth_resolve_shader) { - GPUDepthResolveInterface *interface = GPU_shader_get_interface(depth_resolve_shader); + GPUDepthResolveInterface *interface = GPU_fx_shader_get_interface(depth_resolve_shader); - GPU_shader_bind(depth_resolve_shader); + /* set up quad buffer */ + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(depth_resolve_shader), GPU_shader_get_interface(depth_resolve_shader)); GPU_texture_bind(fx->depth_buffer_xray, 0); - GPU_texture_filter_mode(fx->depth_buffer_xray, false, true); + GPU_texture_compare_mode(fx->depth_buffer_xray, false); + GPU_texture_filter_mode(fx->depth_buffer_xray, true); GPU_shader_uniform_texture(depth_resolve_shader, interface->depth_uniform, fx->depth_buffer_xray); /* draw */ - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ - GPU_texture_filter_mode(fx->depth_buffer_xray, true, false); + GPU_texture_compare_mode(fx->depth_buffer_xray, true); + GPU_texture_filter_mode(fx->depth_buffer_xray, false); GPU_texture_unbind(fx->depth_buffer_xray); GPU_shader_unbind(); @@ -714,11 +751,7 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - glPopAttrib(); + gpuPopAttrib(); } @@ -748,19 +781,13 @@ bool GPU_fx_do_composite_pass( GPU_framebuffer_texture_detach(fx->color_buffer); GPU_framebuffer_texture_detach(fx->depth_buffer); - if (fx->restore_stencil) - glPopAttrib(); + if (fx->restore_stencil) { + gpuPopAttrib(); + } src = fx->color_buffer; target = fx->color_buffer_sec; - /* set up quad buffer */ - glBindBuffer(GL_ARRAY_BUFFER, fx->vbuffer); - glVertexPointer(2, GL_FLOAT, 0, NULL); - glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float))); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - /* full screen FX pass */ /* invert the view matrix */ @@ -788,8 +815,6 @@ bool GPU_fx_do_composite_pass( viewvecs[1][2] = vec_far[2] - viewvecs[0][2]; } - /* set invalid color in case shader fails */ - glColor3f(1.0, 0.0, 1.0); glDisable(GL_DEPTH_TEST); /* ssao pass */ @@ -810,9 +835,9 @@ bool GPU_fx_do_composite_pass( ssao_params[3] = (passes_left == 1 && !ofs) ? dfdyfac[0] : dfdyfac[1]; - GPUSSAOShaderInterface *interface = GPU_shader_get_interface(ssao_shader); + GPUSSAOShaderInterface *interface = GPU_fx_shader_get_interface(ssao_shader); - GPU_shader_bind(ssao_shader); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(ssao_shader), GPU_shader_get_interface(ssao_shader)); GPU_shader_uniform_vector(ssao_shader, interface->ssao_uniform, 4, 1, ssao_params); GPU_shader_uniform_vector(ssao_shader, interface->ssao_color_uniform, 4, 1, fx_ssao->color); @@ -823,7 +848,8 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(ssao_shader, interface->color_uniform, src); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, true); GPU_shader_uniform_texture(ssao_shader, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(fx->jitter_buffer, numslots++); @@ -835,11 +861,12 @@ bool GPU_fx_do_composite_pass( /* draw */ gpu_fx_bind_render_target(&passes_left, fx, ofs, target); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); GPU_texture_unbind(fx->jitter_buffer); GPU_texture_unbind(fx->ssao_spiral_samples_tex); @@ -892,11 +919,8 @@ bool GPU_fx_do_composite_pass( if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3)) { GPU_framebuffer_texture_unbind(fx->gbuffer, NULL); GPU_framebuffer_restore(); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); GPU_shader_unbind(); - glBindBuffer(GL_ARRAY_BUFFER, 0); return false; } @@ -904,9 +928,9 @@ bool GPU_fx_do_composite_pass( { float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h}; - GPUDOFHQPassOneInterface *interface = GPU_shader_get_interface(dof_shader_pass1); + GPUDOFHQPassOneInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass1); - GPU_shader_bind(dof_shader_pass1); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass1), GPU_shader_get_interface(dof_shader_pass1)); GPU_shader_uniform_vector(dof_shader_pass1, interface->dof_uniform, 4, 1, dof_params); GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); @@ -915,28 +939,31 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, false); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(src, numslots++); /* disable filtering for the texture so custom downsample can do the right thing */ - GPU_texture_filter_mode(src, false, false); + GPU_texture_filter_mode(src, false); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, src); /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, NULL); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1, NULL); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, 0); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1, 0); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2, 0); /* binding takes care of setting the viewport to the downsampled size */ GPU_framebuffer_slots_bind(fx->gbuffer, 0); GPU_framebuffer_check_valid(fx->gbuffer, NULL); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); + /* disable bindings */ - GPU_texture_filter_mode(src, false, true); + GPU_texture_filter_mode(src, true); GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); GPU_framebuffer_texture_detach(fx->dof_half_downsampled_near); @@ -953,24 +980,23 @@ bool GPU_fx_do_composite_pass( int rendertargetdim[2] = {fx->dof_downsampled_w, fx->dof_downsampled_h}; float selection[2] = {0.0f, 1.0f}; - GPUDOFHQPassTwoInterface *interface = GPU_shader_get_interface(dof_shader_pass2); + GPUDOFHQPassTwoInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass2); - GPU_shader_bind(dof_shader_pass2); + GWN_batch_program_set(fx->point_batch, GPU_shader_get_program(dof_shader_pass2), GPU_shader_get_interface(dof_shader_pass2)); + + GPU_texture_bind(fx->dof_nearfar_coc, numslots++); + GPU_texture_bind(fx->dof_half_downsampled_far, numslots++); + GPU_texture_bind(fx->dof_half_downsampled_near, numslots++); GPU_shader_uniform_vector(dof_shader_pass2, interface->dof_uniform, 4, 1, dof_params); GPU_shader_uniform_vector_int(dof_shader_pass2, interface->rendertargetdim_uniform, 2, 1, rendertargetdim); GPU_shader_uniform_vector(dof_shader_pass2, interface->select_uniform, 2, 1, selection); - - GPU_texture_bind(fx->dof_nearfar_coc, numslots++); GPU_shader_uniform_texture(dof_shader_pass2, interface->coc_uniform, fx->dof_nearfar_coc); - - GPU_texture_bind(fx->dof_half_downsampled_far, numslots++); - GPU_texture_bind(fx->dof_half_downsampled_near, numslots++); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_far); - GPU_texture_filter_mode(fx->dof_half_downsampled_far, false, false); + GPU_texture_filter_mode(fx->dof_half_downsampled_far, false); /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, 0); GPU_texture_bind_as_framebuffer(fx->dof_far_blur); glDisable(GL_DEPTH_TEST); @@ -981,24 +1007,24 @@ bool GPU_fx_do_composite_pass( glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */ - glDrawArraysInstancedARB(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h); + GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, 0, NULL, NULL); GPU_texture_unbind(fx->dof_half_downsampled_far); GPU_framebuffer_texture_detach(fx->dof_far_blur); - GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_near); - GPU_texture_filter_mode(fx->dof_half_downsampled_near, false, false); - selection[0] = 1.0f; selection[1] = 0.0f; GPU_shader_uniform_vector(dof_shader_pass2, interface->select_uniform, 2, 1, selection); + GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_near); + GPU_texture_filter_mode(fx->dof_half_downsampled_near, false); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, 0); /* have to clear the buffer unfortunately */ glClear(GL_COLOR_BUFFER_BIT); /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */ - glDrawArraysInstancedARB(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h); + GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, 0, NULL, NULL); + GWN_batch_program_use_end(fx->point_batch); /* disable bindings */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -1010,15 +1036,16 @@ bool GPU_fx_do_composite_pass( GPU_texture_unbind(fx->dof_nearfar_coc); GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_far_blur); + numslots = 0; } /* third pass, accumulate the near/far blur fields */ { float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h}; - GPUDOFHQPassThreeInterface *interface = GPU_shader_get_interface(dof_shader_pass3); + GPUDOFHQPassThreeInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass3); - GPU_shader_bind(dof_shader_pass3); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass3), GPU_shader_get_interface(dof_shader_pass3)); GPU_shader_uniform_vector(dof_shader_pass3, interface->dof_uniform, 4, 1, dof_params); @@ -1027,14 +1054,15 @@ bool GPU_fx_do_composite_pass( GPU_texture_bind(fx->dof_near_blur, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, interface->near_uniform, fx->dof_near_blur); - GPU_texture_filter_mode(fx->dof_near_blur, false, true); + GPU_texture_filter_mode(fx->dof_near_blur, true); GPU_texture_bind(fx->dof_far_blur, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, interface->far_uniform, fx->dof_far_blur); - GPU_texture_filter_mode(fx->dof_far_blur, false, true); + GPU_texture_filter_mode(fx->dof_far_blur, true); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, false); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_shader_uniform_texture(dof_shader_pass3, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(src, numslots++); @@ -1043,13 +1071,13 @@ bool GPU_fx_do_composite_pass( /* if this is the last pass, prepare for rendering on the frambuffer */ gpu_fx_bind_render_target(&passes_left, fx, ofs, target); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ GPU_texture_unbind(fx->dof_near_blur); GPU_texture_unbind(fx->dof_far_blur); GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); GPU_texture_unbind(fx->depth_buffer); /* may not be attached, in that case this just returns */ @@ -1085,11 +1113,8 @@ bool GPU_fx_do_composite_pass( if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3 && dof_shader_pass4 && dof_shader_pass5)) { GPU_framebuffer_texture_unbind(fx->gbuffer, NULL); GPU_framebuffer_restore(); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); GPU_shader_unbind(); - glBindBuffer(GL_ARRAY_BUFFER, 0); return false; } @@ -1097,9 +1122,9 @@ bool GPU_fx_do_composite_pass( { float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; - GPUDOFPassOneInterface *interface = GPU_shader_get_interface(dof_shader_pass1); + GPUDOFPassOneInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass1); - GPU_shader_bind(dof_shader_pass1); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass1), GPU_shader_get_interface(dof_shader_pass1)); GPU_shader_uniform_vector(dof_shader_pass1, interface->dof_uniform, 4, 1, dof_params); GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); @@ -1109,18 +1134,20 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(dof_shader_pass1, interface->color_uniform, src); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, true); GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer); /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, 0); /* binding takes care of setting the viewport to the downsampled size */ GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); @@ -1134,32 +1161,37 @@ bool GPU_fx_do_composite_pass( float tmp = invrendertargetdim[0]; invrendertargetdim[0] = 0.0f; - GPUDOFPassTwoInterface *interface = GPU_shader_get_interface(dof_shader_pass2); + GPUDOFPassTwoInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass2); dof_params[2] = GPU_texture_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor); /* Blurring vertically */ - GPU_shader_bind(dof_shader_pass2); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass2), GPU_shader_get_interface(dof_shader_pass2)); GPU_shader_uniform_vector(dof_shader_pass2, interface->dof_uniform, 4, 1, dof_params); GPU_shader_uniform_vector(dof_shader_pass2, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); GPU_shader_uniform_vector(dof_shader_pass2, interface->viewvecs_uniform, 4, 3, viewvecs[0]); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, true); GPU_shader_uniform_texture(dof_shader_pass2, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_near_coc_buffer); /* use final buffer as a temp here */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, 0); /* Drawing quad */ - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); + + /* Rebind Shader */ + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass2), GPU_shader_get_interface(dof_shader_pass2)); /* *unbind/detach */ GPU_texture_unbind(fx->dof_near_coc_buffer); + GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer); /* Blurring horizontally */ @@ -1170,11 +1202,13 @@ bool GPU_fx_do_composite_pass( GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_near_coc_final_buffer); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, NULL); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, 0); + + GWN_batch_draw(fx->quad_batch); /* *unbind/detach */ - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); GPU_texture_unbind(fx->dof_near_coc_final_buffer); @@ -1187,9 +1221,9 @@ bool GPU_fx_do_composite_pass( /* third pass, calculate near coc */ { - GPUDOFPassThreeInterface *interface = GPU_shader_get_interface(dof_shader_pass3); + GPUDOFPassThreeInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass3); - GPU_shader_bind(dof_shader_pass3); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass3), GPU_shader_get_interface(dof_shader_pass3)); GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, interface->near_coc_downsampled, fx->dof_near_coc_buffer); @@ -1197,9 +1231,9 @@ bool GPU_fx_do_composite_pass( GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, interface->near_coc_blurred, fx->dof_near_coc_blurred_buffer); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, 0); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ GPU_texture_unbind(fx->dof_near_coc_buffer); GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); @@ -1215,17 +1249,17 @@ bool GPU_fx_do_composite_pass( float invrendertargetdim[2] = {1.0f / GPU_texture_width(fx->dof_near_coc_blurred_buffer), 1.0f / GPU_texture_height(fx->dof_near_coc_blurred_buffer)}; - GPUDOFPassFourInterface *interface = GPU_shader_get_interface(dof_shader_pass4); + GPUDOFPassFourInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass4); - GPU_shader_bind(dof_shader_pass4); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass4), GPU_shader_get_interface(dof_shader_pass4)); GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass4, interface->near_coc_downsampled, fx->dof_near_coc_final_buffer); GPU_shader_uniform_vector(dof_shader_pass4, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, 0); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ GPU_texture_unbind(fx->dof_near_coc_final_buffer); @@ -1240,9 +1274,9 @@ bool GPU_fx_do_composite_pass( { float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; - GPUDOFPassFiveInterface *interface = GPU_shader_get_interface(dof_shader_pass5); + GPUDOFPassFiveInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass5); - GPU_shader_bind(dof_shader_pass5); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass5), GPU_shader_get_interface(dof_shader_pass5)); GPU_shader_uniform_vector(dof_shader_pass5, interface->dof_uniform, 4, 1, dof_params); GPU_shader_uniform_vector(dof_shader_pass5, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); @@ -1258,18 +1292,20 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(dof_shader_pass5, interface->medium_blurred_uniform, fx->dof_near_coc_buffer); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, true); GPU_shader_uniform_texture(dof_shader_pass5, interface->depth_uniform, fx->depth_buffer); /* if this is the last pass, prepare for rendering on the frambuffer */ gpu_fx_bind_render_target(&passes_left, fx, ofs, target); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ GPU_texture_unbind(fx->dof_near_coc_buffer); GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); /* may not be attached, in that case this just returns */ @@ -1289,10 +1325,6 @@ bool GPU_fx_do_composite_pass( } } - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, 0); - GPU_shader_unbind(); return true; @@ -1305,6 +1337,7 @@ void GPU_fx_compositor_init_dof_settings(GPUDOFSettings *fx_dof) fx_dof->focus_distance = 1.0f; fx_dof->sensor = 1.0f; fx_dof->num_blades = 6; + fx_dof->ratio = 1.0f; } void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao) @@ -1315,7 +1348,7 @@ void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao) fx_ssao->samples = 20; } -void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect effect) +void GPU_fx_shader_init_interface(GPUShader *shader, GPUFXShaderEffect effect) { if (!shader) return; @@ -1334,7 +1367,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->ssao_concentric_tex = GPU_shader_get_uniform(shader, "ssao_concentric_tex"); interface->ssao_jitter_uniform = GPU_shader_get_uniform(shader, "jitter_tex"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } @@ -1348,7 +1381,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } @@ -1362,7 +1395,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->select_uniform = GPU_shader_get_uniform(shader, "layerselection"); interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } @@ -1378,7 +1411,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } @@ -1392,7 +1425,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO: @@ -1405,7 +1438,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE: @@ -1415,7 +1448,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->near_coc_downsampled = GPU_shader_get_uniform(shader, "colorbuffer"); interface->near_coc_blurred = GPU_shader_get_uniform(shader, "blurredcolorbuffer"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR: @@ -1425,7 +1458,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->near_coc_downsampled = GPU_shader_get_uniform(shader, "colorbuffer"); interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE: @@ -1440,7 +1473,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } @@ -1450,7 +1483,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c index 859aab9565f..8aea87ef659 100644 --- a/source/blender/gpu/intern/gpu_debug.c +++ b/source/blender/gpu/intern/gpu_debug.c @@ -20,7 +20,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): Brecht Van Lommel, Jason Wilkins. + * Contributor(s): Brecht Van Lommel, Jason Wilkins, Mike Erwin. * * ***** END GPL LICENSE BLOCK ***** */ @@ -44,122 +44,18 @@ #include <stdlib.h> #include <string.h> -#define CASE_CODE_RETURN_STR(code) case code: return #code; +#ifndef __APPLE__ /* only non-Apple systems implement OpenGL debug callbacks */ -static const char *gpu_gl_error_symbol(GLenum err) -{ - switch (err) { - CASE_CODE_RETURN_STR(GL_NO_ERROR) - CASE_CODE_RETURN_STR(GL_INVALID_ENUM) - CASE_CODE_RETURN_STR(GL_INVALID_VALUE) - CASE_CODE_RETURN_STR(GL_INVALID_OPERATION) - CASE_CODE_RETURN_STR(GL_STACK_OVERFLOW) - CASE_CODE_RETURN_STR(GL_STACK_UNDERFLOW) - CASE_CODE_RETURN_STR(GL_OUT_OF_MEMORY) - -#if GL_ARB_imaging - CASE_CODE_RETURN_STR(GL_TABLE_TOO_LARGE) -#endif - -#if defined(WITH_GLU) - CASE_CODE_RETURN_STR(GLU_INVALID_ENUM) - CASE_CODE_RETURN_STR(GLU_INVALID_VALUE) - CASE_CODE_RETURN_STR(GLU_OUT_OF_MEMORY) -#endif +/* control whether we use older AMD_debug_output extension + * some supported GPU + OS combos do not have the newer extensions */ +# define LEGACY_DEBUG 1 - default: - return "<unknown error>"; - } -} - -#undef CASE_CODE_RETURN_STR - - -static bool gpu_report_gl_errors(const char *file, int line, const char *str) -{ - GLenum gl_error = glGetError(); - - if (gl_error == GL_NO_ERROR) { - return true; - } - else { - /* glGetError should have cleared the error flag, so if we get the - * same flag twice that means glGetError itself probably triggered - * the error. This happens on Windows if the GL context is invalid. - */ - { - GLenum new_error = glGetError(); - if (gl_error == new_error) { - fprintf(stderr, "GL: Possible context invalidation issue\n"); - return false; - } - } - - fprintf(stderr, - "%s:%d: ``%s'' -> GL Error (0x%04X - %s): %s\n", - file, line, str, gl_error, - gpu_gl_error_symbol(gl_error), - gpuErrorString(gl_error)); - - return false; - } -} - - -const char *gpuErrorString(GLenum err) -{ - switch (err) { - case GL_NO_ERROR: - return "No Error"; - - case GL_INVALID_ENUM: - return "Invalid Enumeration"; - - case GL_INVALID_VALUE: - return "Invalid Value"; - - case GL_INVALID_OPERATION: - return "Invalid Operation"; - - case GL_STACK_OVERFLOW: - return "Stack Overflow"; - - case GL_STACK_UNDERFLOW: - return "Stack Underflow"; - - case GL_OUT_OF_MEMORY: - return "Out of Memory"; - -#if GL_ARB_imaging - case GL_TABLE_TOO_LARGE: - return "Table Too Large"; -#endif - -#if defined(WITH_GLU) - case GLU_INVALID_ENUM: - return "Invalid Enum (GLU)"; - - case GLU_INVALID_VALUE: - return "Invalid Value (GLU)"; - - case GLU_OUT_OF_MEMORY: - return "Out of Memory (GLU)"; -#endif - - default: - return "<unknown error>"; - } -} - - -/* Debug callbacks need the same calling convention as OpenGL functions. - */ -#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) - /* Win32 but not WinCE */ -# define APIENTRY __stdcall -#else -# define APIENTRY -#endif +/* Debug callbacks need the same calling convention as OpenGL functions. */ +# if defined(_WIN32) +# define APIENTRY __stdcall +# else +# define APIENTRY +# endif static const char *source_name(GLenum source) @@ -189,32 +85,11 @@ static const char *message_type_name(GLenum message) } } -static const char *category_name_amd(GLenum category) -{ - switch (category) { - case GL_DEBUG_CATEGORY_API_ERROR_AMD: return "API error"; - case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: return "window system"; - case GL_DEBUG_CATEGORY_DEPRECATION_AMD: return "deprecated behavior"; - case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: return "undefined behavior"; - case GL_DEBUG_CATEGORY_PERFORMANCE_AMD: return "performance"; - case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: return "shader compiler"; - case GL_DEBUG_CATEGORY_APPLICATION_AMD: return "application"; - case GL_DEBUG_CATEGORY_OTHER_AMD: return "other"; - default: return "???"; - } -} - - static void APIENTRY gpu_debug_proc( GLenum source, GLenum type, GLuint UNUSED(id), GLenum severity, GLsizei UNUSED(length), const GLchar *message, const GLvoid *UNUSED(userParm)) { - if (type == GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR) { - /* Blender 2.7x uses OpenGL 2.1, we don't care if features are deprecated */ - return; - } - bool backtrace = false; switch (severity) { @@ -233,18 +108,28 @@ static void APIENTRY gpu_debug_proc( } } +# if LEGACY_DEBUG + +static const char *category_name_amd(GLenum category) +{ + switch (category) { + case GL_DEBUG_CATEGORY_API_ERROR_AMD: return "API error"; + case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: return "window system"; + case GL_DEBUG_CATEGORY_DEPRECATION_AMD: return "deprecated behavior"; + case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: return "undefined behavior"; + case GL_DEBUG_CATEGORY_PERFORMANCE_AMD: return "performance"; + case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: return "shader compiler"; + case GL_DEBUG_CATEGORY_APPLICATION_AMD: return "application"; + case GL_DEBUG_CATEGORY_OTHER_AMD: return "other"; + default: return "???"; + } +} -#ifndef GLEW_ES_ONLY static void APIENTRY gpu_debug_proc_amd( GLuint UNUSED(id), GLenum category, GLenum severity, GLsizei UNUSED(length), const GLchar *message, GLvoid *UNUSED(userParm)) { - if (category == GL_DEBUG_CATEGORY_DEPRECATION_AMD) { - /* Blender 2.7x uses OpenGL 2.1, we don't care if features are deprecated */ - return; - } - bool backtrace = false; switch (severity) { @@ -261,148 +146,88 @@ static void APIENTRY gpu_debug_proc_amd( fflush(stderr); } } -#endif +# endif /* LEGACY_DEBUG */ - -#undef APIENTRY +# undef APIENTRY +#endif /* not Apple */ void gpu_debug_init(void) { +#ifdef __APPLE__ + fprintf(stderr, "OpenGL debug callback is not available on Apple.\n"); +#else /* not Apple */ const char success[] = "Successfully hooked OpenGL debug callback."; -#if !defined(WITH_GLEW_ES) && !defined(GLEW_ES_ONLY) - if (GLEW_VERSION_4_3) { - fprintf(stderr, "Using OpenGL 4.3 debug facilities\n"); - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext()); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); - GPU_string_marker(success); - return; - } -#endif - - if (GLEW_KHR_debug) { -#ifndef GLEW_ES_ONLY - fprintf(stderr, "Using KHR_debug extension\n"); + if (GLEW_VERSION_4_3 || GLEW_KHR_debug) { + fprintf(stderr, "Using %s\n", GLEW_VERSION_4_3 ? "OpenGL 4.3 debug facilities" : "KHR_debug extension"); glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext()); + glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, NULL); glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); GPU_string_marker(success); -#endif - return; } - -#ifndef GLEW_ES_ONLY - if (GLEW_ARB_debug_output) { + else if (GLEW_ARB_debug_output) { fprintf(stderr, "Using ARB_debug_output extension\n"); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallbackARB((GLDEBUGPROCARB)gpu_debug_proc, mxGetCurrentContext()); + glDebugMessageCallbackARB((GLDEBUGPROCARB)gpu_debug_proc, NULL); glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); GPU_string_marker(success); - - return; } - - if (GLEW_AMD_debug_output) { +# if LEGACY_DEBUG + else if (GLEW_AMD_debug_output) { fprintf(stderr, "Using AMD_debug_output extension\n"); - glDebugMessageCallbackAMD(gpu_debug_proc_amd, mxGetCurrentContext()); + glDebugMessageCallbackAMD(gpu_debug_proc_amd, NULL); glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); GPU_string_marker(success); - - return; } -#endif - - fprintf(stderr, "Failed to hook OpenGL debug callback.\n"); - - return; +# endif + else { + fprintf(stderr, "Failed to hook OpenGL debug callback.\n"); + } +#endif /* not Apple */ } void gpu_debug_exit(void) { -#ifndef WITH_GLEW_ES -#ifndef GLEW_ES_ONLY - if (GLEW_VERSION_4_3) { - glDebugMessageCallback(NULL, NULL); - - return; - } -#endif -#endif - - if (GLEW_KHR_debug) { -#ifndef GLEW_ES_ONLY +#ifndef __APPLE__ + if (GLEW_VERSION_4_3 || GLEW_KHR_debug) { glDebugMessageCallback(NULL, NULL); -#endif - return; } - -#ifndef GLEW_ES_ONLY - if (GLEW_ARB_debug_output) { + else if (GLEW_ARB_debug_output) { glDebugMessageCallbackARB(NULL, NULL); - - return; } - - if (GLEW_AMD_debug_output) { +# if LEGACY_DEBUG + else if (GLEW_AMD_debug_output) { glDebugMessageCallbackAMD(NULL, NULL); - - return; } +# endif #endif - - return; } void GPU_string_marker(const char *buf) { -#ifndef WITH_GLEW_ES -#ifndef GLEW_ES_ONLY - if (GLEW_VERSION_4_3) { - glDebugMessageInsert( - GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, - GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf); - - return; - } -#endif -#endif - - if (GLEW_KHR_debug) { -#ifndef GLEW_ES_ONLY +#ifdef __APPLE__ + UNUSED_VARS(buf); +#else /* not Apple */ + if (GLEW_VERSION_4_3 || GLEW_KHR_debug) { glDebugMessageInsert( GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf); -#endif - return; } - -#ifndef GLEW_ES_ONLY - if (GLEW_ARB_debug_output) { + else if (GLEW_ARB_debug_output) { glDebugMessageInsertARB( GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, -1, buf); - - return; } - - if (GLEW_AMD_debug_output) { +# if LEGACY_DEBUG + else if (GLEW_AMD_debug_output) { glDebugMessageInsertAMD( GL_DEBUG_CATEGORY_APPLICATION_AMD, GL_DEBUG_SEVERITY_LOW_AMD, 0, 0, buf); - - return; } - - if (GLEW_GREMEDY_string_marker) { - glStringMarkerGREMEDY(0, buf); - - return; - } -#endif +# endif +#endif /* not Apple */ } void GPU_print_error_debug(const char *str) @@ -410,406 +235,3 @@ void GPU_print_error_debug(const char *str) if (G.debug & G_DEBUG) fprintf(stderr, "GPU: %s\n", str); } - - -void GPU_assert_no_gl_errors(const char *file, int line, const char *str) -{ - if (G.debug) { - GLboolean gl_ok = gpu_report_gl_errors(file, line, str); - - BLI_assert(gl_ok); - (void) gl_ok; - } -} - - -static void gpu_state_print_fl_ex(const char *name, GLenum type) -{ -#define MAX_ARRAY_SIZE 64 - - const unsigned char err_mark[4] = {0xff, 0xff, 0xff, 0xff}; - - float value[MAX_ARRAY_SIZE]; - int a; - - memset(value, 0xff, sizeof(value)); - glGetFloatv(type, value); - - if (glGetError() == GL_NO_ERROR) { - printf("%s: ", name); - for (a = 0; a < MAX_ARRAY_SIZE; a++) { - if (memcmp(&value[a], err_mark, sizeof(value[a])) == 0) { - break; - } - printf("%.2f ", value[a]); - } - printf("\n"); - } - -#undef MAX_ARRAY_SIZE -} - -#define gpu_state_print_fl(val) gpu_state_print_fl_ex(#val, val) - -void GPU_state_print(void) -{ - GPU_ASSERT_NO_GL_ERRORS("GPU_state_print"); /* clear any errors */ - - gpu_state_print_fl(GL_ACCUM_ALPHA_BITS); - gpu_state_print_fl(GL_ACCUM_BLUE_BITS); - gpu_state_print_fl(GL_ACCUM_CLEAR_VALUE); - gpu_state_print_fl(GL_ACCUM_GREEN_BITS); - gpu_state_print_fl(GL_ACCUM_RED_BITS); - gpu_state_print_fl(GL_ACTIVE_TEXTURE); - gpu_state_print_fl(GL_ALIASED_LINE_WIDTH_RANGE); - gpu_state_print_fl(GL_ALIASED_POINT_SIZE_RANGE); - gpu_state_print_fl(GL_ALPHA_BIAS); - gpu_state_print_fl(GL_ALPHA_BITS); - gpu_state_print_fl(GL_ALPHA_SCALE); - gpu_state_print_fl(GL_ALPHA_TEST); - gpu_state_print_fl(GL_ALPHA_TEST_FUNC); - gpu_state_print_fl(GL_ALPHA_TEST_REF); - gpu_state_print_fl(GL_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_ATTRIB_STACK_DEPTH); - gpu_state_print_fl(GL_AUTO_NORMAL); - gpu_state_print_fl(GL_AUX_BUFFERS); - gpu_state_print_fl(GL_BLEND); - gpu_state_print_fl(GL_BLEND_COLOR); - gpu_state_print_fl(GL_BLEND_DST_ALPHA); - gpu_state_print_fl(GL_BLEND_DST_RGB); - gpu_state_print_fl(GL_BLEND_EQUATION_ALPHA); - gpu_state_print_fl(GL_BLEND_EQUATION_RGB); - gpu_state_print_fl(GL_BLEND_SRC_ALPHA); - gpu_state_print_fl(GL_BLEND_SRC_RGB); - gpu_state_print_fl(GL_BLUE_BIAS); - gpu_state_print_fl(GL_BLUE_BITS); - gpu_state_print_fl(GL_BLUE_SCALE); - gpu_state_print_fl(GL_CLIENT_ACTIVE_TEXTURE); - gpu_state_print_fl(GL_CLIENT_ATTRIB_STACK_DEPTH); - gpu_state_print_fl(GL_CLIP_PLANE0); - gpu_state_print_fl(GL_COLOR_ARRAY); - gpu_state_print_fl(GL_COLOR_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_COLOR_ARRAY_SIZE); - gpu_state_print_fl(GL_COLOR_ARRAY_STRIDE); - gpu_state_print_fl(GL_COLOR_ARRAY_TYPE); - gpu_state_print_fl(GL_COLOR_CLEAR_VALUE); - gpu_state_print_fl(GL_COLOR_LOGIC_OP); - gpu_state_print_fl(GL_COLOR_MATERIAL); - gpu_state_print_fl(GL_COLOR_MATERIAL_FACE); - gpu_state_print_fl(GL_COLOR_MATERIAL_PARAMETER); - gpu_state_print_fl(GL_COLOR_MATRIX); - gpu_state_print_fl(GL_COLOR_MATRIX_STACK_DEPTH); - gpu_state_print_fl(GL_COLOR_SUM); - gpu_state_print_fl(GL_COLOR_TABLE); - gpu_state_print_fl(GL_COLOR_WRITEMASK); - gpu_state_print_fl(GL_NUM_COMPRESSED_TEXTURE_FORMATS); - gpu_state_print_fl(GL_COMPRESSED_TEXTURE_FORMATS); - gpu_state_print_fl(GL_CONVOLUTION_1D); - gpu_state_print_fl(GL_CONVOLUTION_2D); - gpu_state_print_fl(GL_CULL_FACE); - gpu_state_print_fl(GL_CULL_FACE_MODE); - gpu_state_print_fl(GL_CURRENT_COLOR); - gpu_state_print_fl(GL_CURRENT_FOG_COORD); - gpu_state_print_fl(GL_CURRENT_INDEX); - gpu_state_print_fl(GL_CURRENT_NORMAL); - gpu_state_print_fl(GL_CURRENT_PROGRAM); - gpu_state_print_fl(GL_CURRENT_RASTER_COLOR); - gpu_state_print_fl(GL_CURRENT_RASTER_DISTANCE); - gpu_state_print_fl(GL_CURRENT_RASTER_INDEX); - gpu_state_print_fl(GL_CURRENT_RASTER_POSITION); - gpu_state_print_fl(GL_CURRENT_RASTER_POSITION_VALID); - gpu_state_print_fl(GL_CURRENT_RASTER_SECONDARY_COLOR); - gpu_state_print_fl(GL_CURRENT_RASTER_TEXTURE_COORDS); - gpu_state_print_fl(GL_CURRENT_SECONDARY_COLOR); - gpu_state_print_fl(GL_CURRENT_TEXTURE_COORDS); - gpu_state_print_fl(GL_DEPTH_BIAS); - gpu_state_print_fl(GL_DEPTH_BITS); - gpu_state_print_fl(GL_DEPTH_CLEAR_VALUE); - gpu_state_print_fl(GL_DEPTH_FUNC); - gpu_state_print_fl(GL_DEPTH_RANGE); - gpu_state_print_fl(GL_DEPTH_SCALE); - gpu_state_print_fl(GL_DEPTH_TEST); - gpu_state_print_fl(GL_DEPTH_WRITEMASK); - gpu_state_print_fl(GL_DITHER); - gpu_state_print_fl(GL_DOUBLEBUFFER); - gpu_state_print_fl(GL_DRAW_BUFFER); - gpu_state_print_fl(GL_DRAW_BUFFER0); - gpu_state_print_fl(GL_EDGE_FLAG); - gpu_state_print_fl(GL_EDGE_FLAG_ARRAY); - gpu_state_print_fl(GL_EDGE_FLAG_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_EDGE_FLAG_ARRAY_STRIDE); - gpu_state_print_fl(GL_ELEMENT_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_FEEDBACK_BUFFER_SIZE); - gpu_state_print_fl(GL_FEEDBACK_BUFFER_TYPE); - gpu_state_print_fl(GL_FOG); - gpu_state_print_fl(GL_FOG_COLOR); - gpu_state_print_fl(GL_FOG_COORD_ARRAY); - gpu_state_print_fl(GL_FOG_COORD_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_FOG_COORD_ARRAY_STRIDE); - gpu_state_print_fl(GL_FOG_COORD_ARRAY_TYPE); - gpu_state_print_fl(GL_FOG_COORD_SRC); - gpu_state_print_fl(GL_FOG_DENSITY); - gpu_state_print_fl(GL_FOG_END); - gpu_state_print_fl(GL_FOG_HINT); - gpu_state_print_fl(GL_FOG_INDEX); - gpu_state_print_fl(GL_FOG_MODE); - gpu_state_print_fl(GL_FOG_START); - gpu_state_print_fl(GL_FRAGMENT_PROGRAM_ARB); /* TODO: remove ARB program support */ - gpu_state_print_fl(GL_FRAGMENT_SHADER_DERIVATIVE_HINT); - gpu_state_print_fl(GL_FRONT_FACE); - gpu_state_print_fl(GL_GENERATE_MIPMAP_HINT); - gpu_state_print_fl(GL_GREEN_BIAS); - gpu_state_print_fl(GL_GREEN_BITS); - gpu_state_print_fl(GL_GREEN_SCALE); - gpu_state_print_fl(GL_HISTOGRAM); - gpu_state_print_fl(GL_INDEX_ARRAY); - gpu_state_print_fl(GL_INDEX_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_INDEX_ARRAY_STRIDE); - gpu_state_print_fl(GL_INDEX_ARRAY_TYPE); - gpu_state_print_fl(GL_INDEX_BITS); - gpu_state_print_fl(GL_INDEX_CLEAR_VALUE); - gpu_state_print_fl(GL_INDEX_LOGIC_OP); - gpu_state_print_fl(GL_INDEX_MODE); - gpu_state_print_fl(GL_INDEX_OFFSET); - gpu_state_print_fl(GL_INDEX_SHIFT); - gpu_state_print_fl(GL_INDEX_WRITEMASK); - gpu_state_print_fl(GL_LIGHT0); - gpu_state_print_fl(GL_LIGHT1); - gpu_state_print_fl(GL_LIGHT2); - gpu_state_print_fl(GL_LIGHT3); - gpu_state_print_fl(GL_LIGHT4); - gpu_state_print_fl(GL_LIGHT5); - gpu_state_print_fl(GL_LIGHT6); - gpu_state_print_fl(GL_LIGHT7); - gpu_state_print_fl(GL_LIGHTING); - gpu_state_print_fl(GL_LIGHT_MODEL_AMBIENT); - gpu_state_print_fl(GL_LIGHT_MODEL_COLOR_CONTROL); - gpu_state_print_fl(GL_LIGHT_MODEL_LOCAL_VIEWER); - gpu_state_print_fl(GL_LIGHT_MODEL_TWO_SIDE); - gpu_state_print_fl(GL_LINE_SMOOTH); - gpu_state_print_fl(GL_LINE_SMOOTH_HINT); - gpu_state_print_fl(GL_LINE_STIPPLE); - gpu_state_print_fl(GL_LINE_STIPPLE_PATTERN); - gpu_state_print_fl(GL_LINE_STIPPLE_REPEAT); - gpu_state_print_fl(GL_LINE_WIDTH); - gpu_state_print_fl(GL_LINE_WIDTH_GRANULARITY); - gpu_state_print_fl(GL_LINE_WIDTH_RANGE); - gpu_state_print_fl(GL_LIST_BASE); - gpu_state_print_fl(GL_LIST_INDEX); - gpu_state_print_fl(GL_LIST_MODE); - gpu_state_print_fl(GL_LOGIC_OP); - gpu_state_print_fl(GL_LOGIC_OP_MODE); - gpu_state_print_fl(GL_MAP1_COLOR_4); - gpu_state_print_fl(GL_MAP1_GRID_DOMAIN); - gpu_state_print_fl(GL_MAP1_GRID_SEGMENTS); - gpu_state_print_fl(GL_MAP1_INDEX); - gpu_state_print_fl(GL_MAP1_NORMAL); - gpu_state_print_fl(GL_MAP1_TEXTURE_COORD_1); - gpu_state_print_fl(GL_MAP1_TEXTURE_COORD_2); - gpu_state_print_fl(GL_MAP1_TEXTURE_COORD_3); - gpu_state_print_fl(GL_MAP1_TEXTURE_COORD_4); - gpu_state_print_fl(GL_MAP1_VERTEX_3); - gpu_state_print_fl(GL_MAP1_VERTEX_4); - gpu_state_print_fl(GL_MAP2_COLOR_4); - gpu_state_print_fl(GL_MAP2_GRID_DOMAIN); - gpu_state_print_fl(GL_MAP2_GRID_SEGMENTS); - gpu_state_print_fl(GL_MAP2_INDEX); - gpu_state_print_fl(GL_MAP2_NORMAL); - gpu_state_print_fl(GL_MAP2_TEXTURE_COORD_1); - gpu_state_print_fl(GL_MAP2_TEXTURE_COORD_2); - gpu_state_print_fl(GL_MAP2_TEXTURE_COORD_3); - gpu_state_print_fl(GL_MAP2_TEXTURE_COORD_4); - gpu_state_print_fl(GL_MAP2_VERTEX_3); - gpu_state_print_fl(GL_MAP2_VERTEX_4); - gpu_state_print_fl(GL_MAP_COLOR); - gpu_state_print_fl(GL_MAP_STENCIL); - gpu_state_print_fl(GL_MATRIX_MODE); - gpu_state_print_fl(GL_MAX_3D_TEXTURE_SIZE); - gpu_state_print_fl(GL_MAX_ATTRIB_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_CLIENT_ATTRIB_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_CLIP_PLANES); - gpu_state_print_fl(GL_MAX_COLOR_MATRIX_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS); - gpu_state_print_fl(GL_MAX_CUBE_MAP_TEXTURE_SIZE); - gpu_state_print_fl(GL_MAX_DRAW_BUFFERS); - gpu_state_print_fl(GL_MAX_ELEMENTS_INDICES); - gpu_state_print_fl(GL_MAX_ELEMENTS_VERTICES); - gpu_state_print_fl(GL_MAX_EVAL_ORDER); - gpu_state_print_fl(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS); - gpu_state_print_fl(GL_MAX_LIGHTS); - gpu_state_print_fl(GL_MAX_LIST_NESTING); - gpu_state_print_fl(GL_MAX_MODELVIEW_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_NAME_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_PIXEL_MAP_TABLE); - gpu_state_print_fl(GL_MAX_PROJECTION_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_TEXTURE_COORDS); - gpu_state_print_fl(GL_MAX_TEXTURE_IMAGE_UNITS); - gpu_state_print_fl(GL_MAX_TEXTURE_LOD_BIAS); - gpu_state_print_fl(GL_MAX_TEXTURE_SIZE); - gpu_state_print_fl(GL_MAX_TEXTURE_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_TEXTURE_UNITS); - gpu_state_print_fl(GL_MAX_VARYING_FLOATS); - gpu_state_print_fl(GL_MAX_VERTEX_ATTRIBS); - gpu_state_print_fl(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS); - gpu_state_print_fl(GL_MAX_VERTEX_UNIFORM_COMPONENTS); - gpu_state_print_fl(GL_MAX_VIEWPORT_DIMS); - gpu_state_print_fl(GL_MINMAX); - gpu_state_print_fl(GL_MODELVIEW_MATRIX); - gpu_state_print_fl(GL_MODELVIEW_STACK_DEPTH); - gpu_state_print_fl(GL_MULTISAMPLE); - gpu_state_print_fl(GL_NAME_STACK_DEPTH); - gpu_state_print_fl(GL_NORMALIZE); - gpu_state_print_fl(GL_NORMAL_ARRAY); - gpu_state_print_fl(GL_NORMAL_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_NORMAL_ARRAY_STRIDE); - gpu_state_print_fl(GL_NORMAL_ARRAY_TYPE); - gpu_state_print_fl(GL_NUM_COMPRESSED_TEXTURE_FORMATS); - gpu_state_print_fl(GL_PACK_ALIGNMENT); - gpu_state_print_fl(GL_PACK_IMAGE_HEIGHT); - gpu_state_print_fl(GL_PACK_LSB_FIRST); - gpu_state_print_fl(GL_PACK_ROW_LENGTH); - gpu_state_print_fl(GL_PACK_SKIP_IMAGES); - gpu_state_print_fl(GL_PACK_SKIP_PIXELS); - gpu_state_print_fl(GL_PACK_SKIP_ROWS); - gpu_state_print_fl(GL_PACK_SWAP_BYTES); - gpu_state_print_fl(GL_PERSPECTIVE_CORRECTION_HINT); - gpu_state_print_fl(GL_PIXEL_MAP_A_TO_A_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_B_TO_B_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_G_TO_G_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_I_TO_A_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_I_TO_B_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_I_TO_G_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_I_TO_I_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_I_TO_R_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_R_TO_R_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_S_TO_S_SIZE); - gpu_state_print_fl(GL_PIXEL_PACK_BUFFER_BINDING); - gpu_state_print_fl(GL_PIXEL_UNPACK_BUFFER_BINDING); - gpu_state_print_fl(GL_POINT_DISTANCE_ATTENUATION); - gpu_state_print_fl(GL_POINT_FADE_THRESHOLD_SIZE); - gpu_state_print_fl(GL_POINT_SIZE); - gpu_state_print_fl(GL_POINT_SIZE_GRANULARITY); - gpu_state_print_fl(GL_POINT_SIZE_MAX); - gpu_state_print_fl(GL_POINT_SIZE_MIN); - gpu_state_print_fl(GL_POINT_SIZE_RANGE); - gpu_state_print_fl(GL_POINT_SMOOTH); - gpu_state_print_fl(GL_POINT_SMOOTH_HINT); - gpu_state_print_fl(GL_POINT_SPRITE); - gpu_state_print_fl(GL_POLYGON_MODE); - gpu_state_print_fl(GL_POLYGON_OFFSET_FACTOR); - gpu_state_print_fl(GL_POLYGON_OFFSET_FILL); - gpu_state_print_fl(GL_POLYGON_OFFSET_LINE); - gpu_state_print_fl(GL_POLYGON_OFFSET_POINT); - gpu_state_print_fl(GL_POLYGON_OFFSET_UNITS); - gpu_state_print_fl(GL_POLYGON_SMOOTH); - gpu_state_print_fl(GL_POLYGON_SMOOTH_HINT); - gpu_state_print_fl(GL_POLYGON_STIPPLE); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_ALPHA_BIAS); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_ALPHA_SCALE); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_BLUE_BIAS); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_BLUE_SCALE); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_COLOR_TABLE); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_GREEN_BIAS); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_GREEN_SCALE); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_RED_BIAS); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_RED_SCALE); - gpu_state_print_fl(GL_POST_CONVOLUTION_ALPHA_BIAS); - gpu_state_print_fl(GL_POST_CONVOLUTION_ALPHA_SCALE); - gpu_state_print_fl(GL_POST_CONVOLUTION_BLUE_BIAS); - gpu_state_print_fl(GL_POST_CONVOLUTION_BLUE_SCALE); - gpu_state_print_fl(GL_POST_CONVOLUTION_COLOR_TABLE); - gpu_state_print_fl(GL_POST_CONVOLUTION_GREEN_BIAS); - gpu_state_print_fl(GL_POST_CONVOLUTION_GREEN_SCALE); - gpu_state_print_fl(GL_POST_CONVOLUTION_RED_BIAS); - gpu_state_print_fl(GL_POST_CONVOLUTION_RED_SCALE); - gpu_state_print_fl(GL_PROJECTION_MATRIX); - gpu_state_print_fl(GL_PROJECTION_STACK_DEPTH); - gpu_state_print_fl(GL_READ_BUFFER); - gpu_state_print_fl(GL_RED_BIAS); - gpu_state_print_fl(GL_RED_BITS); - gpu_state_print_fl(GL_RED_SCALE); - gpu_state_print_fl(GL_RENDER_MODE); - gpu_state_print_fl(GL_RESCALE_NORMAL); - gpu_state_print_fl(GL_RGBA_MODE); - gpu_state_print_fl(GL_SAMPLES); - gpu_state_print_fl(GL_SAMPLE_BUFFERS); - gpu_state_print_fl(GL_SAMPLE_COVERAGE_INVERT); - gpu_state_print_fl(GL_SAMPLE_COVERAGE_VALUE); - gpu_state_print_fl(GL_SCISSOR_BOX); - gpu_state_print_fl(GL_SCISSOR_TEST); - gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY); - gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY_SIZE); - gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY_STRIDE); - gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY_TYPE); - gpu_state_print_fl(GL_SELECTION_BUFFER_SIZE); - gpu_state_print_fl(GL_SEPARABLE_2D); - gpu_state_print_fl(GL_SHADE_MODEL); - gpu_state_print_fl(GL_SMOOTH_LINE_WIDTH_GRANULARITY); - gpu_state_print_fl(GL_SMOOTH_LINE_WIDTH_RANGE); - gpu_state_print_fl(GL_SMOOTH_POINT_SIZE_GRANULARITY); - gpu_state_print_fl(GL_SMOOTH_POINT_SIZE_RANGE); - gpu_state_print_fl(GL_STENCIL_BACK_FAIL); - gpu_state_print_fl(GL_STENCIL_BACK_FUNC); - gpu_state_print_fl(GL_STENCIL_BACK_PASS_DEPTH_FAIL); - gpu_state_print_fl(GL_STENCIL_BACK_PASS_DEPTH_PASS); - gpu_state_print_fl(GL_STENCIL_BACK_REF); - gpu_state_print_fl(GL_STENCIL_BACK_VALUE_MASK); - gpu_state_print_fl(GL_STENCIL_BACK_WRITEMASK); - gpu_state_print_fl(GL_STENCIL_BITS); - gpu_state_print_fl(GL_STENCIL_CLEAR_VALUE); - gpu_state_print_fl(GL_STENCIL_FAIL); - gpu_state_print_fl(GL_STENCIL_FUNC); - gpu_state_print_fl(GL_STENCIL_PASS_DEPTH_FAIL); - gpu_state_print_fl(GL_STENCIL_PASS_DEPTH_PASS); - gpu_state_print_fl(GL_STENCIL_REF); - gpu_state_print_fl(GL_STENCIL_TEST); - gpu_state_print_fl(GL_STENCIL_VALUE_MASK); - gpu_state_print_fl(GL_STENCIL_WRITEMASK); - gpu_state_print_fl(GL_STEREO); - gpu_state_print_fl(GL_SUBPIXEL_BITS); - gpu_state_print_fl(GL_TEXTURE_1D); - gpu_state_print_fl(GL_TEXTURE_2D); - gpu_state_print_fl(GL_TEXTURE_3D); - gpu_state_print_fl(GL_TEXTURE_BINDING_1D); - gpu_state_print_fl(GL_TEXTURE_BINDING_2D); - gpu_state_print_fl(GL_TEXTURE_BINDING_3D); - gpu_state_print_fl(GL_TEXTURE_BINDING_CUBE_MAP); - gpu_state_print_fl(GL_TEXTURE_COMPRESSION_HINT); - gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY); - gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_SIZE); - gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_STRIDE); - gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_TYPE); - gpu_state_print_fl(GL_TEXTURE_CUBE_MAP); - gpu_state_print_fl(GL_TEXTURE_GEN_Q); - gpu_state_print_fl(GL_TEXTURE_GEN_R); - gpu_state_print_fl(GL_TEXTURE_GEN_S); - gpu_state_print_fl(GL_TEXTURE_GEN_T); - gpu_state_print_fl(GL_TEXTURE_MATRIX); - gpu_state_print_fl(GL_TEXTURE_STACK_DEPTH); - gpu_state_print_fl(GL_TRANSPOSE_COLOR_MATRIX); - gpu_state_print_fl(GL_TRANSPOSE_MODELVIEW_MATRIX); - gpu_state_print_fl(GL_TRANSPOSE_PROJECTION_MATRIX); - gpu_state_print_fl(GL_TRANSPOSE_TEXTURE_MATRIX); - gpu_state_print_fl(GL_UNPACK_ALIGNMENT); - gpu_state_print_fl(GL_UNPACK_IMAGE_HEIGHT); - gpu_state_print_fl(GL_UNPACK_LSB_FIRST); - gpu_state_print_fl(GL_UNPACK_ROW_LENGTH); - gpu_state_print_fl(GL_UNPACK_SKIP_IMAGES); - gpu_state_print_fl(GL_UNPACK_SKIP_PIXELS); - gpu_state_print_fl(GL_UNPACK_SKIP_ROWS); - gpu_state_print_fl(GL_UNPACK_SWAP_BYTES); - gpu_state_print_fl(GL_VERTEX_ARRAY); - gpu_state_print_fl(GL_VERTEX_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_VERTEX_ARRAY_SIZE); - gpu_state_print_fl(GL_VERTEX_ARRAY_STRIDE); - gpu_state_print_fl(GL_VERTEX_ARRAY_TYPE); - gpu_state_print_fl(GL_VERTEX_PROGRAM_POINT_SIZE); - gpu_state_print_fl(GL_VERTEX_PROGRAM_TWO_SIDE); - gpu_state_print_fl(GL_VIEWPORT); - gpu_state_print_fl(GL_ZOOM_X); - gpu_state_print_fl(GL_ZOOM_Y); -} - -#undef gpu_state_print_fl diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 427e179f29a..f9cf3235ac1 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -38,8 +38,6 @@ #include <string.h> -#include "GPU_glew.h" - #include "BLI_blenlib.h" #include "BLI_linklist.h" #include "BLI_math.h" @@ -81,6 +79,7 @@ #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_material.h" +#include "GPU_matrix.h" #include "GPU_shader.h" #include "GPU_texture.h" @@ -109,23 +108,27 @@ static void gpu_mcol(unsigned int ucol) } void GPU_render_text( - MTexPoly *mtexpoly, int mode, - const char *textstr, int textlen, unsigned int *col, + int mode, const char *textstr, int textlen, unsigned int *col, const float *v_quad[4], const float *uv_quad[4], int glattrib) { - if ((mode & GEMAT_TEXT) && (textlen > 0) && mtexpoly->tpage) { + /* XXX, 2.8 removes texface */ +#if 0 + Image *ima = mtexpoly->tpage; +#else + Image *ima = NULL; +#endif + if ((mode & GEMAT_TEXT) && (textlen > 0) && ima) { const float *v1 = v_quad[0]; const float *v2 = v_quad[1]; const float *v3 = v_quad[2]; const float *v4 = v_quad[3]; - Image *ima = (Image *)mtexpoly->tpage; const size_t textlen_st = textlen; float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance; - + /* multiline */ float line_start = 0.0f, line_height; - + if (v4) line_height = max_ffff(v1[1], v2[1], v3[1], v4[2]) - min_ffff(v1[1], v2[1], v3[1], v4[2]); else @@ -133,50 +136,48 @@ void GPU_render_text( line_height *= 1.2f; /* could be an option? */ /* end multiline */ - + /* color has been set */ - if (mtexpoly->mode & TF_OBCOL) - col = NULL; - else if (!col) + if (!col) glColor3f(1.0f, 1.0f, 1.0f); - glPushMatrix(); - + gpuPushMatrix(); + /* get the tab width */ ImBuf *first_ibuf = BKE_image_get_first_ibuf(ima); matrixGlyph(first_ibuf, ' ', ¢erx, ¢ery, - &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); - + &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); + float advance_tab = advance * 4; /* tab width could also be an option */ - - + + for (size_t index = 0; index < textlen_st; ) { unsigned int character; float uv[4][2]; /* lets calculate offset stuff */ character = BLI_str_utf8_as_unicode_and_size_safe(textstr + index, &index); - + if (character == '\n') { - glTranslatef(line_start, -line_height, 0.0f); + gpuTranslate2f(line_start, -line_height); line_start = 0.0f; continue; } else if (character == '\t') { - glTranslatef(advance_tab, 0.0f, 0.0f); + gpuTranslate2f(advance_tab, 0.0f); line_start -= advance_tab; /* so we can go back to the start of the line */ continue; - + } else if (character > USHRT_MAX) { /* not much we can do here bmfonts take ushort */ character = '?'; } - + /* space starts at offset 1 */ /* character = character - ' ' + 1; */ matrixGlyph(first_ibuf, character, & centerx, ¢ery, - &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); + &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); uv[0][0] = (uv_quad[0][0] - centerx) * sizex + transx; uv[0][1] = (uv_quad[0][1] - centery) * sizey + transy; @@ -184,13 +185,13 @@ void GPU_render_text( uv[1][1] = (uv_quad[1][1] - centery) * sizey + transy; uv[2][0] = (uv_quad[2][0] - centerx) * sizex + transx; uv[2][1] = (uv_quad[2][1] - centery) * sizey + transy; - + glBegin(GL_POLYGON); if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[0]); else glTexCoord2fv(uv[0]); if (col) gpu_mcol(col[0]); glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]); - + if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[1]); else glTexCoord2fv(uv[1]); if (col) gpu_mcol(col[1]); @@ -212,28 +213,29 @@ void GPU_render_text( } glEnd(); - glTranslatef(advance, 0.0f, 0.0f); + gpuTranslate2f(advance, 0.0f); line_start -= advance; /* so we can go back to the start of the line */ } - glPopMatrix(); + gpuPopMatrix(); BKE_image_release_ibuf(ima, first_ibuf, NULL); } } /* Checking powers of two for images since OpenGL ES requires it */ - +#ifdef WITH_DDS static bool is_power_of_2_resolution(int w, int h) { return is_power_of_2_i(w) && is_power_of_2_i(h); } +#endif static bool is_over_resolution_limit(GLenum textarget, int w, int h) { int size = (textarget == GL_TEXTURE_2D) ? GPU_max_texture_size() : GPU_max_cube_map_size(); int reslimit = (U.glreslimit != 0) ? - min_ii(U.glreslimit, size) : size; + min_ii(U.glreslimit, size) : size; return (w > reslimit || h > reslimit); } @@ -269,8 +271,7 @@ static struct GPUTextureState { int alphablend; float anisotropic; int gpu_mipmap; - MTexPoly *lasttface; -} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0, NULL}; +} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0}; /* Mipmap settings */ @@ -279,36 +280,13 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap) int old_value = GTS.gpu_mipmap; /* only actually enable if it's supported */ - GTS.gpu_mipmap = gpu_mipmap && GLEW_EXT_framebuffer_object; + GTS.gpu_mipmap = gpu_mipmap; if (old_value != GTS.gpu_mipmap) { GPU_free_images(); } } -static void gpu_generate_mipmap(GLenum target) -{ - const bool is_ati = GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY); - int target_enabled = 0; - - /* work around bug in ATI driver, need to have GL_TEXTURE_2D enabled - * http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation */ - if (is_ati) { - target_enabled = glIsEnabled(target); - if (!target_enabled) - glEnable(target); - } - - /* TODO: simplify when we transition to GL >= 3 */ - if (GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object) - glGenerateMipmap(target); - else if (GLEW_EXT_framebuffer_object) - glGenerateMipmapEXT(target); - - if (is_ati && !target_enabled) - glDisable(target); -} - void GPU_set_mipmap(bool mipmap) { if (GTS.domipmap != mipmap) { @@ -415,43 +393,16 @@ static unsigned int *gpu_get_image_bindcode(Image *ima, GLenum textarget) return bind; } -void GPU_clear_tpage(bool force) -{ - if (GTS.lasttface == NULL && !force) - return; - - GTS.lasttface = NULL; - GTS.curtile = 0; - GTS.curima = NULL; - if (GTS.curtilemode != 0) { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - } - GTS.curtilemode = 0; - GTS.curtileXRep = 0; - GTS.curtileYRep = 0; - GTS.alphablend = -1; - - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - glDisable(GL_ALPHA_TEST); -} - static void gpu_set_alpha_blend(GPUBlendMode alphablend) { if (alphablend == GPU_BLEND_SOLID) { glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else if (alphablend == GPU_BLEND_ADD) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); - glDisable(GL_ALPHA_TEST); glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); } else if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ALPHA_SORT)) { @@ -460,59 +411,20 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend) /* for OpenGL render we use the alpha channel, this makes alpha blend correct */ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - + /* if U.glalphaclip == 1.0, some cards go bonkers... * turn off alpha test in this case */ - /* added after 2.45 to clip alpha */ - if (U.glalphaclip == 1.0f) { - glDisable(GL_ALPHA_TEST); - } - else { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, U.glalphaclip); - } } else if (alphablend == GPU_BLEND_CLIP) { glDisable(GL_BLEND); glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0.5f); } else if (alphablend == GPU_BLEND_ALPHA_TO_COVERAGE) { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, U.glalphaclip); glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); } } -static void gpu_verify_alpha_blend(int alphablend) -{ - /* verify alpha blending modes */ - if (GTS.alphablend == alphablend) - return; - - gpu_set_alpha_blend(alphablend); - GTS.alphablend = alphablend; -} - -static void gpu_verify_reflection(Image *ima) -{ - if (ima && (ima->flag & IMA_REFLECT)) { - /* enable reflection mapping */ - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - } - else { - /* disable reflection mapping */ - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - } -} - typedef struct VerifyThreadData { ImBuf *ibuf; float *srgb_frect; @@ -534,8 +446,6 @@ static void gpu_verify_high_bit_srgb_buffer_slice(float *srgb_frect, ibuf->x, height, ibuf->x, ibuf->x); IMB_buffer_float_unpremultiply(current_srgb_frect, ibuf->x, height); - /* Clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images. */ - IMB_buffer_float_clamp(current_srgb_frect, ibuf->x, height); } static void verify_thread_do(void *data_v, @@ -604,19 +514,6 @@ int GPU_verify_image( return (ima != NULL); } - /* if tiling mode or repeat changed, change texture matrix to fit */ - if (GTS.tilemode != GTS.curtilemode || GTS.curtileXRep != GTS.tileXRep || - GTS.curtileYRep != GTS.tileYRep) - { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - - if (ima && (ima->tpageflag & IMA_TILES)) - glScalef(ima->xrep, ima->yrep, 1.0f); - - glMatrixMode(GL_MODELVIEW); - } - /* check if we have a valid image */ if (ima == NULL || ima->ok == 0) return 0; @@ -652,29 +549,29 @@ int GPU_verify_image( GPU_free_image(ima); ima->tpageflag &= ~IMA_TPAGE_REFRESH; } - + if (GTS.tilemode) { /* tiled mode */ if (ima->repbind == NULL) gpu_make_repbind(ima); if (GTS.tile >= ima->totbind) GTS.tile = 0; - + /* this happens when you change repeat buttons */ if (ima->repbind && textarget == GL_TEXTURE_2D) bind = &ima->repbind[GTS.tile]; else bind = gpu_get_image_bindcode(ima, textarget); - + if (*bind == 0) { short texwindx = ibuf->x / ima->xrep; short texwindy = ibuf->y / ima->yrep; - + if (GTS.tile >= ima->xrep * ima->yrep) GTS.tile = ima->xrep * ima->yrep - 1; - + short texwinsy = GTS.tile / ima->xrep; short texwinsx = GTS.tile - texwinsy * ima->xrep; - + texwinsx *= texwindx; texwinsy *= texwindy; - + tpx = texwindx; tpy = texwindy; @@ -748,7 +645,7 @@ int GPU_verify_image( memcpy(tilerectrow, rectrow, tpx * sizeof(*rectrow)); } - + rect = tilerect; } } @@ -759,13 +656,13 @@ int GPU_verify_image( else #endif GPU_create_gl_tex(bind, rect, frect, rectw, recth, textarget, mipmap, use_high_bit_depth, ima); - + /* mark as non-color data texture */ if (*bind) { if (is_data) - ima->tpageflag |= IMA_GLBIND_IS_DATA; + ima->tpageflag |= IMA_GLBIND_IS_DATA; else - ima->tpageflag &= ~IMA_GLBIND_IS_DATA; + ima->tpageflag &= ~IMA_GLBIND_IS_DATA; } /* clean up */ @@ -858,30 +755,6 @@ void GPU_create_gl_tex( int tpx = rectw; int tpy = recth; - /* scale if not a power of two. this is not strictly necessary for newer - * GPUs (OpenGL version >= 2.0) since they support non-power-of-two-textures - * Then don't bother scaling for hardware that supports NPOT textures! */ - if (textarget == GL_TEXTURE_2D && - ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(rectw, recth)) || - is_over_resolution_limit(textarget, rectw, recth))) - { - rectw = smaller_power_of_2_limit(rectw); - recth = smaller_power_of_2_limit(recth); - - if (use_high_bit_depth) { - ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy); - IMB_scaleImBuf(ibuf, rectw, recth); - - frect = ibuf->rect_float; - } - else { - ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy); - IMB_scaleImBuf(ibuf, rectw, recth); - - rect = ibuf->rect; - } - } - /* create image */ glGenTextures(1, (GLuint *)bind); glBindTexture(textarget, *bind); @@ -900,7 +773,7 @@ void GPU_create_gl_tex( if (GPU_get_mipmap() && mipmap) { if (GTS.gpu_mipmap) { - gpu_generate_mipmap(GL_TEXTURE_2D); + glGenerateMipmap(GL_TEXTURE_2D); } else { int i; @@ -951,7 +824,7 @@ void GPU_create_gl_tex( if (GPU_get_mipmap() && mipmap) { if (GTS.gpu_mipmap) { - gpu_generate_mipmap(GL_TEXTURE_CUBE_MAP); + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); } else { if (!ibuf) { @@ -975,7 +848,7 @@ void GPU_create_gl_tex( if (mip_cube_map) { for (int j = 0; j < 6; j++) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i, - informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]); + informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]); } } gpu_del_cube_map(mip_cube_map); @@ -1056,7 +929,7 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf) size = ((width + 3) / 4) * ((height + 3) / 4) * blocksize; glCompressedTexImage2D(GL_TEXTURE_2D, i, format, width, height, - 0, size, ibuf->dds_data.data + offset); + 0, size, ibuf->dds_data.data + offset); offset += size; width >>= 1; @@ -1091,62 +964,6 @@ void GPU_create_gl_tex_compressed( } #endif } -static void gpu_verify_repeat(Image *ima) -{ - /* set either clamp or repeat in X/Y */ - if (ima->tpageflag & IMA_CLAMP_U) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - - if (ima->tpageflag & IMA_CLAMP_V) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); -} - -int GPU_set_tpage(MTexPoly *mtexpoly, int mipmap, int alphablend) -{ - /* check if we need to clear the state */ - if (mtexpoly == NULL) { - GPU_clear_tpage(false); - return 0; - } - - Image *ima = mtexpoly->tpage; - GTS.lasttface = mtexpoly; - - gpu_verify_alpha_blend(alphablend); - gpu_verify_reflection(ima); - - if (GPU_verify_image(ima, NULL, GL_TEXTURE_2D, mtexpoly->tile, 1, mipmap, false)) { - GTS.curtile = GTS.tile; - GTS.curima = GTS.ima; - GTS.curtilemode = GTS.tilemode; - GTS.curtileXRep = GTS.tileXRep; - GTS.curtileYRep = GTS.tileYRep; - - glEnable(GL_TEXTURE_2D); - } - else { - glDisable(GL_TEXTURE_2D); - - GTS.curtile = 0; - GTS.curima = NULL; - GTS.curtilemode = 0; - GTS.curtileXRep = 0; - GTS.curtileYRep = 0; - - return 0; - } - - gpu_verify_repeat(ima); - - /* Did this get lost in the image recode? */ - /* BKE_image_tag_time(ima);*/ - - return 1; -} /* these two functions are called on entering and exiting texture paint mode, * temporary disabling/enabling mipmapping on all images for quick texture @@ -1206,9 +1023,7 @@ void GPU_paint_set_mipmap(bool mipmap) /* check if image has been downscaled and do scaled partial update */ static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h) { - if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) || - is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) - { + if (is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) { int x_limit = smaller_power_of_2_limit(ibuf->x); int y_limit = smaller_power_of_2_limit(ibuf->y); @@ -1261,7 +1076,7 @@ static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, } if (GPU_get_mipmap()) { - gpu_generate_mipmap(GL_TEXTURE_2D); + glGenerateMipmap(GL_TEXTURE_2D); } else { ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; @@ -1296,7 +1111,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i float *buffer = MEM_mallocN(w * h * sizeof(float) * 4, "temp_texpaint_float_buf"); bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0; IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data); - + if (gpu_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) { MEM_freeN(buffer); BKE_image_release_ibuf(ima, ibuf, NULL); @@ -1311,7 +1126,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i /* we have already accounted for the case where GTS.gpu_mipmap is false * so we will be using GPU mipmap generation here */ if (GPU_get_mipmap()) { - gpu_generate_mipmap(GL_TEXTURE_2D); + glGenerateMipmap(GL_TEXTURE_2D); } else { ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; @@ -1337,7 +1152,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i glPixelStorei(GL_UNPACK_SKIP_ROWS, y); glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, - GL_UNSIGNED_BYTE, ibuf->rect); + GL_UNSIGNED_BYTE, ibuf->rect); glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length); glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels); @@ -1345,7 +1160,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i /* see comment above as to why we are using gpu mipmap generation here */ if (GPU_get_mipmap()) { - gpu_generate_mipmap(GL_TEXTURE_2D); + glGenerateMipmap(GL_TEXTURE_2D); } else { ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; @@ -1361,9 +1176,9 @@ void GPU_update_images_framechange(void) if (ima->tpageflag & IMA_TWINANIM) { if (ima->twend >= ima->xrep * ima->yrep) ima->twend = ima->xrep * ima->yrep - 1; - + /* check: is bindcode not in the array? free. (to do) */ - + ima->lastframe++; if (ima->lastframe > ima->twend) ima->lastframe = ima->twsta; @@ -1386,9 +1201,9 @@ int GPU_update_image_time(Image *ima, double time) if (ima->tpageflag & IMA_TWINANIM) { if (ima->twend >= ima->xrep * ima->yrep) ima->twend = ima->xrep * ima->yrep - 1; - + /* check: is the bindcode not in the array? Then free. (still to do) */ - + float diff = (float)((float)time - ima->lastupdate); inc = (int)(diff * (float)ima->animspeed); @@ -1437,31 +1252,60 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres) if (smoke_has_colors(sds->fluid)) { float *data = MEM_callocN(sizeof(float) * sds->total_cells * 4, "smokeColorTexture"); smoke_get_rgba(sds->fluid, data, 0); - sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 4, data); + sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], data, NULL); MEM_freeN(data); } /* density only */ else { - sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_density(sds->fluid)); + sds->tex = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1, + GPU_R8, smoke_get_density(sds->fluid), NULL); + + /* Swizzle the RGBA components to read the Red channel so + * that the shader stay the same for colored and non color + * density textures. */ + GPU_texture_bind(sds->tex, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); + GPU_texture_unbind(sds->tex); } - sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_flame(sds->fluid)) : NULL; + sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? + GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1, + GPU_R8, smoke_get_flame(sds->fluid), NULL) : + NULL; } else if (!sds->tex && highres) { /* rgba texture for color + density */ if (smoke_turbulence_has_colors(sds->wt)) { float *data = MEM_callocN(sizeof(float) * smoke_turbulence_get_cells(sds->wt) * 4, "smokeColorTexture"); smoke_turbulence_get_rgba(sds->wt, data, 0); - sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 4, data); + sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], data, NULL); MEM_freeN(data); } /* density only */ else { - sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_density(sds->wt)); + sds->tex = GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, + GPU_R8, smoke_turbulence_get_density(sds->wt), NULL); + + /* Swizzle the RGBA components to read the Red channel so + * that the shader stay the same for colored and non color + * density textures. */ + GPU_texture_bind(sds->tex, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); + GPU_texture_unbind(sds->tex); } - sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_flame(sds->wt)) : NULL; + sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? + GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, + GPU_R8, smoke_turbulence_get_flame(sds->wt), NULL) : + NULL; } - sds->tex_shadow = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, sds->shadow); + sds->tex_shadow = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1, + GPU_R8, sds->shadow, NULL); } #else // WITH_SMOKE (void)highres; @@ -1528,7 +1372,7 @@ void GPU_free_image(Image *ima) /* free repeated image binding */ if (ima->repbind) { glDeleteTextures(ima->totbind, (GLuint *)ima->repbind); - + MEM_freeN(ima->repbind); ima->repbind = NULL; } @@ -1601,7 +1445,7 @@ typedef struct GPUMaterialFixed { float spec[3]; int hard; float alpha; -} GPUMaterialFixed; +} GPUMaterialFixed; static struct GPUMaterialState { GPUMaterialFixed (*matbuf); @@ -1619,7 +1463,6 @@ static struct GPUMaterialState { DupliObject *dob; Scene *gscene; int glay; - bool gscenelock; float (*gviewmat)[4]; float (*gviewinv)[4]; float (*gviewcamtexcofac); @@ -1657,12 +1500,12 @@ static void gpu_material_to_fixed( copy_v3_v3(smat->spec, &bmat->specr); smat->alpha = 1.0f; smat->hard = CLAMPIS(bmat->har, 0, 128); - + if (dimdown) { mul_v3_fl(smat->diff, 0.8f); mul_v3_fl(smat->spec, 0.5f); } - + if (gamma) { linearrgb_to_srgb_v3_v3(smat->diff, smat->diff); linearrgb_to_srgb_v3_v3(smat->spec, smat->spec); @@ -1673,7 +1516,7 @@ static void gpu_material_to_fixed( if (bmat->shade_flag & MA_OBCOLOR) mul_v3_v3(smat->diff, ob->col); - + mul_v3_v3fl(smat->spec, &bmat->specr, bmat->spec); smat->hard = CLAMPIS(bmat->har, 1, 128); smat->alpha = 1.0f; @@ -1710,7 +1553,7 @@ void GPU_end_dupli_object(void) } void GPU_begin_object_materials( - View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob, + View3D *v3d, RegionView3D *rv3d, Scene *scene, ViewLayer *view_layer, Object *ob, bool glsl, bool *do_alpha_after) { Material *ma; @@ -1749,8 +1592,10 @@ void GPU_begin_object_materials( #ifdef WITH_GAMEENGINE if (rv3d->rflag & RV3D_IS_GAME_ENGINE) { - ob = BKE_object_lod_matob_get(ob, scene); + ob = BKE_object_lod_matob_get(ob, view_layer); } +#else + UNUSED_VARS(view_layer); #endif /* initialize state */ @@ -1775,7 +1620,6 @@ void GPU_begin_object_materials( GMS.is_opensubdiv = use_opensubdiv; GMS.totmat = use_matcap ? 1 : ob->totcol + 1; /* materials start from 1, default material is 0 */ GMS.glay = (v3d->localvd) ? v3d->localvd->lay : v3d->lay; /* keep lamps visible in local view */ - GMS.gscenelock = (v3d->scenelock != 0); GMS.gviewmat = rv3d->viewmat; GMS.gviewinv = rv3d->viewinv; GMS.gviewcamtexcofac = rv3d->viewcamtexcofac; @@ -1789,7 +1633,7 @@ void GPU_begin_object_materials( GMS.is_alpha_pass = (v3d->transp != false); if (GMS.use_alpha_pass) *do_alpha_after = false; - + if (GMS.totmat > FIXEDMAT) { GMS.matbuf = MEM_callocN(sizeof(GPUMaterialFixed) * GMS.totmat, "GMS.matbuf"); GMS.gmatbuf = MEM_callocN(sizeof(*GMS.gmatbuf) * GMS.totmat, "GMS.matbuf"); @@ -1808,11 +1652,11 @@ void GPU_begin_object_materials( /* do material 1 too, for displists! */ memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed)); - + GMS.alphablend[0] = GPU_BLEND_SOLID; } else { - + /* no materials assigned? */ if (ob->totcol == 0) { gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes, true); @@ -1827,7 +1671,7 @@ void GPU_begin_object_materials( GMS.alphablend[0] = GPU_BLEND_SOLID; } - + /* setup materials */ for (a = 1; a <= ob->totcol; a++) { /* find a suitable material */ @@ -1985,13 +1829,13 @@ int GPU_object_material_bind(int nr, void *attribs) gpu_get_particle_info(&partile_info); } - if (GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) { + if ((GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) != 0) { GPU_get_object_info(object_info, mat); } GPU_material_bind( gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT), - GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock); + GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac); auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f; GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info, object_info); @@ -2062,7 +1906,7 @@ void GPU_set_material_alpha_blend(int alphablend) { if (GMS.lastalphablend == alphablend) return; - + gpu_set_alpha_blend(alphablend); GMS.lastalphablend = alphablend; } @@ -2133,13 +1977,6 @@ void GPU_end_object_materials(void) GMS.gmatbuf = NULL; GMS.alphablend = NULL; GMS.two_sided_lighting = false; - - /* resetting the texture matrix after the scaling needed for tiled textures */ - if (GTS.tilemode) { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - } } /* Lights */ @@ -2153,13 +1990,13 @@ int GPU_default_lights(void) U.light[0].col[0] = 0.8; U.light[0].col[1] = 0.8; U.light[0].col[2] = 0.8; U.light[0].spec[0] = 0.5; U.light[0].spec[1] = 0.5; U.light[0].spec[2] = 0.5; U.light[0].spec[3] = 1.0; - + U.light[1].flag = 0; U.light[1].vec[0] = 0.5; U.light[1].vec[1] = 0.5; U.light[1].vec[2] = 0.1; U.light[1].col[0] = 0.4; U.light[1].col[1] = 0.4; U.light[1].col[2] = 0.8; U.light[1].spec[0] = 0.3; U.light[1].spec[1] = 0.3; U.light[1].spec[2] = 0.5; U.light[1].spec[3] = 1.0; - + U.light[2].flag = 0; U.light[2].vec[0] = 0.3; U.light[2].vec[1] = -0.3; U.light[2].vec[2] = -0.2; U.light[2].col[0] = 0.8; U.light[2].col[1] = 0.5; U.light[2].col[2] = 0.4; @@ -2192,31 +2029,28 @@ int GPU_default_lights(void) return count; } -int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][4], int ortho) +int GPU_scene_object_lights(ViewLayer *view_layer, float viewmat[4][4], int ortho) { /* disable all lights */ for (int count = 0; count < 8; count++) GPU_basic_shader_light_set(count, NULL); - + /* view direction for specular is not computed correct by default in * opengl, so we set the settings ourselves */ GPU_basic_shader_light_set_viewer(!ortho); int count = 0; - for (Base *base = scene->base.first; base; base = base->next) { + for (Base *base = FIRSTBASE(view_layer); base; base = base->next) { if (base->object->type != OB_LAMP) continue; - if (!(base->lay & lay) || !(base->lay & ob->lay)) - continue; - Lamp *la = base->object->data; - + /* setup lamp transform */ - glPushMatrix(); - glLoadMatrixf((float *)viewmat); - + gpuPushMatrix(); + gpuLoadMatrix(viewmat); + /* setup light */ GPULightData light = {0}; @@ -2235,7 +2069,7 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][ light.constant_attenuation = 1.0f; light.linear_attenuation = la->att1 / la->dist; light.quadratic_attenuation = la->att2 / (la->dist * la->dist); - + if (la->type == LA_SPOT) { light.type = GPU_LIGHT_SPOT; negate_v3_v3(light.direction, base->object->obmat[2]); @@ -2246,11 +2080,11 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][ else light.type = GPU_LIGHT_POINT; } - + GPU_basic_shader_light_set(count, &light); - - glPopMatrix(); - + + gpuPopMatrix(); + count++; if (count == 8) break; @@ -2297,64 +2131,36 @@ static void gpu_multisample(bool enable) void GPU_state_init(void) { - float mat_ambient[] = { 0.0, 0.0, 0.0, 0.0 }; - float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 }; - - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient); - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 35); - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - GPU_default_lights(); - + + GPU_disable_program_point_size(); + + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + glDepthFunc(GL_LEQUAL); - /* scaling matrices */ - glEnable(GL_NORMALIZE); - glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); - glDisable(GL_FOG); - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); - glDisable(GL_LOGIC_OP); + glDisable(GL_COLOR_LOGIC_OP); glDisable(GL_STENCIL_TEST); - glDisable(GL_TEXTURE_1D); - glDisable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - /* default disabled, enable should be local per function */ - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - glPixelTransferi(GL_MAP_COLOR, GL_FALSE); - glPixelTransferi(GL_RED_SCALE, 1); - glPixelTransferi(GL_RED_BIAS, 0); - glPixelTransferi(GL_GREEN_SCALE, 1); - glPixelTransferi(GL_GREEN_BIAS, 0); - glPixelTransferi(GL_BLUE_SCALE, 1); - glPixelTransferi(GL_BLUE_BIAS, 0); - glPixelTransferi(GL_ALPHA_SCALE, 1); - glPixelTransferi(GL_ALPHA_BIAS, 0); - - glPixelTransferi(GL_DEPTH_BIAS, 0); - glPixelTransferi(GL_DEPTH_SCALE, 1); - glDepthRange(0.0, 1.0); - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); + glDepthRange(0.0, 1.0); glFrontFace(GL_CCW); glCullFace(GL_BACK); glDisable(GL_CULL_FACE); gpu_multisample(false); +} + +void GPU_enable_program_point_size(void) +{ + glEnable(GL_PROGRAM_POINT_SIZE); +} - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); +void GPU_disable_program_point_size(void) +{ + glDisable(GL_PROGRAM_POINT_SIZE); } #ifdef WITH_OPENSUBDIV @@ -2500,10 +2306,10 @@ void GPU_select_to_index_array(unsigned int *col, const unsigned int size) { #define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \ for (i = size; i--; col++) { \ - if ((c = *col)) { \ - *col = INDEX_FROM_BUF_BITS(c); \ - } \ - } ((void)0) + if ((c = *col)) { \ + *col = INDEX_FROM_BUF_BITS(c); \ + } \ + } ((void)0) if (size > 0) { unsigned int i, c; @@ -2531,4 +2337,173 @@ void GPU_select_to_index_array(unsigned int *col, const unsigned int size) #undef INDEX_BUF_ARRAY } +#define STATE_STACK_DEPTH 16 + +typedef struct { + eGPUAttribMask mask; + + /* GL_ENABLE_BIT */ + unsigned int is_blend : 1; + unsigned int is_cull_face : 1; + unsigned int is_depth_test : 1; + unsigned int is_dither : 1; + unsigned int is_lighting : 1; + unsigned int is_line_smooth : 1; + unsigned int is_color_logic_op : 1; + unsigned int is_multisample : 1; + unsigned int is_polygon_offset_line : 1; + unsigned int is_polygon_offset_fill : 1; + unsigned int is_polygon_smooth : 1; + unsigned int is_sample_alpha_to_coverage : 1; + unsigned int is_scissor_test : 1; + unsigned int is_stencil_test : 1; + + bool is_clip_plane[6]; + + /* GL_DEPTH_BUFFER_BIT */ + /* unsigned int is_depth_test : 1; */ + int depth_func; + double depth_clear_value; + bool depth_write_mask; + + /* GL_SCISSOR_BIT */ + int scissor_box[4]; + /* unsigned int is_scissor_test : 1; */ + + /* GL_VIEWPORT_BIT */ + int viewport[4]; + double near_far[2]; +} GPUAttribValues; + +typedef struct { + GPUAttribValues attrib_stack[STATE_STACK_DEPTH]; + unsigned int top; +} GPUAttribStack; + +static GPUAttribStack state = { + .top = 0 +}; + +#define AttribStack state +#define Gwn_VertAttr state.attrib_stack[state.top] + +/** + * Replacement for glPush/PopAttributes + * + * We don't need to cover all the options of legacy OpenGL + * but simply the ones used by Blender. + */ +void gpuPushAttrib(eGPUAttribMask mask) +{ + Gwn_VertAttr.mask = mask; + + if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { + Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); + glGetIntegerv(GL_DEPTH_FUNC, &Gwn_VertAttr.depth_func); + glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Gwn_VertAttr.depth_clear_value); + glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Gwn_VertAttr.depth_write_mask); + } + + if ((mask & GPU_ENABLE_BIT) != 0) { + Gwn_VertAttr.is_blend = glIsEnabled(GL_BLEND); + + for (int i = 0; i < 6; i++) { + Gwn_VertAttr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i); + } + + Gwn_VertAttr.is_cull_face = glIsEnabled(GL_CULL_FACE); + Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); + Gwn_VertAttr.is_dither = glIsEnabled(GL_DITHER); + Gwn_VertAttr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH); + Gwn_VertAttr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP); + Gwn_VertAttr.is_multisample = glIsEnabled(GL_MULTISAMPLE); + Gwn_VertAttr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE); + Gwn_VertAttr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL); + Gwn_VertAttr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH); + Gwn_VertAttr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE); + Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + Gwn_VertAttr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST); + } + + if ((mask & GPU_SCISSOR_BIT) != 0) { + Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Gwn_VertAttr.scissor_box); + } + + if ((mask & GPU_VIEWPORT_BIT) != 0) { + glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Gwn_VertAttr.near_far); + glGetIntegerv(GL_VIEWPORT, (GLint *)&Gwn_VertAttr.viewport); + } + + if ((mask & GPU_BLEND_BIT) != 0) { + Gwn_VertAttr.is_blend = glIsEnabled(GL_BLEND); + } + + BLI_assert(AttribStack.top < STATE_STACK_DEPTH); + AttribStack.top++; +} + +static void restore_mask(GLenum cap, const bool value) +{ + if (value) { + glEnable(cap); + } + else { + glDisable(cap); + } +} + +void gpuPopAttrib(void) +{ + BLI_assert(AttribStack.top > 0); + AttribStack.top--; + + GLint mask = Gwn_VertAttr.mask; + + if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { + restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test); + glDepthFunc(Gwn_VertAttr.depth_func); + glClearDepth(Gwn_VertAttr.depth_clear_value); + glDepthMask(Gwn_VertAttr.depth_write_mask); + } + + if ((mask & GPU_ENABLE_BIT) != 0) { + restore_mask(GL_BLEND, Gwn_VertAttr.is_blend); + + for (int i = 0; i < 6; i++) { + restore_mask(GL_CLIP_PLANE0 + i, Gwn_VertAttr.is_clip_plane[i]); + } + + restore_mask(GL_CULL_FACE, Gwn_VertAttr.is_cull_face); + restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test); + restore_mask(GL_DITHER, Gwn_VertAttr.is_dither); + restore_mask(GL_LINE_SMOOTH, Gwn_VertAttr.is_line_smooth); + restore_mask(GL_COLOR_LOGIC_OP, Gwn_VertAttr.is_color_logic_op); + restore_mask(GL_MULTISAMPLE, Gwn_VertAttr.is_multisample); + restore_mask(GL_POLYGON_OFFSET_LINE, Gwn_VertAttr.is_polygon_offset_line); + restore_mask(GL_POLYGON_OFFSET_FILL, Gwn_VertAttr.is_polygon_offset_fill); + restore_mask(GL_POLYGON_SMOOTH, Gwn_VertAttr.is_polygon_smooth); + restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Gwn_VertAttr.is_sample_alpha_to_coverage); + restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test); + restore_mask(GL_STENCIL_TEST, Gwn_VertAttr.is_stencil_test); + } + + if ((mask & GPU_VIEWPORT_BIT) != 0) { + glViewport(Gwn_VertAttr.viewport[0], Gwn_VertAttr.viewport[1], Gwn_VertAttr.viewport[2], Gwn_VertAttr.viewport[3]); + glDepthRange(Gwn_VertAttr.near_far[0], Gwn_VertAttr.near_far[1]); + } + + if ((mask & GPU_SCISSOR_BIT) != 0) { + restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test); + glScissor(Gwn_VertAttr.scissor_box[0], Gwn_VertAttr.scissor_box[1], Gwn_VertAttr.scissor_box[2], Gwn_VertAttr.scissor_box[3]); + } + + if ((mask & GPU_BLEND_BIT) != 0) { + restore_mask(GL_BLEND, Gwn_VertAttr.is_blend); + } +} + +#undef Gwn_VertAttr +#undef AttribStack + /** \} */ diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index e0ce87d0e68..57df877bf18 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -56,14 +56,11 @@ /* Extensions support */ /* -- extension: version of GL that absorbs it + * EXT_gpu_shader4: 3.0 * ARB_framebuffer object: 3.0 - * EXT_framebuffer_object: 3.0 - * EXT_framebuffer_blit: 3.0 - * EXT_framebuffer_multisample: 3.0 * EXT_framebuffer_multisample_blit_scaled: ??? * ARB_draw_instanced: 3.1 * ARB_texture_multisample: 3.2 - * EXT_geometry_shader4: 3.2 * ARB_texture_query_lod: 4.0 */ @@ -71,7 +68,8 @@ static struct GPUGlobal { GLint maxtexsize; GLint maxcubemapsize; GLint maxtextures; - bool extdisabled; + GLint maxubosize; + GLint maxubobinds; int colordepth; int samples_color_texture_max; GPUDeviceType device; @@ -93,11 +91,6 @@ bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver) /* GPU Extensions */ -void GPU_extensions_disable(void) -{ - GG.extdisabled = true; -} - int GPU_max_texture_size(void) { return GG.maxtexsize; @@ -123,6 +116,16 @@ int GPU_max_cube_map_size(void) return GG.maxcubemapsize; } +int GPU_max_ubo_binds(void) +{ + return GG.maxubobinds; +} + +int GPU_max_ubo_size(void) +{ + return GG.maxubosize; +} + void GPU_get_dfdy_factors(float fac[2]) { copy_v2_v2(fac, GG.dfdyfactors); @@ -130,8 +133,11 @@ void GPU_get_dfdy_factors(float fac[2]) void gpu_extensions_init(void) { - /* BLI_assert(GLEW_VERSION_2_1); */ - /* ^-- maybe a bit extreme? */ + /* during 2.8 development each platform has its own OpenGL minimum requirements + * final 2.8 release will be unified on OpenGL 3.3 core profile, no required extensions + * see developer.blender.org/T49012 for details + */ + BLI_assert(GLEW_VERSION_3_3); glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GG.maxtextures); @@ -143,11 +149,22 @@ void gpu_extensions_init(void) else GG.max_anisotropy = 1.0f; + glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &GG.maxubobinds); + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GG.maxubosize); + +#ifndef NDEBUG + GLint ret; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &ret); + /* We expect FRONT_LEFT to be the default buffer. */ + BLI_assert(ret == GL_FRAMEBUFFER_DEFAULT); +#endif + GLint r, g, b; - glGetIntegerv(GL_RED_BITS, &r); - glGetIntegerv(GL_GREEN_BITS, &g); - glGetIntegerv(GL_BLUE_BITS, &b); - GG.colordepth = r + g + b; /* assumes same depth for RGB */ + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &r); + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, &g); + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, &b); + GG.colordepth = r + g + b; /* Assumes same depth for RGB. */ if (GLEW_VERSION_3_2 || GLEW_ARB_texture_multisample) { glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &GG.samples_color_texture_max); @@ -161,6 +178,14 @@ void gpu_extensions_init(void) GG.device = GPU_DEVICE_ATI; GG.driver = GPU_DRIVER_OFFICIAL; } + /* XXX : TODO : Remove this once this sampling mipmap problem is gone. + * https://github.com/dfelinto/opengl-sandbox/blob/downsample/README.md */ + else if (strstr(renderer, "AMD VEGA") && + strstr(vendor, "X.Org")) + { + GG.device = GPU_DEVICE_AMD_VEGA; + GG.driver = GPU_DRIVER_OPENSOURCE; + } else if (strstr(vendor, "NVIDIA")) { GG.device = GPU_DEVICE_NVIDIA; GG.driver = GPU_DRIVER_OFFICIAL; @@ -201,10 +226,6 @@ void gpu_extensions_init(void) GG.driver = GPU_DRIVER_ANY; } - /* make sure double side isn't used by default and only getting enabled in places where it's - * really needed to prevent different unexpected behaviors like with intel gme965 card (sergey) */ - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); - #ifdef _WIN32 GG.os = GPU_OS_WIN; #elif defined(__APPLE__) @@ -246,43 +267,6 @@ void gpu_extensions_exit(void) GPU_invalid_tex_free(); } -bool GPU_legacy_support(void) -{ - /* return whether or not current GL context is compatible with legacy OpenGL */ - static bool checked = false; - static bool support = true; - - if (!checked) { - if (GLEW_VERSION_3_2) { - GLint profile; - glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile); - - if (G.debug & G_DEBUG_GPU) { - printf("GL_CONTEXT_PROFILE_MASK = %#x (%s profile)\n", (unsigned int)profile, - (profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) ? "compatibility" : - (profile & GL_CONTEXT_CORE_PROFILE_BIT) ? "core" : "unknown"); - } - - if (profile == 0) { - /* workaround for nVidia's Linux driver */ - support = GLEW_ARB_compatibility; - } - else { - support = profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT; - } - } - else if (GLEW_VERSION_3_1) { - support = GLEW_ARB_compatibility; - } - - /* any OpenGL version <= 3.0 is legacy, so support remains true */ - - checked = true; - } - - return support; -} - bool GPU_full_non_power_of_two_support(void) { /* always supported on full GL but still relevant for OpenGL ES 2.0 where @@ -290,39 +274,11 @@ bool GPU_full_non_power_of_two_support(void) return true; } -bool GPU_display_list_support(void) -{ - /* deprecated in GL 3 - * supported on older GL and compatibility profile - * still queried by game engine - */ - return true; -} - bool GPU_bicubic_bump_support(void) { return GLEW_VERSION_4_0 || (GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0); } -bool GPU_geometry_shader_support(void) -{ - /* in GL 3.2 geometry shaders are fully supported - * core profile clashes with our other shaders so accept compatibility only - * other GL versions can use EXT_geometry_shader4 if available - */ - return (GLEW_VERSION_3_2 && GPU_legacy_support()) || GLEW_EXT_geometry_shader4; -} - -bool GPU_geometry_shader_support_via_extension(void) -{ - return GLEW_EXT_geometry_shader4 && !(GLEW_VERSION_3_2 && GPU_legacy_support()); -} - -bool GPU_instanced_drawing_support(void) -{ - return GLEW_VERSION_3_1 || GLEW_ARB_draw_instanced; -} - int GPU_color_depth(void) { return GG.colordepth; @@ -330,12 +286,14 @@ int GPU_color_depth(void) bool GPU_mem_stats_supported(void) { - return (GLEW_NVX_gpu_memory_info || (GLEW_ATI_meminfo)) && (G.debug & G_DEBUG_GPU_MEM); + return (GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo) && (G.debug & G_DEBUG_GPU_MEM); } void GPU_mem_stats_get(int *totalmem, int *freemem) { + /* TODO(merwin): use Apple's platform API to get this info */ + if (GLEW_NVX_gpu_memory_info) { /* returned value in Kb */ glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, totalmem); diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index e7a8beae5cc..09013cd29bd 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -32,9 +32,11 @@ #include "BKE_global.h" -#include "GPU_debug.h" -#include "GPU_glew.h" +#include "GPU_batch.h" +#include "GPU_draw.h" +#include "GPU_extensions.h" #include "GPU_framebuffer.h" +#include "GPU_matrix.h" #include "GPU_shader.h" #include "GPU_texture.h" @@ -43,8 +45,8 @@ static struct GPUFrameBufferGlobal { } GG = {0}; /* Number of maximum output slots. - * We support 4 outputs for now (usually we wouldn't need more to preserve fill rate) */ -#define GPU_FB_MAX_SLOTS 4 + * We support 5 outputs for now (usually we wouldn't need more to preserve fill rate) */ +#define GPU_FB_MAX_SLOTS 5 struct GPUFrameBuffer { GLuint object; @@ -54,44 +56,37 @@ struct GPUFrameBuffer { static void gpu_print_framebuffer_error(GLenum status, char err_out[256]) { + const char *format = "GPUFrameBuffer: framebuffer status %s\n"; const char *err = "unknown"; +#define format_status(X) \ + case GL_FRAMEBUFFER_##X: err = "GL_FRAMEBUFFER_"#X; \ + break; + switch (status) { - case GL_FRAMEBUFFER_COMPLETE_EXT: - break; - case GL_INVALID_OPERATION: - err = "Invalid operation"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - err = "Incomplete attachment"; - break; - case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - err = "Unsupported framebuffer format"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: - err = "Missing attachment"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: - err = "Attached images must have same dimensions"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: - err = "Attached images must have same format"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: - err = "Missing draw buffer"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: - err = "Missing read buffer"; - break; + /* success */ + format_status(COMPLETE) + /* errors shared by OpenGL desktop & ES */ + format_status(INCOMPLETE_ATTACHMENT) + format_status(INCOMPLETE_MISSING_ATTACHMENT) + format_status(UNSUPPORTED) +#if 0 /* for OpenGL ES only */ + format_status(INCOMPLETE_DIMENSIONS) +#else /* for desktop GL only */ + format_status(INCOMPLETE_DRAW_BUFFER) + format_status(INCOMPLETE_READ_BUFFER) + format_status(INCOMPLETE_MULTISAMPLE) + format_status(UNDEFINED) +#endif } +#undef format_status + if (err_out) { - BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'", - (int)status, err); + BLI_snprintf(err_out, 256, format, err); } else { - fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n", - (int)status, err); + fprintf(stderr, format, err); } } @@ -101,41 +96,33 @@ GPUFrameBuffer *GPU_framebuffer_create(void) { GPUFrameBuffer *fb; - if (!(GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object || - (GLEW_EXT_framebuffer_object && GLEW_EXT_framebuffer_blit))) - { - return NULL; - } - fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer"); - glGenFramebuffersEXT(1, &fb->object); + glGenFramebuffers(1, &fb->object); if (!fb->object) { - fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n", - (int)glGetError()); + fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed.\n"); GPU_framebuffer_free(fb); return NULL; } /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); glReadBuffer(GL_NONE); glDrawBuffer(GL_NONE); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); return fb; } -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]) +bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip) { GLenum attachment; - GLenum error; if (slot >= GPU_FB_MAX_SLOTS) { fprintf(stderr, "Attaching to index %d framebuffer slot unsupported. " "Use at most %d\n", slot, GPU_FB_MAX_SLOTS); - return 0; + return false; } if ((G.debug & G_DEBUG)) { @@ -146,26 +133,64 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot } } + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + GG.currentfb = fb->object; + + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) + attachment = GL_DEPTH_STENCIL_ATTACHMENT; + else if (GPU_texture_depth(tex)) + attachment = GL_DEPTH_ATTACHMENT; + else + attachment = GL_COLOR_ATTACHMENT0 + slot; + + glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), mip); + if (GPU_texture_depth(tex)) - attachment = GL_DEPTH_ATTACHMENT_EXT; + fb->depthtex = tex; else - attachment = GL_COLOR_ATTACHMENT0_EXT + slot; + fb->colortex[slot] = tex; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - GG.currentfb = fb->object; + GPU_texture_framebuffer_set(tex, fb, slot); - /* Clean glError buffer. */ - while (glGetError() != GL_NO_ERROR) {} + return true; +} - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, - GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), 0); +static bool gpu_framebuffer_texture_layer_attach_ex(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip, bool cubemap) +{ + GLenum attachment; + GLenum facetarget; - error = glGetError(); + if (slot >= GPU_FB_MAX_SLOTS) { + fprintf(stderr, + "Attaching to index %d framebuffer slot unsupported. " + "Use at most %d\n", slot, GPU_FB_MAX_SLOTS); + return false; + } - if (error == GL_INVALID_OPERATION) { - GPU_framebuffer_restore(); - gpu_print_framebuffer_error(error, err_out); - return 0; + if ((G.debug & G_DEBUG)) { + if (GPU_texture_bound_number(tex) != -1) { + fprintf(stderr, + "Feedback loop warning!: " + "Attempting to attach texture to framebuffer while still bound to texture unit for drawing!\n"); + } + } + + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + GG.currentfb = fb->object; + + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) + attachment = GL_DEPTH_STENCIL_ATTACHMENT; + else if (GPU_texture_depth(tex)) + attachment = GL_DEPTH_ATTACHMENT; + else + attachment = GL_COLOR_ATTACHMENT0 + slot; + + if (cubemap) { + facetarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; + glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, facetarget, GPU_texture_opengl_bindcode(tex), mip); + } + else { + glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), mip, layer); } if (GPU_texture_depth(tex)) @@ -175,7 +200,18 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot GPU_texture_framebuffer_set(tex, fb, slot); - return 1; + return true; +} + +bool GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) +{ + return gpu_framebuffer_texture_layer_attach_ex(fb, tex, slot, layer, mip, false); +} + +bool GPU_framebuffer_texture_cubeface_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip) +{ + BLI_assert(GPU_texture_target(tex) == GL_TEXTURE_CUBE_MAP); + return gpu_framebuffer_texture_layer_attach_ex(fb, tex, slot, face, mip, true); } void GPU_framebuffer_texture_detach(GPUTexture *tex) @@ -188,21 +224,25 @@ void GPU_framebuffer_texture_detach(GPUTexture *tex) return; if (GG.currentfb != fb->object) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); GG.currentfb = fb->object; } - if (GPU_texture_depth(tex)) { + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) { + fb->depthtex = NULL; + attachment = GL_DEPTH_STENCIL_ATTACHMENT; + } + else if (GPU_texture_depth(tex)) { fb->depthtex = NULL; - attachment = GL_DEPTH_ATTACHMENT_EXT; + attachment = GL_DEPTH_ATTACHMENT; } else { BLI_assert(fb->colortex[fb_attachment] == tex); fb->colortex[fb_attachment] = NULL; - attachment = GL_COLOR_ATTACHMENT0_EXT + fb_attachment; + attachment = GL_COLOR_ATTACHMENT0 + fb_attachment; } - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GPU_texture_target(tex), 0, 0); + glFramebufferTexture(GL_FRAMEBUFFER, attachment, 0, 0); GPU_texture_framebuffer_set(tex, NULL, -1); } @@ -218,11 +258,11 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex) } /* push attributes */ - glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); + gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT); glDisable(GL_SCISSOR_TEST); /* bind framebuffer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); if (GPU_texture_depth(tex)) { glDrawBuffer(GL_NONE); @@ -230,86 +270,109 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex) } else { /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment); + glReadBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment); } if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) { glEnable(GL_MULTISAMPLE); } - /* push matrices and set default viewport and matrix */ + /* set default viewport */ glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); GG.currentfb = fb->object; - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); } void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) { int numslots = 0, i; - GLenum attachments[4]; + GLenum attachments[GPU_FB_MAX_SLOTS]; if (!fb->colortex[slot]) { fprintf(stderr, "Error, framebuffer slot empty!\n"); return; } - for (i = 0; i < 4; i++) { + for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { if (fb->colortex[i]) { - attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i; + attachments[numslots] = GL_COLOR_ATTACHMENT0 + i; numslots++; } } /* push attributes */ - glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); + gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT); glDisable(GL_SCISSOR_TEST); /* bind framebuffer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); /* last bound prevails here, better allow explicit control here too */ glDrawBuffers(numslots, attachments); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); - /* push matrices and set default viewport and matrix */ + /* set default viewport */ glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); GG.currentfb = fb->object; - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); } +void GPU_framebuffer_bind(GPUFrameBuffer *fb) +{ + int numslots = 0, i; + GLenum attachments[GPU_FB_MAX_SLOTS]; + GLenum readattachement = 0; + GPUTexture *tex; + + for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { + if (fb->colortex[i]) { + attachments[numslots] = GL_COLOR_ATTACHMENT0 + i; + tex = fb->colortex[i]; + + if (!readattachement) + readattachement = GL_COLOR_ATTACHMENT0 + i; + + numslots++; + } + } + + /* bind framebuffer */ + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + + if (numslots == 0) { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + tex = fb->depthtex; + } + else { + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffers(numslots, attachments); + glReadBuffer(readattachement); + } + + if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) { + glEnable(GL_MULTISAMPLE); + } + + glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); + GG.currentfb = fb->object; +} void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex)) { - /* restore matrix */ - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - /* restore attributes */ - glPopAttrib(); + /* Restore attributes. */ + gpuPopAttrib(); } void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + slot); + glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); /* push matrices and set default viewport and matrix */ glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); GG.currentfb = fb->object; - GG.currentfb = fb->object; } bool GPU_framebuffer_bound(GPUFrameBuffer *fb) @@ -319,22 +382,17 @@ bool GPU_framebuffer_bound(GPUFrameBuffer *fb) bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) { - GLenum status; - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); GG.currentfb = fb->object; - - /* Clean glError buffer. */ - while (glGetError() != GL_NO_ERROR) {} - - status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) { GPU_framebuffer_restore(); gpu_print_framebuffer_error(status, err_out); return false; } - + return true; } @@ -351,10 +409,10 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb) } if (fb->object) { - glDeleteFramebuffersEXT(1, &fb->object); + glDeleteFramebuffers(1, &fb->object); if (GG.currentfb == fb->object) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); GG.currentfb = 0; } } @@ -365,7 +423,7 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb) void GPU_framebuffer_restore(void) { if (GG.currentfb != 0) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); GG.currentfb = 0; } } @@ -374,73 +432,214 @@ void GPU_framebuffer_blur( GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex) { + const float fullscreencos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}}; + const float fullscreenuvs[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}}; + + static Gwn_VertFormat format = {0}; + static Gwn_VertBuf vbo = {{0}}; + static Gwn_Batch batch = {{0}}; + const float scaleh[2] = {1.0f / GPU_texture_width(blurtex), 0.0f}; const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(tex)}; GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR); - int scale_uniform, texture_source_uniform; if (!blur_shader) return; - scale_uniform = GPU_shader_get_uniform(blur_shader, "ScaleU"); - texture_source_uniform = GPU_shader_get_uniform(blur_shader, "textureSource"); + /* Preparing to draw quad */ + if (format.attrib_ct == 0) { + unsigned int i = 0; + /* Vertex format */ + unsigned int pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned int uvs = GWN_vertformat_attr_add(&format, "uvs", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + /* Vertices */ + GWN_vertbuf_init_with_format(&vbo, &format); + GWN_vertbuf_data_alloc(&vbo, 36); + + for (int j = 0; j < 3; ++j) { + GWN_vertbuf_attr_set(&vbo, uvs, i, fullscreenuvs[j]); + GWN_vertbuf_attr_set(&vbo, pos, i++, fullscreencos[j]); + } + for (int j = 1; j < 4; ++j) { + GWN_vertbuf_attr_set(&vbo, uvs, i, fullscreenuvs[j]); + GWN_vertbuf_attr_set(&vbo, pos, i++, fullscreencos[j]); + } + + GWN_batch_init(&batch, GL_TRIANGLES, &vbo, NULL); + } + glDisable(GL_DEPTH_TEST); + /* Blurring horizontally */ - /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid * pushing unnecessary matrices onto the OpenGL stack. */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glBindFramebuffer(GL_FRAMEBUFFER, blurfb->object); + glDrawBuffer(GL_COLOR_ATTACHMENT0); /* avoid warnings from texture binding */ GG.currentfb = blurfb->object; - GPU_shader_bind(blur_shader); - GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scaleh); - GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex); glViewport(0, 0, GPU_texture_width(blurtex), GPU_texture_height(blurtex)); - /* Preparing to draw quad */ - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glDisable(GL_DEPTH_TEST); - GPU_texture_bind(tex, 0); - /* Drawing quad */ - glBegin(GL_QUADS); - glTexCoord2d(0, 0); glVertex2f(1, 1); - glTexCoord2d(1, 0); glVertex2f(-1, 1); - glTexCoord2d(1, 1); glVertex2f(-1, -1); - glTexCoord2d(0, 1); glVertex2f(1, -1); - glEnd(); + GWN_batch_program_set_builtin(&batch, GPU_SHADER_SEP_GAUSSIAN_BLUR); + GWN_batch_uniform_2f(&batch, "ScaleU", scaleh[0], scaleh[1]); + GWN_batch_uniform_1i(&batch, "textureSource", GL_TEXTURE0); + GWN_batch_draw(&batch); /* Blurring vertically */ - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + glDrawBuffer(GL_COLOR_ATTACHMENT0); GG.currentfb = fb->object; glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); - GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scalev); - GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex); + GPU_texture_bind(blurtex, 0); - glBegin(GL_QUADS); - glTexCoord2d(0, 0); glVertex2f(1, 1); - glTexCoord2d(1, 0); glVertex2f(-1, 1); - glTexCoord2d(1, 1); glVertex2f(-1, -1); - glTexCoord2d(0, 1); glVertex2f(1, -1); - glEnd(); + /* Hack to make the following uniform stick */ + GWN_batch_program_set_builtin(&batch, GPU_SHADER_SEP_GAUSSIAN_BLUR); + GWN_batch_uniform_2f(&batch, "ScaleU", scalev[0], scalev[1]); + GWN_batch_uniform_1i(&batch, "textureSource", GL_TEXTURE0); + GWN_batch_draw(&batch); +} + +void GPU_framebuffer_blit( + GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer *fb_write, + int write_slot, bool use_depth, bool use_stencil) +{ + GPUTexture *read_tex = (use_depth || use_stencil) ? fb_read->depthtex : fb_read->colortex[read_slot]; + GPUTexture *write_tex = (use_depth || use_stencil) ? fb_write->depthtex : fb_write->colortex[write_slot]; + int read_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : + (use_stencil) ? GL_DEPTH_STENCIL_ATTACHMENT : + GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(read_tex); + int write_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : + (use_stencil) ? GL_DEPTH_STENCIL_ATTACHMENT : + GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(write_tex); + int read_bind = GPU_texture_opengl_bindcode(read_tex); + int write_bind = GPU_texture_opengl_bindcode(write_tex); + const int read_w = GPU_texture_width(read_tex); + const int read_h = GPU_texture_height(read_tex); + const int write_w = GPU_texture_width(write_tex); + const int write_h = GPU_texture_height(write_tex); + + + /* Never both! */ + BLI_assert(!(use_depth && use_stencil)); + + if (use_depth) { + BLI_assert(GPU_texture_depth(read_tex) && GPU_texture_depth(write_tex)); + BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex)); + } + else if (use_stencil) { + BLI_assert(GPU_texture_stencil(read_tex) && GPU_texture_stencil(write_tex)); + BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex)); + } - GPU_shader_unbind(); + /* read from multi-sample buffer */ + glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object); + glFramebufferTexture2D( + GL_READ_FRAMEBUFFER, read_attach, + GPU_texture_target(read_tex), read_bind, 0); + BLI_assert(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + /* write into new single-sample buffer */ + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object); + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, write_attach, + GPU_texture_target(write_tex), write_bind, 0); + BLI_assert(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + glDrawBuffer((use_depth || use_stencil) ? GL_COLOR_ATTACHMENT0 : read_attach); + glBlitFramebuffer(0, 0, read_w, read_h, 0, 0, write_w, write_h, + (use_depth) ? GL_DEPTH_BUFFER_BIT : + (use_stencil) ? GL_STENCIL_BUFFER_BIT : + GL_COLOR_BUFFER_BIT, GL_NEAREST); + + /* Restore previous framebuffer */ + glBindFramebuffer(GL_FRAMEBUFFER, GG.currentfb); + glDrawBuffer(GL_COLOR_ATTACHMENT0); +} + +/** + * Use this if you need to custom downsample your texture and use the previous mip level as input. + * This function only takes care of the correct texture handling. It execute the callback for each texture level. + **/ +void GPU_framebuffer_recursive_downsample( + GPUFrameBuffer *fb, GPUTexture *tex, int num_iter, void (*callback)(void *userData, int level), void *userData) +{ + int i; + int current_dim[2] = {GPU_texture_width(tex), GPU_texture_height(tex)}; + GLenum attachment; + + /* Manually setup framebuffer to not use GPU_texture_framebuffer_set() */ + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + GG.currentfb = fb->object; + + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) + attachment = GL_DEPTH_STENCIL_ATTACHMENT; + else if (GPU_texture_depth(tex)) + attachment = GL_DEPTH_ATTACHMENT; + else + attachment = GL_COLOR_ATTACHMENT0; + + /* last bound prevails here, better allow explicit control here too */ + if (GPU_texture_depth(tex)) { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } + else { + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glReadBuffer(GL_COLOR_ATTACHMENT0); + } + + for (i = 1; i < num_iter + 1; i++) { + + /* calculate next viewport size */ + current_dim[0] /= 2; + current_dim[1] /= 2; + + if (GPU_type_matches(GPU_DEVICE_AMD_VEGA, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) { + /* NOTE : here 16 is because of a bug on AMD Vega GPU + non-pro drivers, that prevents us + * from sampling mipmaps that are smaller or equal to 16px. (9) */ + if (current_dim[0] <= 16 && current_dim[1] <= 16) { + break; + } + } + else { + if (current_dim[0] <= 2 && current_dim[1] <= 2) { + /* Cannot reduce further. */ + break; + } + } + + /* ensure that the viewport size is always at least 1x1 */ + CLAMP_MIN(current_dim[0], 1); + CLAMP_MIN(current_dim[1], 1); + + glViewport(0, 0, current_dim[0], current_dim[1]); + + /* bind next level for rendering but first restrict fetches only to previous level */ + GPU_texture_bind(tex, 0); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, i - 1); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1); + GPU_texture_unbind(tex); + + glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), i); + + callback(userData, i); + } + + glFramebufferTexture(GL_FRAMEBUFFER, attachment, 0, 0); + + /* reset mipmap level range for the depth image */ + GPU_texture_bind(tex, 0); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1); + GPU_texture_unbind(tex); } /* GPUOffScreen */ @@ -451,7 +650,7 @@ struct GPUOffScreen { GPUTexture *depth; }; -GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]) +GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, bool high_bitdepth, char err_out[256]) { GPUOffScreen *ofs; @@ -464,12 +663,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_ } if (samples) { - if (!GLEW_EXT_framebuffer_multisample || - !GLEW_ARB_texture_multisample || - /* Only needed for GPU_offscreen_read_pixels. - * We could add an arg if we intend to use multi-sample - * offscreen buffers w/o reading their pixels */ - !GLEW_EXT_framebuffer_blit || + if (!GLEW_ARB_texture_multisample || /* This is required when blitting from a multi-sampled buffers, * even though we're not scaling. */ !GLEW_EXT_framebuffer_multisample_blit_scaled) @@ -478,24 +672,29 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_ } } - ofs->depth = GPU_texture_create_depth_multisample(width, height, samples, err_out); + ofs->depth = GPU_texture_create_depth_with_stencil_multisample(width, height, samples, err_out); if (!ofs->depth) { GPU_offscreen_free(ofs); return NULL; } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) { + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, 0)) { GPU_offscreen_free(ofs); return NULL; } - ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out); + if (high_bitdepth) { + ofs->color = GPU_texture_create_2D_custom_multisample(width, height, 4, GPU_RGBA16F, NULL, samples, err_out); + } + else { + ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, samples, err_out); + } if (!ofs->color) { GPU_offscreen_free(ofs); return NULL; } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) { + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, 0)) { GPU_offscreen_free(ofs); return NULL; } @@ -569,37 +768,37 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) #ifdef USE_FBO_CTX_SWITCH /* read from multi-sample buffer */ - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, ofs->color->fb->object); - glFramebufferTexture2DEXT( - GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + ofs->color->fb_attachment, + glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs->color->fb->object); + glFramebufferTexture2D( + GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ofs->color->fb_attachment, GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0); - status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { goto finally; } #endif /* write into new single-sample buffer */ - glGenFramebuffersEXT(1, &fbo_blit); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit); - glFramebufferTexture2DEXT( - GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + glGenFramebuffers(1, &fbo_blit); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit); + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex_blit, 0); - status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { goto finally; } /* perform the copy */ - glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); /* read the results */ - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fbo_blit); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_blit); glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); #ifdef USE_FBO_CTX_SWITCH /* restore the original frame-bufer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ofs->color->fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, ofs->color->fb->object); #undef USE_FBO_CTX_SWITCH #endif @@ -610,10 +809,8 @@ finally: glDeleteTextures(1, &tex_blit); } if (fbo_blit) { - glDeleteFramebuffersEXT(1, &fbo_blit); + glDeleteFramebuffers(1, &fbo_blit); } - - GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels"); } else { glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); @@ -635,3 +832,12 @@ int GPU_offscreen_color_texture(const GPUOffScreen *ofs) return GPU_texture_opengl_bindcode(ofs->color); } +/* only to be used by viewport code! */ +void GPU_offscreen_viewport_data_get( + GPUOffScreen *ofs, + GPUFrameBuffer **r_fb, GPUTexture **r_color, GPUTexture **r_depth) +{ + *r_fb = ofs->fb; + *r_color = ofs->color; + *r_depth = ofs->depth; +} diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c new file mode 100644 index 00000000000..5f22b7f9279 --- /dev/null +++ b/source/blender/gpu/intern/gpu_immediate.c @@ -0,0 +1,88 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "UI_resources.h" +#include "BLI_utildefines.h" + +#include "gpu_shader_private.h" + +void immBindBuiltinProgram(GPUBuiltinShader shader_id) +{ + GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); + immBindProgram(shader->program, shader->interface); +} + +void immUniformThemeColor(int color_id) +{ + float color[4]; + UI_GetThemeColor4fv(color_id, color); + immUniformColor4fv(color); +} + +void immUniformThemeColor3(int color_id) +{ + float color[3]; + UI_GetThemeColor3fv(color_id, color); + immUniformColor3fv(color); +} + +void immUniformThemeColorShade(int color_id, int offset) +{ + float color[4]; + UI_GetThemeColorShade4fv(color_id, offset, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset) +{ + float color[4]; + UI_GetThemeColorShadeAlpha4fv(color_id, color_offset, alpha_offset, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int offset) +{ + float color[4]; + UI_GetThemeColorBlendShade4fv(color_id1, color_id2, fac, offset, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorBlend(int color_id1, int color_id2, float fac) +{ + uint8_t color[3]; + UI_GetThemeColorBlend3ubv(color_id1, color_id2, fac, color); + immUniformColor3ubv(color); +} + +void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset) +{ + unsigned char col[4]; + UI_GetThemeColorShadeAlpha4ubv(colorid, coloffset, alphaoffset, col); + immUniformColor4ub(col[0], col[1], col[2], col[3]); +} diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c new file mode 100644 index 00000000000..bad878ef4bf --- /dev/null +++ b/source/blender/gpu/intern/gpu_immediate_util.c @@ -0,0 +1,424 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/intern/gpu_immediate_util.c + * \ingroup gpu + */ + +#include <stdio.h> +#include <string.h> + +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "GPU_basic_shader.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" + +static const float cube_coords[8][3] = { + {-1, -1, -1}, + {-1, -1, +1}, + {-1, +1, -1}, + {-1, +1, +1}, + {+1, -1, -1}, + {+1, -1, +1}, + {+1, +1, -1}, + {+1, +1, +1}, +}; +static const int cube_quad_index[6][4] = { + {0, 1, 3, 2}, + {0, 2, 6, 4}, + {0, 4, 5, 1}, + {1, 5, 7, 3}, + {2, 3, 7, 6}, + {4, 6, 7, 5}, +}; +static const int cube_line_index[12][2] = { + {0, 1}, + {0, 2}, + {0, 4}, + {1, 3}, + {1, 5}, + {2, 3}, + {2, 6}, + {3, 7}, + {4, 5}, + {4, 6}, + {5, 7}, + {6, 7}, +}; + +/** + * Pack color into 3 bytes + * + * This define converts a numerical value to the equivalent 24-bit + * color, while not being endian-sensitive. On little-endians, this + * is the same as doing a 'naive' indexing, on big-endian, it is not! + * + * \note BGR format (i.e. 0xBBGGRR)... + * + * \param x color. + */ +void imm_cpack(unsigned int x) +{ + immUniformColor3ub(((x) & 0xFF), + (((x) >> 8) & 0xFF), + (((x) >> 16) & 0xFF)); +} + +static void imm_draw_circle( + Gwn_PrimType prim_type, const uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments) +{ + immBegin(prim_type, nsegments); + for (int i = 0; i < nsegments; ++i) { + const float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments); + immVertex2f(shdr_pos, x + (rad_x * cosf(angle)), y + (rad_y * sinf(angle))); + } + immEnd(); +} + +/** + * Draw a circle outline with the given \a radius. + * The circle is centered at \a x, \a y and drawn in the XY plane. + * + * \param shdr_pos The vertex attribute number for position. + * \param x Horizontal center. + * \param y Vertical center. + * \param radius The circle's radius. + * \param nsegments The number of segments to use in drawing (more = smoother). + */ +void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float rad, int nsegments) +{ + imm_draw_circle(GWN_PRIM_LINE_LOOP, shdr_pos, x, y, rad, rad, nsegments); +} + +/** + * Draw a filled circle with the given \a radius. + * The circle is centered at \a x, \a y and drawn in the XY plane. + * + * \param shdr_pos The vertex attribute number for position. + * \param x Horizontal center. + * \param y Vertical center. + * \param radius The circle's radius. + * \param nsegments The number of segments to use in drawing (more = smoother). + */ +void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float rad, int nsegments) +{ + imm_draw_circle(GWN_PRIM_TRI_FAN, shdr_pos, x, y, rad, rad, nsegments); +} + +void imm_draw_circle_wire_aspect_2d(uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments) +{ + imm_draw_circle(GWN_PRIM_LINE_LOOP, shdr_pos, x, y, rad_x, rad_y, nsegments); +} +void imm_draw_circle_fill_aspect_2d(uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments) +{ + imm_draw_circle(GWN_PRIM_TRI_FAN, shdr_pos, x, y, rad_x, rad_y, nsegments); +} + +/** + * \note We could have `imm_draw_lined_disk_partial` but currently there is no need. + */ +static void imm_draw_disk_partial( + Gwn_PrimType prim_type, unsigned pos, float x, float y, + float rad_inner, float rad_outer, int nsegments, float start, float sweep) +{ + /* shift & reverse angle, increase 'nsegments' to match gluPartialDisk */ + const float angle_start = -(DEG2RADF(start)) + (float)(M_PI / 2); + const float angle_end = -(DEG2RADF(sweep) - angle_start); + nsegments += 1; + immBegin(prim_type, nsegments * 2); + for (int i = 0; i < nsegments; ++i) { + const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1))); + const float angle_sin = sinf(angle); + const float angle_cos = cosf(angle); + immVertex2f(pos, x + rad_inner * angle_cos, y + rad_inner * angle_sin); + immVertex2f(pos, x + rad_outer * angle_cos, y + rad_outer * angle_sin); + } + immEnd(); +} + +/** + * Draw a filled arc with the given inner and outer radius. + * The circle is centered at \a x, \a y and drawn in the XY plane. + * + * \note Arguments are `gluPartialDisk` compatible. + * + * \param pos: The vertex attribute number for position. + * \param x: Horizontal center. + * \param y: Vertical center. + * \param radius_inner: The inner circle's radius. + * \param radius_outer: The outer circle's radius (can be zero). + * \param nsegments: The number of segments to use in drawing (more = smoother). + * \param start: Specifies the starting angle, in degrees, of the disk portion. + * \param sweep: Specifies the sweep angle, in degrees, of the disk portion. + */ +void imm_draw_disk_partial_fill_2d( + unsigned pos, float x, float y, + float rad_inner, float rad_outer, int nsegments, float start, float sweep) +{ + imm_draw_disk_partial(GWN_PRIM_TRI_STRIP, pos, x, y, rad_inner, rad_outer, nsegments, start, sweep); +} + +static void imm_draw_circle_3D( + Gwn_PrimType prim_type, unsigned pos, float x, float y, + float rad, int nsegments) +{ + immBegin(prim_type, nsegments); + for (int i = 0; i < nsegments; ++i) { + float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments); + immVertex3f(pos, x + rad * cosf(angle), y + rad * sinf(angle), 0.0f); + } + immEnd(); +} + +void imm_draw_circle_wire_3d(unsigned pos, float x, float y, float rad, int nsegments) +{ + imm_draw_circle_3D(GWN_PRIM_LINE_LOOP, pos, x, y, rad, nsegments); +} + +void imm_draw_circle_fill_3d(unsigned pos, float x, float y, float rad, int nsegments) +{ + imm_draw_circle_3D(GWN_PRIM_TRI_FAN, pos, x, y, rad, nsegments); +} + +/** +* Draw a lined box. +* +* \param pos The vertex attribute number for position. +* \param x1 left. +* \param y1 bottom. +* \param x2 right. +* \param y2 top. +*/ +void imm_draw_box_wire_2d(unsigned pos, float x1, float y1, float x2, float y2) +{ + immBegin(GWN_PRIM_LINE_LOOP, 4); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x2, y1); + immEnd(); +} + +void imm_draw_box_wire_3d(unsigned pos, float x1, float y1, float x2, float y2) +{ + /* use this version when Gwn_VertFormat has a vec3 position */ + immBegin(GWN_PRIM_LINE_LOOP, 4); + immVertex3f(pos, x1, y1, 0.0f); + immVertex3f(pos, x1, y2, 0.0f); + immVertex3f(pos, x2, y2, 0.0f); + immVertex3f(pos, x2, y1, 0.0f); + immEnd(); +} + +/** + * Draw a standard checkerboard to indicate transparent backgrounds. + */ +void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2) +{ + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_CHECKER); + + immUniform4f("color1", 0.15f, 0.15f, 0.15f, 1.0f); + immUniform4f("color2", 0.2f, 0.2f, 0.2f, 1.0f); + immUniform1i("size", 8); + + immRectf(pos, x1, y1, x2, y2); + + immUnbindProgram(); +} + +void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]) +{ + float coords[ARRAY_SIZE(cube_coords)][3]; + + for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) { + madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect); + } + + immBegin(GWN_PRIM_TRIS, ARRAY_SIZE(cube_quad_index) * 3 * 2); + for (int i = 0; i < ARRAY_SIZE(cube_quad_index); i++) { + immVertex3fv(pos, coords[cube_quad_index[i][0]]); + immVertex3fv(pos, coords[cube_quad_index[i][1]]); + immVertex3fv(pos, coords[cube_quad_index[i][2]]); + + immVertex3fv(pos, coords[cube_quad_index[i][0]]); + immVertex3fv(pos, coords[cube_quad_index[i][2]]); + immVertex3fv(pos, coords[cube_quad_index[i][3]]); + } + immEnd(); +} + +void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3]) +{ + float coords[ARRAY_SIZE(cube_coords)][3]; + + for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) { + madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect); + } + + immBegin(GWN_PRIM_LINES, ARRAY_SIZE(cube_line_index) * 2); + for (int i = 0; i < ARRAY_SIZE(cube_line_index); i++) { + immVertex3fv(pos, coords[cube_line_index[i][0]]); + immVertex3fv(pos, coords[cube_line_index[i][1]]); + } + immEnd(); +} + +/** +* Draw a cylinder. Replacement for gluCylinder. +* _warning_ : Slow, better use it only if you no other choices. +* +* \param pos The vertex attribute number for position. +* \param nor The vertex attribute number for normal. +* \param base Specifies the radius of the cylinder at z = 0. +* \param top Specifies the radius of the cylinder at z = height. +* \param height Specifies the height of the cylinder. +* \param slices Specifies the number of subdivisions around the z axis. +* \param stacks Specifies the number of subdivisions along the z axis. +*/ +void imm_draw_cylinder_fill_normal_3d( + unsigned int pos, unsigned int nor, float base, float top, float height, int slices, int stacks) +{ + immBegin(GWN_PRIM_TRIS, 6 * slices * stacks); + for (int i = 0; i < slices; ++i) { + const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices); + const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices); + const float cos1 = cosf(angle1); + const float sin1 = sinf(angle1); + const float cos2 = cosf(angle2); + const float sin2 = sinf(angle2); + + for (int j = 0; j < stacks; ++j) { + float fac1 = (float)j / (float)stacks; + float fac2 = (float)(j + 1) / (float)stacks; + float r1 = base * (1.f - fac1) + top * fac1; + float r2 = base * (1.f - fac2) + top * fac2; + float h1 = height * ((float)j / (float)stacks); + float h2 = height * ((float)(j + 1) / (float)stacks); + + float v1[3] = {r1 *cos2, r1 * sin2, h1}; + float v2[3] = {r2 *cos2, r2 * sin2, h2}; + float v3[3] = {r2 *cos1, r2 * sin1, h2}; + float v4[3] = {r1 *cos1, r1 * sin1, h1}; + float n1[3], n2[3]; + + /* calc normals */ + sub_v3_v3v3(n1, v2, v1); + normalize_v3(n1); + n1[0] = cos1; n1[1] = sin1; n1[2] = 1 - n1[2]; + + sub_v3_v3v3(n2, v3, v4); + normalize_v3(n2); + n2[0] = cos2; n2[1] = sin2; n2[2] = 1 - n2[2]; + + /* first tri */ + immAttrib3fv(nor, n2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immAttrib3fv(nor, n1); + immVertex3fv(pos, v3); + + /* second tri */ + immVertex3fv(pos, v3); + immVertex3fv(pos, v4); + immAttrib3fv(nor, n2); + immVertex3fv(pos, v1); + } + } + immEnd(); +} + +void imm_draw_cylinder_wire_3d(unsigned int pos, float base, float top, float height, int slices, int stacks) +{ + immBegin(GWN_PRIM_LINES, 6 * slices * stacks); + for (int i = 0; i < slices; ++i) { + const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices); + const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices); + const float cos1 = cosf(angle1); + const float sin1 = sinf(angle1); + const float cos2 = cosf(angle2); + const float sin2 = sinf(angle2); + + for (int j = 0; j < stacks; ++j) { + float fac1 = (float)j / (float)stacks; + float fac2 = (float)(j + 1) / (float)stacks; + float r1 = base * (1.f - fac1) + top * fac1; + float r2 = base * (1.f - fac2) + top * fac2; + float h1 = height * ((float)j / (float)stacks); + float h2 = height * ((float)(j + 1) / (float)stacks); + + float v1[3] = {r1 * cos2, r1 * sin2, h1}; + float v2[3] = {r2 * cos2, r2 * sin2, h2}; + float v3[3] = {r2 * cos1, r2 * sin1, h2}; + float v4[3] = {r1 * cos1, r1 * sin1, h1}; + + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + + immVertex3fv(pos, v2); + immVertex3fv(pos, v3); + + immVertex3fv(pos, v1); + immVertex3fv(pos, v4); + } + } + immEnd(); +} + +void imm_draw_cylinder_fill_3d(unsigned int pos, float base, float top, float height, int slices, int stacks) +{ + immBegin(GWN_PRIM_TRIS, 6 * slices * stacks); + for (int i = 0; i < slices; ++i) { + const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices); + const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices); + const float cos1 = cosf(angle1); + const float sin1 = sinf(angle1); + const float cos2 = cosf(angle2); + const float sin2 = sinf(angle2); + + for (int j = 0; j < stacks; ++j) { + float fac1 = (float)j / (float)stacks; + float fac2 = (float)(j + 1) / (float)stacks; + float r1 = base * (1.f - fac1) + top * fac1; + float r2 = base * (1.f - fac2) + top * fac2; + float h1 = height * ((float)j / (float)stacks); + float h2 = height * ((float)(j + 1) / (float)stacks); + + float v1[3] = {r1 * cos2, r1 * sin2, h1}; + float v2[3] = {r2 * cos2, r2 * sin2, h2}; + float v3[3] = {r2 * cos1, r2 * sin1, h2}; + float v4[3] = {r1 * cos1, r1 * sin1, h1}; + + /* first tri */ + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immVertex3fv(pos, v3); + + /* second tri */ + immVertex3fv(pos, v3); + immVertex3fv(pos, v4); + immVertex3fv(pos, v1); + } + } + immEnd(); +} diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index c72c83b6b07..7a6b1ff6c70 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -31,7 +31,8 @@ #include "BLI_sys_types.h" #include "GPU_init_exit.h" /* interface */ - +#include "GPU_immediate.h" +#include "GPU_batch.h" #include "BKE_global.h" #include "intern/gpu_codegen.h" @@ -59,14 +60,22 @@ void GPU_init(void) if (G.debug & G_DEBUG_GPU) gpu_debug_init(); + gpu_batch_init(); + + immInit(); } void GPU_exit(void) { + immDestroy(); + + gpu_batch_exit(); + if (G.debug & G_DEBUG_GPU) gpu_debug_exit(); + gpu_codegen_exit(); gpu_extensions_exit(); /* must come last */ diff --git a/source/blender/gpu/intern/gpu_lamp.c b/source/blender/gpu/intern/gpu_lamp.c new file mode 100644 index 00000000000..3c49c057b49 --- /dev/null +++ b/source/blender/gpu/intern/gpu_lamp.c @@ -0,0 +1,483 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Brecht Van Lommel, Clément Foucault. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_lamp.c + * \ingroup gpu + * + * Manages Opengl lights. + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_lamp_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_group.h" + +#include "GPU_framebuffer.h" +#include "GPU_glew.h" +#include "GPU_lamp.h" +#include "GPU_material.h" +#include "GPU_shader.h" +#include "GPU_texture.h" + +#include "gpu_lamp_private.h" + +bool GPU_lamp_visible(GPULamp *lamp, Material *ma) +{ + if (lamp->hide) + return false; + else if (ma && ma->group) + return BKE_group_object_exists(ma->group, lamp->ob); + else + return true; +} + +static void gpu_lamp_calc_winmat(GPULamp *lamp) +{ + float temp, angle, pixsize, wsize; + + if (lamp->type == LA_SUN) { + wsize = lamp->la->shadow_frustum_size; + orthographic_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend); + } + else if (lamp->type == LA_SPOT) { + angle = saacos(lamp->spotsi); + temp = 0.5f * lamp->size * cosf(angle) / sinf(angle); + pixsize = lamp->d / temp; + wsize = pixsize * 0.5f * lamp->size; + /* compute shadows according to X and Y scaling factors */ + perspective_m4( + lamp->winmat, + -wsize * lamp->spotvec[0], wsize * lamp->spotvec[0], + -wsize * lamp->spotvec[1], wsize * lamp->spotvec[1], + lamp->d, lamp->clipend); + } +} + +void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4]) +{ + float mat[4][4]; + float obmat_scale[3]; + + lamp->lay = lay; + lamp->hide = hide; + + normalize_m4_m4_ex(mat, obmat, obmat_scale); + + copy_v3_v3(lamp->vec, mat[2]); + copy_v3_v3(lamp->co, mat[3]); + copy_m4_m4(lamp->obmat, mat); + invert_m4_m4(lamp->imat, mat); + + if (lamp->type == LA_SPOT) { + /* update spotlamp scale on X and Y axis */ + lamp->spotvec[0] = obmat_scale[0] / obmat_scale[2]; + lamp->spotvec[1] = obmat_scale[1] / obmat_scale[2]; + } + + if (GPU_lamp_has_shadow_buffer(lamp)) { + /* makeshadowbuf */ + gpu_lamp_calc_winmat(lamp); + } +} + +void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy) +{ + lamp->energy = energy; + if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy; + + lamp->col[0] = r; + lamp->col[1] = g; + lamp->col[2] = b; +} + +void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2, + float coeff_const, float coeff_lin, float coeff_quad) +{ + lamp->dist = distance; + lamp->att1 = att1; + lamp->att2 = att2; + lamp->coeff_const = coeff_const; + lamp->coeff_lin = coeff_lin; + lamp->coeff_quad = coeff_quad; +} + +void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend) +{ + lamp->spotsi = cosf(spotsize * 0.5f); + lamp->spotbl = (1.0f - lamp->spotsi) * spotblend; +} + +static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *la, GPULamp *lamp) +{ + lamp->scene = scene; + lamp->ob = ob; + lamp->par = par; + lamp->la = la; + + /* add_render_lamp */ + lamp->mode = la->mode; + lamp->type = la->type; + + lamp->energy = la->energy; + if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy; + + lamp->col[0] = la->r; + lamp->col[1] = la->g; + lamp->col[2] = la->b; + + GPU_lamp_update(lamp, ob->lay, (ob->restrictflag & OB_RESTRICT_RENDER), ob->obmat); + + lamp->spotsi = la->spotsize; + if (lamp->mode & LA_HALO) + if (lamp->spotsi > DEG2RADF(170.0f)) + lamp->spotsi = DEG2RADF(170.0f); + lamp->spotsi = cosf(lamp->spotsi * 0.5f); + lamp->spotbl = (1.0f - lamp->spotsi) * la->spotblend; + lamp->k = la->k; + + lamp->dist = la->dist; + lamp->falloff_type = la->falloff_type; + lamp->att1 = la->att1; + lamp->att2 = la->att2; + lamp->coeff_const = la->coeff_const; + lamp->coeff_lin = la->coeff_lin; + lamp->coeff_quad = la->coeff_quad; + lamp->curfalloff = la->curfalloff; + + /* initshadowbuf */ + lamp->bias = 0.02f * la->bias; + lamp->size = la->bufsize; + lamp->d = la->clipsta; + lamp->clipend = la->clipend; + + /* arbitrary correction for the fact we do no soft transition */ + lamp->bias *= 0.25f; +} + +static void gpu_lamp_shadow_free(GPULamp *lamp) +{ + if (lamp->tex) { + GPU_texture_free(lamp->tex); + lamp->tex = NULL; + } + if (lamp->depthtex) { + GPU_texture_free(lamp->depthtex); + lamp->depthtex = NULL; + } + if (lamp->fb) { + GPU_framebuffer_free(lamp->fb); + lamp->fb = NULL; + } + if (lamp->blurtex) { + GPU_texture_free(lamp->blurtex); + lamp->blurtex = NULL; + } + if (lamp->blurfb) { + GPU_framebuffer_free(lamp->blurfb); + lamp->blurfb = NULL; + } +} + +static GPUTexture *gpu_lamp_create_vsm_shadow_map(int size) +{ + return GPU_texture_create_2D_custom(size, size, 2, GPU_RG32F, NULL, NULL); +} + +LampEngineData *GPU_lamp_engine_data_get(Scene *scene, Object *ob, Object *par, struct RenderEngineType *re) +{ + GPULamp *lamp; + LinkData *link; + + for (link = ob->gpulamp.first; link; link = link->next) { + lamp = (GPULamp *)link->data; + + if ((lamp->par == par) && (lamp->scene == scene) && (lamp->re == re)) + return &lamp->data; + } + + lamp = MEM_callocN(sizeof(GPULamp), "GPULamp"); + + link = MEM_callocN(sizeof(LinkData), "GPULampLink"); + link->data = lamp; + BLI_addtail(&ob->gpulamp, link); + + lamp->scene = scene; + lamp->ob = ob; + lamp->par = par; + lamp->la = ob->data; + lamp->re = re; + + return &lamp->data; +} + +GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) +{ + Lamp *la; + GPULamp *lamp; + LinkData *link; + + for (link = ob->gpulamp.first; link; link = link->next) { + lamp = (GPULamp *)link->data; + + if (lamp->par == par && lamp->scene == scene) + return link->data; + } + + lamp = MEM_callocN(sizeof(GPULamp), "GPULamp"); + + link = MEM_callocN(sizeof(LinkData), "GPULampLink"); + link->data = lamp; + BLI_addtail(&ob->gpulamp, link); + + la = ob->data; + gpu_lamp_from_blender(scene, ob, par, la, lamp); + + if ((la->type == LA_SPOT && (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY))) || + (la->type == LA_SUN && (la->mode & LA_SHAD_RAY))) + { + /* opengl */ + lamp->fb = GPU_framebuffer_create(); + if (!lamp->fb) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { + /* Shadow depth map */ + lamp->depthtex = GPU_texture_create_depth(lamp->size, lamp->size, NULL); + if (!lamp->depthtex) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + GPU_texture_bind(lamp->depthtex, 0); + GPU_texture_compare_mode(lamp->depthtex, true); + GPU_texture_unbind(lamp->depthtex); + + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, 0)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + /* Shadow color map */ + lamp->tex = gpu_lamp_create_vsm_shadow_map(lamp->size); + if (!lamp->tex) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + /* FBO and texture for blurring */ + lamp->blurfb = GPU_framebuffer_create(); + if (!lamp->blurfb) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + lamp->blurtex = gpu_lamp_create_vsm_shadow_map(lamp->size * 0.5); + if (!lamp->blurtex) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, 0)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + /* we need to properly bind to test for completeness */ + GPU_texture_bind_as_framebuffer(lamp->blurtex); + + if (!GPU_framebuffer_check_valid(lamp->blurfb, NULL)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + GPU_framebuffer_texture_unbind(lamp->blurfb, lamp->blurtex); + } + else { + lamp->tex = GPU_texture_create_depth(lamp->size, lamp->size, NULL); + if (!lamp->tex) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + GPU_texture_bind(lamp->tex, 0); + GPU_texture_compare_mode(lamp->tex, true); + GPU_texture_unbind(lamp->tex); + + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + } + + GPU_framebuffer_restore(); + + lamp->shadow_color[0] = la->shdwr; + lamp->shadow_color[1] = la->shdwg; + lamp->shadow_color[2] = la->shdwb; + } + else { + lamp->shadow_color[0] = 1.0; + lamp->shadow_color[1] = 1.0; + lamp->shadow_color[2] = 1.0; + } + + return lamp; +} + +void GPU_lamp_engine_data_free(LampEngineData *led) +{ + for (int i = 0; i < MAX_LAMP_DATA; ++i) { + if (led->storage[i]) { + MEM_freeN(led->storage[i]); + led->storage[i] = NULL; + } + } +} + +void GPU_lamp_free(Object *ob) +{ + GPULamp *lamp; + LinkData *link; + + for (link = ob->gpulamp.first; link; link = link->next) { + lamp = link->data; + + gpu_lamp_shadow_free(lamp); + GPU_lamp_engine_data_free(&lamp->data); + + MEM_freeN(lamp); + } + + BLI_freelistN(&ob->gpulamp); +} + +bool GPU_lamp_has_shadow_buffer(GPULamp *lamp) +{ + return (!(lamp->scene->gm.flag & GAME_GLSL_NO_SHADOWS) && + !(lamp->scene->gm.flag & GAME_GLSL_NO_LIGHTS) && + lamp->tex && lamp->fb); +} + +void GPU_lamp_update_buffer_mats(GPULamp *lamp) +{ + float rangemat[4][4], persmat[4][4]; + + /* initshadowbuf */ + invert_m4_m4(lamp->viewmat, lamp->obmat); + normalize_v3(lamp->viewmat[0]); + normalize_v3(lamp->viewmat[1]); + normalize_v3(lamp->viewmat[2]); + + /* makeshadowbuf */ + mul_m4_m4m4(persmat, lamp->winmat, lamp->viewmat); + + /* opengl depth buffer is range 0.0..1.0 instead of -1.0..1.0 in blender */ + unit_m4(rangemat); + rangemat[0][0] = 0.5f; + rangemat[1][1] = 0.5f; + rangemat[2][2] = 0.5f; + rangemat[3][0] = 0.5f; + rangemat[3][1] = 0.5f; + rangemat[3][2] = 0.5f; + + mul_m4_m4m4(lamp->persmat, rangemat, persmat); +} + +void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsize, float winmat[4][4]) +{ + GPU_lamp_update_buffer_mats(lamp); + + /* opengl */ + glDisable(GL_SCISSOR_TEST); + GPU_texture_bind_as_framebuffer(lamp->tex); + if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) + GPU_shader_bind(GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE)); + + /* set matrices */ + copy_m4_m4(viewmat, lamp->viewmat); + copy_m4_m4(winmat, lamp->winmat); + *winsize = lamp->size; +} + +void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp) +{ + if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { + GPU_shader_unbind(); + GPU_framebuffer_blur(lamp->fb, lamp->tex, lamp->blurfb, lamp->blurtex); + } + + GPU_framebuffer_texture_unbind(lamp->fb, lamp->tex); + GPU_framebuffer_restore(); + glEnable(GL_SCISSOR_TEST); +} + +int GPU_lamp_shadow_buffer_type(GPULamp *lamp) +{ + return lamp->la->shadowmap_type; +} + +int GPU_lamp_shadow_bind_code(GPULamp *lamp) +{ + return lamp->tex ? GPU_texture_opengl_bindcode(lamp->tex) : -1; +} + +float *GPU_lamp_dynpersmat(GPULamp *lamp) +{ + return &lamp->dynpersmat[0][0]; +} + +int GPU_lamp_shadow_layer(GPULamp *lamp) +{ + if (lamp->fb && lamp->tex && (lamp->mode & (LA_LAYER | LA_LAYER_SHADOW))) + return lamp->lay; + else + return -1; +} diff --git a/source/blender/gpu/intern/gpu_lamp_private.h b/source/blender/gpu/intern/gpu_lamp_private.h new file mode 100644 index 00000000000..f227ce74e7e --- /dev/null +++ b/source/blender/gpu/intern/gpu_lamp_private.h @@ -0,0 +1,84 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Brecht Van Lommel, Clément Foucault. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpu_lamp_private.h + * \ingroup gpu + */ + +#ifndef __GPU_LAMP_PRIVATE_H__ +#define __GPU_LAMP_PRIVATE_H__ + +#include "BLI_sys_types.h" /* for bool */ + +struct GPULamp { + Scene *scene; + Object *ob; + Object *par; + Lamp *la; + struct RenderEngineType *re; + + /* Old Viewport (pre-2.8) */ + int type, mode, lay, hide; + + float dynenergy, dyncol[3]; + float energy, col[3]; + + float co[3], vec[3]; + float dynco[3], dynvec[3]; + float obmat[4][4]; + float imat[4][4]; + float dynimat[4][4]; + + float spotsi, spotbl, k; + float spotvec[2]; + float dyndist, dynatt1, dynatt2; + float dist, att1, att2; + float coeff_const, coeff_lin, coeff_quad; + float shadow_color[3]; + + float bias, d, clipend; + int size; + + int falloff_type; + struct CurveMapping *curfalloff; + + float winmat[4][4]; + float viewmat[4][4]; + float persmat[4][4]; + float dynpersmat[4][4]; + + GPUFrameBuffer *fb; + GPUFrameBuffer *blurfb; + GPUTexture *tex; + GPUTexture *depthtex; + GPUTexture *blurtex; + + /* New viewport */ + struct LampEngineData data; +}; + +#endif /* __GPU_LAMP_PRIVATE_H__ */ diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 33eac16dadf..2e6c1cbf9df 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -45,12 +45,14 @@ #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_rand.h" #include "BKE_anim.h" #include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_global.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_scene.h" @@ -60,11 +62,14 @@ #include "GPU_extensions.h" #include "GPU_framebuffer.h" +#include "GPU_lamp.h" #include "GPU_material.h" #include "GPU_shader.h" #include "GPU_texture.h" +#include "GPU_uniformbuffer.h" #include "gpu_codegen.h" +#include "gpu_lamp_private.h" #ifdef WITH_OPENSUBDIV # include "BKE_DerivedMesh.h" @@ -92,12 +97,15 @@ static struct GPUWorld { } GPUWorld; struct GPUMaterial { - Scene *scene; + Scene *scene; /* DEPRECATED was only usefull for lamps */ Material *ma; /* material for mesh surface, worlds or something else. * some code generation is done differently depending on the use case */ - int type; + int type; /* DEPRECATED */ + + const void *engine_type; /* attached engine type */ + int options; /* to identify shader variations (shadow, probe, world background...) */ /* for creating the material */ ListBase nodes; @@ -128,50 +136,26 @@ struct GPUMaterial { bool bound; bool is_opensubdiv; -}; - -struct GPULamp { - Scene *scene; - Object *ob; - Object *par; - Lamp *la; - - int type, mode, lay, hide; - - float dynenergy, dyncol[3]; - float energy, col[3]; - - float co[3], vec[3]; - float dynco[3], dynvec[3]; - float obmat[4][4]; - float imat[4][4]; - float dynimat[4][4]; - - float spotsi, spotbl, k; - float spotvec[2]; - float dyndist, dynatt1, dynatt2; - float dist, att1, att2; - float coeff_const, coeff_lin, coeff_quad; - float shadow_color[3]; - - float bias, d, clipend; - int size; - - int falloff_type; - struct CurveMapping *curfalloff; - float winmat[4][4]; - float viewmat[4][4]; - float persmat[4][4]; - float dynpersmat[4][4]; - - GPUFrameBuffer *fb; - GPUFrameBuffer *blurfb; - GPUTexture *tex; - GPUTexture *depthtex; - GPUTexture *blurtex; + /* XXX: Should be in Material. But it depends on the output node + * used and since the output selection is difference for GPUMaterial... + */ + int domain; + + GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */ + GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */ + GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */ + float *sss_radii; /* UBO containing SSS profile. */ + int sss_samples; + short int *sss_falloff; + float *sss_sharpness; + bool sss_dirty; +}; - ListBase materials; +enum { + GPU_DOMAIN_SURFACE = (1 << 0), + GPU_DOMAIN_VOLUME = (1 << 1), + GPU_DOMAIN_SSS = (1 << 2) }; /* Forward declaration so shade_light_textures() can use this, while still keeping the code somewhat organized */ @@ -289,21 +273,18 @@ void GPU_material_free(ListBase *gpumaterial) if (material->pass) GPU_pass_free(material->pass); - for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) { - GPULamp *lamp = nlink->data; + if (material->ubo != NULL) { + GPU_uniformbuffer_free(material->ubo); + } - if (material->ma) { - Material *ma = material->ma; - - LinkData *next = NULL; - for (LinkData *mlink = lamp->materials.first; mlink; mlink = next) { - next = mlink->next; - if (mlink->data == ma) - BLI_freelinkN(&lamp->materials, mlink); - } - } + if (material->sss_tex_profile != NULL) { + GPU_texture_free(material->sss_tex_profile); } - + + if (material->sss_profile != NULL) { + GPU_uniformbuffer_free(material->sss_profile); + } + BLI_freelistN(&material->lamps); MEM_freeN(material); @@ -312,28 +293,12 @@ void GPU_material_free(ListBase *gpumaterial) BLI_freelistN(gpumaterial); } -bool GPU_lamp_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma) -{ - if (lamp->hide) - return false; - else if (srl && srl->light_override) - return BKE_group_object_exists(srl->light_override, lamp->ob); - else if (ma && ma->group) - return BKE_group_object_exists(ma->group, lamp->ob); - else - return true; -} - void GPU_material_bind( GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, - float viewmat[4][4], float viewinv[4][4], float camerafactors[4], bool scenelock) + float viewmat[4][4], float viewinv[4][4], float camerafactors[4]) { if (material->pass) { GPUShader *shader = GPU_pass_shader(material->pass); - SceneRenderLayer *srl = scenelock ? BLI_findlink(&material->scene->r.layers, material->scene->r.actlay) : NULL; - - if (srl) - viewlay &= srl->lay; /* handle layer lamps */ if (material->type == GPU_MATERIAL_TYPE_MESH) { @@ -341,7 +306,7 @@ void GPU_material_bind( GPULamp *lamp = nlink->data; if ((lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) && - GPU_lamp_visible(lamp, srl, material->ma)) + GPU_lamp_visible(lamp, material->ma)) { lamp->dynenergy = lamp->energy; copy_v3_v3(lamp->dyncol, lamp->col); @@ -490,6 +455,346 @@ GPUMatType GPU_Material_get_type(GPUMaterial *material) return material->type; } +GPUPass *GPU_material_get_pass(GPUMaterial *material) +{ + return material->pass; +} + +GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material) +{ + return material->ubo; +} + +/** + * Create dynamic UBO from parameters + * \param ListBase of BLI_genericNodeN(GPUInput) + */ +void GPU_material_create_uniform_buffer(GPUMaterial *material, ListBase *inputs) +{ + material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL); +} + +void GPU_material_uniform_buffer_tag_dirty(ListBase *gpumaterials) +{ + for (LinkData *link = gpumaterials->first; link; link = link->next) { + GPUMaterial *material = link->data; + if (material->ubo != NULL) { + GPU_uniformbuffer_tag_dirty(material->ubo); + } + if (material->sss_profile != NULL) { + material->sss_dirty = true; + } + } +} + +/* Eevee Subsurface scattering. */ +/* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */ + +#define SSS_SAMPLES 65 +#define SSS_EXPONENT 2.0f /* Importance sampling exponent */ + +typedef struct GPUSssKernelData { + float kernel[SSS_SAMPLES][4]; + float param[3], max_radius; + int samples; +} GPUSssKernelData; + +static void sss_calculate_offsets(GPUSssKernelData *kd, int count, float exponent) +{ + float step = 2.0f / (float)(count - 1); + for (int i = 0; i < count; i++) { + float o = ((float)i) * step - 1.0f; + float sign = (o < 0.0f) ? -1.0f : 1.0f; + float ofs = sign * fabsf(powf(o, exponent)); + kd->kernel[i][3] = ofs; + } +} + +#define GAUSS_TRUNCATE 12.46f +static float gaussian_profile(float r, float radius) +{ + const float v = radius * radius * (0.25f * 0.25f); + const float Rm = sqrtf(v * GAUSS_TRUNCATE); + + if (r >= Rm) { + return 0.0f; + } + return expf(-r * r / (2.0f * v)) / (2.0f * M_PI * v); +} + +#define BURLEY_TRUNCATE 16.0f +#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE) +static float burley_profile(float r, float d) +{ + float exp_r_3_d = expf(-r / (3.0f * d)); + float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d; + return (exp_r_d + exp_r_3_d) / (4.0f * d); +} + +static float cubic_profile(float r, float radius, float sharpness) +{ + float Rm = radius * (1.0f + sharpness); + + if (r >= Rm) { + return 0.0f; + } + /* custom variation with extra sharpness, to match the previous code */ + const float y = 1.0f / (1.0f + sharpness); + float Rmy, ry, ryinv; + + Rmy = powf(Rm, y); + ry = powf(r, y); + ryinv = (r > 0.0f) ? powf(r, y - 1.0f) : 0.0f; + + const float Rmy5 = (Rmy * Rmy) * (Rmy * Rmy) * Rmy; + const float f = Rmy - ry; + const float num = f * (f * f) * (y * ryinv); + + return (10.0f * num) / (Rmy5 * M_PI); +} + +static float eval_profile(float r, short falloff_type, float sharpness, float param) +{ + r = fabsf(r); + + if (falloff_type == SHD_SUBSURFACE_BURLEY) { + return burley_profile(r, param) / BURLEY_TRUNCATE_CDF; + } + else if (falloff_type == SHD_SUBSURFACE_CUBIC) { + return cubic_profile(r, param, sharpness); + } + else { + return gaussian_profile(r, param); + } +} + +/* Resolution for each sample of the precomputed kernel profile */ +#define INTEGRAL_RESOLUTION 32 +static float eval_integral(float x0, float x1, short falloff_type, float sharpness, float param) +{ + const float range = x1 - x0; + const float step = range / INTEGRAL_RESOLUTION; + float integral = 0.0f; + + for (int i = 0; i < INTEGRAL_RESOLUTION; ++i) { + float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION; + float y = eval_profile(x, falloff_type, sharpness, param); + integral += y * step; + } + + return integral; +} +#undef INTEGRAL_RESOLUTION + +static void compute_sss_kernel( + GPUSssKernelData *kd, float *radii, int sample_ct, int falloff_type, float sharpness) +{ + float rad[3]; + /* Minimum radius */ + rad[0] = MAX2(radii[0], 1e-15f); + rad[1] = MAX2(radii[1], 1e-15f); + rad[2] = MAX2(radii[2], 1e-15f); + + /* Christensen-Burley fitting */ + float l[3], d[3]; + + if (falloff_type == SHD_SUBSURFACE_BURLEY) { + mul_v3_v3fl(l, rad, 0.25f * M_1_PI); + const float A = 1.0f; + const float s = 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f); + /* XXX 0.6f Out of nowhere to match cycles! Empirical! Can be tweak better. */ + mul_v3_v3fl(d, l, 0.6f / s); + mul_v3_v3fl(rad, d, BURLEY_TRUNCATE); + kd->max_radius = MAX3(rad[0], rad[1], rad[2]); + + copy_v3_v3(kd->param, d); + } + else if (falloff_type == SHD_SUBSURFACE_CUBIC) { + copy_v3_v3(kd->param, rad); + mul_v3_fl(rad, 1.0f + sharpness); + kd->max_radius = MAX3(rad[0], rad[1], rad[2]); + } + else { + kd->max_radius = MAX3(rad[0], rad[1], rad[2]); + + copy_v3_v3(kd->param, rad); + } + + /* Compute samples locations on the 1d kernel [-1..1] */ + sss_calculate_offsets(kd, sample_ct, SSS_EXPONENT); + + /* Weights sum for normalization */ + float sum[3] = {0.0f, 0.0f, 0.0f}; + + /* Compute integral of each sample footprint */ + for (int i = 0; i < sample_ct; i++) { + float x0, x1; + + if (i == 0) { + x0 = kd->kernel[0][3] - fabsf(kd->kernel[0][3] - kd->kernel[1][3]) / 2.0f; + } + else { + x0 = (kd->kernel[i - 1][3] + kd->kernel[i][3]) / 2.0f; + } + + if (i == sample_ct - 1) { + x1 = kd->kernel[sample_ct - 1][3] + fabsf(kd->kernel[sample_ct - 2][3] - kd->kernel[sample_ct - 1][3]) / 2.0f; + } + else { + x1 = (kd->kernel[i][3] + kd->kernel[i + 1][3]) / 2.0f; + } + + x0 *= kd->max_radius; + x1 *= kd->max_radius; + + kd->kernel[i][0] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[0]); + kd->kernel[i][1] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[1]); + kd->kernel[i][2] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[2]); + + sum[0] += kd->kernel[i][0]; + sum[1] += kd->kernel[i][1]; + sum[2] += kd->kernel[i][2]; + } + + for (int i = 0; i < 3; ++i) { + if (sum[i] > 0.0f) { + /* Normalize */ + for (int j = 0; j < sample_ct; j++) { + kd->kernel[j][i] /= sum[i]; + } + } + else { + /* Avoid 0 kernel sum. */ + kd->kernel[sample_ct / 2][i] = 1.0f; + } + } + + /* Put center sample at the start of the array (to sample first) */ + float tmpv[4]; + copy_v4_v4(tmpv, kd->kernel[sample_ct / 2]); + for (int i = sample_ct / 2; i > 0; i--) { + copy_v4_v4(kd->kernel[i], kd->kernel[i - 1]); + } + copy_v4_v4(kd->kernel[0], tmpv); + + kd->samples = sample_ct; +} + +#define INTEGRAL_RESOLUTION 512 +static void compute_sss_translucence_kernel( + const GPUSssKernelData *kd, int resolution, short falloff_type, float sharpness, float **output) +{ + float (*texels)[4]; + texels = MEM_callocN(sizeof(float) * 4 * resolution, "compute_sss_translucence_kernel"); + *output = (float *)texels; + + /* Last texel should be black, hence the - 1. */ + for (int i = 0; i < resolution - 1; ++i) { + /* Distance from surface. */ + float d = kd->max_radius * ((float)i + 0.00001f) / ((float)resolution); + + /* For each distance d we compute the radiance incomming from an hypothetic parallel plane. */ + /* Compute radius of the footprint on the hypothetic plane */ + float r_fp = sqrtf(kd->max_radius * kd->max_radius - d * d); + float r_step = r_fp / INTEGRAL_RESOLUTION; + float area_accum = 0.0f; + for (float r = 0.0f; r < r_fp; r += r_step) { + /* Compute distance to the "shading" point through the medium. */ + /* r_step * 0.5f to put sample between the area borders */ + float dist = hypotf(r + r_step * 0.5f, d); + + float profile[3]; + profile[0] = eval_profile(dist, falloff_type, sharpness, kd->param[0]); + profile[1] = eval_profile(dist, falloff_type, sharpness, kd->param[1]); + profile[2] = eval_profile(dist, falloff_type, sharpness, kd->param[2]); + + /* Since the profile and configuration are radially symetrical we + * can just evaluate it once and weight it accordingly */ + float r_next = r + r_step; + float disk_area = (M_PI * r_next * r_next) - (M_PI * r * r); + + mul_v3_fl(profile, disk_area); + add_v3_v3(texels[i], profile); + area_accum += disk_area; + } + /* Normalize over the disk. */ + mul_v3_fl(texels[i], 1.0f / (area_accum)); + } + + /* Normalize */ + for (int j = resolution - 2; j > 0; j--) { + texels[j][0] /= (texels[0][0] > 0.0f) ? texels[0][0] : 1.0f; + texels[j][1] /= (texels[0][1] > 0.0f) ? texels[0][1] : 1.0f; + texels[j][2] /= (texels[0][2] > 0.0f) ? texels[0][2] : 1.0f; + } + + /* First texel should be white */ + texels[0][0] = (texels[0][0] > 0.0f) ? 1.0f : 0.0f; + texels[0][1] = (texels[0][1] > 0.0f) ? 1.0f : 0.0f; + texels[0][2] = (texels[0][2] > 0.0f) ? 1.0f : 0.0f; + + /* dim the last few texels for smoother transition */ + mul_v3_fl(texels[resolution - 2], 0.25f); + mul_v3_fl(texels[resolution - 3], 0.5f); + mul_v3_fl(texels[resolution - 4], 0.75f); +} +#undef INTEGRAL_RESOLUTION + +void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short *falloff_type, float *sharpness) +{ + material->sss_radii = radii; + material->sss_falloff = falloff_type; + material->sss_sharpness = sharpness; + material->sss_dirty = true; + + /* Update / Create UBO */ + if (material->sss_profile == NULL) { + material->sss_profile = GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL); + } +} + +struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, int sample_ct, GPUTexture **tex_profile) +{ + if (material->sss_radii == NULL) + return NULL; + + if (material->sss_dirty || (material->sss_samples != sample_ct)) { + GPUSssKernelData kd; + + float sharpness = (material->sss_sharpness != NULL) ? *material->sss_sharpness : 0.0f; + + /* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */ + sharpness *= 0.5f; + + compute_sss_kernel(&kd, material->sss_radii, sample_ct, *material->sss_falloff, sharpness); + + /* Update / Create UBO */ + GPU_uniformbuffer_update(material->sss_profile, &kd); + + /* Update / Create Tex */ + float *translucence_profile; + compute_sss_translucence_kernel(&kd, 64, *material->sss_falloff, sharpness, &translucence_profile); + + if (material->sss_tex_profile != NULL) { + GPU_texture_free(material->sss_tex_profile); + } + + material->sss_tex_profile = GPU_texture_create_1D_custom(64, 4, GPU_RGBA16F, translucence_profile, NULL); + + MEM_freeN(translucence_profile); + + material->sss_samples = sample_ct; + material->sss_dirty = false; + } + + if (tex_profile != NULL) { + *tex_profile = material->sss_tex_profile; + } + return material->sss_profile; +} + +#undef SSS_EXPONENT +#undef SSS_SAMPLES void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs) { @@ -540,6 +845,16 @@ bool GPU_material_use_world_space_shading(GPUMaterial *mat) return BKE_scene_use_world_space_shading(mat->scene); } +bool GPU_material_use_domain_surface(GPUMaterial *mat) +{ + return (mat->domain & GPU_DOMAIN_SURFACE); +} + +bool GPU_material_use_domain_volume(GPUMaterial *mat) +{ + return (mat->domain & GPU_DOMAIN_VOLUME); +} + static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **lv, GPUNodeLink **dist) { GPUNodeLink *visifac; @@ -951,14 +1266,12 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la } add_user_list(&mat->lamps, lamp); - add_user_list(&lamp->materials, shi->gpumat->ma); return; } } } else if ((mat->scene->gm.flag & GAME_GLSL_NO_SHADOWS) && (lamp->mode & LA_ONLYSHADOW)) { add_user_list(&mat->lamps, lamp); - add_user_list(&lamp->materials, shi->gpumat->ma); return; } else @@ -1025,7 +1338,6 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la } add_user_list(&mat->lamps, lamp); - add_user_list(&lamp->materials, shi->gpumat->ma); } static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr) @@ -2150,6 +2462,73 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo) return mat; } +GPUMaterial *GPU_material_from_nodetree_find( + ListBase *gpumaterials, const void *engine_type, int options) +{ + for (LinkData *link = gpumaterials->first; link; link = link->next) { + GPUMaterial *current_material = (GPUMaterial *)link->data; + if (current_material->engine_type == engine_type && + current_material->options == options) + { + return current_material; + } + } + + return NULL; +} + +/** + * TODO: This is supposed to replace GPU_material_from_blender/_world in the future + * + * \note Caller must use #GPU_material_from_nodetree_find to re-use existing materials, + * This is enforced since constructing other arguments to this function may be expensive + * so only do this when they are needed. + */ +GPUMaterial *GPU_material_from_nodetree( + Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options, + const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines) +{ + GPUMaterial *mat; + GPUNodeLink *outlink; + LinkData *link; + bool has_volume_output, has_surface_output; + + /* Caller must re-use materials. */ + BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL); + + /* allocate material */ + mat = GPU_material_construct_begin(NULL); /* TODO remove GPU_material_construct_begin */ + mat->scene = scene; + mat->engine_type = engine_type; + mat->options = options; + + ntreeGPUMaterialNodes(ntree, mat, NODE_NEW_SHADING | NODE_NEWER_SHADING); + ntreeGPUMaterialDomain(ntree, &has_surface_output, &has_volume_output); + + if (has_surface_output) { + mat->domain |= GPU_DOMAIN_SURFACE; + } + if (has_volume_output) { + mat->domain |= GPU_DOMAIN_VOLUME; + } + + /* Let Draw manager finish the construction. */ + if (mat->outlink) { + outlink = mat->outlink; + mat->pass = GPU_generate_pass_new( + mat, &mat->nodes, outlink, &mat->attribs, vert_code, geom_code, frag_lib, defines); + } + + /* note that even if building the shader fails in some way, we still keep + * it to avoid trying to compile again and again, and simple do not use + * the actual shader on drawing */ + + link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); + link->data = mat; + BLI_addtail(gpumaterials, link); + + return mat; +} GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv) { @@ -2237,386 +2616,6 @@ void GPU_materials_free(void) /* Lamps and shadow buffers */ -static void gpu_lamp_calc_winmat(GPULamp *lamp) -{ - float temp, angle, pixsize, wsize; - - if (lamp->type == LA_SUN) { - wsize = lamp->la->shadow_frustum_size; - orthographic_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend); - } - else if (lamp->type == LA_SPOT) { - angle = saacos(lamp->spotsi); - temp = 0.5f * lamp->size * cosf(angle) / sinf(angle); - pixsize = lamp->d / temp; - wsize = pixsize * 0.5f * lamp->size; - /* compute shadows according to X and Y scaling factors */ - perspective_m4( - lamp->winmat, - -wsize * lamp->spotvec[0], wsize * lamp->spotvec[0], - -wsize * lamp->spotvec[1], wsize * lamp->spotvec[1], - lamp->d, lamp->clipend); - } -} - -void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4]) -{ - float mat[4][4]; - float obmat_scale[3]; - - lamp->lay = lay; - lamp->hide = hide; - - normalize_m4_m4_ex(mat, obmat, obmat_scale); - - copy_v3_v3(lamp->vec, mat[2]); - copy_v3_v3(lamp->co, mat[3]); - copy_m4_m4(lamp->obmat, mat); - invert_m4_m4(lamp->imat, mat); - - if (lamp->type == LA_SPOT) { - /* update spotlamp scale on X and Y axis */ - lamp->spotvec[0] = obmat_scale[0] / obmat_scale[2]; - lamp->spotvec[1] = obmat_scale[1] / obmat_scale[2]; - } - - if (GPU_lamp_has_shadow_buffer(lamp)) { - /* makeshadowbuf */ - gpu_lamp_calc_winmat(lamp); - } -} - -void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy) -{ - lamp->energy = energy; - if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy; - - lamp->col[0] = r; - lamp->col[1] = g; - lamp->col[2] = b; -} - -void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2, - float coeff_const, float coeff_lin, float coeff_quad) -{ - lamp->dist = distance; - lamp->att1 = att1; - lamp->att2 = att2; - lamp->coeff_const = coeff_const; - lamp->coeff_lin = coeff_lin; - lamp->coeff_quad = coeff_quad; -} - -void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend) -{ - lamp->spotsi = cosf(spotsize * 0.5f); - lamp->spotbl = (1.0f - lamp->spotsi) * spotblend; -} - -static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *la, GPULamp *lamp) -{ - lamp->scene = scene; - lamp->ob = ob; - lamp->par = par; - lamp->la = la; - - /* add_render_lamp */ - lamp->mode = la->mode; - lamp->type = la->type; - - lamp->energy = la->energy; - if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy; - - lamp->col[0] = la->r; - lamp->col[1] = la->g; - lamp->col[2] = la->b; - - GPU_lamp_update(lamp, ob->lay, (ob->restrictflag & OB_RESTRICT_RENDER), ob->obmat); - - lamp->spotsi = la->spotsize; - if (lamp->mode & LA_HALO) - if (lamp->spotsi > DEG2RADF(170.0f)) - lamp->spotsi = DEG2RADF(170.0f); - lamp->spotsi = cosf(lamp->spotsi * 0.5f); - lamp->spotbl = (1.0f - lamp->spotsi) * la->spotblend; - lamp->k = la->k; - - lamp->dist = la->dist; - lamp->falloff_type = la->falloff_type; - lamp->att1 = la->att1; - lamp->att2 = la->att2; - lamp->coeff_const = la->coeff_const; - lamp->coeff_lin = la->coeff_lin; - lamp->coeff_quad = la->coeff_quad; - lamp->curfalloff = la->curfalloff; - - /* initshadowbuf */ - lamp->bias = 0.02f * la->bias; - lamp->size = la->bufsize; - lamp->d = la->clipsta; - lamp->clipend = la->clipend; - - /* arbitrary correction for the fact we do no soft transition */ - lamp->bias *= 0.25f; -} - -static void gpu_lamp_shadow_free(GPULamp *lamp) -{ - if (lamp->tex) { - GPU_texture_free(lamp->tex); - lamp->tex = NULL; - } - if (lamp->depthtex) { - GPU_texture_free(lamp->depthtex); - lamp->depthtex = NULL; - } - if (lamp->fb) { - GPU_framebuffer_free(lamp->fb); - lamp->fb = NULL; - } - if (lamp->blurtex) { - GPU_texture_free(lamp->blurtex); - lamp->blurtex = NULL; - } - if (lamp->blurfb) { - GPU_framebuffer_free(lamp->blurfb); - lamp->blurfb = NULL; - } -} - -GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) -{ - Lamp *la; - GPULamp *lamp; - LinkData *link; - - for (link = ob->gpulamp.first; link; link = link->next) { - lamp = (GPULamp *)link->data; - - if (lamp->par == par && lamp->scene == scene) - return link->data; - } - - lamp = MEM_callocN(sizeof(GPULamp), "GPULamp"); - - link = MEM_callocN(sizeof(LinkData), "GPULampLink"); - link->data = lamp; - BLI_addtail(&ob->gpulamp, link); - - la = ob->data; - gpu_lamp_from_blender(scene, ob, par, la, lamp); - - if ((la->type == LA_SPOT && (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY))) || - (la->type == LA_SUN && (la->mode & LA_SHAD_RAY))) - { - /* opengl */ - lamp->fb = GPU_framebuffer_create(); - if (!lamp->fb) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { - /* Shadow depth map */ - lamp->depthtex = GPU_texture_create_depth(lamp->size, lamp->size, NULL); - if (!lamp->depthtex) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - /* Shadow color map */ - lamp->tex = GPU_texture_create_vsm_shadow_map(lamp->size, NULL); - if (!lamp->tex) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - /* FBO and texture for blurring */ - lamp->blurfb = GPU_framebuffer_create(); - if (!lamp->blurfb) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - lamp->blurtex = GPU_texture_create_vsm_shadow_map(lamp->size * 0.5, NULL); - if (!lamp->blurtex) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - /* we need to properly bind to test for completeness */ - GPU_texture_bind_as_framebuffer(lamp->blurtex); - - if (!GPU_framebuffer_check_valid(lamp->blurfb, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - GPU_framebuffer_texture_unbind(lamp->blurfb, lamp->blurtex); - } - else { - lamp->tex = GPU_texture_create_depth(lamp->size, lamp->size, NULL); - if (!lamp->tex) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - } - - GPU_framebuffer_restore(); - - lamp->shadow_color[0] = la->shdwr; - lamp->shadow_color[1] = la->shdwg; - lamp->shadow_color[2] = la->shdwb; - } - else { - lamp->shadow_color[0] = 1.0; - lamp->shadow_color[1] = 1.0; - lamp->shadow_color[2] = 1.0; - } - - return lamp; -} - -void GPU_lamp_free(Object *ob) -{ - GPULamp *lamp; - LinkData *link; - LinkData *nlink; - Material *ma; - - for (link = ob->gpulamp.first; link; link = link->next) { - lamp = link->data; - - while (lamp->materials.first) { - nlink = lamp->materials.first; - ma = nlink->data; - BLI_freelinkN(&lamp->materials, nlink); - - if (ma->gpumaterial.first) - GPU_material_free(&ma->gpumaterial); - } - - gpu_lamp_shadow_free(lamp); - - MEM_freeN(lamp); - } - - BLI_freelistN(&ob->gpulamp); -} - -bool GPU_lamp_has_shadow_buffer(GPULamp *lamp) -{ - return (!(lamp->scene->gm.flag & GAME_GLSL_NO_SHADOWS) && - !(lamp->scene->gm.flag & GAME_GLSL_NO_LIGHTS) && - lamp->tex && lamp->fb); -} - -void GPU_lamp_update_buffer_mats(GPULamp *lamp) -{ - float rangemat[4][4], persmat[4][4]; - - /* initshadowbuf */ - invert_m4_m4(lamp->viewmat, lamp->obmat); - normalize_v3(lamp->viewmat[0]); - normalize_v3(lamp->viewmat[1]); - normalize_v3(lamp->viewmat[2]); - - /* makeshadowbuf */ - mul_m4_m4m4(persmat, lamp->winmat, lamp->viewmat); - - /* opengl depth buffer is range 0.0..1.0 instead of -1.0..1.0 in blender */ - unit_m4(rangemat); - rangemat[0][0] = 0.5f; - rangemat[1][1] = 0.5f; - rangemat[2][2] = 0.5f; - rangemat[3][0] = 0.5f; - rangemat[3][1] = 0.5f; - rangemat[3][2] = 0.5f; - - mul_m4_m4m4(lamp->persmat, rangemat, persmat); -} - -void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsize, float winmat[4][4]) -{ - GPU_lamp_update_buffer_mats(lamp); - - /* opengl */ - glDisable(GL_SCISSOR_TEST); - GPU_texture_bind_as_framebuffer(lamp->tex); - if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) - GPU_shader_bind(GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE)); - - /* set matrices */ - copy_m4_m4(viewmat, lamp->viewmat); - copy_m4_m4(winmat, lamp->winmat); - *winsize = lamp->size; -} - -void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp) -{ - if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { - GPU_shader_unbind(); - GPU_framebuffer_blur(lamp->fb, lamp->tex, lamp->blurfb, lamp->blurtex); - } - - GPU_framebuffer_texture_unbind(lamp->fb, lamp->tex); - GPU_framebuffer_restore(); - glEnable(GL_SCISSOR_TEST); -} - -int GPU_lamp_shadow_buffer_type(GPULamp *lamp) -{ - return lamp->la->shadowmap_type; -} - -int GPU_lamp_shadow_bind_code(GPULamp *lamp) -{ - return lamp->tex ? GPU_texture_opengl_bindcode(lamp->tex) : -1; -} - -float *GPU_lamp_dynpersmat(GPULamp *lamp) -{ - return &lamp->dynpersmat[0][0]; -} - -int GPU_lamp_shadow_layer(GPULamp *lamp) -{ - if (lamp->fb && lamp->tex && (lamp->mode & (LA_LAYER | LA_LAYER_SHADOW))) - return lamp->lay; - else - return -1; -} - GPUNodeLink *GPU_lamp_get_data( GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **r_col, GPUNodeLink **r_lv, GPUNodeLink **r_dist, GPUNodeLink **r_shadow, GPUNodeLink **r_energy) @@ -2658,7 +2657,6 @@ GPUNodeLink *GPU_lamp_get_data( /* ensure shadow buffer and lamp textures will be updated */ add_user_list(&mat->lamps, lamp); - add_user_list(&lamp->materials, mat->ma); return visifac; } @@ -2728,6 +2726,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) break; case GPU_NONE: + case GPU_TEX3D: case GPU_TEXCUBE: case GPU_FLOAT: case GPU_VEC2: @@ -2735,6 +2734,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) case GPU_VEC4: case GPU_MAT3: case GPU_MAT4: + case GPU_CLOSURE: case GPU_ATTRIB: break; } @@ -2763,7 +2763,9 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) break; case GPU_NONE: + case GPU_CLOSURE: case GPU_TEX2D: + case GPU_TEX3D: case GPU_TEXCUBE: case GPU_SHADOW2D: case GPU_ATTRIB: diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c new file mode 100644 index 00000000000..b6214f2778b --- /dev/null +++ b/source/blender/gpu/intern/gpu_matrix.c @@ -0,0 +1,649 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 ipmlied 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) 2012 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Alexandr Kuznetsov, Jason Wilkins, Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/intern/gpu_matrix.c + * \ingroup gpu + */ + +#include "../../../intern/gawain/gawain/gwn_shader_interface.h" + +#define SUPPRESS_GENERIC_MATRIX_API +#define USE_GPU_PY_MATRIX_API /* only so values are declared */ +#include "GPU_matrix.h" +#undef USE_GPU_PY_MATRIX_API + +#include "BLI_math_matrix.h" +#include "BLI_math_rotation.h" +#include "BLI_math_vector.h" + + +#define DEBUG_MATRIX_BIND 0 + +#define MATRIX_STACK_DEPTH 32 + +typedef float Mat4[4][4]; +typedef float Mat3[3][3]; + +typedef struct MatrixStack { + Mat4 stack[MATRIX_STACK_DEPTH]; + unsigned int top; +} MatrixStack; + +typedef struct { + MatrixStack model_view_stack; + MatrixStack projection_stack; + + bool dirty; + + /* TODO: cache of derived matrices (Normal, MVP, inverse MVP, etc) + * generate as needed for shaders, invalidate when original matrices change + * + * TODO: separate Model from View transform? Batches/objects have model, + * camera/eye has view & projection + */ +} MatrixState; + +#define MATRIX_4X4_IDENTITY {{1.0f, 0.0f, 0.0f, 0.0f}, \ + {0.0f, 1.0f, 0.0f, 0.0f}, \ + {0.0f, 0.0f, 1.0f, 0.0f}, \ + {0.0f, 0.0f, 0.0f, 1.0f}} + +static MatrixState state = { + .model_view_stack = {{MATRIX_4X4_IDENTITY}, 0}, + .projection_stack = {{MATRIX_4X4_IDENTITY}, 0}, + .dirty = true +}; + +#undef MATRIX_4X4_IDENTITY + +#define ModelViewStack state.model_view_stack +#define ModelView ModelViewStack.stack[ModelViewStack.top] + +#define ProjectionStack state.projection_stack +#define Projection ProjectionStack.stack[ProjectionStack.top] + +void gpuMatrixReset(void) +{ + state.model_view_stack.top = 0; + state.projection_stack.top = 0; + unit_m4(ModelView); + unit_m4(Projection); + state.dirty = true; +} + +#ifdef WITH_GPU_SAFETY + +/* Check if matrix is numerically good */ +static void checkmat(cosnt float *m) +{ + const int n = 16; + for (int i = 0; i < n; i++) { +#if _MSC_VER + BLI_assert(_finite(m[i])); +#else + BLI_assert(!isinf(m[i])); +#endif + } +} + +#define CHECKMAT(m) checkmat((const float*)m) + +#else + +#define CHECKMAT(m) + +#endif + + +void gpuPushMatrix(void) +{ + BLI_assert(ModelViewStack.top + 1 < MATRIX_STACK_DEPTH); + ModelViewStack.top++; + copy_m4_m4(ModelView, ModelViewStack.stack[ModelViewStack.top - 1]); +} + +void gpuPopMatrix(void) +{ + BLI_assert(ModelViewStack.top > 0); + ModelViewStack.top--; + state.dirty = true; +} + +void gpuPushProjectionMatrix(void) +{ + BLI_assert(ProjectionStack.top + 1 < MATRIX_STACK_DEPTH); + ProjectionStack.top++; + copy_m4_m4(Projection, ProjectionStack.stack[ProjectionStack.top - 1]); +} + +void gpuPopProjectionMatrix(void) +{ + BLI_assert(ProjectionStack.top > 0); + ProjectionStack.top--; + state.dirty = true; +} + +void gpuLoadMatrix(const float m[4][4]) +{ + copy_m4_m4(ModelView, m); + CHECKMAT(ModelView3D); + state.dirty = true; +} + +void gpuLoadIdentityProjectionMatrix(void) +{ + unit_m4(Projection); + CHECKMAT(Projection3D); + state.dirty = true; +} + +void gpuLoadProjectionMatrix(const float m[4][4]) +{ + copy_m4_m4(Projection, m); + CHECKMAT(Projection3D); + state.dirty = true; +} + +void gpuLoadIdentity(void) +{ + unit_m4(ModelView); + state.dirty = true; +} + +void gpuTranslate2f(float x, float y) +{ + Mat4 m; + unit_m4(m); + m[3][0] = x; + m[3][1] = y; + gpuMultMatrix(m); +} + +void gpuTranslate2fv(const float vec[2]) +{ + gpuTranslate2f(vec[0], vec[1]); +} + +void gpuTranslate3f(float x, float y, float z) +{ +#if 1 + translate_m4(ModelView, x, y, z); + CHECKMAT(ModelView); +#else /* above works well in early testing, below is generic version */ + Mat4 m; + unit_m4(m); + m[3][0] = x; + m[3][1] = y; + m[3][2] = z; + gpuMultMatrix(m); +#endif + state.dirty = true; +} + +void gpuTranslate3fv(const float vec[3]) +{ + gpuTranslate3f(vec[0], vec[1], vec[2]); +} + +void gpuScaleUniform(float factor) +{ + Mat4 m; + scale_m4_fl(m, factor); + gpuMultMatrix(m); +} + +void gpuScale2f(float x, float y) +{ + Mat4 m = {{0.0f}}; + m[0][0] = x; + m[1][1] = y; + m[2][2] = 1.0f; + m[3][3] = 1.0f; + gpuMultMatrix(m); +} + +void gpuScale2fv(const float vec[2]) +{ + gpuScale2f(vec[0], vec[1]); +} + +void gpuScale3f(float x, float y, float z) +{ + Mat4 m = {{0.0f}}; + m[0][0] = x; + m[1][1] = y; + m[2][2] = z; + m[3][3] = 1.0f; + gpuMultMatrix(m); +} + +void gpuScale3fv(const float vec[3]) +{ + gpuScale3f(vec[0], vec[1], vec[2]); +} + +void gpuMultMatrix(const float m[4][4]) +{ + mul_m4_m4_post(ModelView, m); + CHECKMAT(ModelView); + state.dirty = true; +} + +void gpuRotate2D(float deg) +{ + /* essentially RotateAxis('Z') + * TODO: simpler math for 2D case + */ + rotate_m4(ModelView, 'Z', DEG2RADF(deg)); +} + +void gpuRotate3f(float deg, float x, float y, float z) +{ + const float axis[3] = {x, y, z}; + gpuRotate3fv(deg, axis); +} + +void gpuRotate3fv(float deg, const float axis[3]) +{ + Mat4 m; + axis_angle_to_mat4(m, axis, DEG2RADF(deg)); + gpuMultMatrix(m); +} + +void gpuRotateAxis(float deg, char axis) +{ + /* rotate_m4 works in place */ + rotate_m4(ModelView, axis, DEG2RADF(deg)); + CHECKMAT(ModelView); + state.dirty = true; +} + +static void mat4_ortho_set(float m[4][4], float left, float right, float bottom, float top, float near, float far) +{ + m[0][0] = 2.0f / (right - left); + m[1][0] = 0.0f; + m[2][0] = 0.0f; + m[3][0] = -(right + left) / (right - left); + + m[0][1] = 0.0f; + m[1][1] = 2.0f / (top - bottom); + m[2][1] = 0.0f; + m[3][1] = -(top + bottom) / (top - bottom); + + m[0][2] = 0.0f; + m[1][2] = 0.0f; + m[2][2] = -2.0f / (far - near); + m[3][2] = -(far + near) / (far - near); + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = 0.0f; + m[3][3] = 1.0f; + + state.dirty = true; +} + +static void mat4_frustum_set(float m[4][4], float left, float right, float bottom, float top, float near, float far) +{ + m[0][0] = 2.0f * near / (right - left); + m[1][0] = 0.0f; + m[2][0] = (right + left) / (right - left); + m[3][0] = 0.0f; + + m[0][1] = 0.0f; + m[1][1] = 2.0f * near / (top - bottom); + m[2][1] = (top + bottom) / (top - bottom); + m[3][1] = 0.0f; + + m[0][2] = 0.0f; + m[1][2] = 0.0f; + m[2][2] = -(far + near) / (far - near); + m[3][2] = -2.0f * far * near / (far - near); + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = -1.0f; + m[3][3] = 0.0f; + + state.dirty = true; +} + +static void mat4_look_from_origin(float m[4][4], float lookdir[3], float camup[3]) +{ +/* This function is loosely based on Mesa implementation. + * + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + + float side[3]; + + normalize_v3(lookdir); + + cross_v3_v3v3(side, lookdir, camup); + + normalize_v3(side); + + cross_v3_v3v3(camup, side, lookdir); + + m[0][0] = side[0]; + m[1][0] = side[1]; + m[2][0] = side[2]; + m[3][0] = 0.0f; + + m[0][1] = camup[0]; + m[1][1] = camup[1]; + m[2][1] = camup[2]; + m[3][1] = 0.0f; + + m[0][2] = -lookdir[0]; + m[1][2] = -lookdir[1]; + m[2][2] = -lookdir[2]; + m[3][2] = 0.0f; + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = 0.0f; + m[3][3] = 1.0f; + + state.dirty = true; +} + +void gpuOrtho(float left, float right, float bottom, float top, float near, float far) +{ + mat4_ortho_set(Projection, left, right, bottom, top, near, far); + CHECKMAT(Projection); + state.dirty = true; +} + +void gpuOrtho2D(float left, float right, float bottom, float top) +{ + Mat4 m; + mat4_ortho_set(m, left, right, bottom, top, -1.0f, 1.0f); + CHECKMAT(Projection2D); + state.dirty = true; +} + +void gpuFrustum(float left, float right, float bottom, float top, float near, float far) +{ + mat4_frustum_set(Projection, left, right, bottom, top, near, far); + CHECKMAT(Projection); + state.dirty = true; +} + +void gpuPerspective(float fovy, float aspect, float near, float far) +{ + float half_height = tanf(fovy * (float)(M_PI / 360.0)) * near; + float half_width = half_height * aspect; + gpuFrustum(-half_width, +half_width, -half_height, +half_height, near, far); +} + +void gpuLookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ) +{ + Mat4 cm; + float lookdir[3]; + float camup[3] = {upX, upY, upZ}; + + lookdir[0] = centerX - eyeX; + lookdir[1] = centerY - eyeY; + lookdir[2] = centerZ - eyeZ; + + mat4_look_from_origin(cm, lookdir, camup); + + gpuMultMatrix(cm); + gpuTranslate3f(-eyeX, -eyeY, -eyeZ); +} + +void gpuProject(const float world[3], const float model[4][4], const float proj[4][4], const int view[4], float win[3]) +{ + float v[4]; + + mul_v4_m4v3(v, model, world); + mul_m4_v4(proj, v); + + if (v[3] != 0.0f) { + mul_v3_fl(v, 1.0f / v[3]); + } + + win[0] = view[0] + (view[2] * (v[0] + 1)) * 0.5f; + win[1] = view[1] + (view[3] * (v[1] + 1)) * 0.5f; + win[2] = (v[2] + 1) * 0.5f; +} + +bool gpuUnProject(const float win[3], const float model[4][4], const float proj[4][4], const int view[4], float world[3]) +{ + float pm[4][4]; + float in[4]; + float out[4]; + + mul_m4_m4m4(pm, proj, model); + + if (!invert_m4(pm)) { + zero_v3(world); + return false; + } + + in[0] = win[0]; + in[1] = win[1]; + in[2] = win[2]; + in[3] = 1; + + /* Map x and y from window coordinates */ + in[0] = (in[0] - view[0]) / view[2]; + in[1] = (in[1] - view[1]) / view[3]; + + /* Map to range -1 to +1 */ + in[0] = 2 * in[0] - 1; + in[1] = 2 * in[1] - 1; + in[2] = 2 * in[2] - 1; + + mul_v4_m4v3(out, pm, in); + + if (out[3] == 0.0f) { + copy_v3_v3(world, out); + return false; + } + + mul_v3_v3fl(world, out, 1.0f / out[3]); + return true; +} + +const float (*gpuGetModelViewMatrix(float m[4][4]))[4] +{ + if (m) { + copy_m4_m4(m, ModelView); + return m; + } + else { + return ModelView; + } +} + +const float (*gpuGetProjectionMatrix(float m[4][4]))[4] +{ + if (m) { + copy_m4_m4(m, Projection); + return m; + } + else { + return Projection; + } +} + +const float (*gpuGetModelViewProjectionMatrix(float m[4][4]))[4] +{ + if (m == NULL) { + static Mat4 temp; + m = temp; + } + + mul_m4_m4m4(m, Projection, ModelView); + return m; +} + +const float (*gpuGetNormalMatrix(float m[3][3]))[3] +{ + if (m == NULL) { + static Mat3 temp3; + m = temp3; + } + + copy_m3_m4(m, (const float (*)[4])gpuGetModelViewMatrix(NULL)); + + invert_m3(m); + transpose_m3(m); + + return m; +} + +const float (*gpuGetNormalMatrixInverse(float m[3][3]))[3] +{ + if (m == NULL) { + static Mat3 temp3; + m = temp3; + } + + gpuGetNormalMatrix(m); + invert_m3(m); + + return m; +} + +void gpuBindMatrices(const Gwn_ShaderInterface *shaderface) +{ + /* set uniform values to matrix stack values + * call this before a draw call if desired matrices are dirty + * call glUseProgram before this, as glUniform expects program to be bound + */ + + const Gwn_ShaderInput *MV = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_MODELVIEW); + const Gwn_ShaderInput *P = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_PROJECTION); + const Gwn_ShaderInput *MVP = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_MVP); + + const Gwn_ShaderInput *N = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_NORMAL); + const Gwn_ShaderInput *MV_inv = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_MODELVIEW_INV); + const Gwn_ShaderInput *P_inv = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_PROJECTION_INV); + + if (MV) { +#if DEBUG_MATRIX_BIND + puts("setting MV matrix"); +#endif + + glUniformMatrix4fv(MV->location, 1, GL_FALSE, (const float *)gpuGetModelViewMatrix(NULL)); + } + + if (P) { +#if DEBUG_MATRIX_BIND + puts("setting P matrix"); +#endif + + glUniformMatrix4fv(P->location, 1, GL_FALSE, (const float *)gpuGetProjectionMatrix(NULL)); + } + + if (MVP) { +#if DEBUG_MATRIX_BIND + puts("setting MVP matrix"); +#endif + + glUniformMatrix4fv(MVP->location, 1, GL_FALSE, (const float *)gpuGetModelViewProjectionMatrix(NULL)); + } + + if (N) { +#if DEBUG_MATRIX_BIND + puts("setting normal matrix"); +#endif + + glUniformMatrix3fv(N->location, 1, GL_FALSE, (const float *)gpuGetNormalMatrix(NULL)); + } + + if (MV_inv) { + Mat4 m; + gpuGetModelViewMatrix(m); + invert_m4(m); + glUniformMatrix4fv(MV_inv->location, 1, GL_FALSE, (const float *)m); + } + + if (P_inv) { + Mat4 m; + gpuGetProjectionMatrix(m); + invert_m4(m); + glUniformMatrix4fv(P_inv->location, 1, GL_FALSE, (const float *)m); + } + + state.dirty = false; +} + +bool gpuMatricesDirty(void) +{ + return state.dirty; +} + + +/* -------------------------------------------------------------------- */ + +/** \name Python API Helpers + * \{ */ +BLI_STATIC_ASSERT(GPU_PY_MATRIX_STACK_LEN + 1 == MATRIX_STACK_DEPTH, "define mismatch"); + +/* Return int since caller is may subtract. */ + +int GPU_matrix_stack_level_get_model_view(void) +{ + return (int)state.model_view_stack.top; +} + +int GPU_matrix_stack_level_get_projection(void) +{ + return (int)state.projection_stack.top; +} + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c index 632b0cfee1b..153cf5f1e97 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -187,12 +187,7 @@ unsigned int GPU_select_end(void) */ bool GPU_select_query_check_active(void) { - return ((U.gpu_select_method == USER_SELECT_USE_OCCLUSION_QUERY) || - ((U.gpu_select_method == USER_SELECT_AUTO) && - (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY) || - /* unsupported by nouveau, gallium 0.4, see: T47940 */ - GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)))); - + return ELEM(U.gpu_select_method, USER_SELECT_USE_OCCLUSION_QUERY, USER_SELECT_AUTO); } /* ---------------------------------------------------------------------------- @@ -232,3 +227,29 @@ bool GPU_select_is_cached(void) { return g_select_state.use_cache && gpu_select_pick_is_cached(); } + + +/* ---------------------------------------------------------------------------- + * Utilities + */ + +/** + * Helper function, nothing special but avoids doing inline since hit's aren't sorted by depth + * and purpose of 4x buffer indices isn't so clear. + * + * Note that comparing depth as uint is fine. + */ +const uint *GPU_select_buffer_near(const uint *buffer, int hits) +{ + const uint *buffer_near = NULL; + uint depth_min = (uint)-1; + for (int i = 0; i < hits; i++) { + if (buffer[1] < depth_min) { + BLI_assert(buffer[3] != -1); + depth_min = buffer[1]; + buffer_near = buffer; + } + buffer += 4; + } + return buffer_near; +} diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c index 0a77420fa25..f1d311890e6 100644 --- a/source/blender/gpu/intern/gpu_select_pick.c +++ b/source/blender/gpu/intern/gpu_select_pick.c @@ -31,6 +31,8 @@ #include <stdlib.h> #include <float.h> +#include "GPU_immediate.h" +#include "GPU_draw.h" #include "GPU_select.h" #include "GPU_extensions.h" #include "GPU_glew.h" @@ -316,8 +318,8 @@ void gpu_select_pick_begin( /* Restrict OpenGL operations for when we don't have cache */ if (ps->is_cached == false) { + gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_VIEWPORT_BIT); - glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT); /* disable writing to the framebuffer */ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); @@ -331,10 +333,6 @@ void gpu_select_pick_begin( glDepthFunc(GL_LEQUAL); } - /* set just in case */ - glPixelTransferf(GL_DEPTH_BIAS, 0.0); - glPixelTransferf(GL_DEPTH_SCALE, 1.0); - float viewport[4]; glGetFloatv(GL_SCISSOR_BOX, viewport); @@ -540,7 +538,7 @@ unsigned int gpu_select_pick_end(void) gpu_select_pick_load_id(ps->gl.prev_id); } - glPopAttrib(); + gpuPopAttrib(); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c index 3d589986281..e3bd20f3776 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.c +++ b/source/blender/gpu/intern/gpu_select_sample_query.c @@ -32,6 +32,8 @@ #include <stdlib.h> +#include "GPU_immediate.h" +#include "GPU_draw.h" #include "GPU_select.h" #include "GPU_extensions.h" #include "GPU_glew.h" @@ -94,7 +96,7 @@ void gpu_select_query_begin( g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id), "gpu selection ids"); glGenQueries(g_query_state.num_of_queries, g_query_state.queries); - glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT); + gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_VIEWPORT_BIT); /* disable writing to the framebuffer */ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); @@ -206,7 +208,7 @@ unsigned int gpu_select_query_end(void) glDeleteQueries(g_query_state.num_of_queries, g_query_state.queries); MEM_freeN(g_query_state.queries); MEM_freeN(g_query_state.id); - glPopAttrib(); + gpuPopAttrib(); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); return hits; diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index b579f87698c..598722d372b 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -30,22 +30,113 @@ #include "BLI_utildefines.h" #include "BLI_math_base.h" #include "BLI_math_vector.h" +#include "BLI_path_util.h" +#include "BKE_appdir.h" #include "BKE_global.h" +#include "DNA_space_types.h" + #include "GPU_compositing.h" -#include "GPU_debug.h" #include "GPU_extensions.h" -#include "GPU_glew.h" +#include "GPU_matrix.h" #include "GPU_shader.h" #include "GPU_texture.h" -#include "GPU_material.h" +#include "GPU_uniformbuffer.h" + +#include "gpu_shader_private.h" -/* TODO(sergey): Find better default values for this constants. */ -#define MAX_DEFINE_LENGTH 1024 -#define MAX_EXT_DEFINE_LENGTH 1024 +/* Adjust these constants as needed. */ +#define MAX_DEFINE_LENGTH 256 +#define MAX_EXT_DEFINE_LENGTH 256 /* Non-generated shaders */ +extern char datatoc_gpu_shader_depth_only_frag_glsl[]; +extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; +extern char datatoc_gpu_shader_checker_frag_glsl[]; +extern char datatoc_gpu_shader_diag_stripes_frag_glsl[]; +extern char datatoc_gpu_shader_simple_lighting_frag_glsl[]; +extern char datatoc_gpu_shader_simple_lighting_flat_color_frag_glsl[]; +extern char datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl[]; +extern char datatoc_gpu_shader_simple_lighting_smooth_color_alpha_frag_glsl[]; +extern char datatoc_gpu_shader_flat_color_frag_glsl[]; +extern char datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl[]; +extern char datatoc_gpu_shader_2D_vert_glsl[]; +extern char datatoc_gpu_shader_2D_flat_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_smooth_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_smooth_color_frag_glsl[]; +extern char datatoc_gpu_shader_2D_image_vert_glsl[]; + +extern char datatoc_gpu_shader_3D_image_vert_glsl[]; +extern char datatoc_gpu_shader_image_linear_frag_glsl[]; +extern char datatoc_gpu_shader_image_color_frag_glsl[]; +extern char datatoc_gpu_shader_image_alpha_color_frag_glsl[]; +extern char datatoc_gpu_shader_image_shuffle_color_frag_glsl[]; +extern char datatoc_gpu_shader_image_interlace_frag_glsl[]; +extern char datatoc_gpu_shader_image_mask_uniform_color_frag_glsl[]; +extern char datatoc_gpu_shader_image_modulate_alpha_frag_glsl[]; +extern char datatoc_gpu_shader_image_rect_modulate_alpha_frag_glsl[]; +extern char datatoc_gpu_shader_image_depth_linear_frag_glsl[]; +extern char datatoc_gpu_shader_3D_vert_glsl[]; +extern char datatoc_gpu_shader_3D_normal_vert_glsl[]; +extern char datatoc_gpu_shader_3D_flat_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_smooth_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_normal_flat_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; +extern char datatoc_gpu_shader_3D_passthrough_vert_glsl[]; +extern char datatoc_gpu_shader_3D_clipped_uniform_color_vert_glsl[]; + +extern char datatoc_gpu_shader_instance_vert_glsl[]; +extern char datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl[]; +extern char datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl[]; +extern char datatoc_gpu_shader_instance_screenspace_variying_color_vert_glsl[]; +extern char datatoc_gpu_shader_instance_screen_aligned_vert_glsl[]; +extern char datatoc_gpu_shader_instance_camera_vert_glsl[]; +extern char datatoc_gpu_shader_instance_distance_line_vert_glsl[]; +extern char datatoc_gpu_shader_instance_edges_variying_color_geom_glsl[]; +extern char datatoc_gpu_shader_instance_edges_variying_color_vert_glsl[]; +extern char datatoc_gpu_shader_instance_bone_envelope_solid_vert_glsl[]; +extern char datatoc_gpu_shader_instance_bone_envelope_wire_vert_glsl[]; +extern char datatoc_gpu_shader_instance_mball_helpers_vert_glsl[]; + +extern char datatoc_gpu_shader_3D_groundpoint_vert_glsl[]; +extern char datatoc_gpu_shader_3D_groundline_geom_glsl[]; + +extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[]; +extern char datatoc_gpu_shader_point_uniform_color_aa_frag_glsl[]; +extern char datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl[]; +extern char datatoc_gpu_shader_point_varying_color_outline_aa_frag_glsl[]; +extern char datatoc_gpu_shader_point_varying_color_frag_glsl[]; +extern char datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_varying_size_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_uniform_size_aa_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_uniform_size_outline_aa_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert_glsl[]; + +extern char datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_line_dashed_frag_glsl[]; +extern char datatoc_gpu_shader_2D_line_dashed_geom_glsl[]; +extern char datatoc_gpu_shader_3D_line_dashed_uniform_color_legacy_vert_glsl[]; +extern char datatoc_gpu_shader_3D_line_dashed_uniform_color_vert_glsl[]; + +extern char datatoc_gpu_shader_edges_front_back_persp_vert_glsl[]; +extern char datatoc_gpu_shader_edges_front_back_persp_geom_glsl[]; +extern char datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl[]; +extern char datatoc_gpu_shader_edges_front_back_ortho_vert_glsl[]; +extern char datatoc_gpu_shader_edges_overlay_vert_glsl[]; +extern char datatoc_gpu_shader_edges_overlay_geom_glsl[]; +extern char datatoc_gpu_shader_edges_overlay_simple_geom_glsl[]; +extern char datatoc_gpu_shader_edges_overlay_frag_glsl[]; +extern char datatoc_gpu_shader_text_vert_glsl[]; +extern char datatoc_gpu_shader_text_frag_glsl[]; +extern char datatoc_gpu_shader_keyframe_diamond_vert_glsl[]; +extern char datatoc_gpu_shader_keyframe_diamond_frag_glsl[]; + extern char datatoc_gpu_shader_fire_frag_glsl[]; extern char datatoc_gpu_shader_smoke_vert_glsl[]; extern char datatoc_gpu_shader_smoke_frag_glsl[]; @@ -53,7 +144,7 @@ extern char datatoc_gpu_shader_vsm_store_vert_glsl[]; extern char datatoc_gpu_shader_vsm_store_frag_glsl[]; extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[]; extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[]; -extern char datatoc_gpu_shader_fx_vert_glsl[]; +extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; extern char datatoc_gpu_shader_fx_ssao_frag_glsl[]; extern char datatoc_gpu_shader_fx_dof_frag_glsl[]; extern char datatoc_gpu_shader_fx_dof_vert_glsl[]; @@ -63,41 +154,25 @@ extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[]; extern char datatoc_gpu_shader_fx_depth_resolve_glsl[]; extern char datatoc_gpu_shader_fx_lib_glsl[]; -static struct GPUShadersGlobal { - struct { - GPUShader *vsm_store; - GPUShader *sep_gaussian_blur; - GPUShader *smoke; - GPUShader *smoke_fire; - GPUShader *smoke_coba; - /* cache for shader fx. Those can exist in combinations so store them here */ - GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; - } shaders; -} GG = {{NULL}}; - -/* GPUShader */ +/* cache of built-in shaders (each is created on first use) */ +static GPUShader *builtin_shaders[GPU_NUM_BUILTIN_SHADERS] = { NULL }; -struct GPUShader { - GLuint program; /* handle for full program (links shader stages below) */ +/* cache for shader fx. Those can exist in combinations so store them here */ +static GPUShader *fx_shaders[MAX_FX_SHADERS * 2] = { NULL }; - GLuint vertex; /* handle for vertex shader */ - GLuint geometry; /* handle for geometry shader */ - GLuint fragment; /* handle for fragment shader */ - - int totattrib; /* total number of attributes */ - int uniforms; /* required uniforms */ - - void *uniform_interface; /* cached uniform interface for shader. Data depends on shader */ -}; +typedef struct { + const char *vert; + const char *frag; + const char *geom; /* geometry stage runs between vert & frag, but is less common, so it goes last */ +} GPUShaderStages; static void shader_print_errors(const char *task, const char *log, const char **code, int totcode) { - int i; int line = 1; fprintf(stderr, "GPUShader: %s error:\n", task); - for (i = 0; i < totcode; i++) { + for (int i = 0; i < totcode; i++) { const char *c, *pos, *end = code[i] + strlen(code[i]); if (G.debug & G_DEBUG) { @@ -120,71 +195,19 @@ static void shader_print_errors(const char *task, const char *log, const char ** static const char *gpu_shader_version(void) { - if (GLEW_VERSION_3_2) { - if (GLEW_ARB_compatibility) { - return "#version 150 compatibility\n"; - /* highest version that is widely supported - * gives us native geometry shaders! - * use compatibility profile so we can continue using builtin shader input/output names - */ - } - else { - return "#version 130\n"; - /* latest version that is compatible with existing shaders */ - } - } - else if (GLEW_VERSION_3_1) { - if (GLEW_ARB_compatibility) { - return "#version 140\n"; - /* also need the ARB_compatibility extension, handled below */ - } - else { - return "#version 130\n"; - /* latest version that is compatible with existing shaders */ - } - } - else if (GLEW_VERSION_3_0) { - return "#version 130\n"; - /* GLSL 1.3 has modern syntax/keywords/datatypes so use if available - * older features are deprecated but still available without compatibility extension or profile - */ - } - else { - return "#version 120\n"; - /* minimum supported */ - } + return "#version 330\n"; } - -static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], bool use_geometry_shader) +static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH]) { /* enable extensions for features that are not part of our base GLSL version * don't use an extension for something already available! */ if (GLEW_ARB_texture_query_lod) { - /* a #version 400 feature, but we use #version 150 maximum so use extension */ + /* a #version 400 feature, but we use #version 330 maximum so use extension */ strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n"); } - - if (use_geometry_shader && GPU_geometry_shader_support_via_extension()) { - strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n"); - } - - if (GLEW_VERSION_3_1 && !GLEW_VERSION_3_2 && GLEW_ARB_compatibility) { - strcat(defines, "#extension GL_ARB_compatibility: enable\n"); - } - - if (!GLEW_VERSION_3_1) { - if (GLEW_ARB_draw_instanced) { - strcat(defines, "#extension GL_ARB_draw_instanced: enable\n"); - } - - if (!GLEW_VERSION_3_0 && GLEW_EXT_gpu_shader4) { - strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n"); - /* TODO: maybe require this? shaders become so much nicer */ - } - } } static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH], @@ -207,10 +230,6 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH], if (GPU_bicubic_bump_support()) strcat(defines, "#define BUMP_BICUBIC\n"); - if (GLEW_VERSION_3_0) { - strcat(defines, "#define BIT_OPERATIONS\n"); - } - #ifdef WITH_OPENSUBDIV /* TODO(sergey): Check whether we actually compiling shader for * the OpenSubdiv mesh. @@ -243,37 +262,71 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, - const char *defines, - int input, - int output, - int number) + const char *defines) { return GPU_shader_create_ex(vertexcode, fragcode, geocode, libcode, defines, - input, - output, - number, GPU_SHADER_FLAGS_NONE); } +#define DEBUG_SHADER_NONE "" +#define DEBUG_SHADER_VERTEX "vert" +#define DEBUG_SHADER_FRAGMENT "frag" +#define DEBUG_SHADER_GEOMETRY "geom" + +/** + * Dump GLSL shaders to disk + * + * This is used for profiling shader performance externally and debug if shader code is correct. + * If called with no code, it simply bumps the shader index, so different shaders for the same + * program share the same index. + */ +static void gpu_dump_shaders(const char **code, const int num_shaders, const char *extension) +{ + if ((G.debug & G_DEBUG_GPU_SHADERS) == 0) { + return; + } + + /* We use the same shader index for shaders in the same program. + * So we call this function once before calling for the invidual shaders. */ + static int shader_index = 0; + if (code == NULL) { + shader_index++; + BLI_assert(STREQ(DEBUG_SHADER_NONE, extension)); + return; + } + + /* Determine the full path of the new shader. */ + char shader_path[FILE_MAX]; + + char file_name[512] = {'\0'}; + sprintf(file_name, "%04d.%s", shader_index, extension); + + BLI_join_dirfile(shader_path, sizeof(shader_path), BKE_tempdir_session(), file_name); + + /* Write shader to disk. */ + FILE *f = fopen(shader_path, "w"); + if (f == NULL) { + printf("Error writing to file: %s\n", shader_path); + } + for (int j = 0; j < num_shaders; j++) { + fprintf(f, "%s", code[j]); + } + fclose(f); + printf("Shader file written to disk: %s\n", shader_path); +} + GPUShader *GPU_shader_create_ex(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, - int input, - int output, - int number, const int flags) { #ifdef WITH_OPENSUBDIV - /* TODO(sergey): used to add #version 150 to the geometry shader. - * Could safely be renamed to "use_geometry_code" since it's very - * likely any of geometry code will want to use GLSL 1.5. - */ bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0; #else UNUSED_VARS(flags); @@ -286,10 +339,8 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, char standard_defines[MAX_DEFINE_LENGTH] = ""; char standard_extensions[MAX_EXT_DEFINE_LENGTH] = ""; - if (geocode && !GPU_geometry_shader_support()) - return NULL; - shader = MEM_callocN(sizeof(GPUShader), "GPUShader"); + gpu_dump_shaders(NULL, 0, DEBUG_SHADER_NONE); if (vertexcode) shader->vertex = glCreateShader(GL_VERTEX_SHADER); @@ -313,7 +364,7 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, gpu_shader_standard_defines(standard_defines, use_opensubdiv, (flags & GPU_SHADER_FLAGS_NEW_SHADING) != 0); - gpu_shader_standard_extensions(standard_extensions, geocode != NULL); + gpu_shader_standard_extensions(standard_extensions); if (vertexcode) { const char *source[5]; @@ -327,6 +378,8 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, if (defines) source[num_source++] = defines; source[num_source++] = vertexcode; + gpu_dump_shaders(source, num_source, DEBUG_SHADER_VERTEX); + glAttachShader(shader->program, shader->vertex); glShaderSource(shader->vertex, num_source, source, NULL); @@ -366,6 +419,8 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, if (libcode) source[num_source++] = libcode; source[num_source++] = fragcode; + gpu_dump_shaders(source, num_source, DEBUG_SHADER_FRAGMENT); + glAttachShader(shader->program, shader->fragment); glShaderSource(shader->fragment, num_source, source, NULL); @@ -392,6 +447,8 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, if (defines) source[num_source++] = defines; source[num_source++] = geocode; + gpu_dump_shaders(source, num_source, DEBUG_SHADER_GEOMETRY); + glAttachShader(shader->program, shader->geometry); glShaderSource(shader->geometry, num_source, source, NULL); @@ -405,20 +462,12 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, GPU_shader_free(shader); return NULL; } - - if (!use_opensubdiv) { - GPU_shader_geometry_stage_primitive_io(shader, input, output, number); - } } #ifdef WITH_OPENSUBDIV if (use_opensubdiv) { glBindAttribLocation(shader->program, 0, "position"); glBindAttribLocation(shader->program, 1, "normal"); - GPU_shader_geometry_stage_primitive_io(shader, - GL_LINES_ADJACENCY_EXT, - GL_TRIANGLE_STRIP, - 4); } #endif @@ -436,38 +485,54 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, return NULL; } + shader->interface = GWN_shaderinterface_create(shader->program); + #ifdef WITH_OPENSUBDIV /* TODO(sergey): Find a better place for this. */ - if (use_opensubdiv && GLEW_VERSION_4_1) { - glProgramUniform1i(shader->program, - glGetUniformLocation(shader->program, "FVarDataOffsetBuffer"), - 30); /* GL_TEXTURE30 */ - - glProgramUniform1i(shader->program, - glGetUniformLocation(shader->program, "FVarDataBuffer"), - 31); /* GL_TEXTURE31 */ + if (use_opensubdiv) { + if (GLEW_VERSION_4_1) { + glProgramUniform1i(shader->program, + GWN_shaderinterface_uniform(shader->interface, "FVarDataOffsetBuffer")->location, + 30); /* GL_TEXTURE30 */ + + glProgramUniform1i(shader->program, + GWN_shaderinterface_uniform(shader->interface, "FVarDataBuffer")->location, + 31); /* GL_TEXTURE31 */ + } + else { + glUseProgram(shader->program); + glUniform1i(GWN_shaderinterface_uniform(shader->interface, "FVarDataOffsetBuffer")->location, 30); + glUniform1i(GWN_shaderinterface_uniform(shader->interface, "FVarDataBuffer")->location, 31); + glUseProgram(0); + } } #endif return shader; } +#undef DEBUG_SHADER_GEOMETRY +#undef DEBUG_SHADER_FRAGMENT +#undef DEBUG_SHADER_VERTEX +#undef DEBUG_SHADER_NONE + void GPU_shader_bind(GPUShader *shader) { - GPU_ASSERT_NO_GL_ERRORS("Pre Shader Bind"); + BLI_assert(shader && shader->program); + glUseProgram(shader->program); - GPU_ASSERT_NO_GL_ERRORS("Post Shader Bind"); + gpuBindMatrices(shader->interface); } void GPU_shader_unbind(void) { - GPU_ASSERT_NO_GL_ERRORS("Pre Shader Unbind"); glUseProgram(0); - GPU_ASSERT_NO_GL_ERRORS("Post Shader Unbind"); } void GPU_shader_free(GPUShader *shader) { + BLI_assert(shader); + if (shader->vertex) glDeleteShader(shader->vertex); if (shader->geometry) @@ -480,20 +545,51 @@ void GPU_shader_free(GPUShader *shader) if (shader->uniform_interface) MEM_freeN(shader->uniform_interface); + if (shader->interface) + GWN_shaderinterface_discard(shader->interface); + MEM_freeN(shader); } int GPU_shader_get_uniform(GPUShader *shader, const char *name) { - return glGetUniformLocation(shader->program, name); + BLI_assert(shader && shader->program); + const Gwn_ShaderInput *uniform = GWN_shaderinterface_uniform(shader->interface, name); + return uniform ? uniform->location : -1; } -void *GPU_shader_get_interface(GPUShader *shader) +int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin) +{ + BLI_assert(shader && shader->program); + const Gwn_ShaderInput *uniform = GWN_shaderinterface_uniform_builtin(shader->interface, builtin); + return uniform ? uniform->location : -1; +} + +int GPU_shader_get_uniform_block(GPUShader *shader, const char *name) +{ + BLI_assert(shader && shader->program); + + const Gwn_ShaderInput *ubo = GWN_shaderinterface_ubo(shader->interface, name); + return ubo ? ubo->location : -1; +} + +void *GPU_fx_shader_get_interface(GPUShader *shader) { return shader->uniform_interface; } -void GPU_shader_set_interface(GPUShader *shader, void *interface) +void *GPU_shader_get_interface(GPUShader *shader) +{ + return shader->interface; +} + +/* Clement : Temp */ +int GPU_shader_get_program(GPUShader *shader) +{ + return (int)shader->program; +} + +void GPU_fx_shader_set_interface(GPUShader *shader, void *interface) { shader->uniform_interface = interface; } @@ -503,16 +599,12 @@ void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int leng if (location == -1 || value == NULL) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); - if (length == 1) glUniform1fv(location, arraysize, value); else if (length == 2) glUniform2fv(location, arraysize, value); else if (length == 3) glUniform3fv(location, arraysize, value); else if (length == 4) glUniform4fv(location, arraysize, value); else if (length == 9) glUniformMatrix3fv(location, arraysize, 0, value); else if (length == 16) glUniformMatrix4fv(location, arraysize, 0, value); - - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); } void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value) @@ -520,14 +612,10 @@ void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int if (location == -1) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); - if (length == 1) glUniform1iv(location, arraysize, value); else if (length == 2) glUniform2iv(location, arraysize, value); else if (length == 3) glUniform3iv(location, arraysize, value); else if (length == 4) glUniform4iv(location, arraysize, value); - - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); } void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) @@ -535,22 +623,22 @@ void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) if (location == -1) return; - GPU_CHECK_ERRORS_AROUND(glUniform1i(location, value)); + glUniform1i(location, value); } -void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number) +void GPU_shader_uniform_buffer(GPUShader *shader, int location, GPUUniformBuffer *ubo) { - if (GPU_geometry_shader_support_via_extension()) { - /* geometry shaders must provide this info themselves for #version 150 and up */ - glProgramParameteriEXT(shader->program, GL_GEOMETRY_INPUT_TYPE_EXT, input); - glProgramParameteriEXT(shader->program, GL_GEOMETRY_OUTPUT_TYPE_EXT, output); - glProgramParameteriEXT(shader->program, GL_GEOMETRY_VERTICES_OUT_EXT, number); + int bindpoint = GPU_uniformbuffer_bindpoint(ubo); + + if (location == -1) { + return; } + + glUniformBlockBinding(shader->program, location, bindpoint); } void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex) { - GLenum arbnumber; int number = GPU_texture_bound_number(tex); int bindcode = GPU_texture_opengl_bindcode(tex); int target = GPU_texture_target(tex); @@ -566,78 +654,228 @@ void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUText if (location == -1) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture"); - - arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); + if (number != 0) + glActiveTexture(GL_TEXTURE0 + number); - if (number != 0) glActiveTexture(arbnumber); if (bindcode != 0) glBindTexture(target, bindcode); else GPU_invalid_tex_bind(target); + glUniform1i(location, number); - glEnable(target); - if (number != 0) glActiveTexture(GL_TEXTURE0); - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Texture"); + if (number != 0) + glActiveTexture(GL_TEXTURE0); } int GPU_shader_get_attribute(GPUShader *shader, const char *name) { - int index; - - GPU_CHECK_ERRORS_AROUND(index = glGetAttribLocation(shader->program, name)); - - return index; + BLI_assert(shader && shader->program); + const Gwn_ShaderInput *attrib = GWN_shaderinterface_attr(shader->interface, name); + return attrib ? attrib->location : -1; } GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) { - GPUShader *retval = NULL; - - switch (shader) { - case GPU_SHADER_VSM_STORE: - if (!GG.shaders.vsm_store) - GG.shaders.vsm_store = GPU_shader_create( - datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.vsm_store; - break; - case GPU_SHADER_SEP_GAUSSIAN_BLUR: - if (!GG.shaders.sep_gaussian_blur) - GG.shaders.sep_gaussian_blur = GPU_shader_create( - datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, - datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.sep_gaussian_blur; - break; - case GPU_SHADER_SMOKE: - if (!GG.shaders.smoke) - GG.shaders.smoke = GPU_shader_create( - datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.smoke; - break; - case GPU_SHADER_SMOKE_FIRE: - if (!GG.shaders.smoke_fire) - GG.shaders.smoke_fire = GPU_shader_create( - datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_fire_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.smoke_fire; - break; - case GPU_SHADER_SMOKE_COBA: - if (!GG.shaders.smoke_coba) - GG.shaders.smoke_coba = GPU_shader_create( - datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl, - NULL, NULL, "#define USE_COBA;\n", 0, 0, 0); - retval = GG.shaders.smoke_coba; - break; - } + BLI_assert(shader != GPU_NUM_BUILTIN_SHADERS); /* don't be a troll */ + + static const GPUShaderStages builtin_shader_stages[GPU_NUM_BUILTIN_SHADERS] = { + [GPU_SHADER_VSM_STORE] = { datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl }, + [GPU_SHADER_SEP_GAUSSIAN_BLUR] = { datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, + datatoc_gpu_shader_sep_gaussian_blur_frag_glsl }, + [GPU_SHADER_SMOKE] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl }, + [GPU_SHADER_SMOKE_FIRE] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl }, + [GPU_SHADER_SMOKE_COBA] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl }, + + [GPU_SHADER_TEXT] = { datatoc_gpu_shader_text_vert_glsl, datatoc_gpu_shader_text_frag_glsl }, + [GPU_SHADER_KEYFRAME_DIAMOND] = { datatoc_gpu_shader_keyframe_diamond_vert_glsl, + datatoc_gpu_shader_keyframe_diamond_frag_glsl }, + [GPU_SHADER_EDGES_FRONT_BACK_PERSP] = { datatoc_gpu_shader_edges_front_back_persp_vert_glsl, + /* this version is */ datatoc_gpu_shader_flat_color_frag_glsl, + /* magical but slooow */ datatoc_gpu_shader_edges_front_back_persp_geom_glsl }, + [GPU_SHADER_EDGES_FRONT_BACK_ORTHO] = { datatoc_gpu_shader_edges_front_back_ortho_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_EDGES_OVERLAY_SIMPLE] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_edges_overlay_frag_glsl, + datatoc_gpu_shader_edges_overlay_simple_geom_glsl }, + [GPU_SHADER_EDGES_OVERLAY] = { datatoc_gpu_shader_edges_overlay_vert_glsl, + datatoc_gpu_shader_edges_overlay_frag_glsl, + datatoc_gpu_shader_edges_overlay_geom_glsl }, + [GPU_SHADER_SIMPLE_LIGHTING] = { datatoc_gpu_shader_3D_normal_vert_glsl, datatoc_gpu_shader_simple_lighting_frag_glsl }, + /* Use 'USE_FLAT_NORMAL' to make flat shader from smooth */ + [GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR] = { datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl, datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl }, + [GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR] = { datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl, datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl }, + [GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA] = { datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl, datatoc_gpu_shader_simple_lighting_smooth_color_alpha_frag_glsl }, + + [GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_image_vert_glsl, + datatoc_gpu_shader_image_mask_uniform_color_frag_glsl }, + [GPU_SHADER_3D_IMAGE_MODULATE_ALPHA] = { datatoc_gpu_shader_3D_image_vert_glsl, + datatoc_gpu_shader_image_modulate_alpha_frag_glsl }, + [GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA] = { datatoc_gpu_shader_3D_image_vert_glsl, + datatoc_gpu_shader_image_rect_modulate_alpha_frag_glsl }, + [GPU_SHADER_3D_IMAGE_DEPTH] = { datatoc_gpu_shader_3D_image_vert_glsl, + datatoc_gpu_shader_image_depth_linear_frag_glsl }, + + [GPU_SHADER_2D_IMAGE_INTERLACE] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_interlace_frag_glsl }, + [GPU_SHADER_2D_CHECKER] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_checker_frag_glsl }, + + [GPU_SHADER_2D_DIAG_STRIPES] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_diag_stripes_frag_glsl }, + + [GPU_SHADER_2D_UNIFORM_COLOR] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, + [GPU_SHADER_2D_FLAT_COLOR] = { datatoc_gpu_shader_2D_flat_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_2D_SMOOTH_COLOR] = { datatoc_gpu_shader_2D_smooth_color_vert_glsl, + datatoc_gpu_shader_2D_smooth_color_frag_glsl }, + [GPU_SHADER_2D_IMAGE_LINEAR_TO_SRGB] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_linear_frag_glsl }, + [GPU_SHADER_2D_IMAGE_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_color_frag_glsl }, + [GPU_SHADER_2D_IMAGE_ALPHA_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_alpha_color_frag_glsl }, + [GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_shuffle_color_frag_glsl }, + [GPU_SHADER_3D_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, + [GPU_SHADER_3D_UNIFORM_COLOR_U32] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, + [GPU_SHADER_3D_FLAT_COLOR] = { datatoc_gpu_shader_3D_flat_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_3D_FLAT_COLOR_U32] = { datatoc_gpu_shader_3D_flat_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_3D_SMOOTH_COLOR] = { datatoc_gpu_shader_3D_smooth_color_vert_glsl, + datatoc_gpu_shader_3D_smooth_color_frag_glsl }, + [GPU_SHADER_3D_DEPTH_ONLY] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_depth_only_frag_glsl }, + [GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_clipped_uniform_color_vert_glsl, + datatoc_gpu_shader_uniform_color_frag_glsl }, + + [GPU_SHADER_3D_GROUNDPOINT] = { datatoc_gpu_shader_3D_groundpoint_vert_glsl, datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_3D_GROUNDLINE] = { datatoc_gpu_shader_3D_passthrough_vert_glsl, + datatoc_gpu_shader_uniform_color_frag_glsl, + datatoc_gpu_shader_3D_groundline_geom_glsl }, + + [GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR] = { datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl, + datatoc_gpu_shader_2D_line_dashed_frag_glsl, + datatoc_gpu_shader_2D_line_dashed_geom_glsl }, + [GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_line_dashed_uniform_color_vert_glsl, + datatoc_gpu_shader_2D_line_dashed_frag_glsl, + datatoc_gpu_shader_2D_line_dashed_geom_glsl }, + + [GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR] = + { datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl, + datatoc_gpu_shader_simple_lighting_frag_glsl}, + [GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR] = { datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + [GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR] = { datatoc_gpu_shader_instance_screenspace_variying_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + [GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS] = { datatoc_gpu_shader_instance_screen_aligned_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + [GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED] = { datatoc_gpu_shader_instance_screen_aligned_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + + [GPU_SHADER_CAMERA] = { datatoc_gpu_shader_instance_camera_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + [GPU_SHADER_DISTANCE_LINES] = { datatoc_gpu_shader_instance_distance_line_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + + [GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR] = + { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR] = + { datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl }, + [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] = + { datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl, + datatoc_gpu_shader_point_uniform_color_aa_frag_glsl }, + [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA] = + { datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl, + datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl }, + [GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA] = + { datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert_glsl, + datatoc_gpu_shader_point_varying_color_outline_aa_frag_glsl }, + [GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_vert_glsl, + datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR] = { datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl }, + [GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_point_varying_size_vert_glsl, + datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR] = + { datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl }, + [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] = + { datatoc_gpu_shader_3D_point_uniform_size_aa_vert_glsl, + datatoc_gpu_shader_point_uniform_color_aa_frag_glsl }, + [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA] = + { datatoc_gpu_shader_3D_point_uniform_size_outline_aa_vert_glsl, + datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl }, + + [GPU_SHADER_INSTANCE_UNIFORM_COLOR] = { datatoc_gpu_shader_instance_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, + [GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE] = + { datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE] = + { datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR] = { datatoc_gpu_shader_instance_edges_variying_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl, + datatoc_gpu_shader_instance_edges_variying_color_geom_glsl}, + + [GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID] = { datatoc_gpu_shader_instance_bone_envelope_solid_vert_glsl, + datatoc_gpu_shader_simple_lighting_frag_glsl }, + [GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_WIRE] = { datatoc_gpu_shader_instance_bone_envelope_wire_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + + [GPU_SHADER_3D_INSTANCE_MBALL_HELPERS] = { datatoc_gpu_shader_instance_mball_helpers_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + }; + + if (builtin_shaders[shader] == NULL) { + /* just a few special cases */ + const char *defines = NULL; + switch (shader) { + case GPU_SHADER_SMOKE_COBA: + defines = "#define USE_COBA;\n"; + break; + case GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE: + defines = "#define UNIFORM_SCALE;\n"; + break; + case GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS: + defines = "#define AXIS_NAME;\n"; + break; + case GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR: + case GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID: + defines = "#define USE_INSTANCE_COLOR;\n"; + break; + case GPU_SHADER_3D_FLAT_COLOR_U32: + case GPU_SHADER_3D_UNIFORM_COLOR_U32: + defines = "#define USE_COLOR_U32;\n"; + break; + case GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR: + defines = "#define USE_FLAT_NORMAL;\n"; + break; + default: + break; + } + + const GPUShaderStages *stages = builtin_shader_stages + shader; - if (retval == NULL) - printf("Unable to create a GPUShader for builtin shader: %u\n", shader); + if (shader == GPU_SHADER_EDGES_FRONT_BACK_PERSP && !GLEW_VERSION_3_2) { + /* TODO: remove after switch to core profile (maybe) */ + static const GPUShaderStages legacy_fancy_edges = + { datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl, + datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl }; + stages = &legacy_fancy_edges; + } + + if (shader == GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR && !GLEW_VERSION_3_2) { + /* Dashed need geometry shader, which are not supported by legacy OpenGL, fallback to solid lines. */ + /* TODO: remove after switch to core profile (maybe) */ + static const GPUShaderStages legacy_dashed_lines = { datatoc_gpu_shader_3D_line_dashed_uniform_color_legacy_vert_glsl, + datatoc_gpu_shader_2D_line_dashed_frag_glsl }; + stages = &legacy_dashed_lines; + } - return retval; + /* common case */ + builtin_shaders[shader] = GPU_shader_create(stages->vert, stages->frag, stages->geom, NULL, defines); + } + + return builtin_shaders[shader]; } #define MAX_DEFINES 100 @@ -657,103 +895,80 @@ GPUShader *GPU_shader_get_builtin_fx_shader(int effect, bool persp) strcat(defines, "#define PERSP_MATRIX\n"); } - if (!GG.shaders.fx_shaders[offset]) { + if (!fx_shaders[offset]) { GPUShader *shader = NULL; switch (effect) { case GPU_SHADER_FX_SSAO: - shader = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fullscreen_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE: strcat(defines, "#define FIRST_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO: strcat(defines, "#define SECOND_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE: strcat(defines, "#define THIRD_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR: strcat(defines, "#define FOURTH_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE: strcat(defines, "#define FIFTH_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE: strcat(defines, "#define FIRST_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO: strcat(defines, "#define SECOND_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl, - defines, GL_POINTS, GL_TRIANGLE_STRIP, 4); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE: strcat(defines, "#define THIRD_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_RESOLVE: - shader = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fullscreen_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines); break; } - GG.shaders.fx_shaders[offset] = shader; + fx_shaders[offset] = shader; GPU_fx_shader_init_interface(shader, effect); } - return GG.shaders.fx_shaders[offset]; + return fx_shaders[offset]; } void GPU_shader_free_builtin_shaders(void) { - int i; - - if (GG.shaders.vsm_store) { - GPU_shader_free(GG.shaders.vsm_store); - GG.shaders.vsm_store = NULL; - } - - if (GG.shaders.sep_gaussian_blur) { - GPU_shader_free(GG.shaders.sep_gaussian_blur); - GG.shaders.sep_gaussian_blur = NULL; - } - - if (GG.shaders.smoke) { - GPU_shader_free(GG.shaders.smoke); - GG.shaders.smoke = NULL; - } - - if (GG.shaders.smoke_fire) { - GPU_shader_free(GG.shaders.smoke_fire); - GG.shaders.smoke_fire = NULL; - } - - if (GG.shaders.smoke_coba) { - GPU_shader_free(GG.shaders.smoke_coba); - GG.shaders.smoke_coba = NULL; + for (int i = 0; i < GPU_NUM_BUILTIN_SHADERS; ++i) { + if (builtin_shaders[i]) { + GPU_shader_free(builtin_shaders[i]); + builtin_shaders[i] = NULL; + } } - for (i = 0; i < 2 * MAX_FX_SHADERS; ++i) { - if (GG.shaders.fx_shaders[i]) { - GPU_shader_free(GG.shaders.fx_shaders[i]); - GG.shaders.fx_shaders[i] = NULL; + for (int i = 0; i < 2 * MAX_FX_SHADERS; ++i) { + if (fx_shaders[i]) { + GPU_shader_free(fx_shaders[i]); + fx_shaders[i] = NULL; } } } - - diff --git a/source/blender/gpu/intern/gpu_shader_private.h b/source/blender/gpu/intern/gpu_shader_private.h new file mode 100644 index 00000000000..f883773df17 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_private.h @@ -0,0 +1,45 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpu_shader_private.h + * \ingroup gpu + */ + +#ifndef __GPU_SHADER_PRIVATE_H__ +#define __GPU_SHADER_PRIVATE_H__ + +#include "GPU_glew.h" +#include "gawain/gwn_shader_interface.h" + +struct GPUShader { + GLuint program; /* handle for full program (links shader stages below) */ + + GLuint vertex; /* handle for vertex shader */ + GLuint geometry; /* handle for geometry shader */ + GLuint fragment; /* handle for fragment shader */ + + void *uniform_interface; /* cached uniform interface for shader. Data depends on shader */ + /* NOTE: ^-- only FX compositing shaders use this */ + + Gwn_ShaderInterface *interface; /* cached uniform & attrib interface for shader */ +}; + +#endif /* __GPU_SHADER_PRIVATE_H__ */ + diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 1c97c2ce811..d6b641af225 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -49,9 +49,8 @@ static struct GPUTextureGlobal { } GG = {NULL, NULL, NULL}; /* GPUTexture */ - struct GPUTexture { - int w, h; /* width/height */ + int w, h, d; /* width/height/depth */ int number; /* number for multitexture binding */ int refcount; /* reference count */ GLenum target; /* GL_TEXTURE_* */ @@ -62,43 +61,277 @@ struct GPUTexture { GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */ int fb_attachment; /* slot the texture is attached to */ - int depth; /* is a depth texture? if 3D how deep? */ + bool depth; /* is a depth texture? */ + bool stencil; /* is a stencil texture? */ + + unsigned int bytesize; /* number of byte for one pixel */ + int format; /* GPUTextureFormat */ + int components; /* number of color/alpha channels */ }; -static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels) +/* ------ Memory Management ------- */ +/* Records every texture allocation / free + * to estimate the Texture Pool Memory consumption */ +static unsigned int memory_usage; + +static unsigned int gpu_texture_memory_footprint_compute(GPUTexture *tex) { - unsigned char *pixels, *p; - const float *fp = fpixels; - const int len = 4 * length; + switch (tex->target) { + case GL_TEXTURE_1D: + return tex->bytesize * tex->w; + case GL_TEXTURE_1D_ARRAY: + case GL_TEXTURE_2D: + return tex->bytesize * tex->w * tex->h; + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_3D: + return tex->bytesize * tex->w * tex->h * tex->d; + case GL_TEXTURE_CUBE_MAP: + return tex->bytesize * 6 * tex->w * tex->h; + case GL_TEXTURE_CUBE_MAP_ARRAY: + return tex->bytesize * 6 * tex->w * tex->h * tex->d; + default: + return 0; + } +} - p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels"); +static void gpu_texture_memory_footprint_add(GPUTexture *tex) +{ + memory_usage += gpu_texture_memory_footprint_compute(tex); +} - for (int a = 0; a < len; a++, p++, fp++) - *p = FTOCHAR((*fp)); +static void gpu_texture_memory_footprint_remove(GPUTexture *tex) +{ + memory_usage -= gpu_texture_memory_footprint_compute(tex); +} - return pixels; +unsigned int GPU_texture_memory_usage_get(void) +{ + return memory_usage; } -static void gpu_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h) +/* -------------------------------- */ + +static GLenum gpu_texture_get_format( + int components, GPUTextureFormat data_type, + GLenum *format, GLenum *data_format, bool *is_depth, bool *is_stencil, unsigned int *bytesize) { - void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels"); + if (ELEM(data_type, GPU_DEPTH_COMPONENT24, + GPU_DEPTH_COMPONENT16, + GPU_DEPTH_COMPONENT32F)) + { + *is_depth = true; + *is_stencil = false; + *data_format = GL_FLOAT; + *format = GL_DEPTH_COMPONENT; + } + else if (data_type == GPU_DEPTH24_STENCIL8) { + *is_depth = true; + *is_stencil = true; + *data_format = GL_UNSIGNED_INT_24_8; + *format = GL_DEPTH_STENCIL; + } + else { + *is_depth = false; + *is_stencil = false; + + /* Integer formats */ + if (ELEM(data_type, GPU_RG16I)) { + *data_format = GL_INT; + + switch (components) { + case 1: *format = GL_RED_INTEGER; break; + case 2: *format = GL_RG_INTEGER; break; + case 3: *format = GL_RGB_INTEGER; break; + case 4: *format = GL_RGBA_INTEGER; break; + default: break; + } + } + else { + *data_format = GL_FLOAT; + + switch (components) { + case 1: *format = GL_RED; break; + case 2: *format = GL_RG; break; + case 3: *format = GL_RGB; break; + case 4: *format = GL_RGBA; break; + default: break; + } + } + } - if (target == GL_TEXTURE_1D) - glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels); - else - glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels); - - MEM_freeN(pixels); + switch (data_type) { + case GPU_RGBA32F: + *bytesize = 32; + break; + case GPU_RG32F: + case GPU_RGBA16F: + *bytesize = 16; + break; + case GPU_RGB16F: + *bytesize = 12; + break; + case GPU_RG16F: + case GPU_RG16I: + case GPU_DEPTH24_STENCIL8: + case GPU_DEPTH_COMPONENT32F: + case GPU_RGBA8: + case GPU_R11F_G11F_B10F: + case GPU_R32F: + *bytesize = 4; + break; + case GPU_DEPTH_COMPONENT24: + *bytesize = 3; + break; + case GPU_DEPTH_COMPONENT16: + case GPU_R16F: + case GPU_RG8: + *bytesize = 2; + break; + case GPU_R8: + *bytesize = 1; + break; + default: + *bytesize = 0; + break; + } + + /* You can add any of the available type to this list + * For available types see GPU_texture.h */ + switch (data_type) { + /* Formats texture & renderbuffer */ + case GPU_RGBA32F: return GL_RGBA32F; + case GPU_RGBA16F: return GL_RGBA16F; + case GPU_RG32F: return GL_RG32F; + case GPU_RGB16F: return GL_RGB16F; + case GPU_RG16F: return GL_RG16F; + case GPU_RG16I: return GL_RG16I; + case GPU_RGBA8: return GL_RGBA8; + case GPU_R32F: return GL_R32F; + case GPU_R16F: return GL_R16F; + case GPU_RG8: return GL_RG8; + case GPU_R8: return GL_R8; + /* Special formats texture & renderbuffer */ + case GPU_R11F_G11F_B10F: return GL_R11F_G11F_B10F; + case GPU_DEPTH24_STENCIL8: return GL_DEPTH24_STENCIL8; + /* Texture only format */ + /* ** Add Format here **/ + /* Special formats texture only */ + /* ** Add Format here **/ + /* Depth Formats */ + case GPU_DEPTH_COMPONENT32F: return GL_DEPTH_COMPONENT32F; + case GPU_DEPTH_COMPONENT24: return GL_DEPTH_COMPONENT24; + case GPU_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT16; + default: + fprintf(stderr, "Texture format incorrect or unsupported\n"); + return 0; + } } -static GPUTexture *GPU_texture_create_nD( - int w, int h, int n, const float *fpixels, int depth, - GPUHDRType hdr_type, int components, int samples, - char err_out[256]) +static float *GPU_texture_3D_rescale(GPUTexture *tex, int w, int h, int d, int channels, const float *fpixels) { - GLenum type, format, internalformat; - void *pixels = NULL; + const unsigned int xf = w / tex->w, yf = h / tex->h, zf = d / tex->d; + float *nfpixels = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->d, "GPUTexture Rescaled 3Dtex"); + + if (nfpixels) { + GPU_print_error_debug("You need to scale a 3D texture, feel the pain!"); + + for (unsigned k = 0; k < tex->d; k++) { + for (unsigned j = 0; j < tex->h; j++) { + for (unsigned i = 0; i < tex->w; i++) { + /* obviously doing nearest filtering here, + * it's going to be slow in any case, let's not make it worse */ + float xb = i * xf; + float yb = j * yf; + float zb = k * zf; + unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j; + unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb); + + if (channels == 4) { + nfpixels[offset * 4] = fpixels[offset_orig * 4]; + nfpixels[offset * 4 + 1] = fpixels[offset_orig * 4 + 1]; + nfpixels[offset * 4 + 2] = fpixels[offset_orig * 4 + 2]; + nfpixels[offset * 4 + 3] = fpixels[offset_orig * 4 + 3]; + } + else + nfpixels[offset] = fpixels[offset_orig]; + } + } + } + } + + return nfpixels; +} + +/* This tries to allocate video memory for a given texture + * If alloc fails, lower the resolution until it fits. */ +static bool gpu_texture_try_alloc( + GPUTexture *tex, GLenum proxy, GLenum internalformat, GLenum format, GLenum data_format, + int channels, bool try_rescale, const float *fpixels, float **rescaled_fpixels) +{ + int r_width; + + switch (proxy) { + case GL_PROXY_TEXTURE_1D: + glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, data_format, NULL); + break; + case GL_PROXY_TEXTURE_1D_ARRAY: + case GL_PROXY_TEXTURE_2D: + glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, data_format, NULL); + break; + case GL_PROXY_TEXTURE_2D_ARRAY: + case GL_PROXY_TEXTURE_3D: + glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, NULL); + break; + } + + glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &r_width); + + if (r_width == 0 && try_rescale) { + const int w = tex->w, h = tex->h, d = tex->d; + + /* Find largest texture possible */ + while (r_width == 0) { + tex->w /= 2; + tex->h /= 2; + tex->d /= 2; + + /* really unlikely to happen but keep this just in case */ + if (tex->w == 0) break; + if (tex->h == 0 && proxy != GL_PROXY_TEXTURE_1D) break; + if (tex->d == 0 && proxy == GL_PROXY_TEXTURE_3D) break; + + if (proxy == GL_PROXY_TEXTURE_1D) + glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, data_format, NULL); + else if (proxy == GL_PROXY_TEXTURE_2D) + glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, data_format, NULL); + else if (proxy == GL_PROXY_TEXTURE_3D) + glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, NULL); + + glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); + } + + /* Rescale */ + if (r_width > 0) { + switch (proxy) { + case GL_PROXY_TEXTURE_1D: + case GL_PROXY_TEXTURE_2D: + /* Do nothing for now */ + return false; + case GL_PROXY_TEXTURE_3D: + *rescaled_fpixels = GPU_texture_3D_rescale(tex, w, h, d, channels, fpixels); + return (bool)*rescaled_fpixels; + } + } + } + return (r_width > 0); +} + +static GPUTexture *GPU_texture_create_nD( + int w, int h, int d, int n, const float *fpixels, + GPUTextureFormat data_type, int components, int samples, + const bool can_rescale, char err_out[256]) +{ if (samples) { CLAMP_MAX(samples, GPU_max_color_texture_samples()); } @@ -106,264 +339,206 @@ static GPUTexture *GPU_texture_create_nD( GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->w = w; tex->h = h; + tex->d = d; tex->number = -1; tex->refcount = 1; - tex->target = (n == 1) ? GL_TEXTURE_1D : (samples ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D); - tex->target_base = (n == 1) ? GL_TEXTURE_1D : GL_TEXTURE_2D; - tex->depth = depth; tex->fb_attachment = -1; + tex->format = data_type; + tex->components = components; + + if (n == 2) { + if (d == 0) + tex->target_base = tex->target = GL_TEXTURE_2D; + else + tex->target_base = tex->target = GL_TEXTURE_2D_ARRAY; + } + else if (n == 1) { + if (h == 0) + tex->target_base = tex->target = GL_TEXTURE_1D; + else + tex->target_base = tex->target = GL_TEXTURE_1D_ARRAY; + } + else if (n == 3) { + tex->target_base = tex->target = GL_TEXTURE_3D; + } + else { + /* should never happen */ + MEM_freeN(tex); + return NULL; + } + + if (samples && n == 2 && d == 0) + tex->target = GL_TEXTURE_2D_MULTISAMPLE; + GLenum format, internalformat, data_format; + internalformat = gpu_texture_get_format(components, data_type, &format, &data_format, &tex->depth, &tex->stencil, &tex->bytesize); + + gpu_texture_memory_footprint_add(tex); + + /* Generate Texture object */ glGenTextures(1, &tex->bindcode); if (!tex->bindcode) { - if (err_out) { - BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d", - (int)glGetError()); - } - else { - fprintf(stderr, "GPUTexture: texture create failed: %d\n", - (int)glGetError()); - } + if (err_out) + BLI_snprintf(err_out, 256, "GPUTexture: texture create failed"); + else + fprintf(stderr, "GPUTexture: texture create failed"); GPU_texture_free(tex); return NULL; } - if (!GPU_full_non_power_of_two_support()) { - tex->w = power_of_2_max_i(tex->w); - tex->h = power_of_2_max_i(tex->h); - } - tex->number = 0; glBindTexture(tex->target, tex->bindcode); - if (depth) { - type = GL_UNSIGNED_BYTE; - format = GL_DEPTH_COMPONENT; - internalformat = GL_DEPTH_COMPONENT; - } - else { - type = GL_FLOAT; - - if (components == 4) { - format = GL_RGBA; - switch (hdr_type) { - case GPU_HDR_NONE: - internalformat = GL_RGBA8; - break; - /* the following formats rely on ARB_texture_float or OpenGL 3.0 */ - case GPU_HDR_HALF_FLOAT: - internalformat = GL_RGBA16F_ARB; - break; - case GPU_HDR_FULL_FLOAT: - internalformat = GL_RGBA32F_ARB; - break; - default: - break; - } - } - else if (components == 2) { - /* these formats rely on ARB_texture_rg or OpenGL 3.0 */ - format = GL_RG; - switch (hdr_type) { - case GPU_HDR_NONE: - internalformat = GL_RG8; - break; - case GPU_HDR_HALF_FLOAT: - internalformat = GL_RG16F; - break; - case GPU_HDR_FULL_FLOAT: - internalformat = GL_RG32F; - break; - default: - break; - } - } + /* Check if texture fit in VRAM */ + GLenum proxy = GL_PROXY_TEXTURE_2D; - if (fpixels && hdr_type == GPU_HDR_NONE) { - type = GL_UNSIGNED_BYTE; - pixels = GPU_texture_convert_pixels(w * h, fpixels); - } + if (n == 2) { + if (d > 0) + proxy = GL_PROXY_TEXTURE_2D_ARRAY; + } + else if (n == 1) { + if (h == 0) + proxy = GL_PROXY_TEXTURE_1D; + else + proxy = GL_PROXY_TEXTURE_1D_ARRAY; + } + else if (n == 3) { + proxy = GL_PROXY_TEXTURE_3D; } - if (tex->target == GL_TEXTURE_1D) { - glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL); + float *rescaled_fpixels = NULL; + bool valid = gpu_texture_try_alloc(tex, proxy, internalformat, format, data_format, components, can_rescale, + fpixels, &rescaled_fpixels); + if (!valid) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUTexture: texture alloc failed"); + else + fprintf(stderr, "GPUTexture: texture alloc failed. Not enough Video Memory."); + GPU_texture_free(tex); + return NULL; + } - if (fpixels) { - glTexSubImage1D(tex->target, 0, 0, w, format, type, - pixels ? pixels : fpixels); + /* Upload Texture */ + const float *pix = (rescaled_fpixels) ? rescaled_fpixels : fpixels; - if (tex->w > w) { - gpu_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1); - } - } - } - else { + if (tex->target == GL_TEXTURE_2D || + tex->target == GL_TEXTURE_2D_MULTISAMPLE || + tex->target == GL_TEXTURE_1D_ARRAY) + { if (samples) { glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true); + if (pix) + glTexSubImage2D(tex->target, 0, 0, 0, tex->w, tex->h, format, data_format, pix); } else { - glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, - format, type, NULL); - } - - if (fpixels) { - glTexSubImage2D(tex->target, 0, 0, 0, w, h, - format, type, pixels ? pixels : fpixels); - - if (tex->w > w) { - gpu_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h); - } - if (tex->h > h) { - gpu_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h); - } + glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, format, data_format, pix); } } + else if (tex->target == GL_TEXTURE_1D) { + glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, data_format, pix); + } + else { + glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, pix); + } - if (pixels) - MEM_freeN(pixels); + if (rescaled_fpixels) + MEM_freeN(rescaled_fpixels); - if (depth) { + /* Texture Parameters */ + if (tex->depth) { glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE); glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); } else { glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } - if (tex->target_base != GL_TEXTURE_1D) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + if (n > 1) { glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - else - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + if (n > 2) { + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + } + + GPU_texture_unbind(tex); return tex; } - -GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels) +static GPUTexture *GPU_texture_cube_create( + int w, int d, + const float *fpixels_px, const float *fpixels_py, const float *fpixels_pz, + const float *fpixels_nx, const float *fpixels_ny, const float *fpixels_nz, + GPUTextureFormat data_type, int components, + char err_out[256]) { - GLenum type, format, internalformat; - void *pixels = NULL; + GLenum format, internalformat, data_format; GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->w = w; - tex->h = h; - tex->depth = depth; + tex->h = w; + tex->d = d; tex->number = -1; tex->refcount = 1; - tex->target = GL_TEXTURE_3D; - tex->target_base = GL_TEXTURE_3D; - - glGenTextures(1, &tex->bindcode); - - if (!tex->bindcode) { - fprintf(stderr, "GPUTexture: texture create failed: %d\n", - (int)glGetError()); - GPU_texture_free(tex); - return NULL; - } - - tex->number = 0; - glBindTexture(tex->target, tex->bindcode); - - GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture"); + tex->fb_attachment = -1; + tex->format = data_type; + tex->components = components; - type = GL_FLOAT; - if (channels == 4) { - format = GL_RGBA; - internalformat = GL_RGBA8; + if (d == 0) { + tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP; } else { - format = GL_RED; - internalformat = GL_INTENSITY8; + BLI_assert(false && "Cubemap array Not implemented yet"); + // tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY; } - /* 3D textures are quite heavy, test if it's possible to create them first */ - glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); + internalformat = gpu_texture_get_format(components, data_type, &format, &data_format, &tex->depth, &tex->stencil, &tex->bytesize); - bool rescale = false; - int r_width; + gpu_texture_memory_footprint_add(tex); - glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); + /* Generate Texture object */ + glGenTextures(1, &tex->bindcode); - while (r_width == 0) { - rescale = true; - tex->w /= 2; - tex->h /= 2; - tex->depth /= 2; - glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); - glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); + if (!tex->bindcode) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUTexture: texture create failed"); + else + fprintf(stderr, "GPUTexture: texture create failed"); + GPU_texture_free(tex); + return NULL; } - /* really unlikely to happen but keep this just in case */ - tex->w = max_ii(tex->w, 1); - tex->h = max_ii(tex->h, 1); - tex->depth = max_ii(tex->depth, 1); - -#if 0 - if (fpixels) - pixels = GPU_texture_convert_pixels(w*h*depth, fpixels); -#endif - - GPU_ASSERT_NO_GL_ERRORS("3D glTexImage3D"); - - /* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it - * for gooseberry */ - if (rescale && fpixels) { - /* FIXME: should these be floating point? */ - const unsigned int xf = w / tex->w, yf = h / tex->h, zf = depth / tex->depth; - float *tex3d = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->depth, "tex3d"); - - GPU_print_error_debug("You need to scale a 3D texture, feel the pain!"); - - for (unsigned k = 0; k < tex->depth; k++) { - for (unsigned j = 0; j < tex->h; j++) { - for (unsigned i = 0; i < tex->w; i++) { - /* obviously doing nearest filtering here, - * it's going to be slow in any case, let's not make it worse */ - float xb = i * xf; - float yb = j * yf; - float zb = k * zf; - unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j; - unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb); - - if (channels == 4) { - tex3d[offset * 4] = fpixels[offset_orig * 4]; - tex3d[offset * 4 + 1] = fpixels[offset_orig * 4 + 1]; - tex3d[offset * 4 + 2] = fpixels[offset_orig * 4 + 2]; - tex3d[offset * 4 + 3] = fpixels[offset_orig * 4 + 3]; - } - else - tex3d[offset] = fpixels[offset_orig]; - } - } - } + tex->number = 0; + glBindTexture(tex->target, tex->bindcode); - glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d); + /* Upload Texture */ + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_px); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_py); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_pz); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_nx); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_ny); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_nz); - MEM_freeN(tex3d); + /* Texture Parameters */ + if (tex->depth) { + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); } else { - if (fpixels) { - glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels); - GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D"); - } + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } - - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - if (pixels) - MEM_freeN(pixels); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); GPU_texture_unbind(tex); @@ -380,6 +555,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget /* see GPUInput::textarget: it can take two values - GL_TEXTURE_2D and GL_TEXTURE_CUBE_MAP * these values are correct for glDisable, so textarget can be safely used in * GPU_texture_bind/GPU_texture_unbind through tex->target_base */ + /* (is any of this obsolete now that we don't glEnable/Disable textures?) */ if (textarget == GL_TEXTURE_2D) gputt = TEXTARGET_TEXTURE_2D; else @@ -398,14 +574,16 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget tex->target = textarget; tex->target_base = textarget; tex->fromblender = 1; + tex->format = -1; + tex->components = -1; ima->gputexture[gputt] = tex; if (!glIsTexture(tex->bindcode)) { - GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); + GPU_print_error_debug("Blender Texture Not Loaded"); } else { - GLint w, h, border; + GLint w, h; GLenum gettarget; @@ -417,10 +595,8 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget glBindTexture(textarget, tex->bindcode); glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_WIDTH, &w); glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_HEIGHT, &h); - glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_BORDER, &border); - - tex->w = w - border; - tex->h = h - border; + tex->w = w; + tex->h = h; } glBindTexture(textarget, 0); @@ -452,11 +628,13 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) tex->refcount = 1; tex->target = GL_TEXTURE_2D; tex->target_base = GL_TEXTURE_2D; + tex->format = -1; + tex->components = -1; prv->gputexture[0] = tex; if (!glIsTexture(tex->bindcode)) { - GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); + GPU_print_error_debug("Blender Texture Not Loaded"); } else { GLint w, h; @@ -475,114 +653,129 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) } -GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256]) +GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, 0, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; + return GPU_texture_create_nD(w, 0, 0, 1, pixels, GPU_RGBA8, 4, 0, false, err_out); } -GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256]) +GPUTexture *GPU_texture_create_1D_custom( + int w, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, 0, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; + return GPU_texture_create_nD(w, 0, 0, 1, pixels, data_type, channels, 0, false, err_out); } -GPUTexture *GPU_texture_create_2D_multisample( - int w, int h, const float *fpixels, GPUHDRType hdr, int samples, char err_out[256]) -{ - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out); - - if (tex) - GPU_texture_unbind(tex); - return tex; +GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, 0, false, err_out); } -GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]) +GPUTexture *GPU_texture_create_2D_custom( + int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, 0, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; + return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, channels, 0, false, err_out); } -GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]) -{ - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, samples, err_out); - if (tex) - GPU_texture_unbind(tex); +GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, int samples, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, samples, false, err_out); +} - return tex; +GPUTexture *GPU_texture_create_2D_custom_multisample( + int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, int samples, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, channels, samples, false, err_out); } -/** - * A shadow map for VSM needs two components (depth and depth^2) - */ -GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]) +GPUTexture *GPU_texture_create_2D_array_custom(int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out); + return GPU_texture_create_nD(w, h, d, 2, pixels, data_type, channels, 0, false, err_out); +} - if (tex) { - /* Now we tweak some of the settings */ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +GPUTexture *GPU_texture_create_3D(int w, int h, int d, const float *pixels, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, d, 3, pixels, GPU_RGBA8, 4, 0, true, err_out); +} - GPU_texture_unbind(tex); +GPUTexture *GPU_texture_create_3D_custom(int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, d, 3, pixels, data_type, channels, 0, true, err_out); +} +GPUTexture *GPU_texture_create_cube_custom(int w, int channels, GPUTextureFormat data_type, const float *fpixels, char err_out[256]) +{ + const float *fpixels_px, *fpixels_py, *fpixels_pz, *fpixels_nx, *fpixels_ny, *fpixels_nz; + + if (fpixels) { + fpixels_px = fpixels + 0 * w * w * channels; + fpixels_nx = fpixels + 1 * w * w * channels; + fpixels_py = fpixels + 2 * w * w * channels; + fpixels_ny = fpixels + 3 * w * w * channels; + fpixels_pz = fpixels + 4 * w * w * channels; + fpixels_nz = fpixels + 5 * w * w * channels; + } + else { + fpixels_px = fpixels_py = fpixels_pz = fpixels_nx = fpixels_ny = fpixels_nz = NULL; } - return tex; + return GPU_texture_cube_create(w, 0, fpixels_px, fpixels_py, fpixels_pz, fpixels_nx, fpixels_ny, fpixels_nz, data_type, channels, err_out); } -GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]) +GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); + return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH_COMPONENT24, 1, 0, false, err_out); +} - if (tex) { - /* Now we tweak some of the settings */ - if (repeat) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +GPUTexture *GPU_texture_create_depth_with_stencil(int w, int h, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH24_STENCIL8, 1, 0, false, err_out); +} - GPU_texture_unbind(tex); - } +GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH_COMPONENT24, 1, samples, false, err_out); +} - return tex; +GPUTexture *GPU_texture_create_depth_with_stencil_multisample(int w, int h, int samples, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH24_STENCIL8, 1, samples, false, err_out); } -GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]) +void GPU_texture_update(GPUTexture *tex, const float *pixels) { - GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); + BLI_assert(tex->format > -1); + BLI_assert(tex->components > -1); - if (tex) { - /* Now we tweak some of the settings */ - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + GLenum format, data_format; + gpu_texture_get_format(tex->components, tex->format, &format, &data_format, &tex->depth, &tex->stencil, &tex->bytesize); + + glBindTexture(tex->target, tex->bindcode); - GPU_texture_unbind(tex); + switch (tex->target) { + case GL_TEXTURE_2D: + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_1D_ARRAY: + glTexSubImage2D(tex->target, 0, 0, 0, tex->w, tex->h, format, data_format, pixels); + break; + case GL_TEXTURE_1D: + glTexSubImage1D(tex->target, 0, 0, tex->w, format, data_format, pixels); + break; + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->d, format, data_format, pixels); + break; + default: + BLI_assert(!"tex->target mode not supported"); } - return tex; + glBindTexture(tex->target, 0); } void GPU_invalid_tex_init(void) { + memory_usage = 0; const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f}; GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL); - GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL); - GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color); + GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, NULL); + GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, color, NULL); } void GPU_invalid_tex_bind(int mode) @@ -627,21 +820,18 @@ void GPU_texture_bind(GPUTexture *tex, int number) if (number < 0) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind"); + if (number != 0) + glActiveTexture(GL_TEXTURE0 + number); - GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); - if (number != 0) glActiveTexture(arbnumber); - if (tex->bindcode != 0) { - glBindTexture(tex->target_base, tex->bindcode); - } + if (tex->bindcode != 0) + glBindTexture(tex->target, tex->bindcode); else GPU_invalid_tex_bind(tex->target_base); - glEnable(tex->target_base); - if (number != 0) glActiveTexture(GL_TEXTURE0); - tex->number = number; + if (number != 0) + glActiveTexture(GL_TEXTURE0); - GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind"); + tex->number = number; } void GPU_texture_unbind(GPUTexture *tex) @@ -653,18 +843,16 @@ void GPU_texture_unbind(GPUTexture *tex) if (tex->number == -1) return; - - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); - GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); - if (tex->number != 0) glActiveTexture(arbnumber); - glBindTexture(tex->target_base, 0); - glDisable(tex->target_base); - if (tex->number != 0) glActiveTexture(GL_TEXTURE0); + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); - tex->number = -1; + glBindTexture(tex->target, 0); - GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); + + tex->number = -1; } int GPU_texture_bound_number(GPUTexture *tex) @@ -672,7 +860,7 @@ int GPU_texture_bound_number(GPUTexture *tex) return tex->number; } -void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) +void GPU_texture_generate_mipmap(GPUTexture *tex) { if (tex->number >= GPU_max_textures()) { fprintf(stderr, "Not enough texture slots.\n"); @@ -682,29 +870,104 @@ void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) if (tex->number == -1) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); - GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); - if (tex->number != 0) glActiveTexture(arbnumber); + glGenerateMipmap(tex->target_base); - if (tex->depth) { - if (compare) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); +} + +void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare) +{ + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; + } + + if (tex->number == -1) + return; + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); + + /* TODO viewport: use GL_COMPARE_REF_TO_TEXTURE after we switch to core profile */ + if (tex->depth) + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, use_compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE); + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); +} + +void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter) +{ + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; } - if (use_filter) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (tex->number == -1) + return; + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); + + GLenum filter = use_filter ? GL_LINEAR : GL_NEAREST; + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, filter); + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); +} + +void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter) +{ + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; } - else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + if (tex->number == -1) + return; + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); + + GLenum mipmap = (use_filter) + ? use_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR + : use_mipmap ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST; + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, mipmap); + + GLenum filter = use_filter ? GL_LINEAR : GL_NEAREST; + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); +} + +void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat) +{ + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; } - if (tex->number != 0) glActiveTexture(GL_TEXTURE0); - GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); + if (tex->number == -1) + return; + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); + + GLenum repeat = use_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE; + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, repeat); + if (tex->target_base != GL_TEXTURE_1D) + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, repeat); + if (tex->target_base == GL_TEXTURE_3D) + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, repeat); + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); } void GPU_texture_free(GPUTexture *tex) @@ -720,6 +983,8 @@ void GPU_texture_free(GPUTexture *tex) if (tex->bindcode && !tex->fromblender) glDeleteTextures(1, &tex->bindcode); + gpu_texture_memory_footprint_remove(tex); + MEM_freeN(tex); } } @@ -744,11 +1009,21 @@ int GPU_texture_height(const GPUTexture *tex) return tex->h; } -int GPU_texture_depth(const GPUTexture *tex) +int GPU_texture_format(const GPUTexture *tex) +{ + return tex->format; +} + +bool GPU_texture_depth(const GPUTexture *tex) { return tex->depth; } +bool GPU_texture_stencil(const GPUTexture *tex) +{ + return tex->stencil; +} + int GPU_texture_opengl_bindcode(const GPUTexture *tex) { return tex->bindcode; diff --git a/source/blender/gpu/intern/gpu_uniformbuffer.c b/source/blender/gpu/intern/gpu_uniformbuffer.c new file mode 100644 index 00000000000..6d52dab5a1f --- /dev/null +++ b/source/blender/gpu/intern/gpu_uniformbuffer.c @@ -0,0 +1,378 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Clement Foucault. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpu_uniformbuffer.c + * \ingroup gpu + */ + +#include <string.h> +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" + +#include "gpu_codegen.h" + +#include "GPU_extensions.h" +#include "GPU_glew.h" +#include "GPU_material.h" +#include "GPU_uniformbuffer.h" + +typedef enum GPUUniformBufferFlag { + GPU_UBO_FLAG_INITIALIZED = (1 << 0), + GPU_UBO_FLAG_DIRTY = (1 << 1), +} GPUUniformBufferFlag; + +typedef enum GPUUniformBufferType { + GPU_UBO_STATIC = 0, + GPU_UBO_DYNAMIC = 1, +} GPUUniformBufferType; + +struct GPUUniformBuffer { + int size; /* in bytes */ + GLuint bindcode; /* opengl identifier for UBO */ + int bindpoint; /* current binding point */ + GPUUniformBufferType type; +}; + +#define GPUUniformBufferStatic GPUUniformBuffer + +typedef struct GPUUniformBufferDynamic { + GPUUniformBuffer buffer; + ListBase items; /* GPUUniformBufferDynamicItem */ + void *data; + char flag; +} GPUUniformBufferDynamic; + +struct GPUUniformBufferDynamicItem { + struct GPUUniformBufferDynamicItem *next, *prev; + GPUType gputype; + float *data; + int size; +}; + + +/* Prototypes */ +static GPUType get_padded_gpu_type(struct LinkData *link); +static void gpu_uniformbuffer_inputs_sort(struct ListBase *inputs); + +static GPUUniformBufferDynamicItem *gpu_uniformbuffer_populate( + GPUUniformBufferDynamic *ubo, const GPUType gputype, float *num); + +/* Only support up to this type, if you want to extend it, make sure the + * padding logic is correct for the new types. */ +#define MAX_UBO_GPU_TYPE GPU_VEC4 + +static void gpu_uniformbuffer_initialize(GPUUniformBuffer *ubo, const void *data) +{ + glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode); + glBufferData(GL_UNIFORM_BUFFER, ubo->size, data, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); +} + +GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256]) +{ + GPUUniformBuffer *ubo = MEM_callocN(sizeof(GPUUniformBufferStatic), "GPUUniformBufferStatic"); + ubo->size = size; + ubo->bindpoint = -1; + + /* Generate Buffer object */ + glGenBuffers(1, &ubo->bindcode); + + if (!ubo->bindcode) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO create failed"); + GPU_uniformbuffer_free(ubo); + return NULL; + } + + if (ubo->size > GPU_max_ubo_size()) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO too big"); + GPU_uniformbuffer_free(ubo); + return NULL; + } + + gpu_uniformbuffer_initialize(ubo, data); + return ubo; +} + +/** + * 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]) +{ + /* There is no point on creating an UBO if there is no arguments. */ + if (BLI_listbase_is_empty(inputs)) { + return NULL; + } + + GPUUniformBufferDynamic *ubo = MEM_callocN(sizeof(GPUUniformBufferDynamic), "GPUUniformBufferDynamic"); + ubo->buffer.type = GPU_UBO_DYNAMIC; + ubo->buffer.bindpoint = -1; + ubo->flag = GPU_UBO_FLAG_DIRTY; + + /* Generate Buffer object. */ + glGenBuffers(1, &ubo->buffer.bindcode); + + if (!ubo->buffer.bindcode) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO create failed"); + GPU_uniformbuffer_free(&ubo->buffer); + return NULL; + } + + if (ubo->buffer.size > GPU_max_ubo_size()) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO too big"); + GPU_uniformbuffer_free(&ubo->buffer); + return NULL; + } + + /* Make sure we comply to the ubo alignment requirements. */ + gpu_uniformbuffer_inputs_sort(inputs); + + for (LinkData *link = inputs->first; link; link = link->next) { + GPUInput *input = link->data; + GPUType gputype = get_padded_gpu_type(link); + gpu_uniformbuffer_populate(ubo, gputype, input->dynamicvec); + } + + ubo->data = MEM_mallocN(ubo->buffer.size, __func__); + + /* Initialize buffer data. */ + GPU_uniformbuffer_dynamic_update(&ubo->buffer); + return &ubo->buffer; +} + +/** + * Free the data, and clean the items list. + */ +static void gpu_uniformbuffer_dynamic_reset(GPUUniformBufferDynamic *ubo) +{ + ubo->buffer.size = 0; + if (ubo->data) { + MEM_freeN(ubo->data); + } + BLI_freelistN(&ubo->items); +} + +void GPU_uniformbuffer_free(GPUUniformBuffer *ubo) +{ + if (ubo->type == GPU_UBO_DYNAMIC) { + gpu_uniformbuffer_dynamic_reset((GPUUniformBufferDynamic *)ubo); + } + + glDeleteBuffers(1, &ubo->bindcode); + MEM_freeN(ubo); +} + +static void gpu_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data) +{ + glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode); + glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo->size, data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); +} + +void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data) +{ + BLI_assert(ubo->type == GPU_UBO_STATIC); + gpu_uniformbuffer_update(ubo, data); +} + +/** + * We need to recalculate the internal data, and re-generate it + * from its populated items. + */ +void GPU_uniformbuffer_dynamic_update(GPUUniformBuffer *ubo_) +{ + BLI_assert(ubo_->type == GPU_UBO_DYNAMIC); + GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_; + + float *offset = ubo->data; + for (GPUUniformBufferDynamicItem *item = ubo->items.first; item; item = item->next) { + memcpy(offset, item->data, item->size); + offset += item->gputype; + } + + if (ubo->flag & GPU_UBO_FLAG_INITIALIZED) { + gpu_uniformbuffer_update(ubo_, ubo->data); + } + else { + ubo->flag |= GPU_UBO_FLAG_INITIALIZED; + gpu_uniformbuffer_initialize(ubo_, ubo->data); + } + + ubo->flag &= ~GPU_UBO_FLAG_DIRTY; +} + +/** + * We need to pad some data types (vec3) on the C side + * To match the GPU expected memory block alignment. + */ +static GPUType get_padded_gpu_type(LinkData *link) +{ + GPUInput *input = link->data; + GPUType gputype = input->type; + + /* Unless the vec3 is followed by a float we need to treat it as a vec4. */ + if (gputype == GPU_VEC3 && + (link->next != NULL) && + (((GPUInput *)link->next->data)->type != GPU_FLOAT)) + { + gputype = GPU_VEC4; + } + + return gputype; +} + +/** + * Returns 1 if the first item shold be after second item. + * We make sure the vec4 uniforms come first. + */ +static int inputs_cmp(const void *a, const void *b) +{ + const LinkData *link_a = a, *link_b = b; + const GPUInput *input_a = link_a->data, *input_b = link_b->data; + return input_a->type < input_b->type ? 1 : 0; +} + +/** + * Make sure we respect the expected alignment of UBOs. + * vec4, pad vec3 as vec4, then vec2, then floats. + */ +static void gpu_uniformbuffer_inputs_sort(ListBase *inputs) +{ + /* Order them as vec4, vec3, vec2, float. */ + BLI_listbase_sort(inputs, inputs_cmp); + + /* Creates a lookup table for the different types; */ + LinkData *inputs_lookup[MAX_UBO_GPU_TYPE + 1] = {NULL}; + GPUType cur_type = MAX_UBO_GPU_TYPE + 1; + + for (LinkData *link = inputs->first; link; link = link->next) { + GPUInput *input = link->data; + if (input->type == cur_type) { + continue; + } + else { + inputs_lookup[input->type] = link; + cur_type = input->type; + } + } + + /* If there is no GPU_VEC3 there is no need for alignment. */ + if (inputs_lookup[GPU_VEC3] == NULL) { + return; + } + + LinkData *link = inputs_lookup[GPU_VEC3]; + while (link != NULL && ((GPUInput *)link->data)->type == GPU_VEC3) { + LinkData *link_next = link->next; + + /* If GPU_VEC3 is followed by nothing or a GPU_FLOAT, no need for aligment. */ + if ((link_next == NULL) || + ((GPUInput *)link_next->data)->type == GPU_FLOAT) + { + break; + } + + /* If there is a float, move it next to current vec3. */ + if (inputs_lookup[GPU_FLOAT] != NULL) { + LinkData *float_input = inputs_lookup[GPU_FLOAT]; + inputs_lookup[GPU_FLOAT] = float_input->next; + + BLI_remlink(inputs, float_input); + BLI_insertlinkafter(inputs, link, float_input); + } + + link = link_next; + } +} + +/** + * This may now happen from the main thread, so we can't update the UBO + * We simply flag it as dirty + */ +static GPUUniformBufferDynamicItem *gpu_uniformbuffer_populate( + GPUUniformBufferDynamic *ubo, const GPUType gputype, float *num) +{ + BLI_assert(gputype <= MAX_UBO_GPU_TYPE); + GPUUniformBufferDynamicItem *item = MEM_callocN(sizeof(GPUUniformBufferDynamicItem), __func__); + + item->gputype = gputype; + item->data = num; + item->size = gputype * sizeof(float); + ubo->buffer.size += item->size; + + ubo->flag |= GPU_UBO_FLAG_DIRTY; + BLI_addtail(&ubo->items, item); + + return item; +} + +void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number) +{ + if (number >= GPU_max_ubo_binds()) { + fprintf(stderr, "Not enough UBO slots.\n"); + return; + } + + if (ubo->type == GPU_UBO_DYNAMIC) { + GPUUniformBufferDynamic *ubo_dynamic = (GPUUniformBufferDynamic *)ubo; + if (ubo_dynamic->flag & GPU_UBO_FLAG_DIRTY) { + GPU_uniformbuffer_dynamic_update(ubo); + } + } + + if (ubo->bindcode != 0) { + glBindBufferBase(GL_UNIFORM_BUFFER, number, ubo->bindcode); + } + + ubo->bindpoint = number; +} + +void GPU_uniformbuffer_unbind(GPUUniformBuffer *ubo) +{ + ubo->bindpoint = -1; +} + +int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo) +{ + return ubo->bindpoint; +} + +void GPU_uniformbuffer_tag_dirty(GPUUniformBuffer *ubo_) +{ + BLI_assert(ubo_->type == GPU_UBO_DYNAMIC); + GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_; + ubo->flag |= GPU_UBO_FLAG_DIRTY; +} + +#undef MAX_UBO_GPU_TYPE diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c new file mode 100644 index 00000000000..3ef53b3a6c3 --- /dev/null +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -0,0 +1,686 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_viewport.c + * \ingroup gpu + * + * System that manages viewport drawing. + */ + +#include <string.h> + +#include "BLI_listbase.h" +#include "BLI_rect.h" +#include "BLI_string.h" +#include "BLI_mempool.h" + +#include "DNA_vec_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_global.h" + +#include "GPU_framebuffer.h" +#include "GPU_glew.h" +#include "GPU_immediate.h" +#include "GPU_texture.h" +#include "GPU_viewport.h" + +#include "DRW_engine.h" + +#include "MEM_guardedalloc.h" + +static const int default_fbl_len = (sizeof(DefaultFramebufferList)) / sizeof(void *); +static const int default_txl_len = (sizeof(DefaultTextureList)) / sizeof(void *); + +/* Maximum number of simultaneous engine enabled at the same time. + * Setting it lower than the real number will do lead to + * higher VRAM usage due to sub-efficient buffer reuse. */ +#define MAX_ENGINE_BUFFER_SHARING 5 + +typedef struct ViewportTempTexture { + struct ViewportTempTexture *next, *prev; + void *user[MAX_ENGINE_BUFFER_SHARING]; + GPUTexture *texture; +} ViewportTempTexture; + +struct GPUViewport { + float pad[4]; + + /* debug */ + GPUTexture *debug_depth; + int size[2]; + + int samples; + int flag; + + ListBase data; /* ViewportEngineData wrapped in LinkData */ + unsigned int data_hash; /* If hash mismatch we free all ViewportEngineData in this viewport */ + + DefaultFramebufferList *fbl; + DefaultTextureList *txl; + + ViewportMemoryPool vmempool; /* Used for rendering data structure. */ + struct DRWInstanceDataList *idatalist; /* Used for rendering data structure. */ + + ListBase tex_pool; /* ViewportTempTexture list : Temporary textures shared across draw engines */ +}; + +enum { + DO_UPDATE = (1 << 0), +}; + +static void gpu_viewport_buffers_free(FramebufferList *fbl, int fbl_len, TextureList *txl, int txl_len); +static void gpu_viewport_storage_free(StorageList *stl, int stl_len); +static void gpu_viewport_passes_free(PassList *psl, int psl_len); +static void gpu_viewport_texture_pool_free(GPUViewport *viewport); + +void GPU_viewport_tag_update(GPUViewport *viewport) +{ + viewport->flag |= DO_UPDATE; +} + +bool GPU_viewport_do_update(GPUViewport *viewport) +{ + bool ret = (viewport->flag & DO_UPDATE); + viewport->flag &= ~DO_UPDATE; + return ret; +} + +GPUViewport *GPU_viewport_create(void) +{ + GPUViewport *viewport = MEM_callocN(sizeof(GPUViewport), "GPUViewport"); + viewport->fbl = MEM_callocN(sizeof(DefaultFramebufferList), "FramebufferList"); + viewport->txl = MEM_callocN(sizeof(DefaultTextureList), "TextureList"); + viewport->idatalist = DRW_instance_data_list_create(); + + viewport->size[0] = viewport->size[1] = -1; + + return viewport; +} + +GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs) +{ + GPUViewport *viewport = GPU_viewport_create(); + GPU_offscreen_viewport_data_get(ofs, &viewport->fbl->default_fb, &viewport->txl->color, &viewport->txl->depth); + viewport->size[0] = GPU_offscreen_width(ofs); + viewport->size[1] = GPU_offscreen_height(ofs); + return viewport; +} +/** + * Clear vars assigned from offscreen, so we don't free data owned by `GPUOffScreen`. + */ +void GPU_viewport_clear_from_offscreen(GPUViewport *viewport) +{ + viewport->fbl->default_fb = NULL; + viewport->txl->color = NULL; + viewport->txl->depth = NULL; +} + +void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type) +{ + LinkData *ld = MEM_callocN(sizeof(LinkData), "LinkData"); + ViewportEngineData *data = MEM_callocN(sizeof(ViewportEngineData), "ViewportEngineData"); + int fbl_len, txl_len, psl_len, stl_len; + + DRW_engine_viewport_data_size_get(engine_type, &fbl_len, &txl_len, &psl_len, &stl_len); + + data->engine_type = engine_type; + + data->fbl = MEM_callocN((sizeof(void *) * fbl_len) + sizeof(FramebufferList), "FramebufferList"); + data->txl = MEM_callocN((sizeof(void *) * txl_len) + sizeof(TextureList), "TextureList"); + data->psl = MEM_callocN((sizeof(void *) * psl_len) + sizeof(PassList), "PassList"); + data->stl = MEM_callocN((sizeof(void *) * stl_len) + sizeof(StorageList), "StorageList"); + + ld->data = data; + BLI_addtail(&viewport->data, ld); + + return data; +} + +static void gpu_viewport_engines_data_free(GPUViewport *viewport) +{ + int fbl_len, txl_len, psl_len, stl_len; + + LinkData *next; + for (LinkData *link = viewport->data.first; link; link = next) { + next = link->next; + ViewportEngineData *data = link->data; + DRW_engine_viewport_data_size_get(data->engine_type, &fbl_len, &txl_len, &psl_len, &stl_len); + + gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, txl_len); + gpu_viewport_passes_free(data->psl, psl_len); + gpu_viewport_storage_free(data->stl, stl_len); + + MEM_freeN(data->fbl); + MEM_freeN(data->txl); + MEM_freeN(data->psl); + MEM_freeN(data->stl); + + /* We could handle this in the DRW module */ + if (data->text_draw_cache) { + extern void DRW_text_cache_destroy(struct DRWTextStore *dt); + DRW_text_cache_destroy(data->text_draw_cache); + data->text_draw_cache = NULL; + } + + MEM_freeN(data); + + BLI_remlink(&viewport->data, link); + MEM_freeN(link); + } + + gpu_viewport_texture_pool_free(viewport); +} + +void *GPU_viewport_engine_data_get(GPUViewport *viewport, void *engine_type) +{ + for (LinkData *link = viewport->data.first; link; link = link->next) { + ViewportEngineData *vdata = link->data; + if (vdata->engine_type == engine_type) { + return vdata; + } + } + return NULL; +} + +ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport) +{ + return &viewport->vmempool; +} + +struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport) +{ + return viewport->idatalist; +} + +void *GPU_viewport_framebuffer_list_get(GPUViewport *viewport) +{ + return viewport->fbl; +} + +void *GPU_viewport_texture_list_get(GPUViewport *viewport) +{ + return viewport->txl; +} + +void GPU_viewport_size_get(const GPUViewport *viewport, int size[2]) +{ + size[0] = viewport->size[0]; + size[1] = viewport->size[1]; +} + +/** + * Special case, this is needed for when we have a viewport without a frame-buffer output + * (occlusion queries for eg) but still need to set the size since it may be used for other calculations. + */ +void GPU_viewport_size_set(GPUViewport *viewport, const int size[2]) +{ + viewport->size[0] = size[0]; + viewport->size[1] = size[1]; +} + +/** + * Try to find a texture coresponding to params into the texture pool. + * If no texture was found, create one and add it to the pool. + */ +GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, int width, int height, int channels, int format) +{ + GPUTexture *tex; + + for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) { + if ((GPU_texture_width(tmp_tex->texture) == width) && + (GPU_texture_height(tmp_tex->texture) == height) && + (GPU_texture_format(tmp_tex->texture) == format)) + { + /* Search if the engine is not already using this texture */ + for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) { + if (tmp_tex->user[i] == engine) { + break; + } + + if (tmp_tex->user[i] == NULL) { + tmp_tex->user[i] = engine; + return tmp_tex->texture; + } + } + } + } + + tex = GPU_texture_create_2D_custom(width, height, channels, format, NULL, NULL); + + ViewportTempTexture *tmp_tex = MEM_callocN(sizeof(ViewportTempTexture), "ViewportTempTexture"); + tmp_tex->texture = tex; + tmp_tex->user[0] = engine; + + BLI_addtail(&viewport->tex_pool, tmp_tex); + + return tex; +} + +static void gpu_viewport_texture_pool_clear_users(GPUViewport *viewport) +{ + ViewportTempTexture *tmp_tex_next; + + for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex_next) { + tmp_tex_next = tmp_tex->next; + bool no_user = true; + for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) { + if (tmp_tex->user[i] != NULL) { + tmp_tex->user[i] = NULL; + no_user = false; + } + } + + if (no_user) { + GPU_texture_free(tmp_tex->texture); + BLI_freelinkN(&viewport->tex_pool, tmp_tex); + } + } +} + +static void gpu_viewport_texture_pool_free(GPUViewport *viewport) +{ + for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) { + GPU_texture_free(tmp_tex->texture); + } + + BLI_freelistN(&viewport->tex_pool); +} + +bool GPU_viewport_engines_data_validate(GPUViewport *viewport, unsigned int hash) +{ + bool dirty = false; + + if (viewport->data_hash != hash) { + gpu_viewport_engines_data_free(viewport); + dirty = true; + } + + viewport->data_hash = hash; + + return dirty; +} + +void GPU_viewport_cache_release(GPUViewport *viewport) +{ + for (LinkData *link = viewport->data.first; link; link = link->next) { + ViewportEngineData *data = link->data; + int psl_len; + DRW_engine_viewport_data_size_get(data->engine_type, NULL, NULL, &psl_len, NULL); + gpu_viewport_passes_free(data->psl, psl_len); + } +} + +void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) +{ + DefaultFramebufferList *dfbl = viewport->fbl; + DefaultTextureList *dtxl = viewport->txl; + int fbl_len, txl_len; + + /* add one pixel because of scissor test */ + int rect_w = BLI_rcti_size_x(rect) + 1; + int rect_h = BLI_rcti_size_y(rect) + 1; + + if (dfbl->default_fb) { + if (rect_w != viewport->size[0] || rect_h != viewport->size[1] || U.ogl_multisamples != viewport->samples) { + gpu_viewport_buffers_free( + (FramebufferList *)viewport->fbl, default_fbl_len, + (TextureList *)viewport->txl, default_txl_len); + + for (LinkData *link = viewport->data.first; link; link = link->next) { + ViewportEngineData *data = link->data; + DRW_engine_viewport_data_size_get(data->engine_type, &fbl_len, &txl_len, NULL, NULL); + gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, txl_len); + } + + gpu_viewport_texture_pool_free(viewport); + } + } + + gpu_viewport_texture_pool_clear_users(viewport); + + /* Multisample Buffer */ + if (U.ogl_multisamples > 0) { + if (!dfbl->default_fb) { + bool ok = true; + viewport->samples = U.ogl_multisamples; + + dfbl->multisample_fb = GPU_framebuffer_create(); + if (!dfbl->multisample_fb) { + ok = false; + goto cleanup_multisample; + } + + /* Color */ + dtxl->multisample_color = GPU_texture_create_2D_multisample(rect_w, rect_h, NULL, U.ogl_multisamples, NULL); + if (!dtxl->multisample_color) { + ok = false; + goto cleanup_multisample; + } + + if (!GPU_framebuffer_texture_attach(dfbl->multisample_fb, dtxl->multisample_color, 0, 0)) { + ok = false; + goto cleanup_multisample; + } + + /* Depth */ + dtxl->multisample_depth = GPU_texture_create_depth_with_stencil_multisample(rect_w, rect_h, + U.ogl_multisamples, NULL); + + if (!dtxl->multisample_depth) { + ok = false; + goto cleanup_multisample; + } + + if (!GPU_framebuffer_texture_attach(dfbl->multisample_fb, dtxl->multisample_depth, 0, 0)) { + ok = false; + goto cleanup_multisample; + } + else if (!GPU_framebuffer_check_valid(dfbl->multisample_fb, NULL)) { + ok = false; + goto cleanup_multisample; + } + +cleanup_multisample: + if (!ok) { + GPU_viewport_free(viewport); + MEM_freeN(viewport); + return; + } + } + } + + if (!dfbl->default_fb) { + bool ok = true; + viewport->size[0] = rect_w; + viewport->size[1] = rect_h; + + dfbl->default_fb = GPU_framebuffer_create(); + if (!dfbl->default_fb) { + ok = false; + goto cleanup; + } + + /* Color */ + dtxl->color = GPU_texture_create_2D(rect_w, rect_h, NULL, NULL); + if (!dtxl->color) { + ok = false; + goto cleanup; + } + + if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->color, 0, 0)) { + ok = false; + goto cleanup; + } + + /* Depth */ + dtxl->depth = GPU_texture_create_depth_with_stencil(rect_w, rect_h, NULL); + + if (dtxl->depth) { + /* Define texture parameters */ + GPU_texture_bind(dtxl->depth, 0); + GPU_texture_compare_mode(dtxl->depth, false); + GPU_texture_filter_mode(dtxl->depth, true); + GPU_texture_unbind(dtxl->depth); + } + else { + ok = false; + goto cleanup; + } + + if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0)) { + ok = false; + goto cleanup; + } + else if (!GPU_framebuffer_check_valid(dfbl->default_fb, NULL)) { + ok = false; + goto cleanup; + } + +cleanup: + if (!ok) { + GPU_viewport_free(viewport); + MEM_freeN(viewport); + return; + } + + GPU_framebuffer_restore(); + } + + GPU_framebuffer_slots_bind(dfbl->default_fb, 0); +} + +static void draw_ofs_to_screen(GPUViewport *viewport) +{ + DefaultTextureList *dtxl = viewport->txl; + + GPUTexture *color = dtxl->color; + + const float w = (float)GPU_texture_width(color); + const float h = (float)GPU_texture_height(color); + + Gwn_VertFormat *format = immVertexFormat(); + unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA); + GPU_texture_bind(color, 0); + + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ + + immBegin(GWN_PRIM_TRI_STRIP, 4); + + immAttrib2f(texcoord, 0.0f, 0.0f); + immVertex2f(pos, 0.0f, 0.0f); + + immAttrib2f(texcoord, 1.0f, 0.0f); + immVertex2f(pos, w, 0.0f); + + immAttrib2f(texcoord, 0.0f, 1.0f); + immVertex2f(pos, 0.0f, h); + + immAttrib2f(texcoord, 1.0f, 1.0f); + immVertex2f(pos, w, h); + + immEnd(); + + GPU_texture_unbind(color); + + immUnbindProgram(); +} + +void GPU_viewport_unbind(GPUViewport *viewport) +{ + DefaultFramebufferList *dfbl = viewport->fbl; + + if (dfbl->default_fb) { + GPU_framebuffer_texture_unbind(NULL, NULL); + GPU_framebuffer_restore(); + + glEnable(GL_SCISSOR_TEST); + glDisable(GL_DEPTH_TEST); + + /* This might be bandwidth limiting */ + draw_ofs_to_screen(viewport); + } +} + +static void gpu_viewport_buffers_free( + FramebufferList *fbl, int fbl_len, + TextureList *txl, int txl_len) +{ + for (int i = 0; i < fbl_len; i++) { + GPUFrameBuffer *fb = fbl->framebuffers[i]; + if (fb) { + GPU_framebuffer_free(fb); + fbl->framebuffers[i] = NULL; + } + } + for (int i = 0; i < txl_len; i++) { + GPUTexture *tex = txl->textures[i]; + if (tex) { + GPU_texture_free(tex); + txl->textures[i] = NULL; + } + } +} + +static void gpu_viewport_storage_free(StorageList *stl, int stl_len) +{ + for (int i = 0; i < stl_len; i++) { + void *storage = stl->storage[i]; + if (storage) { + MEM_freeN(storage); + stl->storage[i] = NULL; + } + } +} + +static void gpu_viewport_passes_free(PassList *psl, int psl_len) +{ + for (int i = 0; i < psl_len; i++) { + struct DRWPass *pass = psl->passes[i]; + if (pass) { + DRW_pass_free(pass); + psl->passes[i] = NULL; + } + } +} + +void GPU_viewport_free(GPUViewport *viewport) +{ + gpu_viewport_engines_data_free(viewport); + + gpu_viewport_buffers_free( + (FramebufferList *)viewport->fbl, default_fbl_len, + (TextureList *)viewport->txl, default_txl_len); + + gpu_viewport_texture_pool_free(viewport); + + MEM_freeN(viewport->fbl); + MEM_freeN(viewport->txl); + + if (viewport->vmempool.calls != NULL) { + BLI_mempool_destroy(viewport->vmempool.calls); + } + if (viewport->vmempool.calls_generate != NULL) { + BLI_mempool_destroy(viewport->vmempool.calls_generate); + } + if (viewport->vmempool.shgroups != NULL) { + BLI_mempool_destroy(viewport->vmempool.shgroups); + } + if (viewport->vmempool.uniforms != NULL) { + BLI_mempool_destroy(viewport->vmempool.uniforms); + } + if (viewport->vmempool.passes != NULL) { + BLI_mempool_destroy(viewport->vmempool.passes); + } + + DRW_instance_data_list_free(viewport->idatalist); + MEM_freeN(viewport->idatalist); + + GPU_viewport_debug_depth_free(viewport); +} + +/****************** debug ********************/ + +bool GPU_viewport_debug_depth_create(GPUViewport *viewport, int width, int height, char err_out[256]) +{ + viewport->debug_depth = GPU_texture_create_2D_custom(width, height, 4, GPU_RGBA16F, NULL, err_out); + return (viewport->debug_depth != NULL); +} + +void GPU_viewport_debug_depth_free(GPUViewport *viewport) +{ + if (viewport->debug_depth != NULL) { + MEM_freeN(viewport->debug_depth); + viewport->debug_depth = NULL; + } +} + +void GPU_viewport_debug_depth_store(GPUViewport *viewport, const int x, const int y) +{ + const int w = GPU_texture_width(viewport->debug_depth); + const int h = GPU_texture_height(viewport->debug_depth); + + GPU_texture_bind(viewport->debug_depth, 0); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, x, y, w, h, 0); + GPU_texture_unbind(viewport->debug_depth); +} + +void GPU_viewport_debug_depth_draw(GPUViewport *viewport, const float znear, const float zfar) +{ + const float w = (float)GPU_texture_width(viewport->debug_depth); + const float h = (float)GPU_texture_height(viewport->debug_depth); + + Gwn_VertFormat *format = immVertexFormat(); + unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_DEPTH); + + GPU_texture_bind(viewport->debug_depth, 0); + + immUniform1f("znear", znear); + immUniform1f("zfar", zfar); + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ + + immBegin(GWN_PRIM_TRI_STRIP, 4); + + immAttrib2f(texcoord, 0.0f, 0.0f); + immVertex2f(pos, 0.0f, 0.0f); + + immAttrib2f(texcoord, 1.0f, 0.0f); + immVertex2f(pos, w, 0.0f); + + immAttrib2f(texcoord, 0.0f, 1.0f); + immVertex2f(pos, 0.0f, h); + + immAttrib2f(texcoord, 1.0f, 1.0f); + immVertex2f(pos, w, h); + + immEnd(); + + GPU_texture_unbind(viewport->debug_depth); + + immUnbindProgram(); +} + +int GPU_viewport_debug_depth_width(const GPUViewport *viewport) +{ + return GPU_texture_width(viewport->debug_depth); +} + +int GPU_viewport_debug_depth_height(const GPUViewport *viewport) +{ + return GPU_texture_height(viewport->debug_depth); +} + +bool GPU_viewport_debug_depth_is_valid(GPUViewport *viewport) +{ + return viewport->debug_depth != NULL; +} |