diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2020-06-08 11:58:45 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2020-06-08 11:58:45 +0300 |
commit | 1f6d1213d27cbe3e50460aa6da54e0c7606f2216 (patch) | |
tree | e2c42891c2e76fc3f36ce62d9e81a2d4751c6f59 /source/blender/draw | |
parent | 11ba9eec70175b39e34943c8ffacb54c35cbb897 (diff) |
Workbench: Use eGPUSamplerState to change texture sampling behavior
This removes some fragment shader hacks and improve the support of
different repeat & filtering modes.
This fix T77453 Image texture not repeating in viewport
Diffstat (limited to 'source/blender/draw')
6 files changed, 57 insertions, 70 deletions
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl index e45f7a7b9e3..c5ad48191d1 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl @@ -4,17 +4,20 @@ bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map) { vec2 tile_pos = floor(co.xy); - if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10) + if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10) { return false; + } float tile = 10.0 * tile_pos.y + tile_pos.x; - if (tile >= textureSize(map, 0).x) + if (tile >= textureSize(map, 0).x) { return false; + } /* Fetch tile information. */ float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x; - if (tile_layer < 0.0) + if (tile_layer < 0.0) { return false; + } vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0); @@ -22,59 +25,29 @@ bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map) return true; } -vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling) -{ - /* TODO(fclem) We could do the same with sampler objects. - * But this is a quick workaround instead of messing with the GPUTexture itself. */ - if (nearest_sampling) { - /* Use texelFetch for nearest_sampling to reduce glitches. See: T73726 */ - vec2 tex_size = vec2(textureSize(image, 0).xy); - ivec2 uv = ivec2(floor(coord * tex_size) + 0.5); - return texelFetch(image, uv, 0); - } - else { - return texture(image, coord); - } -} - -vec4 workbench_sample_texture_array(sampler2DArray tile_array, - sampler1DArray tile_data, - vec2 coord, - bool nearest_sampling) -{ - - vec3 uv = vec3(coord, 0); - if (!node_tex_tile_lookup(uv, tile_array, tile_data)) - return vec4(1.0, 0.0, 1.0, 1.0); - - /* TODO(fclem) We could do the same with sampler objects. - * But this is a quick workaround instead of messing with the GPUTexture itself. */ - if (nearest_sampling) { - /* Use texelFetch for nearest_sampling to reduce glitches. See: T73726 */ - vec3 tex_size = vec3(textureSize(tile_array, 0)); - uv.xy = floor(uv.xy * tex_size.xy) + 0.5; - return texelFetch(tile_array, ivec3(uv), 0); - } - else { - return texture(tile_array, uv); - } -} - uniform sampler2DArray imageTileArray; uniform sampler1DArray imageTileData; uniform sampler2D imageTexture; uniform float imageTransparencyCutoff = 0.1; -uniform bool imageNearest; uniform bool imagePremult; vec3 workbench_image_color(vec2 uvs) { #ifdef V3D_SHADING_TEXTURE_COLOR + vec4 color; + # ifdef TEXTURE_IMAGE_ARRAY - vec4 color = workbench_sample_texture_array(imageTileArray, imageTileData, uvs, imageNearest); + vec3 co = vec3(uvs, 0.0); + if (node_tex_tile_lookup(co, imageTileArray, imageTileData)) { + color = texture(imageTileArray, co); + } + else { + color = vec4(1.0, 0.0, 1.0, 1.0); + } # else - vec4 color = workbench_sample_texture(imageTexture, uvs, imageNearest); + + color = texture(imageTexture, uvs); # endif /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */ @@ -90,6 +63,7 @@ vec3 workbench_image_color(vec2 uvs) return color.rgb; #else + return vec3(1.0); #endif } diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 511dd563b46..bc5a2c14538 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -141,10 +141,10 @@ static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); if (geom) { Image *ima = imapaint->canvas; - int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : - SHD_INTERP_CLOSEST; + eGPUSamplerState state = GPU_SAMPLER_REPEAT; + SET_FLAG_FROM_TEST(state, imapaint->interp == IMAGEPAINT_INTERP_LINEAR, GPU_SAMPLER_FILTER); - DRWShadingGroup *grp = workbench_image_setup(wpd, ob, 0, ima, NULL, interp); + DRWShadingGroup *grp = workbench_image_setup(wpd, ob, 0, ima, NULL, state); DRW_shgroup_call(grp, geom, ob); } } @@ -210,10 +210,10 @@ static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd, const ImagePaintSettings *imapaint = use_texpaint_mode ? &scene->toolsettings->imapaint : NULL; Image *ima = (imapaint && imapaint->mode == IMAGEPAINT_MODE_IMAGE) ? imapaint->canvas : NULL; - int interp = (imapaint && imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : - SHD_INTERP_CLOSEST; + eGPUSamplerState state = 0; + SET_FLAG_FROM_TEST(state, imapaint->interp == IMAGEPAINT_INTERP_LINEAR, GPU_SAMPLER_FILTER); DRWShadingGroup *grp = (use_texpaint_mode) ? - workbench_image_hair_setup(wpd, ob, matnr, ima, NULL, interp) : + workbench_image_hair_setup(wpd, ob, matnr, ima, NULL, state) : workbench_material_hair_setup(wpd, ob, matnr, color_type); DRW_shgroup_hair_create_sub(ob, psys, md, grp); diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index b36a4a3a494..0b2d508fee5 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -101,31 +101,34 @@ BLI_INLINE Material *workbench_object_material_get(Object *ob, int mat_nr) } BLI_INLINE void workbench_material_get_image( - Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp) + Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, eGPUSamplerState *r_sampler) { bNode *node; + *r_sampler = 0; ED_object_get_active_image(ob, mat_nr, r_image, r_iuser, &node, NULL); if (node && *r_image) { switch (node->type) { case SH_NODE_TEX_IMAGE: { NodeTexImage *storage = node->storage; - *r_interp = storage->interpolation; + const bool use_filter = (storage->interpolation != SHD_INTERP_CLOSEST); + const bool use_repeat = (storage->extension == SHD_IMAGE_EXTENSION_REPEAT); + const bool use_clip = (storage->extension == SHD_IMAGE_EXTENSION_CLIP); + SET_FLAG_FROM_TEST(*r_sampler, use_filter, GPU_SAMPLER_FILTER); + SET_FLAG_FROM_TEST(*r_sampler, use_repeat, GPU_SAMPLER_REPEAT); + SET_FLAG_FROM_TEST(*r_sampler, use_clip, GPU_SAMPLER_CLAMP_BORDER); break; } case SH_NODE_TEX_ENVIRONMENT: { NodeTexEnvironment *storage = node->storage; - *r_interp = storage->interpolation; + const bool use_filter = (storage->interpolation != SHD_INTERP_CLOSEST); + SET_FLAG_FROM_TEST(*r_sampler, use_filter, GPU_SAMPLER_FILTER); break; } default: BLI_assert(!"Node type not supported by workbench"); - *r_interp = 0; } } - else { - *r_interp = 0; - } } /* Return true if the current material ubo has changed and needs to be rebind. */ @@ -164,11 +167,11 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd, { Image *ima = NULL; ImageUser *iuser = NULL; - int interp; + eGPUSamplerState sampler; const bool infront = (ob->dtx & OB_DRAWXRAY) != 0; if (color_type == V3D_SHADING_TEXTURE_COLOR) { - workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp); + workbench_material_get_image(ob, mat_nr, &ima, &iuser, &sampler); if (ima == NULL) { /* Fallback to material color. */ color_type = V3D_SHADING_MATERIAL_COLOR; @@ -177,7 +180,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd, switch (color_type) { case V3D_SHADING_TEXTURE_COLOR: { - return workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, hair); + return workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, sampler, hair); } case V3D_SHADING_MATERIAL_COLOR: { /* For now, we use the same ubo for material and object coloring but with different indices. @@ -247,13 +250,13 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, int mat_nr, Image *ima, ImageUser *iuser, - int interp, + eGPUSamplerState sampler, bool hair) { GPUTexture *tex = NULL, *tex_tile_data = NULL; if (ima == NULL) { - workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp); + workbench_material_get_image(ob, mat_nr, &ima, &iuser, &sampler); } if (ima) { @@ -284,13 +287,12 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, *grp_tex = grp = DRW_shgroup_create_sub(grp); if (tex_tile_data) { - DRW_shgroup_uniform_texture(grp, "imageTileArray", tex); + DRW_shgroup_uniform_texture_ex(grp, "imageTileArray", tex, sampler); DRW_shgroup_uniform_texture(grp, "imageTileData", tex_tile_data); } else { - DRW_shgroup_uniform_texture(grp, "imageTexture", tex); + DRW_shgroup_uniform_texture_ex(grp, "imageTexture", tex, sampler); } DRW_shgroup_uniform_bool_copy(grp, "imagePremult", (ima && ima->alpha_mode == IMA_ALPHA_PREMUL)); - DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST)); return grp; } diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 967bdf9bae0..20b6d368ac0 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -462,7 +462,7 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, int mat_nr, Image *ima, ImageUser *iuser, - int interp, + eGPUSamplerState sampler, bool hair); #define workbench_material_setup(wpd, ob, mat_nr, color_type, r_transp) \ diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index e7dd9e449b7..89dd6fa210c 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -458,6 +458,10 @@ void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup, float depth, uchar stencil); +void DRW_shgroup_uniform_texture_ex(DRWShadingGroup *shgroup, + const char *name, + const struct GPUTexture *tex, + eGPUSamplerState sampler_state); void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex); diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index ea67dd87772..07fb97236fb 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -247,11 +247,19 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup, drw_shgroup_uniform_create_ex(shgroup, location, type, value, 0, length, arraysize); } -void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex) +void DRW_shgroup_uniform_texture_ex(DRWShadingGroup *shgroup, + const char *name, + const GPUTexture *tex, + eGPUSamplerState sampler_state) { BLI_assert(tex != NULL); int loc = GPU_shader_get_texture_binding(shgroup->shader, name); - drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE, tex, GPU_SAMPLER_MAX, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE, tex, sampler_state, 0, 1); +} + +void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex) +{ + DRW_shgroup_uniform_texture_ex(shgroup, name, tex, GPU_SAMPLER_MAX); } void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) @@ -1278,8 +1286,7 @@ static void drw_shgroup_material_texture(DRWShadingGroup *grp, { GPUTexture *gputex = GPU_texture_from_blender(tex->ima, tex->iuser, NULL, textarget); - int loc = GPU_shader_get_texture_binding(grp->shader, name); - drw_shgroup_uniform_create_ex(grp, loc, DRW_UNIFORM_TEXTURE, gputex, state, 0, 1); + DRW_shgroup_uniform_texture_ex(grp, name, gputex, state); GPUTexture **gputex_ref = BLI_memblock_alloc(DST.vmempool->images); *gputex_ref = gputex; |