Bug 1552084 - Remove lifetime requirements on DrawTarget and ReadTarget in WR. r=emilio
authorGlenn Watson <github@intuitionlibrary.com>
Thu, 16 May 2019 22:25:35 +0000
changeset 474252 c110061df4c16715a491ead8cab815a259ae7846
parent 474251 c215a31ef6ea248566743ad6f9fd471e356c7b80
child 474253 7321594dab268ea3f11722178c98d6412f1db078
push id36027
push usershindli@mozilla.com
push dateFri, 17 May 2019 16:24:38 +0000
treeherdermozilla-central@c94c54aff466 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs1552084
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1552084 - Remove lifetime requirements on DrawTarget and ReadTarget in WR. r=emilio This makes DrawTarget and ReadTarget no longer require a borrow on a texture. This was previously fine, but in the near future WR will be rendering picture caching surfaces directly into texture handles. To allow this, we need to remove the borrow check requirement on DrawTarget for rustc. Differential Revision: https://phabricator.services.mozilla.com/D31390
gfx/wr/webrender/src/device/gl.rs
gfx/wr/webrender/src/frame_builder.rs
gfx/wr/webrender/src/gpu_glyph_renderer.rs
gfx/wr/webrender/src/picture.rs
gfx/wr/webrender/src/render_task.rs
gfx/wr/webrender/src/renderer.rs
--- a/gfx/wr/webrender/src/device/gl.rs
+++ b/gfx/wr/webrender/src/device/gl.rs
@@ -999,63 +999,93 @@ pub struct Device {
     optimal_pbo_stride: NonZeroUsize,
 
     // GL extensions
     extensions: Vec<String>,
 }
 
 /// Contains the parameters necessary to bind a draw target.
 #[derive(Clone, Copy)]
-pub enum DrawTarget<'a> {
+pub enum DrawTarget {
     /// Use the device's default draw target, with the provided dimensions,
     /// which are used to set the viewport.
     Default {
         /// Target rectangle to draw.
         rect: FramebufferIntRect,
         /// Total size of the target.
         total_size: FramebufferIntSize,
     },
     /// Use the provided texture.
     Texture {
-        /// The target texture.
-        texture: &'a Texture,
-        /// The slice within the texture array to draw to.
+        /// Size of the texture in pixels
+        dimensions: DeviceIntSize,
+        /// The slice within the texture array to draw to
         layer: LayerIndex,
-        /// Whether to draw with the texture's associated depth target.
+        /// Whether to draw with the texture's associated depth target
         with_depth: bool,
+        /// Workaround buffers for devices with broken texture array copy implementation
+        blit_workaround_buffer: Option<(RBOId, FBOId)>,
+        /// FBO that corresponds to the selected layer / depth mode
+        fbo_id: FBOId,
+        /// Native GL texture ID
+        id: gl::GLuint,
+        /// Native GL texture target
+        target: gl::GLuint,
     },
     /// Use an FBO attached to an external texture.
     External {
         fbo: FBOId,
         size: FramebufferIntSize,
     },
 }
 
