diff options
Diffstat (limited to 'source/blender/gpu/intern/gpu_texture.c')
-rw-r--r-- | source/blender/gpu/intern/gpu_texture.c | 232 |
1 files changed, 116 insertions, 116 deletions
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 38ba8bc612f..1d870ed2fdc 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -50,7 +50,9 @@ 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 @@ -72,7 +74,7 @@ typedef enum eGPUTextureFormatFlag { 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 number; /* Texture unit to which this texture is bound. */ int refcount; /* reference count */ GLenum target; /* GL_TEXTURE_* */ GLenum target_base; /* same as target, (but no multisample) @@ -81,6 +83,7 @@ struct GPUTexture { 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 +830,12 @@ 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; + tex->number = -1; if (n == 2) { if (d == 0) { @@ -976,26 +979,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 +1004,12 @@ 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; + tex->number = -1; if (d == 0) { tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP; @@ -1117,22 +1107,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); + tex->sampler_state = GPU_SAMPLER_DEFAULT; } - - 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); - 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,13 +1124,13 @@ 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); tex->format_flag = 0; tex->target_base = tex->target = GL_TEXTURE_BUFFER; tex->mipmaps = 0; + tex->number = -1; GLenum internalformat = gpu_format_to_gl_internalformat(tex_format); @@ -1196,11 +1177,15 @@ 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); + } + tex->number = -1; if (!glIsTexture(tex->bindcode)) { GPU_print_error_debug("Blender Texture Not Loaded"); @@ -1727,16 +1712,17 @@ void GPU_invalid_tex_free(void) } } -void GPU_texture_bind(GPUTexture *tex, int number) +/* set_number is to save the the texture unit for setting texture parameters. */ +void GPU_texture_bind_ex(GPUTexture *tex, eGPUSamplerState state, int unit, const bool set_number) { - 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; } - if ((G.debug & G_DEBUG)) { + if (G.debug & G_DEBUG) { for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) { if (tex->fb[i] && GPU_framebuffer_bound(tex->fb[i])) { fprintf(stderr, @@ -1748,16 +1734,27 @@ void GPU_texture_bind(GPUTexture *tex, int number) } } - glActiveTexture(GL_TEXTURE0 + number); + if (set_number) { + tex->number = unit; + } + + glActiveTexture(GL_TEXTURE0 + unit); + + state = (state < GPU_SAMPLER_MAX) ? state : tex->sampler_state; if (tex->bindcode != 0) { glBindTexture(tex->target, tex->bindcode); + glBindSampler(unit, GG.samplers[state]); } else { GPU_invalid_tex_bind(tex->target_base); + glBindSampler(unit, 0); } +} - tex->number = number; +void GPU_texture_bind(GPUTexture *tex, int unit) +{ + GPU_texture_bind_ex(tex, GPU_SAMPLER_MAX, unit, true); } void GPU_texture_unbind(GPUTexture *tex) @@ -1768,13 +1765,26 @@ void GPU_texture_unbind(GPUTexture *tex) glActiveTexture(GL_TEXTURE0 + tex->number); glBindTexture(tex->target, 0); - + glBindSampler(tex->number, 0); tex->number = -1; } -int GPU_texture_bound_number(GPUTexture *tex) +void GPU_texture_unbind_all(void) { - return tex->number; + for (int i = 0; i < GPU_max_textures(); i++) { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); + glBindTexture(GL_TEXTURE_1D, 0); + glBindTexture(GL_TEXTURE_1D_ARRAY, 0); + glBindTexture(GL_TEXTURE_3D, 0); + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + glBindTexture(GL_TEXTURE_BUFFER, 0); + if (GPU_arb_texture_cube_map_array_is_supported()) { + glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY_ARB, 0); + } + glBindSampler(i, 0); + } } #define WARN_NOT_BOUND(_tex) \ @@ -1798,8 +1808,8 @@ void GPU_texture_generate_mipmap(GPUTexture *tex) if (GPU_texture_depth(tex)) { /* Some drivers have bugs when using glGenerateMipmap with depth textures (see T56789). - * In this case we just create a complete texture with mipmaps manually without down-sampling. - * You must initialize the texture levels using other methods like + * In this case we just create a complete texture with mipmaps manually without + * down-sampling. You must initialize the texture levels using other methods like * GPU_framebuffer_recursive_downsample(). */ eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex->format); for (int i = 1; i < levels; i++) { @@ -1905,69 +1915,35 @@ 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) @@ -1981,34 +1957,6 @@ void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels) 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 +2117,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_S) ? GL_REPEAT : clamp_type; + GLenum wrap_t = (state & GPU_SAMPLER_REPEAT_T) ? GL_REPEAT : clamp_type; + GLenum wrap_r = (state & GPU_SAMPLER_REPEAT_R) ? 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); +} + +/** \} */ |