diff options
author | Jeroen Bakker <jbakker> | 2022-01-28 10:37:12 +0300 |
---|---|---|
committer | Jeroen Bakker <jeroen@blender.org> | 2022-01-28 10:37:45 +0300 |
commit | bdd74e1e9338b18e4f80458f284d0c6a4d100f30 (patch) | |
tree | 86daecf79b6a9d0896482d7fe8d85da9a6becc81 /source/blender/draw/engines/image/shaders | |
parent | 0a32ac02e976a4723802ed09bed64c0625e889a2 (diff) |
DrawManager: Image engine support huge images.
Adding better support for drawing huge images in the image/uv editor. Also solved tearing artifacts.
The approach is that for each image/uv editor a screen space gpu texture is created that only contains
the visible pixels. When zooming or panning the gpu texture is rebuild.
Although the solution isn't memory intensive other parts of blender memory usage scales together with
the image size.
* Due to complexity we didn't implement partial updates when drawing images tiled (wrap repeat).
This could be added, but is complicated as a change in the source could mean many different
changes on the GPU texture. The work around for now is to tag all gpu textures to be dirty when
changes are detected.
Original plan was to have 4 screen space images to support panning without gpu texture creation.
For now we don't see the need to implement it as the solution is already fast. Especially when
GPU memory is shared with CPU ram.
Reviewed By: fclem
Maniphest Tasks: T92525, T92903
Differential Revision: https://developer.blender.org/D13424
Diffstat (limited to 'source/blender/draw/engines/image/shaders')
-rw-r--r-- | source/blender/draw/engines/image/shaders/engine_image_frag.glsl | 91 | ||||
-rw-r--r-- | source/blender/draw/engines/image/shaders/engine_image_vert.glsl | 34 |
2 files changed, 42 insertions, 83 deletions
diff --git a/source/blender/draw/engines/image/shaders/engine_image_frag.glsl b/source/blender/draw/engines/image/shaders/engine_image_frag.glsl index 55a2f2a72f1..604f9b807b3 100644 --- a/source/blender/draw/engines/image/shaders/engine_image_frag.glsl +++ b/source/blender/draw/engines/image/shaders/engine_image_frag.glsl @@ -7,12 +7,7 @@ #define IMAGE_DRAW_FLAG_DEPTH (1 << 3) #define IMAGE_DRAW_FLAG_DO_REPEAT (1 << 4) -#ifdef TILED_IMAGE -uniform sampler2DArray imageTileArray; -uniform sampler1DArray imageTileData; -#else uniform sampler2D imageTexture; -#endif uniform bool imgPremultiplied; uniform int drawFlags; @@ -20,75 +15,49 @@ uniform vec2 farNearDistances; uniform vec4 color; uniform vec4 shuffle; +/* Maximum UV range. + * Negative UV coordinates and UV coordinates beyond maxUV would draw a border. */ +uniform vec2 maxUv; + #define FAR_DISTANCE farNearDistances.x #define NEAR_DISTANCE farNearDistances.y -in vec2 uvs; +#define Z_DEPTH_BORDER 1.0 +#define Z_DEPTH_IMAGE 0.75 + +in vec2 uv_screen; +in vec2 uv_image; out vec4 fragColor; -#ifdef TILED_IMAGE -/* TODO(fclem): deduplicate code. */ -bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map) +bool is_border(vec2 uv) { - vec2 tile_pos = floor(co.xy); - - 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) { - return false; - } - - /* Fetch tile information. */ - float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x; - if (tile_layer < 0.0) { - return false; - } - - vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0); - - co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer); - return true; + return (uv.x < 0.0 || uv.y < 0.0 || uv.x > maxUv.x || uv.y > maxUv.y); } -#endif void main() { - vec4 tex_color; - /* Read texture */ -#ifdef TILED_IMAGE - vec3 co = vec3(uvs, 0.0); - if (node_tex_tile_lookup(co, imageTileArray, imageTileData)) { - tex_color = texture(imageTileArray, co); - } - else { - tex_color = vec4(1.0, 0.0, 1.0, 1.0); - } -#else - vec2 uvs_clamped = ((drawFlags & IMAGE_DRAW_FLAG_DO_REPEAT) != 0) ? - fract(uvs) : - clamp(uvs, vec2(0.0), vec2(1.0)); - tex_color = texture(imageTexture, uvs_clamped); -#endif - - if ((drawFlags & IMAGE_DRAW_FLAG_APPLY_ALPHA) != 0) { - if (!imgPremultiplied) { - tex_color.rgb *= tex_color.a; + ivec2 uvs_clamped = ivec2(uv_screen); + vec4 tex_color = texelFetch(imageTexture, uvs_clamped, 0); + + bool border = is_border(uv_image); + if (!border) { + if ((drawFlags & IMAGE_DRAW_FLAG_APPLY_ALPHA) != 0) { + if (!imgPremultiplied) { + tex_color.rgb *= tex_color.a; + } + } + if ((drawFlags & IMAGE_DRAW_FLAG_DEPTH) != 0) { + tex_color = smoothstep(FAR_DISTANCE, NEAR_DISTANCE, tex_color); } - } - if ((drawFlags & IMAGE_DRAW_FLAG_DEPTH) != 0) { - tex_color = smoothstep(FAR_DISTANCE, NEAR_DISTANCE, tex_color); - } - if ((drawFlags & IMAGE_DRAW_FLAG_SHUFFLING) != 0) { - tex_color = color * dot(tex_color, shuffle); - } - if ((drawFlags & IMAGE_DRAW_FLAG_SHOW_ALPHA) == 0) { - tex_color.a = 1.0; + if ((drawFlags & IMAGE_DRAW_FLAG_SHUFFLING) != 0) { + tex_color = color * dot(tex_color, shuffle); + } + if ((drawFlags & IMAGE_DRAW_FLAG_SHOW_ALPHA) == 0) { + tex_color.a = 1.0; + } } - fragColor = tex_color; + gl_FragDepth = border ? Z_DEPTH_BORDER : Z_DEPTH_IMAGE; } diff --git a/source/blender/draw/engines/image/shaders/engine_image_vert.glsl b/source/blender/draw/engines/image/shaders/engine_image_vert.glsl index da2b1907c41..71100a5681a 100644 --- a/source/blender/draw/engines/image/shaders/engine_image_vert.glsl +++ b/source/blender/draw/engines/image/shaders/engine_image_vert.glsl @@ -1,34 +1,24 @@ #pragma BLENDER_REQUIRE(common_view_lib.glsl) #define IMAGE_DRAW_FLAG_DO_REPEAT (1 << 4) -#define IMAGE_DRAW_FLAG_USE_WORLD_POS (1 << 5) #define IMAGE_Z_DEPTH 0.75 uniform int drawFlags; -in vec3 pos; -out vec2 uvs; +in vec2 pos; +in vec2 uv; + +/* Normalized screen space uv coordinates. */ +out vec2 uv_screen; +out vec2 uv_image; void main() { - /* `pos` contains the coordinates of a quad (-1..1). but we need the coordinates of an image - * plane (0..1) */ - vec3 image_pos = pos * 0.5 + 0.5; + vec3 image_pos = vec3(pos, 0.0); + uv_screen = image_pos.xy; + uv_image = uv; - if ((drawFlags & IMAGE_DRAW_FLAG_DO_REPEAT) != 0) { - gl_Position = vec4(pos.xy, IMAGE_Z_DEPTH, 1.0); - uvs = point_view_to_object(image_pos).xy; - } - else { - vec3 world_pos = point_object_to_world(image_pos); - vec4 position = point_world_to_ndc(world_pos); - /* Move drawn pixels to the front. In the overlay engine the depth is used - * to detect if a transparency texture or the background color should be drawn. - * Vertices are between 0.0 and 0.2, Edges between 0.2 and 0.4 - * actual pixels are at 0.75, 1.0 is used for the background. */ - position.z = IMAGE_Z_DEPTH; - gl_Position = position; - /* UDIM texture uses the world position for tile selection. */ - uvs = ((drawFlags & IMAGE_DRAW_FLAG_USE_WORLD_POS) != 0) ? world_pos.xy : image_pos.xy; - } + vec3 world_pos = point_object_to_world(image_pos); + vec4 position = point_world_to_ndc(world_pos); + gl_Position = position; } |