Changeset View
Changeset View
Standalone View
Standalone View
source/blender/gpu/intern/gpu_texture.c
| Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
| #include "gpu_context_private.h" | #include "gpu_context_private.h" | ||||
| static struct GPUTextureGlobal { | static struct GPUTextureGlobal { | ||||
| /** Texture used in place of invalid textures (not loaded correctly, missing). */ | /** Texture used in place of invalid textures (not loaded correctly, missing). */ | ||||
| GPUTexture *invalid_tex_1D; | GPUTexture *invalid_tex_1D; | ||||
| GPUTexture *invalid_tex_2D; | GPUTexture *invalid_tex_2D; | ||||
| GPUTexture *invalid_tex_3D; | 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. */ | /* Maximum number of FBOs a texture can be attached to. */ | ||||
| #define GPU_TEX_MAX_FBO_ATTACHED 12 | #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 { | typedef enum eGPUTextureFormatFlag { | ||||
| GPU_FORMAT_DEPTH = (1 << 0), | GPU_FORMAT_DEPTH = (1 << 0), | ||||
| GPU_FORMAT_STENCIL = (1 << 1), | GPU_FORMAT_STENCIL = (1 << 1), | ||||
| GPU_FORMAT_INTEGER = (1 << 2), | GPU_FORMAT_INTEGER = (1 << 2), | ||||
| GPU_FORMAT_FLOAT = (1 << 3), | GPU_FORMAT_FLOAT = (1 << 3), | ||||
| GPU_FORMAT_1D = (1 << 10), | GPU_FORMAT_1D = (1 << 10), | ||||
| GPU_FORMAT_2D = (1 << 11), | GPU_FORMAT_2D = (1 << 11), | ||||
| GPU_FORMAT_3D = (1 << 12), | GPU_FORMAT_3D = (1 << 12), | ||||
| GPU_FORMAT_CUBE = (1 << 13), | GPU_FORMAT_CUBE = (1 << 13), | ||||
| GPU_FORMAT_ARRAY = (1 << 14), | GPU_FORMAT_ARRAY = (1 << 14), | ||||
| } eGPUTextureFormatFlag; | } eGPUTextureFormatFlag; | ||||
| /* GPUTexture */ | /* GPUTexture */ | ||||
| struct GPUTexture { | struct GPUTexture { | ||||
| int w, h, d; /* width/height/depth */ | int w, h, d; /* width/height/depth */ | ||||
| int orig_w, orig_h; /* width/height (of source data), optional. */ | int orig_w, orig_h; /* width/height (of source data), optional. */ | ||||
| int number; /* number for multitexture binding */ | int number[GPU_TEX_MAX_BIND]; /* Texture unit(s) to which this texture is bound. */ | ||||
| int refcount; /* reference count */ | int refcount; /* reference count */ | ||||
| GLenum target; /* GL_TEXTURE_* */ | GLenum target; /* GL_TEXTURE_* */ | ||||
| GLenum target_base; /* same as target, (but no multisample) | GLenum target_base; /* same as target, (but no multisample) | ||||
| * use it for unbinding */ | * use it for unbinding */ | ||||
| GLuint bindcode; /* opengl identifier for texture */ | GLuint bindcode; /* opengl identifier for texture */ | ||||
| eGPUTextureFormat format; | eGPUTextureFormat format; | ||||
| eGPUTextureFormatFlag format_flag; | eGPUTextureFormatFlag format_flag; | ||||
| eGPUSamplerState sampler_state; /* Internal Sampler state. */ | |||||
| int mipmaps; /* number of mipmaps */ | int mipmaps; /* number of mipmaps */ | ||||
| int components; /* number of color/alpha channels */ | int components; /* number of color/alpha channels */ | ||||
| int samples; /* number of samples for multisamples textures. 0 if not multisample target */ | int samples; /* number of samples for multisamples textures. 0 if not multisample target */ | ||||
| int fb_attachment[GPU_TEX_MAX_FBO_ATTACHED]; | int fb_attachment[GPU_TEX_MAX_FBO_ATTACHED]; | ||||
| GPUFrameBuffer *fb[GPU_TEX_MAX_FBO_ATTACHED]; | GPUFrameBuffer *fb[GPU_TEX_MAX_FBO_ATTACHED]; | ||||
| /* Legacy workaround for texture copy. */ | /* Legacy workaround for texture copy. */ | ||||
| ▲ Show 20 Lines • Show All 730 Lines • ▼ Show 20 Lines | if ((tex_format == GPU_DEPTH24_STENCIL8) && GPU_depth_blitting_workaround()) { | ||||
| tex_format = GPU_DEPTH32F_STENCIL8; | tex_format = GPU_DEPTH32F_STENCIL8; | ||||
| } | } | ||||
| GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); | GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); | ||||
| tex->w = w; | tex->w = w; | ||||
| tex->h = h; | tex->h = h; | ||||
| tex->d = d; | tex->d = d; | ||||
| tex->samples = samples; | tex->samples = samples; | ||||
| tex->number = -1; | |||||
| tex->refcount = 1; | tex->refcount = 1; | ||||
| tex->format = tex_format; | tex->format = tex_format; | ||||
| tex->components = gpu_get_component_count(tex_format); | tex->components = gpu_get_component_count(tex_format); | ||||
| tex->mipmaps = 0; | tex->mipmaps = 0; | ||||
| tex->format_flag = 0; | tex->format_flag = 0; | ||||
| for (int i = 0; i < GPU_TEX_MAX_BIND; i++) { | |||||
| tex->number[i] = -1; | |||||
| } | |||||
| if (n == 2) { | if (n == 2) { | ||||
| if (d == 0) { | if (d == 0) { | ||||
| tex->target_base = tex->target = GL_TEXTURE_2D; | tex->target_base = tex->target = GL_TEXTURE_2D; | ||||
| } | } | ||||
| else { | else { | ||||
| tex->target_base = tex->target = GL_TEXTURE_2D_ARRAY; | tex->target_base = tex->target = GL_TEXTURE_2D_ARRAY; | ||||
| tex->format_flag |= GPU_FORMAT_ARRAY; | tex->format_flag |= GPU_FORMAT_ARRAY; | ||||
| ▲ Show 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | GPUTexture *GPU_texture_create_nD(int w, | ||||
| if (rescaled_pixels) { | if (rescaled_pixels) { | ||||
| MEM_freeN(rescaled_pixels); | MEM_freeN(rescaled_pixels); | ||||
| } | } | ||||
| /* Texture Parameters */ | /* Texture Parameters */ | ||||
| if (GPU_texture_stencil(tex) || /* Does not support filtering */ | if (GPU_texture_stencil(tex) || /* Does not support filtering */ | ||||
| GPU_texture_integer(tex) || /* Does not support filtering */ | GPU_texture_integer(tex) || /* Does not support filtering */ | ||||
| GPU_texture_depth(tex)) { | GPU_texture_depth(tex)) { | ||||
| glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | tex->sampler_state = GPU_SAMPLER_DEFAULT & ~GPU_SAMPLER_FILTER; | ||||
| glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |||||
| } | } | ||||
| else { | else { | ||||
| glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | tex->sampler_state = GPU_SAMPLER_DEFAULT; | ||||
| 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); | |||||
| } | } | ||||
| /* Avoid issue with incomplete textures. */ | |||||
| glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |||||
| glBindTexture(tex->target, 0); | glBindTexture(tex->target, 0); | ||||
| return tex; | return tex; | ||||
| } | } | ||||
| GPUTexture *GPU_texture_cube_create(int w, | GPUTexture *GPU_texture_cube_create(int w, | ||||
| int d, | int d, | ||||
| const void *pixels, | const void *pixels, | ||||
| eGPUTextureFormat tex_format, | eGPUTextureFormat tex_format, | ||||
| eGPUDataFormat gpu_data_format, | eGPUDataFormat gpu_data_format, | ||||
| char err_out[256]) | char err_out[256]) | ||||
| { | { | ||||
| GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); | GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); | ||||
| tex->w = w; | tex->w = w; | ||||
| tex->h = w; | tex->h = w; | ||||
| tex->d = d; | tex->d = d; | ||||
| tex->samples = 0; | tex->samples = 0; | ||||
| tex->number = -1; | |||||
| tex->refcount = 1; | tex->refcount = 1; | ||||
| tex->format = tex_format; | tex->format = tex_format; | ||||
| tex->components = gpu_get_component_count(tex_format); | tex->components = gpu_get_component_count(tex_format); | ||||
| tex->mipmaps = 0; | tex->mipmaps = 0; | ||||
| tex->format_flag = GPU_FORMAT_CUBE; | tex->format_flag = GPU_FORMAT_CUBE; | ||||
| for (int i = 0; i < GPU_TEX_MAX_BIND; i++) { | |||||
| tex->number[i] = -1; | |||||
| } | |||||
| if (d == 0) { | if (d == 0) { | ||||
| tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP; | tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP; | ||||
| } | } | ||||
| else { | else { | ||||
| tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY_ARB; | tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY_ARB; | ||||
| tex->format_flag |= GPU_FORMAT_ARRAY; | tex->format_flag |= GPU_FORMAT_ARRAY; | ||||
| ▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | glTexImage3D(tex->target, | ||||
| data_type, | data_type, | ||||
| pixels); | pixels); | ||||
| } | } | ||||
| /* Texture Parameters */ | /* Texture Parameters */ | ||||
| if (GPU_texture_stencil(tex) || /* Does not support filtering */ | if (GPU_texture_stencil(tex) || /* Does not support filtering */ | ||||
| GPU_texture_integer(tex) || /* Does not support filtering */ | GPU_texture_integer(tex) || /* Does not support filtering */ | ||||
| GPU_texture_depth(tex)) { | GPU_texture_depth(tex)) { | ||||
| glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | tex->sampler_state = GPU_SAMPLER_DEFAULT & ~GPU_SAMPLER_FILTER; | ||||
| glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |||||
| } | } | ||||
| else { | else { | ||||
| glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | tex->sampler_state = GPU_SAMPLER_DEFAULT; | ||||
| glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||||
| } | } | ||||
| /* Avoid issue with incomplete textures. */ | |||||
| if (GPU_texture_depth(tex)) { | glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||||
| 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); | |||||
| glBindTexture(tex->target, 0); | glBindTexture(tex->target, 0); | ||||
| return tex; | return tex; | ||||
| } | } | ||||
| /* Special buffer textures. tex_format must be compatible with the buffer content. */ | /* Special buffer textures. tex_format must be compatible with the buffer content. */ | ||||
| GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint buffer) | GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint buffer) | ||||
| { | { | ||||
| GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); | GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); | ||||
| tex->number = -1; | |||||
| tex->refcount = 1; | tex->refcount = 1; | ||||
| tex->format = tex_format; | tex->format = tex_format; | ||||
| tex->components = gpu_get_component_count(tex_format); | tex->components = gpu_get_component_count(tex_format); | ||||
| tex->format_flag = 0; | tex->format_flag = 0; | ||||
| tex->target_base = tex->target = GL_TEXTURE_BUFFER; | tex->target_base = tex->target = GL_TEXTURE_BUFFER; | ||||
| tex->mipmaps = 0; | 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); | GLenum internalformat = gpu_format_to_gl_internalformat(tex_format); | ||||
| gpu_get_gl_dataformat(tex_format, &tex->format_flag); | gpu_get_gl_dataformat(tex_format, &tex->format_flag); | ||||
| if (!(ELEM(tex_format, GPU_R8, GPU_R16) || ELEM(tex_format, GPU_R16F, GPU_R32F) || | if (!(ELEM(tex_format, GPU_R8, GPU_R16) || ELEM(tex_format, GPU_R16F, GPU_R32F) || | ||||
| ELEM(tex_format, GPU_R8I, GPU_R16I, GPU_R32I) || | ELEM(tex_format, GPU_R8I, GPU_R16I, GPU_R32I) || | ||||
| ELEM(tex_format, GPU_R8UI, GPU_R16UI, GPU_R32UI) || ELEM(tex_format, GPU_RG8, GPU_RG16) || | ELEM(tex_format, GPU_R8UI, GPU_R16UI, GPU_R32UI) || ELEM(tex_format, GPU_RG8, GPU_RG16) || | ||||
| ELEM(tex_format, GPU_RG16F, GPU_RG32F) || | ELEM(tex_format, GPU_RG16F, GPU_RG32F) || | ||||
| Show All 29 Lines | GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint buffer) | ||||
| return tex; | return tex; | ||||
| } | } | ||||
| GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode) | GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode) | ||||
| { | { | ||||
| GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); | GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); | ||||
| tex->bindcode = bindcode; | tex->bindcode = bindcode; | ||||
| tex->number = -1; | |||||
| tex->refcount = 1; | tex->refcount = 1; | ||||
| tex->target = textarget; | tex->target = textarget; | ||||
| tex->target_base = textarget; | tex->target_base = textarget; | ||||
| tex->samples = 0; | 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)) { | if (!glIsTexture(tex->bindcode)) { | ||||
| GPU_print_error_debug("Blender Texture Not Loaded"); | GPU_print_error_debug("Blender Texture Not Loaded"); | ||||
| } | } | ||||
| else { | else { | ||||
| GLint w, h, gl_format; | GLint w, h, gl_format; | ||||
| GLenum gettarget; | GLenum gettarget; | ||||
| gettarget = (textarget == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : textarget; | gettarget = (textarget == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : textarget; | ||||
| ▲ Show 20 Lines • Show All 510 Lines • ▼ Show 20 Lines | void GPU_invalid_tex_free(void) | ||||
| if (GG.invalid_tex_2D) { | if (GG.invalid_tex_2D) { | ||||
| GPU_texture_free(GG.invalid_tex_2D); | GPU_texture_free(GG.invalid_tex_2D); | ||||
| } | } | ||||
| if (GG.invalid_tex_3D) { | if (GG.invalid_tex_3D) { | ||||
| GPU_texture_free(GG.invalid_tex_3D); | GPU_texture_free(GG.invalid_tex_3D); | ||||
| } | } | ||||
| } | } | ||||
| 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"); | fprintf(stderr, "Not enough texture slots.\n"); | ||||
| return; | return; | ||||
| } | } | ||||
| if ((G.debug & G_DEBUG)) { | if ((G.debug & G_DEBUG)) { | ||||
| for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) { | for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) { | ||||
| if (tex->fb[i] && GPU_framebuffer_bound(tex->fb[i])) { | if (tex->fb[i] && GPU_framebuffer_bound(tex->fb[i])) { | ||||
| fprintf(stderr, | fprintf(stderr, | ||||
| "Feedback loop warning!: Attempting to bind " | "Feedback loop warning!: Attempting to bind " | ||||
| "texture attached to current framebuffer!\n"); | "texture attached to current framebuffer!\n"); | ||||
| BLI_assert(0); /* Should never happen! */ | BLI_assert(0); /* Should never happen! */ | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| 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) { | if (tex->bindcode != 0) { | ||||
| glBindTexture(tex->target, tex->bindcode); | glBindTexture(tex->target, tex->bindcode); | ||||
| glBindSampler(unit, GG.samplers[tex->sampler_state]); | |||||
| } | } | ||||
| else { | else { | ||||
| GPU_invalid_tex_bind(tex->target_base); | GPU_invalid_tex_bind(tex->target_base); | ||||
| glBindSampler(unit, 0); | |||||
| } | } | ||||
| tex->number = number; | |||||
| } | } | ||||
brecht: Assert and print an error when no free texture unit is found? | |||||
| void GPU_texture_unbind(GPUTexture *tex) | void GPU_texture_unbind(GPUTexture *tex) | ||||
| { | { | ||||
| if (tex->number == -1) { | for (int i = 0; i < GPU_TEX_MAX_BIND; i++) { | ||||
| return; | if (tex->number[i] != -1) { | ||||
| } | glActiveTexture(GL_TEXTURE0 + tex->number[i]); | ||||
| glActiveTexture(GL_TEXTURE0 + tex->number); | |||||
| glBindTexture(tex->target, 0); | glBindTexture(tex->target, 0); | ||||
| glBindSampler(tex->number[i], 0); | |||||
| tex->number = -1; | tex->number[i] = -1; | ||||
| } | |||||
| else { | |||||
| break; | |||||
| } | |||||
| } | |||||
Done Inline ActionsThis early return could be replaced by else { break; } inside the loop below. brecht: This early return could be replaced by `else { break; }` inside the loop below. | |||||
| } | } | ||||
| int GPU_texture_bound_number(GPUTexture *tex) | 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) \ | #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"); \ | fprintf(stderr, "Warning : Trying to set parameter on a texture not bound.\n"); \ | ||||
| BLI_assert(0); \ | BLI_assert(0); \ | ||||
| return; \ | return; \ | ||||
| } \ | } \ | ||||
| } \ | } \ | ||||
| ((void)0) | ((void)0) | ||||
| void GPU_texture_generate_mipmap(GPUTexture *tex) | void GPU_texture_generate_mipmap(GPUTexture *tex) | ||||
| { | { | ||||
| WARN_NOT_BOUND(tex); | WARN_NOT_BOUND(tex); | ||||
| gpu_texture_memory_footprint_remove(tex); | gpu_texture_memory_footprint_remove(tex); | ||||
| int levels = 1 + floor(log2(max_ii(tex->w, tex->h))); | 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)) { | if (GPU_texture_depth(tex)) { | ||||
| /* Some drivers have bugs when using glGenerateMipmap with depth textures (see T56789). | /* 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. | * 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 | * You must initialize the texture levels using other methods like | ||||
| * GPU_framebuffer_recursive_downsample(). */ | * GPU_framebuffer_recursive_downsample(). */ | ||||
| eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex->format); | eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex->format); | ||||
| for (int i = 1; i < levels; i++) { | for (int i = 1; i < levels; i++) { | ||||
| ▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | else { | ||||
| if (prev_fb) { | if (prev_fb) { | ||||
| GPU_framebuffer_bind(prev_fb); | GPU_framebuffer_bind(prev_fb); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare) | void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare) | ||||
| { | { | ||||
| WARN_NOT_BOUND(tex); | |||||
| /* Could become an assertion ? (fclem) */ | /* Could become an assertion ? (fclem) */ | ||||
| if (!GPU_texture_depth(tex)) { | if (!GPU_texture_depth(tex)) { | ||||
| return; | return; | ||||
| } | } | ||||
| SET_FLAG_FROM_TEST(tex->sampler_state, use_compare, GPU_SAMPLER_COMPARE); | |||||
| 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); | |||||
| } | } | ||||
| void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter) | void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter) | ||||
| { | { | ||||
| WARN_NOT_BOUND(tex); | |||||
| /* Stencil and integer format does not support filtering. */ | /* Stencil and integer format does not support filtering. */ | ||||
| BLI_assert(!use_filter || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); | BLI_assert(!use_filter || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); | ||||
| GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST; | SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER); | ||||
| glActiveTexture(GL_TEXTURE0 + tex->number); | |||||
| glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); | |||||
| glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, filter); | |||||
| } | } | ||||
| void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_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. */ | /* 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))); | !(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); | ||||
| GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST; | SET_FLAG_FROM_TEST(tex->sampler_state, use_mipmap, GPU_SAMPLER_MIPMAP); | ||||
| GLenum mipmap = ((use_filter) ? (use_mipmap) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR : | SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER); | ||||
| (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); | |||||
| } | } | ||||
| void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp) | void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp) | ||||
| { | { | ||||
| WARN_NOT_BOUND(tex); | 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); | |||||
| 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); | |||||
| } | |||||
| } | } | ||||
| void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels) | void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels) | ||||
| { | { | ||||
| WARN_NOT_BOUND(tex); | 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_R, GL_RED); | ||||
| glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, (channels >= 2) ? GL_GREEN : 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_B, (channels >= 3) ? GL_BLUE : GL_RED); | ||||
| glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, (channels >= 4) ? GL_ALPHA : GL_ONE); | 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) | void GPU_texture_free(GPUTexture *tex) | ||||
| { | { | ||||
| tex->refcount--; | tex->refcount--; | ||||
| if (tex->refcount < 0) { | if (tex->refcount < 0) { | ||||
| fprintf(stderr, "GPUTexture: negative refcount\n"); | fprintf(stderr, "GPUTexture: negative refcount\n"); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | if (GPU_texture_array(tex)) { | ||||
| if (GPU_texture_cube(tex)) { | if (GPU_texture_cube(tex)) { | ||||
| size[2] *= 6; | size[2] *= 6; | ||||
| } | } | ||||
| } | } | ||||
| else if (tex->d > 0) { | else if (tex->d > 0) { | ||||
| size[2] = max_ii(1, tex->d / div); | 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); | |||||
| } | |||||
| /** \} */ | |||||
Assert and print an error when no free texture unit is found?