diff options
-rw-r--r-- | source/blender/blenkernel/intern/studiolight.c | 4 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_lightcache.c | 6 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_subsurface.c | 8 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_volumes.c | 4 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_effect_antialiasing.c | 5 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager_texture.c | 4 | ||||
-rw-r--r-- | source/blender/gpu/GPU_texture.h | 25 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_draw.c | 37 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_extensions.c | 2 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_texture.c | 265 |
10 files changed, 169 insertions, 191 deletions
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c index aef274f7d91..4892e8d6ede 100644 --- a/source/blender/blenkernel/intern/studiolight.c +++ b/source/blender/blenkernel/intern/studiolight.c @@ -503,10 +503,8 @@ static void studiolight_create_equirect_radiance_gputexture(StudioLight *sl) sl->equirect_radiance_gputexture = GPU_texture_create_2d( ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, NULL); GPUTexture *tex = sl->equirect_radiance_gputexture; - GPU_texture_bind(tex, 0); GPU_texture_filter_mode(tex, true); GPU_texture_wrap_mode(tex, true, true); - GPU_texture_unbind(tex); } sl->flag |= STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE; } @@ -567,10 +565,8 @@ static void studiolight_create_equirect_irradiance_gputexture(StudioLight *sl) sl->equirect_irradiance_gputexture = GPU_texture_create_2d( ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, NULL); GPUTexture *tex = sl->equirect_irradiance_gputexture; - GPU_texture_bind(tex, 0); GPU_texture_filter_mode(tex, true); GPU_texture_wrap_mode(tex, true, true); - GPU_texture_unbind(tex); } sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE; } diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 614c749b9aa..198d06d845c 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -379,9 +379,7 @@ static bool eevee_lightcache_static_load(LightCache *lcache) 0, false, NULL); - GPU_texture_bind(lcache->grid_tx.tex, 0); GPU_texture_filter_mode(lcache->grid_tx.tex, true); - GPU_texture_unbind(lcache->grid_tx.tex); } if (lcache->cube_tx.tex == NULL) { @@ -406,13 +404,11 @@ static bool eevee_lightcache_static_load(LightCache *lcache) NULL); } - GPU_texture_bind(lcache->cube_tx.tex, 0); - GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true); for (int mip = 0; mip < lcache->mips_len; mip++) { GPU_texture_add_mipmap( lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, mip + 1, lcache->cube_mips[mip].data); } - GPU_texture_unbind(lcache->cube_tx.tex); + GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true); } return true; } diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 4f334812a8e..0726f1822cc 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -350,23 +350,15 @@ void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) if (!DRW_pass_is_empty(psl->sss_translucency_ps)) { /* We sample the shadow-maps using normal sampler. We need to disable Comparison mode. * TODO(fclem) avoid this by using sampler objects.*/ - GPU_texture_bind(sldata->shadow_cube_pool, 0); GPU_texture_compare_mode(sldata->shadow_cube_pool, false); - GPU_texture_unbind(sldata->shadow_cube_pool); - GPU_texture_bind(sldata->shadow_cascade_pool, 0); GPU_texture_compare_mode(sldata->shadow_cascade_pool, false); - GPU_texture_unbind(sldata->shadow_cascade_pool); GPU_framebuffer_bind(fbl->sss_translucency_fb); DRW_draw_pass(psl->sss_translucency_ps); /* Reset original state. */ - GPU_texture_bind(sldata->shadow_cube_pool, 0); GPU_texture_compare_mode(sldata->shadow_cube_pool, true); - GPU_texture_unbind(sldata->shadow_cube_pool); - GPU_texture_bind(sldata->shadow_cascade_pool, 0); GPU_texture_compare_mode(sldata->shadow_cascade_pool, true); - GPU_texture_unbind(sldata->shadow_cascade_pool); } /* 1. horizontal pass */ diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 83bd4fcf8d2..55e7b0eb0e3 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -775,12 +775,8 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) /* We sample the shadow-maps using shadow sampler. We need to enable Comparison mode. * TODO(fclem) avoid this by using sampler objects.*/ - GPU_texture_bind(sldata->shadow_cube_pool, 0); GPU_texture_compare_mode(sldata->shadow_cube_pool, true); - GPU_texture_unbind(sldata->shadow_cube_pool); - GPU_texture_bind(sldata->shadow_cascade_pool, 0); GPU_texture_compare_mode(sldata->shadow_cascade_pool, true); - GPU_texture_unbind(sldata->shadow_cascade_pool); GPU_framebuffer_bind(fbl->volumetric_fb); DRW_draw_pass(psl->volumetric_world_ps); diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c index cb8eb7d1e92..0e896c4b7bb 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c +++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c @@ -266,13 +266,8 @@ void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata) false, NULL); - GPU_texture_bind(txl->smaa_search_tx, 0); GPU_texture_filter_mode(txl->smaa_search_tx, true); - GPU_texture_unbind(txl->smaa_search_tx); - - GPU_texture_bind(txl->smaa_area_tx, 0); GPU_texture_filter_mode(txl->smaa_area_tx, true); - GPU_texture_unbind(txl->smaa_area_tx); } } else { diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c index 810a2e9389b..77b0462303d 100644 --- a/source/blender/draw/intern/draw_manager_texture.c +++ b/source/blender/draw/intern/draw_manager_texture.c @@ -61,17 +61,17 @@ static bool drw_texture_format_supports_framebuffer(eGPUTextureFormat format) void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags) { - GPU_texture_bind(tex, 0); if (flags & DRW_TEX_MIPMAP) { GPU_texture_mipmap_mode(tex, true, flags & DRW_TEX_FILTER); + GPU_texture_bind(tex, 0); GPU_texture_generate_mipmap(tex); + GPU_texture_unbind(tex); } else { GPU_texture_filter_mode(tex, flags & DRW_TEX_FILTER); } GPU_texture_wrap_mode(tex, flags & DRW_TEX_WRAP, true); GPU_texture_compare_mode(tex, flags & DRW_TEX_COMPARE); - GPU_texture_unbind(tex); } GPUTexture *DRW_texture_create_1d(int w, diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 3d99a3c8a56..a1e00793857 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -41,6 +41,31 @@ struct PreviewImage; struct GPUFrameBuffer; typedef struct GPUTexture GPUTexture; +/* GPU Samplers state + * - Specify the sampler state to bind a texture with. + * - Internally used by textures. + * - All states are created at startup to avoid runtime costs. + */ + +typedef enum eGPUSamplerState { + GPU_SAMPLER_FILTER = (1 << 0), + GPU_SAMPLER_MIPMAP = (1 << 1), + GPU_SAMPLER_REPEAT_S = (1 << 2), + GPU_SAMPLER_REPEAT_T = (1 << 3), + GPU_SAMPLER_REPEAT_R = (1 << 4), + GPU_SAMPLER_CLAMP_BORDER = (1 << 5), /* Clamp to border color instead of border texel. */ + GPU_SAMPLER_COMPARE = (1 << 6), + GPU_SAMPLER_ANISO = (1 << 7), + /* Don't use that. */ + GPU_SAMPLER_MAX = (1 << 8), +} eGPUSamplerState; + +#define GPU_SAMPLER_DEFAULT GPU_SAMPLER_FILTER +#define GPU_SAMPLER_REPEAT (GPU_SAMPLER_REPEAT_S | GPU_SAMPLER_REPEAT_T | GPU_SAMPLER_REPEAT_R) + +void GPU_samplers_init(void); +void GPU_samplers_free(void); + /* GPU Texture * - always returns unsigned char RGBA textures * - if texture with non square dimensions is created, depending on the diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 7871907a7d4..7a9b4bafc74 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -161,7 +161,7 @@ static GLenum gpu_get_mipmap_filter(bool mag) void GPU_set_anisotropic(Main *bmain, float value) { if (GTS.anisotropic != value) { - GPU_free_images(bmain); + GPU_samplers_free(); /* Clamp value to the maximum value the graphics card supports */ const float max = GPU_max_texture_anisotropy(); @@ -170,6 +170,8 @@ void GPU_set_anisotropic(Main *bmain, float value) } GTS.anisotropic = value; + + GPU_samplers_init(); } } @@ -449,22 +451,12 @@ static uint gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) BKE_image_release_ibuf(ima, ibuf, NULL); } - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - if (GPU_get_mipmap()) { glGenerateMipmap(GL_TEXTURE_2D_ARRAY); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); if (ima) { ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE; } } - else { - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - - if (GLEW_EXT_texture_filter_anisotropic) { - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); - } glBindTexture(GL_TEXTURE_2D_ARRAY, 0); @@ -1098,18 +1090,12 @@ void GPU_create_gl_tex(uint *bind, GL_TEXTURE_2D, 0, internal_format, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect); } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - if (GPU_get_mipmap() && mipmap) { glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); if (ima) { ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE; } } - else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } } else if (textarget == GL_TEXTURE_CUBE_MAP) { int w = rectw / 3, h = recth / 2; @@ -1132,22 +1118,13 @@ void GPU_create_gl_tex(uint *bind, } } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - if (GPU_get_mipmap() && mipmap) { glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); if (ima) { ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE; } } - else { - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); gpu_del_cube_map(cube_map); } @@ -1156,10 +1133,6 @@ void GPU_create_gl_tex(uint *bind, } } - if (GLEW_EXT_texture_filter_anisotropic) { - glTexParameterf(textarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); - } - glBindTexture(textarget, 0); if (ibuf) { @@ -1211,10 +1184,6 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf, bool use_srgb) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - if (GLEW_EXT_texture_filter_anisotropic) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); - } - blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16; for (i = 0; i < ibuf->dds_data.nummipmaps && (width || height); i++) { if (width == 0) { diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index ff745787630..8f911f3c77d 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -355,11 +355,13 @@ void gpu_extensions_init(void) } GPU_invalid_tex_init(); + GPU_samplers_init(); } void gpu_extensions_exit(void) { GPU_invalid_tex_free(); + GPU_samplers_free(); } bool GPU_mem_stats_supported(void) diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 38ba8bc612f..6bc455033db 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -50,10 +50,14 @@ static struct GPUTextureGlobal { GPUTexture *invalid_tex_1D; GPUTexture *invalid_tex_2D; GPUTexture *invalid_tex_3D; -} GG = {NULL, NULL, NULL}; + /** Sampler objects used to replace internal texture parameters. */ + GLuint samplers[GPU_SAMPLER_MAX]; +} GG = {NULL}; /* Maximum number of FBOs a texture can be attached to. */ #define GPU_TEX_MAX_FBO_ATTACHED 12 +/* Maximum number of texture unit a texture can be attached to. */ +#define GPU_TEX_MAX_BIND 4 typedef enum eGPUTextureFormatFlag { GPU_FORMAT_DEPTH = (1 << 0), @@ -70,17 +74,18 @@ typedef enum eGPUTextureFormatFlag { /* GPUTexture */ struct GPUTexture { - int w, h, d; /* width/height/depth */ - int orig_w, orig_h; /* width/height (of source data), optional. */ - int number; /* number for multitexture binding */ - int refcount; /* reference count */ - GLenum target; /* GL_TEXTURE_* */ - GLenum target_base; /* same as target, (but no multisample) - * use it for unbinding */ - GLuint bindcode; /* opengl identifier for texture */ + int w, h, d; /* width/height/depth */ + int orig_w, orig_h; /* width/height (of source data), optional. */ + int number[GPU_TEX_MAX_BIND]; /* Texture unit(s) to which this texture is bound. */ + int refcount; /* reference count */ + GLenum target; /* GL_TEXTURE_* */ + GLenum target_base; /* same as target, (but no multisample) + * use it for unbinding */ + GLuint bindcode; /* opengl identifier for texture */ eGPUTextureFormat format; eGPUTextureFormatFlag format_flag; + eGPUSamplerState sampler_state; /* Internal Sampler state. */ int mipmaps; /* number of mipmaps */ int components; /* number of color/alpha channels */ @@ -827,12 +832,14 @@ GPUTexture *GPU_texture_create_nD(int w, tex->h = h; tex->d = d; tex->samples = samples; - tex->number = -1; tex->refcount = 1; tex->format = tex_format; tex->components = gpu_get_component_count(tex_format); tex->mipmaps = 0; tex->format_flag = 0; + for (int i = 0; i < GPU_TEX_MAX_BIND; i++) { + tex->number[i] = -1; + } if (n == 2) { if (d == 0) { @@ -976,26 +983,13 @@ GPUTexture *GPU_texture_create_nD(int w, if (GPU_texture_stencil(tex) || /* Does not support filtering */ GPU_texture_integer(tex) || /* Does not support filtering */ GPU_texture_depth(tex)) { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + tex->sampler_state = GPU_SAMPLER_DEFAULT & ~GPU_SAMPLER_FILTER; } else { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - if (GPU_texture_depth(tex)) { - 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_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - if (n > 1) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - if (n > 2) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + tex->sampler_state = GPU_SAMPLER_DEFAULT; } + /* Avoid issue with incomplete textures. */ + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glBindTexture(tex->target, 0); @@ -1014,12 +1008,14 @@ GPUTexture *GPU_texture_cube_create(int w, tex->h = w; tex->d = d; tex->samples = 0; - tex->number = -1; tex->refcount = 1; tex->format = tex_format; tex->components = gpu_get_component_count(tex_format); tex->mipmaps = 0; tex->format_flag = GPU_FORMAT_CUBE; + for (int i = 0; i < GPU_TEX_MAX_BIND; i++) { + tex->number[i] = -1; + } if (d == 0) { tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP; @@ -1117,22 +1113,13 @@ GPUTexture *GPU_texture_cube_create(int w, if (GPU_texture_stencil(tex) || /* Does not support filtering */ GPU_texture_integer(tex) || /* Does not support filtering */ GPU_texture_depth(tex)) { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + tex->sampler_state = GPU_SAMPLER_DEFAULT & ~GPU_SAMPLER_FILTER; } else { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - if (GPU_texture_depth(tex)) { - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + tex->sampler_state = GPU_SAMPLER_DEFAULT; } - - 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); + /* Avoid issue with incomplete textures. */ + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glBindTexture(tex->target, 0); @@ -1143,7 +1130,6 @@ GPUTexture *GPU_texture_cube_create(int w, GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint buffer) { GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->number = -1; tex->refcount = 1; tex->format = tex_format; tex->components = gpu_get_component_count(tex_format); @@ -1151,6 +1137,10 @@ GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint tex->target_base = tex->target = GL_TEXTURE_BUFFER; tex->mipmaps = 0; + for (int i = 0; i < GPU_TEX_MAX_BIND; i++) { + tex->number[i] = -1; + } + GLenum internalformat = gpu_format_to_gl_internalformat(tex_format); gpu_get_gl_dataformat(tex_format, &tex->format_flag); @@ -1196,11 +1186,17 @@ GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode) { GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->bindcode = bindcode; - tex->number = -1; tex->refcount = 1; tex->target = textarget; tex->target_base = textarget; tex->samples = 0; + tex->sampler_state = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO; + if (GPU_get_mipmap()) { + tex->sampler_state |= (GPU_SAMPLER_MIPMAP | GPU_SAMPLER_FILTER); + } + for (int i = 0; i < GPU_TEX_MAX_BIND; i++) { + tex->number[i] = -1; + } if (!glIsTexture(tex->bindcode)) { GPU_print_error_debug("Blender Texture Not Loaded"); @@ -1727,11 +1723,11 @@ void GPU_invalid_tex_free(void) } } -void GPU_texture_bind(GPUTexture *tex, int number) +void GPU_texture_bind(GPUTexture *tex, int unit) { - BLI_assert(number >= 0); + BLI_assert(unit >= 0); - if (number >= GPU_max_textures()) { + if (unit >= GPU_max_textures()) { fprintf(stderr, "Not enough texture slots.\n"); return; } @@ -1748,38 +1744,59 @@ void GPU_texture_bind(GPUTexture *tex, int number) } } - glActiveTexture(GL_TEXTURE0 + number); + for (int i = 0; i < GPU_TEX_MAX_BIND; i++) { + if (tex->number[i] == -1) { + tex->number[i] = unit; + break; + } + else if (tex->number[i] == unit) { + /* Already bound to this unit. + * But might be with another sampler object so we still rebind. */ + break; + } + else if (i == GPU_TEX_MAX_BIND - 1) { + fprintf(stderr, "Texture is already bound to its maximum number of sampler units!\n"); + BLI_assert(0); /* Should never happen! */ + return; + } + } + + glActiveTexture(GL_TEXTURE0 + unit); if (tex->bindcode != 0) { glBindTexture(tex->target, tex->bindcode); + glBindSampler(unit, GG.samplers[tex->sampler_state]); } else { GPU_invalid_tex_bind(tex->target_base); + glBindSampler(unit, 0); } - - tex->number = number; } void GPU_texture_unbind(GPUTexture *tex) { - if (tex->number == -1) { - return; + for (int i = 0; i < GPU_TEX_MAX_BIND; i++) { + if (tex->number[i] != -1) { + glActiveTexture(GL_TEXTURE0 + tex->number[i]); + glBindTexture(tex->target, 0); + glBindSampler(tex->number[i], 0); + tex->number[i] = -1; + } + else { + break; + } } - - glActiveTexture(GL_TEXTURE0 + tex->number); - glBindTexture(tex->target, 0); - - tex->number = -1; } int GPU_texture_bound_number(GPUTexture *tex) { - return tex->number; + /* TODO remove. Makes no sense now. */ + return tex->number[0]; } #define WARN_NOT_BOUND(_tex) \ { \ - if (_tex->number == -1) { \ + if (_tex->number[0] == -1) { \ fprintf(stderr, "Warning : Trying to set parameter on a texture not bound.\n"); \ BLI_assert(0); \ return; \ @@ -1794,7 +1811,7 @@ void GPU_texture_generate_mipmap(GPUTexture *tex) gpu_texture_memory_footprint_remove(tex); int levels = 1 + floor(log2(max_ii(tex->w, tex->h))); - glActiveTexture(GL_TEXTURE0 + tex->number); + glActiveTexture(GL_TEXTURE0 + tex->number[0]); if (GPU_texture_depth(tex)) { /* Some drivers have bugs when using glGenerateMipmap with depth textures (see T56789). @@ -1905,110 +1922,48 @@ void GPU_texture_copy(GPUTexture *dst, GPUTexture *src) void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare) { - WARN_NOT_BOUND(tex); - /* Could become an assertion ? (fclem) */ if (!GPU_texture_depth(tex)) { return; } - - GLenum mode = (use_compare) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE; - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, mode); + SET_FLAG_FROM_TEST(tex->sampler_state, use_compare, GPU_SAMPLER_COMPARE); } void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter) { - WARN_NOT_BOUND(tex); - /* Stencil and integer format does not support filtering. */ BLI_assert(!use_filter || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); - GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST; - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, filter); + SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER); } void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter) { - WARN_NOT_BOUND(tex); - /* Stencil and integer format does not support filtering. */ - BLI_assert((!use_filter && !use_mipmap) || + BLI_assert(!(use_filter || use_mipmap) || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); - GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST; - GLenum mipmap = ((use_filter) ? (use_mipmap) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR : - (use_mipmap) ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST); - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, mipmap); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); + SET_FLAG_FROM_TEST(tex->sampler_state, use_mipmap, GPU_SAMPLER_MIPMAP); + SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER); } void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp) { - WARN_NOT_BOUND(tex); - - GLenum repeat = (use_repeat) ? GL_REPEAT : (use_clamp) ? GL_CLAMP_TO_EDGE : GL_CLAMP_TO_BORDER; - - glActiveTexture(GL_TEXTURE0 + tex->number); - 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 (repeat == GL_CLAMP_TO_BORDER) { - const float black[] = {0.0f, 0.0f, 0.0f, 0.0f}; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, black); - } + SET_FLAG_FROM_TEST(tex->sampler_state, use_repeat, GPU_SAMPLER_REPEAT); + SET_FLAG_FROM_TEST(tex->sampler_state, !use_clamp, GPU_SAMPLER_CLAMP_BORDER); } void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels) { WARN_NOT_BOUND(tex); - glActiveTexture(GL_TEXTURE0 + tex->number); + glActiveTexture(GL_TEXTURE0 + tex->number[0]); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, (channels >= 2) ? GL_GREEN : GL_RED); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, (channels >= 3) ? GL_BLUE : GL_RED); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, (channels >= 4) ? GL_ALPHA : GL_ONE); } -static GLenum gpu_get_gl_filterfunction(eGPUFilterFunction filter) -{ - switch (filter) { - case GPU_NEAREST: - return GL_NEAREST; - case GPU_LINEAR: - return GL_LINEAR; - default: - BLI_assert(!"Unhandled filter mode"); - return GL_NEAREST; - } -} - -void GPU_texture_filters(GPUTexture *tex, - eGPUFilterFunction min_filter, - eGPUFilterFunction mag_filter) -{ - WARN_NOT_BOUND(tex); - - /* Stencil and integer format does not support filtering. */ - BLI_assert(!(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); - BLI_assert(mag_filter == GPU_NEAREST || mag_filter == GPU_LINEAR); - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, gpu_get_gl_filterfunction(min_filter)); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, gpu_get_gl_filterfunction(mag_filter)); -} - void GPU_texture_free(GPUTexture *tex) { tex->refcount--; @@ -2169,3 +2124,55 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size) size[2] = max_ii(1, tex->d / div); } } + +/* -------------------------------------------------------------------- */ +/** \name GPU Sampler Objects + * + * Simple wrapper around opengl sampler objects. + * Override texture sampler state for one sampler unit only. + * \{ */ + +void GPU_samplers_init(void) +{ + glGenSamplers(GPU_SAMPLER_MAX, GG.samplers); + for (int i = 0; i < GPU_SAMPLER_MAX; i++) { + eGPUSamplerState state = i; + GLenum clamp_type = (state & GPU_SAMPLER_CLAMP_BORDER) ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE; + GLenum wrap_s = (state & GPU_SAMPLER_REPEAT_R) ? GL_REPEAT : clamp_type; + GLenum wrap_t = (state & GPU_SAMPLER_REPEAT_S) ? GL_REPEAT : clamp_type; + GLenum wrap_r = (state & GPU_SAMPLER_REPEAT_T) ? GL_REPEAT : clamp_type; + GLenum mag_filter = (state & GPU_SAMPLER_FILTER) ? GL_LINEAR : GL_NEAREST; + GLenum min_filter = (state & GPU_SAMPLER_FILTER) ? + ((state & GPU_SAMPLER_MIPMAP) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) : + ((state & GPU_SAMPLER_MIPMAP) ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST); + GLenum compare_mode = (state & GPU_SAMPLER_COMPARE) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE; + float aniso_filter = ((state & GPU_SAMPLER_MIPMAP) && (state & GPU_SAMPLER_ANISO)) ? + GPU_get_anisotropic() : + 1.0f; + + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_S, wrap_s); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_T, wrap_t); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_R, wrap_r); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_MIN_FILTER, min_filter); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_MAG_FILTER, mag_filter); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_COMPARE_MODE, compare_mode); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + if (GLEW_EXT_texture_filter_anisotropic) { + glSamplerParameterf(GG.samplers[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso_filter); + } + + /** Other states are left to default: + * - GL_TEXTURE_BORDER_COLOR is {0, 0, 0, 0}. + * - GL_TEXTURE_MIN_LOD is -1000. + * - GL_TEXTURE_MAX_LOD is 1000. + * - GL_TEXTURE_LOD_BIAS is 0.0f. + **/ + } +} + +void GPU_samplers_free(void) +{ + glDeleteSamplers(GPU_SAMPLER_MAX, GG.samplers); +} + +/** \} */ |