From cc294fffcc70aff976886dd1b328108e232a87db Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Sat, 17 Sep 2016 16:02:06 +0100 Subject: [PATCH 1/5] webgl: Update the match for WebGLError's new InvalidFramebufferOperation. --- components/script/dom/webglrenderingcontext.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 3fc63349634..bb4ff17133b 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -591,6 +591,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { let error_code = if let Some(error) = self.last_error.get() { match error { WebGLError::InvalidEnum => constants::INVALID_ENUM, + WebGLError::InvalidFramebufferOperation => constants::INVALID_FRAMEBUFFER_OPERATION, WebGLError::InvalidValue => constants::INVALID_VALUE, WebGLError::InvalidOperation => constants::INVALID_OPERATION, WebGLError::OutOfMemory => constants::OUT_OF_MEMORY, From 2d66840145e8a2fdf270ff0cb47679bd7bb8c30c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Sat, 17 Sep 2016 15:57:13 +0100 Subject: [PATCH 2/5] webgl: Don't forget to update the WebGL context's RB binding. We need to track the RB in the DOM context for getParameter(gl.RENDERBUFFER_BINDING), among others. --- components/script/dom/webglrenderingcontext.rs | 4 +++- .../conformance/misc/object-deletion-behaviour.html.ini | 9 --------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index bb4ff17133b..52afabeb8bd 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -749,9 +749,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // case: Chromium currently unbinds, and Gecko silently // returns. The conformance tests don't cover this case. Some(renderbuffer) if !renderbuffer.is_deleted() => { - renderbuffer.bind(target) + self.bound_renderbuffer.set(Some(renderbuffer)); + renderbuffer.bind(target); } _ => { + self.bound_renderbuffer.set(None); // Unbind the currently bound renderbuffer self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::BindRenderbuffer(target, None))) diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/misc/object-deletion-behaviour.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/misc/object-deletion-behaviour.html.ini index 3232baffd25..5561797ccd9 100644 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/misc/object-deletion-behaviour.html.ini +++ b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/misc/object-deletion-behaviour.html.ini @@ -48,9 +48,6 @@ [WebGL test #45: getError expected: NO_ERROR. Was INVALID_OPERATION : after evaluating: gl.bindTexture(gl.TEXTURE_CUBE_MAP, texCubeMap)] expected: FAIL - [WebGL test #68: gl.getParameter(gl.RENDERBUFFER_BINDING) should be [object WebGLRenderbuffer\]. Was null.] - expected: FAIL - [WebGL test #69: gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo) threw exception TypeError: gl.framebufferRenderbuffer is not a function] expected: FAIL @@ -66,12 +63,6 @@ [WebGL test #74: gl.isRenderbuffer(rbo) should be false. Threw exception TypeError: gl.isRenderbuffer is not a function] expected: FAIL - [WebGL test #79: gl.getParameter(gl.RENDERBUFFER_BINDING) should be [object WebGLRenderbuffer\]. Was null.] - expected: FAIL - - [WebGL test #81: gl.getParameter(gl.RENDERBUFFER_BINDING) should be [object WebGLRenderbuffer\]. Was null.] - expected: FAIL - [WebGL test #83: gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 16, 16) threw exception TypeError: gl.renderbufferStorage is not a function] expected: FAIL From b2c169274ac88636ccbd9e67b10fc12faa612e4d Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Sat, 17 Sep 2016 17:40:17 +0100 Subject: [PATCH 3/5] webgl: Don't forget update WebGL's texture binding on unbind. This doesn't appear to fix any testcases, but I noticed it when fixing renderbuffers. --- components/script/dom/webglrenderingcontext.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 52afabeb8bd..71585c94def 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -776,6 +776,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { Err(err) => return self.webgl_error(err), } } else { + slot.set(None); // Unbind the currently bound texture self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::BindTexture(target, None))) From 87c9333abddbf8fb16e2f79a09c59579d34dd49f Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 16 Sep 2016 23:39:42 +0100 Subject: [PATCH 4/5] webgl: Do validation that the framebuffer is complete for FBO operations. Given that we can't make a complete FBO yet, just return false from the status check. --- components/script/dom/webglframebuffer.rs | 7 +++ .../script/dom/webglrenderingcontext.rs | 56 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs index 6e426fa0969..cd212d644bf 100644 --- a/components/script/dom/webglframebuffer.rs +++ b/components/script/dom/webglframebuffer.rs @@ -5,6 +5,7 @@ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl use canvas_traits::CanvasMsg; use dom::bindings::codegen::Bindings::WebGLFramebufferBinding; +use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use dom::bindings::global::GlobalRef; use dom::bindings::js::Root; use dom::bindings::reflector::reflect_dom_object; @@ -79,6 +80,12 @@ impl WebGLFramebuffer { self.is_deleted.get() } + pub fn check_status(&self) -> u32 { + // Until we build support for attaching renderbuffers or + // textures, all user FBOs are incomplete. + return constants::FRAMEBUFFER_UNSUPPORTED; + } + pub fn target(&self) -> Option { self.target.get() } diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 71585c94def..f42eeab4dbf 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -212,6 +212,38 @@ impl WebGLRenderingContext { } } + // Helper function for validating framebuffer completeness in + // calls touching the framebuffer. From the GLES 2.0.25 spec, + // page 119: + // + // "Effects of Framebuffer Completeness on Framebuffer + // Operations + // + // If the currently bound framebuffer is not framebuffer + // complete, then it is an error to attempt to use the + // framebuffer for writing or reading. This means that + // rendering commands such as DrawArrays and DrawElements, as + // well as commands that read the framebuffer such as + // ReadPixels and CopyTexSubImage, will generate the error + // INVALID_FRAMEBUFFER_OPERATION if called while the + // framebuffer is not framebuffer complete." + // + // The WebGL spec mentions a couple more operations that trigger + // this: clear() and getParameter(IMPLEMENTATION_COLOR_READ_*). + fn validate_framebuffer_complete(&self) -> bool { + match self.bound_framebuffer.get() { + Some(fb) => match fb.check_status() { + constants::FRAMEBUFFER_COMPLETE => return true, + _ => { + self.webgl_error(InvalidFramebufferOperation); + return false; + } + }, + // The default framebuffer is always complete. + None => return true, + } + } + fn tex_parameter(&self, target: u32, name: u32, value: TexParameterValue) { let texture = match target { constants::TEXTURE_2D => self.bound_texture_2d.get(), @@ -886,6 +918,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 fn CopyTexImage2D(&self, target: u32, level: i32, internal_format: u32, x: i32, y: i32, width: i32, height: i32, border: i32) { + if !self.validate_framebuffer_complete() { + return; + } + let validator = CommonTexImage2DValidator::new(self, target, level, internal_format, width, height, border); @@ -939,6 +975,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 fn CopyTexSubImage2D(&self, target: u32, level: i32, xoffset: i32, yoffset: i32, x: i32, y: i32, width: i32, height: i32) { + if !self.validate_framebuffer_complete() { + return; + } + // NB: We use a dummy (valid) format and border in order to reuse the // common validations, but this should have its own validator. let validator = CommonTexImage2DValidator::new(self, target, level, @@ -978,6 +1018,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11 fn Clear(&self, mask: u32) { + if !self.validate_framebuffer_complete() { + return; + } + self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::Clear(mask))).unwrap(); self.mark_as_dirty(); } @@ -1204,6 +1248,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidValue); } + if !self.validate_framebuffer_complete() { + return; + } + self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::DrawArrays(mode, first, count))) .unwrap(); @@ -1240,6 +1288,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidOperation); } + if !self.validate_framebuffer_complete() { + return; + } + match mode { constants::POINTS | constants::LINE_STRIP | constants::LINE_LOOP | constants::LINES | @@ -1508,6 +1560,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { None => return self.webgl_error(InvalidValue), }; + if !self.validate_framebuffer_complete() { + return; + } + match unsafe { JS_GetArrayBufferViewType(pixels) } { Type::Uint8 => (), _ => return self.webgl_error(InvalidOperation) From 6b1104e7f64f947466366d6aee7db2e0ee95b298 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Wed, 21 Sep 2016 08:24:59 +1000 Subject: [PATCH 5/5] Update webrender to master, including shaders. This updates webrender to include the webgl related changes needed for this patch. There was an additional commit in webrender before these landed, so also copy the shaders for that change across. There is an interface change to webrender push_image. For now, just pass zero, which is a no-op to this function. A follow up commit will introduce the servo specific changes to use this new interface. --- components/layout/webrender_helpers.rs | 3 +++ components/servo/Cargo.lock | 4 ++-- ports/cef/Cargo.lock | 4 ++-- resources/shaders/prim_shared.glsl | 24 +++++++++++++++--------- resources/shaders/ps_image.fs.glsl | 23 +++++++++++++---------- resources/shaders/ps_image.glsl | 4 +++- resources/shaders/ps_image.vs.glsl | 8 +++++--- resources/shaders/ps_image_clip.fs.glsl | 17 +++++++++++------ resources/shaders/ps_image_clip.glsl | 5 +++-- resources/shaders/ps_image_clip.vs.glsl | 8 ++++---- 10 files changed, 61 insertions(+), 39 deletions(-) diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs index c6da8f2d105..dacc8278306 100644 --- a/components/layout/webrender_helpers.rs +++ b/components/layout/webrender_helpers.rs @@ -427,9 +427,12 @@ impl WebRenderDisplayItemConverter for DisplayItem { if let Some(id) = item.webrender_image.key { if item.stretch_size.width > Au(0) && item.stretch_size.height > Au(0) { + // TODO(gw): Pass through the tile spacing once the other + // changes related to this land (parsing etc). builder.push_image(item.base.bounds.to_rectf(), item.base.clip.to_clip_region(frame_builder), item.stretch_size.to_sizef(), + Size2D::zero(), item.image_rendering.to_image_rendering(), id); } diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 647b62e58ae..e3b03e9f8bb 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -2643,7 +2643,7 @@ dependencies = [ [[package]] name = "webrender" version = "0.5.1" -source = "git+https://github.com/servo/webrender#61b8f8bfefd472bd71dd9a06c1d16dab28c1fcc0" +source = "git+https://github.com/servo/webrender#58b9e983a5e74ac1670fcf67f9c2ba68740ab2cc" dependencies = [ "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2668,7 +2668,7 @@ dependencies = [ [[package]] name = "webrender_traits" version = "0.5.1" -source = "git+https://github.com/servo/webrender#61b8f8bfefd472bd71dd9a06c1d16dab28c1fcc0" +source = "git+https://github.com/servo/webrender#58b9e983a5e74ac1670fcf67f9c2ba68740ab2cc" dependencies = [ "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 92108a43380..6c5f8cd1394 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -2503,7 +2503,7 @@ dependencies = [ [[package]] name = "webrender" version = "0.5.1" -source = "git+https://github.com/servo/webrender#61b8f8bfefd472bd71dd9a06c1d16dab28c1fcc0" +source = "git+https://github.com/servo/webrender#58b9e983a5e74ac1670fcf67f9c2ba68740ab2cc" dependencies = [ "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2528,7 +2528,7 @@ dependencies = [ [[package]] name = "webrender_traits" version = "0.5.1" -source = "git+https://github.com/servo/webrender#61b8f8bfefd472bd71dd9a06c1d16dab28c1fcc0" +source = "git+https://github.com/servo/webrender#58b9e983a5e74ac1670fcf67f9c2ba68740ab2cc" dependencies = [ "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/resources/shaders/prim_shared.glsl b/resources/shaders/prim_shared.glsl index 7336a400624..2220a7de34d 100644 --- a/resources/shaders/prim_shared.glsl +++ b/resources/shaders/prim_shared.glsl @@ -375,38 +375,44 @@ PrimitiveInfo fetch_text_run_glyph(int index, out vec4 color, out vec4 uv_rect) struct Image { PrimitiveInfo info; - vec4 st_rect; // Location of the image texture in the texture atlas. - vec4 stretch_size_uvkind; // Size of the actual image. + vec4 st_rect; // Location of the image texture in the texture atlas. + vec4 stretch_size_and_tile_spacing; // Size of the actual image and amount of space between + // tiled instances of this image. + vec4 uvkind; // Type of texture coordinates. }; Image fetch_image(int index) { Image image; - int offset = index * 5; + int offset = index * 6; image.info = unpack_prim_info(offset); image.st_rect = data[offset + 3]; - image.stretch_size_uvkind = data[offset + 4]; + image.stretch_size_and_tile_spacing = data[offset + 4]; + image.uvkind = data[offset + 5]; return image; } struct ImageClip { PrimitiveInfo info; - vec4 st_rect; // Location of the image texture in the texture atlas. - vec4 stretch_size_uvkind; // Size of the actual image. + vec4 st_rect; // Location of the image texture in the texture atlas. + vec4 stretch_size_and_tile_spacing; // Size of the actual image and amount of space between + // tiled instances of this image. + vec4 uvkind; // Type of texture coordinates. Clip clip; }; ImageClip fetch_image_clip(int index) { ImageClip image; - int offset = index * 14; + int offset = index * 15; image.info = unpack_prim_info(offset); image.st_rect = data[offset + 3]; - image.stretch_size_uvkind = data[offset + 4]; - image.clip = unpack_clip(offset + 5); + image.stretch_size_and_tile_spacing = data[offset + 4]; + image.uvkind = data[offset + 5]; + image.clip = unpack_clip(offset + 6); return image; } diff --git a/resources/shaders/ps_image.fs.glsl b/resources/shaders/ps_image.fs.glsl index e787b9bbd65..b685e4772e1 100644 --- a/resources/shaders/ps_image.fs.glsl +++ b/resources/shaders/ps_image.fs.glsl @@ -11,16 +11,19 @@ void main(void) { // We clamp the texture coordinate calculation here to the local rectangle boundaries, // which makes the edge of the texture stretch instead of repeat. - vec2 uv = clamp(pos, vLocalRect.xy, vLocalRect.xy + vLocalRect.zw); + vec2 relative_pos_in_rect = + clamp(pos, vLocalRect.xy, vLocalRect.xy + vLocalRect.zw) - vLocalRect.xy; +#else + float alpha = 1.0;; + vec2 relative_pos_in_rect = vLocalPos; +#endif + + // We calculate the particular tile this fragment belongs to, taking into + // account the spacing in between tiles. We only paint if our fragment does + // not fall into that spacing. + vec2 position_in_tile = mod(relative_pos_in_rect, vStretchSize + vTileSpacing); + vec2 st = vTextureOffset + ((position_in_tile / vStretchSize) * vTextureSize); + alpha = alpha * float(all(bvec2(step(position_in_tile, vStretchSize)))); - uv = (uv - vLocalRect.xy) / vStretchSize; -#else - vec2 uv = vUv; -#endif - vec2 st = vTextureOffset + vTextureSize * fract(uv); -#ifdef WR_FEATURE_TRANSFORM oFragColor = vec4(1, 1, 1, alpha) * texture(sDiffuse, st); -#else - oFragColor = texture(sDiffuse, st); -#endif } diff --git a/resources/shaders/ps_image.glsl b/resources/shaders/ps_image.glsl index b89a421789b..0ca0ac57211 100644 --- a/resources/shaders/ps_image.glsl +++ b/resources/shaders/ps_image.glsl @@ -4,11 +4,13 @@ flat varying vec2 vTextureOffset; // Offset of this image into the texture atlas. flat varying vec2 vTextureSize; // Size of the image in the texture atlas. +flat varying vec2 vTileSpacing; // Amount of space between tiled instances of this image. #ifdef WR_FEATURE_TRANSFORM varying vec3 vLocalPos; flat varying vec4 vLocalRect; flat varying vec2 vStretchSize; #else -varying vec2 vUv; // Location within the CSS box to draw. +varying vec2 vLocalPos; +flat varying vec2 vStretchSize; #endif diff --git a/resources/shaders/ps_image.vs.glsl b/resources/shaders/ps_image.vs.glsl index d146e98c8c3..1f5a997b0af 100644 --- a/resources/shaders/ps_image.vs.glsl +++ b/resources/shaders/ps_image.vs.glsl @@ -10,17 +10,18 @@ void main(void) { TransformVertexInfo vi = write_transform_vertex(image.info); vLocalRect = vi.clipped_local_rect; vLocalPos = vi.local_pos; - vStretchSize = image.stretch_size_uvkind.xy; + vStretchSize = image.stretch_size_and_tile_spacing.xy; #else VertexInfo vi = write_vertex(image.info); - vUv = (vi.local_clamped_pos - vi.local_rect.p0) / image.stretch_size_uvkind.xy; + vStretchSize = image.stretch_size_and_tile_spacing.xy; + vLocalPos = vi.local_clamped_pos - vi.local_rect.p0; #endif // vUv will contain how many times this image has wrapped around the image size. vec2 st0 = image.st_rect.xy; vec2 st1 = image.st_rect.zw; - switch (uint(image.stretch_size_uvkind.z)) { + switch (uint(image.uvkind.x)) { case UV_NORMALIZED: break; case UV_PIXEL: { @@ -33,4 +34,5 @@ void main(void) { vTextureSize = st1 - st0; vTextureOffset = st0; + vTileSpacing = image.stretch_size_and_tile_spacing.zw; } diff --git a/resources/shaders/ps_image_clip.fs.glsl b/resources/shaders/ps_image_clip.fs.glsl index 2ee0f8ee0c7..62da5a846f9 100644 --- a/resources/shaders/ps_image_clip.fs.glsl +++ b/resources/shaders/ps_image_clip.fs.glsl @@ -11,17 +11,22 @@ void main(void) { // We clamp the texture coordinate calculation here to the local rectangle boundaries, // which makes the edge of the texture stretch instead of repeat. - vec2 uv = clamp(local_pos.xy, vLocalRect.xy, vLocalRect.xy + vLocalRect.zw); - - uv = (uv - vLocalRect.xy) / vStretchSize; + vec2 pos_for_texture = + clamp(pos, vLocalRect.xy, vLocalRect.xy + vLocalRect.zw) - vLocalRect.xy; #else float alpha = 1; vec2 local_pos = vLocalPos; - vec2 uv = vUv; + vec2 relative_pos_in_rect = vLocalPos - vLocalRect.xy; #endif - vec2 st = vTextureOffset + vTextureSize * fract(uv); - alpha = min(alpha, do_clip(local_pos, vClipRect, vClipRadius)); + + // We calculate the particular tile this fragment belongs to, taking into + // account the spacing in between tiles. We only paint if our fragment does + // not fall into that spacing. + vec2 position_in_tile = mod(relative_pos_in_rect, vStretchSize + vTileSpacing); + vec2 st = vTextureOffset + ((position_in_tile / vStretchSize) * vTextureSize); + alpha = alpha * float(all(bvec2(step(position_in_tile, vStretchSize)))); + oFragColor = texture(sDiffuse, st) * vec4(1, 1, 1, alpha); } diff --git a/resources/shaders/ps_image_clip.glsl b/resources/shaders/ps_image_clip.glsl index 8b5f263fe72..fe4333271d9 100644 --- a/resources/shaders/ps_image_clip.glsl +++ b/resources/shaders/ps_image_clip.glsl @@ -4,13 +4,14 @@ flat varying vec2 vTextureOffset; // Offset of this image into the texture atlas. flat varying vec2 vTextureSize; // Size of the image in the texture atlas. +flat varying vec2 vTileSpacing; // Amount of space between tiled instances of this image. +flat varying vec2 vStretchSize; flat varying vec4 vClipRect; flat varying vec4 vClipRadius; +flat varying vec4 vLocalRect; #ifdef WR_FEATURE_TRANSFORM varying vec3 vLocalPos; -flat varying vec4 vLocalRect; -flat varying vec2 vStretchSize; #else varying vec2 vLocalPos; varying vec2 vUv; // Location within the CSS box to draw. diff --git a/resources/shaders/ps_image_clip.vs.glsl b/resources/shaders/ps_image_clip.vs.glsl index 6165f535ad9..3ba4bc3b49f 100644 --- a/resources/shaders/ps_image_clip.vs.glsl +++ b/resources/shaders/ps_image_clip.vs.glsl @@ -8,13 +8,11 @@ void main(void) { #ifdef WR_FEATURE_TRANSFORM TransformVertexInfo vi = write_transform_vertex(image.info); - vLocalRect = vi.clipped_local_rect; vLocalPos = vi.local_pos; - vStretchSize = image.stretch_size_uvkind.xy; #else VertexInfo vi = write_vertex(image.info); - vUv = (vi.local_clamped_pos - vi.local_rect.p0) / image.stretch_size_uvkind.xy; vLocalPos = vi.local_clamped_pos; + vLocalRect = image.info.local_rect; #endif vClipRect = vec4(image.clip.rect.xy, image.clip.rect.xy + image.clip.rect.zw); @@ -26,7 +24,7 @@ void main(void) { vec2 st0 = image.st_rect.xy; vec2 st1 = image.st_rect.zw; - switch (uint(image.stretch_size_uvkind.z)) { + switch (uint(image.uvkind.x)) { case UV_NORMALIZED: break; case UV_PIXEL: { @@ -39,4 +37,6 @@ void main(void) { vTextureSize = st1 - st0; vTextureOffset = st0; + vStretchSize = image.stretch_size_and_tile_spacing.xy; + vTileSpacing = image.stretch_size_and_tile_spacing.zw; }