-impl<'a> DrawTarget<'a> {
+impl DrawTarget {
     pub fn new_default(size: DeviceIntSize) -> Self {
         let total_size = FramebufferIntSize::from_untyped(&size.to_untyped());
         DrawTarget::Default {
             rect: total_size.into(),
             total_size,
         }
     }
 
     /// Returns true if this draw target corresponds to the default framebuffer.
     pub fn is_default(&self) -> bool {
         match *self {
             DrawTarget::Default {..} => true,
             _ => false,
         }
     }
 
+    pub fn from_texture(
+        texture: &Texture,
+        layer: usize,
+        with_depth: bool,
+    ) -> Self {
+        let fbo_id = if with_depth {
+            texture.fbos_with_depth[layer]
+        } else {
+            texture.fbos[layer]
+        };
+
+        DrawTarget::Texture {
+            dimensions: texture.get_dimensions(),
+            fbo_id,
+            with_depth,
+            layer,
+            blit_workaround_buffer: texture.blit_workaround_buffer,
+            id: texture.id,
+            target: texture.target,
+        }
+    }
+
     /// Returns the dimensions of this draw-target.
     pub fn dimensions(&self) -> DeviceIntSize {
         match *self {
             DrawTarget::Default { total_size, .. } => DeviceIntSize::from_untyped(&total_size.to_untyped()),
-            DrawTarget::Texture { texture, .. } => texture.get_dimensions(),
+            DrawTarget::Texture { dimensions, .. } => dimensions,
             DrawTarget::External { size, .. } => DeviceIntSize::from_untyped(&size.to_untyped()),
         }
     }
 
     pub fn to_framebuffer_rect(&self, device_rect: DeviceIntRect) -> FramebufferIntRect {
         let mut fb_rect = FramebufferIntRect::from_untyped(&device_rect.to_untyped());
         match *self {
             DrawTarget::Default { ref rect, .. } => {
@@ -1096,38 +1126,47 @@ impl<'a> DrawTarget<'a> {
                 )
             }
         }
     }
 }
 
 /// Contains the parameters necessary to bind a texture-backed read target.
 #[derive(Clone, Copy)]
-pub enum ReadTarget<'a> {
+pub enum ReadTarget {
     /// Use the device's default draw target.
     Default,
     /// Use the provided texture,
     Texture {
-        /// The source texture.
-        texture: &'a Texture,
-        /// The slice within the texture array to read from.
-        layer: LayerIndex,
+        /// ID of the FBO to read from.
+        fbo_id: FBOId,
     },
     /// Use an FBO attached to an external texture.
     External {
         fbo: FBOId,
     },
 }
 
-impl<'a> From<DrawTarget<'a>> for ReadTarget<'a> {
-    fn from(t: DrawTarget<'a>) -> Self {
+impl ReadTarget {
+    pub fn from_texture(
+        texture: &Texture,
+        layer: usize,
+    ) -> Self {
+        ReadTarget::Texture {
+            fbo_id: texture.fbos[layer],
+        }
+    }
+}
+
+impl From<DrawTarget> for ReadTarget {
+    fn from(t: DrawTarget) -> Self {
         match t {
             DrawTarget::Default { .. } => ReadTarget::Default,
-            DrawTarget::Texture { texture, layer, .. } =>
-                ReadTarget::Texture { texture, layer },
+            DrawTarget::Texture { fbo_id, .. } =>
+                ReadTarget::Texture { fbo_id },
             DrawTarget::External { fbo, .. } =>
                 ReadTarget::External { fbo },
         }
     }
 }
 
 impl Device {
     pub fn new(
@@ -1502,17 +1541,17 @@ impl Device {
             self.bound_read_fbo = fbo_id;
             fbo_id.bind(self.gl(), FBOTarget::Read);
         }
     }
 
     pub fn bind_read_target(&mut self, target: ReadTarget) {
         let fbo_id = match target {
             ReadTarget::Default => self.default_read_fbo,
-            ReadTarget::Texture { texture, layer } => texture.fbos[layer],
+            ReadTarget::Texture { fbo_id } => fbo_id,
             ReadTarget::External { fbo } => fbo,
         };
 
         self.bind_read_target_impl(fbo_id)
     }
 
     fn bind_draw_target_impl(&mut self, fbo_id: FBOId) {
         debug_assert!(self.inside_frame);
@@ -1536,26 +1575,22 @@ impl Device {
     }
 
     pub fn bind_draw_target(
         &mut self,
         target: DrawTarget,
     ) {
         let (fbo_id, rect, depth_available) = match target {
             DrawTarget::Default { rect, .. } => (self.default_draw_fbo, rect, true),
-            DrawTarget::Texture { texture, layer, with_depth } => {
+            DrawTarget::Texture { dimensions, fbo_id, with_depth, .. } => {
                 let rect = FramebufferIntRect::new(
                     FramebufferIntPoint::zero(),
-                    FramebufferIntSize::from_untyped(&texture.get_dimensions().to_untyped()),
+                    FramebufferIntSize::from_untyped(&dimensions.to_untyped()),
                 );
-                if with_depth {
-                    (texture.fbos_with_depth[layer], rect, true)
-                } else {
-                    (texture.fbos[layer], rect, false)
-                }
+                (fbo_id, rect, with_depth)
             },
             DrawTarget::External { fbo, size } => (fbo, size.into(), false),
         };
 
         self.depth_available = depth_available;
         self.bind_draw_target_impl(fbo_id);
         self.gl.viewport(
             rect.origin.x,
@@ -1935,19 +1970,19 @@ impl Device {
             }
         } else {
             let rect = FramebufferIntRect::new(
                 FramebufferIntPoint::zero(),
                 FramebufferIntSize::from_untyped(&src.get_dimensions().to_untyped()),
             );
             for layer in 0..src.layer_count.min(dst.layer_count) as LayerIndex {
                 self.blit_render_target(
-                    ReadTarget::Texture { texture: src, layer },
+                    ReadTarget::from_texture(src, layer),
                     rect,
-                    DrawTarget::Texture { texture: dst, layer, with_depth: false },
+                    DrawTarget::from_texture(dst, layer, false),
                     rect,
                     TextureFilter::Linear
                 );
             }
             self.reset_draw_target();
             self.reset_read_target();
         }
     }
@@ -2134,21 +2169,21 @@ impl Device {
         dest_rect: FramebufferIntRect,
         filter: TextureFilter,
     ) {
         debug_assert!(self.inside_frame);
 
         self.bind_read_target(src_target);
 
         match dest_target {
-            DrawTarget::Texture { texture, layer, .. } if layer != 0 &&
+            DrawTarget::Texture { layer, blit_workaround_buffer, dimensions, id, target, .. } if layer != 0 &&
                 !self.capabilities.supports_blit_to_texture_array =>
             {
                 // This should have been initialized in create_texture().
-                let (_rbo, fbo) = texture.blit_workaround_buffer.expect("Blit workaround buffer has not been initialized.");
+                let (_rbo, fbo) = blit_workaround_buffer.expect("Blit workaround buffer has not been initialized.");
 
                 // Blit from read target to intermediate buffer.
                 self.bind_draw_target_impl(fbo);
                 self.blit_render_target_impl(
                     src_rect,
                     dest_rect,
                     filter
                 );
@@ -2161,24 +2196,28 @@ impl Device {
                     DeviceIntPoint::new(
                         dest_rect.min_x().min(dest_rect.max_x()),
                         dest_rect.min_y().min(dest_rect.max_y()),
                     ),
                     DeviceIntSize::new(
                         dest_rect.size.width.abs(),
                         dest_rect.size.height.abs(),
                     ),
-                ).intersection(&texture.size.into()).unwrap_or(DeviceIntRect::zero());
+                ).intersection(&dimensions.into()).unwrap_or(DeviceIntRect::zero());
 
                 self.bind_read_target_impl(fbo);
-                self.bind_texture(DEFAULT_TEXTURE, texture);
+                self.bind_texture_impl(
+                    DEFAULT_TEXTURE,
+                    id,
+                    target,
+                );
 
                 // Copy from intermediate buffer to the texture layer.
                 self.gl.copy_tex_sub_image_3d(
-                    texture.target, 0,
+                    target, 0,
                     dest_bounds.origin.x, dest_bounds.origin.y,
                     layer as _,
                     dest_bounds.origin.x, dest_bounds.origin.y,
                     dest_bounds.size.width, dest_bounds.size.height,
                 );
 
             }
             _ => {
--- a/gfx/wr/webrender/src/frame_builder.rs
+++ b/gfx/wr/webrender/src/frame_builder.rs
@@ -429,17 +429,16 @@ impl FrameBuilder {
             clip_chain_stack: ClipChainStack::new(),
         };
 
         let root_render_task = RenderTask::new_picture(
             RenderTaskLocation::Fixed(self.output_rect),
             self.output_rect.size.to_f32(),
             self.root_pic_index,
             DeviceIntPoint::zero(),
-            Vec::new(),
             UvRectKind::Rect,
             root_spatial_node_index,
             global_device_pixel_scale,
         );
 
         let root_render_task_id = frame_state.render_tasks.add(root_render_task);
         frame_state
             .surfaces
--- a/gfx/wr/webrender/src/gpu_glyph_renderer.rs
+++ b/gfx/wr/webrender/src/gpu_glyph_renderer.rs
@@ -186,21 +186,21 @@ impl Renderer {
             1,
         );
         self.device.upload_texture_immediate(&path_info_texture, &path_info_texels);
 
         self.gpu_glyph_renderer.vector_stencil.bind(&mut self.device,
                                                     projection,
                                                     &mut self.renderer_errors);
 
-        self.device.bind_draw_target(DrawTarget::Texture {
-            texture: &current_page.texture,
-            layer: 0,
-            with_depth: false,
-        });
+        self.device.bind_draw_target(DrawTarget::from_texture(
+            &current_page.texture,
+            0,
+            false,
+        ));
         self.device.clear_target(Some([0.0, 0.0, 0.0, 0.0]), None, None);
 
         self.device.set_blend(true);
         self.device.set_blend_mode_subpixel_pass1();
 
         let mut instance_data = vec![];
         for (path_id, &glyph_id) in glyph_indices.iter().enumerate() {
             let glyph = &glyphs[glyph_id];
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -2505,17 +2505,16 @@ impl PicturePrimitive {
                             true,
                         );
 
                         let picture_task = RenderTask::new_picture(
                             RenderTaskLocation::Dynamic(None, device_rect.size),
                             unclipped.size,
                             pic_index,
                             device_rect.origin,
-                            Vec::new(),
                             uv_rect_kind,
                             raster_spatial_node_index,
                             device_pixel_scale,
                         );
 
                         let picture_task_id = frame_state.render_tasks.add(picture_task);
 
                         let blur_render_task_id = RenderTask::new_blur(
@@ -2555,17 +2554,16 @@ impl PicturePrimitive {
                             true,
                         );
         
                         let mut picture_task = RenderTask::new_picture(
                             RenderTaskLocation::Dynamic(None, device_rect.size),
                             unclipped.size,
                             pic_index,
                             device_rect.origin,
-                            Vec::new(),
                             uv_rect_kind,
                             raster_spatial_node_index,
                             device_pixel_scale,
                         );
                         picture_task.mark_for_saving();
         
                         let picture_task_id = frame_state.render_tasks.add(picture_task);
         
@@ -2600,17 +2598,16 @@ impl PicturePrimitive {
                             true,
                         );
 
                         let picture_task = RenderTask::new_picture(
                             RenderTaskLocation::Dynamic(None, clipped.size),
                             unclipped.size,
                             pic_index,
                             clipped.origin,
-                            Vec::new(),
                             uv_rect_kind,
                             raster_spatial_node_index,
                             device_pixel_scale,
                         );
 
                         let readback_task_id = frame_state.render_tasks.add(
                             RenderTask::new_readback(clipped)
                         );
@@ -2635,17 +2632,16 @@ impl PicturePrimitive {
                             true,
                         );
 
                         let picture_task = RenderTask::new_picture(
                             RenderTaskLocation::Dynamic(None, clipped.size),
                             unclipped.size,
                             pic_index,
                             clipped.origin,
-                            Vec::new(),
                             uv_rect_kind,
                             raster_spatial_node_index,
                             device_pixel_scale,
                         );
 
                         let render_task_id = frame_state.render_tasks.add(picture_task);
 
                         (render_task_id, render_task_id)
@@ -2659,17 +2655,16 @@ impl PicturePrimitive {
                             true,
                         );
 
                         let picture_task = RenderTask::new_picture(
                             RenderTaskLocation::Dynamic(None, clipped.size),
                             unclipped.size,
                             pic_index,
                             clipped.origin,
-                            Vec::new(),
                             uv_rect_kind,
                             raster_spatial_node_index,
                             device_pixel_scale,
                         );
 
                         let render_task_id = frame_state.render_tasks.add(picture_task);
 
                         (render_task_id, render_task_id)
@@ -2691,17 +2686,16 @@ impl PicturePrimitive {
                             supports_snapping,
                         );
 
                         let picture_task = RenderTask::new_picture(
                             RenderTaskLocation::Dynamic(None, clipped.size),
                             unclipped.size,
                             pic_index,
                             clipped.origin,
-                            Vec::new(),
                             uv_rect_kind,
                             raster_spatial_node_index,
                             device_pixel_scale,
                         );
 
                         let render_task_id = frame_state.render_tasks.add(picture_task);
 
                         (render_task_id, render_task_id)
--- a/gfx/wr/webrender/src/render_task.rs
+++ b/gfx/wr/webrender/src/render_task.rs
@@ -747,17 +747,16 @@ impl RenderTask {
         }
     }
 
     pub fn new_picture(
         location: RenderTaskLocation,
         unclipped_size: DeviceSize,
         pic_index: PictureIndex,
         content_origin: DeviceIntPoint,
-        children: Vec<RenderTaskId>,
         uv_rect_kind: UvRectKind,
         root_spatial_node_index: SpatialNodeIndex,
         device_pixel_scale: DevicePixelScale,
     ) -> Self {
         let size = match location {
             RenderTaskLocation::Dynamic(_, size) => size,
             RenderTaskLocation::Fixed(rect) => rect.size,
             RenderTaskLocation::TextureCache { rect, .. } => rect.size,
@@ -765,17 +764,17 @@ impl RenderTask {
 
         render_task_sanity_check(&size);
 
         let can_merge = size.width as f32 >= unclipped_size.width &&
                         size.height as f32 >= unclipped_size.height;
 
         RenderTask {
             location,
-            children,
+            children: Vec::new(),
             kind: RenderTaskKind::Picture(PictureTask {
                 pic_index,
                 content_origin,
                 can_merge,
                 uv_rect_handle: GpuCacheHandle::new(),
                 uv_rect_kind,
                 root_spatial_node_index,
                 device_pixel_scale,
--- a/gfx/wr/webrender/src/renderer.rs
+++ b/gfx/wr/webrender/src/renderer.rs
@@ -1405,21 +1405,21 @@ impl GpuCacheTexture {
                 rows_dirty
             }
             GpuCacheBus::Scatter { ref program, ref vao, count, .. } => {
                 device.disable_depth();
                 device.set_blend(false);
                 device.bind_program(program);
                 device.bind_custom_vao(vao);
                 device.bind_draw_target(
-                    DrawTarget::Texture {
+                    DrawTarget::from_texture(
                         texture,
-                        layer: 0,
-                        with_depth: false,
-                    },
+                        0,
+                        false,
+                    ),
                 );
                 device.draw_nonindexed_points(0, count as _);
                 0
             }
         }
     }
 }
 
@@ -1683,20 +1683,20 @@ impl AsyncScreenshotGrabber {
             window_rect,
             buffer_size,
             screenshot_size,
             image_format,
             0,
         );
 
         device.read_pixels_into_pbo(
-            ReadTarget::Texture {
-                texture: &self.scaling_textures[0],
-                layer: 0 as _,
-            },
+            ReadTarget::from_texture(
+                &self.scaling_textures[0],
+                0,
+            ),
             DeviceIntRect::new(DeviceIntPoint::new(0, 0), screenshot_size),
             image_format,
             &pbo,
         );
 
         let handle = AsyncScreenshotHandle(self.next_pbo_handle);
         self.next_pbo_handle += 1;
 
@@ -1753,34 +1753,34 @@ impl AsyncScreenshotGrabber {
                 read_target_rect,
                 buffer_size,
                 dest_size * 2,
                 image_format,
                 level + 1,
             );
 
             (
-                ReadTarget::Texture {
-                    texture: &self.scaling_textures[level + 1],
-                    layer: 0 as _,
-                },
+                ReadTarget::from_texture(
+                    &self.scaling_textures[level + 1],
+                    0,
+                ),
                 DeviceIntRect::new(
                     DeviceIntPoint::new(0, 0),
                     dest_size * 2,
                 ),
             )
         } else {
             (read_target, read_target_rect)
         };
 
-        let draw_target = DrawTarget::Texture {
-            texture: &self.scaling_textures[level],
-            layer: 0 as _,
-            with_depth: false,
-        };
+        let draw_target = DrawTarget::from_texture(
+            &self.scaling_textures[level],
+            0 as _,
+            false,
+        );
 
         let draw_target_rect = draw_target.to_framebuffer_rect(
             DeviceIntRect::new(DeviceIntPoint::new(0, 0), dest_size),
         );
 
         let read_target_rect = FramebufferIntRect::from_untyped(&read_target_rect.to_untyped());
 
         if level == 0 {
@@ -3406,21 +3406,21 @@ impl Renderer {
                                 ExternalImageSource::NativeTexture(eid) => {
                                     panic!("Unexpected external texture {:?} for the texture cache update of {:?}", eid, id);
                                 }
                             };
                             handler.unlock(id, channel_index);
                             size
                         }
                         TextureUpdateSource::DebugClear => {
-                            let draw_target = DrawTarget::Texture {
+                            let draw_target = DrawTarget::from_texture(
                                 texture,
-                                layer: layer_index as usize,
-                                with_depth: false,
-                            };
+                                layer_index as usize,
+                                false,
+                            );
                             self.device.bind_draw_target(draw_target);
                             self.device.clear_target(
                                 Some(TEXTURE_CACHE_DBG_CLEAR_COLOR),
                                 None,
                                 Some(draw_target.to_framebuffer_rect(rect.to_i32()))
                             );
                             0
                         }
@@ -3532,21 +3532,21 @@ impl Renderer {
             RenderTaskKind::Picture(ref task_info) => task_info.content_origin,
             _ => panic!("bug: composite on non-picture?"),
         };
 
         // Bind the FBO to blit the backdrop to.
         // Called per-instance in case the layer (and therefore FBO)
         // changes. The device will skip the GL call if the requested
         // target is already bound.
-        let cache_draw_target = DrawTarget::Texture {
-            texture: cache_texture,
-            layer: readback_layer.0 as usize,
-            with_depth: false,
-        };
+        let cache_draw_target = DrawTarget::from_texture(
+            cache_texture,
+            readback_layer.0 as usize,
+            false,
+        );
 
         let mut src = DeviceIntRect::new(
             source_screen_origin + (backdrop_rect.origin - backdrop_screen_origin),
             readback_rect.size,
         );
         let mut dest = readback_rect.to_i32();
         let device_to_framebuffer = TypedScale::new(1i32);
 
@@ -3609,17 +3609,21 @@ impl Renderer {
                     let (source_rect, layer) = source.get_target_rect();
                     (TextureSource::PrevPassColor, layer.0, source_rect)
                 }
             };
             debug_assert_eq!(source_rect.size, blit.target_rect.size);
             let texture = texture_resolver
                 .resolve(&source)
                 .expect("BUG: invalid source texture");
-            let read_target = DrawTarget::Texture { texture, layer, with_depth: false };
+            let read_target = DrawTarget::from_texture(
+                texture,
+                layer,
+                false,
+            );
 
             device.blit_render_target(
                 read_target.into(),
                 read_target.to_framebuffer_rect(source_rect),
                 draw_target,
                 draw_target.to_framebuffer_rect(blit.target_rect.translate(&-content_origin.to_vector())),
                 TextureFilter::Linear,
             );
@@ -3672,18 +3676,18 @@ impl Renderer {
         projection: &Transform3D<f32>,
         frame_id: GpuFrameId,
         stats: &mut RendererStats,
     ) {
         self.profile_counters.color_targets.inc();
         let _gm = self.gpu_profile.start_marker("color target");
 
         // sanity check for the depth buffer
-        if let DrawTarget::Texture { texture, .. } = draw_target {
-            assert!(texture.supports_depth() >= target.needs_depth());
+        if let DrawTarget::Texture { with_depth, .. } = draw_target {
+            assert!(with_depth >= target.needs_depth());
         }
 
         let framebuffer_kind = if draw_target.is_default() {
             FramebufferKind::Main
         } else {
             FramebufferKind::Other
         };
 
@@ -4038,21 +4042,21 @@ impl Renderer {
             if !alpha_batch_container.tile_blits.is_empty() {
                 let _timer = self.gpu_profile.start_timer(GPU_TAG_BLIT);
 
                 for blit in &alpha_batch_container.tile_blits {
                     let texture = self.texture_resolver
                         .resolve(&blit.target.texture_id)
                         .expect("BUG: invalid target texture");
 
-                    let blit_target = DrawTarget::Texture {
+                    let blit_target = DrawTarget::from_texture(
                         texture,
-                        layer: blit.target.texture_layer as usize,
-                        with_depth: false,
-                    };
+                        blit.target.texture_layer as usize,
+                        false,
+                    );
 
                     let src_rect = draw_target.to_framebuffer_rect(DeviceIntRect::new(
                         blit.src_offset - content_origin.to_vector(),
                         blit.size,
                     ));
 
                     let target_rect = blit.target.uv_rect.to_i32();
 
@@ -4335,21 +4339,21 @@ impl Renderer {
 
         // Handle any Pathfinder glyphs.
         let stencil_page = self.stencil_glyphs(&target.glyphs, &projection, &target_size, stats);
 
         {
             let texture = self.texture_resolver
                 .resolve(&texture_source)
                 .expect("BUG: invalid target texture");
-            let draw_target = DrawTarget::Texture {
+            let draw_target = DrawTarget::from_texture(
                 texture,
                 layer,
-                with_depth: false,
-            };
+                false,
+            );
             self.device.bind_draw_target(draw_target);
 
             self.device.disable_depth();
             self.device.disable_depth_write();
             self.set_blend(false, FramebufferKind::Other);
 
             for rect in &target.clears {
                 self.device.clear_target(
@@ -4798,21 +4802,21 @@ impl Renderer {
                                 &frame.render_tasks,
                                 stats,
                             );
                         }
                     }
 
                     for (target_index, target) in alpha.targets.iter().enumerate() {
                         stats.alpha_target_count += 1;
-                        let draw_target = DrawTarget::Texture {
-                            texture: &alpha_tex.as_ref().unwrap().texture,
-                            layer: target_index,
-                            with_depth: false,
-                        };
+                        let draw_target = DrawTarget::from_texture(
+                            &alpha_tex.as_ref().unwrap().texture,
+                            target_index,
+                            false,
+                        );
 
                         let projection = Transform3D::ortho(
                             0.0,
                             draw_target.dimensions().width as f32,
                             0.0,
                             draw_target.dimensions().height as f32,
                             ORTHO_NEAR_PLANE,
                             ORTHO_FAR_PLANE,
@@ -4824,21 +4828,21 @@ impl Renderer {
                             &projection,
                             &frame.render_tasks,
                             stats,
                         );
                     }
 
                     for (target_index, target) in color.targets.iter().enumerate() {
                         stats.color_target_count += 1;
-                        let draw_target = DrawTarget::Texture {
-                            texture: &color_tex.as_ref().unwrap().texture,
-                            layer: target_index,
-                            with_depth: target.needs_depth(),
-                        };
+                        let draw_target = DrawTarget::from_texture(
+                            &color_tex.as_ref().unwrap().texture,
+                            target_index,
+                            target.needs_depth(),
+                        );
 
                         let projection = Transform3D::ortho(
                             0.0,
                             draw_target.dimensions().width as f32,
                             0.0,
                             draw_target.dimensions().height as f32,
                             ORTHO_NEAR_PLANE,
                             ORTHO_FAR_PLANE,
@@ -5118,31 +5122,31 @@ impl Renderer {
             self.zoom_debug_texture = Some(texture);
         }
 
         // Copy frame buffer into the zoom texture
         let read_target = DrawTarget::new_default(device_size);
         self.device.blit_render_target(
             read_target.into(),
             read_target.to_framebuffer_rect(source_rect),
-            DrawTarget::Texture {
-                texture: self.zoom_debug_texture.as_ref().unwrap(),
-                layer: 0,
-                with_depth: false,
-            },
+            DrawTarget::from_texture(
+                self.zoom_debug_texture.as_ref().unwrap(),
+                0,
+                false,
+            ),
             texture_rect,
             TextureFilter::Nearest,
         );
 
         // Draw the zoom texture back to the framebuffer
         self.device.blit_render_target(
-            ReadTarget::Texture {
-                texture: self.zoom_debug_texture.as_ref().unwrap(),
-                layer: 0,
-            },
+            ReadTarget::from_texture(
+                self.zoom_debug_texture.as_ref().unwrap(),
+                0,
+            ),
             texture_rect,
             read_target,
             read_target.to_framebuffer_rect(target_rect),
             TextureFilter::Nearest,
         );
     }
 
     fn draw_texture_cache_debug(&mut self, device_size: DeviceIntSize) {
@@ -5251,17 +5255,17 @@ impl Renderer {
                     Some(text_rect.to_f32())
                 );
 
                 // Blit the contents of the layer. We need to invert Y because
                 // we're blitting from a texture to the main framebuffer, which
                 // use different conventions.
                 let dest_rect = rect(x, y + tag_height, size, size);
                 device.blit_render_target_invert_y(
-                    ReadTarget::Texture { texture, layer },
+                    ReadTarget::from_texture(texture, layer),
                     src_rect,
                     DrawTarget::new_default(device_size),
                     FramebufferIntRect::from_untyped(&dest_rect),
                 );
                 i += 1;
             }
         }
     }
@@ -5351,17 +5355,17 @@ impl Renderer {
         pixels
     }
 
     pub fn read_gpu_cache(&mut self) -> (DeviceIntSize, Vec<u8>) {
         let texture = self.gpu_cache_texture.texture.as_ref().unwrap();
         let size = FramebufferIntSize::from_untyped(&texture.get_dimensions().to_untyped());
         let mut texels = vec![0; (size.width * size.height * 16) as usize];
         self.device.begin_frame();
-        self.device.bind_read_target(ReadTarget::Texture { texture, layer: 0 });
+        self.device.bind_read_target(ReadTarget::from_texture(texture, 0));
         self.device.read_pixels_into(
             size.into(),
             ImageFormat::RGBAF32,
             &mut texels,
         );
         self.device.reset_read_target();
         self.device.end_frame();
         (texture.get_dimensions(), texels)
@@ -5500,21 +5504,21 @@ impl Renderer {
         } else {
             self.device.set_blend_mode_subpixel_with_bg_color_pass2();
         }
     }
 
     /// Clears all the layers of a texture with a given color.
     fn clear_texture(&mut self, texture: &Texture, color: [f32; 4]) {
         for i in 0..texture.get_layer_count() {
-            self.device.bind_draw_target(DrawTarget::Texture {
-                texture: &texture,
-                layer: i as usize,
-                with_depth: false,
-            });
+            self.device.bind_draw_target(DrawTarget::from_texture(
+                &texture,
+                i as usize,
+                false,
+            ));
             self.device.clear_target(Some(color), None, None);
         }
     }
 }
 
 pub enum ExternalImageSource<'a> {
     RawData(&'a [u8]),  // raw buffers.
     NativeTexture(u32), // It's a gl::GLuint texture handle